Salome HOME
Replace oe by ?
[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 #include <algorithm>
98 #include <sstream>
99
100 #define cast2Node(elem) static_cast<const SMDS_MeshNode*>( elem )
101
102 using namespace std;
103 using namespace SMESH::Controls;
104
105 typedef map<const SMDS_MeshElement*, list<const SMDS_MeshNode*> >    TElemOfNodeListMap;
106 typedef map<const SMDS_MeshElement*, list<const SMDS_MeshElement*> > TElemOfElemListMap;
107
108 typedef SMDS_SetIterator< SMDS_pElement, TIDSortedElemSet::const_iterator> TSetIterator;
109
110 //=======================================================================
111 //function : SMESH_MeshEditor
112 //purpose  :
113 //=======================================================================
114
115 SMESH_MeshEditor::SMESH_MeshEditor( SMESH_Mesh* theMesh )
116   :myMesh( theMesh ) // theMesh may be NULL
117 {
118 }
119
120 //=======================================================================
121 /*!
122  * \brief Add element
123  */
124 //=======================================================================
125
126 SMDS_MeshElement*
127 SMESH_MeshEditor::AddElement(const vector<const SMDS_MeshNode*> & node,
128                              const SMDSAbs_ElementType            type,
129                              const bool                           isPoly,
130                              const int                            ID)
131 {
132   //MESSAGE("AddElement " <<node.size() << " " << type << " " << isPoly << " " << ID);
133   SMDS_MeshElement* e = 0;
134   int nbnode = node.size();
135   SMESHDS_Mesh* mesh = GetMeshDS();
136   switch ( type ) {
137   case SMDSAbs_Face:
138     if ( !isPoly ) {
139       if      (nbnode == 3) {
140         if ( ID >= 1 ) e = mesh->AddFaceWithID(node[0], node[1], node[2], ID);
141         else           e = mesh->AddFace      (node[0], node[1], node[2] );
142       }
143       else if (nbnode == 4) {
144         if ( ID >= 1 ) e = mesh->AddFaceWithID(node[0], node[1], node[2], node[3], ID);
145         else           e = mesh->AddFace      (node[0], node[1], node[2], node[3] );
146       }
147       else if (nbnode == 6) {
148         if ( ID >= 1 ) e = mesh->AddFaceWithID(node[0], node[1], node[2], node[3],
149                                                node[4], node[5], ID);
150         else           e = mesh->AddFace      (node[0], node[1], node[2], node[3],
151                                                node[4], node[5] );
152       }
153       else if (nbnode == 8) {
154         if ( ID >= 1 ) e = mesh->AddFaceWithID(node[0], node[1], node[2], node[3],
155                                                node[4], node[5], node[6], node[7], ID);
156         else           e = mesh->AddFace      (node[0], node[1], node[2], node[3],
157                                                node[4], node[5], node[6], node[7] );
158       }
159     } else {
160       if ( ID >= 1 ) e = mesh->AddPolygonalFaceWithID(node, ID);
161       else           e = mesh->AddPolygonalFace      (node    );
162     }
163     break;
164
165   case SMDSAbs_Volume:
166     if ( !isPoly ) {
167       if      (nbnode == 4) {
168         if ( ID >= 1 ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3], ID);
169         else           e = mesh->AddVolume      (node[0], node[1], node[2], node[3] );
170       }
171       else if (nbnode == 5) {
172         if ( ID >= 1 ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
173                                                  node[4], ID);
174         else           e = mesh->AddVolume      (node[0], node[1], node[2], node[3],
175                                                  node[4] );
176       }
177       else if (nbnode == 6) {
178         if ( ID >= 1 ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
179                                                  node[4], node[5], ID);
180         else           e = mesh->AddVolume      (node[0], node[1], node[2], node[3],
181                                                  node[4], node[5] );
182       }
183       else if (nbnode == 8) {
184         if ( ID >= 1 ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
185                                                  node[4], node[5], node[6], node[7], ID);
186         else           e = mesh->AddVolume      (node[0], node[1], node[2], node[3],
187                                                  node[4], node[5], node[6], node[7] );
188       }
189       else if (nbnode == 10) {
190         if ( ID >= 1 ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
191                                                  node[4], node[5], node[6], node[7],
192                                                  node[8], node[9], ID);
193         else           e = mesh->AddVolume      (node[0], node[1], node[2], node[3],
194                                                  node[4], node[5], node[6], node[7],
195                                                  node[8], node[9] );
196       }
197       else if (nbnode == 13) {
198         if ( ID >= 1 ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
199                                                  node[4], node[5], node[6], node[7],
200                                                  node[8], node[9], node[10],node[11],
201                                                  node[12],ID);
202         else           e = mesh->AddVolume      (node[0], node[1], node[2], node[3],
203                                                  node[4], node[5], node[6], node[7],
204                                                  node[8], node[9], node[10],node[11],
205                                                  node[12] );
206       }
207       else if (nbnode == 15) {
208         if ( ID >= 1 ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
209                                                  node[4], node[5], node[6], node[7],
210                                                  node[8], node[9], node[10],node[11],
211                                                  node[12],node[13],node[14],ID);
212         else           e = mesh->AddVolume      (node[0], node[1], node[2], node[3],
213                                                  node[4], node[5], node[6], node[7],
214                                                  node[8], node[9], node[10],node[11],
215                                                  node[12],node[13],node[14] );
216       }
217       else if (nbnode == 20) {
218         if ( ID >= 1 ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
219                                                  node[4], node[5], node[6], node[7],
220                                                  node[8], node[9], node[10],node[11],
221                                                  node[12],node[13],node[14],node[15],
222                                                  node[16],node[17],node[18],node[19],ID);
223         else           e = mesh->AddVolume      (node[0], node[1], node[2], node[3],
224                                                  node[4], node[5], node[6], node[7],
225                                                  node[8], node[9], node[10],node[11],
226                                                  node[12],node[13],node[14],node[15],
227                                                  node[16],node[17],node[18],node[19] );
228       }
229     }
230     break;
231
232   case SMDSAbs_Edge:
233     if ( nbnode == 2 ) {
234       if ( ID >= 1 ) e = mesh->AddEdgeWithID(node[0], node[1], ID);
235       else           e = mesh->AddEdge      (node[0], node[1] );
236     }
237     else if ( nbnode == 3 ) {
238       if ( ID >= 1 ) e = mesh->AddEdgeWithID(node[0], node[1], node[2], ID);
239       else           e = mesh->AddEdge      (node[0], node[1], node[2] );
240     }
241     break;
242
243   case SMDSAbs_0DElement:
244     if ( nbnode == 1 ) {
245       if ( ID >= 1 ) e = mesh->Add0DElementWithID(node[0], ID);
246       else           e = mesh->Add0DElement      (node[0] );
247     }
248     break;
249
250   case SMDSAbs_Node:
251     if ( ID >= 1 ) e = mesh->AddNodeWithID(node[0]->X(), node[0]->Y(), node[0]->Z(), ID);
252     else           e = mesh->AddNode      (node[0]->X(), node[0]->Y(), node[0]->Z());
253     break;
254
255   default:;
256   }
257   if ( e ) myLastCreatedElems.Append( e );
258   return e;
259 }
260
261 //=======================================================================
262 /*!
263  * \brief Add element
264  */
265 //=======================================================================
266
267 SMDS_MeshElement* SMESH_MeshEditor::AddElement(const vector<int> &       nodeIDs,
268                                                const SMDSAbs_ElementType type,
269                                                const bool                isPoly,
270                                                const int                 ID)
271 {
272   vector<const SMDS_MeshNode*> nodes;
273   nodes.reserve( nodeIDs.size() );
274   vector<int>::const_iterator id = nodeIDs.begin();
275   while ( id != nodeIDs.end() ) {
276     if ( const SMDS_MeshNode* node = GetMeshDS()->FindNode( *id++ ))
277       nodes.push_back( node );
278     else
279       return 0;
280   }
281   return AddElement( nodes, type, isPoly, ID );
282 }
283
284 //=======================================================================
285 //function : Remove
286 //purpose  : Remove a node or an element.
287 //           Modify a compute state of sub-meshes which become empty
288 //=======================================================================
289
290 int SMESH_MeshEditor::Remove (const list< int >& theIDs,
291                               const bool         isNodes )
292 {
293   myLastCreatedElems.Clear();
294   myLastCreatedNodes.Clear();
295
296   SMESHDS_Mesh* aMesh = GetMeshDS();
297   set< SMESH_subMesh *> smmap;
298
299   int removed = 0;
300   list<int>::const_iterator it = theIDs.begin();
301   for ( ; it != theIDs.end(); it++ ) {
302     const SMDS_MeshElement * elem;
303     if ( isNodes )
304       elem = aMesh->FindNode( *it );
305     else
306       elem = aMesh->FindElement( *it );
307     if ( !elem )
308       continue;
309
310     // Notify VERTEX sub-meshes about modification
311     if ( isNodes ) {
312       const SMDS_MeshNode* node = cast2Node( elem );
313       if ( node->GetPosition()->GetTypeOfPosition() == SMDS_TOP_VERTEX )
314         if ( int aShapeID = node->getshapeId() )
315           if ( SMESH_subMesh * sm = GetMesh()->GetSubMeshContaining( aShapeID ) )
316             smmap.insert( sm );
317     }
318     // Find sub-meshes to notify about modification
319     //     SMDS_ElemIteratorPtr nodeIt = elem->nodesIterator();
320     //     while ( nodeIt->more() ) {
321     //       const SMDS_MeshNode* node = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
322     //       const SMDS_PositionPtr& aPosition = node->GetPosition();
323     //       if ( aPosition.get() ) {
324     //         if ( int aShapeID = aPosition->GetShapeId() ) {
325     //           if ( SMESH_subMesh * sm = GetMesh()->GetSubMeshContaining( aShapeID ) )
326     //             smmap.insert( sm );
327     //         }
328     //       }
329     //     }
330
331     // Do remove
332     if ( isNodes )
333       aMesh->RemoveNode( static_cast< const SMDS_MeshNode* >( elem ));
334     else
335       aMesh->RemoveElement( elem );
336     removed++;
337   }
338
339   // Notify sub-meshes about modification
340   if ( !smmap.empty() ) {
341     set< SMESH_subMesh *>::iterator smIt;
342     for ( smIt = smmap.begin(); smIt != smmap.end(); smIt++ )
343       (*smIt)->ComputeStateEngine( SMESH_subMesh::MESH_ENTITY_REMOVED );
344   }
345
346   //   // Check if the whole mesh becomes empty
347   //   if ( SMESH_subMesh * sm = GetMesh()->GetSubMeshContaining( 1 ) )
348   //     sm->ComputeStateEngine( SMESH_subMesh::CHECK_COMPUTE_STATE );
349
350   return removed;
351 }
352
353 //=======================================================================
354 //function : FindShape
355 //purpose  : Return an index of the shape theElem is on
356 //           or zero if a shape not found
357 //=======================================================================
358
359 int SMESH_MeshEditor::FindShape (const SMDS_MeshElement * theElem)
360 {
361   myLastCreatedElems.Clear();
362   myLastCreatedNodes.Clear();
363
364   SMESHDS_Mesh * aMesh = GetMeshDS();
365   if ( aMesh->ShapeToMesh().IsNull() )
366     return 0;
367
368   if ( theElem->GetType() == SMDSAbs_Node )
369     {
370       int aShapeID = theElem->getshapeId();
371       if (aShapeID <= 0)
372         return 0;
373       else
374         return aShapeID;
375     }
376
377   TopoDS_Shape aShape; // the shape a node is on
378   SMDS_ElemIteratorPtr nodeIt = theElem->nodesIterator();
379   while ( nodeIt->more() ) {
380     const SMDS_MeshNode* node = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
381     int aShapeID = node->getshapeId();
382     if (aShapeID > 0) {
383       SMESHDS_SubMesh * sm = aMesh->MeshElements( aShapeID );
384       if ( sm ) {
385         if ( sm->Contains( theElem ))
386           return aShapeID;
387         if ( aShape.IsNull() )
388           aShape = aMesh->IndexToShape( aShapeID );
389       }
390       else {
391         //MESSAGE ( "::FindShape() No SubShape for aShapeID " << aShapeID );
392       }
393     }
394   }
395
396   // None of nodes is on a proper shape,
397   // find the shape among ancestors of aShape on which a node is
398   if ( aShape.IsNull() ) {
399     //MESSAGE ("::FindShape() - NONE node is on shape")
400     return 0;
401   }
402   TopTools_ListIteratorOfListOfShape ancIt( GetMesh()->GetAncestors( aShape ));
403   for ( ; ancIt.More(); ancIt.Next() ) {
404     SMESHDS_SubMesh * sm = aMesh->MeshElements( ancIt.Value() );
405     if ( sm && sm->Contains( theElem ))
406       return aMesh->ShapeToIndex( ancIt.Value() );
407   }
408
409   //MESSAGE ("::FindShape() - SHAPE NOT FOUND")
410   return 0;
411 }
412
413 //=======================================================================
414 //function : IsMedium
415 //purpose  :
416 //=======================================================================
417
418 bool SMESH_MeshEditor::IsMedium(const SMDS_MeshNode*      node,
419                                 const SMDSAbs_ElementType typeToCheck)
420 {
421   bool isMedium = false;
422   SMDS_ElemIteratorPtr it = node->GetInverseElementIterator(typeToCheck);
423   while (it->more() && !isMedium ) {
424     const SMDS_MeshElement* elem = it->next();
425     isMedium = elem->IsMediumNode(node);
426   }
427   return isMedium;
428 }
429
430 //=======================================================================
431 //function : ShiftNodesQuadTria
432 //purpose  : auxilary
433 //           Shift nodes in the array corresponded to quadratic triangle
434 //           example: (0,1,2,3,4,5) -> (1,2,0,4,5,3)
435 //=======================================================================
436 static void ShiftNodesQuadTria(const SMDS_MeshNode* aNodes[])
437 {
438   const SMDS_MeshNode* nd1 = aNodes[0];
439   aNodes[0] = aNodes[1];
440   aNodes[1] = aNodes[2];
441   aNodes[2] = nd1;
442   const SMDS_MeshNode* nd2 = aNodes[3];
443   aNodes[3] = aNodes[4];
444   aNodes[4] = aNodes[5];
445   aNodes[5] = nd2;
446 }
447
448 //=======================================================================
449 //function : GetNodesFromTwoTria
450 //purpose  : auxilary
451 //           Shift nodes in the array corresponded to quadratic triangle
452 //           example: (0,1,2,3,4,5) -> (1,2,0,4,5,3)
453 //=======================================================================
454 static bool GetNodesFromTwoTria(const SMDS_MeshElement * theTria1,
455                                 const SMDS_MeshElement * theTria2,
456                                 const SMDS_MeshNode* N1[],
457                                 const SMDS_MeshNode* N2[])
458 {
459   SMDS_ElemIteratorPtr it = theTria1->nodesIterator();
460   int i=0;
461   while(i<6) {
462     N1[i] = static_cast<const SMDS_MeshNode*>( it->next() );
463     i++;
464   }
465   if(it->more()) return false;
466   it = theTria2->nodesIterator();
467   i=0;
468   while(i<6) {
469     N2[i] = static_cast<const SMDS_MeshNode*>( it->next() );
470     i++;
471   }
472   if(it->more()) return false;
473
474   int sames[3] = {-1,-1,-1};
475   int nbsames = 0;
476   int j;
477   for(i=0; i<3; i++) {
478     for(j=0; j<3; j++) {
479       if(N1[i]==N2[j]) {
480         sames[i] = j;
481         nbsames++;
482         break;
483       }
484     }
485   }
486   if(nbsames!=2) return false;
487   if(sames[0]>-1) {
488     ShiftNodesQuadTria(N1);
489     if(sames[1]>-1) {
490       ShiftNodesQuadTria(N1);
491     }
492   }
493   i = sames[0] + sames[1] + sames[2];
494   for(; i<2; i++) {
495     ShiftNodesQuadTria(N2);
496   }
497   // now we receive following N1 and N2 (using numeration as above image)
498   // tria1 : (1 2 4 5 9 7)  and  tria2 : (3 4 2 8 9 6)
499   // i.e. first nodes from both arrays determ new diagonal
500   return true;
501 }
502
503 //=======================================================================
504 //function : InverseDiag
505 //purpose  : Replace two neighbour triangles with ones built on the same 4 nodes
506 //           but having other common link.
507 //           Return False if args are improper
508 //=======================================================================
509
510 bool SMESH_MeshEditor::InverseDiag (const SMDS_MeshElement * theTria1,
511                                     const SMDS_MeshElement * theTria2 )
512 {
513   MESSAGE("InverseDiag");
514   myLastCreatedElems.Clear();
515   myLastCreatedNodes.Clear();
516
517   if (!theTria1 || !theTria2)
518     return false;
519
520   const SMDS_VtkFace* F1 = dynamic_cast<const SMDS_VtkFace*>( theTria1 );
521   if (!F1) return false;
522   const SMDS_VtkFace* F2 = dynamic_cast<const SMDS_VtkFace*>( theTria2 );
523   if (!F2) return false;
524   if ((theTria1->GetEntityType() == SMDSEntity_Triangle) &&
525       (theTria2->GetEntityType() == SMDSEntity_Triangle)) {
526
527     //  1 +--+ A  theTria1: ( 1 A B ) A->2 ( 1 2 B ) 1 +--+ A
528     //    | /|    theTria2: ( B A 2 ) B->1 ( 1 A 2 )   |\ |
529     //    |/ |                                         | \|
530     //  B +--+ 2                                     B +--+ 2
531
532     // put nodes in array and find out indices of the same ones
533     const SMDS_MeshNode* aNodes [6];
534     int sameInd [] = { 0, 0, 0, 0, 0, 0 };
535     int i = 0;
536     SMDS_ElemIteratorPtr it = theTria1->nodesIterator();
537     while ( it->more() ) {
538       aNodes[ i ] = static_cast<const SMDS_MeshNode*>( it->next() );
539
540       if ( i > 2 ) // theTria2
541         // find same node of theTria1
542         for ( int j = 0; j < 3; j++ )
543           if ( aNodes[ i ] == aNodes[ j ]) {
544             sameInd[ j ] = i;
545             sameInd[ i ] = j;
546             break;
547           }
548       // next
549       i++;
550       if ( i == 3 ) {
551         if ( it->more() )
552           return false; // theTria1 is not a triangle
553         it = theTria2->nodesIterator();
554       }
555       if ( i == 6 && it->more() )
556         return false; // theTria2 is not a triangle
557     }
558
559     // find indices of 1,2 and of A,B in theTria1
560     int iA = 0, iB = 0, i1 = 0, i2 = 0;
561     for ( i = 0; i < 6; i++ ) {
562       if ( sameInd [ i ] == 0 ) {
563         if ( i < 3 ) i1 = i;
564         else         i2 = i;
565       }
566       else if (i < 3) {
567         if ( iA ) iB = i;
568         else      iA = i;
569       }
570     }
571     // nodes 1 and 2 should not be the same
572     if ( aNodes[ i1 ] == aNodes[ i2 ] )
573       return false;
574
575     // theTria1: A->2
576     aNodes[ iA ] = aNodes[ i2 ];
577     // theTria2: B->1
578     aNodes[ sameInd[ iB ]] = aNodes[ i1 ];
579
580     GetMeshDS()->ChangeElementNodes( theTria1, aNodes, 3 );
581     GetMeshDS()->ChangeElementNodes( theTria2, &aNodes[ 3 ], 3 );
582
583     return true;
584
585   } // end if(F1 && F2)
586
587   // check case of quadratic faces
588   if (theTria1->GetEntityType() != SMDSEntity_Quad_Triangle)
589     return false;
590   if (theTria2->GetEntityType() != SMDSEntity_Quad_Triangle)
591     return false;
592
593   //       5
594   //  1 +--+--+ 2  theTria1: (1 2 4 5 9 7) or (2 4 1 9 7 5) or (4 1 2 7 5 9)
595   //    |    /|    theTria2: (2 3 4 6 8 9) or (3 4 2 8 9 6) or (4 2 3 9 6 8)
596   //    |   / |
597   //  7 +  +  + 6
598   //    | /9  |
599   //    |/    |
600   //  4 +--+--+ 3
601   //       8
602
603   const SMDS_MeshNode* N1 [6];
604   const SMDS_MeshNode* N2 [6];
605   if(!GetNodesFromTwoTria(theTria1,theTria2,N1,N2))
606     return false;
607   // now we receive following N1 and N2 (using numeration as above image)
608   // tria1 : (1 2 4 5 9 7)  and  tria2 : (3 4 2 8 9 6)
609   // i.e. first nodes from both arrays determ new diagonal
610
611   const SMDS_MeshNode* N1new [6];
612   const SMDS_MeshNode* N2new [6];
613   N1new[0] = N1[0];
614   N1new[1] = N2[0];
615   N1new[2] = N2[1];
616   N1new[3] = N1[4];
617   N1new[4] = N2[3];
618   N1new[5] = N1[5];
619   N2new[0] = N1[0];
620   N2new[1] = N1[1];
621   N2new[2] = N2[0];
622   N2new[3] = N1[3];
623   N2new[4] = N2[5];
624   N2new[5] = N1[4];
625   // replaces nodes in faces
626   GetMeshDS()->ChangeElementNodes( theTria1, N1new, 6 );
627   GetMeshDS()->ChangeElementNodes( theTria2, N2new, 6 );
628
629   return true;
630 }
631
632 //=======================================================================
633 //function : findTriangles
634 //purpose  : find triangles sharing theNode1-theNode2 link
635 //=======================================================================
636
637 static bool findTriangles(const SMDS_MeshNode *    theNode1,
638                           const SMDS_MeshNode *    theNode2,
639                           const SMDS_MeshElement*& theTria1,
640                           const SMDS_MeshElement*& theTria2)
641 {
642   if ( !theNode1 || !theNode2 ) return false;
643
644   theTria1 = theTria2 = 0;
645
646   set< const SMDS_MeshElement* > emap;
647   SMDS_ElemIteratorPtr it = theNode1->GetInverseElementIterator(SMDSAbs_Face);
648   while (it->more()) {
649     const SMDS_MeshElement* elem = it->next();
650     if ( elem->NbNodes() == 3 )
651       emap.insert( elem );
652   }
653   it = theNode2->GetInverseElementIterator(SMDSAbs_Face);
654   while (it->more()) {
655     const SMDS_MeshElement* elem = it->next();
656     if ( emap.find( elem ) != emap.end() ) {
657       if ( theTria1 ) {
658         // theTria1 must be element with minimum ID
659         if( theTria1->GetID() < elem->GetID() ) {
660           theTria2 = elem;
661         }
662         else {
663           theTria2 = theTria1;
664           theTria1 = elem;
665         }
666         break;
667       }
668       else {
669         theTria1 = elem;
670       }
671     }
672   }
673   return ( theTria1 && theTria2 );
674 }
675
676 //=======================================================================
677 //function : InverseDiag
678 //purpose  : Replace two neighbour triangles sharing theNode1-theNode2 link
679 //           with ones built on the same 4 nodes but having other common link.
680 //           Return false if proper faces not found
681 //=======================================================================
682
683 bool SMESH_MeshEditor::InverseDiag (const SMDS_MeshNode * theNode1,
684                                     const SMDS_MeshNode * theNode2)
685 {
686   myLastCreatedElems.Clear();
687   myLastCreatedNodes.Clear();
688
689   MESSAGE( "::InverseDiag()" );
690
691   const SMDS_MeshElement *tr1, *tr2;
692   if ( !findTriangles( theNode1, theNode2, tr1, tr2 ))
693     return false;
694
695   const SMDS_VtkFace* F1 = dynamic_cast<const SMDS_VtkFace*>( tr1 );
696   if (!F1) return false;
697   const SMDS_VtkFace* F2 = dynamic_cast<const SMDS_VtkFace*>( tr2 );
698   if (!F2) return false;
699   if ((tr1->GetEntityType() == SMDSEntity_Triangle) &&
700       (tr2->GetEntityType() == SMDSEntity_Triangle)) {
701
702     //  1 +--+ A  tr1: ( 1 A B ) A->2 ( 1 2 B ) 1 +--+ A
703     //    | /|    tr2: ( B A 2 ) B->1 ( 1 A 2 )   |\ |
704     //    |/ |                                    | \|
705     //  B +--+ 2                                B +--+ 2
706
707     // put nodes in array
708     // and find indices of 1,2 and of A in tr1 and of B in tr2
709     int i, iA1 = 0, i1 = 0;
710     const SMDS_MeshNode* aNodes1 [3];
711     SMDS_ElemIteratorPtr it;
712     for (i = 0, it = tr1->nodesIterator(); it->more(); i++ ) {
713       aNodes1[ i ] = static_cast<const SMDS_MeshNode*>( it->next() );
714       if ( aNodes1[ i ] == theNode1 )
715         iA1 = i; // node A in tr1
716       else if ( aNodes1[ i ] != theNode2 )
717         i1 = i;  // node 1
718     }
719     int iB2 = 0, i2 = 0;
720     const SMDS_MeshNode* aNodes2 [3];
721     for (i = 0, it = tr2->nodesIterator(); it->more(); i++ ) {
722       aNodes2[ i ] = static_cast<const SMDS_MeshNode*>( it->next() );
723       if ( aNodes2[ i ] == theNode2 )
724         iB2 = i; // node B in tr2
725       else if ( aNodes2[ i ] != theNode1 )
726         i2 = i;  // node 2
727     }
728
729     // nodes 1 and 2 should not be the same
730     if ( aNodes1[ i1 ] == aNodes2[ i2 ] )
731       return false;
732
733     // tr1: A->2
734     aNodes1[ iA1 ] = aNodes2[ i2 ];
735     // tr2: B->1
736     aNodes2[ iB2 ] = aNodes1[ i1 ];
737
738     GetMeshDS()->ChangeElementNodes( tr1, aNodes1, 3 );
739     GetMeshDS()->ChangeElementNodes( tr2, aNodes2, 3 );
740
741     return true;
742   }
743
744   // check case of quadratic faces
745   return InverseDiag(tr1,tr2);
746 }
747
748 //=======================================================================
749 //function : getQuadrangleNodes
750 //purpose  : fill theQuadNodes - nodes of a quadrangle resulting from
751 //           fusion of triangles tr1 and tr2 having shared link on
752 //           theNode1 and theNode2
753 //=======================================================================
754
755 bool getQuadrangleNodes(const SMDS_MeshNode *    theQuadNodes [],
756                         const SMDS_MeshNode *    theNode1,
757                         const SMDS_MeshNode *    theNode2,
758                         const SMDS_MeshElement * tr1,
759                         const SMDS_MeshElement * tr2 )
760 {
761   if( tr1->NbNodes() != tr2->NbNodes() )
762     return false;
763   // find the 4-th node to insert into tr1
764   const SMDS_MeshNode* n4 = 0;
765   SMDS_ElemIteratorPtr it = tr2->nodesIterator();
766   int i=0;
767   while ( !n4 && i<3 ) {
768     const SMDS_MeshNode * n = cast2Node( it->next() );
769     i++;
770     bool isDiag = ( n == theNode1 || n == theNode2 );
771     if ( !isDiag )
772       n4 = n;
773   }
774   // Make an array of nodes to be in a quadrangle
775   int iNode = 0, iFirstDiag = -1;
776   it = tr1->nodesIterator();
777   i=0;
778   while ( i<3 ) {
779     const SMDS_MeshNode * n = cast2Node( it->next() );
780     i++;
781     bool isDiag = ( n == theNode1 || n == theNode2 );
782     if ( isDiag ) {
783       if ( iFirstDiag < 0 )
784         iFirstDiag = iNode;
785       else if ( iNode - iFirstDiag == 1 )
786         theQuadNodes[ iNode++ ] = n4; // insert the 4-th node between diagonal nodes
787     }
788     else if ( n == n4 ) {
789       return false; // tr1 and tr2 should not have all the same nodes
790     }
791     theQuadNodes[ iNode++ ] = n;
792   }
793   if ( iNode == 3 ) // diagonal nodes have 0 and 2 indices
794     theQuadNodes[ iNode ] = n4;
795
796   return true;
797 }
798
799 //=======================================================================
800 //function : DeleteDiag
801 //purpose  : Replace two neighbour triangles sharing theNode1-theNode2 link
802 //           with a quadrangle built on the same 4 nodes.
803 //           Return false if proper faces not found
804 //=======================================================================
805
806 bool SMESH_MeshEditor::DeleteDiag (const SMDS_MeshNode * theNode1,
807                                    const SMDS_MeshNode * theNode2)
808 {
809   myLastCreatedElems.Clear();
810   myLastCreatedNodes.Clear();
811
812   MESSAGE( "::DeleteDiag()" );
813
814   const SMDS_MeshElement *tr1, *tr2;
815   if ( !findTriangles( theNode1, theNode2, tr1, tr2 ))
816     return false;
817
818   const SMDS_VtkFace* F1 = dynamic_cast<const SMDS_VtkFace*>( tr1 );
819   if (!F1) return false;
820   const SMDS_VtkFace* F2 = dynamic_cast<const SMDS_VtkFace*>( tr2 );
821   if (!F2) return false;
822   SMESHDS_Mesh * aMesh = GetMeshDS();
823
824   if ((tr1->GetEntityType() == SMDSEntity_Triangle) &&
825       (tr2->GetEntityType() == SMDSEntity_Triangle)) {
826
827     const SMDS_MeshNode* aNodes [ 4 ];
828     if ( ! getQuadrangleNodes( aNodes, theNode1, theNode2, tr1, tr2 ))
829       return false;
830
831     const SMDS_MeshElement* newElem = 0;
832     newElem = aMesh->AddFace( aNodes[0], aNodes[1], aNodes[2], aNodes[3] );
833     myLastCreatedElems.Append(newElem);
834     AddToSameGroups( newElem, tr1, aMesh );
835     int aShapeId = tr1->getshapeId();
836     if ( aShapeId )
837       {
838         aMesh->SetMeshElementOnShape( newElem, aShapeId );
839       }
840     aMesh->RemoveElement( tr1 );
841     aMesh->RemoveElement( tr2 );
842
843     return true;
844   }
845
846   // check case of quadratic faces
847   if (tr1->GetEntityType() != SMDSEntity_Quad_Triangle)
848     return false;
849   if (tr2->GetEntityType() != SMDSEntity_Quad_Triangle)
850     return false;
851
852   //       5
853   //  1 +--+--+ 2  tr1: (1 2 4 5 9 7) or (2 4 1 9 7 5) or (4 1 2 7 5 9)
854   //    |    /|    tr2: (2 3 4 6 8 9) or (3 4 2 8 9 6) or (4 2 3 9 6 8)
855   //    |   / |
856   //  7 +  +  + 6
857   //    | /9  |
858   //    |/    |
859   //  4 +--+--+ 3
860   //       8
861
862   const SMDS_MeshNode* N1 [6];
863   const SMDS_MeshNode* N2 [6];
864   if(!GetNodesFromTwoTria(tr1,tr2,N1,N2))
865     return false;
866   // now we receive following N1 and N2 (using numeration as above image)
867   // tria1 : (1 2 4 5 9 7)  and  tria2 : (3 4 2 8 9 6)
868   // i.e. first nodes from both arrays determ new diagonal
869
870   const SMDS_MeshNode* aNodes[8];
871   aNodes[0] = N1[0];
872   aNodes[1] = N1[1];
873   aNodes[2] = N2[0];
874   aNodes[3] = N2[1];
875   aNodes[4] = N1[3];
876   aNodes[5] = N2[5];
877   aNodes[6] = N2[3];
878   aNodes[7] = N1[5];
879
880   const SMDS_MeshElement* newElem = 0;
881   newElem = aMesh->AddFace( aNodes[0], aNodes[1], aNodes[2], aNodes[3],
882                             aNodes[4], aNodes[5], aNodes[6], aNodes[7]);
883   myLastCreatedElems.Append(newElem);
884   AddToSameGroups( newElem, tr1, aMesh );
885   int aShapeId = tr1->getshapeId();
886   if ( aShapeId )
887     {
888       aMesh->SetMeshElementOnShape( newElem, aShapeId );
889     }
890   aMesh->RemoveElement( tr1 );
891   aMesh->RemoveElement( tr2 );
892
893   // remove middle node (9)
894   GetMeshDS()->RemoveNode( N1[4] );
895
896   return true;
897 }
898
899 //=======================================================================
900 //function : Reorient
901 //purpose  : Reverse theElement orientation
902 //=======================================================================
903
904 bool SMESH_MeshEditor::Reorient (const SMDS_MeshElement * theElem)
905 {
906   MESSAGE("Reorient");
907   myLastCreatedElems.Clear();
908   myLastCreatedNodes.Clear();
909
910   if (!theElem)
911     return false;
912   SMDS_ElemIteratorPtr it = theElem->nodesIterator();
913   if ( !it || !it->more() )
914     return false;
915
916   switch ( theElem->GetType() ) {
917
918   case SMDSAbs_Edge:
919   case SMDSAbs_Face: {
920     if(!theElem->IsQuadratic()) {
921       int i = theElem->NbNodes();
922       vector<const SMDS_MeshNode*> aNodes( i );
923       while ( it->more() )
924         aNodes[ --i ]= static_cast<const SMDS_MeshNode*>( it->next() );
925       return GetMeshDS()->ChangeElementNodes( theElem, &aNodes[0], theElem->NbNodes() );
926     }
927     else {
928       // quadratic elements
929       if(theElem->GetType()==SMDSAbs_Edge) {
930         vector<const SMDS_MeshNode*> aNodes(3);
931         aNodes[1]= static_cast<const SMDS_MeshNode*>( it->next() );
932         aNodes[0]= static_cast<const SMDS_MeshNode*>( it->next() );
933         aNodes[2]= static_cast<const SMDS_MeshNode*>( it->next() );
934         return GetMeshDS()->ChangeElementNodes( theElem, &aNodes[0], 3 );
935       }
936       else {
937         int nbn = theElem->NbNodes();
938         vector<const SMDS_MeshNode*> aNodes(nbn);
939         aNodes[0]= static_cast<const SMDS_MeshNode*>( it->next() );
940         int i=1;
941         for(; i<nbn/2; i++) {
942           aNodes[nbn/2-i]= static_cast<const SMDS_MeshNode*>( it->next() );
943         }
944         for(i=0; i<nbn/2; i++) {
945           aNodes[nbn-i-1]= static_cast<const SMDS_MeshNode*>( it->next() );
946         }
947         return GetMeshDS()->ChangeElementNodes( theElem, &aNodes[0], nbn );
948       }
949     }
950   }
951   case SMDSAbs_Volume: {
952     if (theElem->IsPoly()) {
953       // TODO reorient vtk polyhedron
954       MESSAGE("reorient vtk polyhedron ?");
955       const SMDS_VtkVolume* aPolyedre =
956         dynamic_cast<const SMDS_VtkVolume*>( theElem );
957       if (!aPolyedre) {
958         MESSAGE("Warning: bad volumic element");
959         return false;
960       }
961
962       int nbFaces = aPolyedre->NbFaces();
963       vector<const SMDS_MeshNode *> poly_nodes;
964       vector<int> quantities (nbFaces);
965
966       // reverse each face of the polyedre
967       for (int iface = 1; iface <= nbFaces; iface++) {
968         int inode, nbFaceNodes = aPolyedre->NbFaceNodes(iface);
969         quantities[iface - 1] = nbFaceNodes;
970
971         for (inode = nbFaceNodes; inode >= 1; inode--) {
972           const SMDS_MeshNode* curNode = aPolyedre->GetFaceNode(iface, inode);
973           poly_nodes.push_back(curNode);
974         }
975       }
976
977       return GetMeshDS()->ChangePolyhedronNodes( theElem, poly_nodes, quantities );
978
979     }
980     else {
981       SMDS_VolumeTool vTool;
982       if ( !vTool.Set( theElem ))
983         return false;
984       vTool.Inverse();
985       MESSAGE("ChangeElementNodes reorient: check vTool.Inverse");
986       return GetMeshDS()->ChangeElementNodes( theElem, vTool.GetNodes(), vTool.NbNodes() );
987     }
988   }
989   default:;
990   }
991
992   return false;
993 }
994
995 //=======================================================================
996 //function : getBadRate
997 //purpose  :
998 //=======================================================================
999
1000 static double getBadRate (const SMDS_MeshElement*               theElem,
1001                           SMESH::Controls::NumericalFunctorPtr& theCrit)
1002 {
1003   SMESH::Controls::TSequenceOfXYZ P;
1004   if ( !theElem || !theCrit->GetPoints( theElem, P ))
1005     return 1e100;
1006   return theCrit->GetBadRate( theCrit->GetValue( P ), theElem->NbNodes() );
1007   //return theCrit->GetBadRate( theCrit->GetValue( theElem->GetID() ), theElem->NbNodes() );
1008 }
1009
1010 //=======================================================================
1011 //function : QuadToTri
1012 //purpose  : Cut quadrangles into triangles.
1013 //           theCrit is used to select a diagonal to cut
1014 //=======================================================================
1015
1016 bool SMESH_MeshEditor::QuadToTri (TIDSortedElemSet &                   theElems,
1017                                   SMESH::Controls::NumericalFunctorPtr theCrit)
1018 {
1019   myLastCreatedElems.Clear();
1020   myLastCreatedNodes.Clear();
1021
1022   MESSAGE( "::QuadToTri()" );
1023
1024   if ( !theCrit.get() )
1025     return false;
1026
1027   SMESHDS_Mesh * aMesh = GetMeshDS();
1028
1029   Handle(Geom_Surface) surface;
1030   SMESH_MesherHelper   helper( *GetMesh() );
1031
1032   TIDSortedElemSet::iterator itElem;
1033   for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
1034     const SMDS_MeshElement* elem = *itElem;
1035     if ( !elem || elem->GetType() != SMDSAbs_Face )
1036       continue;
1037     if ( elem->NbNodes() != ( elem->IsQuadratic() ? 8 : 4 ))
1038       continue;
1039
1040     // retrieve element nodes
1041     const SMDS_MeshNode* aNodes [8];
1042     SMDS_ElemIteratorPtr itN = elem->nodesIterator();
1043     int i = 0;
1044     while ( itN->more() )
1045       aNodes[ i++ ] = static_cast<const SMDS_MeshNode*>( itN->next() );
1046
1047     // compare two sets of possible triangles
1048     double aBadRate1, aBadRate2; // to what extent a set is bad
1049     SMDS_FaceOfNodes tr1 ( aNodes[0], aNodes[1], aNodes[2] );
1050     SMDS_FaceOfNodes tr2 ( aNodes[2], aNodes[3], aNodes[0] );
1051     aBadRate1 = getBadRate( &tr1, theCrit ) + getBadRate( &tr2, theCrit );
1052
1053     SMDS_FaceOfNodes tr3 ( aNodes[1], aNodes[2], aNodes[3] );
1054     SMDS_FaceOfNodes tr4 ( aNodes[3], aNodes[0], aNodes[1] );
1055     aBadRate2 = getBadRate( &tr3, theCrit ) + getBadRate( &tr4, theCrit );
1056
1057     int aShapeId = FindShape( elem );
1058     const SMDS_MeshElement* newElem1 = 0;
1059     const SMDS_MeshElement* newElem2 = 0;
1060
1061     if( !elem->IsQuadratic() ) {
1062
1063       // split liner quadrangle
1064       if ( aBadRate1 <= aBadRate2 ) {
1065         // tr1 + tr2 is better
1066         newElem1 = aMesh->AddFace( aNodes[2], aNodes[3], aNodes[0] );
1067         newElem2 = aMesh->AddFace( aNodes[2], aNodes[0], aNodes[1] );
1068       }
1069       else {
1070         // tr3 + tr4 is better
1071         newElem1 = aMesh->AddFace( aNodes[3], aNodes[0], aNodes[1] );
1072         newElem2 = aMesh->AddFace( aNodes[3], aNodes[1], aNodes[2] );
1073       }
1074     }
1075     else {
1076
1077       // split quadratic quadrangle
1078
1079       // get surface elem is on
1080       if ( aShapeId != helper.GetSubShapeID() ) {
1081         surface.Nullify();
1082         TopoDS_Shape shape;
1083         if ( aShapeId > 0 )
1084           shape = aMesh->IndexToShape( aShapeId );
1085         if ( !shape.IsNull() && shape.ShapeType() == TopAbs_FACE ) {
1086           TopoDS_Face face = TopoDS::Face( shape );
1087           surface = BRep_Tool::Surface( face );
1088           if ( !surface.IsNull() )
1089             helper.SetSubShape( shape );
1090         }
1091       }
1092       // get elem nodes
1093       const SMDS_MeshNode* aNodes [8];
1094       const SMDS_MeshNode* inFaceNode = 0;
1095       SMDS_ElemIteratorPtr itN = elem->nodesIterator();
1096       int i = 0;
1097       while ( itN->more() ) {
1098         aNodes[ i++ ] = static_cast<const SMDS_MeshNode*>( itN->next() );
1099         if ( !inFaceNode && helper.GetNodeUVneedInFaceNode() &&
1100              aNodes[ i-1 ]->GetPosition()->GetTypeOfPosition() == SMDS_TOP_FACE )
1101         {
1102           inFaceNode = aNodes[ i-1 ];
1103         }
1104       }
1105       // find middle point for (0,1,2,3)
1106       // and create a node in this point;
1107       gp_XYZ p( 0,0,0 );
1108       if ( surface.IsNull() ) {
1109         for(i=0; i<4; i++)
1110           p += gp_XYZ(aNodes[i]->X(), aNodes[i]->Y(), aNodes[i]->Z() );
1111         p /= 4;
1112       }
1113       else {
1114         TopoDS_Face face = TopoDS::Face( helper.GetSubShape() );
1115         gp_XY uv( 0,0 );
1116         for(i=0; i<4; i++)
1117           uv += helper.GetNodeUV( face, aNodes[i], inFaceNode );
1118         uv /= 4.;
1119         p = surface->Value( uv.X(), uv.Y() ).XYZ();
1120       }
1121       const SMDS_MeshNode* newN = aMesh->AddNode( p.X(), p.Y(), p.Z() );
1122       myLastCreatedNodes.Append(newN);
1123
1124       // create a new element
1125       const SMDS_MeshNode* N[6];
1126       if ( aBadRate1 <= aBadRate2 ) {
1127         N[0] = aNodes[0];
1128         N[1] = aNodes[1];
1129         N[2] = aNodes[2];
1130         N[3] = aNodes[4];
1131         N[4] = aNodes[5];
1132         N[5] = newN;
1133         newElem1 = aMesh->AddFace(aNodes[2], aNodes[3], aNodes[0],
1134                                   aNodes[6], aNodes[7], newN );
1135         newElem2 = aMesh->AddFace(aNodes[2], aNodes[0], aNodes[1],
1136                                   newN,      aNodes[4], aNodes[5] );
1137       }
1138       else {
1139         N[0] = aNodes[1];
1140         N[1] = aNodes[2];
1141         N[2] = aNodes[3];
1142         N[3] = aNodes[5];
1143         N[4] = aNodes[6];
1144         N[5] = newN;
1145         newElem1 = aMesh->AddFace(aNodes[3], aNodes[0], aNodes[1],
1146                                   aNodes[7], aNodes[4], newN );
1147         newElem2 = aMesh->AddFace(aNodes[3], aNodes[1], aNodes[2],
1148                                   newN,      aNodes[5], aNodes[6] );
1149       }
1150     } // quadratic case
1151
1152     // care of a new element
1153
1154     myLastCreatedElems.Append(newElem1);
1155     myLastCreatedElems.Append(newElem2);
1156     AddToSameGroups( newElem1, elem, aMesh );
1157     AddToSameGroups( newElem2, elem, aMesh );
1158
1159     // put a new triangle on the same shape
1160     if ( aShapeId )
1161       {
1162         aMesh->SetMeshElementOnShape( newElem1, aShapeId );
1163         aMesh->SetMeshElementOnShape( newElem2, aShapeId );
1164       }
1165     aMesh->RemoveElement( elem );
1166   }
1167   return true;
1168 }
1169
1170 //=======================================================================
1171 //function : BestSplit
1172 //purpose  : Find better diagonal for cutting.
1173 //=======================================================================
1174
1175 int SMESH_MeshEditor::BestSplit (const SMDS_MeshElement*              theQuad,
1176                                  SMESH::Controls::NumericalFunctorPtr theCrit)
1177 {
1178   myLastCreatedElems.Clear();
1179   myLastCreatedNodes.Clear();
1180
1181   if (!theCrit.get())
1182     return -1;
1183
1184   if (!theQuad || theQuad->GetType() != SMDSAbs_Face )
1185     return -1;
1186
1187   if( theQuad->NbNodes()==4 ||
1188       (theQuad->NbNodes()==8 && theQuad->IsQuadratic()) ) {
1189
1190     // retrieve element nodes
1191     const SMDS_MeshNode* aNodes [4];
1192     SMDS_ElemIteratorPtr itN = theQuad->nodesIterator();
1193     int i = 0;
1194     //while (itN->more())
1195     while (i<4) {
1196       aNodes[ i++ ] = static_cast<const SMDS_MeshNode*>( itN->next() );
1197     }
1198     // compare two sets of possible triangles
1199     double aBadRate1, aBadRate2; // to what extent a set is bad
1200     SMDS_FaceOfNodes tr1 ( aNodes[0], aNodes[1], aNodes[2] );
1201     SMDS_FaceOfNodes tr2 ( aNodes[2], aNodes[3], aNodes[0] );
1202     aBadRate1 = getBadRate( &tr1, theCrit ) + getBadRate( &tr2, theCrit );
1203
1204     SMDS_FaceOfNodes tr3 ( aNodes[1], aNodes[2], aNodes[3] );
1205     SMDS_FaceOfNodes tr4 ( aNodes[3], aNodes[0], aNodes[1] );
1206     aBadRate2 = getBadRate( &tr3, theCrit ) + getBadRate( &tr4, theCrit );
1207
1208     if (aBadRate1 <= aBadRate2) // tr1 + tr2 is better
1209       return 1; // diagonal 1-3
1210
1211     return 2; // diagonal 2-4
1212   }
1213   return -1;
1214 }
1215
1216 namespace
1217 {
1218   // Methods of splitting volumes into tetra
1219
1220   const int theHexTo5_1[5*4+1] =
1221     {
1222       0, 1, 2, 5,    0, 4, 5, 7,     0, 2, 3, 7,    2, 5, 6, 7,     0, 5, 2, 7,   -1
1223     };
1224   const int theHexTo5_2[5*4+1] =
1225     {
1226       1, 2, 3, 6,    1, 4, 5, 6,     0, 1, 3, 4,    3, 4, 6, 7,     1, 3, 4, 6,   -1
1227     };
1228   const int* theHexTo5[2] = { theHexTo5_1, theHexTo5_2 };
1229
1230   const int theHexTo6_1[6*4+1] =
1231     {
1232       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
1233     };
1234   const int theHexTo6_2[6*4+1] =
1235     {
1236       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
1237     };
1238   const int theHexTo6_3[6*4+1] =
1239     {
1240       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
1241     };
1242   const int theHexTo6_4[6*4+1] =
1243     {
1244       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
1245     };
1246   const int* theHexTo6[4] = { theHexTo6_1, theHexTo6_2, theHexTo6_3, theHexTo6_4 };
1247
1248   const int thePyraTo2_1[2*4+1] =
1249     {
1250       0, 1, 2, 4,    0, 2, 3, 4,   -1
1251     };
1252   const int thePyraTo2_2[2*4+1] =
1253     {
1254       1, 2, 3, 4,    1, 3, 0, 4,   -1
1255     };
1256   const int* thePyraTo2[2] = { thePyraTo2_1, thePyraTo2_2 };
1257
1258   const int thePentaTo3_1[3*4+1] =
1259     {
1260       0, 1, 2, 3,    1, 3, 4, 2,     2, 3, 4, 5,    -1
1261     };
1262   const int thePentaTo3_2[3*4+1] =
1263     {
1264       1, 2, 0, 4,    2, 4, 5, 0,     0, 4, 5, 3,    -1
1265     };
1266   const int thePentaTo3_3[3*4+1] =
1267     {
1268       2, 0, 1, 5,    0, 5, 3, 1,     1, 5, 3, 4,    -1
1269     };
1270   const int thePentaTo3_4[3*4+1] =
1271     {
1272       0, 1, 2, 3,    1, 3, 4, 5,     2, 3, 1, 5,    -1
1273     };
1274   const int thePentaTo3_5[3*4+1] =
1275     {
1276       1, 2, 0, 4,    2, 4, 5, 3,     0, 4, 2, 3,    -1
1277     };
1278   const int thePentaTo3_6[3*4+1] =
1279     {
1280       2, 0, 1, 5,    0, 5, 3, 4,     1, 5, 0, 4,    -1
1281     };
1282   const int* thePentaTo3[6] = { thePentaTo3_1, thePentaTo3_2, thePentaTo3_3,
1283                                 thePentaTo3_4, thePentaTo3_5, thePentaTo3_6 };
1284
1285   struct TTriangleFacet //!< stores indices of three nodes of tetra facet
1286   {
1287     int _n1, _n2, _n3;
1288     TTriangleFacet(int n1, int n2, int n3): _n1(n1), _n2(n2), _n3(n3) {}
1289     bool contains(int n) const { return ( n == _n1 || n == _n2 || n == _n3 ); }
1290     bool hasAdjacentTetra( const SMDS_MeshElement* elem ) const;
1291   };
1292   struct TSplitMethod
1293   {
1294     int        _nbTetra;
1295     const int* _connectivity; //!< foursomes of tetra connectivy finished by -1
1296     bool       _baryNode;     //!< additional node is to be created at cell barycenter
1297     bool       _ownConn;      //!< to delete _connectivity in destructor
1298     map<int, const SMDS_MeshNode*> _faceBaryNode; //!< map face index to node at BC of face
1299
1300     TSplitMethod( int nbTet=0, const int* conn=0, bool addNode=false)
1301       : _nbTetra(nbTet), _connectivity(conn), _baryNode(addNode), _ownConn(false) {}
1302     ~TSplitMethod() { if ( _ownConn ) delete [] _connectivity; _connectivity = 0; }
1303     bool hasFacet( const TTriangleFacet& facet ) const
1304     {
1305       const int* tetConn = _connectivity;
1306       for ( ; tetConn[0] >= 0; tetConn += 4 )
1307         if (( facet.contains( tetConn[0] ) +
1308               facet.contains( tetConn[1] ) +
1309               facet.contains( tetConn[2] ) +
1310               facet.contains( tetConn[3] )) == 3 )
1311           return true;
1312       return false;
1313     }
1314   };
1315
1316   //=======================================================================
1317   /*!
1318    * \brief return TSplitMethod for the given element
1319    */
1320   //=======================================================================
1321
1322   TSplitMethod getSplitMethod( SMDS_VolumeTool& vol, const int theMethodFlags)
1323   {
1324     const int iQ = vol.Element()->IsQuadratic() ? 2 : 1;
1325
1326     // at HEXA_TO_24 method, each face of volume is split into triangles each based on
1327     // an edge and a face barycenter; tertaherdons are based on triangles and
1328     // a volume barycenter
1329     const bool is24TetMode = ( theMethodFlags == SMESH_MeshEditor::HEXA_TO_24 );
1330
1331     // Find out how adjacent volumes are split
1332
1333     vector < list< TTriangleFacet > > triaSplitsByFace( vol.NbFaces() ); // splits of each side
1334     int hasAdjacentSplits = 0, maxTetConnSize = 0;
1335     for ( int iF = 0; iF < vol.NbFaces(); ++iF )
1336     {
1337       int nbNodes = vol.NbFaceNodes( iF ) / iQ;
1338       maxTetConnSize += 4 * ( nbNodes - (is24TetMode ? 0 : 2));
1339       if ( nbNodes < 4 ) continue;
1340
1341       list< TTriangleFacet >& triaSplits = triaSplitsByFace[ iF ];
1342       const int* nInd = vol.GetFaceNodesIndices( iF );
1343       if ( nbNodes == 4 )
1344       {
1345         TTriangleFacet t012( nInd[0*iQ], nInd[1*iQ], nInd[2*iQ] );
1346         TTriangleFacet t123( nInd[1*iQ], nInd[2*iQ], nInd[3*iQ] );
1347         if      ( t012.hasAdjacentTetra( vol.Element() )) triaSplits.push_back( t012 );
1348         else if ( t123.hasAdjacentTetra( vol.Element() )) triaSplits.push_back( t123 );
1349       }
1350       else
1351       {
1352         int iCom = 0; // common node of triangle faces to split into
1353         for ( int iVar = 0; iVar < nbNodes; ++iVar, ++iCom )
1354         {
1355           TTriangleFacet t012( nInd[ iQ * ( iCom             )],
1356                                nInd[ iQ * ( (iCom+1)%nbNodes )],
1357                                nInd[ iQ * ( (iCom+2)%nbNodes )]);
1358           TTriangleFacet t023( nInd[ iQ * ( iCom             )],
1359                                nInd[ iQ * ( (iCom+2)%nbNodes )],
1360                                nInd[ iQ * ( (iCom+3)%nbNodes )]);
1361           if ( t012.hasAdjacentTetra( vol.Element() ) && t023.hasAdjacentTetra( vol.Element() ))
1362           {
1363             triaSplits.push_back( t012 );
1364             triaSplits.push_back( t023 );
1365             break;
1366           }
1367         }
1368       }
1369       if ( !triaSplits.empty() )
1370         hasAdjacentSplits = true;
1371     }
1372
1373     // Among variants of split method select one compliant with adjacent volumes
1374
1375     TSplitMethod method;
1376     if ( !vol.Element()->IsPoly() && !is24TetMode )
1377     {
1378       int nbVariants = 2, nbTet = 0;
1379       const int** connVariants = 0;
1380       switch ( vol.Element()->GetEntityType() )
1381       {
1382       case SMDSEntity_Hexa:
1383       case SMDSEntity_Quad_Hexa:
1384         if ( theMethodFlags == SMESH_MeshEditor::HEXA_TO_5 )
1385           connVariants = theHexTo5, nbTet = 5;
1386         else
1387           connVariants = theHexTo6, nbTet = 6, nbVariants = 4;
1388         break;
1389       case SMDSEntity_Pyramid:
1390       case SMDSEntity_Quad_Pyramid:
1391         connVariants = thePyraTo2;  nbTet = 2;
1392         break;
1393       case SMDSEntity_Penta:
1394       case SMDSEntity_Quad_Penta:
1395         connVariants = thePentaTo3; nbTet = 3; nbVariants = 6;
1396         break;
1397       default:
1398         nbVariants = 0;
1399       }
1400       for ( int variant = 0; variant < nbVariants && method._nbTetra == 0; ++variant )
1401       {
1402         // check method compliancy with adjacent tetras,
1403         // all found splits must be among facets of tetras described by this method
1404         method = TSplitMethod( nbTet, connVariants[variant] );
1405         if ( hasAdjacentSplits && method._nbTetra > 0 )
1406         {
1407           bool facetCreated = true;
1408           for ( int iF = 0; facetCreated && iF < triaSplitsByFace.size(); ++iF )
1409           {
1410             list< TTriangleFacet >::const_iterator facet = triaSplitsByFace[iF].begin();
1411             for ( ; facetCreated && facet != triaSplitsByFace[iF].end(); ++facet )
1412               facetCreated = method.hasFacet( *facet );
1413           }
1414           if ( !facetCreated )
1415             method = TSplitMethod(0); // incompatible method
1416         }
1417       }
1418     }
1419     if ( method._nbTetra < 1 )
1420     {
1421       // No standard method is applicable, use a generic solution:
1422       // each facet of a volume is split into triangles and
1423       // each of triangles and a volume barycenter form a tetrahedron.
1424
1425       int* connectivity = new int[ maxTetConnSize + 1 ];
1426       method._connectivity = connectivity;
1427       method._ownConn = true;
1428       method._baryNode = true;
1429
1430       int connSize = 0;
1431       int baryCenInd = vol.NbNodes();
1432       for ( int iF = 0; iF < vol.NbFaces(); ++iF )
1433       {
1434         const int nbNodes = vol.NbFaceNodes( iF ) / iQ;
1435         const int*   nInd = vol.GetFaceNodesIndices( iF );
1436         // find common node of triangle facets of tetra to create
1437         int iCommon = 0; // index in linear numeration
1438         const list< TTriangleFacet >& triaSplits = triaSplitsByFace[ iF ];
1439         if ( !triaSplits.empty() )
1440         {
1441           // by found facets
1442           const TTriangleFacet* facet = &triaSplits.front();
1443           for ( ; iCommon < nbNodes-1 ; ++iCommon )
1444             if ( facet->contains( nInd[ iQ * iCommon ]) &&
1445                  facet->contains( nInd[ iQ * ((iCommon+2)%nbNodes) ]))
1446               break;
1447         }
1448         else if ( nbNodes > 3 && !is24TetMode )
1449         {
1450           // find the best method of splitting into triangles by aspect ratio
1451           SMESH::Controls::NumericalFunctorPtr aspectRatio( new SMESH::Controls::AspectRatio);
1452           map< double, int > badness2iCommon;
1453           const SMDS_MeshNode** nodes = vol.GetFaceNodes( iF );
1454           int nbVariants = ( nbNodes == 4 ? 2 : nbNodes );
1455           for ( int iVar = 0; iVar < nbVariants; ++iVar, ++iCommon )
1456             for ( int iLast = iCommon+2; iLast < iCommon+nbNodes; ++iLast )
1457             {
1458               SMDS_FaceOfNodes tria ( nodes[ iQ*( iCommon         )],
1459                                       nodes[ iQ*((iLast-1)%nbNodes)],
1460                                       nodes[ iQ*((iLast  )%nbNodes)]);
1461               double badness = getBadRate( &tria, aspectRatio );
1462               badness2iCommon.insert( make_pair( badness, iCommon ));
1463             }
1464           // use iCommon with lowest badness
1465           iCommon = badness2iCommon.begin()->second;
1466         }
1467         if ( iCommon >= nbNodes )
1468           iCommon = 0; // something wrong
1469
1470         // fill connectivity of tetrahedra based on a current face
1471         int nbTet = nbNodes - 2;
1472         if ( is24TetMode && nbNodes > 3 && triaSplits.empty())
1473         {
1474           method._faceBaryNode.insert( make_pair( iF, (const SMDS_MeshNode*)0 ));
1475           int faceBaryCenInd = baryCenInd + method._faceBaryNode.size();
1476           nbTet = nbNodes;
1477           for ( int i = 0; i < nbTet; ++i )
1478           {
1479             int i1 = i, i2 = (i+1) % nbNodes;
1480             if ( !vol.IsFaceExternal( iF )) swap( i1, i2 );
1481             connectivity[ connSize++ ] = nInd[ iQ * i1 ];
1482             connectivity[ connSize++ ] = nInd[ iQ * i2 ];
1483             connectivity[ connSize++ ] = faceBaryCenInd;
1484             connectivity[ connSize++ ] = baryCenInd;
1485           }
1486         }
1487         else
1488         {
1489           for ( int i = 0; i < nbTet; ++i )
1490           {
1491             int i1 = (iCommon+1+i) % nbNodes, i2 = (iCommon+2+i) % nbNodes;
1492             if ( !vol.IsFaceExternal( iF )) swap( i1, i2 );
1493             connectivity[ connSize++ ] = nInd[ iQ * iCommon ];
1494             connectivity[ connSize++ ] = nInd[ iQ * i1 ];
1495             connectivity[ connSize++ ] = nInd[ iQ * i2 ];
1496             connectivity[ connSize++ ] = baryCenInd;
1497           }
1498         }
1499         method._nbTetra += nbTet;
1500       }
1501       connectivity[ connSize++ ] = -1;
1502     }
1503     return method;
1504   }
1505   //================================================================================
1506   /*!
1507    * \brief Check if there is a tetraherdon adjacent to the given element via this facet
1508    */
1509   //================================================================================
1510
1511   bool TTriangleFacet::hasAdjacentTetra( const SMDS_MeshElement* elem ) const
1512   {
1513     // find the tetrahedron including the three nodes of facet
1514     const SMDS_MeshNode* n1 = elem->GetNode(_n1);
1515     const SMDS_MeshNode* n2 = elem->GetNode(_n2);
1516     const SMDS_MeshNode* n3 = elem->GetNode(_n3);
1517     SMDS_ElemIteratorPtr volIt1 = n1->GetInverseElementIterator(SMDSAbs_Volume);
1518     while ( volIt1->more() )
1519     {
1520       const SMDS_MeshElement* v = volIt1->next();
1521       if ( v->GetEntityType() != ( v->IsQuadratic() ? SMDSEntity_Quad_Tetra : SMDSEntity_Tetra ))
1522         continue;
1523       SMDS_ElemIteratorPtr volIt2 = n2->GetInverseElementIterator(SMDSAbs_Volume);
1524       while ( volIt2->more() )
1525         if ( v != volIt2->next() )
1526           continue;
1527       SMDS_ElemIteratorPtr volIt3 = n3->GetInverseElementIterator(SMDSAbs_Volume);
1528       while ( volIt3->more() )
1529         if ( v == volIt3->next() )
1530           return true;
1531     }
1532     return false;
1533   }
1534
1535   //=======================================================================
1536   /*!
1537    * \brief A key of a face of volume
1538    */
1539   //=======================================================================
1540
1541   struct TVolumeFaceKey: pair< int, pair< int, int> >
1542   {
1543     TVolumeFaceKey( SMDS_VolumeTool& vol, int iF )
1544     {
1545       TIDSortedNodeSet sortedNodes;
1546       const int iQ = vol.Element()->IsQuadratic() ? 2 : 1;
1547       int nbNodes = vol.NbFaceNodes( iF );
1548       const SMDS_MeshNode** fNodes = vol.GetFaceNodes( iF );
1549       for ( int i = 0; i < nbNodes; i += iQ )
1550         sortedNodes.insert( fNodes[i] );
1551       TIDSortedNodeSet::iterator n = sortedNodes.begin();
1552       first = (*(n++))->GetID();
1553       second.first = (*(n++))->GetID();
1554       second.second = (*(n++))->GetID();
1555     }
1556   };
1557 } // namespace
1558
1559 //=======================================================================
1560 //function : SplitVolumesIntoTetra
1561 //purpose  : Split volumic elements into tetrahedra.
1562 //=======================================================================
1563
1564 void SMESH_MeshEditor::SplitVolumesIntoTetra (const TIDSortedElemSet & theElems,
1565                                               const int                theMethodFlags)
1566 {
1567   // std-like iterator on coordinates of nodes of mesh element
1568   typedef SMDS_StdIterator< SMESH_TNodeXYZ, SMDS_ElemIteratorPtr > NXyzIterator;
1569   NXyzIterator xyzEnd;
1570
1571   SMDS_VolumeTool    volTool;
1572   SMESH_MesherHelper helper( *GetMesh());
1573
1574   SMESHDS_SubMesh* subMesh = 0;//GetMeshDS()->MeshElements(1);
1575   SMESHDS_SubMesh* fSubMesh = 0;//subMesh;
1576   
1577   SMESH_SequenceOfElemPtr newNodes, newElems;
1578
1579   // map face of volume to it's baricenrtic node
1580   map< TVolumeFaceKey, const SMDS_MeshNode* > volFace2BaryNode;
1581   double bc[3];
1582
1583   TIDSortedElemSet::const_iterator elem = theElems.begin();
1584   for ( ; elem != theElems.end(); ++elem )
1585   {
1586     SMDSAbs_EntityType geomType = (*elem)->GetEntityType();
1587     if ( geomType <= SMDSEntity_Quad_Tetra )
1588       continue; // tetra or face or ...
1589
1590     if ( !volTool.Set( *elem )) continue; // not volume? strange...
1591
1592     TSplitMethod splitMethod = getSplitMethod( volTool, theMethodFlags );
1593     if ( splitMethod._nbTetra < 1 ) continue;
1594
1595     // find submesh to add new tetras to
1596     if ( !subMesh || !subMesh->Contains( *elem ))
1597     {
1598       int shapeID = FindShape( *elem );
1599       helper.SetSubShape( shapeID ); // helper will add tetras to the found submesh
1600       subMesh = GetMeshDS()->MeshElements( shapeID );
1601     }
1602     int iQ;
1603     if ( (*elem)->IsQuadratic() )
1604     {
1605       iQ = 2;
1606       // add quadratic links to the helper
1607       for ( int iF = 0; iF < volTool.NbFaces(); ++iF )
1608       {
1609         const SMDS_MeshNode** fNodes = volTool.GetFaceNodes( iF );
1610         for ( int iN = 0; iN < volTool.NbFaceNodes( iF ); iN += iQ )
1611           helper.AddTLinkNode( fNodes[iF], fNodes[iF+2], fNodes[iF+1] );
1612       }
1613       helper.SetIsQuadratic( true );
1614     }
1615     else
1616     {
1617       iQ = 1;
1618       helper.SetIsQuadratic( false );
1619     }
1620     vector<const SMDS_MeshNode*> nodes( (*elem)->begin_nodes(), (*elem)->end_nodes() );
1621     if ( splitMethod._baryNode )
1622     {
1623       // make a node at barycenter
1624       volTool.GetBaryCenter( bc[0], bc[1], bc[2] );
1625       SMDS_MeshNode* gcNode = helper.AddNode( bc[0], bc[1], bc[2] );
1626       nodes.push_back( gcNode );
1627       newNodes.Append( gcNode );
1628     }
1629     if ( !splitMethod._faceBaryNode.empty() )
1630     {
1631       // make or find baricentric nodes of faces
1632       map<int, const SMDS_MeshNode*>::iterator iF_n = splitMethod._faceBaryNode.begin();
1633       for ( ; iF_n != splitMethod._faceBaryNode.end(); ++iF_n )
1634       {
1635         map< TVolumeFaceKey, const SMDS_MeshNode* >::iterator f_n =
1636           volFace2BaryNode.insert
1637           ( make_pair( TVolumeFaceKey( volTool,iF_n->first ), (const SMDS_MeshNode*)0) ).first;
1638         if ( !f_n->second )
1639         {
1640           volTool.GetFaceBaryCenter( iF_n->first, bc[0], bc[1], bc[2] );
1641           newNodes.Append( f_n->second = helper.AddNode( bc[0], bc[1], bc[2] ));
1642         }
1643         nodes.push_back( iF_n->second = f_n->second );
1644       }
1645     }
1646
1647     // make tetras
1648     helper.SetElementsOnShape( true );
1649     vector<const SMDS_MeshElement* > tetras( splitMethod._nbTetra ); // splits of a volume
1650     const int* tetConn = splitMethod._connectivity;
1651     for ( int i = 0; i < splitMethod._nbTetra; ++i, tetConn += 4 )
1652       newElems.Append( tetras[ i ] = helper.AddVolume( nodes[ tetConn[0] ],
1653                                                        nodes[ tetConn[1] ],
1654                                                        nodes[ tetConn[2] ],
1655                                                        nodes[ tetConn[3] ]));
1656
1657     ReplaceElemInGroups( *elem, tetras, GetMeshDS() );
1658
1659     // Split faces on sides of the split volume
1660
1661     const SMDS_MeshNode** volNodes = volTool.GetNodes();
1662     for ( int iF = 0; iF < volTool.NbFaces(); ++iF )
1663     {
1664       const int nbNodes = volTool.NbFaceNodes( iF ) / iQ;
1665       if ( nbNodes < 4 ) continue;
1666
1667       // find an existing face
1668       vector<const SMDS_MeshNode*> fNodes( volTool.GetFaceNodes( iF ),
1669                                            volTool.GetFaceNodes( iF ) + nbNodes*iQ );
1670       while ( const SMDS_MeshElement* face = GetMeshDS()->FindFace( fNodes ))
1671       {
1672         // make triangles
1673         helper.SetElementsOnShape( false );
1674         vector< const SMDS_MeshElement* > triangles;
1675
1676         map<int, const SMDS_MeshNode*>::iterator iF_n = splitMethod._faceBaryNode.find(iF);
1677         if ( iF_n != splitMethod._faceBaryNode.end() )
1678         {
1679           for ( int iN = 0; iN < nbNodes*iQ; iN += iQ )
1680           {
1681             const SMDS_MeshNode* n1 = fNodes[iN];
1682             const SMDS_MeshNode *n2 = fNodes[(iN+iQ)%nbNodes*iQ];
1683             const SMDS_MeshNode *n3 = iF_n->second;
1684             if ( !volTool.IsFaceExternal( iF ))
1685               swap( n2, n3 );
1686             triangles.push_back( helper.AddFace( n1,n2,n3 ));
1687           }
1688         }
1689         else
1690         {
1691           // among possible triangles create ones discribed by split method
1692           const int* nInd = volTool.GetFaceNodesIndices( iF );
1693           int nbVariants = ( nbNodes == 4 ? 2 : nbNodes );
1694           int iCom = 0; // common node of triangle faces to split into
1695           list< TTriangleFacet > facets;
1696           for ( int iVar = 0; iVar < nbVariants; ++iVar, ++iCom )
1697           {
1698             TTriangleFacet t012( nInd[ iQ * ( iCom                )],
1699                                  nInd[ iQ * ( (iCom+1)%nbNodes )],
1700                                  nInd[ iQ * ( (iCom+2)%nbNodes )]);
1701             TTriangleFacet t023( nInd[ iQ * ( iCom                )],
1702                                  nInd[ iQ * ( (iCom+2)%nbNodes )],
1703                                  nInd[ iQ * ( (iCom+3)%nbNodes )]);
1704             if ( splitMethod.hasFacet( t012 ) && splitMethod.hasFacet( t023 ))
1705             {
1706               facets.push_back( t012 );
1707               facets.push_back( t023 );
1708               for ( int iLast = iCom+4; iLast < iCom+nbNodes; ++iLast )
1709                 facets.push_back( TTriangleFacet( nInd[ iQ * ( iCom             )],
1710                                                   nInd[ iQ * ((iLast-1)%nbNodes )],
1711                                                   nInd[ iQ * ((iLast  )%nbNodes )]));
1712               break;
1713             }
1714           }
1715           list< TTriangleFacet >::iterator facet = facets.begin();
1716           for ( ; facet != facets.end(); ++facet )
1717           {
1718             if ( !volTool.IsFaceExternal( iF ))
1719               swap( facet->_n2, facet->_n3 );
1720             triangles.push_back( helper.AddFace( volNodes[ facet->_n1 ],
1721                                                  volNodes[ facet->_n2 ],
1722                                                  volNodes[ facet->_n3 ]));
1723           }
1724         }
1725         // find submesh to add new triangles in
1726         if ( !fSubMesh || !fSubMesh->Contains( face ))
1727         {
1728           int shapeID = FindShape( face );
1729           fSubMesh = GetMeshDS()->MeshElements( shapeID );
1730         }
1731         for ( int i = 0; i < triangles.size(); ++i )
1732         {
1733           if ( !triangles[i] ) continue;
1734           if ( fSubMesh )
1735             fSubMesh->AddElement( triangles[i]);
1736           newElems.Append( triangles[i] );
1737         }
1738         ReplaceElemInGroups( face, triangles, GetMeshDS() );
1739         GetMeshDS()->RemoveFreeElement( face, fSubMesh, /*fromGroups=*/false );
1740       }
1741
1742     } // loop on volume faces to split them into triangles
1743
1744     GetMeshDS()->RemoveFreeElement( *elem, subMesh, /*fromGroups=*/false );
1745
1746   } // loop on volumes to split
1747
1748   myLastCreatedNodes = newNodes;
1749   myLastCreatedElems = newElems;
1750 }
1751
1752 //=======================================================================
1753 //function : AddToSameGroups
1754 //purpose  : add elemToAdd to the groups the elemInGroups belongs to
1755 //=======================================================================
1756
1757 void SMESH_MeshEditor::AddToSameGroups (const SMDS_MeshElement* elemToAdd,
1758                                         const SMDS_MeshElement* elemInGroups,
1759                                         SMESHDS_Mesh *          aMesh)
1760 {
1761   const set<SMESHDS_GroupBase*>& groups = aMesh->GetGroups();
1762   if (!groups.empty()) {
1763     set<SMESHDS_GroupBase*>::const_iterator grIt = groups.begin();
1764     for ( ; grIt != groups.end(); grIt++ ) {
1765       SMESHDS_Group* group = dynamic_cast<SMESHDS_Group*>( *grIt );
1766       if ( group && group->Contains( elemInGroups ))
1767         group->SMDSGroup().Add( elemToAdd );
1768     }
1769   }
1770 }
1771
1772
1773 //=======================================================================
1774 //function : RemoveElemFromGroups
1775 //purpose  : Remove removeelem to the groups the elemInGroups belongs to
1776 //=======================================================================
1777 void SMESH_MeshEditor::RemoveElemFromGroups (const SMDS_MeshElement* removeelem,
1778                                              SMESHDS_Mesh *          aMesh)
1779 {
1780   const set<SMESHDS_GroupBase*>& groups = aMesh->GetGroups();
1781   if (!groups.empty())
1782   {
1783     set<SMESHDS_GroupBase*>::const_iterator GrIt = groups.begin();
1784     for (; GrIt != groups.end(); GrIt++)
1785     {
1786       SMESHDS_Group* grp = dynamic_cast<SMESHDS_Group*>(*GrIt);
1787       if (!grp || grp->IsEmpty()) continue;
1788       grp->SMDSGroup().Remove(removeelem);
1789     }
1790   }
1791 }
1792
1793 //================================================================================
1794 /*!
1795  * \brief Replace elemToRm by elemToAdd in the all groups
1796  */
1797 //================================================================================
1798
1799 void SMESH_MeshEditor::ReplaceElemInGroups (const SMDS_MeshElement* elemToRm,
1800                                             const SMDS_MeshElement* elemToAdd,
1801                                             SMESHDS_Mesh *          aMesh)
1802 {
1803   const set<SMESHDS_GroupBase*>& groups = aMesh->GetGroups();
1804   if (!groups.empty()) {
1805     set<SMESHDS_GroupBase*>::const_iterator grIt = groups.begin();
1806     for ( ; grIt != groups.end(); grIt++ ) {
1807       SMESHDS_Group* group = dynamic_cast<SMESHDS_Group*>( *grIt );
1808       if ( group && group->SMDSGroup().Remove( elemToRm ) && elemToAdd )
1809         group->SMDSGroup().Add( elemToAdd );
1810     }
1811   }
1812 }
1813
1814 //================================================================================
1815 /*!
1816  * \brief Replace elemToRm by elemToAdd in the all groups
1817  */
1818 //================================================================================
1819
1820 void SMESH_MeshEditor::ReplaceElemInGroups (const SMDS_MeshElement*                elemToRm,
1821                                             const vector<const SMDS_MeshElement*>& elemToAdd,
1822                                             SMESHDS_Mesh *                         aMesh)
1823 {
1824   const set<SMESHDS_GroupBase*>& groups = aMesh->GetGroups();
1825   if (!groups.empty())
1826   {
1827     set<SMESHDS_GroupBase*>::const_iterator grIt = groups.begin();
1828     for ( ; grIt != groups.end(); grIt++ ) {
1829       SMESHDS_Group* group = dynamic_cast<SMESHDS_Group*>( *grIt );
1830       if ( group && group->SMDSGroup().Remove( elemToRm ) )
1831         for ( int i = 0; i < elemToAdd.size(); ++i )
1832           group->SMDSGroup().Add( elemToAdd[ i ] );
1833     }
1834   }
1835 }
1836
1837 //=======================================================================
1838 //function : QuadToTri
1839 //purpose  : Cut quadrangles into triangles.
1840 //           theCrit is used to select a diagonal to cut
1841 //=======================================================================
1842
1843 bool SMESH_MeshEditor::QuadToTri (TIDSortedElemSet & theElems,
1844                                   const bool         the13Diag)
1845 {
1846   myLastCreatedElems.Clear();
1847   myLastCreatedNodes.Clear();
1848
1849   MESSAGE( "::QuadToTri()" );
1850
1851   SMESHDS_Mesh * aMesh = GetMeshDS();
1852
1853   Handle(Geom_Surface) surface;
1854   SMESH_MesherHelper   helper( *GetMesh() );
1855
1856   TIDSortedElemSet::iterator itElem;
1857   for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
1858     const SMDS_MeshElement* elem = *itElem;
1859     if ( !elem || elem->GetType() != SMDSAbs_Face )
1860       continue;
1861     bool isquad = elem->NbNodes()==4 || elem->NbNodes()==8;
1862     if(!isquad) continue;
1863
1864     if(elem->NbNodes()==4) {
1865       // retrieve element nodes
1866       const SMDS_MeshNode* aNodes [4];
1867       SMDS_ElemIteratorPtr itN = elem->nodesIterator();
1868       int i = 0;
1869       while ( itN->more() )
1870         aNodes[ i++ ] = static_cast<const SMDS_MeshNode*>( itN->next() );
1871
1872       int aShapeId = FindShape( elem );
1873       const SMDS_MeshElement* newElem1 = 0;
1874       const SMDS_MeshElement* newElem2 = 0;
1875       if ( the13Diag ) {
1876         newElem1 = aMesh->AddFace( aNodes[2], aNodes[0], aNodes[1] );
1877         newElem2 = aMesh->AddFace( aNodes[2], aNodes[3], aNodes[0] );
1878       }
1879       else {
1880         newElem1 = aMesh->AddFace( aNodes[3], aNodes[0], aNodes[1] );
1881         newElem2 = aMesh->AddFace( aNodes[3], aNodes[1], aNodes[2] );
1882       }
1883       myLastCreatedElems.Append(newElem1);
1884       myLastCreatedElems.Append(newElem2);
1885       // put a new triangle on the same shape and add to the same groups
1886       if ( aShapeId )
1887         {
1888           aMesh->SetMeshElementOnShape( newElem1, aShapeId );
1889           aMesh->SetMeshElementOnShape( newElem2, aShapeId );
1890         }
1891       AddToSameGroups( newElem1, elem, aMesh );
1892       AddToSameGroups( newElem2, elem, aMesh );
1893       //aMesh->RemoveFreeElement(elem, aMesh->MeshElements(aShapeId), true);
1894       aMesh->RemoveElement( elem );
1895     }
1896
1897     // Quadratic quadrangle
1898
1899     if( elem->NbNodes()==8 && elem->IsQuadratic() ) {
1900
1901       // get surface elem is on
1902       int aShapeId = FindShape( elem );
1903       if ( aShapeId != helper.GetSubShapeID() ) {
1904         surface.Nullify();
1905         TopoDS_Shape shape;
1906         if ( aShapeId > 0 )
1907           shape = aMesh->IndexToShape( aShapeId );
1908         if ( !shape.IsNull() && shape.ShapeType() == TopAbs_FACE ) {
1909           TopoDS_Face face = TopoDS::Face( shape );
1910           surface = BRep_Tool::Surface( face );
1911           if ( !surface.IsNull() )
1912             helper.SetSubShape( shape );
1913         }
1914       }
1915
1916       const SMDS_MeshNode* aNodes [8];
1917       const SMDS_MeshNode* inFaceNode = 0;
1918       SMDS_ElemIteratorPtr itN = elem->nodesIterator();
1919       int i = 0;
1920       while ( itN->more() ) {
1921         aNodes[ i++ ] = static_cast<const SMDS_MeshNode*>( itN->next() );
1922         if ( !inFaceNode && helper.GetNodeUVneedInFaceNode() &&
1923              aNodes[ i-1 ]->GetPosition()->GetTypeOfPosition() == SMDS_TOP_FACE )
1924         {
1925           inFaceNode = aNodes[ i-1 ];
1926         }
1927       }
1928
1929       // find middle point for (0,1,2,3)
1930       // and create a node in this point;
1931       gp_XYZ p( 0,0,0 );
1932       if ( surface.IsNull() ) {
1933         for(i=0; i<4; i++)
1934           p += gp_XYZ(aNodes[i]->X(), aNodes[i]->Y(), aNodes[i]->Z() );
1935         p /= 4;
1936       }
1937       else {
1938         TopoDS_Face geomFace = TopoDS::Face( helper.GetSubShape() );
1939         gp_XY uv( 0,0 );
1940         for(i=0; i<4; i++)
1941           uv += helper.GetNodeUV( geomFace, aNodes[i], inFaceNode );
1942         uv /= 4.;
1943         p = surface->Value( uv.X(), uv.Y() ).XYZ();
1944       }
1945       const SMDS_MeshNode* newN = aMesh->AddNode( p.X(), p.Y(), p.Z() );
1946       myLastCreatedNodes.Append(newN);
1947
1948       // create a new element
1949       const SMDS_MeshElement* newElem1 = 0;
1950       const SMDS_MeshElement* newElem2 = 0;
1951       const SMDS_MeshNode* N[6];
1952       if ( the13Diag ) {
1953         N[0] = aNodes[0];
1954         N[1] = aNodes[1];
1955         N[2] = aNodes[2];
1956         N[3] = aNodes[4];
1957         N[4] = aNodes[5];
1958         N[5] = newN;
1959         newElem1 = aMesh->AddFace(aNodes[2], aNodes[3], aNodes[0],
1960                                   aNodes[6], aNodes[7], newN );
1961         newElem2 = aMesh->AddFace(aNodes[2], aNodes[0], aNodes[1],
1962                                   newN,      aNodes[4], aNodes[5] );
1963       }
1964       else {
1965         N[0] = aNodes[1];
1966         N[1] = aNodes[2];
1967         N[2] = aNodes[3];
1968         N[3] = aNodes[5];
1969         N[4] = aNodes[6];
1970         N[5] = newN;
1971         newElem1 = aMesh->AddFace(aNodes[3], aNodes[0], aNodes[1],
1972                                   aNodes[7], aNodes[4], newN );
1973         newElem2 = aMesh->AddFace(aNodes[3], aNodes[1], aNodes[2],
1974                                   newN,      aNodes[5], aNodes[6] );
1975       }
1976       myLastCreatedElems.Append(newElem1);
1977       myLastCreatedElems.Append(newElem2);
1978       // put a new triangle on the same shape and add to the same groups
1979       if ( aShapeId )
1980         {
1981           aMesh->SetMeshElementOnShape( newElem1, aShapeId );
1982           aMesh->SetMeshElementOnShape( newElem2, aShapeId );
1983         }
1984       AddToSameGroups( newElem1, elem, aMesh );
1985       AddToSameGroups( newElem2, elem, aMesh );
1986       aMesh->RemoveElement( elem );
1987     }
1988   }
1989
1990   return true;
1991 }
1992
1993 //=======================================================================
1994 //function : getAngle
1995 //purpose  :
1996 //=======================================================================
1997
1998 double getAngle(const SMDS_MeshElement * tr1,
1999                 const SMDS_MeshElement * tr2,
2000                 const SMDS_MeshNode *    n1,
2001                 const SMDS_MeshNode *    n2)
2002 {
2003   double angle = 2*PI; // bad angle
2004
2005   // get normals
2006   SMESH::Controls::TSequenceOfXYZ P1, P2;
2007   if ( !SMESH::Controls::NumericalFunctor::GetPoints( tr1, P1 ) ||
2008        !SMESH::Controls::NumericalFunctor::GetPoints( tr2, P2 ))
2009     return angle;
2010   gp_Vec N1,N2;
2011   if(!tr1->IsQuadratic())
2012     N1 = gp_Vec( P1(2) - P1(1) ) ^ gp_Vec( P1(3) - P1(1) );
2013   else
2014     N1 = gp_Vec( P1(3) - P1(1) ) ^ gp_Vec( P1(5) - P1(1) );
2015   if ( N1.SquareMagnitude() <= gp::Resolution() )
2016     return angle;
2017   if(!tr2->IsQuadratic())
2018     N2 = gp_Vec( P2(2) - P2(1) ) ^ gp_Vec( P2(3) - P2(1) );
2019   else
2020     N2 = gp_Vec( P2(3) - P2(1) ) ^ gp_Vec( P2(5) - P2(1) );
2021   if ( N2.SquareMagnitude() <= gp::Resolution() )
2022     return angle;
2023
2024   // find the first diagonal node n1 in the triangles:
2025   // take in account a diagonal link orientation
2026   const SMDS_MeshElement *nFirst[2], *tr[] = { tr1, tr2 };
2027   for ( int t = 0; t < 2; t++ ) {
2028     SMDS_ElemIteratorPtr it = tr[ t ]->nodesIterator();
2029     int i = 0, iDiag = -1;
2030     while ( it->more()) {
2031       const SMDS_MeshElement *n = it->next();
2032       if ( n == n1 || n == n2 ) {
2033         if ( iDiag < 0)
2034           iDiag = i;
2035         else {
2036           if ( i - iDiag == 1 )
2037             nFirst[ t ] = ( n == n1 ? n2 : n1 );
2038           else
2039             nFirst[ t ] = n;
2040           break;
2041         }
2042       }
2043       i++;
2044     }
2045   }
2046   if ( nFirst[ 0 ] == nFirst[ 1 ] )
2047     N2.Reverse();
2048
2049   angle = N1.Angle( N2 );
2050   //SCRUTE( angle );
2051   return angle;
2052 }
2053
2054 // =================================================
2055 // class generating a unique ID for a pair of nodes
2056 // and able to return nodes by that ID
2057 // =================================================
2058 class LinkID_Gen {
2059 public:
2060
2061   LinkID_Gen( const SMESHDS_Mesh* theMesh )
2062     :myMesh( theMesh ), myMaxID( theMesh->MaxNodeID() + 1)
2063   {}
2064
2065   long GetLinkID (const SMDS_MeshNode * n1,
2066                   const SMDS_MeshNode * n2) const
2067   {
2068     return ( Min(n1->GetID(),n2->GetID()) * myMaxID + Max(n1->GetID(),n2->GetID()));
2069   }
2070
2071   bool GetNodes (const long             theLinkID,
2072                  const SMDS_MeshNode* & theNode1,
2073                  const SMDS_MeshNode* & theNode2) const
2074   {
2075     theNode1 = myMesh->FindNode( theLinkID / myMaxID );
2076     if ( !theNode1 ) return false;
2077     theNode2 = myMesh->FindNode( theLinkID % myMaxID );
2078     if ( !theNode2 ) return false;
2079     return true;
2080   }
2081
2082 private:
2083   LinkID_Gen();
2084   const SMESHDS_Mesh* myMesh;
2085   long                myMaxID;
2086 };
2087
2088
2089 //=======================================================================
2090 //function : TriToQuad
2091 //purpose  : Fuse neighbour triangles into quadrangles.
2092 //           theCrit is used to select a neighbour to fuse with.
2093 //           theMaxAngle is a max angle between element normals at which
2094 //           fusion is still performed.
2095 //=======================================================================
2096
2097 bool SMESH_MeshEditor::TriToQuad (TIDSortedElemSet &                   theElems,
2098                                   SMESH::Controls::NumericalFunctorPtr theCrit,
2099                                   const double                         theMaxAngle)
2100 {
2101   myLastCreatedElems.Clear();
2102   myLastCreatedNodes.Clear();
2103
2104   MESSAGE( "::TriToQuad()" );
2105
2106   if ( !theCrit.get() )
2107     return false;
2108
2109   SMESHDS_Mesh * aMesh = GetMeshDS();
2110
2111   // Prepare data for algo: build
2112   // 1. map of elements with their linkIDs
2113   // 2. map of linkIDs with their elements
2114
2115   map< SMESH_TLink, list< const SMDS_MeshElement* > > mapLi_listEl;
2116   map< SMESH_TLink, list< const SMDS_MeshElement* > >::iterator itLE;
2117   map< const SMDS_MeshElement*, set< SMESH_TLink > >  mapEl_setLi;
2118   map< const SMDS_MeshElement*, set< SMESH_TLink > >::iterator itEL;
2119
2120   TIDSortedElemSet::iterator itElem;
2121   for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
2122     const SMDS_MeshElement* elem = *itElem;
2123     if(!elem || elem->GetType() != SMDSAbs_Face ) continue;
2124     bool IsTria = elem->NbNodes()==3 || (elem->NbNodes()==6 && elem->IsQuadratic());
2125     if(!IsTria) continue;
2126
2127     // retrieve element nodes
2128     const SMDS_MeshNode* aNodes [4];
2129     SMDS_ElemIteratorPtr itN = elem->nodesIterator();
2130     int i = 0;
2131     while ( i<3 )
2132       aNodes[ i++ ] = cast2Node( itN->next() );
2133     aNodes[ 3 ] = aNodes[ 0 ];
2134
2135     // fill maps
2136     for ( i = 0; i < 3; i++ ) {
2137       SMESH_TLink link( aNodes[i], aNodes[i+1] );
2138       // check if elements sharing a link can be fused
2139       itLE = mapLi_listEl.find( link );
2140       if ( itLE != mapLi_listEl.end() ) {
2141         if ((*itLE).second.size() > 1 ) // consider only 2 elems adjacent by a link
2142           continue;
2143         const SMDS_MeshElement* elem2 = (*itLE).second.front();
2144         //if ( FindShape( elem ) != FindShape( elem2 ))
2145         //  continue; // do not fuse triangles laying on different shapes
2146         if ( getAngle( elem, elem2, aNodes[i], aNodes[i+1] ) > theMaxAngle )
2147           continue; // avoid making badly shaped quads
2148         (*itLE).second.push_back( elem );
2149       }
2150       else {
2151         mapLi_listEl[ link ].push_back( elem );
2152       }
2153       mapEl_setLi [ elem ].insert( link );
2154     }
2155   }
2156   // Clean the maps from the links shared by a sole element, ie
2157   // links to which only one element is bound in mapLi_listEl
2158
2159   for ( itLE = mapLi_listEl.begin(); itLE != mapLi_listEl.end(); itLE++ ) {
2160     int nbElems = (*itLE).second.size();
2161     if ( nbElems < 2  ) {
2162       const SMDS_MeshElement* elem = (*itLE).second.front();
2163       SMESH_TLink link = (*itLE).first;
2164       mapEl_setLi[ elem ].erase( link );
2165       if ( mapEl_setLi[ elem ].empty() )
2166         mapEl_setLi.erase( elem );
2167     }
2168   }
2169
2170   // Algo: fuse triangles into quadrangles
2171
2172   while ( ! mapEl_setLi.empty() ) {
2173     // Look for the start element:
2174     // the element having the least nb of shared links
2175     const SMDS_MeshElement* startElem = 0;
2176     int minNbLinks = 4;
2177     for ( itEL = mapEl_setLi.begin(); itEL != mapEl_setLi.end(); itEL++ ) {
2178       int nbLinks = (*itEL).second.size();
2179       if ( nbLinks < minNbLinks ) {
2180         startElem = (*itEL).first;
2181         minNbLinks = nbLinks;
2182         if ( minNbLinks == 1 )
2183           break;
2184       }
2185     }
2186
2187     // search elements to fuse starting from startElem or links of elements
2188     // fused earlyer - startLinks
2189     list< SMESH_TLink > startLinks;
2190     while ( startElem || !startLinks.empty() ) {
2191       while ( !startElem && !startLinks.empty() ) {
2192         // Get an element to start, by a link
2193         SMESH_TLink linkId = startLinks.front();
2194         startLinks.pop_front();
2195         itLE = mapLi_listEl.find( linkId );
2196         if ( itLE != mapLi_listEl.end() ) {
2197           list< const SMDS_MeshElement* > & listElem = (*itLE).second;
2198           list< const SMDS_MeshElement* >::iterator itE = listElem.begin();
2199           for ( ; itE != listElem.end() ; itE++ )
2200             if ( mapEl_setLi.find( (*itE) ) != mapEl_setLi.end() )
2201               startElem = (*itE);
2202           mapLi_listEl.erase( itLE );
2203         }
2204       }
2205
2206       if ( startElem ) {
2207         // Get candidates to be fused
2208         const SMDS_MeshElement *tr1 = startElem, *tr2 = 0, *tr3 = 0;
2209         const SMESH_TLink *link12, *link13;
2210         startElem = 0;
2211         ASSERT( mapEl_setLi.find( tr1 ) != mapEl_setLi.end() );
2212         set< SMESH_TLink >& setLi = mapEl_setLi[ tr1 ];
2213         ASSERT( !setLi.empty() );
2214         set< SMESH_TLink >::iterator itLi;
2215         for ( itLi = setLi.begin(); itLi != setLi.end(); itLi++ )
2216         {
2217           const SMESH_TLink & link = (*itLi);
2218           itLE = mapLi_listEl.find( link );
2219           if ( itLE == mapLi_listEl.end() )
2220             continue;
2221
2222           const SMDS_MeshElement* elem = (*itLE).second.front();
2223           if ( elem == tr1 )
2224             elem = (*itLE).second.back();
2225           mapLi_listEl.erase( itLE );
2226           if ( mapEl_setLi.find( elem ) == mapEl_setLi.end())
2227             continue;
2228           if ( tr2 ) {
2229             tr3 = elem;
2230             link13 = &link;
2231           }
2232           else {
2233             tr2 = elem;
2234             link12 = &link;
2235           }
2236
2237           // add other links of elem to list of links to re-start from
2238           set< SMESH_TLink >& links = mapEl_setLi[ elem ];
2239           set< SMESH_TLink >::iterator it;
2240           for ( it = links.begin(); it != links.end(); it++ ) {
2241             const SMESH_TLink& link2 = (*it);
2242             if ( link2 != link )
2243               startLinks.push_back( link2 );
2244           }
2245         }
2246
2247         // Get nodes of possible quadrangles
2248         const SMDS_MeshNode *n12 [4], *n13 [4];
2249         bool Ok12 = false, Ok13 = false;
2250         const SMDS_MeshNode *linkNode1, *linkNode2;
2251         if(tr2) {
2252           linkNode1 = link12->first;
2253           linkNode2 = link12->second;
2254           if ( tr2 && getQuadrangleNodes( n12, linkNode1, linkNode2, tr1, tr2 ))
2255             Ok12 = true;
2256         }
2257         if(tr3) {
2258           linkNode1 = link13->first;
2259           linkNode2 = link13->second;
2260           if ( tr3 && getQuadrangleNodes( n13, linkNode1, linkNode2, tr1, tr3 ))
2261             Ok13 = true;
2262         }
2263
2264         // Choose a pair to fuse
2265         if ( Ok12 && Ok13 ) {
2266           SMDS_FaceOfNodes quad12 ( n12[ 0 ], n12[ 1 ], n12[ 2 ], n12[ 3 ] );
2267           SMDS_FaceOfNodes quad13 ( n13[ 0 ], n13[ 1 ], n13[ 2 ], n13[ 3 ] );
2268           double aBadRate12 = getBadRate( &quad12, theCrit );
2269           double aBadRate13 = getBadRate( &quad13, theCrit );
2270           if (  aBadRate13 < aBadRate12 )
2271             Ok12 = false;
2272           else
2273             Ok13 = false;
2274         }
2275
2276         // Make quadrangles
2277         // and remove fused elems and removed links from the maps
2278         mapEl_setLi.erase( tr1 );
2279         if ( Ok12 ) {
2280           mapEl_setLi.erase( tr2 );
2281           mapLi_listEl.erase( *link12 );
2282           if(tr1->NbNodes()==3) {
2283             const SMDS_MeshElement* newElem = 0;
2284             newElem = aMesh->AddFace(n12[0], n12[1], n12[2], n12[3] );
2285             myLastCreatedElems.Append(newElem);
2286             AddToSameGroups( newElem, tr1, aMesh );
2287             int aShapeId = tr1->getshapeId();
2288             if ( aShapeId )
2289               {
2290                 aMesh->SetMeshElementOnShape( newElem, aShapeId );
2291               }
2292             aMesh->RemoveElement( tr1 );
2293             aMesh->RemoveElement( tr2 );
2294           }
2295           else {
2296             const SMDS_MeshNode* N1 [6];
2297             const SMDS_MeshNode* N2 [6];
2298             GetNodesFromTwoTria(tr1,tr2,N1,N2);
2299             // now we receive following N1 and N2 (using numeration as above image)
2300             // tria1 : (1 2 4 5 9 7)  and  tria2 : (3 4 2 8 9 6)
2301             // i.e. first nodes from both arrays determ new diagonal
2302             const SMDS_MeshNode* aNodes[8];
2303             aNodes[0] = N1[0];
2304             aNodes[1] = N1[1];
2305             aNodes[2] = N2[0];
2306             aNodes[3] = N2[1];
2307             aNodes[4] = N1[3];
2308             aNodes[5] = N2[5];
2309             aNodes[6] = N2[3];
2310             aNodes[7] = N1[5];
2311             const SMDS_MeshElement* newElem = 0;
2312             newElem = aMesh->AddFace(aNodes[0], aNodes[1], aNodes[2], aNodes[3],
2313                                      aNodes[4], aNodes[5], aNodes[6], aNodes[7]);
2314             myLastCreatedElems.Append(newElem);
2315             AddToSameGroups( newElem, tr1, aMesh );
2316             int aShapeId = tr1->getshapeId();
2317             if ( aShapeId )
2318               {
2319                 aMesh->SetMeshElementOnShape( newElem, aShapeId );
2320               }
2321             aMesh->RemoveElement( tr1 );
2322             aMesh->RemoveElement( tr2 );
2323             // remove middle node (9)
2324             GetMeshDS()->RemoveNode( N1[4] );
2325           }
2326         }
2327         else if ( Ok13 ) {
2328           mapEl_setLi.erase( tr3 );
2329           mapLi_listEl.erase( *link13 );
2330           if(tr1->NbNodes()==3) {
2331             const SMDS_MeshElement* newElem = 0;
2332             newElem = aMesh->AddFace(n13[0], n13[1], n13[2], n13[3] );
2333             myLastCreatedElems.Append(newElem);
2334             AddToSameGroups( newElem, tr1, aMesh );
2335             int aShapeId = tr1->getshapeId();
2336             if ( aShapeId )
2337               {
2338                 aMesh->SetMeshElementOnShape( newElem, aShapeId );
2339               }
2340             aMesh->RemoveElement( tr1 );
2341             aMesh->RemoveElement( tr3 );
2342           }
2343           else {
2344             const SMDS_MeshNode* N1 [6];
2345             const SMDS_MeshNode* N2 [6];
2346             GetNodesFromTwoTria(tr1,tr3,N1,N2);
2347             // now we receive following N1 and N2 (using numeration as above image)
2348             // tria1 : (1 2 4 5 9 7)  and  tria2 : (3 4 2 8 9 6)
2349             // i.e. first nodes from both arrays determ new diagonal
2350             const SMDS_MeshNode* aNodes[8];
2351             aNodes[0] = N1[0];
2352             aNodes[1] = N1[1];
2353             aNodes[2] = N2[0];
2354             aNodes[3] = N2[1];
2355             aNodes[4] = N1[3];
2356             aNodes[5] = N2[5];
2357             aNodes[6] = N2[3];
2358             aNodes[7] = N1[5];
2359             const SMDS_MeshElement* newElem = 0;
2360             newElem = aMesh->AddFace(aNodes[0], aNodes[1], aNodes[2], aNodes[3],
2361                                      aNodes[4], aNodes[5], aNodes[6], aNodes[7]);
2362             myLastCreatedElems.Append(newElem);
2363             AddToSameGroups( newElem, tr1, aMesh );
2364             int aShapeId = tr1->getshapeId();
2365             if ( aShapeId )
2366               {
2367                 aMesh->SetMeshElementOnShape( newElem, aShapeId );
2368               }
2369             aMesh->RemoveElement( tr1 );
2370             aMesh->RemoveElement( tr3 );
2371             // remove middle node (9)
2372             GetMeshDS()->RemoveNode( N1[4] );
2373           }
2374         }
2375
2376         // Next element to fuse: the rejected one
2377         if ( tr3 )
2378           startElem = Ok12 ? tr3 : tr2;
2379
2380       } // if ( startElem )
2381     } // while ( startElem || !startLinks.empty() )
2382   } // while ( ! mapEl_setLi.empty() )
2383
2384   return true;
2385 }
2386
2387
2388 /*#define DUMPSO(txt) \
2389 //  cout << txt << endl;
2390 //=============================================================================
2391 //
2392 //
2393 //
2394 //=============================================================================
2395 static void swap( int i1, int i2, int idNodes[], gp_Pnt P[] )
2396 {
2397 if ( i1 == i2 )
2398 return;
2399 int tmp = idNodes[ i1 ];
2400 idNodes[ i1 ] = idNodes[ i2 ];
2401 idNodes[ i2 ] = tmp;
2402 gp_Pnt Ptmp = P[ i1 ];
2403 P[ i1 ] = P[ i2 ];
2404 P[ i2 ] = Ptmp;
2405 DUMPSO( i1 << "(" << idNodes[ i2 ] << ") <-> " << i2 << "(" << idNodes[ i1 ] << ")");
2406 }
2407
2408 //=======================================================================
2409 //function : SortQuadNodes
2410 //purpose  : Set 4 nodes of a quadrangle face in a good order.
2411 //           Swap 1<->2 or 2<->3 nodes and correspondingly return
2412 //           1 or 2 else 0.
2413 //=======================================================================
2414
2415 int SMESH_MeshEditor::SortQuadNodes (const SMDS_Mesh * theMesh,
2416 int               idNodes[] )
2417 {
2418   gp_Pnt P[4];
2419   int i;
2420   for ( i = 0; i < 4; i++ ) {
2421     const SMDS_MeshNode *n = theMesh->FindNode( idNodes[i] );
2422     if ( !n ) return 0;
2423     P[ i ].SetCoord( n->X(), n->Y(), n->Z() );
2424   }
2425
2426   gp_Vec V1(P[0], P[1]);
2427   gp_Vec V2(P[0], P[2]);
2428   gp_Vec V3(P[0], P[3]);
2429
2430   gp_Vec Cross1 = V1 ^ V2;
2431   gp_Vec Cross2 = V2 ^ V3;
2432
2433   i = 0;
2434   if (Cross1.Dot(Cross2) < 0)
2435   {
2436     Cross1 = V2 ^ V1;
2437     Cross2 = V1 ^ V3;
2438
2439     if (Cross1.Dot(Cross2) < 0)
2440       i = 2;
2441     else
2442       i = 1;
2443     swap ( i, i + 1, idNodes, P );
2444
2445     //     for ( int ii = 0; ii < 4; ii++ ) {
2446     //       const SMDS_MeshNode *n = theMesh->FindNode( idNodes[ii] );
2447     //       DUMPSO( ii << "(" << idNodes[ii] <<") : "<<n->X()<<" "<<n->Y()<<" "<<n->Z());
2448     //     }
2449   }
2450   return i;
2451 }
2452
2453 //=======================================================================
2454 //function : SortHexaNodes
2455 //purpose  : Set 8 nodes of a hexahedron in a good order.
2456 //           Return success status
2457 //=======================================================================
2458
2459 bool SMESH_MeshEditor::SortHexaNodes (const SMDS_Mesh * theMesh,
2460                                       int               idNodes[] )
2461 {
2462   gp_Pnt P[8];
2463   int i;
2464   DUMPSO( "INPUT: ========================================");
2465   for ( i = 0; i < 8; i++ ) {
2466     const SMDS_MeshNode *n = theMesh->FindNode( idNodes[i] );
2467     if ( !n ) return false;
2468     P[ i ].SetCoord( n->X(), n->Y(), n->Z() );
2469     DUMPSO( i << "(" << idNodes[i] <<") : "<<n->X()<<" "<<n->Y()<<" "<<n->Z());
2470   }
2471   DUMPSO( "========================================");
2472
2473
2474   set<int> faceNodes;  // ids of bottom face nodes, to be found
2475   set<int> checkedId1; // ids of tried 2-nd nodes
2476   Standard_Real leastDist = DBL_MAX; // dist of the 4-th node from 123 plane
2477   const Standard_Real tol = 1.e-6;   // tolerance to find nodes in plane
2478   int iMin, iLoop1 = 0;
2479
2480   // Loop to try the 2-nd nodes
2481
2482   while ( leastDist > DBL_MIN && ++iLoop1 < 8 )
2483   {
2484     // Find not checked 2-nd node
2485     for ( i = 1; i < 8; i++ )
2486       if ( checkedId1.find( idNodes[i] ) == checkedId1.end() ) {
2487         int id1 = idNodes[i];
2488         swap ( 1, i, idNodes, P );
2489         checkedId1.insert ( id1 );
2490         break;
2491       }
2492
2493     // Find the 3-d node so that 1-2-3 triangle to be on a hexa face,
2494     // ie that all but meybe one (id3 which is on the same face) nodes
2495     // lay on the same side from the triangle plane.
2496
2497     bool manyInPlane = false; // more than 4 nodes lay in plane
2498     int iLoop2 = 0;
2499     while ( ++iLoop2 < 6 ) {
2500
2501       // get 1-2-3 plane coeffs
2502       Standard_Real A, B, C, D;
2503       gp_Vec N = gp_Vec (P[0], P[1]).Crossed( gp_Vec (P[0], P[2]) );
2504       if ( N.SquareMagnitude() > gp::Resolution() )
2505       {
2506         gp_Pln pln ( P[0], N );
2507         pln.Coefficients( A, B, C, D );
2508
2509         // find the node (iMin) closest to pln
2510         Standard_Real dist[ 8 ], minDist = DBL_MAX;
2511         set<int> idInPln;
2512         for ( i = 3; i < 8; i++ ) {
2513           dist[i] = A * P[i].X() + B * P[i].Y() + C * P[i].Z() + D;
2514           if ( fabs( dist[i] ) < minDist ) {
2515             minDist = fabs( dist[i] );
2516             iMin = i;
2517           }
2518           if ( fabs( dist[i] ) <= tol )
2519             idInPln.insert( idNodes[i] );
2520         }
2521
2522         // there should not be more than 4 nodes in bottom plane
2523         if ( idInPln.size() > 1 )
2524         {
2525           DUMPSO( "### idInPln.size() = " << idInPln.size());
2526           // idInPlane does not contain the first 3 nodes
2527           if ( manyInPlane || idInPln.size() == 5)
2528             return false; // all nodes in one plane
2529           manyInPlane = true;
2530
2531           // set the 1-st node to be not in plane
2532           for ( i = 3; i < 8; i++ ) {
2533             if ( idInPln.find( idNodes[ i ] ) == idInPln.end() ) {
2534               DUMPSO( "### Reset 0-th node");
2535               swap( 0, i, idNodes, P );
2536               break;
2537             }
2538           }
2539
2540           // reset to re-check second nodes
2541           leastDist = DBL_MAX;
2542           faceNodes.clear();
2543           checkedId1.clear();
2544           iLoop1 = 0;
2545           break; // from iLoop2;
2546         }
2547
2548         // check that the other 4 nodes are on the same side
2549         bool sameSide = true;
2550         bool isNeg = dist[ iMin == 3 ? 4 : 3 ] <= 0.;
2551         for ( i = 3; sameSide && i < 8; i++ ) {
2552           if ( i != iMin )
2553             sameSide = ( isNeg == dist[i] <= 0.);
2554         }
2555
2556         // keep best solution
2557         if ( sameSide && minDist < leastDist ) {
2558           leastDist = minDist;
2559           faceNodes.clear();
2560           faceNodes.insert( idNodes[ 1 ] );
2561           faceNodes.insert( idNodes[ 2 ] );
2562           faceNodes.insert( idNodes[ iMin ] );
2563           DUMPSO( "loop " << iLoop2 << " id2 " << idNodes[ 1 ] << " id3 " << idNodes[ 2 ]
2564                   << " leastDist = " << leastDist);
2565           if ( leastDist <= DBL_MIN )
2566             break;
2567         }
2568       }
2569
2570       // set next 3-d node to check
2571       int iNext = 2 + iLoop2;
2572       if ( iNext < 8 ) {
2573         DUMPSO( "Try 2-nd");
2574         swap ( 2, iNext, idNodes, P );
2575       }
2576     } // while ( iLoop2 < 6 )
2577   } // iLoop1
2578
2579   if ( faceNodes.empty() ) return false;
2580
2581   // Put the faceNodes in proper places
2582   for ( i = 4; i < 8; i++ ) {
2583     if ( faceNodes.find( idNodes[ i ] ) != faceNodes.end() ) {
2584       // find a place to put
2585       int iTo = 1;
2586       while ( faceNodes.find( idNodes[ iTo ] ) != faceNodes.end() )
2587         iTo++;
2588       DUMPSO( "Set faceNodes");
2589       swap ( iTo, i, idNodes, P );
2590     }
2591   }
2592
2593
2594   // Set nodes of the found bottom face in good order
2595   DUMPSO( " Found bottom face: ");
2596   i = SortQuadNodes( theMesh, idNodes );
2597   if ( i ) {
2598     gp_Pnt Ptmp = P[ i ];
2599     P[ i ] = P[ i+1 ];
2600     P[ i+1 ] = Ptmp;
2601   }
2602   //   else
2603   //     for ( int ii = 0; ii < 4; ii++ ) {
2604   //       const SMDS_MeshNode *n = theMesh->FindNode( idNodes[ii] );
2605   //       DUMPSO( ii << "(" << idNodes[ii] <<") : "<<n->X()<<" "<<n->Y()<<" "<<n->Z());
2606   //    }
2607
2608   // Gravity center of the top and bottom faces
2609   gp_Pnt aGCb = ( P[0].XYZ() + P[1].XYZ() + P[2].XYZ() + P[3].XYZ() ) / 4.;
2610   gp_Pnt aGCt = ( P[4].XYZ() + P[5].XYZ() + P[6].XYZ() + P[7].XYZ() ) / 4.;
2611
2612   // Get direction from the bottom to the top face
2613   gp_Vec upDir ( aGCb, aGCt );
2614   Standard_Real upDirSize = upDir.Magnitude();
2615   if ( upDirSize <= gp::Resolution() ) return false;
2616   upDir / upDirSize;
2617
2618   // Assure that the bottom face normal points up
2619   gp_Vec Nb = gp_Vec (P[0], P[1]).Crossed( gp_Vec (P[0], P[2]) );
2620   Nb += gp_Vec (P[0], P[2]).Crossed( gp_Vec (P[0], P[3]) );
2621   if ( Nb.Dot( upDir ) < 0 ) {
2622     DUMPSO( "Reverse bottom face");
2623     swap( 1, 3, idNodes, P );
2624   }
2625
2626   // Find 5-th node - the one closest to the 1-st among the last 4 nodes.
2627   Standard_Real minDist = DBL_MAX;
2628   for ( i = 4; i < 8; i++ ) {
2629     // projection of P[i] to the plane defined by P[0] and upDir
2630     gp_Pnt Pp = P[i].Translated( upDir * ( upDir.Dot( gp_Vec( P[i], P[0] ))));
2631     Standard_Real sqDist = P[0].SquareDistance( Pp );
2632     if ( sqDist < minDist ) {
2633       minDist = sqDist;
2634       iMin = i;
2635     }
2636   }
2637   DUMPSO( "Set 4-th");
2638   swap ( 4, iMin, idNodes, P );
2639
2640   // Set nodes of the top face in good order
2641   DUMPSO( "Sort top face");
2642   i = SortQuadNodes( theMesh, &idNodes[4] );
2643   if ( i ) {
2644     i += 4;
2645     gp_Pnt Ptmp = P[ i ];
2646     P[ i ] = P[ i+1 ];
2647     P[ i+1 ] = Ptmp;
2648   }
2649
2650   // Assure that direction of the top face normal is from the bottom face
2651   gp_Vec Nt = gp_Vec (P[4], P[5]).Crossed( gp_Vec (P[4], P[6]) );
2652   Nt += gp_Vec (P[4], P[6]).Crossed( gp_Vec (P[4], P[7]) );
2653   if ( Nt.Dot( upDir ) < 0 ) {
2654     DUMPSO( "Reverse top face");
2655     swap( 5, 7, idNodes, P );
2656   }
2657
2658   //   DUMPSO( "OUTPUT: ========================================");
2659   //   for ( i = 0; i < 8; i++ ) {
2660   //     float *p = ugrid->GetPoint(idNodes[i]);
2661   //     DUMPSO( i << "(" << idNodes[i] << ") : " << p[0] << " " << p[1] << " " << p[2]);
2662   //   }
2663
2664   return true;
2665 }*/
2666
2667 //================================================================================
2668 /*!
2669  * \brief Return nodes linked to the given one
2670  * \param theNode - the node
2671  * \param linkedNodes - the found nodes
2672  * \param type - the type of elements to check
2673  *
2674  * Medium nodes are ignored
2675  */
2676 //================================================================================
2677
2678 void SMESH_MeshEditor::GetLinkedNodes( const SMDS_MeshNode* theNode,
2679                                        TIDSortedElemSet &   linkedNodes,
2680                                        SMDSAbs_ElementType  type )
2681 {
2682   SMDS_ElemIteratorPtr elemIt = theNode->GetInverseElementIterator(type);
2683   while ( elemIt->more() )
2684   {
2685     const SMDS_MeshElement* elem = elemIt->next();
2686     if(elem->GetType() == SMDSAbs_0DElement)
2687       continue;
2688     
2689     SMDS_ElemIteratorPtr nodeIt = elem->nodesIterator();
2690     if ( elem->GetType() == SMDSAbs_Volume )
2691     {
2692       SMDS_VolumeTool vol( elem );
2693       while ( nodeIt->more() ) {
2694         const SMDS_MeshNode* n = cast2Node( nodeIt->next() );
2695         if ( theNode != n && vol.IsLinked( theNode, n ))
2696           linkedNodes.insert( n );
2697       }
2698     }
2699     else
2700     {
2701       for ( int i = 0; nodeIt->more(); ++i ) {
2702         const SMDS_MeshNode* n = cast2Node( nodeIt->next() );
2703         if ( n == theNode ) {
2704           int iBefore = i - 1;
2705           int iAfter  = i + 1;
2706           if ( elem->IsQuadratic() ) {
2707             int nb = elem->NbNodes() / 2;
2708             iAfter  = SMESH_MesherHelper::WrapIndex( iAfter, nb );
2709             iBefore = SMESH_MesherHelper::WrapIndex( iBefore, nb );
2710           }
2711           linkedNodes.insert( elem->GetNodeWrap( iAfter ));
2712           linkedNodes.insert( elem->GetNodeWrap( iBefore ));
2713         }
2714       }
2715     }
2716   }
2717 }
2718
2719 //=======================================================================
2720 //function : laplacianSmooth
2721 //purpose  : pulls theNode toward the center of surrounding nodes directly
2722 //           connected to that node along an element edge
2723 //=======================================================================
2724
2725 void laplacianSmooth(const SMDS_MeshNode*                 theNode,
2726                      const Handle(Geom_Surface)&          theSurface,
2727                      map< const SMDS_MeshNode*, gp_XY* >& theUVMap)
2728 {
2729   // find surrounding nodes
2730
2731   TIDSortedElemSet nodeSet;
2732   SMESH_MeshEditor::GetLinkedNodes( theNode, nodeSet, SMDSAbs_Face );
2733
2734   // compute new coodrs
2735
2736   double coord[] = { 0., 0., 0. };
2737   TIDSortedElemSet::iterator nodeSetIt = nodeSet.begin();
2738   for ( ; nodeSetIt != nodeSet.end(); nodeSetIt++ ) {
2739     const SMDS_MeshNode* node = cast2Node(*nodeSetIt);
2740     if ( theSurface.IsNull() ) { // smooth in 3D
2741       coord[0] += node->X();
2742       coord[1] += node->Y();
2743       coord[2] += node->Z();
2744     }
2745     else { // smooth in 2D
2746       ASSERT( theUVMap.find( node ) != theUVMap.end() );
2747       gp_XY* uv = theUVMap[ node ];
2748       coord[0] += uv->X();
2749       coord[1] += uv->Y();
2750     }
2751   }
2752   int nbNodes = nodeSet.size();
2753   if ( !nbNodes )
2754     return;
2755   coord[0] /= nbNodes;
2756   coord[1] /= nbNodes;
2757
2758   if ( !theSurface.IsNull() ) {
2759     ASSERT( theUVMap.find( theNode ) != theUVMap.end() );
2760     theUVMap[ theNode ]->SetCoord( coord[0], coord[1] );
2761     gp_Pnt p3d = theSurface->Value( coord[0], coord[1] );
2762     coord[0] = p3d.X();
2763     coord[1] = p3d.Y();
2764     coord[2] = p3d.Z();
2765   }
2766   else
2767     coord[2] /= nbNodes;
2768
2769   // move node
2770
2771   const_cast< SMDS_MeshNode* >( theNode )->setXYZ(coord[0],coord[1],coord[2]);
2772 }
2773
2774 //=======================================================================
2775 //function : centroidalSmooth
2776 //purpose  : pulls theNode toward the element-area-weighted centroid of the
2777 //           surrounding elements
2778 //=======================================================================
2779
2780 void centroidalSmooth(const SMDS_MeshNode*                 theNode,
2781                       const Handle(Geom_Surface)&          theSurface,
2782                       map< const SMDS_MeshNode*, gp_XY* >& theUVMap)
2783 {
2784   gp_XYZ aNewXYZ(0.,0.,0.);
2785   SMESH::Controls::Area anAreaFunc;
2786   double totalArea = 0.;
2787   int nbElems = 0;
2788
2789   // compute new XYZ
2790
2791   SMDS_ElemIteratorPtr elemIt = theNode->GetInverseElementIterator(SMDSAbs_Face);
2792   while ( elemIt->more() )
2793   {
2794     const SMDS_MeshElement* elem = elemIt->next();
2795     nbElems++;
2796
2797     gp_XYZ elemCenter(0.,0.,0.);
2798     SMESH::Controls::TSequenceOfXYZ aNodePoints;
2799     SMDS_ElemIteratorPtr itN = elem->nodesIterator();
2800     int nn = elem->NbNodes();
2801     if(elem->IsQuadratic()) nn = nn/2;
2802     int i=0;
2803     //while ( itN->more() ) {
2804     while ( i<nn ) {
2805       const SMDS_MeshNode* aNode = static_cast<const SMDS_MeshNode*>( itN->next() );
2806       i++;
2807       gp_XYZ aP( aNode->X(), aNode->Y(), aNode->Z() );
2808       aNodePoints.push_back( aP );
2809       if ( !theSurface.IsNull() ) { // smooth in 2D
2810         ASSERT( theUVMap.find( aNode ) != theUVMap.end() );
2811         gp_XY* uv = theUVMap[ aNode ];
2812         aP.SetCoord( uv->X(), uv->Y(), 0. );
2813       }
2814       elemCenter += aP;
2815     }
2816     double elemArea = anAreaFunc.GetValue( aNodePoints );
2817     totalArea += elemArea;
2818     elemCenter /= nn;
2819     aNewXYZ += elemCenter * elemArea;
2820   }
2821   aNewXYZ /= totalArea;
2822   if ( !theSurface.IsNull() ) {
2823     theUVMap[ theNode ]->SetCoord( aNewXYZ.X(), aNewXYZ.Y() );
2824     aNewXYZ = theSurface->Value( aNewXYZ.X(), aNewXYZ.Y() ).XYZ();
2825   }
2826
2827   // move node
2828
2829   const_cast< SMDS_MeshNode* >( theNode )->setXYZ(aNewXYZ.X(),aNewXYZ.Y(),aNewXYZ.Z());
2830 }
2831
2832 //=======================================================================
2833 //function : getClosestUV
2834 //purpose  : return UV of closest projection
2835 //=======================================================================
2836
2837 static bool getClosestUV (Extrema_GenExtPS& projector,
2838                           const gp_Pnt&     point,
2839                           gp_XY &           result)
2840 {
2841   projector.Perform( point );
2842   if ( projector.IsDone() ) {
2843     double u, v, minVal = DBL_MAX;
2844     for ( int i = projector.NbExt(); i > 0; i-- )
2845       if ( projector.Value( i ) < minVal ) {
2846         minVal = projector.Value( i );
2847         projector.Point( i ).Parameter( u, v );
2848       }
2849     result.SetCoord( u, v );
2850     return true;
2851   }
2852   return false;
2853 }
2854
2855 //=======================================================================
2856 //function : Smooth
2857 //purpose  : Smooth theElements during theNbIterations or until a worst
2858 //           element has aspect ratio <= theTgtAspectRatio.
2859 //           Aspect Ratio varies in range [1.0, inf].
2860 //           If theElements is empty, the whole mesh is smoothed.
2861 //           theFixedNodes contains additionally fixed nodes. Nodes built
2862 //           on edges and boundary nodes are always fixed.
2863 //=======================================================================
2864
2865 void SMESH_MeshEditor::Smooth (TIDSortedElemSet &          theElems,
2866                                set<const SMDS_MeshNode*> & theFixedNodes,
2867                                const SmoothMethod          theSmoothMethod,
2868                                const int                   theNbIterations,
2869                                double                      theTgtAspectRatio,
2870                                const bool                  the2D)
2871 {
2872   myLastCreatedElems.Clear();
2873   myLastCreatedNodes.Clear();
2874
2875   MESSAGE((theSmoothMethod==LAPLACIAN ? "LAPLACIAN" : "CENTROIDAL") << "--::Smooth()");
2876
2877   if ( theTgtAspectRatio < 1.0 )
2878     theTgtAspectRatio = 1.0;
2879
2880   const double disttol = 1.e-16;
2881
2882   SMESH::Controls::AspectRatio aQualityFunc;
2883
2884   SMESHDS_Mesh* aMesh = GetMeshDS();
2885
2886   if ( theElems.empty() ) {
2887     // add all faces to theElems
2888     SMDS_FaceIteratorPtr fIt = aMesh->facesIterator();
2889     while ( fIt->more() ) {
2890       const SMDS_MeshElement* face = fIt->next();
2891       theElems.insert( face );
2892     }
2893   }
2894   // get all face ids theElems are on
2895   set< int > faceIdSet;
2896   TIDSortedElemSet::iterator itElem;
2897   if ( the2D )
2898     for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
2899       int fId = FindShape( *itElem );
2900       // check that corresponding submesh exists and a shape is face
2901       if (fId &&
2902           faceIdSet.find( fId ) == faceIdSet.end() &&
2903           aMesh->MeshElements( fId )) {
2904         TopoDS_Shape F = aMesh->IndexToShape( fId );
2905         if ( !F.IsNull() && F.ShapeType() == TopAbs_FACE )
2906           faceIdSet.insert( fId );
2907       }
2908     }
2909   faceIdSet.insert( 0 ); // to smooth elements that are not on any TopoDS_Face
2910
2911   // ===============================================
2912   // smooth elements on each TopoDS_Face separately
2913   // ===============================================
2914
2915   set< int >::reverse_iterator fId = faceIdSet.rbegin(); // treate 0 fId at the end
2916   for ( ; fId != faceIdSet.rend(); ++fId ) {
2917     // get face surface and submesh
2918     Handle(Geom_Surface) surface;
2919     SMESHDS_SubMesh* faceSubMesh = 0;
2920     TopoDS_Face face;
2921     double fToler2 = 0, vPeriod = 0., uPeriod = 0., f,l;
2922     double u1 = 0, u2 = 0, v1 = 0, v2 = 0;
2923     bool isUPeriodic = false, isVPeriodic = false;
2924     if ( *fId ) {
2925       face = TopoDS::Face( aMesh->IndexToShape( *fId ));
2926       surface = BRep_Tool::Surface( face );
2927       faceSubMesh = aMesh->MeshElements( *fId );
2928       fToler2 = BRep_Tool::Tolerance( face );
2929       fToler2 *= fToler2 * 10.;
2930       isUPeriodic = surface->IsUPeriodic();
2931       if ( isUPeriodic )
2932         vPeriod = surface->UPeriod();
2933       isVPeriodic = surface->IsVPeriodic();
2934       if ( isVPeriodic )
2935         uPeriod = surface->VPeriod();
2936       surface->Bounds( u1, u2, v1, v2 );
2937     }
2938     // ---------------------------------------------------------
2939     // for elements on a face, find movable and fixed nodes and
2940     // compute UV for them
2941     // ---------------------------------------------------------
2942     bool checkBoundaryNodes = false;
2943     bool isQuadratic = false;
2944     set<const SMDS_MeshNode*> setMovableNodes;
2945     map< const SMDS_MeshNode*, gp_XY* > uvMap, uvMap2;
2946     list< gp_XY > listUV; // uvs the 2 uvMaps refer to
2947     list< const SMDS_MeshElement* > elemsOnFace;
2948
2949     Extrema_GenExtPS projector;
2950     GeomAdaptor_Surface surfAdaptor;
2951     if ( !surface.IsNull() ) {
2952       surfAdaptor.Load( surface );
2953       projector.Initialize( surfAdaptor, 20,20, 1e-5,1e-5 );
2954     }
2955     int nbElemOnFace = 0;
2956     itElem = theElems.begin();
2957     // loop on not yet smoothed elements: look for elems on a face
2958     while ( itElem != theElems.end() ) {
2959       if ( faceSubMesh && nbElemOnFace == faceSubMesh->NbElements() )
2960         break; // all elements found
2961
2962       const SMDS_MeshElement* elem = *itElem;
2963       if ( !elem || elem->GetType() != SMDSAbs_Face || elem->NbNodes() < 3 ||
2964            ( faceSubMesh && !faceSubMesh->Contains( elem ))) {
2965         ++itElem;
2966         continue;
2967       }
2968       elemsOnFace.push_back( elem );
2969       theElems.erase( itElem++ );
2970       nbElemOnFace++;
2971
2972       if ( !isQuadratic )
2973         isQuadratic = elem->IsQuadratic();
2974
2975       // get movable nodes of elem
2976       const SMDS_MeshNode* node;
2977       SMDS_TypeOfPosition posType;
2978       SMDS_ElemIteratorPtr itN = elem->nodesIterator();
2979       int nn = 0, nbn =  elem->NbNodes();
2980       if(elem->IsQuadratic())
2981         nbn = nbn/2;
2982       while ( nn++ < nbn ) {
2983         node = static_cast<const SMDS_MeshNode*>( itN->next() );
2984         const SMDS_PositionPtr& pos = node->GetPosition();
2985         posType = pos ? pos->GetTypeOfPosition() : SMDS_TOP_3DSPACE;
2986         if (posType != SMDS_TOP_EDGE &&
2987             posType != SMDS_TOP_VERTEX &&
2988             theFixedNodes.find( node ) == theFixedNodes.end())
2989         {
2990           // check if all faces around the node are on faceSubMesh
2991           // because a node on edge may be bound to face
2992           SMDS_ElemIteratorPtr eIt = node->GetInverseElementIterator(SMDSAbs_Face);
2993           bool all = true;
2994           if ( faceSubMesh ) {
2995             while ( eIt->more() && all ) {
2996               const SMDS_MeshElement* e = eIt->next();
2997               all = faceSubMesh->Contains( e );
2998             }
2999           }
3000           if ( all )
3001             setMovableNodes.insert( node );
3002           else
3003             checkBoundaryNodes = true;
3004         }
3005         if ( posType == SMDS_TOP_3DSPACE )
3006           checkBoundaryNodes = true;
3007       }
3008
3009       if ( surface.IsNull() )
3010         continue;
3011
3012       // get nodes to check UV
3013       list< const SMDS_MeshNode* > uvCheckNodes;
3014       itN = elem->nodesIterator();
3015       nn = 0; nbn =  elem->NbNodes();
3016       if(elem->IsQuadratic())
3017         nbn = nbn/2;
3018       while ( nn++ < nbn ) {
3019         node = static_cast<const SMDS_MeshNode*>( itN->next() );
3020         if ( uvMap.find( node ) == uvMap.end() )
3021           uvCheckNodes.push_back( node );
3022         // add nodes of elems sharing node
3023         //         SMDS_ElemIteratorPtr eIt = node->GetInverseElementIterator(SMDSAbs_Face);
3024         //         while ( eIt->more() ) {
3025         //           const SMDS_MeshElement* e = eIt->next();
3026         //           if ( e != elem ) {
3027         //             SMDS_ElemIteratorPtr nIt = e->nodesIterator();
3028         //             while ( nIt->more() ) {
3029         //               const SMDS_MeshNode* n =
3030         //                 static_cast<const SMDS_MeshNode*>( nIt->next() );
3031         //               if ( uvMap.find( n ) == uvMap.end() )
3032         //                 uvCheckNodes.push_back( n );
3033         //             }
3034         //           }
3035         //         }
3036       }
3037       // check UV on face
3038       list< const SMDS_MeshNode* >::iterator n = uvCheckNodes.begin();
3039       for ( ; n != uvCheckNodes.end(); ++n ) {
3040         node = *n;
3041         gp_XY uv( 0, 0 );
3042         const SMDS_PositionPtr& pos = node->GetPosition();
3043         posType = pos ? pos->GetTypeOfPosition() : SMDS_TOP_3DSPACE;
3044         // get existing UV
3045         switch ( posType ) {
3046         case SMDS_TOP_FACE: {
3047           SMDS_FacePosition* fPos = ( SMDS_FacePosition* ) pos;
3048           uv.SetCoord( fPos->GetUParameter(), fPos->GetVParameter() );
3049           break;
3050         }
3051         case SMDS_TOP_EDGE: {
3052           TopoDS_Shape S = aMesh->IndexToShape( node->getshapeId() );
3053           Handle(Geom2d_Curve) pcurve;
3054           if ( !S.IsNull() && S.ShapeType() == TopAbs_EDGE )
3055             pcurve = BRep_Tool::CurveOnSurface( TopoDS::Edge( S ), face, f,l );
3056           if ( !pcurve.IsNull() ) {
3057             double u = (( SMDS_EdgePosition* ) pos )->GetUParameter();
3058             uv = pcurve->Value( u ).XY();
3059           }
3060           break;
3061         }
3062         case SMDS_TOP_VERTEX: {
3063           TopoDS_Shape S = aMesh->IndexToShape( node->getshapeId() );
3064           if ( !S.IsNull() && S.ShapeType() == TopAbs_VERTEX )
3065             uv = BRep_Tool::Parameters( TopoDS::Vertex( S ), face ).XY();
3066           break;
3067         }
3068         default:;
3069         }
3070         // check existing UV
3071         bool project = true;
3072         gp_Pnt pNode ( node->X(), node->Y(), node->Z() );
3073         double dist1 = DBL_MAX, dist2 = 0;
3074         if ( posType != SMDS_TOP_3DSPACE ) {
3075           dist1 = pNode.SquareDistance( surface->Value( uv.X(), uv.Y() ));
3076           project = dist1 > fToler2;
3077         }
3078         if ( project ) { // compute new UV
3079           gp_XY newUV;
3080           if ( !getClosestUV( projector, pNode, newUV )) {
3081             MESSAGE("Node Projection Failed " << node);
3082           }
3083           else {
3084             if ( isUPeriodic )
3085               newUV.SetX( ElCLib::InPeriod( newUV.X(), u1, u2 ));
3086             if ( isVPeriodic )
3087               newUV.SetY( ElCLib::InPeriod( newUV.Y(), v1, v2 ));
3088             // check new UV
3089             if ( posType != SMDS_TOP_3DSPACE )
3090               dist2 = pNode.SquareDistance( surface->Value( newUV.X(), newUV.Y() ));
3091             if ( dist2 < dist1 )
3092               uv = newUV;
3093           }
3094         }
3095         // store UV in the map
3096         listUV.push_back( uv );
3097         uvMap.insert( make_pair( node, &listUV.back() ));
3098       }
3099     } // loop on not yet smoothed elements
3100
3101     if ( !faceSubMesh || nbElemOnFace != faceSubMesh->NbElements() )
3102       checkBoundaryNodes = true;
3103
3104     // fix nodes on mesh boundary
3105
3106     if ( checkBoundaryNodes ) {
3107       map< NLink, int > linkNbMap; // how many times a link encounters in elemsOnFace
3108       map< NLink, int >::iterator link_nb;
3109       // put all elements links to linkNbMap
3110       list< const SMDS_MeshElement* >::iterator elemIt = elemsOnFace.begin();
3111       for ( ; elemIt != elemsOnFace.end(); ++elemIt ) {
3112         const SMDS_MeshElement* elem = (*elemIt);
3113         int nbn =  elem->NbNodes();
3114         if(elem->IsQuadratic())
3115           nbn = nbn/2;
3116         // loop on elem links: insert them in linkNbMap
3117         const SMDS_MeshNode* curNode, *prevNode = elem->GetNodeWrap( nbn );
3118         for ( int iN = 0; iN < nbn; ++iN ) {
3119           curNode = elem->GetNode( iN );
3120           NLink link;
3121           if ( curNode < prevNode ) link = make_pair( curNode , prevNode );
3122           else                      link = make_pair( prevNode , curNode );
3123           prevNode = curNode;
3124           link_nb = linkNbMap.find( link );
3125           if ( link_nb == linkNbMap.end() )
3126             linkNbMap.insert( make_pair ( link, 1 ));
3127           else
3128             link_nb->second++;
3129         }
3130       }
3131       // remove nodes that are in links encountered only once from setMovableNodes
3132       for ( link_nb = linkNbMap.begin(); link_nb != linkNbMap.end(); ++link_nb ) {
3133         if ( link_nb->second == 1 ) {
3134           setMovableNodes.erase( link_nb->first.first );
3135           setMovableNodes.erase( link_nb->first.second );
3136         }
3137       }
3138     }
3139
3140     // -----------------------------------------------------
3141     // for nodes on seam edge, compute one more UV ( uvMap2 );
3142     // find movable nodes linked to nodes on seam and which
3143     // are to be smoothed using the second UV ( uvMap2 )
3144     // -----------------------------------------------------
3145
3146     set<const SMDS_MeshNode*> nodesNearSeam; // to smooth using uvMap2
3147     if ( !surface.IsNull() ) {
3148       TopExp_Explorer eExp( face, TopAbs_EDGE );
3149       for ( ; eExp.More(); eExp.Next() ) {
3150         TopoDS_Edge edge = TopoDS::Edge( eExp.Current() );
3151         if ( !BRep_Tool::IsClosed( edge, face ))
3152           continue;
3153         SMESHDS_SubMesh* sm = aMesh->MeshElements( edge );
3154         if ( !sm ) continue;
3155         // find out which parameter varies for a node on seam
3156         double f,l;
3157         gp_Pnt2d uv1, uv2;
3158         Handle(Geom2d_Curve) pcurve = BRep_Tool::CurveOnSurface( edge, face, f, l );
3159         if ( pcurve.IsNull() ) continue;
3160         uv1 = pcurve->Value( f );
3161         edge.Reverse();
3162         pcurve = BRep_Tool::CurveOnSurface( edge, face, f, l );
3163         if ( pcurve.IsNull() ) continue;
3164         uv2 = pcurve->Value( f );
3165         int iPar = Abs( uv1.X() - uv2.X() ) > Abs( uv1.Y() - uv2.Y() ) ? 1 : 2;
3166         // assure uv1 < uv2
3167         if ( uv1.Coord( iPar ) > uv2.Coord( iPar )) {
3168           gp_Pnt2d tmp = uv1; uv1 = uv2; uv2 = tmp;
3169         }
3170         // get nodes on seam and its vertices
3171         list< const SMDS_MeshNode* > seamNodes;
3172         SMDS_NodeIteratorPtr nSeamIt = sm->GetNodes();
3173         while ( nSeamIt->more() ) {
3174           const SMDS_MeshNode* node = nSeamIt->next();
3175           if ( !isQuadratic || !IsMedium( node ))
3176             seamNodes.push_back( node );
3177         }
3178         TopExp_Explorer vExp( edge, TopAbs_VERTEX );
3179         for ( ; vExp.More(); vExp.Next() ) {
3180           sm = aMesh->MeshElements( vExp.Current() );
3181           if ( sm ) {
3182             nSeamIt = sm->GetNodes();
3183             while ( nSeamIt->more() )
3184               seamNodes.push_back( nSeamIt->next() );
3185           }
3186         }
3187         // loop on nodes on seam
3188         list< const SMDS_MeshNode* >::iterator noSeIt = seamNodes.begin();
3189         for ( ; noSeIt != seamNodes.end(); ++noSeIt ) {
3190           const SMDS_MeshNode* nSeam = *noSeIt;
3191           map< const SMDS_MeshNode*, gp_XY* >::iterator n_uv = uvMap.find( nSeam );
3192           if ( n_uv == uvMap.end() )
3193             continue;
3194           // set the first UV
3195           n_uv->second->SetCoord( iPar, uv1.Coord( iPar ));
3196           // set the second UV
3197           listUV.push_back( *n_uv->second );
3198           listUV.back().SetCoord( iPar, uv2.Coord( iPar ));
3199           if ( uvMap2.empty() )
3200             uvMap2 = uvMap; // copy the uvMap contents
3201           uvMap2[ nSeam ] = &listUV.back();
3202
3203           // collect movable nodes linked to ones on seam in nodesNearSeam
3204           SMDS_ElemIteratorPtr eIt = nSeam->GetInverseElementIterator(SMDSAbs_Face);
3205           while ( eIt->more() ) {
3206             const SMDS_MeshElement* e = eIt->next();
3207             int nbUseMap1 = 0, nbUseMap2 = 0;
3208             SMDS_ElemIteratorPtr nIt = e->nodesIterator();
3209             int nn = 0, nbn =  e->NbNodes();
3210             if(e->IsQuadratic()) nbn = nbn/2;
3211             while ( nn++ < nbn )
3212             {
3213               const SMDS_MeshNode* n =
3214                 static_cast<const SMDS_MeshNode*>( nIt->next() );
3215               if (n == nSeam ||
3216                   setMovableNodes.find( n ) == setMovableNodes.end() )
3217                 continue;
3218               // add only nodes being closer to uv2 than to uv1
3219               gp_Pnt pMid (0.5 * ( n->X() + nSeam->X() ),
3220                            0.5 * ( n->Y() + nSeam->Y() ),
3221                            0.5 * ( n->Z() + nSeam->Z() ));
3222               gp_XY uv;
3223               getClosestUV( projector, pMid, uv );
3224               if ( uv.Coord( iPar ) > uvMap[ n ]->Coord( iPar ) ) {
3225                 nodesNearSeam.insert( n );
3226                 nbUseMap2++;
3227               }
3228               else
3229                 nbUseMap1++;
3230             }
3231             // for centroidalSmooth all element nodes must
3232             // be on one side of a seam
3233             if ( theSmoothMethod == CENTROIDAL && nbUseMap1 && nbUseMap2 ) {
3234               SMDS_ElemIteratorPtr nIt = e->nodesIterator();
3235               nn = 0;
3236               while ( nn++ < nbn ) {
3237                 const SMDS_MeshNode* n =
3238                   static_cast<const SMDS_MeshNode*>( nIt->next() );
3239                 setMovableNodes.erase( n );
3240               }
3241             }
3242           }
3243         } // loop on nodes on seam
3244       } // loop on edge of a face
3245     } // if ( !face.IsNull() )
3246
3247     if ( setMovableNodes.empty() ) {
3248       MESSAGE( "Face id : " << *fId << " - NO SMOOTHING: no nodes to move!!!");
3249       continue; // goto next face
3250     }
3251
3252     // -------------
3253     // SMOOTHING //
3254     // -------------
3255
3256     int it = -1;
3257     double maxRatio = -1., maxDisplacement = -1.;
3258     set<const SMDS_MeshNode*>::iterator nodeToMove;
3259     for ( it = 0; it < theNbIterations; it++ ) {
3260       maxDisplacement = 0.;
3261       nodeToMove = setMovableNodes.begin();
3262       for ( ; nodeToMove != setMovableNodes.end(); nodeToMove++ ) {
3263         const SMDS_MeshNode* node = (*nodeToMove);
3264         gp_XYZ aPrevPos ( node->X(), node->Y(), node->Z() );
3265
3266         // smooth
3267         bool map2 = ( nodesNearSeam.find( node ) != nodesNearSeam.end() );
3268         if ( theSmoothMethod == LAPLACIAN )
3269           laplacianSmooth( node, surface, map2 ? uvMap2 : uvMap );
3270         else
3271           centroidalSmooth( node, surface, map2 ? uvMap2 : uvMap );
3272
3273         // node displacement
3274         gp_XYZ aNewPos ( node->X(), node->Y(), node->Z() );
3275         Standard_Real aDispl = (aPrevPos - aNewPos).SquareModulus();
3276         if ( aDispl > maxDisplacement )
3277           maxDisplacement = aDispl;
3278       }
3279       // no node movement => exit
3280       //if ( maxDisplacement < 1.e-16 ) {
3281       if ( maxDisplacement < disttol ) {
3282         MESSAGE("-- no node movement --");
3283         break;
3284       }
3285
3286       // check elements quality
3287       maxRatio  = 0;
3288       list< const SMDS_MeshElement* >::iterator elemIt = elemsOnFace.begin();
3289       for ( ; elemIt != elemsOnFace.end(); ++elemIt ) {
3290         const SMDS_MeshElement* elem = (*elemIt);
3291         if ( !elem || elem->GetType() != SMDSAbs_Face )
3292           continue;
3293         SMESH::Controls::TSequenceOfXYZ aPoints;
3294         if ( aQualityFunc.GetPoints( elem, aPoints )) {
3295           double aValue = aQualityFunc.GetValue( aPoints );
3296           if ( aValue > maxRatio )
3297             maxRatio = aValue;
3298         }
3299       }
3300       if ( maxRatio <= theTgtAspectRatio ) {
3301         MESSAGE("-- quality achived --");
3302         break;
3303       }
3304       if (it+1 == theNbIterations) {
3305         MESSAGE("-- Iteration limit exceeded --");
3306       }
3307     } // smoothing iterations
3308
3309     MESSAGE(" Face id: " << *fId <<
3310             " Nb iterstions: " << it <<
3311             " Displacement: " << maxDisplacement <<
3312             " Aspect Ratio " << maxRatio);
3313
3314     // ---------------------------------------
3315     // new nodes positions are computed,
3316     // record movement in DS and set new UV
3317     // ---------------------------------------
3318     nodeToMove = setMovableNodes.begin();
3319     for ( ; nodeToMove != setMovableNodes.end(); nodeToMove++ ) {
3320       SMDS_MeshNode* node = const_cast< SMDS_MeshNode* > (*nodeToMove);
3321       aMesh->MoveNode( node, node->X(), node->Y(), node->Z() );
3322       map< const SMDS_MeshNode*, gp_XY* >::iterator node_uv = uvMap.find( node );
3323       if ( node_uv != uvMap.end() ) {
3324         gp_XY* uv = node_uv->second;
3325         node->SetPosition
3326           ( SMDS_PositionPtr( new SMDS_FacePosition( uv->X(), uv->Y() )));
3327       }
3328     }
3329
3330     // move medium nodes of quadratic elements
3331     if ( isQuadratic )
3332     {
3333       SMESH_MesherHelper helper( *GetMesh() );
3334       if ( !face.IsNull() )
3335         helper.SetSubShape( face );
3336       list< const SMDS_MeshElement* >::iterator elemIt = elemsOnFace.begin();
3337       for ( ; elemIt != elemsOnFace.end(); ++elemIt ) {
3338         const SMDS_VtkFace* QF =
3339           dynamic_cast<const SMDS_VtkFace*> (*elemIt);
3340         if(QF && QF->IsQuadratic()) {
3341           vector<const SMDS_MeshNode*> Ns;
3342           Ns.reserve(QF->NbNodes()+1);
3343           SMDS_ElemIteratorPtr anIter = QF->interlacedNodesElemIterator();
3344           while ( anIter->more() )
3345             Ns.push_back( cast2Node(anIter->next()) );
3346           Ns.push_back( Ns[0] );
3347           double x, y, z;
3348           for(int i=0; i<QF->NbNodes(); i=i+2) {
3349             if ( !surface.IsNull() ) {
3350               gp_XY uv1 = helper.GetNodeUV( face, Ns[i], Ns[i+2] );
3351               gp_XY uv2 = helper.GetNodeUV( face, Ns[i+2], Ns[i] );
3352               gp_XY uv = ( uv1 + uv2 ) / 2.;
3353               gp_Pnt xyz = surface->Value( uv.X(), uv.Y() );
3354               x = xyz.X(); y = xyz.Y(); z = xyz.Z();
3355             }
3356             else {
3357               x = (Ns[i]->X() + Ns[i+2]->X())/2;
3358               y = (Ns[i]->Y() + Ns[i+2]->Y())/2;
3359               z = (Ns[i]->Z() + Ns[i+2]->Z())/2;
3360             }
3361             if( fabs( Ns[i+1]->X() - x ) > disttol ||
3362                 fabs( Ns[i+1]->Y() - y ) > disttol ||
3363                 fabs( Ns[i+1]->Z() - z ) > disttol ) {
3364               // we have to move i+1 node
3365               aMesh->MoveNode( Ns[i+1], x, y, z );
3366             }
3367           }
3368         }
3369       }
3370     }
3371
3372   } // loop on face ids
3373
3374 }
3375
3376 //=======================================================================
3377 //function : isReverse
3378 //purpose  : Return true if normal of prevNodes is not co-directied with
3379 //           gp_Vec(prevNodes[iNotSame],nextNodes[iNotSame]).
3380 //           iNotSame is where prevNodes and nextNodes are different
3381 //=======================================================================
3382
3383 static bool isReverse(vector<const SMDS_MeshNode*> prevNodes,
3384                       vector<const SMDS_MeshNode*> nextNodes,
3385                       const int            nbNodes,
3386                       const int            iNotSame)
3387 {
3388   int iBeforeNotSame = ( iNotSame == 0 ? nbNodes - 1 : iNotSame - 1 );
3389   int iAfterNotSame  = ( iNotSame + 1 == nbNodes ? 0 : iNotSame + 1 );
3390
3391   const SMDS_MeshNode* nB = prevNodes[ iBeforeNotSame ];
3392   const SMDS_MeshNode* nA = prevNodes[ iAfterNotSame ];
3393   const SMDS_MeshNode* nP = prevNodes[ iNotSame ];
3394   const SMDS_MeshNode* nN = nextNodes[ iNotSame ];
3395
3396   gp_Pnt pB ( nB->X(), nB->Y(), nB->Z() );
3397   gp_Pnt pA ( nA->X(), nA->Y(), nA->Z() );
3398   gp_Pnt pP ( nP->X(), nP->Y(), nP->Z() );
3399   gp_Pnt pN ( nN->X(), nN->Y(), nN->Z() );
3400
3401   gp_Vec vB ( pP, pB ), vA ( pP, pA ), vN ( pP, pN );
3402
3403   return (vA ^ vB) * vN < 0.0;
3404 }
3405
3406 //=======================================================================
3407 /*!
3408  * \brief Create elements by sweeping an element
3409  * \param elem - element to sweep
3410  * \param newNodesItVec - nodes generated from each node of the element
3411  * \param newElems - generated elements
3412  * \param nbSteps - number of sweeping steps
3413  * \param srcElements - to append elem for each generated element
3414  */
3415 //=======================================================================
3416
3417 void SMESH_MeshEditor::sweepElement(const SMDS_MeshElement*               elem,
3418                                     const vector<TNodeOfNodeListMapItr> & newNodesItVec,
3419                                     list<const SMDS_MeshElement*>&        newElems,
3420                                     const int                             nbSteps,
3421                                     SMESH_SequenceOfElemPtr&              srcElements)
3422 {
3423   //MESSAGE("sweepElement " << nbSteps);
3424   SMESHDS_Mesh* aMesh = GetMeshDS();
3425
3426   // Loop on elem nodes:
3427   // find new nodes and detect same nodes indices
3428   int nbNodes = elem->NbNodes();
3429   vector < list< const SMDS_MeshNode* >::const_iterator > itNN( nbNodes );
3430   vector<const SMDS_MeshNode*> prevNod( nbNodes );
3431   vector<const SMDS_MeshNode*> nextNod( nbNodes );
3432   vector<const SMDS_MeshNode*> midlNod( nbNodes );
3433
3434   int iNode, nbSame = 0, iNotSameNode = 0, iSameNode = 0;
3435   vector<int> sames(nbNodes);
3436   vector<bool> issimple(nbNodes);
3437
3438   for ( iNode = 0; iNode < nbNodes; iNode++ ) {
3439     TNodeOfNodeListMapItr nnIt = newNodesItVec[ iNode ];
3440     const SMDS_MeshNode*                 node         = nnIt->first;
3441     const list< const SMDS_MeshNode* > & listNewNodes = nnIt->second;
3442     if ( listNewNodes.empty() ) {
3443       return;
3444     }
3445
3446     issimple[iNode] = (listNewNodes.size()==nbSteps); // is node medium
3447
3448     itNN[ iNode ] = listNewNodes.begin();
3449     prevNod[ iNode ] = node;
3450     nextNod[ iNode ] = listNewNodes.front();
3451     if( !elem->IsQuadratic() || !issimple[iNode] ) {
3452       if ( prevNod[ iNode ] != nextNod [ iNode ])
3453         iNotSameNode = iNode;
3454       else {
3455         iSameNode = iNode;
3456         //nbSame++;
3457         sames[nbSame++] = iNode;
3458       }
3459     }
3460   }
3461
3462   //cerr<<"  nbSame = "<<nbSame<<endl;
3463   if ( nbSame == nbNodes || nbSame > 2) {
3464     MESSAGE( " Too many same nodes of element " << elem->GetID() );
3465     //INFOS( " Too many same nodes of element " << elem->GetID() );
3466     return;
3467   }
3468
3469   //  if( elem->IsQuadratic() && nbSame>0 ) {
3470   //    MESSAGE( "Can not rotate quadratic element " << elem->GetID() );
3471   //    return;
3472   //  }
3473
3474   int iBeforeSame = 0, iAfterSame = 0, iOpposSame = 0;
3475   int nbBaseNodes = ( elem->IsQuadratic() ? nbNodes/2 : nbNodes );
3476   if ( nbSame > 0 ) {
3477     iBeforeSame = ( iSameNode == 0 ? nbBaseNodes - 1 : iSameNode - 1 );
3478     iAfterSame  = ( iSameNode + 1 == nbBaseNodes ? 0 : iSameNode + 1 );
3479     iOpposSame  = ( iSameNode - 2 < 0  ? iSameNode + 2 : iSameNode - 2 );
3480   }
3481
3482   //if(nbNodes==8)
3483   //cout<<" prevNod[0]="<< prevNod[0]<<" prevNod[1]="<< prevNod[1]
3484   //    <<" prevNod[2]="<< prevNod[2]<<" prevNod[3]="<< prevNod[4]
3485   //    <<" prevNod[4]="<< prevNod[4]<<" prevNod[5]="<< prevNod[5]
3486   //    <<" prevNod[6]="<< prevNod[6]<<" prevNod[7]="<< prevNod[7]<<endl;
3487
3488   // check element orientation
3489   int i0 = 0, i2 = 2;
3490   if ( nbNodes > 2 && !isReverse( prevNod, nextNod, nbNodes, iNotSameNode )) {
3491     //MESSAGE("Reversed elem " << elem );
3492     i0 = 2;
3493     i2 = 0;
3494     if ( nbSame > 0 )
3495       std::swap( iBeforeSame, iAfterSame );
3496   }
3497
3498   // make new elements
3499   const SMDS_MeshElement* lastElem = elem;
3500   for (int iStep = 0; iStep < nbSteps; iStep++ ) {
3501     // get next nodes
3502     for ( iNode = 0; iNode < nbNodes; iNode++ ) {
3503       if(issimple[iNode]) {
3504         nextNod[ iNode ] = *itNN[ iNode ];
3505         itNN[ iNode ]++;
3506       }
3507       else {
3508         if( elem->GetType()==SMDSAbs_Node ) {
3509           // we have to use two nodes
3510           midlNod[ iNode ] = *itNN[ iNode ];
3511           itNN[ iNode ]++;
3512           nextNod[ iNode ] = *itNN[ iNode ];
3513           itNN[ iNode ]++;
3514         }
3515         else if(!elem->IsQuadratic() || lastElem->IsMediumNode(prevNod[iNode]) ) {
3516           // we have to use each second node
3517           //itNN[ iNode ]++;
3518           nextNod[ iNode ] = *itNN[ iNode ];
3519           itNN[ iNode ]++;
3520         }
3521         else {
3522           // we have to use two nodes
3523           midlNod[ iNode ] = *itNN[ iNode ];
3524           itNN[ iNode ]++;
3525           nextNod[ iNode ] = *itNN[ iNode ];
3526           itNN[ iNode ]++;
3527         }
3528       }
3529     }
3530     SMDS_MeshElement* aNewElem = 0;
3531     if(!elem->IsPoly()) {
3532       switch ( nbNodes ) {
3533       case 0:
3534         return;
3535       case 1: { // NODE
3536         if ( nbSame == 0 ) {
3537           if(issimple[0])
3538             aNewElem = aMesh->AddEdge( prevNod[ 0 ], nextNod[ 0 ] );
3539           else
3540             aNewElem = aMesh->AddEdge( prevNod[ 0 ], nextNod[ 0 ], midlNod[ 0 ] );
3541         }
3542         break;
3543       }
3544       case 2: { // EDGE
3545         if ( nbSame == 0 )
3546           aNewElem = aMesh->AddFace(prevNod[ 0 ], prevNod[ 1 ],
3547                                     nextNod[ 1 ], nextNod[ 0 ] );
3548         else
3549           aNewElem = aMesh->AddFace(prevNod[ 0 ], prevNod[ 1 ],
3550                                     nextNod[ iNotSameNode ] );
3551         break;
3552       }
3553
3554       case 3: { // TRIANGLE or quadratic edge
3555         if(elem->GetType() == SMDSAbs_Face) { // TRIANGLE
3556
3557           if ( nbSame == 0 )       // --- pentahedron
3558             aNewElem = aMesh->AddVolume (prevNod[ i0 ], prevNod[ 1 ], prevNod[ i2 ],
3559                                          nextNod[ i0 ], nextNod[ 1 ], nextNod[ i2 ] );
3560
3561           else if ( nbSame == 1 )  // --- pyramid
3562             aNewElem = aMesh->AddVolume (prevNod[ iBeforeSame ],  prevNod[ iAfterSame ],
3563                                          nextNod[ iAfterSame ], nextNod[ iBeforeSame ],
3564                                          nextNod[ iSameNode ]);
3565
3566           else // 2 same nodes:      --- tetrahedron
3567             aNewElem = aMesh->AddVolume (prevNod[ i0 ], prevNod[ 1 ], prevNod[ i2 ],
3568                                          nextNod[ iNotSameNode ]);
3569         }
3570         else { // quadratic edge
3571           if(nbSame==0) {     // quadratic quadrangle
3572             aNewElem = aMesh->AddFace(prevNod[0], nextNod[0], nextNod[1], prevNod[1],
3573                                       midlNod[0], nextNod[2], midlNod[1], prevNod[2]);
3574           }
3575           else if(nbSame==1) { // quadratic triangle
3576             if(sames[0]==2) {
3577               return; // medium node on axis
3578             }
3579             else if(sames[0]==0) {
3580               aNewElem = aMesh->AddFace(prevNod[0], nextNod[1], prevNod[1],
3581                                         nextNod[2], midlNod[1], prevNod[2]);
3582             }
3583             else { // sames[0]==1
3584               aNewElem = aMesh->AddFace(prevNod[0], nextNod[0], prevNod[1],
3585                                         midlNod[0], nextNod[2], prevNod[2]);
3586             }
3587           }
3588           else {
3589             return;
3590           }
3591         }
3592         break;
3593       }
3594       case 4: { // QUADRANGLE
3595
3596         if ( nbSame == 0 )       // --- hexahedron
3597           aNewElem = aMesh->AddVolume (prevNod[ i0 ], prevNod[ 1 ], prevNod[ i2 ], prevNod[ 3 ],
3598                                        nextNod[ i0 ], nextNod[ 1 ], nextNod[ i2 ], nextNod[ 3 ]);
3599
3600         else if ( nbSame == 1 ) { // --- pyramid + pentahedron
3601           aNewElem = aMesh->AddVolume (prevNod[ iBeforeSame ],  prevNod[ iAfterSame ],
3602                                        nextNod[ iAfterSame ], nextNod[ iBeforeSame ],
3603                                        nextNod[ iSameNode ]);
3604           newElems.push_back( aNewElem );
3605           aNewElem = aMesh->AddVolume (prevNod[ iAfterSame ], prevNod[ iOpposSame ],
3606                                        prevNod[ iBeforeSame ],  nextNod[ iAfterSame ],
3607                                        nextNod[ iOpposSame ],  nextNod[ iBeforeSame ] );
3608         }
3609         else if ( nbSame == 2 ) { // pentahedron
3610           if ( prevNod[ iBeforeSame ] == nextNod[ iBeforeSame ] )
3611             // iBeforeSame is same too
3612             aNewElem = aMesh->AddVolume (prevNod[ iBeforeSame ], prevNod[ iOpposSame ],
3613                                          nextNod[ iOpposSame ], prevNod[ iSameNode ],
3614                                          prevNod[ iAfterSame ],  nextNod[ iAfterSame ]);
3615           else
3616             // iAfterSame is same too
3617             aNewElem = aMesh->AddVolume (prevNod[ iSameNode ], prevNod[ iBeforeSame ],
3618                                          nextNod[ iBeforeSame ], prevNod[ iAfterSame ],
3619                                          prevNod[ iOpposSame ],  nextNod[ iOpposSame ]);
3620         }
3621         break;
3622       }
3623       case 6: { // quadratic triangle
3624         // create pentahedron with 15 nodes
3625         if(nbSame==0) {
3626           if(i0>0) { // reversed case
3627             aNewElem = aMesh->AddVolume (prevNod[0], prevNod[2], prevNod[1],
3628                                          nextNod[0], nextNod[2], nextNod[1],
3629                                          prevNod[5], prevNod[4], prevNod[3],
3630                                          nextNod[5], nextNod[4], nextNod[3],
3631                                          midlNod[0], midlNod[2], midlNod[1]);
3632           }
3633           else { // not reversed case
3634             aNewElem = aMesh->AddVolume (prevNod[0], prevNod[1], prevNod[2],
3635                                          nextNod[0], nextNod[1], nextNod[2],
3636                                          prevNod[3], prevNod[4], prevNod[5],
3637                                          nextNod[3], nextNod[4], nextNod[5],
3638                                          midlNod[0], midlNod[1], midlNod[2]);
3639           }
3640         }
3641         else if(nbSame==1) {
3642           // 2d order pyramid of 13 nodes
3643           //SMDS_MeshVolume* AddVolumeWithID(int n1, int n2, int n3, int n4, int n5,
3644           //                                 int n12,int n23,int n34,int n41,
3645           //                                 int n15,int n25,int n35,int n45, int ID);
3646           int n5 = iSameNode;
3647           int n1,n4,n41,n15,n45;
3648           if(i0>0) { // reversed case
3649             n1 = ( n5 + 1 == nbBaseNodes ? 0 : n5 + 1 );
3650             n4 = ( n5 == 0 ? nbBaseNodes - 1 : n5 - 1 );
3651             n41 = n1 + 3;
3652             n15 = n5 + 3;
3653             n45 = n4 + 3;
3654           }
3655           else {
3656             n1 = ( n5 == 0 ? nbBaseNodes - 1 : n5 - 1 );
3657             n4 = ( n5 + 1 == nbBaseNodes ? 0 : n5 + 1 );
3658             n41 = n4 + 3;
3659             n15 = n1 + 3;
3660             n45 = n5 + 3;
3661           }
3662           aNewElem = aMesh->AddVolume(prevNod[n1], nextNod[n1],
3663                                       nextNod[n4], prevNod[n4], prevNod[n5],
3664                                       midlNod[n1], nextNod[n41],
3665                                       midlNod[n4], prevNod[n41],
3666                                       prevNod[n15], nextNod[n15],
3667                                       nextNod[n45], prevNod[n45]);
3668         }
3669         else if(nbSame==2) {
3670           // 2d order tetrahedron of 10 nodes
3671           //SMDS_MeshVolume* AddVolumeWithID(int n1, int n2, int n3, int n4,
3672           //                                 int n12,int n23,int n31,
3673           //                                 int n14,int n24,int n34, int ID);
3674           int n1 = iNotSameNode;
3675           int n2,n3,n12,n23,n31;
3676           if(i0>0) { // reversed case
3677             n2 = ( n1 == 0 ? nbBaseNodes - 1 : n1 - 1 );
3678             n3 = ( n1 + 1 == nbBaseNodes ? 0 : n1 + 1 );
3679             n12 = n2 + 3;
3680             n23 = n3 + 3;
3681             n31 = n1 + 3;
3682           }
3683           else {
3684             n2 = ( n1 + 1 == nbBaseNodes ? 0 : n1 + 1 );
3685             n3 = ( n1 == 0 ? nbBaseNodes - 1 : n1 - 1 );
3686             n12 = n1 + 3;
3687             n23 = n2 + 3;
3688             n31 = n3 + 3;
3689           }
3690           aNewElem = aMesh->AddVolume (prevNod[n1], prevNod[n2], prevNod[n3], nextNod[n1],
3691                                        prevNod[n12], prevNod[n23], prevNod[n31],
3692                                        midlNod[n1], nextNod[n12], nextNod[n31]);
3693         }
3694         break;
3695       }
3696       case 8: { // quadratic quadrangle
3697         if(nbSame==0) {
3698           // create hexahedron with 20 nodes
3699           if(i0>0) { // reversed case
3700             aNewElem = aMesh->AddVolume (prevNod[0], prevNod[3], prevNod[2], prevNod[1],
3701                                          nextNod[0], nextNod[3], nextNod[2], nextNod[1],
3702                                          prevNod[7], prevNod[6], prevNod[5], prevNod[4],
3703                                          nextNod[7], nextNod[6], nextNod[5], nextNod[4],
3704                                          midlNod[0], midlNod[3], midlNod[2], midlNod[1]);
3705           }
3706           else { // not reversed case
3707             aNewElem = aMesh->AddVolume (prevNod[0], prevNod[1], prevNod[2], prevNod[3],
3708                                          nextNod[0], nextNod[1], nextNod[2], nextNod[3],
3709                                          prevNod[4], prevNod[5], prevNod[6], prevNod[7],
3710                                          nextNod[4], nextNod[5], nextNod[6], nextNod[7],
3711                                          midlNod[0], midlNod[1], midlNod[2], midlNod[3]);
3712           }
3713         }
3714         else if(nbSame==1) { 
3715           // --- pyramid + pentahedron - can not be created since it is needed 
3716           // additional middle node ot the center of face
3717           INFOS( " Sweep for face " << elem->GetID() << " can not be created" );
3718           return;
3719         }
3720         else if(nbSame==2) {
3721           // 2d order Pentahedron with 15 nodes
3722           //SMDS_MeshVolume* AddVolumeWithID(int n1, int n2, int n3, int n4, int n5, int n6,
3723           //                                 int n12,int n23,int n31,int n45,int n56,int n64,
3724           //                                 int n14,int n25,int n36, int ID);
3725           int n1,n2,n4,n5;
3726           if ( prevNod[ iBeforeSame ] == nextNod[ iBeforeSame ] ) {
3727             // iBeforeSame is same too
3728             n1 = iBeforeSame;
3729             n2 = iOpposSame;
3730             n4 = iSameNode;
3731             n5 = iAfterSame;
3732           }
3733           else {
3734             // iAfterSame is same too
3735             n1 = iSameNode;
3736             n2 = iBeforeSame;
3737             n4 = iAfterSame;
3738             n5 = iOpposSame;
3739           }
3740           int n12,n45,n14,n25;
3741           if(i0>0) { //reversed case
3742             n12 = n1 + 4;
3743             n45 = n5 + 4;
3744             n14 = n4 + 4;
3745             n25 = n2 + 4;
3746           }
3747           else {
3748             n12 = n2 + 4;
3749             n45 = n4 + 4;
3750             n14 = n1 + 4;
3751             n25 = n5 + 4;
3752           }
3753           aNewElem = aMesh->AddVolume (prevNod[n1], prevNod[n2], nextNod[n2],
3754                                        prevNod[n4], prevNod[n5], nextNod[n5],
3755                                        prevNod[n12], midlNod[n2], nextNod[n12],
3756                                        prevNod[n45], midlNod[n5], nextNod[n45],
3757                                        prevNod[n14], prevNod[n25], nextNod[n25]);
3758         }
3759         break;
3760       }
3761       default: {
3762         // realized for extrusion only
3763         //vector<const SMDS_MeshNode*> polyedre_nodes (nbNodes*2 + 4*nbNodes);
3764         //vector<int> quantities (nbNodes + 2);
3765
3766         //quantities[0] = nbNodes; // bottom of prism
3767         //for (int inode = 0; inode < nbNodes; inode++) {
3768         //  polyedre_nodes[inode] = prevNod[inode];
3769         //}
3770
3771         //quantities[1] = nbNodes; // top of prism
3772         //for (int inode = 0; inode < nbNodes; inode++) {
3773         //  polyedre_nodes[nbNodes + inode] = nextNod[inode];
3774         //}
3775
3776         //for (int iface = 0; iface < nbNodes; iface++) {
3777         //  quantities[iface + 2] = 4;
3778         //  int inextface = (iface == nbNodes - 1) ? 0 : iface + 1;
3779         //  polyedre_nodes[2*nbNodes + 4*iface + 0] = prevNod[iface];
3780         //  polyedre_nodes[2*nbNodes + 4*iface + 1] = prevNod[inextface];
3781         //  polyedre_nodes[2*nbNodes + 4*iface + 2] = nextNod[inextface];
3782         //  polyedre_nodes[2*nbNodes + 4*iface + 3] = nextNod[iface];
3783         //}
3784         //aNewElem = aMesh->AddPolyhedralVolume (polyedre_nodes, quantities);
3785         break;
3786       }
3787       }
3788     }
3789
3790     if(!aNewElem) {
3791       // realized for extrusion only
3792       vector<const SMDS_MeshNode*> polyedre_nodes (nbNodes*2 + 4*nbNodes);
3793       vector<int> quantities (nbNodes + 2);
3794
3795       quantities[0] = nbNodes; // bottom of prism
3796       for (int inode = 0; inode < nbNodes; inode++) {
3797         polyedre_nodes[inode] = prevNod[inode];
3798       }
3799
3800       quantities[1] = nbNodes; // top of prism
3801       for (int inode = 0; inode < nbNodes; inode++) {
3802         polyedre_nodes[nbNodes + inode] = nextNod[inode];
3803       }
3804
3805       for (int iface = 0; iface < nbNodes; iface++) {
3806         quantities[iface + 2] = 4;
3807         int inextface = (iface == nbNodes - 1) ? 0 : iface + 1;
3808         polyedre_nodes[2*nbNodes + 4*iface + 0] = prevNod[iface];
3809         polyedre_nodes[2*nbNodes + 4*iface + 1] = prevNod[inextface];
3810         polyedre_nodes[2*nbNodes + 4*iface + 2] = nextNod[inextface];
3811         polyedre_nodes[2*nbNodes + 4*iface + 3] = nextNod[iface];
3812       }
3813       aNewElem = aMesh->AddPolyhedralVolume (polyedre_nodes, quantities);
3814     }
3815
3816     if ( aNewElem ) {
3817       newElems.push_back( aNewElem );
3818       myLastCreatedElems.Append(aNewElem);
3819       srcElements.Append( elem );
3820       lastElem = aNewElem;
3821     }
3822
3823     // set new prev nodes
3824     for ( iNode = 0; iNode < nbNodes; iNode++ )
3825       prevNod[ iNode ] = nextNod[ iNode ];
3826
3827   } // for steps
3828 }
3829
3830 //=======================================================================
3831 /*!
3832  * \brief Create 1D and 2D elements around swept elements
3833  * \param mapNewNodes - source nodes and ones generated from them
3834  * \param newElemsMap - source elements and ones generated from them
3835  * \param elemNewNodesMap - nodes generated from each node of each element
3836  * \param elemSet - all swept elements
3837  * \param nbSteps - number of sweeping steps
3838  * \param srcElements - to append elem for each generated element
3839  */
3840 //=======================================================================
3841
3842 void SMESH_MeshEditor::makeWalls (TNodeOfNodeListMap &     mapNewNodes,
3843                                   TElemOfElemListMap &     newElemsMap,
3844                                   TElemOfVecOfNnlmiMap &   elemNewNodesMap,
3845                                   TIDSortedElemSet&        elemSet,
3846                                   const int                nbSteps,
3847                                   SMESH_SequenceOfElemPtr& srcElements)
3848 {
3849   MESSAGE("makeWalls");
3850   ASSERT( newElemsMap.size() == elemNewNodesMap.size() );
3851   SMESHDS_Mesh* aMesh = GetMeshDS();
3852
3853   // Find nodes belonging to only one initial element - sweep them to get edges.
3854
3855   TNodeOfNodeListMapItr nList = mapNewNodes.begin();
3856   for ( ; nList != mapNewNodes.end(); nList++ ) {
3857     const SMDS_MeshNode* node =
3858       static_cast<const SMDS_MeshNode*>( nList->first );
3859     SMDS_ElemIteratorPtr eIt = node->GetInverseElementIterator();
3860     int nbInitElems = 0;
3861     const SMDS_MeshElement* el = 0;
3862     SMDSAbs_ElementType highType = SMDSAbs_Edge; // count most complex elements only
3863     while ( eIt->more() && nbInitElems < 2 ) {
3864       el = eIt->next();
3865       SMDSAbs_ElementType type = el->GetType();
3866       if ( type == SMDSAbs_Volume || type < highType ) continue;
3867       if ( type > highType ) {
3868         nbInitElems = 0;
3869         highType = type;
3870       }
3871       if ( elemSet.find(el) != elemSet.end() )
3872         nbInitElems++;
3873     }
3874     if ( nbInitElems < 2 ) {
3875       bool NotCreateEdge = el && el->IsQuadratic() && el->IsMediumNode(node);
3876       if(!NotCreateEdge) {
3877         vector<TNodeOfNodeListMapItr> newNodesItVec( 1, nList );
3878         list<const SMDS_MeshElement*> newEdges;
3879         sweepElement( node, newNodesItVec, newEdges, nbSteps, srcElements );
3880       }
3881     }
3882   }
3883
3884   // Make a ceiling for each element ie an equal element of last new nodes.
3885   // Find free links of faces - make edges and sweep them into faces.
3886
3887   TElemOfElemListMap::iterator   itElem      = newElemsMap.begin();
3888   TElemOfVecOfNnlmiMap::iterator itElemNodes = elemNewNodesMap.begin();
3889   for ( ; itElem != newElemsMap.end(); itElem++, itElemNodes++ ) {
3890     const SMDS_MeshElement* elem = itElem->first;
3891     vector<TNodeOfNodeListMapItr>& vecNewNodes = itElemNodes->second;
3892
3893     if(itElem->second.size()==0) continue;
3894
3895     if ( elem->GetType() == SMDSAbs_Edge ) {
3896       // create a ceiling edge
3897       if (!elem->IsQuadratic()) {
3898         if ( !aMesh->FindEdge( vecNewNodes[ 0 ]->second.back(),
3899                                vecNewNodes[ 1 ]->second.back())) {
3900           myLastCreatedElems.Append(aMesh->AddEdge(vecNewNodes[ 0 ]->second.back(),
3901                                                    vecNewNodes[ 1 ]->second.back()));
3902           srcElements.Append( myLastCreatedElems.Last() );
3903         }
3904       }
3905       else {
3906         if ( !aMesh->FindEdge( vecNewNodes[ 0 ]->second.back(),
3907                                vecNewNodes[ 1 ]->second.back(),
3908                                vecNewNodes[ 2 ]->second.back())) {
3909           myLastCreatedElems.Append(aMesh->AddEdge(vecNewNodes[ 0 ]->second.back(),
3910                                                    vecNewNodes[ 1 ]->second.back(),
3911                                                    vecNewNodes[ 2 ]->second.back()));
3912           srcElements.Append( myLastCreatedElems.Last() );
3913         }
3914       }
3915     }
3916     if ( elem->GetType() != SMDSAbs_Face )
3917       continue;
3918
3919     bool hasFreeLinks = false;
3920
3921     TIDSortedElemSet avoidSet;
3922     avoidSet.insert( elem );
3923
3924     set<const SMDS_MeshNode*> aFaceLastNodes;
3925     int iNode, nbNodes = vecNewNodes.size();
3926     if(!elem->IsQuadratic()) {
3927       // loop on the face nodes
3928       for ( iNode = 0; iNode < nbNodes; iNode++ ) {
3929         aFaceLastNodes.insert( vecNewNodes[ iNode ]->second.back() );
3930         // look for free links of the face
3931         int iNext = ( iNode + 1 == nbNodes ) ? 0 : iNode + 1;
3932         const SMDS_MeshNode* n1 = vecNewNodes[ iNode ]->first;
3933         const SMDS_MeshNode* n2 = vecNewNodes[ iNext ]->first;
3934         // check if a link is free
3935         if ( ! SMESH_MeshEditor::FindFaceInSet ( n1, n2, elemSet, avoidSet )) {
3936           hasFreeLinks = true;
3937           // make an edge and a ceiling for a new edge
3938           if ( !aMesh->FindEdge( n1, n2 )) {
3939             myLastCreatedElems.Append(aMesh->AddEdge( n1, n2 )); // free link edge
3940             srcElements.Append( myLastCreatedElems.Last() );
3941           }
3942           n1 = vecNewNodes[ iNode ]->second.back();
3943           n2 = vecNewNodes[ iNext ]->second.back();
3944           if ( !aMesh->FindEdge( n1, n2 )) {
3945             myLastCreatedElems.Append(aMesh->AddEdge( n1, n2 )); // ceiling edge
3946             srcElements.Append( myLastCreatedElems.Last() );
3947           }
3948         }
3949       }
3950     }
3951     else { // elem is quadratic face
3952       int nbn = nbNodes/2;
3953       for ( iNode = 0; iNode < nbn; iNode++ ) {
3954         aFaceLastNodes.insert( vecNewNodes[ iNode ]->second.back() );
3955         int iNext = ( iNode + 1 == nbn ) ? 0 : iNode + 1;
3956         const SMDS_MeshNode* n1 = vecNewNodes[ iNode ]->first;
3957         const SMDS_MeshNode* n2 = vecNewNodes[ iNext ]->first;
3958         // check if a link is free
3959         if ( ! SMESH_MeshEditor::FindFaceInSet ( n1, n2, elemSet, avoidSet )) {
3960           hasFreeLinks = true;
3961           // make an edge and a ceiling for a new edge
3962           // find medium node
3963           const SMDS_MeshNode* n3 = vecNewNodes[ iNode+nbn ]->first;
3964           if ( !aMesh->FindEdge( n1, n2, n3 )) {
3965             myLastCreatedElems.Append(aMesh->AddEdge( n1, n2, n3 )); // free link edge
3966             srcElements.Append( myLastCreatedElems.Last() );
3967           }
3968           n1 = vecNewNodes[ iNode ]->second.back();
3969           n2 = vecNewNodes[ iNext ]->second.back();
3970           n3 = vecNewNodes[ iNode+nbn ]->second.back();
3971           if ( !aMesh->FindEdge( n1, n2, n3 )) {
3972             myLastCreatedElems.Append(aMesh->AddEdge( n1, n2, n3 )); // ceiling edge
3973             srcElements.Append( myLastCreatedElems.Last() );
3974           }
3975         }
3976       }
3977       for ( iNode = nbn; iNode < 2*nbn; iNode++ ) {
3978         aFaceLastNodes.insert( vecNewNodes[ iNode ]->second.back() );
3979       }
3980     }
3981
3982     // sweep free links into faces
3983
3984     if ( hasFreeLinks )  {
3985       list<const SMDS_MeshElement*> & newVolumes = itElem->second;
3986       int iVol, volNb, nbVolumesByStep = newVolumes.size() / nbSteps;
3987
3988       set<const SMDS_MeshNode*> initNodeSet, topNodeSet, faceNodeSet;
3989       for ( iNode = 0; iNode < nbNodes; iNode++ ) {
3990         initNodeSet.insert( vecNewNodes[ iNode ]->first );
3991         topNodeSet .insert( vecNewNodes[ iNode ]->second.back() );
3992       }
3993       for ( volNb = 0; volNb < nbVolumesByStep; volNb++ ) {
3994         list<const SMDS_MeshElement*>::iterator v = newVolumes.begin();
3995         iVol = 0;
3996         while ( iVol++ < volNb ) v++;
3997         // find indices of free faces of a volume and their source edges
3998         list< int > freeInd;
3999         list< const SMDS_MeshElement* > srcEdges; // source edges of free faces
4000         SMDS_VolumeTool vTool( *v );
4001         int iF, nbF = vTool.NbFaces();
4002         for ( iF = 0; iF < nbF; iF ++ ) {
4003           if (vTool.IsFreeFace( iF ) &&
4004               vTool.GetFaceNodes( iF, faceNodeSet ) &&
4005               initNodeSet != faceNodeSet) // except an initial face
4006           {
4007             if ( nbSteps == 1 && faceNodeSet == topNodeSet )
4008               continue;
4009             freeInd.push_back( iF );
4010             // find source edge of a free face iF
4011             vector<const SMDS_MeshNode*> commonNodes; // shared by the initial and free faces
4012             commonNodes.resize( initNodeSet.size(), NULL ); // avoid spoiling memory
4013             std::set_intersection( faceNodeSet.begin(), faceNodeSet.end(),
4014                                    initNodeSet.begin(), initNodeSet.end(),
4015                                    commonNodes.begin());
4016             if ( (*v)->IsQuadratic() )
4017               srcEdges.push_back(aMesh->FindEdge (commonNodes[0],commonNodes[1],commonNodes[2]));
4018             else
4019               srcEdges.push_back(aMesh->FindEdge (commonNodes[0],commonNodes[1]));
4020 #ifdef _DEBUG_
4021             if ( !srcEdges.back() )
4022             {
4023               cout << "SMESH_MeshEditor::makeWalls(), no source edge found for a free face #"
4024                    << iF << " of volume #" << vTool.ID() << endl;
4025             }
4026 #endif
4027           }
4028         }
4029         if ( freeInd.empty() )
4030           continue;
4031
4032         // create faces for all steps;
4033         // if such a face has been already created by sweep of edge,
4034         // assure that its orientation is OK
4035         for ( int iStep = 0; iStep < nbSteps; iStep++ )  {
4036           vTool.Set( *v );
4037           vTool.SetExternalNormal();
4038           list< int >::iterator ind = freeInd.begin();
4039           list< const SMDS_MeshElement* >::iterator srcEdge = srcEdges.begin();
4040           for ( ; ind != freeInd.end(); ++ind, ++srcEdge ) // loop on free faces
4041           {
4042             const SMDS_MeshNode** nodes = vTool.GetFaceNodes( *ind );
4043             int nbn = vTool.NbFaceNodes( *ind );
4044             switch ( nbn ) {
4045             case 3: { ///// triangle
4046               const SMDS_MeshFace * f = aMesh->FindFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ]);
4047               if ( !f )
4048                 myLastCreatedElems.Append(aMesh->AddFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ] ));
4049               else if ( nodes[ 1 ] != f->GetNodeWrap( f->GetNodeIndex( nodes[ 0 ] ) + 1 ))
4050                 {
4051                   myLastCreatedElems.Append(aMesh->AddFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ] ));
4052                   aMesh->RemoveElement(f);
4053                 }
4054               break;
4055             }
4056             case 4: { ///// quadrangle
4057               const SMDS_MeshFace * f = aMesh->FindFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ], nodes[ 3 ]);
4058               if ( !f )
4059                 myLastCreatedElems.Append(aMesh->AddFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ], nodes[ 3 ] ));
4060               else if ( nodes[ 1 ] != f->GetNodeWrap( f->GetNodeIndex( nodes[ 0 ] ) + 1 ))
4061                 {
4062                   myLastCreatedElems.Append(aMesh->AddFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ], nodes[ 3 ] ));
4063                   aMesh->RemoveElement(f);
4064                 }
4065               break;
4066             }
4067             default:
4068               if( (*v)->IsQuadratic() ) {
4069                 if(nbn==6) { /////// quadratic triangle
4070                   const SMDS_MeshFace * f = aMesh->FindFace( nodes[0], nodes[2], nodes[4],
4071                                                              nodes[1], nodes[3], nodes[5] );
4072                   if ( !f ) {
4073                     myLastCreatedElems.Append(aMesh->AddFace(nodes[0], nodes[2], nodes[4],
4074                                                              nodes[1], nodes[3], nodes[5]));
4075                   }
4076                   else if ( nodes[ 2 ] != f->GetNodeWrap( f->GetNodeIndex( nodes[ 0 ] ) + 1 )) {
4077                     const SMDS_MeshNode** tmpnodes = new const SMDS_MeshNode*[6];
4078                     tmpnodes[0] = nodes[0];
4079                     tmpnodes[1] = nodes[2];
4080                     tmpnodes[2] = nodes[4];
4081                     tmpnodes[3] = nodes[1];
4082                     tmpnodes[4] = nodes[3];
4083                     tmpnodes[5] = nodes[5];
4084                     myLastCreatedElems.Append(aMesh->AddFace(nodes[0], nodes[2], nodes[4],
4085                                                              nodes[1], nodes[3], nodes[5]));
4086                     aMesh->RemoveElement(f);
4087                   }
4088                 }
4089                 else {       /////// quadratic quadrangle
4090                   const SMDS_MeshFace * f = aMesh->FindFace( nodes[0], nodes[2], nodes[4], nodes[6],
4091                                                              nodes[1], nodes[3], nodes[5], nodes[7] );
4092                   if ( !f ) {
4093                     myLastCreatedElems.Append(aMesh->AddFace(nodes[0], nodes[2], nodes[4], nodes[6],
4094                                                              nodes[1], nodes[3], nodes[5], nodes[7]));
4095                   }
4096                   else if ( nodes[ 2 ] != f->GetNodeWrap( f->GetNodeIndex( nodes[ 0 ] ) + 1 )) {
4097                     const SMDS_MeshNode** tmpnodes = new const SMDS_MeshNode*[8];
4098                     tmpnodes[0] = nodes[0];
4099                     tmpnodes[1] = nodes[2];
4100                     tmpnodes[2] = nodes[4];
4101                     tmpnodes[3] = nodes[6];
4102                     tmpnodes[4] = nodes[1];
4103                     tmpnodes[5] = nodes[3];
4104                     tmpnodes[6] = nodes[5];
4105                     tmpnodes[7] = nodes[7];
4106                     myLastCreatedElems.Append(aMesh->AddFace(nodes[0], nodes[2], nodes[4], nodes[6],
4107                                                              nodes[1], nodes[3], nodes[5], nodes[7]));
4108                     aMesh->RemoveElement(f);
4109                   }
4110                 }
4111               }
4112               else { //////// polygon
4113                 vector<const SMDS_MeshNode*> polygon_nodes ( nodes, &nodes[nbn] );
4114                 const SMDS_MeshFace * f = aMesh->FindFace( polygon_nodes );
4115                 if ( !f )
4116                   myLastCreatedElems.Append(aMesh->AddPolygonalFace(polygon_nodes));
4117                 else if ( nodes[ 1 ] != f->GetNodeWrap( f->GetNodeIndex( nodes[ 0 ] ) + 1 ))
4118                   {
4119                   // TODO problem ChangeElementNodes : not the same number of nodes, not the same type
4120                   MESSAGE("ChangeElementNodes");
4121                   aMesh->ChangeElementNodes( f, nodes, nbn );
4122                   }
4123               }
4124             }
4125             while ( srcElements.Length() < myLastCreatedElems.Length() )
4126               srcElements.Append( *srcEdge );
4127
4128           }  // loop on free faces
4129
4130           // go to the next volume
4131           iVol = 0;
4132           while ( iVol++ < nbVolumesByStep ) v++;
4133         }
4134       }
4135     } // sweep free links into faces
4136
4137     // Make a ceiling face with a normal external to a volume
4138
4139     SMDS_VolumeTool lastVol( itElem->second.back() );
4140
4141     int iF = lastVol.GetFaceIndex( aFaceLastNodes );
4142     if ( iF >= 0 ) {
4143       lastVol.SetExternalNormal();
4144       const SMDS_MeshNode** nodes = lastVol.GetFaceNodes( iF );
4145       int nbn = lastVol.NbFaceNodes( iF );
4146       switch ( nbn ) {
4147       case 3:
4148         if (!hasFreeLinks ||
4149             !aMesh->FindFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ]))
4150           myLastCreatedElems.Append(aMesh->AddFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ] ));
4151         break;
4152       case 4:
4153         if (!hasFreeLinks ||
4154             !aMesh->FindFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ], nodes[ 3 ]))
4155           myLastCreatedElems.Append(aMesh->AddFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ], nodes[ 3 ] ));
4156         break;
4157       default:
4158         if(itElem->second.back()->IsQuadratic()) {
4159           if(nbn==6) {
4160             if (!hasFreeLinks ||
4161                 !aMesh->FindFace(nodes[0], nodes[2], nodes[4],
4162                                  nodes[1], nodes[3], nodes[5]) ) {
4163               myLastCreatedElems.Append(aMesh->AddFace(nodes[0], nodes[2], nodes[4],
4164                                                        nodes[1], nodes[3], nodes[5]));
4165             }
4166           }
4167           else { // nbn==8
4168             if (!hasFreeLinks ||
4169                 !aMesh->FindFace(nodes[0], nodes[2], nodes[4], nodes[6],
4170                                  nodes[1], nodes[3], nodes[5], nodes[7]) )
4171               myLastCreatedElems.Append(aMesh->AddFace(nodes[0], nodes[2], nodes[4], nodes[6],
4172                                                        nodes[1], nodes[3], nodes[5], nodes[7]));
4173           }
4174         }
4175         else {
4176           vector<const SMDS_MeshNode*> polygon_nodes ( nodes, &nodes[nbn] );
4177           if (!hasFreeLinks || !aMesh->FindFace(polygon_nodes))
4178             myLastCreatedElems.Append(aMesh->AddPolygonalFace(polygon_nodes));
4179         }
4180       } // switch
4181
4182       while ( srcElements.Length() < myLastCreatedElems.Length() )
4183         srcElements.Append( myLastCreatedElems.Last() );
4184     }
4185   } // loop on swept elements
4186 }
4187
4188 //=======================================================================
4189 //function : RotationSweep
4190 //purpose  :
4191 //=======================================================================
4192
4193 SMESH_MeshEditor::PGroupIDs
4194 SMESH_MeshEditor::RotationSweep(TIDSortedElemSet & theElems,
4195                                 const gp_Ax1&      theAxis,
4196                                 const double       theAngle,
4197                                 const int          theNbSteps,
4198                                 const double       theTol,
4199                                 const bool         theMakeGroups,
4200                                 const bool         theMakeWalls)
4201 {
4202   myLastCreatedElems.Clear();
4203   myLastCreatedNodes.Clear();
4204
4205   // source elements for each generated one
4206   SMESH_SequenceOfElemPtr srcElems, srcNodes;
4207
4208   MESSAGE( "RotationSweep()");
4209   gp_Trsf aTrsf;
4210   aTrsf.SetRotation( theAxis, theAngle );
4211   gp_Trsf aTrsf2;
4212   aTrsf2.SetRotation( theAxis, theAngle/2. );
4213
4214   gp_Lin aLine( theAxis );
4215   double aSqTol = theTol * theTol;
4216
4217   SMESHDS_Mesh* aMesh = GetMeshDS();
4218
4219   TNodeOfNodeListMap mapNewNodes;
4220   TElemOfVecOfNnlmiMap mapElemNewNodes;
4221   TElemOfElemListMap newElemsMap;
4222
4223   // loop on theElems
4224   TIDSortedElemSet::iterator itElem;
4225   for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
4226     const SMDS_MeshElement* elem = *itElem;
4227     if ( !elem || elem->GetType() == SMDSAbs_Volume )
4228       continue;
4229     vector<TNodeOfNodeListMapItr> & newNodesItVec = mapElemNewNodes[ elem ];
4230     newNodesItVec.reserve( elem->NbNodes() );
4231
4232     // loop on elem nodes
4233     SMDS_ElemIteratorPtr itN = elem->nodesIterator();
4234     while ( itN->more() ) {
4235       // check if a node has been already sweeped
4236       const SMDS_MeshNode* node = cast2Node( itN->next() );
4237
4238       gp_XYZ aXYZ( node->X(), node->Y(), node->Z() );
4239       double coord[3];
4240       aXYZ.Coord( coord[0], coord[1], coord[2] );
4241       bool isOnAxis = ( aLine.SquareDistance( aXYZ ) <= aSqTol );
4242
4243       TNodeOfNodeListMapItr nIt = mapNewNodes.find( node );
4244       if ( nIt == mapNewNodes.end() ) {
4245         nIt = mapNewNodes.insert( make_pair( node, list<const SMDS_MeshNode*>() )).first;
4246         list<const SMDS_MeshNode*>& listNewNodes = nIt->second;
4247
4248         // make new nodes
4249         //gp_XYZ aXYZ( node->X(), node->Y(), node->Z() );
4250         //double coord[3];
4251         //aXYZ.Coord( coord[0], coord[1], coord[2] );
4252         //bool isOnAxis = ( aLine.SquareDistance( aXYZ ) <= aSqTol );
4253         const SMDS_MeshNode * newNode = node;
4254         for ( int i = 0; i < theNbSteps; i++ ) {
4255           if ( !isOnAxis ) {
4256             if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
4257               // create two nodes
4258               aTrsf2.Transforms( coord[0], coord[1], coord[2] );
4259               //aTrsf.Transforms( coord[0], coord[1], coord[2] );
4260               newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
4261               myLastCreatedNodes.Append(newNode);
4262               srcNodes.Append( node );
4263               listNewNodes.push_back( newNode );
4264               aTrsf2.Transforms( coord[0], coord[1], coord[2] );
4265               //aTrsf.Transforms( coord[0], coord[1], coord[2] );
4266             }
4267             else {
4268               aTrsf.Transforms( coord[0], coord[1], coord[2] );
4269             }
4270             newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
4271             myLastCreatedNodes.Append(newNode);
4272             srcNodes.Append( node );
4273             listNewNodes.push_back( newNode );
4274           }
4275           else {
4276             listNewNodes.push_back( newNode );
4277             if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
4278               listNewNodes.push_back( newNode );
4279             }
4280           }
4281         }
4282       }
4283       /*
4284         else {
4285         // if current elem is quadratic and current node is not medium
4286         // we have to check - may be it is needed to insert additional nodes
4287         if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
4288         list< const SMDS_MeshNode* > & listNewNodes = nIt->second;
4289         if(listNewNodes.size()==theNbSteps) {
4290         listNewNodes.clear();
4291         // make new nodes
4292         //gp_XYZ aXYZ( node->X(), node->Y(), node->Z() );
4293         //double coord[3];
4294         //aXYZ.Coord( coord[0], coord[1], coord[2] );
4295         const SMDS_MeshNode * newNode = node;
4296         if ( !isOnAxis ) {
4297         for(int i = 0; i<theNbSteps; i++) {
4298         aTrsf2.Transforms( coord[0], coord[1], coord[2] );
4299         newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
4300         cout<<"    3 AddNode:  "<<newNode;
4301         myLastCreatedNodes.Append(newNode);
4302         listNewNodes.push_back( newNode );
4303         srcNodes.Append( node );
4304         aTrsf2.Transforms( coord[0], coord[1], coord[2] );
4305         newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
4306         cout<<"    4 AddNode:  "<<newNode;
4307         myLastCreatedNodes.Append(newNode);
4308         srcNodes.Append( node );
4309         listNewNodes.push_back( newNode );
4310         }
4311         }
4312         else {
4313         listNewNodes.push_back( newNode );
4314         }
4315         }
4316         }
4317         }
4318       */
4319       newNodesItVec.push_back( nIt );
4320     }
4321     // make new elements
4322     sweepElement( elem, newNodesItVec, newElemsMap[elem], theNbSteps, srcElems );
4323   }
4324
4325   if ( theMakeWalls )
4326     makeWalls( mapNewNodes, newElemsMap, mapElemNewNodes, theElems, theNbSteps, srcElems );
4327
4328   PGroupIDs newGroupIDs;
4329   if ( theMakeGroups )
4330     newGroupIDs = generateGroups( srcNodes, srcElems, "rotated");
4331
4332   return newGroupIDs;
4333 }
4334
4335
4336 //=======================================================================
4337 //function : CreateNode
4338 //purpose  :
4339 //=======================================================================
4340 const SMDS_MeshNode* SMESH_MeshEditor::CreateNode(const double x,
4341                                                   const double y,
4342                                                   const double z,
4343                                                   const double tolnode,
4344                                                   SMESH_SequenceOfNode& aNodes)
4345 {
4346   myLastCreatedElems.Clear();
4347   myLastCreatedNodes.Clear();
4348
4349   gp_Pnt P1(x,y,z);
4350   SMESHDS_Mesh * aMesh = myMesh->GetMeshDS();
4351
4352   // try to search in sequence of existing nodes
4353   // if aNodes.Length()>0 we 'nave to use given sequence
4354   // else - use all nodes of mesh
4355   if(aNodes.Length()>0) {
4356     int i;
4357     for(i=1; i<=aNodes.Length(); i++) {
4358       gp_Pnt P2(aNodes.Value(i)->X(),aNodes.Value(i)->Y(),aNodes.Value(i)->Z());
4359       if(P1.Distance(P2)<tolnode)
4360         return aNodes.Value(i);
4361     }
4362   }
4363   else {
4364     SMDS_NodeIteratorPtr itn = aMesh->nodesIterator();
4365     while(itn->more()) {
4366       const SMDS_MeshNode* aN = static_cast<const SMDS_MeshNode*> (itn->next());
4367       gp_Pnt P2(aN->X(),aN->Y(),aN->Z());
4368       if(P1.Distance(P2)<tolnode)
4369         return aN;
4370     }
4371   }
4372
4373   // create new node and return it
4374   const SMDS_MeshNode* NewNode = aMesh->AddNode(x,y,z);
4375   myLastCreatedNodes.Append(NewNode);
4376   return NewNode;
4377 }
4378
4379
4380 //=======================================================================
4381 //function : ExtrusionSweep
4382 //purpose  :
4383 //=======================================================================
4384
4385 SMESH_MeshEditor::PGroupIDs
4386 SMESH_MeshEditor::ExtrusionSweep (TIDSortedElemSet &  theElems,
4387                                   const gp_Vec&       theStep,
4388                                   const int           theNbSteps,
4389                                   TElemOfElemListMap& newElemsMap,
4390                                   const bool          theMakeGroups,
4391                                   const int           theFlags,
4392                                   const double        theTolerance)
4393 {
4394   ExtrusParam aParams;
4395   aParams.myDir = gp_Dir(theStep);
4396   aParams.myNodes.Clear();
4397   aParams.mySteps = new TColStd_HSequenceOfReal;
4398   int i;
4399   for(i=1; i<=theNbSteps; i++)
4400     aParams.mySteps->Append(theStep.Magnitude());
4401
4402   return
4403     ExtrusionSweep(theElems,aParams,newElemsMap,theMakeGroups,theFlags,theTolerance);
4404 }
4405
4406
4407 //=======================================================================
4408 //function : ExtrusionSweep
4409 //purpose  :
4410 //=======================================================================
4411
4412 SMESH_MeshEditor::PGroupIDs
4413 SMESH_MeshEditor::ExtrusionSweep (TIDSortedElemSet &  theElems,
4414                                   ExtrusParam&        theParams,
4415                                   TElemOfElemListMap& newElemsMap,
4416                                   const bool          theMakeGroups,
4417                                   const int           theFlags,
4418                                   const double        theTolerance)
4419 {
4420   MESSAGE("ExtrusionSweep " << theMakeGroups << " " << theFlags << " " << theTolerance);
4421   myLastCreatedElems.Clear();
4422   myLastCreatedNodes.Clear();
4423
4424   // source elements for each generated one
4425   SMESH_SequenceOfElemPtr srcElems, srcNodes;
4426
4427   SMESHDS_Mesh* aMesh = GetMeshDS();
4428
4429   int nbsteps = theParams.mySteps->Length();
4430
4431   TNodeOfNodeListMap mapNewNodes;
4432   //TNodeOfNodeVecMap mapNewNodes;
4433   TElemOfVecOfNnlmiMap mapElemNewNodes;
4434   //TElemOfVecOfMapNodesMap mapElemNewNodes;
4435
4436   // loop on theElems
4437   TIDSortedElemSet::iterator itElem;
4438   for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
4439     // check element type
4440     const SMDS_MeshElement* elem = *itElem;
4441     if ( !elem  || elem->GetType() == SMDSAbs_Volume )
4442       continue;
4443
4444     vector<TNodeOfNodeListMapItr> & newNodesItVec = mapElemNewNodes[ elem ];
4445     //vector<TNodeOfNodeVecMapItr> & newNodesItVec = mapElemNewNodes[ elem ];
4446     newNodesItVec.reserve( elem->NbNodes() );
4447
4448     // loop on elem nodes
4449     SMDS_ElemIteratorPtr itN = elem->nodesIterator();
4450     while ( itN->more() )
4451     {
4452       // check if a node has been already sweeped
4453       const SMDS_MeshNode* node = cast2Node( itN->next() );
4454       TNodeOfNodeListMap::iterator nIt = mapNewNodes.find( node );
4455       //TNodeOfNodeVecMap::iterator nIt = mapNewNodes.find( node );
4456       if ( nIt == mapNewNodes.end() ) {
4457         nIt = mapNewNodes.insert( make_pair( node, list<const SMDS_MeshNode*>() )).first;
4458         //nIt = mapNewNodes.insert( make_pair( node, vector<const SMDS_MeshNode*>() )).first;
4459         list<const SMDS_MeshNode*>& listNewNodes = nIt->second;
4460         //vector<const SMDS_MeshNode*>& vecNewNodes = nIt->second;
4461         //vecNewNodes.reserve(nbsteps);
4462
4463         // make new nodes
4464         double coord[] = { node->X(), node->Y(), node->Z() };
4465         //int nbsteps = theParams.mySteps->Length();
4466         for ( int i = 0; i < nbsteps; i++ ) {
4467           if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
4468             // create additional node
4469             double x = coord[0] + theParams.myDir.X()*theParams.mySteps->Value(i+1)/2.;
4470             double y = coord[1] + theParams.myDir.Y()*theParams.mySteps->Value(i+1)/2.;
4471             double z = coord[2] + theParams.myDir.Z()*theParams.mySteps->Value(i+1)/2.;
4472             if( theFlags & EXTRUSION_FLAG_SEW ) {
4473               const SMDS_MeshNode * newNode = CreateNode(x, y, z,
4474                                                          theTolerance, theParams.myNodes);
4475               listNewNodes.push_back( newNode );
4476             }
4477             else {
4478               const SMDS_MeshNode * newNode = aMesh->AddNode(x, y, z);
4479               myLastCreatedNodes.Append(newNode);
4480               srcNodes.Append( node );
4481               listNewNodes.push_back( newNode );
4482             }
4483           }
4484           //aTrsf.Transforms( coord[0], coord[1], coord[2] );
4485           coord[0] = coord[0] + theParams.myDir.X()*theParams.mySteps->Value(i+1);
4486           coord[1] = coord[1] + theParams.myDir.Y()*theParams.mySteps->Value(i+1);
4487           coord[2] = coord[2] + theParams.myDir.Z()*theParams.mySteps->Value(i+1);
4488           if( theFlags & EXTRUSION_FLAG_SEW ) {
4489             const SMDS_MeshNode * newNode = CreateNode(coord[0], coord[1], coord[2],
4490                                                        theTolerance, theParams.myNodes);
4491             listNewNodes.push_back( newNode );
4492             //vecNewNodes[i]=newNode;
4493           }
4494           else {
4495             const SMDS_MeshNode * newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
4496             myLastCreatedNodes.Append(newNode);
4497             srcNodes.Append( node );
4498             listNewNodes.push_back( newNode );
4499             //vecNewNodes[i]=newNode;
4500           }
4501         }
4502       }
4503       else {
4504         // if current elem is quadratic and current node is not medium
4505         // we have to check - may be it is needed to insert additional nodes
4506         if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
4507           list< const SMDS_MeshNode* > & listNewNodes = nIt->second;
4508           if(listNewNodes.size()==nbsteps) {
4509             listNewNodes.clear();
4510             double coord[] = { node->X(), node->Y(), node->Z() };
4511             for ( int i = 0; i < nbsteps; i++ ) {
4512               double x = coord[0] + theParams.myDir.X()*theParams.mySteps->Value(i+1);
4513               double y = coord[1] + theParams.myDir.Y()*theParams.mySteps->Value(i+1);
4514               double z = coord[2] + theParams.myDir.Z()*theParams.mySteps->Value(i+1);
4515               if( theFlags & EXTRUSION_FLAG_SEW ) {
4516                 const SMDS_MeshNode * newNode = CreateNode(x, y, z,
4517                                                            theTolerance, theParams.myNodes);
4518                 listNewNodes.push_back( newNode );
4519               }
4520               else {
4521                 const SMDS_MeshNode * newNode = aMesh->AddNode(x, y, z);
4522                 myLastCreatedNodes.Append(newNode);
4523                 srcNodes.Append( node );
4524                 listNewNodes.push_back( newNode );
4525               }
4526               coord[0] = coord[0] + theParams.myDir.X()*theParams.mySteps->Value(i+1);
4527               coord[1] = coord[1] + theParams.myDir.Y()*theParams.mySteps->Value(i+1);
4528               coord[2] = coord[2] + theParams.myDir.Z()*theParams.mySteps->Value(i+1);
4529               if( theFlags & EXTRUSION_FLAG_SEW ) {
4530                 const SMDS_MeshNode * newNode = CreateNode(coord[0], coord[1], coord[2],
4531                                                            theTolerance, theParams.myNodes);
4532                 listNewNodes.push_back( newNode );
4533               }
4534               else {
4535                 const SMDS_MeshNode * newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
4536                 myLastCreatedNodes.Append(newNode);
4537                 srcNodes.Append( node );
4538                 listNewNodes.push_back( newNode );
4539               }
4540             }
4541           }
4542         }
4543       }
4544       newNodesItVec.push_back( nIt );
4545     }
4546     // make new elements
4547     sweepElement( elem, newNodesItVec, newElemsMap[elem], nbsteps, srcElems );
4548   }
4549
4550   if( theFlags & EXTRUSION_FLAG_BOUNDARY ) {
4551     makeWalls( mapNewNodes, newElemsMap, mapElemNewNodes, theElems, nbsteps, srcElems );
4552   }
4553   PGroupIDs newGroupIDs;
4554   if ( theMakeGroups )
4555     newGroupIDs = generateGroups( srcNodes, srcElems, "extruded");
4556
4557   return newGroupIDs;
4558 }
4559
4560 /*
4561 //=======================================================================
4562 //class    : SMESH_MeshEditor_PathPoint
4563 //purpose  : auxiliary class
4564 //=======================================================================
4565 class SMESH_MeshEditor_PathPoint {
4566 public:
4567 SMESH_MeshEditor_PathPoint() {
4568 myPnt.SetCoord(99., 99., 99.);
4569 myTgt.SetCoord(1.,0.,0.);
4570 myAngle=0.;
4571 myPrm=0.;
4572 }
4573 void SetPnt(const gp_Pnt& aP3D){
4574 myPnt=aP3D;
4575 }
4576 void SetTangent(const gp_Dir& aTgt){
4577 myTgt=aTgt;
4578 }
4579 void SetAngle(const double& aBeta){
4580 myAngle=aBeta;
4581 }
4582 void SetParameter(const double& aPrm){
4583 myPrm=aPrm;
4584 }
4585 const gp_Pnt& Pnt()const{
4586 return myPnt;
4587 }
4588 const gp_Dir& Tangent()const{
4589 return myTgt;
4590 }
4591 double Angle()const{
4592 return myAngle;
4593 }
4594 double Parameter()const{
4595 return myPrm;
4596 }
4597
4598 protected:
4599 gp_Pnt myPnt;
4600 gp_Dir myTgt;
4601 double myAngle;
4602 double myPrm;
4603 };
4604 */
4605
4606 //=======================================================================
4607 //function : ExtrusionAlongTrack
4608 //purpose  :
4609 //=======================================================================
4610 SMESH_MeshEditor::Extrusion_Error
4611 SMESH_MeshEditor::ExtrusionAlongTrack (TIDSortedElemSet &   theElements,
4612                                        SMESH_subMesh*       theTrack,
4613                                        const SMDS_MeshNode* theN1,
4614                                        const bool           theHasAngles,
4615                                        list<double>&        theAngles,
4616                                        const bool           theLinearVariation,
4617                                        const bool           theHasRefPoint,
4618                                        const gp_Pnt&        theRefPoint,
4619                                        const bool           theMakeGroups)
4620 {
4621   MESSAGE("ExtrusionAlongTrack");
4622   myLastCreatedElems.Clear();
4623   myLastCreatedNodes.Clear();
4624
4625   int aNbE;
4626   std::list<double> aPrms;
4627   TIDSortedElemSet::iterator itElem;
4628
4629   gp_XYZ aGC;
4630   TopoDS_Edge aTrackEdge;
4631   TopoDS_Vertex aV1, aV2;
4632
4633   SMDS_ElemIteratorPtr aItE;
4634   SMDS_NodeIteratorPtr aItN;
4635   SMDSAbs_ElementType aTypeE;
4636
4637   TNodeOfNodeListMap mapNewNodes;
4638
4639   // 1. Check data
4640   aNbE = theElements.size();
4641   // nothing to do
4642   if ( !aNbE )
4643     return EXTR_NO_ELEMENTS;
4644
4645   // 1.1 Track Pattern
4646   ASSERT( theTrack );
4647
4648   SMESHDS_SubMesh* pSubMeshDS = theTrack->GetSubMeshDS();
4649
4650   aItE = pSubMeshDS->GetElements();
4651   while ( aItE->more() ) {
4652     const SMDS_MeshElement* pE = aItE->next();
4653     aTypeE = pE->GetType();
4654     // Pattern must contain links only
4655     if ( aTypeE != SMDSAbs_Edge )
4656       return EXTR_PATH_NOT_EDGE;
4657   }
4658
4659   list<SMESH_MeshEditor_PathPoint> fullList;
4660
4661   const TopoDS_Shape& aS = theTrack->GetSubShape();
4662   // Sub shape for the Pattern must be an Edge or Wire
4663   if( aS.ShapeType() == TopAbs_EDGE ) {
4664     aTrackEdge = TopoDS::Edge( aS );
4665     // the Edge must not be degenerated
4666     if ( BRep_Tool::Degenerated( aTrackEdge ) )
4667       return EXTR_BAD_PATH_SHAPE;
4668     TopExp::Vertices( aTrackEdge, aV1, aV2 );
4669     aItN = theTrack->GetFather()->GetSubMesh( aV1 )->GetSubMeshDS()->GetNodes();
4670     const SMDS_MeshNode* aN1 = aItN->next();
4671     aItN = theTrack->GetFather()->GetSubMesh( aV2 )->GetSubMeshDS()->GetNodes();
4672     const SMDS_MeshNode* aN2 = aItN->next();
4673     // starting node must be aN1 or aN2
4674     if ( !( aN1 == theN1 || aN2 == theN1 ) )
4675       return EXTR_BAD_STARTING_NODE;
4676     aItN = pSubMeshDS->GetNodes();
4677     while ( aItN->more() ) {
4678       const SMDS_MeshNode* pNode = aItN->next();
4679       const SMDS_EdgePosition* pEPos =
4680         static_cast<const SMDS_EdgePosition*>( pNode->GetPosition() );
4681       double aT = pEPos->GetUParameter();
4682       aPrms.push_back( aT );
4683     }
4684     //Extrusion_Error err =
4685     MakeEdgePathPoints(aPrms, aTrackEdge, (aN1==theN1), fullList);
4686   }
4687   else if( aS.ShapeType() == TopAbs_WIRE ) {
4688     list< SMESH_subMesh* > LSM;
4689     TopTools_SequenceOfShape Edges;
4690     SMESH_subMeshIteratorPtr itSM = theTrack->getDependsOnIterator(false,true);
4691     while(itSM->more()) {
4692       SMESH_subMesh* SM = itSM->next();
4693       LSM.push_back(SM);
4694       const TopoDS_Shape& aS = SM->GetSubShape();
4695       Edges.Append(aS);
4696     }
4697     list< list<SMESH_MeshEditor_PathPoint> > LLPPs;
4698     int startNid = theN1->GetID();
4699     TColStd_MapOfInteger UsedNums;
4700     int NbEdges = Edges.Length();
4701     int i = 1;
4702     for(; i<=NbEdges; i++) {
4703       int k = 0;
4704       list< SMESH_subMesh* >::iterator itLSM = LSM.begin();
4705       for(; itLSM!=LSM.end(); itLSM++) {
4706         k++;
4707         if(UsedNums.Contains(k)) continue;
4708         aTrackEdge = TopoDS::Edge( Edges.Value(k) );
4709         SMESH_subMesh* locTrack = *itLSM;
4710         SMESHDS_SubMesh* locMeshDS = locTrack->GetSubMeshDS();
4711         TopExp::Vertices( aTrackEdge, aV1, aV2 );
4712         aItN = locTrack->GetFather()->GetSubMesh(aV1)->GetSubMeshDS()->GetNodes();
4713         const SMDS_MeshNode* aN1 = aItN->next();
4714         aItN = locTrack->GetFather()->GetSubMesh(aV2)->GetSubMeshDS()->GetNodes();
4715         const SMDS_MeshNode* aN2 = aItN->next();
4716         // starting node must be aN1 or aN2
4717         if ( !( aN1->GetID() == startNid || aN2->GetID() == startNid ) ) continue;
4718         // 2. Collect parameters on the track edge
4719         aPrms.clear();
4720         aItN = locMeshDS->GetNodes();
4721         while ( aItN->more() ) {
4722           const SMDS_MeshNode* pNode = aItN->next();
4723           const SMDS_EdgePosition* pEPos =
4724             static_cast<const SMDS_EdgePosition*>( pNode->GetPosition() );
4725           double aT = pEPos->GetUParameter();
4726           aPrms.push_back( aT );
4727         }
4728         list<SMESH_MeshEditor_PathPoint> LPP;
4729         //Extrusion_Error err =
4730         MakeEdgePathPoints(aPrms, aTrackEdge,(aN1->GetID()==startNid), LPP);
4731         LLPPs.push_back(LPP);
4732         UsedNums.Add(k);
4733         // update startN for search following egde
4734         if( aN1->GetID() == startNid ) startNid = aN2->GetID();
4735         else startNid = aN1->GetID();
4736         break;
4737       }
4738     }
4739     list< list<SMESH_MeshEditor_PathPoint> >::iterator itLLPP = LLPPs.begin();
4740     list<SMESH_MeshEditor_PathPoint> firstList = *itLLPP;
4741     list<SMESH_MeshEditor_PathPoint>::iterator itPP = firstList.begin();
4742     for(; itPP!=firstList.end(); itPP++) {
4743       fullList.push_back( *itPP );
4744     }
4745     SMESH_MeshEditor_PathPoint PP1 = fullList.back();
4746     fullList.pop_back();
4747     itLLPP++;
4748     for(; itLLPP!=LLPPs.end(); itLLPP++) {
4749       list<SMESH_MeshEditor_PathPoint> currList = *itLLPP;
4750       itPP = currList.begin();
4751       SMESH_MeshEditor_PathPoint PP2 = currList.front();
4752       gp_Dir D1 = PP1.Tangent();
4753       gp_Dir D2 = PP2.Tangent();
4754       gp_Dir Dnew( gp_Vec( (D1.X()+D2.X())/2, (D1.Y()+D2.Y())/2,
4755                            (D1.Z()+D2.Z())/2 ) );
4756       PP1.SetTangent(Dnew);
4757       fullList.push_back(PP1);
4758       itPP++;
4759       for(; itPP!=firstList.end(); itPP++) {
4760         fullList.push_back( *itPP );
4761       }
4762       PP1 = fullList.back();
4763       fullList.pop_back();
4764     }
4765     // if wire not closed
4766     fullList.push_back(PP1);
4767     // else ???
4768   }
4769   else {
4770     return EXTR_BAD_PATH_SHAPE;
4771   }
4772
4773   return MakeExtrElements(theElements, fullList, theHasAngles, theAngles, theLinearVariation,
4774                           theHasRefPoint, theRefPoint, theMakeGroups);
4775 }
4776
4777
4778 //=======================================================================
4779 //function : ExtrusionAlongTrack
4780 //purpose  :
4781 //=======================================================================
4782 SMESH_MeshEditor::Extrusion_Error
4783 SMESH_MeshEditor::ExtrusionAlongTrack (TIDSortedElemSet &   theElements,
4784                                        SMESH_Mesh*          theTrack,
4785                                        const SMDS_MeshNode* theN1,
4786                                        const bool           theHasAngles,
4787                                        list<double>&        theAngles,
4788                                        const bool           theLinearVariation,
4789                                        const bool           theHasRefPoint,
4790                                        const gp_Pnt&        theRefPoint,
4791                                        const bool           theMakeGroups)
4792 {
4793   myLastCreatedElems.Clear();
4794   myLastCreatedNodes.Clear();
4795
4796   int aNbE;
4797   std::list<double> aPrms;
4798   TIDSortedElemSet::iterator itElem;
4799
4800   gp_XYZ aGC;
4801   TopoDS_Edge aTrackEdge;
4802   TopoDS_Vertex aV1, aV2;
4803
4804   SMDS_ElemIteratorPtr aItE;
4805   SMDS_NodeIteratorPtr aItN;
4806   SMDSAbs_ElementType aTypeE;
4807
4808   TNodeOfNodeListMap mapNewNodes;
4809
4810   // 1. Check data
4811   aNbE = theElements.size();
4812   // nothing to do
4813   if ( !aNbE )
4814     return EXTR_NO_ELEMENTS;
4815
4816   // 1.1 Track Pattern
4817   ASSERT( theTrack );
4818
4819   SMESHDS_Mesh* pMeshDS = theTrack->GetMeshDS();
4820
4821   aItE = pMeshDS->elementsIterator();
4822   while ( aItE->more() ) {
4823     const SMDS_MeshElement* pE = aItE->next();
4824     aTypeE = pE->GetType();
4825     // Pattern must contain links only
4826     if ( aTypeE != SMDSAbs_Edge )
4827       return EXTR_PATH_NOT_EDGE;
4828   }
4829
4830   list<SMESH_MeshEditor_PathPoint> fullList;
4831
4832   const TopoDS_Shape& aS = theTrack->GetShapeToMesh();
4833   // Sub shape for the Pattern must be an Edge or Wire
4834   if( aS.ShapeType() == TopAbs_EDGE ) {
4835     aTrackEdge = TopoDS::Edge( aS );
4836     // the Edge must not be degenerated
4837     if ( BRep_Tool::Degenerated( aTrackEdge ) )
4838       return EXTR_BAD_PATH_SHAPE;
4839     TopExp::Vertices( aTrackEdge, aV1, aV2 );
4840     aItN = theTrack->GetSubMesh( aV1 )->GetSubMeshDS()->GetNodes();
4841     const SMDS_MeshNode* aN1 = aItN->next();
4842     aItN = theTrack->GetSubMesh( aV2 )->GetSubMeshDS()->GetNodes();
4843     const SMDS_MeshNode* aN2 = aItN->next();
4844     // starting node must be aN1 or aN2
4845     if ( !( aN1 == theN1 || aN2 == theN1 ) )
4846       return EXTR_BAD_STARTING_NODE;
4847     aItN = pMeshDS->nodesIterator();
4848     while ( aItN->more() ) {
4849       const SMDS_MeshNode* pNode = aItN->next();
4850       if( pNode==aN1 || pNode==aN2 ) continue;
4851       const SMDS_EdgePosition* pEPos =
4852         static_cast<const SMDS_EdgePosition*>( pNode->GetPosition() );
4853       double aT = pEPos->GetUParameter();
4854       aPrms.push_back( aT );
4855     }
4856     //Extrusion_Error err =
4857     MakeEdgePathPoints(aPrms, aTrackEdge, (aN1==theN1), fullList);
4858   }
4859   else if( aS.ShapeType() == TopAbs_WIRE ) {
4860     list< SMESH_subMesh* > LSM;
4861     TopTools_SequenceOfShape Edges;
4862     TopExp_Explorer eExp(aS, TopAbs_EDGE);
4863     for(; eExp.More(); eExp.Next()) {
4864       TopoDS_Edge E = TopoDS::Edge( eExp.Current() );
4865       if( BRep_Tool::Degenerated(E) ) continue;
4866       SMESH_subMesh* SM = theTrack->GetSubMesh(E);
4867       if(SM) {
4868         LSM.push_back(SM);
4869         Edges.Append(E);
4870       }
4871     }
4872     list< list<SMESH_MeshEditor_PathPoint> > LLPPs;
4873     int startNid = theN1->GetID();
4874     TColStd_MapOfInteger UsedNums;
4875     int NbEdges = Edges.Length();
4876     int i = 1;
4877     for(; i<=NbEdges; i++) {
4878       int k = 0;
4879       list< SMESH_subMesh* >::iterator itLSM = LSM.begin();
4880       for(; itLSM!=LSM.end(); itLSM++) {
4881         k++;
4882         if(UsedNums.Contains(k)) continue;
4883         aTrackEdge = TopoDS::Edge( Edges.Value(k) );
4884         SMESH_subMesh* locTrack = *itLSM;
4885         SMESHDS_SubMesh* locMeshDS = locTrack->GetSubMeshDS();
4886         TopExp::Vertices( aTrackEdge, aV1, aV2 );
4887         aItN = locTrack->GetFather()->GetSubMesh(aV1)->GetSubMeshDS()->GetNodes();
4888         const SMDS_MeshNode* aN1 = aItN->next();
4889         aItN = locTrack->GetFather()->GetSubMesh(aV2)->GetSubMeshDS()->GetNodes();
4890         const SMDS_MeshNode* aN2 = aItN->next();
4891         // starting node must be aN1 or aN2
4892         if ( !( aN1->GetID() == startNid || aN2->GetID() == startNid ) ) continue;
4893         // 2. Collect parameters on the track edge
4894         aPrms.clear();
4895         aItN = locMeshDS->GetNodes();
4896         while ( aItN->more() ) {
4897           const SMDS_MeshNode* pNode = aItN->next();
4898           const SMDS_EdgePosition* pEPos =
4899             static_cast<const SMDS_EdgePosition*>( pNode->GetPosition() );
4900           double aT = pEPos->GetUParameter();
4901           aPrms.push_back( aT );
4902         }
4903         list<SMESH_MeshEditor_PathPoint> LPP;
4904         //Extrusion_Error err =
4905         MakeEdgePathPoints(aPrms, aTrackEdge,(aN1->GetID()==startNid), LPP);
4906         LLPPs.push_back(LPP);
4907         UsedNums.Add(k);
4908         // update startN for search following egde
4909         if( aN1->GetID() == startNid ) startNid = aN2->GetID();
4910         else startNid = aN1->GetID();
4911         break;
4912       }
4913     }
4914     list< list<SMESH_MeshEditor_PathPoint> >::iterator itLLPP = LLPPs.begin();
4915     list<SMESH_MeshEditor_PathPoint> firstList = *itLLPP;
4916     list<SMESH_MeshEditor_PathPoint>::iterator itPP = firstList.begin();
4917     for(; itPP!=firstList.end(); itPP++) {
4918       fullList.push_back( *itPP );
4919     }
4920     SMESH_MeshEditor_PathPoint PP1 = fullList.back();
4921     fullList.pop_back();
4922     itLLPP++;
4923     for(; itLLPP!=LLPPs.end(); itLLPP++) {
4924       list<SMESH_MeshEditor_PathPoint> currList = *itLLPP;
4925       itPP = currList.begin();
4926       SMESH_MeshEditor_PathPoint PP2 = currList.front();
4927       gp_Pnt P1 = PP1.Pnt();
4928       //cout<<"    PP1: Pnt("<<P1.X()<<","<<P1.Y()<<","<<P1.Z()<<")"<<endl;
4929       gp_Pnt P2 = PP2.Pnt();
4930       gp_Dir D1 = PP1.Tangent();
4931       gp_Dir D2 = PP2.Tangent();
4932       gp_Dir Dnew( gp_Vec( (D1.X()+D2.X())/2, (D1.Y()+D2.Y())/2,
4933                            (D1.Z()+D2.Z())/2 ) );
4934       PP1.SetTangent(Dnew);
4935       fullList.push_back(PP1);
4936       itPP++;
4937       for(; itPP!=currList.end(); itPP++) {
4938         fullList.push_back( *itPP );
4939       }
4940       PP1 = fullList.back();
4941       fullList.pop_back();
4942     }
4943     // if wire not closed
4944     fullList.push_back(PP1);
4945     // else ???
4946   }
4947   else {
4948     return EXTR_BAD_PATH_SHAPE;
4949   }
4950
4951   return MakeExtrElements(theElements, fullList, theHasAngles, theAngles, theLinearVariation,
4952                           theHasRefPoint, theRefPoint, theMakeGroups);
4953 }
4954
4955
4956 //=======================================================================
4957 //function : MakeEdgePathPoints
4958 //purpose  : auxilary for ExtrusionAlongTrack
4959 //=======================================================================
4960 SMESH_MeshEditor::Extrusion_Error
4961 SMESH_MeshEditor::MakeEdgePathPoints(std::list<double>& aPrms,
4962                                      const TopoDS_Edge& aTrackEdge,
4963                                      bool FirstIsStart,
4964                                      list<SMESH_MeshEditor_PathPoint>& LPP)
4965 {
4966   Standard_Real aTx1, aTx2, aL2, aTolVec, aTolVec2;
4967   aTolVec=1.e-7;
4968   aTolVec2=aTolVec*aTolVec;
4969   double aT1, aT2;
4970   TopoDS_Vertex aV1, aV2;
4971   TopExp::Vertices( aTrackEdge, aV1, aV2 );
4972   aT1=BRep_Tool::Parameter( aV1, aTrackEdge );
4973   aT2=BRep_Tool::Parameter( aV2, aTrackEdge );
4974   // 2. Collect parameters on the track edge
4975   aPrms.push_front( aT1 );
4976   aPrms.push_back( aT2 );
4977   // sort parameters
4978   aPrms.sort();
4979   if( FirstIsStart ) {
4980     if ( aT1 > aT2 ) {
4981       aPrms.reverse();
4982     }
4983   }
4984   else {
4985     if ( aT2 > aT1 ) {
4986       aPrms.reverse();
4987     }
4988   }
4989   // 3. Path Points
4990   SMESH_MeshEditor_PathPoint aPP;
4991   Handle(Geom_Curve) aC3D = BRep_Tool::Curve( aTrackEdge, aTx1, aTx2 );
4992   std::list<double>::iterator aItD = aPrms.begin();
4993   for(; aItD != aPrms.end(); ++aItD) {
4994     double aT = *aItD;
4995     gp_Pnt aP3D;
4996     gp_Vec aVec;
4997     aC3D->D1( aT, aP3D, aVec );
4998     aL2 = aVec.SquareMagnitude();
4999     if ( aL2 < aTolVec2 )
5000       return EXTR_CANT_GET_TANGENT;
5001     gp_Dir aTgt( aVec );
5002     aPP.SetPnt( aP3D );
5003     aPP.SetTangent( aTgt );
5004     aPP.SetParameter( aT );
5005     LPP.push_back(aPP);
5006   }
5007   return EXTR_OK;
5008 }
5009
5010
5011 //=======================================================================
5012 //function : MakeExtrElements
5013 //purpose  : auxilary for ExtrusionAlongTrack
5014 //=======================================================================
5015 SMESH_MeshEditor::Extrusion_Error
5016 SMESH_MeshEditor::MakeExtrElements(TIDSortedElemSet&  theElements,
5017                                    list<SMESH_MeshEditor_PathPoint>& fullList,
5018                                    const bool theHasAngles,
5019                                    list<double>& theAngles,
5020                                    const bool theLinearVariation,
5021                                    const bool theHasRefPoint,
5022                                    const gp_Pnt& theRefPoint,
5023                                    const bool theMakeGroups)
5024 {
5025   MESSAGE("MakeExtrElements");
5026   //cout<<"MakeExtrElements  fullList.size() = "<<fullList.size()<<endl;
5027   int aNbTP = fullList.size();
5028   vector<SMESH_MeshEditor_PathPoint> aPPs(aNbTP);
5029   // Angles
5030   if( theHasAngles && theAngles.size()>0 && theLinearVariation ) {
5031     LinearAngleVariation(aNbTP-1, theAngles);
5032   }
5033   vector<double> aAngles( aNbTP );
5034   int j = 0;
5035   for(; j<aNbTP; ++j) {
5036     aAngles[j] = 0.;
5037   }
5038   if ( theHasAngles ) {
5039     double anAngle;;
5040     std::list<double>::iterator aItD = theAngles.begin();
5041     for ( j=1; (aItD != theAngles.end()) && (j<aNbTP); ++aItD, ++j ) {
5042       anAngle = *aItD;
5043       aAngles[j] = anAngle;
5044     }
5045   }
5046   // fill vector of path points with angles
5047   //aPPs.resize(fullList.size());
5048   j = -1;
5049   list<SMESH_MeshEditor_PathPoint>::iterator itPP = fullList.begin();
5050   for(; itPP!=fullList.end(); itPP++) {
5051     j++;
5052     SMESH_MeshEditor_PathPoint PP = *itPP;
5053     PP.SetAngle(aAngles[j]);
5054     aPPs[j] = PP;
5055   }
5056
5057   TNodeOfNodeListMap mapNewNodes;
5058   TElemOfVecOfNnlmiMap mapElemNewNodes;
5059   TElemOfElemListMap newElemsMap;
5060   TIDSortedElemSet::iterator itElem;
5061   double aX, aY, aZ;
5062   int aNb;
5063   SMDSAbs_ElementType aTypeE;
5064   // source elements for each generated one
5065   SMESH_SequenceOfElemPtr srcElems, srcNodes;
5066
5067   // 3. Center of rotation aV0
5068   gp_Pnt aV0 = theRefPoint;
5069   gp_XYZ aGC;
5070   if ( !theHasRefPoint ) {
5071     aNb = 0;
5072     aGC.SetCoord( 0.,0.,0. );
5073
5074     itElem = theElements.begin();
5075     for ( ; itElem != theElements.end(); itElem++ ) {
5076       const SMDS_MeshElement* elem = *itElem;
5077
5078       SMDS_ElemIteratorPtr itN = elem->nodesIterator();
5079       while ( itN->more() ) {
5080         const SMDS_MeshNode* node = static_cast<const SMDS_MeshNode*>( itN->next() );
5081         aX = node->X();
5082         aY = node->Y();
5083         aZ = node->Z();
5084
5085         if ( mapNewNodes.find( node ) == mapNewNodes.end() ) {
5086           list<const SMDS_MeshNode*> aLNx;
5087           mapNewNodes[node] = aLNx;
5088           //
5089           gp_XYZ aXYZ( aX, aY, aZ );
5090           aGC += aXYZ;
5091           ++aNb;
5092         }
5093       }
5094     }
5095     aGC /= aNb;
5096     aV0.SetXYZ( aGC );
5097   } // if (!theHasRefPoint) {
5098   mapNewNodes.clear();
5099
5100   // 4. Processing the elements
5101   SMESHDS_Mesh* aMesh = GetMeshDS();
5102
5103   for ( itElem = theElements.begin(); itElem != theElements.end(); itElem++ ) {
5104     // check element type
5105     const SMDS_MeshElement* elem = *itElem;
5106     aTypeE = elem->GetType();
5107     if ( !elem || ( aTypeE != SMDSAbs_Face && aTypeE != SMDSAbs_Edge ) )
5108       continue;
5109
5110     vector<TNodeOfNodeListMapItr> & newNodesItVec = mapElemNewNodes[ elem ];
5111     newNodesItVec.reserve( elem->NbNodes() );
5112
5113     // loop on elem nodes
5114     int nodeIndex = -1;
5115     SMDS_ElemIteratorPtr itN = elem->nodesIterator();
5116     while ( itN->more() )
5117     {
5118       ++nodeIndex;
5119       // check if a node has been already processed
5120       const SMDS_MeshNode* node =
5121         static_cast<const SMDS_MeshNode*>( itN->next() );
5122       TNodeOfNodeListMap::iterator nIt = mapNewNodes.find( node );
5123       if ( nIt == mapNewNodes.end() ) {
5124         nIt = mapNewNodes.insert( make_pair( node, list<const SMDS_MeshNode*>() )).first;
5125         list<const SMDS_MeshNode*>& listNewNodes = nIt->second;
5126
5127         // make new nodes
5128         aX = node->X();  aY = node->Y(); aZ = node->Z();
5129
5130         Standard_Real aAngle1x, aAngleT1T0, aTolAng;
5131         gp_Pnt aP0x, aP1x, aPN0, aPN1, aV0x, aV1x;
5132         gp_Ax1 anAx1, anAxT1T0;
5133         gp_Dir aDT1x, aDT0x, aDT1T0;
5134
5135         aTolAng=1.e-4;
5136
5137         aV0x = aV0;
5138         aPN0.SetCoord(aX, aY, aZ);
5139
5140         const SMESH_MeshEditor_PathPoint& aPP0 = aPPs[0];
5141         aP0x = aPP0.Pnt();
5142         aDT0x= aPP0.Tangent();
5143         //cout<<"j = 0   PP: Pnt("<<aP0x.X()<<","<<aP0x.Y()<<","<<aP0x.Z()<<")"<<endl;
5144
5145         for ( j = 1; j < aNbTP; ++j ) {
5146           const SMESH_MeshEditor_PathPoint& aPP1 = aPPs[j];
5147           aP1x = aPP1.Pnt();
5148           aDT1x = aPP1.Tangent();
5149           aAngle1x = aPP1.Angle();
5150
5151           gp_Trsf aTrsf, aTrsfRot, aTrsfRotT1T0;
5152           // Translation
5153           gp_Vec aV01x( aP0x, aP1x );
5154           aTrsf.SetTranslation( aV01x );
5155
5156           // traslated point
5157           aV1x = aV0x.Transformed( aTrsf );
5158           aPN1 = aPN0.Transformed( aTrsf );
5159
5160           // rotation 1 [ T1,T0 ]
5161           aAngleT1T0=-aDT1x.Angle( aDT0x );
5162           if (fabs(aAngleT1T0) > aTolAng) {
5163             aDT1T0=aDT1x^aDT0x;
5164             anAxT1T0.SetLocation( aV1x );
5165             anAxT1T0.SetDirection( aDT1T0 );
5166             aTrsfRotT1T0.SetRotation( anAxT1T0, aAngleT1T0 );
5167
5168             aPN1 = aPN1.Transformed( aTrsfRotT1T0 );
5169           }
5170
5171           // rotation 2
5172           if ( theHasAngles ) {
5173             anAx1.SetLocation( aV1x );
5174             anAx1.SetDirection( aDT1x );
5175             aTrsfRot.SetRotation( anAx1, aAngle1x );
5176
5177             aPN1 = aPN1.Transformed( aTrsfRot );
5178           }
5179
5180           // make new node
5181           //MESSAGE("elem->IsQuadratic " << elem->IsQuadratic() << " " << elem->IsMediumNode(node));
5182           if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
5183             // create additional node
5184             double x = ( aPN1.X() + aPN0.X() )/2.;
5185             double y = ( aPN1.Y() + aPN0.Y() )/2.;
5186             double z = ( aPN1.Z() + aPN0.Z() )/2.;
5187             const SMDS_MeshNode* newNode = aMesh->AddNode(x,y,z);
5188             myLastCreatedNodes.Append(newNode);
5189             srcNodes.Append( node );
5190             listNewNodes.push_back( newNode );
5191           }
5192           aX = aPN1.X();
5193           aY = aPN1.Y();
5194           aZ = aPN1.Z();
5195           const SMDS_MeshNode* newNode = aMesh->AddNode( aX, aY, aZ );
5196           myLastCreatedNodes.Append(newNode);
5197           srcNodes.Append( node );
5198           listNewNodes.push_back( newNode );
5199
5200           aPN0 = aPN1;
5201           aP0x = aP1x;
5202           aV0x = aV1x;
5203           aDT0x = aDT1x;
5204         }
5205       }
5206
5207       else {
5208         // if current elem is quadratic and current node is not medium
5209         // we have to check - may be it is needed to insert additional nodes
5210         if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
5211           list< const SMDS_MeshNode* > & listNewNodes = nIt->second;
5212           if(listNewNodes.size()==aNbTP-1) {
5213             vector<const SMDS_MeshNode*> aNodes(2*(aNbTP-1));
5214             gp_XYZ P(node->X(), node->Y(), node->Z());
5215             list< const SMDS_MeshNode* >::iterator it = listNewNodes.begin();
5216             int i;
5217             for(i=0; i<aNbTP-1; i++) {
5218               const SMDS_MeshNode* N = *it;
5219               double x = ( N->X() + P.X() )/2.;
5220               double y = ( N->Y() + P.Y() )/2.;
5221               double z = ( N->Z() + P.Z() )/2.;
5222               const SMDS_MeshNode* newN = aMesh->AddNode(x,y,z);
5223               srcNodes.Append( node );
5224               myLastCreatedNodes.Append(newN);
5225               aNodes[2*i] = newN;
5226               aNodes[2*i+1] = N;
5227               P = gp_XYZ(N->X(),N->Y(),N->Z());
5228             }
5229             listNewNodes.clear();
5230             for(i=0; i<2*(aNbTP-1); i++) {
5231               listNewNodes.push_back(aNodes[i]);
5232             }
5233           }
5234         }
5235       }
5236
5237       newNodesItVec.push_back( nIt );
5238     }
5239     // make new elements
5240     //sweepElement( aMesh, elem, newNodesItVec, newElemsMap[elem],
5241     //              newNodesItVec[0]->second.size(), myLastCreatedElems );
5242     sweepElement( elem, newNodesItVec, newElemsMap[elem], aNbTP-1, srcElems );
5243   }
5244
5245   makeWalls( mapNewNodes, newElemsMap, mapElemNewNodes, theElements, aNbTP-1, srcElems );
5246
5247   if ( theMakeGroups )
5248     generateGroups( srcNodes, srcElems, "extruded");
5249
5250   return EXTR_OK;
5251 }
5252
5253
5254 //=======================================================================
5255 //function : LinearAngleVariation
5256 //purpose  : auxilary for ExtrusionAlongTrack
5257 //=======================================================================
5258 void SMESH_MeshEditor::LinearAngleVariation(const int nbSteps,
5259                                             list<double>& Angles)
5260 {
5261   int nbAngles = Angles.size();
5262   if( nbSteps > nbAngles ) {
5263     vector<double> theAngles(nbAngles);
5264     list<double>::iterator it = Angles.begin();
5265     int i = -1;
5266     for(; it!=Angles.end(); it++) {
5267       i++;
5268       theAngles[i] = (*it);
5269     }
5270     list<double> res;
5271     double rAn2St = double( nbAngles ) / double( nbSteps );
5272     double angPrev = 0, angle;
5273     for ( int iSt = 0; iSt < nbSteps; ++iSt ) {
5274       double angCur = rAn2St * ( iSt+1 );
5275       double angCurFloor  = floor( angCur );
5276       double angPrevFloor = floor( angPrev );
5277       if ( angPrevFloor == angCurFloor )
5278         angle = rAn2St * theAngles[ int( angCurFloor ) ];
5279       else {
5280         int iP = int( angPrevFloor );
5281         double angPrevCeil = ceil(angPrev);
5282         angle = ( angPrevCeil - angPrev ) * theAngles[ iP ];
5283
5284         int iC = int( angCurFloor );
5285         if ( iC < nbAngles )
5286           angle += ( angCur - angCurFloor ) * theAngles[ iC ];
5287
5288         iP = int( angPrevCeil );
5289         while ( iC-- > iP )
5290           angle += theAngles[ iC ];
5291       }
5292       res.push_back(angle);
5293       angPrev = angCur;
5294     }
5295     Angles.clear();
5296     it = res.begin();
5297     for(; it!=res.end(); it++)
5298       Angles.push_back( *it );
5299   }
5300 }
5301
5302
5303 //================================================================================
5304 /*!
5305  * \brief Move or copy theElements applying theTrsf to their nodes
5306  *  \param theElems - elements to transform, if theElems is empty then apply to all mesh nodes
5307  *  \param theTrsf - transformation to apply
5308  *  \param theCopy - if true, create translated copies of theElems
5309  *  \param theMakeGroups - if true and theCopy, create translated groups
5310  *  \param theTargetMesh - mesh to copy translated elements into
5311  *  \return SMESH_MeshEditor::PGroupIDs - list of ids of created groups
5312  */
5313 //================================================================================
5314
5315 SMESH_MeshEditor::PGroupIDs
5316 SMESH_MeshEditor::Transform (TIDSortedElemSet & theElems,
5317                              const gp_Trsf&     theTrsf,
5318                              const bool         theCopy,
5319                              const bool         theMakeGroups,
5320                              SMESH_Mesh*        theTargetMesh)
5321 {
5322   myLastCreatedElems.Clear();
5323   myLastCreatedNodes.Clear();
5324
5325   bool needReverse = false;
5326   string groupPostfix;
5327   switch ( theTrsf.Form() ) {
5328   case gp_PntMirror:
5329     MESSAGE("gp_PntMirror");
5330     needReverse = true;
5331     groupPostfix = "mirrored";
5332     break;
5333   case gp_Ax1Mirror:
5334     MESSAGE("gp_Ax1Mirror");
5335     groupPostfix = "mirrored";
5336     break;
5337   case gp_Ax2Mirror:
5338     MESSAGE("gp_Ax2Mirror");
5339     needReverse = true;
5340     groupPostfix = "mirrored";
5341     break;
5342   case gp_Rotation:
5343     MESSAGE("gp_Rotation");
5344     groupPostfix = "rotated";
5345     break;
5346   case gp_Translation:
5347     MESSAGE("gp_Translation");
5348     groupPostfix = "translated";
5349     break;
5350   case gp_Scale:
5351     MESSAGE("gp_Scale");
5352     groupPostfix = "scaled";
5353     break;
5354   case gp_CompoundTrsf: // different scale by axis
5355     MESSAGE("gp_CompoundTrsf");
5356     groupPostfix = "scaled";
5357     break;
5358   default:
5359     MESSAGE("default");
5360     needReverse = false;
5361     groupPostfix = "transformed";
5362   }
5363
5364   SMESH_MeshEditor targetMeshEditor( theTargetMesh );
5365   SMESHDS_Mesh* aTgtMesh = theTargetMesh ? theTargetMesh->GetMeshDS() : 0;
5366   SMESHDS_Mesh* aMesh    = GetMeshDS();
5367
5368
5369   // map old node to new one
5370   TNodeNodeMap nodeMap;
5371
5372   // elements sharing moved nodes; those of them which have all
5373   // nodes mirrored but are not in theElems are to be reversed
5374   TIDSortedElemSet inverseElemSet;
5375
5376   // source elements for each generated one
5377   SMESH_SequenceOfElemPtr srcElems, srcNodes;
5378
5379   // issue 021015: EDF 1578 SMESH: Free nodes are removed when translating a mesh
5380   TIDSortedElemSet orphanNode;
5381
5382   if ( theElems.empty() ) // transform the whole mesh
5383   {
5384     // add all elements
5385     SMDS_ElemIteratorPtr eIt = aMesh->elementsIterator();
5386     while ( eIt->more() ) theElems.insert( eIt->next() );
5387     // add orphan nodes
5388     SMDS_NodeIteratorPtr nIt = aMesh->nodesIterator();
5389     while ( nIt->more() )
5390     {
5391       const SMDS_MeshNode* node = nIt->next();
5392       if ( node->NbInverseElements() == 0)
5393         orphanNode.insert( node );
5394     }
5395   }
5396
5397   // loop on elements to transform nodes : first orphan nodes then elems
5398   TIDSortedElemSet::iterator itElem;
5399   TIDSortedElemSet *elements[] = {&orphanNode, &theElems };
5400   for (int i=0; i<2; i++)
5401   for ( itElem = elements[i]->begin(); itElem != elements[i]->end(); itElem++ ) {
5402     const SMDS_MeshElement* elem = *itElem;
5403     if ( !elem )
5404       continue;
5405
5406     // loop on elem nodes
5407     SMDS_ElemIteratorPtr itN = elem->nodesIterator();
5408     while ( itN->more() ) {
5409
5410       const SMDS_MeshNode* node = cast2Node( itN->next() );
5411       // check if a node has been already transformed
5412       pair<TNodeNodeMap::iterator,bool> n2n_isnew =
5413         nodeMap.insert( make_pair ( node, node ));
5414       if ( !n2n_isnew.second )
5415         continue;
5416
5417       double coord[3];
5418       coord[0] = node->X();
5419       coord[1] = node->Y();
5420       coord[2] = node->Z();
5421       theTrsf.Transforms( coord[0], coord[1], coord[2] );
5422       if ( theTargetMesh ) {
5423         const SMDS_MeshNode * newNode = aTgtMesh->AddNode( coord[0], coord[1], coord[2] );
5424         n2n_isnew.first->second = newNode;
5425         myLastCreatedNodes.Append(newNode);
5426         srcNodes.Append( node );
5427       }
5428       else if ( theCopy ) {
5429         const SMDS_MeshNode * newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
5430         n2n_isnew.first->second = newNode;
5431         myLastCreatedNodes.Append(newNode);
5432         srcNodes.Append( node );
5433       }
5434       else {
5435         aMesh->MoveNode( node, coord[0], coord[1], coord[2] );
5436         // node position on shape becomes invalid
5437         const_cast< SMDS_MeshNode* > ( node )->SetPosition
5438           ( SMDS_SpacePosition::originSpacePosition() );
5439       }
5440
5441       // keep inverse elements
5442       if ( !theCopy && !theTargetMesh && needReverse ) {
5443         SMDS_ElemIteratorPtr invElemIt = node->GetInverseElementIterator();
5444         while ( invElemIt->more() ) {
5445           const SMDS_MeshElement* iel = invElemIt->next();
5446           inverseElemSet.insert( iel );
5447         }
5448       }
5449     }
5450   }
5451
5452   // either create new elements or reverse mirrored ones
5453   if ( !theCopy && !needReverse && !theTargetMesh )
5454     return PGroupIDs();
5455
5456   TIDSortedElemSet::iterator invElemIt = inverseElemSet.begin();
5457   for ( ; invElemIt != inverseElemSet.end(); invElemIt++ )
5458     theElems.insert( *invElemIt );
5459
5460   // replicate or reverse elements
5461   // TODO revoir ordre reverse vtk
5462   enum {
5463     REV_TETRA   = 0,  //  = nbNodes - 4
5464     REV_PYRAMID = 1,  //  = nbNodes - 4
5465     REV_PENTA   = 2,  //  = nbNodes - 4
5466     REV_FACE    = 3,
5467     REV_HEXA    = 4,  //  = nbNodes - 4
5468     FORWARD     = 5
5469   };
5470   int index[][8] = {
5471     { 2, 1, 0, 3, 4, 0, 0, 0 },  // REV_TETRA
5472     { 2, 1, 0, 3, 4, 0, 0, 0 },  // REV_PYRAMID
5473     { 2, 1, 0, 5, 4, 3, 0, 0 },  // REV_PENTA
5474     { 2, 1, 0, 3, 0, 0, 0, 0 },  // REV_FACE
5475     { 2, 1, 0, 3, 6, 5, 4, 7 },  // REV_HEXA
5476     { 0, 1, 2, 3, 4, 5, 6, 7 }   // FORWARD
5477   };
5478
5479   for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ )
5480   {
5481     const SMDS_MeshElement* elem = *itElem;
5482     if ( !elem || elem->GetType() == SMDSAbs_Node )
5483       continue;
5484
5485     int nbNodes = elem->NbNodes();
5486     int elemType = elem->GetType();
5487
5488     if (elem->IsPoly()) {
5489       // Polygon or Polyhedral Volume
5490       switch ( elemType ) {
5491       case SMDSAbs_Face:
5492         {
5493           vector<const SMDS_MeshNode*> poly_nodes (nbNodes);
5494           int iNode = 0;
5495           SMDS_ElemIteratorPtr itN = elem->nodesIterator();
5496           while (itN->more()) {
5497             const SMDS_MeshNode* node =
5498               static_cast<const SMDS_MeshNode*>(itN->next());
5499             TNodeNodeMap::iterator nodeMapIt = nodeMap.find(node);
5500             if (nodeMapIt == nodeMap.end())
5501               break; // not all nodes transformed
5502             if (needReverse) {
5503               // reverse mirrored faces and volumes
5504               poly_nodes[nbNodes - iNode - 1] = (*nodeMapIt).second;
5505             } else {
5506               poly_nodes[iNode] = (*nodeMapIt).second;
5507             }
5508             iNode++;
5509           }
5510           if ( iNode != nbNodes )
5511             continue; // not all nodes transformed
5512
5513           if ( theTargetMesh ) {
5514             myLastCreatedElems.Append(aTgtMesh->AddPolygonalFace(poly_nodes));
5515             srcElems.Append( elem );
5516           }
5517           else if ( theCopy ) {
5518             myLastCreatedElems.Append(aMesh->AddPolygonalFace(poly_nodes));
5519             srcElems.Append( elem );
5520           }
5521           else {
5522             aMesh->ChangePolygonNodes(elem, poly_nodes);
5523           }
5524         }
5525         break;
5526       case SMDSAbs_Volume:
5527         {
5528           // ATTENTION: Reversing is not yet done!!!
5529           const SMDS_VtkVolume* aPolyedre =
5530             dynamic_cast<const SMDS_VtkVolume*>( elem );
5531           if (!aPolyedre) {
5532             MESSAGE("Warning: bad volumic element");
5533             continue;
5534           }
5535
5536           vector<const SMDS_MeshNode*> poly_nodes;
5537           vector<int> quantities;
5538
5539           bool allTransformed = true;
5540           int nbFaces = aPolyedre->NbFaces();
5541           for (int iface = 1; iface <= nbFaces && allTransformed; iface++) {
5542             int nbFaceNodes = aPolyedre->NbFaceNodes(iface);
5543             for (int inode = 1; inode <= nbFaceNodes && allTransformed; inode++) {
5544               const SMDS_MeshNode* node = aPolyedre->GetFaceNode(iface, inode);
5545               TNodeNodeMap::iterator nodeMapIt = nodeMap.find(node);
5546               if (nodeMapIt == nodeMap.end()) {
5547                 allTransformed = false; // not all nodes transformed
5548               } else {
5549                 poly_nodes.push_back((*nodeMapIt).second);
5550               }
5551             }
5552             quantities.push_back(nbFaceNodes);
5553           }
5554           if ( !allTransformed )
5555             continue; // not all nodes transformed
5556
5557           if ( theTargetMesh ) {
5558             myLastCreatedElems.Append(aTgtMesh->AddPolyhedralVolume(poly_nodes, quantities));
5559             srcElems.Append( elem );
5560           }
5561           else if ( theCopy ) {
5562             myLastCreatedElems.Append(aMesh->AddPolyhedralVolume(poly_nodes, quantities));
5563             srcElems.Append( elem );
5564           }
5565           else {
5566             aMesh->ChangePolyhedronNodes(elem, poly_nodes, quantities);
5567           }
5568         }
5569         break;
5570       default:;
5571       }
5572       continue;
5573     }
5574
5575     // Regular elements
5576     int* i = index[ FORWARD ];
5577     if ( needReverse && nbNodes > 2) {// reverse mirrored faces and volumes
5578       if ( elemType == SMDSAbs_Face )
5579         i = index[ REV_FACE ];
5580       else
5581         i = index[ nbNodes - 4 ];
5582     }
5583     if(elem->IsQuadratic()) {
5584       static int anIds[] = {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19};
5585       i = anIds;
5586       if(needReverse) {
5587         if(nbNodes==3) { // quadratic edge
5588           static int anIds[] = {1,0,2};
5589           i = anIds;
5590         }
5591         else if(nbNodes==6) { // quadratic triangle
5592           static int anIds[] = {0,2,1,5,4,3};
5593           i = anIds;
5594         }
5595         else if(nbNodes==8) { // quadratic quadrangle
5596           static int anIds[] = {0,3,2,1,7,6,5,4};
5597           i = anIds;
5598         }
5599         else if(nbNodes==10) { // quadratic tetrahedron of 10 nodes
5600           static int anIds[] = {0,2,1,3,6,5,4,7,9,8};
5601           i = anIds;
5602         }
5603         else if(nbNodes==13) { // quadratic pyramid of 13 nodes
5604           static int anIds[] = {0,3,2,1,4,8,7,6,5,9,12,11,10};
5605           i = anIds;
5606         }
5607         else if(nbNodes==15) { // quadratic pentahedron with 15 nodes
5608           static int anIds[] = {0,2,1,3,5,4,8,7,6,11,10,9,12,14,13};
5609           i = anIds;
5610         }
5611         else { // nbNodes==20 - quadratic hexahedron with 20 nodes
5612           static int anIds[] = {0,3,2,1,4,7,6,5,11,10,9,8,15,14,13,12,16,19,18,17};
5613           i = anIds;
5614         }
5615       }
5616     }
5617
5618     // find transformed nodes
5619     vector<const SMDS_MeshNode*> nodes(nbNodes);
5620     int iNode = 0;
5621     SMDS_ElemIteratorPtr itN = elem->nodesIterator();
5622     while ( itN->more() ) {
5623       const SMDS_MeshNode* node =
5624         static_cast<const SMDS_MeshNode*>( itN->next() );
5625       TNodeNodeMap::iterator nodeMapIt = nodeMap.find( node );
5626       if ( nodeMapIt == nodeMap.end() )
5627         break; // not all nodes transformed
5628       nodes[ i [ iNode++ ]] = (*nodeMapIt).second;
5629     }
5630     if ( iNode != nbNodes )
5631       continue; // not all nodes transformed
5632
5633     if ( theTargetMesh ) {
5634       if ( SMDS_MeshElement* copy =
5635            targetMeshEditor.AddElement( nodes, elem->GetType(), elem->IsPoly() )) {
5636         myLastCreatedElems.Append( copy );
5637         srcElems.Append( elem );
5638       }
5639     }
5640     else if ( theCopy ) {
5641       if ( AddElement( nodes, elem->GetType(), elem->IsPoly() ))
5642         srcElems.Append( elem );
5643     }
5644     else {
5645       // reverse element as it was reversed by transformation
5646       if ( nbNodes > 2 )
5647         aMesh->ChangeElementNodes( elem, &nodes[0], nbNodes );
5648     }
5649   }
5650
5651   PGroupIDs newGroupIDs;
5652
5653   if ( theMakeGroups && theCopy ||
5654        theMakeGroups && theTargetMesh )
5655     newGroupIDs = generateGroups( srcNodes, srcElems, groupPostfix, theTargetMesh );
5656
5657   return newGroupIDs;
5658 }
5659
5660
5661 ////=======================================================================
5662 ////function : Scale
5663 ////purpose  :
5664 ////=======================================================================
5665 //
5666 //SMESH_MeshEditor::PGroupIDs
5667 //SMESH_MeshEditor::Scale (TIDSortedElemSet & theElems,
5668 //                         const gp_Pnt&            thePoint,
5669 //                         const std::list<double>& theScaleFact,
5670 //                         const bool         theCopy,
5671 //                         const bool         theMakeGroups,
5672 //                         SMESH_Mesh*        theTargetMesh)
5673 //{
5674 //  MESSAGE("Scale");
5675 //  myLastCreatedElems.Clear();
5676 //  myLastCreatedNodes.Clear();
5677 //
5678 //  SMESH_MeshEditor targetMeshEditor( theTargetMesh );
5679 //  SMESHDS_Mesh* aTgtMesh = theTargetMesh ? theTargetMesh->GetMeshDS() : 0;
5680 //  SMESHDS_Mesh* aMesh    = GetMeshDS();
5681 //
5682 //  double scaleX=1.0, scaleY=1.0, scaleZ=1.0;
5683 //  std::list<double>::const_iterator itS = theScaleFact.begin();
5684 //  scaleX = (*itS);
5685 //  if(theScaleFact.size()==1) {
5686 //    scaleY = (*itS);
5687 //    scaleZ= (*itS);
5688 //  }
5689 //  if(theScaleFact.size()==2) {
5690 //    itS++;
5691 //    scaleY = (*itS);
5692 //    scaleZ= (*itS);
5693 //  }
5694 //  if(theScaleFact.size()>2) {
5695 //    itS++;
5696 //    scaleY = (*itS);
5697 //    itS++;
5698 //    scaleZ= (*itS);
5699 //  }
5700 //
5701 //  // map old node to new one
5702 //  TNodeNodeMap nodeMap;
5703 //
5704 //  // elements sharing moved nodes; those of them which have all
5705 //  // nodes mirrored but are not in theElems are to be reversed
5706 //  TIDSortedElemSet inverseElemSet;
5707 //
5708 //  // source elements for each generated one
5709 //  SMESH_SequenceOfElemPtr srcElems, srcNodes;
5710 //
5711 //  // loop on theElems
5712 //  TIDSortedElemSet::iterator itElem;
5713 //  for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
5714 //    const SMDS_MeshElement* elem = *itElem;
5715 //    if ( !elem )
5716 //      continue;
5717 //
5718 //    // loop on elem nodes
5719 //    SMDS_ElemIteratorPtr itN = elem->nodesIterator();
5720 //    while ( itN->more() ) {
5721 //
5722 //      // check if a node has been already transformed
5723 //      const SMDS_MeshNode* node = cast2Node( itN->next() );
5724 //      pair<TNodeNodeMap::iterator,bool> n2n_isnew =
5725 //        nodeMap.insert( make_pair ( node, node ));
5726 //      if ( !n2n_isnew.second )
5727 //        continue;
5728 //
5729 //      //double coord[3];
5730 //      //coord[0] = node->X();
5731 //      //coord[1] = node->Y();
5732 //      //coord[2] = node->Z();
5733 //      //theTrsf.Transforms( coord[0], coord[1], coord[2] );
5734 //      double dx = (node->X() - thePoint.X()) * scaleX;
5735 //      double dy = (node->Y() - thePoint.Y()) * scaleY;
5736 //      double dz = (node->Z() - thePoint.Z()) * scaleZ;
5737 //      if ( theTargetMesh ) {
5738 //        //const SMDS_MeshNode * newNode = aTgtMesh->AddNode( coord[0], coord[1], coord[2] );
5739 //        const SMDS_MeshNode * newNode =
5740 //          aTgtMesh->AddNode( thePoint.X()+dx, thePoint.Y()+dy, thePoint.Z()+dz );
5741 //        n2n_isnew.first->second = newNode;
5742 //        myLastCreatedNodes.Append(newNode);
5743 //        srcNodes.Append( node );
5744 //      }
5745 //      else if ( theCopy ) {
5746 //        //const SMDS_MeshNode * newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
5747 //        const SMDS_MeshNode * newNode =
5748 //          aMesh->AddNode( thePoint.X()+dx, thePoint.Y()+dy, thePoint.Z()+dz );
5749 //        n2n_isnew.first->second = newNode;
5750 //        myLastCreatedNodes.Append(newNode);
5751 //        srcNodes.Append( node );
5752 //      }
5753 //      else {
5754 //        //aMesh->MoveNode( node, coord[0], coord[1], coord[2] );
5755 //        aMesh->MoveNode( node, thePoint.X()+dx, thePoint.Y()+dy, thePoint.Z()+dz );
5756 //        // node position on shape becomes invalid
5757 //        const_cast< SMDS_MeshNode* > ( node )->SetPosition
5758 //          ( SMDS_SpacePosition::originSpacePosition() );
5759 //      }
5760 //
5761 //      // keep inverse elements
5762 //      //if ( !theCopy && !theTargetMesh && needReverse ) {
5763 //      //  SMDS_ElemIteratorPtr invElemIt = node->GetInverseElementIterator();
5764 //      //  while ( invElemIt->more() ) {
5765 //      //    const SMDS_MeshElement* iel = invElemIt->next();
5766 //      //    inverseElemSet.insert( iel );
5767 //      //  }
5768 //      //}
5769 //    }
5770 //  }
5771 //
5772 //  // either create new elements or reverse mirrored ones
5773 //  //if ( !theCopy && !needReverse && !theTargetMesh )
5774 //  if ( !theCopy && !theTargetMesh )
5775 //    return PGroupIDs();
5776 //
5777 //  TIDSortedElemSet::iterator invElemIt = inverseElemSet.begin();
5778 //  for ( ; invElemIt != inverseElemSet.end(); invElemIt++ )
5779 //    theElems.insert( *invElemIt );
5780 //
5781 //  // replicate or reverse elements
5782 //
5783 //  enum {
5784 //    REV_TETRA   = 0,  //  = nbNodes - 4
5785 //    REV_PYRAMID = 1,  //  = nbNodes - 4
5786 //    REV_PENTA   = 2,  //  = nbNodes - 4
5787 //    REV_FACE    = 3,
5788 //    REV_HEXA    = 4,  //  = nbNodes - 4
5789 //    FORWARD     = 5
5790 //  };
5791 //  int index[][8] = {
5792 //    { 2, 1, 0, 3, 4, 0, 0, 0 },  // REV_TETRA
5793 //    { 2, 1, 0, 3, 4, 0, 0, 0 },  // REV_PYRAMID
5794 //    { 2, 1, 0, 5, 4, 3, 0, 0 },  // REV_PENTA
5795 //    { 2, 1, 0, 3, 0, 0, 0, 0 },  // REV_FACE
5796 //    { 2, 1, 0, 3, 6, 5, 4, 7 },  // REV_HEXA
5797 //    { 0, 1, 2, 3, 4, 5, 6, 7 }   // FORWARD
5798 //  };
5799 //
5800 //  for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ )
5801 //  {
5802 //    const SMDS_MeshElement* elem = *itElem;
5803 //    if ( !elem || elem->GetType() == SMDSAbs_Node )
5804 //      continue;
5805 //
5806 //    int nbNodes = elem->NbNodes();
5807 //    int elemType = elem->GetType();
5808 //
5809 //    if (elem->IsPoly()) {
5810 //      // Polygon or Polyhedral Volume
5811 //      switch ( elemType ) {
5812 //      case SMDSAbs_Face:
5813 //        {
5814 //          vector<const SMDS_MeshNode*> poly_nodes (nbNodes);
5815 //          int iNode = 0;
5816 //          SMDS_ElemIteratorPtr itN = elem->nodesIterator();
5817 //          while (itN->more()) {
5818 //            const SMDS_MeshNode* node =
5819 //              static_cast<const SMDS_MeshNode*>(itN->next());
5820 //            TNodeNodeMap::iterator nodeMapIt = nodeMap.find(node);
5821 //            if (nodeMapIt == nodeMap.end())
5822 //              break; // not all nodes transformed
5823 //            //if (needReverse) {
5824 //            //  // reverse mirrored faces and volumes
5825 //            //  poly_nodes[nbNodes - iNode - 1] = (*nodeMapIt).second;
5826 //            //} else {
5827 //            poly_nodes[iNode] = (*nodeMapIt).second;
5828 //            //}
5829 //            iNode++;
5830 //          }
5831 //          if ( iNode != nbNodes )
5832 //            continue; // not all nodes transformed
5833 //
5834 //          if ( theTargetMesh ) {
5835 //            myLastCreatedElems.Append(aTgtMesh->AddPolygonalFace(poly_nodes));
5836 //            srcElems.Append( elem );
5837 //          }
5838 //          else if ( theCopy ) {
5839 //            myLastCreatedElems.Append(aMesh->AddPolygonalFace(poly_nodes));
5840 //            srcElems.Append( elem );
5841 //          }
5842 //          else {
5843 //            aMesh->ChangePolygonNodes(elem, poly_nodes);
5844 //          }
5845 //        }
5846 //        break;
5847 //      case SMDSAbs_Volume:
5848 //        {
5849 //          // ATTENTION: Reversing is not yet done!!!
5850 //          const SMDS_VtkVolume* aPolyedre =
5851 //            dynamic_cast<const SMDS_VtkVolume*>( elem );
5852 //          if (!aPolyedre) {
5853 //            MESSAGE("Warning: bad volumic element");
5854 //            continue;
5855 //          }
5856 //
5857 //          vector<const SMDS_MeshNode*> poly_nodes;
5858 //          vector<int> quantities;
5859 //
5860 //          bool allTransformed = true;
5861 //          int nbFaces = aPolyedre->NbFaces();
5862 //          for (int iface = 1; iface <= nbFaces && allTransformed; iface++) {
5863 //            int nbFaceNodes = aPolyedre->NbFaceNodes(iface);
5864 //            for (int inode = 1; inode <= nbFaceNodes && allTransformed; inode++) {
5865 //              const SMDS_MeshNode* node = aPolyedre->GetFaceNode(iface, inode);
5866 //              TNodeNodeMap::iterator nodeMapIt = nodeMap.find(node);
5867 //              if (nodeMapIt == nodeMap.end()) {
5868 //                allTransformed = false; // not all nodes transformed
5869 //              } else {
5870 //                poly_nodes.push_back((*nodeMapIt).second);
5871 //              }
5872 //            }
5873 //            quantities.push_back(nbFaceNodes);
5874 //          }
5875 //          if ( !allTransformed )
5876 //            continue; // not all nodes transformed
5877 //
5878 //          if ( theTargetMesh ) {
5879 //            myLastCreatedElems.Append(aTgtMesh->AddPolyhedralVolume(poly_nodes, quantities));
5880 //            srcElems.Append( elem );
5881 //          }
5882 //          else if ( theCopy ) {
5883 //            myLastCreatedElems.Append(aMesh->AddPolyhedralVolume(poly_nodes, quantities));
5884 //            srcElems.Append( elem );
5885 //          }
5886 //          else {
5887 //            aMesh->ChangePolyhedronNodes(elem, poly_nodes, quantities);
5888 //          }
5889 //        }
5890 //        break;
5891 //      default:;
5892 //      }
5893 //      continue;
5894 //    }
5895 //
5896 //    // Regular elements
5897 //    int* i = index[ FORWARD ];
5898 //    //if ( needReverse && nbNodes > 2) // reverse mirrored faces and volumes
5899 //    //  if ( elemType == SMDSAbs_Face )
5900 //    //    i = index[ REV_FACE ];
5901 //    //  else
5902 //    //    i = index[ nbNodes - 4 ];
5903 //
5904 //    if(elem->IsQuadratic()) {
5905 //      static int anIds[] = {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19};
5906 //      i = anIds;
5907 //      //if(needReverse) {
5908 //      //  if(nbNodes==3) { // quadratic edge
5909 //      //    static int anIds[] = {1,0,2};
5910 //      //    i = anIds;
5911 //      //  }
5912 //      //  else if(nbNodes==6) { // quadratic triangle
5913 //      //    static int anIds[] = {0,2,1,5,4,3};
5914 //      //    i = anIds;
5915 //      //  }
5916 //      //  else if(nbNodes==8) { // quadratic quadrangle
5917 //      //    static int anIds[] = {0,3,2,1,7,6,5,4};
5918 //      //    i = anIds;
5919 //      //  }
5920 //      //  else if(nbNodes==10) { // quadratic tetrahedron of 10 nodes
5921 //      //    static int anIds[] = {0,2,1,3,6,5,4,7,9,8};
5922 //      //    i = anIds;
5923 //      //  }
5924 //      //  else if(nbNodes==13) { // quadratic pyramid of 13 nodes
5925 //      //    static int anIds[] = {0,3,2,1,4,8,7,6,5,9,12,11,10};
5926 //      //    i = anIds;
5927 //      //  }
5928 //      //  else if(nbNodes==15) { // quadratic pentahedron with 15 nodes
5929 //      //    static int anIds[] = {0,2,1,3,5,4,8,7,6,11,10,9,12,14,13};
5930 //      //    i = anIds;
5931 //      //  }
5932 //      //  else { // nbNodes==20 - quadratic hexahedron with 20 nodes
5933 //      //    static int anIds[] = {0,3,2,1,4,7,6,5,11,10,9,8,15,14,13,12,16,19,18,17};
5934 //      //    i = anIds;
5935 //      //  }
5936 //      //}
5937 //    }
5938 //
5939 //    // find transformed nodes
5940 //    vector<const SMDS_MeshNode*> nodes(nbNodes);
5941 //    int iNode = 0;
5942 //    SMDS_ElemIteratorPtr itN = elem->nodesIterator();
5943 //    while ( itN->more() ) {
5944 //      const SMDS_MeshNode* node =
5945 //        static_cast<const SMDS_MeshNode*>( itN->next() );
5946 //      TNodeNodeMap::iterator nodeMapIt = nodeMap.find( node );
5947 //      if ( nodeMapIt == nodeMap.end() )
5948 //        break; // not all nodes transformed
5949 //      nodes[ i [ iNode++ ]] = (*nodeMapIt).second;
5950 //    }
5951 //    if ( iNode != nbNodes )
5952 //      continue; // not all nodes transformed
5953 //
5954 //    if ( theTargetMesh ) {
5955 //      if ( SMDS_MeshElement* copy =
5956 //           targetMeshEditor.AddElement( nodes, elem->GetType(), elem->IsPoly() )) {
5957 //        myLastCreatedElems.Append( copy );
5958 //        srcElems.Append( elem );
5959 //      }
5960 //    }
5961 //    else if ( theCopy ) {
5962 //      if ( SMDS_MeshElement* copy = AddElement( nodes, elem->GetType(), elem->IsPoly() )) {
5963 //        myLastCreatedElems.Append( copy );
5964 //        srcElems.Append( elem );
5965 //      }
5966 //    }
5967 //    else {
5968 //      // reverse element as it was reversed by transformation
5969 //      if ( nbNodes > 2 )
5970 //        aMesh->ChangeElementNodes( elem, &nodes[0], nbNodes );
5971 //    }
5972 //  }
5973 //
5974 //  PGroupIDs newGroupIDs;
5975 //
5976 //  if ( theMakeGroups && theCopy ||
5977 //       theMakeGroups && theTargetMesh ) {
5978 //    string groupPostfix = "scaled";
5979 //    newGroupIDs = generateGroups( srcNodes, srcElems, groupPostfix, theTargetMesh );
5980 //  }
5981 //
5982 //  return newGroupIDs;
5983 //}
5984
5985
5986 //=======================================================================
5987 /*!
5988  * \brief Create groups of elements made during transformation
5989  * \param nodeGens - nodes making corresponding myLastCreatedNodes
5990  * \param elemGens - elements making corresponding myLastCreatedElems
5991  * \param postfix - to append to names of new groups
5992  */
5993 //=======================================================================
5994
5995 SMESH_MeshEditor::PGroupIDs
5996 SMESH_MeshEditor::generateGroups(const SMESH_SequenceOfElemPtr& nodeGens,
5997                                  const SMESH_SequenceOfElemPtr& elemGens,
5998                                  const std::string&             postfix,
5999                                  SMESH_Mesh*                    targetMesh)
6000 {
6001   PGroupIDs newGroupIDs( new list<int> );
6002   SMESH_Mesh* mesh = targetMesh ? targetMesh : GetMesh();
6003
6004   // Sort existing groups by types and collect their names
6005
6006   // to store an old group and a generated new one
6007   typedef pair< SMESHDS_GroupBase*, SMDS_MeshGroup* > TOldNewGroup;
6008   vector< list< TOldNewGroup > > groupsByType( SMDSAbs_NbElementTypes );
6009   // group names
6010   set< string > groupNames;
6011   //
6012   SMDS_MeshGroup* nullNewGroup = (SMDS_MeshGroup*) 0;
6013   SMESH_Mesh::GroupIteratorPtr groupIt = GetMesh()->GetGroups();
6014   while ( groupIt->more() ) {
6015     SMESH_Group * group = groupIt->next();
6016     if ( !group ) continue;
6017     SMESHDS_GroupBase* groupDS = group->GetGroupDS();
6018     if ( !groupDS || groupDS->IsEmpty() ) continue;
6019     groupNames.insert( group->GetName() );
6020     groupDS->SetStoreName( group->GetName() );
6021     groupsByType[ groupDS->GetType() ].push_back( make_pair( groupDS, nullNewGroup ));
6022   }
6023
6024   // Groups creation
6025
6026   // loop on nodes and elements
6027   for ( int isNodes = 0; isNodes < 2; ++isNodes )
6028   {
6029     const SMESH_SequenceOfElemPtr& gens  = isNodes ? nodeGens : elemGens;
6030     const SMESH_SequenceOfElemPtr& elems = isNodes ? myLastCreatedNodes : myLastCreatedElems;
6031     if ( gens.Length() != elems.Length() )
6032       throw SALOME_Exception(LOCALIZED("invalid args"));
6033
6034     // loop on created elements
6035     for (int iElem = 1; iElem <= elems.Length(); ++iElem )
6036     {
6037       const SMDS_MeshElement* sourceElem = gens( iElem );
6038       if ( !sourceElem ) {
6039         MESSAGE("generateGroups(): NULL source element");
6040         continue;
6041       }
6042       list< TOldNewGroup > & groupsOldNew = groupsByType[ sourceElem->GetType() ];
6043       if ( groupsOldNew.empty() ) {
6044         while ( iElem < gens.Length() && gens( iElem+1 ) == sourceElem )
6045           ++iElem; // skip all elements made by sourceElem
6046         continue;
6047       }
6048       // collect all elements made by sourceElem
6049       list< const SMDS_MeshElement* > resultElems;
6050       if ( const SMDS_MeshElement* resElem = elems( iElem ))
6051         if ( resElem != sourceElem )
6052           resultElems.push_back( resElem );
6053       while ( iElem < gens.Length() && gens( iElem+1 ) == sourceElem )
6054         if ( const SMDS_MeshElement* resElem = elems( ++iElem ))
6055           if ( resElem != sourceElem )
6056             resultElems.push_back( resElem );
6057       // do not generate element groups from node ones
6058       if ( sourceElem->GetType() == SMDSAbs_Node &&
6059            elems( iElem )->GetType() != SMDSAbs_Node )
6060         continue;
6061
6062       // add resultElems to groups made by ones the sourceElem belongs to
6063       list< TOldNewGroup >::iterator gOldNew, gLast = groupsOldNew.end();
6064       for ( gOldNew = groupsOldNew.begin(); gOldNew != gLast; ++gOldNew )
6065       {
6066         SMESHDS_GroupBase* oldGroup = gOldNew->first;
6067         if ( oldGroup->Contains( sourceElem )) // sourceElem in oldGroup
6068         {
6069           SMDS_MeshGroup* & newGroup = gOldNew->second;
6070           if ( !newGroup )// create a new group
6071           {
6072             // make a name
6073             string name = oldGroup->GetStoreName();
6074             if ( !targetMesh ) {
6075               name += "_";
6076               name += postfix;
6077               int nb = 0;
6078               while ( !groupNames.insert( name ).second ) // name exists
6079               {
6080                 if ( nb == 0 ) {
6081                   name += "_1";
6082                 }
6083                 else {
6084                   TCollection_AsciiString nbStr(nb+1);
6085                   name.resize( name.rfind('_')+1 );
6086                   name += nbStr.ToCString();
6087                 }
6088                 ++nb;
6089               }
6090             }
6091             // make a group
6092             int id;
6093             SMESH_Group* group = mesh->AddGroup( resultElems.back()->GetType(),
6094                                                  name.c_str(), id );
6095             SMESHDS_Group* groupDS = static_cast<SMESHDS_Group*>(group->GetGroupDS());
6096             newGroup = & groupDS->SMDSGroup();
6097             newGroupIDs->push_back( id );
6098           }
6099
6100           // fill in a new group
6101           list< const SMDS_MeshElement* >::iterator resLast = resultElems.end(), resElemIt;
6102           for ( resElemIt = resultElems.begin(); resElemIt != resLast; ++resElemIt )
6103             newGroup->Add( *resElemIt );
6104         }
6105       }
6106     } // loop on created elements
6107   }// loop on nodes and elements
6108
6109   return newGroupIDs;
6110 }
6111
6112 //================================================================================
6113 /*!
6114  * \brief Return list of group of nodes close to each other within theTolerance
6115  *        Search among theNodes or in the whole mesh if theNodes is empty using
6116  *        an Octree algorithm
6117  */
6118 //================================================================================
6119
6120 void SMESH_MeshEditor::FindCoincidentNodes (TIDSortedNodeSet &   theNodes,
6121                                             const double         theTolerance,
6122                                             TListOfListOfNodes & theGroupsOfNodes)
6123 {
6124   myLastCreatedElems.Clear();
6125   myLastCreatedNodes.Clear();
6126
6127   if ( theNodes.empty() )
6128   { // get all nodes in the mesh
6129     SMDS_NodeIteratorPtr nIt = GetMeshDS()->nodesIterator(/*idInceasingOrder=*/true);
6130     while ( nIt->more() )
6131       theNodes.insert( theNodes.end(),nIt->next());
6132   }
6133
6134   SMESH_OctreeNode::FindCoincidentNodes ( theNodes, &theGroupsOfNodes, theTolerance);
6135 }
6136
6137
6138 //=======================================================================
6139 /*!
6140  * \brief Implementation of search for the node closest to point
6141  */
6142 //=======================================================================
6143
6144 struct SMESH_NodeSearcherImpl: public SMESH_NodeSearcher
6145 {
6146   //---------------------------------------------------------------------
6147   /*!
6148    * \brief Constructor
6149    */
6150   SMESH_NodeSearcherImpl( const SMESHDS_Mesh* theMesh )
6151   {
6152     myMesh = ( SMESHDS_Mesh* ) theMesh;
6153
6154     TIDSortedNodeSet nodes;
6155     if ( theMesh ) {
6156       SMDS_NodeIteratorPtr nIt = theMesh->nodesIterator(/*idInceasingOrder=*/true);
6157       while ( nIt->more() )
6158         nodes.insert( nodes.end(), nIt->next() );
6159     }
6160     myOctreeNode = new SMESH_OctreeNode(nodes) ;
6161
6162     // get max size of a leaf box
6163     SMESH_OctreeNode* tree = myOctreeNode;
6164     while ( !tree->isLeaf() )
6165     {
6166       SMESH_OctreeNodeIteratorPtr cIt = tree->GetChildrenIterator();
6167       if ( cIt->more() )
6168         tree = cIt->next();
6169     }
6170     myHalfLeafSize = tree->maxSize() / 2.;
6171   }
6172
6173   //---------------------------------------------------------------------
6174   /*!
6175    * \brief Move node and update myOctreeNode accordingly
6176    */
6177   void MoveNode( const SMDS_MeshNode* node, const gp_Pnt& toPnt )
6178   {
6179     myOctreeNode->UpdateByMoveNode( node, toPnt );
6180     myMesh->MoveNode( node, toPnt.X(), toPnt.Y(), toPnt.Z() );
6181   }
6182
6183   //---------------------------------------------------------------------
6184   /*!
6185    * \brief Do it's job
6186    */
6187   const SMDS_MeshNode* FindClosestTo( const gp_Pnt& thePnt )
6188   {
6189     map<double, const SMDS_MeshNode*> dist2Nodes;
6190     myOctreeNode->NodesAround( thePnt.Coord(), dist2Nodes, myHalfLeafSize );
6191     if ( !dist2Nodes.empty() )
6192       return dist2Nodes.begin()->second;
6193     list<const SMDS_MeshNode*> nodes;
6194     //myOctreeNode->NodesAround( &tgtNode, &nodes, myHalfLeafSize );
6195
6196     double minSqDist = DBL_MAX;
6197     if ( nodes.empty() )  // get all nodes of OctreeNode's closest to thePnt
6198     {
6199       // sort leafs by their distance from thePnt
6200       typedef map< double, SMESH_OctreeNode* > TDistTreeMap;
6201       TDistTreeMap treeMap;
6202       list< SMESH_OctreeNode* > treeList;
6203       list< SMESH_OctreeNode* >::iterator trIt;
6204       treeList.push_back( myOctreeNode );
6205
6206       gp_XYZ pointNode( thePnt.X(), thePnt.Y(), thePnt.Z() );
6207       bool pointInside = myOctreeNode->isInside( pointNode, myHalfLeafSize );
6208       for ( trIt = treeList.begin(); trIt != treeList.end(); ++trIt)
6209       {
6210         SMESH_OctreeNode* tree = *trIt;
6211         if ( !tree->isLeaf() ) // put children to the queue
6212         {
6213           if ( pointInside && !tree->isInside( pointNode, myHalfLeafSize )) continue;
6214           SMESH_OctreeNodeIteratorPtr cIt = tree->GetChildrenIterator();
6215           while ( cIt->more() )
6216             treeList.push_back( cIt->next() );
6217         }
6218         else if ( tree->NbNodes() ) // put a tree to the treeMap
6219         {
6220           const Bnd_B3d& box = tree->getBox();
6221           double sqDist = thePnt.SquareDistance( 0.5 * ( box.CornerMin() + box.CornerMax() ));
6222           pair<TDistTreeMap::iterator,bool> it_in = treeMap.insert( make_pair( sqDist, tree ));
6223           if ( !it_in.second ) // not unique distance to box center
6224             treeMap.insert( it_in.first, make_pair( sqDist + 1e-13*treeMap.size(), tree ));
6225         }
6226       }
6227       // find distance after which there is no sense to check tree's
6228       double sqLimit = DBL_MAX;
6229       TDistTreeMap::iterator sqDist_tree = treeMap.begin();
6230       if ( treeMap.size() > 5 ) {
6231         SMESH_OctreeNode* closestTree = sqDist_tree->second;
6232         const Bnd_B3d& box = closestTree->getBox();
6233         double limit = sqrt( sqDist_tree->first ) + sqrt ( box.SquareExtent() );
6234         sqLimit = limit * limit;
6235       }
6236       // get all nodes from trees
6237       for ( ; sqDist_tree != treeMap.end(); ++sqDist_tree) {
6238         if ( sqDist_tree->first > sqLimit )
6239           break;
6240         SMESH_OctreeNode* tree = sqDist_tree->second;
6241         tree->NodesAround( tree->GetNodeIterator()->next(), &nodes );
6242       }
6243     }
6244     // find closest among nodes
6245     minSqDist = DBL_MAX;
6246     const SMDS_MeshNode* closestNode = 0;
6247     list<const SMDS_MeshNode*>::iterator nIt = nodes.begin();
6248     for ( ; nIt != nodes.end(); ++nIt ) {
6249       double sqDist = thePnt.SquareDistance( SMESH_TNodeXYZ( *nIt ) );
6250       if ( minSqDist > sqDist ) {
6251         closestNode = *nIt;
6252         minSqDist = sqDist;
6253       }
6254     }
6255     return closestNode;
6256   }
6257
6258   //---------------------------------------------------------------------
6259   /*!
6260    * \brief Destructor
6261    */
6262   ~SMESH_NodeSearcherImpl() { delete myOctreeNode; }
6263
6264   //---------------------------------------------------------------------
6265   /*!
6266    * \brief Return the node tree
6267    */
6268   const SMESH_OctreeNode* getTree() const { return myOctreeNode; }
6269
6270 private:
6271   SMESH_OctreeNode* myOctreeNode;
6272   SMESHDS_Mesh*     myMesh;
6273   double            myHalfLeafSize; // max size of a leaf box
6274 };
6275
6276 //=======================================================================
6277 /*!
6278  * \brief Return SMESH_NodeSearcher
6279  */
6280 //=======================================================================
6281
6282 SMESH_NodeSearcher* SMESH_MeshEditor::GetNodeSearcher() 
6283 {
6284   return new SMESH_NodeSearcherImpl( GetMeshDS() );
6285 }
6286
6287 // ========================================================================
6288 namespace // Utils used in SMESH_ElementSearcherImpl::FindElementsByPoint()
6289 {
6290   const int MaxNbElemsInLeaf = 10; // maximal number of elements in a leaf of tree
6291   const int MaxLevel         = 7;  // maximal tree height -> nb terminal boxes: 8^7 = 2097152
6292   const double NodeRadius = 1e-9;  // to enlarge bnd box of element
6293
6294   //=======================================================================
6295   /*!
6296    * \brief Octal tree of bounding boxes of elements
6297    */
6298   //=======================================================================
6299
6300   class ElementBndBoxTree : public SMESH_Octree
6301   {
6302   public:
6303
6304     ElementBndBoxTree(const SMDS_Mesh& mesh, SMDSAbs_ElementType elemType, SMDS_ElemIteratorPtr theElemIt = SMDS_ElemIteratorPtr(), double tolerance = NodeRadius );
6305     void getElementsNearPoint( const gp_Pnt& point, TIDSortedElemSet& foundElems);
6306     void getElementsNearLine ( const gp_Ax1& line, TIDSortedElemSet& foundElems);
6307     ~ElementBndBoxTree();
6308
6309   protected:
6310     ElementBndBoxTree() {}
6311     SMESH_Octree* allocateOctreeChild() const { return new ElementBndBoxTree; }
6312     void buildChildrenData();
6313     Bnd_B3d* buildRootBox();
6314   private:
6315     //!< Bounding box of element
6316     struct ElementBox : public Bnd_B3d
6317     {
6318       const SMDS_MeshElement* _element;
6319       int                     _refCount; // an ElementBox can be included in several tree branches
6320       ElementBox(const SMDS_MeshElement* elem, double tolerance);
6321     };
6322     vector< ElementBox* > _elements;
6323   };
6324
6325   //================================================================================
6326   /*!
6327    * \brief ElementBndBoxTree creation
6328    */
6329   //================================================================================
6330
6331   ElementBndBoxTree::ElementBndBoxTree(const SMDS_Mesh& mesh, SMDSAbs_ElementType elemType, SMDS_ElemIteratorPtr theElemIt, double tolerance)
6332     :SMESH_Octree( new SMESH_Octree::Limit( MaxLevel, /*minSize=*/0. ))
6333   {
6334     int nbElems = mesh.GetMeshInfo().NbElements( elemType );
6335     _elements.reserve( nbElems );
6336
6337     SMDS_ElemIteratorPtr elemIt = theElemIt ? theElemIt : mesh.elementsIterator( elemType );
6338     while ( elemIt->more() )
6339       _elements.push_back( new ElementBox( elemIt->next(),tolerance  ));
6340
6341     if ( _elements.size() > MaxNbElemsInLeaf )
6342       compute();
6343     else
6344       myIsLeaf = true;
6345   }
6346
6347   //================================================================================
6348   /*!
6349    * \brief Destructor
6350    */
6351   //================================================================================
6352
6353   ElementBndBoxTree::~ElementBndBoxTree()
6354   {
6355     for ( int i = 0; i < _elements.size(); ++i )
6356       if ( --_elements[i]->_refCount <= 0 )
6357         delete _elements[i];
6358   }
6359
6360   //================================================================================
6361   /*!
6362    * \brief Return the maximal box
6363    */
6364   //================================================================================
6365
6366   Bnd_B3d* ElementBndBoxTree::buildRootBox()
6367   {
6368     Bnd_B3d* box = new Bnd_B3d;
6369     for ( int i = 0; i < _elements.size(); ++i )
6370       box->Add( *_elements[i] );
6371     return box;
6372   }
6373
6374   //================================================================================
6375   /*!
6376    * \brief Redistrubute element boxes among children
6377    */
6378   //================================================================================
6379
6380   void ElementBndBoxTree::buildChildrenData()
6381   {
6382     for ( int i = 0; i < _elements.size(); ++i )
6383     {
6384       for (int j = 0; j < 8; j++)
6385       {
6386         if ( !_elements[i]->IsOut( myChildren[j]->getBox() ))
6387         {
6388           _elements[i]->_refCount++;
6389           ((ElementBndBoxTree*)myChildren[j])->_elements.push_back( _elements[i]);
6390         }
6391       }
6392       _elements[i]->_refCount--;
6393     }
6394     _elements.clear();
6395
6396     for (int j = 0; j < 8; j++)
6397     {
6398       ElementBndBoxTree* child = static_cast<ElementBndBoxTree*>( myChildren[j]);
6399       if ( child->_elements.size() <= MaxNbElemsInLeaf )
6400         child->myIsLeaf = true;
6401
6402       if ( child->_elements.capacity() - child->_elements.size() > 1000 )
6403         child->_elements.resize( child->_elements.size() ); // compact
6404     }
6405   }
6406
6407   //================================================================================
6408   /*!
6409    * \brief Return elements which can include the point
6410    */
6411   //================================================================================
6412
6413   void ElementBndBoxTree::getElementsNearPoint( const gp_Pnt&     point,
6414                                                 TIDSortedElemSet& foundElems)
6415   {
6416     if ( level() && getBox().IsOut( point.XYZ() ))
6417       return;
6418
6419     if ( isLeaf() )
6420     {
6421       for ( int i = 0; i < _elements.size(); ++i )
6422         if ( !_elements[i]->IsOut( point.XYZ() ))
6423           foundElems.insert( _elements[i]->_element );
6424     }
6425     else
6426     {
6427       for (int i = 0; i < 8; i++)
6428         ((ElementBndBoxTree*) myChildren[i])->getElementsNearPoint( point, foundElems );
6429     }
6430   }
6431
6432   //================================================================================
6433   /*!
6434    * \brief Return elements which can be intersected by the line
6435    */
6436   //================================================================================
6437
6438   void ElementBndBoxTree::getElementsNearLine( const gp_Ax1&     line,
6439                                                TIDSortedElemSet& foundElems)
6440   {
6441     if ( level() && getBox().IsOut( line ))
6442       return;
6443
6444     if ( isLeaf() )
6445     {
6446       for ( int i = 0; i < _elements.size(); ++i )
6447         if ( !_elements[i]->IsOut( line ))
6448           foundElems.insert( _elements[i]->_element );
6449     }
6450     else
6451     {
6452       for (int i = 0; i < 8; i++)
6453         ((ElementBndBoxTree*) myChildren[i])->getElementsNearLine( line, foundElems );
6454     }
6455   }
6456
6457   //================================================================================
6458   /*!
6459    * \brief Construct the element box
6460    */
6461   //================================================================================
6462
6463   ElementBndBoxTree::ElementBox::ElementBox(const SMDS_MeshElement* elem, double tolerance)
6464   {
6465     _element  = elem;
6466     _refCount = 1;
6467     SMDS_ElemIteratorPtr nIt = elem->nodesIterator();
6468     while ( nIt->more() )
6469       Add( SMESH_TNodeXYZ( cast2Node( nIt->next() )));
6470     Enlarge( tolerance );
6471   }
6472
6473 } // namespace
6474
6475 //=======================================================================
6476 /*!
6477  * \brief Implementation of search for the elements by point and
6478  *        of classification of point in 2D mesh
6479  */
6480 //=======================================================================
6481
6482 struct SMESH_ElementSearcherImpl: public SMESH_ElementSearcher
6483 {
6484   SMESHDS_Mesh*                _mesh;
6485   SMDS_ElemIteratorPtr         _meshPartIt;
6486   ElementBndBoxTree*           _ebbTree;
6487   SMESH_NodeSearcherImpl*      _nodeSearcher;
6488   SMDSAbs_ElementType          _elementType;
6489   double                       _tolerance;
6490   bool                         _outerFacesFound;
6491   set<const SMDS_MeshElement*> _outerFaces; // empty means "no internal faces at all"
6492
6493   SMESH_ElementSearcherImpl( SMESHDS_Mesh& mesh, SMDS_ElemIteratorPtr elemIt=SMDS_ElemIteratorPtr())
6494     : _mesh(&mesh),_meshPartIt(elemIt),_ebbTree(0),_nodeSearcher(0),_tolerance(-1),_outerFacesFound(false) {}
6495   ~SMESH_ElementSearcherImpl()
6496   {
6497     if ( _ebbTree )      delete _ebbTree;      _ebbTree      = 0;
6498     if ( _nodeSearcher ) delete _nodeSearcher; _nodeSearcher = 0;
6499   }
6500   virtual int FindElementsByPoint(const gp_Pnt&                      point,
6501                                   SMDSAbs_ElementType                type,
6502                                   vector< const SMDS_MeshElement* >& foundElements);
6503   virtual TopAbs_State GetPointState(const gp_Pnt& point);
6504
6505   void GetElementsNearLine( const gp_Ax1&                      line,
6506                             SMDSAbs_ElementType                type,
6507                             vector< const SMDS_MeshElement* >& foundElems);
6508   double getTolerance();
6509   bool getIntersParamOnLine(const gp_Lin& line, const SMDS_MeshElement* face,
6510                             const double tolerance, double & param);
6511   void findOuterBoundary(const SMDS_MeshElement* anyOuterFace);
6512   bool isOuterBoundary(const SMDS_MeshElement* face) const
6513   {
6514     return _outerFaces.empty() || _outerFaces.count(face);
6515   }
6516   struct TInters //!< data of intersection of the line and the mesh face (used in GetPointState())
6517   {
6518     const SMDS_MeshElement* _face;
6519     gp_Vec                  _faceNorm;
6520     bool                    _coincides; //!< the line lays in face plane
6521     TInters(const SMDS_MeshElement* face, const gp_Vec& faceNorm, bool coinc=false)
6522       : _face(face), _faceNorm( faceNorm ), _coincides( coinc ) {}
6523   };
6524   struct TFaceLink //!< link and faces sharing it (used in findOuterBoundary())
6525   {
6526     SMESH_TLink      _link;
6527     TIDSortedElemSet _faces;
6528     TFaceLink( const SMDS_MeshNode* n1, const SMDS_MeshNode* n2, const SMDS_MeshElement* face)
6529       : _link( n1, n2 ), _faces( &face, &face + 1) {}
6530   };
6531 };
6532
6533 ostream& operator<< (ostream& out, const SMESH_ElementSearcherImpl::TInters& i)
6534 {
6535   return out << "TInters(face=" << ( i._face ? i._face->GetID() : 0)
6536              << ", _coincides="<<i._coincides << ")";
6537 }
6538
6539 //=======================================================================
6540 /*!
6541  * \brief define tolerance for search
6542  */
6543 //=======================================================================
6544
6545 double SMESH_ElementSearcherImpl::getTolerance()
6546 {
6547   if ( _tolerance < 0 )
6548   {
6549     const SMDS_MeshInfo& meshInfo = _mesh->GetMeshInfo();
6550
6551     _tolerance = 0;
6552     if ( _nodeSearcher && meshInfo.NbNodes() > 1 )
6553     {
6554       double boxSize = _nodeSearcher->getTree()->maxSize();
6555       _tolerance = 1e-8 * boxSize/* / meshInfo.NbNodes()*/;
6556     }
6557     else if ( _ebbTree && meshInfo.NbElements() > 0 )
6558     {
6559       double boxSize = _ebbTree->maxSize();
6560       _tolerance = 1e-8 * boxSize/* / meshInfo.NbElements()*/;
6561     }
6562     if ( _tolerance == 0 )
6563     {
6564       // define tolerance by size of a most complex element
6565       int complexType = SMDSAbs_Volume;
6566       while ( complexType > SMDSAbs_All &&
6567               meshInfo.NbElements( SMDSAbs_ElementType( complexType )) < 1 )
6568         --complexType;
6569       if ( complexType == SMDSAbs_All ) return 0; // empty mesh
6570       double elemSize;
6571       if ( complexType == int( SMDSAbs_Node ))
6572       {
6573         SMDS_NodeIteratorPtr nodeIt = _mesh->nodesIterator();
6574         elemSize = 1;
6575         if ( meshInfo.NbNodes() > 2 )
6576           elemSize = SMESH_TNodeXYZ( nodeIt->next() ).Distance( nodeIt->next() );
6577       }
6578       else
6579       {
6580         SMDS_ElemIteratorPtr elemIt =
6581             _mesh->elementsIterator( SMDSAbs_ElementType( complexType ));
6582         const SMDS_MeshElement* elem = elemIt->next();
6583         SMDS_ElemIteratorPtr nodeIt = elem->nodesIterator();
6584         SMESH_TNodeXYZ n1( cast2Node( nodeIt->next() ));
6585         elemSize = 0;
6586         while ( nodeIt->more() )
6587         {
6588           double dist = n1.Distance( cast2Node( nodeIt->next() ));
6589           elemSize = max( dist, elemSize );
6590         }
6591       }
6592       _tolerance = 1e-4 * elemSize;
6593     }
6594   }
6595   return _tolerance;
6596 }
6597
6598 //================================================================================
6599 /*!
6600  * \brief Find intersection of the line and an edge of face and return parameter on line
6601  */
6602 //================================================================================
6603
6604 bool SMESH_ElementSearcherImpl::getIntersParamOnLine(const gp_Lin&           line,
6605                                                      const SMDS_MeshElement* face,
6606                                                      const double            tol,
6607                                                      double &                param)
6608 {
6609   int nbInts = 0;
6610   param = 0;
6611
6612   GeomAPI_ExtremaCurveCurve anExtCC;
6613   Handle(Geom_Curve) lineCurve = new Geom_Line( line );
6614   
6615   int nbNodes = face->IsQuadratic() ? face->NbNodes()/2 : face->NbNodes();
6616   for ( int i = 0; i < nbNodes && nbInts < 2; ++i )
6617   {
6618     GC_MakeSegment edge( SMESH_TNodeXYZ( face->GetNode( i )),
6619                          SMESH_TNodeXYZ( face->GetNode( (i+1)%nbNodes) )); 
6620     anExtCC.Init( lineCurve, edge);
6621     if ( anExtCC.NbExtrema() > 0 && anExtCC.LowerDistance() <= tol)
6622     {
6623       Quantity_Parameter pl, pe;
6624       anExtCC.LowerDistanceParameters( pl, pe );
6625       param += pl;
6626       if ( ++nbInts == 2 )
6627         break;
6628     }
6629   }
6630   if ( nbInts > 0 ) param /= nbInts;
6631   return nbInts > 0;
6632 }
6633 //================================================================================
6634 /*!
6635  * \brief Find all faces belonging to the outer boundary of mesh
6636  */
6637 //================================================================================
6638
6639 void SMESH_ElementSearcherImpl::findOuterBoundary(const SMDS_MeshElement* outerFace)
6640 {
6641   if ( _outerFacesFound ) return;
6642
6643   // Collect all outer faces by passing from one outer face to another via their links
6644   // and BTW find out if there are internal faces at all.
6645
6646   // checked links and links where outer boundary meets internal one
6647   set< SMESH_TLink > visitedLinks, seamLinks;
6648
6649   // links to treat with already visited faces sharing them
6650   list < TFaceLink > startLinks;
6651
6652   // load startLinks with the first outerFace
6653   startLinks.push_back( TFaceLink( outerFace->GetNode(0), outerFace->GetNode(1), outerFace));
6654   _outerFaces.insert( outerFace );
6655
6656   TIDSortedElemSet emptySet;
6657   while ( !startLinks.empty() )
6658   {
6659     const SMESH_TLink& link  = startLinks.front()._link;
6660     TIDSortedElemSet&  faces = startLinks.front()._faces;
6661
6662     outerFace = *faces.begin();
6663     // find other faces sharing the link
6664     const SMDS_MeshElement* f;
6665     while (( f = SMESH_MeshEditor::FindFaceInSet(link.node1(), link.node2(), emptySet, faces )))
6666       faces.insert( f );
6667
6668     // select another outer face among the found 
6669     const SMDS_MeshElement* outerFace2 = 0;
6670     if ( faces.size() == 2 )
6671     {
6672       outerFace2 = (outerFace == *faces.begin() ? *faces.rbegin() : *faces.begin());
6673     }
6674     else if ( faces.size() > 2 )
6675     {
6676       seamLinks.insert( link );
6677
6678       // link direction within the outerFace
6679       gp_Vec n1n2( SMESH_TNodeXYZ( link.node1()),
6680                    SMESH_TNodeXYZ( link.node2()));
6681       int i1 = outerFace->GetNodeIndex( link.node1() );
6682       int i2 = outerFace->GetNodeIndex( link.node2() );
6683       bool rev = ( abs(i2-i1) == 1 ? i1 > i2 : i2 > i1 );
6684       if ( rev ) n1n2.Reverse();
6685       // outerFace normal
6686       gp_XYZ ofNorm, fNorm;
6687       if ( SMESH_Algo::FaceNormal( outerFace, ofNorm, /*normalized=*/false ))
6688       {
6689         // direction from the link inside outerFace
6690         gp_Vec dirInOF = gp_Vec( ofNorm ) ^ n1n2;
6691         // sort all other faces by angle with the dirInOF
6692         map< double, const SMDS_MeshElement* > angle2Face;
6693         set< const SMDS_MeshElement*, TIDCompare >::const_iterator face = faces.begin();
6694         for ( ; face != faces.end(); ++face )
6695         {
6696           if ( !SMESH_Algo::FaceNormal( *face, fNorm, /*normalized=*/false ))
6697             continue;
6698           gp_Vec dirInF = gp_Vec( fNorm ) ^ n1n2;
6699           double angle = dirInOF.AngleWithRef( dirInF, n1n2 );
6700           if ( angle < 0 ) angle += 2*PI;
6701           angle2Face.insert( make_pair( angle, *face ));
6702         }
6703         if ( !angle2Face.empty() )
6704           outerFace2 = angle2Face.begin()->second;
6705       }
6706     }
6707     // store the found outer face and add its links to continue seaching from
6708     if ( outerFace2 )
6709     {
6710       _outerFaces.insert( outerFace );
6711       int nbNodes = outerFace2->NbNodes()/( outerFace2->IsQuadratic() ? 2 : 1 );
6712       for ( int i = 0; i < nbNodes; ++i )
6713       {
6714         SMESH_TLink link2( outerFace2->GetNode(i), outerFace2->GetNode((i+1)%nbNodes));
6715         if ( visitedLinks.insert( link2 ).second )
6716           startLinks.push_back( TFaceLink( link2.node1(), link2.node2(), outerFace2 ));
6717       }
6718     }
6719     startLinks.pop_front();
6720   }
6721   _outerFacesFound = true;
6722
6723   if ( !seamLinks.empty() )
6724   {
6725     // There are internal boundaries touching the outher one,
6726     // find all faces of internal boundaries in order to find
6727     // faces of boundaries of holes, if any.
6728     
6729   }
6730   else
6731   {
6732     _outerFaces.clear();
6733   }
6734 }
6735
6736 //=======================================================================
6737 /*!
6738  * \brief Find elements of given type where the given point is IN or ON.
6739  *        Returns nb of found elements and elements them-selves.
6740  *
6741  * 'ALL' type means elements of any type excluding nodes and 0D elements
6742  */
6743 //=======================================================================
6744
6745 int SMESH_ElementSearcherImpl::
6746 FindElementsByPoint(const gp_Pnt&                      point,
6747                     SMDSAbs_ElementType                type,
6748                     vector< const SMDS_MeshElement* >& foundElements)
6749 {
6750   foundElements.clear();
6751
6752   double tolerance = getTolerance();
6753
6754   // =================================================================================
6755   if ( type == SMDSAbs_Node || type == SMDSAbs_0DElement )
6756   {
6757     if ( !_nodeSearcher )
6758       _nodeSearcher = new SMESH_NodeSearcherImpl( _mesh );
6759
6760     const SMDS_MeshNode* closeNode = _nodeSearcher->FindClosestTo( point );
6761     if ( !closeNode ) return foundElements.size();
6762
6763     if ( point.Distance( SMESH_TNodeXYZ( closeNode )) > tolerance )
6764       return foundElements.size(); // to far from any node
6765
6766     if ( type == SMDSAbs_Node )
6767     {
6768       foundElements.push_back( closeNode );
6769     }
6770     else
6771     {
6772       SMDS_ElemIteratorPtr elemIt = closeNode->GetInverseElementIterator( SMDSAbs_0DElement );
6773       while ( elemIt->more() )
6774         foundElements.push_back( elemIt->next() );
6775     }
6776   }
6777   // =================================================================================
6778   else // elements more complex than 0D
6779   {
6780     if ( !_ebbTree || _elementType != type )
6781     {
6782       if ( _ebbTree ) delete _ebbTree;
6783       _ebbTree = new ElementBndBoxTree( *_mesh, _elementType = type, _meshPartIt, tolerance );
6784     }
6785     TIDSortedElemSet suspectElems;
6786     _ebbTree->getElementsNearPoint( point, suspectElems );
6787     TIDSortedElemSet::iterator elem = suspectElems.begin();
6788     for ( ; elem != suspectElems.end(); ++elem )
6789       if ( !SMESH_MeshEditor::isOut( *elem, point, tolerance ))
6790         foundElements.push_back( *elem );
6791   }
6792   return foundElements.size();
6793 }
6794
6795 //================================================================================
6796 /*!
6797  * \brief Classify the given point in the closed 2D mesh
6798  */
6799 //================================================================================
6800
6801 TopAbs_State SMESH_ElementSearcherImpl::GetPointState(const gp_Pnt& point)
6802 {
6803   double tolerance = getTolerance();
6804   if ( !_ebbTree || _elementType != SMDSAbs_Face )
6805   {
6806     if ( _ebbTree ) delete _ebbTree;
6807     _ebbTree = new ElementBndBoxTree( *_mesh, _elementType = SMDSAbs_Face, _meshPartIt );
6808   }
6809   // Algo: analyse transition of a line starting at the point through mesh boundary;
6810   // try three lines parallel to axis of the coordinate system and perform rough
6811   // analysis. If solution is not clear perform thorough analysis.
6812
6813   const int nbAxes = 3;
6814   gp_Dir axisDir[ nbAxes ] = { gp::DX(), gp::DY(), gp::DZ() };
6815   map< double, TInters >   paramOnLine2TInters[ nbAxes ];
6816   list< TInters > tangentInters[ nbAxes ]; // of faces whose plane includes the line
6817   multimap< int, int > nbInt2Axis; // to find the simplest case
6818   for ( int axis = 0; axis < nbAxes; ++axis )
6819   {
6820     gp_Ax1 lineAxis( point, axisDir[axis]);
6821     gp_Lin line    ( lineAxis );
6822
6823     TIDSortedElemSet suspectFaces; // faces possibly intersecting the line
6824     _ebbTree->getElementsNearLine( lineAxis, suspectFaces );
6825
6826     // Intersect faces with the line
6827
6828     map< double, TInters > & u2inters = paramOnLine2TInters[ axis ];
6829     TIDSortedElemSet::iterator face = suspectFaces.begin();
6830     for ( ; face != suspectFaces.end(); ++face )
6831     {
6832       // get face plane
6833       gp_XYZ fNorm;
6834       if ( !SMESH_Algo::FaceNormal( *face, fNorm, /*normalized=*/false)) continue;
6835       gp_Pln facePlane( SMESH_TNodeXYZ( (*face)->GetNode(0)), fNorm );
6836
6837       // perform intersection
6838       IntAna_IntConicQuad intersection( line, IntAna_Quadric( facePlane ));
6839       if ( !intersection.IsDone() )
6840         continue;
6841       if ( intersection.IsInQuadric() )
6842       {
6843         tangentInters[ axis ].push_back( TInters( *face, fNorm, true ));
6844       }
6845       else if ( ! intersection.IsParallel() && intersection.NbPoints() > 0 )
6846       {
6847         gp_Pnt intersectionPoint = intersection.Point(1);
6848         if ( !SMESH_MeshEditor::isOut( *face, intersectionPoint, tolerance ))
6849           u2inters.insert(make_pair( intersection.ParamOnConic(1), TInters( *face, fNorm )));
6850       }
6851     }
6852     // Analyse intersections roughly
6853
6854     int nbInter = u2inters.size();
6855     if ( nbInter == 0 )
6856       return TopAbs_OUT; 
6857
6858     double f = u2inters.begin()->first, l = u2inters.rbegin()->first;
6859     if ( nbInter == 1 ) // not closed mesh
6860       return fabs( f ) < tolerance ? TopAbs_ON : TopAbs_UNKNOWN;
6861
6862     if ( fabs( f ) < tolerance || fabs( l ) < tolerance )
6863       return TopAbs_ON;
6864
6865     if ( (f<0) == (l<0) )
6866       return TopAbs_OUT;
6867
6868     int nbIntBeforePoint = std::distance( u2inters.begin(), u2inters.lower_bound(0));
6869     int nbIntAfterPoint  = nbInter - nbIntBeforePoint;
6870     if ( nbIntBeforePoint == 1 || nbIntAfterPoint == 1 )
6871       return TopAbs_IN;
6872
6873     nbInt2Axis.insert( make_pair( min( nbIntBeforePoint, nbIntAfterPoint ), axis ));
6874
6875     if ( _outerFacesFound ) break; // pass to thorough analysis
6876
6877   } // three attempts - loop on CS axes
6878
6879   // Analyse intersections thoroughly.
6880   // We make two loops maximum, on the first one we only exclude touching intersections,
6881   // on the second, if situation is still unclear, we gather and use information on
6882   // position of faces (internal or outer). If faces position is already gathered,
6883   // we make the second loop right away.
6884
6885   for ( int hasPositionInfo = _outerFacesFound; hasPositionInfo < 2; ++hasPositionInfo )
6886   {
6887     multimap< int, int >::const_iterator nb_axis = nbInt2Axis.begin();
6888     for ( ; nb_axis != nbInt2Axis.end(); ++nb_axis )
6889     {
6890       int axis = nb_axis->second;
6891       map< double, TInters > & u2inters = paramOnLine2TInters[ axis ];
6892
6893       gp_Ax1 lineAxis( point, axisDir[axis]);
6894       gp_Lin line    ( lineAxis );
6895
6896       // add tangent intersections to u2inters
6897       double param;
6898       list< TInters >::const_iterator tgtInt = tangentInters[ axis ].begin();
6899       for ( ; tgtInt != tangentInters[ axis ].end(); ++tgtInt )
6900         if ( getIntersParamOnLine( line, tgtInt->_face, tolerance, param ))
6901           u2inters.insert(make_pair( param, *tgtInt ));
6902       tangentInters[ axis ].clear();
6903
6904       // Count intersections before and after the point excluding touching ones.
6905       // If hasPositionInfo we count intersections of outer boundary only
6906
6907       int nbIntBeforePoint = 0, nbIntAfterPoint = 0;
6908       double f = numeric_limits<double>::max(), l = -numeric_limits<double>::max();
6909       map< double, TInters >::iterator u_int1 = u2inters.begin(), u_int2 = u_int1;
6910       bool ok = ! u_int1->second._coincides;
6911       while ( ok && u_int1 != u2inters.end() )
6912       {
6913         double u = u_int1->first;
6914         bool touchingInt = false;
6915         if ( ++u_int2 != u2inters.end() )
6916         {
6917           // skip intersections at the same point (if the line passes through edge or node)
6918           int nbSamePnt = 0;
6919           while ( u_int2 != u2inters.end() && fabs( u_int2->first - u ) < tolerance )
6920           {
6921             ++nbSamePnt;
6922             ++u_int2;
6923           }
6924
6925           // skip tangent intersections
6926           int nbTgt = 0;
6927           const SMDS_MeshElement* prevFace = u_int1->second._face;
6928           while ( ok && u_int2->second._coincides )
6929           {
6930             if ( SMESH_Algo::GetCommonNodes(prevFace , u_int2->second._face).empty() )
6931               ok = false;
6932             else
6933             {
6934               nbTgt++;
6935               u_int2++;
6936               ok = ( u_int2 != u2inters.end() );
6937             }
6938           }
6939           if ( !ok ) break;
6940
6941           // skip intersections at the same point after tangent intersections
6942           if ( nbTgt > 0 )
6943           {
6944             double u2 = u_int2->first;
6945             ++u_int2;
6946             while ( u_int2 != u2inters.end() && fabs( u_int2->first - u2 ) < tolerance )
6947             {
6948               ++nbSamePnt;
6949               ++u_int2;
6950             }
6951           }
6952           // decide if we skipped a touching intersection
6953           if ( nbSamePnt + nbTgt > 0 )
6954           {
6955             double minDot = numeric_limits<double>::max(), maxDot = -numeric_limits<double>::max();
6956             map< double, TInters >::iterator u_int = u_int1;
6957             for ( ; u_int != u_int2; ++u_int )
6958             {
6959               if ( u_int->second._coincides ) continue;
6960               double dot = u_int->second._faceNorm * line.Direction();
6961               if ( dot > maxDot ) maxDot = dot;
6962               if ( dot < minDot ) minDot = dot;
6963             }
6964             touchingInt = ( minDot*maxDot < 0 );
6965           }
6966         }
6967         if ( !touchingInt )
6968         {
6969           if ( !hasPositionInfo || isOuterBoundary( u_int1->second._face ))
6970           {
6971             if ( u < 0 )
6972               ++nbIntBeforePoint;
6973             else
6974               ++nbIntAfterPoint;
6975           }
6976           if ( u < f ) f = u;
6977           if ( u > l ) l = u;
6978         }
6979
6980         u_int1 = u_int2; // to next intersection
6981
6982       } // loop on intersections with one line
6983
6984       if ( ok )
6985       {
6986         if ( fabs( f ) < tolerance || fabs( l ) < tolerance )
6987           return TopAbs_ON;
6988
6989         if ( nbIntBeforePoint == 0  || nbIntAfterPoint == 0)
6990           return TopAbs_OUT; 
6991
6992         if ( nbIntBeforePoint + nbIntAfterPoint == 1 ) // not closed mesh
6993           return fabs( f ) < tolerance ? TopAbs_ON : TopAbs_UNKNOWN;
6994
6995         if ( nbIntBeforePoint == 1 || nbIntAfterPoint == 1 )
6996           return TopAbs_IN;
6997
6998         if ( (f<0) == (l<0) )
6999           return TopAbs_OUT;
7000
7001         if ( hasPositionInfo )
7002           return nbIntBeforePoint % 2 ? TopAbs_IN : TopAbs_OUT;
7003       }
7004     } // loop on intersections of the tree lines - thorough analysis
7005
7006     if ( !hasPositionInfo )
7007     {
7008       // gather info on faces position - is face in the outer boundary or not
7009       map< double, TInters > & u2inters = paramOnLine2TInters[ 0 ];
7010       findOuterBoundary( u2inters.begin()->second._face );
7011     }
7012
7013   } // two attempts - with and w/o faces position info in the mesh
7014
7015   return TopAbs_UNKNOWN;
7016 }
7017
7018 //=======================================================================
7019 /*!
7020  * \brief Return elements possibly intersecting the line
7021  */
7022 //=======================================================================
7023
7024 void SMESH_ElementSearcherImpl::GetElementsNearLine( const gp_Ax1&                      line,
7025                                                      SMDSAbs_ElementType                type,
7026                                                      vector< const SMDS_MeshElement* >& foundElems)
7027 {
7028   if ( !_ebbTree || _elementType != type )
7029   {
7030     if ( _ebbTree ) delete _ebbTree;
7031     _ebbTree = new ElementBndBoxTree( *_mesh, _elementType = type, _meshPartIt );
7032   }
7033   TIDSortedElemSet suspectFaces; // elements possibly intersecting the line
7034   _ebbTree->getElementsNearLine( line, suspectFaces );
7035   foundElems.assign( suspectFaces.begin(), suspectFaces.end());
7036 }
7037
7038 //=======================================================================
7039 /*!
7040  * \brief Return SMESH_ElementSearcher
7041  */
7042 //=======================================================================
7043
7044 SMESH_ElementSearcher* SMESH_MeshEditor::GetElementSearcher()
7045 {
7046   return new SMESH_ElementSearcherImpl( *GetMeshDS() );
7047 }
7048
7049 //=======================================================================
7050 /*!
7051  * \brief Return SMESH_ElementSearcher
7052  */
7053 //=======================================================================
7054
7055 SMESH_ElementSearcher* SMESH_MeshEditor::GetElementSearcher(SMDS_ElemIteratorPtr elemIt)
7056 {
7057   return new SMESH_ElementSearcherImpl( *GetMeshDS(), elemIt );
7058 }
7059
7060 //=======================================================================
7061 /*!
7062  * \brief Return true if the point is IN or ON of the element
7063  */
7064 //=======================================================================
7065
7066 bool SMESH_MeshEditor::isOut( const SMDS_MeshElement* element, const gp_Pnt& point, double tol )
7067 {
7068   if ( element->GetType() == SMDSAbs_Volume)
7069   {
7070     return SMDS_VolumeTool( element ).IsOut( point.X(), point.Y(), point.Z(), tol );
7071   }
7072
7073   // get ordered nodes
7074
7075   vector< gp_XYZ > xyz;
7076   vector<const SMDS_MeshNode*> nodeList;
7077
7078   SMDS_ElemIteratorPtr nodeIt = element->nodesIterator();
7079   if ( element->IsQuadratic() ) {
7080     if (const SMDS_VtkFace* f=dynamic_cast<const SMDS_VtkFace*>(element))
7081       nodeIt = f->interlacedNodesElemIterator();
7082     else if (const SMDS_VtkEdge*  e =dynamic_cast<const SMDS_VtkEdge*>(element))
7083       nodeIt = e->interlacedNodesElemIterator();
7084   }
7085   while ( nodeIt->more() )
7086     {
7087       const SMDS_MeshNode* node = cast2Node( nodeIt->next() );
7088       xyz.push_back( SMESH_TNodeXYZ(node) );
7089       nodeList.push_back(node);
7090     }
7091
7092   int i, nbNodes = element->NbNodes();
7093
7094   if ( element->GetType() == SMDSAbs_Face ) // --------------------------------------------------
7095   {
7096     // compute face normal
7097     gp_Vec faceNorm(0,0,0);
7098     xyz.push_back( xyz.front() );
7099     nodeList.push_back( nodeList.front() );
7100     for ( i = 0; i < nbNodes; ++i )
7101     {
7102       gp_Vec edge1( xyz[i+1], xyz[i]);
7103       gp_Vec edge2( xyz[i+1], xyz[(i+2)%nbNodes] );
7104       faceNorm += edge1 ^ edge2;
7105     }
7106     double normSize = faceNorm.Magnitude();
7107     if ( normSize <= tol )
7108     {
7109       // degenerated face: point is out if it is out of all face edges
7110       for ( i = 0; i < nbNodes; ++i )
7111       {
7112         SMDS_LinearEdge edge( nodeList[i], nodeList[i+1] );
7113         if ( !isOut( &edge, point, tol ))
7114           return false;
7115       }
7116       return true;
7117     }
7118     faceNorm /= normSize;
7119
7120     // check if the point lays on face plane
7121     gp_Vec n2p( xyz[0], point );
7122     if ( fabs( n2p * faceNorm ) > tol )
7123       return true; // not on face plane
7124
7125     // check if point is out of face boundary:
7126     // define it by closest transition of a ray point->infinity through face boundary
7127     // on the face plane.
7128     // First, find normal of a plane perpendicular to face plane, to be used as a cutting tool
7129     // to find intersections of the ray with the boundary.
7130     gp_Vec ray = n2p;
7131     gp_Vec plnNorm = ray ^ faceNorm;
7132     normSize = plnNorm.Magnitude();
7133     if ( normSize <= tol ) return false; // point coincides with the first node
7134     plnNorm /= normSize;
7135     // for each node of the face, compute its signed distance to the plane
7136     vector<double> dist( nbNodes + 1);
7137     for ( i = 0; i < nbNodes; ++i )
7138     {
7139       gp_Vec n2p( xyz[i], point );
7140       dist[i] = n2p * plnNorm;
7141     }
7142     dist.back() = dist.front();
7143     // find the closest intersection
7144     int    iClosest = -1;
7145     double rClosest, distClosest = 1e100;;
7146     gp_Pnt pClosest;
7147     for ( i = 0; i < nbNodes; ++i )
7148     {
7149       double r;
7150       if ( fabs( dist[i]) < tol )
7151         r = 0.;
7152       else if ( fabs( dist[i+1]) < tol )
7153         r = 1.;
7154       else if ( dist[i] * dist[i+1] < 0 )
7155         r = dist[i] / ( dist[i] - dist[i+1] );
7156       else
7157         continue; // no intersection
7158       gp_Pnt pInt = xyz[i] * (1.-r) + xyz[i+1] * r;
7159       gp_Vec p2int ( point, pInt);
7160       if ( p2int * ray > -tol ) // right half-space
7161       {
7162         double intDist = p2int.SquareMagnitude();
7163         if ( intDist < distClosest )
7164         {
7165           iClosest = i;
7166           rClosest = r;
7167           pClosest = pInt;
7168           distClosest = intDist;
7169         }
7170       }
7171     }
7172     if ( iClosest < 0 )
7173       return true; // no intesections - out
7174
7175     // analyse transition
7176     gp_Vec edge( xyz[iClosest], xyz[iClosest+1] );
7177     gp_Vec edgeNorm = -( edge ^ faceNorm ); // normal to intersected edge pointing out of face
7178     gp_Vec p2int ( point, pClosest );
7179     bool out = (edgeNorm * p2int) < -tol;
7180     if ( rClosest > 0. && rClosest < 1. ) // not node intersection
7181       return out;
7182
7183     // ray pass through a face node; analyze transition through an adjacent edge
7184     gp_Pnt p1 = xyz[ (rClosest == 0.) ? ((iClosest+nbNodes-1) % nbNodes) : (iClosest+1) ];
7185     gp_Pnt p2 = xyz[ (rClosest == 0.) ? iClosest : ((iClosest+2) % nbNodes) ];
7186     gp_Vec edgeAdjacent( p1, p2 );
7187     gp_Vec edgeNorm2 = -( edgeAdjacent ^ faceNorm );
7188     bool out2 = (edgeNorm2 * p2int) < -tol;
7189
7190     bool covexCorner = ( edgeNorm * edgeAdjacent * (rClosest==1. ? 1. : -1.)) < 0;
7191     return covexCorner ? (out || out2) : (out && out2);
7192   }
7193   if ( element->GetType() == SMDSAbs_Edge ) // --------------------------------------------------
7194   {
7195     // point is out of edge if it is NOT ON any straight part of edge
7196     // (we consider quadratic edge as being composed of two straight parts)
7197     for ( i = 1; i < nbNodes; ++i )
7198     {
7199       gp_Vec edge( xyz[i-1], xyz[i]);
7200       gp_Vec n1p ( xyz[i-1], point);
7201       double dist = ( edge ^ n1p ).Magnitude() / edge.Magnitude();
7202       if ( dist > tol )
7203         continue;
7204       gp_Vec n2p( xyz[i], point );
7205       if ( fabs( edge.Magnitude() - n1p.Magnitude() - n2p.Magnitude()) > tol )
7206         continue;
7207       return false; // point is ON this part
7208     }
7209     return true;
7210   }
7211   // Node or 0D element -------------------------------------------------------------------------
7212   {
7213     gp_Vec n2p ( xyz[0], point );
7214     return n2p.Magnitude() <= tol;
7215   }
7216   return true;
7217 }
7218
7219 //=======================================================================
7220 //function : SimplifyFace
7221 //purpose  :
7222 //=======================================================================
7223 int SMESH_MeshEditor::SimplifyFace (const vector<const SMDS_MeshNode *> faceNodes,
7224                                     vector<const SMDS_MeshNode *>&      poly_nodes,
7225                                     vector<int>&                        quantities) const
7226 {
7227   int nbNodes = faceNodes.size();
7228
7229   if (nbNodes < 3)
7230     return 0;
7231
7232   set<const SMDS_MeshNode*> nodeSet;
7233
7234   // get simple seq of nodes
7235   //const SMDS_MeshNode* simpleNodes[ nbNodes ];
7236   vector<const SMDS_MeshNode*> simpleNodes( nbNodes );
7237   int iSimple = 0, nbUnique = 0;
7238
7239   simpleNodes[iSimple++] = faceNodes[0];
7240   nbUnique++;
7241   for (int iCur = 1; iCur < nbNodes; iCur++) {
7242     if (faceNodes[iCur] != simpleNodes[iSimple - 1]) {
7243       simpleNodes[iSimple++] = faceNodes[iCur];
7244       if (nodeSet.insert( faceNodes[iCur] ).second)
7245         nbUnique++;
7246     }
7247   }
7248   int nbSimple = iSimple;
7249   if (simpleNodes[nbSimple - 1] == simpleNodes[0]) {
7250     nbSimple--;
7251     iSimple--;
7252   }
7253
7254   if (nbUnique < 3)
7255     return 0;
7256
7257   // separate loops
7258   int nbNew = 0;
7259   bool foundLoop = (nbSimple > nbUnique);
7260   while (foundLoop) {
7261     foundLoop = false;
7262     set<const SMDS_MeshNode*> loopSet;
7263     for (iSimple = 0; iSimple < nbSimple && !foundLoop; iSimple++) {
7264       const SMDS_MeshNode* n = simpleNodes[iSimple];
7265       if (!loopSet.insert( n ).second) {
7266         foundLoop = true;
7267
7268         // separate loop
7269         int iC = 0, curLast = iSimple;
7270         for (; iC < curLast; iC++) {
7271           if (simpleNodes[iC] == n) break;
7272         }
7273         int loopLen = curLast - iC;
7274         if (loopLen > 2) {
7275           // create sub-element
7276           nbNew++;
7277           quantities.push_back(loopLen);
7278           for (; iC < curLast; iC++) {
7279             poly_nodes.push_back(simpleNodes[iC]);
7280           }
7281         }
7282         // shift the rest nodes (place from the first loop position)
7283         for (iC = curLast + 1; iC < nbSimple; iC++) {
7284           simpleNodes[iC - loopLen] = simpleNodes[iC];
7285         }
7286         nbSimple -= loopLen;
7287         iSimple -= loopLen;
7288       }
7289     } // for (iSimple = 0; iSimple < nbSimple; iSimple++)
7290   } // while (foundLoop)
7291
7292   if (iSimple > 2) {
7293     nbNew++;
7294     quantities.push_back(iSimple);
7295     for (int i = 0; i < iSimple; i++)
7296       poly_nodes.push_back(simpleNodes[i]);
7297   }
7298
7299   return nbNew;
7300 }
7301
7302 //=======================================================================
7303 //function : MergeNodes
7304 //purpose  : In each group, the cdr of nodes are substituted by the first one
7305 //           in all elements.
7306 //=======================================================================
7307
7308 void SMESH_MeshEditor::MergeNodes (TListOfListOfNodes & theGroupsOfNodes)
7309 {
7310   MESSAGE("MergeNodes");
7311   myLastCreatedElems.Clear();
7312   myLastCreatedNodes.Clear();
7313
7314   SMESHDS_Mesh* aMesh = GetMeshDS();
7315
7316   TNodeNodeMap nodeNodeMap; // node to replace - new node
7317   set<const SMDS_MeshElement*> elems; // all elements with changed nodes
7318   list< int > rmElemIds, rmNodeIds;
7319
7320   // Fill nodeNodeMap and elems
7321
7322   TListOfListOfNodes::iterator grIt = theGroupsOfNodes.begin();
7323   for ( ; grIt != theGroupsOfNodes.end(); grIt++ ) {
7324     list<const SMDS_MeshNode*>& nodes = *grIt;
7325     list<const SMDS_MeshNode*>::iterator nIt = nodes.begin();
7326     const SMDS_MeshNode* nToKeep = *nIt;
7327     //MESSAGE("node to keep " << nToKeep->GetID());
7328     for ( ++nIt; nIt != nodes.end(); nIt++ ) {
7329       const SMDS_MeshNode* nToRemove = *nIt;
7330       nodeNodeMap.insert( TNodeNodeMap::value_type( nToRemove, nToKeep ));
7331       if ( nToRemove != nToKeep ) {
7332         //MESSAGE("  node to remove " << nToRemove->GetID());
7333         rmNodeIds.push_back( nToRemove->GetID() );
7334         AddToSameGroups( nToKeep, nToRemove, aMesh );
7335       }
7336
7337       SMDS_ElemIteratorPtr invElemIt = nToRemove->GetInverseElementIterator();
7338       while ( invElemIt->more() ) {
7339         const SMDS_MeshElement* elem = invElemIt->next();
7340         elems.insert(elem);
7341       }
7342     }
7343   }
7344   // Change element nodes or remove an element
7345
7346   set<const SMDS_MeshElement*>::iterator eIt = elems.begin();
7347   for ( ; eIt != elems.end(); eIt++ ) {
7348     const SMDS_MeshElement* elem = *eIt;
7349     //MESSAGE(" ---- inverse elem on node to remove " << elem->GetID());
7350     int nbNodes = elem->NbNodes();
7351     int aShapeId = FindShape( elem );
7352
7353     set<const SMDS_MeshNode*> nodeSet;
7354     vector< const SMDS_MeshNode*> curNodes( nbNodes ), uniqueNodes( nbNodes );
7355     int iUnique = 0, iCur = 0, nbRepl = 0;
7356     vector<int> iRepl( nbNodes );
7357
7358     // get new seq of nodes
7359     SMDS_ElemIteratorPtr itN = elem->nodesIterator();
7360     while ( itN->more() ) {
7361       const SMDS_MeshNode* n =
7362         static_cast<const SMDS_MeshNode*>( itN->next() );
7363
7364       TNodeNodeMap::iterator nnIt = nodeNodeMap.find( n );
7365       if ( nnIt != nodeNodeMap.end() ) { // n sticks
7366         n = (*nnIt).second;
7367         // BUG 0020185: begin
7368         {
7369           bool stopRecur = false;
7370           set<const SMDS_MeshNode*> nodesRecur;
7371           nodesRecur.insert(n);
7372           while (!stopRecur) {
7373             TNodeNodeMap::iterator nnIt_i = nodeNodeMap.find( n );
7374             if ( nnIt_i != nodeNodeMap.end() ) { // n sticks
7375               n = (*nnIt_i).second;
7376               if (!nodesRecur.insert(n).second) {
7377                 // error: recursive dependancy
7378                 stopRecur = true;
7379               }
7380             }
7381             else
7382               stopRecur = true;
7383           }
7384         }
7385         // BUG 0020185: end
7386         iRepl[ nbRepl++ ] = iCur;
7387       }
7388       curNodes[ iCur ] = n;
7389       bool isUnique = nodeSet.insert( n ).second;
7390       if ( isUnique )
7391         uniqueNodes[ iUnique++ ] = n;
7392       iCur++;
7393     }
7394
7395     // Analyse element topology after replacement
7396
7397     bool isOk = true;
7398     int nbUniqueNodes = nodeSet.size();
7399     //MESSAGE("nbNodes nbUniqueNodes " << nbNodes << " " << nbUniqueNodes);
7400     if ( nbNodes != nbUniqueNodes ) { // some nodes stick
7401       // Polygons and Polyhedral volumes
7402       if (elem->IsPoly()) {
7403
7404         if (elem->GetType() == SMDSAbs_Face) {
7405           // Polygon
7406           vector<const SMDS_MeshNode *> face_nodes (nbNodes);
7407           int inode = 0;
7408           for (; inode < nbNodes; inode++) {
7409             face_nodes[inode] = curNodes[inode];
7410           }
7411
7412           vector<const SMDS_MeshNode *> polygons_nodes;
7413           vector<int> quantities;
7414           int nbNew = SimplifyFace(face_nodes, polygons_nodes, quantities);
7415           if (nbNew > 0) {
7416             inode = 0;
7417             for (int iface = 0; iface < nbNew; iface++) {
7418               int nbNodes = quantities[iface];
7419               vector<const SMDS_MeshNode *> poly_nodes (nbNodes);
7420               for (int ii = 0; ii < nbNodes; ii++, inode++) {
7421                 poly_nodes[ii] = polygons_nodes[inode];
7422               }
7423               SMDS_MeshElement* newElem = aMesh->AddPolygonalFace(poly_nodes);
7424               myLastCreatedElems.Append(newElem);
7425               if (aShapeId)
7426                 aMesh->SetMeshElementOnShape(newElem, aShapeId);
7427             }
7428
7429             MESSAGE("ChangeElementNodes MergeNodes Polygon");
7430             //aMesh->ChangeElementNodes(elem, &polygons_nodes[inode], quantities[nbNew - 1]);
7431             vector<const SMDS_MeshNode *> polynodes(polygons_nodes.begin()+inode,polygons_nodes.end());
7432             int quid =0;
7433             if (nbNew > 0) quid = nbNew - 1;
7434             vector<int> newquant(quantities.begin()+quid, quantities.end());
7435             const SMDS_MeshElement* newElem = 0;
7436             newElem = aMesh->AddPolyhedralVolume(polynodes, newquant);
7437             myLastCreatedElems.Append(newElem);
7438             if ( aShapeId && newElem )
7439               aMesh->SetMeshElementOnShape( newElem, aShapeId );
7440             rmElemIds.push_back(elem->GetID());
7441           }
7442           else {
7443             rmElemIds.push_back(elem->GetID());
7444           }
7445
7446         }
7447         else if (elem->GetType() == SMDSAbs_Volume) {
7448           // Polyhedral volume
7449           if (nbUniqueNodes < 4) {
7450             rmElemIds.push_back(elem->GetID());
7451           }
7452           else {
7453             // each face has to be analyzed in order to check volume validity
7454             const SMDS_VtkVolume* aPolyedre =
7455               dynamic_cast<const SMDS_VtkVolume*>( elem );
7456             if (aPolyedre) {
7457               int nbFaces = aPolyedre->NbFaces();
7458
7459               vector<const SMDS_MeshNode *> poly_nodes;
7460               vector<int> quantities;
7461
7462               for (int iface = 1; iface <= nbFaces; iface++) {
7463                 int nbFaceNodes = aPolyedre->NbFaceNodes(iface);
7464                 vector<const SMDS_MeshNode *> faceNodes (nbFaceNodes);
7465
7466                 for (int inode = 1; inode <= nbFaceNodes; inode++) {
7467                   const SMDS_MeshNode * faceNode = aPolyedre->GetFaceNode(iface, inode);
7468                   TNodeNodeMap::iterator nnIt = nodeNodeMap.find(faceNode);
7469                   if (nnIt != nodeNodeMap.end()) { // faceNode sticks
7470                     faceNode = (*nnIt).second;
7471                   }
7472                   faceNodes[inode - 1] = faceNode;
7473                 }
7474
7475                 SimplifyFace(faceNodes, poly_nodes, quantities);
7476               }
7477
7478               if (quantities.size() > 3) {
7479                 // to be done: remove coincident faces
7480               }
7481
7482               if (quantities.size() > 3)
7483                 {
7484                   MESSAGE("ChangeElementNodes MergeNodes Polyhedron");
7485                   //aMesh->ChangePolyhedronNodes(elem, poly_nodes, quantities);
7486                   const SMDS_MeshElement* newElem = 0;
7487                   newElem = aMesh->AddPolyhedralVolume(poly_nodes, quantities);
7488                   myLastCreatedElems.Append(newElem);
7489                   if ( aShapeId && newElem )
7490                     aMesh->SetMeshElementOnShape( newElem, aShapeId );
7491                   rmElemIds.push_back(elem->GetID());
7492                 }
7493             }
7494             else {
7495               rmElemIds.push_back(elem->GetID());
7496             }
7497           }
7498         }
7499         else {
7500         }
7501
7502         continue;
7503       }
7504
7505       // Regular elements
7506       // TODO not all the possible cases are solved. Find something more generic?
7507       switch ( nbNodes ) {
7508       case 2: ///////////////////////////////////// EDGE
7509         isOk = false; break;
7510       case 3: ///////////////////////////////////// TRIANGLE
7511         isOk = false; break;
7512       case 4:
7513         if ( elem->GetType() == SMDSAbs_Volume ) // TETRAHEDRON
7514           isOk = false;
7515         else { //////////////////////////////////// QUADRANGLE
7516           if ( nbUniqueNodes < 3 )
7517             isOk = false;
7518           else if ( nbRepl == 2 && iRepl[ 1 ] - iRepl[ 0 ] == 2 )
7519             isOk = false; // opposite nodes stick
7520           //MESSAGE("isOk " << isOk);
7521         }
7522         break;
7523       case 6: ///////////////////////////////////// PENTAHEDRON
7524         if ( nbUniqueNodes == 4 ) {
7525           // ---------------------------------> tetrahedron
7526           if (nbRepl == 3 &&
7527               iRepl[ 0 ] > 2 && iRepl[ 1 ] > 2 && iRepl[ 2 ] > 2 ) {
7528             // all top nodes stick: reverse a bottom
7529             uniqueNodes[ 0 ] = curNodes [ 1 ];
7530             uniqueNodes[ 1 ] = curNodes [ 0 ];
7531           }
7532           else if (nbRepl == 3 &&
7533                    iRepl[ 0 ] < 3 && iRepl[ 1 ] < 3 && iRepl[ 2 ] < 3 ) {
7534             // all bottom nodes stick: set a top before
7535             uniqueNodes[ 3 ] = uniqueNodes [ 0 ];
7536             uniqueNodes[ 0 ] = curNodes [ 3 ];
7537             uniqueNodes[ 1 ] = curNodes [ 4 ];
7538             uniqueNodes[ 2 ] = curNodes [ 5 ];
7539           }
7540           else if (nbRepl == 4 &&
7541                    iRepl[ 2 ] - iRepl [ 0 ] == 3 && iRepl[ 3 ] - iRepl [ 1 ] == 3 ) {
7542             // a lateral face turns into a line: reverse a bottom
7543             uniqueNodes[ 0 ] = curNodes [ 1 ];
7544             uniqueNodes[ 1 ] = curNodes [ 0 ];
7545           }
7546           else
7547             isOk = false;
7548         }
7549         else if ( nbUniqueNodes == 5 ) {
7550           // PENTAHEDRON --------------------> 2 tetrahedrons
7551           if ( nbRepl == 2 && iRepl[ 1 ] - iRepl [ 0 ] == 3 ) {
7552             // a bottom node sticks with a linked top one
7553             // 1.
7554             SMDS_MeshElement* newElem =
7555               aMesh->AddVolume(curNodes[ 3 ],
7556                                curNodes[ 4 ],
7557                                curNodes[ 5 ],
7558                                curNodes[ iRepl[ 0 ] == 2 ? 1 : 2 ]);
7559             myLastCreatedElems.Append(newElem);
7560             if ( aShapeId )
7561               aMesh->SetMeshElementOnShape( newElem, aShapeId );
7562             // 2. : reverse a bottom
7563             uniqueNodes[ 0 ] = curNodes [ 1 ];
7564             uniqueNodes[ 1 ] = curNodes [ 0 ];
7565             nbUniqueNodes = 4;
7566           }
7567           else
7568             isOk = false;
7569         }
7570         else
7571           isOk = false;
7572         break;
7573       case 8: {
7574         if(elem->IsQuadratic()) { // Quadratic quadrangle
7575           //   1    5    2
7576           //    +---+---+
7577           //    |       |
7578           //    |       |
7579           //   4+       +6
7580           //    |       |
7581           //    |       |
7582           //    +---+---+
7583           //   0    7    3
7584           isOk = false;
7585           if(nbRepl==2) {
7586             MESSAGE("nbRepl=2: " << iRepl[0] << " " << iRepl[1]);
7587           }
7588           if(nbRepl==3) {
7589             MESSAGE("nbRepl=3: " << iRepl[0] << " " << iRepl[1]  << " " << iRepl[2]);
7590             nbUniqueNodes = 6;
7591             if( iRepl[0]==0 && iRepl[1]==1 && iRepl[2]==4 ) {
7592               uniqueNodes[0] = curNodes[0];
7593               uniqueNodes[1] = curNodes[2];
7594               uniqueNodes[2] = curNodes[3];
7595               uniqueNodes[3] = curNodes[5];
7596               uniqueNodes[4] = curNodes[6];
7597               uniqueNodes[5] = curNodes[7];
7598               isOk = true;
7599             }
7600             if( iRepl[0]==0 && iRepl[1]==3 && iRepl[2]==7 ) {
7601               uniqueNodes[0] = curNodes[0];
7602               uniqueNodes[1] = curNodes[1];
7603               uniqueNodes[2] = curNodes[2];
7604               uniqueNodes[3] = curNodes[4];
7605               uniqueNodes[4] = curNodes[5];
7606               uniqueNodes[5] = curNodes[6];
7607               isOk = true;
7608             }
7609             if( iRepl[0]==0 && iRepl[1]==4 && iRepl[2]==7 ) {
7610               uniqueNodes[0] = curNodes[1];
7611               uniqueNodes[1] = curNodes[2];
7612               uniqueNodes[2] = curNodes[3];
7613               uniqueNodes[3] = curNodes[5];
7614               uniqueNodes[4] = curNodes[6];
7615               uniqueNodes[5] = curNodes[0];
7616               isOk = true;
7617             }
7618             if( iRepl[0]==1 && iRepl[1]==2 && iRepl[2]==5 ) {
7619               uniqueNodes[0] = curNodes[0];
7620               uniqueNodes[1] = curNodes[1];
7621               uniqueNodes[2] = curNodes[3];
7622               uniqueNodes[3] = curNodes[4];
7623               uniqueNodes[4] = curNodes[6];
7624               uniqueNodes[5] = curNodes[7];
7625               isOk = true;
7626             }
7627             if( iRepl[0]==1 && iRepl[1]==4 && iRepl[2]==5 ) {
7628               uniqueNodes[0] = curNodes[0];
7629               uniqueNodes[1] = curNodes[2];
7630               uniqueNodes[2] = curNodes[3];
7631               uniqueNodes[3] = curNodes[1];
7632               uniqueNodes[4] = curNodes[6];
7633               uniqueNodes[5] = curNodes[7];
7634               isOk = true;
7635             }
7636             if( iRepl[0]==2 && iRepl[1]==3 && iRepl[2]==6 ) {
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[7];
7643               isOk = true;
7644             }
7645             if( iRepl[0]==2 && iRepl[1]==5 && iRepl[2]==6 ) {
7646               uniqueNodes[0] = curNodes[0];
7647               uniqueNodes[1] = curNodes[1];
7648               uniqueNodes[2] = curNodes[3];
7649               uniqueNodes[3] = curNodes[4];
7650               uniqueNodes[4] = curNodes[2];
7651               uniqueNodes[5] = curNodes[7];
7652               isOk = true;
7653             }
7654             if( iRepl[0]==3 && iRepl[1]==6 && iRepl[2]==7 ) {
7655               uniqueNodes[0] = curNodes[0];
7656               uniqueNodes[1] = curNodes[1];
7657               uniqueNodes[2] = curNodes[2];
7658               uniqueNodes[3] = curNodes[4];
7659               uniqueNodes[4] = curNodes[5];
7660               uniqueNodes[5] = curNodes[3];
7661               isOk = true;
7662             }
7663           }
7664           if(nbRepl==4) {
7665             MESSAGE("nbRepl=4: " << iRepl[0] << " " << iRepl[1]  << " " << iRepl[2] << " " << iRepl[3]);
7666           }
7667           if(nbRepl==5) {
7668             MESSAGE("nbRepl=5: " << iRepl[0] << " " << iRepl[1]  << " " << iRepl[2] << " " << iRepl[3] << " " << iRepl[4]);
7669           }
7670           break;
7671         }
7672         //////////////////////////////////// HEXAHEDRON
7673         isOk = false;
7674         SMDS_VolumeTool hexa (elem);
7675         hexa.SetExternalNormal();
7676         if ( nbUniqueNodes == 4 && nbRepl == 6 ) {
7677           //////////////////////// ---> tetrahedron
7678           for ( int iFace = 0; iFace < 6; iFace++ ) {
7679             const int *ind = hexa.GetFaceNodesIndices( iFace ); // indices of face nodes
7680             if (curNodes[ind[ 0 ]] == curNodes[ind[ 1 ]] &&
7681                 curNodes[ind[ 0 ]] == curNodes[ind[ 2 ]] &&
7682                 curNodes[ind[ 0 ]] == curNodes[ind[ 3 ]] ) {
7683               // one face turns into a point ...
7684               int iOppFace = hexa.GetOppFaceIndex( iFace );
7685               ind = hexa.GetFaceNodesIndices( iOppFace );
7686               int nbStick = 0;
7687               iUnique = 2; // reverse a tetrahedron bottom
7688               for ( iCur = 0; iCur < 4 && nbStick < 2; iCur++ ) {
7689                 if ( curNodes[ind[ iCur ]] == curNodes[ind[ iCur + 1 ]] )
7690                   nbStick++;
7691                 else if ( iUnique >= 0 )
7692                   uniqueNodes[ iUnique-- ] = curNodes[ind[ iCur ]];
7693               }
7694               if ( nbStick == 1 ) {
7695                 // ... and the opposite one - into a triangle.
7696                 // set a top node
7697                 ind = hexa.GetFaceNodesIndices( iFace );
7698                 uniqueNodes[ 3 ] = curNodes[ind[ 0 ]];
7699                 isOk = true;
7700               }
7701               break;
7702             }
7703           }
7704         }
7705         else if (nbUniqueNodes == 5 && nbRepl == 4 ) {
7706           //////////////////// HEXAHEDRON ---> 2 tetrahedrons
7707           for ( int iFace = 0; iFace < 6; iFace++ ) {
7708             const int *ind = hexa.GetFaceNodesIndices( iFace ); // indices of face nodes
7709             if (curNodes[ind[ 0 ]] == curNodes[ind[ 1 ]] &&
7710                 curNodes[ind[ 0 ]] == curNodes[ind[ 2 ]] &&
7711                 curNodes[ind[ 0 ]] == curNodes[ind[ 3 ]] ) {
7712               // one face turns into a point ...
7713               int iOppFace = hexa.GetOppFaceIndex( iFace );
7714               ind = hexa.GetFaceNodesIndices( iOppFace );
7715               int nbStick = 0;
7716               iUnique = 2;  // reverse a tetrahedron 1 bottom
7717               for ( iCur = 0; iCur < 4 && nbStick == 0; iCur++ ) {
7718                 if ( curNodes[ind[ iCur ]] == curNodes[ind[ iCur + 1 ]] )
7719                   nbStick++;
7720                 else if ( iUnique >= 0 )
7721                   uniqueNodes[ iUnique-- ] = curNodes[ind[ iCur ]];
7722               }
7723               if ( nbStick == 0 ) {
7724                 // ... and the opposite one is a quadrangle
7725                 // set a top node
7726                 const int* indTop = hexa.GetFaceNodesIndices( iFace );
7727                 uniqueNodes[ 3 ] = curNodes[indTop[ 0 ]];
7728                 nbUniqueNodes = 4;
7729                 // tetrahedron 2
7730                 SMDS_MeshElement* newElem =
7731                   aMesh->AddVolume(curNodes[ind[ 0 ]],
7732                                    curNodes[ind[ 3 ]],
7733                                    curNodes[ind[ 2 ]],
7734                                    curNodes[indTop[ 0 ]]);
7735                 myLastCreatedElems.Append(newElem);
7736                 if ( aShapeId )
7737                   aMesh->SetMeshElementOnShape( newElem, aShapeId );
7738                 isOk = true;
7739               }
7740               break;
7741             }
7742           }
7743         }
7744         else if ( nbUniqueNodes == 6 && nbRepl == 4 ) {
7745           ////////////////// HEXAHEDRON ---> 2 tetrahedrons or 1 prism
7746           // find indices of quad and tri faces
7747           int iQuadFace[ 6 ], iTriFace[ 6 ], nbQuad = 0, nbTri = 0, iFace;
7748           for ( iFace = 0; iFace < 6; iFace++ ) {
7749             const int *ind = hexa.GetFaceNodesIndices( iFace ); // indices of face nodes
7750             nodeSet.clear();
7751             for ( iCur = 0; iCur < 4; iCur++ )
7752               nodeSet.insert( curNodes[ind[ iCur ]] );
7753             nbUniqueNodes = nodeSet.size();
7754             if ( nbUniqueNodes == 3 )
7755               iTriFace[ nbTri++ ] = iFace;
7756             else if ( nbUniqueNodes == 4 )
7757               iQuadFace[ nbQuad++ ] = iFace;
7758           }
7759           if (nbQuad == 2 && nbTri == 4 &&
7760               hexa.GetOppFaceIndex( iQuadFace[ 0 ] ) == iQuadFace[ 1 ]) {
7761             // 2 opposite quadrangles stuck with a diagonal;
7762             // sample groups of merged indices: (0-4)(2-6)
7763             // --------------------------------------------> 2 tetrahedrons
7764             const int *ind1 = hexa.GetFaceNodesIndices( iQuadFace[ 0 ]); // indices of quad1 nodes
7765             const int *ind2 = hexa.GetFaceNodesIndices( iQuadFace[ 1 ]);
7766             int i0, i1d, i2, i3d, i0t, i2t; // d-daigonal, t-top
7767             if (curNodes[ind1[ 0 ]] == curNodes[ind2[ 0 ]] &&
7768                 curNodes[ind1[ 2 ]] == curNodes[ind2[ 2 ]]) {
7769               // stuck with 0-2 diagonal
7770               i0  = ind1[ 3 ];
7771               i1d = ind1[ 0 ];
7772               i2  = ind1[ 1 ];
7773               i3d = ind1[ 2 ];
7774               i0t = ind2[ 1 ];
7775               i2t = ind2[ 3 ];
7776             }
7777             else if (curNodes[ind1[ 1 ]] == curNodes[ind2[ 3 ]] &&
7778                      curNodes[ind1[ 3 ]] == curNodes[ind2[ 1 ]]) {
7779               // stuck with 1-3 diagonal
7780               i0  = ind1[ 0 ];
7781               i1d = ind1[ 1 ];
7782               i2  = ind1[ 2 ];
7783               i3d = ind1[ 3 ];
7784               i0t = ind2[ 0 ];
7785               i2t = ind2[ 1 ];
7786             }
7787             else {
7788               ASSERT(0);
7789             }
7790             // tetrahedron 1
7791             uniqueNodes[ 0 ] = curNodes [ i0 ];
7792             uniqueNodes[ 1 ] = curNodes [ i1d ];
7793             uniqueNodes[ 2 ] = curNodes [ i3d ];
7794             uniqueNodes[ 3 ] = curNodes [ i0t ];
7795             nbUniqueNodes = 4;
7796             // tetrahedron 2
7797             SMDS_MeshElement* newElem = aMesh->AddVolume(curNodes[ i1d ],
7798                                                          curNodes[ i2 ],
7799                                                          curNodes[ i3d ],
7800                                                          curNodes[ i2t ]);
7801             myLastCreatedElems.Append(newElem);
7802             if ( aShapeId )
7803               aMesh->SetMeshElementOnShape( newElem, aShapeId );
7804             isOk = true;
7805           }
7806           else if (( nbTri == 2 && nbQuad == 3 ) || // merged (0-4)(1-5)
7807                    ( nbTri == 4 && nbQuad == 2 )) { // merged (7-4)(1-5)
7808             // --------------------------------------------> prism
7809             // find 2 opposite triangles
7810             nbUniqueNodes = 6;
7811             for ( iFace = 0; iFace + 1 < nbTri; iFace++ ) {
7812               if ( hexa.GetOppFaceIndex( iTriFace[ iFace ] ) == iTriFace[ iFace + 1 ]) {
7813                 // find indices of kept and replaced nodes
7814                 // and fill unique nodes of 2 opposite triangles
7815                 const int *ind1 = hexa.GetFaceNodesIndices( iTriFace[ iFace ]);
7816                 const int *ind2 = hexa.GetFaceNodesIndices( iTriFace[ iFace + 1 ]);
7817                 const SMDS_MeshNode** hexanodes = hexa.GetNodes();
7818                 // fill unique nodes
7819                 iUnique = 0;
7820                 isOk = true;
7821                 for ( iCur = 0; iCur < 4 && isOk; iCur++ ) {
7822                   const SMDS_MeshNode* n     = curNodes[ind1[ iCur ]];
7823                   const SMDS_MeshNode* nInit = hexanodes[ind1[ iCur ]];
7824                   if ( n == nInit ) {
7825                     // iCur of a linked node of the opposite face (make normals co-directed):
7826                     int iCurOpp = ( iCur == 1 || iCur == 3 ) ? 4 - iCur : iCur;
7827                     // check that correspondent corners of triangles are linked
7828                     if ( !hexa.IsLinked( ind1[ iCur ], ind2[ iCurOpp ] ))
7829                       isOk = false;
7830                     else {
7831                       uniqueNodes[ iUnique ] = n;
7832                       uniqueNodes[ iUnique + 3 ] = curNodes[ind2[ iCurOpp ]];
7833                       iUnique++;
7834                     }
7835                   }
7836                 }
7837                 break;
7838               }
7839             }
7840           }
7841         } // if ( nbUniqueNodes == 6 && nbRepl == 4 )
7842         break;
7843       } // HEXAHEDRON
7844
7845       default:
7846         isOk = false;
7847       } // switch ( nbNodes )
7848
7849     } // if ( nbNodes != nbUniqueNodes ) // some nodes stick
7850
7851     if ( isOk ) {
7852       if (elem->IsPoly() && elem->GetType() == SMDSAbs_Volume) {
7853         // Change nodes of polyedre
7854         const SMDS_VtkVolume* aPolyedre =
7855           dynamic_cast<const SMDS_VtkVolume*>( elem );
7856         if (aPolyedre) {
7857           int nbFaces = aPolyedre->NbFaces();
7858
7859           vector<const SMDS_MeshNode *> poly_nodes;
7860           vector<int> quantities (nbFaces);
7861
7862           for (int iface = 1; iface <= nbFaces; iface++) {
7863             int inode, nbFaceNodes = aPolyedre->NbFaceNodes(iface);
7864             quantities[iface - 1] = nbFaceNodes;
7865
7866             for (inode = 1; inode <= nbFaceNodes; inode++) {
7867               const SMDS_MeshNode* curNode = aPolyedre->GetFaceNode(iface, inode);
7868
7869               TNodeNodeMap::iterator nnIt = nodeNodeMap.find( curNode );
7870               if (nnIt != nodeNodeMap.end()) { // curNode sticks
7871                 curNode = (*nnIt).second;
7872               }
7873               poly_nodes.push_back(curNode);
7874             }
7875           }
7876           aMesh->ChangePolyhedronNodes( elem, poly_nodes, quantities );
7877         }
7878       }
7879       else {
7880         //int elemId = elem->GetID();
7881         //MESSAGE("Change regular element or polygon " << elemId);
7882         SMDSAbs_ElementType etyp = elem->GetType();
7883         uniqueNodes.resize(nbUniqueNodes);
7884         SMDS_MeshElement* newElem = 0;
7885         if (elem->GetEntityType() == SMDSEntity_Polygon)
7886           newElem = this->AddElement(uniqueNodes, etyp, true);
7887         else
7888           newElem = this->AddElement(uniqueNodes, etyp, false);
7889         if (newElem)
7890           {
7891             myLastCreatedElems.Append(newElem);
7892             if ( aShapeId )
7893               aMesh->SetMeshElementOnShape( newElem, aShapeId );
7894           }
7895         aMesh->RemoveElement(elem);
7896       }
7897     }
7898     else {
7899       // Remove invalid regular element or invalid polygon
7900       //MESSAGE("Remove invalid " << elem->GetID());
7901       rmElemIds.push_back( elem->GetID() );
7902     }
7903
7904   } // loop on elements
7905
7906   // Remove bad elements, then equal nodes (order important)
7907
7908   Remove( rmElemIds, false );
7909   Remove( rmNodeIds, true );
7910
7911 }
7912
7913
7914 // ========================================================
7915 // class   : SortableElement
7916 // purpose : allow sorting elements basing on their nodes
7917 // ========================================================
7918 class SortableElement : public set <const SMDS_MeshElement*>
7919 {
7920 public:
7921
7922   SortableElement( const SMDS_MeshElement* theElem )
7923   {
7924     myElem = theElem;
7925     SMDS_ElemIteratorPtr nodeIt = theElem->nodesIterator();
7926     while ( nodeIt->more() )
7927       this->insert( nodeIt->next() );
7928   }
7929
7930   const SMDS_MeshElement* Get() const
7931   { return myElem; }
7932
7933   void Set(const SMDS_MeshElement* e) const
7934   { myElem = e; }
7935
7936
7937 private:
7938   mutable const SMDS_MeshElement* myElem;
7939 };
7940
7941 //=======================================================================
7942 //function : FindEqualElements
7943 //purpose  : Return list of group of elements built on the same nodes.
7944 //           Search among theElements or in the whole mesh if theElements is empty
7945 //=======================================================================
7946 void SMESH_MeshEditor::FindEqualElements(set<const SMDS_MeshElement*> & theElements,
7947                                          TListOfListOfElementsID &      theGroupsOfElementsID)
7948 {
7949   myLastCreatedElems.Clear();
7950   myLastCreatedNodes.Clear();
7951
7952   typedef set<const SMDS_MeshElement*> TElemsSet;
7953   typedef map< SortableElement, int > TMapOfNodeSet;
7954   typedef list<int> TGroupOfElems;
7955
7956   TElemsSet elems;
7957   if ( theElements.empty() )
7958   { // get all elements in the mesh
7959     SMDS_ElemIteratorPtr eIt = GetMeshDS()->elementsIterator();
7960     while ( eIt->more() )
7961       elems.insert( elems.end(), eIt->next());
7962   }
7963   else
7964     elems = theElements;
7965
7966   vector< TGroupOfElems > arrayOfGroups;
7967   TGroupOfElems groupOfElems;
7968   TMapOfNodeSet mapOfNodeSet;
7969
7970   TElemsSet::iterator elemIt = elems.begin();
7971   for ( int i = 0, j=0; elemIt != elems.end(); ++elemIt, ++j ) {
7972     const SMDS_MeshElement* curElem = *elemIt;
7973     SortableElement SE(curElem);
7974     int ind = -1;
7975     // check uniqueness
7976     pair< TMapOfNodeSet::iterator, bool> pp = mapOfNodeSet.insert(make_pair(SE, i));
7977     if( !(pp.second) ) {
7978       TMapOfNodeSet::iterator& itSE = pp.first;
7979       ind = (*itSE).second;
7980       arrayOfGroups[ind].push_back(curElem->GetID());
7981     }
7982     else {
7983       groupOfElems.clear();
7984       groupOfElems.push_back(curElem->GetID());
7985       arrayOfGroups.push_back(groupOfElems);
7986       i++;
7987     }
7988   }
7989
7990   vector< TGroupOfElems >::iterator groupIt = arrayOfGroups.begin();
7991   for ( ; groupIt != arrayOfGroups.end(); ++groupIt ) {
7992     groupOfElems = *groupIt;
7993     if ( groupOfElems.size() > 1 ) {
7994       groupOfElems.sort();
7995       theGroupsOfElementsID.push_back(groupOfElems);
7996     }
7997   }
7998 }
7999
8000 //=======================================================================
8001 //function : MergeElements
8002 //purpose  : In each given group, substitute all elements by the first one.
8003 //=======================================================================
8004
8005 void SMESH_MeshEditor::MergeElements(TListOfListOfElementsID & theGroupsOfElementsID)
8006 {
8007   myLastCreatedElems.Clear();
8008   myLastCreatedNodes.Clear();
8009
8010   typedef list<int> TListOfIDs;
8011   TListOfIDs rmElemIds; // IDs of elems to remove
8012
8013   SMESHDS_Mesh* aMesh = GetMeshDS();
8014
8015   TListOfListOfElementsID::iterator groupsIt = theGroupsOfElementsID.begin();
8016   while ( groupsIt != theGroupsOfElementsID.end() ) {
8017     TListOfIDs& aGroupOfElemID = *groupsIt;
8018     aGroupOfElemID.sort();
8019     int elemIDToKeep = aGroupOfElemID.front();
8020     const SMDS_MeshElement* elemToKeep = aMesh->FindElement(elemIDToKeep);
8021     aGroupOfElemID.pop_front();
8022     TListOfIDs::iterator idIt = aGroupOfElemID.begin();
8023     while ( idIt != aGroupOfElemID.end() ) {
8024       int elemIDToRemove = *idIt;
8025       const SMDS_MeshElement* elemToRemove = aMesh->FindElement(elemIDToRemove);
8026       // add the kept element in groups of removed one (PAL15188)
8027       AddToSameGroups( elemToKeep, elemToRemove, aMesh );
8028       rmElemIds.push_back( elemIDToRemove );
8029       ++idIt;
8030     }
8031     ++groupsIt;
8032   }
8033
8034   Remove( rmElemIds, false );
8035 }
8036
8037 //=======================================================================
8038 //function : MergeEqualElements
8039 //purpose  : Remove all but one of elements built on the same nodes.
8040 //=======================================================================
8041
8042 void SMESH_MeshEditor::MergeEqualElements()
8043 {
8044   set<const SMDS_MeshElement*> aMeshElements; /* empty input -
8045                                                  to merge equal elements in the whole mesh */
8046   TListOfListOfElementsID aGroupsOfElementsID;
8047   FindEqualElements(aMeshElements, aGroupsOfElementsID);
8048   MergeElements(aGroupsOfElementsID);
8049 }
8050
8051 //=======================================================================
8052 //function : FindFaceInSet
8053 //purpose  : Return a face having linked nodes n1 and n2 and which is
8054 //           - not in avoidSet,
8055 //           - in elemSet provided that !elemSet.empty()
8056 //           i1 and i2 optionally returns indices of n1 and n2
8057 //=======================================================================
8058
8059 const SMDS_MeshElement*
8060 SMESH_MeshEditor::FindFaceInSet(const SMDS_MeshNode*    n1,
8061                                 const SMDS_MeshNode*    n2,
8062                                 const TIDSortedElemSet& elemSet,
8063                                 const TIDSortedElemSet& avoidSet,
8064                                 int*                    n1ind,
8065                                 int*                    n2ind)
8066
8067 {
8068   int i1, i2;
8069   const SMDS_MeshElement* face = 0;
8070
8071   SMDS_ElemIteratorPtr invElemIt = n1->GetInverseElementIterator(SMDSAbs_Face);
8072   //MESSAGE("n1->GetInverseElementIterator(SMDSAbs_Face) " << invElemIt);
8073   while ( invElemIt->more() && !face ) // loop on inverse faces of n1
8074   {
8075     //MESSAGE("in while ( invElemIt->more() && !face )");
8076     const SMDS_MeshElement* elem = invElemIt->next();
8077     if (avoidSet.count( elem ))
8078       continue;
8079     if ( !elemSet.empty() && !elemSet.count( elem ))
8080       continue;
8081     // index of n1
8082     i1 = elem->GetNodeIndex( n1 );
8083     // find a n2 linked to n1
8084     int nbN = elem->IsQuadratic() ? elem->NbNodes()/2 : elem->NbNodes();
8085     for ( int di = -1; di < 2 && !face; di += 2 )
8086     {
8087       i2 = (i1+di+nbN) % nbN;
8088       if ( elem->GetNode( i2 ) == n2 )
8089         face = elem;
8090     }
8091     if ( !face && elem->IsQuadratic())
8092     {
8093       // analysis for quadratic elements using all nodes
8094       const SMDS_VtkFace* F =
8095         dynamic_cast<const SMDS_VtkFace*>(elem);
8096       if (!F) throw SALOME_Exception(LOCALIZED("not an SMDS_VtkFace"));
8097       // use special nodes iterator
8098       SMDS_ElemIteratorPtr anIter = F->interlacedNodesElemIterator();
8099       const SMDS_MeshNode* prevN = cast2Node( anIter->next() );
8100       for ( i1 = -1, i2 = 0; anIter->more() && !face; i1++, i2++ )
8101       {
8102         const SMDS_MeshNode* n = cast2Node( anIter->next() );
8103         if ( n1 == prevN && n2 == n )
8104         {
8105           face = elem;
8106         }
8107         else if ( n2 == prevN && n1 == n )
8108         {
8109           face = elem; swap( i1, i2 );
8110         }
8111         prevN = n;
8112       }
8113     }
8114   }
8115   if ( n1ind ) *n1ind = i1;
8116   if ( n2ind ) *n2ind = i2;
8117   return face;
8118 }
8119
8120 //=======================================================================
8121 //function : findAdjacentFace
8122 //purpose  :
8123 //=======================================================================
8124
8125 static const SMDS_MeshElement* findAdjacentFace(const SMDS_MeshNode* n1,
8126                                                 const SMDS_MeshNode* n2,
8127                                                 const SMDS_MeshElement* elem)
8128 {
8129   TIDSortedElemSet elemSet, avoidSet;
8130   if ( elem )
8131     avoidSet.insert ( elem );
8132   return SMESH_MeshEditor::FindFaceInSet( n1, n2, elemSet, avoidSet );
8133 }
8134
8135 //=======================================================================
8136 //function : FindFreeBorder
8137 //purpose  :
8138 //=======================================================================
8139
8140 #define ControlFreeBorder SMESH::Controls::FreeEdges::IsFreeEdge
8141
8142 bool SMESH_MeshEditor::FindFreeBorder (const SMDS_MeshNode*             theFirstNode,
8143                                        const SMDS_MeshNode*             theSecondNode,
8144                                        const SMDS_MeshNode*             theLastNode,
8145                                        list< const SMDS_MeshNode* > &   theNodes,
8146                                        list< const SMDS_MeshElement* >& theFaces)
8147 {
8148   if ( !theFirstNode || !theSecondNode )
8149     return false;
8150   // find border face between theFirstNode and theSecondNode
8151   const SMDS_MeshElement* curElem = findAdjacentFace( theFirstNode, theSecondNode, 0 );
8152   if ( !curElem )
8153     return false;
8154
8155   theFaces.push_back( curElem );
8156   theNodes.push_back( theFirstNode );
8157   theNodes.push_back( theSecondNode );
8158
8159   //vector<const SMDS_MeshNode*> nodes;
8160   const SMDS_MeshNode *nIgnore = theFirstNode, *nStart = theSecondNode;
8161   TIDSortedElemSet foundElems;
8162   bool needTheLast = ( theLastNode != 0 );
8163
8164   while ( nStart != theLastNode ) {
8165     if ( nStart == theFirstNode )
8166       return !needTheLast;
8167
8168     // find all free border faces sharing form nStart
8169
8170     list< const SMDS_MeshElement* > curElemList;
8171     list< const SMDS_MeshNode* > nStartList;
8172     SMDS_ElemIteratorPtr invElemIt = nStart->GetInverseElementIterator(SMDSAbs_Face);
8173     while ( invElemIt->more() ) {
8174       const SMDS_MeshElement* e = invElemIt->next();
8175       if ( e == curElem || foundElems.insert( e ).second ) {
8176         // get nodes
8177         int iNode = 0, nbNodes = e->NbNodes();
8178         //const SMDS_MeshNode* nodes[nbNodes+1];
8179         vector<const SMDS_MeshNode*> nodes(nbNodes+1);
8180
8181         if(e->IsQuadratic()) {
8182           const SMDS_VtkFace* F =
8183             dynamic_cast<const SMDS_VtkFace*>(e);
8184           if (!F) throw SALOME_Exception(LOCALIZED("not an SMDS_VtkFace"));
8185           // use special nodes iterator
8186           SMDS_ElemIteratorPtr anIter = F->interlacedNodesElemIterator();
8187           while( anIter->more() ) {
8188             nodes[ iNode++ ] = cast2Node(anIter->next());
8189           }
8190         }
8191         else {
8192           SMDS_ElemIteratorPtr nIt = e->nodesIterator();
8193           while ( nIt->more() )
8194             nodes[ iNode++ ] = static_cast<const SMDS_MeshNode*>( nIt->next() );
8195         }
8196         nodes[ iNode ] = nodes[ 0 ];
8197         // check 2 links
8198         for ( iNode = 0; iNode < nbNodes; iNode++ )
8199           if (((nodes[ iNode ] == nStart && nodes[ iNode + 1] != nIgnore ) ||
8200                (nodes[ iNode + 1] == nStart && nodes[ iNode ] != nIgnore )) &&
8201               ControlFreeBorder( &nodes[ iNode ], e->GetID() ))
8202           {
8203             nStartList.push_back( nodes[ iNode + ( nodes[ iNode ] == nStart ? 1 : 0 )]);
8204             curElemList.push_back( e );
8205           }
8206       }
8207     }
8208     // analyse the found
8209
8210     int nbNewBorders = curElemList.size();
8211     if ( nbNewBorders == 0 ) {
8212       // no free border furthermore
8213       return !needTheLast;
8214     }
8215     else if ( nbNewBorders == 1 ) {
8216       // one more element found
8217       nIgnore = nStart;
8218       nStart = nStartList.front();
8219       curElem = curElemList.front();
8220       theFaces.push_back( curElem );
8221       theNodes.push_back( nStart );
8222     }
8223     else {
8224       // several continuations found
8225       list< const SMDS_MeshElement* >::iterator curElemIt;
8226       list< const SMDS_MeshNode* >::iterator nStartIt;
8227       // check if one of them reached the last node
8228       if ( needTheLast ) {
8229         for (curElemIt = curElemList.begin(), nStartIt = nStartList.begin();
8230              curElemIt!= curElemList.end();
8231              curElemIt++, nStartIt++ )
8232           if ( *nStartIt == theLastNode ) {
8233             theFaces.push_back( *curElemIt );
8234             theNodes.push_back( *nStartIt );
8235             return true;
8236           }
8237       }
8238       // find the best free border by the continuations
8239       list<const SMDS_MeshNode*>    contNodes[ 2 ], *cNL;
8240       list<const SMDS_MeshElement*> contFaces[ 2 ], *cFL;
8241       for (curElemIt = curElemList.begin(), nStartIt = nStartList.begin();
8242            curElemIt!= curElemList.end();
8243            curElemIt++, nStartIt++ )
8244       {
8245         cNL = & contNodes[ contNodes[0].empty() ? 0 : 1 ];
8246         cFL = & contFaces[ contFaces[0].empty() ? 0 : 1 ];
8247         // find one more free border
8248         if ( ! FindFreeBorder( nStart, *nStartIt, theLastNode, *cNL, *cFL )) {
8249           cNL->clear();
8250           cFL->clear();
8251         }
8252         else if ( !contNodes[0].empty() && !contNodes[1].empty() ) {
8253           // choice: clear a worse one
8254           int iLongest = ( contNodes[0].size() < contNodes[1].size() ? 1 : 0 );
8255           int iWorse = ( needTheLast ? 1 - iLongest : iLongest );
8256           contNodes[ iWorse ].clear();
8257           contFaces[ iWorse ].clear();
8258         }
8259       }
8260       if ( contNodes[0].empty() && contNodes[1].empty() )
8261         return false;
8262
8263       // append the best free border
8264       cNL = & contNodes[ contNodes[0].empty() ? 1 : 0 ];
8265       cFL = & contFaces[ contFaces[0].empty() ? 1 : 0 ];
8266       theNodes.pop_back(); // remove nIgnore
8267       theNodes.pop_back(); // remove nStart
8268       theFaces.pop_back(); // remove curElem
8269       list< const SMDS_MeshNode* >::iterator nIt = cNL->begin();
8270       list< const SMDS_MeshElement* >::iterator fIt = cFL->begin();
8271       for ( ; nIt != cNL->end(); nIt++ ) theNodes.push_back( *nIt );
8272       for ( ; fIt != cFL->end(); fIt++ ) theFaces.push_back( *fIt );
8273       return true;
8274
8275     } // several continuations found
8276   } // while ( nStart != theLastNode )
8277
8278   return true;
8279 }
8280
8281 //=======================================================================
8282 //function : CheckFreeBorderNodes
8283 //purpose  : Return true if the tree nodes are on a free border
8284 //=======================================================================
8285
8286 bool SMESH_MeshEditor::CheckFreeBorderNodes(const SMDS_MeshNode* theNode1,
8287                                             const SMDS_MeshNode* theNode2,
8288                                             const SMDS_MeshNode* theNode3)
8289 {
8290   list< const SMDS_MeshNode* > nodes;
8291   list< const SMDS_MeshElement* > faces;
8292   return FindFreeBorder( theNode1, theNode2, theNode3, nodes, faces);
8293 }
8294
8295 //=======================================================================
8296 //function : SewFreeBorder
8297 //purpose  :
8298 //=======================================================================
8299
8300 SMESH_MeshEditor::Sew_Error
8301 SMESH_MeshEditor::SewFreeBorder (const SMDS_MeshNode* theBordFirstNode,
8302                                  const SMDS_MeshNode* theBordSecondNode,
8303                                  const SMDS_MeshNode* theBordLastNode,
8304                                  const SMDS_MeshNode* theSideFirstNode,
8305                                  const SMDS_MeshNode* theSideSecondNode,
8306                                  const SMDS_MeshNode* theSideThirdNode,
8307                                  const bool           theSideIsFreeBorder,
8308                                  const bool           toCreatePolygons,
8309                                  const bool           toCreatePolyedrs)
8310 {
8311   myLastCreatedElems.Clear();
8312   myLastCreatedNodes.Clear();
8313
8314   MESSAGE("::SewFreeBorder()");
8315   Sew_Error aResult = SEW_OK;
8316
8317   // ====================================
8318   //    find side nodes and elements
8319   // ====================================
8320
8321   list< const SMDS_MeshNode* > nSide[ 2 ];
8322   list< const SMDS_MeshElement* > eSide[ 2 ];
8323   list< const SMDS_MeshNode* >::iterator nIt[ 2 ];
8324   list< const SMDS_MeshElement* >::iterator eIt[ 2 ];
8325
8326   // Free border 1
8327   // --------------
8328   if (!FindFreeBorder(theBordFirstNode,theBordSecondNode,theBordLastNode,
8329                       nSide[0], eSide[0])) {
8330     MESSAGE(" Free Border 1 not found " );
8331     aResult = SEW_BORDER1_NOT_FOUND;
8332   }
8333   if (theSideIsFreeBorder) {
8334     // Free border 2
8335     // --------------
8336     if (!FindFreeBorder(theSideFirstNode, theSideSecondNode, theSideThirdNode,
8337                         nSide[1], eSide[1])) {
8338       MESSAGE(" Free Border 2 not found " );
8339       aResult = ( aResult != SEW_OK ? SEW_BOTH_BORDERS_NOT_FOUND : SEW_BORDER2_NOT_FOUND );
8340     }
8341   }
8342   if ( aResult != SEW_OK )
8343     return aResult;
8344
8345   if (!theSideIsFreeBorder) {
8346     // Side 2
8347     // --------------
8348
8349     // -------------------------------------------------------------------------
8350     // Algo:
8351     // 1. If nodes to merge are not coincident, move nodes of the free border
8352     //    from the coord sys defined by the direction from the first to last
8353     //    nodes of the border to the correspondent sys of the side 2
8354     // 2. On the side 2, find the links most co-directed with the correspondent
8355     //    links of the free border
8356     // -------------------------------------------------------------------------
8357
8358     // 1. Since sewing may break if there are volumes to split on the side 2,
8359     //    we wont move nodes but just compute new coordinates for them
8360     typedef map<const SMDS_MeshNode*, gp_XYZ> TNodeXYZMap;
8361     TNodeXYZMap nBordXYZ;
8362     list< const SMDS_MeshNode* >& bordNodes = nSide[ 0 ];
8363     list< const SMDS_MeshNode* >::iterator nBordIt;
8364
8365     gp_XYZ Pb1( theBordFirstNode->X(), theBordFirstNode->Y(), theBordFirstNode->Z() );
8366     gp_XYZ Pb2( theBordLastNode->X(), theBordLastNode->Y(), theBordLastNode->Z() );
8367     gp_XYZ Ps1( theSideFirstNode->X(), theSideFirstNode->Y(), theSideFirstNode->Z() );
8368     gp_XYZ Ps2( theSideSecondNode->X(), theSideSecondNode->Y(), theSideSecondNode->Z() );
8369     double tol2 = 1.e-8;
8370     gp_Vec Vbs1( Pb1 - Ps1 ),Vbs2( Pb2 - Ps2 );
8371     if ( Vbs1.SquareMagnitude() > tol2 || Vbs2.SquareMagnitude() > tol2 ) {
8372       // Need node movement.
8373
8374       // find X and Z axes to create trsf
8375       gp_Vec Zb( Pb1 - Pb2 ), Zs( Ps1 - Ps2 );
8376       gp_Vec X = Zs ^ Zb;
8377       if ( X.SquareMagnitude() <= gp::Resolution() * gp::Resolution() )
8378         // Zb || Zs
8379         X = gp_Ax2( gp::Origin(), Zb ).XDirection();
8380
8381       // coord systems
8382       gp_Ax3 toBordAx( Pb1, Zb, X );
8383       gp_Ax3 fromSideAx( Ps1, Zs, X );
8384       gp_Ax3 toGlobalAx( gp::Origin(), gp::DZ(), gp::DX() );
8385       // set trsf
8386       gp_Trsf toBordSys, fromSide2Sys;
8387       toBordSys.SetTransformation( toBordAx );
8388       fromSide2Sys.SetTransformation( fromSideAx, toGlobalAx );
8389       fromSide2Sys.SetScaleFactor( Zs.Magnitude() / Zb.Magnitude() );
8390
8391       // move
8392       for ( nBordIt = bordNodes.begin(); nBordIt != bordNodes.end(); nBordIt++ ) {
8393         const SMDS_MeshNode* n = *nBordIt;
8394         gp_XYZ xyz( n->X(),n->Y(),n->Z() );
8395         toBordSys.Transforms( xyz );
8396         fromSide2Sys.Transforms( xyz );
8397         nBordXYZ.insert( TNodeXYZMap::value_type( n, xyz ));
8398       }
8399     }
8400     else {
8401       // just insert nodes XYZ in the nBordXYZ map
8402       for ( nBordIt = bordNodes.begin(); nBordIt != bordNodes.end(); nBordIt++ ) {
8403         const SMDS_MeshNode* n = *nBordIt;
8404         nBordXYZ.insert( TNodeXYZMap::value_type( n, gp_XYZ( n->X(),n->Y(),n->Z() )));
8405       }
8406     }
8407
8408     // 2. On the side 2, find the links most co-directed with the correspondent
8409     //    links of the free border
8410
8411     list< const SMDS_MeshElement* >& sideElems = eSide[ 1 ];
8412     list< const SMDS_MeshNode* >& sideNodes = nSide[ 1 ];
8413     sideNodes.push_back( theSideFirstNode );
8414
8415     bool hasVolumes = false;
8416     LinkID_Gen aLinkID_Gen( GetMeshDS() );
8417     set<long> foundSideLinkIDs, checkedLinkIDs;
8418     SMDS_VolumeTool volume;
8419     //const SMDS_MeshNode* faceNodes[ 4 ];
8420
8421     const SMDS_MeshNode*    sideNode;
8422     const SMDS_MeshElement* sideElem;
8423     const SMDS_MeshNode* prevSideNode = theSideFirstNode;
8424     const SMDS_MeshNode* prevBordNode = theBordFirstNode;
8425     nBordIt = bordNodes.begin();
8426     nBordIt++;
8427     // border node position and border link direction to compare with
8428     gp_XYZ bordPos = nBordXYZ[ *nBordIt ];
8429     gp_XYZ bordDir = bordPos - nBordXYZ[ prevBordNode ];
8430     // choose next side node by link direction or by closeness to
8431     // the current border node:
8432     bool searchByDir = ( *nBordIt != theBordLastNode );
8433     do {
8434       // find the next node on the Side 2
8435       sideNode = 0;
8436       double maxDot = -DBL_MAX, minDist = DBL_MAX;
8437       long linkID;
8438       checkedLinkIDs.clear();
8439       gp_XYZ prevXYZ( prevSideNode->X(), prevSideNode->Y(), prevSideNode->Z() );
8440
8441       // loop on inverse elements of current node (prevSideNode) on the Side 2
8442       SMDS_ElemIteratorPtr invElemIt = prevSideNode->GetInverseElementIterator();
8443       while ( invElemIt->more() )
8444       {
8445         const SMDS_MeshElement* elem = invElemIt->next();
8446         // prepare data for a loop on links coming to prevSideNode, of a face or a volume
8447         int iPrevNode, iNode = 0, nbNodes = elem->NbNodes();
8448         vector< const SMDS_MeshNode* > faceNodes( nbNodes, (const SMDS_MeshNode*)0 );
8449         bool isVolume = volume.Set( elem );
8450         const SMDS_MeshNode** nodes = isVolume ? volume.GetNodes() : & faceNodes[0];
8451         if ( isVolume ) // --volume
8452           hasVolumes = true;
8453         else if ( elem->GetType()==SMDSAbs_Face ) { // --face
8454           // retrieve all face nodes and find iPrevNode - an index of the prevSideNode
8455           if(elem->IsQuadratic()) {
8456             const SMDS_VtkFace* F =
8457               dynamic_cast<const SMDS_VtkFace*>(elem);
8458             if (!F) throw SALOME_Exception(LOCALIZED("not an SMDS_VtkFace"));
8459             // use special nodes iterator
8460             SMDS_ElemIteratorPtr anIter = F->interlacedNodesElemIterator();
8461             while( anIter->more() ) {
8462               nodes[ iNode ] = cast2Node(anIter->next());
8463               if ( nodes[ iNode++ ] == prevSideNode )
8464                 iPrevNode = iNode - 1;
8465             }
8466           }
8467           else {
8468             SMDS_ElemIteratorPtr nIt = elem->nodesIterator();
8469             while ( nIt->more() ) {
8470               nodes[ iNode ] = cast2Node( nIt->next() );
8471               if ( nodes[ iNode++ ] == prevSideNode )
8472                 iPrevNode = iNode - 1;
8473             }
8474           }
8475           // there are 2 links to check
8476           nbNodes = 2;
8477         }
8478         else // --edge
8479           continue;
8480         // loop on links, to be precise, on the second node of links
8481         for ( iNode = 0; iNode < nbNodes; iNode++ ) {
8482           const SMDS_MeshNode* n = nodes[ iNode ];
8483           if ( isVolume ) {
8484             if ( !volume.IsLinked( n, prevSideNode ))
8485               continue;
8486           }
8487           else {
8488             if ( iNode ) // a node before prevSideNode
8489               n = nodes[ iPrevNode == 0 ? elem->NbNodes() - 1 : iPrevNode - 1 ];
8490             else         // a node after prevSideNode
8491               n = nodes[ iPrevNode + 1 == elem->NbNodes() ? 0 : iPrevNode + 1 ];
8492           }
8493           // check if this link was already used
8494           long iLink = aLinkID_Gen.GetLinkID( prevSideNode, n );
8495           bool isJustChecked = !checkedLinkIDs.insert( iLink ).second;
8496           if (!isJustChecked &&
8497               foundSideLinkIDs.find( iLink ) == foundSideLinkIDs.end() )
8498           {
8499             // test a link geometrically
8500             gp_XYZ nextXYZ ( n->X(), n->Y(), n->Z() );
8501             bool linkIsBetter = false;
8502             double dot = 0.0, dist = 0.0;
8503             if ( searchByDir ) { // choose most co-directed link
8504               dot = bordDir * ( nextXYZ - prevXYZ ).Normalized();
8505               linkIsBetter = ( dot > maxDot );
8506             }
8507             else { // choose link with the node closest to bordPos
8508               dist = ( nextXYZ - bordPos ).SquareModulus();
8509               linkIsBetter = ( dist < minDist );
8510             }
8511             if ( linkIsBetter ) {
8512               maxDot = dot;
8513               minDist = dist;
8514               linkID = iLink;
8515               sideNode = n;
8516               sideElem = elem;
8517             }
8518           }
8519         }
8520       } // loop on inverse elements of prevSideNode
8521
8522       if ( !sideNode ) {
8523         MESSAGE(" Cant find path by links of the Side 2 ");
8524         return SEW_BAD_SIDE_NODES;
8525       }
8526       sideNodes.push_back( sideNode );
8527       sideElems.push_back( sideElem );
8528       foundSideLinkIDs.insert ( linkID );
8529       prevSideNode = sideNode;
8530
8531       if ( *nBordIt == theBordLastNode )
8532         searchByDir = false;
8533       else {
8534         // find the next border link to compare with
8535         gp_XYZ sidePos( sideNode->X(), sideNode->Y(), sideNode->Z() );
8536         searchByDir = ( bordDir * ( sidePos - bordPos ) <= 0 );
8537         // move to next border node if sideNode is before forward border node (bordPos)
8538         while ( *nBordIt != theBordLastNode && !searchByDir ) {
8539           prevBordNode = *nBordIt;
8540           nBordIt++;
8541           bordPos = nBordXYZ[ *nBordIt ];
8542           bordDir = bordPos - nBordXYZ[ prevBordNode ];
8543           searchByDir = ( bordDir * ( sidePos - bordPos ) <= 0 );
8544         }
8545       }
8546     }
8547     while ( sideNode != theSideSecondNode );
8548
8549     if ( hasVolumes && sideNodes.size () != bordNodes.size() && !toCreatePolyedrs) {
8550       MESSAGE("VOLUME SPLITTING IS FORBIDDEN");
8551       return SEW_VOLUMES_TO_SPLIT; // volume splitting is forbidden
8552     }
8553   } // end nodes search on the side 2
8554
8555   // ============================
8556   // sew the border to the side 2
8557   // ============================
8558
8559   int nbNodes[]  = { nSide[0].size(), nSide[1].size() };
8560   int maxNbNodes = Max( nbNodes[0], nbNodes[1] );
8561
8562   TListOfListOfNodes nodeGroupsToMerge;
8563   if ( nbNodes[0] == nbNodes[1] ||
8564        ( theSideIsFreeBorder && !theSideThirdNode)) {
8565
8566     // all nodes are to be merged
8567
8568     for (nIt[0] = nSide[0].begin(), nIt[1] = nSide[1].begin();
8569          nIt[0] != nSide[0].end() && nIt[1] != nSide[1].end();
8570          nIt[0]++, nIt[1]++ )
8571     {
8572       nodeGroupsToMerge.push_back( list<const SMDS_MeshNode*>() );
8573       nodeGroupsToMerge.back().push_back( *nIt[1] ); // to keep
8574       nodeGroupsToMerge.back().push_back( *nIt[0] ); // to remove
8575     }
8576   }
8577   else {
8578
8579     // insert new nodes into the border and the side to get equal nb of segments
8580
8581     // get normalized parameters of nodes on the borders
8582     //double param[ 2 ][ maxNbNodes ];
8583     double* param[ 2 ];
8584     param[0] = new double [ maxNbNodes ];
8585     param[1] = new double [ maxNbNodes ];
8586     int iNode, iBord;
8587     for ( iBord = 0; iBord < 2; iBord++ ) { // loop on 2 borders
8588       list< const SMDS_MeshNode* >& nodes = nSide[ iBord ];
8589       list< const SMDS_MeshNode* >::iterator nIt = nodes.begin();
8590       const SMDS_MeshNode* nPrev = *nIt;
8591       double bordLength = 0;
8592       for ( iNode = 0; nIt != nodes.end(); nIt++, iNode++ ) { // loop on border nodes
8593         const SMDS_MeshNode* nCur = *nIt;
8594         gp_XYZ segment (nCur->X() - nPrev->X(),
8595                         nCur->Y() - nPrev->Y(),
8596                         nCur->Z() - nPrev->Z());
8597         double segmentLen = segment.Modulus();
8598         bordLength += segmentLen;
8599         param[ iBord ][ iNode ] = bordLength;
8600         nPrev = nCur;
8601       }
8602       // normalize within [0,1]
8603       for ( iNode = 0; iNode < nbNodes[ iBord ]; iNode++ ) {
8604         param[ iBord ][ iNode ] /= bordLength;
8605       }
8606     }
8607
8608     // loop on border segments
8609     const SMDS_MeshNode *nPrev[ 2 ] = { 0, 0 };
8610     int i[ 2 ] = { 0, 0 };
8611     nIt[0] = nSide[0].begin(); eIt[0] = eSide[0].begin();
8612     nIt[1] = nSide[1].begin(); eIt[1] = eSide[1].begin();
8613
8614     TElemOfNodeListMap insertMap;
8615     TElemOfNodeListMap::iterator insertMapIt;
8616     // insertMap is
8617     // key:   elem to insert nodes into
8618     // value: 2 nodes to insert between + nodes to be inserted
8619     do {
8620       bool next[ 2 ] = { false, false };
8621
8622       // find min adjacent segment length after sewing
8623       double nextParam = 10., prevParam = 0;
8624       for ( iBord = 0; iBord < 2; iBord++ ) { // loop on 2 borders
8625         if ( i[ iBord ] + 1 < nbNodes[ iBord ])
8626           nextParam = Min( nextParam, param[iBord][ i[iBord] + 1 ]);
8627         if ( i[ iBord ] > 0 )
8628           prevParam = Max( prevParam, param[iBord][ i[iBord] - 1 ]);
8629       }
8630       double minParam = Min( param[ 0 ][ i[0] ], param[ 1 ][ i[1] ]);
8631       double maxParam = Max( param[ 0 ][ i[0] ], param[ 1 ][ i[1] ]);
8632       double minSegLen = Min( nextParam - minParam, maxParam - prevParam );
8633
8634       // choose to insert or to merge nodes
8635       double du = param[ 1 ][ i[1] ] - param[ 0 ][ i[0] ];
8636       if ( Abs( du ) <= minSegLen * 0.2 ) {
8637         // merge
8638         // ------
8639         nodeGroupsToMerge.push_back( list<const SMDS_MeshNode*>() );
8640         const SMDS_MeshNode* n0 = *nIt[0];
8641         const SMDS_MeshNode* n1 = *nIt[1];
8642         nodeGroupsToMerge.back().push_back( n1 );
8643         nodeGroupsToMerge.back().push_back( n0 );
8644         // position of node of the border changes due to merge
8645         param[ 0 ][ i[0] ] += du;
8646         // move n1 for the sake of elem shape evaluation during insertion.
8647         // n1 will be removed by MergeNodes() anyway
8648         const_cast<SMDS_MeshNode*>( n0 )->setXYZ( n1->X(), n1->Y(), n1->Z() );
8649         next[0] = next[1] = true;
8650       }
8651       else {
8652         // insert
8653         // ------
8654         int intoBord = ( du < 0 ) ? 0 : 1;
8655         const SMDS_MeshElement* elem = *eIt[ intoBord ];
8656         const SMDS_MeshNode*    n1   = nPrev[ intoBord ];
8657         const SMDS_MeshNode*    n2   = *nIt[ intoBord ];
8658         const SMDS_MeshNode*    nIns = *nIt[ 1 - intoBord ];
8659         if ( intoBord == 1 ) {
8660           // move node of the border to be on a link of elem of the side
8661           gp_XYZ p1 (n1->X(), n1->Y(), n1->Z());
8662           gp_XYZ p2 (n2->X(), n2->Y(), n2->Z());
8663           double ratio = du / ( param[ 1 ][ i[1] ] - param[ 1 ][ i[1]-1 ]);
8664           gp_XYZ p = p2 * ( 1 - ratio ) + p1 * ratio;
8665           GetMeshDS()->MoveNode( nIns, p.X(), p.Y(), p.Z() );
8666         }
8667         insertMapIt = insertMap.find( elem );
8668         bool notFound = ( insertMapIt == insertMap.end() );
8669         bool otherLink = ( !notFound && (*insertMapIt).second.front() != n1 );
8670         if ( otherLink ) {
8671           // insert into another link of the same element:
8672           // 1. perform insertion into the other link of the elem
8673           list<const SMDS_MeshNode*> & nodeList = (*insertMapIt).second;
8674           const SMDS_MeshNode* n12 = nodeList.front(); nodeList.pop_front();
8675           const SMDS_MeshNode* n22 = nodeList.front(); nodeList.pop_front();
8676           InsertNodesIntoLink( elem, n12, n22, nodeList, toCreatePolygons );
8677           // 2. perform insertion into the link of adjacent faces
8678           while (true) {
8679             const SMDS_MeshElement* adjElem = findAdjacentFace( n12, n22, elem );
8680             if ( adjElem )
8681               InsertNodesIntoLink( adjElem, n12, n22, nodeList, toCreatePolygons );
8682             else
8683               break;
8684           }
8685           if (toCreatePolyedrs) {
8686             // perform insertion into the links of adjacent volumes
8687             UpdateVolumes(n12, n22, nodeList);
8688           }
8689           // 3. find an element appeared on n1 and n2 after the insertion
8690           insertMap.erase( elem );
8691           elem = findAdjacentFace( n1, n2, 0 );
8692         }
8693         if ( notFound || otherLink ) {
8694           // add element and nodes of the side into the insertMap
8695           insertMapIt = insertMap.insert
8696             ( TElemOfNodeListMap::value_type( elem, list<const SMDS_MeshNode*>() )).first;
8697           (*insertMapIt).second.push_back( n1 );
8698           (*insertMapIt).second.push_back( n2 );
8699         }
8700         // add node to be inserted into elem
8701         (*insertMapIt).second.push_back( nIns );
8702         next[ 1 - intoBord ] = true;
8703       }
8704
8705       // go to the next segment
8706       for ( iBord = 0; iBord < 2; iBord++ ) { // loop on 2 borders
8707         if ( next[ iBord ] ) {
8708           if ( i[ iBord ] != 0 && eIt[ iBord ] != eSide[ iBord ].end())
8709             eIt[ iBord ]++;
8710           nPrev[ iBord ] = *nIt[ iBord ];
8711           nIt[ iBord ]++; i[ iBord ]++;
8712         }
8713       }
8714     }
8715     while ( nIt[0] != nSide[0].end() && nIt[1] != nSide[1].end());
8716
8717     // perform insertion of nodes into elements
8718
8719     for (insertMapIt = insertMap.begin();
8720          insertMapIt != insertMap.end();
8721          insertMapIt++ )
8722     {
8723       const SMDS_MeshElement* elem = (*insertMapIt).first;
8724       list<const SMDS_MeshNode*> & nodeList = (*insertMapIt).second;
8725       const SMDS_MeshNode* n1 = nodeList.front(); nodeList.pop_front();
8726       const SMDS_MeshNode* n2 = nodeList.front(); nodeList.pop_front();
8727
8728       InsertNodesIntoLink( elem, n1, n2, nodeList, toCreatePolygons );
8729
8730       if ( !theSideIsFreeBorder ) {
8731         // look for and insert nodes into the faces adjacent to elem
8732         while (true) {
8733           const SMDS_MeshElement* adjElem = findAdjacentFace( n1, n2, elem );
8734           if ( adjElem )
8735             InsertNodesIntoLink( adjElem, n1, n2, nodeList, toCreatePolygons );
8736           else
8737             break;
8738         }
8739       }
8740       if (toCreatePolyedrs) {
8741         // perform insertion into the links of adjacent volumes
8742         UpdateVolumes(n1, n2, nodeList);
8743       }
8744     }
8745
8746     delete param[0];
8747     delete param[1];
8748   } // end: insert new nodes
8749
8750   MergeNodes ( nodeGroupsToMerge );
8751
8752   return aResult;
8753 }
8754
8755 //=======================================================================
8756 //function : InsertNodesIntoLink
8757 //purpose  : insert theNodesToInsert into theFace between theBetweenNode1
8758 //           and theBetweenNode2 and split theElement
8759 //=======================================================================
8760
8761 void SMESH_MeshEditor::InsertNodesIntoLink(const SMDS_MeshElement*     theFace,
8762                                            const SMDS_MeshNode*        theBetweenNode1,
8763                                            const SMDS_MeshNode*        theBetweenNode2,
8764                                            list<const SMDS_MeshNode*>& theNodesToInsert,
8765                                            const bool                  toCreatePoly)
8766 {
8767   if ( theFace->GetType() != SMDSAbs_Face ) return;
8768
8769   // find indices of 2 link nodes and of the rest nodes
8770   int iNode = 0, il1, il2, i3, i4;
8771   il1 = il2 = i3 = i4 = -1;
8772   //const SMDS_MeshNode* nodes[ theFace->NbNodes() ];
8773   vector<const SMDS_MeshNode*> nodes( theFace->NbNodes() );
8774
8775   if(theFace->IsQuadratic()) {
8776     const SMDS_VtkFace* F =
8777       dynamic_cast<const SMDS_VtkFace*>(theFace);
8778     if (!F) throw SALOME_Exception(LOCALIZED("not an SMDS_VtkFace"));
8779     // use special nodes iterator
8780     SMDS_ElemIteratorPtr anIter = F->interlacedNodesElemIterator();
8781     while( anIter->more() ) {
8782       const SMDS_MeshNode* n = cast2Node(anIter->next());
8783       if ( n == theBetweenNode1 )
8784         il1 = iNode;
8785       else if ( n == theBetweenNode2 )
8786         il2 = iNode;
8787       else if ( i3 < 0 )
8788         i3 = iNode;
8789       else
8790         i4 = iNode;
8791       nodes[ iNode++ ] = n;
8792     }
8793   }
8794   else {
8795     SMDS_ElemIteratorPtr nodeIt = theFace->nodesIterator();
8796     while ( nodeIt->more() ) {
8797       const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
8798       if ( n == theBetweenNode1 )
8799         il1 = iNode;
8800       else if ( n == theBetweenNode2 )
8801         il2 = iNode;
8802       else if ( i3 < 0 )
8803         i3 = iNode;
8804       else
8805         i4 = iNode;
8806       nodes[ iNode++ ] = n;
8807     }
8808   }
8809   if ( il1 < 0 || il2 < 0 || i3 < 0 )
8810     return ;
8811
8812   // arrange link nodes to go one after another regarding the face orientation
8813   bool reverse = ( Abs( il2 - il1 ) == 1 ? il2 < il1 : il1 < il2 );
8814   list<const SMDS_MeshNode *> aNodesToInsert = theNodesToInsert;
8815   if ( reverse ) {
8816     iNode = il1;
8817     il1 = il2;
8818     il2 = iNode;
8819     aNodesToInsert.reverse();
8820   }
8821   // check that not link nodes of a quadrangles are in good order
8822   int nbFaceNodes = theFace->NbNodes();
8823   if ( nbFaceNodes == 4 && i4 - i3 != 1 ) {
8824     iNode = i3;
8825     i3 = i4;
8826     i4 = iNode;
8827   }
8828
8829   if (toCreatePoly || theFace->IsPoly()) {
8830
8831     iNode = 0;
8832     vector<const SMDS_MeshNode *> poly_nodes (nbFaceNodes + aNodesToInsert.size());
8833
8834     // add nodes of face up to first node of link
8835     bool isFLN = false;
8836
8837     if(theFace->IsQuadratic()) {
8838       const SMDS_VtkFace* F =
8839         dynamic_cast<const SMDS_VtkFace*>(theFace);
8840       if (!F) throw SALOME_Exception(LOCALIZED("not an SMDS_VtkFace"));
8841       // use special nodes iterator
8842       SMDS_ElemIteratorPtr anIter = F->interlacedNodesElemIterator();
8843       while( anIter->more()  && !isFLN ) {
8844         const SMDS_MeshNode* n = cast2Node(anIter->next());
8845         poly_nodes[iNode++] = n;
8846         if (n == nodes[il1]) {
8847           isFLN = true;
8848         }
8849       }
8850       // add nodes to insert
8851       list<const SMDS_MeshNode*>::iterator nIt = aNodesToInsert.begin();
8852       for (; nIt != aNodesToInsert.end(); nIt++) {
8853         poly_nodes[iNode++] = *nIt;
8854       }
8855       // add nodes of face starting from last node of link
8856       while ( anIter->more() ) {
8857         poly_nodes[iNode++] = cast2Node(anIter->next());
8858       }
8859     }
8860     else {
8861       SMDS_ElemIteratorPtr nodeIt = theFace->nodesIterator();
8862       while ( nodeIt->more() && !isFLN ) {
8863         const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
8864         poly_nodes[iNode++] = n;
8865         if (n == nodes[il1]) {
8866           isFLN = true;
8867         }
8868       }
8869       // add nodes to insert
8870       list<const SMDS_MeshNode*>::iterator nIt = aNodesToInsert.begin();
8871       for (; nIt != aNodesToInsert.end(); nIt++) {
8872         poly_nodes[iNode++] = *nIt;
8873       }
8874       // add nodes of face starting from last node of link
8875       while ( nodeIt->more() ) {
8876         const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
8877         poly_nodes[iNode++] = n;
8878       }
8879     }
8880
8881     // edit or replace the face
8882     SMESHDS_Mesh *aMesh = GetMeshDS();
8883
8884     if (theFace->IsPoly()) {
8885       aMesh->ChangePolygonNodes(theFace, poly_nodes);
8886     }
8887     else {
8888       int aShapeId = FindShape( theFace );
8889
8890       SMDS_MeshElement* newElem = aMesh->AddPolygonalFace(poly_nodes);
8891       myLastCreatedElems.Append(newElem);
8892       if ( aShapeId && newElem )
8893         aMesh->SetMeshElementOnShape( newElem, aShapeId );
8894
8895       aMesh->RemoveElement(theFace);
8896     }
8897     return;
8898   }
8899
8900   SMESHDS_Mesh *aMesh = GetMeshDS();
8901   if( !theFace->IsQuadratic() ) {
8902
8903     // put aNodesToInsert between theBetweenNode1 and theBetweenNode2
8904     int nbLinkNodes = 2 + aNodesToInsert.size();
8905     //const SMDS_MeshNode* linkNodes[ nbLinkNodes ];
8906     vector<const SMDS_MeshNode*> linkNodes( nbLinkNodes );
8907     linkNodes[ 0 ] = nodes[ il1 ];
8908     linkNodes[ nbLinkNodes - 1 ] = nodes[ il2 ];
8909     list<const SMDS_MeshNode*>::iterator nIt = aNodesToInsert.begin();
8910     for ( iNode = 1; nIt != aNodesToInsert.end(); nIt++ ) {
8911       linkNodes[ iNode++ ] = *nIt;
8912     }
8913     // decide how to split a quadrangle: compare possible variants
8914     // and choose which of splits to be a quadrangle
8915     int i1, i2, iSplit, nbSplits = nbLinkNodes - 1, iBestQuad;
8916     if ( nbFaceNodes == 3 ) {
8917       iBestQuad = nbSplits;
8918       i4 = i3;
8919     }
8920     else if ( nbFaceNodes == 4 ) {
8921       SMESH::Controls::NumericalFunctorPtr aCrit( new SMESH::Controls::AspectRatio);
8922       double aBestRate = DBL_MAX;
8923       for ( int iQuad = 0; iQuad < nbSplits; iQuad++ ) {
8924         i1 = 0; i2 = 1;
8925         double aBadRate = 0;
8926         // evaluate elements quality
8927         for ( iSplit = 0; iSplit < nbSplits; iSplit++ ) {
8928           if ( iSplit == iQuad ) {
8929             SMDS_FaceOfNodes quad (linkNodes[ i1++ ],
8930                                    linkNodes[ i2++ ],
8931                                    nodes[ i3 ],
8932                                    nodes[ i4 ]);
8933             aBadRate += getBadRate( &quad, aCrit );
8934           }
8935           else {
8936             SMDS_FaceOfNodes tria (linkNodes[ i1++ ],
8937                                    linkNodes[ i2++ ],
8938                                    nodes[ iSplit < iQuad ? i4 : i3 ]);
8939             aBadRate += getBadRate( &tria, aCrit );
8940           }
8941         }
8942         // choice
8943         if ( aBadRate < aBestRate ) {
8944           iBestQuad = iQuad;
8945           aBestRate = aBadRate;
8946         }
8947       }
8948     }
8949
8950     // create new elements
8951     int aShapeId = FindShape( theFace );
8952
8953     i1 = 0; i2 = 1;
8954     for ( iSplit = 0; iSplit < nbSplits - 1; iSplit++ ) {
8955       SMDS_MeshElement* newElem = 0;
8956       if ( iSplit == iBestQuad )
8957         newElem = aMesh->AddFace (linkNodes[ i1++ ],
8958                                   linkNodes[ i2++ ],
8959                                   nodes[ i3 ],
8960                                   nodes[ i4 ]);
8961       else
8962         newElem = aMesh->AddFace (linkNodes[ i1++ ],
8963                                   linkNodes[ i2++ ],
8964                                   nodes[ iSplit < iBestQuad ? i4 : i3 ]);
8965       myLastCreatedElems.Append(newElem);
8966       if ( aShapeId && newElem )
8967         aMesh->SetMeshElementOnShape( newElem, aShapeId );
8968     }
8969
8970     // change nodes of theFace
8971     const SMDS_MeshNode* newNodes[ 4 ];
8972     newNodes[ 0 ] = linkNodes[ i1 ];
8973     newNodes[ 1 ] = linkNodes[ i2 ];
8974     newNodes[ 2 ] = nodes[ iSplit >= iBestQuad ? i3 : i4 ];
8975     newNodes[ 3 ] = nodes[ i4 ];
8976     //aMesh->ChangeElementNodes( theFace, newNodes, iSplit == iBestQuad ? 4 : 3 );
8977     const SMDS_MeshElement* newElem = 0;
8978     if (iSplit == iBestQuad)
8979       newElem = aMesh->AddFace( newNodes[0], newNodes[1], newNodes[2], newNodes[3] );
8980     else
8981       newElem = aMesh->AddFace( newNodes[0], newNodes[1], newNodes[2] );
8982     myLastCreatedElems.Append(newElem);
8983     if ( aShapeId && newElem )
8984       aMesh->SetMeshElementOnShape( newElem, aShapeId );
8985 } // end if(!theFace->IsQuadratic())
8986   else { // theFace is quadratic
8987     // we have to split theFace on simple triangles and one simple quadrangle
8988     int tmp = il1/2;
8989     int nbshift = tmp*2;
8990     // shift nodes in nodes[] by nbshift
8991     int i,j;
8992     for(i=0; i<nbshift; i++) {
8993       const SMDS_MeshNode* n = nodes[0];
8994       for(j=0; j<nbFaceNodes-1; j++) {
8995         nodes[j] = nodes[j+1];
8996       }
8997       nodes[nbFaceNodes-1] = n;
8998     }
8999     il1 = il1 - nbshift;
9000     // now have to insert nodes between n0 and n1 or n1 and n2 (see below)
9001     //   n0      n1     n2    n0      n1     n2
9002     //     +-----+-----+        +-----+-----+
9003     //      \         /         |           |
9004     //       \       /          |           |
9005     //      n5+     +n3       n7+           +n3
9006     //         \   /            |           |
9007     //          \ /             |           |
9008     //           +              +-----+-----+
9009     //           n4           n6      n5     n4
9010
9011     // create new elements
9012     int aShapeId = FindShape( theFace );
9013
9014     int n1,n2,n3;
9015     if(nbFaceNodes==6) { // quadratic triangle
9016       SMDS_MeshElement* newElem =
9017         aMesh->AddFace(nodes[3],nodes[4],nodes[5]);
9018       myLastCreatedElems.Append(newElem);
9019       if ( aShapeId && newElem )
9020         aMesh->SetMeshElementOnShape( newElem, aShapeId );
9021       if(theFace->IsMediumNode(nodes[il1])) {
9022         // create quadrangle
9023         newElem = aMesh->AddFace(nodes[0],nodes[1],nodes[3],nodes[5]);
9024         myLastCreatedElems.Append(newElem);
9025         if ( aShapeId && newElem )
9026           aMesh->SetMeshElementOnShape( newElem, aShapeId );
9027         n1 = 1;
9028         n2 = 2;
9029         n3 = 3;
9030       }
9031       else {
9032         // create quadrangle
9033         newElem = aMesh->AddFace(nodes[1],nodes[2],nodes[3],nodes[5]);
9034         myLastCreatedElems.Append(newElem);
9035         if ( aShapeId && newElem )
9036           aMesh->SetMeshElementOnShape( newElem, aShapeId );
9037         n1 = 0;
9038         n2 = 1;
9039         n3 = 5;
9040       }
9041     }
9042     else { // nbFaceNodes==8 - quadratic quadrangle
9043       SMDS_MeshElement* newElem =
9044         aMesh->AddFace(nodes[3],nodes[4],nodes[5]);
9045       myLastCreatedElems.Append(newElem);
9046       if ( aShapeId && newElem )
9047         aMesh->SetMeshElementOnShape( newElem, aShapeId );
9048       newElem = aMesh->AddFace(nodes[5],nodes[6],nodes[7]);
9049       myLastCreatedElems.Append(newElem);
9050       if ( aShapeId && newElem )
9051         aMesh->SetMeshElementOnShape( newElem, aShapeId );
9052       newElem = aMesh->AddFace(nodes[5],nodes[7],nodes[3]);
9053       myLastCreatedElems.Append(newElem);
9054       if ( aShapeId && newElem )
9055         aMesh->SetMeshElementOnShape( newElem, aShapeId );
9056       if(theFace->IsMediumNode(nodes[il1])) {
9057         // create quadrangle
9058         newElem = aMesh->AddFace(nodes[0],nodes[1],nodes[3],nodes[7]);
9059         myLastCreatedElems.Append(newElem);
9060         if ( aShapeId && newElem )
9061           aMesh->SetMeshElementOnShape( newElem, aShapeId );
9062         n1 = 1;
9063         n2 = 2;
9064         n3 = 3;
9065       }
9066       else {
9067         // create quadrangle
9068         newElem = aMesh->AddFace(nodes[1],nodes[2],nodes[3],nodes[7]);
9069         myLastCreatedElems.Append(newElem);
9070         if ( aShapeId && newElem )
9071           aMesh->SetMeshElementOnShape( newElem, aShapeId );
9072         n1 = 0;
9073         n2 = 1;
9074         n3 = 7;
9075       }
9076     }
9077     // create needed triangles using n1,n2,n3 and inserted nodes
9078     int nbn = 2 + aNodesToInsert.size();
9079     //const SMDS_MeshNode* aNodes[nbn];
9080     vector<const SMDS_MeshNode*> aNodes(nbn);
9081     aNodes[0] = nodes[n1];
9082     aNodes[nbn-1] = nodes[n2];
9083     list<const SMDS_MeshNode*>::iterator nIt = aNodesToInsert.begin();
9084     for ( iNode = 1; nIt != aNodesToInsert.end(); nIt++ ) {
9085       aNodes[iNode++] = *nIt;
9086     }
9087     for(i=1; i<nbn; i++) {
9088       SMDS_MeshElement* newElem =
9089         aMesh->AddFace(aNodes[i-1],aNodes[i],nodes[n3]);
9090       myLastCreatedElems.Append(newElem);
9091       if ( aShapeId && newElem )
9092         aMesh->SetMeshElementOnShape( newElem, aShapeId );
9093     }
9094   }
9095   // remove old face
9096   aMesh->RemoveElement(theFace);
9097 }
9098
9099 //=======================================================================
9100 //function : UpdateVolumes
9101 //purpose  :
9102 //=======================================================================
9103 void SMESH_MeshEditor::UpdateVolumes (const SMDS_MeshNode*        theBetweenNode1,
9104                                       const SMDS_MeshNode*        theBetweenNode2,
9105                                       list<const SMDS_MeshNode*>& theNodesToInsert)
9106 {
9107   myLastCreatedElems.Clear();
9108   myLastCreatedNodes.Clear();
9109
9110   SMDS_ElemIteratorPtr invElemIt = theBetweenNode1->GetInverseElementIterator(SMDSAbs_Volume);
9111   while (invElemIt->more()) { // loop on inverse elements of theBetweenNode1
9112     const SMDS_MeshElement* elem = invElemIt->next();
9113
9114     // check, if current volume has link theBetweenNode1 - theBetweenNode2
9115     SMDS_VolumeTool aVolume (elem);
9116     if (!aVolume.IsLinked(theBetweenNode1, theBetweenNode2))
9117       continue;
9118
9119     // insert new nodes in all faces of the volume, sharing link theBetweenNode1 - theBetweenNode2
9120     int iface, nbFaces = aVolume.NbFaces();
9121     vector<const SMDS_MeshNode *> poly_nodes;
9122     vector<int> quantities (nbFaces);
9123
9124     for (iface = 0; iface < nbFaces; iface++) {
9125       int nbFaceNodes = aVolume.NbFaceNodes(iface), nbInserted = 0;
9126       // faceNodes will contain (nbFaceNodes + 1) nodes, last = first
9127       const SMDS_MeshNode** faceNodes = aVolume.GetFaceNodes(iface);
9128
9129       for (int inode = 0; inode < nbFaceNodes; inode++) {
9130         poly_nodes.push_back(faceNodes[inode]);
9131
9132         if (nbInserted == 0) {
9133           if (faceNodes[inode] == theBetweenNode1) {
9134             if (faceNodes[inode + 1] == theBetweenNode2) {
9135               nbInserted = theNodesToInsert.size();
9136
9137               // add nodes to insert
9138               list<const SMDS_MeshNode*>::iterator nIt = theNodesToInsert.begin();
9139               for (; nIt != theNodesToInsert.end(); nIt++) {
9140                 poly_nodes.push_back(*nIt);
9141               }
9142             }
9143           }
9144           else if (faceNodes[inode] == theBetweenNode2) {
9145             if (faceNodes[inode + 1] == theBetweenNode1) {
9146               nbInserted = theNodesToInsert.size();
9147
9148               // add nodes to insert in reversed order
9149               list<const SMDS_MeshNode*>::iterator nIt = theNodesToInsert.end();
9150               nIt--;
9151               for (; nIt != theNodesToInsert.begin(); nIt--) {
9152                 poly_nodes.push_back(*nIt);
9153               }
9154               poly_nodes.push_back(*nIt);
9155             }
9156           }
9157           else {
9158           }
9159         }
9160       }
9161       quantities[iface] = nbFaceNodes + nbInserted;
9162     }
9163
9164     // Replace or update the volume
9165     SMESHDS_Mesh *aMesh = GetMeshDS();
9166
9167     if (elem->IsPoly()) {
9168       aMesh->ChangePolyhedronNodes(elem, poly_nodes, quantities);
9169
9170     }
9171     else {
9172       int aShapeId = FindShape( elem );
9173
9174       SMDS_MeshElement* newElem =
9175         aMesh->AddPolyhedralVolume(poly_nodes, quantities);
9176       myLastCreatedElems.Append(newElem);
9177       if (aShapeId && newElem)
9178         aMesh->SetMeshElementOnShape(newElem, aShapeId);
9179
9180       aMesh->RemoveElement(elem);
9181     }
9182   }
9183 }
9184
9185 //=======================================================================
9186 /*!
9187  * \brief Convert elements contained in a submesh to quadratic
9188  * \return int - nb of checked elements
9189  */
9190 //=======================================================================
9191
9192 int SMESH_MeshEditor::convertElemToQuadratic(SMESHDS_SubMesh *   theSm,
9193                                              SMESH_MesherHelper& theHelper,
9194                                              const bool          theForce3d)
9195 {
9196   int nbElem = 0;
9197   if( !theSm ) return nbElem;
9198
9199   vector<int> nbNodeInFaces;
9200   SMDS_ElemIteratorPtr ElemItr = theSm->GetElements();
9201   while(ElemItr->more())
9202   {
9203     nbElem++;
9204     const SMDS_MeshElement* elem = ElemItr->next();
9205     if( !elem || elem->IsQuadratic() ) continue;
9206
9207     int id = elem->GetID();
9208     int nbNodes = elem->NbNodes();
9209     SMDSAbs_ElementType aType = elem->GetType();
9210
9211     vector<const SMDS_MeshNode *> nodes (elem->begin_nodes(), elem->end_nodes());
9212     if ( elem->GetEntityType() == SMDSEntity_Polyhedra )
9213       nbNodeInFaces = static_cast<const SMDS_VtkVolume* >( elem )->GetQuantities();
9214
9215     GetMeshDS()->RemoveFreeElement(elem, theSm, /*fromGroups=*/false);
9216
9217     const SMDS_MeshElement* NewElem = 0;
9218
9219     switch( aType )
9220     {
9221     case SMDSAbs_Edge :
9222       {
9223         NewElem = theHelper.AddEdge(nodes[0], nodes[1], id, theForce3d);
9224         break;
9225       }
9226     case SMDSAbs_Face :
9227       {
9228         switch(nbNodes)
9229         {
9230         case 3:
9231           NewElem = theHelper.AddFace(nodes[0], nodes[1], nodes[2], id, theForce3d);
9232           break;
9233         case 4:
9234           NewElem = theHelper.AddFace(nodes[0], nodes[1], nodes[2], nodes[3], id, theForce3d);
9235           break;
9236         default:
9237           NewElem = theHelper.AddPolygonalFace(nodes, id, theForce3d);
9238           continue;
9239         }
9240         break;
9241       }
9242     case SMDSAbs_Volume :
9243       {
9244         switch(nbNodes)
9245         {
9246         case 4:
9247           NewElem = theHelper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3], id, theForce3d);
9248           break;
9249         case 5:
9250           NewElem = theHelper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3], nodes[4], id, theForce3d);
9251           break;
9252         case 6:
9253           NewElem = theHelper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3], nodes[4], nodes[5], id, theForce3d);
9254           break;
9255         case 8:
9256           NewElem = theHelper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3],
9257                                         nodes[4], nodes[5], nodes[6], nodes[7], id, theForce3d);
9258           break;
9259         default:
9260           NewElem = theHelper.AddPolyhedralVolume(nodes, nbNodeInFaces, id, theForce3d);
9261         }
9262         break;
9263       }
9264     default :
9265       continue;
9266     }
9267     ReplaceElemInGroups( elem, NewElem, GetMeshDS());
9268     if( NewElem )
9269       theSm->AddElement( NewElem );
9270   }
9271 //  if (!GetMeshDS()->isCompacted())
9272 //    GetMeshDS()->compactMesh();
9273   return nbElem;
9274 }
9275
9276 //=======================================================================
9277 //function : ConvertToQuadratic
9278 //purpose  :
9279 //=======================================================================
9280 void SMESH_MeshEditor::ConvertToQuadratic(const bool theForce3d)
9281 {
9282   SMESHDS_Mesh* meshDS = GetMeshDS();
9283
9284   SMESH_MesherHelper aHelper(*myMesh);
9285   aHelper.SetIsQuadratic( true );
9286
9287   int nbCheckedElems = 0;
9288   if ( myMesh->HasShapeToMesh() )
9289   {
9290     if ( SMESH_subMesh *aSubMesh = myMesh->GetSubMeshContaining(myMesh->GetShapeToMesh()))
9291     {
9292       SMESH_subMeshIteratorPtr smIt = aSubMesh->getDependsOnIterator(true,false);
9293       while ( smIt->more() ) {
9294         SMESH_subMesh* sm = smIt->next();
9295         if ( SMESHDS_SubMesh *smDS = sm->GetSubMeshDS() ) {
9296           aHelper.SetSubShape( sm->GetSubShape() );
9297           nbCheckedElems += convertElemToQuadratic(smDS, aHelper, theForce3d);
9298         }
9299       }
9300     }
9301   }
9302   int totalNbElems = meshDS->NbEdges() + meshDS->NbFaces() + meshDS->NbVolumes();
9303   if ( nbCheckedElems < totalNbElems ) // not all elements are in submeshes
9304   {
9305     SMESHDS_SubMesh *smDS = 0;
9306     SMDS_EdgeIteratorPtr aEdgeItr = meshDS->edgesIterator();
9307     while(aEdgeItr->more())
9308     {
9309       const SMDS_MeshEdge* edge = aEdgeItr->next();
9310       if(edge && !edge->IsQuadratic())
9311       {
9312         int id = edge->GetID();
9313         //MESSAGE("edge->GetID() " << id);
9314         const SMDS_MeshNode* n1 = edge->GetNode(0);
9315         const SMDS_MeshNode* n2 = edge->GetNode(1);
9316
9317         meshDS->RemoveFreeElement(edge, smDS, /*fromGroups=*/false);
9318
9319         const SMDS_MeshEdge* NewEdge = aHelper.AddEdge(n1, n2, id, theForce3d);
9320         ReplaceElemInGroups( edge, NewEdge, GetMeshDS());
9321       }
9322     }
9323     SMDS_FaceIteratorPtr aFaceItr = meshDS->facesIterator();
9324     while(aFaceItr->more())
9325     {
9326       const SMDS_MeshFace* face = aFaceItr->next();
9327       if(!face || face->IsQuadratic() ) continue;
9328
9329       int id = face->GetID();
9330       int nbNodes = face->NbNodes();
9331       vector<const SMDS_MeshNode *> nodes ( face->begin_nodes(), face->end_nodes());
9332
9333       meshDS->RemoveFreeElement(face, smDS, /*fromGroups=*/false);
9334
9335       SMDS_MeshFace * NewFace = 0;
9336       switch(nbNodes)
9337       {
9338       case 3:
9339         NewFace = aHelper.AddFace(nodes[0], nodes[1], nodes[2], id, theForce3d);
9340         break;
9341       case 4:
9342         NewFace = aHelper.AddFace(nodes[0], nodes[1], nodes[2], nodes[3], id, theForce3d);
9343         break;
9344       default:
9345         NewFace = aHelper.AddPolygonalFace(nodes, id, theForce3d);
9346       }
9347       ReplaceElemInGroups( face, NewFace, GetMeshDS());
9348     }
9349     vector<int> nbNodeInFaces;
9350     SMDS_VolumeIteratorPtr aVolumeItr = meshDS->volumesIterator();
9351     while(aVolumeItr->more())
9352     {
9353       const SMDS_MeshVolume* volume = aVolumeItr->next();
9354       if(!volume || volume->IsQuadratic() ) continue;
9355
9356       int id = volume->GetID();
9357       int nbNodes = volume->NbNodes();
9358       vector<const SMDS_MeshNode *> nodes (volume->begin_nodes(), volume->end_nodes());
9359       if ( volume->GetEntityType() == SMDSEntity_Polyhedra )
9360         nbNodeInFaces = static_cast<const SMDS_VtkVolume* >(volume)->GetQuantities();
9361
9362       meshDS->RemoveFreeElement(volume, smDS, /*fromGroups=*/false);
9363
9364       SMDS_MeshVolume * NewVolume = 0;
9365       switch(nbNodes)
9366       {
9367       case 4:
9368         NewVolume = aHelper.AddVolume(nodes[0], nodes[1], nodes[2],
9369                                       nodes[3], id, theForce3d );
9370         break;
9371       case 5:
9372         NewVolume = aHelper.AddVolume(nodes[0], nodes[1], nodes[2],
9373                                       nodes[3], nodes[4], id, theForce3d);
9374         break;
9375       case 6:
9376         NewVolume = aHelper.AddVolume(nodes[0], nodes[1], nodes[2],
9377                                       nodes[3], nodes[4], nodes[5], id, theForce3d);
9378         break;
9379       case 8:
9380         NewVolume = aHelper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3],
9381                                       nodes[4], nodes[5], nodes[6], nodes[7], id, theForce3d);
9382         break;
9383       default:
9384         NewVolume = aHelper.AddPolyhedralVolume(nodes, nbNodeInFaces, id, theForce3d);
9385       }
9386       ReplaceElemInGroups(volume, NewVolume, meshDS);
9387     }
9388   }
9389
9390   if ( !theForce3d  && !getenv("NO_FixQuadraticElements"))
9391   { // setenv NO_FixQuadraticElements to know if FixQuadraticElements() is guilty of bad conversion
9392     aHelper.SetSubShape(0); // apply FixQuadraticElements() to the whole mesh
9393     aHelper.FixQuadraticElements();
9394   }
9395 }
9396
9397 //================================================================================
9398 /*!
9399  * \brief Makes given elements quadratic
9400  *  \param theForce3d - if true, the medium nodes will be placed in the middle of link
9401  *  \param theElements - elements to make quadratic 
9402  */
9403 //================================================================================
9404
9405 void SMESH_MeshEditor::ConvertToQuadratic(const bool        theForce3d,
9406                                           TIDSortedElemSet& theElements)
9407 {
9408   if ( theElements.empty() ) return;
9409
9410   // we believe that all theElements are of the same type
9411   SMDSAbs_ElementType elemType = (*theElements.begin())->GetType();
9412   
9413   // get all nodes shared by theElements
9414   TIDSortedNodeSet allNodes;
9415   TIDSortedElemSet::iterator eIt = theElements.begin();
9416   for ( ; eIt != theElements.end(); ++eIt )
9417     allNodes.insert( (*eIt)->begin_nodes(), (*eIt)->end_nodes() );
9418
9419   // complete theElements with elements of lower dim whose all nodes are in allNodes
9420
9421   TIDSortedElemSet quadAdjacentElems    [ SMDSAbs_NbElementTypes ]; // quadratic adjacent elements
9422   TIDSortedElemSet checkedAdjacentElems [ SMDSAbs_NbElementTypes ];
9423   TIDSortedNodeSet::iterator nIt = allNodes.begin();
9424   for ( ; nIt != allNodes.end(); ++nIt )
9425   {
9426     const SMDS_MeshNode* n = *nIt;
9427     SMDS_ElemIteratorPtr invIt = n->GetInverseElementIterator();
9428     while ( invIt->more() )
9429     {
9430       const SMDS_MeshElement* e = invIt->next();
9431       if ( e->IsQuadratic() )
9432       {
9433         quadAdjacentElems[ e->GetType() ].insert( e );
9434         continue;
9435       }
9436       if ( e->GetType() >= elemType )
9437       {
9438         continue; // same type of more complex linear element
9439       }
9440
9441       if ( !checkedAdjacentElems[ e->GetType() ].insert( e ).second )
9442         continue; // e is already checked
9443
9444       // check nodes
9445       bool allIn = true;
9446       SMDS_ElemIteratorPtr nodeIt = e->nodesIterator();
9447       while ( nodeIt->more() && allIn )
9448         allIn = allNodes.count( cast2Node( nodeIt->next() ));
9449       if ( allIn )
9450         theElements.insert(e );
9451     }
9452   }
9453
9454   SMESH_MesherHelper helper(*myMesh);
9455   helper.SetIsQuadratic( true );
9456
9457   // add links of quadratic adjacent elements to the helper
9458
9459   if ( !quadAdjacentElems[SMDSAbs_Edge].empty() )
9460     for ( eIt  = quadAdjacentElems[SMDSAbs_Edge].begin();
9461           eIt != quadAdjacentElems[SMDSAbs_Edge].end(); ++eIt )
9462     {
9463       helper.AddTLinks( static_cast< const SMDS_MeshEdge*> (*eIt) );
9464     }
9465   if ( !quadAdjacentElems[SMDSAbs_Face].empty() )
9466     for ( eIt  = quadAdjacentElems[SMDSAbs_Face].begin();
9467           eIt != quadAdjacentElems[SMDSAbs_Face].end(); ++eIt )
9468     {
9469       helper.AddTLinks( static_cast< const SMDS_MeshFace*> (*eIt) );
9470     }
9471   if ( !quadAdjacentElems[SMDSAbs_Volume].empty() )
9472     for ( eIt  = quadAdjacentElems[SMDSAbs_Volume].begin();
9473           eIt != quadAdjacentElems[SMDSAbs_Volume].end(); ++eIt )
9474     {
9475       helper.AddTLinks( static_cast< const SMDS_MeshVolume*> (*eIt) );
9476     }
9477
9478   // make quadratic elements instead of linear ones
9479
9480   SMESHDS_Mesh* meshDS = GetMeshDS();
9481   SMESHDS_SubMesh* smDS = 0;
9482   for ( eIt = theElements.begin(); eIt != theElements.end(); ++eIt )
9483   {
9484     const SMDS_MeshElement* elem = *eIt;
9485     if( elem->IsQuadratic() || elem->NbNodes() < 2 || elem->IsPoly() )
9486       continue;
9487
9488     int id = elem->GetID();
9489     SMDSAbs_ElementType type = elem->GetType();
9490     vector<const SMDS_MeshNode *> nodes ( elem->begin_nodes(), elem->end_nodes());
9491
9492     if ( !smDS || !smDS->Contains( elem ))
9493       smDS = meshDS->MeshElements( elem->getshapeId() );
9494     meshDS->RemoveFreeElement(elem, smDS, /*fromGroups=*/false);
9495
9496     SMDS_MeshElement * newElem = 0;
9497     switch( nodes.size() )
9498     {
9499     case 4: // cases for most multiple element types go first (for optimization)
9500       if ( type == SMDSAbs_Volume )
9501         newElem = helper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3], id, theForce3d);
9502       else
9503         newElem = helper.AddFace  (nodes[0], nodes[1], nodes[2], nodes[3], id, theForce3d);
9504       break;
9505     case 8:
9506       newElem = helper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3],
9507                                  nodes[4], nodes[5], nodes[6], nodes[7], id, theForce3d);
9508       break;
9509     case 3:
9510       newElem = helper.AddFace  (nodes[0], nodes[1], nodes[2], id, theForce3d);
9511       break;
9512     case 2:
9513       newElem = helper.AddEdge(nodes[0], nodes[1], id, theForce3d);
9514       break;
9515     case 5:
9516       newElem = helper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3],
9517                                  nodes[4], id, theForce3d);
9518       break;
9519     case 6:
9520       newElem = helper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3],
9521                                  nodes[4], nodes[5], id, theForce3d);
9522       break;
9523     default:;
9524     }
9525     ReplaceElemInGroups( elem, newElem, meshDS);
9526     if( newElem && smDS )
9527       smDS->AddElement( newElem );
9528   }
9529
9530   if ( !theForce3d  && !getenv("NO_FixQuadraticElements"))
9531   { // setenv NO_FixQuadraticElements to know if FixQuadraticElements() is guilty of bad conversion
9532     helper.SetSubShape(0); // apply FixQuadraticElements() to the whole mesh
9533     helper.FixQuadraticElements();
9534   }
9535 }
9536
9537 //=======================================================================
9538 /*!
9539  * \brief Convert quadratic elements to linear ones and remove quadratic nodes
9540  * \return int - nb of checked elements
9541  */
9542 //=======================================================================
9543
9544 int SMESH_MeshEditor::removeQuadElem(SMESHDS_SubMesh *    theSm,
9545                                      SMDS_ElemIteratorPtr theItr,
9546                                      const int            theShapeID)
9547 {
9548   int nbElem = 0;
9549   SMESHDS_Mesh* meshDS = GetMeshDS();
9550
9551   while( theItr->more() )
9552   {
9553     const SMDS_MeshElement* elem = theItr->next();
9554     nbElem++;
9555     if( elem && elem->IsQuadratic())
9556     {
9557       int id                    = elem->GetID();
9558       int nbCornerNodes         = elem->NbCornerNodes();
9559       SMDSAbs_ElementType aType = elem->GetType();
9560
9561       vector<const SMDS_MeshNode *> nodes( elem->begin_nodes(), elem->end_nodes() );
9562
9563       //remove a quadratic element
9564       if ( !theSm || !theSm->Contains( elem ))
9565         theSm = meshDS->MeshElements( elem->getshapeId() );
9566       meshDS->RemoveFreeElement( elem, theSm, /*fromGroups=*/false );
9567
9568       // remove medium nodes
9569       for ( unsigned i = nbCornerNodes; i < nodes.size(); ++i )
9570         if ( nodes[i]->NbInverseElements() == 0 )
9571           meshDS->RemoveFreeNode( nodes[i], theSm );
9572
9573       // add a linear element
9574       nodes.resize( nbCornerNodes );
9575       SMDS_MeshElement * newElem = AddElement( nodes, aType, false, id );
9576       ReplaceElemInGroups(elem, newElem, meshDS);
9577       if( theSm && newElem )
9578         theSm->AddElement( newElem );
9579     }
9580   }
9581   return nbElem;
9582 }
9583
9584 //=======================================================================
9585 //function : ConvertFromQuadratic
9586 //purpose  :
9587 //=======================================================================
9588
9589 bool SMESH_MeshEditor::ConvertFromQuadratic()
9590 {
9591   int nbCheckedElems = 0;
9592   if ( myMesh->HasShapeToMesh() )
9593   {
9594     if ( SMESH_subMesh *aSubMesh = myMesh->GetSubMeshContaining(myMesh->GetShapeToMesh()))
9595     {
9596       SMESH_subMeshIteratorPtr smIt = aSubMesh->getDependsOnIterator(true,false);
9597       while ( smIt->more() ) {
9598         SMESH_subMesh* sm = smIt->next();
9599         if ( SMESHDS_SubMesh *smDS = sm->GetSubMeshDS() )
9600           nbCheckedElems += removeQuadElem( smDS, smDS->GetElements(), sm->GetId() );
9601       }
9602     }
9603   }
9604
9605   int totalNbElems =
9606     GetMeshDS()->NbEdges() + GetMeshDS()->NbFaces() + GetMeshDS()->NbVolumes();
9607   if ( nbCheckedElems < totalNbElems ) // not all elements are in submeshes
9608   {
9609     SMESHDS_SubMesh *aSM = 0;
9610     removeQuadElem( aSM, GetMeshDS()->elementsIterator(), 0 );
9611   }
9612
9613   return true;
9614 }
9615
9616 namespace
9617 {
9618   //================================================================================
9619   /*!
9620    * \brief Return true if all medium nodes of the element are in the node set
9621    */
9622   //================================================================================
9623
9624   bool allMediumNodesIn(const SMDS_MeshElement* elem, TIDSortedNodeSet& nodeSet )
9625   {
9626     for ( int i = elem->NbCornerNodes(); i < elem->NbNodes(); ++i )
9627       if ( !nodeSet.count( elem->GetNode(i) ))
9628         return false;
9629     return true;
9630   }
9631 }
9632
9633 //================================================================================
9634 /*!
9635  * \brief Makes given elements linear
9636  */
9637 //================================================================================
9638
9639 void SMESH_MeshEditor::ConvertFromQuadratic(TIDSortedElemSet& theElements)
9640 {
9641   if ( theElements.empty() ) return;
9642
9643   // collect IDs of medium nodes of theElements; some of these nodes will be removed
9644   set<int> mediumNodeIDs;
9645   TIDSortedElemSet::iterator eIt = theElements.begin();
9646   for ( ; eIt != theElements.end(); ++eIt )
9647   {
9648     const SMDS_MeshElement* e = *eIt;
9649     for ( int i = e->NbCornerNodes(); i < e->NbNodes(); ++i )
9650       mediumNodeIDs.insert( e->GetNode(i)->GetID() );
9651   }
9652
9653   // replace given elements by linear ones
9654   typedef SMDS_SetIterator<const SMDS_MeshElement*, TIDSortedElemSet::iterator> TSetIterator;
9655   SMDS_ElemIteratorPtr elemIt( new TSetIterator( theElements.begin(), theElements.end() ));
9656   removeQuadElem( /*theSm=*/0, elemIt, /*theShapeID=*/0 );
9657
9658   // we need to convert remaining elements whose all medium nodes are in mediumNodeIDs
9659   // except those elements sharing medium nodes of quadratic element whose medium nodes
9660   // are not all in mediumNodeIDs
9661
9662   // get remaining medium nodes
9663   TIDSortedNodeSet mediumNodes;
9664   set<int>::iterator nIdsIt = mediumNodeIDs.begin();
9665   for ( ; nIdsIt != mediumNodeIDs.end(); ++nIdsIt )
9666     if ( const SMDS_MeshNode* n = GetMeshDS()->FindNode( *nIdsIt ))
9667       mediumNodes.insert( mediumNodes.end(), n );
9668
9669   // find more quadratic elements to convert
9670   TIDSortedElemSet moreElemsToConvert;
9671   TIDSortedNodeSet::iterator nIt = mediumNodes.begin();
9672   for ( ; nIt != mediumNodes.end(); ++nIt )
9673   {
9674     SMDS_ElemIteratorPtr invIt = (*nIt)->GetInverseElementIterator();
9675     while ( invIt->more() )
9676     {
9677       const SMDS_MeshElement* e = invIt->next();
9678       if ( e->IsQuadratic() && allMediumNodesIn( e, mediumNodes ))
9679       {
9680         // find a more complex element including e and
9681         // whose medium nodes are not in mediumNodes
9682         bool complexFound = false;
9683         for ( int type = e->GetType() + 1; type < SMDSAbs_0DElement; ++type )
9684         {
9685           SMDS_ElemIteratorPtr invIt2 =
9686             (*nIt)->GetInverseElementIterator( SMDSAbs_ElementType( type ));
9687           while ( invIt2->more() )
9688           {
9689             const SMDS_MeshElement* eComplex = invIt2->next();
9690             if ( eComplex->IsQuadratic() && !allMediumNodesIn( eComplex, mediumNodes))
9691             {
9692               int nbCommonNodes = SMESH_Algo::GetCommonNodes( e, eComplex ).size();
9693               if ( nbCommonNodes == e->NbNodes())
9694               {
9695                 complexFound = true;
9696                 type = SMDSAbs_NbElementTypes; // to quit from the outer loop
9697                 break;
9698               }
9699             }
9700           }
9701         }
9702         if ( !complexFound )
9703           moreElemsToConvert.insert( e );
9704       }
9705     }
9706   }
9707   elemIt = SMDS_ElemIteratorPtr
9708     (new TSetIterator( moreElemsToConvert.begin(), moreElemsToConvert.end() ));
9709   removeQuadElem( /*theSm=*/0, elemIt, /*theShapeID=*/0 );
9710 }
9711
9712 //=======================================================================
9713 //function : SewSideElements
9714 //purpose  :
9715 //=======================================================================
9716
9717 SMESH_MeshEditor::Sew_Error
9718 SMESH_MeshEditor::SewSideElements (TIDSortedElemSet&    theSide1,
9719                                    TIDSortedElemSet&    theSide2,
9720                                    const SMDS_MeshNode* theFirstNode1,
9721                                    const SMDS_MeshNode* theFirstNode2,
9722                                    const SMDS_MeshNode* theSecondNode1,
9723                                    const SMDS_MeshNode* theSecondNode2)
9724 {
9725   myLastCreatedElems.Clear();
9726   myLastCreatedNodes.Clear();
9727
9728   MESSAGE ("::::SewSideElements()");
9729   if ( theSide1.size() != theSide2.size() )
9730     return SEW_DIFF_NB_OF_ELEMENTS;
9731
9732   Sew_Error aResult = SEW_OK;
9733   // Algo:
9734   // 1. Build set of faces representing each side
9735   // 2. Find which nodes of the side 1 to merge with ones on the side 2
9736   // 3. Replace nodes in elements of the side 1 and remove replaced nodes
9737
9738   // =======================================================================
9739   // 1. Build set of faces representing each side:
9740   // =======================================================================
9741   // a. build set of nodes belonging to faces
9742   // b. complete set of faces: find missing faces whose nodes are in set of nodes
9743   // c. create temporary faces representing side of volumes if correspondent
9744   //    face does not exist
9745
9746   SMESHDS_Mesh* aMesh = GetMeshDS();
9747   // TODO algoritm not OK with vtkUnstructuredGrid: 2 meshes can't share nodes
9748   //SMDS_Mesh aTmpFacesMesh; // try to use the same mesh
9749   set<const SMDS_MeshElement*> faceSet1, faceSet2;
9750   set<const SMDS_MeshElement*> volSet1,  volSet2;
9751   set<const SMDS_MeshNode*>    nodeSet1, nodeSet2;
9752   set<const SMDS_MeshElement*> * faceSetPtr[] = { &faceSet1, &faceSet2 };
9753   set<const SMDS_MeshElement*>  * volSetPtr[] = { &volSet1,  &volSet2  };
9754   set<const SMDS_MeshNode*>    * nodeSetPtr[] = { &nodeSet1, &nodeSet2 };
9755   TIDSortedElemSet * elemSetPtr[] = { &theSide1, &theSide2 };
9756   int iSide, iFace, iNode;
9757
9758   list<const SMDS_MeshElement* > tempFaceList;
9759   for ( iSide = 0; iSide < 2; iSide++ ) {
9760     set<const SMDS_MeshNode*>    * nodeSet = nodeSetPtr[ iSide ];
9761     TIDSortedElemSet * elemSet = elemSetPtr[ iSide ];
9762     set<const SMDS_MeshElement*> * faceSet = faceSetPtr[ iSide ];
9763     set<const SMDS_MeshElement*> * volSet  = volSetPtr [ iSide ];
9764     set<const SMDS_MeshElement*>::iterator vIt;
9765     TIDSortedElemSet::iterator eIt;
9766     set<const SMDS_MeshNode*>::iterator    nIt;
9767
9768     // check that given nodes belong to given elements
9769     const SMDS_MeshNode* n1 = ( iSide == 0 ) ? theFirstNode1 : theFirstNode2;
9770     const SMDS_MeshNode* n2 = ( iSide == 0 ) ? theSecondNode1 : theSecondNode2;
9771     int firstIndex = -1, secondIndex = -1;
9772     for (eIt = elemSet->begin(); eIt != elemSet->end(); eIt++ ) {
9773       const SMDS_MeshElement* elem = *eIt;
9774       if ( firstIndex  < 0 ) firstIndex  = elem->GetNodeIndex( n1 );
9775       if ( secondIndex < 0 ) secondIndex = elem->GetNodeIndex( n2 );
9776       if ( firstIndex > -1 && secondIndex > -1 ) break;
9777     }
9778     if ( firstIndex < 0 || secondIndex < 0 ) {
9779       // we can simply return until temporary faces created
9780       return (iSide == 0 ) ? SEW_BAD_SIDE1_NODES : SEW_BAD_SIDE2_NODES;
9781     }
9782
9783     // -----------------------------------------------------------
9784     // 1a. Collect nodes of existing faces
9785     //     and build set of face nodes in order to detect missing
9786     //     faces corresponding to sides of volumes
9787     // -----------------------------------------------------------
9788
9789     set< set <const SMDS_MeshNode*> > setOfFaceNodeSet;
9790
9791     // loop on the given element of a side
9792     for (eIt = elemSet->begin(); eIt != elemSet->end(); eIt++ ) {
9793       //const SMDS_MeshElement* elem = *eIt;
9794       const SMDS_MeshElement* elem = *eIt;
9795       if ( elem->GetType() == SMDSAbs_Face ) {
9796         faceSet->insert( elem );
9797         set <const SMDS_MeshNode*> faceNodeSet;
9798         SMDS_ElemIteratorPtr nodeIt = elem->nodesIterator();
9799         while ( nodeIt->more() ) {
9800           const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
9801           nodeSet->insert( n );
9802           faceNodeSet.insert( n );
9803         }
9804         setOfFaceNodeSet.insert( faceNodeSet );
9805       }
9806       else if ( elem->GetType() == SMDSAbs_Volume )
9807         volSet->insert( elem );
9808     }
9809     // ------------------------------------------------------------------------------
9810     // 1b. Complete set of faces: find missing faces whose nodes are in set of nodes
9811     // ------------------------------------------------------------------------------
9812
9813     for ( nIt = nodeSet->begin(); nIt != nodeSet->end(); nIt++ ) { // loop on nodes of iSide
9814       SMDS_ElemIteratorPtr fIt = (*nIt)->GetInverseElementIterator(SMDSAbs_Face);
9815       while ( fIt->more() ) { // loop on faces sharing a node
9816         const SMDS_MeshElement* f = fIt->next();
9817         if ( faceSet->find( f ) == faceSet->end() ) {
9818           // check if all nodes are in nodeSet and
9819           // complete setOfFaceNodeSet if they are
9820           set <const SMDS_MeshNode*> faceNodeSet;
9821           SMDS_ElemIteratorPtr nodeIt = f->nodesIterator();
9822           bool allInSet = true;
9823           while ( nodeIt->more() && allInSet ) { // loop on nodes of a face
9824             const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
9825             if ( nodeSet->find( n ) == nodeSet->end() )
9826               allInSet = false;
9827             else
9828               faceNodeSet.insert( n );
9829           }
9830           if ( allInSet ) {
9831             faceSet->insert( f );
9832             setOfFaceNodeSet.insert( faceNodeSet );
9833           }
9834         }
9835       }
9836     }
9837
9838     // -------------------------------------------------------------------------
9839     // 1c. Create temporary faces representing sides of volumes if correspondent
9840     //     face does not exist
9841     // -------------------------------------------------------------------------
9842
9843     if ( !volSet->empty() ) {
9844       //int nodeSetSize = nodeSet->size();
9845
9846       // loop on given volumes
9847       for ( vIt = volSet->begin(); vIt != volSet->end(); vIt++ ) {
9848         SMDS_VolumeTool vol (*vIt);
9849         // loop on volume faces: find free faces
9850         // --------------------------------------
9851         list<const SMDS_MeshElement* > freeFaceList;
9852         for ( iFace = 0; iFace < vol.NbFaces(); iFace++ ) {
9853           if ( !vol.IsFreeFace( iFace ))
9854             continue;
9855           // check if there is already a face with same nodes in a face set
9856           const SMDS_MeshElement* aFreeFace = 0;
9857           const SMDS_MeshNode** fNodes = vol.GetFaceNodes( iFace );
9858           int nbNodes = vol.NbFaceNodes( iFace );
9859           set <const SMDS_MeshNode*> faceNodeSet;
9860           vol.GetFaceNodes( iFace, faceNodeSet );
9861           bool isNewFace = setOfFaceNodeSet.insert( faceNodeSet ).second;
9862           if ( isNewFace ) {
9863             // no such a face is given but it still can exist, check it
9864             if ( nbNodes == 3 ) {
9865               aFreeFace = aMesh->FindFace( fNodes[0],fNodes[1],fNodes[2] );
9866             }
9867             else if ( nbNodes == 4 ) {
9868               aFreeFace = aMesh->FindFace( fNodes[0],fNodes[1],fNodes[2],fNodes[3] );
9869             }
9870             else {
9871               vector<const SMDS_MeshNode *> poly_nodes ( fNodes, & fNodes[nbNodes]);
9872               aFreeFace = aMesh->FindFace(poly_nodes);
9873             }
9874           }
9875           if ( !aFreeFace ) {
9876             // create a temporary face
9877             if ( nbNodes == 3 ) {
9878               //aFreeFace = aTmpFacesMesh.AddFace( fNodes[0],fNodes[1],fNodes[2] );
9879               aFreeFace = aMesh->AddFace( fNodes[0],fNodes[1],fNodes[2] );
9880             }
9881             else if ( nbNodes == 4 ) {
9882               //aFreeFace = aTmpFacesMesh.AddFace( fNodes[0],fNodes[1],fNodes[2],fNodes[3] );
9883               aFreeFace = aMesh->AddFace( fNodes[0],fNodes[1],fNodes[2],fNodes[3] );
9884             }
9885             else {
9886               vector<const SMDS_MeshNode *> poly_nodes ( fNodes, & fNodes[nbNodes]);
9887               //aFreeFace = aTmpFacesMesh.AddPolygonalFace(poly_nodes);
9888               aFreeFace = aMesh->AddPolygonalFace(poly_nodes);
9889             }
9890           }
9891           if ( aFreeFace ) {
9892             freeFaceList.push_back( aFreeFace );
9893             tempFaceList.push_back( aFreeFace );
9894           }
9895
9896         } // loop on faces of a volume
9897
9898         // choose one of several free faces
9899         // --------------------------------------
9900         if ( freeFaceList.size() > 1 ) {
9901           // choose a face having max nb of nodes shared by other elems of a side
9902           int maxNbNodes = -1/*, nbExcludedFaces = 0*/;
9903           list<const SMDS_MeshElement* >::iterator fIt = freeFaceList.begin();
9904           while ( fIt != freeFaceList.end() ) { // loop on free faces
9905             int nbSharedNodes = 0;
9906             SMDS_ElemIteratorPtr nodeIt = (*fIt)->nodesIterator();
9907             while ( nodeIt->more() ) { // loop on free face nodes
9908               const SMDS_MeshNode* n =
9909                 static_cast<const SMDS_MeshNode*>( nodeIt->next() );
9910               SMDS_ElemIteratorPtr invElemIt = n->GetInverseElementIterator();
9911               while ( invElemIt->more() ) {
9912                 const SMDS_MeshElement* e = invElemIt->next();
9913                 if ( faceSet->find( e ) != faceSet->end() )
9914                   nbSharedNodes++;
9915                 if ( elemSet->find( e ) != elemSet->end() )
9916                   nbSharedNodes++;
9917               }
9918             }
9919             if ( nbSharedNodes >= maxNbNodes ) {
9920               maxNbNodes = nbSharedNodes;
9921               fIt++;
9922             }
9923             else
9924               freeFaceList.erase( fIt++ ); // here fIt++ occurs before erase
9925           }
9926           if ( freeFaceList.size() > 1 )
9927           {
9928             // could not choose one face, use another way
9929             // choose a face most close to the bary center of the opposite side
9930             gp_XYZ aBC( 0., 0., 0. );
9931             set <const SMDS_MeshNode*> addedNodes;
9932             TIDSortedElemSet * elemSet2 = elemSetPtr[ 1 - iSide ];
9933             eIt = elemSet2->begin();
9934             for ( eIt = elemSet2->begin(); eIt != elemSet2->end(); eIt++ ) {
9935               SMDS_ElemIteratorPtr nodeIt = (*eIt)->nodesIterator();
9936               while ( nodeIt->more() ) { // loop on free face nodes
9937                 const SMDS_MeshNode* n =
9938                   static_cast<const SMDS_MeshNode*>( nodeIt->next() );
9939                 if ( addedNodes.insert( n ).second )
9940                   aBC += gp_XYZ( n->X(),n->Y(),n->Z() );
9941               }
9942             }
9943             aBC /= addedNodes.size();
9944             double minDist = DBL_MAX;
9945             fIt = freeFaceList.begin();
9946             while ( fIt != freeFaceList.end() ) { // loop on free faces
9947               double dist = 0;
9948               SMDS_ElemIteratorPtr nodeIt = (*fIt)->nodesIterator();
9949               while ( nodeIt->more() ) { // loop on free face nodes
9950                 const SMDS_MeshNode* n =
9951                   static_cast<const SMDS_MeshNode*>( nodeIt->next() );
9952                 gp_XYZ p( n->X(),n->Y(),n->Z() );
9953                 dist += ( aBC - p ).SquareModulus();
9954               }
9955               if ( dist < minDist ) {
9956                 minDist = dist;
9957                 freeFaceList.erase( freeFaceList.begin(), fIt++ );
9958               }
9959               else
9960                 fIt = freeFaceList.erase( fIt++ );
9961             }
9962           }
9963         } // choose one of several free faces of a volume
9964
9965         if ( freeFaceList.size() == 1 ) {
9966           const SMDS_MeshElement* aFreeFace = freeFaceList.front();
9967           faceSet->insert( aFreeFace );
9968           // complete a node set with nodes of a found free face
9969           //           for ( iNode = 0; iNode < ; iNode++ )
9970           //             nodeSet->insert( fNodes[ iNode ] );
9971         }
9972
9973       } // loop on volumes of a side
9974
9975       //       // complete a set of faces if new nodes in a nodeSet appeared
9976       //       // ----------------------------------------------------------
9977       //       if ( nodeSetSize != nodeSet->size() ) {
9978       //         for ( ; nIt != nodeSet->end(); nIt++ ) { // loop on nodes of iSide
9979       //           SMDS_ElemIteratorPtr fIt = (*nIt)->GetInverseElementIterator(SMDSAbs_Face);
9980       //           while ( fIt->more() ) { // loop on faces sharing a node
9981       //             const SMDS_MeshElement* f = fIt->next();
9982       //             if ( faceSet->find( f ) == faceSet->end() ) {
9983       //               // check if all nodes are in nodeSet and
9984       //               // complete setOfFaceNodeSet if they are
9985       //               set <const SMDS_MeshNode*> faceNodeSet;
9986       //               SMDS_ElemIteratorPtr nodeIt = f->nodesIterator();
9987       //               bool allInSet = true;
9988       //               while ( nodeIt->more() && allInSet ) { // loop on nodes of a face
9989       //                 const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
9990       //                 if ( nodeSet->find( n ) == nodeSet->end() )
9991       //                   allInSet = false;
9992       //                 else
9993       //                   faceNodeSet.insert( n );
9994       //               }
9995       //               if ( allInSet ) {
9996       //                 faceSet->insert( f );
9997       //                 setOfFaceNodeSet.insert( faceNodeSet );
9998       //               }
9999       //             }
10000       //           }
10001       //         }
10002       //       }
10003     } // Create temporary faces, if there are volumes given
10004   } // loop on sides
10005
10006   if ( faceSet1.size() != faceSet2.size() ) {
10007     // delete temporary faces: they are in reverseElements of actual nodes
10008 //    SMDS_FaceIteratorPtr tmpFaceIt = aTmpFacesMesh.facesIterator();
10009 //    while ( tmpFaceIt->more() )
10010 //      aTmpFacesMesh.RemoveElement( tmpFaceIt->next() );
10011 //    list<const SMDS_MeshElement* >::iterator tmpFaceIt = tempFaceList.begin();
10012 //    for (; tmpFaceIt !=tempFaceList.end(); ++tmpFaceIt)
10013 //      aMesh->RemoveElement(*tmpFaceIt);
10014     MESSAGE("Diff nb of faces");
10015     return SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
10016   }
10017
10018   // ============================================================
10019   // 2. Find nodes to merge:
10020   //              bind a node to remove to a node to put instead
10021   // ============================================================
10022
10023   TNodeNodeMap nReplaceMap; // bind a node to remove to a node to put instead
10024   if ( theFirstNode1 != theFirstNode2 )
10025     nReplaceMap.insert( TNodeNodeMap::value_type( theFirstNode1, theFirstNode2 ));
10026   if ( theSecondNode1 != theSecondNode2 )
10027     nReplaceMap.insert( TNodeNodeMap::value_type( theSecondNode1, theSecondNode2 ));
10028
10029   LinkID_Gen aLinkID_Gen( GetMeshDS() );
10030   set< long > linkIdSet; // links to process
10031   linkIdSet.insert( aLinkID_Gen.GetLinkID( theFirstNode1, theSecondNode1 ));
10032
10033   typedef pair< const SMDS_MeshNode*, const SMDS_MeshNode* > NLink;
10034   list< NLink > linkList[2];
10035   linkList[0].push_back( NLink( theFirstNode1, theSecondNode1 ));
10036   linkList[1].push_back( NLink( theFirstNode2, theSecondNode2 ));
10037   // loop on links in linkList; find faces by links and append links
10038   // of the found faces to linkList
10039   list< NLink >::iterator linkIt[] = { linkList[0].begin(), linkList[1].begin() } ;
10040   for ( ; linkIt[0] != linkList[0].end(); linkIt[0]++, linkIt[1]++ ) {
10041     NLink link[] = { *linkIt[0], *linkIt[1] };
10042     long linkID = aLinkID_Gen.GetLinkID( link[0].first, link[0].second );
10043     if ( linkIdSet.find( linkID ) == linkIdSet.end() )
10044       continue;
10045
10046     // by links, find faces in the face sets,
10047     // and find indices of link nodes in the found faces;
10048     // in a face set, there is only one or no face sharing a link
10049     // ---------------------------------------------------------------
10050
10051     const SMDS_MeshElement* face[] = { 0, 0 };
10052     //const SMDS_MeshNode* faceNodes[ 2 ][ 5 ];
10053     vector<const SMDS_MeshNode*> fnodes1(9);
10054     vector<const SMDS_MeshNode*> fnodes2(9);
10055     //const SMDS_MeshNode* notLinkNodes[ 2 ][ 2 ] = {{ 0, 0 },{ 0, 0 }} ;
10056     vector<const SMDS_MeshNode*> notLinkNodes1(6);
10057     vector<const SMDS_MeshNode*> notLinkNodes2(6);
10058     int iLinkNode[2][2];
10059     for ( iSide = 0; iSide < 2; iSide++ ) { // loop on 2 sides
10060       const SMDS_MeshNode* n1 = link[iSide].first;
10061       const SMDS_MeshNode* n2 = link[iSide].second;
10062       set<const SMDS_MeshElement*> * faceSet = faceSetPtr[ iSide ];
10063       set< const SMDS_MeshElement* > fMap;
10064       for ( int i = 0; i < 2; i++ ) { // loop on 2 nodes of a link
10065         const SMDS_MeshNode* n = i ? n1 : n2; // a node of a link
10066         SMDS_ElemIteratorPtr fIt = n->GetInverseElementIterator(SMDSAbs_Face);
10067         while ( fIt->more() ) { // loop on faces sharing a node
10068           const SMDS_MeshElement* f = fIt->next();
10069           if (faceSet->find( f ) != faceSet->end() && // f is in face set
10070               ! fMap.insert( f ).second ) // f encounters twice
10071           {
10072             if ( face[ iSide ] ) {
10073               MESSAGE( "2 faces per link " );
10074               aResult = iSide ? SEW_BAD_SIDE2_NODES : SEW_BAD_SIDE1_NODES;
10075               break;
10076             }
10077             face[ iSide ] = f;
10078             faceSet->erase( f );
10079             // get face nodes and find ones of a link
10080             iNode = 0;
10081             int nbl = -1;
10082             if(f->IsPoly()) {
10083               if(iSide==0) {
10084                 fnodes1.resize(f->NbNodes()+1);
10085                 notLinkNodes1.resize(f->NbNodes()-2);
10086               }
10087               else {
10088                 fnodes2.resize(f->NbNodes()+1);
10089                 notLinkNodes2.resize(f->NbNodes()-2);
10090               }
10091             }
10092             if(!f->IsQuadratic()) {
10093               SMDS_ElemIteratorPtr nIt = f->nodesIterator();
10094               while ( nIt->more() ) {
10095                 const SMDS_MeshNode* n =
10096                   static_cast<const SMDS_MeshNode*>( nIt->next() );
10097                 if ( n == n1 ) {
10098                   iLinkNode[ iSide ][ 0 ] = iNode;
10099                 }
10100                 else if ( n == n2 ) {
10101                   iLinkNode[ iSide ][ 1 ] = iNode;
10102                 }
10103                 //else if ( notLinkNodes[ iSide ][ 0 ] )
10104                 //  notLinkNodes[ iSide ][ 1 ] = n;
10105                 //else
10106                 //  notLinkNodes[ iSide ][ 0 ] = n;
10107                 else {
10108                   nbl++;
10109                   if(iSide==0)
10110                     notLinkNodes1[nbl] = n;
10111                   //notLinkNodes1.push_back(n);
10112                   else
10113                     notLinkNodes2[nbl] = n;
10114                   //notLinkNodes2.push_back(n);
10115                 }
10116                 //faceNodes[ iSide ][ iNode++ ] = n;
10117                 if(iSide==0) {
10118                   fnodes1[iNode++] = n;
10119                 }
10120                 else {
10121                   fnodes2[iNode++] = n;
10122                 }
10123               }
10124             }
10125             else { // f->IsQuadratic()
10126               const SMDS_VtkFace* F =
10127                 dynamic_cast<const SMDS_VtkFace*>(f);
10128               if (!F) throw SALOME_Exception(LOCALIZED("not an SMDS_VtkFace"));
10129               // use special nodes iterator
10130               SMDS_ElemIteratorPtr anIter = F->interlacedNodesElemIterator();
10131               while ( anIter->more() ) {
10132                 const SMDS_MeshNode* n =
10133                   static_cast<const SMDS_MeshNode*>( anIter->next() );
10134                 if ( n == n1 ) {
10135                   iLinkNode[ iSide ][ 0 ] = iNode;
10136                 }
10137                 else if ( n == n2 ) {
10138                   iLinkNode[ iSide ][ 1 ] = iNode;
10139                 }
10140                 else {
10141                   nbl++;
10142                   if(iSide==0) {
10143                     notLinkNodes1[nbl] = n;
10144                   }
10145                   else {
10146                     notLinkNodes2[nbl] = n;
10147                   }
10148                 }
10149                 if(iSide==0) {
10150                   fnodes1[iNode++] = n;
10151                 }
10152                 else {
10153                   fnodes2[iNode++] = n;
10154                 }
10155               }
10156             }
10157             //faceNodes[ iSide ][ iNode ] = faceNodes[ iSide ][ 0 ];
10158             if(iSide==0) {
10159               fnodes1[iNode] = fnodes1[0];
10160             }
10161             else {
10162               fnodes2[iNode] = fnodes1[0];
10163             }
10164           }
10165         }
10166       }
10167     }
10168
10169     // check similarity of elements of the sides
10170     if (aResult == SEW_OK && ( face[0] && !face[1] ) || ( !face[0] && face[1] )) {
10171       MESSAGE("Correspondent face not found on side " << ( face[0] ? 1 : 0 ));
10172       if ( nReplaceMap.size() == 2 ) { // faces on input nodes not found
10173         aResult = ( face[0] ? SEW_BAD_SIDE2_NODES : SEW_BAD_SIDE1_NODES );
10174       }
10175       else {
10176         aResult = SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
10177       }
10178       break; // do not return because it s necessary to remove tmp faces
10179     }
10180
10181     // set nodes to merge
10182     // -------------------
10183
10184     if ( face[0] && face[1] )  {
10185       int nbNodes = face[0]->NbNodes();
10186       if ( nbNodes != face[1]->NbNodes() ) {
10187         MESSAGE("Diff nb of face nodes");
10188         aResult = SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
10189         break; // do not return because it s necessary to remove tmp faces
10190       }
10191       bool reverse[] = { false, false }; // order of notLinkNodes of quadrangle
10192       if ( nbNodes == 3 ) {
10193         //nReplaceMap.insert( TNodeNodeMap::value_type
10194         //                   ( notLinkNodes[0][0], notLinkNodes[1][0] ));
10195         nReplaceMap.insert( TNodeNodeMap::value_type
10196                             ( notLinkNodes1[0], notLinkNodes2[0] ));
10197       }
10198       else {
10199         for ( iSide = 0; iSide < 2; iSide++ ) { // loop on 2 sides
10200           // analyse link orientation in faces
10201           int i1 = iLinkNode[ iSide ][ 0 ];
10202           int i2 = iLinkNode[ iSide ][ 1 ];
10203           reverse[ iSide ] = Abs( i1 - i2 ) == 1 ? i1 > i2 : i2 > i1;
10204           // if notLinkNodes are the first and the last ones, then
10205           // their order does not correspond to the link orientation
10206           if (( i1 == 1 && i2 == 2 ) ||
10207               ( i1 == 2 && i2 == 1 ))
10208             reverse[ iSide ] = !reverse[ iSide ];
10209         }
10210         if ( reverse[0] == reverse[1] ) {
10211           //nReplaceMap.insert( TNodeNodeMap::value_type
10212           //                   ( notLinkNodes[0][0], notLinkNodes[1][0] ));
10213           //nReplaceMap.insert( TNodeNodeMap::value_type
10214           //                   ( notLinkNodes[0][1], notLinkNodes[1][1] ));
10215           for(int nn=0; nn<nbNodes-2; nn++) {
10216             nReplaceMap.insert( TNodeNodeMap::value_type
10217                                 ( notLinkNodes1[nn], notLinkNodes2[nn] ));
10218           }
10219         }
10220         else {
10221           //nReplaceMap.insert( TNodeNodeMap::value_type
10222           //                   ( notLinkNodes[0][0], notLinkNodes[1][1] ));
10223           //nReplaceMap.insert( TNodeNodeMap::value_type
10224           //                   ( notLinkNodes[0][1], notLinkNodes[1][0] ));
10225           for(int nn=0; nn<nbNodes-2; nn++) {
10226             nReplaceMap.insert( TNodeNodeMap::value_type
10227                                 ( notLinkNodes1[nn], notLinkNodes2[nbNodes-3-nn] ));
10228           }
10229         }
10230       }
10231
10232       // add other links of the faces to linkList
10233       // -----------------------------------------
10234
10235       //const SMDS_MeshNode** nodes = faceNodes[ 0 ];
10236       for ( iNode = 0; iNode < nbNodes; iNode++ )  {
10237         //linkID = aLinkID_Gen.GetLinkID( nodes[iNode], nodes[iNode+1] );
10238         linkID = aLinkID_Gen.GetLinkID( fnodes1[iNode], fnodes1[iNode+1] );
10239         pair< set<long>::iterator, bool > iter_isnew = linkIdSet.insert( linkID );
10240         if ( !iter_isnew.second ) { // already in a set: no need to process
10241           linkIdSet.erase( iter_isnew.first );
10242         }
10243         else // new in set == encountered for the first time: add
10244         {
10245           //const SMDS_MeshNode* n1 = nodes[ iNode ];
10246           //const SMDS_MeshNode* n2 = nodes[ iNode + 1];
10247           const SMDS_MeshNode* n1 = fnodes1[ iNode ];
10248           const SMDS_MeshNode* n2 = fnodes1[ iNode + 1];
10249           linkList[0].push_back ( NLink( n1, n2 ));
10250           linkList[1].push_back ( NLink( nReplaceMap[n1], nReplaceMap[n2] ));
10251         }
10252       }
10253     } // 2 faces found
10254   } // loop on link lists
10255
10256   if ( aResult == SEW_OK &&
10257        ( linkIt[0] != linkList[0].end() ||
10258          !faceSetPtr[0]->empty() || !faceSetPtr[1]->empty() )) {
10259     MESSAGE( (linkIt[0] != linkList[0].end()) <<" "<< (faceSetPtr[0]->empty()) <<
10260              " " << (faceSetPtr[1]->empty()));
10261     aResult = SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
10262   }
10263
10264   // ====================================================================
10265   // 3. Replace nodes in elements of the side 1 and remove replaced nodes
10266   // ====================================================================
10267
10268   // delete temporary faces: they are in reverseElements of actual nodes
10269 //  SMDS_FaceIteratorPtr tmpFaceIt = aTmpFacesMesh.facesIterator();
10270 //  while ( tmpFaceIt->more() )
10271 //    aTmpFacesMesh.RemoveElement( tmpFaceIt->next() );
10272 //  list<const SMDS_MeshElement* >::iterator tmpFaceIt = tempFaceList.begin();
10273 //  for (; tmpFaceIt !=tempFaceList.end(); ++tmpFaceIt)
10274 //    aMesh->RemoveElement(*tmpFaceIt);
10275
10276   if ( aResult != SEW_OK)
10277     return aResult;
10278
10279   list< int > nodeIDsToRemove/*, elemIDsToRemove*/;
10280   // loop on nodes replacement map
10281   TNodeNodeMap::iterator nReplaceMapIt = nReplaceMap.begin(), nnIt;
10282   for ( ; nReplaceMapIt != nReplaceMap.end(); nReplaceMapIt++ )
10283     if ( (*nReplaceMapIt).first != (*nReplaceMapIt).second ) {
10284       const SMDS_MeshNode* nToRemove = (*nReplaceMapIt).first;
10285       nodeIDsToRemove.push_back( nToRemove->GetID() );
10286       // loop on elements sharing nToRemove
10287       SMDS_ElemIteratorPtr invElemIt = nToRemove->GetInverseElementIterator();
10288       while ( invElemIt->more() ) {
10289         const SMDS_MeshElement* e = invElemIt->next();
10290         // get a new suite of nodes: make replacement
10291         int nbReplaced = 0, i = 0, nbNodes = e->NbNodes();
10292         vector< const SMDS_MeshNode*> nodes( nbNodes );
10293         SMDS_ElemIteratorPtr nIt = e->nodesIterator();
10294         while ( nIt->more() ) {
10295           const SMDS_MeshNode* n =
10296             static_cast<const SMDS_MeshNode*>( nIt->next() );
10297           nnIt = nReplaceMap.find( n );
10298           if ( nnIt != nReplaceMap.end() ) {
10299             nbReplaced++;
10300             n = (*nnIt).second;
10301           }
10302           nodes[ i++ ] = n;
10303         }
10304         //       if ( nbReplaced == nbNodes && e->GetType() == SMDSAbs_Face )
10305         //         elemIDsToRemove.push_back( e->GetID() );
10306         //       else
10307         if ( nbReplaced )
10308           {
10309             SMDSAbs_ElementType etyp = e->GetType();
10310             SMDS_MeshElement* newElem = this->AddElement(nodes, etyp, false);
10311             if (newElem)
10312               {
10313                 myLastCreatedElems.Append(newElem);
10314                 AddToSameGroups(newElem, e, aMesh);
10315                 int aShapeId = e->getshapeId();
10316                 if ( aShapeId )
10317                   {
10318                     aMesh->SetMeshElementOnShape( newElem, aShapeId );
10319                   }
10320               }
10321             aMesh->RemoveElement(e);
10322           }
10323       }
10324     }
10325
10326   Remove( nodeIDsToRemove, true );
10327
10328   return aResult;
10329 }
10330
10331 //================================================================================
10332 /*!
10333  * \brief Find corresponding nodes in two sets of faces
10334  * \param theSide1 - first face set
10335  * \param theSide2 - second first face
10336  * \param theFirstNode1 - a boundary node of set 1
10337  * \param theFirstNode2 - a node of set 2 corresponding to theFirstNode1
10338  * \param theSecondNode1 - a boundary node of set 1 linked with theFirstNode1
10339  * \param theSecondNode2 - a node of set 2 corresponding to theSecondNode1
10340  * \param nReplaceMap - output map of corresponding nodes
10341  * \return bool  - is a success or not
10342  */
10343 //================================================================================
10344
10345 #ifdef _DEBUG_
10346 //#define DEBUG_MATCHING_NODES
10347 #endif
10348
10349 SMESH_MeshEditor::Sew_Error
10350 SMESH_MeshEditor::FindMatchingNodes(set<const SMDS_MeshElement*>& theSide1,
10351                                     set<const SMDS_MeshElement*>& theSide2,
10352                                     const SMDS_MeshNode*          theFirstNode1,
10353                                     const SMDS_MeshNode*          theFirstNode2,
10354                                     const SMDS_MeshNode*          theSecondNode1,
10355                                     const SMDS_MeshNode*          theSecondNode2,
10356                                     TNodeNodeMap &                nReplaceMap)
10357 {
10358   set<const SMDS_MeshElement*> * faceSetPtr[] = { &theSide1, &theSide2 };
10359
10360   nReplaceMap.clear();
10361   if ( theFirstNode1 != theFirstNode2 )
10362     nReplaceMap.insert( make_pair( theFirstNode1, theFirstNode2 ));
10363   if ( theSecondNode1 != theSecondNode2 )
10364     nReplaceMap.insert( make_pair( theSecondNode1, theSecondNode2 ));
10365
10366   set< SMESH_TLink > linkSet; // set of nodes where order of nodes is ignored
10367   linkSet.insert( SMESH_TLink( theFirstNode1, theSecondNode1 ));
10368
10369   list< NLink > linkList[2];
10370   linkList[0].push_back( NLink( theFirstNode1, theSecondNode1 ));
10371   linkList[1].push_back( NLink( theFirstNode2, theSecondNode2 ));
10372
10373   // loop on links in linkList; find faces by links and append links
10374   // of the found faces to linkList
10375   list< NLink >::iterator linkIt[] = { linkList[0].begin(), linkList[1].begin() } ;
10376   for ( ; linkIt[0] != linkList[0].end(); linkIt[0]++, linkIt[1]++ ) {
10377     NLink link[] = { *linkIt[0], *linkIt[1] };
10378     if ( linkSet.find( link[0] ) == linkSet.end() )
10379       continue;
10380
10381     // by links, find faces in the face sets,
10382     // and find indices of link nodes in the found faces;
10383     // in a face set, there is only one or no face sharing a link
10384     // ---------------------------------------------------------------
10385
10386     const SMDS_MeshElement* face[] = { 0, 0 };
10387     list<const SMDS_MeshNode*> notLinkNodes[2];
10388     //bool reverse[] = { false, false }; // order of notLinkNodes
10389     int nbNodes[2];
10390     for ( int iSide = 0; iSide < 2; iSide++ ) // loop on 2 sides
10391     {
10392       const SMDS_MeshNode* n1 = link[iSide].first;
10393       const SMDS_MeshNode* n2 = link[iSide].second;
10394       set<const SMDS_MeshElement*> * faceSet = faceSetPtr[ iSide ];
10395       set< const SMDS_MeshElement* > facesOfNode1;
10396       for ( int iNode = 0; iNode < 2; iNode++ ) // loop on 2 nodes of a link
10397       {
10398         // during a loop of the first node, we find all faces around n1,
10399         // during a loop of the second node, we find one face sharing both n1 and n2
10400         const SMDS_MeshNode* n = iNode ? n1 : n2; // a node of a link
10401         SMDS_ElemIteratorPtr fIt = n->GetInverseElementIterator(SMDSAbs_Face);
10402         while ( fIt->more() ) { // loop on faces sharing a node
10403           const SMDS_MeshElement* f = fIt->next();
10404           if (faceSet->find( f ) != faceSet->end() && // f is in face set
10405               ! facesOfNode1.insert( f ).second ) // f encounters twice
10406           {
10407             if ( face[ iSide ] ) {
10408               MESSAGE( "2 faces per link " );
10409               return ( iSide ? SEW_BAD_SIDE2_NODES : SEW_BAD_SIDE1_NODES );
10410             }
10411             face[ iSide ] = f;
10412             faceSet->erase( f );
10413
10414             // get not link nodes
10415             int nbN = f->NbNodes();
10416             if ( f->IsQuadratic() )
10417               nbN /= 2;
10418             nbNodes[ iSide ] = nbN;
10419             list< const SMDS_MeshNode* > & nodes = notLinkNodes[ iSide ];
10420             int i1 = f->GetNodeIndex( n1 );
10421             int i2 = f->GetNodeIndex( n2 );
10422             int iEnd = nbN, iBeg = -1, iDelta = 1;
10423             bool reverse = ( Abs( i1 - i2 ) == 1 ? i1 > i2 : i2 > i1 );
10424             if ( reverse ) {
10425               std::swap( iEnd, iBeg ); iDelta = -1;
10426             }
10427             int i = i2;
10428             while ( true ) {
10429               i += iDelta;
10430               if ( i == iEnd ) i = iBeg + iDelta;
10431               if ( i == i1 ) break;
10432               nodes.push_back ( f->GetNode( i ) );
10433             }
10434           }
10435         }
10436       }
10437     }
10438     // check similarity of elements of the sides
10439     if (( face[0] && !face[1] ) || ( !face[0] && face[1] )) {
10440       MESSAGE("Correspondent face not found on side " << ( face[0] ? 1 : 0 ));
10441       if ( nReplaceMap.size() == 2 ) { // faces on input nodes not found
10442         return ( face[0] ? SEW_BAD_SIDE2_NODES : SEW_BAD_SIDE1_NODES );
10443       }
10444       else {
10445         return SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
10446       }
10447     }
10448
10449     // set nodes to merge
10450     // -------------------
10451
10452     if ( face[0] && face[1] )  {
10453       if ( nbNodes[0] != nbNodes[1] ) {
10454         MESSAGE("Diff nb of face nodes");
10455         return SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
10456       }
10457 #ifdef DEBUG_MATCHING_NODES
10458       MESSAGE ( " Link 1: " << link[0].first->GetID() <<" "<< link[0].second->GetID()
10459                 << " F 1: " << face[0] << "| Link 2: " << link[1].first->GetID() <<" "
10460                 << link[1].second->GetID() << " F 2: " << face[1] << " | Bind: " ) ;
10461 #endif
10462       int nbN = nbNodes[0];
10463       {
10464         list<const SMDS_MeshNode*>::iterator n1 = notLinkNodes[0].begin();
10465         list<const SMDS_MeshNode*>::iterator n2 = notLinkNodes[1].begin();
10466         for ( int i = 0 ; i < nbN - 2; ++i ) {
10467 #ifdef DEBUG_MATCHING_NODES
10468           MESSAGE ( (*n1)->GetID() << " to " << (*n2)->GetID() );
10469 #endif
10470           nReplaceMap.insert( make_pair( *(n1++), *(n2++) ));
10471         }
10472       }
10473
10474       // add other links of the face 1 to linkList
10475       // -----------------------------------------
10476
10477       const SMDS_MeshElement* f0 = face[0];
10478       const SMDS_MeshNode* n1 = f0->GetNode( nbN - 1 );
10479       for ( int i = 0; i < nbN; i++ )
10480       {
10481         const SMDS_MeshNode* n2 = f0->GetNode( i );
10482         pair< set< SMESH_TLink >::iterator, bool > iter_isnew =
10483           linkSet.insert( SMESH_TLink( n1, n2 ));
10484         if ( !iter_isnew.second ) { // already in a set: no need to process
10485           linkSet.erase( iter_isnew.first );
10486         }
10487         else // new in set == encountered for the first time: add
10488         {
10489 #ifdef DEBUG_MATCHING_NODES
10490           MESSAGE ( "Add link 1: " << n1->GetID() << " " << n2->GetID() << " "
10491                     << " | link 2: " << nReplaceMap[n1]->GetID() << " " << nReplaceMap[n2]->GetID() << " " );
10492 #endif
10493           linkList[0].push_back ( NLink( n1, n2 ));
10494           linkList[1].push_back ( NLink( nReplaceMap[n1], nReplaceMap[n2] ));
10495         }
10496         n1 = n2;
10497       }
10498     } // 2 faces found
10499   } // loop on link lists
10500
10501   return SEW_OK;
10502 }
10503
10504 //================================================================================
10505 /*!
10506   \brief Creates a hole in a mesh by doubling the nodes of some particular elements
10507   \param theElems - the list of elements (edges or faces) to be replicated
10508   The nodes for duplication could be found from these elements
10509   \param theNodesNot - list of nodes to NOT replicate
10510   \param theAffectedElems - the list of elements (cells and edges) to which the 
10511   replicated nodes should be associated to.
10512   \return TRUE if operation has been completed successfully, FALSE otherwise
10513 */
10514 //================================================================================
10515
10516 bool SMESH_MeshEditor::DoubleNodes( const TIDSortedElemSet& theElems,
10517                                     const TIDSortedElemSet& theNodesNot,
10518                                     const TIDSortedElemSet& theAffectedElems )
10519 {
10520   myLastCreatedElems.Clear();
10521   myLastCreatedNodes.Clear();
10522
10523   if ( theElems.size() == 0 )
10524     return false;
10525
10526   SMESHDS_Mesh* aMeshDS = GetMeshDS();
10527   if ( !aMeshDS )
10528     return false;
10529
10530   bool res = false;
10531   std::map< const SMDS_MeshNode*, const SMDS_MeshNode* > anOldNodeToNewNode;
10532   // duplicate elements and nodes
10533   res = doubleNodes( aMeshDS, theElems, theNodesNot, anOldNodeToNewNode, true );
10534   // replce nodes by duplications
10535   res = doubleNodes( aMeshDS, theAffectedElems, theNodesNot, anOldNodeToNewNode, false );
10536   return res;
10537 }
10538
10539 //================================================================================
10540 /*!
10541   \brief Creates a hole in a mesh by doubling the nodes of some particular elements
10542   \param theMeshDS - mesh instance
10543   \param theElems - the elements replicated or modified (nodes should be changed)
10544   \param theNodesNot - nodes to NOT replicate
10545   \param theNodeNodeMap - relation of old node to new created node
10546   \param theIsDoubleElem - flag os to replicate element or modify
10547   \return TRUE if operation has been completed successfully, FALSE otherwise
10548 */
10549 //================================================================================
10550
10551 bool SMESH_MeshEditor::doubleNodes( SMESHDS_Mesh*     theMeshDS,
10552                                     const TIDSortedElemSet& theElems,
10553                                     const TIDSortedElemSet& theNodesNot,
10554                                     std::map< const SMDS_MeshNode*,
10555                                     const SMDS_MeshNode* >& theNodeNodeMap,
10556                                     const bool theIsDoubleElem )
10557 {
10558   MESSAGE("doubleNodes");
10559   // iterate on through element and duplicate them (by nodes duplication)
10560   bool res = false;
10561   TIDSortedElemSet::const_iterator elemItr = theElems.begin();
10562   for ( ;  elemItr != theElems.end(); ++elemItr )
10563   {
10564     const SMDS_MeshElement* anElem = *elemItr;
10565     if (!anElem)
10566       continue;
10567
10568     bool isDuplicate = false;
10569     // duplicate nodes to duplicate element
10570     std::vector<const SMDS_MeshNode*> newNodes( anElem->NbNodes() );
10571     SMDS_ElemIteratorPtr anIter = anElem->nodesIterator();
10572     int ind = 0;
10573     while ( anIter->more() ) 
10574     { 
10575
10576       SMDS_MeshNode* aCurrNode = (SMDS_MeshNode*)anIter->next();
10577       SMDS_MeshNode* aNewNode = aCurrNode;
10578       if ( theNodeNodeMap.find( aCurrNode ) != theNodeNodeMap.end() )
10579         aNewNode = (SMDS_MeshNode*)theNodeNodeMap[ aCurrNode ];
10580       else if ( theIsDoubleElem && theNodesNot.find( aCurrNode ) == theNodesNot.end() )
10581       {
10582         // duplicate node
10583         aNewNode = theMeshDS->AddNode( aCurrNode->X(), aCurrNode->Y(), aCurrNode->Z() );
10584         theNodeNodeMap[ aCurrNode ] = aNewNode;
10585         myLastCreatedNodes.Append( aNewNode );
10586       }
10587       isDuplicate |= (aCurrNode != aNewNode);
10588       newNodes[ ind++ ] = aNewNode;
10589     }
10590     if ( !isDuplicate )
10591       continue;
10592
10593     if ( theIsDoubleElem )
10594       AddElement(newNodes, anElem->GetType(), anElem->IsPoly());
10595     else
10596       {
10597       MESSAGE("ChangeElementNodes");
10598       theMeshDS->ChangeElementNodes( anElem, &newNodes[ 0 ], anElem->NbNodes() );
10599       }
10600     res = true;
10601   }
10602   return res;
10603 }
10604
10605 //================================================================================
10606 /*!
10607   \brief Creates a hole in a mesh by doubling the nodes of some particular elements
10608   \param theNodes - identifiers of nodes to be doubled
10609   \param theModifiedElems - identifiers of elements to be updated by the new (doubled) 
10610          nodes. If list of element identifiers is empty then nodes are doubled but 
10611          they not assigned to elements
10612   \return TRUE if operation has been completed successfully, FALSE otherwise
10613 */
10614 //================================================================================
10615
10616 bool SMESH_MeshEditor::DoubleNodes( const std::list< int >& theListOfNodes, 
10617                                     const std::list< int >& theListOfModifiedElems )
10618 {
10619   MESSAGE("DoubleNodes");
10620   myLastCreatedElems.Clear();
10621   myLastCreatedNodes.Clear();
10622
10623   if ( theListOfNodes.size() == 0 )
10624     return false;
10625
10626   SMESHDS_Mesh* aMeshDS = GetMeshDS();
10627   if ( !aMeshDS )
10628     return false;
10629
10630   // iterate through nodes and duplicate them
10631
10632   std::map< const SMDS_MeshNode*, const SMDS_MeshNode* > anOldNodeToNewNode;
10633
10634   std::list< int >::const_iterator aNodeIter;
10635   for ( aNodeIter = theListOfNodes.begin(); aNodeIter != theListOfNodes.end(); ++aNodeIter )
10636   {
10637     int aCurr = *aNodeIter;
10638     SMDS_MeshNode* aNode = (SMDS_MeshNode*)aMeshDS->FindNode( aCurr );
10639     if ( !aNode )
10640       continue;
10641
10642     // duplicate node
10643
10644     const SMDS_MeshNode* aNewNode = aMeshDS->AddNode( aNode->X(), aNode->Y(), aNode->Z() );
10645     if ( aNewNode )
10646     {
10647       anOldNodeToNewNode[ aNode ] = aNewNode;
10648       myLastCreatedNodes.Append( aNewNode );
10649     }
10650   }
10651
10652   // Create map of new nodes for modified elements
10653
10654   std::map< SMDS_MeshElement*, vector<const SMDS_MeshNode*> > anElemToNodes;
10655
10656   std::list< int >::const_iterator anElemIter;
10657   for ( anElemIter = theListOfModifiedElems.begin(); 
10658         anElemIter != theListOfModifiedElems.end(); ++anElemIter )
10659   {
10660     int aCurr = *anElemIter;
10661     SMDS_MeshElement* anElem = (SMDS_MeshElement*)aMeshDS->FindElement( aCurr );
10662     if ( !anElem )
10663       continue;
10664
10665     vector<const SMDS_MeshNode*> aNodeArr( anElem->NbNodes() );
10666
10667     SMDS_ElemIteratorPtr anIter = anElem->nodesIterator();
10668     int ind = 0;
10669     while ( anIter->more() ) 
10670     { 
10671       SMDS_MeshNode* aCurrNode = (SMDS_MeshNode*)anIter->next();
10672       if ( aCurr && anOldNodeToNewNode.find( aCurrNode ) != anOldNodeToNewNode.end() )
10673       {
10674         const SMDS_MeshNode* aNewNode = anOldNodeToNewNode[ aCurrNode ];
10675         aNodeArr[ ind++ ] = aNewNode;
10676       }
10677       else
10678         aNodeArr[ ind++ ] = aCurrNode;
10679     }
10680     anElemToNodes[ anElem ] = aNodeArr;
10681   }
10682
10683   // Change nodes of elements  
10684
10685   std::map< SMDS_MeshElement*, vector<const SMDS_MeshNode*> >::iterator
10686     anElemToNodesIter = anElemToNodes.begin();
10687   for ( ; anElemToNodesIter != anElemToNodes.end(); ++anElemToNodesIter )
10688   {
10689     const SMDS_MeshElement* anElem = anElemToNodesIter->first;
10690     vector<const SMDS_MeshNode*> aNodeArr = anElemToNodesIter->second;
10691     if ( anElem )
10692       {
10693       MESSAGE("ChangeElementNodes");
10694       aMeshDS->ChangeElementNodes( anElem, &aNodeArr[ 0 ], anElem->NbNodes() );
10695       }
10696   }
10697
10698   return true;
10699 }
10700
10701 namespace {
10702
10703   //================================================================================
10704   /*!
10705   \brief Check if element located inside shape
10706   \return TRUE if IN or ON shape, FALSE otherwise
10707   */
10708   //================================================================================
10709
10710   template<class Classifier>
10711   bool isInside(const SMDS_MeshElement* theElem,
10712                 Classifier&             theClassifier,
10713                 const double            theTol)
10714   {
10715     gp_XYZ centerXYZ (0, 0, 0);
10716     SMDS_ElemIteratorPtr aNodeItr = theElem->nodesIterator();
10717     while (aNodeItr->more())
10718       centerXYZ += SMESH_TNodeXYZ(cast2Node( aNodeItr->next()));
10719
10720     gp_Pnt aPnt = centerXYZ / theElem->NbNodes();
10721     theClassifier.Perform(aPnt, theTol);
10722     TopAbs_State aState = theClassifier.State();
10723     return (aState == TopAbs_IN || aState == TopAbs_ON );
10724   }
10725
10726   //================================================================================
10727   /*!
10728    * \brief Classifier of the 3D point on the TopoDS_Face
10729    *        with interaface suitable for isInside()
10730    */
10731   //================================================================================
10732
10733   struct _FaceClassifier
10734   {
10735     Extrema_ExtPS       _extremum;
10736     BRepAdaptor_Surface _surface;
10737     TopAbs_State        _state;
10738
10739     _FaceClassifier(const TopoDS_Face& face):_extremum(),_surface(face),_state(TopAbs_OUT)
10740     {
10741       _extremum.Initialize( _surface,
10742                             _surface.FirstUParameter(), _surface.LastUParameter(),
10743                             _surface.FirstVParameter(), _surface.LastVParameter(),
10744                             _surface.Tolerance(), _surface.Tolerance() );
10745     }
10746     void Perform(const gp_Pnt& aPnt, double theTol)
10747     {
10748       _state = TopAbs_OUT;
10749       _extremum.Perform(aPnt);
10750       if ( _extremum.IsDone() )
10751         for ( int iSol = 1; iSol <= _extremum.NbExt() && _state == TopAbs_OUT; ++iSol)
10752           _state = ( _extremum.Value(iSol) <= theTol ? TopAbs_IN : TopAbs_OUT );
10753     }
10754     TopAbs_State State() const
10755     {
10756       return _state;
10757     }
10758   };
10759 }
10760
10761 //================================================================================
10762 /*!
10763   \brief Creates a hole in a mesh by doubling the nodes of some particular elements
10764   \param theElems - group of of elements (edges or faces) to be replicated
10765   \param theNodesNot - group of nodes not to replicate
10766   \param theShape - shape to detect affected elements (element which geometric center
10767   located on or inside shape).
10768   The replicated nodes should be associated to affected elements.
10769   \return TRUE if operation has been completed successfully, FALSE otherwise
10770 */
10771 //================================================================================
10772
10773 bool SMESH_MeshEditor::DoubleNodesInRegion( const TIDSortedElemSet& theElems,
10774                                             const TIDSortedElemSet& theNodesNot,
10775                                             const TopoDS_Shape&     theShape )
10776 {
10777   if ( theShape.IsNull() )
10778     return false;
10779
10780   const double aTol = Precision::Confusion();
10781   auto_ptr< BRepClass3d_SolidClassifier> bsc3d;
10782   auto_ptr<_FaceClassifier>              aFaceClassifier;
10783   if ( theShape.ShapeType() == TopAbs_SOLID )
10784   {
10785     bsc3d.reset( new BRepClass3d_SolidClassifier(theShape));;
10786     bsc3d->PerformInfinitePoint(aTol);
10787   }
10788   else if (theShape.ShapeType() == TopAbs_FACE )
10789   {
10790     aFaceClassifier.reset( new _FaceClassifier(TopoDS::Face(theShape)));
10791   }
10792
10793   // iterates on indicated elements and get elements by back references from their nodes
10794   TIDSortedElemSet anAffected;
10795   TIDSortedElemSet::const_iterator elemItr = theElems.begin();
10796   for ( ;  elemItr != theElems.end(); ++elemItr )
10797   {
10798     SMDS_MeshElement* anElem = (SMDS_MeshElement*)*elemItr;
10799     if (!anElem)
10800       continue;
10801
10802     SMDS_ElemIteratorPtr nodeItr = anElem->nodesIterator();
10803     while ( nodeItr->more() )
10804     {
10805       const SMDS_MeshNode* aNode = cast2Node(nodeItr->next());
10806       if ( !aNode || theNodesNot.find(aNode) != theNodesNot.end() )
10807         continue;
10808       SMDS_ElemIteratorPtr backElemItr = aNode->GetInverseElementIterator();
10809       while ( backElemItr->more() )
10810       {
10811         const SMDS_MeshElement* curElem = backElemItr->next();
10812         if ( curElem && theElems.find(curElem) == theElems.end() &&
10813              ( bsc3d.get() ?
10814                isInside( curElem, *bsc3d, aTol ) :
10815                isInside( curElem, *aFaceClassifier, aTol )))
10816           anAffected.insert( curElem );
10817       }
10818     }
10819   }
10820   return DoubleNodes( theElems, theNodesNot, anAffected );
10821 }
10822
10823 /*!
10824  *  \brief compute an oriented angle between two planes defined by four points.
10825  *  The vector (p0,p1) defines the intersection of the 2 planes (p0,p1,g1) and (p0,p1,g2)
10826  *  @param p0 base of the rotation axe
10827  *  @param p1 extremity of the rotation axe
10828  *  @param g1 belongs to the first plane
10829  *  @param g2 belongs to the second plane
10830  */
10831 double SMESH_MeshEditor::OrientedAngle(const gp_Pnt& p0, const gp_Pnt& p1, const gp_Pnt& g1, const gp_Pnt& g2)
10832 {
10833 //  MESSAGE("    p0: " << p0.X() << " " << p0.Y() << " " << p0.Z());
10834 //  MESSAGE("    p1: " << p1.X() << " " << p1.Y() << " " << p1.Z());
10835 //  MESSAGE("    g1: " << g1.X() << " " << g1.Y() << " " << g1.Z());
10836 //  MESSAGE("    g2: " << g2.X() << " " << g2.Y() << " " << g2.Z());
10837   gp_Vec vref(p0, p1);
10838   gp_Vec v1(p0, g1);
10839   gp_Vec v2(p0, g2);
10840   gp_Vec n1 = vref.Crossed(v1);
10841   gp_Vec n2 = vref.Crossed(v2);
10842   return n2.AngleWithRef(n1, vref);
10843 }
10844
10845 /*!
10846  * \brief Double nodes on shared faces between groups of volumes and create flat elements on demand.
10847  * The list of groups must describe a partition of the mesh volumes.
10848  * The nodes of the internal faces at the boundaries of the groups are doubled.
10849  * In option, the internal faces are replaced by flat elements.
10850  * Triangles are transformed in prisms, and quadrangles in hexahedrons.
10851  * The flat elements are stored in groups of volumes.
10852  * @param theElems - list of groups of volumes, where a group of volume is a set of
10853  * SMDS_MeshElements sorted by Id.
10854  * @param createJointElems - if TRUE, create the elements
10855  * @return TRUE if operation has been completed successfully, FALSE otherwise
10856  */
10857 bool SMESH_MeshEditor::DoubleNodesOnGroupBoundaries( const std::vector<TIDSortedElemSet>& theElems,
10858                                                      bool createJointElems)
10859 {
10860   MESSAGE("----------------------------------------------");
10861   MESSAGE("SMESH_MeshEditor::doubleNodesOnGroupBoundaries");
10862   MESSAGE("----------------------------------------------");
10863
10864   SMESHDS_Mesh *meshDS = this->myMesh->GetMeshDS();
10865   meshDS->BuildDownWardConnectivity(true);
10866   CHRONO(50);
10867   SMDS_UnstructuredGrid *grid = meshDS->getGrid();
10868
10869   // --- build the list of faces shared by 2 domains (group of elements), with their domain and volume indexes
10870   //     build the list of cells with only a node or an edge on the border, with their domain and volume indexes
10871   //     build the list of nodes shared by 2 or more domains, with their domain indexes
10872
10873   std::map<DownIdType, std::map<int,int>, DownIdCompare> faceDomains; // face --> (id domain --> id volume)
10874   std::map<int,int>celldom; // cell vtkId --> domain
10875   std::map<DownIdType, std::map<int,int>, DownIdCompare> cellDomains;  // oldNode --> (id domain --> id cell)
10876   std::map<int, std::map<int,int> > nodeDomains; // oldId -->  (domainId --> newId)
10877   faceDomains.clear();
10878   celldom.clear();
10879   cellDomains.clear();
10880   nodeDomains.clear();
10881   std::map<int,int> emptyMap;
10882   std::set<int> emptySet;
10883   emptyMap.clear();
10884
10885   for (int idom = 0; idom < theElems.size(); idom++)
10886     {
10887
10888       // --- build a map (face to duplicate --> volume to modify)
10889       //     with all the faces shared by 2 domains (group of elements)
10890       //     and corresponding volume of this domain, for each shared face.
10891       //     a volume has a face shared by 2 domains if it has a neighbor which is not in is domain.
10892
10893       const TIDSortedElemSet& domain = theElems[idom];
10894       TIDSortedElemSet::const_iterator elemItr = domain.begin();
10895       for (; elemItr != domain.end(); ++elemItr)
10896         {
10897           SMDS_MeshElement* anElem = (SMDS_MeshElement*) *elemItr;
10898           if (!anElem)
10899             continue;
10900           int vtkId = anElem->getVtkId();
10901           int neighborsVtkIds[NBMAXNEIGHBORS];
10902           int downIds[NBMAXNEIGHBORS];
10903           unsigned char downTypes[NBMAXNEIGHBORS];
10904           int nbNeighbors = grid->GetNeighbors(neighborsVtkIds, downIds, downTypes, vtkId);
10905           for (int n = 0; n < nbNeighbors; n++)
10906             {
10907               int smdsId = meshDS->fromVtkToSmds(neighborsVtkIds[n]);
10908               const SMDS_MeshElement* elem = meshDS->FindElement(smdsId);
10909               if (! domain.count(elem)) // neighbor is in another domain : face is shared
10910                 {
10911                   DownIdType face(downIds[n], downTypes[n]);
10912                   if (!faceDomains.count(face))
10913                     faceDomains[face] = emptyMap; // create an empty entry for face
10914                   if (!faceDomains[face].count(idom))
10915                     {
10916                       faceDomains[face][idom] = vtkId; // volume associated to face in this domain
10917                       celldom[vtkId] = idom;
10918                     }
10919                 }
10920             }
10921         }
10922     }
10923
10924   //MESSAGE("Number of shared faces " << faceDomains.size());
10925   std::map<DownIdType, std::map<int, int>, DownIdCompare>::iterator itface;
10926
10927   // --- explore the shared faces domain by domain,
10928   //     explore the nodes of the face and see if they belong to a cell in the domain,
10929   //     which has only a node or an edge on the border (not a shared face)
10930
10931   for (int idomain = 0; idomain < theElems.size(); idomain++)
10932     {
10933       const TIDSortedElemSet& domain = theElems[idomain];
10934       itface = faceDomains.begin();
10935       for (; itface != faceDomains.end(); ++itface)
10936         {
10937           std::map<int, int> domvol = itface->second;
10938           if (!domvol.count(idomain))
10939             continue;
10940           DownIdType face = itface->first;
10941           //MESSAGE(" --- face " << face.cellId);
10942           std::set<int> oldNodes;
10943           oldNodes.clear();
10944           grid->GetNodeIds(oldNodes, face.cellId, face.cellType);
10945           std::set<int>::iterator itn = oldNodes.begin();
10946           for (; itn != oldNodes.end(); ++itn)
10947             {
10948               int oldId = *itn;
10949               //MESSAGE("     node " << oldId);
10950               std::set<int> cells;
10951               cells.clear();
10952               vtkCellLinks::Link l = grid->GetCellLinks()->GetLink(oldId);
10953               for (int i=0; i<l.ncells; i++)
10954                 {
10955                   int vtkId = l.cells[i];
10956                   const SMDS_MeshElement* anElem = GetMeshDS()->FindElement(GetMeshDS()->fromVtkToSmds(vtkId));
10957                   if (!domain.count(anElem))
10958                     continue;
10959                   int vtkType = grid->GetCellType(vtkId);
10960                   int downId = grid->CellIdToDownId(vtkId);
10961                   DownIdType aCell(downId, vtkType);
10962                   if (celldom.count(vtkId))
10963                     continue;
10964                   cellDomains[aCell][idomain] = vtkId;
10965                   celldom[vtkId] = idomain;
10966                 }
10967             }
10968         }
10969     }
10970
10971   // --- explore the shared faces domain by domain, to duplicate the nodes in a coherent way
10972   //     for each shared face, get the nodes
10973   //     for each node, for each domain of the face, create a clone of the node
10974
10975   // --- edges at the intersection of 3 or 4 domains, with the order of domains to build
10976   //     junction elements of type prism or hexa. the key is the pair of nodesId (lower first)
10977   //     the value is the ordered domain ids. (more than 4 domains not taken into account)
10978
10979   std::map<std::vector<int>, std::vector<int> > edgesMultiDomains; // nodes of edge --> ordered domains
10980   std::map<int, std::vector<int> > mutipleNodes; // nodes muti domains with domain order
10981
10982   for (int idomain = 0; idomain < theElems.size(); idomain++)
10983     {
10984       itface = faceDomains.begin();
10985       for (; itface != faceDomains.end(); ++itface)
10986         {
10987           std::map<int, int> domvol = itface->second;
10988           if (!domvol.count(idomain))
10989             continue;
10990           DownIdType face = itface->first;
10991           //MESSAGE(" --- face " << face.cellId);
10992           std::set<int> oldNodes;
10993           oldNodes.clear();
10994           grid->GetNodeIds(oldNodes, face.cellId, face.cellType);
10995           bool isMultipleDetected = false;
10996           std::set<int>::iterator itn = oldNodes.begin();
10997           for (; itn != oldNodes.end(); ++itn)
10998             {
10999               int oldId = *itn;
11000               //MESSAGE("     node " << oldId);
11001               if (!nodeDomains.count(oldId))
11002                 nodeDomains[oldId] = emptyMap; // create an empty entry for node
11003               if (nodeDomains[oldId].empty())
11004                 nodeDomains[oldId][idomain] = oldId; // keep the old node in the first domain
11005               std::map<int, int>::iterator itdom = domvol.begin();
11006               for (; itdom != domvol.end(); ++itdom)
11007                 {
11008                   int idom = itdom->first;
11009                   //MESSAGE("         domain " << idom);
11010                   if (!nodeDomains[oldId].count(idom)) // --- node to clone
11011                     {
11012                       if (nodeDomains[oldId].size() >= 2) // a multiple node
11013                         {
11014                           vector<int> orderedDoms;
11015                           //MESSAGE("multiple node " << oldId);
11016                           isMultipleDetected =true;
11017                           if (mutipleNodes.count(oldId))
11018                             orderedDoms = mutipleNodes[oldId];
11019                           else
11020                             {
11021                               map<int,int>::iterator it = nodeDomains[oldId].begin();
11022                               for (; it != nodeDomains[oldId].end(); ++it)
11023                                 orderedDoms.push_back(it->first);
11024                             }
11025                           orderedDoms.push_back(idom); // TODO order ==> push_front or back
11026                           //stringstream txt;
11027                           //for (int i=0; i<orderedDoms.size(); i++)
11028                           //  txt << orderedDoms[i] << " ";
11029                           //MESSAGE("orderedDoms " << txt.str());
11030                           mutipleNodes[oldId] = orderedDoms;
11031                         }
11032                       double *coords = grid->GetPoint(oldId);
11033                       SMDS_MeshNode *newNode = meshDS->AddNode(coords[0], coords[1], coords[2]);
11034                       int newId = newNode->getVtkId();
11035                       nodeDomains[oldId][idom] = newId; // cloned node for other domains
11036                       //MESSAGE("   newNode " << newId << " oldNode " << oldId << " size=" <<nodeDomains[oldId].size());
11037                     }
11038                 }
11039             }
11040           if (isMultipleDetected) // check if an edge of the face is shared between 3 or more domains
11041             {
11042               //MESSAGE("multiple Nodes detected on a shared face");
11043               int downId = itface->first.cellId;
11044               unsigned char cellType = itface->first.cellType;
11045               int nbEdges = grid->getDownArray(cellType)->getNumberOfDownCells(downId);
11046               const int *downEdgeIds = grid->getDownArray(cellType)->getDownCells(downId);
11047               const unsigned char* edgeType = grid->getDownArray(cellType)->getDownTypes(downId);
11048               for (int ie =0; ie < nbEdges; ie++)
11049                 {
11050                   int nodes[3];
11051                   int nbNodes = grid->getDownArray(edgeType[ie])->getNodes(downEdgeIds[ie], nodes);
11052                   if (mutipleNodes.count(nodes[0]) && mutipleNodes.count(nodes[nbNodes-1]))
11053                     {
11054                       vector<int> vn0 = mutipleNodes[nodes[0]];
11055                       vector<int> vn1 = mutipleNodes[nodes[nbNodes - 1]];
11056                       sort( vn0.begin(), vn0.end() );
11057                       sort( vn1.begin(), vn1.end() );
11058                       if (vn0 == vn1)
11059                         {
11060                           //MESSAGE(" detect edgesMultiDomains " << nodes[0] << " " << nodes[nbNodes - 1]);
11061                           double *coords = grid->GetPoint(nodes[0]);
11062                           gp_Pnt p0(coords[0], coords[1], coords[2]);
11063                           coords = grid->GetPoint(nodes[nbNodes - 1]);
11064                           gp_Pnt p1(coords[0], coords[1], coords[2]);
11065                           gp_Pnt gref;
11066                           int vtkVolIds[1000];  // an edge can belong to a lot of volumes
11067                           map<int, SMDS_VtkVolume*> domvol; // domain --> a volume with the edge
11068                           map<int, double> angleDom; // oriented angles between planes defined by edge and volume centers
11069                           int nbvol = grid->GetParentVolumes(vtkVolIds, downEdgeIds[ie], edgeType[ie]);
11070                           for (int id=0; id < vn0.size(); id++)
11071                             {
11072                               int idom = vn0[id];
11073                               for (int ivol=0; ivol<nbvol; ivol++)
11074                                 {
11075                                   int smdsId = meshDS->fromVtkToSmds(vtkVolIds[ivol]);
11076                                   SMDS_MeshElement* elem = (SMDS_MeshElement*)meshDS->FindElement(smdsId);
11077                                   if (theElems[idom].count(elem))
11078                                     {
11079                                       SMDS_VtkVolume* svol = dynamic_cast<SMDS_VtkVolume*>(elem);
11080                                       domvol[idom] = svol;
11081                                       //MESSAGE("  domain " << idom << " volume " << elem->GetID());
11082                                       double values[3];
11083                                       vtkIdType npts = 0;
11084                                       vtkIdType* pts = 0;
11085                                       grid->GetCellPoints(vtkVolIds[ivol], npts, pts);
11086                                       SMDS_VtkVolume::gravityCenter(grid, pts, npts, values);
11087                                       if (id ==0)
11088                                         {
11089                                           gref.SetXYZ(gp_XYZ(values[0], values[1], values[2]));
11090                                           angleDom[idom] = 0;
11091                                         }
11092                                       else
11093                                         {
11094                                           gp_Pnt g(values[0], values[1], values[2]);
11095                                           angleDom[idom] = OrientedAngle(p0, p1, gref, g); // -pi<angle<+pi
11096                                           //MESSAGE("  angle=" << angleDom[idom]);
11097                                         }
11098                                       break;
11099                                     }
11100                                 }
11101                             }
11102                           map<double, int> sortedDom; // sort domains by angle
11103                           for (map<int, double>::iterator ia = angleDom.begin(); ia != angleDom.end(); ++ia)
11104                             sortedDom[ia->second] = ia->first;
11105                           vector<int> vnodes;
11106                           vector<int> vdom;
11107                           for (map<double, int>::iterator ib = sortedDom.begin(); ib != sortedDom.end(); ++ib)
11108                             {
11109                               vdom.push_back(ib->second);
11110                               //MESSAGE("  ordered domain " << ib->second << "  angle " << ib->first);
11111                             }
11112                           for (int ino = 0; ino < nbNodes; ino++)
11113                             vnodes.push_back(nodes[ino]);
11114                           edgesMultiDomains[vnodes] = vdom; // nodes vector --> ordered domains
11115                         }
11116                     }
11117                 }
11118             }
11119         }
11120     }
11121
11122   // --- iterate on shared faces (volumes to modify, face to extrude)
11123   //     get node id's of the face (id SMDS = id VTK)
11124   //     create flat element with old and new nodes if requested
11125
11126   // --- new quad nodes on flat quad elements: oldId --> ((domain1 X domain2) --> newId)
11127   //     (domain1 X domain2) = domain1 + MAXINT*domain2
11128
11129   std::map<int, std::map<long,int> > nodeQuadDomains;
11130   std::map<std::string, SMESH_Group*> mapOfJunctionGroups;
11131
11132   if (createJointElems)
11133     {
11134       itface = faceDomains.begin();
11135       for (; itface != faceDomains.end(); ++itface)
11136         {
11137           DownIdType face = itface->first;
11138           std::set<int> oldNodes;
11139           std::set<int>::iterator itn;
11140           oldNodes.clear();
11141           grid->GetNodeIds(oldNodes, face.cellId, face.cellType);
11142
11143           std::map<int, int> domvol = itface->second;
11144           std::map<int, int>::iterator itdom = domvol.begin();
11145           int dom1 = itdom->first;
11146           int vtkVolId = itdom->second;
11147           itdom++;
11148           int dom2 = itdom->first;
11149           SMDS_MeshVolume *vol = grid->extrudeVolumeFromFace(vtkVolId, dom1, dom2, oldNodes, nodeDomains,
11150                                                              nodeQuadDomains);
11151           stringstream grpname;
11152           grpname << "junction_";
11153           if (dom1 < dom2)
11154             grpname << dom1 << "_" << dom2;
11155           else
11156             grpname << dom2 << "_" << dom1;
11157           int idg;
11158           string namegrp = grpname.str();
11159           if (!mapOfJunctionGroups.count(namegrp))
11160             mapOfJunctionGroups[namegrp] = this->myMesh->AddGroup(SMDSAbs_Volume, namegrp.c_str(), idg);
11161           SMESHDS_Group *sgrp = dynamic_cast<SMESHDS_Group*>(mapOfJunctionGroups[namegrp]->GetGroupDS());
11162           if (sgrp)
11163             sgrp->Add(vol->GetID());
11164         }
11165     }
11166
11167   // --- create volumes on multiple domain intersection if requested
11168   //     iterate on edgesMultiDomains
11169
11170   if (createJointElems)
11171     {
11172       std::map<std::vector<int>, std::vector<int> >::iterator ite = edgesMultiDomains.begin();
11173       for (; ite != edgesMultiDomains.end(); ++ite)
11174         {
11175           vector<int> nodes = ite->first;
11176           vector<int> orderDom = ite->second;
11177           vector<vtkIdType> orderedNodes;
11178           if (nodes.size() == 2)
11179             {
11180               //MESSAGE(" use edgesMultiDomains " << nodes[0] << " " << nodes[1]);
11181               for (int ino=0; ino < nodes.size(); ino++)
11182                 if (orderDom.size() == 3)
11183                   for (int idom = 0; idom <orderDom.size(); idom++)
11184                     orderedNodes.push_back( nodeDomains[nodes[ino]][orderDom[idom]] );
11185                 else
11186                   for (int idom = orderDom.size()-1; idom >=0; idom--)
11187                     orderedNodes.push_back( nodeDomains[nodes[ino]][orderDom[idom]] );
11188               SMDS_MeshVolume* vol = this->GetMeshDS()->AddVolumeFromVtkIds(orderedNodes);
11189
11190               stringstream grpname;
11191               grpname << "junction_";
11192               grpname << 0 << "_" << 0;
11193               int idg;
11194               string namegrp = grpname.str();
11195               if (!mapOfJunctionGroups.count(namegrp))
11196                 mapOfJunctionGroups[namegrp] = this->myMesh->AddGroup(SMDSAbs_Volume, namegrp.c_str(), idg);
11197               SMESHDS_Group *sgrp = dynamic_cast<SMESHDS_Group*>(mapOfJunctionGroups[namegrp]->GetGroupDS());
11198               if (sgrp)
11199                 sgrp->Add(vol->GetID());
11200             }
11201           else
11202             {
11203               // TODO quadratic nodes
11204             }
11205         }
11206     }
11207
11208   // --- list the explicit faces and edges of the mesh that need to be modified,
11209   //     i.e. faces and edges built with one or more duplicated nodes.
11210   //     associate these faces or edges to their corresponding domain.
11211   //     only the first domain found is kept when a face or edge is shared
11212
11213   std::map<DownIdType, std::map<int,int>, DownIdCompare> faceOrEdgeDom; // cellToModify --> (id domain --> id cell)
11214   std::map<int,int> feDom; // vtk id of cell to modify --> id domain
11215   faceOrEdgeDom.clear();
11216   feDom.clear();
11217
11218   for (int idomain = 0; idomain < theElems.size(); idomain++)
11219     {
11220       std::map<int, std::map<int, int> >::const_iterator itnod = nodeDomains.begin();
11221       for (; itnod != nodeDomains.end(); ++itnod)
11222         {
11223           int oldId = itnod->first;
11224           //MESSAGE("     node " << oldId);
11225           vtkCellLinks::Link l = grid->GetCellLinks()->GetLink(oldId);
11226           for (int i = 0; i < l.ncells; i++)
11227             {
11228               int vtkId = l.cells[i];
11229               int vtkType = grid->GetCellType(vtkId);
11230               int downId = grid->CellIdToDownId(vtkId);
11231               DownIdType aCell(downId, vtkType);
11232               int volParents[1000];
11233               int nbvol = grid->GetParentVolumes(volParents, vtkId);
11234               for (int j = 0; j < nbvol; j++)
11235                 if (celldom.count(volParents[j]) && (celldom[volParents[j]] == idomain))
11236                   if (!feDom.count(vtkId))
11237                     {
11238                       feDom[vtkId] = idomain;
11239                       faceOrEdgeDom[aCell] = emptyMap;
11240                       faceOrEdgeDom[aCell][idomain] = vtkId; // affect face or edge to the first domain only
11241                       //MESSAGE("affect cell " << this->GetMeshDS()->fromVtkToSmds(vtkId) << " domain " << idomain
11242                       //        << " type " << vtkType << " downId " << downId);
11243                     }
11244             }
11245         }
11246     }
11247
11248   // --- iterate on shared faces (volumes to modify, face to extrude)
11249   //     get node id's of the face
11250   //     replace old nodes by new nodes in volumes, and update inverse connectivity
11251
11252   std::map<DownIdType, std::map<int,int>, DownIdCompare>* maps[3] = {&faceDomains, &cellDomains, &faceOrEdgeDom};
11253   for (int m=0; m<3; m++)
11254     {
11255       std::map<DownIdType, std::map<int,int>, DownIdCompare>* amap = maps[m];
11256       itface = (*amap).begin();
11257       for (; itface != (*amap).end(); ++itface)
11258         {
11259           DownIdType face = itface->first;
11260           std::set<int> oldNodes;
11261           std::set<int>::iterator itn;
11262           oldNodes.clear();
11263           grid->GetNodeIds(oldNodes, face.cellId, face.cellType);
11264           //MESSAGE("examine cell, downId " << face.cellId << " type " << int(face.cellType));
11265           std::map<int, int> localClonedNodeIds;
11266
11267           std::map<int, int> domvol = itface->second;
11268           std::map<int, int>::iterator itdom = domvol.begin();
11269           for (; itdom != domvol.end(); ++itdom)
11270             {
11271               int idom = itdom->first;
11272               int vtkVolId = itdom->second;
11273               //MESSAGE("modify nodes of cell " << this->GetMeshDS()->fromVtkToSmds(vtkVolId) << " domain " << idom);
11274               localClonedNodeIds.clear();
11275               for (itn = oldNodes.begin(); itn != oldNodes.end(); ++itn)
11276                 {
11277                   int oldId = *itn;
11278                   if (nodeDomains[oldId].count(idom))
11279                     {
11280                       localClonedNodeIds[oldId] = nodeDomains[oldId][idom];
11281                       //MESSAGE("     node " << oldId << " --> " << localClonedNodeIds[oldId]);
11282                     }
11283                 }
11284               meshDS->ModifyCellNodes(vtkVolId, localClonedNodeIds);
11285             }
11286         }
11287     }
11288
11289   meshDS->CleanDownWardConnectivity(); // Mesh has been modified, downward connectivity is no more usable, free memory
11290   grid->BuildLinks();
11291
11292   CHRONOSTOP(50);
11293   counters::stats();
11294   return true;
11295 }
11296
11297 /*!
11298  * \brief Double nodes on some external faces and create flat elements.
11299  * Flat elements are mainly used by some types of mechanic calculations.
11300  *
11301  * Each group of the list must be constituted of faces.
11302  * Triangles are transformed in prisms, and quadrangles in hexahedrons.
11303  * @param theElems - list of groups of faces, where a group of faces is a set of
11304  * SMDS_MeshElements sorted by Id.
11305  * @return TRUE if operation has been completed successfully, FALSE otherwise
11306  */
11307 bool SMESH_MeshEditor::CreateFlatElementsOnFacesGroups(const std::vector<TIDSortedElemSet>& theElems)
11308 {
11309   MESSAGE("-------------------------------------------------");
11310   MESSAGE("SMESH_MeshEditor::CreateFlatElementsOnFacesGroups");
11311   MESSAGE("-------------------------------------------------");
11312
11313   SMESHDS_Mesh *meshDS = this->myMesh->GetMeshDS();
11314
11315   // --- For each group of faces
11316   //     duplicate the nodes, create a flat element based on the face
11317   //     replace the nodes of the faces by their clones
11318
11319   std::map<const SMDS_MeshNode*, const SMDS_MeshNode*> clonedNodes;
11320   std::map<const SMDS_MeshNode*, const SMDS_MeshNode*> intermediateNodes;
11321   clonedNodes.clear();
11322   intermediateNodes.clear();
11323
11324   for (int idom = 0; idom < theElems.size(); idom++)
11325     {
11326       const TIDSortedElemSet& domain = theElems[idom];
11327       TIDSortedElemSet::const_iterator elemItr = domain.begin();
11328       for (; elemItr != domain.end(); ++elemItr)
11329         {
11330           SMDS_MeshElement* anElem = (SMDS_MeshElement*) *elemItr;
11331           SMDS_MeshFace* aFace = dynamic_cast<SMDS_MeshFace*> (anElem);
11332           if (!aFace)
11333             continue;
11334           // MESSAGE("aFace=" << aFace->GetID());
11335           bool isQuad = aFace->IsQuadratic();
11336           vector<const SMDS_MeshNode*> ln0, ln1, ln2, ln3, ln4;
11337
11338           // --- clone the nodes, create intermediate nodes for non medium nodes of a quad face
11339
11340           SMDS_ElemIteratorPtr nodeIt = aFace->nodesIterator();
11341           while (nodeIt->more())
11342             {
11343               const SMDS_MeshNode* node = static_cast<const SMDS_MeshNode*> (nodeIt->next());
11344               bool isMedium = isQuad && (aFace->IsMediumNode(node));
11345               if (isMedium)
11346                 ln2.push_back(node);
11347               else
11348                 ln0.push_back(node);
11349
11350               const SMDS_MeshNode* clone = 0;
11351               if (!clonedNodes.count(node))
11352                 {
11353                   clone = meshDS->AddNode(node->X(), node->Y(), node->Z());
11354                   clonedNodes[node] = clone;
11355                 }
11356               else
11357                 clone = clonedNodes[node];
11358
11359               if (isMedium)
11360                 ln3.push_back(clone);
11361               else
11362                 ln1.push_back(clone);
11363
11364               const SMDS_MeshNode* inter = 0;
11365               if (isQuad && (!isMedium))
11366                 {
11367                   if (!intermediateNodes.count(node))
11368                     {
11369                       inter = meshDS->AddNode(node->X(), node->Y(), node->Z());
11370                       intermediateNodes[node] = inter;
11371                     }
11372                   else
11373                     inter = intermediateNodes[node];
11374                   ln4.push_back(inter);
11375                 }
11376             }
11377
11378           // --- extrude the face
11379
11380           vector<const SMDS_MeshNode*> ln;
11381           SMDS_MeshVolume* vol = 0;
11382           vtkIdType aType = aFace->GetVtkType();
11383           switch (aType)
11384           {
11385             case VTK_TRIANGLE:
11386               vol = meshDS->AddVolume(ln0[2], ln0[1], ln0[0], ln1[2], ln1[1], ln1[0]);
11387               // MESSAGE("vol prism " << vol->GetID());
11388               ln.push_back(ln1[0]);
11389               ln.push_back(ln1[1]);
11390               ln.push_back(ln1[2]);
11391               break;
11392             case VTK_QUAD:
11393               vol = meshDS->AddVolume(ln0[3], ln0[2], ln0[1], ln0[0], ln1[3], ln1[2], ln1[1], ln1[0]);
11394               // MESSAGE("vol hexa " << vol->GetID());
11395               ln.push_back(ln1[0]);
11396               ln.push_back(ln1[1]);
11397               ln.push_back(ln1[2]);
11398               ln.push_back(ln1[3]);
11399               break;
11400             case VTK_QUADRATIC_TRIANGLE:
11401               vol = meshDS->AddVolume(ln1[0], ln1[1], ln1[2], ln0[0], ln0[1], ln0[2], ln3[0], ln3[1], ln3[2],
11402                                       ln2[0], ln2[1], ln2[2], ln4[0], ln4[1], ln4[2]);
11403               // MESSAGE("vol quad prism " << vol->GetID());
11404               ln.push_back(ln1[0]);
11405               ln.push_back(ln1[1]);
11406               ln.push_back(ln1[2]);
11407               ln.push_back(ln3[0]);
11408               ln.push_back(ln3[1]);
11409               ln.push_back(ln3[2]);
11410               break;
11411             case VTK_QUADRATIC_QUAD:
11412 //              vol = meshDS->AddVolume(ln0[0], ln0[1], ln0[2], ln0[3], ln1[0], ln1[1], ln1[2], ln1[3],
11413 //                                      ln2[0], ln2[1], ln2[2], ln2[3], ln3[0], ln3[1], ln3[2], ln3[3],
11414 //                                      ln4[0], ln4[1], ln4[2], ln4[3]);
11415               vol = meshDS->AddVolume(ln1[0], ln1[1], ln1[2], ln1[3], ln0[0], ln0[1], ln0[2], ln0[3],
11416                                       ln3[0], ln3[1], ln3[2], ln3[3], ln2[0], ln2[1], ln2[2], ln2[3],
11417                                       ln4[0], ln4[1], ln4[2], ln4[3]);
11418               // MESSAGE("vol quad hexa " << vol->GetID());
11419               ln.push_back(ln1[0]);
11420               ln.push_back(ln1[1]);
11421               ln.push_back(ln1[2]);
11422               ln.push_back(ln1[3]);
11423               ln.push_back(ln3[0]);
11424               ln.push_back(ln3[1]);
11425               ln.push_back(ln3[2]);
11426               ln.push_back(ln3[3]);
11427               break;
11428             case VTK_POLYGON:
11429               break;
11430             default:
11431               break;
11432           }
11433
11434           // --- modify the face
11435
11436           aFace->ChangeNodes(&ln[0], ln.size());
11437         }
11438     }
11439   return true;
11440 }
11441
11442 //================================================================================
11443 /*!
11444  * \brief Generates skin mesh (containing 2D cells) from 3D mesh
11445  * The created 2D mesh elements based on nodes of free faces of boundary volumes
11446  * \return TRUE if operation has been completed successfully, FALSE otherwise
11447  */
11448 //================================================================================
11449
11450 bool SMESH_MeshEditor::Make2DMeshFrom3D()
11451 {
11452   // iterates on volume elements and detect all free faces on them
11453   SMESHDS_Mesh* aMesh = GetMeshDS();
11454   if (!aMesh)
11455     return false;
11456   //bool res = false;
11457   int nbFree = 0, nbExisted = 0, nbCreated = 0;
11458   SMDS_VolumeIteratorPtr vIt = aMesh->volumesIterator();
11459   while(vIt->more())
11460   {
11461     const SMDS_MeshVolume* volume = vIt->next();
11462     SMDS_VolumeTool vTool( volume );
11463     vTool.SetExternalNormal();
11464     const bool isPoly = volume->IsPoly();
11465     const bool isQuad = volume->IsQuadratic();
11466     for ( int iface = 0, n = vTool.NbFaces(); iface < n; iface++ )
11467     {
11468       if (!vTool.IsFreeFace(iface))
11469         continue;
11470       nbFree++;
11471       vector<const SMDS_MeshNode *> nodes;
11472       int nbFaceNodes = vTool.NbFaceNodes(iface);
11473       const SMDS_MeshNode** faceNodes = vTool.GetFaceNodes(iface);
11474       int inode = 0;
11475       for ( ; inode < nbFaceNodes; inode += isQuad ? 2 : 1)
11476         nodes.push_back(faceNodes[inode]);
11477       if (isQuad)
11478         for ( inode = 1; inode < nbFaceNodes; inode += 2)
11479           nodes.push_back(faceNodes[inode]);
11480
11481       // add new face based on volume nodes
11482       if (aMesh->FindFace( nodes ) ) {
11483         nbExisted++;
11484         continue; // face already exsist
11485       }
11486       AddElement(nodes, SMDSAbs_Face, isPoly && iface == 1);
11487       nbCreated++;
11488     }
11489   }
11490   return ( nbFree==(nbExisted+nbCreated) );
11491 }
11492
11493 namespace
11494 {
11495   inline const SMDS_MeshNode* getNodeWithSameID(SMESHDS_Mesh* mesh, const SMDS_MeshNode* node)
11496   {
11497     if ( const SMDS_MeshNode* n = mesh->FindNode( node->GetID() ))
11498       return n;
11499     return mesh->AddNodeWithID( node->X(),node->Y(),node->Z(), node->GetID() );
11500   }
11501 }
11502 //================================================================================
11503 /*!
11504  * \brief Creates missing boundary elements
11505  *  \param elements - elements whose boundary is to be checked
11506  *  \param dimension - defines type of boundary elements to create
11507  *  \param group - a group to store created boundary elements in
11508  *  \param targetMesh - a mesh to store created boundary elements in
11509  *  \param toCopyElements - if true, the checked elements will be copied into the targetMesh
11510  *  \param toCopyExistingBondary - if true, not only new but also pre-existing
11511  *                                boundary elements will be copied into the targetMesh
11512  *  \param toAddExistingBondary - if true, not only new but also pre-existing
11513  *                                boundary elements will be added into the new group
11514  *  \param aroundElements - if true, elements will be created on boundary of given
11515  *                          elements else, on boundary of the whole mesh. This
11516  *                          option works for 2D elements only.
11517  * \return nb of added boundary elements
11518  */
11519 //================================================================================
11520
11521 int SMESH_MeshEditor::MakeBoundaryMesh(const TIDSortedElemSet& elements,
11522                                        Bnd_Dimension           dimension,
11523                                        SMESH_Group*            group/*=0*/,
11524                                        SMESH_Mesh*             targetMesh/*=0*/,
11525                                        bool                    toCopyElements/*=false*/,
11526                                        bool                    toCopyExistingBondary/*=false*/,
11527                                        bool                    toAddExistingBondary/*= false*/,
11528                                        bool                    aroundElements/*= false*/)
11529 {
11530   SMDSAbs_ElementType missType = (dimension == BND_2DFROM3D) ? SMDSAbs_Face : SMDSAbs_Edge;
11531   SMDSAbs_ElementType elemType = (dimension == BND_1DFROM2D) ? SMDSAbs_Face : SMDSAbs_Volume;
11532   // hope that all elements are of the same type, do not check them all
11533   if ( !elements.empty() && (*elements.begin())->GetType() != elemType )
11534     throw SALOME_Exception(LOCALIZED("wrong element type"));
11535
11536   if ( aroundElements && elemType == SMDSAbs_Volume )
11537     throw SALOME_Exception(LOCALIZED("wrong element type for aroundElements==true"));
11538
11539   if ( !targetMesh )
11540     toCopyElements = toCopyExistingBondary = false;
11541
11542   SMESH_MeshEditor tgtEditor( targetMesh ? targetMesh : myMesh );
11543   SMESHDS_Mesh* aMesh = GetMeshDS(), *tgtMeshDS = tgtEditor.GetMeshDS();
11544   int nbAddedBnd = 0;
11545
11546   // editor adding present bnd elements and optionally holding elements to add to the group
11547   SMESH_MeshEditor* presentEditor;
11548   SMESH_MeshEditor tgtEditor2( tgtEditor.GetMesh() );
11549   presentEditor = toAddExistingBondary ? &tgtEditor : &tgtEditor2;
11550
11551   SMDS_VolumeTool vTool;
11552   TIDSortedElemSet avoidSet;
11553   const TIDSortedElemSet emptySet, *elemSet = aroundElements ? &elements : &emptySet;
11554   int inode;
11555
11556   typedef vector<const SMDS_MeshNode*> TConnectivity;
11557
11558   SMDS_ElemIteratorPtr eIt;
11559   if (elements.empty())
11560     eIt = aMesh->elementsIterator(elemType);
11561   else
11562     eIt = SMDS_ElemIteratorPtr( new TSetIterator( elements.begin(), elements.end() ));
11563
11564   while (eIt->more())
11565   {
11566     const SMDS_MeshElement* elem = eIt->next();
11567     const int iQuad = elem->IsQuadratic();
11568
11569     // ------------------------------------------------------------------------------------
11570     // 1. For an elem, get present bnd elements and connectivities of missing bnd elements
11571     // ------------------------------------------------------------------------------------
11572     vector<const SMDS_MeshElement*> presentBndElems;
11573     vector<TConnectivity>           missingBndElems;
11574     TConnectivity nodes;
11575     if ( vTool.Set(elem) ) // elem is a volume ------------------------------------------
11576     {
11577       vTool.SetExternalNormal();
11578       for ( int iface = 0, n = vTool.NbFaces(); iface < n; iface++ )
11579       {
11580         if (!vTool.IsFreeFace(iface))
11581           continue;
11582         int nbFaceNodes = vTool.NbFaceNodes(iface);
11583         const SMDS_MeshNode** nn = vTool.GetFaceNodes(iface);
11584         if ( missType == SMDSAbs_Edge ) // boundary edges
11585         {
11586           nodes.resize( 2+iQuad );
11587           for ( int i = 0; i < nbFaceNodes; i += 1+iQuad)
11588           {
11589             for ( int j = 0; j < nodes.size(); ++j )
11590               nodes[j] =nn[i+j];
11591             if ( const SMDS_MeshElement* edge =
11592                  aMesh->FindElement(nodes,SMDSAbs_Edge,/*noMedium=*/0))
11593               presentBndElems.push_back( edge );
11594             else
11595               missingBndElems.push_back( nodes );
11596           }
11597         }
11598         else // boundary face
11599         {
11600           nodes.clear();
11601           for ( inode = 0; inode < nbFaceNodes; inode += 1+iQuad)
11602             nodes.push_back( nn[inode] );
11603           if (iQuad)
11604             for ( inode = 1; inode < nbFaceNodes; inode += 2)
11605               nodes.push_back( nn[inode] );
11606
11607           if (const SMDS_MeshFace * f = aMesh->FindFace( nodes ) )
11608             presentBndElems.push_back( f );
11609           else
11610             missingBndElems.push_back( nodes );
11611         }
11612       }
11613     }
11614     else                     // elem is a face ------------------------------------------
11615     {
11616       avoidSet.clear(), avoidSet.insert( elem );
11617       int nbNodes = elem->NbCornerNodes();
11618       nodes.resize( 2 /*+ iQuad*/);
11619       for ( int i = 0; i < nbNodes; i++ )
11620       {
11621         nodes[0] = elem->GetNode(i);
11622         nodes[1] = elem->GetNode((i+1)%nbNodes);
11623         if ( FindFaceInSet( nodes[0], nodes[1], *elemSet, avoidSet))
11624           continue; // not free link
11625
11626         //if ( iQuad )
11627         //nodes[2] = elem->GetNode( i + nbNodes );
11628         if ( const SMDS_MeshElement* edge =
11629              aMesh->FindElement(nodes,SMDSAbs_Edge,/*noMedium=*/true))
11630           presentBndElems.push_back( edge );
11631         else
11632           missingBndElems.push_back( nodes );
11633       }
11634     }
11635
11636     // ---------------------------------
11637     // 2. Add missing boundary elements
11638     // ---------------------------------
11639     if ( targetMesh != myMesh )
11640       // instead of making a map of nodes in this mesh and targetMesh,
11641       // we create nodes with same IDs. We can renumber them later, if needed
11642       for ( int i = 0; i < missingBndElems.size(); ++i )
11643       {
11644         TConnectivity& srcNodes = missingBndElems[i];
11645         TConnectivity  nodes( srcNodes.size() );
11646         for ( inode = 0; inode < nodes.size(); ++inode )
11647           nodes[inode] = getNodeWithSameID( tgtMeshDS, srcNodes[inode] );
11648         if ( aroundElements && tgtEditor.GetMeshDS()->FindElement( nodes,
11649                                                                    missType,
11650                                                                    /*noMedium=*/true))
11651           continue;
11652         tgtEditor.AddElement(nodes, missType, elem->IsPoly() && nodes.size()/(iQuad+1)>4);
11653         ++nbAddedBnd;
11654       }
11655     else
11656       for ( int i = 0; i < missingBndElems.size(); ++i )
11657       {
11658         TConnectivity& nodes = missingBndElems[i];
11659         if ( aroundElements && tgtEditor.GetMeshDS()->FindElement( nodes,
11660                                                                    missType,
11661                                                                    /*noMedium=*/true))
11662           continue;
11663         tgtEditor.AddElement(nodes, missType, elem->IsPoly() && nodes.size()/(iQuad+1)>4);
11664         ++nbAddedBnd;
11665       }
11666
11667     // ----------------------------------
11668     // 3. Copy present boundary elements
11669     // ----------------------------------
11670     if ( toCopyExistingBondary )
11671       for ( int i = 0 ; i < presentBndElems.size(); ++i )
11672       {
11673         const SMDS_MeshElement* e = presentBndElems[i];
11674         TConnectivity nodes( e->NbNodes() );
11675         for ( inode = 0; inode < nodes.size(); ++inode )
11676           nodes[inode] = getNodeWithSameID( tgtMeshDS, e->GetNode(inode) );
11677         presentEditor->AddElement(nodes, missType, e->IsPoly());
11678       }
11679     else // store present elements to add them to a group
11680       for ( int i = 0 ; i < presentBndElems.size(); ++i )
11681       {
11682         presentEditor->myLastCreatedElems.Append(presentBndElems[i]);
11683       }
11684       
11685   } // loop on given elements
11686
11687   // ---------------------------------------------
11688   // 4. Fill group with boundary elements
11689   // ---------------------------------------------
11690   if ( group )
11691   {
11692     if ( SMESHDS_Group* g = dynamic_cast<SMESHDS_Group*>( group->GetGroupDS() ))
11693       for ( int i = 0; i < tgtEditor.myLastCreatedElems.Size(); ++i )
11694         g->SMDSGroup().Add( tgtEditor.myLastCreatedElems( i+1 ));
11695   }
11696   tgtEditor.myLastCreatedElems.Clear();
11697   tgtEditor2.myLastCreatedElems.Clear();
11698
11699   // -----------------------
11700   // 5. Copy given elements
11701   // -----------------------
11702   if ( toCopyElements && targetMesh != myMesh )
11703   {
11704     if (elements.empty())
11705       eIt = aMesh->elementsIterator(elemType);
11706     else
11707       eIt = SMDS_ElemIteratorPtr( new TSetIterator( elements.begin(), elements.end() ));
11708     while (eIt->more())
11709     {
11710       const SMDS_MeshElement* elem = eIt->next();
11711       TConnectivity nodes( elem->NbNodes() );
11712       for ( inode = 0; inode < nodes.size(); ++inode )
11713         nodes[inode] = getNodeWithSameID( tgtMeshDS, elem->GetNode(inode) );
11714       tgtEditor.AddElement(nodes, elemType, elem->IsPoly());
11715
11716       tgtEditor.myLastCreatedElems.Clear();
11717     }
11718   }
11719   return nbAddedBnd;
11720 }