Salome HOME
Merge from V5_1_main 10/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 #define CHRONODEF
29 #include "SMESH_MeshEditor.hxx"
30
31 #include "SMDS_FaceOfNodes.hxx"
32 #include "SMDS_VolumeTool.hxx"
33 #include "SMDS_EdgePosition.hxx"
34 #include "SMDS_PolyhedralVolumeOfNodes.hxx"
35 #include "SMDS_FacePosition.hxx"
36 #include "SMDS_SpacePosition.hxx"
37 //#include "SMDS_QuadraticFaceOfNodes.hxx"
38 #include "SMDS_MeshGroup.hxx"
39 #include "SMDS_LinearEdge.hxx"
40 #include "SMDS_Downward.hxx"
41 #include "SMDS_SetIterator.hxx"
42
43 #include "SMESHDS_Group.hxx"
44 #include "SMESHDS_Mesh.hxx"
45
46 #include "SMESH_Algo.hxx"
47 #include "SMESH_ControlsDef.hxx"
48 #include "SMESH_Group.hxx"
49 #include "SMESH_MesherHelper.hxx"
50 #include "SMESH_OctreeNode.hxx"
51 #include "SMESH_subMesh.hxx"
52
53 #include "utilities.h"
54
55 #include <BRepAdaptor_Surface.hxx>
56 #include <BRepClass3d_SolidClassifier.hxx>
57 #include <BRep_Tool.hxx>
58 #include <ElCLib.hxx>
59 #include <Extrema_GenExtPS.hxx>
60 #include <Extrema_POnCurv.hxx>
61 #include <Extrema_POnSurf.hxx>
62 #include <GC_MakeSegment.hxx>
63 #include <Geom2d_Curve.hxx>
64 #include <GeomAPI_ExtremaCurveCurve.hxx>
65 #include <GeomAdaptor_Surface.hxx>
66 #include <Geom_Curve.hxx>
67 #include <Geom_Line.hxx>
68 #include <Geom_Surface.hxx>
69 #include <IntAna_IntConicQuad.hxx>
70 #include <IntAna_Quadric.hxx>
71 #include <Precision.hxx>
72 #include <TColStd_ListOfInteger.hxx>
73 #include <TopAbs_State.hxx>
74 #include <TopExp.hxx>
75 #include <TopExp_Explorer.hxx>
76 #include <TopTools_ListIteratorOfListOfShape.hxx>
77 #include <TopTools_ListOfShape.hxx>
78 #include <TopTools_SequenceOfShape.hxx>
79 #include <TopoDS.hxx>
80 #include <TopoDS_Face.hxx>
81 #include <gp.hxx>
82 #include <gp_Ax1.hxx>
83 #include <gp_Dir.hxx>
84 #include <gp_Lin.hxx>
85 #include <gp_Pln.hxx>
86 #include <gp_Trsf.hxx>
87 #include <gp_Vec.hxx>
88 #include <gp_XY.hxx>
89 #include <gp_XYZ.hxx>
90
91 #include <math.h>
92
93 #include <map>
94 #include <set>
95 #include <numeric>
96 #include <limits>
97
98 #define cast2Node(elem) static_cast<const SMDS_MeshNode*>( elem )
99
100 using namespace std;
101 using namespace SMESH::Controls;
102
103 typedef map<const SMDS_MeshElement*, list<const SMDS_MeshNode*> >    TElemOfNodeListMap;
104 typedef map<const SMDS_MeshElement*, list<const SMDS_MeshElement*> > TElemOfElemListMap;
105
106 typedef SMDS_SetIterator< SMDS_pElement, TIDSortedElemSet::const_iterator> TSetIterator;
107
108 //=======================================================================
109 //function : SMESH_MeshEditor
110 //purpose  :
111 //=======================================================================
112
113 SMESH_MeshEditor::SMESH_MeshEditor( SMESH_Mesh* theMesh )
114   :myMesh( theMesh ) // theMesh may be NULL
115 {
116 }
117
118 //=======================================================================
119 /*!
120  * \brief Add element
121  */
122 //=======================================================================
123
124 SMDS_MeshElement*
125 SMESH_MeshEditor::AddElement(const vector<const SMDS_MeshNode*> & node,
126                              const SMDSAbs_ElementType            type,
127                              const bool                           isPoly,
128                              const int                            ID)
129 {
130   //MESSAGE("AddElement " <<node.size() << " " << type << " " << isPoly << " " << ID);
131   SMDS_MeshElement* e = 0;
132   int nbnode = node.size();
133   SMESHDS_Mesh* mesh = GetMeshDS();
134   switch ( type ) {
135   case SMDSAbs_Face:
136     if ( !isPoly ) {
137       if      (nbnode == 3) {
138         if ( ID >= 0 ) e = mesh->AddFaceWithID(node[0], node[1], node[2], ID);
139         else           e = mesh->AddFace      (node[0], node[1], node[2] );
140       }
141       else if (nbnode == 4) {
142         if ( ID >= 0 ) e = mesh->AddFaceWithID(node[0], node[1], node[2], node[3], ID);
143         else           e = mesh->AddFace      (node[0], node[1], node[2], node[3] );
144       }
145       else if (nbnode == 6) {
146         if ( ID >= 0 ) e = mesh->AddFaceWithID(node[0], node[1], node[2], node[3],
147                                                node[4], node[5], ID);
148         else           e = mesh->AddFace      (node[0], node[1], node[2], node[3],
149                                                node[4], node[5] );
150       }
151       else if (nbnode == 8) {
152         if ( ID >= 0 ) e = mesh->AddFaceWithID(node[0], node[1], node[2], node[3],
153                                                node[4], node[5], node[6], node[7], ID);
154         else           e = mesh->AddFace      (node[0], node[1], node[2], node[3],
155                                                node[4], node[5], node[6], node[7] );
156       }
157     } else {
158       if ( ID >= 0 ) e = mesh->AddPolygonalFaceWithID(node, ID);
159       else           e = mesh->AddPolygonalFace      (node    );
160     }
161     break;
162
163   case SMDSAbs_Volume:
164     if ( !isPoly ) {
165       if      (nbnode == 4) {
166         if ( ID >= 0 ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3], ID);
167         else           e = mesh->AddVolume      (node[0], node[1], node[2], node[3] );
168       }
169       else if (nbnode == 5) {
170         if ( ID >= 0 ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
171                                                  node[4], ID);
172         else           e = mesh->AddVolume      (node[0], node[1], node[2], node[3],
173                                                  node[4] );
174       }
175       else if (nbnode == 6) {
176         if ( ID >= 0 ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
177                                                  node[4], node[5], ID);
178         else           e = mesh->AddVolume      (node[0], node[1], node[2], node[3],
179                                                  node[4], node[5] );
180       }
181       else if (nbnode == 8) {
182         if ( ID >= 0 ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
183                                                  node[4], node[5], node[6], node[7], ID);
184         else           e = mesh->AddVolume      (node[0], node[1], node[2], node[3],
185                                                  node[4], node[5], node[6], node[7] );
186       }
187       else if (nbnode == 10) {
188         if ( ID >= 0 ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
189                                                  node[4], node[5], node[6], node[7],
190                                                  node[8], node[9], ID);
191         else           e = mesh->AddVolume      (node[0], node[1], node[2], node[3],
192                                                  node[4], node[5], node[6], node[7],
193                                                  node[8], node[9] );
194       }
195       else if (nbnode == 13) {
196         if ( ID >= 0 ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
197                                                  node[4], node[5], node[6], node[7],
198                                                  node[8], node[9], node[10],node[11],
199                                                  node[12],ID);
200         else           e = mesh->AddVolume      (node[0], node[1], node[2], node[3],
201                                                  node[4], node[5], node[6], node[7],
202                                                  node[8], node[9], node[10],node[11],
203                                                  node[12] );
204       }
205       else if (nbnode == 15) {
206         if ( ID >= 0 ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
207                                                  node[4], node[5], node[6], node[7],
208                                                  node[8], node[9], node[10],node[11],
209                                                  node[12],node[13],node[14],ID);
210         else           e = mesh->AddVolume      (node[0], node[1], node[2], node[3],
211                                                  node[4], node[5], node[6], node[7],
212                                                  node[8], node[9], node[10],node[11],
213                                                  node[12],node[13],node[14] );
214       }
215       else if (nbnode == 20) {
216         if ( ID >= 0 ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
217                                                  node[4], node[5], node[6], node[7],
218                                                  node[8], node[9], node[10],node[11],
219                                                  node[12],node[13],node[14],node[15],
220                                                  node[16],node[17],node[18],node[19],ID);
221         else           e = mesh->AddVolume      (node[0], node[1], node[2], node[3],
222                                                  node[4], node[5], node[6], node[7],
223                                                  node[8], node[9], node[10],node[11],
224                                                  node[12],node[13],node[14],node[15],
225                                                  node[16],node[17],node[18],node[19] );
226       }
227     }
228     break;
229
230   case SMDSAbs_Edge:
231     if ( nbnode == 2 ) {
232       if ( ID >= 0 ) e = mesh->AddEdgeWithID(node[0], node[1], ID);
233       else           e = mesh->AddEdge      (node[0], node[1] );
234     }
235     else if ( nbnode == 3 ) {
236       if ( ID >= 0 ) e = mesh->AddEdgeWithID(node[0], node[1], node[2], ID);
237       else           e = mesh->AddEdge      (node[0], node[1], node[2] );
238     }
239     break;
240
241   case SMDSAbs_0DElement:
242     if ( nbnode == 1 ) {
243       if ( ID >= 0 ) e = mesh->Add0DElementWithID(node[0], ID);
244       else           e = mesh->Add0DElement      (node[0] );
245     }
246     break;
247
248   case SMDSAbs_Node:
249     if ( ID >= 0 ) e = mesh->AddNodeWithID(node[0]->X(), node[0]->Y(), node[0]->Z(), ID);
250     else           e = mesh->AddNode      (node[0]->X(), node[0]->Y(), node[0]->Z());
251     break;
252
253   default:;
254   }
255   if ( e ) myLastCreatedElems.Append( e );
256   return e;
257 }
258
259 //=======================================================================
260 /*!
261  * \brief Add element
262  */
263 //=======================================================================
264
265 SMDS_MeshElement* SMESH_MeshEditor::AddElement(const vector<int> &       nodeIDs,
266                                                const SMDSAbs_ElementType type,
267                                                const bool                isPoly,
268                                                const int                 ID)
269 {
270   vector<const SMDS_MeshNode*> nodes;
271   nodes.reserve( nodeIDs.size() );
272   vector<int>::const_iterator id = nodeIDs.begin();
273   while ( id != nodeIDs.end() ) {
274     if ( const SMDS_MeshNode* node = GetMeshDS()->FindNode( *id++ ))
275       nodes.push_back( node );
276     else
277       return 0;
278   }
279   return AddElement( nodes, type, isPoly, ID );
280 }
281
282 //=======================================================================
283 //function : Remove
284 //purpose  : Remove a node or an element.
285 //           Modify a compute state of sub-meshes which become empty
286 //=======================================================================
287
288 int SMESH_MeshEditor::Remove (const list< int >& theIDs,
289                               const bool         isNodes )
290 {
291   myLastCreatedElems.Clear();
292   myLastCreatedNodes.Clear();
293
294   SMESHDS_Mesh* aMesh = GetMeshDS();
295   set< SMESH_subMesh *> smmap;
296
297   int removed = 0;
298   list<int>::const_iterator it = theIDs.begin();
299   for ( ; it != theIDs.end(); it++ ) {
300     const SMDS_MeshElement * elem;
301     if ( isNodes )
302       elem = aMesh->FindNode( *it );
303     else
304       elem = aMesh->FindElement( *it );
305     if ( !elem )
306       continue;
307
308     // Notify VERTEX sub-meshes about modification
309     if ( isNodes ) {
310       const SMDS_MeshNode* node = cast2Node( elem );
311       if ( node->GetPosition()->GetTypeOfPosition() == SMDS_TOP_VERTEX )
312         if ( int aShapeID = node->getshapeId() )
313           if ( SMESH_subMesh * sm = GetMesh()->GetSubMeshContaining( aShapeID ) )
314             smmap.insert( sm );
315     }
316     // Find sub-meshes to notify about modification
317     //     SMDS_ElemIteratorPtr nodeIt = elem->nodesIterator();
318     //     while ( nodeIt->more() ) {
319     //       const SMDS_MeshNode* node = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
320     //       const SMDS_PositionPtr& aPosition = node->GetPosition();
321     //       if ( aPosition.get() ) {
322     //         if ( int aShapeID = aPosition->GetShapeId() ) {
323     //           if ( SMESH_subMesh * sm = GetMesh()->GetSubMeshContaining( aShapeID ) )
324     //             smmap.insert( sm );
325     //         }
326     //       }
327     //     }
328
329     // Do remove
330     if ( isNodes )
331       aMesh->RemoveNode( static_cast< const SMDS_MeshNode* >( elem ));
332     else
333       aMesh->RemoveElement( elem );
334     removed++;
335   }
336
337   // Notify sub-meshes about modification
338   if ( !smmap.empty() ) {
339     set< SMESH_subMesh *>::iterator smIt;
340     for ( smIt = smmap.begin(); smIt != smmap.end(); smIt++ )
341       (*smIt)->ComputeStateEngine( SMESH_subMesh::MESH_ENTITY_REMOVED );
342   }
343
344   //   // Check if the whole mesh becomes empty
345   //   if ( SMESH_subMesh * sm = GetMesh()->GetSubMeshContaining( 1 ) )
346   //     sm->ComputeStateEngine( SMESH_subMesh::CHECK_COMPUTE_STATE );
347
348   return removed;
349 }
350
351 //=======================================================================
352 //function : FindShape
353 //purpose  : Return an index of the shape theElem is on
354 //           or zero if a shape not found
355 //=======================================================================
356
357 int SMESH_MeshEditor::FindShape (const SMDS_MeshElement * theElem)
358 {
359   myLastCreatedElems.Clear();
360   myLastCreatedNodes.Clear();
361
362   SMESHDS_Mesh * aMesh = GetMeshDS();
363   if ( aMesh->ShapeToMesh().IsNull() )
364     return 0;
365
366   if ( theElem->GetType() == SMDSAbs_Node )
367     {
368       int aShapeID = theElem->getshapeId();
369       if (aShapeID <= 0)
370         return 0;
371       else
372         return aShapeID;
373     }
374
375   TopoDS_Shape aShape; // the shape a node is on
376   SMDS_ElemIteratorPtr nodeIt = theElem->nodesIterator();
377   while ( nodeIt->more() ) {
378     const SMDS_MeshNode* node = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
379     int aShapeID = node->getshapeId();
380     if (aShapeID > 0) {
381       SMESHDS_SubMesh * sm = aMesh->MeshElements( aShapeID );
382       if ( sm ) {
383         if ( sm->Contains( theElem ))
384           return aShapeID;
385         if ( aShape.IsNull() )
386           aShape = aMesh->IndexToShape( aShapeID );
387       }
388       else {
389         //MESSAGE ( "::FindShape() No SubShape for aShapeID " << aShapeID );
390       }
391     }
392   }
393
394   // None of nodes is on a proper shape,
395   // find the shape among ancestors of aShape on which a node is
396   if ( aShape.IsNull() ) {
397     //MESSAGE ("::FindShape() - NONE node is on shape")
398     return 0;
399   }
400   TopTools_ListIteratorOfListOfShape ancIt( GetMesh()->GetAncestors( aShape ));
401   for ( ; ancIt.More(); ancIt.Next() ) {
402     SMESHDS_SubMesh * sm = aMesh->MeshElements( ancIt.Value() );
403     if ( sm && sm->Contains( theElem ))
404       return aMesh->ShapeToIndex( ancIt.Value() );
405   }
406
407   //MESSAGE ("::FindShape() - SHAPE NOT FOUND")
408   return 0;
409 }
410
411 //=======================================================================
412 //function : IsMedium
413 //purpose  :
414 //=======================================================================
415
416 bool SMESH_MeshEditor::IsMedium(const SMDS_MeshNode*      node,
417                                 const SMDSAbs_ElementType typeToCheck)
418 {
419   bool isMedium = false;
420   SMDS_ElemIteratorPtr it = node->GetInverseElementIterator(typeToCheck);
421   while (it->more() && !isMedium ) {
422     const SMDS_MeshElement* elem = it->next();
423     isMedium = elem->IsMediumNode(node);
424   }
425   return isMedium;
426 }
427
428 //=======================================================================
429 //function : ShiftNodesQuadTria
430 //purpose  : auxilary
431 //           Shift nodes in the array corresponded to quadratic triangle
432 //           example: (0,1,2,3,4,5) -> (1,2,0,4,5,3)
433 //=======================================================================
434 static void ShiftNodesQuadTria(const SMDS_MeshNode* aNodes[])
435 {
436   const SMDS_MeshNode* nd1 = aNodes[0];
437   aNodes[0] = aNodes[1];
438   aNodes[1] = aNodes[2];
439   aNodes[2] = nd1;
440   const SMDS_MeshNode* nd2 = aNodes[3];
441   aNodes[3] = aNodes[4];
442   aNodes[4] = aNodes[5];
443   aNodes[5] = nd2;
444 }
445
446 //=======================================================================
447 //function : GetNodesFromTwoTria
448 //purpose  : auxilary
449 //           Shift nodes in the array corresponded to quadratic triangle
450 //           example: (0,1,2,3,4,5) -> (1,2,0,4,5,3)
451 //=======================================================================
452 static bool GetNodesFromTwoTria(const SMDS_MeshElement * theTria1,
453                                 const SMDS_MeshElement * theTria2,
454                                 const SMDS_MeshNode* N1[],
455                                 const SMDS_MeshNode* N2[])
456 {
457   SMDS_ElemIteratorPtr it = theTria1->nodesIterator();
458   int i=0;
459   while(i<6) {
460     N1[i] = static_cast<const SMDS_MeshNode*>( it->next() );
461     i++;
462   }
463   if(it->more()) return false;
464   it = theTria2->nodesIterator();
465   i=0;
466   while(i<6) {
467     N2[i] = static_cast<const SMDS_MeshNode*>( it->next() );
468     i++;
469   }
470   if(it->more()) return false;
471
472   int sames[3] = {-1,-1,-1};
473   int nbsames = 0;
474   int j;
475   for(i=0; i<3; i++) {
476     for(j=0; j<3; j++) {
477       if(N1[i]==N2[j]) {
478         sames[i] = j;
479         nbsames++;
480         break;
481       }
482     }
483   }
484   if(nbsames!=2) return false;
485   if(sames[0]>-1) {
486     ShiftNodesQuadTria(N1);
487     if(sames[1]>-1) {
488       ShiftNodesQuadTria(N1);
489     }
490   }
491   i = sames[0] + sames[1] + sames[2];
492   for(; i<2; i++) {
493     ShiftNodesQuadTria(N2);
494   }
495   // now we receive following N1 and N2 (using numeration as above image)
496   // tria1 : (1 2 4 5 9 7)  and  tria2 : (3 4 2 8 9 6)
497   // i.e. first nodes from both arrays determ new diagonal
498   return true;
499 }
500
501 //=======================================================================
502 //function : InverseDiag
503 //purpose  : Replace two neighbour triangles with ones built on the same 4 nodes
504 //           but having other common link.
505 //           Return False if args are improper
506 //=======================================================================
507
508 bool SMESH_MeshEditor::InverseDiag (const SMDS_MeshElement * theTria1,
509                                     const SMDS_MeshElement * theTria2 )
510 {
511   MESSAGE("InverseDiag");
512   myLastCreatedElems.Clear();
513   myLastCreatedNodes.Clear();
514
515   if (!theTria1 || !theTria2)
516     return false;
517
518   const SMDS_VtkFace* F1 = dynamic_cast<const SMDS_VtkFace*>( theTria1 );
519   if (!F1) return false;
520   const SMDS_VtkFace* F2 = dynamic_cast<const SMDS_VtkFace*>( theTria2 );
521   if (!F2) return false;
522   if ((theTria1->GetEntityType() == SMDSEntity_Triangle) &&
523       (theTria2->GetEntityType() == SMDSEntity_Triangle)) {
524
525     //  1 +--+ A  theTria1: ( 1 A B ) A->2 ( 1 2 B ) 1 +--+ A
526     //    | /|    theTria2: ( B A 2 ) B->1 ( 1 A 2 )   |\ |
527     //    |/ |                                         | \|
528     //  B +--+ 2                                     B +--+ 2
529
530     // put nodes in array and find out indices of the same ones
531     const SMDS_MeshNode* aNodes [6];
532     int sameInd [] = { 0, 0, 0, 0, 0, 0 };
533     int i = 0;
534     SMDS_ElemIteratorPtr it = theTria1->nodesIterator();
535     while ( it->more() ) {
536       aNodes[ i ] = static_cast<const SMDS_MeshNode*>( it->next() );
537
538       if ( i > 2 ) // theTria2
539         // find same node of theTria1
540         for ( int j = 0; j < 3; j++ )
541           if ( aNodes[ i ] == aNodes[ j ]) {
542             sameInd[ j ] = i;
543             sameInd[ i ] = j;
544             break;
545           }
546       // next
547       i++;
548       if ( i == 3 ) {
549         if ( it->more() )
550           return false; // theTria1 is not a triangle
551         it = theTria2->nodesIterator();
552       }
553       if ( i == 6 && it->more() )
554         return false; // theTria2 is not a triangle
555     }
556
557     // find indices of 1,2 and of A,B in theTria1
558     int iA = 0, iB = 0, i1 = 0, i2 = 0;
559     for ( i = 0; i < 6; i++ ) {
560       if ( sameInd [ i ] == 0 ) {
561         if ( i < 3 ) i1 = i;
562         else         i2 = i;
563       }
564       else if (i < 3) {
565         if ( iA ) iB = i;
566         else      iA = i;
567       }
568     }
569     // nodes 1 and 2 should not be the same
570     if ( aNodes[ i1 ] == aNodes[ i2 ] )
571       return false;
572
573     // theTria1: A->2
574     aNodes[ iA ] = aNodes[ i2 ];
575     // theTria2: B->1
576     aNodes[ sameInd[ iB ]] = aNodes[ i1 ];
577
578     GetMeshDS()->ChangeElementNodes( theTria1, aNodes, 3 );
579     GetMeshDS()->ChangeElementNodes( theTria2, &aNodes[ 3 ], 3 );
580
581     return true;
582
583   } // end if(F1 && F2)
584
585   // check case of quadratic faces
586   if (theTria1->GetEntityType() != SMDSEntity_Quad_Triangle)
587     return false;
588   if (theTria2->GetEntityType() != SMDSEntity_Quad_Triangle)
589     return false;
590
591   //       5
592   //  1 +--+--+ 2  theTria1: (1 2 4 5 9 7) or (2 4 1 9 7 5) or (4 1 2 7 5 9)
593   //    |    /|    theTria2: (2 3 4 6 8 9) or (3 4 2 8 9 6) or (4 2 3 9 6 8)
594   //    |   / |
595   //  7 +  +  + 6
596   //    | /9  |
597   //    |/    |
598   //  4 +--+--+ 3
599   //       8
600
601   const SMDS_MeshNode* N1 [6];
602   const SMDS_MeshNode* N2 [6];
603   if(!GetNodesFromTwoTria(theTria1,theTria2,N1,N2))
604     return false;
605   // now we receive following N1 and N2 (using numeration as above image)
606   // tria1 : (1 2 4 5 9 7)  and  tria2 : (3 4 2 8 9 6)
607   // i.e. first nodes from both arrays determ new diagonal
608
609   const SMDS_MeshNode* N1new [6];
610   const SMDS_MeshNode* N2new [6];
611   N1new[0] = N1[0];
612   N1new[1] = N2[0];
613   N1new[2] = N2[1];
614   N1new[3] = N1[4];
615   N1new[4] = N2[3];
616   N1new[5] = N1[5];
617   N2new[0] = N1[0];
618   N2new[1] = N1[1];
619   N2new[2] = N2[0];
620   N2new[3] = N1[3];
621   N2new[4] = N2[5];
622   N2new[5] = N1[4];
623   // replaces nodes in faces
624   GetMeshDS()->ChangeElementNodes( theTria1, N1new, 6 );
625   GetMeshDS()->ChangeElementNodes( theTria2, N2new, 6 );
626
627   return true;
628 }
629
630 //=======================================================================
631 //function : findTriangles
632 //purpose  : find triangles sharing theNode1-theNode2 link
633 //=======================================================================
634
635 static bool findTriangles(const SMDS_MeshNode *    theNode1,
636                           const SMDS_MeshNode *    theNode2,
637                           const SMDS_MeshElement*& theTria1,
638                           const SMDS_MeshElement*& theTria2)
639 {
640   if ( !theNode1 || !theNode2 ) return false;
641
642   theTria1 = theTria2 = 0;
643
644   set< const SMDS_MeshElement* > emap;
645   SMDS_ElemIteratorPtr it = theNode1->GetInverseElementIterator(SMDSAbs_Face);
646   while (it->more()) {
647     const SMDS_MeshElement* elem = it->next();
648     if ( elem->NbNodes() == 3 )
649       emap.insert( elem );
650   }
651   it = theNode2->GetInverseElementIterator(SMDSAbs_Face);
652   while (it->more()) {
653     const SMDS_MeshElement* elem = it->next();
654     if ( emap.find( elem ) != emap.end() ) {
655       if ( theTria1 ) {
656         // theTria1 must be element with minimum ID
657         if( theTria1->GetID() < elem->GetID() ) {
658           theTria2 = elem;
659         }
660         else {
661           theTria2 = theTria1;
662           theTria1 = elem;
663         }
664         break;
665       }
666       else {
667         theTria1 = elem;
668       }
669     }
670   }
671   return ( theTria1 && theTria2 );
672 }
673
674 //=======================================================================
675 //function : InverseDiag
676 //purpose  : Replace two neighbour triangles sharing theNode1-theNode2 link
677 //           with ones built on the same 4 nodes but having other common link.
678 //           Return false if proper faces not found
679 //=======================================================================
680
681 bool SMESH_MeshEditor::InverseDiag (const SMDS_MeshNode * theNode1,
682                                     const SMDS_MeshNode * theNode2)
683 {
684   myLastCreatedElems.Clear();
685   myLastCreatedNodes.Clear();
686
687   MESSAGE( "::InverseDiag()" );
688
689   const SMDS_MeshElement *tr1, *tr2;
690   if ( !findTriangles( theNode1, theNode2, tr1, tr2 ))
691     return false;
692
693   const SMDS_VtkFace* F1 = dynamic_cast<const SMDS_VtkFace*>( tr1 );
694   if (!F1) return false;
695   const SMDS_VtkFace* F2 = dynamic_cast<const SMDS_VtkFace*>( tr2 );
696   if (!F2) return false;
697   if ((tr1->GetEntityType() == SMDSEntity_Triangle) &&
698       (tr2->GetEntityType() == SMDSEntity_Triangle)) {
699
700     //  1 +--+ A  tr1: ( 1 A B ) A->2 ( 1 2 B ) 1 +--+ A
701     //    | /|    tr2: ( B A 2 ) B->1 ( 1 A 2 )   |\ |
702     //    |/ |                                    | \|
703     //  B +--+ 2                                B +--+ 2
704
705     // put nodes in array
706     // and find indices of 1,2 and of A in tr1 and of B in tr2
707     int i, iA1 = 0, i1 = 0;
708     const SMDS_MeshNode* aNodes1 [3];
709     SMDS_ElemIteratorPtr it;
710     for (i = 0, it = tr1->nodesIterator(); it->more(); i++ ) {
711       aNodes1[ i ] = static_cast<const SMDS_MeshNode*>( it->next() );
712       if ( aNodes1[ i ] == theNode1 )
713         iA1 = i; // node A in tr1
714       else if ( aNodes1[ i ] != theNode2 )
715         i1 = i;  // node 1
716     }
717     int iB2 = 0, i2 = 0;
718     const SMDS_MeshNode* aNodes2 [3];
719     for (i = 0, it = tr2->nodesIterator(); it->more(); i++ ) {
720       aNodes2[ i ] = static_cast<const SMDS_MeshNode*>( it->next() );
721       if ( aNodes2[ i ] == theNode2 )
722         iB2 = i; // node B in tr2
723       else if ( aNodes2[ i ] != theNode1 )
724         i2 = i;  // node 2
725     }
726
727     // nodes 1 and 2 should not be the same
728     if ( aNodes1[ i1 ] == aNodes2[ i2 ] )
729       return false;
730
731     // tr1: A->2
732     aNodes1[ iA1 ] = aNodes2[ i2 ];
733     // tr2: B->1
734     aNodes2[ iB2 ] = aNodes1[ i1 ];
735
736     GetMeshDS()->ChangeElementNodes( tr1, aNodes1, 3 );
737     GetMeshDS()->ChangeElementNodes( tr2, aNodes2, 3 );
738
739     return true;
740   }
741
742   // check case of quadratic faces
743   return InverseDiag(tr1,tr2);
744 }
745
746 //=======================================================================
747 //function : getQuadrangleNodes
748 //purpose  : fill theQuadNodes - nodes of a quadrangle resulting from
749 //           fusion of triangles tr1 and tr2 having shared link on
750 //           theNode1 and theNode2
751 //=======================================================================
752
753 bool getQuadrangleNodes(const SMDS_MeshNode *    theQuadNodes [],
754                         const SMDS_MeshNode *    theNode1,
755                         const SMDS_MeshNode *    theNode2,
756                         const SMDS_MeshElement * tr1,
757                         const SMDS_MeshElement * tr2 )
758 {
759   if( tr1->NbNodes() != tr2->NbNodes() )
760     return false;
761   // find the 4-th node to insert into tr1
762   const SMDS_MeshNode* n4 = 0;
763   SMDS_ElemIteratorPtr it = tr2->nodesIterator();
764   int i=0;
765   while ( !n4 && i<3 ) {
766     const SMDS_MeshNode * n = cast2Node( it->next() );
767     i++;
768     bool isDiag = ( n == theNode1 || n == theNode2 );
769     if ( !isDiag )
770       n4 = n;
771   }
772   // Make an array of nodes to be in a quadrangle
773   int iNode = 0, iFirstDiag = -1;
774   it = tr1->nodesIterator();
775   i=0;
776   while ( i<3 ) {
777     const SMDS_MeshNode * n = cast2Node( it->next() );
778     i++;
779     bool isDiag = ( n == theNode1 || n == theNode2 );
780     if ( isDiag ) {
781       if ( iFirstDiag < 0 )
782         iFirstDiag = iNode;
783       else if ( iNode - iFirstDiag == 1 )
784         theQuadNodes[ iNode++ ] = n4; // insert the 4-th node between diagonal nodes
785     }
786     else if ( n == n4 ) {
787       return false; // tr1 and tr2 should not have all the same nodes
788     }
789     theQuadNodes[ iNode++ ] = n;
790   }
791   if ( iNode == 3 ) // diagonal nodes have 0 and 2 indices
792     theQuadNodes[ iNode ] = n4;
793
794   return true;
795 }
796
797 //=======================================================================
798 //function : DeleteDiag
799 //purpose  : Replace two neighbour triangles sharing theNode1-theNode2 link
800 //           with a quadrangle built on the same 4 nodes.
801 //           Return false if proper faces not found
802 //=======================================================================
803
804 bool SMESH_MeshEditor::DeleteDiag (const SMDS_MeshNode * theNode1,
805                                    const SMDS_MeshNode * theNode2)
806 {
807   myLastCreatedElems.Clear();
808   myLastCreatedNodes.Clear();
809
810   MESSAGE( "::DeleteDiag()" );
811
812   const SMDS_MeshElement *tr1, *tr2;
813   if ( !findTriangles( theNode1, theNode2, tr1, tr2 ))
814     return false;
815
816   const SMDS_VtkFace* F1 = dynamic_cast<const SMDS_VtkFace*>( tr1 );
817   if (!F1) return false;
818   const SMDS_VtkFace* F2 = dynamic_cast<const SMDS_VtkFace*>( tr2 );
819   if (!F2) return false;
820   SMESHDS_Mesh * aMesh = GetMeshDS();
821
822   if ((tr1->GetEntityType() == SMDSEntity_Triangle) &&
823       (tr2->GetEntityType() == SMDSEntity_Triangle)) {
824
825     const SMDS_MeshNode* aNodes [ 4 ];
826     if ( ! getQuadrangleNodes( aNodes, theNode1, theNode2, tr1, tr2 ))
827       return false;
828
829     const SMDS_MeshElement* newElem = 0;
830     newElem = aMesh->AddFace( aNodes[0], aNodes[1], aNodes[2], aNodes[3] );
831     myLastCreatedElems.Append(newElem);
832     AddToSameGroups( newElem, tr1, aMesh );
833     int aShapeId = tr1->getshapeId();
834     if ( aShapeId )
835       {
836         aMesh->SetMeshElementOnShape( newElem, aShapeId );
837       }
838     aMesh->RemoveElement( tr1 );
839     aMesh->RemoveElement( tr2 );
840
841     return true;
842   }
843
844   // check case of quadratic faces
845   if (tr1->GetEntityType() != SMDSEntity_Quad_Triangle)
846     return false;
847   if (tr2->GetEntityType() != SMDSEntity_Quad_Triangle)
848     return false;
849
850   //       5
851   //  1 +--+--+ 2  tr1: (1 2 4 5 9 7) or (2 4 1 9 7 5) or (4 1 2 7 5 9)
852   //    |    /|    tr2: (2 3 4 6 8 9) or (3 4 2 8 9 6) or (4 2 3 9 6 8)
853   //    |   / |
854   //  7 +  +  + 6
855   //    | /9  |
856   //    |/    |
857   //  4 +--+--+ 3
858   //       8
859
860   const SMDS_MeshNode* N1 [6];
861   const SMDS_MeshNode* N2 [6];
862   if(!GetNodesFromTwoTria(tr1,tr2,N1,N2))
863     return false;
864   // now we receive following N1 and N2 (using numeration as above image)
865   // tria1 : (1 2 4 5 9 7)  and  tria2 : (3 4 2 8 9 6)
866   // i.e. first nodes from both arrays determ new diagonal
867
868   const SMDS_MeshNode* aNodes[8];
869   aNodes[0] = N1[0];
870   aNodes[1] = N1[1];
871   aNodes[2] = N2[0];
872   aNodes[3] = N2[1];
873   aNodes[4] = N1[3];
874   aNodes[5] = N2[5];
875   aNodes[6] = N2[3];
876   aNodes[7] = N1[5];
877
878   const SMDS_MeshElement* newElem = 0;
879   newElem = aMesh->AddFace( aNodes[0], aNodes[1], aNodes[2], aNodes[3],
880                             aNodes[4], aNodes[5], aNodes[6], aNodes[7]);
881   myLastCreatedElems.Append(newElem);
882   AddToSameGroups( newElem, tr1, aMesh );
883   int aShapeId = tr1->getshapeId();
884   if ( aShapeId )
885     {
886       aMesh->SetMeshElementOnShape( newElem, aShapeId );
887     }
888   aMesh->RemoveElement( tr1 );
889   aMesh->RemoveElement( tr2 );
890
891   // remove middle node (9)
892   GetMeshDS()->RemoveNode( N1[4] );
893
894   return true;
895 }
896
897 //=======================================================================
898 //function : Reorient
899 //purpose  : Reverse theElement orientation
900 //=======================================================================
901
902 bool SMESH_MeshEditor::Reorient (const SMDS_MeshElement * theElem)
903 {
904   MESSAGE("Reorient");
905   myLastCreatedElems.Clear();
906   myLastCreatedNodes.Clear();
907
908   if (!theElem)
909     return false;
910   SMDS_ElemIteratorPtr it = theElem->nodesIterator();
911   if ( !it || !it->more() )
912     return false;
913
914   switch ( theElem->GetType() ) {
915
916   case SMDSAbs_Edge:
917   case SMDSAbs_Face: {
918     if(!theElem->IsQuadratic()) {
919       int i = theElem->NbNodes();
920       vector<const SMDS_MeshNode*> aNodes( i );
921       while ( it->more() )
922         aNodes[ --i ]= static_cast<const SMDS_MeshNode*>( it->next() );
923       return GetMeshDS()->ChangeElementNodes( theElem, &aNodes[0], theElem->NbNodes() );
924     }
925     else {
926       // quadratic elements
927       if(theElem->GetType()==SMDSAbs_Edge) {
928         vector<const SMDS_MeshNode*> aNodes(3);
929         aNodes[1]= static_cast<const SMDS_MeshNode*>( it->next() );
930         aNodes[0]= static_cast<const SMDS_MeshNode*>( it->next() );
931         aNodes[2]= static_cast<const SMDS_MeshNode*>( it->next() );
932         return GetMeshDS()->ChangeElementNodes( theElem, &aNodes[0], 3 );
933       }
934       else {
935         int nbn = theElem->NbNodes();
936         vector<const SMDS_MeshNode*> aNodes(nbn);
937         aNodes[0]= static_cast<const SMDS_MeshNode*>( it->next() );
938         int i=1;
939         for(; i<nbn/2; i++) {
940           aNodes[nbn/2-i]= static_cast<const SMDS_MeshNode*>( it->next() );
941         }
942         for(i=0; i<nbn/2; i++) {
943           aNodes[nbn-i-1]= static_cast<const SMDS_MeshNode*>( it->next() );
944         }
945         return GetMeshDS()->ChangeElementNodes( theElem, &aNodes[0], nbn );
946       }
947     }
948   }
949   case SMDSAbs_Volume: {
950     if (theElem->IsPoly()) {
951       // TODO reorient vtk polyhedron
952       MESSAGE("reorient vtk polyhedron ?");
953       const SMDS_VtkVolume* aPolyedre =
954         dynamic_cast<const SMDS_VtkVolume*>( theElem );
955       if (!aPolyedre) {
956         MESSAGE("Warning: bad volumic element");
957         return false;
958       }
959
960       int nbFaces = aPolyedre->NbFaces();
961       vector<const SMDS_MeshNode *> poly_nodes;
962       vector<int> quantities (nbFaces);
963
964       // reverse each face of the polyedre
965       for (int iface = 1; iface <= nbFaces; iface++) {
966         int inode, nbFaceNodes = aPolyedre->NbFaceNodes(iface);
967         quantities[iface - 1] = nbFaceNodes;
968
969         for (inode = nbFaceNodes; inode >= 1; inode--) {
970           const SMDS_MeshNode* curNode = aPolyedre->GetFaceNode(iface, inode);
971           poly_nodes.push_back(curNode);
972         }
973       }
974
975       return GetMeshDS()->ChangePolyhedronNodes( theElem, poly_nodes, quantities );
976
977     }
978     else {
979       SMDS_VolumeTool vTool;
980       if ( !vTool.Set( theElem ))
981         return false;
982       vTool.Inverse();
983       MESSAGE("ChangeElementNodes reorient: check vTool.Inverse");
984       return GetMeshDS()->ChangeElementNodes( theElem, vTool.GetNodes(), vTool.NbNodes() );
985     }
986   }
987   default:;
988   }
989
990   return false;
991 }
992
993 //=======================================================================
994 //function : getBadRate
995 //purpose  :
996 //=======================================================================
997
998 static double getBadRate (const SMDS_MeshElement*               theElem,
999                           SMESH::Controls::NumericalFunctorPtr& theCrit)
1000 {
1001   SMESH::Controls::TSequenceOfXYZ P;
1002   if ( !theElem || !theCrit->GetPoints( theElem, P ))
1003     return 1e100;
1004   return theCrit->GetBadRate( theCrit->GetValue( P ), theElem->NbNodes() );
1005   //return theCrit->GetBadRate( theCrit->GetValue( theElem->GetID() ), theElem->NbNodes() );
1006 }
1007
1008 //=======================================================================
1009 //function : QuadToTri
1010 //purpose  : Cut quadrangles into triangles.
1011 //           theCrit is used to select a diagonal to cut
1012 //=======================================================================
1013
1014 bool SMESH_MeshEditor::QuadToTri (TIDSortedElemSet &                   theElems,
1015                                   SMESH::Controls::NumericalFunctorPtr theCrit)
1016 {
1017   myLastCreatedElems.Clear();
1018   myLastCreatedNodes.Clear();
1019
1020   MESSAGE( "::QuadToTri()" );
1021
1022   if ( !theCrit.get() )
1023     return false;
1024
1025   SMESHDS_Mesh * aMesh = GetMeshDS();
1026
1027   Handle(Geom_Surface) surface;
1028   SMESH_MesherHelper   helper( *GetMesh() );
1029
1030   TIDSortedElemSet::iterator itElem;
1031   for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
1032     const SMDS_MeshElement* elem = *itElem;
1033     if ( !elem || elem->GetType() != SMDSAbs_Face )
1034       continue;
1035     if ( elem->NbNodes() != ( elem->IsQuadratic() ? 8 : 4 ))
1036       continue;
1037
1038     // retrieve element nodes
1039     const SMDS_MeshNode* aNodes [8];
1040     SMDS_ElemIteratorPtr itN = elem->nodesIterator();
1041     int i = 0;
1042     while ( itN->more() )
1043       aNodes[ i++ ] = static_cast<const SMDS_MeshNode*>( itN->next() );
1044
1045     // compare two sets of possible triangles
1046     double aBadRate1, aBadRate2; // to what extent a set is bad
1047     SMDS_FaceOfNodes tr1 ( aNodes[0], aNodes[1], aNodes[2] );
1048     SMDS_FaceOfNodes tr2 ( aNodes[2], aNodes[3], aNodes[0] );
1049     aBadRate1 = getBadRate( &tr1, theCrit ) + getBadRate( &tr2, theCrit );
1050
1051     SMDS_FaceOfNodes tr3 ( aNodes[1], aNodes[2], aNodes[3] );
1052     SMDS_FaceOfNodes tr4 ( aNodes[3], aNodes[0], aNodes[1] );
1053     aBadRate2 = getBadRate( &tr3, theCrit ) + getBadRate( &tr4, theCrit );
1054
1055     int aShapeId = FindShape( elem );
1056     const SMDS_MeshElement* newElem1 = 0;
1057     const SMDS_MeshElement* newElem2 = 0;
1058
1059     if( !elem->IsQuadratic() ) {
1060
1061       // split liner quadrangle
1062       if ( aBadRate1 <= aBadRate2 ) {
1063         // tr1 + tr2 is better
1064         newElem1 = aMesh->AddFace( aNodes[2], aNodes[3], aNodes[0] );
1065         newElem2 = aMesh->AddFace( aNodes[2], aNodes[0], aNodes[1] );
1066       }
1067       else {
1068         // tr3 + tr4 is better
1069         newElem1 = aMesh->AddFace( aNodes[3], aNodes[0], aNodes[1] );
1070         newElem2 = aMesh->AddFace( aNodes[3], aNodes[1], aNodes[2] );
1071       }
1072     }
1073     else {
1074
1075       // split quadratic quadrangle
1076
1077       // get surface elem is on
1078       if ( aShapeId != helper.GetSubShapeID() ) {
1079         surface.Nullify();
1080         TopoDS_Shape shape;
1081         if ( aShapeId > 0 )
1082           shape = aMesh->IndexToShape( aShapeId );
1083         if ( !shape.IsNull() && shape.ShapeType() == TopAbs_FACE ) {
1084           TopoDS_Face face = TopoDS::Face( shape );
1085           surface = BRep_Tool::Surface( face );
1086           if ( !surface.IsNull() )
1087             helper.SetSubShape( shape );
1088         }
1089       }
1090       // get elem nodes
1091       const SMDS_MeshNode* aNodes [8];
1092       const SMDS_MeshNode* inFaceNode = 0;
1093       SMDS_ElemIteratorPtr itN = elem->nodesIterator();
1094       int i = 0;
1095       while ( itN->more() ) {
1096         aNodes[ i++ ] = static_cast<const SMDS_MeshNode*>( itN->next() );
1097         if ( !inFaceNode && helper.GetNodeUVneedInFaceNode() &&
1098              aNodes[ i-1 ]->GetPosition()->GetTypeOfPosition() == SMDS_TOP_FACE )
1099         {
1100           inFaceNode = aNodes[ i-1 ];
1101         }
1102       }
1103       // find middle point for (0,1,2,3)
1104       // and create a node in this point;
1105       gp_XYZ p( 0,0,0 );
1106       if ( surface.IsNull() ) {
1107         for(i=0; i<4; i++)
1108           p += gp_XYZ(aNodes[i]->X(), aNodes[i]->Y(), aNodes[i]->Z() );
1109         p /= 4;
1110       }
1111       else {
1112         TopoDS_Face face = TopoDS::Face( helper.GetSubShape() );
1113         gp_XY uv( 0,0 );
1114         for(i=0; i<4; i++)
1115           uv += helper.GetNodeUV( face, aNodes[i], inFaceNode );
1116         uv /= 4.;
1117         p = surface->Value( uv.X(), uv.Y() ).XYZ();
1118       }
1119       const SMDS_MeshNode* newN = aMesh->AddNode( p.X(), p.Y(), p.Z() );
1120       myLastCreatedNodes.Append(newN);
1121
1122       // create a new element
1123       const SMDS_MeshNode* N[6];
1124       if ( aBadRate1 <= aBadRate2 ) {
1125         N[0] = aNodes[0];
1126         N[1] = aNodes[1];
1127         N[2] = aNodes[2];
1128         N[3] = aNodes[4];
1129         N[4] = aNodes[5];
1130         N[5] = newN;
1131         newElem1 = aMesh->AddFace(aNodes[2], aNodes[3], aNodes[0],
1132                                   aNodes[6], aNodes[7], newN );
1133         newElem2 = aMesh->AddFace(aNodes[2], aNodes[0], aNodes[1],
1134                                   newN,      aNodes[4], aNodes[5] );
1135       }
1136       else {
1137         N[0] = aNodes[1];
1138         N[1] = aNodes[2];
1139         N[2] = aNodes[3];
1140         N[3] = aNodes[5];
1141         N[4] = aNodes[6];
1142         N[5] = newN;
1143         newElem1 = aMesh->AddFace(aNodes[3], aNodes[0], aNodes[1],
1144                                   aNodes[7], aNodes[4], newN );
1145         newElem2 = aMesh->AddFace(aNodes[3], aNodes[1], aNodes[2],
1146                                   newN,      aNodes[5], aNodes[6] );
1147       }
1148     } // quadratic case
1149
1150     // care of a new element
1151
1152     myLastCreatedElems.Append(newElem1);
1153     myLastCreatedElems.Append(newElem2);
1154     AddToSameGroups( newElem1, elem, aMesh );
1155     AddToSameGroups( newElem2, elem, aMesh );
1156
1157     // put a new triangle on the same shape
1158     if ( aShapeId )
1159       {
1160         aMesh->SetMeshElementOnShape( newElem1, aShapeId );
1161         aMesh->SetMeshElementOnShape( newElem2, aShapeId );
1162       }
1163     aMesh->RemoveElement( elem );
1164   }
1165   return true;
1166 }
1167
1168 //=======================================================================
1169 //function : BestSplit
1170 //purpose  : Find better diagonal for cutting.
1171 //=======================================================================
1172
1173 int SMESH_MeshEditor::BestSplit (const SMDS_MeshElement*              theQuad,
1174                                  SMESH::Controls::NumericalFunctorPtr theCrit)
1175 {
1176   myLastCreatedElems.Clear();
1177   myLastCreatedNodes.Clear();
1178
1179   if (!theCrit.get())
1180     return -1;
1181
1182   if (!theQuad || theQuad->GetType() != SMDSAbs_Face )
1183     return -1;
1184
1185   if( theQuad->NbNodes()==4 ||
1186       (theQuad->NbNodes()==8 && theQuad->IsQuadratic()) ) {
1187
1188     // retrieve element nodes
1189     const SMDS_MeshNode* aNodes [4];
1190     SMDS_ElemIteratorPtr itN = theQuad->nodesIterator();
1191     int i = 0;
1192     //while (itN->more())
1193     while (i<4) {
1194       aNodes[ i++ ] = static_cast<const SMDS_MeshNode*>( itN->next() );
1195     }
1196     // compare two sets of possible triangles
1197     double aBadRate1, aBadRate2; // to what extent a set is bad
1198     SMDS_FaceOfNodes tr1 ( aNodes[0], aNodes[1], aNodes[2] );
1199     SMDS_FaceOfNodes tr2 ( aNodes[2], aNodes[3], aNodes[0] );
1200     aBadRate1 = getBadRate( &tr1, theCrit ) + getBadRate( &tr2, theCrit );
1201
1202     SMDS_FaceOfNodes tr3 ( aNodes[1], aNodes[2], aNodes[3] );
1203     SMDS_FaceOfNodes tr4 ( aNodes[3], aNodes[0], aNodes[1] );
1204     aBadRate2 = getBadRate( &tr3, theCrit ) + getBadRate( &tr4, theCrit );
1205
1206     if (aBadRate1 <= aBadRate2) // tr1 + tr2 is better
1207       return 1; // diagonal 1-3
1208
1209     return 2; // diagonal 2-4
1210   }
1211   return -1;
1212 }
1213
1214 namespace
1215 {
1216   // Methods of splitting volumes into tetra
1217
1218   const int theHexTo5_1[5*4+1] =
1219     {
1220       0, 1, 2, 5,    0, 4, 5, 7,     0, 2, 3, 7,    2, 5, 6, 7,     0, 5, 2, 7,   -1
1221     };
1222   const int theHexTo5_2[5*4+1] =
1223     {
1224       1, 2, 3, 6,    1, 4, 5, 6,     0, 1, 3, 4,    3, 4, 6, 7,     1, 3, 4, 6,   -1
1225     };
1226   const int* theHexTo5[2] = { theHexTo5_1, theHexTo5_2 };
1227
1228   const int theHexTo6_1[6*4+1] =
1229     {
1230       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
1231     };
1232   const int theHexTo6_2[6*4+1] =
1233     {
1234       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
1235     };
1236   const int theHexTo6_3[6*4+1] =
1237     {
1238       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
1239     };
1240   const int theHexTo6_4[6*4+1] =
1241     {
1242       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
1243     };
1244   const int* theHexTo6[4] = { theHexTo6_1, theHexTo6_2, theHexTo6_3, theHexTo6_4 };
1245
1246   const int thePyraTo2_1[2*4+1] =
1247     {
1248       0, 1, 2, 4,    0, 2, 3, 4,   -1
1249     };
1250   const int thePyraTo2_2[2*4+1] =
1251     {
1252       1, 2, 3, 4,    1, 3, 0, 4,   -1
1253     };
1254   const int* thePyraTo2[2] = { thePyraTo2_1, thePyraTo2_2 };
1255
1256   const int thePentaTo3_1[3*4+1] =
1257     {
1258       0, 1, 2, 3,    1, 3, 4, 2,     2, 3, 4, 5,    -1
1259     };
1260   const int thePentaTo3_2[3*4+1] =
1261     {
1262       1, 2, 0, 4,    2, 4, 5, 0,     0, 4, 5, 3,    -1
1263     };
1264   const int thePentaTo3_3[3*4+1] =
1265     {
1266       2, 0, 1, 5,    0, 5, 3, 1,     1, 5, 3, 4,    -1
1267     };
1268   const int thePentaTo3_4[3*4+1] =
1269     {
1270       0, 1, 2, 3,    1, 3, 4, 5,     2, 3, 1, 5,    -1
1271     };
1272   const int thePentaTo3_5[3*4+1] =
1273     {
1274       1, 2, 0, 4,    2, 4, 5, 3,     0, 4, 2, 3,    -1
1275     };
1276   const int thePentaTo3_6[3*4+1] =
1277     {
1278       2, 0, 1, 5,    0, 5, 3, 4,     1, 5, 0, 4,    -1
1279     };
1280   const int* thePentaTo3[6] = { thePentaTo3_1, thePentaTo3_2, thePentaTo3_3,
1281                                 thePentaTo3_4, thePentaTo3_5, thePentaTo3_6 };
1282
1283   struct TTriangleFacet //!< stores indices of three nodes of tetra facet
1284   {
1285     int _n1, _n2, _n3;
1286     TTriangleFacet(int n1, int n2, int n3): _n1(n1), _n2(n2), _n3(n3) {}
1287     bool contains(int n) const { return ( n == _n1 || n == _n2 || n == _n3 ); }
1288     bool hasAdjacentTetra( const SMDS_MeshElement* elem ) const;
1289   };
1290   struct TSplitMethod
1291   {
1292     int        _nbTetra;
1293     const int* _connectivity; //!< foursomes of tetra connectivy finished by -1
1294     bool       _baryNode;     //!< additional node is to be created at cell barycenter
1295     bool       _ownConn;      //!< to delete _connectivity in destructor
1296     map<int, const SMDS_MeshNode*> _faceBaryNode; //!< map face index to node at BC of face
1297
1298     TSplitMethod( int nbTet=0, const int* conn=0, bool addNode=false)
1299       : _nbTetra(nbTet), _connectivity(conn), _baryNode(addNode), _ownConn(false) {}
1300     ~TSplitMethod() { if ( _ownConn ) delete [] _connectivity; _connectivity = 0; }
1301     bool hasFacet( const TTriangleFacet& facet ) const
1302     {
1303       const int* tetConn = _connectivity;
1304       for ( ; tetConn[0] >= 0; tetConn += 4 )
1305         if (( facet.contains( tetConn[0] ) +
1306               facet.contains( tetConn[1] ) +
1307               facet.contains( tetConn[2] ) +
1308               facet.contains( tetConn[3] )) == 3 )
1309           return true;
1310       return false;
1311     }
1312   };
1313
1314   //=======================================================================
1315   /*!
1316    * \brief return TSplitMethod for the given element
1317    */
1318   //=======================================================================
1319
1320   TSplitMethod getSplitMethod( SMDS_VolumeTool& vol, const int theMethodFlags)
1321   {
1322     const int iQ = vol.Element()->IsQuadratic() ? 2 : 1;
1323
1324     // at HEXA_TO_24 method, each face of volume is split into triangles each based on
1325     // an edge and a face barycenter; tertaherdons are based on triangles and
1326     // a volume barycenter
1327     const bool is24TetMode = ( theMethodFlags == SMESH_MeshEditor::HEXA_TO_24 );
1328
1329     // Find out how adjacent volumes are split
1330
1331     vector < list< TTriangleFacet > > triaSplitsByFace( vol.NbFaces() ); // splits of each side
1332     int hasAdjacentSplits = 0, maxTetConnSize = 0;
1333     for ( int iF = 0; iF < vol.NbFaces(); ++iF )
1334     {
1335       int nbNodes = vol.NbFaceNodes( iF ) / iQ;
1336       maxTetConnSize += 4 * ( nbNodes - (is24TetMode ? 0 : 2));
1337       if ( nbNodes < 4 ) continue;
1338
1339       list< TTriangleFacet >& triaSplits = triaSplitsByFace[ iF ];
1340       const int* nInd = vol.GetFaceNodesIndices( iF );
1341       if ( nbNodes == 4 )
1342       {
1343         TTriangleFacet t012( nInd[0*iQ], nInd[1*iQ], nInd[2*iQ] );
1344         TTriangleFacet t123( nInd[1*iQ], nInd[2*iQ], nInd[3*iQ] );
1345         if      ( t012.hasAdjacentTetra( vol.Element() )) triaSplits.push_back( t012 );
1346         else if ( t123.hasAdjacentTetra( vol.Element() )) triaSplits.push_back( t123 );
1347       }
1348       else
1349       {
1350         int iCom = 0; // common node of triangle faces to split into
1351         for ( int iVar = 0; iVar < nbNodes; ++iVar, ++iCom )
1352         {
1353           TTriangleFacet t012( nInd[ iQ * ( iCom             )],
1354                                nInd[ iQ * ( (iCom+1)%nbNodes )],
1355                                nInd[ iQ * ( (iCom+2)%nbNodes )]);
1356           TTriangleFacet t023( nInd[ iQ * ( iCom             )],
1357                                nInd[ iQ * ( (iCom+2)%nbNodes )],
1358                                nInd[ iQ * ( (iCom+3)%nbNodes )]);
1359           if ( t012.hasAdjacentTetra( vol.Element() ) && t023.hasAdjacentTetra( vol.Element() ))
1360           {
1361             triaSplits.push_back( t012 );
1362             triaSplits.push_back( t023 );
1363             break;
1364           }
1365         }
1366       }
1367       if ( !triaSplits.empty() )
1368         hasAdjacentSplits = true;
1369     }
1370
1371     // Among variants of split method select one compliant with adjacent volumes
1372
1373     TSplitMethod method;
1374     if ( !vol.Element()->IsPoly() && !is24TetMode )
1375     {
1376       int nbVariants = 2, nbTet = 0;
1377       const int** connVariants = 0;
1378       switch ( vol.Element()->GetEntityType() )
1379       {
1380       case SMDSEntity_Hexa:
1381       case SMDSEntity_Quad_Hexa:
1382         if ( theMethodFlags == SMESH_MeshEditor::HEXA_TO_5 )
1383           connVariants = theHexTo5, nbTet = 5;
1384         else
1385           connVariants = theHexTo6, nbTet = 6, nbVariants = 4;
1386         break;
1387       case SMDSEntity_Pyramid:
1388       case SMDSEntity_Quad_Pyramid:
1389         connVariants = thePyraTo2;  nbTet = 2;
1390         break;
1391       case SMDSEntity_Penta:
1392       case SMDSEntity_Quad_Penta:
1393         connVariants = thePentaTo3; nbTet = 3; nbVariants = 6;
1394         break;
1395       default:
1396         nbVariants = 0;
1397       }
1398       for ( int variant = 0; variant < nbVariants && method._nbTetra == 0; ++variant )
1399       {
1400         // check method compliancy with adjacent tetras,
1401         // all found splits must be among facets of tetras described by this method
1402         method = TSplitMethod( nbTet, connVariants[variant] );
1403         if ( hasAdjacentSplits && method._nbTetra > 0 )
1404         {
1405           bool facetCreated = true;
1406           for ( int iF = 0; facetCreated && iF < triaSplitsByFace.size(); ++iF )
1407           {
1408             list< TTriangleFacet >::const_iterator facet = triaSplitsByFace[iF].begin();
1409             for ( ; facetCreated && facet != triaSplitsByFace[iF].end(); ++facet )
1410               facetCreated = method.hasFacet( *facet );
1411           }
1412           if ( !facetCreated )
1413             method = TSplitMethod(0); // incompatible method
1414         }
1415       }
1416     }
1417     if ( method._nbTetra < 1 )
1418     {
1419       // No standard method is applicable, use a generic solution:
1420       // each facet of a volume is split into triangles and
1421       // each of triangles and a volume barycenter form a tetrahedron.
1422
1423       int* connectivity = new int[ maxTetConnSize + 1 ];
1424       method._connectivity = connectivity;
1425       method._ownConn = true;
1426       method._baryNode = true;
1427
1428       int connSize = 0;
1429       int baryCenInd = vol.NbNodes();
1430       for ( int iF = 0; iF < vol.NbFaces(); ++iF )
1431       {
1432         const int nbNodes = vol.NbFaceNodes( iF ) / iQ;
1433         const int*   nInd = vol.GetFaceNodesIndices( iF );
1434         // find common node of triangle facets of tetra to create
1435         int iCommon = 0; // index in linear numeration
1436         const list< TTriangleFacet >& triaSplits = triaSplitsByFace[ iF ];
1437         if ( !triaSplits.empty() )
1438         {
1439           // by found facets
1440           const TTriangleFacet* facet = &triaSplits.front();
1441           for ( ; iCommon < nbNodes-1 ; ++iCommon )
1442             if ( facet->contains( nInd[ iQ * iCommon ]) &&
1443                  facet->contains( nInd[ iQ * ((iCommon+2)%nbNodes) ]))
1444               break;
1445         }
1446         else if ( nbNodes > 3 && !is24TetMode )
1447         {
1448           // find the best method of splitting into triangles by aspect ratio
1449           SMESH::Controls::NumericalFunctorPtr aspectRatio( new SMESH::Controls::AspectRatio);
1450           map< double, int > badness2iCommon;
1451           const SMDS_MeshNode** nodes = vol.GetFaceNodes( iF );
1452           int nbVariants = ( nbNodes == 4 ? 2 : nbNodes );
1453           for ( int iVar = 0; iVar < nbVariants; ++iVar, ++iCommon )
1454             for ( int iLast = iCommon+2; iLast < iCommon+nbNodes; ++iLast )
1455             {
1456               SMDS_FaceOfNodes tria ( nodes[ iQ*( iCommon         )],
1457                                       nodes[ iQ*((iLast-1)%nbNodes)],
1458                                       nodes[ iQ*((iLast  )%nbNodes)]);
1459               double badness = getBadRate( &tria, aspectRatio );
1460               badness2iCommon.insert( make_pair( badness, iCommon ));
1461             }
1462           // use iCommon with lowest badness
1463           iCommon = badness2iCommon.begin()->second;
1464         }
1465         if ( iCommon >= nbNodes )
1466           iCommon = 0; // something wrong
1467
1468         // fill connectivity of tetrahedra based on a current face
1469         int nbTet = nbNodes - 2;
1470         if ( is24TetMode && nbNodes > 3 && triaSplits.empty())
1471         {
1472           method._faceBaryNode.insert( make_pair( iF, (const SMDS_MeshNode*)0 ));
1473           int faceBaryCenInd = baryCenInd + method._faceBaryNode.size();
1474           nbTet = nbNodes;
1475           for ( int i = 0; i < nbTet; ++i )
1476           {
1477             int i1 = i, i2 = (i+1) % nbNodes;
1478             if ( !vol.IsFaceExternal( iF )) swap( i1, i2 );
1479             connectivity[ connSize++ ] = nInd[ iQ * i1 ];
1480             connectivity[ connSize++ ] = nInd[ iQ * i2 ];
1481             connectivity[ connSize++ ] = faceBaryCenInd;
1482             connectivity[ connSize++ ] = baryCenInd;
1483           }
1484         }
1485         else
1486         {
1487           for ( int i = 0; i < nbTet; ++i )
1488           {
1489             int i1 = (iCommon+1+i) % nbNodes, i2 = (iCommon+2+i) % nbNodes;
1490             if ( !vol.IsFaceExternal( iF )) swap( i1, i2 );
1491             connectivity[ connSize++ ] = nInd[ iQ * iCommon ];
1492             connectivity[ connSize++ ] = nInd[ iQ * i1 ];
1493             connectivity[ connSize++ ] = nInd[ iQ * i2 ];
1494             connectivity[ connSize++ ] = baryCenInd;
1495           }
1496         }
1497         method._nbTetra += nbTet;
1498       }
1499       connectivity[ connSize++ ] = -1;
1500     }
1501     return method;
1502   }
1503   //================================================================================
1504   /*!
1505    * \brief Check if there is a tetraherdon adjacent to the given element via this facet
1506    */
1507   //================================================================================
1508
1509   bool TTriangleFacet::hasAdjacentTetra( const SMDS_MeshElement* elem ) const
1510   {
1511     // find the tetrahedron including the three nodes of facet
1512     const SMDS_MeshNode* n1 = elem->GetNode(_n1);
1513     const SMDS_MeshNode* n2 = elem->GetNode(_n2);
1514     const SMDS_MeshNode* n3 = elem->GetNode(_n3);
1515     SMDS_ElemIteratorPtr volIt1 = n1->GetInverseElementIterator(SMDSAbs_Volume);
1516     while ( volIt1->more() )
1517     {
1518       const SMDS_MeshElement* v = volIt1->next();
1519       if ( v->GetEntityType() != ( v->IsQuadratic() ? SMDSEntity_Quad_Tetra : SMDSEntity_Tetra ))
1520         continue;
1521       SMDS_ElemIteratorPtr volIt2 = n2->GetInverseElementIterator(SMDSAbs_Volume);
1522       while ( volIt2->more() )
1523         if ( v != volIt2->next() )
1524           continue;
1525       SMDS_ElemIteratorPtr volIt3 = n3->GetInverseElementIterator(SMDSAbs_Volume);
1526       while ( volIt3->more() )
1527         if ( v == volIt3->next() )
1528           return true;
1529     }
1530     return false;
1531   }
1532
1533   //=======================================================================
1534   /*!
1535    * \brief A key of a face of volume
1536    */
1537   //=======================================================================
1538
1539   struct TVolumeFaceKey: pair< int, pair< int, int> >
1540   {
1541     TVolumeFaceKey( SMDS_VolumeTool& vol, int iF )
1542     {
1543       TIDSortedNodeSet sortedNodes;
1544       const int iQ = vol.Element()->IsQuadratic() ? 2 : 1;
1545       int nbNodes = vol.NbFaceNodes( iF );
1546       const SMDS_MeshNode** fNodes = vol.GetFaceNodes( iF );
1547       for ( int i = 0; i < nbNodes; i += iQ )
1548         sortedNodes.insert( fNodes[i] );
1549       TIDSortedNodeSet::iterator n = sortedNodes.begin();
1550       first = (*(n++))->GetID();
1551       second.first = (*(n++))->GetID();
1552       second.second = (*(n++))->GetID();
1553     }
1554   };
1555 } // namespace
1556
1557 //=======================================================================
1558 //function : SplitVolumesIntoTetra
1559 //purpose  : Split volumic elements into tetrahedra.
1560 //=======================================================================
1561
1562 void SMESH_MeshEditor::SplitVolumesIntoTetra (const TIDSortedElemSet & theElems,
1563                                               const int                theMethodFlags)
1564 {
1565   // std-like iterator on coordinates of nodes of mesh element
1566   typedef SMDS_StdIterator< TNodeXYZ, SMDS_ElemIteratorPtr > NXyzIterator;
1567   NXyzIterator xyzEnd;
1568
1569   SMDS_VolumeTool    volTool;
1570   SMESH_MesherHelper helper( *GetMesh());
1571
1572   SMESHDS_SubMesh* subMesh = GetMeshDS()->MeshElements(1);
1573   SMESHDS_SubMesh* fSubMesh = subMesh;
1574   
1575   SMESH_SequenceOfElemPtr newNodes, newElems;
1576
1577   // map face of volume to it's baricenrtic node
1578   map< TVolumeFaceKey, const SMDS_MeshNode* > volFace2BaryNode;
1579   double bc[3];
1580
1581   TIDSortedElemSet::const_iterator elem = theElems.begin();
1582   for ( ; elem != theElems.end(); ++elem )
1583   {
1584     SMDSAbs_EntityType geomType = (*elem)->GetEntityType();
1585     if ( geomType <= SMDSEntity_Quad_Tetra )
1586       continue; // tetra or face or ...
1587
1588     if ( !volTool.Set( *elem )) continue; // not volume? strange...
1589
1590     TSplitMethod splitMethod = getSplitMethod( volTool, theMethodFlags );
1591     if ( splitMethod._nbTetra < 1 ) continue;
1592
1593     // find submesh to add new tetras to
1594     if ( !subMesh || !subMesh->Contains( *elem ))
1595     {
1596       int shapeID = FindShape( *elem );
1597       helper.SetSubShape( shapeID ); // helper will add tetras to the found submesh
1598       subMesh = GetMeshDS()->MeshElements( shapeID );
1599     }
1600     int iQ;
1601     if ( (*elem)->IsQuadratic() )
1602     {
1603       iQ = 2;
1604       // add quadratic links to the helper
1605       for ( int iF = 0; iF < volTool.NbFaces(); ++iF )
1606       {
1607         const SMDS_MeshNode** fNodes = volTool.GetFaceNodes( iF );
1608         for ( int iN = 0; iN < volTool.NbFaceNodes( iF ); iN += iQ )
1609           helper.AddTLinkNode( fNodes[iF], fNodes[iF+2], fNodes[iF+1] );
1610       }
1611       helper.SetIsQuadratic( true );
1612     }
1613     else
1614     {
1615       iQ = 1;
1616       helper.SetIsQuadratic( false );
1617     }
1618     vector<const SMDS_MeshNode*> nodes( (*elem)->begin_nodes(), (*elem)->end_nodes() );
1619     if ( splitMethod._baryNode )
1620     {
1621       // make a node at barycenter
1622       volTool.GetBaryCenter( bc[0], bc[1], bc[2] );
1623       SMDS_MeshNode* gcNode = helper.AddNode( bc[0], bc[1], bc[2] );
1624       nodes.push_back( gcNode );
1625       newNodes.Append( gcNode );
1626     }
1627     if ( !splitMethod._faceBaryNode.empty() )
1628     {
1629       // make or find baricentric nodes of faces
1630       map<int, const SMDS_MeshNode*>::iterator iF_n = splitMethod._faceBaryNode.begin();
1631       for ( ; iF_n != splitMethod._faceBaryNode.end(); ++iF_n )
1632       {
1633         map< TVolumeFaceKey, const SMDS_MeshNode* >::iterator f_n =
1634           volFace2BaryNode.insert
1635           ( make_pair( TVolumeFaceKey( volTool,iF_n->first ), (const SMDS_MeshNode*)0) ).first;
1636         if ( !f_n->second )
1637         {
1638           volTool.GetFaceBaryCenter( iF_n->first, bc[0], bc[1], bc[2] );
1639           newNodes.Append( f_n->second = helper.AddNode( bc[0], bc[1], bc[2] ));
1640         }
1641         nodes.push_back( iF_n->second = f_n->second );
1642       }
1643     }
1644
1645     // make tetras
1646     helper.SetElementsOnShape( true );
1647     vector<const SMDS_MeshElement* > tetras( splitMethod._nbTetra ); // splits of a volume
1648     const int* tetConn = splitMethod._connectivity;
1649     for ( int i = 0; i < splitMethod._nbTetra; ++i, tetConn += 4 )
1650       newElems.Append( tetras[ i ] = helper.AddVolume( nodes[ tetConn[0] ],
1651                                                        nodes[ tetConn[1] ],
1652                                                        nodes[ tetConn[2] ],
1653                                                        nodes[ tetConn[3] ]));
1654
1655     ReplaceElemInGroups( *elem, tetras, GetMeshDS() );
1656
1657     // Split faces on sides of the split volume
1658
1659     const SMDS_MeshNode** volNodes = volTool.GetNodes();
1660     for ( int iF = 0; iF < volTool.NbFaces(); ++iF )
1661     {
1662       const int nbNodes = volTool.NbFaceNodes( iF ) / iQ;
1663       if ( nbNodes < 4 ) continue;
1664
1665       // find an existing face
1666       vector<const SMDS_MeshNode*> fNodes( volTool.GetFaceNodes( iF ),
1667                                            volTool.GetFaceNodes( iF ) + nbNodes*iQ );
1668       while ( const SMDS_MeshElement* face = GetMeshDS()->FindFace( fNodes ))
1669       {
1670         // make triangles
1671         helper.SetElementsOnShape( false );
1672         vector< const SMDS_MeshElement* > triangles;
1673
1674         map<int, const SMDS_MeshNode*>::iterator iF_n = splitMethod._faceBaryNode.find(iF);
1675         if ( iF_n != splitMethod._faceBaryNode.end() )
1676         {
1677           for ( int iN = 0; iN < nbNodes*iQ; iN += iQ )
1678           {
1679             const SMDS_MeshNode* n1 = fNodes[iN];
1680             const SMDS_MeshNode *n2 = fNodes[(iN+iQ)%nbNodes*iQ];
1681             const SMDS_MeshNode *n3 = iF_n->second;
1682             if ( !volTool.IsFaceExternal( iF ))
1683               swap( n2, n3 );
1684             triangles.push_back( helper.AddFace( n1,n2,n3 ));
1685           }
1686         }
1687         else
1688         {
1689           // among possible triangles create ones discribed by split method
1690           const int* nInd = volTool.GetFaceNodesIndices( iF );
1691           int nbVariants = ( nbNodes == 4 ? 2 : nbNodes );
1692           int iCom = 0; // common node of triangle faces to split into
1693           list< TTriangleFacet > facets;
1694           for ( int iVar = 0; iVar < nbVariants; ++iVar, ++iCom )
1695           {
1696             TTriangleFacet t012( nInd[ iQ * ( iCom                )],
1697                                  nInd[ iQ * ( (iCom+1)%nbNodes )],
1698                                  nInd[ iQ * ( (iCom+2)%nbNodes )]);
1699             TTriangleFacet t023( nInd[ iQ * ( iCom                )],
1700                                  nInd[ iQ * ( (iCom+2)%nbNodes )],
1701                                  nInd[ iQ * ( (iCom+3)%nbNodes )]);
1702             if ( splitMethod.hasFacet( t012 ) && splitMethod.hasFacet( t023 ))
1703             {
1704               facets.push_back( t012 );
1705               facets.push_back( t023 );
1706               for ( int iLast = iCom+4; iLast < iCom+nbNodes; ++iLast )
1707                 facets.push_back( TTriangleFacet( nInd[ iQ * ( iCom             )],
1708                                                   nInd[ iQ * ((iLast-1)%nbNodes )],
1709                                                   nInd[ iQ * ((iLast  )%nbNodes )]));
1710               break;
1711             }
1712           }
1713           list< TTriangleFacet >::iterator facet = facets.begin();
1714           for ( ; facet != facets.end(); ++facet )
1715           {
1716             if ( !volTool.IsFaceExternal( iF ))
1717               swap( facet->_n2, facet->_n3 );
1718             triangles.push_back( helper.AddFace( volNodes[ facet->_n1 ],
1719                                                  volNodes[ facet->_n2 ],
1720                                                  volNodes[ facet->_n3 ]));
1721           }
1722         }
1723         // find submesh to add new triangles in
1724         if ( !fSubMesh || !fSubMesh->Contains( face ))
1725         {
1726           int shapeID = FindShape( face );
1727           fSubMesh = GetMeshDS()->MeshElements( shapeID );
1728         }
1729         for ( int i = 0; i < triangles.size(); ++i )
1730         {
1731           if ( !triangles[i] ) continue;
1732           if ( fSubMesh )
1733             fSubMesh->AddElement( triangles[i]);
1734           newElems.Append( triangles[i] );
1735         }
1736         ReplaceElemInGroups( face, triangles, GetMeshDS() );
1737         GetMeshDS()->RemoveFreeElement( face, fSubMesh, /*fromGroups=*/false );
1738       }
1739
1740     } // loop on volume faces to split them into triangles
1741
1742     GetMeshDS()->RemoveFreeElement( *elem, subMesh, /*fromGroups=*/false );
1743
1744   } // loop on volumes to split
1745
1746   myLastCreatedNodes = newNodes;
1747   myLastCreatedElems = newElems;
1748 }
1749
1750 //=======================================================================
1751 //function : AddToSameGroups
1752 //purpose  : add elemToAdd to the groups the elemInGroups belongs to
1753 //=======================================================================
1754
1755 void SMESH_MeshEditor::AddToSameGroups (const SMDS_MeshElement* elemToAdd,
1756                                         const SMDS_MeshElement* elemInGroups,
1757                                         SMESHDS_Mesh *          aMesh)
1758 {
1759   const set<SMESHDS_GroupBase*>& groups = aMesh->GetGroups();
1760   if (!groups.empty()) {
1761     set<SMESHDS_GroupBase*>::const_iterator grIt = groups.begin();
1762     for ( ; grIt != groups.end(); grIt++ ) {
1763       SMESHDS_Group* group = dynamic_cast<SMESHDS_Group*>( *grIt );
1764       if ( group && group->Contains( elemInGroups ))
1765         group->SMDSGroup().Add( elemToAdd );
1766     }
1767   }
1768 }
1769
1770
1771 //=======================================================================
1772 //function : RemoveElemFromGroups
1773 //purpose  : Remove removeelem to the groups the elemInGroups belongs to
1774 //=======================================================================
1775 void SMESH_MeshEditor::RemoveElemFromGroups (const SMDS_MeshElement* removeelem,
1776                                              SMESHDS_Mesh *          aMesh)
1777 {
1778   const set<SMESHDS_GroupBase*>& groups = aMesh->GetGroups();
1779   if (!groups.empty())
1780   {
1781     set<SMESHDS_GroupBase*>::const_iterator GrIt = groups.begin();
1782     for (; GrIt != groups.end(); GrIt++)
1783     {
1784       SMESHDS_Group* grp = dynamic_cast<SMESHDS_Group*>(*GrIt);
1785       if (!grp || grp->IsEmpty()) continue;
1786       grp->SMDSGroup().Remove(removeelem);
1787     }
1788   }
1789 }
1790
1791 //================================================================================
1792 /*!
1793  * \brief Replace elemToRm by elemToAdd in the all groups
1794  */
1795 //================================================================================
1796
1797 void SMESH_MeshEditor::ReplaceElemInGroups (const SMDS_MeshElement* elemToRm,
1798                                             const SMDS_MeshElement* elemToAdd,
1799                                             SMESHDS_Mesh *          aMesh)
1800 {
1801   const set<SMESHDS_GroupBase*>& groups = aMesh->GetGroups();
1802   if (!groups.empty()) {
1803     set<SMESHDS_GroupBase*>::const_iterator grIt = groups.begin();
1804     for ( ; grIt != groups.end(); grIt++ ) {
1805       SMESHDS_Group* group = dynamic_cast<SMESHDS_Group*>( *grIt );
1806       if ( group && group->SMDSGroup().Remove( elemToRm ) && elemToAdd )
1807         group->SMDSGroup().Add( elemToAdd );
1808     }
1809   }
1810 }
1811
1812 //================================================================================
1813 /*!
1814  * \brief Replace elemToRm by elemToAdd in the all groups
1815  */
1816 //================================================================================
1817
1818 void SMESH_MeshEditor::ReplaceElemInGroups (const SMDS_MeshElement*                elemToRm,
1819                                             const vector<const SMDS_MeshElement*>& elemToAdd,
1820                                             SMESHDS_Mesh *                         aMesh)
1821 {
1822   const set<SMESHDS_GroupBase*>& groups = aMesh->GetGroups();
1823   if (!groups.empty())
1824   {
1825     set<SMESHDS_GroupBase*>::const_iterator grIt = groups.begin();
1826     for ( ; grIt != groups.end(); grIt++ ) {
1827       SMESHDS_Group* group = dynamic_cast<SMESHDS_Group*>( *grIt );
1828       if ( group && group->SMDSGroup().Remove( elemToRm ) )
1829         for ( int i = 0; i < elemToAdd.size(); ++i )
1830           group->SMDSGroup().Add( elemToAdd[ i ] );
1831     }
1832   }
1833 }
1834
1835 //=======================================================================
1836 //function : QuadToTri
1837 //purpose  : Cut quadrangles into triangles.
1838 //           theCrit is used to select a diagonal to cut
1839 //=======================================================================
1840
1841 bool SMESH_MeshEditor::QuadToTri (TIDSortedElemSet & theElems,
1842                                   const bool         the13Diag)
1843 {
1844   myLastCreatedElems.Clear();
1845   myLastCreatedNodes.Clear();
1846
1847   MESSAGE( "::QuadToTri()" );
1848
1849   SMESHDS_Mesh * aMesh = GetMeshDS();
1850
1851   Handle(Geom_Surface) surface;
1852   SMESH_MesherHelper   helper( *GetMesh() );
1853
1854   TIDSortedElemSet::iterator itElem;
1855   for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
1856     const SMDS_MeshElement* elem = *itElem;
1857     if ( !elem || elem->GetType() != SMDSAbs_Face )
1858       continue;
1859     bool isquad = elem->NbNodes()==4 || elem->NbNodes()==8;
1860     if(!isquad) continue;
1861
1862     if(elem->NbNodes()==4) {
1863       // retrieve element nodes
1864       const SMDS_MeshNode* aNodes [4];
1865       SMDS_ElemIteratorPtr itN = elem->nodesIterator();
1866       int i = 0;
1867       while ( itN->more() )
1868         aNodes[ i++ ] = static_cast<const SMDS_MeshNode*>( itN->next() );
1869
1870       int aShapeId = FindShape( elem );
1871       const SMDS_MeshElement* newElem1 = 0;
1872       const SMDS_MeshElement* newElem2 = 0;
1873       if ( the13Diag ) {
1874         newElem1 = aMesh->AddFace( aNodes[2], aNodes[0], aNodes[1] );
1875         newElem2 = aMesh->AddFace( aNodes[2], aNodes[3], aNodes[0] );
1876       }
1877       else {
1878         newElem1 = aMesh->AddFace( aNodes[3], aNodes[0], aNodes[1] );
1879         newElem2 = aMesh->AddFace( aNodes[3], aNodes[1], aNodes[2] );
1880       }
1881       myLastCreatedElems.Append(newElem1);
1882       myLastCreatedElems.Append(newElem2);
1883       // put a new triangle on the same shape and add to the same groups
1884       if ( aShapeId )
1885         {
1886           aMesh->SetMeshElementOnShape( newElem1, aShapeId );
1887           aMesh->SetMeshElementOnShape( newElem2, aShapeId );
1888         }
1889       AddToSameGroups( newElem1, elem, aMesh );
1890       AddToSameGroups( newElem2, elem, aMesh );
1891       //aMesh->RemoveFreeElement(elem, aMesh->MeshElements(aShapeId), true);
1892       aMesh->RemoveElement( elem );
1893     }
1894
1895     // Quadratic quadrangle
1896
1897     if( elem->NbNodes()==8 && elem->IsQuadratic() ) {
1898
1899       // get surface elem is on
1900       int aShapeId = FindShape( elem );
1901       if ( aShapeId != helper.GetSubShapeID() ) {
1902         surface.Nullify();
1903         TopoDS_Shape shape;
1904         if ( aShapeId > 0 )
1905           shape = aMesh->IndexToShape( aShapeId );
1906         if ( !shape.IsNull() && shape.ShapeType() == TopAbs_FACE ) {
1907           TopoDS_Face face = TopoDS::Face( shape );
1908           surface = BRep_Tool::Surface( face );
1909           if ( !surface.IsNull() )
1910             helper.SetSubShape( shape );
1911         }
1912       }
1913
1914       const SMDS_MeshNode* aNodes [8];
1915       const SMDS_MeshNode* inFaceNode = 0;
1916       SMDS_ElemIteratorPtr itN = elem->nodesIterator();
1917       int i = 0;
1918       while ( itN->more() ) {
1919         aNodes[ i++ ] = static_cast<const SMDS_MeshNode*>( itN->next() );
1920         if ( !inFaceNode && helper.GetNodeUVneedInFaceNode() &&
1921              aNodes[ i-1 ]->GetPosition()->GetTypeOfPosition() == SMDS_TOP_FACE )
1922         {
1923           inFaceNode = aNodes[ i-1 ];
1924         }
1925       }
1926
1927       // find middle point for (0,1,2,3)
1928       // and create a node in this point;
1929       gp_XYZ p( 0,0,0 );
1930       if ( surface.IsNull() ) {
1931         for(i=0; i<4; i++)
1932           p += gp_XYZ(aNodes[i]->X(), aNodes[i]->Y(), aNodes[i]->Z() );
1933         p /= 4;
1934       }
1935       else {
1936         TopoDS_Face geomFace = TopoDS::Face( helper.GetSubShape() );
1937         gp_XY uv( 0,0 );
1938         for(i=0; i<4; i++)
1939           uv += helper.GetNodeUV( geomFace, aNodes[i], inFaceNode );
1940         uv /= 4.;
1941         p = surface->Value( uv.X(), uv.Y() ).XYZ();
1942       }
1943       const SMDS_MeshNode* newN = aMesh->AddNode( p.X(), p.Y(), p.Z() );
1944       myLastCreatedNodes.Append(newN);
1945
1946       // create a new element
1947       const SMDS_MeshElement* newElem1 = 0;
1948       const SMDS_MeshElement* newElem2 = 0;
1949       const SMDS_MeshNode* N[6];
1950       if ( the13Diag ) {
1951         N[0] = aNodes[0];
1952         N[1] = aNodes[1];
1953         N[2] = aNodes[2];
1954         N[3] = aNodes[4];
1955         N[4] = aNodes[5];
1956         N[5] = newN;
1957         newElem1 = aMesh->AddFace(aNodes[2], aNodes[3], aNodes[0],
1958                                   aNodes[6], aNodes[7], newN );
1959         newElem2 = aMesh->AddFace(aNodes[2], aNodes[0], aNodes[1],
1960                                   newN,      aNodes[4], aNodes[5] );
1961       }
1962       else {
1963         N[0] = aNodes[1];
1964         N[1] = aNodes[2];
1965         N[2] = aNodes[3];
1966         N[3] = aNodes[5];
1967         N[4] = aNodes[6];
1968         N[5] = newN;
1969         newElem1 = aMesh->AddFace(aNodes[3], aNodes[0], aNodes[1],
1970                                   aNodes[7], aNodes[4], newN );
1971         newElem2 = aMesh->AddFace(aNodes[3], aNodes[1], aNodes[2],
1972                                   newN,      aNodes[5], aNodes[6] );
1973       }
1974       myLastCreatedElems.Append(newElem1);
1975       myLastCreatedElems.Append(newElem2);
1976       // put a new triangle on the same shape and add to the same groups
1977       if ( aShapeId )
1978         {
1979           aMesh->SetMeshElementOnShape( newElem1, aShapeId );
1980           aMesh->SetMeshElementOnShape( newElem2, aShapeId );
1981         }
1982       AddToSameGroups( newElem1, elem, aMesh );
1983       AddToSameGroups( newElem2, elem, aMesh );
1984       aMesh->RemoveElement( elem );
1985     }
1986   }
1987
1988   return true;
1989 }
1990
1991 //=======================================================================
1992 //function : getAngle
1993 //purpose  :
1994 //=======================================================================
1995
1996 double getAngle(const SMDS_MeshElement * tr1,
1997                 const SMDS_MeshElement * tr2,
1998                 const SMDS_MeshNode *    n1,
1999                 const SMDS_MeshNode *    n2)
2000 {
2001   double angle = 2*PI; // bad angle
2002
2003   // get normals
2004   SMESH::Controls::TSequenceOfXYZ P1, P2;
2005   if ( !SMESH::Controls::NumericalFunctor::GetPoints( tr1, P1 ) ||
2006        !SMESH::Controls::NumericalFunctor::GetPoints( tr2, P2 ))
2007     return angle;
2008   gp_Vec N1,N2;
2009   if(!tr1->IsQuadratic())
2010     N1 = gp_Vec( P1(2) - P1(1) ) ^ gp_Vec( P1(3) - P1(1) );
2011   else
2012     N1 = gp_Vec( P1(3) - P1(1) ) ^ gp_Vec( P1(5) - P1(1) );
2013   if ( N1.SquareMagnitude() <= gp::Resolution() )
2014     return angle;
2015   if(!tr2->IsQuadratic())
2016     N2 = gp_Vec( P2(2) - P2(1) ) ^ gp_Vec( P2(3) - P2(1) );
2017   else
2018     N2 = gp_Vec( P2(3) - P2(1) ) ^ gp_Vec( P2(5) - P2(1) );
2019   if ( N2.SquareMagnitude() <= gp::Resolution() )
2020     return angle;
2021
2022   // find the first diagonal node n1 in the triangles:
2023   // take in account a diagonal link orientation
2024   const SMDS_MeshElement *nFirst[2], *tr[] = { tr1, tr2 };
2025   for ( int t = 0; t < 2; t++ ) {
2026     SMDS_ElemIteratorPtr it = tr[ t ]->nodesIterator();
2027     int i = 0, iDiag = -1;
2028     while ( it->more()) {
2029       const SMDS_MeshElement *n = it->next();
2030       if ( n == n1 || n == n2 ) {
2031         if ( iDiag < 0)
2032           iDiag = i;
2033         else {
2034           if ( i - iDiag == 1 )
2035             nFirst[ t ] = ( n == n1 ? n2 : n1 );
2036           else
2037             nFirst[ t ] = n;
2038           break;
2039         }
2040       }
2041       i++;
2042     }
2043   }
2044   if ( nFirst[ 0 ] == nFirst[ 1 ] )
2045     N2.Reverse();
2046
2047   angle = N1.Angle( N2 );
2048   //SCRUTE( angle );
2049   return angle;
2050 }
2051
2052 // =================================================
2053 // class generating a unique ID for a pair of nodes
2054 // and able to return nodes by that ID
2055 // =================================================
2056 class LinkID_Gen {
2057 public:
2058
2059   LinkID_Gen( const SMESHDS_Mesh* theMesh )
2060     :myMesh( theMesh ), myMaxID( theMesh->MaxNodeID() + 1)
2061   {}
2062
2063   long GetLinkID (const SMDS_MeshNode * n1,
2064                   const SMDS_MeshNode * n2) const
2065   {
2066     return ( Min(n1->GetID(),n2->GetID()) * myMaxID + Max(n1->GetID(),n2->GetID()));
2067   }
2068
2069   bool GetNodes (const long             theLinkID,
2070                  const SMDS_MeshNode* & theNode1,
2071                  const SMDS_MeshNode* & theNode2) const
2072   {
2073     theNode1 = myMesh->FindNode( theLinkID / myMaxID );
2074     if ( !theNode1 ) return false;
2075     theNode2 = myMesh->FindNode( theLinkID % myMaxID );
2076     if ( !theNode2 ) return false;
2077     return true;
2078   }
2079
2080 private:
2081   LinkID_Gen();
2082   const SMESHDS_Mesh* myMesh;
2083   long                myMaxID;
2084 };
2085
2086
2087 //=======================================================================
2088 //function : TriToQuad
2089 //purpose  : Fuse neighbour triangles into quadrangles.
2090 //           theCrit is used to select a neighbour to fuse with.
2091 //           theMaxAngle is a max angle between element normals at which
2092 //           fusion is still performed.
2093 //=======================================================================
2094
2095 bool SMESH_MeshEditor::TriToQuad (TIDSortedElemSet &                   theElems,
2096                                   SMESH::Controls::NumericalFunctorPtr theCrit,
2097                                   const double                         theMaxAngle)
2098 {
2099   myLastCreatedElems.Clear();
2100   myLastCreatedNodes.Clear();
2101
2102   MESSAGE( "::TriToQuad()" );
2103
2104   if ( !theCrit.get() )
2105     return false;
2106
2107   SMESHDS_Mesh * aMesh = GetMeshDS();
2108
2109   // Prepare data for algo: build
2110   // 1. map of elements with their linkIDs
2111   // 2. map of linkIDs with their elements
2112
2113   map< SMESH_TLink, list< const SMDS_MeshElement* > > mapLi_listEl;
2114   map< SMESH_TLink, list< const SMDS_MeshElement* > >::iterator itLE;
2115   map< const SMDS_MeshElement*, set< SMESH_TLink > >  mapEl_setLi;
2116   map< const SMDS_MeshElement*, set< SMESH_TLink > >::iterator itEL;
2117
2118   TIDSortedElemSet::iterator itElem;
2119   for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
2120     const SMDS_MeshElement* elem = *itElem;
2121     if(!elem || elem->GetType() != SMDSAbs_Face ) continue;
2122     bool IsTria = elem->NbNodes()==3 || (elem->NbNodes()==6 && elem->IsQuadratic());
2123     if(!IsTria) continue;
2124
2125     // retrieve element nodes
2126     const SMDS_MeshNode* aNodes [4];
2127     SMDS_ElemIteratorPtr itN = elem->nodesIterator();
2128     int i = 0;
2129     while ( i<3 )
2130       aNodes[ i++ ] = cast2Node( itN->next() );
2131     aNodes[ 3 ] = aNodes[ 0 ];
2132
2133     // fill maps
2134     for ( i = 0; i < 3; i++ ) {
2135       SMESH_TLink link( aNodes[i], aNodes[i+1] );
2136       // check if elements sharing a link can be fused
2137       itLE = mapLi_listEl.find( link );
2138       if ( itLE != mapLi_listEl.end() ) {
2139         if ((*itLE).second.size() > 1 ) // consider only 2 elems adjacent by a link
2140           continue;
2141         const SMDS_MeshElement* elem2 = (*itLE).second.front();
2142         //if ( FindShape( elem ) != FindShape( elem2 ))
2143         //  continue; // do not fuse triangles laying on different shapes
2144         if ( getAngle( elem, elem2, aNodes[i], aNodes[i+1] ) > theMaxAngle )
2145           continue; // avoid making badly shaped quads
2146         (*itLE).second.push_back( elem );
2147       }
2148       else {
2149         mapLi_listEl[ link ].push_back( elem );
2150       }
2151       mapEl_setLi [ elem ].insert( link );
2152     }
2153   }
2154   // Clean the maps from the links shared by a sole element, ie
2155   // links to which only one element is bound in mapLi_listEl
2156
2157   for ( itLE = mapLi_listEl.begin(); itLE != mapLi_listEl.end(); itLE++ ) {
2158     int nbElems = (*itLE).second.size();
2159     if ( nbElems < 2  ) {
2160       const SMDS_MeshElement* elem = (*itLE).second.front();
2161       SMESH_TLink link = (*itLE).first;
2162       mapEl_setLi[ elem ].erase( link );
2163       if ( mapEl_setLi[ elem ].empty() )
2164         mapEl_setLi.erase( elem );
2165     }
2166   }
2167
2168   // Algo: fuse triangles into quadrangles
2169
2170   while ( ! mapEl_setLi.empty() ) {
2171     // Look for the start element:
2172     // the element having the least nb of shared links
2173     const SMDS_MeshElement* startElem = 0;
2174     int minNbLinks = 4;
2175     for ( itEL = mapEl_setLi.begin(); itEL != mapEl_setLi.end(); itEL++ ) {
2176       int nbLinks = (*itEL).second.size();
2177       if ( nbLinks < minNbLinks ) {
2178         startElem = (*itEL).first;
2179         minNbLinks = nbLinks;
2180         if ( minNbLinks == 1 )
2181           break;
2182       }
2183     }
2184
2185     // search elements to fuse starting from startElem or links of elements
2186     // fused earlyer - startLinks
2187     list< SMESH_TLink > startLinks;
2188     while ( startElem || !startLinks.empty() ) {
2189       while ( !startElem && !startLinks.empty() ) {
2190         // Get an element to start, by a link
2191         SMESH_TLink linkId = startLinks.front();
2192         startLinks.pop_front();
2193         itLE = mapLi_listEl.find( linkId );
2194         if ( itLE != mapLi_listEl.end() ) {
2195           list< const SMDS_MeshElement* > & listElem = (*itLE).second;
2196           list< const SMDS_MeshElement* >::iterator itE = listElem.begin();
2197           for ( ; itE != listElem.end() ; itE++ )
2198             if ( mapEl_setLi.find( (*itE) ) != mapEl_setLi.end() )
2199               startElem = (*itE);
2200           mapLi_listEl.erase( itLE );
2201         }
2202       }
2203
2204       if ( startElem ) {
2205         // Get candidates to be fused
2206         const SMDS_MeshElement *tr1 = startElem, *tr2 = 0, *tr3 = 0;
2207         const SMESH_TLink *link12, *link13;
2208         startElem = 0;
2209         ASSERT( mapEl_setLi.find( tr1 ) != mapEl_setLi.end() );
2210         set< SMESH_TLink >& setLi = mapEl_setLi[ tr1 ];
2211         ASSERT( !setLi.empty() );
2212         set< SMESH_TLink >::iterator itLi;
2213         for ( itLi = setLi.begin(); itLi != setLi.end(); itLi++ )
2214         {
2215           const SMESH_TLink & link = (*itLi);
2216           itLE = mapLi_listEl.find( link );
2217           if ( itLE == mapLi_listEl.end() )
2218             continue;
2219
2220           const SMDS_MeshElement* elem = (*itLE).second.front();
2221           if ( elem == tr1 )
2222             elem = (*itLE).second.back();
2223           mapLi_listEl.erase( itLE );
2224           if ( mapEl_setLi.find( elem ) == mapEl_setLi.end())
2225             continue;
2226           if ( tr2 ) {
2227             tr3 = elem;
2228             link13 = &link;
2229           }
2230           else {
2231             tr2 = elem;
2232             link12 = &link;
2233           }
2234
2235           // add other links of elem to list of links to re-start from
2236           set< SMESH_TLink >& links = mapEl_setLi[ elem ];
2237           set< SMESH_TLink >::iterator it;
2238           for ( it = links.begin(); it != links.end(); it++ ) {
2239             const SMESH_TLink& link2 = (*it);
2240             if ( link2 != link )
2241               startLinks.push_back( link2 );
2242           }
2243         }
2244
2245         // Get nodes of possible quadrangles
2246         const SMDS_MeshNode *n12 [4], *n13 [4];
2247         bool Ok12 = false, Ok13 = false;
2248         const SMDS_MeshNode *linkNode1, *linkNode2;
2249         if(tr2) {
2250           linkNode1 = link12->first;
2251           linkNode2 = link12->second;
2252           if ( tr2 && getQuadrangleNodes( n12, linkNode1, linkNode2, tr1, tr2 ))
2253             Ok12 = true;
2254         }
2255         if(tr3) {
2256           linkNode1 = link13->first;
2257           linkNode2 = link13->second;
2258           if ( tr3 && getQuadrangleNodes( n13, linkNode1, linkNode2, tr1, tr3 ))
2259             Ok13 = true;
2260         }
2261
2262         // Choose a pair to fuse
2263         if ( Ok12 && Ok13 ) {
2264           SMDS_FaceOfNodes quad12 ( n12[ 0 ], n12[ 1 ], n12[ 2 ], n12[ 3 ] );
2265           SMDS_FaceOfNodes quad13 ( n13[ 0 ], n13[ 1 ], n13[ 2 ], n13[ 3 ] );
2266           double aBadRate12 = getBadRate( &quad12, theCrit );
2267           double aBadRate13 = getBadRate( &quad13, theCrit );
2268           if (  aBadRate13 < aBadRate12 )
2269             Ok12 = false;
2270           else
2271             Ok13 = false;
2272         }
2273
2274         // Make quadrangles
2275         // and remove fused elems and removed links from the maps
2276         mapEl_setLi.erase( tr1 );
2277         if ( Ok12 ) {
2278           mapEl_setLi.erase( tr2 );
2279           mapLi_listEl.erase( *link12 );
2280           if(tr1->NbNodes()==3) {
2281             const SMDS_MeshElement* newElem = 0;
2282             newElem = aMesh->AddFace(n12[0], n12[1], n12[2], n12[3] );
2283             myLastCreatedElems.Append(newElem);
2284             AddToSameGroups( newElem, tr1, aMesh );
2285             int aShapeId = tr1->getshapeId();
2286             if ( aShapeId )
2287               {
2288                 aMesh->SetMeshElementOnShape( newElem, aShapeId );
2289               }
2290             aMesh->RemoveElement( tr1 );
2291             aMesh->RemoveElement( tr2 );
2292           }
2293           else {
2294             const SMDS_MeshNode* N1 [6];
2295             const SMDS_MeshNode* N2 [6];
2296             GetNodesFromTwoTria(tr1,tr2,N1,N2);
2297             // now we receive following N1 and N2 (using numeration as above image)
2298             // tria1 : (1 2 4 5 9 7)  and  tria2 : (3 4 2 8 9 6)
2299             // i.e. first nodes from both arrays determ new diagonal
2300             const SMDS_MeshNode* aNodes[8];
2301             aNodes[0] = N1[0];
2302             aNodes[1] = N1[1];
2303             aNodes[2] = N2[0];
2304             aNodes[3] = N2[1];
2305             aNodes[4] = N1[3];
2306             aNodes[5] = N2[5];
2307             aNodes[6] = N2[3];
2308             aNodes[7] = N1[5];
2309             const SMDS_MeshElement* newElem = 0;
2310             newElem = aMesh->AddFace(aNodes[0], aNodes[1], aNodes[2], aNodes[3],
2311                                      aNodes[4], aNodes[5], aNodes[6], aNodes[7]);
2312             myLastCreatedElems.Append(newElem);
2313             AddToSameGroups( newElem, tr1, aMesh );
2314             int aShapeId = tr1->getshapeId();
2315             if ( aShapeId )
2316               {
2317                 aMesh->SetMeshElementOnShape( newElem, aShapeId );
2318               }
2319             aMesh->RemoveElement( tr1 );
2320             aMesh->RemoveElement( tr2 );
2321             // remove middle node (9)
2322             GetMeshDS()->RemoveNode( N1[4] );
2323           }
2324         }
2325         else if ( Ok13 ) {
2326           mapEl_setLi.erase( tr3 );
2327           mapLi_listEl.erase( *link13 );
2328           if(tr1->NbNodes()==3) {
2329             const SMDS_MeshElement* newElem = 0;
2330             newElem = aMesh->AddFace(n13[0], n13[1], n13[2], n13[3] );
2331             myLastCreatedElems.Append(newElem);
2332             AddToSameGroups( newElem, tr1, aMesh );
2333             int aShapeId = tr1->getshapeId();
2334             if ( aShapeId )
2335               {
2336                 aMesh->SetMeshElementOnShape( newElem, aShapeId );
2337               }
2338             aMesh->RemoveElement( tr1 );
2339             aMesh->RemoveElement( tr3 );
2340           }
2341           else {
2342             const SMDS_MeshNode* N1 [6];
2343             const SMDS_MeshNode* N2 [6];
2344             GetNodesFromTwoTria(tr1,tr3,N1,N2);
2345             // now we receive following N1 and N2 (using numeration as above image)
2346             // tria1 : (1 2 4 5 9 7)  and  tria2 : (3 4 2 8 9 6)
2347             // i.e. first nodes from both arrays determ new diagonal
2348             const SMDS_MeshNode* aNodes[8];
2349             aNodes[0] = N1[0];
2350             aNodes[1] = N1[1];
2351             aNodes[2] = N2[0];
2352             aNodes[3] = N2[1];
2353             aNodes[4] = N1[3];
2354             aNodes[5] = N2[5];
2355             aNodes[6] = N2[3];
2356             aNodes[7] = N1[5];
2357             const SMDS_MeshElement* newElem = 0;
2358             newElem = aMesh->AddFace(aNodes[0], aNodes[1], aNodes[2], aNodes[3],
2359                                      aNodes[4], aNodes[5], aNodes[6], aNodes[7]);
2360             myLastCreatedElems.Append(newElem);
2361             AddToSameGroups( newElem, tr1, aMesh );
2362             int aShapeId = tr1->getshapeId();
2363             if ( aShapeId )
2364               {
2365                 aMesh->SetMeshElementOnShape( newElem, aShapeId );
2366               }
2367             aMesh->RemoveElement( tr1 );
2368             aMesh->RemoveElement( tr3 );
2369             // remove middle node (9)
2370             GetMeshDS()->RemoveNode( N1[4] );
2371           }
2372         }
2373
2374         // Next element to fuse: the rejected one
2375         if ( tr3 )
2376           startElem = Ok12 ? tr3 : tr2;
2377
2378       } // if ( startElem )
2379     } // while ( startElem || !startLinks.empty() )
2380   } // while ( ! mapEl_setLi.empty() )
2381
2382   return true;
2383 }
2384
2385
2386 /*#define DUMPSO(txt) \
2387 //  cout << txt << endl;
2388 //=============================================================================
2389 //
2390 //
2391 //
2392 //=============================================================================
2393 static void swap( int i1, int i2, int idNodes[], gp_Pnt P[] )
2394 {
2395 if ( i1 == i2 )
2396 return;
2397 int tmp = idNodes[ i1 ];
2398 idNodes[ i1 ] = idNodes[ i2 ];
2399 idNodes[ i2 ] = tmp;
2400 gp_Pnt Ptmp = P[ i1 ];
2401 P[ i1 ] = P[ i2 ];
2402 P[ i2 ] = Ptmp;
2403 DUMPSO( i1 << "(" << idNodes[ i2 ] << ") <-> " << i2 << "(" << idNodes[ i1 ] << ")");
2404 }
2405
2406 //=======================================================================
2407 //function : SortQuadNodes
2408 //purpose  : Set 4 nodes of a quadrangle face in a good order.
2409 //           Swap 1<->2 or 2<->3 nodes and correspondingly return
2410 //           1 or 2 else 0.
2411 //=======================================================================
2412
2413 int SMESH_MeshEditor::SortQuadNodes (const SMDS_Mesh * theMesh,
2414 int               idNodes[] )
2415 {
2416   gp_Pnt P[4];
2417   int i;
2418   for ( i = 0; i < 4; i++ ) {
2419     const SMDS_MeshNode *n = theMesh->FindNode( idNodes[i] );
2420     if ( !n ) return 0;
2421     P[ i ].SetCoord( n->X(), n->Y(), n->Z() );
2422   }
2423
2424   gp_Vec V1(P[0], P[1]);
2425   gp_Vec V2(P[0], P[2]);
2426   gp_Vec V3(P[0], P[3]);
2427
2428   gp_Vec Cross1 = V1 ^ V2;
2429   gp_Vec Cross2 = V2 ^ V3;
2430
2431   i = 0;
2432   if (Cross1.Dot(Cross2) < 0)
2433   {
2434     Cross1 = V2 ^ V1;
2435     Cross2 = V1 ^ V3;
2436
2437     if (Cross1.Dot(Cross2) < 0)
2438       i = 2;
2439     else
2440       i = 1;
2441     swap ( i, i + 1, idNodes, P );
2442
2443     //     for ( int ii = 0; ii < 4; ii++ ) {
2444     //       const SMDS_MeshNode *n = theMesh->FindNode( idNodes[ii] );
2445     //       DUMPSO( ii << "(" << idNodes[ii] <<") : "<<n->X()<<" "<<n->Y()<<" "<<n->Z());
2446     //     }
2447   }
2448   return i;
2449 }
2450
2451 //=======================================================================
2452 //function : SortHexaNodes
2453 //purpose  : Set 8 nodes of a hexahedron in a good order.
2454 //           Return success status
2455 //=======================================================================
2456
2457 bool SMESH_MeshEditor::SortHexaNodes (const SMDS_Mesh * theMesh,
2458                                       int               idNodes[] )
2459 {
2460   gp_Pnt P[8];
2461   int i;
2462   DUMPSO( "INPUT: ========================================");
2463   for ( i = 0; i < 8; i++ ) {
2464     const SMDS_MeshNode *n = theMesh->FindNode( idNodes[i] );
2465     if ( !n ) return false;
2466     P[ i ].SetCoord( n->X(), n->Y(), n->Z() );
2467     DUMPSO( i << "(" << idNodes[i] <<") : "<<n->X()<<" "<<n->Y()<<" "<<n->Z());
2468   }
2469   DUMPSO( "========================================");
2470
2471
2472   set<int> faceNodes;  // ids of bottom face nodes, to be found
2473   set<int> checkedId1; // ids of tried 2-nd nodes
2474   Standard_Real leastDist = DBL_MAX; // dist of the 4-th node from 123 plane
2475   const Standard_Real tol = 1.e-6;   // tolerance to find nodes in plane
2476   int iMin, iLoop1 = 0;
2477
2478   // Loop to try the 2-nd nodes
2479
2480   while ( leastDist > DBL_MIN && ++iLoop1 < 8 )
2481   {
2482     // Find not checked 2-nd node
2483     for ( i = 1; i < 8; i++ )
2484       if ( checkedId1.find( idNodes[i] ) == checkedId1.end() ) {
2485         int id1 = idNodes[i];
2486         swap ( 1, i, idNodes, P );
2487         checkedId1.insert ( id1 );
2488         break;
2489       }
2490
2491     // Find the 3-d node so that 1-2-3 triangle to be on a hexa face,
2492     // ie that all but meybe one (id3 which is on the same face) nodes
2493     // lay on the same side from the triangle plane.
2494
2495     bool manyInPlane = false; // more than 4 nodes lay in plane
2496     int iLoop2 = 0;
2497     while ( ++iLoop2 < 6 ) {
2498
2499       // get 1-2-3 plane coeffs
2500       Standard_Real A, B, C, D;
2501       gp_Vec N = gp_Vec (P[0], P[1]).Crossed( gp_Vec (P[0], P[2]) );
2502       if ( N.SquareMagnitude() > gp::Resolution() )
2503       {
2504         gp_Pln pln ( P[0], N );
2505         pln.Coefficients( A, B, C, D );
2506
2507         // find the node (iMin) closest to pln
2508         Standard_Real dist[ 8 ], minDist = DBL_MAX;
2509         set<int> idInPln;
2510         for ( i = 3; i < 8; i++ ) {
2511           dist[i] = A * P[i].X() + B * P[i].Y() + C * P[i].Z() + D;
2512           if ( fabs( dist[i] ) < minDist ) {
2513             minDist = fabs( dist[i] );
2514             iMin = i;
2515           }
2516           if ( fabs( dist[i] ) <= tol )
2517             idInPln.insert( idNodes[i] );
2518         }
2519
2520         // there should not be more than 4 nodes in bottom plane
2521         if ( idInPln.size() > 1 )
2522         {
2523           DUMPSO( "### idInPln.size() = " << idInPln.size());
2524           // idInPlane does not contain the first 3 nodes
2525           if ( manyInPlane || idInPln.size() == 5)
2526             return false; // all nodes in one plane
2527           manyInPlane = true;
2528
2529           // set the 1-st node to be not in plane
2530           for ( i = 3; i < 8; i++ ) {
2531             if ( idInPln.find( idNodes[ i ] ) == idInPln.end() ) {
2532               DUMPSO( "### Reset 0-th node");
2533               swap( 0, i, idNodes, P );
2534               break;
2535             }
2536           }
2537
2538           // reset to re-check second nodes
2539           leastDist = DBL_MAX;
2540           faceNodes.clear();
2541           checkedId1.clear();
2542           iLoop1 = 0;
2543           break; // from iLoop2;
2544         }
2545
2546         // check that the other 4 nodes are on the same side
2547         bool sameSide = true;
2548         bool isNeg = dist[ iMin == 3 ? 4 : 3 ] <= 0.;
2549         for ( i = 3; sameSide && i < 8; i++ ) {
2550           if ( i != iMin )
2551             sameSide = ( isNeg == dist[i] <= 0.);
2552         }
2553
2554         // keep best solution
2555         if ( sameSide && minDist < leastDist ) {
2556           leastDist = minDist;
2557           faceNodes.clear();
2558           faceNodes.insert( idNodes[ 1 ] );
2559           faceNodes.insert( idNodes[ 2 ] );
2560           faceNodes.insert( idNodes[ iMin ] );
2561           DUMPSO( "loop " << iLoop2 << " id2 " << idNodes[ 1 ] << " id3 " << idNodes[ 2 ]
2562                   << " leastDist = " << leastDist);
2563           if ( leastDist <= DBL_MIN )
2564             break;
2565         }
2566       }
2567
2568       // set next 3-d node to check
2569       int iNext = 2 + iLoop2;
2570       if ( iNext < 8 ) {
2571         DUMPSO( "Try 2-nd");
2572         swap ( 2, iNext, idNodes, P );
2573       }
2574     } // while ( iLoop2 < 6 )
2575   } // iLoop1
2576
2577   if ( faceNodes.empty() ) return false;
2578
2579   // Put the faceNodes in proper places
2580   for ( i = 4; i < 8; i++ ) {
2581     if ( faceNodes.find( idNodes[ i ] ) != faceNodes.end() ) {
2582       // find a place to put
2583       int iTo = 1;
2584       while ( faceNodes.find( idNodes[ iTo ] ) != faceNodes.end() )
2585         iTo++;
2586       DUMPSO( "Set faceNodes");
2587       swap ( iTo, i, idNodes, P );
2588     }
2589   }
2590
2591
2592   // Set nodes of the found bottom face in good order
2593   DUMPSO( " Found bottom face: ");
2594   i = SortQuadNodes( theMesh, idNodes );
2595   if ( i ) {
2596     gp_Pnt Ptmp = P[ i ];
2597     P[ i ] = P[ i+1 ];
2598     P[ i+1 ] = Ptmp;
2599   }
2600   //   else
2601   //     for ( int ii = 0; ii < 4; ii++ ) {
2602   //       const SMDS_MeshNode *n = theMesh->FindNode( idNodes[ii] );
2603   //       DUMPSO( ii << "(" << idNodes[ii] <<") : "<<n->X()<<" "<<n->Y()<<" "<<n->Z());
2604   //    }
2605
2606   // Gravity center of the top and bottom faces
2607   gp_Pnt aGCb = ( P[0].XYZ() + P[1].XYZ() + P[2].XYZ() + P[3].XYZ() ) / 4.;
2608   gp_Pnt aGCt = ( P[4].XYZ() + P[5].XYZ() + P[6].XYZ() + P[7].XYZ() ) / 4.;
2609
2610   // Get direction from the bottom to the top face
2611   gp_Vec upDir ( aGCb, aGCt );
2612   Standard_Real upDirSize = upDir.Magnitude();
2613   if ( upDirSize <= gp::Resolution() ) return false;
2614   upDir / upDirSize;
2615
2616   // Assure that the bottom face normal points up
2617   gp_Vec Nb = gp_Vec (P[0], P[1]).Crossed( gp_Vec (P[0], P[2]) );
2618   Nb += gp_Vec (P[0], P[2]).Crossed( gp_Vec (P[0], P[3]) );
2619   if ( Nb.Dot( upDir ) < 0 ) {
2620     DUMPSO( "Reverse bottom face");
2621     swap( 1, 3, idNodes, P );
2622   }
2623
2624   // Find 5-th node - the one closest to the 1-st among the last 4 nodes.
2625   Standard_Real minDist = DBL_MAX;
2626   for ( i = 4; i < 8; i++ ) {
2627     // projection of P[i] to the plane defined by P[0] and upDir
2628     gp_Pnt Pp = P[i].Translated( upDir * ( upDir.Dot( gp_Vec( P[i], P[0] ))));
2629     Standard_Real sqDist = P[0].SquareDistance( Pp );
2630     if ( sqDist < minDist ) {
2631       minDist = sqDist;
2632       iMin = i;
2633     }
2634   }
2635   DUMPSO( "Set 4-th");
2636   swap ( 4, iMin, idNodes, P );
2637
2638   // Set nodes of the top face in good order
2639   DUMPSO( "Sort top face");
2640   i = SortQuadNodes( theMesh, &idNodes[4] );
2641   if ( i ) {
2642     i += 4;
2643     gp_Pnt Ptmp = P[ i ];
2644     P[ i ] = P[ i+1 ];
2645     P[ i+1 ] = Ptmp;
2646   }
2647
2648   // Assure that direction of the top face normal is from the bottom face
2649   gp_Vec Nt = gp_Vec (P[4], P[5]).Crossed( gp_Vec (P[4], P[6]) );
2650   Nt += gp_Vec (P[4], P[6]).Crossed( gp_Vec (P[4], P[7]) );
2651   if ( Nt.Dot( upDir ) < 0 ) {
2652     DUMPSO( "Reverse top face");
2653     swap( 5, 7, idNodes, P );
2654   }
2655
2656   //   DUMPSO( "OUTPUT: ========================================");
2657   //   for ( i = 0; i < 8; i++ ) {
2658   //     float *p = ugrid->GetPoint(idNodes[i]);
2659   //     DUMPSO( i << "(" << idNodes[i] << ") : " << p[0] << " " << p[1] << " " << p[2]);
2660   //   }
2661
2662   return true;
2663 }*/
2664
2665 //================================================================================
2666 /*!
2667  * \brief Return nodes linked to the given one
2668  * \param theNode - the node
2669  * \param linkedNodes - the found nodes
2670  * \param type - the type of elements to check
2671  *
2672  * Medium nodes are ignored
2673  */
2674 //================================================================================
2675
2676 void SMESH_MeshEditor::GetLinkedNodes( const SMDS_MeshNode* theNode,
2677                                        TIDSortedElemSet &   linkedNodes,
2678                                        SMDSAbs_ElementType  type )
2679 {
2680   SMDS_ElemIteratorPtr elemIt = theNode->GetInverseElementIterator(type);
2681   while ( elemIt->more() )
2682   {
2683     const SMDS_MeshElement* elem = elemIt->next();
2684     SMDS_ElemIteratorPtr nodeIt = elem->nodesIterator();
2685     if ( elem->GetType() == SMDSAbs_Volume )
2686     {
2687       SMDS_VolumeTool vol( elem );
2688       while ( nodeIt->more() ) {
2689         const SMDS_MeshNode* n = cast2Node( nodeIt->next() );
2690         if ( theNode != n && vol.IsLinked( theNode, n ))
2691           linkedNodes.insert( n );
2692       }
2693     }
2694     else
2695     {
2696       for ( int i = 0; nodeIt->more(); ++i ) {
2697         const SMDS_MeshNode* n = cast2Node( nodeIt->next() );
2698         if ( n == theNode ) {
2699           int iBefore = i - 1;
2700           int iAfter  = i + 1;
2701           if ( elem->IsQuadratic() ) {
2702             int nb = elem->NbNodes() / 2;
2703             iAfter  = SMESH_MesherHelper::WrapIndex( iAfter, nb );
2704             iBefore = SMESH_MesherHelper::WrapIndex( iBefore, nb );
2705           }
2706           linkedNodes.insert( elem->GetNodeWrap( iAfter ));
2707           linkedNodes.insert( elem->GetNodeWrap( iBefore ));
2708         }
2709       }
2710     }
2711   }
2712 }
2713
2714 //=======================================================================
2715 //function : laplacianSmooth
2716 //purpose  : pulls theNode toward the center of surrounding nodes directly
2717 //           connected to that node along an element edge
2718 //=======================================================================
2719
2720 void laplacianSmooth(const SMDS_MeshNode*                 theNode,
2721                      const Handle(Geom_Surface)&          theSurface,
2722                      map< const SMDS_MeshNode*, gp_XY* >& theUVMap)
2723 {
2724   // find surrounding nodes
2725
2726   TIDSortedElemSet nodeSet;
2727   SMESH_MeshEditor::GetLinkedNodes( theNode, nodeSet, SMDSAbs_Face );
2728
2729   // compute new coodrs
2730
2731   double coord[] = { 0., 0., 0. };
2732   TIDSortedElemSet::iterator nodeSetIt = nodeSet.begin();
2733   for ( ; nodeSetIt != nodeSet.end(); nodeSetIt++ ) {
2734     const SMDS_MeshNode* node = cast2Node(*nodeSetIt);
2735     if ( theSurface.IsNull() ) { // smooth in 3D
2736       coord[0] += node->X();
2737       coord[1] += node->Y();
2738       coord[2] += node->Z();
2739     }
2740     else { // smooth in 2D
2741       ASSERT( theUVMap.find( node ) != theUVMap.end() );
2742       gp_XY* uv = theUVMap[ node ];
2743       coord[0] += uv->X();
2744       coord[1] += uv->Y();
2745     }
2746   }
2747   int nbNodes = nodeSet.size();
2748   if ( !nbNodes )
2749     return;
2750   coord[0] /= nbNodes;
2751   coord[1] /= nbNodes;
2752
2753   if ( !theSurface.IsNull() ) {
2754     ASSERT( theUVMap.find( theNode ) != theUVMap.end() );
2755     theUVMap[ theNode ]->SetCoord( coord[0], coord[1] );
2756     gp_Pnt p3d = theSurface->Value( coord[0], coord[1] );
2757     coord[0] = p3d.X();
2758     coord[1] = p3d.Y();
2759     coord[2] = p3d.Z();
2760   }
2761   else
2762     coord[2] /= nbNodes;
2763
2764   // move node
2765
2766   const_cast< SMDS_MeshNode* >( theNode )->setXYZ(coord[0],coord[1],coord[2]);
2767 }
2768
2769 //=======================================================================
2770 //function : centroidalSmooth
2771 //purpose  : pulls theNode toward the element-area-weighted centroid of the
2772 //           surrounding elements
2773 //=======================================================================
2774
2775 void centroidalSmooth(const SMDS_MeshNode*                 theNode,
2776                       const Handle(Geom_Surface)&          theSurface,
2777                       map< const SMDS_MeshNode*, gp_XY* >& theUVMap)
2778 {
2779   gp_XYZ aNewXYZ(0.,0.,0.);
2780   SMESH::Controls::Area anAreaFunc;
2781   double totalArea = 0.;
2782   int nbElems = 0;
2783
2784   // compute new XYZ
2785
2786   SMDS_ElemIteratorPtr elemIt = theNode->GetInverseElementIterator(SMDSAbs_Face);
2787   while ( elemIt->more() )
2788   {
2789     const SMDS_MeshElement* elem = elemIt->next();
2790     nbElems++;
2791
2792     gp_XYZ elemCenter(0.,0.,0.);
2793     SMESH::Controls::TSequenceOfXYZ aNodePoints;
2794     SMDS_ElemIteratorPtr itN = elem->nodesIterator();
2795     int nn = elem->NbNodes();
2796     if(elem->IsQuadratic()) nn = nn/2;
2797     int i=0;
2798     //while ( itN->more() ) {
2799     while ( i<nn ) {
2800       const SMDS_MeshNode* aNode = static_cast<const SMDS_MeshNode*>( itN->next() );
2801       i++;
2802       gp_XYZ aP( aNode->X(), aNode->Y(), aNode->Z() );
2803       aNodePoints.push_back( aP );
2804       if ( !theSurface.IsNull() ) { // smooth in 2D
2805         ASSERT( theUVMap.find( aNode ) != theUVMap.end() );
2806         gp_XY* uv = theUVMap[ aNode ];
2807         aP.SetCoord( uv->X(), uv->Y(), 0. );
2808       }
2809       elemCenter += aP;
2810     }
2811     double elemArea = anAreaFunc.GetValue( aNodePoints );
2812     totalArea += elemArea;
2813     elemCenter /= nn;
2814     aNewXYZ += elemCenter * elemArea;
2815   }
2816   aNewXYZ /= totalArea;
2817   if ( !theSurface.IsNull() ) {
2818     theUVMap[ theNode ]->SetCoord( aNewXYZ.X(), aNewXYZ.Y() );
2819     aNewXYZ = theSurface->Value( aNewXYZ.X(), aNewXYZ.Y() ).XYZ();
2820   }
2821
2822   // move node
2823
2824   const_cast< SMDS_MeshNode* >( theNode )->setXYZ(aNewXYZ.X(),aNewXYZ.Y(),aNewXYZ.Z());
2825 }
2826
2827 //=======================================================================
2828 //function : getClosestUV
2829 //purpose  : return UV of closest projection
2830 //=======================================================================
2831
2832 static bool getClosestUV (Extrema_GenExtPS& projector,
2833                           const gp_Pnt&     point,
2834                           gp_XY &           result)
2835 {
2836   projector.Perform( point );
2837   if ( projector.IsDone() ) {
2838     double u, v, minVal = DBL_MAX;
2839     for ( int i = projector.NbExt(); i > 0; i-- )
2840       if ( projector.Value( i ) < minVal ) {
2841         minVal = projector.Value( i );
2842         projector.Point( i ).Parameter( u, v );
2843       }
2844     result.SetCoord( u, v );
2845     return true;
2846   }
2847   return false;
2848 }
2849
2850 //=======================================================================
2851 //function : Smooth
2852 //purpose  : Smooth theElements during theNbIterations or until a worst
2853 //           element has aspect ratio <= theTgtAspectRatio.
2854 //           Aspect Ratio varies in range [1.0, inf].
2855 //           If theElements is empty, the whole mesh is smoothed.
2856 //           theFixedNodes contains additionally fixed nodes. Nodes built
2857 //           on edges and boundary nodes are always fixed.
2858 //=======================================================================
2859
2860 void SMESH_MeshEditor::Smooth (TIDSortedElemSet &          theElems,
2861                                set<const SMDS_MeshNode*> & theFixedNodes,
2862                                const SmoothMethod          theSmoothMethod,
2863                                const int                   theNbIterations,
2864                                double                      theTgtAspectRatio,
2865                                const bool                  the2D)
2866 {
2867   myLastCreatedElems.Clear();
2868   myLastCreatedNodes.Clear();
2869
2870   MESSAGE((theSmoothMethod==LAPLACIAN ? "LAPLACIAN" : "CENTROIDAL") << "--::Smooth()");
2871
2872   if ( theTgtAspectRatio < 1.0 )
2873     theTgtAspectRatio = 1.0;
2874
2875   const double disttol = 1.e-16;
2876
2877   SMESH::Controls::AspectRatio aQualityFunc;
2878
2879   SMESHDS_Mesh* aMesh = GetMeshDS();
2880
2881   if ( theElems.empty() ) {
2882     // add all faces to theElems
2883     SMDS_FaceIteratorPtr fIt = aMesh->facesIterator();
2884     while ( fIt->more() ) {
2885       const SMDS_MeshElement* face = fIt->next();
2886       theElems.insert( face );
2887     }
2888   }
2889   // get all face ids theElems are on
2890   set< int > faceIdSet;
2891   TIDSortedElemSet::iterator itElem;
2892   if ( the2D )
2893     for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
2894       int fId = FindShape( *itElem );
2895       // check that corresponding submesh exists and a shape is face
2896       if (fId &&
2897           faceIdSet.find( fId ) == faceIdSet.end() &&
2898           aMesh->MeshElements( fId )) {
2899         TopoDS_Shape F = aMesh->IndexToShape( fId );
2900         if ( !F.IsNull() && F.ShapeType() == TopAbs_FACE )
2901           faceIdSet.insert( fId );
2902       }
2903     }
2904   faceIdSet.insert( 0 ); // to smooth elements that are not on any TopoDS_Face
2905
2906   // ===============================================
2907   // smooth elements on each TopoDS_Face separately
2908   // ===============================================
2909
2910   set< int >::reverse_iterator fId = faceIdSet.rbegin(); // treate 0 fId at the end
2911   for ( ; fId != faceIdSet.rend(); ++fId ) {
2912     // get face surface and submesh
2913     Handle(Geom_Surface) surface;
2914     SMESHDS_SubMesh* faceSubMesh = 0;
2915     TopoDS_Face face;
2916     double fToler2 = 0, vPeriod = 0., uPeriod = 0., f,l;
2917     double u1 = 0, u2 = 0, v1 = 0, v2 = 0;
2918     bool isUPeriodic = false, isVPeriodic = false;
2919     if ( *fId ) {
2920       face = TopoDS::Face( aMesh->IndexToShape( *fId ));
2921       surface = BRep_Tool::Surface( face );
2922       faceSubMesh = aMesh->MeshElements( *fId );
2923       fToler2 = BRep_Tool::Tolerance( face );
2924       fToler2 *= fToler2 * 10.;
2925       isUPeriodic = surface->IsUPeriodic();
2926       if ( isUPeriodic )
2927         vPeriod = surface->UPeriod();
2928       isVPeriodic = surface->IsVPeriodic();
2929       if ( isVPeriodic )
2930         uPeriod = surface->VPeriod();
2931       surface->Bounds( u1, u2, v1, v2 );
2932     }
2933     // ---------------------------------------------------------
2934     // for elements on a face, find movable and fixed nodes and
2935     // compute UV for them
2936     // ---------------------------------------------------------
2937     bool checkBoundaryNodes = false;
2938     bool isQuadratic = false;
2939     set<const SMDS_MeshNode*> setMovableNodes;
2940     map< const SMDS_MeshNode*, gp_XY* > uvMap, uvMap2;
2941     list< gp_XY > listUV; // uvs the 2 uvMaps refer to
2942     list< const SMDS_MeshElement* > elemsOnFace;
2943
2944     Extrema_GenExtPS projector;
2945     GeomAdaptor_Surface surfAdaptor;
2946     if ( !surface.IsNull() ) {
2947       surfAdaptor.Load( surface );
2948       projector.Initialize( surfAdaptor, 20,20, 1e-5,1e-5 );
2949     }
2950     int nbElemOnFace = 0;
2951     itElem = theElems.begin();
2952     // loop on not yet smoothed elements: look for elems on a face
2953     while ( itElem != theElems.end() ) {
2954       if ( faceSubMesh && nbElemOnFace == faceSubMesh->NbElements() )
2955         break; // all elements found
2956
2957       const SMDS_MeshElement* elem = *itElem;
2958       if ( !elem || elem->GetType() != SMDSAbs_Face || elem->NbNodes() < 3 ||
2959            ( faceSubMesh && !faceSubMesh->Contains( elem ))) {
2960         ++itElem;
2961         continue;
2962       }
2963       elemsOnFace.push_back( elem );
2964       theElems.erase( itElem++ );
2965       nbElemOnFace++;
2966
2967       if ( !isQuadratic )
2968         isQuadratic = elem->IsQuadratic();
2969
2970       // get movable nodes of elem
2971       const SMDS_MeshNode* node;
2972       SMDS_TypeOfPosition posType;
2973       SMDS_ElemIteratorPtr itN = elem->nodesIterator();
2974       int nn = 0, nbn =  elem->NbNodes();
2975       if(elem->IsQuadratic())
2976         nbn = nbn/2;
2977       while ( nn++ < nbn ) {
2978         node = static_cast<const SMDS_MeshNode*>( itN->next() );
2979         const SMDS_PositionPtr& pos = node->GetPosition();
2980         posType = pos ? pos->GetTypeOfPosition() : SMDS_TOP_3DSPACE;
2981         if (posType != SMDS_TOP_EDGE &&
2982             posType != SMDS_TOP_VERTEX &&
2983             theFixedNodes.find( node ) == theFixedNodes.end())
2984         {
2985           // check if all faces around the node are on faceSubMesh
2986           // because a node on edge may be bound to face
2987           SMDS_ElemIteratorPtr eIt = node->GetInverseElementIterator(SMDSAbs_Face);
2988           bool all = true;
2989           if ( faceSubMesh ) {
2990             while ( eIt->more() && all ) {
2991               const SMDS_MeshElement* e = eIt->next();
2992               all = faceSubMesh->Contains( e );
2993             }
2994           }
2995           if ( all )
2996             setMovableNodes.insert( node );
2997           else
2998             checkBoundaryNodes = true;
2999         }
3000         if ( posType == SMDS_TOP_3DSPACE )
3001           checkBoundaryNodes = true;
3002       }
3003
3004       if ( surface.IsNull() )
3005         continue;
3006
3007       // get nodes to check UV
3008       list< const SMDS_MeshNode* > uvCheckNodes;
3009       itN = elem->nodesIterator();
3010       nn = 0; nbn =  elem->NbNodes();
3011       if(elem->IsQuadratic())
3012         nbn = nbn/2;
3013       while ( nn++ < nbn ) {
3014         node = static_cast<const SMDS_MeshNode*>( itN->next() );
3015         if ( uvMap.find( node ) == uvMap.end() )
3016           uvCheckNodes.push_back( node );
3017         // add nodes of elems sharing node
3018         //         SMDS_ElemIteratorPtr eIt = node->GetInverseElementIterator(SMDSAbs_Face);
3019         //         while ( eIt->more() ) {
3020         //           const SMDS_MeshElement* e = eIt->next();
3021         //           if ( e != elem ) {
3022         //             SMDS_ElemIteratorPtr nIt = e->nodesIterator();
3023         //             while ( nIt->more() ) {
3024         //               const SMDS_MeshNode* n =
3025         //                 static_cast<const SMDS_MeshNode*>( nIt->next() );
3026         //               if ( uvMap.find( n ) == uvMap.end() )
3027         //                 uvCheckNodes.push_back( n );
3028         //             }
3029         //           }
3030         //         }
3031       }
3032       // check UV on face
3033       list< const SMDS_MeshNode* >::iterator n = uvCheckNodes.begin();
3034       for ( ; n != uvCheckNodes.end(); ++n ) {
3035         node = *n;
3036         gp_XY uv( 0, 0 );
3037         const SMDS_PositionPtr& pos = node->GetPosition();
3038         posType = pos ? pos->GetTypeOfPosition() : SMDS_TOP_3DSPACE;
3039         // get existing UV
3040         switch ( posType ) {
3041         case SMDS_TOP_FACE: {
3042           SMDS_FacePosition* fPos = ( SMDS_FacePosition* ) pos;
3043           uv.SetCoord( fPos->GetUParameter(), fPos->GetVParameter() );
3044           break;
3045         }
3046         case SMDS_TOP_EDGE: {
3047           TopoDS_Shape S = aMesh->IndexToShape( node->getshapeId() );
3048           Handle(Geom2d_Curve) pcurve;
3049           if ( !S.IsNull() && S.ShapeType() == TopAbs_EDGE )
3050             pcurve = BRep_Tool::CurveOnSurface( TopoDS::Edge( S ), face, f,l );
3051           if ( !pcurve.IsNull() ) {
3052             double u = (( SMDS_EdgePosition* ) pos )->GetUParameter();
3053             uv = pcurve->Value( u ).XY();
3054           }
3055           break;
3056         }
3057         case SMDS_TOP_VERTEX: {
3058           TopoDS_Shape S = aMesh->IndexToShape( node->getshapeId() );
3059           if ( !S.IsNull() && S.ShapeType() == TopAbs_VERTEX )
3060             uv = BRep_Tool::Parameters( TopoDS::Vertex( S ), face ).XY();
3061           break;
3062         }
3063         default:;
3064         }
3065         // check existing UV
3066         bool project = true;
3067         gp_Pnt pNode ( node->X(), node->Y(), node->Z() );
3068         double dist1 = DBL_MAX, dist2 = 0;
3069         if ( posType != SMDS_TOP_3DSPACE ) {
3070           dist1 = pNode.SquareDistance( surface->Value( uv.X(), uv.Y() ));
3071           project = dist1 > fToler2;
3072         }
3073         if ( project ) { // compute new UV
3074           gp_XY newUV;
3075           if ( !getClosestUV( projector, pNode, newUV )) {
3076             MESSAGE("Node Projection Failed " << node);
3077           }
3078           else {
3079             if ( isUPeriodic )
3080               newUV.SetX( ElCLib::InPeriod( newUV.X(), u1, u2 ));
3081             if ( isVPeriodic )
3082               newUV.SetY( ElCLib::InPeriod( newUV.Y(), v1, v2 ));
3083             // check new UV
3084             if ( posType != SMDS_TOP_3DSPACE )
3085               dist2 = pNode.SquareDistance( surface->Value( newUV.X(), newUV.Y() ));
3086             if ( dist2 < dist1 )
3087               uv = newUV;
3088           }
3089         }
3090         // store UV in the map
3091         listUV.push_back( uv );
3092         uvMap.insert( make_pair( node, &listUV.back() ));
3093       }
3094     } // loop on not yet smoothed elements
3095
3096     if ( !faceSubMesh || nbElemOnFace != faceSubMesh->NbElements() )
3097       checkBoundaryNodes = true;
3098
3099     // fix nodes on mesh boundary
3100
3101     if ( checkBoundaryNodes ) {
3102       map< NLink, int > linkNbMap; // how many times a link encounters in elemsOnFace
3103       map< NLink, int >::iterator link_nb;
3104       // put all elements links to linkNbMap
3105       list< const SMDS_MeshElement* >::iterator elemIt = elemsOnFace.begin();
3106       for ( ; elemIt != elemsOnFace.end(); ++elemIt ) {
3107         const SMDS_MeshElement* elem = (*elemIt);
3108         int nbn =  elem->NbNodes();
3109         if(elem->IsQuadratic())
3110           nbn = nbn/2;
3111         // loop on elem links: insert them in linkNbMap
3112         const SMDS_MeshNode* curNode, *prevNode = elem->GetNodeWrap( nbn );
3113         for ( int iN = 0; iN < nbn; ++iN ) {
3114           curNode = elem->GetNode( iN );
3115           NLink link;
3116           if ( curNode < prevNode ) link = make_pair( curNode , prevNode );
3117           else                      link = make_pair( prevNode , curNode );
3118           prevNode = curNode;
3119           link_nb = linkNbMap.find( link );
3120           if ( link_nb == linkNbMap.end() )
3121             linkNbMap.insert( make_pair ( link, 1 ));
3122           else
3123             link_nb->second++;
3124         }
3125       }
3126       // remove nodes that are in links encountered only once from setMovableNodes
3127       for ( link_nb = linkNbMap.begin(); link_nb != linkNbMap.end(); ++link_nb ) {
3128         if ( link_nb->second == 1 ) {
3129           setMovableNodes.erase( link_nb->first.first );
3130           setMovableNodes.erase( link_nb->first.second );
3131         }
3132       }
3133     }
3134
3135     // -----------------------------------------------------
3136     // for nodes on seam edge, compute one more UV ( uvMap2 );
3137     // find movable nodes linked to nodes on seam and which
3138     // are to be smoothed using the second UV ( uvMap2 )
3139     // -----------------------------------------------------
3140
3141     set<const SMDS_MeshNode*> nodesNearSeam; // to smooth using uvMap2
3142     if ( !surface.IsNull() ) {
3143       TopExp_Explorer eExp( face, TopAbs_EDGE );
3144       for ( ; eExp.More(); eExp.Next() ) {
3145         TopoDS_Edge edge = TopoDS::Edge( eExp.Current() );
3146         if ( !BRep_Tool::IsClosed( edge, face ))
3147           continue;
3148         SMESHDS_SubMesh* sm = aMesh->MeshElements( edge );
3149         if ( !sm ) continue;
3150         // find out which parameter varies for a node on seam
3151         double f,l;
3152         gp_Pnt2d uv1, uv2;
3153         Handle(Geom2d_Curve) pcurve = BRep_Tool::CurveOnSurface( edge, face, f, l );
3154         if ( pcurve.IsNull() ) continue;
3155         uv1 = pcurve->Value( f );
3156         edge.Reverse();
3157         pcurve = BRep_Tool::CurveOnSurface( edge, face, f, l );
3158         if ( pcurve.IsNull() ) continue;
3159         uv2 = pcurve->Value( f );
3160         int iPar = Abs( uv1.X() - uv2.X() ) > Abs( uv1.Y() - uv2.Y() ) ? 1 : 2;
3161         // assure uv1 < uv2
3162         if ( uv1.Coord( iPar ) > uv2.Coord( iPar )) {
3163           gp_Pnt2d tmp = uv1; uv1 = uv2; uv2 = tmp;
3164         }
3165         // get nodes on seam and its vertices
3166         list< const SMDS_MeshNode* > seamNodes;
3167         SMDS_NodeIteratorPtr nSeamIt = sm->GetNodes();
3168         while ( nSeamIt->more() ) {
3169           const SMDS_MeshNode* node = nSeamIt->next();
3170           if ( !isQuadratic || !IsMedium( node ))
3171             seamNodes.push_back( node );
3172         }
3173         TopExp_Explorer vExp( edge, TopAbs_VERTEX );
3174         for ( ; vExp.More(); vExp.Next() ) {
3175           sm = aMesh->MeshElements( vExp.Current() );
3176           if ( sm ) {
3177             nSeamIt = sm->GetNodes();
3178             while ( nSeamIt->more() )
3179               seamNodes.push_back( nSeamIt->next() );
3180           }
3181         }
3182         // loop on nodes on seam
3183         list< const SMDS_MeshNode* >::iterator noSeIt = seamNodes.begin();
3184         for ( ; noSeIt != seamNodes.end(); ++noSeIt ) {
3185           const SMDS_MeshNode* nSeam = *noSeIt;
3186           map< const SMDS_MeshNode*, gp_XY* >::iterator n_uv = uvMap.find( nSeam );
3187           if ( n_uv == uvMap.end() )
3188             continue;
3189           // set the first UV
3190           n_uv->second->SetCoord( iPar, uv1.Coord( iPar ));
3191           // set the second UV
3192           listUV.push_back( *n_uv->second );
3193           listUV.back().SetCoord( iPar, uv2.Coord( iPar ));
3194           if ( uvMap2.empty() )
3195             uvMap2 = uvMap; // copy the uvMap contents
3196           uvMap2[ nSeam ] = &listUV.back();
3197
3198           // collect movable nodes linked to ones on seam in nodesNearSeam
3199           SMDS_ElemIteratorPtr eIt = nSeam->GetInverseElementIterator(SMDSAbs_Face);
3200           while ( eIt->more() ) {
3201             const SMDS_MeshElement* e = eIt->next();
3202             int nbUseMap1 = 0, nbUseMap2 = 0;
3203             SMDS_ElemIteratorPtr nIt = e->nodesIterator();
3204             int nn = 0, nbn =  e->NbNodes();
3205             if(e->IsQuadratic()) nbn = nbn/2;
3206             while ( nn++ < nbn )
3207             {
3208               const SMDS_MeshNode* n =
3209                 static_cast<const SMDS_MeshNode*>( nIt->next() );
3210               if (n == nSeam ||
3211                   setMovableNodes.find( n ) == setMovableNodes.end() )
3212                 continue;
3213               // add only nodes being closer to uv2 than to uv1
3214               gp_Pnt pMid (0.5 * ( n->X() + nSeam->X() ),
3215                            0.5 * ( n->Y() + nSeam->Y() ),
3216                            0.5 * ( n->Z() + nSeam->Z() ));
3217               gp_XY uv;
3218               getClosestUV( projector, pMid, uv );
3219               if ( uv.Coord( iPar ) > uvMap[ n ]->Coord( iPar ) ) {
3220                 nodesNearSeam.insert( n );
3221                 nbUseMap2++;
3222               }
3223               else
3224                 nbUseMap1++;
3225             }
3226             // for centroidalSmooth all element nodes must
3227             // be on one side of a seam
3228             if ( theSmoothMethod == CENTROIDAL && nbUseMap1 && nbUseMap2 ) {
3229               SMDS_ElemIteratorPtr nIt = e->nodesIterator();
3230               nn = 0;
3231               while ( nn++ < nbn ) {
3232                 const SMDS_MeshNode* n =
3233                   static_cast<const SMDS_MeshNode*>( nIt->next() );
3234                 setMovableNodes.erase( n );
3235               }
3236             }
3237           }
3238         } // loop on nodes on seam
3239       } // loop on edge of a face
3240     } // if ( !face.IsNull() )
3241
3242     if ( setMovableNodes.empty() ) {
3243       MESSAGE( "Face id : " << *fId << " - NO SMOOTHING: no nodes to move!!!");
3244       continue; // goto next face
3245     }
3246
3247     // -------------
3248     // SMOOTHING //
3249     // -------------
3250
3251     int it = -1;
3252     double maxRatio = -1., maxDisplacement = -1.;
3253     set<const SMDS_MeshNode*>::iterator nodeToMove;
3254     for ( it = 0; it < theNbIterations; it++ ) {
3255       maxDisplacement = 0.;
3256       nodeToMove = setMovableNodes.begin();
3257       for ( ; nodeToMove != setMovableNodes.end(); nodeToMove++ ) {
3258         const SMDS_MeshNode* node = (*nodeToMove);
3259         gp_XYZ aPrevPos ( node->X(), node->Y(), node->Z() );
3260
3261         // smooth
3262         bool map2 = ( nodesNearSeam.find( node ) != nodesNearSeam.end() );
3263         if ( theSmoothMethod == LAPLACIAN )
3264           laplacianSmooth( node, surface, map2 ? uvMap2 : uvMap );
3265         else
3266           centroidalSmooth( node, surface, map2 ? uvMap2 : uvMap );
3267
3268         // node displacement
3269         gp_XYZ aNewPos ( node->X(), node->Y(), node->Z() );
3270         Standard_Real aDispl = (aPrevPos - aNewPos).SquareModulus();
3271         if ( aDispl > maxDisplacement )
3272           maxDisplacement = aDispl;
3273       }
3274       // no node movement => exit
3275       //if ( maxDisplacement < 1.e-16 ) {
3276       if ( maxDisplacement < disttol ) {
3277         MESSAGE("-- no node movement --");
3278         break;
3279       }
3280
3281       // check elements quality
3282       maxRatio  = 0;
3283       list< const SMDS_MeshElement* >::iterator elemIt = elemsOnFace.begin();
3284       for ( ; elemIt != elemsOnFace.end(); ++elemIt ) {
3285         const SMDS_MeshElement* elem = (*elemIt);
3286         if ( !elem || elem->GetType() != SMDSAbs_Face )
3287           continue;
3288         SMESH::Controls::TSequenceOfXYZ aPoints;
3289         if ( aQualityFunc.GetPoints( elem, aPoints )) {
3290           double aValue = aQualityFunc.GetValue( aPoints );
3291           if ( aValue > maxRatio )
3292             maxRatio = aValue;
3293         }
3294       }
3295       if ( maxRatio <= theTgtAspectRatio ) {
3296         MESSAGE("-- quality achived --");
3297         break;
3298       }
3299       if (it+1 == theNbIterations) {
3300         MESSAGE("-- Iteration limit exceeded --");
3301       }
3302     } // smoothing iterations
3303
3304     MESSAGE(" Face id: " << *fId <<
3305             " Nb iterstions: " << it <<
3306             " Displacement: " << maxDisplacement <<
3307             " Aspect Ratio " << maxRatio);
3308
3309     // ---------------------------------------
3310     // new nodes positions are computed,
3311     // record movement in DS and set new UV
3312     // ---------------------------------------
3313     nodeToMove = setMovableNodes.begin();
3314     for ( ; nodeToMove != setMovableNodes.end(); nodeToMove++ ) {
3315       SMDS_MeshNode* node = const_cast< SMDS_MeshNode* > (*nodeToMove);
3316       aMesh->MoveNode( node, node->X(), node->Y(), node->Z() );
3317       map< const SMDS_MeshNode*, gp_XY* >::iterator node_uv = uvMap.find( node );
3318       if ( node_uv != uvMap.end() ) {
3319         gp_XY* uv = node_uv->second;
3320         node->SetPosition
3321           ( SMDS_PositionPtr( new SMDS_FacePosition( uv->X(), uv->Y() )));
3322       }
3323     }
3324
3325     // move medium nodes of quadratic elements
3326     if ( isQuadratic )
3327     {
3328       SMESH_MesherHelper helper( *GetMesh() );
3329       if ( !face.IsNull() )
3330         helper.SetSubShape( face );
3331       list< const SMDS_MeshElement* >::iterator elemIt = elemsOnFace.begin();
3332       for ( ; elemIt != elemsOnFace.end(); ++elemIt ) {
3333         const SMDS_VtkFace* QF =
3334           dynamic_cast<const SMDS_VtkFace*> (*elemIt);
3335         if(QF && QF->IsQuadratic()) {
3336           vector<const SMDS_MeshNode*> Ns;
3337           Ns.reserve(QF->NbNodes()+1);
3338           SMDS_ElemIteratorPtr anIter = QF->interlacedNodesElemIterator();
3339           while ( anIter->more() )
3340             Ns.push_back( cast2Node(anIter->next()) );
3341           Ns.push_back( Ns[0] );
3342           double x, y, z;
3343           for(int i=0; i<QF->NbNodes(); i=i+2) {
3344             if ( !surface.IsNull() ) {
3345               gp_XY uv1 = helper.GetNodeUV( face, Ns[i], Ns[i+2] );
3346               gp_XY uv2 = helper.GetNodeUV( face, Ns[i+2], Ns[i] );
3347               gp_XY uv = ( uv1 + uv2 ) / 2.;
3348               gp_Pnt xyz = surface->Value( uv.X(), uv.Y() );
3349               x = xyz.X(); y = xyz.Y(); z = xyz.Z();
3350             }
3351             else {
3352               x = (Ns[i]->X() + Ns[i+2]->X())/2;
3353               y = (Ns[i]->Y() + Ns[i+2]->Y())/2;
3354               z = (Ns[i]->Z() + Ns[i+2]->Z())/2;
3355             }
3356             if( fabs( Ns[i+1]->X() - x ) > disttol ||
3357                 fabs( Ns[i+1]->Y() - y ) > disttol ||
3358                 fabs( Ns[i+1]->Z() - z ) > disttol ) {
3359               // we have to move i+1 node
3360               aMesh->MoveNode( Ns[i+1], x, y, z );
3361             }
3362           }
3363         }
3364       }
3365     }
3366
3367   } // loop on face ids
3368
3369 }
3370
3371 //=======================================================================
3372 //function : isReverse
3373 //purpose  : Return true if normal of prevNodes is not co-directied with
3374 //           gp_Vec(prevNodes[iNotSame],nextNodes[iNotSame]).
3375 //           iNotSame is where prevNodes and nextNodes are different
3376 //=======================================================================
3377
3378 static bool isReverse(vector<const SMDS_MeshNode*> prevNodes,
3379                       vector<const SMDS_MeshNode*> nextNodes,
3380                       const int            nbNodes,
3381                       const int            iNotSame)
3382 {
3383   int iBeforeNotSame = ( iNotSame == 0 ? nbNodes - 1 : iNotSame - 1 );
3384   int iAfterNotSame  = ( iNotSame + 1 == nbNodes ? 0 : iNotSame + 1 );
3385
3386   const SMDS_MeshNode* nB = prevNodes[ iBeforeNotSame ];
3387   const SMDS_MeshNode* nA = prevNodes[ iAfterNotSame ];
3388   const SMDS_MeshNode* nP = prevNodes[ iNotSame ];
3389   const SMDS_MeshNode* nN = nextNodes[ iNotSame ];
3390
3391   gp_Pnt pB ( nB->X(), nB->Y(), nB->Z() );
3392   gp_Pnt pA ( nA->X(), nA->Y(), nA->Z() );
3393   gp_Pnt pP ( nP->X(), nP->Y(), nP->Z() );
3394   gp_Pnt pN ( nN->X(), nN->Y(), nN->Z() );
3395
3396   gp_Vec vB ( pP, pB ), vA ( pP, pA ), vN ( pP, pN );
3397
3398   return (vA ^ vB) * vN < 0.0;
3399 }
3400
3401 //=======================================================================
3402 /*!
3403  * \brief Create elements by sweeping an element
3404  * \param elem - element to sweep
3405  * \param newNodesItVec - nodes generated from each node of the element
3406  * \param newElems - generated elements
3407  * \param nbSteps - number of sweeping steps
3408  * \param srcElements - to append elem for each generated element
3409  */
3410 //=======================================================================
3411
3412 void SMESH_MeshEditor::sweepElement(const SMDS_MeshElement*               elem,
3413                                     const vector<TNodeOfNodeListMapItr> & newNodesItVec,
3414                                     list<const SMDS_MeshElement*>&        newElems,
3415                                     const int                             nbSteps,
3416                                     SMESH_SequenceOfElemPtr&              srcElements)
3417 {
3418   //MESSAGE("sweepElement " << nbSteps);
3419   SMESHDS_Mesh* aMesh = GetMeshDS();
3420
3421   // Loop on elem nodes:
3422   // find new nodes and detect same nodes indices
3423   int nbNodes = elem->NbNodes();
3424   vector < list< const SMDS_MeshNode* >::const_iterator > itNN( nbNodes );
3425   vector<const SMDS_MeshNode*> prevNod( nbNodes );
3426   vector<const SMDS_MeshNode*> nextNod( nbNodes );
3427   vector<const SMDS_MeshNode*> midlNod( nbNodes );
3428
3429   int iNode, nbSame = 0, iNotSameNode = 0, iSameNode = 0;
3430   vector<int> sames(nbNodes);
3431   vector<bool> issimple(nbNodes);
3432
3433   for ( iNode = 0; iNode < nbNodes; iNode++ ) {
3434     TNodeOfNodeListMapItr nnIt = newNodesItVec[ iNode ];
3435     const SMDS_MeshNode*                 node         = nnIt->first;
3436     const list< const SMDS_MeshNode* > & listNewNodes = nnIt->second;
3437     if ( listNewNodes.empty() ) {
3438       return;
3439     }
3440
3441     issimple[iNode] = (listNewNodes.size()==nbSteps); // is node medium
3442
3443     itNN[ iNode ] = listNewNodes.begin();
3444     prevNod[ iNode ] = node;
3445     nextNod[ iNode ] = listNewNodes.front();
3446     if( !elem->IsQuadratic() || !issimple[iNode] ) {
3447       if ( prevNod[ iNode ] != nextNod [ iNode ])
3448         iNotSameNode = iNode;
3449       else {
3450         iSameNode = iNode;
3451         //nbSame++;
3452         sames[nbSame++] = iNode;
3453       }
3454     }
3455   }
3456
3457   //cerr<<"  nbSame = "<<nbSame<<endl;
3458   if ( nbSame == nbNodes || nbSame > 2) {
3459     MESSAGE( " Too many same nodes of element " << elem->GetID() );
3460     //INFOS( " Too many same nodes of element " << elem->GetID() );
3461     return;
3462   }
3463
3464   //  if( elem->IsQuadratic() && nbSame>0 ) {
3465   //    MESSAGE( "Can not rotate quadratic element " << elem->GetID() );
3466   //    return;
3467   //  }
3468
3469   int iBeforeSame = 0, iAfterSame = 0, iOpposSame = 0;
3470   int nbBaseNodes = ( elem->IsQuadratic() ? nbNodes/2 : nbNodes );
3471   if ( nbSame > 0 ) {
3472     iBeforeSame = ( iSameNode == 0 ? nbBaseNodes - 1 : iSameNode - 1 );
3473     iAfterSame  = ( iSameNode + 1 == nbBaseNodes ? 0 : iSameNode + 1 );
3474     iOpposSame  = ( iSameNode - 2 < 0  ? iSameNode + 2 : iSameNode - 2 );
3475   }
3476
3477   //if(nbNodes==8)
3478   //cout<<" prevNod[0]="<< prevNod[0]<<" prevNod[1]="<< prevNod[1]
3479   //    <<" prevNod[2]="<< prevNod[2]<<" prevNod[3]="<< prevNod[4]
3480   //    <<" prevNod[4]="<< prevNod[4]<<" prevNod[5]="<< prevNod[5]
3481   //    <<" prevNod[6]="<< prevNod[6]<<" prevNod[7]="<< prevNod[7]<<endl;
3482
3483   // check element orientation
3484   int i0 = 0, i2 = 2;
3485   if ( nbNodes > 2 && !isReverse( prevNod, nextNod, nbNodes, iNotSameNode )) {
3486     //MESSAGE("Reversed elem " << elem );
3487     i0 = 2;
3488     i2 = 0;
3489     if ( nbSame > 0 )
3490       std::swap( iBeforeSame, iAfterSame );
3491   }
3492
3493   // make new elements
3494   const SMDS_MeshElement* lastElem = elem;
3495   for (int iStep = 0; iStep < nbSteps; iStep++ ) {
3496     // get next nodes
3497     for ( iNode = 0; iNode < nbNodes; iNode++ ) {
3498       if(issimple[iNode]) {
3499         nextNod[ iNode ] = *itNN[ iNode ];
3500         itNN[ iNode ]++;
3501       }
3502       else {
3503         if( elem->GetType()==SMDSAbs_Node ) {
3504           // we have to use two nodes
3505           midlNod[ iNode ] = *itNN[ iNode ];
3506           itNN[ iNode ]++;
3507           nextNod[ iNode ] = *itNN[ iNode ];
3508           itNN[ iNode ]++;
3509         }
3510         else if(!elem->IsQuadratic() || lastElem->IsMediumNode(prevNod[iNode]) ) {
3511           // we have to use each second node
3512           //itNN[ iNode ]++;
3513           nextNod[ iNode ] = *itNN[ iNode ];
3514           itNN[ iNode ]++;
3515         }
3516         else {
3517           // we have to use two nodes
3518           midlNod[ iNode ] = *itNN[ iNode ];
3519           itNN[ iNode ]++;
3520           nextNod[ iNode ] = *itNN[ iNode ];
3521           itNN[ iNode ]++;
3522         }
3523       }
3524     }
3525     SMDS_MeshElement* aNewElem = 0;
3526     if(!elem->IsPoly()) {
3527       switch ( nbNodes ) {
3528       case 0:
3529         return;
3530       case 1: { // NODE
3531         if ( nbSame == 0 ) {
3532           if(issimple[0])
3533             aNewElem = aMesh->AddEdge( prevNod[ 0 ], nextNod[ 0 ] );
3534           else
3535             aNewElem = aMesh->AddEdge( prevNod[ 0 ], nextNod[ 0 ], midlNod[ 0 ] );
3536         }
3537         break;
3538       }
3539       case 2: { // EDGE
3540         if ( nbSame == 0 )
3541           aNewElem = aMesh->AddFace(prevNod[ 0 ], prevNod[ 1 ],
3542                                     nextNod[ 1 ], nextNod[ 0 ] );
3543         else
3544           aNewElem = aMesh->AddFace(prevNod[ 0 ], prevNod[ 1 ],
3545                                     nextNod[ iNotSameNode ] );
3546         break;
3547       }
3548
3549       case 3: { // TRIANGLE or quadratic edge
3550         if(elem->GetType() == SMDSAbs_Face) { // TRIANGLE
3551
3552           if ( nbSame == 0 )       // --- pentahedron
3553             aNewElem = aMesh->AddVolume (prevNod[ i0 ], prevNod[ 1 ], prevNod[ i2 ],
3554                                          nextNod[ i0 ], nextNod[ 1 ], nextNod[ i2 ] );
3555
3556           else if ( nbSame == 1 )  // --- pyramid
3557             aNewElem = aMesh->AddVolume (prevNod[ iBeforeSame ],  prevNod[ iAfterSame ],
3558                                          nextNod[ iAfterSame ], nextNod[ iBeforeSame ],
3559                                          nextNod[ iSameNode ]);
3560
3561           else // 2 same nodes:      --- tetrahedron
3562             aNewElem = aMesh->AddVolume (prevNod[ i0 ], prevNod[ 1 ], prevNod[ i2 ],
3563                                          nextNod[ iNotSameNode ]);
3564         }
3565         else { // quadratic edge
3566           if(nbSame==0) {     // quadratic quadrangle
3567             aNewElem = aMesh->AddFace(prevNod[0], nextNod[0], nextNod[1], prevNod[1],
3568                                       midlNod[0], nextNod[2], midlNod[1], prevNod[2]);
3569           }
3570           else if(nbSame==1) { // quadratic triangle
3571             if(sames[0]==2) {
3572               return; // medium node on axis
3573             }
3574             else if(sames[0]==0) {
3575               aNewElem = aMesh->AddFace(prevNod[0], nextNod[1], prevNod[1],
3576                                         nextNod[2], midlNod[1], prevNod[2]);
3577             }
3578             else { // sames[0]==1
3579               aNewElem = aMesh->AddFace(prevNod[0], nextNod[0], prevNod[1],
3580                                         midlNod[0], nextNod[2], prevNod[2]);
3581             }
3582           }
3583           else {
3584             return;
3585           }
3586         }
3587         break;
3588       }
3589       case 4: { // QUADRANGLE
3590
3591         if ( nbSame == 0 )       // --- hexahedron
3592           aNewElem = aMesh->AddVolume (prevNod[ i0 ], prevNod[ 1 ], prevNod[ i2 ], prevNod[ 3 ],
3593                                        nextNod[ i0 ], nextNod[ 1 ], nextNod[ i2 ], nextNod[ 3 ]);
3594
3595         else if ( nbSame == 1 ) { // --- pyramid + pentahedron
3596           aNewElem = aMesh->AddVolume (prevNod[ iBeforeSame ],  prevNod[ iAfterSame ],
3597                                        nextNod[ iAfterSame ], nextNod[ iBeforeSame ],
3598                                        nextNod[ iSameNode ]);
3599           newElems.push_back( aNewElem );
3600           aNewElem = aMesh->AddVolume (prevNod[ iAfterSame ], prevNod[ iOpposSame ],
3601                                        prevNod[ iBeforeSame ],  nextNod[ iAfterSame ],
3602                                        nextNod[ iOpposSame ],  nextNod[ iBeforeSame ] );
3603         }
3604         else if ( nbSame == 2 ) { // pentahedron
3605           if ( prevNod[ iBeforeSame ] == nextNod[ iBeforeSame ] )
3606             // iBeforeSame is same too
3607             aNewElem = aMesh->AddVolume (prevNod[ iBeforeSame ], prevNod[ iOpposSame ],
3608                                          nextNod[ iOpposSame ], prevNod[ iSameNode ],
3609                                          prevNod[ iAfterSame ],  nextNod[ iAfterSame ]);
3610           else
3611             // iAfterSame is same too
3612             aNewElem = aMesh->AddVolume (prevNod[ iSameNode ], prevNod[ iBeforeSame ],
3613                                          nextNod[ iBeforeSame ], prevNod[ iAfterSame ],
3614                                          prevNod[ iOpposSame ],  nextNod[ iOpposSame ]);
3615         }
3616         break;
3617       }
3618       case 6: { // quadratic triangle
3619         // create pentahedron with 15 nodes
3620         if(nbSame==0) {
3621           if(i0>0) { // reversed case
3622             aNewElem = aMesh->AddVolume (prevNod[0], prevNod[2], prevNod[1],
3623                                          nextNod[0], nextNod[2], nextNod[1],
3624                                          prevNod[5], prevNod[4], prevNod[3],
3625                                          nextNod[5], nextNod[4], nextNod[3],
3626                                          midlNod[0], midlNod[2], midlNod[1]);
3627           }
3628           else { // not reversed case
3629             aNewElem = aMesh->AddVolume (prevNod[0], prevNod[1], prevNod[2],
3630                                          nextNod[0], nextNod[1], nextNod[2],
3631                                          prevNod[3], prevNod[4], prevNod[5],
3632                                          nextNod[3], nextNod[4], nextNod[5],
3633                                          midlNod[0], midlNod[1], midlNod[2]);
3634           }
3635         }
3636         else if(nbSame==1) {
3637           // 2d order pyramid of 13 nodes
3638           //SMDS_MeshVolume* AddVolumeWithID(int n1, int n2, int n3, int n4, int n5,
3639           //                                 int n12,int n23,int n34,int n41,
3640           //                                 int n15,int n25,int n35,int n45, int ID);
3641           int n5 = iSameNode;
3642           int n1,n4,n41,n15,n45;
3643           if(i0>0) { // reversed case
3644             n1 = ( n5 + 1 == nbBaseNodes ? 0 : n5 + 1 );
3645             n4 = ( n5 == 0 ? nbBaseNodes - 1 : n5 - 1 );
3646             n41 = n1 + 3;
3647             n15 = n5 + 3;
3648             n45 = n4 + 3;
3649           }
3650           else {
3651             n1 = ( n5 == 0 ? nbBaseNodes - 1 : n5 - 1 );
3652             n4 = ( n5 + 1 == nbBaseNodes ? 0 : n5 + 1 );
3653             n41 = n4 + 3;
3654             n15 = n1 + 3;
3655             n45 = n5 + 3;
3656           }
3657           aNewElem = aMesh->AddVolume(prevNod[n1], nextNod[n1],
3658                                       nextNod[n4], prevNod[n4], prevNod[n5],
3659                                       midlNod[n1], nextNod[n41],
3660                                       midlNod[n4], prevNod[n41],
3661                                       prevNod[n15], nextNod[n15],
3662                                       nextNod[n45], prevNod[n45]);
3663         }
3664         else if(nbSame==2) {
3665           // 2d order tetrahedron of 10 nodes
3666           //SMDS_MeshVolume* AddVolumeWithID(int n1, int n2, int n3, int n4,
3667           //                                 int n12,int n23,int n31,
3668           //                                 int n14,int n24,int n34, int ID);
3669           int n1 = iNotSameNode;
3670           int n2,n3,n12,n23,n31;
3671           if(i0>0) { // reversed case
3672             n2 = ( n1 == 0 ? nbBaseNodes - 1 : n1 - 1 );
3673             n3 = ( n1 + 1 == nbBaseNodes ? 0 : n1 + 1 );
3674             n12 = n2 + 3;
3675             n23 = n3 + 3;
3676             n31 = n1 + 3;
3677           }
3678           else {
3679             n2 = ( n1 + 1 == nbBaseNodes ? 0 : n1 + 1 );
3680             n3 = ( n1 == 0 ? nbBaseNodes - 1 : n1 - 1 );
3681             n12 = n1 + 3;
3682             n23 = n2 + 3;
3683             n31 = n3 + 3;
3684           }
3685           aNewElem = aMesh->AddVolume (prevNod[n1], prevNod[n2], prevNod[n3], nextNod[n1],
3686                                        prevNod[n12], prevNod[n23], prevNod[n31],
3687                                        midlNod[n1], nextNod[n12], nextNod[n31]);
3688         }
3689         break;
3690       }
3691       case 8: { // quadratic quadrangle
3692         if(nbSame==0) {
3693           // create hexahedron with 20 nodes
3694           if(i0>0) { // reversed case
3695             aNewElem = aMesh->AddVolume (prevNod[0], prevNod[3], prevNod[2], prevNod[1],
3696                                          nextNod[0], nextNod[3], nextNod[2], nextNod[1],
3697                                          prevNod[7], prevNod[6], prevNod[5], prevNod[4],
3698                                          nextNod[7], nextNod[6], nextNod[5], nextNod[4],
3699                                          midlNod[0], midlNod[3], midlNod[2], midlNod[1]);
3700           }
3701           else { // not reversed case
3702             aNewElem = aMesh->AddVolume (prevNod[0], prevNod[1], prevNod[2], prevNod[3],
3703                                          nextNod[0], nextNod[1], nextNod[2], nextNod[3],
3704                                          prevNod[4], prevNod[5], prevNod[6], prevNod[7],
3705                                          nextNod[4], nextNod[5], nextNod[6], nextNod[7],
3706                                          midlNod[0], midlNod[1], midlNod[2], midlNod[3]);
3707           }
3708         }
3709         else if(nbSame==1) { 
3710           // --- pyramid + pentahedron - can not be created since it is needed 
3711           // additional middle node ot the center of face
3712           INFOS( " Sweep for face " << elem->GetID() << " can not be created" );
3713           return;
3714         }
3715         else if(nbSame==2) {
3716           // 2d order Pentahedron with 15 nodes
3717           //SMDS_MeshVolume* AddVolumeWithID(int n1, int n2, int n3, int n4, int n5, int n6,
3718           //                                 int n12,int n23,int n31,int n45,int n56,int n64,
3719           //                                 int n14,int n25,int n36, int ID);
3720           int n1,n2,n4,n5;
3721           if ( prevNod[ iBeforeSame ] == nextNod[ iBeforeSame ] ) {
3722             // iBeforeSame is same too
3723             n1 = iBeforeSame;
3724             n2 = iOpposSame;
3725             n4 = iSameNode;
3726             n5 = iAfterSame;
3727           }
3728           else {
3729             // iAfterSame is same too
3730             n1 = iSameNode;
3731             n2 = iBeforeSame;
3732             n4 = iAfterSame;
3733             n5 = iOpposSame;
3734           }
3735           int n12,n45,n14,n25;
3736           if(i0>0) { //reversed case
3737             n12 = n1 + 4;
3738             n45 = n5 + 4;
3739             n14 = n4 + 4;
3740             n25 = n2 + 4;
3741           }
3742           else {
3743             n12 = n2 + 4;
3744             n45 = n4 + 4;
3745             n14 = n1 + 4;
3746             n25 = n5 + 4;
3747           }
3748           aNewElem = aMesh->AddVolume (prevNod[n1], prevNod[n2], nextNod[n2],
3749                                        prevNod[n4], prevNod[n5], nextNod[n5],
3750                                        prevNod[n12], midlNod[n2], nextNod[n12],
3751                                        prevNod[n45], midlNod[n5], nextNod[n45],
3752                                        prevNod[n14], prevNod[n25], nextNod[n25]);
3753         }
3754         break;
3755       }
3756       default: {
3757         // realized for extrusion only
3758         //vector<const SMDS_MeshNode*> polyedre_nodes (nbNodes*2 + 4*nbNodes);
3759         //vector<int> quantities (nbNodes + 2);
3760
3761         //quantities[0] = nbNodes; // bottom of prism
3762         //for (int inode = 0; inode < nbNodes; inode++) {
3763         //  polyedre_nodes[inode] = prevNod[inode];
3764         //}
3765
3766         //quantities[1] = nbNodes; // top of prism
3767         //for (int inode = 0; inode < nbNodes; inode++) {
3768         //  polyedre_nodes[nbNodes + inode] = nextNod[inode];
3769         //}
3770
3771         //for (int iface = 0; iface < nbNodes; iface++) {
3772         //  quantities[iface + 2] = 4;
3773         //  int inextface = (iface == nbNodes - 1) ? 0 : iface + 1;
3774         //  polyedre_nodes[2*nbNodes + 4*iface + 0] = prevNod[iface];
3775         //  polyedre_nodes[2*nbNodes + 4*iface + 1] = prevNod[inextface];
3776         //  polyedre_nodes[2*nbNodes + 4*iface + 2] = nextNod[inextface];
3777         //  polyedre_nodes[2*nbNodes + 4*iface + 3] = nextNod[iface];
3778         //}
3779         //aNewElem = aMesh->AddPolyhedralVolume (polyedre_nodes, quantities);
3780         break;
3781       }
3782       }
3783     }
3784
3785     if(!aNewElem) {
3786       // realized for extrusion only
3787       vector<const SMDS_MeshNode*> polyedre_nodes (nbNodes*2 + 4*nbNodes);
3788       vector<int> quantities (nbNodes + 2);
3789
3790       quantities[0] = nbNodes; // bottom of prism
3791       for (int inode = 0; inode < nbNodes; inode++) {
3792         polyedre_nodes[inode] = prevNod[inode];
3793       }
3794
3795       quantities[1] = nbNodes; // top of prism
3796       for (int inode = 0; inode < nbNodes; inode++) {
3797         polyedre_nodes[nbNodes + inode] = nextNod[inode];
3798       }
3799
3800       for (int iface = 0; iface < nbNodes; iface++) {
3801         quantities[iface + 2] = 4;
3802         int inextface = (iface == nbNodes - 1) ? 0 : iface + 1;
3803         polyedre_nodes[2*nbNodes + 4*iface + 0] = prevNod[iface];
3804         polyedre_nodes[2*nbNodes + 4*iface + 1] = prevNod[inextface];
3805         polyedre_nodes[2*nbNodes + 4*iface + 2] = nextNod[inextface];
3806         polyedre_nodes[2*nbNodes + 4*iface + 3] = nextNod[iface];
3807       }
3808       aNewElem = aMesh->AddPolyhedralVolume (polyedre_nodes, quantities);
3809     }
3810
3811     if ( aNewElem ) {
3812       newElems.push_back( aNewElem );
3813       myLastCreatedElems.Append(aNewElem);
3814       srcElements.Append( elem );
3815       lastElem = aNewElem;
3816     }
3817
3818     // set new prev nodes
3819     for ( iNode = 0; iNode < nbNodes; iNode++ )
3820       prevNod[ iNode ] = nextNod[ iNode ];
3821
3822   } // for steps
3823 }
3824
3825 //=======================================================================
3826 /*!
3827  * \brief Create 1D and 2D elements around swept elements
3828  * \param mapNewNodes - source nodes and ones generated from them
3829  * \param newElemsMap - source elements and ones generated from them
3830  * \param elemNewNodesMap - nodes generated from each node of each element
3831  * \param elemSet - all swept elements
3832  * \param nbSteps - number of sweeping steps
3833  * \param srcElements - to append elem for each generated element
3834  */
3835 //=======================================================================
3836
3837 void SMESH_MeshEditor::makeWalls (TNodeOfNodeListMap &     mapNewNodes,
3838                                   TElemOfElemListMap &     newElemsMap,
3839                                   TElemOfVecOfNnlmiMap &   elemNewNodesMap,
3840                                   TIDSortedElemSet&        elemSet,
3841                                   const int                nbSteps,
3842                                   SMESH_SequenceOfElemPtr& srcElements)
3843 {
3844   MESSAGE("makeWalls");
3845   ASSERT( newElemsMap.size() == elemNewNodesMap.size() );
3846   SMESHDS_Mesh* aMesh = GetMeshDS();
3847
3848   // Find nodes belonging to only one initial element - sweep them to get edges.
3849
3850   TNodeOfNodeListMapItr nList = mapNewNodes.begin();
3851   for ( ; nList != mapNewNodes.end(); nList++ ) {
3852     const SMDS_MeshNode* node =
3853       static_cast<const SMDS_MeshNode*>( nList->first );
3854     SMDS_ElemIteratorPtr eIt = node->GetInverseElementIterator();
3855     int nbInitElems = 0;
3856     const SMDS_MeshElement* el = 0;
3857     SMDSAbs_ElementType highType = SMDSAbs_Edge; // count most complex elements only
3858     while ( eIt->more() && nbInitElems < 2 ) {
3859       el = eIt->next();
3860       SMDSAbs_ElementType type = el->GetType();
3861       if ( type == SMDSAbs_Volume || type < highType ) continue;
3862       if ( type > highType ) {
3863         nbInitElems = 0;
3864         highType = type;
3865       }
3866       if ( elemSet.find(el) != elemSet.end() )
3867         nbInitElems++;
3868     }
3869     if ( nbInitElems < 2 ) {
3870       bool NotCreateEdge = el && el->IsQuadratic() && el->IsMediumNode(node);
3871       if(!NotCreateEdge) {
3872         vector<TNodeOfNodeListMapItr> newNodesItVec( 1, nList );
3873         list<const SMDS_MeshElement*> newEdges;
3874         sweepElement( node, newNodesItVec, newEdges, nbSteps, srcElements );
3875       }
3876     }
3877   }
3878
3879   // Make a ceiling for each element ie an equal element of last new nodes.
3880   // Find free links of faces - make edges and sweep them into faces.
3881
3882   TElemOfElemListMap::iterator   itElem      = newElemsMap.begin();
3883   TElemOfVecOfNnlmiMap::iterator itElemNodes = elemNewNodesMap.begin();
3884   for ( ; itElem != newElemsMap.end(); itElem++, itElemNodes++ ) {
3885     const SMDS_MeshElement* elem = itElem->first;
3886     vector<TNodeOfNodeListMapItr>& vecNewNodes = itElemNodes->second;
3887
3888     if ( elem->GetType() == SMDSAbs_Edge ) {
3889       // create a ceiling edge
3890       if (!elem->IsQuadratic()) {
3891         if ( !aMesh->FindEdge( vecNewNodes[ 0 ]->second.back(),
3892                                vecNewNodes[ 1 ]->second.back())) {
3893           myLastCreatedElems.Append(aMesh->AddEdge(vecNewNodes[ 0 ]->second.back(),
3894                                                    vecNewNodes[ 1 ]->second.back()));
3895           srcElements.Append( myLastCreatedElems.Last() );
3896         }
3897       }
3898       else {
3899         if ( !aMesh->FindEdge( vecNewNodes[ 0 ]->second.back(),
3900                                vecNewNodes[ 1 ]->second.back(),
3901                                vecNewNodes[ 2 ]->second.back())) {
3902           myLastCreatedElems.Append(aMesh->AddEdge(vecNewNodes[ 0 ]->second.back(),
3903                                                    vecNewNodes[ 1 ]->second.back(),
3904                                                    vecNewNodes[ 2 ]->second.back()));
3905           srcElements.Append( myLastCreatedElems.Last() );
3906         }
3907       }
3908     }
3909     if ( elem->GetType() != SMDSAbs_Face )
3910       continue;
3911
3912     if(itElem->second.size()==0) continue;
3913
3914     bool hasFreeLinks = false;
3915
3916     TIDSortedElemSet avoidSet;
3917     avoidSet.insert( elem );
3918
3919     set<const SMDS_MeshNode*> aFaceLastNodes;
3920     int iNode, nbNodes = vecNewNodes.size();
3921     if(!elem->IsQuadratic()) {
3922       // loop on the face nodes
3923       for ( iNode = 0; iNode < nbNodes; iNode++ ) {
3924         aFaceLastNodes.insert( vecNewNodes[ iNode ]->second.back() );
3925         // look for free links of the face
3926         int iNext = ( iNode + 1 == nbNodes ) ? 0 : iNode + 1;
3927         const SMDS_MeshNode* n1 = vecNewNodes[ iNode ]->first;
3928         const SMDS_MeshNode* n2 = vecNewNodes[ iNext ]->first;
3929         // check if a link is free
3930         if ( ! SMESH_MeshEditor::FindFaceInSet ( n1, n2, elemSet, avoidSet )) {
3931           hasFreeLinks = true;
3932           // make an edge and a ceiling for a new edge
3933           if ( !aMesh->FindEdge( n1, n2 )) {
3934             myLastCreatedElems.Append(aMesh->AddEdge( n1, n2 )); // free link edge
3935             srcElements.Append( myLastCreatedElems.Last() );
3936           }
3937           n1 = vecNewNodes[ iNode ]->second.back();
3938           n2 = vecNewNodes[ iNext ]->second.back();
3939           if ( !aMesh->FindEdge( n1, n2 )) {
3940             myLastCreatedElems.Append(aMesh->AddEdge( n1, n2 )); // ceiling edge
3941             srcElements.Append( myLastCreatedElems.Last() );
3942           }
3943         }
3944       }
3945     }
3946     else { // elem is quadratic face
3947       int nbn = nbNodes/2;
3948       for ( iNode = 0; iNode < nbn; iNode++ ) {
3949         aFaceLastNodes.insert( vecNewNodes[ iNode ]->second.back() );
3950         int iNext = ( iNode + 1 == nbn ) ? 0 : iNode + 1;
3951         const SMDS_MeshNode* n1 = vecNewNodes[ iNode ]->first;
3952         const SMDS_MeshNode* n2 = vecNewNodes[ iNext ]->first;
3953         // check if a link is free
3954         if ( ! SMESH_MeshEditor::FindFaceInSet ( n1, n2, elemSet, avoidSet )) {
3955           hasFreeLinks = true;
3956           // make an edge and a ceiling for a new edge
3957           // find medium node
3958           const SMDS_MeshNode* n3 = vecNewNodes[ iNode+nbn ]->first;
3959           if ( !aMesh->FindEdge( n1, n2, n3 )) {
3960             myLastCreatedElems.Append(aMesh->AddEdge( n1, n2, n3 )); // free link edge
3961             srcElements.Append( myLastCreatedElems.Last() );
3962           }
3963           n1 = vecNewNodes[ iNode ]->second.back();
3964           n2 = vecNewNodes[ iNext ]->second.back();
3965           n3 = vecNewNodes[ iNode+nbn ]->second.back();
3966           if ( !aMesh->FindEdge( n1, n2, n3 )) {
3967             myLastCreatedElems.Append(aMesh->AddEdge( n1, n2, n3 )); // ceiling edge
3968             srcElements.Append( myLastCreatedElems.Last() );
3969           }
3970         }
3971       }
3972       for ( iNode = nbn; iNode < 2*nbn; iNode++ ) {
3973         aFaceLastNodes.insert( vecNewNodes[ iNode ]->second.back() );
3974       }
3975     }
3976
3977     // sweep free links into faces
3978
3979     if ( hasFreeLinks )  {
3980       list<const SMDS_MeshElement*> & newVolumes = itElem->second;
3981       int iVol, volNb, nbVolumesByStep = newVolumes.size() / nbSteps;
3982
3983       set<const SMDS_MeshNode*> initNodeSet, topNodeSet, faceNodeSet;
3984       for ( iNode = 0; iNode < nbNodes; iNode++ ) {
3985         initNodeSet.insert( vecNewNodes[ iNode ]->first );
3986         topNodeSet .insert( vecNewNodes[ iNode ]->second.back() );
3987       }
3988       for ( volNb = 0; volNb < nbVolumesByStep; volNb++ ) {
3989         list<const SMDS_MeshElement*>::iterator v = newVolumes.begin();
3990         iVol = 0;
3991         while ( iVol++ < volNb ) v++;
3992         // find indices of free faces of a volume and their source edges
3993         list< int > freeInd;
3994         list< const SMDS_MeshElement* > srcEdges; // source edges of free faces
3995         SMDS_VolumeTool vTool( *v );
3996         int iF, nbF = vTool.NbFaces();
3997         for ( iF = 0; iF < nbF; iF ++ ) {
3998           if (vTool.IsFreeFace( iF ) &&
3999               vTool.GetFaceNodes( iF, faceNodeSet ) &&
4000               initNodeSet != faceNodeSet) // except an initial face
4001           {
4002             if ( nbSteps == 1 && faceNodeSet == topNodeSet )
4003               continue;
4004             freeInd.push_back( iF );
4005             // find source edge of a free face iF
4006             vector<const SMDS_MeshNode*> commonNodes; // shared by the initial and free faces
4007             commonNodes.resize( initNodeSet.size(), NULL ); // avoid spoiling memory
4008             std::set_intersection( faceNodeSet.begin(), faceNodeSet.end(),
4009                                    initNodeSet.begin(), initNodeSet.end(),
4010                                    commonNodes.begin());
4011             if ( (*v)->IsQuadratic() )
4012               srcEdges.push_back(aMesh->FindEdge (commonNodes[0],commonNodes[1],commonNodes[2]));
4013             else
4014               srcEdges.push_back(aMesh->FindEdge (commonNodes[0],commonNodes[1]));
4015 #ifdef _DEBUG_
4016             if ( !srcEdges.back() )
4017             {
4018               cout << "SMESH_MeshEditor::makeWalls(), no source edge found for a free face #"
4019                    << iF << " of volume #" << vTool.ID() << endl;
4020             }
4021 #endif
4022           }
4023         }
4024         if ( freeInd.empty() )
4025           continue;
4026
4027         // create faces for all steps;
4028         // if such a face has been already created by sweep of edge,
4029         // assure that its orientation is OK
4030         for ( int iStep = 0; iStep < nbSteps; iStep++ )  {
4031           vTool.Set( *v );
4032           vTool.SetExternalNormal();
4033           list< int >::iterator ind = freeInd.begin();
4034           list< const SMDS_MeshElement* >::iterator srcEdge = srcEdges.begin();
4035           for ( ; ind != freeInd.end(); ++ind, ++srcEdge ) // loop on free faces
4036           {
4037             const SMDS_MeshNode** nodes = vTool.GetFaceNodes( *ind );
4038             int nbn = vTool.NbFaceNodes( *ind );
4039             switch ( nbn ) {
4040             case 3: { ///// triangle
4041               const SMDS_MeshFace * f = aMesh->FindFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ]);
4042               if ( !f )
4043                 myLastCreatedElems.Append(aMesh->AddFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ] ));
4044               else if ( nodes[ 1 ] != f->GetNodeWrap( f->GetNodeIndex( nodes[ 0 ] ) + 1 ))
4045                 {
4046                   myLastCreatedElems.Append(aMesh->AddFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ] ));
4047                   aMesh->RemoveElement(f);
4048                 }
4049               break;
4050             }
4051             case 4: { ///// quadrangle
4052               const SMDS_MeshFace * f = aMesh->FindFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ], nodes[ 3 ]);
4053               if ( !f )
4054                 myLastCreatedElems.Append(aMesh->AddFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ], nodes[ 3 ] ));
4055               else if ( nodes[ 1 ] != f->GetNodeWrap( f->GetNodeIndex( nodes[ 0 ] ) + 1 ))
4056                 {
4057                   myLastCreatedElems.Append(aMesh->AddFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ], nodes[ 3 ] ));
4058                   aMesh->RemoveElement(f);
4059                 }
4060               break;
4061             }
4062             default:
4063               if( (*v)->IsQuadratic() ) {
4064                 if(nbn==6) { /////// quadratic triangle
4065                   const SMDS_MeshFace * f = aMesh->FindFace( nodes[0], nodes[2], nodes[4],
4066                                                              nodes[1], nodes[3], nodes[5] );
4067                   if ( !f ) {
4068                     myLastCreatedElems.Append(aMesh->AddFace(nodes[0], nodes[2], nodes[4],
4069                                                              nodes[1], nodes[3], nodes[5]));
4070                   }
4071                   else if ( nodes[ 2 ] != f->GetNodeWrap( f->GetNodeIndex( nodes[ 0 ] ) + 1 )) {
4072                     const SMDS_MeshNode** tmpnodes = new const SMDS_MeshNode*[6];
4073                     tmpnodes[0] = nodes[0];
4074                     tmpnodes[1] = nodes[2];
4075                     tmpnodes[2] = nodes[4];
4076                     tmpnodes[3] = nodes[1];
4077                     tmpnodes[4] = nodes[3];
4078                     tmpnodes[5] = nodes[5];
4079                     myLastCreatedElems.Append(aMesh->AddFace(nodes[0], nodes[2], nodes[4],
4080                                                              nodes[1], nodes[3], nodes[5]));
4081                     aMesh->RemoveElement(f);
4082                   }
4083                 }
4084                 else {       /////// quadratic quadrangle
4085                   const SMDS_MeshFace * f = aMesh->FindFace( nodes[0], nodes[2], nodes[4], nodes[6],
4086                                                              nodes[1], nodes[3], nodes[5], nodes[7] );
4087                   if ( !f ) {
4088                     myLastCreatedElems.Append(aMesh->AddFace(nodes[0], nodes[2], nodes[4], nodes[6],
4089                                                              nodes[1], nodes[3], nodes[5], nodes[7]));
4090                   }
4091                   else if ( nodes[ 2 ] != f->GetNodeWrap( f->GetNodeIndex( nodes[ 0 ] ) + 1 )) {
4092                     const SMDS_MeshNode** tmpnodes = new const SMDS_MeshNode*[8];
4093                     tmpnodes[0] = nodes[0];
4094                     tmpnodes[1] = nodes[2];
4095                     tmpnodes[2] = nodes[4];
4096                     tmpnodes[3] = nodes[6];
4097                     tmpnodes[4] = nodes[1];
4098                     tmpnodes[5] = nodes[3];
4099                     tmpnodes[6] = nodes[5];
4100                     tmpnodes[7] = nodes[7];
4101                     myLastCreatedElems.Append(aMesh->AddFace(nodes[0], nodes[2], nodes[4], nodes[6],
4102                                                              nodes[1], nodes[3], nodes[5], nodes[7]));
4103                     aMesh->RemoveElement(f);
4104                   }
4105                 }
4106               }
4107               else { //////// polygon
4108                 vector<const SMDS_MeshNode*> polygon_nodes ( nodes, &nodes[nbn] );
4109                 const SMDS_MeshFace * f = aMesh->FindFace( polygon_nodes );
4110                 if ( !f )
4111                   myLastCreatedElems.Append(aMesh->AddPolygonalFace(polygon_nodes));
4112                 else if ( nodes[ 1 ] != f->GetNodeWrap( f->GetNodeIndex( nodes[ 0 ] ) + 1 ))
4113                   {
4114                   // TODO problem ChangeElementNodes : not the same number of nodes, not the same type
4115                   MESSAGE("ChangeElementNodes");
4116                   aMesh->ChangeElementNodes( f, nodes, nbn );
4117                   }
4118               }
4119             }
4120             while ( srcElements.Length() < myLastCreatedElems.Length() )
4121               srcElements.Append( *srcEdge );
4122
4123           }  // loop on free faces
4124
4125           // go to the next volume
4126           iVol = 0;
4127           while ( iVol++ < nbVolumesByStep ) v++;
4128         }
4129       }
4130     } // sweep free links into faces
4131
4132     // Make a ceiling face with a normal external to a volume
4133
4134     SMDS_VolumeTool lastVol( itElem->second.back() );
4135
4136     int iF = lastVol.GetFaceIndex( aFaceLastNodes );
4137     if ( iF >= 0 ) {
4138       lastVol.SetExternalNormal();
4139       const SMDS_MeshNode** nodes = lastVol.GetFaceNodes( iF );
4140       int nbn = lastVol.NbFaceNodes( iF );
4141       switch ( nbn ) {
4142       case 3:
4143         if (!hasFreeLinks ||
4144             !aMesh->FindFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ]))
4145           myLastCreatedElems.Append(aMesh->AddFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ] ));
4146         break;
4147       case 4:
4148         if (!hasFreeLinks ||
4149             !aMesh->FindFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ], nodes[ 3 ]))
4150           myLastCreatedElems.Append(aMesh->AddFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ], nodes[ 3 ] ));
4151         break;
4152       default:
4153         if(itElem->second.back()->IsQuadratic()) {
4154           if(nbn==6) {
4155             if (!hasFreeLinks ||
4156                 !aMesh->FindFace(nodes[0], nodes[2], nodes[4],
4157                                  nodes[1], nodes[3], nodes[5]) ) {
4158               myLastCreatedElems.Append(aMesh->AddFace(nodes[0], nodes[2], nodes[4],
4159                                                        nodes[1], nodes[3], nodes[5]));
4160             }
4161           }
4162           else { // nbn==8
4163             if (!hasFreeLinks ||
4164                 !aMesh->FindFace(nodes[0], nodes[2], nodes[4], nodes[6],
4165                                  nodes[1], nodes[3], nodes[5], nodes[7]) )
4166               myLastCreatedElems.Append(aMesh->AddFace(nodes[0], nodes[2], nodes[4], nodes[6],
4167                                                        nodes[1], nodes[3], nodes[5], nodes[7]));
4168           }
4169         }
4170         else {
4171           vector<const SMDS_MeshNode*> polygon_nodes ( nodes, &nodes[nbn] );
4172           if (!hasFreeLinks || !aMesh->FindFace(polygon_nodes))
4173             myLastCreatedElems.Append(aMesh->AddPolygonalFace(polygon_nodes));
4174         }
4175       } // switch
4176
4177       while ( srcElements.Length() < myLastCreatedElems.Length() )
4178         srcElements.Append( myLastCreatedElems.Last() );
4179     }
4180   } // loop on swept elements
4181 }
4182
4183 //=======================================================================
4184 //function : RotationSweep
4185 //purpose  :
4186 //=======================================================================
4187
4188 SMESH_MeshEditor::PGroupIDs
4189 SMESH_MeshEditor::RotationSweep(TIDSortedElemSet & theElems,
4190                                 const gp_Ax1&      theAxis,
4191                                 const double       theAngle,
4192                                 const int          theNbSteps,
4193                                 const double       theTol,
4194                                 const bool         theMakeGroups,
4195                                 const bool         theMakeWalls)
4196 {
4197   myLastCreatedElems.Clear();
4198   myLastCreatedNodes.Clear();
4199
4200   // source elements for each generated one
4201   SMESH_SequenceOfElemPtr srcElems, srcNodes;
4202
4203   MESSAGE( "RotationSweep()");
4204   gp_Trsf aTrsf;
4205   aTrsf.SetRotation( theAxis, theAngle );
4206   gp_Trsf aTrsf2;
4207   aTrsf2.SetRotation( theAxis, theAngle/2. );
4208
4209   gp_Lin aLine( theAxis );
4210   double aSqTol = theTol * theTol;
4211
4212   SMESHDS_Mesh* aMesh = GetMeshDS();
4213
4214   TNodeOfNodeListMap mapNewNodes;
4215   TElemOfVecOfNnlmiMap mapElemNewNodes;
4216   TElemOfElemListMap newElemsMap;
4217
4218   // loop on theElems
4219   TIDSortedElemSet::iterator itElem;
4220   for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
4221     const SMDS_MeshElement* elem = *itElem;
4222     if ( !elem || elem->GetType() == SMDSAbs_Volume )
4223       continue;
4224     vector<TNodeOfNodeListMapItr> & newNodesItVec = mapElemNewNodes[ elem ];
4225     newNodesItVec.reserve( elem->NbNodes() );
4226
4227     // loop on elem nodes
4228     SMDS_ElemIteratorPtr itN = elem->nodesIterator();
4229     while ( itN->more() ) {
4230       // check if a node has been already sweeped
4231       const SMDS_MeshNode* node = cast2Node( itN->next() );
4232
4233       gp_XYZ aXYZ( node->X(), node->Y(), node->Z() );
4234       double coord[3];
4235       aXYZ.Coord( coord[0], coord[1], coord[2] );
4236       bool isOnAxis = ( aLine.SquareDistance( aXYZ ) <= aSqTol );
4237
4238       TNodeOfNodeListMapItr nIt = mapNewNodes.find( node );
4239       if ( nIt == mapNewNodes.end() ) {
4240         nIt = mapNewNodes.insert( make_pair( node, list<const SMDS_MeshNode*>() )).first;
4241         list<const SMDS_MeshNode*>& listNewNodes = nIt->second;
4242
4243         // make new nodes
4244         //gp_XYZ aXYZ( node->X(), node->Y(), node->Z() );
4245         //double coord[3];
4246         //aXYZ.Coord( coord[0], coord[1], coord[2] );
4247         //bool isOnAxis = ( aLine.SquareDistance( aXYZ ) <= aSqTol );
4248         const SMDS_MeshNode * newNode = node;
4249         for ( int i = 0; i < theNbSteps; i++ ) {
4250           if ( !isOnAxis ) {
4251             if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
4252               // create two nodes
4253               aTrsf2.Transforms( coord[0], coord[1], coord[2] );
4254               //aTrsf.Transforms( coord[0], coord[1], coord[2] );
4255               newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
4256               myLastCreatedNodes.Append(newNode);
4257               srcNodes.Append( node );
4258               listNewNodes.push_back( newNode );
4259               aTrsf2.Transforms( coord[0], coord[1], coord[2] );
4260               //aTrsf.Transforms( coord[0], coord[1], coord[2] );
4261             }
4262             else {
4263               aTrsf.Transforms( coord[0], coord[1], coord[2] );
4264             }
4265             newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
4266             myLastCreatedNodes.Append(newNode);
4267             srcNodes.Append( node );
4268             listNewNodes.push_back( newNode );
4269           }
4270           else {
4271             listNewNodes.push_back( newNode );
4272             if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
4273               listNewNodes.push_back( newNode );
4274             }
4275           }
4276         }
4277       }
4278       /*
4279         else {
4280         // if current elem is quadratic and current node is not medium
4281         // we have to check - may be it is needed to insert additional nodes
4282         if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
4283         list< const SMDS_MeshNode* > & listNewNodes = nIt->second;
4284         if(listNewNodes.size()==theNbSteps) {
4285         listNewNodes.clear();
4286         // make new nodes
4287         //gp_XYZ aXYZ( node->X(), node->Y(), node->Z() );
4288         //double coord[3];
4289         //aXYZ.Coord( coord[0], coord[1], coord[2] );
4290         const SMDS_MeshNode * newNode = node;
4291         if ( !isOnAxis ) {
4292         for(int i = 0; i<theNbSteps; i++) {
4293         aTrsf2.Transforms( coord[0], coord[1], coord[2] );
4294         newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
4295         cout<<"    3 AddNode:  "<<newNode;
4296         myLastCreatedNodes.Append(newNode);
4297         listNewNodes.push_back( newNode );
4298         srcNodes.Append( node );
4299         aTrsf2.Transforms( coord[0], coord[1], coord[2] );
4300         newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
4301         cout<<"    4 AddNode:  "<<newNode;
4302         myLastCreatedNodes.Append(newNode);
4303         srcNodes.Append( node );
4304         listNewNodes.push_back( newNode );
4305         }
4306         }
4307         else {
4308         listNewNodes.push_back( newNode );
4309         }
4310         }
4311         }
4312         }
4313       */
4314       newNodesItVec.push_back( nIt );
4315     }
4316     // make new elements
4317     sweepElement( elem, newNodesItVec, newElemsMap[elem], theNbSteps, srcElems );
4318   }
4319
4320   if ( theMakeWalls )
4321     makeWalls( mapNewNodes, newElemsMap, mapElemNewNodes, theElems, theNbSteps, srcElems );
4322
4323   PGroupIDs newGroupIDs;
4324   if ( theMakeGroups )
4325     newGroupIDs = generateGroups( srcNodes, srcElems, "rotated");
4326
4327   return newGroupIDs;
4328 }
4329
4330
4331 //=======================================================================
4332 //function : CreateNode
4333 //purpose  :
4334 //=======================================================================
4335 const SMDS_MeshNode* SMESH_MeshEditor::CreateNode(const double x,
4336                                                   const double y,
4337                                                   const double z,
4338                                                   const double tolnode,
4339                                                   SMESH_SequenceOfNode& aNodes)
4340 {
4341   myLastCreatedElems.Clear();
4342   myLastCreatedNodes.Clear();
4343
4344   gp_Pnt P1(x,y,z);
4345   SMESHDS_Mesh * aMesh = myMesh->GetMeshDS();
4346
4347   // try to search in sequence of existing nodes
4348   // if aNodes.Length()>0 we 'nave to use given sequence
4349   // else - use all nodes of mesh
4350   if(aNodes.Length()>0) {
4351     int i;
4352     for(i=1; i<=aNodes.Length(); i++) {
4353       gp_Pnt P2(aNodes.Value(i)->X(),aNodes.Value(i)->Y(),aNodes.Value(i)->Z());
4354       if(P1.Distance(P2)<tolnode)
4355         return aNodes.Value(i);
4356     }
4357   }
4358   else {
4359     SMDS_NodeIteratorPtr itn = aMesh->nodesIterator();
4360     while(itn->more()) {
4361       const SMDS_MeshNode* aN = static_cast<const SMDS_MeshNode*> (itn->next());
4362       gp_Pnt P2(aN->X(),aN->Y(),aN->Z());
4363       if(P1.Distance(P2)<tolnode)
4364         return aN;
4365     }
4366   }
4367
4368   // create new node and return it
4369   const SMDS_MeshNode* NewNode = aMesh->AddNode(x,y,z);
4370   myLastCreatedNodes.Append(NewNode);
4371   return NewNode;
4372 }
4373
4374
4375 //=======================================================================
4376 //function : ExtrusionSweep
4377 //purpose  :
4378 //=======================================================================
4379
4380 SMESH_MeshEditor::PGroupIDs
4381 SMESH_MeshEditor::ExtrusionSweep (TIDSortedElemSet &  theElems,
4382                                   const gp_Vec&       theStep,
4383                                   const int           theNbSteps,
4384                                   TElemOfElemListMap& newElemsMap,
4385                                   const bool          theMakeGroups,
4386                                   const int           theFlags,
4387                                   const double        theTolerance)
4388 {
4389   ExtrusParam aParams;
4390   aParams.myDir = gp_Dir(theStep);
4391   aParams.myNodes.Clear();
4392   aParams.mySteps = new TColStd_HSequenceOfReal;
4393   int i;
4394   for(i=1; i<=theNbSteps; i++)
4395     aParams.mySteps->Append(theStep.Magnitude());
4396
4397   return
4398     ExtrusionSweep(theElems,aParams,newElemsMap,theMakeGroups,theFlags,theTolerance);
4399 }
4400
4401
4402 //=======================================================================
4403 //function : ExtrusionSweep
4404 //purpose  :
4405 //=======================================================================
4406
4407 SMESH_MeshEditor::PGroupIDs
4408 SMESH_MeshEditor::ExtrusionSweep (TIDSortedElemSet &  theElems,
4409                                   ExtrusParam&        theParams,
4410                                   TElemOfElemListMap& newElemsMap,
4411                                   const bool          theMakeGroups,
4412                                   const int           theFlags,
4413                                   const double        theTolerance)
4414 {
4415   MESSAGE("ExtrusionSweep " << theMakeGroups << " " << theFlags << " " << theTolerance);
4416   myLastCreatedElems.Clear();
4417   myLastCreatedNodes.Clear();
4418
4419   // source elements for each generated one
4420   SMESH_SequenceOfElemPtr srcElems, srcNodes;
4421
4422   SMESHDS_Mesh* aMesh = GetMeshDS();
4423
4424   int nbsteps = theParams.mySteps->Length();
4425
4426   TNodeOfNodeListMap mapNewNodes;
4427   //TNodeOfNodeVecMap mapNewNodes;
4428   TElemOfVecOfNnlmiMap mapElemNewNodes;
4429   //TElemOfVecOfMapNodesMap mapElemNewNodes;
4430
4431   // loop on theElems
4432   TIDSortedElemSet::iterator itElem;
4433   for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
4434     // check element type
4435     const SMDS_MeshElement* elem = *itElem;
4436     if ( !elem  || elem->GetType() == SMDSAbs_Volume )
4437       continue;
4438
4439     vector<TNodeOfNodeListMapItr> & newNodesItVec = mapElemNewNodes[ elem ];
4440     //vector<TNodeOfNodeVecMapItr> & newNodesItVec = mapElemNewNodes[ elem ];
4441     newNodesItVec.reserve( elem->NbNodes() );
4442
4443     // loop on elem nodes
4444     SMDS_ElemIteratorPtr itN = elem->nodesIterator();
4445     while ( itN->more() )
4446     {
4447       // check if a node has been already sweeped
4448       const SMDS_MeshNode* node = cast2Node( itN->next() );
4449       TNodeOfNodeListMap::iterator nIt = mapNewNodes.find( node );
4450       //TNodeOfNodeVecMap::iterator nIt = mapNewNodes.find( node );
4451       if ( nIt == mapNewNodes.end() ) {
4452         nIt = mapNewNodes.insert( make_pair( node, list<const SMDS_MeshNode*>() )).first;
4453         //nIt = mapNewNodes.insert( make_pair( node, vector<const SMDS_MeshNode*>() )).first;
4454         list<const SMDS_MeshNode*>& listNewNodes = nIt->second;
4455         //vector<const SMDS_MeshNode*>& vecNewNodes = nIt->second;
4456         //vecNewNodes.reserve(nbsteps);
4457
4458         // make new nodes
4459         double coord[] = { node->X(), node->Y(), node->Z() };
4460         //int nbsteps = theParams.mySteps->Length();
4461         for ( int i = 0; i < nbsteps; i++ ) {
4462           if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
4463             // create additional node
4464             double x = coord[0] + theParams.myDir.X()*theParams.mySteps->Value(i+1)/2.;
4465             double y = coord[1] + theParams.myDir.Y()*theParams.mySteps->Value(i+1)/2.;
4466             double z = coord[2] + theParams.myDir.Z()*theParams.mySteps->Value(i+1)/2.;
4467             if( theFlags & EXTRUSION_FLAG_SEW ) {
4468               const SMDS_MeshNode * newNode = CreateNode(x, y, z,
4469                                                          theTolerance, theParams.myNodes);
4470               listNewNodes.push_back( newNode );
4471             }
4472             else {
4473               const SMDS_MeshNode * newNode = aMesh->AddNode(x, y, z);
4474               myLastCreatedNodes.Append(newNode);
4475               srcNodes.Append( node );
4476               listNewNodes.push_back( newNode );
4477             }
4478           }
4479           //aTrsf.Transforms( coord[0], coord[1], coord[2] );
4480           coord[0] = coord[0] + theParams.myDir.X()*theParams.mySteps->Value(i+1);
4481           coord[1] = coord[1] + theParams.myDir.Y()*theParams.mySteps->Value(i+1);
4482           coord[2] = coord[2] + theParams.myDir.Z()*theParams.mySteps->Value(i+1);
4483           if( theFlags & EXTRUSION_FLAG_SEW ) {
4484             const SMDS_MeshNode * newNode = CreateNode(coord[0], coord[1], coord[2],
4485                                                        theTolerance, theParams.myNodes);
4486             listNewNodes.push_back( newNode );
4487             //vecNewNodes[i]=newNode;
4488           }
4489           else {
4490             const SMDS_MeshNode * newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
4491             myLastCreatedNodes.Append(newNode);
4492             srcNodes.Append( node );
4493             listNewNodes.push_back( newNode );
4494             //vecNewNodes[i]=newNode;
4495           }
4496         }
4497       }
4498       else {
4499         // if current elem is quadratic and current node is not medium
4500         // we have to check - may be it is needed to insert additional nodes
4501         if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
4502           list< const SMDS_MeshNode* > & listNewNodes = nIt->second;
4503           if(listNewNodes.size()==nbsteps) {
4504             listNewNodes.clear();
4505             double coord[] = { node->X(), node->Y(), node->Z() };
4506             for ( int i = 0; i < nbsteps; i++ ) {
4507               double x = coord[0] + theParams.myDir.X()*theParams.mySteps->Value(i+1);
4508               double y = coord[1] + theParams.myDir.Y()*theParams.mySteps->Value(i+1);
4509               double z = coord[2] + theParams.myDir.Z()*theParams.mySteps->Value(i+1);
4510               if( theFlags & EXTRUSION_FLAG_SEW ) {
4511                 const SMDS_MeshNode * newNode = CreateNode(x, y, z,
4512                                                            theTolerance, theParams.myNodes);
4513                 listNewNodes.push_back( newNode );
4514               }
4515               else {
4516                 const SMDS_MeshNode * newNode = aMesh->AddNode(x, y, z);
4517                 myLastCreatedNodes.Append(newNode);
4518                 srcNodes.Append( node );
4519                 listNewNodes.push_back( newNode );
4520               }
4521               coord[0] = coord[0] + theParams.myDir.X()*theParams.mySteps->Value(i+1);
4522               coord[1] = coord[1] + theParams.myDir.Y()*theParams.mySteps->Value(i+1);
4523               coord[2] = coord[2] + theParams.myDir.Z()*theParams.mySteps->Value(i+1);
4524               if( theFlags & EXTRUSION_FLAG_SEW ) {
4525                 const SMDS_MeshNode * newNode = CreateNode(coord[0], coord[1], coord[2],
4526                                                            theTolerance, theParams.myNodes);
4527                 listNewNodes.push_back( newNode );
4528               }
4529               else {
4530                 const SMDS_MeshNode * newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
4531                 myLastCreatedNodes.Append(newNode);
4532                 srcNodes.Append( node );
4533                 listNewNodes.push_back( newNode );
4534               }
4535             }
4536           }
4537         }
4538       }
4539       newNodesItVec.push_back( nIt );
4540     }
4541     // make new elements
4542     sweepElement( elem, newNodesItVec, newElemsMap[elem], nbsteps, srcElems );
4543   }
4544
4545   if( theFlags & EXTRUSION_FLAG_BOUNDARY ) {
4546     makeWalls( mapNewNodes, newElemsMap, mapElemNewNodes, theElems, nbsteps, srcElems );
4547   }
4548   PGroupIDs newGroupIDs;
4549   if ( theMakeGroups )
4550     newGroupIDs = generateGroups( srcNodes, srcElems, "extruded");
4551
4552   return newGroupIDs;
4553 }
4554
4555 /*
4556 //=======================================================================
4557 //class    : SMESH_MeshEditor_PathPoint
4558 //purpose  : auxiliary class
4559 //=======================================================================
4560 class SMESH_MeshEditor_PathPoint {
4561 public:
4562 SMESH_MeshEditor_PathPoint() {
4563 myPnt.SetCoord(99., 99., 99.);
4564 myTgt.SetCoord(1.,0.,0.);
4565 myAngle=0.;
4566 myPrm=0.;
4567 }
4568 void SetPnt(const gp_Pnt& aP3D){
4569 myPnt=aP3D;
4570 }
4571 void SetTangent(const gp_Dir& aTgt){
4572 myTgt=aTgt;
4573 }
4574 void SetAngle(const double& aBeta){
4575 myAngle=aBeta;
4576 }
4577 void SetParameter(const double& aPrm){
4578 myPrm=aPrm;
4579 }
4580 const gp_Pnt& Pnt()const{
4581 return myPnt;
4582 }
4583 const gp_Dir& Tangent()const{
4584 return myTgt;
4585 }
4586 double Angle()const{
4587 return myAngle;
4588 }
4589 double Parameter()const{
4590 return myPrm;
4591 }
4592
4593 protected:
4594 gp_Pnt myPnt;
4595 gp_Dir myTgt;
4596 double myAngle;
4597 double myPrm;
4598 };
4599 */
4600
4601 //=======================================================================
4602 //function : ExtrusionAlongTrack
4603 //purpose  :
4604 //=======================================================================
4605 SMESH_MeshEditor::Extrusion_Error
4606 SMESH_MeshEditor::ExtrusionAlongTrack (TIDSortedElemSet &   theElements,
4607                                        SMESH_subMesh*       theTrack,
4608                                        const SMDS_MeshNode* theN1,
4609                                        const bool           theHasAngles,
4610                                        list<double>&        theAngles,
4611                                        const bool           theLinearVariation,
4612                                        const bool           theHasRefPoint,
4613                                        const gp_Pnt&        theRefPoint,
4614                                        const bool           theMakeGroups)
4615 {
4616   MESSAGE("ExtrusionAlongTrack");
4617   myLastCreatedElems.Clear();
4618   myLastCreatedNodes.Clear();
4619
4620   int aNbE;
4621   std::list<double> aPrms;
4622   TIDSortedElemSet::iterator itElem;
4623
4624   gp_XYZ aGC;
4625   TopoDS_Edge aTrackEdge;
4626   TopoDS_Vertex aV1, aV2;
4627
4628   SMDS_ElemIteratorPtr aItE;
4629   SMDS_NodeIteratorPtr aItN;
4630   SMDSAbs_ElementType aTypeE;
4631
4632   TNodeOfNodeListMap mapNewNodes;
4633
4634   // 1. Check data
4635   aNbE = theElements.size();
4636   // nothing to do
4637   if ( !aNbE )
4638     return EXTR_NO_ELEMENTS;
4639
4640   // 1.1 Track Pattern
4641   ASSERT( theTrack );
4642
4643   SMESHDS_SubMesh* pSubMeshDS = theTrack->GetSubMeshDS();
4644
4645   aItE = pSubMeshDS->GetElements();
4646   while ( aItE->more() ) {
4647     const SMDS_MeshElement* pE = aItE->next();
4648     aTypeE = pE->GetType();
4649     // Pattern must contain links only
4650     if ( aTypeE != SMDSAbs_Edge )
4651       return EXTR_PATH_NOT_EDGE;
4652   }
4653
4654   list<SMESH_MeshEditor_PathPoint> fullList;
4655
4656   const TopoDS_Shape& aS = theTrack->GetSubShape();
4657   // Sub shape for the Pattern must be an Edge or Wire
4658   if( aS.ShapeType() == TopAbs_EDGE ) {
4659     aTrackEdge = TopoDS::Edge( aS );
4660     // the Edge must not be degenerated
4661     if ( BRep_Tool::Degenerated( aTrackEdge ) )
4662       return EXTR_BAD_PATH_SHAPE;
4663     TopExp::Vertices( aTrackEdge, aV1, aV2 );
4664     aItN = theTrack->GetFather()->GetSubMesh( aV1 )->GetSubMeshDS()->GetNodes();
4665     const SMDS_MeshNode* aN1 = aItN->next();
4666     aItN = theTrack->GetFather()->GetSubMesh( aV2 )->GetSubMeshDS()->GetNodes();
4667     const SMDS_MeshNode* aN2 = aItN->next();
4668     // starting node must be aN1 or aN2
4669     if ( !( aN1 == theN1 || aN2 == theN1 ) )
4670       return EXTR_BAD_STARTING_NODE;
4671     aItN = pSubMeshDS->GetNodes();
4672     while ( aItN->more() ) {
4673       const SMDS_MeshNode* pNode = aItN->next();
4674       const SMDS_EdgePosition* pEPos =
4675         static_cast<const SMDS_EdgePosition*>( pNode->GetPosition() );
4676       double aT = pEPos->GetUParameter();
4677       aPrms.push_back( aT );
4678     }
4679     //Extrusion_Error err =
4680     MakeEdgePathPoints(aPrms, aTrackEdge, (aN1==theN1), fullList);
4681   }
4682   else if( aS.ShapeType() == TopAbs_WIRE ) {
4683     list< SMESH_subMesh* > LSM;
4684     TopTools_SequenceOfShape Edges;
4685     SMESH_subMeshIteratorPtr itSM = theTrack->getDependsOnIterator(false,true);
4686     while(itSM->more()) {
4687       SMESH_subMesh* SM = itSM->next();
4688       LSM.push_back(SM);
4689       const TopoDS_Shape& aS = SM->GetSubShape();
4690       Edges.Append(aS);
4691     }
4692     list< list<SMESH_MeshEditor_PathPoint> > LLPPs;
4693     int startNid = theN1->GetID();
4694     TColStd_MapOfInteger UsedNums;
4695     int NbEdges = Edges.Length();
4696     int i = 1;
4697     for(; i<=NbEdges; i++) {
4698       int k = 0;
4699       list< SMESH_subMesh* >::iterator itLSM = LSM.begin();
4700       for(; itLSM!=LSM.end(); itLSM++) {
4701         k++;
4702         if(UsedNums.Contains(k)) continue;
4703         aTrackEdge = TopoDS::Edge( Edges.Value(k) );
4704         SMESH_subMesh* locTrack = *itLSM;
4705         SMESHDS_SubMesh* locMeshDS = locTrack->GetSubMeshDS();
4706         TopExp::Vertices( aTrackEdge, aV1, aV2 );
4707         aItN = locTrack->GetFather()->GetSubMesh(aV1)->GetSubMeshDS()->GetNodes();
4708         const SMDS_MeshNode* aN1 = aItN->next();
4709         aItN = locTrack->GetFather()->GetSubMesh(aV2)->GetSubMeshDS()->GetNodes();
4710         const SMDS_MeshNode* aN2 = aItN->next();
4711         // starting node must be aN1 or aN2
4712         if ( !( aN1->GetID() == startNid || aN2->GetID() == startNid ) ) continue;
4713         // 2. Collect parameters on the track edge
4714         aPrms.clear();
4715         aItN = locMeshDS->GetNodes();
4716         while ( aItN->more() ) {
4717           const SMDS_MeshNode* pNode = aItN->next();
4718           const SMDS_EdgePosition* pEPos =
4719             static_cast<const SMDS_EdgePosition*>( pNode->GetPosition() );
4720           double aT = pEPos->GetUParameter();
4721           aPrms.push_back( aT );
4722         }
4723         list<SMESH_MeshEditor_PathPoint> LPP;
4724         //Extrusion_Error err =
4725         MakeEdgePathPoints(aPrms, aTrackEdge,(aN1->GetID()==startNid), LPP);
4726         LLPPs.push_back(LPP);
4727         UsedNums.Add(k);
4728         // update startN for search following egde
4729         if( aN1->GetID() == startNid ) startNid = aN2->GetID();
4730         else startNid = aN1->GetID();
4731         break;
4732       }
4733     }
4734     list< list<SMESH_MeshEditor_PathPoint> >::iterator itLLPP = LLPPs.begin();
4735     list<SMESH_MeshEditor_PathPoint> firstList = *itLLPP;
4736     list<SMESH_MeshEditor_PathPoint>::iterator itPP = firstList.begin();
4737     for(; itPP!=firstList.end(); itPP++) {
4738       fullList.push_back( *itPP );
4739     }
4740     SMESH_MeshEditor_PathPoint PP1 = fullList.back();
4741     fullList.pop_back();
4742     itLLPP++;
4743     for(; itLLPP!=LLPPs.end(); itLLPP++) {
4744       list<SMESH_MeshEditor_PathPoint> currList = *itLLPP;
4745       itPP = currList.begin();
4746       SMESH_MeshEditor_PathPoint PP2 = currList.front();
4747       gp_Dir D1 = PP1.Tangent();
4748       gp_Dir D2 = PP2.Tangent();
4749       gp_Dir Dnew( gp_Vec( (D1.X()+D2.X())/2, (D1.Y()+D2.Y())/2,
4750                            (D1.Z()+D2.Z())/2 ) );
4751       PP1.SetTangent(Dnew);
4752       fullList.push_back(PP1);
4753       itPP++;
4754       for(; itPP!=firstList.end(); itPP++) {
4755         fullList.push_back( *itPP );
4756       }
4757       PP1 = fullList.back();
4758       fullList.pop_back();
4759     }
4760     // if wire not closed
4761     fullList.push_back(PP1);
4762     // else ???
4763   }
4764   else {
4765     return EXTR_BAD_PATH_SHAPE;
4766   }
4767
4768   return MakeExtrElements(theElements, fullList, theHasAngles, theAngles, theLinearVariation,
4769                           theHasRefPoint, theRefPoint, theMakeGroups);
4770 }
4771
4772
4773 //=======================================================================
4774 //function : ExtrusionAlongTrack
4775 //purpose  :
4776 //=======================================================================
4777 SMESH_MeshEditor::Extrusion_Error
4778 SMESH_MeshEditor::ExtrusionAlongTrack (TIDSortedElemSet &   theElements,
4779                                        SMESH_Mesh*          theTrack,
4780                                        const SMDS_MeshNode* theN1,
4781                                        const bool           theHasAngles,
4782                                        list<double>&        theAngles,
4783                                        const bool           theLinearVariation,
4784                                        const bool           theHasRefPoint,
4785                                        const gp_Pnt&        theRefPoint,
4786                                        const bool           theMakeGroups)
4787 {
4788   myLastCreatedElems.Clear();
4789   myLastCreatedNodes.Clear();
4790
4791   int aNbE;
4792   std::list<double> aPrms;
4793   TIDSortedElemSet::iterator itElem;
4794
4795   gp_XYZ aGC;
4796   TopoDS_Edge aTrackEdge;
4797   TopoDS_Vertex aV1, aV2;
4798
4799   SMDS_ElemIteratorPtr aItE;
4800   SMDS_NodeIteratorPtr aItN;
4801   SMDSAbs_ElementType aTypeE;
4802
4803   TNodeOfNodeListMap mapNewNodes;
4804
4805   // 1. Check data
4806   aNbE = theElements.size();
4807   // nothing to do
4808   if ( !aNbE )
4809     return EXTR_NO_ELEMENTS;
4810
4811   // 1.1 Track Pattern
4812   ASSERT( theTrack );
4813
4814   SMESHDS_Mesh* pMeshDS = theTrack->GetMeshDS();
4815
4816   aItE = pMeshDS->elementsIterator();
4817   while ( aItE->more() ) {
4818     const SMDS_MeshElement* pE = aItE->next();
4819     aTypeE = pE->GetType();
4820     // Pattern must contain links only
4821     if ( aTypeE != SMDSAbs_Edge )
4822       return EXTR_PATH_NOT_EDGE;
4823   }
4824
4825   list<SMESH_MeshEditor_PathPoint> fullList;
4826
4827   const TopoDS_Shape& aS = theTrack->GetShapeToMesh();
4828   // Sub shape for the Pattern must be an Edge or Wire
4829   if( aS.ShapeType() == TopAbs_EDGE ) {
4830     aTrackEdge = TopoDS::Edge( aS );
4831     // the Edge must not be degenerated
4832     if ( BRep_Tool::Degenerated( aTrackEdge ) )
4833       return EXTR_BAD_PATH_SHAPE;
4834     TopExp::Vertices( aTrackEdge, aV1, aV2 );
4835     aItN = theTrack->GetSubMesh( aV1 )->GetSubMeshDS()->GetNodes();
4836     const SMDS_MeshNode* aN1 = aItN->next();
4837     aItN = theTrack->GetSubMesh( aV2 )->GetSubMeshDS()->GetNodes();
4838     const SMDS_MeshNode* aN2 = aItN->next();
4839     // starting node must be aN1 or aN2
4840     if ( !( aN1 == theN1 || aN2 == theN1 ) )
4841       return EXTR_BAD_STARTING_NODE;
4842     aItN = pMeshDS->nodesIterator();
4843     while ( aItN->more() ) {
4844       const SMDS_MeshNode* pNode = aItN->next();
4845       if( pNode==aN1 || pNode==aN2 ) continue;
4846       const SMDS_EdgePosition* pEPos =
4847         static_cast<const SMDS_EdgePosition*>( pNode->GetPosition() );
4848       double aT = pEPos->GetUParameter();
4849       aPrms.push_back( aT );
4850     }
4851     //Extrusion_Error err =
4852     MakeEdgePathPoints(aPrms, aTrackEdge, (aN1==theN1), fullList);
4853   }
4854   else if( aS.ShapeType() == TopAbs_WIRE ) {
4855     list< SMESH_subMesh* > LSM;
4856     TopTools_SequenceOfShape Edges;
4857     TopExp_Explorer eExp(aS, TopAbs_EDGE);
4858     for(; eExp.More(); eExp.Next()) {
4859       TopoDS_Edge E = TopoDS::Edge( eExp.Current() );
4860       if( BRep_Tool::Degenerated(E) ) continue;
4861       SMESH_subMesh* SM = theTrack->GetSubMesh(E);
4862       if(SM) {
4863         LSM.push_back(SM);
4864         Edges.Append(E);
4865       }
4866     }
4867     list< list<SMESH_MeshEditor_PathPoint> > LLPPs;
4868     int startNid = theN1->GetID();
4869     TColStd_MapOfInteger UsedNums;
4870     int NbEdges = Edges.Length();
4871     int i = 1;
4872     for(; i<=NbEdges; i++) {
4873       int k = 0;
4874       list< SMESH_subMesh* >::iterator itLSM = LSM.begin();
4875       for(; itLSM!=LSM.end(); itLSM++) {
4876         k++;
4877         if(UsedNums.Contains(k)) continue;
4878         aTrackEdge = TopoDS::Edge( Edges.Value(k) );
4879         SMESH_subMesh* locTrack = *itLSM;
4880         SMESHDS_SubMesh* locMeshDS = locTrack->GetSubMeshDS();
4881         TopExp::Vertices( aTrackEdge, aV1, aV2 );
4882         aItN = locTrack->GetFather()->GetSubMesh(aV1)->GetSubMeshDS()->GetNodes();
4883         const SMDS_MeshNode* aN1 = aItN->next();
4884         aItN = locTrack->GetFather()->GetSubMesh(aV2)->GetSubMeshDS()->GetNodes();
4885         const SMDS_MeshNode* aN2 = aItN->next();
4886         // starting node must be aN1 or aN2
4887         if ( !( aN1->GetID() == startNid || aN2->GetID() == startNid ) ) continue;
4888         // 2. Collect parameters on the track edge
4889         aPrms.clear();
4890         aItN = locMeshDS->GetNodes();
4891         while ( aItN->more() ) {
4892           const SMDS_MeshNode* pNode = aItN->next();
4893           const SMDS_EdgePosition* pEPos =
4894             static_cast<const SMDS_EdgePosition*>( pNode->GetPosition() );
4895           double aT = pEPos->GetUParameter();
4896           aPrms.push_back( aT );
4897         }
4898         list<SMESH_MeshEditor_PathPoint> LPP;
4899         //Extrusion_Error err =
4900         MakeEdgePathPoints(aPrms, aTrackEdge,(aN1->GetID()==startNid), LPP);
4901         LLPPs.push_back(LPP);
4902         UsedNums.Add(k);
4903         // update startN for search following egde
4904         if( aN1->GetID() == startNid ) startNid = aN2->GetID();
4905         else startNid = aN1->GetID();
4906         break;
4907       }
4908     }
4909     list< list<SMESH_MeshEditor_PathPoint> >::iterator itLLPP = LLPPs.begin();
4910     list<SMESH_MeshEditor_PathPoint> firstList = *itLLPP;
4911     list<SMESH_MeshEditor_PathPoint>::iterator itPP = firstList.begin();
4912     for(; itPP!=firstList.end(); itPP++) {
4913       fullList.push_back( *itPP );
4914     }
4915     SMESH_MeshEditor_PathPoint PP1 = fullList.back();
4916     fullList.pop_back();
4917     itLLPP++;
4918     for(; itLLPP!=LLPPs.end(); itLLPP++) {
4919       list<SMESH_MeshEditor_PathPoint> currList = *itLLPP;
4920       itPP = currList.begin();
4921       SMESH_MeshEditor_PathPoint PP2 = currList.front();
4922       gp_Pnt P1 = PP1.Pnt();
4923       //cout<<"    PP1: Pnt("<<P1.X()<<","<<P1.Y()<<","<<P1.Z()<<")"<<endl;
4924       gp_Pnt P2 = PP2.Pnt();
4925       gp_Dir D1 = PP1.Tangent();
4926       gp_Dir D2 = PP2.Tangent();
4927       gp_Dir Dnew( gp_Vec( (D1.X()+D2.X())/2, (D1.Y()+D2.Y())/2,
4928                            (D1.Z()+D2.Z())/2 ) );
4929       PP1.SetTangent(Dnew);
4930       fullList.push_back(PP1);
4931       itPP++;
4932       for(; itPP!=currList.end(); itPP++) {
4933         fullList.push_back( *itPP );
4934       }
4935       PP1 = fullList.back();
4936       fullList.pop_back();
4937     }
4938     // if wire not closed
4939     fullList.push_back(PP1);
4940     // else ???
4941   }
4942   else {
4943     return EXTR_BAD_PATH_SHAPE;
4944   }
4945
4946   return MakeExtrElements(theElements, fullList, theHasAngles, theAngles, theLinearVariation,
4947                           theHasRefPoint, theRefPoint, theMakeGroups);
4948 }
4949
4950
4951 //=======================================================================
4952 //function : MakeEdgePathPoints
4953 //purpose  : auxilary for ExtrusionAlongTrack
4954 //=======================================================================
4955 SMESH_MeshEditor::Extrusion_Error
4956 SMESH_MeshEditor::MakeEdgePathPoints(std::list<double>& aPrms,
4957                                      const TopoDS_Edge& aTrackEdge,
4958                                      bool FirstIsStart,
4959                                      list<SMESH_MeshEditor_PathPoint>& LPP)
4960 {
4961   Standard_Real aTx1, aTx2, aL2, aTolVec, aTolVec2;
4962   aTolVec=1.e-7;
4963   aTolVec2=aTolVec*aTolVec;
4964   double aT1, aT2;
4965   TopoDS_Vertex aV1, aV2;
4966   TopExp::Vertices( aTrackEdge, aV1, aV2 );
4967   aT1=BRep_Tool::Parameter( aV1, aTrackEdge );
4968   aT2=BRep_Tool::Parameter( aV2, aTrackEdge );
4969   // 2. Collect parameters on the track edge
4970   aPrms.push_front( aT1 );
4971   aPrms.push_back( aT2 );
4972   // sort parameters
4973   aPrms.sort();
4974   if( FirstIsStart ) {
4975     if ( aT1 > aT2 ) {
4976       aPrms.reverse();
4977     }
4978   }
4979   else {
4980     if ( aT2 > aT1 ) {
4981       aPrms.reverse();
4982     }
4983   }
4984   // 3. Path Points
4985   SMESH_MeshEditor_PathPoint aPP;
4986   Handle(Geom_Curve) aC3D = BRep_Tool::Curve( aTrackEdge, aTx1, aTx2 );
4987   std::list<double>::iterator aItD = aPrms.begin();
4988   for(; aItD != aPrms.end(); ++aItD) {
4989     double aT = *aItD;
4990     gp_Pnt aP3D;
4991     gp_Vec aVec;
4992     aC3D->D1( aT, aP3D, aVec );
4993     aL2 = aVec.SquareMagnitude();
4994     if ( aL2 < aTolVec2 )
4995       return EXTR_CANT_GET_TANGENT;
4996     gp_Dir aTgt( aVec );
4997     aPP.SetPnt( aP3D );
4998     aPP.SetTangent( aTgt );
4999     aPP.SetParameter( aT );
5000     LPP.push_back(aPP);
5001   }
5002   return EXTR_OK;
5003 }
5004
5005
5006 //=======================================================================
5007 //function : MakeExtrElements
5008 //purpose  : auxilary for ExtrusionAlongTrack
5009 //=======================================================================
5010 SMESH_MeshEditor::Extrusion_Error
5011 SMESH_MeshEditor::MakeExtrElements(TIDSortedElemSet&  theElements,
5012                                    list<SMESH_MeshEditor_PathPoint>& fullList,
5013                                    const bool theHasAngles,
5014                                    list<double>& theAngles,
5015                                    const bool theLinearVariation,
5016                                    const bool theHasRefPoint,
5017                                    const gp_Pnt& theRefPoint,
5018                                    const bool theMakeGroups)
5019 {
5020   MESSAGE("MakeExtrElements");
5021   //cout<<"MakeExtrElements  fullList.size() = "<<fullList.size()<<endl;
5022   int aNbTP = fullList.size();
5023   vector<SMESH_MeshEditor_PathPoint> aPPs(aNbTP);
5024   // Angles
5025   if( theHasAngles && theAngles.size()>0 && theLinearVariation ) {
5026     LinearAngleVariation(aNbTP-1, theAngles);
5027   }
5028   vector<double> aAngles( aNbTP );
5029   int j = 0;
5030   for(; j<aNbTP; ++j) {
5031     aAngles[j] = 0.;
5032   }
5033   if ( theHasAngles ) {
5034     double anAngle;;
5035     std::list<double>::iterator aItD = theAngles.begin();
5036     for ( j=1; (aItD != theAngles.end()) && (j<aNbTP); ++aItD, ++j ) {
5037       anAngle = *aItD;
5038       aAngles[j] = anAngle;
5039     }
5040   }
5041   // fill vector of path points with angles
5042   //aPPs.resize(fullList.size());
5043   j = -1;
5044   list<SMESH_MeshEditor_PathPoint>::iterator itPP = fullList.begin();
5045   for(; itPP!=fullList.end(); itPP++) {
5046     j++;
5047     SMESH_MeshEditor_PathPoint PP = *itPP;
5048     PP.SetAngle(aAngles[j]);
5049     aPPs[j] = PP;
5050   }
5051
5052   TNodeOfNodeListMap mapNewNodes;
5053   TElemOfVecOfNnlmiMap mapElemNewNodes;
5054   TElemOfElemListMap newElemsMap;
5055   TIDSortedElemSet::iterator itElem;
5056   double aX, aY, aZ;
5057   int aNb;
5058   SMDSAbs_ElementType aTypeE;
5059   // source elements for each generated one
5060   SMESH_SequenceOfElemPtr srcElems, srcNodes;
5061
5062   // 3. Center of rotation aV0
5063   gp_Pnt aV0 = theRefPoint;
5064   gp_XYZ aGC;
5065   if ( !theHasRefPoint ) {
5066     aNb = 0;
5067     aGC.SetCoord( 0.,0.,0. );
5068
5069     itElem = theElements.begin();
5070     for ( ; itElem != theElements.end(); itElem++ ) {
5071       const SMDS_MeshElement* elem = *itElem;
5072
5073       SMDS_ElemIteratorPtr itN = elem->nodesIterator();
5074       while ( itN->more() ) {
5075         const SMDS_MeshNode* node = static_cast<const SMDS_MeshNode*>( itN->next() );
5076         aX = node->X();
5077         aY = node->Y();
5078         aZ = node->Z();
5079
5080         if ( mapNewNodes.find( node ) == mapNewNodes.end() ) {
5081           list<const SMDS_MeshNode*> aLNx;
5082           mapNewNodes[node] = aLNx;
5083           //
5084           gp_XYZ aXYZ( aX, aY, aZ );
5085           aGC += aXYZ;
5086           ++aNb;
5087         }
5088       }
5089     }
5090     aGC /= aNb;
5091     aV0.SetXYZ( aGC );
5092   } // if (!theHasRefPoint) {
5093   mapNewNodes.clear();
5094
5095   // 4. Processing the elements
5096   SMESHDS_Mesh* aMesh = GetMeshDS();
5097
5098   for ( itElem = theElements.begin(); itElem != theElements.end(); itElem++ ) {
5099     // check element type
5100     const SMDS_MeshElement* elem = *itElem;
5101     aTypeE = elem->GetType();
5102     if ( !elem || ( aTypeE != SMDSAbs_Face && aTypeE != SMDSAbs_Edge ) )
5103       continue;
5104
5105     vector<TNodeOfNodeListMapItr> & newNodesItVec = mapElemNewNodes[ elem ];
5106     newNodesItVec.reserve( elem->NbNodes() );
5107
5108     // loop on elem nodes
5109     int nodeIndex = -1;
5110     SMDS_ElemIteratorPtr itN = elem->nodesIterator();
5111     while ( itN->more() )
5112     {
5113       ++nodeIndex;
5114       // check if a node has been already processed
5115       const SMDS_MeshNode* node =
5116         static_cast<const SMDS_MeshNode*>( itN->next() );
5117       TNodeOfNodeListMap::iterator nIt = mapNewNodes.find( node );
5118       if ( nIt == mapNewNodes.end() ) {
5119         nIt = mapNewNodes.insert( make_pair( node, list<const SMDS_MeshNode*>() )).first;
5120         list<const SMDS_MeshNode*>& listNewNodes = nIt->second;
5121
5122         // make new nodes
5123         aX = node->X();  aY = node->Y(); aZ = node->Z();
5124
5125         Standard_Real aAngle1x, aAngleT1T0, aTolAng;
5126         gp_Pnt aP0x, aP1x, aPN0, aPN1, aV0x, aV1x;
5127         gp_Ax1 anAx1, anAxT1T0;
5128         gp_Dir aDT1x, aDT0x, aDT1T0;
5129
5130         aTolAng=1.e-4;
5131
5132         aV0x = aV0;
5133         aPN0.SetCoord(aX, aY, aZ);
5134
5135         const SMESH_MeshEditor_PathPoint& aPP0 = aPPs[0];
5136         aP0x = aPP0.Pnt();
5137         aDT0x= aPP0.Tangent();
5138         //cout<<"j = 0   PP: Pnt("<<aP0x.X()<<","<<aP0x.Y()<<","<<aP0x.Z()<<")"<<endl;
5139
5140         for ( j = 1; j < aNbTP; ++j ) {
5141           const SMESH_MeshEditor_PathPoint& aPP1 = aPPs[j];
5142           aP1x = aPP1.Pnt();
5143           aDT1x = aPP1.Tangent();
5144           aAngle1x = aPP1.Angle();
5145
5146           gp_Trsf aTrsf, aTrsfRot, aTrsfRotT1T0;
5147           // Translation
5148           gp_Vec aV01x( aP0x, aP1x );
5149           aTrsf.SetTranslation( aV01x );
5150
5151           // traslated point
5152           aV1x = aV0x.Transformed( aTrsf );
5153           aPN1 = aPN0.Transformed( aTrsf );
5154
5155           // rotation 1 [ T1,T0 ]
5156           aAngleT1T0=-aDT1x.Angle( aDT0x );
5157           if (fabs(aAngleT1T0) > aTolAng) {
5158             aDT1T0=aDT1x^aDT0x;
5159             anAxT1T0.SetLocation( aV1x );
5160             anAxT1T0.SetDirection( aDT1T0 );
5161             aTrsfRotT1T0.SetRotation( anAxT1T0, aAngleT1T0 );
5162
5163             aPN1 = aPN1.Transformed( aTrsfRotT1T0 );
5164           }
5165
5166           // rotation 2
5167           if ( theHasAngles ) {
5168             anAx1.SetLocation( aV1x );
5169             anAx1.SetDirection( aDT1x );
5170             aTrsfRot.SetRotation( anAx1, aAngle1x );
5171
5172             aPN1 = aPN1.Transformed( aTrsfRot );
5173           }
5174
5175           // make new node
5176           //MESSAGE("elem->IsQuadratic " << elem->IsQuadratic() << " " << elem->IsMediumNode(node));
5177           if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
5178             // create additional node
5179             double x = ( aPN1.X() + aPN0.X() )/2.;
5180             double y = ( aPN1.Y() + aPN0.Y() )/2.;
5181             double z = ( aPN1.Z() + aPN0.Z() )/2.;
5182             const SMDS_MeshNode* newNode = aMesh->AddNode(x,y,z);
5183             myLastCreatedNodes.Append(newNode);
5184             srcNodes.Append( node );
5185             listNewNodes.push_back( newNode );
5186           }
5187           aX = aPN1.X();
5188           aY = aPN1.Y();
5189           aZ = aPN1.Z();
5190           const SMDS_MeshNode* newNode = aMesh->AddNode( aX, aY, aZ );
5191           myLastCreatedNodes.Append(newNode);
5192           srcNodes.Append( node );
5193           listNewNodes.push_back( newNode );
5194
5195           aPN0 = aPN1;
5196           aP0x = aP1x;
5197           aV0x = aV1x;
5198           aDT0x = aDT1x;
5199         }
5200       }
5201
5202       else {
5203         // if current elem is quadratic and current node is not medium
5204         // we have to check - may be it is needed to insert additional nodes
5205         if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
5206           list< const SMDS_MeshNode* > & listNewNodes = nIt->second;
5207           if(listNewNodes.size()==aNbTP-1) {
5208             vector<const SMDS_MeshNode*> aNodes(2*(aNbTP-1));
5209             gp_XYZ P(node->X(), node->Y(), node->Z());
5210             list< const SMDS_MeshNode* >::iterator it = listNewNodes.begin();
5211             int i;
5212             for(i=0; i<aNbTP-1; i++) {
5213               const SMDS_MeshNode* N = *it;
5214               double x = ( N->X() + P.X() )/2.;
5215               double y = ( N->Y() + P.Y() )/2.;
5216               double z = ( N->Z() + P.Z() )/2.;
5217               const SMDS_MeshNode* newN = aMesh->AddNode(x,y,z);
5218               srcNodes.Append( node );
5219               myLastCreatedNodes.Append(newN);
5220               aNodes[2*i] = newN;
5221               aNodes[2*i+1] = N;
5222               P = gp_XYZ(N->X(),N->Y(),N->Z());
5223             }
5224             listNewNodes.clear();
5225             for(i=0; i<2*(aNbTP-1); i++) {
5226               listNewNodes.push_back(aNodes[i]);
5227             }
5228           }
5229         }
5230       }
5231
5232       newNodesItVec.push_back( nIt );
5233     }
5234     // make new elements
5235     //sweepElement( aMesh, elem, newNodesItVec, newElemsMap[elem],
5236     //              newNodesItVec[0]->second.size(), myLastCreatedElems );
5237     sweepElement( elem, newNodesItVec, newElemsMap[elem], aNbTP-1, srcElems );
5238   }
5239
5240   makeWalls( mapNewNodes, newElemsMap, mapElemNewNodes, theElements, aNbTP-1, srcElems );
5241
5242   if ( theMakeGroups )
5243     generateGroups( srcNodes, srcElems, "extruded");
5244
5245   return EXTR_OK;
5246 }
5247
5248
5249 //=======================================================================
5250 //function : LinearAngleVariation
5251 //purpose  : auxilary for ExtrusionAlongTrack
5252 //=======================================================================
5253 void SMESH_MeshEditor::LinearAngleVariation(const int nbSteps,
5254                                             list<double>& Angles)
5255 {
5256   int nbAngles = Angles.size();
5257   if( nbSteps > nbAngles ) {
5258     vector<double> theAngles(nbAngles);
5259     list<double>::iterator it = Angles.begin();
5260     int i = -1;
5261     for(; it!=Angles.end(); it++) {
5262       i++;
5263       theAngles[i] = (*it);
5264     }
5265     list<double> res;
5266     double rAn2St = double( nbAngles ) / double( nbSteps );
5267     double angPrev = 0, angle;
5268     for ( int iSt = 0; iSt < nbSteps; ++iSt ) {
5269       double angCur = rAn2St * ( iSt+1 );
5270       double angCurFloor  = floor( angCur );
5271       double angPrevFloor = floor( angPrev );
5272       if ( angPrevFloor == angCurFloor )
5273         angle = rAn2St * theAngles[ int( angCurFloor ) ];
5274       else {
5275         int iP = int( angPrevFloor );
5276         double angPrevCeil = ceil(angPrev);
5277         angle = ( angPrevCeil - angPrev ) * theAngles[ iP ];
5278
5279         int iC = int( angCurFloor );
5280         if ( iC < nbAngles )
5281           angle += ( angCur - angCurFloor ) * theAngles[ iC ];
5282
5283         iP = int( angPrevCeil );
5284         while ( iC-- > iP )
5285           angle += theAngles[ iC ];
5286       }
5287       res.push_back(angle);
5288       angPrev = angCur;
5289     }
5290     Angles.clear();
5291     it = res.begin();
5292     for(; it!=res.end(); it++)
5293       Angles.push_back( *it );
5294   }
5295 }
5296
5297
5298 //================================================================================
5299 /*!
5300  * \brief Move or copy theElements applying theTrsf to their nodes
5301  *  \param theElems - elements to transform, if theElems is empty then apply to all mesh nodes
5302  *  \param theTrsf - transformation to apply
5303  *  \param theCopy - if true, create translated copies of theElems
5304  *  \param theMakeGroups - if true and theCopy, create translated groups
5305  *  \param theTargetMesh - mesh to copy translated elements into
5306  *  \retval SMESH_MeshEditor::PGroupIDs - list of ids of created groups
5307  */
5308 //================================================================================
5309
5310 SMESH_MeshEditor::PGroupIDs
5311 SMESH_MeshEditor::Transform (TIDSortedElemSet & theElems,
5312                              const gp_Trsf&     theTrsf,
5313                              const bool         theCopy,
5314                              const bool         theMakeGroups,
5315                              SMESH_Mesh*        theTargetMesh)
5316 {
5317   myLastCreatedElems.Clear();
5318   myLastCreatedNodes.Clear();
5319
5320   bool needReverse = false;
5321   string groupPostfix;
5322   switch ( theTrsf.Form() ) {
5323   case gp_PntMirror:
5324     MESSAGE("gp_PntMirror");
5325     needReverse = true;
5326     groupPostfix = "mirrored";
5327     break;
5328   case gp_Ax1Mirror:
5329     MESSAGE("gp_Ax1Mirror");
5330     groupPostfix = "mirrored";
5331     break;
5332   case gp_Ax2Mirror:
5333     MESSAGE("gp_Ax2Mirror");
5334     needReverse = true;
5335     groupPostfix = "mirrored";
5336     break;
5337   case gp_Rotation:
5338     MESSAGE("gp_Rotation");
5339     groupPostfix = "rotated";
5340     break;
5341   case gp_Translation:
5342     MESSAGE("gp_Translation");
5343     groupPostfix = "translated";
5344     break;
5345   case gp_Scale:
5346     MESSAGE("gp_Scale");
5347     groupPostfix = "scaled";
5348     break;
5349   case gp_CompoundTrsf: // different scale by axis
5350     MESSAGE("gp_CompoundTrsf");
5351     groupPostfix = "scaled";
5352     break;
5353   default:
5354     MESSAGE("default");
5355     needReverse = false;
5356     groupPostfix = "transformed";
5357   }
5358
5359   SMESH_MeshEditor targetMeshEditor( theTargetMesh );
5360   SMESHDS_Mesh* aTgtMesh = theTargetMesh ? theTargetMesh->GetMeshDS() : 0;
5361   SMESHDS_Mesh* aMesh    = GetMeshDS();
5362
5363
5364   // map old node to new one
5365   TNodeNodeMap nodeMap;
5366
5367   // elements sharing moved nodes; those of them which have all
5368   // nodes mirrored but are not in theElems are to be reversed
5369   TIDSortedElemSet inverseElemSet;
5370
5371   // source elements for each generated one
5372   SMESH_SequenceOfElemPtr srcElems, srcNodes;
5373
5374   // issue 021015: EDF 1578 SMESH: Free nodes are removed when translating a mesh
5375   TIDSortedElemSet orphanNode;
5376
5377   if ( theElems.empty() ) // transform the whole mesh
5378   {
5379     // add all elements
5380     SMDS_ElemIteratorPtr eIt = aMesh->elementsIterator();
5381     while ( eIt->more() ) theElems.insert( eIt->next() );
5382     // add orphan nodes
5383     SMDS_NodeIteratorPtr nIt = aMesh->nodesIterator();
5384     while ( nIt->more() )
5385     {
5386       const SMDS_MeshNode* node = nIt->next();
5387       if ( node->NbInverseElements() == 0)
5388         orphanNode.insert( node );
5389     }
5390   }
5391
5392   // loop on elements to transform nodes : first orphan nodes then elems
5393   TIDSortedElemSet::iterator itElem;
5394   TIDSortedElemSet *elements[] = {&orphanNode, &theElems };
5395   for (int i=0; i<2; i++)
5396   for ( itElem = elements[i]->begin(); itElem != elements[i]->end(); itElem++ ) {
5397     const SMDS_MeshElement* elem = *itElem;
5398     if ( !elem )
5399       continue;
5400
5401     // loop on elem nodes
5402     SMDS_ElemIteratorPtr itN = elem->nodesIterator();
5403     while ( itN->more() ) {
5404
5405       const SMDS_MeshNode* node = cast2Node( itN->next() );
5406       // check if a node has been already transformed
5407       pair<TNodeNodeMap::iterator,bool> n2n_isnew =
5408         nodeMap.insert( make_pair ( node, node ));
5409       if ( !n2n_isnew.second )
5410         continue;
5411
5412       double coord[3];
5413       coord[0] = node->X();
5414       coord[1] = node->Y();
5415       coord[2] = node->Z();
5416       theTrsf.Transforms( coord[0], coord[1], coord[2] );
5417       if ( theTargetMesh ) {
5418         const SMDS_MeshNode * newNode = aTgtMesh->AddNode( coord[0], coord[1], coord[2] );
5419         n2n_isnew.first->second = newNode;
5420         myLastCreatedNodes.Append(newNode);
5421         srcNodes.Append( node );
5422       }
5423       else if ( theCopy ) {
5424         const SMDS_MeshNode * newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
5425         n2n_isnew.first->second = newNode;
5426         myLastCreatedNodes.Append(newNode);
5427         srcNodes.Append( node );
5428       }
5429       else {
5430         aMesh->MoveNode( node, coord[0], coord[1], coord[2] );
5431         // node position on shape becomes invalid
5432         const_cast< SMDS_MeshNode* > ( node )->SetPosition
5433           ( SMDS_SpacePosition::originSpacePosition() );
5434       }
5435
5436       // keep inverse elements
5437       if ( !theCopy && !theTargetMesh && needReverse ) {
5438         SMDS_ElemIteratorPtr invElemIt = node->GetInverseElementIterator();
5439         while ( invElemIt->more() ) {
5440           const SMDS_MeshElement* iel = invElemIt->next();
5441           inverseElemSet.insert( iel );
5442         }
5443       }
5444     }
5445   }
5446
5447   // either create new elements or reverse mirrored ones
5448   if ( !theCopy && !needReverse && !theTargetMesh )
5449     return PGroupIDs();
5450
5451   TIDSortedElemSet::iterator invElemIt = inverseElemSet.begin();
5452   for ( ; invElemIt != inverseElemSet.end(); invElemIt++ )
5453     theElems.insert( *invElemIt );
5454
5455   // replicate or reverse elements
5456   // TODO revoir ordre reverse vtk
5457   enum {
5458     REV_TETRA   = 0,  //  = nbNodes - 4
5459     REV_PYRAMID = 1,  //  = nbNodes - 4
5460     REV_PENTA   = 2,  //  = nbNodes - 4
5461     REV_FACE    = 3,
5462     REV_HEXA    = 4,  //  = nbNodes - 4
5463     FORWARD     = 5
5464   };
5465   int index[][8] = {
5466     { 2, 1, 0, 3, 4, 0, 0, 0 },  // REV_TETRA
5467     { 2, 1, 0, 3, 4, 0, 0, 0 },  // REV_PYRAMID
5468     { 2, 1, 0, 5, 4, 3, 0, 0 },  // REV_PENTA
5469     { 2, 1, 0, 3, 0, 0, 0, 0 },  // REV_FACE
5470     { 2, 1, 0, 3, 6, 5, 4, 7 },  // REV_HEXA
5471     { 0, 1, 2, 3, 4, 5, 6, 7 }   // FORWARD
5472   };
5473
5474   for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ )
5475   {
5476     const SMDS_MeshElement* elem = *itElem;
5477     if ( !elem || elem->GetType() == SMDSAbs_Node )
5478       continue;
5479
5480     int nbNodes = elem->NbNodes();
5481     int elemType = elem->GetType();
5482
5483     if (elem->IsPoly()) {
5484       // Polygon or Polyhedral Volume
5485       switch ( elemType ) {
5486       case SMDSAbs_Face:
5487         {
5488           vector<const SMDS_MeshNode*> poly_nodes (nbNodes);
5489           int iNode = 0;
5490           SMDS_ElemIteratorPtr itN = elem->nodesIterator();
5491           while (itN->more()) {
5492             const SMDS_MeshNode* node =
5493               static_cast<const SMDS_MeshNode*>(itN->next());
5494             TNodeNodeMap::iterator nodeMapIt = nodeMap.find(node);
5495             if (nodeMapIt == nodeMap.end())
5496               break; // not all nodes transformed
5497             if (needReverse) {
5498               // reverse mirrored faces and volumes
5499               poly_nodes[nbNodes - iNode - 1] = (*nodeMapIt).second;
5500             } else {
5501               poly_nodes[iNode] = (*nodeMapIt).second;
5502             }
5503             iNode++;
5504           }
5505           if ( iNode != nbNodes )
5506             continue; // not all nodes transformed
5507
5508           if ( theTargetMesh ) {
5509             myLastCreatedElems.Append(aTgtMesh->AddPolygonalFace(poly_nodes));
5510             srcElems.Append( elem );
5511           }
5512           else if ( theCopy ) {
5513             myLastCreatedElems.Append(aMesh->AddPolygonalFace(poly_nodes));
5514             srcElems.Append( elem );
5515           }
5516           else {
5517             aMesh->ChangePolygonNodes(elem, poly_nodes);
5518           }
5519         }
5520         break;
5521       case SMDSAbs_Volume:
5522         {
5523           // ATTENTION: Reversing is not yet done!!!
5524           const SMDS_VtkVolume* aPolyedre =
5525             dynamic_cast<const SMDS_VtkVolume*>( elem );
5526           if (!aPolyedre) {
5527             MESSAGE("Warning: bad volumic element");
5528             continue;
5529           }
5530
5531           vector<const SMDS_MeshNode*> poly_nodes;
5532           vector<int> quantities;
5533
5534           bool allTransformed = true;
5535           int nbFaces = aPolyedre->NbFaces();
5536           for (int iface = 1; iface <= nbFaces && allTransformed; iface++) {
5537             int nbFaceNodes = aPolyedre->NbFaceNodes(iface);
5538             for (int inode = 1; inode <= nbFaceNodes && allTransformed; inode++) {
5539               const SMDS_MeshNode* node = aPolyedre->GetFaceNode(iface, inode);
5540               TNodeNodeMap::iterator nodeMapIt = nodeMap.find(node);
5541               if (nodeMapIt == nodeMap.end()) {
5542                 allTransformed = false; // not all nodes transformed
5543               } else {
5544                 poly_nodes.push_back((*nodeMapIt).second);
5545               }
5546             }
5547             quantities.push_back(nbFaceNodes);
5548           }
5549           if ( !allTransformed )
5550             continue; // not all nodes transformed
5551
5552           if ( theTargetMesh ) {
5553             myLastCreatedElems.Append(aTgtMesh->AddPolyhedralVolume(poly_nodes, quantities));
5554             srcElems.Append( elem );
5555           }
5556           else if ( theCopy ) {
5557             myLastCreatedElems.Append(aMesh->AddPolyhedralVolume(poly_nodes, quantities));
5558             srcElems.Append( elem );
5559           }
5560           else {
5561             aMesh->ChangePolyhedronNodes(elem, poly_nodes, quantities);
5562           }
5563         }
5564         break;
5565       default:;
5566       }
5567       continue;
5568     }
5569
5570     // Regular elements
5571     int* i = index[ FORWARD ];
5572     if ( needReverse && nbNodes > 2) {// reverse mirrored faces and volumes
5573       if ( elemType == SMDSAbs_Face )
5574         i = index[ REV_FACE ];
5575       else
5576         i = index[ nbNodes - 4 ];
5577     }
5578     if(elem->IsQuadratic()) {
5579       static int anIds[] = {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19};
5580       i = anIds;
5581       if(needReverse) {
5582         if(nbNodes==3) { // quadratic edge
5583           static int anIds[] = {1,0,2};
5584           i = anIds;
5585         }
5586         else if(nbNodes==6) { // quadratic triangle
5587           static int anIds[] = {0,2,1,5,4,3};
5588           i = anIds;
5589         }
5590         else if(nbNodes==8) { // quadratic quadrangle
5591           static int anIds[] = {0,3,2,1,7,6,5,4};
5592           i = anIds;
5593         }
5594         else if(nbNodes==10) { // quadratic tetrahedron of 10 nodes
5595           static int anIds[] = {0,2,1,3,6,5,4,7,9,8};
5596           i = anIds;
5597         }
5598         else if(nbNodes==13) { // quadratic pyramid of 13 nodes
5599           static int anIds[] = {0,3,2,1,4,8,7,6,5,9,12,11,10};
5600           i = anIds;
5601         }
5602         else if(nbNodes==15) { // quadratic pentahedron with 15 nodes
5603           static int anIds[] = {0,2,1,3,5,4,8,7,6,11,10,9,12,14,13};
5604           i = anIds;
5605         }
5606         else { // nbNodes==20 - quadratic hexahedron with 20 nodes
5607           static int anIds[] = {0,3,2,1,4,7,6,5,11,10,9,8,15,14,13,12,16,19,18,17};
5608           i = anIds;
5609         }
5610       }
5611     }
5612
5613     // find transformed nodes
5614     vector<const SMDS_MeshNode*> nodes(nbNodes);
5615     int iNode = 0;
5616     SMDS_ElemIteratorPtr itN = elem->nodesIterator();
5617     while ( itN->more() ) {
5618       const SMDS_MeshNode* node =
5619         static_cast<const SMDS_MeshNode*>( itN->next() );
5620       TNodeNodeMap::iterator nodeMapIt = nodeMap.find( node );
5621       if ( nodeMapIt == nodeMap.end() )
5622         break; // not all nodes transformed
5623       nodes[ i [ iNode++ ]] = (*nodeMapIt).second;
5624     }
5625     if ( iNode != nbNodes )
5626       continue; // not all nodes transformed
5627
5628     if ( theTargetMesh ) {
5629       if ( SMDS_MeshElement* copy =
5630            targetMeshEditor.AddElement( nodes, elem->GetType(), elem->IsPoly() )) {
5631         myLastCreatedElems.Append( copy );
5632         srcElems.Append( elem );
5633       }
5634     }
5635     else if ( theCopy ) {
5636       if ( AddElement( nodes, elem->GetType(), elem->IsPoly() ))
5637         srcElems.Append( elem );
5638     }
5639     else {
5640       // reverse element as it was reversed by transformation
5641       if ( nbNodes > 2 )
5642         aMesh->ChangeElementNodes( elem, &nodes[0], nbNodes );
5643     }
5644   }
5645
5646   PGroupIDs newGroupIDs;
5647
5648   if ( theMakeGroups && theCopy ||
5649        theMakeGroups && theTargetMesh )
5650     newGroupIDs = generateGroups( srcNodes, srcElems, groupPostfix, theTargetMesh );
5651
5652   return newGroupIDs;
5653 }
5654
5655
5656 ////=======================================================================
5657 ////function : Scale
5658 ////purpose  :
5659 ////=======================================================================
5660 //
5661 //SMESH_MeshEditor::PGroupIDs
5662 //SMESH_MeshEditor::Scale (TIDSortedElemSet & theElems,
5663 //                         const gp_Pnt&            thePoint,
5664 //                         const std::list<double>& theScaleFact,
5665 //                         const bool         theCopy,
5666 //                         const bool         theMakeGroups,
5667 //                         SMESH_Mesh*        theTargetMesh)
5668 //{
5669 //  MESSAGE("Scale");
5670 //  myLastCreatedElems.Clear();
5671 //  myLastCreatedNodes.Clear();
5672 //
5673 //  SMESH_MeshEditor targetMeshEditor( theTargetMesh );
5674 //  SMESHDS_Mesh* aTgtMesh = theTargetMesh ? theTargetMesh->GetMeshDS() : 0;
5675 //  SMESHDS_Mesh* aMesh    = GetMeshDS();
5676 //
5677 //  double scaleX=1.0, scaleY=1.0, scaleZ=1.0;
5678 //  std::list<double>::const_iterator itS = theScaleFact.begin();
5679 //  scaleX = (*itS);
5680 //  if(theScaleFact.size()==1) {
5681 //    scaleY = (*itS);
5682 //    scaleZ= (*itS);
5683 //  }
5684 //  if(theScaleFact.size()==2) {
5685 //    itS++;
5686 //    scaleY = (*itS);
5687 //    scaleZ= (*itS);
5688 //  }
5689 //  if(theScaleFact.size()>2) {
5690 //    itS++;
5691 //    scaleY = (*itS);
5692 //    itS++;
5693 //    scaleZ= (*itS);
5694 //  }
5695 //
5696 //  // map old node to new one
5697 //  TNodeNodeMap nodeMap;
5698 //
5699 //  // elements sharing moved nodes; those of them which have all
5700 //  // nodes mirrored but are not in theElems are to be reversed
5701 //  TIDSortedElemSet inverseElemSet;
5702 //
5703 //  // source elements for each generated one
5704 //  SMESH_SequenceOfElemPtr srcElems, srcNodes;
5705 //
5706 //  // loop on theElems
5707 //  TIDSortedElemSet::iterator itElem;
5708 //  for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
5709 //    const SMDS_MeshElement* elem = *itElem;
5710 //    if ( !elem )
5711 //      continue;
5712 //
5713 //    // loop on elem nodes
5714 //    SMDS_ElemIteratorPtr itN = elem->nodesIterator();
5715 //    while ( itN->more() ) {
5716 //
5717 //      // check if a node has been already transformed
5718 //      const SMDS_MeshNode* node = cast2Node( itN->next() );
5719 //      pair<TNodeNodeMap::iterator,bool> n2n_isnew =
5720 //        nodeMap.insert( make_pair ( node, node ));
5721 //      if ( !n2n_isnew.second )
5722 //        continue;
5723 //
5724 //      //double coord[3];
5725 //      //coord[0] = node->X();
5726 //      //coord[1] = node->Y();
5727 //      //coord[2] = node->Z();
5728 //      //theTrsf.Transforms( coord[0], coord[1], coord[2] );
5729 //      double dx = (node->X() - thePoint.X()) * scaleX;
5730 //      double dy = (node->Y() - thePoint.Y()) * scaleY;
5731 //      double dz = (node->Z() - thePoint.Z()) * scaleZ;
5732 //      if ( theTargetMesh ) {
5733 //        //const SMDS_MeshNode * newNode = aTgtMesh->AddNode( coord[0], coord[1], coord[2] );
5734 //        const SMDS_MeshNode * newNode =
5735 //          aTgtMesh->AddNode( thePoint.X()+dx, thePoint.Y()+dy, thePoint.Z()+dz );
5736 //        n2n_isnew.first->second = newNode;
5737 //        myLastCreatedNodes.Append(newNode);
5738 //        srcNodes.Append( node );
5739 //      }
5740 //      else if ( theCopy ) {
5741 //        //const SMDS_MeshNode * newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
5742 //        const SMDS_MeshNode * newNode =
5743 //          aMesh->AddNode( thePoint.X()+dx, thePoint.Y()+dy, thePoint.Z()+dz );
5744 //        n2n_isnew.first->second = newNode;
5745 //        myLastCreatedNodes.Append(newNode);
5746 //        srcNodes.Append( node );
5747 //      }
5748 //      else {
5749 //        //aMesh->MoveNode( node, coord[0], coord[1], coord[2] );
5750 //        aMesh->MoveNode( node, thePoint.X()+dx, thePoint.Y()+dy, thePoint.Z()+dz );
5751 //        // node position on shape becomes invalid
5752 //        const_cast< SMDS_MeshNode* > ( node )->SetPosition
5753 //          ( SMDS_SpacePosition::originSpacePosition() );
5754 //      }
5755 //
5756 //      // keep inverse elements
5757 //      //if ( !theCopy && !theTargetMesh && needReverse ) {
5758 //      //  SMDS_ElemIteratorPtr invElemIt = node->GetInverseElementIterator();
5759 //      //  while ( invElemIt->more() ) {
5760 //      //    const SMDS_MeshElement* iel = invElemIt->next();
5761 //      //    inverseElemSet.insert( iel );
5762 //      //  }
5763 //      //}
5764 //    }
5765 //  }
5766 //
5767 //  // either create new elements or reverse mirrored ones
5768 //  //if ( !theCopy && !needReverse && !theTargetMesh )
5769 //  if ( !theCopy && !theTargetMesh )
5770 //    return PGroupIDs();
5771 //
5772 //  TIDSortedElemSet::iterator invElemIt = inverseElemSet.begin();
5773 //  for ( ; invElemIt != inverseElemSet.end(); invElemIt++ )
5774 //    theElems.insert( *invElemIt );
5775 //
5776 //  // replicate or reverse elements
5777 //
5778 //  enum {
5779 //    REV_TETRA   = 0,  //  = nbNodes - 4
5780 //    REV_PYRAMID = 1,  //  = nbNodes - 4
5781 //    REV_PENTA   = 2,  //  = nbNodes - 4
5782 //    REV_FACE    = 3,
5783 //    REV_HEXA    = 4,  //  = nbNodes - 4
5784 //    FORWARD     = 5
5785 //  };
5786 //  int index[][8] = {
5787 //    { 2, 1, 0, 3, 4, 0, 0, 0 },  // REV_TETRA
5788 //    { 2, 1, 0, 3, 4, 0, 0, 0 },  // REV_PYRAMID
5789 //    { 2, 1, 0, 5, 4, 3, 0, 0 },  // REV_PENTA
5790 //    { 2, 1, 0, 3, 0, 0, 0, 0 },  // REV_FACE
5791 //    { 2, 1, 0, 3, 6, 5, 4, 7 },  // REV_HEXA
5792 //    { 0, 1, 2, 3, 4, 5, 6, 7 }   // FORWARD
5793 //  };
5794 //
5795 //  for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ )
5796 //  {
5797 //    const SMDS_MeshElement* elem = *itElem;
5798 //    if ( !elem || elem->GetType() == SMDSAbs_Node )
5799 //      continue;
5800 //
5801 //    int nbNodes = elem->NbNodes();
5802 //    int elemType = elem->GetType();
5803 //
5804 //    if (elem->IsPoly()) {
5805 //      // Polygon or Polyhedral Volume
5806 //      switch ( elemType ) {
5807 //      case SMDSAbs_Face:
5808 //        {
5809 //          vector<const SMDS_MeshNode*> poly_nodes (nbNodes);
5810 //          int iNode = 0;
5811 //          SMDS_ElemIteratorPtr itN = elem->nodesIterator();
5812 //          while (itN->more()) {
5813 //            const SMDS_MeshNode* node =
5814 //              static_cast<const SMDS_MeshNode*>(itN->next());
5815 //            TNodeNodeMap::iterator nodeMapIt = nodeMap.find(node);
5816 //            if (nodeMapIt == nodeMap.end())
5817 //              break; // not all nodes transformed
5818 //            //if (needReverse) {
5819 //            //  // reverse mirrored faces and volumes
5820 //            //  poly_nodes[nbNodes - iNode - 1] = (*nodeMapIt).second;
5821 //            //} else {
5822 //            poly_nodes[iNode] = (*nodeMapIt).second;
5823 //            //}
5824 //            iNode++;
5825 //          }
5826 //          if ( iNode != nbNodes )
5827 //            continue; // not all nodes transformed
5828 //
5829 //          if ( theTargetMesh ) {
5830 //            myLastCreatedElems.Append(aTgtMesh->AddPolygonalFace(poly_nodes));
5831 //            srcElems.Append( elem );
5832 //          }
5833 //          else if ( theCopy ) {
5834 //            myLastCreatedElems.Append(aMesh->AddPolygonalFace(poly_nodes));
5835 //            srcElems.Append( elem );
5836 //          }
5837 //          else {
5838 //            aMesh->ChangePolygonNodes(elem, poly_nodes);
5839 //          }
5840 //        }
5841 //        break;
5842 //      case SMDSAbs_Volume:
5843 //        {
5844 //          // ATTENTION: Reversing is not yet done!!!
5845 //          const SMDS_VtkVolume* aPolyedre =
5846 //            dynamic_cast<const SMDS_VtkVolume*>( elem );
5847 //          if (!aPolyedre) {
5848 //            MESSAGE("Warning: bad volumic element");
5849 //            continue;
5850 //          }
5851 //
5852 //          vector<const SMDS_MeshNode*> poly_nodes;
5853 //          vector<int> quantities;
5854 //
5855 //          bool allTransformed = true;
5856 //          int nbFaces = aPolyedre->NbFaces();
5857 //          for (int iface = 1; iface <= nbFaces && allTransformed; iface++) {
5858 //            int nbFaceNodes = aPolyedre->NbFaceNodes(iface);
5859 //            for (int inode = 1; inode <= nbFaceNodes && allTransformed; inode++) {
5860 //              const SMDS_MeshNode* node = aPolyedre->GetFaceNode(iface, inode);
5861 //              TNodeNodeMap::iterator nodeMapIt = nodeMap.find(node);
5862 //              if (nodeMapIt == nodeMap.end()) {
5863 //                allTransformed = false; // not all nodes transformed
5864 //              } else {
5865 //                poly_nodes.push_back((*nodeMapIt).second);
5866 //              }
5867 //            }
5868 //            quantities.push_back(nbFaceNodes);
5869 //          }
5870 //          if ( !allTransformed )
5871 //            continue; // not all nodes transformed
5872 //
5873 //          if ( theTargetMesh ) {
5874 //            myLastCreatedElems.Append(aTgtMesh->AddPolyhedralVolume(poly_nodes, quantities));
5875 //            srcElems.Append( elem );
5876 //          }
5877 //          else if ( theCopy ) {
5878 //            myLastCreatedElems.Append(aMesh->AddPolyhedralVolume(poly_nodes, quantities));
5879 //            srcElems.Append( elem );
5880 //          }
5881 //          else {
5882 //            aMesh->ChangePolyhedronNodes(elem, poly_nodes, quantities);
5883 //          }
5884 //        }
5885 //        break;
5886 //      default:;
5887 //      }
5888 //      continue;
5889 //    }
5890 //
5891 //    // Regular elements
5892 //    int* i = index[ FORWARD ];
5893 //    //if ( needReverse && nbNodes > 2) // reverse mirrored faces and volumes
5894 //    //  if ( elemType == SMDSAbs_Face )
5895 //    //    i = index[ REV_FACE ];
5896 //    //  else
5897 //    //    i = index[ nbNodes - 4 ];
5898 //
5899 //    if(elem->IsQuadratic()) {
5900 //      static int anIds[] = {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19};
5901 //      i = anIds;
5902 //      //if(needReverse) {
5903 //      //  if(nbNodes==3) { // quadratic edge
5904 //      //    static int anIds[] = {1,0,2};
5905 //      //    i = anIds;
5906 //      //  }
5907 //      //  else if(nbNodes==6) { // quadratic triangle
5908 //      //    static int anIds[] = {0,2,1,5,4,3};
5909 //      //    i = anIds;
5910 //      //  }
5911 //      //  else if(nbNodes==8) { // quadratic quadrangle
5912 //      //    static int anIds[] = {0,3,2,1,7,6,5,4};
5913 //      //    i = anIds;
5914 //      //  }
5915 //      //  else if(nbNodes==10) { // quadratic tetrahedron of 10 nodes
5916 //      //    static int anIds[] = {0,2,1,3,6,5,4,7,9,8};
5917 //      //    i = anIds;
5918 //      //  }
5919 //      //  else if(nbNodes==13) { // quadratic pyramid of 13 nodes
5920 //      //    static int anIds[] = {0,3,2,1,4,8,7,6,5,9,12,11,10};
5921 //      //    i = anIds;
5922 //      //  }
5923 //      //  else if(nbNodes==15) { // quadratic pentahedron with 15 nodes
5924 //      //    static int anIds[] = {0,2,1,3,5,4,8,7,6,11,10,9,12,14,13};
5925 //      //    i = anIds;
5926 //      //  }
5927 //      //  else { // nbNodes==20 - quadratic hexahedron with 20 nodes
5928 //      //    static int anIds[] = {0,3,2,1,4,7,6,5,11,10,9,8,15,14,13,12,16,19,18,17};
5929 //      //    i = anIds;
5930 //      //  }
5931 //      //}
5932 //    }
5933 //
5934 //    // find transformed nodes
5935 //    vector<const SMDS_MeshNode*> nodes(nbNodes);
5936 //    int iNode = 0;
5937 //    SMDS_ElemIteratorPtr itN = elem->nodesIterator();
5938 //    while ( itN->more() ) {
5939 //      const SMDS_MeshNode* node =
5940 //        static_cast<const SMDS_MeshNode*>( itN->next() );
5941 //      TNodeNodeMap::iterator nodeMapIt = nodeMap.find( node );
5942 //      if ( nodeMapIt == nodeMap.end() )
5943 //        break; // not all nodes transformed
5944 //      nodes[ i [ iNode++ ]] = (*nodeMapIt).second;
5945 //    }
5946 //    if ( iNode != nbNodes )
5947 //      continue; // not all nodes transformed
5948 //
5949 //    if ( theTargetMesh ) {
5950 //      if ( SMDS_MeshElement* copy =
5951 //           targetMeshEditor.AddElement( nodes, elem->GetType(), elem->IsPoly() )) {
5952 //        myLastCreatedElems.Append( copy );
5953 //        srcElems.Append( elem );
5954 //      }
5955 //    }
5956 //    else if ( theCopy ) {
5957 //      if ( SMDS_MeshElement* copy = AddElement( nodes, elem->GetType(), elem->IsPoly() )) {
5958 //        myLastCreatedElems.Append( copy );
5959 //        srcElems.Append( elem );
5960 //      }
5961 //    }
5962 //    else {
5963 //      // reverse element as it was reversed by transformation
5964 //      if ( nbNodes > 2 )
5965 //        aMesh->ChangeElementNodes( elem, &nodes[0], nbNodes );
5966 //    }
5967 //  }
5968 //
5969 //  PGroupIDs newGroupIDs;
5970 //
5971 //  if ( theMakeGroups && theCopy ||
5972 //       theMakeGroups && theTargetMesh ) {
5973 //    string groupPostfix = "scaled";
5974 //    newGroupIDs = generateGroups( srcNodes, srcElems, groupPostfix, theTargetMesh );
5975 //  }
5976 //
5977 //  return newGroupIDs;
5978 //}
5979
5980
5981 //=======================================================================
5982 /*!
5983  * \brief Create groups of elements made during transformation
5984  * \param nodeGens - nodes making corresponding myLastCreatedNodes
5985  * \param elemGens - elements making corresponding myLastCreatedElems
5986  * \param postfix - to append to names of new groups
5987  */
5988 //=======================================================================
5989
5990 SMESH_MeshEditor::PGroupIDs
5991 SMESH_MeshEditor::generateGroups(const SMESH_SequenceOfElemPtr& nodeGens,
5992                                  const SMESH_SequenceOfElemPtr& elemGens,
5993                                  const std::string&             postfix,
5994                                  SMESH_Mesh*                    targetMesh)
5995 {
5996   PGroupIDs newGroupIDs( new list<int> );
5997   SMESH_Mesh* mesh = targetMesh ? targetMesh : GetMesh();
5998
5999   // Sort existing groups by types and collect their names
6000
6001   // to store an old group and a generated new one
6002   typedef pair< SMESHDS_GroupBase*, SMDS_MeshGroup* > TOldNewGroup;
6003   vector< list< TOldNewGroup > > groupsByType( SMDSAbs_NbElementTypes );
6004   // group names
6005   set< string > groupNames;
6006   //
6007   SMDS_MeshGroup* nullNewGroup = (SMDS_MeshGroup*) 0;
6008   SMESH_Mesh::GroupIteratorPtr groupIt = GetMesh()->GetGroups();
6009   while ( groupIt->more() ) {
6010     SMESH_Group * group = groupIt->next();
6011     if ( !group ) continue;
6012     SMESHDS_GroupBase* groupDS = group->GetGroupDS();
6013     if ( !groupDS || groupDS->IsEmpty() ) continue;
6014     groupNames.insert( group->GetName() );
6015     groupDS->SetStoreName( group->GetName() );
6016     groupsByType[ groupDS->GetType() ].push_back( make_pair( groupDS, nullNewGroup ));
6017   }
6018
6019   // Groups creation
6020
6021   // loop on nodes and elements
6022   for ( int isNodes = 0; isNodes < 2; ++isNodes )
6023   {
6024     const SMESH_SequenceOfElemPtr& gens  = isNodes ? nodeGens : elemGens;
6025     const SMESH_SequenceOfElemPtr& elems = isNodes ? myLastCreatedNodes : myLastCreatedElems;
6026     if ( gens.Length() != elems.Length() )
6027       throw SALOME_Exception(LOCALIZED("invalid args"));
6028
6029     // loop on created elements
6030     for (int iElem = 1; iElem <= elems.Length(); ++iElem )
6031     {
6032       const SMDS_MeshElement* sourceElem = gens( iElem );
6033       if ( !sourceElem ) {
6034         MESSAGE("generateGroups(): NULL source element");
6035         continue;
6036       }
6037       list< TOldNewGroup > & groupsOldNew = groupsByType[ sourceElem->GetType() ];
6038       if ( groupsOldNew.empty() ) {
6039         while ( iElem < gens.Length() && gens( iElem+1 ) == sourceElem )
6040           ++iElem; // skip all elements made by sourceElem
6041         continue;
6042       }
6043       // collect all elements made by sourceElem
6044       list< const SMDS_MeshElement* > resultElems;
6045       if ( const SMDS_MeshElement* resElem = elems( iElem ))
6046         if ( resElem != sourceElem )
6047           resultElems.push_back( resElem );
6048       while ( iElem < gens.Length() && gens( iElem+1 ) == sourceElem )
6049         if ( const SMDS_MeshElement* resElem = elems( ++iElem ))
6050           if ( resElem != sourceElem )
6051             resultElems.push_back( resElem );
6052       // do not generate element groups from node ones
6053       if ( sourceElem->GetType() == SMDSAbs_Node &&
6054            elems( iElem )->GetType() != SMDSAbs_Node )
6055         continue;
6056
6057       // add resultElems to groups made by ones the sourceElem belongs to
6058       list< TOldNewGroup >::iterator gOldNew, gLast = groupsOldNew.end();
6059       for ( gOldNew = groupsOldNew.begin(); gOldNew != gLast; ++gOldNew )
6060       {
6061         SMESHDS_GroupBase* oldGroup = gOldNew->first;
6062         if ( oldGroup->Contains( sourceElem )) // sourceElem in oldGroup
6063         {
6064           SMDS_MeshGroup* & newGroup = gOldNew->second;
6065           if ( !newGroup )// create a new group
6066           {
6067             // make a name
6068             string name = oldGroup->GetStoreName();
6069             if ( !targetMesh ) {
6070               name += "_";
6071               name += postfix;
6072               int nb = 0;
6073               while ( !groupNames.insert( name ).second ) // name exists
6074               {
6075                 if ( nb == 0 ) {
6076                   name += "_1";
6077                 }
6078                 else {
6079                   TCollection_AsciiString nbStr(nb+1);
6080                   name.resize( name.rfind('_')+1 );
6081                   name += nbStr.ToCString();
6082                 }
6083                 ++nb;
6084               }
6085             }
6086             // make a group
6087             int id;
6088             SMESH_Group* group = mesh->AddGroup( resultElems.back()->GetType(),
6089                                                  name.c_str(), id );
6090             SMESHDS_Group* groupDS = static_cast<SMESHDS_Group*>(group->GetGroupDS());
6091             newGroup = & groupDS->SMDSGroup();
6092             newGroupIDs->push_back( id );
6093           }
6094
6095           // fill in a new group
6096           list< const SMDS_MeshElement* >::iterator resLast = resultElems.end(), resElemIt;
6097           for ( resElemIt = resultElems.begin(); resElemIt != resLast; ++resElemIt )
6098             newGroup->Add( *resElemIt );
6099         }
6100       }
6101     } // loop on created elements
6102   }// loop on nodes and elements
6103
6104   return newGroupIDs;
6105 }
6106
6107 //================================================================================
6108 /*!
6109  * \brief Return list of group of nodes close to each other within theTolerance
6110  *        Search among theNodes or in the whole mesh if theNodes is empty using
6111  *        an Octree algorithm
6112  */
6113 //================================================================================
6114
6115 void SMESH_MeshEditor::FindCoincidentNodes (TIDSortedNodeSet &   theNodes,
6116                                             const double         theTolerance,
6117                                             TListOfListOfNodes & theGroupsOfNodes)
6118 {
6119   myLastCreatedElems.Clear();
6120   myLastCreatedNodes.Clear();
6121
6122   if ( theNodes.empty() )
6123   { // get all nodes in the mesh
6124     SMDS_NodeIteratorPtr nIt = GetMeshDS()->nodesIterator(/*idInceasingOrder=*/true);
6125     while ( nIt->more() )
6126       theNodes.insert( theNodes.end(),nIt->next());
6127   }
6128
6129   SMESH_OctreeNode::FindCoincidentNodes ( theNodes, &theGroupsOfNodes, theTolerance);
6130 }
6131
6132
6133 //=======================================================================
6134 /*!
6135  * \brief Implementation of search for the node closest to point
6136  */
6137 //=======================================================================
6138
6139 struct SMESH_NodeSearcherImpl: public SMESH_NodeSearcher
6140 {
6141   //---------------------------------------------------------------------
6142   /*!
6143    * \brief Constructor
6144    */
6145   SMESH_NodeSearcherImpl( const SMESHDS_Mesh* theMesh )
6146   {
6147     myMesh = ( SMESHDS_Mesh* ) theMesh;
6148
6149     TIDSortedNodeSet nodes;
6150     if ( theMesh ) {
6151       SMDS_NodeIteratorPtr nIt = theMesh->nodesIterator(/*idInceasingOrder=*/true);
6152       while ( nIt->more() )
6153         nodes.insert( nodes.end(), nIt->next() );
6154     }
6155     myOctreeNode = new SMESH_OctreeNode(nodes) ;
6156
6157     // get max size of a leaf box
6158     SMESH_OctreeNode* tree = myOctreeNode;
6159     while ( !tree->isLeaf() )
6160     {
6161       SMESH_OctreeNodeIteratorPtr cIt = tree->GetChildrenIterator();
6162       if ( cIt->more() )
6163         tree = cIt->next();
6164     }
6165     myHalfLeafSize = tree->maxSize() / 2.;
6166   }
6167
6168   //---------------------------------------------------------------------
6169   /*!
6170    * \brief Move node and update myOctreeNode accordingly
6171    */
6172   void MoveNode( const SMDS_MeshNode* node, const gp_Pnt& toPnt )
6173   {
6174     myOctreeNode->UpdateByMoveNode( node, toPnt );
6175     myMesh->MoveNode( node, toPnt.X(), toPnt.Y(), toPnt.Z() );
6176   }
6177
6178   //---------------------------------------------------------------------
6179   /*!
6180    * \brief Do it's job
6181    */
6182   const SMDS_MeshNode* FindClosestTo( const gp_Pnt& thePnt )
6183   {
6184     map<double, const SMDS_MeshNode*> dist2Nodes;
6185     myOctreeNode->NodesAround( thePnt.Coord(), dist2Nodes, myHalfLeafSize );
6186     if ( !dist2Nodes.empty() )
6187       return dist2Nodes.begin()->second;
6188     list<const SMDS_MeshNode*> nodes;
6189     //myOctreeNode->NodesAround( &tgtNode, &nodes, myHalfLeafSize );
6190
6191     double minSqDist = DBL_MAX;
6192     if ( nodes.empty() )  // get all nodes of OctreeNode's closest to thePnt
6193     {
6194       // sort leafs by their distance from thePnt
6195       typedef map< double, SMESH_OctreeNode* > TDistTreeMap;
6196       TDistTreeMap treeMap;
6197       list< SMESH_OctreeNode* > treeList;
6198       list< SMESH_OctreeNode* >::iterator trIt;
6199       treeList.push_back( myOctreeNode );
6200
6201       gp_XYZ pointNode( thePnt.X(), thePnt.Y(), thePnt.Z() );
6202       bool pointInside = myOctreeNode->isInside( pointNode, myHalfLeafSize );
6203       for ( trIt = treeList.begin(); trIt != treeList.end(); ++trIt)
6204       {
6205         SMESH_OctreeNode* tree = *trIt;
6206         if ( !tree->isLeaf() ) // put children to the queue
6207         {
6208           if ( pointInside && !tree->isInside( pointNode, myHalfLeafSize )) continue;
6209           SMESH_OctreeNodeIteratorPtr cIt = tree->GetChildrenIterator();
6210           while ( cIt->more() )
6211             treeList.push_back( cIt->next() );
6212         }
6213         else if ( tree->NbNodes() ) // put a tree to the treeMap
6214         {
6215           const Bnd_B3d& box = tree->getBox();
6216           double sqDist = thePnt.SquareDistance( 0.5 * ( box.CornerMin() + box.CornerMax() ));
6217           pair<TDistTreeMap::iterator,bool> it_in = treeMap.insert( make_pair( sqDist, tree ));
6218           if ( !it_in.second ) // not unique distance to box center
6219             treeMap.insert( it_in.first, make_pair( sqDist + 1e-13*treeMap.size(), tree ));
6220         }
6221       }
6222       // find distance after which there is no sense to check tree's
6223       double sqLimit = DBL_MAX;
6224       TDistTreeMap::iterator sqDist_tree = treeMap.begin();
6225       if ( treeMap.size() > 5 ) {
6226         SMESH_OctreeNode* closestTree = sqDist_tree->second;
6227         const Bnd_B3d& box = closestTree->getBox();
6228         double limit = sqrt( sqDist_tree->first ) + sqrt ( box.SquareExtent() );
6229         sqLimit = limit * limit;
6230       }
6231       // get all nodes from trees
6232       for ( ; sqDist_tree != treeMap.end(); ++sqDist_tree) {
6233         if ( sqDist_tree->first > sqLimit )
6234           break;
6235         SMESH_OctreeNode* tree = sqDist_tree->second;
6236         tree->NodesAround( tree->GetNodeIterator()->next(), &nodes );
6237       }
6238     }
6239     // find closest among nodes
6240     minSqDist = DBL_MAX;
6241     const SMDS_MeshNode* closestNode = 0;
6242     list<const SMDS_MeshNode*>::iterator nIt = nodes.begin();
6243     for ( ; nIt != nodes.end(); ++nIt ) {
6244       double sqDist = thePnt.SquareDistance( SMESH_MeshEditor::TNodeXYZ( *nIt ) );
6245       if ( minSqDist > sqDist ) {
6246         closestNode = *nIt;
6247         minSqDist = sqDist;
6248       }
6249     }
6250     return closestNode;
6251   }
6252
6253   //---------------------------------------------------------------------
6254   /*!
6255    * \brief Destructor
6256    */
6257   ~SMESH_NodeSearcherImpl() { delete myOctreeNode; }
6258
6259   //---------------------------------------------------------------------
6260   /*!
6261    * \brief Return the node tree
6262    */
6263   const SMESH_OctreeNode* getTree() const { return myOctreeNode; }
6264
6265 private:
6266   SMESH_OctreeNode* myOctreeNode;
6267   SMESHDS_Mesh*     myMesh;
6268   double            myHalfLeafSize; // max size of a leaf box
6269 };
6270
6271 //=======================================================================
6272 /*!
6273  * \brief Return SMESH_NodeSearcher
6274  */
6275 //=======================================================================
6276
6277 SMESH_NodeSearcher* SMESH_MeshEditor::GetNodeSearcher() 
6278 {
6279   return new SMESH_NodeSearcherImpl( GetMeshDS() );
6280 }
6281
6282 // ========================================================================
6283 namespace // Utils used in SMESH_ElementSearcherImpl::FindElementsByPoint()
6284 {
6285   const int MaxNbElemsInLeaf = 10; // maximal number of elements in a leaf of tree
6286   const int MaxLevel         = 7;  // maximal tree height -> nb terminal boxes: 8^7 = 2097152
6287   const double NodeRadius = 1e-9;  // to enlarge bnd box of element
6288
6289   //=======================================================================
6290   /*!
6291    * \brief Octal tree of bounding boxes of elements
6292    */
6293   //=======================================================================
6294
6295   class ElementBndBoxTree : public SMESH_Octree
6296   {
6297   public:
6298
6299     ElementBndBoxTree(const SMDS_Mesh& mesh, SMDSAbs_ElementType elemType, double tolerance = NodeRadius );
6300     void getElementsNearPoint( const gp_Pnt& point, TIDSortedElemSet& foundElems);
6301     void getElementsNearLine ( const gp_Ax1& line, TIDSortedElemSet& foundElems);
6302     ~ElementBndBoxTree();
6303
6304   protected:
6305     ElementBndBoxTree() {}
6306     SMESH_Octree* allocateOctreeChild() const { return new ElementBndBoxTree; }
6307     void buildChildrenData();
6308     Bnd_B3d* buildRootBox();
6309   private:
6310     //!< Bounding box of element
6311     struct ElementBox : public Bnd_B3d
6312     {
6313       const SMDS_MeshElement* _element;
6314       int                     _refCount; // an ElementBox can be included in several tree branches
6315       ElementBox(const SMDS_MeshElement* elem, double tolerance);
6316     };
6317     vector< ElementBox* > _elements;
6318   };
6319
6320   //================================================================================
6321   /*!
6322    * \brief ElementBndBoxTree creation
6323    */
6324   //================================================================================
6325
6326   ElementBndBoxTree::ElementBndBoxTree(const SMDS_Mesh& mesh, SMDSAbs_ElementType elemType, double tolerance)
6327     :SMESH_Octree( new SMESH_Octree::Limit( MaxLevel, /*minSize=*/0. ))
6328   {
6329     int nbElems = mesh.GetMeshInfo().NbElements( elemType );
6330     _elements.reserve( nbElems );
6331
6332     SMDS_ElemIteratorPtr elemIt = mesh.elementsIterator( elemType );
6333     while ( elemIt->more() )
6334       _elements.push_back( new ElementBox( elemIt->next(),tolerance  ));
6335
6336     if ( _elements.size() > MaxNbElemsInLeaf )
6337       compute();
6338     else
6339       myIsLeaf = true;
6340   }
6341
6342   //================================================================================
6343   /*!
6344    * \brief Destructor
6345    */
6346   //================================================================================
6347
6348   ElementBndBoxTree::~ElementBndBoxTree()
6349   {
6350     for ( int i = 0; i < _elements.size(); ++i )
6351       if ( --_elements[i]->_refCount <= 0 )
6352         delete _elements[i];
6353   }
6354
6355   //================================================================================
6356   /*!
6357    * \brief Return the maximal box
6358    */
6359   //================================================================================
6360
6361   Bnd_B3d* ElementBndBoxTree::buildRootBox()
6362   {
6363     Bnd_B3d* box = new Bnd_B3d;
6364     for ( int i = 0; i < _elements.size(); ++i )
6365       box->Add( *_elements[i] );
6366     return box;
6367   }
6368
6369   //================================================================================
6370   /*!
6371    * \brief Redistrubute element boxes among children
6372    */
6373   //================================================================================
6374
6375   void ElementBndBoxTree::buildChildrenData()
6376   {
6377     for ( int i = 0; i < _elements.size(); ++i )
6378     {
6379       for (int j = 0; j < 8; j++)
6380       {
6381         if ( !_elements[i]->IsOut( myChildren[j]->getBox() ))
6382         {
6383           _elements[i]->_refCount++;
6384           ((ElementBndBoxTree*)myChildren[j])->_elements.push_back( _elements[i]);
6385         }
6386       }
6387       _elements[i]->_refCount--;
6388     }
6389     _elements.clear();
6390
6391     for (int j = 0; j < 8; j++)
6392     {
6393       ElementBndBoxTree* child = static_cast<ElementBndBoxTree*>( myChildren[j]);
6394       if ( child->_elements.size() <= MaxNbElemsInLeaf )
6395         child->myIsLeaf = true;
6396
6397       if ( child->_elements.capacity() - child->_elements.size() > 1000 )
6398         child->_elements.resize( child->_elements.size() ); // compact
6399     }
6400   }
6401
6402   //================================================================================
6403   /*!
6404    * \brief Return elements which can include the point
6405    */
6406   //================================================================================
6407
6408   void ElementBndBoxTree::getElementsNearPoint( const gp_Pnt&     point,
6409                                                 TIDSortedElemSet& foundElems)
6410   {
6411     if ( level() && getBox().IsOut( point.XYZ() ))
6412       return;
6413
6414     if ( isLeaf() )
6415     {
6416       for ( int i = 0; i < _elements.size(); ++i )
6417         if ( !_elements[i]->IsOut( point.XYZ() ))
6418           foundElems.insert( _elements[i]->_element );
6419     }
6420     else
6421     {
6422       for (int i = 0; i < 8; i++)
6423         ((ElementBndBoxTree*) myChildren[i])->getElementsNearPoint( point, foundElems );
6424     }
6425   }
6426
6427   //================================================================================
6428   /*!
6429    * \brief Return elements which can be intersected by the line
6430    */
6431   //================================================================================
6432
6433   void ElementBndBoxTree::getElementsNearLine( const gp_Ax1&     line,
6434                                                TIDSortedElemSet& foundElems)
6435   {
6436     if ( level() && getBox().IsOut( line ))
6437       return;
6438
6439     if ( isLeaf() )
6440     {
6441       for ( int i = 0; i < _elements.size(); ++i )
6442         if ( !_elements[i]->IsOut( line ))
6443           foundElems.insert( _elements[i]->_element );
6444     }
6445     else
6446     {
6447       for (int i = 0; i < 8; i++)
6448         ((ElementBndBoxTree*) myChildren[i])->getElementsNearLine( line, foundElems );
6449     }
6450   }
6451
6452   //================================================================================
6453   /*!
6454    * \brief Construct the element box
6455    */
6456   //================================================================================
6457
6458   ElementBndBoxTree::ElementBox::ElementBox(const SMDS_MeshElement* elem, double tolerance)
6459   {
6460     _element  = elem;
6461     _refCount = 1;
6462     SMDS_ElemIteratorPtr nIt = elem->nodesIterator();
6463     while ( nIt->more() )
6464       Add( SMESH_MeshEditor::TNodeXYZ( cast2Node( nIt->next() )));
6465     Enlarge( tolerance );
6466   }
6467
6468 } // namespace
6469
6470 //=======================================================================
6471 /*!
6472  * \brief Implementation of search for the elements by point and
6473  *        of classification of point in 2D mesh
6474  */
6475 //=======================================================================
6476
6477 struct SMESH_ElementSearcherImpl: public SMESH_ElementSearcher
6478 {
6479   SMESHDS_Mesh*                _mesh;
6480   ElementBndBoxTree*           _ebbTree;
6481   SMESH_NodeSearcherImpl*      _nodeSearcher;
6482   SMDSAbs_ElementType          _elementType;
6483   double                       _tolerance;
6484   bool                         _outerFacesFound;
6485   set<const SMDS_MeshElement*> _outerFaces; // empty means "no internal faces at all"
6486
6487   SMESH_ElementSearcherImpl( SMESHDS_Mesh& mesh )
6488     : _mesh(&mesh),_ebbTree(0),_nodeSearcher(0), _tolerance(-1), _outerFacesFound(false) {}
6489   ~SMESH_ElementSearcherImpl()
6490   {
6491     if ( _ebbTree )      delete _ebbTree;      _ebbTree      = 0;
6492     if ( _nodeSearcher ) delete _nodeSearcher; _nodeSearcher = 0;
6493   }
6494   virtual int FindElementsByPoint(const gp_Pnt&                      point,
6495                                   SMDSAbs_ElementType                type,
6496                                   vector< const SMDS_MeshElement* >& foundElements);
6497   virtual TopAbs_State GetPointState(const gp_Pnt& point);
6498
6499   void GetElementsNearLine( const gp_Ax1&                      line,
6500                             SMDSAbs_ElementType                type,
6501                             vector< const SMDS_MeshElement* >& foundElems);
6502   double getTolerance();
6503   bool getIntersParamOnLine(const gp_Lin& line, const SMDS_MeshElement* face,
6504                             const double tolerance, double & param);
6505   void findOuterBoundary(const SMDS_MeshElement* anyOuterFace);
6506   bool isOuterBoundary(const SMDS_MeshElement* face) const
6507   {
6508     return _outerFaces.empty() || _outerFaces.count(face);
6509   }
6510   struct TInters //!< data of intersection of the line and the mesh face (used in GetPointState())
6511   {
6512     const SMDS_MeshElement* _face;
6513     gp_Vec                  _faceNorm;
6514     bool                    _coincides; //!< the line lays in face plane
6515     TInters(const SMDS_MeshElement* face, const gp_Vec& faceNorm, bool coinc=false)
6516       : _face(face), _faceNorm( faceNorm ), _coincides( coinc ) {}
6517   };
6518   struct TFaceLink //!< link and faces sharing it (used in findOuterBoundary())
6519   {
6520     SMESH_TLink      _link;
6521     TIDSortedElemSet _faces;
6522     TFaceLink( const SMDS_MeshNode* n1, const SMDS_MeshNode* n2, const SMDS_MeshElement* face)
6523       : _link( n1, n2 ), _faces( &face, &face + 1) {}
6524   };
6525 };
6526
6527 ostream& operator<< (ostream& out, const SMESH_ElementSearcherImpl::TInters& i)
6528 {
6529   return out << "TInters(face=" << ( i._face ? i._face->GetID() : 0)
6530              << ", _coincides="<<i._coincides << ")";
6531 }
6532
6533 //=======================================================================
6534 /*!
6535  * \brief define tolerance for search
6536  */
6537 //=======================================================================
6538
6539 double SMESH_ElementSearcherImpl::getTolerance()
6540 {
6541   if ( _tolerance < 0 )
6542   {
6543     const SMDS_MeshInfo& meshInfo = _mesh->GetMeshInfo();
6544
6545     _tolerance = 0;
6546     if ( _nodeSearcher && meshInfo.NbNodes() > 1 )
6547     {
6548       double boxSize = _nodeSearcher->getTree()->maxSize();
6549       _tolerance = 1e-8 * boxSize/* / meshInfo.NbNodes()*/;
6550     }
6551     else if ( _ebbTree && meshInfo.NbElements() > 0 )
6552     {
6553       double boxSize = _ebbTree->maxSize();
6554       _tolerance = 1e-8 * boxSize/* / meshInfo.NbElements()*/;
6555     }
6556     if ( _tolerance == 0 )
6557     {
6558       // define tolerance by size of a most complex element
6559       int complexType = SMDSAbs_Volume;
6560       while ( complexType > SMDSAbs_All &&
6561               meshInfo.NbElements( SMDSAbs_ElementType( complexType )) < 1 )
6562         --complexType;
6563       if ( complexType == SMDSAbs_All ) return 0; // empty mesh
6564       double elemSize;
6565       if ( complexType == int( SMDSAbs_Node ))
6566       {
6567         SMDS_NodeIteratorPtr nodeIt = _mesh->nodesIterator();
6568         elemSize = 1;
6569         if ( meshInfo.NbNodes() > 2 )
6570           elemSize = SMESH_MeshEditor::TNodeXYZ( nodeIt->next() ).Distance( nodeIt->next() );
6571       }
6572       else
6573       {
6574         SMDS_ElemIteratorPtr elemIt =
6575             _mesh->elementsIterator( SMDSAbs_ElementType( complexType ));
6576         const SMDS_MeshElement* elem = elemIt->next();
6577         SMDS_ElemIteratorPtr nodeIt = elem->nodesIterator();
6578         SMESH_MeshEditor::TNodeXYZ n1( cast2Node( nodeIt->next() ));
6579         while ( nodeIt->more() )
6580         {
6581           double dist = n1.Distance( cast2Node( nodeIt->next() ));
6582           elemSize = max( dist, elemSize );
6583         }
6584       }
6585       _tolerance = 1e-4 * elemSize;
6586     }
6587   }
6588   return _tolerance;
6589 }
6590
6591 //================================================================================
6592 /*!
6593  * \brief Find intersection of the line and an edge of face and return parameter on line
6594  */
6595 //================================================================================
6596
6597 bool SMESH_ElementSearcherImpl::getIntersParamOnLine(const gp_Lin&           line,
6598                                                      const SMDS_MeshElement* face,
6599                                                      const double            tol,
6600                                                      double &                param)
6601 {
6602   int nbInts = 0;
6603   param = 0;
6604
6605   GeomAPI_ExtremaCurveCurve anExtCC;
6606   Handle(Geom_Curve) lineCurve = new Geom_Line( line );
6607   
6608   int nbNodes = face->IsQuadratic() ? face->NbNodes()/2 : face->NbNodes();
6609   for ( int i = 0; i < nbNodes && nbInts < 2; ++i )
6610   {
6611     GC_MakeSegment edge( SMESH_MeshEditor::TNodeXYZ( face->GetNode( i )),
6612                          SMESH_MeshEditor::TNodeXYZ( face->GetNode( (i+1)%nbNodes) )); 
6613     anExtCC.Init( lineCurve, edge);
6614     if ( anExtCC.NbExtrema() > 0 && anExtCC.LowerDistance() <= tol)
6615     {
6616       Quantity_Parameter pl, pe;
6617       anExtCC.LowerDistanceParameters( pl, pe );
6618       param += pl;
6619       if ( ++nbInts == 2 )
6620         break;
6621     }
6622   }
6623   if ( nbInts > 0 ) param /= nbInts;
6624   return nbInts > 0;
6625 }
6626 //================================================================================
6627 /*!
6628  * \brief Find all faces belonging to the outer boundary of mesh
6629  */
6630 //================================================================================
6631
6632 void SMESH_ElementSearcherImpl::findOuterBoundary(const SMDS_MeshElement* outerFace)
6633 {
6634   if ( _outerFacesFound ) return;
6635
6636   // Collect all outer faces by passing from one outer face to another via their links
6637   // and BTW find out if there are internal faces at all.
6638
6639   // checked links and links where outer boundary meets internal one
6640   set< SMESH_TLink > visitedLinks, seamLinks;
6641
6642   // links to treat with already visited faces sharing them
6643   list < TFaceLink > startLinks;
6644
6645   // load startLinks with the first outerFace
6646   startLinks.push_back( TFaceLink( outerFace->GetNode(0), outerFace->GetNode(1), outerFace));
6647   _outerFaces.insert( outerFace );
6648
6649   TIDSortedElemSet emptySet;
6650   while ( !startLinks.empty() )
6651   {
6652     const SMESH_TLink& link  = startLinks.front()._link;
6653     TIDSortedElemSet&  faces = startLinks.front()._faces;
6654
6655     outerFace = *faces.begin();
6656     // find other faces sharing the link
6657     const SMDS_MeshElement* f;
6658     while (( f = SMESH_MeshEditor::FindFaceInSet(link.node1(), link.node2(), emptySet, faces )))
6659       faces.insert( f );
6660
6661     // select another outer face among the found 
6662     const SMDS_MeshElement* outerFace2 = 0;
6663     if ( faces.size() == 2 )
6664     {
6665       outerFace2 = (outerFace == *faces.begin() ? *faces.rbegin() : *faces.begin());
6666     }
6667     else if ( faces.size() > 2 )
6668     {
6669       seamLinks.insert( link );
6670
6671       // link direction within the outerFace
6672       gp_Vec n1n2( SMESH_MeshEditor::TNodeXYZ( link.node1()),
6673                    SMESH_MeshEditor::TNodeXYZ( link.node2()));
6674       int i1 = outerFace->GetNodeIndex( link.node1() );
6675       int i2 = outerFace->GetNodeIndex( link.node2() );
6676       bool rev = ( abs(i2-i1) == 1 ? i1 > i2 : i2 > i1 );
6677       if ( rev ) n1n2.Reverse();
6678       // outerFace normal
6679       gp_XYZ ofNorm, fNorm;
6680       if ( SMESH_Algo::FaceNormal( outerFace, ofNorm, /*normalized=*/false ))
6681       {
6682         // direction from the link inside outerFace
6683         gp_Vec dirInOF = gp_Vec( ofNorm ) ^ n1n2;
6684         // sort all other faces by angle with the dirInOF
6685         map< double, const SMDS_MeshElement* > angle2Face;
6686         set< const SMDS_MeshElement*, TIDCompare >::const_iterator face = faces.begin();
6687         for ( ; face != faces.end(); ++face )
6688         {
6689           if ( !SMESH_Algo::FaceNormal( *face, fNorm, /*normalized=*/false ))
6690             continue;
6691           gp_Vec dirInF = gp_Vec( fNorm ) ^ n1n2;
6692           double angle = dirInOF.AngleWithRef( dirInF, n1n2 );
6693           if ( angle < 0 ) angle += 2*PI;
6694           angle2Face.insert( make_pair( angle, *face ));
6695         }
6696         if ( !angle2Face.empty() )
6697           outerFace2 = angle2Face.begin()->second;
6698       }
6699     }
6700     // store the found outer face and add its links to continue seaching from
6701     if ( outerFace2 )
6702     {
6703       _outerFaces.insert( outerFace );
6704       int nbNodes = outerFace2->NbNodes()/( outerFace2->IsQuadratic() ? 2 : 1 );
6705       for ( int i = 0; i < nbNodes; ++i )
6706       {
6707         SMESH_TLink link2( outerFace2->GetNode(i), outerFace2->GetNode((i+1)%nbNodes));
6708         if ( visitedLinks.insert( link2 ).second )
6709           startLinks.push_back( TFaceLink( link2.node1(), link2.node2(), outerFace2 ));
6710       }
6711     }
6712     startLinks.pop_front();
6713   }
6714   _outerFacesFound = true;
6715
6716   if ( !seamLinks.empty() )
6717   {
6718     // There are internal boundaries touching the outher one,
6719     // find all faces of internal boundaries in order to find
6720     // faces of boundaries of holes, if any.
6721     
6722   }
6723   else
6724   {
6725     _outerFaces.clear();
6726   }
6727 }
6728
6729 //=======================================================================
6730 /*!
6731  * \brief Find elements of given type where the given point is IN or ON.
6732  *        Returns nb of found elements and elements them-selves.
6733  *
6734  * 'ALL' type means elements of any type excluding nodes and 0D elements
6735  */
6736 //=======================================================================
6737
6738 int SMESH_ElementSearcherImpl::
6739 FindElementsByPoint(const gp_Pnt&                      point,
6740                     SMDSAbs_ElementType                type,
6741                     vector< const SMDS_MeshElement* >& foundElements)
6742 {
6743   foundElements.clear();
6744
6745   double tolerance = getTolerance();
6746
6747   // =================================================================================
6748   if ( type == SMDSAbs_Node || type == SMDSAbs_0DElement )
6749   {
6750     if ( !_nodeSearcher )
6751       _nodeSearcher = new SMESH_NodeSearcherImpl( _mesh );
6752
6753     const SMDS_MeshNode* closeNode = _nodeSearcher->FindClosestTo( point );
6754     if ( !closeNode ) return foundElements.size();
6755
6756     if ( point.Distance( SMESH_MeshEditor::TNodeXYZ( closeNode )) > tolerance )
6757       return foundElements.size(); // to far from any node
6758
6759     if ( type == SMDSAbs_Node )
6760     {
6761       foundElements.push_back( closeNode );
6762     }
6763     else
6764     {
6765       SMDS_ElemIteratorPtr elemIt = closeNode->GetInverseElementIterator( SMDSAbs_0DElement );
6766       while ( elemIt->more() )
6767         foundElements.push_back( elemIt->next() );
6768     }
6769   }
6770   // =================================================================================
6771   else // elements more complex than 0D
6772   {
6773     if ( !_ebbTree || _elementType != type )
6774     {
6775       if ( _ebbTree ) delete _ebbTree;
6776       _ebbTree = new ElementBndBoxTree( *_mesh, _elementType = type, tolerance );
6777     }
6778     TIDSortedElemSet suspectElems;
6779     _ebbTree->getElementsNearPoint( point, suspectElems );
6780     TIDSortedElemSet::iterator elem = suspectElems.begin();
6781     for ( ; elem != suspectElems.end(); ++elem )
6782       if ( !SMESH_MeshEditor::isOut( *elem, point, tolerance ))
6783         foundElements.push_back( *elem );
6784   }
6785   return foundElements.size();
6786 }
6787
6788 //================================================================================
6789 /*!
6790  * \brief Classify the given point in the closed 2D mesh
6791  */
6792 //================================================================================
6793
6794 TopAbs_State SMESH_ElementSearcherImpl::GetPointState(const gp_Pnt& point)
6795 {
6796   double tolerance = getTolerance();
6797   if ( !_ebbTree || _elementType != SMDSAbs_Face )
6798   {
6799     if ( _ebbTree ) delete _ebbTree;
6800     _ebbTree = new ElementBndBoxTree( *_mesh, _elementType = SMDSAbs_Face );
6801   }
6802   // Algo: analyse transition of a line starting at the point through mesh boundary;
6803   // try three lines parallel to axis of the coordinate system and perform rough
6804   // analysis. If solution is not clear perform thorough analysis.
6805
6806   const int nbAxes = 3;
6807   gp_Dir axisDir[ nbAxes ] = { gp::DX(), gp::DY(), gp::DZ() };
6808   map< double, TInters >   paramOnLine2TInters[ nbAxes ];
6809   list< TInters > tangentInters[ nbAxes ]; // of faces whose plane includes the line
6810   multimap< int, int > nbInt2Axis; // to find the simplest case
6811   for ( int axis = 0; axis < nbAxes; ++axis )
6812   {
6813     gp_Ax1 lineAxis( point, axisDir[axis]);
6814     gp_Lin line    ( lineAxis );
6815
6816     TIDSortedElemSet suspectFaces; // faces possibly intersecting the line
6817     _ebbTree->getElementsNearLine( lineAxis, suspectFaces );
6818
6819     // Intersect faces with the line
6820
6821     map< double, TInters > & u2inters = paramOnLine2TInters[ axis ];
6822     TIDSortedElemSet::iterator face = suspectFaces.begin();
6823     for ( ; face != suspectFaces.end(); ++face )
6824     {
6825       // get face plane
6826       gp_XYZ fNorm;
6827       if ( !SMESH_Algo::FaceNormal( *face, fNorm, /*normalized=*/false)) continue;
6828       gp_Pln facePlane( SMESH_MeshEditor::TNodeXYZ( (*face)->GetNode(0)), fNorm );
6829
6830       // perform intersection
6831       IntAna_IntConicQuad intersection( line, IntAna_Quadric( facePlane ));
6832       if ( !intersection.IsDone() )
6833         continue;
6834       if ( intersection.IsInQuadric() )
6835       {
6836         tangentInters[ axis ].push_back( TInters( *face, fNorm, true ));
6837       }
6838       else if ( ! intersection.IsParallel() && intersection.NbPoints() > 0 )
6839       {
6840         gp_Pnt intersectionPoint = intersection.Point(1);
6841         if ( !SMESH_MeshEditor::isOut( *face, intersectionPoint, tolerance ))
6842           u2inters.insert(make_pair( intersection.ParamOnConic(1), TInters( *face, fNorm )));
6843       }
6844     }
6845     // Analyse intersections roughly
6846
6847     int nbInter = u2inters.size();
6848     if ( nbInter == 0 )
6849       return TopAbs_OUT; 
6850
6851     double f = u2inters.begin()->first, l = u2inters.rbegin()->first;
6852     if ( nbInter == 1 ) // not closed mesh
6853       return fabs( f ) < tolerance ? TopAbs_ON : TopAbs_UNKNOWN;
6854
6855     if ( fabs( f ) < tolerance || fabs( l ) < tolerance )
6856       return TopAbs_ON;
6857
6858     if ( (f<0) == (l<0) )
6859       return TopAbs_OUT;
6860
6861     int nbIntBeforePoint = std::distance( u2inters.begin(), u2inters.lower_bound(0));
6862     int nbIntAfterPoint  = nbInter - nbIntBeforePoint;
6863     if ( nbIntBeforePoint == 1 || nbIntAfterPoint == 1 )
6864       return TopAbs_IN;
6865
6866     nbInt2Axis.insert( make_pair( min( nbIntBeforePoint, nbIntAfterPoint ), axis ));
6867
6868     if ( _outerFacesFound ) break; // pass to thorough analysis
6869
6870   } // three attempts - loop on CS axes
6871
6872   // Analyse intersections thoroughly.
6873   // We make two loops maximum, on the first one we only exclude touching intersections,
6874   // on the second, if situation is still unclear, we gather and use information on
6875   // position of faces (internal or outer). If faces position is already gathered,
6876   // we make the second loop right away.
6877
6878   for ( int hasPositionInfo = _outerFacesFound; hasPositionInfo < 2; ++hasPositionInfo )
6879   {
6880     multimap< int, int >::const_iterator nb_axis = nbInt2Axis.begin();
6881     for ( ; nb_axis != nbInt2Axis.end(); ++nb_axis )
6882     {
6883       int axis = nb_axis->second;
6884       map< double, TInters > & u2inters = paramOnLine2TInters[ axis ];
6885
6886       gp_Ax1 lineAxis( point, axisDir[axis]);
6887       gp_Lin line    ( lineAxis );
6888
6889       // add tangent intersections to u2inters
6890       double param;
6891       list< TInters >::const_iterator tgtInt = tangentInters[ axis ].begin();
6892       for ( ; tgtInt != tangentInters[ axis ].end(); ++tgtInt )
6893         if ( getIntersParamOnLine( line, tgtInt->_face, tolerance, param ))
6894           u2inters.insert(make_pair( param, *tgtInt ));
6895       tangentInters[ axis ].clear();
6896
6897       // Count intersections before and after the point excluding touching ones.
6898       // If hasPositionInfo we count intersections of outer boundary only
6899
6900       int nbIntBeforePoint = 0, nbIntAfterPoint = 0;
6901       double f = numeric_limits<double>::max(), l = -numeric_limits<double>::max();
6902       map< double, TInters >::iterator u_int1 = u2inters.begin(), u_int2 = u_int1;
6903       bool ok = ! u_int1->second._coincides;
6904       while ( ok && u_int1 != u2inters.end() )
6905       {
6906         double u = u_int1->first;
6907         bool touchingInt = false;
6908         if ( ++u_int2 != u2inters.end() )
6909         {
6910           // skip intersections at the same point (if the line passes through edge or node)
6911           int nbSamePnt = 0;
6912           while ( u_int2 != u2inters.end() && fabs( u_int2->first - u ) < tolerance )
6913           {
6914             ++nbSamePnt;
6915             ++u_int2;
6916           }
6917
6918           // skip tangent intersections
6919           int nbTgt = 0;
6920           const SMDS_MeshElement* prevFace = u_int1->second._face;
6921           while ( ok && u_int2->second._coincides )
6922           {
6923             if ( SMESH_Algo::GetCommonNodes(prevFace , u_int2->second._face).empty() )
6924               ok = false;
6925             else
6926             {
6927               nbTgt++;
6928               u_int2++;
6929               ok = ( u_int2 != u2inters.end() );
6930             }
6931           }
6932           if ( !ok ) break;
6933
6934           // skip intersections at the same point after tangent intersections
6935           if ( nbTgt > 0 )
6936           {
6937             double u2 = u_int2->first;
6938             ++u_int2;
6939             while ( u_int2 != u2inters.end() && fabs( u_int2->first - u2 ) < tolerance )
6940             {
6941               ++nbSamePnt;
6942               ++u_int2;
6943             }
6944           }
6945           // decide if we skipped a touching intersection
6946           if ( nbSamePnt + nbTgt > 0 )
6947           {
6948             double minDot = numeric_limits<double>::max(), maxDot = -numeric_limits<double>::max();
6949             map< double, TInters >::iterator u_int = u_int1;
6950             for ( ; u_int != u_int2; ++u_int )
6951             {
6952               if ( u_int->second._coincides ) continue;
6953               double dot = u_int->second._faceNorm * line.Direction();
6954               if ( dot > maxDot ) maxDot = dot;
6955               if ( dot < minDot ) minDot = dot;
6956             }
6957             touchingInt = ( minDot*maxDot < 0 );
6958           }
6959         }
6960         if ( !touchingInt )
6961         {
6962           if ( !hasPositionInfo || isOuterBoundary( u_int1->second._face ))
6963           {
6964             if ( u < 0 )
6965               ++nbIntBeforePoint;
6966             else
6967               ++nbIntAfterPoint;
6968           }
6969           if ( u < f ) f = u;
6970           if ( u > l ) l = u;
6971         }
6972
6973         u_int1 = u_int2; // to next intersection
6974
6975       } // loop on intersections with one line
6976
6977       if ( ok )
6978       {
6979         if ( fabs( f ) < tolerance || fabs( l ) < tolerance )
6980           return TopAbs_ON;
6981
6982         if ( nbIntBeforePoint == 0  || nbIntAfterPoint == 0)
6983           return TopAbs_OUT; 
6984
6985         if ( nbIntBeforePoint + nbIntAfterPoint == 1 ) // not closed mesh
6986           return fabs( f ) < tolerance ? TopAbs_ON : TopAbs_UNKNOWN;
6987
6988         if ( nbIntBeforePoint == 1 || nbIntAfterPoint == 1 )
6989           return TopAbs_IN;
6990
6991         if ( (f<0) == (l<0) )
6992           return TopAbs_OUT;
6993
6994         if ( hasPositionInfo )
6995           return nbIntBeforePoint % 2 ? TopAbs_IN : TopAbs_OUT;
6996       }
6997     } // loop on intersections of the tree lines - thorough analysis
6998
6999     if ( !hasPositionInfo )
7000     {
7001       // gather info on faces position - is face in the outer boundary or not
7002       map< double, TInters > & u2inters = paramOnLine2TInters[ 0 ];
7003       findOuterBoundary( u2inters.begin()->second._face );
7004     }
7005
7006   } // two attempts - with and w/o faces position info in the mesh
7007
7008   return TopAbs_UNKNOWN;
7009 }
7010
7011 //=======================================================================
7012 /*!
7013  * \brief Return elements possibly intersecting the line
7014  */
7015 //=======================================================================
7016
7017 void SMESH_ElementSearcherImpl::GetElementsNearLine( const gp_Ax1&                      line,
7018                                                      SMDSAbs_ElementType                type,
7019                                                      vector< const SMDS_MeshElement* >& foundElems)
7020 {
7021   if ( !_ebbTree || _elementType != type )
7022   {
7023     if ( _ebbTree ) delete _ebbTree;
7024     _ebbTree = new ElementBndBoxTree( *_mesh, _elementType = type );
7025   }
7026   TIDSortedElemSet suspectFaces; // elements possibly intersecting the line
7027   _ebbTree->getElementsNearLine( line, suspectFaces );
7028   foundElems.assign( suspectFaces.begin(), suspectFaces.end());
7029 }
7030
7031 //=======================================================================
7032 /*!
7033  * \brief Return SMESH_ElementSearcher
7034  */
7035 //=======================================================================
7036
7037 SMESH_ElementSearcher* SMESH_MeshEditor::GetElementSearcher()
7038 {
7039   return new SMESH_ElementSearcherImpl( *GetMeshDS() );
7040 }
7041
7042 //=======================================================================
7043 /*!
7044  * \brief Return true if the point is IN or ON of the element
7045  */
7046 //=======================================================================
7047
7048 bool SMESH_MeshEditor::isOut( const SMDS_MeshElement* element, const gp_Pnt& point, double tol )
7049 {
7050   if ( element->GetType() == SMDSAbs_Volume)
7051   {
7052     return SMDS_VolumeTool( element ).IsOut( point.X(), point.Y(), point.Z(), tol );
7053   }
7054
7055   // get ordered nodes
7056
7057   vector< gp_XYZ > xyz;
7058   vector<const SMDS_MeshNode*> nodeList;
7059
7060   SMDS_ElemIteratorPtr nodeIt = element->nodesIterator();
7061   if ( element->IsQuadratic() ) {
7062     if (const SMDS_VtkFace* f=dynamic_cast<const SMDS_VtkFace*>(element))
7063       nodeIt = f->interlacedNodesElemIterator();
7064     else if (const SMDS_VtkEdge*  e =dynamic_cast<const SMDS_VtkEdge*>(element))
7065       nodeIt = e->interlacedNodesElemIterator();
7066   }
7067   while ( nodeIt->more() )
7068     {
7069       const SMDS_MeshNode* node = cast2Node( nodeIt->next() );
7070       xyz.push_back( TNodeXYZ(node) );
7071       nodeList.push_back(node);
7072     }
7073
7074   int i, nbNodes = element->NbNodes();
7075
7076   if ( element->GetType() == SMDSAbs_Face ) // --------------------------------------------------
7077   {
7078     // compute face normal
7079     gp_Vec faceNorm(0,0,0);
7080     xyz.push_back( xyz.front() );
7081     nodeList.push_back( nodeList.front() );
7082     for ( i = 0; i < nbNodes; ++i )
7083     {
7084       gp_Vec edge1( xyz[i+1], xyz[i]);
7085       gp_Vec edge2( xyz[i+1], xyz[(i+2)%nbNodes] );
7086       faceNorm += edge1 ^ edge2;
7087     }
7088     double normSize = faceNorm.Magnitude();
7089     if ( normSize <= tol )
7090     {
7091       // degenerated face: point is out if it is out of all face edges
7092       for ( i = 0; i < nbNodes; ++i )
7093       {
7094         SMDS_LinearEdge edge( nodeList[i], nodeList[i+1] );
7095         if ( !isOut( &edge, point, tol ))
7096           return false;
7097       }
7098       return true;
7099     }
7100     faceNorm /= normSize;
7101
7102     // check if the point lays on face plane
7103     gp_Vec n2p( xyz[0], point );
7104     if ( fabs( n2p * faceNorm ) > tol )
7105       return true; // not on face plane
7106
7107     // check if point is out of face boundary:
7108     // define it by closest transition of a ray point->infinity through face boundary
7109     // on the face plane.
7110     // First, find normal of a plane perpendicular to face plane, to be used as a cutting tool
7111     // to find intersections of the ray with the boundary.
7112     gp_Vec ray = n2p;
7113     gp_Vec plnNorm = ray ^ faceNorm;
7114     normSize = plnNorm.Magnitude();
7115     if ( normSize <= tol ) return false; // point coincides with the first node
7116     plnNorm /= normSize;
7117     // for each node of the face, compute its signed distance to the plane
7118     vector<double> dist( nbNodes + 1);
7119     for ( i = 0; i < nbNodes; ++i )
7120     {
7121       gp_Vec n2p( xyz[i], point );
7122       dist[i] = n2p * plnNorm;
7123     }
7124     dist.back() = dist.front();
7125     // find the closest intersection
7126     int    iClosest = -1;
7127     double rClosest, distClosest = 1e100;;
7128     gp_Pnt pClosest;
7129     for ( i = 0; i < nbNodes; ++i )
7130     {
7131       double r;
7132       if ( fabs( dist[i]) < tol )
7133         r = 0.;
7134       else if ( fabs( dist[i+1]) < tol )
7135         r = 1.;
7136       else if ( dist[i] * dist[i+1] < 0 )
7137         r = dist[i] / ( dist[i] - dist[i+1] );
7138       else
7139         continue; // no intersection
7140       gp_Pnt pInt = xyz[i] * (1.-r) + xyz[i+1] * r;
7141       gp_Vec p2int ( point, pInt);
7142       if ( p2int * ray > -tol ) // right half-space
7143       {
7144         double intDist = p2int.SquareMagnitude();
7145         if ( intDist < distClosest )
7146         {
7147           iClosest = i;
7148           rClosest = r;
7149           pClosest = pInt;
7150           distClosest = intDist;
7151         }
7152       }
7153     }
7154     if ( iClosest < 0 )
7155       return true; // no intesections - out
7156
7157     // analyse transition
7158     gp_Vec edge( xyz[iClosest], xyz[iClosest+1] );
7159     gp_Vec edgeNorm = -( edge ^ faceNorm ); // normal to intersected edge pointing out of face
7160     gp_Vec p2int ( point, pClosest );
7161     bool out = (edgeNorm * p2int) < -tol;
7162     if ( rClosest > 0. && rClosest < 1. ) // not node intersection
7163       return out;
7164
7165     // ray pass through a face node; analyze transition through an adjacent edge
7166     gp_Pnt p1 = xyz[ (rClosest == 0.) ? ((iClosest+nbNodes-1) % nbNodes) : (iClosest+1) ];
7167     gp_Pnt p2 = xyz[ (rClosest == 0.) ? iClosest : ((iClosest+2) % nbNodes) ];
7168     gp_Vec edgeAdjacent( p1, p2 );
7169     gp_Vec edgeNorm2 = -( edgeAdjacent ^ faceNorm );
7170     bool out2 = (edgeNorm2 * p2int) < -tol;
7171
7172     bool covexCorner = ( edgeNorm * edgeAdjacent * (rClosest==1. ? 1. : -1.)) < 0;
7173     return covexCorner ? (out || out2) : (out && out2);
7174   }
7175   if ( element->GetType() == SMDSAbs_Edge ) // --------------------------------------------------
7176   {
7177     // point is out of edge if it is NOT ON any straight part of edge
7178     // (we consider quadratic edge as being composed of two straight parts)
7179     for ( i = 1; i < nbNodes; ++i )
7180     {
7181       gp_Vec edge( xyz[i-1], xyz[i]);
7182       gp_Vec n1p ( xyz[i-1], point);
7183       double dist = ( edge ^ n1p ).Magnitude() / edge.Magnitude();
7184       if ( dist > tol )
7185         continue;
7186       gp_Vec n2p( xyz[i], point );
7187       if ( fabs( edge.Magnitude() - n1p.Magnitude() - n2p.Magnitude()) > tol )
7188         continue;
7189       return false; // point is ON this part
7190     }
7191     return true;
7192   }
7193   // Node or 0D element -------------------------------------------------------------------------
7194   {
7195     gp_Vec n2p ( xyz[0], point );
7196     return n2p.Magnitude() <= tol;
7197   }
7198   return true;
7199 }
7200
7201 //=======================================================================
7202 //function : SimplifyFace
7203 //purpose  :
7204 //=======================================================================
7205 int SMESH_MeshEditor::SimplifyFace (const vector<const SMDS_MeshNode *> faceNodes,
7206                                     vector<const SMDS_MeshNode *>&      poly_nodes,
7207                                     vector<int>&                        quantities) const
7208 {
7209   int nbNodes = faceNodes.size();
7210
7211   if (nbNodes < 3)
7212     return 0;
7213
7214   set<const SMDS_MeshNode*> nodeSet;
7215
7216   // get simple seq of nodes
7217   //const SMDS_MeshNode* simpleNodes[ nbNodes ];
7218   vector<const SMDS_MeshNode*> simpleNodes( nbNodes );
7219   int iSimple = 0, nbUnique = 0;
7220
7221   simpleNodes[iSimple++] = faceNodes[0];
7222   nbUnique++;
7223   for (int iCur = 1; iCur < nbNodes; iCur++) {
7224     if (faceNodes[iCur] != simpleNodes[iSimple - 1]) {
7225       simpleNodes[iSimple++] = faceNodes[iCur];
7226       if (nodeSet.insert( faceNodes[iCur] ).second)
7227         nbUnique++;
7228     }
7229   }
7230   int nbSimple = iSimple;
7231   if (simpleNodes[nbSimple - 1] == simpleNodes[0]) {
7232     nbSimple--;
7233     iSimple--;
7234   }
7235
7236   if (nbUnique < 3)
7237     return 0;
7238
7239   // separate loops
7240   int nbNew = 0;
7241   bool foundLoop = (nbSimple > nbUnique);
7242   while (foundLoop) {
7243     foundLoop = false;
7244     set<const SMDS_MeshNode*> loopSet;
7245     for (iSimple = 0; iSimple < nbSimple && !foundLoop; iSimple++) {
7246       const SMDS_MeshNode* n = simpleNodes[iSimple];
7247       if (!loopSet.insert( n ).second) {
7248         foundLoop = true;
7249
7250         // separate loop
7251         int iC = 0, curLast = iSimple;
7252         for (; iC < curLast; iC++) {
7253           if (simpleNodes[iC] == n) break;
7254         }
7255         int loopLen = curLast - iC;
7256         if (loopLen > 2) {
7257           // create sub-element
7258           nbNew++;
7259           quantities.push_back(loopLen);
7260           for (; iC < curLast; iC++) {
7261             poly_nodes.push_back(simpleNodes[iC]);
7262           }
7263         }
7264         // shift the rest nodes (place from the first loop position)
7265         for (iC = curLast + 1; iC < nbSimple; iC++) {
7266           simpleNodes[iC - loopLen] = simpleNodes[iC];
7267         }
7268         nbSimple -= loopLen;
7269         iSimple -= loopLen;
7270       }
7271     } // for (iSimple = 0; iSimple < nbSimple; iSimple++)
7272   } // while (foundLoop)
7273
7274   if (iSimple > 2) {
7275     nbNew++;
7276     quantities.push_back(iSimple);
7277     for (int i = 0; i < iSimple; i++)
7278       poly_nodes.push_back(simpleNodes[i]);
7279   }
7280
7281   return nbNew;
7282 }
7283
7284 //=======================================================================
7285 //function : MergeNodes
7286 //purpose  : In each group, the cdr of nodes are substituted by the first one
7287 //           in all elements.
7288 //=======================================================================
7289
7290 void SMESH_MeshEditor::MergeNodes (TListOfListOfNodes & theGroupsOfNodes)
7291 {
7292   MESSAGE("MergeNodes");
7293   myLastCreatedElems.Clear();
7294   myLastCreatedNodes.Clear();
7295
7296   SMESHDS_Mesh* aMesh = GetMeshDS();
7297
7298   TNodeNodeMap nodeNodeMap; // node to replace - new node
7299   set<const SMDS_MeshElement*> elems; // all elements with changed nodes
7300   list< int > rmElemIds, rmNodeIds;
7301
7302   // Fill nodeNodeMap and elems
7303
7304   TListOfListOfNodes::iterator grIt = theGroupsOfNodes.begin();
7305   for ( ; grIt != theGroupsOfNodes.end(); grIt++ ) {
7306     list<const SMDS_MeshNode*>& nodes = *grIt;
7307     list<const SMDS_MeshNode*>::iterator nIt = nodes.begin();
7308     const SMDS_MeshNode* nToKeep = *nIt;
7309     //MESSAGE("node to keep " << nToKeep->GetID());
7310     for ( ++nIt; nIt != nodes.end(); nIt++ ) {
7311       const SMDS_MeshNode* nToRemove = *nIt;
7312       nodeNodeMap.insert( TNodeNodeMap::value_type( nToRemove, nToKeep ));
7313       if ( nToRemove != nToKeep ) {
7314         //MESSAGE("  node to remove " << nToRemove->GetID());
7315         rmNodeIds.push_back( nToRemove->GetID() );
7316         AddToSameGroups( nToKeep, nToRemove, aMesh );
7317       }
7318
7319       SMDS_ElemIteratorPtr invElemIt = nToRemove->GetInverseElementIterator();
7320       while ( invElemIt->more() ) {
7321         const SMDS_MeshElement* elem = invElemIt->next();
7322         elems.insert(elem);
7323       }
7324     }
7325   }
7326   // Change element nodes or remove an element
7327
7328   set<const SMDS_MeshElement*>::iterator eIt = elems.begin();
7329   for ( ; eIt != elems.end(); eIt++ ) {
7330     const SMDS_MeshElement* elem = *eIt;
7331     //MESSAGE(" ---- inverse elem on node to remove " << elem->GetID());
7332     int nbNodes = elem->NbNodes();
7333     int aShapeId = FindShape( elem );
7334
7335     set<const SMDS_MeshNode*> nodeSet;
7336     vector< const SMDS_MeshNode*> curNodes( nbNodes ), uniqueNodes( nbNodes );
7337     int iUnique = 0, iCur = 0, nbRepl = 0;
7338     vector<int> iRepl( nbNodes );
7339
7340     // get new seq of nodes
7341     SMDS_ElemIteratorPtr itN = elem->nodesIterator();
7342     while ( itN->more() ) {
7343       const SMDS_MeshNode* n =
7344         static_cast<const SMDS_MeshNode*>( itN->next() );
7345
7346       TNodeNodeMap::iterator nnIt = nodeNodeMap.find( n );
7347       if ( nnIt != nodeNodeMap.end() ) { // n sticks
7348         n = (*nnIt).second;
7349         // BUG 0020185: begin
7350         {
7351           bool stopRecur = false;
7352           set<const SMDS_MeshNode*> nodesRecur;
7353           nodesRecur.insert(n);
7354           while (!stopRecur) {
7355             TNodeNodeMap::iterator nnIt_i = nodeNodeMap.find( n );
7356             if ( nnIt_i != nodeNodeMap.end() ) { // n sticks
7357               n = (*nnIt_i).second;
7358               if (!nodesRecur.insert(n).second) {
7359                 // error: recursive dependancy
7360                 stopRecur = true;
7361               }
7362             }
7363             else
7364               stopRecur = true;
7365           }
7366         }
7367         // BUG 0020185: end
7368         iRepl[ nbRepl++ ] = iCur;
7369       }
7370       curNodes[ iCur ] = n;
7371       bool isUnique = nodeSet.insert( n ).second;
7372       if ( isUnique )
7373         uniqueNodes[ iUnique++ ] = n;
7374       iCur++;
7375     }
7376
7377     // Analyse element topology after replacement
7378
7379     bool isOk = true;
7380     int nbUniqueNodes = nodeSet.size();
7381     //MESSAGE("nbNodes nbUniqueNodes " << nbNodes << " " << nbUniqueNodes);
7382     if ( nbNodes != nbUniqueNodes ) { // some nodes stick
7383       // Polygons and Polyhedral volumes
7384       if (elem->IsPoly()) {
7385
7386         if (elem->GetType() == SMDSAbs_Face) {
7387           // Polygon
7388           vector<const SMDS_MeshNode *> face_nodes (nbNodes);
7389           int inode = 0;
7390           for (; inode < nbNodes; inode++) {
7391             face_nodes[inode] = curNodes[inode];
7392           }
7393
7394           vector<const SMDS_MeshNode *> polygons_nodes;
7395           vector<int> quantities;
7396           int nbNew = SimplifyFace(face_nodes, polygons_nodes, quantities);
7397           if (nbNew > 0) {
7398             inode = 0;
7399             for (int iface = 0; iface < nbNew; iface++) {
7400               int nbNodes = quantities[iface];
7401               vector<const SMDS_MeshNode *> poly_nodes (nbNodes);
7402               for (int ii = 0; ii < nbNodes; ii++, inode++) {
7403                 poly_nodes[ii] = polygons_nodes[inode];
7404               }
7405               SMDS_MeshElement* newElem = aMesh->AddPolygonalFace(poly_nodes);
7406               myLastCreatedElems.Append(newElem);
7407               if (aShapeId)
7408                 aMesh->SetMeshElementOnShape(newElem, aShapeId);
7409             }
7410
7411             MESSAGE("ChangeElementNodes MergeNodes Polygon");
7412             //aMesh->ChangeElementNodes(elem, &polygons_nodes[inode], quantities[nbNew - 1]);
7413             vector<const SMDS_MeshNode *> polynodes(polygons_nodes.begin()+inode,polygons_nodes.end());
7414             int quid =0;
7415             if (nbNew > 0) quid = nbNew - 1;
7416             vector<int> newquant(quantities.begin()+quid, quantities.end());
7417             const SMDS_MeshElement* newElem = 0;
7418             newElem = aMesh->AddPolyhedralVolume(polynodes, newquant);
7419             myLastCreatedElems.Append(newElem);
7420             if ( aShapeId && newElem )
7421               aMesh->SetMeshElementOnShape( newElem, aShapeId );
7422             rmElemIds.push_back(elem->GetID());
7423           }
7424           else {
7425             rmElemIds.push_back(elem->GetID());
7426           }
7427
7428         }
7429         else if (elem->GetType() == SMDSAbs_Volume) {
7430           // Polyhedral volume
7431           if (nbUniqueNodes < 4) {
7432             rmElemIds.push_back(elem->GetID());
7433           }
7434           else {
7435             // each face has to be analyzed in order to check volume validity
7436             const SMDS_VtkVolume* aPolyedre =
7437               dynamic_cast<const SMDS_VtkVolume*>( elem );
7438             if (aPolyedre) {
7439               int nbFaces = aPolyedre->NbFaces();
7440
7441               vector<const SMDS_MeshNode *> poly_nodes;
7442               vector<int> quantities;
7443
7444               for (int iface = 1; iface <= nbFaces; iface++) {
7445                 int nbFaceNodes = aPolyedre->NbFaceNodes(iface);
7446                 vector<const SMDS_MeshNode *> faceNodes (nbFaceNodes);
7447
7448                 for (int inode = 1; inode <= nbFaceNodes; inode++) {
7449                   const SMDS_MeshNode * faceNode = aPolyedre->GetFaceNode(iface, inode);
7450                   TNodeNodeMap::iterator nnIt = nodeNodeMap.find(faceNode);
7451                   if (nnIt != nodeNodeMap.end()) { // faceNode sticks
7452                     faceNode = (*nnIt).second;
7453                   }
7454                   faceNodes[inode - 1] = faceNode;
7455                 }
7456
7457                 SimplifyFace(faceNodes, poly_nodes, quantities);
7458               }
7459
7460               if (quantities.size() > 3) {
7461                 // to be done: remove coincident faces
7462               }
7463
7464               if (quantities.size() > 3)
7465                 {
7466                   MESSAGE("ChangeElementNodes MergeNodes Polyhedron");
7467                   //aMesh->ChangePolyhedronNodes(elem, poly_nodes, quantities);
7468                   const SMDS_MeshElement* newElem = 0;
7469                   newElem = aMesh->AddPolyhedralVolume(poly_nodes, quantities);
7470                   myLastCreatedElems.Append(newElem);
7471                   if ( aShapeId && newElem )
7472                     aMesh->SetMeshElementOnShape( newElem, aShapeId );
7473                   rmElemIds.push_back(elem->GetID());
7474                 }
7475             }
7476             else {
7477               rmElemIds.push_back(elem->GetID());
7478             }
7479           }
7480         }
7481         else {
7482         }
7483
7484         continue;
7485       }
7486
7487       // Regular elements
7488       // TODO not all the possible cases are solved. Find something more generic?
7489       switch ( nbNodes ) {
7490       case 2: ///////////////////////////////////// EDGE
7491         isOk = false; break;
7492       case 3: ///////////////////////////////////// TRIANGLE
7493         isOk = false; break;
7494       case 4:
7495         if ( elem->GetType() == SMDSAbs_Volume ) // TETRAHEDRON
7496           isOk = false;
7497         else { //////////////////////////////////// QUADRANGLE
7498           if ( nbUniqueNodes < 3 )
7499             isOk = false;
7500           else if ( nbRepl == 2 && iRepl[ 1 ] - iRepl[ 0 ] == 2 )
7501             isOk = false; // opposite nodes stick
7502           //MESSAGE("isOk " << isOk);
7503         }
7504         break;
7505       case 6: ///////////////////////////////////// PENTAHEDRON
7506         if ( nbUniqueNodes == 4 ) {
7507           // ---------------------------------> tetrahedron
7508           if (nbRepl == 3 &&
7509               iRepl[ 0 ] > 2 && iRepl[ 1 ] > 2 && iRepl[ 2 ] > 2 ) {
7510             // all top nodes stick: reverse a bottom
7511             uniqueNodes[ 0 ] = curNodes [ 1 ];
7512             uniqueNodes[ 1 ] = curNodes [ 0 ];
7513           }
7514           else if (nbRepl == 3 &&
7515                    iRepl[ 0 ] < 3 && iRepl[ 1 ] < 3 && iRepl[ 2 ] < 3 ) {
7516             // all bottom nodes stick: set a top before
7517             uniqueNodes[ 3 ] = uniqueNodes [ 0 ];
7518             uniqueNodes[ 0 ] = curNodes [ 3 ];
7519             uniqueNodes[ 1 ] = curNodes [ 4 ];
7520             uniqueNodes[ 2 ] = curNodes [ 5 ];
7521           }
7522           else if (nbRepl == 4 &&
7523                    iRepl[ 2 ] - iRepl [ 0 ] == 3 && iRepl[ 3 ] - iRepl [ 1 ] == 3 ) {
7524             // a lateral face turns into a line: reverse a bottom
7525             uniqueNodes[ 0 ] = curNodes [ 1 ];
7526             uniqueNodes[ 1 ] = curNodes [ 0 ];
7527           }
7528           else
7529             isOk = false;
7530         }
7531         else if ( nbUniqueNodes == 5 ) {
7532           // PENTAHEDRON --------------------> 2 tetrahedrons
7533           if ( nbRepl == 2 && iRepl[ 1 ] - iRepl [ 0 ] == 3 ) {
7534             // a bottom node sticks with a linked top one
7535             // 1.
7536             SMDS_MeshElement* newElem =
7537               aMesh->AddVolume(curNodes[ 3 ],
7538                                curNodes[ 4 ],
7539                                curNodes[ 5 ],
7540                                curNodes[ iRepl[ 0 ] == 2 ? 1 : 2 ]);
7541             myLastCreatedElems.Append(newElem);
7542             if ( aShapeId )
7543               aMesh->SetMeshElementOnShape( newElem, aShapeId );
7544             // 2. : reverse a bottom
7545             uniqueNodes[ 0 ] = curNodes [ 1 ];
7546             uniqueNodes[ 1 ] = curNodes [ 0 ];
7547             nbUniqueNodes = 4;
7548           }
7549           else
7550             isOk = false;
7551         }
7552         else
7553           isOk = false;
7554         break;
7555       case 8: {
7556         if(elem->IsQuadratic()) { // Quadratic quadrangle
7557           //   1    5    2
7558           //    +---+---+
7559           //    |       |
7560           //    |       |
7561           //   4+       +6
7562           //    |       |
7563           //    |       |
7564           //    +---+---+
7565           //   0    7    3
7566           isOk = false;
7567           if(nbRepl==2) {
7568             MESSAGE("nbRepl=2: " << iRepl[0] << " " << iRepl[1]);
7569           }
7570           if(nbRepl==3) {
7571             MESSAGE("nbRepl=3: " << iRepl[0] << " " << iRepl[1]  << " " << iRepl[2]);
7572             nbUniqueNodes = 6;
7573             if( iRepl[0]==0 && iRepl[1]==1 && iRepl[2]==4 ) {
7574               uniqueNodes[0] = curNodes[0];
7575               uniqueNodes[1] = curNodes[2];
7576               uniqueNodes[2] = curNodes[3];
7577               uniqueNodes[3] = curNodes[5];
7578               uniqueNodes[4] = curNodes[6];
7579               uniqueNodes[5] = curNodes[7];
7580               isOk = true;
7581             }
7582             if( iRepl[0]==0 && iRepl[1]==3 && iRepl[2]==7 ) {
7583               uniqueNodes[0] = curNodes[0];
7584               uniqueNodes[1] = curNodes[1];
7585               uniqueNodes[2] = curNodes[2];
7586               uniqueNodes[3] = curNodes[4];
7587               uniqueNodes[4] = curNodes[5];
7588               uniqueNodes[5] = curNodes[6];
7589               isOk = true;
7590             }
7591             if( iRepl[0]==0 && iRepl[1]==4 && iRepl[2]==7 ) {
7592               uniqueNodes[0] = curNodes[1];
7593               uniqueNodes[1] = curNodes[2];
7594               uniqueNodes[2] = curNodes[3];
7595               uniqueNodes[3] = curNodes[5];
7596               uniqueNodes[4] = curNodes[6];
7597               uniqueNodes[5] = curNodes[0];
7598               isOk = true;
7599             }
7600             if( iRepl[0]==1 && iRepl[1]==2 && iRepl[2]==5 ) {
7601               uniqueNodes[0] = curNodes[0];
7602               uniqueNodes[1] = curNodes[1];
7603               uniqueNodes[2] = curNodes[3];
7604               uniqueNodes[3] = curNodes[4];
7605               uniqueNodes[4] = curNodes[6];
7606               uniqueNodes[5] = curNodes[7];
7607               isOk = true;
7608             }
7609             if( iRepl[0]==1 && iRepl[1]==4 && iRepl[2]==5 ) {
7610               uniqueNodes[0] = curNodes[0];
7611               uniqueNodes[1] = curNodes[2];
7612               uniqueNodes[2] = curNodes[3];
7613               uniqueNodes[3] = curNodes[1];
7614               uniqueNodes[4] = curNodes[6];
7615               uniqueNodes[5] = curNodes[7];
7616               isOk = true;
7617             }
7618             if( iRepl[0]==2 && iRepl[1]==3 && iRepl[2]==6 ) {
7619               uniqueNodes[0] = curNodes[0];
7620               uniqueNodes[1] = curNodes[1];
7621               uniqueNodes[2] = curNodes[2];
7622               uniqueNodes[3] = curNodes[4];
7623               uniqueNodes[4] = curNodes[5];
7624               uniqueNodes[5] = curNodes[7];
7625               isOk = true;
7626             }
7627             if( iRepl[0]==2 && iRepl[1]==5 && iRepl[2]==6 ) {
7628               uniqueNodes[0] = curNodes[0];
7629               uniqueNodes[1] = curNodes[1];
7630               uniqueNodes[2] = curNodes[3];
7631               uniqueNodes[3] = curNodes[4];
7632               uniqueNodes[4] = curNodes[2];
7633               uniqueNodes[5] = curNodes[7];
7634               isOk = true;
7635             }
7636             if( iRepl[0]==3 && iRepl[1]==6 && iRepl[2]==7 ) {
7637               uniqueNodes[0] = curNodes[0];
7638               uniqueNodes[1] = curNodes[1];
7639               uniqueNodes[2] = curNodes[2];
7640               uniqueNodes[3] = curNodes[4];
7641               uniqueNodes[4] = curNodes[5];
7642               uniqueNodes[5] = curNodes[3];
7643               isOk = true;
7644             }
7645           }
7646           if(nbRepl==4) {
7647             MESSAGE("nbRepl=4: " << iRepl[0] << " " << iRepl[1]  << " " << iRepl[2] << " " << iRepl[3]);
7648           }
7649           if(nbRepl==5) {
7650             MESSAGE("nbRepl=5: " << iRepl[0] << " " << iRepl[1]  << " " << iRepl[2] << " " << iRepl[3] << " " << iRepl[4]);
7651           }
7652           break;
7653         }
7654         //////////////////////////////////// HEXAHEDRON
7655         isOk = false;
7656         SMDS_VolumeTool hexa (elem);
7657         hexa.SetExternalNormal();
7658         if ( nbUniqueNodes == 4 && nbRepl == 6 ) {
7659           //////////////////////// ---> tetrahedron
7660           for ( int iFace = 0; iFace < 6; iFace++ ) {
7661             const int *ind = hexa.GetFaceNodesIndices( iFace ); // indices of face nodes
7662             if (curNodes[ind[ 0 ]] == curNodes[ind[ 1 ]] &&
7663                 curNodes[ind[ 0 ]] == curNodes[ind[ 2 ]] &&
7664                 curNodes[ind[ 0 ]] == curNodes[ind[ 3 ]] ) {
7665               // one face turns into a point ...
7666               int iOppFace = hexa.GetOppFaceIndex( iFace );
7667               ind = hexa.GetFaceNodesIndices( iOppFace );
7668               int nbStick = 0;
7669               iUnique = 2; // reverse a tetrahedron bottom
7670               for ( iCur = 0; iCur < 4 && nbStick < 2; iCur++ ) {
7671                 if ( curNodes[ind[ iCur ]] == curNodes[ind[ iCur + 1 ]] )
7672                   nbStick++;
7673                 else if ( iUnique >= 0 )
7674                   uniqueNodes[ iUnique-- ] = curNodes[ind[ iCur ]];
7675               }
7676               if ( nbStick == 1 ) {
7677                 // ... and the opposite one - into a triangle.
7678                 // set a top node
7679                 ind = hexa.GetFaceNodesIndices( iFace );
7680                 uniqueNodes[ 3 ] = curNodes[ind[ 0 ]];
7681                 isOk = true;
7682               }
7683               break;
7684             }
7685           }
7686         }
7687         else if (nbUniqueNodes == 5 && nbRepl == 4 ) {
7688           //////////////////// HEXAHEDRON ---> 2 tetrahedrons
7689           for ( int iFace = 0; iFace < 6; iFace++ ) {
7690             const int *ind = hexa.GetFaceNodesIndices( iFace ); // indices of face nodes
7691             if (curNodes[ind[ 0 ]] == curNodes[ind[ 1 ]] &&
7692                 curNodes[ind[ 0 ]] == curNodes[ind[ 2 ]] &&
7693                 curNodes[ind[ 0 ]] == curNodes[ind[ 3 ]] ) {
7694               // one face turns into a point ...
7695               int iOppFace = hexa.GetOppFaceIndex( iFace );
7696               ind = hexa.GetFaceNodesIndices( iOppFace );
7697               int nbStick = 0;
7698               iUnique = 2;  // reverse a tetrahedron 1 bottom
7699               for ( iCur = 0; iCur < 4 && nbStick == 0; iCur++ ) {
7700                 if ( curNodes[ind[ iCur ]] == curNodes[ind[ iCur + 1 ]] )
7701                   nbStick++;
7702                 else if ( iUnique >= 0 )
7703                   uniqueNodes[ iUnique-- ] = curNodes[ind[ iCur ]];
7704               }
7705               if ( nbStick == 0 ) {
7706                 // ... and the opposite one is a quadrangle
7707                 // set a top node
7708                 const int* indTop = hexa.GetFaceNodesIndices( iFace );
7709                 uniqueNodes[ 3 ] = curNodes[indTop[ 0 ]];
7710                 nbUniqueNodes = 4;
7711                 // tetrahedron 2
7712                 SMDS_MeshElement* newElem =
7713                   aMesh->AddVolume(curNodes[ind[ 0 ]],
7714                                    curNodes[ind[ 3 ]],
7715                                    curNodes[ind[ 2 ]],
7716                                    curNodes[indTop[ 0 ]]);
7717                 myLastCreatedElems.Append(newElem);
7718                 if ( aShapeId )
7719                   aMesh->SetMeshElementOnShape( newElem, aShapeId );
7720                 isOk = true;
7721               }
7722               break;
7723             }
7724           }
7725         }
7726         else if ( nbUniqueNodes == 6 && nbRepl == 4 ) {
7727           ////////////////// HEXAHEDRON ---> 2 tetrahedrons or 1 prism
7728           // find indices of quad and tri faces
7729           int iQuadFace[ 6 ], iTriFace[ 6 ], nbQuad = 0, nbTri = 0, iFace;
7730           for ( iFace = 0; iFace < 6; iFace++ ) {
7731             const int *ind = hexa.GetFaceNodesIndices( iFace ); // indices of face nodes
7732             nodeSet.clear();
7733             for ( iCur = 0; iCur < 4; iCur++ )
7734               nodeSet.insert( curNodes[ind[ iCur ]] );
7735             nbUniqueNodes = nodeSet.size();
7736             if ( nbUniqueNodes == 3 )
7737               iTriFace[ nbTri++ ] = iFace;
7738             else if ( nbUniqueNodes == 4 )
7739               iQuadFace[ nbQuad++ ] = iFace;
7740           }
7741           if (nbQuad == 2 && nbTri == 4 &&
7742               hexa.GetOppFaceIndex( iQuadFace[ 0 ] ) == iQuadFace[ 1 ]) {
7743             // 2 opposite quadrangles stuck with a diagonal;
7744             // sample groups of merged indices: (0-4)(2-6)
7745             // --------------------------------------------> 2 tetrahedrons
7746             const int *ind1 = hexa.GetFaceNodesIndices( iQuadFace[ 0 ]); // indices of quad1 nodes
7747             const int *ind2 = hexa.GetFaceNodesIndices( iQuadFace[ 1 ]);
7748             int i0, i1d, i2, i3d, i0t, i2t; // d-daigonal, t-top
7749             if (curNodes[ind1[ 0 ]] == curNodes[ind2[ 0 ]] &&
7750                 curNodes[ind1[ 2 ]] == curNodes[ind2[ 2 ]]) {
7751               // stuck with 0-2 diagonal
7752               i0  = ind1[ 3 ];
7753               i1d = ind1[ 0 ];
7754               i2  = ind1[ 1 ];
7755               i3d = ind1[ 2 ];
7756               i0t = ind2[ 1 ];
7757               i2t = ind2[ 3 ];
7758             }
7759             else if (curNodes[ind1[ 1 ]] == curNodes[ind2[ 3 ]] &&
7760                      curNodes[ind1[ 3 ]] == curNodes[ind2[ 1 ]]) {
7761               // stuck with 1-3 diagonal
7762               i0  = ind1[ 0 ];
7763               i1d = ind1[ 1 ];
7764               i2  = ind1[ 2 ];
7765               i3d = ind1[ 3 ];
7766               i0t = ind2[ 0 ];
7767               i2t = ind2[ 1 ];
7768             }
7769             else {
7770               ASSERT(0);
7771             }
7772             // tetrahedron 1
7773             uniqueNodes[ 0 ] = curNodes [ i0 ];
7774             uniqueNodes[ 1 ] = curNodes [ i1d ];
7775             uniqueNodes[ 2 ] = curNodes [ i3d ];
7776             uniqueNodes[ 3 ] = curNodes [ i0t ];
7777             nbUniqueNodes = 4;
7778             // tetrahedron 2
7779             SMDS_MeshElement* newElem = aMesh->AddVolume(curNodes[ i1d ],
7780                                                          curNodes[ i2 ],
7781                                                          curNodes[ i3d ],
7782                                                          curNodes[ i2t ]);
7783             myLastCreatedElems.Append(newElem);
7784             if ( aShapeId )
7785               aMesh->SetMeshElementOnShape( newElem, aShapeId );
7786             isOk = true;
7787           }
7788           else if (( nbTri == 2 && nbQuad == 3 ) || // merged (0-4)(1-5)
7789                    ( nbTri == 4 && nbQuad == 2 )) { // merged (7-4)(1-5)
7790             // --------------------------------------------> prism
7791             // find 2 opposite triangles
7792             nbUniqueNodes = 6;
7793             for ( iFace = 0; iFace + 1 < nbTri; iFace++ ) {
7794               if ( hexa.GetOppFaceIndex( iTriFace[ iFace ] ) == iTriFace[ iFace + 1 ]) {
7795                 // find indices of kept and replaced nodes
7796                 // and fill unique nodes of 2 opposite triangles
7797                 const int *ind1 = hexa.GetFaceNodesIndices( iTriFace[ iFace ]);
7798                 const int *ind2 = hexa.GetFaceNodesIndices( iTriFace[ iFace + 1 ]);
7799                 const SMDS_MeshNode** hexanodes = hexa.GetNodes();
7800                 // fill unique nodes
7801                 iUnique = 0;
7802                 isOk = true;
7803                 for ( iCur = 0; iCur < 4 && isOk; iCur++ ) {
7804                   const SMDS_MeshNode* n     = curNodes[ind1[ iCur ]];
7805                   const SMDS_MeshNode* nInit = hexanodes[ind1[ iCur ]];
7806                   if ( n == nInit ) {
7807                     // iCur of a linked node of the opposite face (make normals co-directed):
7808                     int iCurOpp = ( iCur == 1 || iCur == 3 ) ? 4 - iCur : iCur;
7809                     // check that correspondent corners of triangles are linked
7810                     if ( !hexa.IsLinked( ind1[ iCur ], ind2[ iCurOpp ] ))
7811                       isOk = false;
7812                     else {
7813                       uniqueNodes[ iUnique ] = n;
7814                       uniqueNodes[ iUnique + 3 ] = curNodes[ind2[ iCurOpp ]];
7815                       iUnique++;
7816                     }
7817                   }
7818                 }
7819                 break;
7820               }
7821             }
7822           }
7823         } // if ( nbUniqueNodes == 6 && nbRepl == 4 )
7824         break;
7825       } // HEXAHEDRON
7826
7827       default:
7828         isOk = false;
7829       } // switch ( nbNodes )
7830
7831     } // if ( nbNodes != nbUniqueNodes ) // some nodes stick
7832
7833     if ( isOk ) {
7834       if (elem->IsPoly() && elem->GetType() == SMDSAbs_Volume) {
7835         // Change nodes of polyedre
7836         const SMDS_VtkVolume* aPolyedre =
7837           dynamic_cast<const SMDS_VtkVolume*>( elem );
7838         if (aPolyedre) {
7839           int nbFaces = aPolyedre->NbFaces();
7840
7841           vector<const SMDS_MeshNode *> poly_nodes;
7842           vector<int> quantities (nbFaces);
7843
7844           for (int iface = 1; iface <= nbFaces; iface++) {
7845             int inode, nbFaceNodes = aPolyedre->NbFaceNodes(iface);
7846             quantities[iface - 1] = nbFaceNodes;
7847
7848             for (inode = 1; inode <= nbFaceNodes; inode++) {
7849               const SMDS_MeshNode* curNode = aPolyedre->GetFaceNode(iface, inode);
7850
7851               TNodeNodeMap::iterator nnIt = nodeNodeMap.find( curNode );
7852               if (nnIt != nodeNodeMap.end()) { // curNode sticks
7853                 curNode = (*nnIt).second;
7854               }
7855               poly_nodes.push_back(curNode);
7856             }
7857           }
7858           aMesh->ChangePolyhedronNodes( elem, poly_nodes, quantities );
7859         }
7860       }
7861       else {
7862         //int elemId = elem->GetID();
7863         //MESSAGE("Change regular element or polygon " << elemId);
7864         SMDSAbs_ElementType etyp = elem->GetType();
7865         uniqueNodes.resize(nbUniqueNodes);
7866         SMDS_MeshElement* newElem = 0;
7867         if (elem->GetEntityType() == SMDSEntity_Polygon)
7868           newElem = this->AddElement(uniqueNodes, etyp, true);
7869         else
7870           newElem = this->AddElement(uniqueNodes, etyp, false);
7871         if (newElem)
7872           {
7873             myLastCreatedElems.Append(newElem);
7874             if ( aShapeId )
7875               aMesh->SetMeshElementOnShape( newElem, aShapeId );
7876           }
7877         aMesh->RemoveElement(elem);
7878       }
7879     }
7880     else {
7881       // Remove invalid regular element or invalid polygon
7882       //MESSAGE("Remove invalid " << elem->GetID());
7883       rmElemIds.push_back( elem->GetID() );
7884     }
7885
7886   } // loop on elements
7887
7888   // Remove bad elements, then equal nodes (order important)
7889
7890   Remove( rmElemIds, false );
7891   Remove( rmNodeIds, true );
7892
7893 }
7894
7895
7896 // ========================================================
7897 // class   : SortableElement
7898 // purpose : allow sorting elements basing on their nodes
7899 // ========================================================
7900 class SortableElement : public set <const SMDS_MeshElement*>
7901 {
7902 public:
7903
7904   SortableElement( const SMDS_MeshElement* theElem )
7905   {
7906     myElem = theElem;
7907     SMDS_ElemIteratorPtr nodeIt = theElem->nodesIterator();
7908     while ( nodeIt->more() )
7909       this->insert( nodeIt->next() );
7910   }
7911
7912   const SMDS_MeshElement* Get() const
7913   { return myElem; }
7914
7915   void Set(const SMDS_MeshElement* e) const
7916   { myElem = e; }
7917
7918
7919 private:
7920   mutable const SMDS_MeshElement* myElem;
7921 };
7922
7923 //=======================================================================
7924 //function : FindEqualElements
7925 //purpose  : Return list of group of elements built on the same nodes.
7926 //           Search among theElements or in the whole mesh if theElements is empty
7927 //=======================================================================
7928 void SMESH_MeshEditor::FindEqualElements(set<const SMDS_MeshElement*> & theElements,
7929                                          TListOfListOfElementsID &      theGroupsOfElementsID)
7930 {
7931   myLastCreatedElems.Clear();
7932   myLastCreatedNodes.Clear();
7933
7934   typedef set<const SMDS_MeshElement*> TElemsSet;
7935   typedef map< SortableElement, int > TMapOfNodeSet;
7936   typedef list<int> TGroupOfElems;
7937
7938   TElemsSet elems;
7939   if ( theElements.empty() )
7940   { // get all elements in the mesh
7941     SMDS_ElemIteratorPtr eIt = GetMeshDS()->elementsIterator();
7942     while ( eIt->more() )
7943       elems.insert( elems.end(), eIt->next());
7944   }
7945   else
7946     elems = theElements;
7947
7948   vector< TGroupOfElems > arrayOfGroups;
7949   TGroupOfElems groupOfElems;
7950   TMapOfNodeSet mapOfNodeSet;
7951
7952   TElemsSet::iterator elemIt = elems.begin();
7953   for ( int i = 0, j=0; elemIt != elems.end(); ++elemIt, ++j ) {
7954     const SMDS_MeshElement* curElem = *elemIt;
7955     SortableElement SE(curElem);
7956     int ind = -1;
7957     // check uniqueness
7958     pair< TMapOfNodeSet::iterator, bool> pp = mapOfNodeSet.insert(make_pair(SE, i));
7959     if( !(pp.second) ) {
7960       TMapOfNodeSet::iterator& itSE = pp.first;
7961       ind = (*itSE).second;
7962       arrayOfGroups[ind].push_back(curElem->GetID());
7963     }
7964     else {
7965       groupOfElems.clear();
7966       groupOfElems.push_back(curElem->GetID());
7967       arrayOfGroups.push_back(groupOfElems);
7968       i++;
7969     }
7970   }
7971
7972   vector< TGroupOfElems >::iterator groupIt = arrayOfGroups.begin();
7973   for ( ; groupIt != arrayOfGroups.end(); ++groupIt ) {
7974     groupOfElems = *groupIt;
7975     if ( groupOfElems.size() > 1 ) {
7976       groupOfElems.sort();
7977       theGroupsOfElementsID.push_back(groupOfElems);
7978     }
7979   }
7980 }
7981
7982 //=======================================================================
7983 //function : MergeElements
7984 //purpose  : In each given group, substitute all elements by the first one.
7985 //=======================================================================
7986
7987 void SMESH_MeshEditor::MergeElements(TListOfListOfElementsID & theGroupsOfElementsID)
7988 {
7989   myLastCreatedElems.Clear();
7990   myLastCreatedNodes.Clear();
7991
7992   typedef list<int> TListOfIDs;
7993   TListOfIDs rmElemIds; // IDs of elems to remove
7994
7995   SMESHDS_Mesh* aMesh = GetMeshDS();
7996
7997   TListOfListOfElementsID::iterator groupsIt = theGroupsOfElementsID.begin();
7998   while ( groupsIt != theGroupsOfElementsID.end() ) {
7999     TListOfIDs& aGroupOfElemID = *groupsIt;
8000     aGroupOfElemID.sort();
8001     int elemIDToKeep = aGroupOfElemID.front();
8002     const SMDS_MeshElement* elemToKeep = aMesh->FindElement(elemIDToKeep);
8003     aGroupOfElemID.pop_front();
8004     TListOfIDs::iterator idIt = aGroupOfElemID.begin();
8005     while ( idIt != aGroupOfElemID.end() ) {
8006       int elemIDToRemove = *idIt;
8007       const SMDS_MeshElement* elemToRemove = aMesh->FindElement(elemIDToRemove);
8008       // add the kept element in groups of removed one (PAL15188)
8009       AddToSameGroups( elemToKeep, elemToRemove, aMesh );
8010       rmElemIds.push_back( elemIDToRemove );
8011       ++idIt;
8012     }
8013     ++groupsIt;
8014   }
8015
8016   Remove( rmElemIds, false );
8017 }
8018
8019 //=======================================================================
8020 //function : MergeEqualElements
8021 //purpose  : Remove all but one of elements built on the same nodes.
8022 //=======================================================================
8023
8024 void SMESH_MeshEditor::MergeEqualElements()
8025 {
8026   set<const SMDS_MeshElement*> aMeshElements; /* empty input -
8027                                                  to merge equal elements in the whole mesh */
8028   TListOfListOfElementsID aGroupsOfElementsID;
8029   FindEqualElements(aMeshElements, aGroupsOfElementsID);
8030   MergeElements(aGroupsOfElementsID);
8031 }
8032
8033 //=======================================================================
8034 //function : FindFaceInSet
8035 //purpose  : Return a face having linked nodes n1 and n2 and which is
8036 //           - not in avoidSet,
8037 //           - in elemSet provided that !elemSet.empty()
8038 //           i1 and i2 optionally returns indices of n1 and n2
8039 //=======================================================================
8040
8041 const SMDS_MeshElement*
8042 SMESH_MeshEditor::FindFaceInSet(const SMDS_MeshNode*    n1,
8043                                 const SMDS_MeshNode*    n2,
8044                                 const TIDSortedElemSet& elemSet,
8045                                 const TIDSortedElemSet& avoidSet,
8046                                 int*                    n1ind,
8047                                 int*                    n2ind)
8048
8049 {
8050   int i1, i2;
8051   const SMDS_MeshElement* face = 0;
8052
8053   SMDS_ElemIteratorPtr invElemIt = n1->GetInverseElementIterator(SMDSAbs_Face);
8054   //MESSAGE("n1->GetInverseElementIterator(SMDSAbs_Face) " << invElemIt);
8055   while ( invElemIt->more() && !face ) // loop on inverse faces of n1
8056   {
8057     //MESSAGE("in while ( invElemIt->more() && !face )");
8058     const SMDS_MeshElement* elem = invElemIt->next();
8059     if (avoidSet.count( elem ))
8060       continue;
8061     if ( !elemSet.empty() && !elemSet.count( elem ))
8062       continue;
8063     // index of n1
8064     i1 = elem->GetNodeIndex( n1 );
8065     // find a n2 linked to n1
8066     int nbN = elem->IsQuadratic() ? elem->NbNodes()/2 : elem->NbNodes();
8067     for ( int di = -1; di < 2 && !face; di += 2 )
8068     {
8069       i2 = (i1+di+nbN) % nbN;
8070       if ( elem->GetNode( i2 ) == n2 )
8071         face = elem;
8072     }
8073     if ( !face && elem->IsQuadratic())
8074     {
8075       // analysis for quadratic elements using all nodes
8076       const SMDS_VtkFace* F =
8077         dynamic_cast<const SMDS_VtkFace*>(elem);
8078       if (!F) throw SALOME_Exception(LOCALIZED("not an SMDS_VtkFace"));
8079       // use special nodes iterator
8080       SMDS_ElemIteratorPtr anIter = F->interlacedNodesElemIterator();
8081       const SMDS_MeshNode* prevN = cast2Node( anIter->next() );
8082       for ( i1 = -1, i2 = 0; anIter->more() && !face; i1++, i2++ )
8083       {
8084         const SMDS_MeshNode* n = cast2Node( anIter->next() );
8085         if ( n1 == prevN && n2 == n )
8086         {
8087           face = elem;
8088         }
8089         else if ( n2 == prevN && n1 == n )
8090         {
8091           face = elem; swap( i1, i2 );
8092         }
8093         prevN = n;
8094       }
8095     }
8096   }
8097   if ( n1ind ) *n1ind = i1;
8098   if ( n2ind ) *n2ind = i2;
8099   return face;
8100 }
8101
8102 //=======================================================================
8103 //function : findAdjacentFace
8104 //purpose  :
8105 //=======================================================================
8106
8107 static const SMDS_MeshElement* findAdjacentFace(const SMDS_MeshNode* n1,
8108                                                 const SMDS_MeshNode* n2,
8109                                                 const SMDS_MeshElement* elem)
8110 {
8111   TIDSortedElemSet elemSet, avoidSet;
8112   if ( elem )
8113     avoidSet.insert ( elem );
8114   return SMESH_MeshEditor::FindFaceInSet( n1, n2, elemSet, avoidSet );
8115 }
8116
8117 //=======================================================================
8118 //function : FindFreeBorder
8119 //purpose  :
8120 //=======================================================================
8121
8122 #define ControlFreeBorder SMESH::Controls::FreeEdges::IsFreeEdge
8123
8124 bool SMESH_MeshEditor::FindFreeBorder (const SMDS_MeshNode*             theFirstNode,
8125                                        const SMDS_MeshNode*             theSecondNode,
8126                                        const SMDS_MeshNode*             theLastNode,
8127                                        list< const SMDS_MeshNode* > &   theNodes,
8128                                        list< const SMDS_MeshElement* >& theFaces)
8129 {
8130   if ( !theFirstNode || !theSecondNode )
8131     return false;
8132   // find border face between theFirstNode and theSecondNode
8133   const SMDS_MeshElement* curElem = findAdjacentFace( theFirstNode, theSecondNode, 0 );
8134   if ( !curElem )
8135     return false;
8136
8137   theFaces.push_back( curElem );
8138   theNodes.push_back( theFirstNode );
8139   theNodes.push_back( theSecondNode );
8140
8141   //vector<const SMDS_MeshNode*> nodes;
8142   const SMDS_MeshNode *nIgnore = theFirstNode, *nStart = theSecondNode;
8143   TIDSortedElemSet foundElems;
8144   bool needTheLast = ( theLastNode != 0 );
8145
8146   while ( nStart != theLastNode ) {
8147     if ( nStart == theFirstNode )
8148       return !needTheLast;
8149
8150     // find all free border faces sharing form nStart
8151
8152     list< const SMDS_MeshElement* > curElemList;
8153     list< const SMDS_MeshNode* > nStartList;
8154     SMDS_ElemIteratorPtr invElemIt = nStart->GetInverseElementIterator(SMDSAbs_Face);
8155     while ( invElemIt->more() ) {
8156       const SMDS_MeshElement* e = invElemIt->next();
8157       if ( e == curElem || foundElems.insert( e ).second ) {
8158         // get nodes
8159         int iNode = 0, nbNodes = e->NbNodes();
8160         //const SMDS_MeshNode* nodes[nbNodes+1];
8161         vector<const SMDS_MeshNode*> nodes(nbNodes+1);
8162
8163         if(e->IsQuadratic()) {
8164           const SMDS_VtkFace* F =
8165             dynamic_cast<const SMDS_VtkFace*>(e);
8166           if (!F) throw SALOME_Exception(LOCALIZED("not an SMDS_VtkFace"));
8167           // use special nodes iterator
8168           SMDS_ElemIteratorPtr anIter = F->interlacedNodesElemIterator();
8169           while( anIter->more() ) {
8170             nodes[ iNode++ ] = cast2Node(anIter->next());
8171           }
8172         }
8173         else {
8174           SMDS_ElemIteratorPtr nIt = e->nodesIterator();
8175           while ( nIt->more() )
8176             nodes[ iNode++ ] = static_cast<const SMDS_MeshNode*>( nIt->next() );
8177         }
8178         nodes[ iNode ] = nodes[ 0 ];
8179         // check 2 links
8180         for ( iNode = 0; iNode < nbNodes; iNode++ )
8181           if (((nodes[ iNode ] == nStart && nodes[ iNode + 1] != nIgnore ) ||
8182                (nodes[ iNode + 1] == nStart && nodes[ iNode ] != nIgnore )) &&
8183               ControlFreeBorder( &nodes[ iNode ], e->GetID() ))
8184           {
8185             nStartList.push_back( nodes[ iNode + ( nodes[ iNode ] == nStart ? 1 : 0 )]);
8186             curElemList.push_back( e );
8187           }
8188       }
8189     }
8190     // analyse the found
8191
8192     int nbNewBorders = curElemList.size();
8193     if ( nbNewBorders == 0 ) {
8194       // no free border furthermore
8195       return !needTheLast;
8196     }
8197     else if ( nbNewBorders == 1 ) {
8198       // one more element found
8199       nIgnore = nStart;
8200       nStart = nStartList.front();
8201       curElem = curElemList.front();
8202       theFaces.push_back( curElem );
8203       theNodes.push_back( nStart );
8204     }
8205     else {
8206       // several continuations found
8207       list< const SMDS_MeshElement* >::iterator curElemIt;
8208       list< const SMDS_MeshNode* >::iterator nStartIt;
8209       // check if one of them reached the last node
8210       if ( needTheLast ) {
8211         for (curElemIt = curElemList.begin(), nStartIt = nStartList.begin();
8212              curElemIt!= curElemList.end();
8213              curElemIt++, nStartIt++ )
8214           if ( *nStartIt == theLastNode ) {
8215             theFaces.push_back( *curElemIt );
8216             theNodes.push_back( *nStartIt );
8217             return true;
8218           }
8219       }
8220       // find the best free border by the continuations
8221       list<const SMDS_MeshNode*>    contNodes[ 2 ], *cNL;
8222       list<const SMDS_MeshElement*> contFaces[ 2 ], *cFL;
8223       for (curElemIt = curElemList.begin(), nStartIt = nStartList.begin();
8224            curElemIt!= curElemList.end();
8225            curElemIt++, nStartIt++ )
8226       {
8227         cNL = & contNodes[ contNodes[0].empty() ? 0 : 1 ];
8228         cFL = & contFaces[ contFaces[0].empty() ? 0 : 1 ];
8229         // find one more free border
8230         if ( ! FindFreeBorder( nStart, *nStartIt, theLastNode, *cNL, *cFL )) {
8231           cNL->clear();
8232           cFL->clear();
8233         }
8234         else if ( !contNodes[0].empty() && !contNodes[1].empty() ) {
8235           // choice: clear a worse one
8236           int iLongest = ( contNodes[0].size() < contNodes[1].size() ? 1 : 0 );
8237           int iWorse = ( needTheLast ? 1 - iLongest : iLongest );
8238           contNodes[ iWorse ].clear();
8239           contFaces[ iWorse ].clear();
8240         }
8241       }
8242       if ( contNodes[0].empty() && contNodes[1].empty() )
8243         return false;
8244
8245       // append the best free border
8246       cNL = & contNodes[ contNodes[0].empty() ? 1 : 0 ];
8247       cFL = & contFaces[ contFaces[0].empty() ? 1 : 0 ];
8248       theNodes.pop_back(); // remove nIgnore
8249       theNodes.pop_back(); // remove nStart
8250       theFaces.pop_back(); // remove curElem
8251       list< const SMDS_MeshNode* >::iterator nIt = cNL->begin();
8252       list< const SMDS_MeshElement* >::iterator fIt = cFL->begin();
8253       for ( ; nIt != cNL->end(); nIt++ ) theNodes.push_back( *nIt );
8254       for ( ; fIt != cFL->end(); fIt++ ) theFaces.push_back( *fIt );
8255       return true;
8256
8257     } // several continuations found
8258   } // while ( nStart != theLastNode )
8259
8260   return true;
8261 }
8262
8263 //=======================================================================
8264 //function : CheckFreeBorderNodes
8265 //purpose  : Return true if the tree nodes are on a free border
8266 //=======================================================================
8267
8268 bool SMESH_MeshEditor::CheckFreeBorderNodes(const SMDS_MeshNode* theNode1,
8269                                             const SMDS_MeshNode* theNode2,
8270                                             const SMDS_MeshNode* theNode3)
8271 {
8272   list< const SMDS_MeshNode* > nodes;
8273   list< const SMDS_MeshElement* > faces;
8274   return FindFreeBorder( theNode1, theNode2, theNode3, nodes, faces);
8275 }
8276
8277 //=======================================================================
8278 //function : SewFreeBorder
8279 //purpose  :
8280 //=======================================================================
8281
8282 SMESH_MeshEditor::Sew_Error
8283 SMESH_MeshEditor::SewFreeBorder (const SMDS_MeshNode* theBordFirstNode,
8284                                  const SMDS_MeshNode* theBordSecondNode,
8285                                  const SMDS_MeshNode* theBordLastNode,
8286                                  const SMDS_MeshNode* theSideFirstNode,
8287                                  const SMDS_MeshNode* theSideSecondNode,
8288                                  const SMDS_MeshNode* theSideThirdNode,
8289                                  const bool           theSideIsFreeBorder,
8290                                  const bool           toCreatePolygons,
8291                                  const bool           toCreatePolyedrs)
8292 {
8293   myLastCreatedElems.Clear();
8294   myLastCreatedNodes.Clear();
8295
8296   MESSAGE("::SewFreeBorder()");
8297   Sew_Error aResult = SEW_OK;
8298
8299   // ====================================
8300   //    find side nodes and elements
8301   // ====================================
8302
8303   list< const SMDS_MeshNode* > nSide[ 2 ];
8304   list< const SMDS_MeshElement* > eSide[ 2 ];
8305   list< const SMDS_MeshNode* >::iterator nIt[ 2 ];
8306   list< const SMDS_MeshElement* >::iterator eIt[ 2 ];
8307
8308   // Free border 1
8309   // --------------
8310   if (!FindFreeBorder(theBordFirstNode,theBordSecondNode,theBordLastNode,
8311                       nSide[0], eSide[0])) {
8312     MESSAGE(" Free Border 1 not found " );
8313     aResult = SEW_BORDER1_NOT_FOUND;
8314   }
8315   if (theSideIsFreeBorder) {
8316     // Free border 2
8317     // --------------
8318     if (!FindFreeBorder(theSideFirstNode, theSideSecondNode, theSideThirdNode,
8319                         nSide[1], eSide[1])) {
8320       MESSAGE(" Free Border 2 not found " );
8321       aResult = ( aResult != SEW_OK ? SEW_BOTH_BORDERS_NOT_FOUND : SEW_BORDER2_NOT_FOUND );
8322     }
8323   }
8324   if ( aResult != SEW_OK )
8325     return aResult;
8326
8327   if (!theSideIsFreeBorder) {
8328     // Side 2
8329     // --------------
8330
8331     // -------------------------------------------------------------------------
8332     // Algo:
8333     // 1. If nodes to merge are not coincident, move nodes of the free border
8334     //    from the coord sys defined by the direction from the first to last
8335     //    nodes of the border to the correspondent sys of the side 2
8336     // 2. On the side 2, find the links most co-directed with the correspondent
8337     //    links of the free border
8338     // -------------------------------------------------------------------------
8339
8340     // 1. Since sewing may break if there are volumes to split on the side 2,
8341     //    we wont move nodes but just compute new coordinates for them
8342     typedef map<const SMDS_MeshNode*, gp_XYZ> TNodeXYZMap;
8343     TNodeXYZMap nBordXYZ;
8344     list< const SMDS_MeshNode* >& bordNodes = nSide[ 0 ];
8345     list< const SMDS_MeshNode* >::iterator nBordIt;
8346
8347     gp_XYZ Pb1( theBordFirstNode->X(), theBordFirstNode->Y(), theBordFirstNode->Z() );
8348     gp_XYZ Pb2( theBordLastNode->X(), theBordLastNode->Y(), theBordLastNode->Z() );
8349     gp_XYZ Ps1( theSideFirstNode->X(), theSideFirstNode->Y(), theSideFirstNode->Z() );
8350     gp_XYZ Ps2( theSideSecondNode->X(), theSideSecondNode->Y(), theSideSecondNode->Z() );
8351     double tol2 = 1.e-8;
8352     gp_Vec Vbs1( Pb1 - Ps1 ),Vbs2( Pb2 - Ps2 );
8353     if ( Vbs1.SquareMagnitude() > tol2 || Vbs2.SquareMagnitude() > tol2 ) {
8354       // Need node movement.
8355
8356       // find X and Z axes to create trsf
8357       gp_Vec Zb( Pb1 - Pb2 ), Zs( Ps1 - Ps2 );
8358       gp_Vec X = Zs ^ Zb;
8359       if ( X.SquareMagnitude() <= gp::Resolution() * gp::Resolution() )
8360         // Zb || Zs
8361         X = gp_Ax2( gp::Origin(), Zb ).XDirection();
8362
8363       // coord systems
8364       gp_Ax3 toBordAx( Pb1, Zb, X );
8365       gp_Ax3 fromSideAx( Ps1, Zs, X );
8366       gp_Ax3 toGlobalAx( gp::Origin(), gp::DZ(), gp::DX() );
8367       // set trsf
8368       gp_Trsf toBordSys, fromSide2Sys;
8369       toBordSys.SetTransformation( toBordAx );
8370       fromSide2Sys.SetTransformation( fromSideAx, toGlobalAx );
8371       fromSide2Sys.SetScaleFactor( Zs.Magnitude() / Zb.Magnitude() );
8372
8373       // move
8374       for ( nBordIt = bordNodes.begin(); nBordIt != bordNodes.end(); nBordIt++ ) {
8375         const SMDS_MeshNode* n = *nBordIt;
8376         gp_XYZ xyz( n->X(),n->Y(),n->Z() );
8377         toBordSys.Transforms( xyz );
8378         fromSide2Sys.Transforms( xyz );
8379         nBordXYZ.insert( TNodeXYZMap::value_type( n, xyz ));
8380       }
8381     }
8382     else {
8383       // just insert nodes XYZ in the nBordXYZ map
8384       for ( nBordIt = bordNodes.begin(); nBordIt != bordNodes.end(); nBordIt++ ) {
8385         const SMDS_MeshNode* n = *nBordIt;
8386         nBordXYZ.insert( TNodeXYZMap::value_type( n, gp_XYZ( n->X(),n->Y(),n->Z() )));
8387       }
8388     }
8389
8390     // 2. On the side 2, find the links most co-directed with the correspondent
8391     //    links of the free border
8392
8393     list< const SMDS_MeshElement* >& sideElems = eSide[ 1 ];
8394     list< const SMDS_MeshNode* >& sideNodes = nSide[ 1 ];
8395     sideNodes.push_back( theSideFirstNode );
8396
8397     bool hasVolumes = false;
8398     LinkID_Gen aLinkID_Gen( GetMeshDS() );
8399     set<long> foundSideLinkIDs, checkedLinkIDs;
8400     SMDS_VolumeTool volume;
8401     //const SMDS_MeshNode* faceNodes[ 4 ];
8402
8403     const SMDS_MeshNode*    sideNode;
8404     const SMDS_MeshElement* sideElem;
8405     const SMDS_MeshNode* prevSideNode = theSideFirstNode;
8406     const SMDS_MeshNode* prevBordNode = theBordFirstNode;
8407     nBordIt = bordNodes.begin();
8408     nBordIt++;
8409     // border node position and border link direction to compare with
8410     gp_XYZ bordPos = nBordXYZ[ *nBordIt ];
8411     gp_XYZ bordDir = bordPos - nBordXYZ[ prevBordNode ];
8412     // choose next side node by link direction or by closeness to
8413     // the current border node:
8414     bool searchByDir = ( *nBordIt != theBordLastNode );
8415     do {
8416       // find the next node on the Side 2
8417       sideNode = 0;
8418       double maxDot = -DBL_MAX, minDist = DBL_MAX;
8419       long linkID;
8420       checkedLinkIDs.clear();
8421       gp_XYZ prevXYZ( prevSideNode->X(), prevSideNode->Y(), prevSideNode->Z() );
8422
8423       // loop on inverse elements of current node (prevSideNode) on the Side 2
8424       SMDS_ElemIteratorPtr invElemIt = prevSideNode->GetInverseElementIterator();
8425       while ( invElemIt->more() )
8426       {
8427         const SMDS_MeshElement* elem = invElemIt->next();
8428         // prepare data for a loop on links coming to prevSideNode, of a face or a volume
8429         int iPrevNode, iNode = 0, nbNodes = elem->NbNodes();
8430         vector< const SMDS_MeshNode* > faceNodes( nbNodes, (const SMDS_MeshNode*)0 );
8431         bool isVolume = volume.Set( elem );
8432         const SMDS_MeshNode** nodes = isVolume ? volume.GetNodes() : & faceNodes[0];
8433         if ( isVolume ) // --volume
8434           hasVolumes = true;
8435         else if ( elem->GetType()==SMDSAbs_Face ) { // --face
8436           // retrieve all face nodes and find iPrevNode - an index of the prevSideNode
8437           if(elem->IsQuadratic()) {
8438             const SMDS_VtkFace* F =
8439               dynamic_cast<const SMDS_VtkFace*>(elem);
8440             if (!F) throw SALOME_Exception(LOCALIZED("not an SMDS_VtkFace"));
8441             // use special nodes iterator
8442             SMDS_ElemIteratorPtr anIter = F->interlacedNodesElemIterator();
8443             while( anIter->more() ) {
8444               nodes[ iNode ] = cast2Node(anIter->next());
8445               if ( nodes[ iNode++ ] == prevSideNode )
8446                 iPrevNode = iNode - 1;
8447             }
8448           }
8449           else {
8450             SMDS_ElemIteratorPtr nIt = elem->nodesIterator();
8451             while ( nIt->more() ) {
8452               nodes[ iNode ] = cast2Node( nIt->next() );
8453               if ( nodes[ iNode++ ] == prevSideNode )
8454                 iPrevNode = iNode - 1;
8455             }
8456           }
8457           // there are 2 links to check
8458           nbNodes = 2;
8459         }
8460         else // --edge
8461           continue;
8462         // loop on links, to be precise, on the second node of links
8463         for ( iNode = 0; iNode < nbNodes; iNode++ ) {
8464           const SMDS_MeshNode* n = nodes[ iNode ];
8465           if ( isVolume ) {
8466             if ( !volume.IsLinked( n, prevSideNode ))
8467               continue;
8468           }
8469           else {
8470             if ( iNode ) // a node before prevSideNode
8471               n = nodes[ iPrevNode == 0 ? elem->NbNodes() - 1 : iPrevNode - 1 ];
8472             else         // a node after prevSideNode
8473               n = nodes[ iPrevNode + 1 == elem->NbNodes() ? 0 : iPrevNode + 1 ];
8474           }
8475           // check if this link was already used
8476           long iLink = aLinkID_Gen.GetLinkID( prevSideNode, n );
8477           bool isJustChecked = !checkedLinkIDs.insert( iLink ).second;
8478           if (!isJustChecked &&
8479               foundSideLinkIDs.find( iLink ) == foundSideLinkIDs.end() )
8480           {
8481             // test a link geometrically
8482             gp_XYZ nextXYZ ( n->X(), n->Y(), n->Z() );
8483             bool linkIsBetter = false;
8484             double dot = 0.0, dist = 0.0;
8485             if ( searchByDir ) { // choose most co-directed link
8486               dot = bordDir * ( nextXYZ - prevXYZ ).Normalized();
8487               linkIsBetter = ( dot > maxDot );
8488             }
8489             else { // choose link with the node closest to bordPos
8490               dist = ( nextXYZ - bordPos ).SquareModulus();
8491               linkIsBetter = ( dist < minDist );
8492             }
8493             if ( linkIsBetter ) {
8494               maxDot = dot;
8495               minDist = dist;
8496               linkID = iLink;
8497               sideNode = n;
8498               sideElem = elem;
8499             }
8500           }
8501         }
8502       } // loop on inverse elements of prevSideNode
8503
8504       if ( !sideNode ) {
8505         MESSAGE(" Cant find path by links of the Side 2 ");
8506         return SEW_BAD_SIDE_NODES;
8507       }
8508       sideNodes.push_back( sideNode );
8509       sideElems.push_back( sideElem );
8510       foundSideLinkIDs.insert ( linkID );
8511       prevSideNode = sideNode;
8512
8513       if ( *nBordIt == theBordLastNode )
8514         searchByDir = false;
8515       else {
8516         // find the next border link to compare with
8517         gp_XYZ sidePos( sideNode->X(), sideNode->Y(), sideNode->Z() );
8518         searchByDir = ( bordDir * ( sidePos - bordPos ) <= 0 );
8519         // move to next border node if sideNode is before forward border node (bordPos)
8520         while ( *nBordIt != theBordLastNode && !searchByDir ) {
8521           prevBordNode = *nBordIt;
8522           nBordIt++;
8523           bordPos = nBordXYZ[ *nBordIt ];
8524           bordDir = bordPos - nBordXYZ[ prevBordNode ];
8525           searchByDir = ( bordDir * ( sidePos - bordPos ) <= 0 );
8526         }
8527       }
8528     }
8529     while ( sideNode != theSideSecondNode );
8530
8531     if ( hasVolumes && sideNodes.size () != bordNodes.size() && !toCreatePolyedrs) {
8532       MESSAGE("VOLUME SPLITTING IS FORBIDDEN");
8533       return SEW_VOLUMES_TO_SPLIT; // volume splitting is forbidden
8534     }
8535   } // end nodes search on the side 2
8536
8537   // ============================
8538   // sew the border to the side 2
8539   // ============================
8540
8541   int nbNodes[]  = { nSide[0].size(), nSide[1].size() };
8542   int maxNbNodes = Max( nbNodes[0], nbNodes[1] );
8543
8544   TListOfListOfNodes nodeGroupsToMerge;
8545   if ( nbNodes[0] == nbNodes[1] ||
8546        ( theSideIsFreeBorder && !theSideThirdNode)) {
8547
8548     // all nodes are to be merged
8549
8550     for (nIt[0] = nSide[0].begin(), nIt[1] = nSide[1].begin();
8551          nIt[0] != nSide[0].end() && nIt[1] != nSide[1].end();
8552          nIt[0]++, nIt[1]++ )
8553     {
8554       nodeGroupsToMerge.push_back( list<const SMDS_MeshNode*>() );
8555       nodeGroupsToMerge.back().push_back( *nIt[1] ); // to keep
8556       nodeGroupsToMerge.back().push_back( *nIt[0] ); // to remove
8557     }
8558   }
8559   else {
8560
8561     // insert new nodes into the border and the side to get equal nb of segments
8562
8563     // get normalized parameters of nodes on the borders
8564     //double param[ 2 ][ maxNbNodes ];
8565     double* param[ 2 ];
8566     param[0] = new double [ maxNbNodes ];
8567     param[1] = new double [ maxNbNodes ];
8568     int iNode, iBord;
8569     for ( iBord = 0; iBord < 2; iBord++ ) { // loop on 2 borders
8570       list< const SMDS_MeshNode* >& nodes = nSide[ iBord ];
8571       list< const SMDS_MeshNode* >::iterator nIt = nodes.begin();
8572       const SMDS_MeshNode* nPrev = *nIt;
8573       double bordLength = 0;
8574       for ( iNode = 0; nIt != nodes.end(); nIt++, iNode++ ) { // loop on border nodes
8575         const SMDS_MeshNode* nCur = *nIt;
8576         gp_XYZ segment (nCur->X() - nPrev->X(),
8577                         nCur->Y() - nPrev->Y(),
8578                         nCur->Z() - nPrev->Z());
8579         double segmentLen = segment.Modulus();
8580         bordLength += segmentLen;
8581         param[ iBord ][ iNode ] = bordLength;
8582         nPrev = nCur;
8583       }
8584       // normalize within [0,1]
8585       for ( iNode = 0; iNode < nbNodes[ iBord ]; iNode++ ) {
8586         param[ iBord ][ iNode ] /= bordLength;
8587       }
8588     }
8589
8590     // loop on border segments
8591     const SMDS_MeshNode *nPrev[ 2 ] = { 0, 0 };
8592     int i[ 2 ] = { 0, 0 };
8593     nIt[0] = nSide[0].begin(); eIt[0] = eSide[0].begin();
8594     nIt[1] = nSide[1].begin(); eIt[1] = eSide[1].begin();
8595
8596     TElemOfNodeListMap insertMap;
8597     TElemOfNodeListMap::iterator insertMapIt;
8598     // insertMap is
8599     // key:   elem to insert nodes into
8600     // value: 2 nodes to insert between + nodes to be inserted
8601     do {
8602       bool next[ 2 ] = { false, false };
8603
8604       // find min adjacent segment length after sewing
8605       double nextParam = 10., prevParam = 0;
8606       for ( iBord = 0; iBord < 2; iBord++ ) { // loop on 2 borders
8607         if ( i[ iBord ] + 1 < nbNodes[ iBord ])
8608           nextParam = Min( nextParam, param[iBord][ i[iBord] + 1 ]);
8609         if ( i[ iBord ] > 0 )
8610           prevParam = Max( prevParam, param[iBord][ i[iBord] - 1 ]);
8611       }
8612       double minParam = Min( param[ 0 ][ i[0] ], param[ 1 ][ i[1] ]);
8613       double maxParam = Max( param[ 0 ][ i[0] ], param[ 1 ][ i[1] ]);
8614       double minSegLen = Min( nextParam - minParam, maxParam - prevParam );
8615
8616       // choose to insert or to merge nodes
8617       double du = param[ 1 ][ i[1] ] - param[ 0 ][ i[0] ];
8618       if ( Abs( du ) <= minSegLen * 0.2 ) {
8619         // merge
8620         // ------
8621         nodeGroupsToMerge.push_back( list<const SMDS_MeshNode*>() );
8622         const SMDS_MeshNode* n0 = *nIt[0];
8623         const SMDS_MeshNode* n1 = *nIt[1];
8624         nodeGroupsToMerge.back().push_back( n1 );
8625         nodeGroupsToMerge.back().push_back( n0 );
8626         // position of node of the border changes due to merge
8627         param[ 0 ][ i[0] ] += du;
8628         // move n1 for the sake of elem shape evaluation during insertion.
8629         // n1 will be removed by MergeNodes() anyway
8630         const_cast<SMDS_MeshNode*>( n0 )->setXYZ( n1->X(), n1->Y(), n1->Z() );
8631         next[0] = next[1] = true;
8632       }
8633       else {
8634         // insert
8635         // ------
8636         int intoBord = ( du < 0 ) ? 0 : 1;
8637         const SMDS_MeshElement* elem = *eIt[ intoBord ];
8638         const SMDS_MeshNode*    n1   = nPrev[ intoBord ];
8639         const SMDS_MeshNode*    n2   = *nIt[ intoBord ];
8640         const SMDS_MeshNode*    nIns = *nIt[ 1 - intoBord ];
8641         if ( intoBord == 1 ) {
8642           // move node of the border to be on a link of elem of the side
8643           gp_XYZ p1 (n1->X(), n1->Y(), n1->Z());
8644           gp_XYZ p2 (n2->X(), n2->Y(), n2->Z());
8645           double ratio = du / ( param[ 1 ][ i[1] ] - param[ 1 ][ i[1]-1 ]);
8646           gp_XYZ p = p2 * ( 1 - ratio ) + p1 * ratio;
8647           GetMeshDS()->MoveNode( nIns, p.X(), p.Y(), p.Z() );
8648         }
8649         insertMapIt = insertMap.find( elem );
8650         bool notFound = ( insertMapIt == insertMap.end() );
8651         bool otherLink = ( !notFound && (*insertMapIt).second.front() != n1 );
8652         if ( otherLink ) {
8653           // insert into another link of the same element:
8654           // 1. perform insertion into the other link of the elem
8655           list<const SMDS_MeshNode*> & nodeList = (*insertMapIt).second;
8656           const SMDS_MeshNode* n12 = nodeList.front(); nodeList.pop_front();
8657           const SMDS_MeshNode* n22 = nodeList.front(); nodeList.pop_front();
8658           InsertNodesIntoLink( elem, n12, n22, nodeList, toCreatePolygons );
8659           // 2. perform insertion into the link of adjacent faces
8660           while (true) {
8661             const SMDS_MeshElement* adjElem = findAdjacentFace( n12, n22, elem );
8662             if ( adjElem )
8663               InsertNodesIntoLink( adjElem, n12, n22, nodeList, toCreatePolygons );
8664             else
8665               break;
8666           }
8667           if (toCreatePolyedrs) {
8668             // perform insertion into the links of adjacent volumes
8669             UpdateVolumes(n12, n22, nodeList);
8670           }
8671           // 3. find an element appeared on n1 and n2 after the insertion
8672           insertMap.erase( elem );
8673           elem = findAdjacentFace( n1, n2, 0 );
8674         }
8675         if ( notFound || otherLink ) {
8676           // add element and nodes of the side into the insertMap
8677           insertMapIt = insertMap.insert
8678             ( TElemOfNodeListMap::value_type( elem, list<const SMDS_MeshNode*>() )).first;
8679           (*insertMapIt).second.push_back( n1 );
8680           (*insertMapIt).second.push_back( n2 );
8681         }
8682         // add node to be inserted into elem
8683         (*insertMapIt).second.push_back( nIns );
8684         next[ 1 - intoBord ] = true;
8685       }
8686
8687       // go to the next segment
8688       for ( iBord = 0; iBord < 2; iBord++ ) { // loop on 2 borders
8689         if ( next[ iBord ] ) {
8690           if ( i[ iBord ] != 0 && eIt[ iBord ] != eSide[ iBord ].end())
8691             eIt[ iBord ]++;
8692           nPrev[ iBord ] = *nIt[ iBord ];
8693           nIt[ iBord ]++; i[ iBord ]++;
8694         }
8695       }
8696     }
8697     while ( nIt[0] != nSide[0].end() && nIt[1] != nSide[1].end());
8698
8699     // perform insertion of nodes into elements
8700
8701     for (insertMapIt = insertMap.begin();
8702          insertMapIt != insertMap.end();
8703          insertMapIt++ )
8704     {
8705       const SMDS_MeshElement* elem = (*insertMapIt).first;
8706       list<const SMDS_MeshNode*> & nodeList = (*insertMapIt).second;
8707       const SMDS_MeshNode* n1 = nodeList.front(); nodeList.pop_front();
8708       const SMDS_MeshNode* n2 = nodeList.front(); nodeList.pop_front();
8709
8710       InsertNodesIntoLink( elem, n1, n2, nodeList, toCreatePolygons );
8711
8712       if ( !theSideIsFreeBorder ) {
8713         // look for and insert nodes into the faces adjacent to elem
8714         while (true) {
8715           const SMDS_MeshElement* adjElem = findAdjacentFace( n1, n2, elem );
8716           if ( adjElem )
8717             InsertNodesIntoLink( adjElem, n1, n2, nodeList, toCreatePolygons );
8718           else
8719             break;
8720         }
8721       }
8722       if (toCreatePolyedrs) {
8723         // perform insertion into the links of adjacent volumes
8724         UpdateVolumes(n1, n2, nodeList);
8725       }
8726     }
8727
8728     delete param[0];
8729     delete param[1];
8730   } // end: insert new nodes
8731
8732   MergeNodes ( nodeGroupsToMerge );
8733
8734   return aResult;
8735 }
8736
8737 //=======================================================================
8738 //function : InsertNodesIntoLink
8739 //purpose  : insert theNodesToInsert into theFace between theBetweenNode1
8740 //           and theBetweenNode2 and split theElement
8741 //=======================================================================
8742
8743 void SMESH_MeshEditor::InsertNodesIntoLink(const SMDS_MeshElement*     theFace,
8744                                            const SMDS_MeshNode*        theBetweenNode1,
8745                                            const SMDS_MeshNode*        theBetweenNode2,
8746                                            list<const SMDS_MeshNode*>& theNodesToInsert,
8747                                            const bool                  toCreatePoly)
8748 {
8749   if ( theFace->GetType() != SMDSAbs_Face ) return;
8750
8751   // find indices of 2 link nodes and of the rest nodes
8752   int iNode = 0, il1, il2, i3, i4;
8753   il1 = il2 = i3 = i4 = -1;
8754   //const SMDS_MeshNode* nodes[ theFace->NbNodes() ];
8755   vector<const SMDS_MeshNode*> nodes( theFace->NbNodes() );
8756
8757   if(theFace->IsQuadratic()) {
8758     const SMDS_VtkFace* F =
8759       dynamic_cast<const SMDS_VtkFace*>(theFace);
8760     if (!F) throw SALOME_Exception(LOCALIZED("not an SMDS_VtkFace"));
8761     // use special nodes iterator
8762     SMDS_ElemIteratorPtr anIter = F->interlacedNodesElemIterator();
8763     while( anIter->more() ) {
8764       const SMDS_MeshNode* n = cast2Node(anIter->next());
8765       if ( n == theBetweenNode1 )
8766         il1 = iNode;
8767       else if ( n == theBetweenNode2 )
8768         il2 = iNode;
8769       else if ( i3 < 0 )
8770         i3 = iNode;
8771       else
8772         i4 = iNode;
8773       nodes[ iNode++ ] = n;
8774     }
8775   }
8776   else {
8777     SMDS_ElemIteratorPtr nodeIt = theFace->nodesIterator();
8778     while ( nodeIt->more() ) {
8779       const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
8780       if ( n == theBetweenNode1 )
8781         il1 = iNode;
8782       else if ( n == theBetweenNode2 )
8783         il2 = iNode;
8784       else if ( i3 < 0 )
8785         i3 = iNode;
8786       else
8787         i4 = iNode;
8788       nodes[ iNode++ ] = n;
8789     }
8790   }
8791   if ( il1 < 0 || il2 < 0 || i3 < 0 )
8792     return ;
8793
8794   // arrange link nodes to go one after another regarding the face orientation
8795   bool reverse = ( Abs( il2 - il1 ) == 1 ? il2 < il1 : il1 < il2 );
8796   list<const SMDS_MeshNode *> aNodesToInsert = theNodesToInsert;
8797   if ( reverse ) {
8798     iNode = il1;
8799     il1 = il2;
8800     il2 = iNode;
8801     aNodesToInsert.reverse();
8802   }
8803   // check that not link nodes of a quadrangles are in good order
8804   int nbFaceNodes = theFace->NbNodes();
8805   if ( nbFaceNodes == 4 && i4 - i3 != 1 ) {
8806     iNode = i3;
8807     i3 = i4;
8808     i4 = iNode;
8809   }
8810
8811   if (toCreatePoly || theFace->IsPoly()) {
8812
8813     iNode = 0;
8814     vector<const SMDS_MeshNode *> poly_nodes (nbFaceNodes + aNodesToInsert.size());
8815
8816     // add nodes of face up to first node of link
8817     bool isFLN = false;
8818
8819     if(theFace->IsQuadratic()) {
8820       const SMDS_VtkFace* F =
8821         dynamic_cast<const SMDS_VtkFace*>(theFace);
8822       if (!F) throw SALOME_Exception(LOCALIZED("not an SMDS_VtkFace"));
8823       // use special nodes iterator
8824       SMDS_ElemIteratorPtr anIter = F->interlacedNodesElemIterator();
8825       while( anIter->more()  && !isFLN ) {
8826         const SMDS_MeshNode* n = cast2Node(anIter->next());
8827         poly_nodes[iNode++] = n;
8828         if (n == nodes[il1]) {
8829           isFLN = true;
8830         }
8831       }
8832       // add nodes to insert
8833       list<const SMDS_MeshNode*>::iterator nIt = aNodesToInsert.begin();
8834       for (; nIt != aNodesToInsert.end(); nIt++) {
8835         poly_nodes[iNode++] = *nIt;
8836       }
8837       // add nodes of face starting from last node of link
8838       while ( anIter->more() ) {
8839         poly_nodes[iNode++] = cast2Node(anIter->next());
8840       }
8841     }
8842     else {
8843       SMDS_ElemIteratorPtr nodeIt = theFace->nodesIterator();
8844       while ( nodeIt->more() && !isFLN ) {
8845         const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
8846         poly_nodes[iNode++] = n;
8847         if (n == nodes[il1]) {
8848           isFLN = true;
8849         }
8850       }
8851       // add nodes to insert
8852       list<const SMDS_MeshNode*>::iterator nIt = aNodesToInsert.begin();
8853       for (; nIt != aNodesToInsert.end(); nIt++) {
8854         poly_nodes[iNode++] = *nIt;
8855       }
8856       // add nodes of face starting from last node of link
8857       while ( nodeIt->more() ) {
8858         const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
8859         poly_nodes[iNode++] = n;
8860       }
8861     }
8862
8863     // edit or replace the face
8864     SMESHDS_Mesh *aMesh = GetMeshDS();
8865
8866     if (theFace->IsPoly()) {
8867       aMesh->ChangePolygonNodes(theFace, poly_nodes);
8868     }
8869     else {
8870       int aShapeId = FindShape( theFace );
8871
8872       SMDS_MeshElement* newElem = aMesh->AddPolygonalFace(poly_nodes);
8873       myLastCreatedElems.Append(newElem);
8874       if ( aShapeId && newElem )
8875         aMesh->SetMeshElementOnShape( newElem, aShapeId );
8876
8877       aMesh->RemoveElement(theFace);
8878     }
8879     return;
8880   }
8881
8882   SMESHDS_Mesh *aMesh = GetMeshDS();
8883   if( !theFace->IsQuadratic() ) {
8884
8885     // put aNodesToInsert between theBetweenNode1 and theBetweenNode2
8886     int nbLinkNodes = 2 + aNodesToInsert.size();
8887     //const SMDS_MeshNode* linkNodes[ nbLinkNodes ];
8888     vector<const SMDS_MeshNode*> linkNodes( nbLinkNodes );
8889     linkNodes[ 0 ] = nodes[ il1 ];
8890     linkNodes[ nbLinkNodes - 1 ] = nodes[ il2 ];
8891     list<const SMDS_MeshNode*>::iterator nIt = aNodesToInsert.begin();
8892     for ( iNode = 1; nIt != aNodesToInsert.end(); nIt++ ) {
8893       linkNodes[ iNode++ ] = *nIt;
8894     }
8895     // decide how to split a quadrangle: compare possible variants
8896     // and choose which of splits to be a quadrangle
8897     int i1, i2, iSplit, nbSplits = nbLinkNodes - 1, iBestQuad;
8898     if ( nbFaceNodes == 3 ) {
8899       iBestQuad = nbSplits;
8900       i4 = i3;
8901     }
8902     else if ( nbFaceNodes == 4 ) {
8903       SMESH::Controls::NumericalFunctorPtr aCrit( new SMESH::Controls::AspectRatio);
8904       double aBestRate = DBL_MAX;
8905       for ( int iQuad = 0; iQuad < nbSplits; iQuad++ ) {
8906         i1 = 0; i2 = 1;
8907         double aBadRate = 0;
8908         // evaluate elements quality
8909         for ( iSplit = 0; iSplit < nbSplits; iSplit++ ) {
8910           if ( iSplit == iQuad ) {
8911             SMDS_FaceOfNodes quad (linkNodes[ i1++ ],
8912                                    linkNodes[ i2++ ],
8913                                    nodes[ i3 ],
8914                                    nodes[ i4 ]);
8915             aBadRate += getBadRate( &quad, aCrit );
8916           }
8917           else {
8918             SMDS_FaceOfNodes tria (linkNodes[ i1++ ],
8919                                    linkNodes[ i2++ ],
8920                                    nodes[ iSplit < iQuad ? i4 : i3 ]);
8921             aBadRate += getBadRate( &tria, aCrit );
8922           }
8923         }
8924         // choice
8925         if ( aBadRate < aBestRate ) {
8926           iBestQuad = iQuad;
8927           aBestRate = aBadRate;
8928         }
8929       }
8930     }
8931
8932     // create new elements
8933     int aShapeId = FindShape( theFace );
8934
8935     i1 = 0; i2 = 1;
8936     for ( iSplit = 0; iSplit < nbSplits - 1; iSplit++ ) {
8937       SMDS_MeshElement* newElem = 0;
8938       if ( iSplit == iBestQuad )
8939         newElem = aMesh->AddFace (linkNodes[ i1++ ],
8940                                   linkNodes[ i2++ ],
8941                                   nodes[ i3 ],
8942                                   nodes[ i4 ]);
8943       else
8944         newElem = aMesh->AddFace (linkNodes[ i1++ ],
8945                                   linkNodes[ i2++ ],
8946                                   nodes[ iSplit < iBestQuad ? i4 : i3 ]);
8947       myLastCreatedElems.Append(newElem);
8948       if ( aShapeId && newElem )
8949         aMesh->SetMeshElementOnShape( newElem, aShapeId );
8950     }
8951
8952     // change nodes of theFace
8953     const SMDS_MeshNode* newNodes[ 4 ];
8954     newNodes[ 0 ] = linkNodes[ i1 ];
8955     newNodes[ 1 ] = linkNodes[ i2 ];
8956     newNodes[ 2 ] = nodes[ iSplit >= iBestQuad ? i3 : i4 ];
8957     newNodes[ 3 ] = nodes[ i4 ];
8958     //aMesh->ChangeElementNodes( theFace, newNodes, iSplit == iBestQuad ? 4 : 3 );
8959     const SMDS_MeshElement* newElem = 0;
8960     if (iSplit == iBestQuad)
8961       newElem = aMesh->AddFace( newNodes[0], newNodes[1], newNodes[2], newNodes[3] );
8962     else
8963       newElem = aMesh->AddFace( newNodes[0], newNodes[1], newNodes[2] );
8964     myLastCreatedElems.Append(newElem);
8965     if ( aShapeId && newElem )
8966       aMesh->SetMeshElementOnShape( newElem, aShapeId );
8967 } // end if(!theFace->IsQuadratic())
8968   else { // theFace is quadratic
8969     // we have to split theFace on simple triangles and one simple quadrangle
8970     int tmp = il1/2;
8971     int nbshift = tmp*2;
8972     // shift nodes in nodes[] by nbshift
8973     int i,j;
8974     for(i=0; i<nbshift; i++) {
8975       const SMDS_MeshNode* n = nodes[0];
8976       for(j=0; j<nbFaceNodes-1; j++) {
8977         nodes[j] = nodes[j+1];
8978       }
8979       nodes[nbFaceNodes-1] = n;
8980     }
8981     il1 = il1 - nbshift;
8982     // now have to insert nodes between n0 and n1 or n1 and n2 (see below)
8983     //   n0      n1     n2    n0      n1     n2
8984     //     +-----+-----+        +-----+-----+
8985     //      \         /         |           |
8986     //       \       /          |           |
8987     //      n5+     +n3       n7+           +n3
8988     //         \   /            |           |
8989     //          \ /             |           |
8990     //           +              +-----+-----+
8991     //           n4           n6      n5     n4
8992
8993     // create new elements
8994     int aShapeId = FindShape( theFace );
8995
8996     int n1,n2,n3;
8997     if(nbFaceNodes==6) { // quadratic triangle
8998       SMDS_MeshElement* newElem =
8999         aMesh->AddFace(nodes[3],nodes[4],nodes[5]);
9000       myLastCreatedElems.Append(newElem);
9001       if ( aShapeId && newElem )
9002         aMesh->SetMeshElementOnShape( newElem, aShapeId );
9003       if(theFace->IsMediumNode(nodes[il1])) {
9004         // create quadrangle
9005         newElem = aMesh->AddFace(nodes[0],nodes[1],nodes[3],nodes[5]);
9006         myLastCreatedElems.Append(newElem);
9007         if ( aShapeId && newElem )
9008           aMesh->SetMeshElementOnShape( newElem, aShapeId );
9009         n1 = 1;
9010         n2 = 2;
9011         n3 = 3;
9012       }
9013       else {
9014         // create quadrangle
9015         newElem = aMesh->AddFace(nodes[1],nodes[2],nodes[3],nodes[5]);
9016         myLastCreatedElems.Append(newElem);
9017         if ( aShapeId && newElem )
9018           aMesh->SetMeshElementOnShape( newElem, aShapeId );
9019         n1 = 0;
9020         n2 = 1;
9021         n3 = 5;
9022       }
9023     }
9024     else { // nbFaceNodes==8 - quadratic quadrangle
9025       SMDS_MeshElement* newElem =
9026         aMesh->AddFace(nodes[3],nodes[4],nodes[5]);
9027       myLastCreatedElems.Append(newElem);
9028       if ( aShapeId && newElem )
9029         aMesh->SetMeshElementOnShape( newElem, aShapeId );
9030       newElem = aMesh->AddFace(nodes[5],nodes[6],nodes[7]);
9031       myLastCreatedElems.Append(newElem);
9032       if ( aShapeId && newElem )
9033         aMesh->SetMeshElementOnShape( newElem, aShapeId );
9034       newElem = aMesh->AddFace(nodes[5],nodes[7],nodes[3]);
9035       myLastCreatedElems.Append(newElem);
9036       if ( aShapeId && newElem )
9037         aMesh->SetMeshElementOnShape( newElem, aShapeId );
9038       if(theFace->IsMediumNode(nodes[il1])) {
9039         // create quadrangle
9040         newElem = aMesh->AddFace(nodes[0],nodes[1],nodes[3],nodes[7]);
9041         myLastCreatedElems.Append(newElem);
9042         if ( aShapeId && newElem )
9043           aMesh->SetMeshElementOnShape( newElem, aShapeId );
9044         n1 = 1;
9045         n2 = 2;
9046         n3 = 3;
9047       }
9048       else {
9049         // create quadrangle
9050         newElem = aMesh->AddFace(nodes[1],nodes[2],nodes[3],nodes[7]);
9051         myLastCreatedElems.Append(newElem);
9052         if ( aShapeId && newElem )
9053           aMesh->SetMeshElementOnShape( newElem, aShapeId );
9054         n1 = 0;
9055         n2 = 1;
9056         n3 = 7;
9057       }
9058     }
9059     // create needed triangles using n1,n2,n3 and inserted nodes
9060     int nbn = 2 + aNodesToInsert.size();
9061     //const SMDS_MeshNode* aNodes[nbn];
9062     vector<const SMDS_MeshNode*> aNodes(nbn);
9063     aNodes[0] = nodes[n1];
9064     aNodes[nbn-1] = nodes[n2];
9065     list<const SMDS_MeshNode*>::iterator nIt = aNodesToInsert.begin();
9066     for ( iNode = 1; nIt != aNodesToInsert.end(); nIt++ ) {
9067       aNodes[iNode++] = *nIt;
9068     }
9069     for(i=1; i<nbn; i++) {
9070       SMDS_MeshElement* newElem =
9071         aMesh->AddFace(aNodes[i-1],aNodes[i],nodes[n3]);
9072       myLastCreatedElems.Append(newElem);
9073       if ( aShapeId && newElem )
9074         aMesh->SetMeshElementOnShape( newElem, aShapeId );
9075     }
9076   }
9077   // remove old face
9078   aMesh->RemoveElement(theFace);
9079 }
9080
9081 //=======================================================================
9082 //function : UpdateVolumes
9083 //purpose  :
9084 //=======================================================================
9085 void SMESH_MeshEditor::UpdateVolumes (const SMDS_MeshNode*        theBetweenNode1,
9086                                       const SMDS_MeshNode*        theBetweenNode2,
9087                                       list<const SMDS_MeshNode*>& theNodesToInsert)
9088 {
9089   myLastCreatedElems.Clear();
9090   myLastCreatedNodes.Clear();
9091
9092   SMDS_ElemIteratorPtr invElemIt = theBetweenNode1->GetInverseElementIterator(SMDSAbs_Volume);
9093   while (invElemIt->more()) { // loop on inverse elements of theBetweenNode1
9094     const SMDS_MeshElement* elem = invElemIt->next();
9095
9096     // check, if current volume has link theBetweenNode1 - theBetweenNode2
9097     SMDS_VolumeTool aVolume (elem);
9098     if (!aVolume.IsLinked(theBetweenNode1, theBetweenNode2))
9099       continue;
9100
9101     // insert new nodes in all faces of the volume, sharing link theBetweenNode1 - theBetweenNode2
9102     int iface, nbFaces = aVolume.NbFaces();
9103     vector<const SMDS_MeshNode *> poly_nodes;
9104     vector<int> quantities (nbFaces);
9105
9106     for (iface = 0; iface < nbFaces; iface++) {
9107       int nbFaceNodes = aVolume.NbFaceNodes(iface), nbInserted = 0;
9108       // faceNodes will contain (nbFaceNodes + 1) nodes, last = first
9109       const SMDS_MeshNode** faceNodes = aVolume.GetFaceNodes(iface);
9110
9111       for (int inode = 0; inode < nbFaceNodes; inode++) {
9112         poly_nodes.push_back(faceNodes[inode]);
9113
9114         if (nbInserted == 0) {
9115           if (faceNodes[inode] == theBetweenNode1) {
9116             if (faceNodes[inode + 1] == theBetweenNode2) {
9117               nbInserted = theNodesToInsert.size();
9118
9119               // add nodes to insert
9120               list<const SMDS_MeshNode*>::iterator nIt = theNodesToInsert.begin();
9121               for (; nIt != theNodesToInsert.end(); nIt++) {
9122                 poly_nodes.push_back(*nIt);
9123               }
9124             }
9125           }
9126           else if (faceNodes[inode] == theBetweenNode2) {
9127             if (faceNodes[inode + 1] == theBetweenNode1) {
9128               nbInserted = theNodesToInsert.size();
9129
9130               // add nodes to insert in reversed order
9131               list<const SMDS_MeshNode*>::iterator nIt = theNodesToInsert.end();
9132               nIt--;
9133               for (; nIt != theNodesToInsert.begin(); nIt--) {
9134                 poly_nodes.push_back(*nIt);
9135               }
9136               poly_nodes.push_back(*nIt);
9137             }
9138           }
9139           else {
9140           }
9141         }
9142       }
9143       quantities[iface] = nbFaceNodes + nbInserted;
9144     }
9145
9146     // Replace or update the volume
9147     SMESHDS_Mesh *aMesh = GetMeshDS();
9148
9149     if (elem->IsPoly()) {
9150       aMesh->ChangePolyhedronNodes(elem, poly_nodes, quantities);
9151
9152     }
9153     else {
9154       int aShapeId = FindShape( elem );
9155
9156       SMDS_MeshElement* newElem =
9157         aMesh->AddPolyhedralVolume(poly_nodes, quantities);
9158       myLastCreatedElems.Append(newElem);
9159       if (aShapeId && newElem)
9160         aMesh->SetMeshElementOnShape(newElem, aShapeId);
9161
9162       aMesh->RemoveElement(elem);
9163     }
9164   }
9165 }
9166
9167 //=======================================================================
9168 /*!
9169  * \brief Convert elements contained in a submesh to quadratic
9170  * \retval int - nb of checked elements
9171  */
9172 //=======================================================================
9173
9174 int SMESH_MeshEditor::convertElemToQuadratic(SMESHDS_SubMesh *   theSm,
9175                                              SMESH_MesherHelper& theHelper,
9176                                              const bool          theForce3d)
9177 {
9178   int nbElem = 0;
9179   if( !theSm ) return nbElem;
9180
9181   vector<int> nbNodeInFaces;
9182   SMDS_ElemIteratorPtr ElemItr = theSm->GetElements();
9183   while(ElemItr->more())
9184   {
9185     nbElem++;
9186     const SMDS_MeshElement* elem = ElemItr->next();
9187     if( !elem || elem->IsQuadratic() ) continue;
9188
9189     int id = elem->GetID();
9190     //MESSAGE("elem " << id);
9191     id = 0; // get a free number for new elements
9192     int nbNodes = elem->NbNodes();
9193     SMDSAbs_ElementType aType = elem->GetType();
9194
9195     vector<const SMDS_MeshNode *> nodes (elem->begin_nodes(), elem->end_nodes());
9196     if ( elem->GetEntityType() == SMDSEntity_Polyhedra )
9197       nbNodeInFaces = static_cast<const SMDS_VtkVolume* >( elem )->GetQuantities();
9198
9199     const SMDS_MeshElement* NewElem = 0;
9200
9201     switch( aType )
9202     {
9203     case SMDSAbs_Edge :
9204       {
9205         NewElem = theHelper.AddEdge(nodes[0], nodes[1], id, theForce3d);
9206         break;
9207       }
9208     case SMDSAbs_Face :
9209       {
9210         switch(nbNodes)
9211         {
9212         case 3:
9213           NewElem = theHelper.AddFace(nodes[0], nodes[1], nodes[2], id, theForce3d);
9214           break;
9215         case 4:
9216           NewElem = theHelper.AddFace(nodes[0], nodes[1], nodes[2], nodes[3], id, theForce3d);
9217           break;
9218         default:
9219           NewElem = theHelper.AddPolygonalFace(nodes, id, theForce3d);
9220           continue;
9221         }
9222         break;
9223       }
9224     case SMDSAbs_Volume :
9225       {
9226         switch(nbNodes)
9227         {
9228         case 4:
9229           NewElem = theHelper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3], id, theForce3d);
9230           break;
9231         case 5:
9232           NewElem = theHelper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3], nodes[4], id, theForce3d);
9233           break;
9234         case 6:
9235           NewElem = theHelper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3], nodes[4], nodes[5], id, theForce3d);
9236           break;
9237         case 8:
9238           NewElem = theHelper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3],
9239                                         nodes[4], nodes[5], nodes[6], nodes[7], id, theForce3d);
9240           break;
9241         default:
9242           NewElem = theHelper.AddPolyhedralVolume(nodes, nbNodeInFaces, id, theForce3d);
9243         }
9244         break;
9245       }
9246     default :
9247       continue;
9248     }
9249     ReplaceElemInGroups( elem, NewElem, GetMeshDS());
9250     if( NewElem )
9251       theSm->AddElement( NewElem );
9252
9253     GetMeshDS()->RemoveFreeElement(elem, theSm, /*fromGroups=*/false);
9254   }
9255 //  if (!GetMeshDS()->isCompacted())
9256 //    GetMeshDS()->compactMesh();
9257   return nbElem;
9258 }
9259
9260 //=======================================================================
9261 //function : ConvertToQuadratic
9262 //purpose  :
9263 //=======================================================================
9264 void SMESH_MeshEditor::ConvertToQuadratic(const bool theForce3d)
9265 {
9266   SMESHDS_Mesh* meshDS = GetMeshDS();
9267
9268   SMESH_MesherHelper aHelper(*myMesh);
9269   aHelper.SetIsQuadratic( true );
9270
9271   int nbCheckedElems = 0;
9272   if ( myMesh->HasShapeToMesh() )
9273   {
9274     if ( SMESH_subMesh *aSubMesh = myMesh->GetSubMeshContaining(myMesh->GetShapeToMesh()))
9275     {
9276       SMESH_subMeshIteratorPtr smIt = aSubMesh->getDependsOnIterator(true,false);
9277       while ( smIt->more() ) {
9278         SMESH_subMesh* sm = smIt->next();
9279         if ( SMESHDS_SubMesh *smDS = sm->GetSubMeshDS() ) {
9280           aHelper.SetSubShape( sm->GetSubShape() );
9281           nbCheckedElems += convertElemToQuadratic(smDS, aHelper, theForce3d);
9282         }
9283       }
9284     }
9285   }
9286   int totalNbElems = meshDS->NbEdges() + meshDS->NbFaces() + meshDS->NbVolumes();
9287   if ( nbCheckedElems < totalNbElems ) // not all elements are in submeshes
9288   {
9289     SMESHDS_SubMesh *smDS = 0;
9290     SMDS_EdgeIteratorPtr aEdgeItr = meshDS->edgesIterator();
9291     while(aEdgeItr->more())
9292     {
9293       const SMDS_MeshEdge* edge = aEdgeItr->next();
9294       if(edge && !edge->IsQuadratic())
9295       {
9296         int id = edge->GetID();
9297         //MESSAGE("edge->GetID() " << id);
9298         const SMDS_MeshNode* n1 = edge->GetNode(0);
9299         const SMDS_MeshNode* n2 = edge->GetNode(1);
9300
9301         meshDS->RemoveFreeElement(edge, smDS, /*fromGroups=*/false);
9302
9303         const SMDS_MeshEdge* NewEdge = aHelper.AddEdge(n1, n2, id, theForce3d);
9304         ReplaceElemInGroups( edge, NewEdge, GetMeshDS());
9305       }
9306     }
9307     SMDS_FaceIteratorPtr aFaceItr = meshDS->facesIterator();
9308     while(aFaceItr->more())
9309     {
9310       const SMDS_MeshFace* face = aFaceItr->next();
9311       if(!face || face->IsQuadratic() ) continue;
9312
9313       int id = face->GetID();
9314       int nbNodes = face->NbNodes();
9315       vector<const SMDS_MeshNode *> nodes ( face->begin_nodes(), face->end_nodes());
9316
9317       meshDS->RemoveFreeElement(face, smDS, /*fromGroups=*/false);
9318
9319       SMDS_MeshFace * NewFace = 0;
9320       switch(nbNodes)
9321       {
9322       case 3:
9323         NewFace = aHelper.AddFace(nodes[0], nodes[1], nodes[2], id, theForce3d);
9324         break;
9325       case 4:
9326         NewFace = aHelper.AddFace(nodes[0], nodes[1], nodes[2], nodes[3], id, theForce3d);
9327         break;
9328       default:
9329         NewFace = aHelper.AddPolygonalFace(nodes, id, theForce3d);
9330       }
9331       ReplaceElemInGroups( face, NewFace, GetMeshDS());
9332     }
9333     vector<int> nbNodeInFaces;
9334     SMDS_VolumeIteratorPtr aVolumeItr = meshDS->volumesIterator();
9335     while(aVolumeItr->more())
9336     {
9337       const SMDS_MeshVolume* volume = aVolumeItr->next();
9338       if(!volume || volume->IsQuadratic() ) continue;
9339
9340       int id = volume->GetID();
9341       int nbNodes = volume->NbNodes();
9342       vector<const SMDS_MeshNode *> nodes (volume->begin_nodes(), volume->end_nodes());
9343       if ( volume->GetEntityType() == SMDSEntity_Polyhedra )
9344         nbNodeInFaces = static_cast<const SMDS_VtkVolume* >(volume)->GetQuantities();
9345
9346       meshDS->RemoveFreeElement(volume, smDS, /*fromGroups=*/false);
9347
9348       SMDS_MeshVolume * NewVolume = 0;
9349       switch(nbNodes)
9350       {
9351       case 4:
9352         NewVolume = aHelper.AddVolume(nodes[0], nodes[1], nodes[2],
9353                                       nodes[3], id, theForce3d );
9354         break;
9355       case 5:
9356         NewVolume = aHelper.AddVolume(nodes[0], nodes[1], nodes[2],
9357                                       nodes[3], nodes[4], id, theForce3d);
9358         break;
9359       case 6:
9360         NewVolume = aHelper.AddVolume(nodes[0], nodes[1], nodes[2],
9361                                       nodes[3], nodes[4], nodes[5], id, theForce3d);
9362         break;
9363       case 8:
9364         NewVolume = aHelper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3],
9365                                       nodes[4], nodes[5], nodes[6], nodes[7], id, theForce3d);
9366         break;
9367       default:
9368         NewVolume = aHelper.AddPolyhedralVolume(nodes, nbNodeInFaces, id, theForce3d);
9369       }
9370       ReplaceElemInGroups(volume, NewVolume, meshDS);
9371     }
9372   }
9373
9374   if ( !theForce3d  && !getenv("NO_FixQuadraticElements"))
9375   { // setenv NO_FixQuadraticElements to know if FixQuadraticElements() is guilty of bad conversion
9376     aHelper.SetSubShape(0); // apply FixQuadraticElements() to the whole mesh
9377     aHelper.FixQuadraticElements();
9378   }
9379   if (!GetMeshDS()->isCompacted())
9380     GetMeshDS()->compactMesh();
9381 }
9382
9383 //=======================================================================
9384 /*!
9385  * \brief Convert quadratic elements to linear ones and remove quadratic nodes
9386  * \retval int - nb of checked elements
9387  */
9388 //=======================================================================
9389
9390 int SMESH_MeshEditor::removeQuadElem(SMESHDS_SubMesh *    theSm,
9391                                      SMDS_ElemIteratorPtr theItr,
9392                                      const int            theShapeID)
9393 {
9394   int nbElem = 0;
9395   SMESHDS_Mesh* meshDS = GetMeshDS();
9396   const bool notFromGroups = false;
9397
9398   while( theItr->more() )
9399   {
9400     const SMDS_MeshElement* elem = theItr->next();
9401     nbElem++;
9402     if( elem && elem->IsQuadratic())
9403     {
9404       int id = elem->GetID();
9405       int nbNodes = elem->NbNodes();
9406       vector<const SMDS_MeshNode *> nodes, mediumNodes;
9407       nodes.reserve( nbNodes );
9408       mediumNodes.reserve( nbNodes );
9409
9410       for(int i = 0; i < nbNodes; i++)
9411       {
9412         const SMDS_MeshNode* n = elem->GetNode(i);
9413
9414         if( elem->IsMediumNode( n ) )
9415           mediumNodes.push_back( n );
9416         else
9417           nodes.push_back( n );
9418       }
9419       if( nodes.empty() ) continue;
9420       SMDSAbs_ElementType aType = elem->GetType();
9421
9422       //remove old quadratic element
9423       meshDS->RemoveFreeElement( elem, theSm, notFromGroups );
9424
9425       SMDS_MeshElement * NewElem = AddElement( nodes, aType, false, id );
9426       ReplaceElemInGroups(elem, NewElem, meshDS);
9427       if( theSm && NewElem )
9428         theSm->AddElement( NewElem );
9429
9430       // remove medium nodes
9431       vector<const SMDS_MeshNode*>::iterator nIt = mediumNodes.begin();
9432       for ( ; nIt != mediumNodes.end(); ++nIt ) {
9433         const SMDS_MeshNode* n = *nIt;
9434         if ( n->NbInverseElements() == 0 ) {
9435           if ( n->getshapeId() != theShapeID )
9436             meshDS->RemoveFreeNode( n, meshDS->MeshElements
9437                                     ( n->getshapeId() ));
9438           else
9439             meshDS->RemoveFreeNode( n, theSm );
9440         }
9441       }
9442     }
9443   }
9444   return nbElem;
9445 }
9446
9447 //=======================================================================
9448 //function : ConvertFromQuadratic
9449 //purpose  :
9450 //=======================================================================
9451 bool  SMESH_MeshEditor::ConvertFromQuadratic()
9452 {
9453   int nbCheckedElems = 0;
9454   if ( myMesh->HasShapeToMesh() )
9455   {
9456     if ( SMESH_subMesh *aSubMesh = myMesh->GetSubMeshContaining(myMesh->GetShapeToMesh()))
9457     {
9458       SMESH_subMeshIteratorPtr smIt = aSubMesh->getDependsOnIterator(true,false);
9459       while ( smIt->more() ) {
9460         SMESH_subMesh* sm = smIt->next();
9461         if ( SMESHDS_SubMesh *smDS = sm->GetSubMeshDS() )
9462           nbCheckedElems += removeQuadElem( smDS, smDS->GetElements(), sm->GetId() );
9463       }
9464     }
9465   }
9466
9467   int totalNbElems =
9468     GetMeshDS()->NbEdges() + GetMeshDS()->NbFaces() + GetMeshDS()->NbVolumes();
9469   if ( nbCheckedElems < totalNbElems ) // not all elements are in submeshes
9470   {
9471     SMESHDS_SubMesh *aSM = 0;
9472     removeQuadElem( aSM, GetMeshDS()->elementsIterator(), 0 );
9473   }
9474
9475   return true;
9476 }
9477
9478 //=======================================================================
9479 //function : SewSideElements
9480 //purpose  :
9481 //=======================================================================
9482
9483 SMESH_MeshEditor::Sew_Error
9484 SMESH_MeshEditor::SewSideElements (TIDSortedElemSet&    theSide1,
9485                                    TIDSortedElemSet&    theSide2,
9486                                    const SMDS_MeshNode* theFirstNode1,
9487                                    const SMDS_MeshNode* theFirstNode2,
9488                                    const SMDS_MeshNode* theSecondNode1,
9489                                    const SMDS_MeshNode* theSecondNode2)
9490 {
9491   myLastCreatedElems.Clear();
9492   myLastCreatedNodes.Clear();
9493
9494   MESSAGE ("::::SewSideElements()");
9495   if ( theSide1.size() != theSide2.size() )
9496     return SEW_DIFF_NB_OF_ELEMENTS;
9497
9498   Sew_Error aResult = SEW_OK;
9499   // Algo:
9500   // 1. Build set of faces representing each side
9501   // 2. Find which nodes of the side 1 to merge with ones on the side 2
9502   // 3. Replace nodes in elements of the side 1 and remove replaced nodes
9503
9504   // =======================================================================
9505   // 1. Build set of faces representing each side:
9506   // =======================================================================
9507   // a. build set of nodes belonging to faces
9508   // b. complete set of faces: find missing faces whose nodes are in set of nodes
9509   // c. create temporary faces representing side of volumes if correspondent
9510   //    face does not exist
9511
9512   SMESHDS_Mesh* aMesh = GetMeshDS();
9513   // TODO algoritm not OK with vtkUnstructuredGrid: 2 meshes can't share nodes
9514   //SMDS_Mesh aTmpFacesMesh; // try to use the same mesh
9515   set<const SMDS_MeshElement*> faceSet1, faceSet2;
9516   set<const SMDS_MeshElement*> volSet1,  volSet2;
9517   set<const SMDS_MeshNode*>    nodeSet1, nodeSet2;
9518   set<const SMDS_MeshElement*> * faceSetPtr[] = { &faceSet1, &faceSet2 };
9519   set<const SMDS_MeshElement*>  * volSetPtr[] = { &volSet1,  &volSet2  };
9520   set<const SMDS_MeshNode*>    * nodeSetPtr[] = { &nodeSet1, &nodeSet2 };
9521   TIDSortedElemSet * elemSetPtr[] = { &theSide1, &theSide2 };
9522   int iSide, iFace, iNode;
9523
9524   list<const SMDS_MeshElement* > tempFaceList;
9525   for ( iSide = 0; iSide < 2; iSide++ ) {
9526     set<const SMDS_MeshNode*>    * nodeSet = nodeSetPtr[ iSide ];
9527     TIDSortedElemSet * elemSet = elemSetPtr[ iSide ];
9528     set<const SMDS_MeshElement*> * faceSet = faceSetPtr[ iSide ];
9529     set<const SMDS_MeshElement*> * volSet  = volSetPtr [ iSide ];
9530     set<const SMDS_MeshElement*>::iterator vIt;
9531     TIDSortedElemSet::iterator eIt;
9532     set<const SMDS_MeshNode*>::iterator    nIt;
9533
9534     // check that given nodes belong to given elements
9535     const SMDS_MeshNode* n1 = ( iSide == 0 ) ? theFirstNode1 : theFirstNode2;
9536     const SMDS_MeshNode* n2 = ( iSide == 0 ) ? theSecondNode1 : theSecondNode2;
9537     int firstIndex = -1, secondIndex = -1;
9538     for (eIt = elemSet->begin(); eIt != elemSet->end(); eIt++ ) {
9539       const SMDS_MeshElement* elem = *eIt;
9540       if ( firstIndex  < 0 ) firstIndex  = elem->GetNodeIndex( n1 );
9541       if ( secondIndex < 0 ) secondIndex = elem->GetNodeIndex( n2 );
9542       if ( firstIndex > -1 && secondIndex > -1 ) break;
9543     }
9544     if ( firstIndex < 0 || secondIndex < 0 ) {
9545       // we can simply return until temporary faces created
9546       return (iSide == 0 ) ? SEW_BAD_SIDE1_NODES : SEW_BAD_SIDE2_NODES;
9547     }
9548
9549     // -----------------------------------------------------------
9550     // 1a. Collect nodes of existing faces
9551     //     and build set of face nodes in order to detect missing
9552     //     faces corresponding to sides of volumes
9553     // -----------------------------------------------------------
9554
9555     set< set <const SMDS_MeshNode*> > setOfFaceNodeSet;
9556
9557     // loop on the given element of a side
9558     for (eIt = elemSet->begin(); eIt != elemSet->end(); eIt++ ) {
9559       //const SMDS_MeshElement* elem = *eIt;
9560       const SMDS_MeshElement* elem = *eIt;
9561       if ( elem->GetType() == SMDSAbs_Face ) {
9562         faceSet->insert( elem );
9563         set <const SMDS_MeshNode*> faceNodeSet;
9564         SMDS_ElemIteratorPtr nodeIt = elem->nodesIterator();
9565         while ( nodeIt->more() ) {
9566           const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
9567           nodeSet->insert( n );
9568           faceNodeSet.insert( n );
9569         }
9570         setOfFaceNodeSet.insert( faceNodeSet );
9571       }
9572       else if ( elem->GetType() == SMDSAbs_Volume )
9573         volSet->insert( elem );
9574     }
9575     // ------------------------------------------------------------------------------
9576     // 1b. Complete set of faces: find missing faces whose nodes are in set of nodes
9577     // ------------------------------------------------------------------------------
9578
9579     for ( nIt = nodeSet->begin(); nIt != nodeSet->end(); nIt++ ) { // loop on nodes of iSide
9580       SMDS_ElemIteratorPtr fIt = (*nIt)->GetInverseElementIterator(SMDSAbs_Face);
9581       while ( fIt->more() ) { // loop on faces sharing a node
9582         const SMDS_MeshElement* f = fIt->next();
9583         if ( faceSet->find( f ) == faceSet->end() ) {
9584           // check if all nodes are in nodeSet and
9585           // complete setOfFaceNodeSet if they are
9586           set <const SMDS_MeshNode*> faceNodeSet;
9587           SMDS_ElemIteratorPtr nodeIt = f->nodesIterator();
9588           bool allInSet = true;
9589           while ( nodeIt->more() && allInSet ) { // loop on nodes of a face
9590             const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
9591             if ( nodeSet->find( n ) == nodeSet->end() )
9592               allInSet = false;
9593             else
9594               faceNodeSet.insert( n );
9595           }
9596           if ( allInSet ) {
9597             faceSet->insert( f );
9598             setOfFaceNodeSet.insert( faceNodeSet );
9599           }
9600         }
9601       }
9602     }
9603
9604     // -------------------------------------------------------------------------
9605     // 1c. Create temporary faces representing sides of volumes if correspondent
9606     //     face does not exist
9607     // -------------------------------------------------------------------------
9608
9609     if ( !volSet->empty() ) {
9610       //int nodeSetSize = nodeSet->size();
9611
9612       // loop on given volumes
9613       for ( vIt = volSet->begin(); vIt != volSet->end(); vIt++ ) {
9614         SMDS_VolumeTool vol (*vIt);
9615         // loop on volume faces: find free faces
9616         // --------------------------------------
9617         list<const SMDS_MeshElement* > freeFaceList;
9618         for ( iFace = 0; iFace < vol.NbFaces(); iFace++ ) {
9619           if ( !vol.IsFreeFace( iFace ))
9620             continue;
9621           // check if there is already a face with same nodes in a face set
9622           const SMDS_MeshElement* aFreeFace = 0;
9623           const SMDS_MeshNode** fNodes = vol.GetFaceNodes( iFace );
9624           int nbNodes = vol.NbFaceNodes( iFace );
9625           set <const SMDS_MeshNode*> faceNodeSet;
9626           vol.GetFaceNodes( iFace, faceNodeSet );
9627           bool isNewFace = setOfFaceNodeSet.insert( faceNodeSet ).second;
9628           if ( isNewFace ) {
9629             // no such a face is given but it still can exist, check it
9630             if ( nbNodes == 3 ) {
9631               aFreeFace = aMesh->FindFace( fNodes[0],fNodes[1],fNodes[2] );
9632             }
9633             else if ( nbNodes == 4 ) {
9634               aFreeFace = aMesh->FindFace( fNodes[0],fNodes[1],fNodes[2],fNodes[3] );
9635             }
9636             else {
9637               vector<const SMDS_MeshNode *> poly_nodes ( fNodes, & fNodes[nbNodes]);
9638               aFreeFace = aMesh->FindFace(poly_nodes);
9639             }
9640           }
9641           if ( !aFreeFace ) {
9642             // create a temporary face
9643             if ( nbNodes == 3 ) {
9644               //aFreeFace = aTmpFacesMesh.AddFace( fNodes[0],fNodes[1],fNodes[2] );
9645               aFreeFace = aMesh->AddFace( fNodes[0],fNodes[1],fNodes[2] );
9646             }
9647             else if ( nbNodes == 4 ) {
9648               //aFreeFace = aTmpFacesMesh.AddFace( fNodes[0],fNodes[1],fNodes[2],fNodes[3] );
9649               aFreeFace = aMesh->AddFace( fNodes[0],fNodes[1],fNodes[2],fNodes[3] );
9650             }
9651             else {
9652               vector<const SMDS_MeshNode *> poly_nodes ( fNodes, & fNodes[nbNodes]);
9653               //aFreeFace = aTmpFacesMesh.AddPolygonalFace(poly_nodes);
9654               aFreeFace = aMesh->AddPolygonalFace(poly_nodes);
9655             }
9656           }
9657           if ( aFreeFace ) {
9658             freeFaceList.push_back( aFreeFace );
9659             tempFaceList.push_back( aFreeFace );
9660           }
9661
9662         } // loop on faces of a volume
9663
9664         // choose one of several free faces
9665         // --------------------------------------
9666         if ( freeFaceList.size() > 1 ) {
9667           // choose a face having max nb of nodes shared by other elems of a side
9668           int maxNbNodes = -1/*, nbExcludedFaces = 0*/;
9669           list<const SMDS_MeshElement* >::iterator fIt = freeFaceList.begin();
9670           while ( fIt != freeFaceList.end() ) { // loop on free faces
9671             int nbSharedNodes = 0;
9672             SMDS_ElemIteratorPtr nodeIt = (*fIt)->nodesIterator();
9673             while ( nodeIt->more() ) { // loop on free face nodes
9674               const SMDS_MeshNode* n =
9675                 static_cast<const SMDS_MeshNode*>( nodeIt->next() );
9676               SMDS_ElemIteratorPtr invElemIt = n->GetInverseElementIterator();
9677               while ( invElemIt->more() ) {
9678                 const SMDS_MeshElement* e = invElemIt->next();
9679                 if ( faceSet->find( e ) != faceSet->end() )
9680                   nbSharedNodes++;
9681                 if ( elemSet->find( e ) != elemSet->end() )
9682                   nbSharedNodes++;
9683               }
9684             }
9685             if ( nbSharedNodes >= maxNbNodes ) {
9686               maxNbNodes = nbSharedNodes;
9687               fIt++;
9688             }
9689             else
9690               freeFaceList.erase( fIt++ ); // here fIt++ occurs before erase
9691           }
9692           if ( freeFaceList.size() > 1 )
9693           {
9694             // could not choose one face, use another way
9695             // choose a face most close to the bary center of the opposite side
9696             gp_XYZ aBC( 0., 0., 0. );
9697             set <const SMDS_MeshNode*> addedNodes;
9698             TIDSortedElemSet * elemSet2 = elemSetPtr[ 1 - iSide ];
9699             eIt = elemSet2->begin();
9700             for ( eIt = elemSet2->begin(); eIt != elemSet2->end(); eIt++ ) {
9701               SMDS_ElemIteratorPtr nodeIt = (*eIt)->nodesIterator();
9702               while ( nodeIt->more() ) { // loop on free face nodes
9703                 const SMDS_MeshNode* n =
9704                   static_cast<const SMDS_MeshNode*>( nodeIt->next() );
9705                 if ( addedNodes.insert( n ).second )
9706                   aBC += gp_XYZ( n->X(),n->Y(),n->Z() );
9707               }
9708             }
9709             aBC /= addedNodes.size();
9710             double minDist = DBL_MAX;
9711             fIt = freeFaceList.begin();
9712             while ( fIt != freeFaceList.end() ) { // loop on free faces
9713               double dist = 0;
9714               SMDS_ElemIteratorPtr nodeIt = (*fIt)->nodesIterator();
9715               while ( nodeIt->more() ) { // loop on free face nodes
9716                 const SMDS_MeshNode* n =
9717                   static_cast<const SMDS_MeshNode*>( nodeIt->next() );
9718                 gp_XYZ p( n->X(),n->Y(),n->Z() );
9719                 dist += ( aBC - p ).SquareModulus();
9720               }
9721               if ( dist < minDist ) {
9722                 minDist = dist;
9723                 freeFaceList.erase( freeFaceList.begin(), fIt++ );
9724               }
9725               else
9726                 fIt = freeFaceList.erase( fIt++ );
9727             }
9728           }
9729         } // choose one of several free faces of a volume
9730
9731         if ( freeFaceList.size() == 1 ) {
9732           const SMDS_MeshElement* aFreeFace = freeFaceList.front();
9733           faceSet->insert( aFreeFace );
9734           // complete a node set with nodes of a found free face
9735           //           for ( iNode = 0; iNode < ; iNode++ )
9736           //             nodeSet->insert( fNodes[ iNode ] );
9737         }
9738
9739       } // loop on volumes of a side
9740
9741       //       // complete a set of faces if new nodes in a nodeSet appeared
9742       //       // ----------------------------------------------------------
9743       //       if ( nodeSetSize != nodeSet->size() ) {
9744       //         for ( ; nIt != nodeSet->end(); nIt++ ) { // loop on nodes of iSide
9745       //           SMDS_ElemIteratorPtr fIt = (*nIt)->GetInverseElementIterator(SMDSAbs_Face);
9746       //           while ( fIt->more() ) { // loop on faces sharing a node
9747       //             const SMDS_MeshElement* f = fIt->next();
9748       //             if ( faceSet->find( f ) == faceSet->end() ) {
9749       //               // check if all nodes are in nodeSet and
9750       //               // complete setOfFaceNodeSet if they are
9751       //               set <const SMDS_MeshNode*> faceNodeSet;
9752       //               SMDS_ElemIteratorPtr nodeIt = f->nodesIterator();
9753       //               bool allInSet = true;
9754       //               while ( nodeIt->more() && allInSet ) { // loop on nodes of a face
9755       //                 const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
9756       //                 if ( nodeSet->find( n ) == nodeSet->end() )
9757       //                   allInSet = false;
9758       //                 else
9759       //                   faceNodeSet.insert( n );
9760       //               }
9761       //               if ( allInSet ) {
9762       //                 faceSet->insert( f );
9763       //                 setOfFaceNodeSet.insert( faceNodeSet );
9764       //               }
9765       //             }
9766       //           }
9767       //         }
9768       //       }
9769     } // Create temporary faces, if there are volumes given
9770   } // loop on sides
9771
9772   if ( faceSet1.size() != faceSet2.size() ) {
9773     // delete temporary faces: they are in reverseElements of actual nodes
9774 //    SMDS_FaceIteratorPtr tmpFaceIt = aTmpFacesMesh.facesIterator();
9775 //    while ( tmpFaceIt->more() )
9776 //      aTmpFacesMesh.RemoveElement( tmpFaceIt->next() );
9777 //    list<const SMDS_MeshElement* >::iterator tmpFaceIt = tempFaceList.begin();
9778 //    for (; tmpFaceIt !=tempFaceList.end(); ++tmpFaceIt)
9779 //      aMesh->RemoveElement(*tmpFaceIt);
9780     MESSAGE("Diff nb of faces");
9781     return SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
9782   }
9783
9784   // ============================================================
9785   // 2. Find nodes to merge:
9786   //              bind a node to remove to a node to put instead
9787   // ============================================================
9788
9789   TNodeNodeMap nReplaceMap; // bind a node to remove to a node to put instead
9790   if ( theFirstNode1 != theFirstNode2 )
9791     nReplaceMap.insert( TNodeNodeMap::value_type( theFirstNode1, theFirstNode2 ));
9792   if ( theSecondNode1 != theSecondNode2 )
9793     nReplaceMap.insert( TNodeNodeMap::value_type( theSecondNode1, theSecondNode2 ));
9794
9795   LinkID_Gen aLinkID_Gen( GetMeshDS() );
9796   set< long > linkIdSet; // links to process
9797   linkIdSet.insert( aLinkID_Gen.GetLinkID( theFirstNode1, theSecondNode1 ));
9798
9799   typedef pair< const SMDS_MeshNode*, const SMDS_MeshNode* > NLink;
9800   list< NLink > linkList[2];
9801   linkList[0].push_back( NLink( theFirstNode1, theSecondNode1 ));
9802   linkList[1].push_back( NLink( theFirstNode2, theSecondNode2 ));
9803   // loop on links in linkList; find faces by links and append links
9804   // of the found faces to linkList
9805   list< NLink >::iterator linkIt[] = { linkList[0].begin(), linkList[1].begin() } ;
9806   for ( ; linkIt[0] != linkList[0].end(); linkIt[0]++, linkIt[1]++ ) {
9807     NLink link[] = { *linkIt[0], *linkIt[1] };
9808     long linkID = aLinkID_Gen.GetLinkID( link[0].first, link[0].second );
9809     if ( linkIdSet.find( linkID ) == linkIdSet.end() )
9810       continue;
9811
9812     // by links, find faces in the face sets,
9813     // and find indices of link nodes in the found faces;
9814     // in a face set, there is only one or no face sharing a link
9815     // ---------------------------------------------------------------
9816
9817     const SMDS_MeshElement* face[] = { 0, 0 };
9818     //const SMDS_MeshNode* faceNodes[ 2 ][ 5 ];
9819     vector<const SMDS_MeshNode*> fnodes1(9);
9820     vector<const SMDS_MeshNode*> fnodes2(9);
9821     //const SMDS_MeshNode* notLinkNodes[ 2 ][ 2 ] = {{ 0, 0 },{ 0, 0 }} ;
9822     vector<const SMDS_MeshNode*> notLinkNodes1(6);
9823     vector<const SMDS_MeshNode*> notLinkNodes2(6);
9824     int iLinkNode[2][2];
9825     for ( iSide = 0; iSide < 2; iSide++ ) { // loop on 2 sides
9826       const SMDS_MeshNode* n1 = link[iSide].first;
9827       const SMDS_MeshNode* n2 = link[iSide].second;
9828       set<const SMDS_MeshElement*> * faceSet = faceSetPtr[ iSide ];
9829       set< const SMDS_MeshElement* > fMap;
9830       for ( int i = 0; i < 2; i++ ) { // loop on 2 nodes of a link
9831         const SMDS_MeshNode* n = i ? n1 : n2; // a node of a link
9832         SMDS_ElemIteratorPtr fIt = n->GetInverseElementIterator(SMDSAbs_Face);
9833         while ( fIt->more() ) { // loop on faces sharing a node
9834           const SMDS_MeshElement* f = fIt->next();
9835           if (faceSet->find( f ) != faceSet->end() && // f is in face set
9836               ! fMap.insert( f ).second ) // f encounters twice
9837           {
9838             if ( face[ iSide ] ) {
9839               MESSAGE( "2 faces per link " );
9840               aResult = iSide ? SEW_BAD_SIDE2_NODES : SEW_BAD_SIDE1_NODES;
9841               break;
9842             }
9843             face[ iSide ] = f;
9844             faceSet->erase( f );
9845             // get face nodes and find ones of a link
9846             iNode = 0;
9847             int nbl = -1;
9848             if(f->IsPoly()) {
9849               if(iSide==0) {
9850                 fnodes1.resize(f->NbNodes()+1);
9851                 notLinkNodes1.resize(f->NbNodes()-2);
9852               }
9853               else {
9854                 fnodes2.resize(f->NbNodes()+1);
9855                 notLinkNodes2.resize(f->NbNodes()-2);
9856               }
9857             }
9858             if(!f->IsQuadratic()) {
9859               SMDS_ElemIteratorPtr nIt = f->nodesIterator();
9860               while ( nIt->more() ) {
9861                 const SMDS_MeshNode* n =
9862                   static_cast<const SMDS_MeshNode*>( nIt->next() );
9863                 if ( n == n1 ) {
9864                   iLinkNode[ iSide ][ 0 ] = iNode;
9865                 }
9866                 else if ( n == n2 ) {
9867                   iLinkNode[ iSide ][ 1 ] = iNode;
9868                 }
9869                 //else if ( notLinkNodes[ iSide ][ 0 ] )
9870                 //  notLinkNodes[ iSide ][ 1 ] = n;
9871                 //else
9872                 //  notLinkNodes[ iSide ][ 0 ] = n;
9873                 else {
9874                   nbl++;
9875                   if(iSide==0)
9876                     notLinkNodes1[nbl] = n;
9877                   //notLinkNodes1.push_back(n);
9878                   else
9879                     notLinkNodes2[nbl] = n;
9880                   //notLinkNodes2.push_back(n);
9881                 }
9882                 //faceNodes[ iSide ][ iNode++ ] = n;
9883                 if(iSide==0) {
9884                   fnodes1[iNode++] = n;
9885                 }
9886                 else {
9887                   fnodes2[iNode++] = n;
9888                 }
9889               }
9890             }
9891             else { // f->IsQuadratic()
9892               const SMDS_VtkFace* F =
9893                 dynamic_cast<const SMDS_VtkFace*>(f);
9894               if (!F) throw SALOME_Exception(LOCALIZED("not an SMDS_VtkFace"));
9895               // use special nodes iterator
9896               SMDS_ElemIteratorPtr anIter = F->interlacedNodesElemIterator();
9897               while ( anIter->more() ) {
9898                 const SMDS_MeshNode* n =
9899                   static_cast<const SMDS_MeshNode*>( anIter->next() );
9900                 if ( n == n1 ) {
9901                   iLinkNode[ iSide ][ 0 ] = iNode;
9902                 }
9903                 else if ( n == n2 ) {
9904                   iLinkNode[ iSide ][ 1 ] = iNode;
9905                 }
9906                 else {
9907                   nbl++;
9908                   if(iSide==0) {
9909                     notLinkNodes1[nbl] = n;
9910                   }
9911                   else {
9912                     notLinkNodes2[nbl] = n;
9913                   }
9914                 }
9915                 if(iSide==0) {
9916                   fnodes1[iNode++] = n;
9917                 }
9918                 else {
9919                   fnodes2[iNode++] = n;
9920                 }
9921               }
9922             }
9923             //faceNodes[ iSide ][ iNode ] = faceNodes[ iSide ][ 0 ];
9924             if(iSide==0) {
9925               fnodes1[iNode] = fnodes1[0];
9926             }
9927             else {
9928               fnodes2[iNode] = fnodes1[0];
9929             }
9930           }
9931         }
9932       }
9933     }
9934
9935     // check similarity of elements of the sides
9936     if (aResult == SEW_OK && ( face[0] && !face[1] ) || ( !face[0] && face[1] )) {
9937       MESSAGE("Correspondent face not found on side " << ( face[0] ? 1 : 0 ));
9938       if ( nReplaceMap.size() == 2 ) { // faces on input nodes not found
9939         aResult = ( face[0] ? SEW_BAD_SIDE2_NODES : SEW_BAD_SIDE1_NODES );
9940       }
9941       else {
9942         aResult = SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
9943       }
9944       break; // do not return because it s necessary to remove tmp faces
9945     }
9946
9947     // set nodes to merge
9948     // -------------------
9949
9950     if ( face[0] && face[1] )  {
9951       int nbNodes = face[0]->NbNodes();
9952       if ( nbNodes != face[1]->NbNodes() ) {
9953         MESSAGE("Diff nb of face nodes");
9954         aResult = SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
9955         break; // do not return because it s necessary to remove tmp faces
9956       }
9957       bool reverse[] = { false, false }; // order of notLinkNodes of quadrangle
9958       if ( nbNodes == 3 ) {
9959         //nReplaceMap.insert( TNodeNodeMap::value_type
9960         //                   ( notLinkNodes[0][0], notLinkNodes[1][0] ));
9961         nReplaceMap.insert( TNodeNodeMap::value_type
9962                             ( notLinkNodes1[0], notLinkNodes2[0] ));
9963       }
9964       else {
9965         for ( iSide = 0; iSide < 2; iSide++ ) { // loop on 2 sides
9966           // analyse link orientation in faces
9967           int i1 = iLinkNode[ iSide ][ 0 ];
9968           int i2 = iLinkNode[ iSide ][ 1 ];
9969           reverse[ iSide ] = Abs( i1 - i2 ) == 1 ? i1 > i2 : i2 > i1;
9970           // if notLinkNodes are the first and the last ones, then
9971           // their order does not correspond to the link orientation
9972           if (( i1 == 1 && i2 == 2 ) ||
9973               ( i1 == 2 && i2 == 1 ))
9974             reverse[ iSide ] = !reverse[ iSide ];
9975         }
9976         if ( reverse[0] == reverse[1] ) {
9977           //nReplaceMap.insert( TNodeNodeMap::value_type
9978           //                   ( notLinkNodes[0][0], notLinkNodes[1][0] ));
9979           //nReplaceMap.insert( TNodeNodeMap::value_type
9980           //                   ( notLinkNodes[0][1], notLinkNodes[1][1] ));
9981           for(int nn=0; nn<nbNodes-2; nn++) {
9982             nReplaceMap.insert( TNodeNodeMap::value_type
9983                                 ( notLinkNodes1[nn], notLinkNodes2[nn] ));
9984           }
9985         }
9986         else {
9987           //nReplaceMap.insert( TNodeNodeMap::value_type
9988           //                   ( notLinkNodes[0][0], notLinkNodes[1][1] ));
9989           //nReplaceMap.insert( TNodeNodeMap::value_type
9990           //                   ( notLinkNodes[0][1], notLinkNodes[1][0] ));
9991           for(int nn=0; nn<nbNodes-2; nn++) {
9992             nReplaceMap.insert( TNodeNodeMap::value_type
9993                                 ( notLinkNodes1[nn], notLinkNodes2[nbNodes-3-nn] ));
9994           }
9995         }
9996       }
9997
9998       // add other links of the faces to linkList
9999       // -----------------------------------------
10000
10001       //const SMDS_MeshNode** nodes = faceNodes[ 0 ];
10002       for ( iNode = 0; iNode < nbNodes; iNode++ )  {
10003         //linkID = aLinkID_Gen.GetLinkID( nodes[iNode], nodes[iNode+1] );
10004         linkID = aLinkID_Gen.GetLinkID( fnodes1[iNode], fnodes1[iNode+1] );
10005         pair< set<long>::iterator, bool > iter_isnew = linkIdSet.insert( linkID );
10006         if ( !iter_isnew.second ) { // already in a set: no need to process
10007           linkIdSet.erase( iter_isnew.first );
10008         }
10009         else // new in set == encountered for the first time: add
10010         {
10011           //const SMDS_MeshNode* n1 = nodes[ iNode ];
10012           //const SMDS_MeshNode* n2 = nodes[ iNode + 1];
10013           const SMDS_MeshNode* n1 = fnodes1[ iNode ];
10014           const SMDS_MeshNode* n2 = fnodes1[ iNode + 1];
10015           linkList[0].push_back ( NLink( n1, n2 ));
10016           linkList[1].push_back ( NLink( nReplaceMap[n1], nReplaceMap[n2] ));
10017         }
10018       }
10019     } // 2 faces found
10020   } // loop on link lists
10021
10022   if ( aResult == SEW_OK &&
10023        ( linkIt[0] != linkList[0].end() ||
10024          !faceSetPtr[0]->empty() || !faceSetPtr[1]->empty() )) {
10025     MESSAGE( (linkIt[0] != linkList[0].end()) <<" "<< (faceSetPtr[0]->empty()) <<
10026              " " << (faceSetPtr[1]->empty()));
10027     aResult = SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
10028   }
10029
10030   // ====================================================================
10031   // 3. Replace nodes in elements of the side 1 and remove replaced nodes
10032   // ====================================================================
10033
10034   // delete temporary faces: they are in reverseElements of actual nodes
10035 //  SMDS_FaceIteratorPtr tmpFaceIt = aTmpFacesMesh.facesIterator();
10036 //  while ( tmpFaceIt->more() )
10037 //    aTmpFacesMesh.RemoveElement( tmpFaceIt->next() );
10038 //  list<const SMDS_MeshElement* >::iterator tmpFaceIt = tempFaceList.begin();
10039 //  for (; tmpFaceIt !=tempFaceList.end(); ++tmpFaceIt)
10040 //    aMesh->RemoveElement(*tmpFaceIt);
10041
10042   if ( aResult != SEW_OK)
10043     return aResult;
10044
10045   list< int > nodeIDsToRemove/*, elemIDsToRemove*/;
10046   // loop on nodes replacement map
10047   TNodeNodeMap::iterator nReplaceMapIt = nReplaceMap.begin(), nnIt;
10048   for ( ; nReplaceMapIt != nReplaceMap.end(); nReplaceMapIt++ )
10049     if ( (*nReplaceMapIt).first != (*nReplaceMapIt).second ) {
10050       const SMDS_MeshNode* nToRemove = (*nReplaceMapIt).first;
10051       nodeIDsToRemove.push_back( nToRemove->GetID() );
10052       // loop on elements sharing nToRemove
10053       SMDS_ElemIteratorPtr invElemIt = nToRemove->GetInverseElementIterator();
10054       while ( invElemIt->more() ) {
10055         const SMDS_MeshElement* e = invElemIt->next();
10056         // get a new suite of nodes: make replacement
10057         int nbReplaced = 0, i = 0, nbNodes = e->NbNodes();
10058         vector< const SMDS_MeshNode*> nodes( nbNodes );
10059         SMDS_ElemIteratorPtr nIt = e->nodesIterator();
10060         while ( nIt->more() ) {
10061           const SMDS_MeshNode* n =
10062             static_cast<const SMDS_MeshNode*>( nIt->next() );
10063           nnIt = nReplaceMap.find( n );
10064           if ( nnIt != nReplaceMap.end() ) {
10065             nbReplaced++;
10066             n = (*nnIt).second;
10067           }
10068           nodes[ i++ ] = n;
10069         }
10070         //       if ( nbReplaced == nbNodes && e->GetType() == SMDSAbs_Face )
10071         //         elemIDsToRemove.push_back( e->GetID() );
10072         //       else
10073         if ( nbReplaced )
10074           {
10075             SMDSAbs_ElementType etyp = e->GetType();
10076             SMDS_MeshElement* newElem = this->AddElement(nodes, etyp, false);
10077             if (newElem)
10078               {
10079                 myLastCreatedElems.Append(newElem);
10080                 AddToSameGroups(newElem, e, aMesh);
10081                 int aShapeId = e->getshapeId();
10082                 if ( aShapeId )
10083                   {
10084                     aMesh->SetMeshElementOnShape( newElem, aShapeId );
10085                   }
10086               }
10087             aMesh->RemoveElement(e);
10088           }
10089       }
10090     }
10091
10092   Remove( nodeIDsToRemove, true );
10093
10094   return aResult;
10095 }
10096
10097 //================================================================================
10098 /*!
10099  * \brief Find corresponding nodes in two sets of faces
10100  * \param theSide1 - first face set
10101  * \param theSide2 - second first face
10102  * \param theFirstNode1 - a boundary node of set 1
10103  * \param theFirstNode2 - a node of set 2 corresponding to theFirstNode1
10104  * \param theSecondNode1 - a boundary node of set 1 linked with theFirstNode1
10105  * \param theSecondNode2 - a node of set 2 corresponding to theSecondNode1
10106  * \param nReplaceMap - output map of corresponding nodes
10107  * \retval bool  - is a success or not
10108  */
10109 //================================================================================
10110
10111 #ifdef _DEBUG_
10112 //#define DEBUG_MATCHING_NODES
10113 #endif
10114
10115 SMESH_MeshEditor::Sew_Error
10116 SMESH_MeshEditor::FindMatchingNodes(set<const SMDS_MeshElement*>& theSide1,
10117                                     set<const SMDS_MeshElement*>& theSide2,
10118                                     const SMDS_MeshNode*          theFirstNode1,
10119                                     const SMDS_MeshNode*          theFirstNode2,
10120                                     const SMDS_MeshNode*          theSecondNode1,
10121                                     const SMDS_MeshNode*          theSecondNode2,
10122                                     TNodeNodeMap &                nReplaceMap)
10123 {
10124   set<const SMDS_MeshElement*> * faceSetPtr[] = { &theSide1, &theSide2 };
10125
10126   nReplaceMap.clear();
10127   if ( theFirstNode1 != theFirstNode2 )
10128     nReplaceMap.insert( make_pair( theFirstNode1, theFirstNode2 ));
10129   if ( theSecondNode1 != theSecondNode2 )
10130     nReplaceMap.insert( make_pair( theSecondNode1, theSecondNode2 ));
10131
10132   set< SMESH_TLink > linkSet; // set of nodes where order of nodes is ignored
10133   linkSet.insert( SMESH_TLink( theFirstNode1, theSecondNode1 ));
10134
10135   list< NLink > linkList[2];
10136   linkList[0].push_back( NLink( theFirstNode1, theSecondNode1 ));
10137   linkList[1].push_back( NLink( theFirstNode2, theSecondNode2 ));
10138
10139   // loop on links in linkList; find faces by links and append links
10140   // of the found faces to linkList
10141   list< NLink >::iterator linkIt[] = { linkList[0].begin(), linkList[1].begin() } ;
10142   for ( ; linkIt[0] != linkList[0].end(); linkIt[0]++, linkIt[1]++ ) {
10143     NLink link[] = { *linkIt[0], *linkIt[1] };
10144     if ( linkSet.find( link[0] ) == linkSet.end() )
10145       continue;
10146
10147     // by links, find faces in the face sets,
10148     // and find indices of link nodes in the found faces;
10149     // in a face set, there is only one or no face sharing a link
10150     // ---------------------------------------------------------------
10151
10152     const SMDS_MeshElement* face[] = { 0, 0 };
10153     list<const SMDS_MeshNode*> notLinkNodes[2];
10154     //bool reverse[] = { false, false }; // order of notLinkNodes
10155     int nbNodes[2];
10156     for ( int iSide = 0; iSide < 2; iSide++ ) // loop on 2 sides
10157     {
10158       const SMDS_MeshNode* n1 = link[iSide].first;
10159       const SMDS_MeshNode* n2 = link[iSide].second;
10160       set<const SMDS_MeshElement*> * faceSet = faceSetPtr[ iSide ];
10161       set< const SMDS_MeshElement* > facesOfNode1;
10162       for ( int iNode = 0; iNode < 2; iNode++ ) // loop on 2 nodes of a link
10163       {
10164         // during a loop of the first node, we find all faces around n1,
10165         // during a loop of the second node, we find one face sharing both n1 and n2
10166         const SMDS_MeshNode* n = iNode ? n1 : n2; // a node of a link
10167         SMDS_ElemIteratorPtr fIt = n->GetInverseElementIterator(SMDSAbs_Face);
10168         while ( fIt->more() ) { // loop on faces sharing a node
10169           const SMDS_MeshElement* f = fIt->next();
10170           if (faceSet->find( f ) != faceSet->end() && // f is in face set
10171               ! facesOfNode1.insert( f ).second ) // f encounters twice
10172           {
10173             if ( face[ iSide ] ) {
10174               MESSAGE( "2 faces per link " );
10175               return ( iSide ? SEW_BAD_SIDE2_NODES : SEW_BAD_SIDE1_NODES );
10176             }
10177             face[ iSide ] = f;
10178             faceSet->erase( f );
10179
10180             // get not link nodes
10181             int nbN = f->NbNodes();
10182             if ( f->IsQuadratic() )
10183               nbN /= 2;
10184             nbNodes[ iSide ] = nbN;
10185             list< const SMDS_MeshNode* > & nodes = notLinkNodes[ iSide ];
10186             int i1 = f->GetNodeIndex( n1 );
10187             int i2 = f->GetNodeIndex( n2 );
10188             int iEnd = nbN, iBeg = -1, iDelta = 1;
10189             bool reverse = ( Abs( i1 - i2 ) == 1 ? i1 > i2 : i2 > i1 );
10190             if ( reverse ) {
10191               std::swap( iEnd, iBeg ); iDelta = -1;
10192             }
10193             int i = i2;
10194             while ( true ) {
10195               i += iDelta;
10196               if ( i == iEnd ) i = iBeg + iDelta;
10197               if ( i == i1 ) break;
10198               nodes.push_back ( f->GetNode( i ) );
10199             }
10200           }
10201         }
10202       }
10203     }
10204     // check similarity of elements of the sides
10205     if (( face[0] && !face[1] ) || ( !face[0] && face[1] )) {
10206       MESSAGE("Correspondent face not found on side " << ( face[0] ? 1 : 0 ));
10207       if ( nReplaceMap.size() == 2 ) { // faces on input nodes not found
10208         return ( face[0] ? SEW_BAD_SIDE2_NODES : SEW_BAD_SIDE1_NODES );
10209       }
10210       else {
10211         return SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
10212       }
10213     }
10214
10215     // set nodes to merge
10216     // -------------------
10217
10218     if ( face[0] && face[1] )  {
10219       if ( nbNodes[0] != nbNodes[1] ) {
10220         MESSAGE("Diff nb of face nodes");
10221         return SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
10222       }
10223 #ifdef DEBUG_MATCHING_NODES
10224       MESSAGE ( " Link 1: " << link[0].first->GetID() <<" "<< link[0].second->GetID()
10225                 << " F 1: " << face[0] << "| Link 2: " << link[1].first->GetID() <<" "
10226                 << link[1].second->GetID() << " F 2: " << face[1] << " | Bind: " ) ;
10227 #endif
10228       int nbN = nbNodes[0];
10229       {
10230         list<const SMDS_MeshNode*>::iterator n1 = notLinkNodes[0].begin();
10231         list<const SMDS_MeshNode*>::iterator n2 = notLinkNodes[1].begin();
10232         for ( int i = 0 ; i < nbN - 2; ++i ) {
10233 #ifdef DEBUG_MATCHING_NODES
10234           MESSAGE ( (*n1)->GetID() << " to " << (*n2)->GetID() );
10235 #endif
10236           nReplaceMap.insert( make_pair( *(n1++), *(n2++) ));
10237         }
10238       }
10239
10240       // add other links of the face 1 to linkList
10241       // -----------------------------------------
10242
10243       const SMDS_MeshElement* f0 = face[0];
10244       const SMDS_MeshNode* n1 = f0->GetNode( nbN - 1 );
10245       for ( int i = 0; i < nbN; i++ )
10246       {
10247         const SMDS_MeshNode* n2 = f0->GetNode( i );
10248         pair< set< SMESH_TLink >::iterator, bool > iter_isnew =
10249           linkSet.insert( SMESH_TLink( n1, n2 ));
10250         if ( !iter_isnew.second ) { // already in a set: no need to process
10251           linkSet.erase( iter_isnew.first );
10252         }
10253         else // new in set == encountered for the first time: add
10254         {
10255 #ifdef DEBUG_MATCHING_NODES
10256           MESSAGE ( "Add link 1: " << n1->GetID() << " " << n2->GetID() << " "
10257                     << " | link 2: " << nReplaceMap[n1]->GetID() << " " << nReplaceMap[n2]->GetID() << " " );
10258 #endif
10259           linkList[0].push_back ( NLink( n1, n2 ));
10260           linkList[1].push_back ( NLink( nReplaceMap[n1], nReplaceMap[n2] ));
10261         }
10262         n1 = n2;
10263       }
10264     } // 2 faces found
10265   } // loop on link lists
10266
10267   return SEW_OK;
10268 }
10269
10270 //================================================================================
10271 /*!
10272   \brief Creates a hole in a mesh by doubling the nodes of some particular elements
10273   \param theElems - the list of elements (edges or faces) to be replicated
10274   The nodes for duplication could be found from these elements
10275   \param theNodesNot - list of nodes to NOT replicate
10276   \param theAffectedElems - the list of elements (cells and edges) to which the 
10277   replicated nodes should be associated to.
10278   \return TRUE if operation has been completed successfully, FALSE otherwise
10279 */
10280 //================================================================================
10281
10282 bool SMESH_MeshEditor::DoubleNodes( const TIDSortedElemSet& theElems,
10283                                     const TIDSortedElemSet& theNodesNot,
10284                                     const TIDSortedElemSet& theAffectedElems )
10285 {
10286   myLastCreatedElems.Clear();
10287   myLastCreatedNodes.Clear();
10288
10289   if ( theElems.size() == 0 )
10290     return false;
10291
10292   SMESHDS_Mesh* aMeshDS = GetMeshDS();
10293   if ( !aMeshDS )
10294     return false;
10295
10296   bool res = false;
10297   std::map< const SMDS_MeshNode*, const SMDS_MeshNode* > anOldNodeToNewNode;
10298   // duplicate elements and nodes
10299   res = doubleNodes( aMeshDS, theElems, theNodesNot, anOldNodeToNewNode, true );
10300   // replce nodes by duplications
10301   res = doubleNodes( aMeshDS, theAffectedElems, theNodesNot, anOldNodeToNewNode, false );
10302   return res;
10303 }
10304
10305 //================================================================================
10306 /*!
10307   \brief Creates a hole in a mesh by doubling the nodes of some particular elements
10308   \param theMeshDS - mesh instance
10309   \param theElems - the elements replicated or modified (nodes should be changed)
10310   \param theNodesNot - nodes to NOT replicate
10311   \param theNodeNodeMap - relation of old node to new created node
10312   \param theIsDoubleElem - flag os to replicate element or modify
10313   \return TRUE if operation has been completed successfully, FALSE otherwise
10314 */
10315 //================================================================================
10316
10317 bool SMESH_MeshEditor::doubleNodes( SMESHDS_Mesh*     theMeshDS,
10318                                     const TIDSortedElemSet& theElems,
10319                                     const TIDSortedElemSet& theNodesNot,
10320                                     std::map< const SMDS_MeshNode*,
10321                                     const SMDS_MeshNode* >& theNodeNodeMap,
10322                                     const bool theIsDoubleElem )
10323 {
10324   MESSAGE("doubleNodes");
10325   // iterate on through element and duplicate them (by nodes duplication)
10326   bool res = false;
10327   TIDSortedElemSet::const_iterator elemItr = theElems.begin();
10328   for ( ;  elemItr != theElems.end(); ++elemItr )
10329   {
10330     const SMDS_MeshElement* anElem = *elemItr;
10331     if (!anElem)
10332       continue;
10333
10334     bool isDuplicate = false;
10335     // duplicate nodes to duplicate element
10336     std::vector<const SMDS_MeshNode*> newNodes( anElem->NbNodes() );
10337     SMDS_ElemIteratorPtr anIter = anElem->nodesIterator();
10338     int ind = 0;
10339     while ( anIter->more() ) 
10340     { 
10341
10342       SMDS_MeshNode* aCurrNode = (SMDS_MeshNode*)anIter->next();
10343       SMDS_MeshNode* aNewNode = aCurrNode;
10344       if ( theNodeNodeMap.find( aCurrNode ) != theNodeNodeMap.end() )
10345         aNewNode = (SMDS_MeshNode*)theNodeNodeMap[ aCurrNode ];
10346       else if ( theIsDoubleElem && theNodesNot.find( aCurrNode ) == theNodesNot.end() )
10347       {
10348         // duplicate node
10349         aNewNode = theMeshDS->AddNode( aCurrNode->X(), aCurrNode->Y(), aCurrNode->Z() );
10350         theNodeNodeMap[ aCurrNode ] = aNewNode;
10351         myLastCreatedNodes.Append( aNewNode );
10352       }
10353       isDuplicate |= (aCurrNode != aNewNode);
10354       newNodes[ ind++ ] = aNewNode;
10355     }
10356     if ( !isDuplicate )
10357       continue;
10358
10359     if ( theIsDoubleElem )
10360       AddElement(newNodes, anElem->GetType(), anElem->IsPoly());
10361     else
10362       {
10363       MESSAGE("ChangeElementNodes");
10364       theMeshDS->ChangeElementNodes( anElem, &newNodes[ 0 ], anElem->NbNodes() );
10365       }
10366     res = true;
10367   }
10368   return res;
10369 }
10370
10371 //================================================================================
10372 /*!
10373   \brief Creates a hole in a mesh by doubling the nodes of some particular elements
10374   \param theNodes - identifiers of nodes to be doubled
10375   \param theModifiedElems - identifiers of elements to be updated by the new (doubled) 
10376          nodes. If list of element identifiers is empty then nodes are doubled but 
10377          they not assigned to elements
10378   \return TRUE if operation has been completed successfully, FALSE otherwise
10379 */
10380 //================================================================================
10381
10382 bool SMESH_MeshEditor::DoubleNodes( const std::list< int >& theListOfNodes, 
10383                                     const std::list< int >& theListOfModifiedElems )
10384 {
10385   MESSAGE("DoubleNodes");
10386   myLastCreatedElems.Clear();
10387   myLastCreatedNodes.Clear();
10388
10389   if ( theListOfNodes.size() == 0 )
10390     return false;
10391
10392   SMESHDS_Mesh* aMeshDS = GetMeshDS();
10393   if ( !aMeshDS )
10394     return false;
10395
10396   // iterate through nodes and duplicate them
10397
10398   std::map< const SMDS_MeshNode*, const SMDS_MeshNode* > anOldNodeToNewNode;
10399
10400   std::list< int >::const_iterator aNodeIter;
10401   for ( aNodeIter = theListOfNodes.begin(); aNodeIter != theListOfNodes.end(); ++aNodeIter )
10402   {
10403     int aCurr = *aNodeIter;
10404     SMDS_MeshNode* aNode = (SMDS_MeshNode*)aMeshDS->FindNode( aCurr );
10405     if ( !aNode )
10406       continue;
10407
10408     // duplicate node
10409
10410     const SMDS_MeshNode* aNewNode = aMeshDS->AddNode( aNode->X(), aNode->Y(), aNode->Z() );
10411     if ( aNewNode )
10412     {
10413       anOldNodeToNewNode[ aNode ] = aNewNode;
10414       myLastCreatedNodes.Append( aNewNode );
10415     }
10416   }
10417
10418   // Create map of new nodes for modified elements
10419
10420   std::map< SMDS_MeshElement*, vector<const SMDS_MeshNode*> > anElemToNodes;
10421
10422   std::list< int >::const_iterator anElemIter;
10423   for ( anElemIter = theListOfModifiedElems.begin(); 
10424         anElemIter != theListOfModifiedElems.end(); ++anElemIter )
10425   {
10426     int aCurr = *anElemIter;
10427     SMDS_MeshElement* anElem = (SMDS_MeshElement*)aMeshDS->FindElement( aCurr );
10428     if ( !anElem )
10429       continue;
10430
10431     vector<const SMDS_MeshNode*> aNodeArr( anElem->NbNodes() );
10432
10433     SMDS_ElemIteratorPtr anIter = anElem->nodesIterator();
10434     int ind = 0;
10435     while ( anIter->more() ) 
10436     { 
10437       SMDS_MeshNode* aCurrNode = (SMDS_MeshNode*)anIter->next();
10438       if ( aCurr && anOldNodeToNewNode.find( aCurrNode ) != anOldNodeToNewNode.end() )
10439       {
10440         const SMDS_MeshNode* aNewNode = anOldNodeToNewNode[ aCurrNode ];
10441         aNodeArr[ ind++ ] = aNewNode;
10442       }
10443       else
10444         aNodeArr[ ind++ ] = aCurrNode;
10445     }
10446     anElemToNodes[ anElem ] = aNodeArr;
10447   }
10448
10449   // Change nodes of elements  
10450
10451   std::map< SMDS_MeshElement*, vector<const SMDS_MeshNode*> >::iterator
10452     anElemToNodesIter = anElemToNodes.begin();
10453   for ( ; anElemToNodesIter != anElemToNodes.end(); ++anElemToNodesIter )
10454   {
10455     const SMDS_MeshElement* anElem = anElemToNodesIter->first;
10456     vector<const SMDS_MeshNode*> aNodeArr = anElemToNodesIter->second;
10457     if ( anElem )
10458       {
10459       MESSAGE("ChangeElementNodes");
10460       aMeshDS->ChangeElementNodes( anElem, &aNodeArr[ 0 ], anElem->NbNodes() );
10461       }
10462   }
10463
10464   return true;
10465 }
10466
10467 namespace {
10468
10469   //================================================================================
10470   /*!
10471   \brief Check if element located inside shape
10472   \return TRUE if IN or ON shape, FALSE otherwise
10473   */
10474   //================================================================================
10475
10476   template<class Classifier>
10477   bool isInside(const SMDS_MeshElement* theElem,
10478                 Classifier&             theClassifier,
10479                 const double            theTol)
10480   {
10481     gp_XYZ centerXYZ (0, 0, 0);
10482     SMDS_ElemIteratorPtr aNodeItr = theElem->nodesIterator();
10483     while (aNodeItr->more())
10484       centerXYZ += SMESH_MeshEditor::TNodeXYZ(cast2Node( aNodeItr->next()));
10485
10486     gp_Pnt aPnt = centerXYZ / theElem->NbNodes();
10487     theClassifier.Perform(aPnt, theTol);
10488     TopAbs_State aState = theClassifier.State();
10489     return (aState == TopAbs_IN || aState == TopAbs_ON );
10490   }
10491
10492   //================================================================================
10493   /*!
10494    * \brief Classifier of the 3D point on the TopoDS_Face
10495    *        with interaface suitable for isInside()
10496    */
10497   //================================================================================
10498
10499   struct _FaceClassifier
10500   {
10501     Extrema_ExtPS       _extremum;
10502     BRepAdaptor_Surface _surface;
10503     TopAbs_State        _state;
10504
10505     _FaceClassifier(const TopoDS_Face& face):_extremum(),_surface(face),_state(TopAbs_OUT)
10506     {
10507       _extremum.Initialize( _surface,
10508                             _surface.FirstUParameter(), _surface.LastUParameter(),
10509                             _surface.FirstVParameter(), _surface.LastVParameter(),
10510                             _surface.Tolerance(), _surface.Tolerance() );
10511     }
10512     void Perform(const gp_Pnt& aPnt, double theTol)
10513     {
10514       _state = TopAbs_OUT;
10515       _extremum.Perform(aPnt);
10516       if ( _extremum.IsDone() )
10517         for ( int iSol = 1; iSol <= _extremum.NbExt() && _state == TopAbs_OUT; ++iSol)
10518           _state = ( _extremum.Value(iSol) <= theTol ? TopAbs_IN : TopAbs_OUT );
10519     }
10520     TopAbs_State State() const
10521     {
10522       return _state;
10523     }
10524   };
10525 }
10526
10527 //================================================================================
10528 /*!
10529   \brief Creates a hole in a mesh by doubling the nodes of some particular elements
10530   \param theElems - group of of elements (edges or faces) to be replicated
10531   \param theNodesNot - group of nodes not to replicate
10532   \param theShape - shape to detect affected elements (element which geometric center
10533   located on or inside shape).
10534   The replicated nodes should be associated to affected elements.
10535   \return TRUE if operation has been completed successfully, FALSE otherwise
10536 */
10537 //================================================================================
10538
10539 bool SMESH_MeshEditor::DoubleNodesInRegion( const TIDSortedElemSet& theElems,
10540                                             const TIDSortedElemSet& theNodesNot,
10541                                             const TopoDS_Shape&     theShape )
10542 {
10543   if ( theShape.IsNull() )
10544     return false;
10545
10546   const double aTol = Precision::Confusion();
10547   auto_ptr< BRepClass3d_SolidClassifier> bsc3d;
10548   auto_ptr<_FaceClassifier>              aFaceClassifier;
10549   if ( theShape.ShapeType() == TopAbs_SOLID )
10550   {
10551     bsc3d.reset( new BRepClass3d_SolidClassifier(theShape));;
10552     bsc3d->PerformInfinitePoint(aTol);
10553   }
10554   else if (theShape.ShapeType() == TopAbs_FACE )
10555   {
10556     aFaceClassifier.reset( new _FaceClassifier(TopoDS::Face(theShape)));
10557   }
10558
10559   // iterates on indicated elements and get elements by back references from their nodes
10560   TIDSortedElemSet anAffected;
10561   TIDSortedElemSet::const_iterator elemItr = theElems.begin();
10562   for ( ;  elemItr != theElems.end(); ++elemItr )
10563   {
10564     SMDS_MeshElement* anElem = (SMDS_MeshElement*)*elemItr;
10565     if (!anElem)
10566       continue;
10567
10568     SMDS_ElemIteratorPtr nodeItr = anElem->nodesIterator();
10569     while ( nodeItr->more() )
10570     {
10571       const SMDS_MeshNode* aNode = cast2Node(nodeItr->next());
10572       if ( !aNode || theNodesNot.find(aNode) != theNodesNot.end() )
10573         continue;
10574       SMDS_ElemIteratorPtr backElemItr = aNode->GetInverseElementIterator();
10575       while ( backElemItr->more() )
10576       {
10577         const SMDS_MeshElement* curElem = backElemItr->next();
10578         if ( curElem && theElems.find(curElem) == theElems.end() &&
10579              ( bsc3d.get() ?
10580                isInside( curElem, *bsc3d, aTol ) :
10581                isInside( curElem, *aFaceClassifier, aTol )))
10582           anAffected.insert( curElem );
10583       }
10584     }
10585   }
10586   return DoubleNodes( theElems, theNodesNot, anAffected );
10587 }
10588
10589 /*!
10590  * \brief Double nodes on shared faces between groups of volumes and create flat elements on demand.
10591  * The list of groups must describe a partition of the mesh volumes.
10592  * The nodes of the internal faces at the boundaries of the groups are doubled.
10593  * In option, the internal faces are replaced by flat elements.
10594  * Triangles are transformed in prisms, and quadrangles in hexahedrons.
10595  * @param theElems - list of groups of volumes, where a group of volume is a set of
10596  * SMDS_MeshElements sorted by Id.
10597  * @param createJointElems - if TRUE, create the elements
10598  * @return TRUE if operation has been completed successfully, FALSE otherwise
10599  */
10600 bool SMESH_MeshEditor::DoubleNodesOnGroupBoundaries( const std::vector<TIDSortedElemSet>& theElems,
10601                                                      bool createJointElems)
10602 {
10603   MESSAGE("------------------------------------------------------");
10604   MESSAGE("SMESH_MeshEditor::CreateJointElementsOnGroupBoundaries");
10605   MESSAGE("------------------------------------------------------");
10606
10607   SMESHDS_Mesh *meshDS = this->myMesh->GetMeshDS();
10608   meshDS->BuildDownWardConnectivity(false);
10609   CHRONO(50);
10610   SMDS_UnstructuredGrid *grid = meshDS->getGrid();
10611
10612   // --- build the list of faces shared by 2 domains (group of elements), with their domain and volume indexes
10613   //     build the list of nodes shared by 2 or more domains, with their domain indexes
10614
10615   std::map<DownIdType, std::map<int,int>, DownIdCompare> faceDomains; // 2x(id domain --> id volume)
10616   std::map<int, std::map<int,int> > nodeDomains; //oldId ->  (domainId -> newId)
10617   faceDomains.clear();
10618   nodeDomains.clear();
10619   std::map<int,int> emptyMap;
10620   emptyMap.clear();
10621
10622   for (int idom = 0; idom < theElems.size(); idom++)
10623     {
10624
10625       // --- build a map (face to duplicate --> volume to modify)
10626       //     with all the faces shared by 2 domains (group of elements)
10627       //     and corresponding volume of this domain, for each shared face.
10628       //     a volume has a face shared by 2 domains if it has a neighbor which is not in is domain.
10629
10630       const TIDSortedElemSet& domain = theElems[idom];
10631       TIDSortedElemSet::const_iterator elemItr = domain.begin();
10632       for (; elemItr != domain.end(); ++elemItr)
10633         {
10634           SMDS_MeshElement* anElem = (SMDS_MeshElement*) *elemItr;
10635           if (!anElem)
10636             continue;
10637           int vtkId = anElem->getVtkId();
10638           int neighborsVtkIds[NBMAXNEIGHBORS];
10639           int downIds[NBMAXNEIGHBORS];
10640           unsigned char downTypes[NBMAXNEIGHBORS];
10641           int nbNeighbors = grid->GetNeighbors(neighborsVtkIds, downIds, downTypes, vtkId);
10642           for (int n = 0; n < nbNeighbors; n++)
10643             {
10644               int smdsId = meshDS->fromVtkToSmds(neighborsVtkIds[n]);
10645               const SMDS_MeshElement* elem = meshDS->FindElement(smdsId);
10646               if (! domain.count(elem)) // neighbor is in another domain : face is shared
10647                 {
10648                   DownIdType face(downIds[n], downTypes[n]);
10649                   if (!faceDomains.count(face))
10650                     faceDomains[face] = emptyMap; // create an empty entry for face
10651                   if (!faceDomains[face].count(idom))
10652                     {
10653                       faceDomains[face][idom] = vtkId; // volume associated to face in this domain
10654                     }
10655                 }
10656             }
10657         }
10658     }
10659
10660   MESSAGE("Number of shared faces " << faceDomains.size());
10661
10662   // --- for each shared face, get the nodes
10663   //     for each node, for each domain of the face, create a clone of the node
10664
10665   std::map<DownIdType, std::map<int,int>, DownIdCompare>::iterator itface = faceDomains.begin();
10666   for( ; itface != faceDomains.end();++itface )
10667     {
10668       DownIdType face = itface->first;
10669       std::map<int,int> domvol = itface->second;
10670       std::set<int> oldNodes;
10671       oldNodes.clear();
10672       grid->GetNodeIds(oldNodes, face.cellId, face.cellType);
10673       std::set<int>::iterator itn = oldNodes.begin();
10674       for (;itn != oldNodes.end(); ++itn)
10675         {
10676           int oldId = *itn;
10677           if (!nodeDomains.count(oldId))
10678             nodeDomains[oldId] = emptyMap; // create an empty entry for node
10679           std::map<int,int>::iterator itdom = domvol.begin();
10680           for(; itdom != domvol.end(); ++itdom)
10681             {
10682               int idom = itdom->first;
10683               if ( nodeDomains[oldId].empty() )
10684                 nodeDomains[oldId][idom] = oldId; // keep the old node in the first domain
10685               else
10686                 {
10687                   double *coords = grid->GetPoint(oldId);
10688                   SMDS_MeshNode *newNode = meshDS->AddNode(coords[0], coords[1], coords[2]);
10689                   int newId = newNode->getVtkId();
10690                   nodeDomains[oldId][idom] = newId; // cloned node for other domains
10691                 }
10692             }
10693         }
10694     }
10695
10696   // --- iterate on shared faces (volumes to modify, face to extrude)
10697   //     get node id's of the face (id SMDS = id VTK)
10698   //     create flat element with old and new nodes if requested
10699
10700   if (createJointElems)
10701     {
10702       itface = faceDomains.begin();
10703       for( ; itface != faceDomains.end();++itface )
10704         {
10705           DownIdType face = itface->first;
10706           std::set<int> oldNodes;
10707           std::set<int>::iterator itn;
10708           oldNodes.clear();
10709           grid->GetNodeIds(oldNodes, face.cellId, face.cellType);
10710           std::map<int,int> localClonedNodeIds;
10711
10712           std::map<int,int> domvol = itface->second;
10713           std::map<int,int>::iterator itdom = domvol.begin();
10714           int dom1 = itdom->first;
10715           int vtkVolId = itdom->second;
10716           itdom++;
10717           int dom2 = itdom->first;
10718
10719           localClonedNodeIds.clear();
10720           for (itn = oldNodes.begin(); itn != oldNodes.end(); ++itn)
10721             {
10722               int oldId = *itn;
10723               int refid = oldId;
10724               if (nodeDomains[oldId].count(dom1))
10725                 refid = nodeDomains[oldId][dom1];
10726               else
10727                 MESSAGE("--- problem domain node " << dom1 << " " << oldId);
10728               int newid = oldId;
10729               if (nodeDomains[oldId].count(dom2))
10730                 newid = nodeDomains[oldId][dom2];
10731               else
10732                 MESSAGE("--- problem domain node " << dom2 << " " << oldId);
10733               localClonedNodeIds[oldId] = newid;
10734             }
10735           meshDS->extrudeVolumeFromFace(vtkVolId, localClonedNodeIds);
10736         }
10737     }
10738
10739   // --- iterate on shared faces (volumes to modify, face to extrude)
10740   //     get node id's of the face
10741   //     replace old nodes by new nodes in volumes, and update inverse connectivity
10742
10743   itface = faceDomains.begin();
10744   for( ; itface != faceDomains.end();++itface )
10745     {
10746       DownIdType face = itface->first;
10747       std::set<int> oldNodes;
10748       std::set<int>::iterator itn;
10749       oldNodes.clear();
10750       grid->GetNodeIds(oldNodes, face.cellId, face.cellType);
10751       std::map<int,int> localClonedNodeIds;
10752
10753       std::map<int,int> domvol = itface->second;
10754       std::map<int,int>::iterator itdom = domvol.begin();
10755       for(; itdom != domvol.end(); ++itdom)
10756         {
10757           int idom = itdom->first;
10758           int vtkVolId = itdom->second;
10759           localClonedNodeIds.clear();
10760           for (itn = oldNodes.begin(); itn != oldNodes.end(); ++itn)
10761             {
10762               int oldId = *itn;
10763               if (nodeDomains[oldId].count(idom))
10764                 localClonedNodeIds[oldId] = nodeDomains[oldId][idom];
10765             }
10766           meshDS->ModifyCellNodes(vtkVolId, localClonedNodeIds);
10767         }
10768     }
10769   grid->BuildLinks();
10770
10771   // TODO replace also old nodes by new nodes in faces and edges
10772   CHRONOSTOP(50);
10773   counters::stats();
10774   return true;
10775 }
10776
10777 //================================================================================
10778 /*!
10779  * \brief Generates skin mesh (containing 2D cells) from 3D mesh
10780  * The created 2D mesh elements based on nodes of free faces of boundary volumes
10781  * \return TRUE if operation has been completed successfully, FALSE otherwise
10782  */
10783 //================================================================================
10784
10785 bool SMESH_MeshEditor::Make2DMeshFrom3D()
10786 {
10787   // iterates on volume elements and detect all free faces on them
10788   SMESHDS_Mesh* aMesh = GetMeshDS();
10789   if (!aMesh)
10790     return false;
10791   //bool res = false;
10792   int nbFree = 0, nbExisted = 0, nbCreated = 0;
10793   SMDS_VolumeIteratorPtr vIt = aMesh->volumesIterator();
10794   while(vIt->more())
10795   {
10796     const SMDS_MeshVolume* volume = vIt->next();
10797     SMDS_VolumeTool vTool( volume );
10798     vTool.SetExternalNormal();
10799     const bool isPoly = volume->IsPoly();
10800     const bool isQuad = volume->IsQuadratic();
10801     for ( int iface = 0, n = vTool.NbFaces(); iface < n; iface++ )
10802     {
10803       if (!vTool.IsFreeFace(iface))
10804         continue;
10805       nbFree++;
10806       vector<const SMDS_MeshNode *> nodes;
10807       int nbFaceNodes = vTool.NbFaceNodes(iface);
10808       const SMDS_MeshNode** faceNodes = vTool.GetFaceNodes(iface);
10809       int inode = 0;
10810       for ( ; inode < nbFaceNodes; inode += isQuad ? 2 : 1)
10811         nodes.push_back(faceNodes[inode]);
10812       if (isQuad)
10813         for ( inode = 1; inode < nbFaceNodes; inode += 2)
10814           nodes.push_back(faceNodes[inode]);
10815
10816       // add new face based on volume nodes
10817       if (aMesh->FindFace( nodes ) ) {
10818         nbExisted++;
10819         continue; // face already exsist
10820       }
10821       AddElement(nodes, SMDSAbs_Face, isPoly && iface == 1);
10822       nbCreated++;
10823     }
10824   }
10825   return ( nbFree==(nbExisted+nbCreated) );
10826 }
10827
10828 namespace
10829 {
10830   inline const SMDS_MeshNode* getNodeWithSameID(SMESHDS_Mesh* mesh, const SMDS_MeshNode* node)
10831   {
10832     if ( const SMDS_MeshNode* n = mesh->FindNode( node->GetID() ))
10833       return n;
10834     return mesh->AddNodeWithID( node->X(),node->Y(),node->Z(), node->GetID() );
10835   }
10836 }
10837 //================================================================================
10838 /*!
10839  * \brief Creates missing boundary elements
10840  *  \param elements - elements whose boundary is to be checked
10841  *  \param dimension - defines type of boundary elements to create
10842  *  \param group - a group to store created boundary elements in
10843  *  \param targetMesh - a mesh to store created boundary elements in
10844  *  \param toCopyElements - if true, the checked elements will be copied into the targetMesh
10845  *  \param toCopyExistingBondary - if true, not only new but also pre-existing
10846  *                                boundary elements will be copied into the targetMesh
10847  */
10848 //================================================================================
10849
10850 void SMESH_MeshEditor::MakeBoundaryMesh(const TIDSortedElemSet& elements,
10851                                         Bnd_Dimension           dimension,
10852                                         SMESH_Group*            group/*=0*/,
10853                                         SMESH_Mesh*             targetMesh/*=0*/,
10854                                         bool                    toCopyElements/*=false*/,
10855                                         bool                    toCopyExistingBondary/*=false*/)
10856 {
10857   SMDSAbs_ElementType missType = (dimension == BND_2DFROM3D) ? SMDSAbs_Face : SMDSAbs_Edge;
10858   SMDSAbs_ElementType elemType = (dimension == BND_1DFROM2D) ? SMDSAbs_Face : SMDSAbs_Volume;
10859   // hope that all elements are of the same type, do not check them all
10860   if ( !elements.empty() && (*elements.begin())->GetType() != elemType )
10861     throw SALOME_Exception(LOCALIZED("wrong element type"));
10862
10863   if ( !targetMesh )
10864     toCopyElements = toCopyExistingBondary = false;
10865
10866   SMESH_MeshEditor tgtEditor( targetMesh ? targetMesh : myMesh );
10867   SMESHDS_Mesh* aMesh = GetMeshDS(), *tgtMeshDS = tgtEditor.GetMeshDS();
10868
10869   SMDS_VolumeTool vTool;
10870   TIDSortedElemSet emptySet, avoidSet;
10871   int inode;
10872
10873   typedef vector<const SMDS_MeshNode*> TConnectivity;
10874
10875   SMDS_ElemIteratorPtr eIt;
10876   if (elements.empty())
10877     eIt = aMesh->elementsIterator(elemType);
10878   else
10879     eIt = SMDS_ElemIteratorPtr( new TSetIterator( elements.begin(), elements.end() ));
10880
10881   while (eIt->more())
10882   {
10883     const SMDS_MeshElement* elem = eIt->next();
10884     const int iQuad = elem->IsQuadratic();
10885
10886     // 1. For an elem, get present bnd elements and connectivities of missing bnd elements
10887     vector<const SMDS_MeshElement*> presentBndElems;
10888     vector<TConnectivity>           missingBndElems;
10889     TConnectivity nodes;
10890     if ( vTool.Set(elem) ) // elem is a volume ------------------------------------------
10891     {
10892       vTool.SetExternalNormal();
10893       for ( int iface = 0, n = vTool.NbFaces(); iface < n; iface++ )
10894       {
10895         if (!vTool.IsFreeFace(iface))
10896           continue;
10897         int nbFaceNodes = vTool.NbFaceNodes(iface);
10898         const SMDS_MeshNode** nn = vTool.GetFaceNodes(iface);
10899         if ( missType == SMDSAbs_Edge ) // boundary edges
10900         {
10901           nodes.resize( 2+iQuad );
10902           for ( int i = 0; i < nbFaceNodes; i += 1+iQuad)
10903           {
10904             for ( int j = 0; j < nodes.size(); ++j )
10905               nodes[j] =nn[i+j];
10906             if ( const SMDS_MeshElement* edge =
10907                  aMesh->FindElement(nodes,SMDSAbs_Edge,/*noMedium=*/0))
10908               presentBndElems.push_back( edge );
10909             else
10910               missingBndElems.push_back( nodes );
10911           }
10912         }
10913         else // boundary face
10914         {
10915           nodes.clear();
10916           for ( inode = 0; inode < nbFaceNodes; inode += 1+iQuad)
10917             nodes.push_back( nn[inode] );
10918           if (iQuad)
10919             for ( inode = 1; inode < nbFaceNodes; inode += 2)
10920               nodes.push_back( nn[inode] );
10921
10922           if (const SMDS_MeshFace * f = aMesh->FindFace( nodes ) )
10923             presentBndElems.push_back( f );
10924           else
10925             missingBndElems.push_back( nodes );
10926         }
10927       }
10928     }
10929     else                     // elem is a face ------------------------------------------
10930     {
10931       avoidSet.clear(), avoidSet.insert( elem );
10932       int nbNodes = elem->NbCornerNodes();
10933       nodes.resize( 2 /*+ iQuad*/);
10934       for ( int i = 0; i < nbNodes; i++ )
10935       {
10936         nodes[0] = elem->GetNode(i);
10937         nodes[1] = elem->GetNode((i+1)%nbNodes);
10938         if ( FindFaceInSet( nodes[0], nodes[1], emptySet, avoidSet))
10939           continue; // not free link
10940
10941         //if ( iQuad )
10942         //nodes[2] = elem->GetNode( i + nbNodes );
10943         if ( const SMDS_MeshElement* edge =
10944              aMesh->FindElement(nodes,SMDSAbs_Edge,/*noMedium=*/true))
10945           presentBndElems.push_back( edge );
10946         else
10947           missingBndElems.push_back( nodes );
10948       }
10949     }
10950
10951     // 2. Add missing boundary elements
10952     if ( targetMesh != myMesh )
10953       // instead of making a map of nodes in this mesh and targetMesh,
10954       // we create nodes with same IDs. We can renumber them later, if needed
10955       for ( int i = 0; i < missingBndElems.size(); ++i )
10956       {
10957         TConnectivity& srcNodes = missingBndElems[i];
10958         TConnectivity  nodes( srcNodes.size() );
10959         for ( inode = 0; inode < nodes.size(); ++inode )
10960           nodes[inode] = getNodeWithSameID( tgtMeshDS, srcNodes[inode] );
10961         tgtEditor.AddElement(nodes, missType, elem->IsPoly() && nodes.size()/(iQuad+1)>4);
10962       }
10963     else
10964       for ( int i = 0; i < missingBndElems.size(); ++i )
10965       {
10966         TConnectivity&  nodes = missingBndElems[i];
10967         tgtEditor.AddElement(nodes, missType, elem->IsPoly() && nodes.size()/(iQuad+1)>4);
10968       }
10969
10970     // 3. Copy present boundary elements
10971     if ( toCopyExistingBondary )
10972       for ( int i = 0 ; i < presentBndElems.size(); ++i )
10973       {
10974         const SMDS_MeshElement* e = presentBndElems[i];
10975         TConnectivity nodes( e->NbNodes() );
10976         for ( inode = 0; inode < nodes.size(); ++inode )
10977           nodes[inode] = getNodeWithSameID( tgtMeshDS, e->GetNode(inode) );
10978         tgtEditor.AddElement(nodes, missType, e->IsPoly());
10979         // leave only missing elements in tgtEditor.myLastCreatedElems
10980         tgtEditor.myLastCreatedElems.Remove( tgtEditor.myLastCreatedElems.Size() );
10981       }
10982   } // loop on given elements
10983
10984   // 4. Fill group with missing boundary elements
10985   if ( group )
10986   {
10987     if ( SMESHDS_Group* g = dynamic_cast<SMESHDS_Group*>( group->GetGroupDS() ))
10988       for ( int i = 0; i < tgtEditor.myLastCreatedElems.Size(); ++i )
10989         g->SMDSGroup().Add( tgtEditor.myLastCreatedElems( i+1 ));
10990   }
10991   tgtEditor.myLastCreatedElems.Clear();
10992
10993   // 5. Copy given elements
10994   if ( toCopyElements )
10995   {
10996     if (elements.empty())
10997       eIt = aMesh->elementsIterator(elemType);
10998     else
10999       eIt = SMDS_ElemIteratorPtr( new TSetIterator( elements.begin(), elements.end() ));
11000     while (eIt->more())
11001     {
11002       const SMDS_MeshElement* elem = eIt->next();
11003       TConnectivity nodes( elem->NbNodes() );
11004       for ( inode = 0; inode < nodes.size(); ++inode )
11005         nodes[inode] = getNodeWithSameID( tgtMeshDS, elem->GetNode(inode) );
11006       tgtEditor.AddElement(nodes, elemType, elem->IsPoly());
11007
11008       tgtEditor.myLastCreatedElems.Clear();
11009     }
11010   }
11011   return;
11012 }