Salome HOME
PR: fix Transform method with orphan nodes
[modules/smesh.git] / src / SMESH / SMESH_MeshEditor.cxx
1 //  Copyright (C) 2007-2010  CEA/DEN, EDF R&D, OPEN CASCADE
2 //
3 //  Copyright (C) 2003-2007  OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN,
4 //  CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS
5 //
6 //  This library is free software; you can redistribute it and/or
7 //  modify it under the terms of the GNU Lesser General Public
8 //  License as published by the Free Software Foundation; either
9 //  version 2.1 of the License.
10 //
11 //  This library is distributed in the hope that it will be useful,
12 //  but WITHOUT ANY WARRANTY; without even the implied warranty of
13 //  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14 //  Lesser General Public License for more details.
15 //
16 //  You should have received a copy of the GNU Lesser General Public
17 //  License along with this library; if not, write to the Free Software
18 //  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
19 //
20 //  See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
21 //
22
23 //  SMESH SMESH : idl implementation based on 'SMESH' unit's classes
24 // File      : SMESH_MeshEditor.cxx
25 // Created   : Mon Apr 12 16:10:22 2004
26 // Author    : Edward AGAPOV (eap)
27 //
28 #define CHRONODEF
29 #include "SMESH_MeshEditor.hxx"
30
31 #include "SMDS_FaceOfNodes.hxx"
32 #include "SMDS_VolumeTool.hxx"
33 #include "SMDS_EdgePosition.hxx"
34 #include "SMDS_PolyhedralVolumeOfNodes.hxx"
35 #include "SMDS_FacePosition.hxx"
36 #include "SMDS_SpacePosition.hxx"
37 //#include "SMDS_QuadraticFaceOfNodes.hxx"
38 #include "SMDS_MeshGroup.hxx"
39 #include "SMDS_LinearEdge.hxx"
40 #include "SMDS_Downward.hxx"
41 #include "SMDS_SetIterator.hxx"
42
43 #include "SMESHDS_Group.hxx"
44 #include "SMESHDS_Mesh.hxx"
45
46 #include "SMESH_Algo.hxx"
47 #include "SMESH_ControlsDef.hxx"
48 #include "SMESH_Group.hxx"
49 #include "SMESH_MesherHelper.hxx"
50 #include "SMESH_OctreeNode.hxx"
51 #include "SMESH_subMesh.hxx"
52
53 #include "utilities.h"
54
55 #include <BRepAdaptor_Surface.hxx>
56 #include <BRepClass3d_SolidClassifier.hxx>
57 #include <BRep_Tool.hxx>
58 #include <ElCLib.hxx>
59 #include <Extrema_GenExtPS.hxx>
60 #include <Extrema_POnCurv.hxx>
61 #include <Extrema_POnSurf.hxx>
62 #include <GC_MakeSegment.hxx>
63 #include <Geom2d_Curve.hxx>
64 #include <GeomAPI_ExtremaCurveCurve.hxx>
65 #include <GeomAdaptor_Surface.hxx>
66 #include <Geom_Curve.hxx>
67 #include <Geom_Line.hxx>
68 #include <Geom_Surface.hxx>
69 #include <IntAna_IntConicQuad.hxx>
70 #include <IntAna_Quadric.hxx>
71 #include <Precision.hxx>
72 #include <TColStd_ListOfInteger.hxx>
73 #include <TopAbs_State.hxx>
74 #include <TopExp.hxx>
75 #include <TopExp_Explorer.hxx>
76 #include <TopTools_ListIteratorOfListOfShape.hxx>
77 #include <TopTools_ListOfShape.hxx>
78 #include <TopTools_SequenceOfShape.hxx>
79 #include <TopoDS.hxx>
80 #include <TopoDS_Face.hxx>
81 #include <gp.hxx>
82 #include <gp_Ax1.hxx>
83 #include <gp_Dir.hxx>
84 #include <gp_Lin.hxx>
85 #include <gp_Pln.hxx>
86 #include <gp_Trsf.hxx>
87 #include <gp_Vec.hxx>
88 #include <gp_XY.hxx>
89 #include <gp_XYZ.hxx>
90
91 #include <math.h>
92
93 #include <map>
94 #include <set>
95 #include <numeric>
96 #include <limits>
97
98 #define cast2Node(elem) static_cast<const SMDS_MeshNode*>( elem )
99
100 using namespace std;
101 using namespace SMESH::Controls;
102
103 typedef map<const SMDS_MeshElement*, list<const SMDS_MeshNode*> >    TElemOfNodeListMap;
104 typedef map<const SMDS_MeshElement*, list<const SMDS_MeshElement*> > TElemOfElemListMap;
105
106 typedef SMDS_SetIterator< SMDS_pElement, TIDSortedElemSet::const_iterator> TSetIterator;
107
108 //=======================================================================
109 //function : SMESH_MeshEditor
110 //purpose  :
111 //=======================================================================
112
113 SMESH_MeshEditor::SMESH_MeshEditor( SMESH_Mesh* theMesh )
114   :myMesh( theMesh ) // theMesh may be NULL
115 {
116 }
117
118 //=======================================================================
119 /*!
120  * \brief Add element
121  */
122 //=======================================================================
123
124 SMDS_MeshElement*
125 SMESH_MeshEditor::AddElement(const vector<const SMDS_MeshNode*> & node,
126                              const SMDSAbs_ElementType            type,
127                              const bool                           isPoly,
128                              const int                            ID)
129 {
130   //MESSAGE("AddElement " <<node.size() << " " << type << " " << isPoly << " " << ID);
131   SMDS_MeshElement* e = 0;
132   int nbnode = node.size();
133   SMESHDS_Mesh* mesh = GetMeshDS();
134   switch ( type ) {
135   case SMDSAbs_0DElement:
136     if ( nbnode == 1 ) {
137       if ( ID >= 0 ) e = mesh->Add0DElementWithID(node[0], ID);
138       else      e = mesh->Add0DElement      (node[0] );
139     }
140     break;
141   case SMDSAbs_Edge:
142     if ( nbnode == 2 ) {
143       if ( ID >= 0 ) e = mesh->AddEdgeWithID(node[0], node[1], ID);
144       else      e = mesh->AddEdge      (node[0], node[1] );
145     }
146     else if ( nbnode == 3 ) {
147       if ( ID >= 0 ) e = mesh->AddEdgeWithID(node[0], node[1], node[2], ID);
148       else      e = mesh->AddEdge      (node[0], node[1], node[2] );
149     }
150     break;
151   case SMDSAbs_Face:
152     if ( !isPoly ) {
153       if      (nbnode == 3) {
154         if ( ID >= 0 ) e = mesh->AddFaceWithID(node[0], node[1], node[2], ID);
155         else      e = mesh->AddFace      (node[0], node[1], node[2] );
156       }
157       else if (nbnode == 4) {
158         if ( ID >= 0 ) e = mesh->AddFaceWithID(node[0], node[1], node[2], node[3], ID);
159         else      e = mesh->AddFace      (node[0], node[1], node[2], node[3] );
160       }
161       else if (nbnode == 6) {
162         if ( ID >= 0 ) e = mesh->AddFaceWithID(node[0], node[1], node[2], node[3],
163                                           node[4], node[5], ID);
164         else      e = mesh->AddFace      (node[0], node[1], node[2], node[3],
165                                           node[4], node[5] );
166       }
167       else if (nbnode == 8) {
168         if ( ID >= 0 ) e = mesh->AddFaceWithID(node[0], node[1], node[2], node[3],
169                                           node[4], node[5], node[6], node[7], ID);
170         else      e = mesh->AddFace      (node[0], node[1], node[2], node[3],
171                                           node[4], node[5], node[6], node[7] );
172       }
173     } else {
174       if ( ID >= 0 ) e = mesh->AddPolygonalFaceWithID(node, ID);
175       else      e = mesh->AddPolygonalFace      (node    );
176     }
177     break;
178   case SMDSAbs_Volume:
179     if ( !isPoly ) {
180       if      (nbnode == 4) {
181         if ( ID >= 0 ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3], ID);
182         else      e = mesh->AddVolume      (node[0], node[1], node[2], node[3] );
183       }
184       else if (nbnode == 5) {
185         if ( ID >= 0 ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
186                                             node[4], ID);
187         else      e = mesh->AddVolume      (node[0], node[1], node[2], node[3],
188                                             node[4] );
189       }
190       else if (nbnode == 6) {
191         if ( ID >= 0 ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
192                                             node[4], node[5], ID);
193         else      e = mesh->AddVolume      (node[0], node[1], node[2], node[3],
194                                             node[4], node[5] );
195       }
196       else if (nbnode == 8) {
197         if ( ID >= 0 ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
198                                             node[4], node[5], node[6], node[7], ID);
199         else      e = mesh->AddVolume      (node[0], node[1], node[2], node[3],
200                                             node[4], node[5], node[6], node[7] );
201       }
202       else if (nbnode == 10) {
203         if ( ID >= 0 ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
204                                             node[4], node[5], node[6], node[7],
205                                             node[8], node[9], ID);
206         else      e = mesh->AddVolume      (node[0], node[1], node[2], node[3],
207                                             node[4], node[5], node[6], node[7],
208                                             node[8], node[9] );
209       }
210       else if (nbnode == 13) {
211         if ( ID >= 0 ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
212                                             node[4], node[5], node[6], node[7],
213                                             node[8], node[9], node[10],node[11],
214                                             node[12],ID);
215         else      e = mesh->AddVolume      (node[0], node[1], node[2], node[3],
216                                             node[4], node[5], node[6], node[7],
217                                             node[8], node[9], node[10],node[11],
218                                             node[12] );
219       }
220       else if (nbnode == 15) {
221         if ( ID >= 0 ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
222                                             node[4], node[5], node[6], node[7],
223                                             node[8], node[9], node[10],node[11],
224                                             node[12],node[13],node[14],ID);
225         else      e = mesh->AddVolume      (node[0], node[1], node[2], node[3],
226                                             node[4], node[5], node[6], node[7],
227                                             node[8], node[9], node[10],node[11],
228                                             node[12],node[13],node[14] );
229       }
230       else if (nbnode == 20) {
231         if ( ID >= 0 ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
232                                             node[4], node[5], node[6], node[7],
233                                             node[8], node[9], node[10],node[11],
234                                             node[12],node[13],node[14],node[15],
235                                             node[16],node[17],node[18],node[19],ID);
236         else      e = mesh->AddVolume      (node[0], node[1], node[2], node[3],
237                                             node[4], node[5], node[6], node[7],
238                                             node[8], node[9], node[10],node[11],
239                                             node[12],node[13],node[14],node[15],
240                                             node[16],node[17],node[18],node[19] );
241       }
242     }
243   }
244   if ( e ) myLastCreatedElems.Append( e );
245   return e;
246 }
247
248 //=======================================================================
249 /*!
250  * \brief Add element
251  */
252 //=======================================================================
253
254 SMDS_MeshElement* SMESH_MeshEditor::AddElement(const vector<int> &       nodeIDs,
255                                                const SMDSAbs_ElementType type,
256                                                const bool                isPoly,
257                                                const int                 ID)
258 {
259   vector<const SMDS_MeshNode*> nodes;
260   nodes.reserve( nodeIDs.size() );
261   vector<int>::const_iterator id = nodeIDs.begin();
262   while ( id != nodeIDs.end() ) {
263     if ( const SMDS_MeshNode* node = GetMeshDS()->FindNode( *id++ ))
264       nodes.push_back( node );
265     else
266       return 0;
267   }
268   return AddElement( nodes, type, isPoly, ID );
269 }
270
271 //=======================================================================
272 //function : Remove
273 //purpose  : Remove a node or an element.
274 //           Modify a compute state of sub-meshes which become empty
275 //=======================================================================
276
277 int SMESH_MeshEditor::Remove (const list< int >& theIDs,
278                               const bool         isNodes )
279 {
280   myLastCreatedElems.Clear();
281   myLastCreatedNodes.Clear();
282
283   SMESHDS_Mesh* aMesh = GetMeshDS();
284   set< SMESH_subMesh *> smmap;
285
286   int removed = 0;
287   list<int>::const_iterator it = theIDs.begin();
288   for ( ; it != theIDs.end(); it++ ) {
289     const SMDS_MeshElement * elem;
290     if ( isNodes )
291       elem = aMesh->FindNode( *it );
292     else
293       elem = aMesh->FindElement( *it );
294     if ( !elem )
295       continue;
296
297     // Notify VERTEX sub-meshes about modification
298     if ( isNodes ) {
299       const SMDS_MeshNode* node = cast2Node( elem );
300       if ( node->GetPosition()->GetTypeOfPosition() == SMDS_TOP_VERTEX )
301         if ( int aShapeID = node->getshapeId() )
302           if ( SMESH_subMesh * sm = GetMesh()->GetSubMeshContaining( aShapeID ) )
303             smmap.insert( sm );
304     }
305     // Find sub-meshes to notify about modification
306     //     SMDS_ElemIteratorPtr nodeIt = elem->nodesIterator();
307     //     while ( nodeIt->more() ) {
308     //       const SMDS_MeshNode* node = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
309     //       const SMDS_PositionPtr& aPosition = node->GetPosition();
310     //       if ( aPosition.get() ) {
311     //         if ( int aShapeID = aPosition->GetShapeId() ) {
312     //           if ( SMESH_subMesh * sm = GetMesh()->GetSubMeshContaining( aShapeID ) )
313     //             smmap.insert( sm );
314     //         }
315     //       }
316     //     }
317
318     // Do remove
319     if ( isNodes )
320       aMesh->RemoveNode( static_cast< const SMDS_MeshNode* >( elem ));
321     else
322       aMesh->RemoveElement( elem );
323     removed++;
324   }
325
326   // Notify sub-meshes about modification
327   if ( !smmap.empty() ) {
328     set< SMESH_subMesh *>::iterator smIt;
329     for ( smIt = smmap.begin(); smIt != smmap.end(); smIt++ )
330       (*smIt)->ComputeStateEngine( SMESH_subMesh::MESH_ENTITY_REMOVED );
331   }
332
333   //   // Check if the whole mesh becomes empty
334   //   if ( SMESH_subMesh * sm = GetMesh()->GetSubMeshContaining( 1 ) )
335   //     sm->ComputeStateEngine( SMESH_subMesh::CHECK_COMPUTE_STATE );
336
337   return removed;
338 }
339
340 //=======================================================================
341 //function : FindShape
342 //purpose  : Return an index of the shape theElem is on
343 //           or zero if a shape not found
344 //=======================================================================
345
346 int SMESH_MeshEditor::FindShape (const SMDS_MeshElement * theElem)
347 {
348   myLastCreatedElems.Clear();
349   myLastCreatedNodes.Clear();
350
351   SMESHDS_Mesh * aMesh = GetMeshDS();
352   if ( aMesh->ShapeToMesh().IsNull() )
353     return 0;
354
355   if ( theElem->GetType() == SMDSAbs_Node )
356     {
357       int aShapeID = theElem->getshapeId();
358       if (aShapeID <= 0)
359         return 0;
360       else
361         return aShapeID;
362     }
363
364   TopoDS_Shape aShape; // the shape a node is on
365   SMDS_ElemIteratorPtr nodeIt = theElem->nodesIterator();
366   while ( nodeIt->more() ) {
367     const SMDS_MeshNode* node = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
368     int aShapeID = node->getshapeId();
369     if (aShapeID > 0) {
370       SMESHDS_SubMesh * sm = aMesh->MeshElements( aShapeID );
371       if ( sm ) {
372         if ( sm->Contains( theElem ))
373           return aShapeID;
374         if ( aShape.IsNull() )
375           aShape = aMesh->IndexToShape( aShapeID );
376       }
377       else {
378         //MESSAGE ( "::FindShape() No SubShape for aShapeID " << aShapeID );
379       }
380     }
381   }
382
383   // None of nodes is on a proper shape,
384   // find the shape among ancestors of aShape on which a node is
385   if ( aShape.IsNull() ) {
386     //MESSAGE ("::FindShape() - NONE node is on shape")
387     return 0;
388   }
389   TopTools_ListIteratorOfListOfShape ancIt( GetMesh()->GetAncestors( aShape ));
390   for ( ; ancIt.More(); ancIt.Next() ) {
391     SMESHDS_SubMesh * sm = aMesh->MeshElements( ancIt.Value() );
392     if ( sm && sm->Contains( theElem ))
393       return aMesh->ShapeToIndex( ancIt.Value() );
394   }
395
396   //MESSAGE ("::FindShape() - SHAPE NOT FOUND")
397   return 0;
398 }
399
400 //=======================================================================
401 //function : IsMedium
402 //purpose  :
403 //=======================================================================
404
405 bool SMESH_MeshEditor::IsMedium(const SMDS_MeshNode*      node,
406                                 const SMDSAbs_ElementType typeToCheck)
407 {
408   bool isMedium = false;
409   SMDS_ElemIteratorPtr it = node->GetInverseElementIterator(typeToCheck);
410   while (it->more() && !isMedium ) {
411     const SMDS_MeshElement* elem = it->next();
412     isMedium = elem->IsMediumNode(node);
413   }
414   return isMedium;
415 }
416
417 //=======================================================================
418 //function : ShiftNodesQuadTria
419 //purpose  : auxilary
420 //           Shift nodes in the array corresponded to quadratic triangle
421 //           example: (0,1,2,3,4,5) -> (1,2,0,4,5,3)
422 //=======================================================================
423 static void ShiftNodesQuadTria(const SMDS_MeshNode* aNodes[])
424 {
425   const SMDS_MeshNode* nd1 = aNodes[0];
426   aNodes[0] = aNodes[1];
427   aNodes[1] = aNodes[2];
428   aNodes[2] = nd1;
429   const SMDS_MeshNode* nd2 = aNodes[3];
430   aNodes[3] = aNodes[4];
431   aNodes[4] = aNodes[5];
432   aNodes[5] = nd2;
433 }
434
435 //=======================================================================
436 //function : GetNodesFromTwoTria
437 //purpose  : auxilary
438 //           Shift nodes in the array corresponded to quadratic triangle
439 //           example: (0,1,2,3,4,5) -> (1,2,0,4,5,3)
440 //=======================================================================
441 static bool GetNodesFromTwoTria(const SMDS_MeshElement * theTria1,
442                                 const SMDS_MeshElement * theTria2,
443                                 const SMDS_MeshNode* N1[],
444                                 const SMDS_MeshNode* N2[])
445 {
446   SMDS_ElemIteratorPtr it = theTria1->nodesIterator();
447   int i=0;
448   while(i<6) {
449     N1[i] = static_cast<const SMDS_MeshNode*>( it->next() );
450     i++;
451   }
452   if(it->more()) return false;
453   it = theTria2->nodesIterator();
454   i=0;
455   while(i<6) {
456     N2[i] = static_cast<const SMDS_MeshNode*>( it->next() );
457     i++;
458   }
459   if(it->more()) return false;
460
461   int sames[3] = {-1,-1,-1};
462   int nbsames = 0;
463   int j;
464   for(i=0; i<3; i++) {
465     for(j=0; j<3; j++) {
466       if(N1[i]==N2[j]) {
467         sames[i] = j;
468         nbsames++;
469         break;
470       }
471     }
472   }
473   if(nbsames!=2) return false;
474   if(sames[0]>-1) {
475     ShiftNodesQuadTria(N1);
476     if(sames[1]>-1) {
477       ShiftNodesQuadTria(N1);
478     }
479   }
480   i = sames[0] + sames[1] + sames[2];
481   for(; i<2; i++) {
482     ShiftNodesQuadTria(N2);
483   }
484   // now we receive following N1 and N2 (using numeration as above image)
485   // tria1 : (1 2 4 5 9 7)  and  tria2 : (3 4 2 8 9 6)
486   // i.e. first nodes from both arrays determ new diagonal
487   return true;
488 }
489
490 //=======================================================================
491 //function : InverseDiag
492 //purpose  : Replace two neighbour triangles with ones built on the same 4 nodes
493 //           but having other common link.
494 //           Return False if args are improper
495 //=======================================================================
496
497 bool SMESH_MeshEditor::InverseDiag (const SMDS_MeshElement * theTria1,
498                                     const SMDS_MeshElement * theTria2 )
499 {
500   MESSAGE("InverseDiag");
501   myLastCreatedElems.Clear();
502   myLastCreatedNodes.Clear();
503
504   if (!theTria1 || !theTria2)
505     return false;
506
507   const SMDS_VtkFace* F1 = dynamic_cast<const SMDS_VtkFace*>( theTria1 );
508   if (!F1) return false;
509   const SMDS_VtkFace* F2 = dynamic_cast<const SMDS_VtkFace*>( theTria2 );
510   if (!F2) return false;
511   if ((theTria1->GetEntityType() == SMDSEntity_Triangle) &&
512       (theTria2->GetEntityType() == SMDSEntity_Triangle)) {
513
514     //  1 +--+ A  theTria1: ( 1 A B ) A->2 ( 1 2 B ) 1 +--+ A
515     //    | /|    theTria2: ( B A 2 ) B->1 ( 1 A 2 )   |\ |
516     //    |/ |                                         | \|
517     //  B +--+ 2                                     B +--+ 2
518
519     // put nodes in array and find out indices of the same ones
520     const SMDS_MeshNode* aNodes [6];
521     int sameInd [] = { 0, 0, 0, 0, 0, 0 };
522     int i = 0;
523     SMDS_ElemIteratorPtr it = theTria1->nodesIterator();
524     while ( it->more() ) {
525       aNodes[ i ] = static_cast<const SMDS_MeshNode*>( it->next() );
526
527       if ( i > 2 ) // theTria2
528         // find same node of theTria1
529         for ( int j = 0; j < 3; j++ )
530           if ( aNodes[ i ] == aNodes[ j ]) {
531             sameInd[ j ] = i;
532             sameInd[ i ] = j;
533             break;
534           }
535       // next
536       i++;
537       if ( i == 3 ) {
538         if ( it->more() )
539           return false; // theTria1 is not a triangle
540         it = theTria2->nodesIterator();
541       }
542       if ( i == 6 && it->more() )
543         return false; // theTria2 is not a triangle
544     }
545
546     // find indices of 1,2 and of A,B in theTria1
547     int iA = 0, iB = 0, i1 = 0, i2 = 0;
548     for ( i = 0; i < 6; i++ ) {
549       if ( sameInd [ i ] == 0 ) {
550         if ( i < 3 ) i1 = i;
551         else         i2 = i;
552       }
553       else if (i < 3) {
554         if ( iA ) iB = i;
555         else      iA = i;
556       }
557     }
558     // nodes 1 and 2 should not be the same
559     if ( aNodes[ i1 ] == aNodes[ i2 ] )
560       return false;
561
562     // theTria1: A->2
563     aNodes[ iA ] = aNodes[ i2 ];
564     // theTria2: B->1
565     aNodes[ sameInd[ iB ]] = aNodes[ i1 ];
566
567     GetMeshDS()->ChangeElementNodes( theTria1, aNodes, 3 );
568     GetMeshDS()->ChangeElementNodes( theTria2, &aNodes[ 3 ], 3 );
569
570     return true;
571
572   } // end if(F1 && F2)
573
574   // check case of quadratic faces
575   if (theTria1->GetEntityType() != SMDSEntity_Quad_Triangle)
576     return false;
577   if (theTria2->GetEntityType() != SMDSEntity_Quad_Triangle)
578     return false;
579
580   //       5
581   //  1 +--+--+ 2  theTria1: (1 2 4 5 9 7) or (2 4 1 9 7 5) or (4 1 2 7 5 9)
582   //    |    /|    theTria2: (2 3 4 6 8 9) or (3 4 2 8 9 6) or (4 2 3 9 6 8)
583   //    |   / |
584   //  7 +  +  + 6
585   //    | /9  |
586   //    |/    |
587   //  4 +--+--+ 3
588   //       8
589
590   const SMDS_MeshNode* N1 [6];
591   const SMDS_MeshNode* N2 [6];
592   if(!GetNodesFromTwoTria(theTria1,theTria2,N1,N2))
593     return false;
594   // now we receive following N1 and N2 (using numeration as above image)
595   // tria1 : (1 2 4 5 9 7)  and  tria2 : (3 4 2 8 9 6)
596   // i.e. first nodes from both arrays determ new diagonal
597
598   const SMDS_MeshNode* N1new [6];
599   const SMDS_MeshNode* N2new [6];
600   N1new[0] = N1[0];
601   N1new[1] = N2[0];
602   N1new[2] = N2[1];
603   N1new[3] = N1[4];
604   N1new[4] = N2[3];
605   N1new[5] = N1[5];
606   N2new[0] = N1[0];
607   N2new[1] = N1[1];
608   N2new[2] = N2[0];
609   N2new[3] = N1[3];
610   N2new[4] = N2[5];
611   N2new[5] = N1[4];
612   // replaces nodes in faces
613   GetMeshDS()->ChangeElementNodes( theTria1, N1new, 6 );
614   GetMeshDS()->ChangeElementNodes( theTria2, N2new, 6 );
615
616   return true;
617 }
618
619 //=======================================================================
620 //function : findTriangles
621 //purpose  : find triangles sharing theNode1-theNode2 link
622 //=======================================================================
623
624 static bool findTriangles(const SMDS_MeshNode *    theNode1,
625                           const SMDS_MeshNode *    theNode2,
626                           const SMDS_MeshElement*& theTria1,
627                           const SMDS_MeshElement*& theTria2)
628 {
629   if ( !theNode1 || !theNode2 ) return false;
630
631   theTria1 = theTria2 = 0;
632
633   set< const SMDS_MeshElement* > emap;
634   SMDS_ElemIteratorPtr it = theNode1->GetInverseElementIterator(SMDSAbs_Face);
635   while (it->more()) {
636     const SMDS_MeshElement* elem = it->next();
637     if ( elem->NbNodes() == 3 )
638       emap.insert( elem );
639   }
640   it = theNode2->GetInverseElementIterator(SMDSAbs_Face);
641   while (it->more()) {
642     const SMDS_MeshElement* elem = it->next();
643     if ( emap.find( elem ) != emap.end() ) {
644       if ( theTria1 ) {
645         // theTria1 must be element with minimum ID
646         if( theTria1->GetID() < elem->GetID() ) {
647           theTria2 = elem;
648         }
649         else {
650           theTria2 = theTria1;
651           theTria1 = elem;
652         }
653         break;
654       }
655       else {
656         theTria1 = elem;
657       }
658     }
659   }
660   return ( theTria1 && theTria2 );
661 }
662
663 //=======================================================================
664 //function : InverseDiag
665 //purpose  : Replace two neighbour triangles sharing theNode1-theNode2 link
666 //           with ones built on the same 4 nodes but having other common link.
667 //           Return false if proper faces not found
668 //=======================================================================
669
670 bool SMESH_MeshEditor::InverseDiag (const SMDS_MeshNode * theNode1,
671                                     const SMDS_MeshNode * theNode2)
672 {
673   myLastCreatedElems.Clear();
674   myLastCreatedNodes.Clear();
675
676   MESSAGE( "::InverseDiag()" );
677
678   const SMDS_MeshElement *tr1, *tr2;
679   if ( !findTriangles( theNode1, theNode2, tr1, tr2 ))
680     return false;
681
682   const SMDS_VtkFace* F1 = dynamic_cast<const SMDS_VtkFace*>( tr1 );
683   if (!F1) return false;
684   const SMDS_VtkFace* F2 = dynamic_cast<const SMDS_VtkFace*>( tr2 );
685   if (!F2) return false;
686   if ((tr1->GetEntityType() == SMDSEntity_Triangle) &&
687       (tr2->GetEntityType() == SMDSEntity_Triangle)) {
688
689     //  1 +--+ A  tr1: ( 1 A B ) A->2 ( 1 2 B ) 1 +--+ A
690     //    | /|    tr2: ( B A 2 ) B->1 ( 1 A 2 )   |\ |
691     //    |/ |                                    | \|
692     //  B +--+ 2                                B +--+ 2
693
694     // put nodes in array
695     // and find indices of 1,2 and of A in tr1 and of B in tr2
696     int i, iA1 = 0, i1 = 0;
697     const SMDS_MeshNode* aNodes1 [3];
698     SMDS_ElemIteratorPtr it;
699     for (i = 0, it = tr1->nodesIterator(); it->more(); i++ ) {
700       aNodes1[ i ] = static_cast<const SMDS_MeshNode*>( it->next() );
701       if ( aNodes1[ i ] == theNode1 )
702         iA1 = i; // node A in tr1
703       else if ( aNodes1[ i ] != theNode2 )
704         i1 = i;  // node 1
705     }
706     int iB2 = 0, i2 = 0;
707     const SMDS_MeshNode* aNodes2 [3];
708     for (i = 0, it = tr2->nodesIterator(); it->more(); i++ ) {
709       aNodes2[ i ] = static_cast<const SMDS_MeshNode*>( it->next() );
710       if ( aNodes2[ i ] == theNode2 )
711         iB2 = i; // node B in tr2
712       else if ( aNodes2[ i ] != theNode1 )
713         i2 = i;  // node 2
714     }
715
716     // nodes 1 and 2 should not be the same
717     if ( aNodes1[ i1 ] == aNodes2[ i2 ] )
718       return false;
719
720     // tr1: A->2
721     aNodes1[ iA1 ] = aNodes2[ i2 ];
722     // tr2: B->1
723     aNodes2[ iB2 ] = aNodes1[ i1 ];
724
725     GetMeshDS()->ChangeElementNodes( tr1, aNodes1, 3 );
726     GetMeshDS()->ChangeElementNodes( tr2, aNodes2, 3 );
727
728     return true;
729   }
730
731   // check case of quadratic faces
732   return InverseDiag(tr1,tr2);
733 }
734
735 //=======================================================================
736 //function : getQuadrangleNodes
737 //purpose  : fill theQuadNodes - nodes of a quadrangle resulting from
738 //           fusion of triangles tr1 and tr2 having shared link on
739 //           theNode1 and theNode2
740 //=======================================================================
741
742 bool getQuadrangleNodes(const SMDS_MeshNode *    theQuadNodes [],
743                         const SMDS_MeshNode *    theNode1,
744                         const SMDS_MeshNode *    theNode2,
745                         const SMDS_MeshElement * tr1,
746                         const SMDS_MeshElement * tr2 )
747 {
748   if( tr1->NbNodes() != tr2->NbNodes() )
749     return false;
750   // find the 4-th node to insert into tr1
751   const SMDS_MeshNode* n4 = 0;
752   SMDS_ElemIteratorPtr it = tr2->nodesIterator();
753   int i=0;
754   while ( !n4 && i<3 ) {
755     const SMDS_MeshNode * n = cast2Node( it->next() );
756     i++;
757     bool isDiag = ( n == theNode1 || n == theNode2 );
758     if ( !isDiag )
759       n4 = n;
760   }
761   // Make an array of nodes to be in a quadrangle
762   int iNode = 0, iFirstDiag = -1;
763   it = tr1->nodesIterator();
764   i=0;
765   while ( i<3 ) {
766     const SMDS_MeshNode * n = cast2Node( it->next() );
767     i++;
768     bool isDiag = ( n == theNode1 || n == theNode2 );
769     if ( isDiag ) {
770       if ( iFirstDiag < 0 )
771         iFirstDiag = iNode;
772       else if ( iNode - iFirstDiag == 1 )
773         theQuadNodes[ iNode++ ] = n4; // insert the 4-th node between diagonal nodes
774     }
775     else if ( n == n4 ) {
776       return false; // tr1 and tr2 should not have all the same nodes
777     }
778     theQuadNodes[ iNode++ ] = n;
779   }
780   if ( iNode == 3 ) // diagonal nodes have 0 and 2 indices
781     theQuadNodes[ iNode ] = n4;
782
783   return true;
784 }
785
786 //=======================================================================
787 //function : DeleteDiag
788 //purpose  : Replace two neighbour triangles sharing theNode1-theNode2 link
789 //           with a quadrangle built on the same 4 nodes.
790 //           Return false if proper faces not found
791 //=======================================================================
792
793 bool SMESH_MeshEditor::DeleteDiag (const SMDS_MeshNode * theNode1,
794                                    const SMDS_MeshNode * theNode2)
795 {
796   myLastCreatedElems.Clear();
797   myLastCreatedNodes.Clear();
798
799   MESSAGE( "::DeleteDiag()" );
800
801   const SMDS_MeshElement *tr1, *tr2;
802   if ( !findTriangles( theNode1, theNode2, tr1, tr2 ))
803     return false;
804
805   const SMDS_VtkFace* F1 = dynamic_cast<const SMDS_VtkFace*>( tr1 );
806   if (!F1) return false;
807   const SMDS_VtkFace* F2 = dynamic_cast<const SMDS_VtkFace*>( tr2 );
808   if (!F2) return false;
809   SMESHDS_Mesh * aMesh = GetMeshDS();
810
811   if ((tr1->GetEntityType() == SMDSEntity_Triangle) &&
812       (tr2->GetEntityType() == SMDSEntity_Triangle)) {
813
814     const SMDS_MeshNode* aNodes [ 4 ];
815     if ( ! getQuadrangleNodes( aNodes, theNode1, theNode2, tr1, tr2 ))
816       return false;
817
818     const SMDS_MeshElement* newElem = 0;
819     newElem = aMesh->AddFace( aNodes[0], aNodes[1], aNodes[2], aNodes[3] );
820     myLastCreatedElems.Append(newElem);
821     AddToSameGroups( newElem, tr1, aMesh );
822     int aShapeId = tr1->getshapeId();
823     if ( aShapeId )
824       {
825         aMesh->SetMeshElementOnShape( newElem, aShapeId );
826       }
827     aMesh->RemoveElement( tr1 );
828     aMesh->RemoveElement( tr2 );
829
830     return true;
831   }
832
833   // check case of quadratic faces
834   if (tr1->GetEntityType() != SMDSEntity_Quad_Triangle)
835     return false;
836   if (tr2->GetEntityType() != SMDSEntity_Quad_Triangle)
837     return false;
838
839   //       5
840   //  1 +--+--+ 2  tr1: (1 2 4 5 9 7) or (2 4 1 9 7 5) or (4 1 2 7 5 9)
841   //    |    /|    tr2: (2 3 4 6 8 9) or (3 4 2 8 9 6) or (4 2 3 9 6 8)
842   //    |   / |
843   //  7 +  +  + 6
844   //    | /9  |
845   //    |/    |
846   //  4 +--+--+ 3
847   //       8
848
849   const SMDS_MeshNode* N1 [6];
850   const SMDS_MeshNode* N2 [6];
851   if(!GetNodesFromTwoTria(tr1,tr2,N1,N2))
852     return false;
853   // now we receive following N1 and N2 (using numeration as above image)
854   // tria1 : (1 2 4 5 9 7)  and  tria2 : (3 4 2 8 9 6)
855   // i.e. first nodes from both arrays determ new diagonal
856
857   const SMDS_MeshNode* aNodes[8];
858   aNodes[0] = N1[0];
859   aNodes[1] = N1[1];
860   aNodes[2] = N2[0];
861   aNodes[3] = N2[1];
862   aNodes[4] = N1[3];
863   aNodes[5] = N2[5];
864   aNodes[6] = N2[3];
865   aNodes[7] = N1[5];
866
867   const SMDS_MeshElement* newElem = 0;
868   newElem = aMesh->AddFace( aNodes[0], aNodes[1], aNodes[2], aNodes[3],
869                             aNodes[4], aNodes[5], aNodes[6], aNodes[7]);
870   myLastCreatedElems.Append(newElem);
871   AddToSameGroups( newElem, tr1, aMesh );
872   int aShapeId = tr1->getshapeId();
873   if ( aShapeId )
874     {
875       aMesh->SetMeshElementOnShape( newElem, aShapeId );
876     }
877   aMesh->RemoveElement( tr1 );
878   aMesh->RemoveElement( tr2 );
879
880   // remove middle node (9)
881   GetMeshDS()->RemoveNode( N1[4] );
882
883   return true;
884 }
885
886 //=======================================================================
887 //function : Reorient
888 //purpose  : Reverse theElement orientation
889 //=======================================================================
890
891 bool SMESH_MeshEditor::Reorient (const SMDS_MeshElement * theElem)
892 {
893   MESSAGE("Reorient");
894   myLastCreatedElems.Clear();
895   myLastCreatedNodes.Clear();
896
897   if (!theElem)
898     return false;
899   SMDS_ElemIteratorPtr it = theElem->nodesIterator();
900   if ( !it || !it->more() )
901     return false;
902
903   switch ( theElem->GetType() ) {
904
905   case SMDSAbs_Edge:
906   case SMDSAbs_Face: {
907     if(!theElem->IsQuadratic()) {
908       int i = theElem->NbNodes();
909       vector<const SMDS_MeshNode*> aNodes( i );
910       while ( it->more() )
911         aNodes[ --i ]= static_cast<const SMDS_MeshNode*>( it->next() );
912       return GetMeshDS()->ChangeElementNodes( theElem, &aNodes[0], theElem->NbNodes() );
913     }
914     else {
915       // quadratic elements
916       if(theElem->GetType()==SMDSAbs_Edge) {
917         vector<const SMDS_MeshNode*> aNodes(3);
918         aNodes[1]= static_cast<const SMDS_MeshNode*>( it->next() );
919         aNodes[0]= static_cast<const SMDS_MeshNode*>( it->next() );
920         aNodes[2]= static_cast<const SMDS_MeshNode*>( it->next() );
921         return GetMeshDS()->ChangeElementNodes( theElem, &aNodes[0], 3 );
922       }
923       else {
924         int nbn = theElem->NbNodes();
925         vector<const SMDS_MeshNode*> aNodes(nbn);
926         aNodes[0]= static_cast<const SMDS_MeshNode*>( it->next() );
927         int i=1;
928         for(; i<nbn/2; i++) {
929           aNodes[nbn/2-i]= static_cast<const SMDS_MeshNode*>( it->next() );
930         }
931         for(i=0; i<nbn/2; i++) {
932           aNodes[nbn-i-1]= static_cast<const SMDS_MeshNode*>( it->next() );
933         }
934         return GetMeshDS()->ChangeElementNodes( theElem, &aNodes[0], nbn );
935       }
936     }
937   }
938   case SMDSAbs_Volume: {
939     if (theElem->IsPoly()) {
940       // TODO reorient vtk polyhedron
941       MESSAGE("reorient vtk polyhedron ?");
942       const SMDS_VtkVolume* aPolyedre =
943         dynamic_cast<const SMDS_VtkVolume*>( theElem );
944       if (!aPolyedre) {
945         MESSAGE("Warning: bad volumic element");
946         return false;
947       }
948
949       int nbFaces = aPolyedre->NbFaces();
950       vector<const SMDS_MeshNode *> poly_nodes;
951       vector<int> quantities (nbFaces);
952
953       // reverse each face of the polyedre
954       for (int iface = 1; iface <= nbFaces; iface++) {
955         int inode, nbFaceNodes = aPolyedre->NbFaceNodes(iface);
956         quantities[iface - 1] = nbFaceNodes;
957
958         for (inode = nbFaceNodes; inode >= 1; inode--) {
959           const SMDS_MeshNode* curNode = aPolyedre->GetFaceNode(iface, inode);
960           poly_nodes.push_back(curNode);
961         }
962       }
963
964       return GetMeshDS()->ChangePolyhedronNodes( theElem, poly_nodes, quantities );
965
966     }
967     else {
968       SMDS_VolumeTool vTool;
969       if ( !vTool.Set( theElem ))
970         return false;
971       vTool.Inverse();
972       MESSAGE("ChangeElementNodes reorient: check vTool.Inverse");
973       return GetMeshDS()->ChangeElementNodes( theElem, vTool.GetNodes(), vTool.NbNodes() );
974     }
975   }
976   default:;
977   }
978
979   return false;
980 }
981
982 //=======================================================================
983 //function : getBadRate
984 //purpose  :
985 //=======================================================================
986
987 static double getBadRate (const SMDS_MeshElement*               theElem,
988                           SMESH::Controls::NumericalFunctorPtr& theCrit)
989 {
990   SMESH::Controls::TSequenceOfXYZ P;
991   if ( !theElem || !theCrit->GetPoints( theElem, P ))
992     return 1e100;
993   return theCrit->GetBadRate( theCrit->GetValue( P ), theElem->NbNodes() );
994   //return theCrit->GetBadRate( theCrit->GetValue( theElem->GetID() ), theElem->NbNodes() );
995 }
996
997 //=======================================================================
998 //function : QuadToTri
999 //purpose  : Cut quadrangles into triangles.
1000 //           theCrit is used to select a diagonal to cut
1001 //=======================================================================
1002
1003 bool SMESH_MeshEditor::QuadToTri (TIDSortedElemSet &                   theElems,
1004                                   SMESH::Controls::NumericalFunctorPtr theCrit)
1005 {
1006   myLastCreatedElems.Clear();
1007   myLastCreatedNodes.Clear();
1008
1009   MESSAGE( "::QuadToTri()" );
1010
1011   if ( !theCrit.get() )
1012     return false;
1013
1014   SMESHDS_Mesh * aMesh = GetMeshDS();
1015
1016   Handle(Geom_Surface) surface;
1017   SMESH_MesherHelper   helper( *GetMesh() );
1018
1019   TIDSortedElemSet::iterator itElem;
1020   for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
1021     const SMDS_MeshElement* elem = *itElem;
1022     if ( !elem || elem->GetType() != SMDSAbs_Face )
1023       continue;
1024     if ( elem->NbNodes() != ( elem->IsQuadratic() ? 8 : 4 ))
1025       continue;
1026
1027     // retrieve element nodes
1028     const SMDS_MeshNode* aNodes [8];
1029     SMDS_ElemIteratorPtr itN = elem->nodesIterator();
1030     int i = 0;
1031     while ( itN->more() )
1032       aNodes[ i++ ] = static_cast<const SMDS_MeshNode*>( itN->next() );
1033
1034     // compare two sets of possible triangles
1035     double aBadRate1, aBadRate2; // to what extent a set is bad
1036     SMDS_FaceOfNodes tr1 ( aNodes[0], aNodes[1], aNodes[2] );
1037     SMDS_FaceOfNodes tr2 ( aNodes[2], aNodes[3], aNodes[0] );
1038     aBadRate1 = getBadRate( &tr1, theCrit ) + getBadRate( &tr2, theCrit );
1039
1040     SMDS_FaceOfNodes tr3 ( aNodes[1], aNodes[2], aNodes[3] );
1041     SMDS_FaceOfNodes tr4 ( aNodes[3], aNodes[0], aNodes[1] );
1042     aBadRate2 = getBadRate( &tr3, theCrit ) + getBadRate( &tr4, theCrit );
1043
1044     int aShapeId = FindShape( elem );
1045     const SMDS_MeshElement* newElem1 = 0;
1046     const SMDS_MeshElement* newElem2 = 0;
1047
1048     if( !elem->IsQuadratic() ) {
1049
1050       // split liner quadrangle
1051       if ( aBadRate1 <= aBadRate2 ) {
1052         // tr1 + tr2 is better
1053         newElem1 = aMesh->AddFace( aNodes[2], aNodes[3], aNodes[0] );
1054         newElem2 = aMesh->AddFace( aNodes[2], aNodes[0], aNodes[1] );
1055       }
1056       else {
1057         // tr3 + tr4 is better
1058         newElem1 = aMesh->AddFace( aNodes[3], aNodes[0], aNodes[1] );
1059         newElem2 = aMesh->AddFace( aNodes[3], aNodes[1], aNodes[2] );
1060       }
1061     }
1062     else {
1063
1064       // split quadratic quadrangle
1065
1066       // get surface elem is on
1067       if ( aShapeId != helper.GetSubShapeID() ) {
1068         surface.Nullify();
1069         TopoDS_Shape shape;
1070         if ( aShapeId > 0 )
1071           shape = aMesh->IndexToShape( aShapeId );
1072         if ( !shape.IsNull() && shape.ShapeType() == TopAbs_FACE ) {
1073           TopoDS_Face face = TopoDS::Face( shape );
1074           surface = BRep_Tool::Surface( face );
1075           if ( !surface.IsNull() )
1076             helper.SetSubShape( shape );
1077         }
1078       }
1079       // get elem nodes
1080       const SMDS_MeshNode* aNodes [8];
1081       const SMDS_MeshNode* inFaceNode = 0;
1082       SMDS_ElemIteratorPtr itN = elem->nodesIterator();
1083       int i = 0;
1084       while ( itN->more() ) {
1085         aNodes[ i++ ] = static_cast<const SMDS_MeshNode*>( itN->next() );
1086         if ( !inFaceNode && helper.GetNodeUVneedInFaceNode() &&
1087              aNodes[ i-1 ]->GetPosition()->GetTypeOfPosition() == SMDS_TOP_FACE )
1088         {
1089           inFaceNode = aNodes[ i-1 ];
1090         }
1091       }
1092       // find middle point for (0,1,2,3)
1093       // and create a node in this point;
1094       gp_XYZ p( 0,0,0 );
1095       if ( surface.IsNull() ) {
1096         for(i=0; i<4; i++)
1097           p += gp_XYZ(aNodes[i]->X(), aNodes[i]->Y(), aNodes[i]->Z() );
1098         p /= 4;
1099       }
1100       else {
1101         TopoDS_Face face = TopoDS::Face( helper.GetSubShape() );
1102         gp_XY uv( 0,0 );
1103         for(i=0; i<4; i++)
1104           uv += helper.GetNodeUV( face, aNodes[i], inFaceNode );
1105         uv /= 4.;
1106         p = surface->Value( uv.X(), uv.Y() ).XYZ();
1107       }
1108       const SMDS_MeshNode* newN = aMesh->AddNode( p.X(), p.Y(), p.Z() );
1109       myLastCreatedNodes.Append(newN);
1110
1111       // create a new element
1112       const SMDS_MeshNode* N[6];
1113       if ( aBadRate1 <= aBadRate2 ) {
1114         N[0] = aNodes[0];
1115         N[1] = aNodes[1];
1116         N[2] = aNodes[2];
1117         N[3] = aNodes[4];
1118         N[4] = aNodes[5];
1119         N[5] = newN;
1120         newElem1 = aMesh->AddFace(aNodes[2], aNodes[3], aNodes[0],
1121                                   aNodes[6], aNodes[7], newN );
1122         newElem2 = aMesh->AddFace(aNodes[2], aNodes[0], aNodes[1],
1123                                   newN,      aNodes[4], aNodes[5] );
1124       }
1125       else {
1126         N[0] = aNodes[1];
1127         N[1] = aNodes[2];
1128         N[2] = aNodes[3];
1129         N[3] = aNodes[5];
1130         N[4] = aNodes[6];
1131         N[5] = newN;
1132         newElem1 = aMesh->AddFace(aNodes[3], aNodes[0], aNodes[1],
1133                                   aNodes[7], aNodes[4], newN );
1134         newElem2 = aMesh->AddFace(aNodes[3], aNodes[1], aNodes[2],
1135                                   newN,      aNodes[5], aNodes[6] );
1136       }
1137     } // quadratic case
1138
1139     // care of a new element
1140
1141     myLastCreatedElems.Append(newElem1);
1142     myLastCreatedElems.Append(newElem2);
1143     AddToSameGroups( newElem1, elem, aMesh );
1144     AddToSameGroups( newElem2, elem, aMesh );
1145
1146     // put a new triangle on the same shape
1147     if ( aShapeId )
1148       {
1149         aMesh->SetMeshElementOnShape( newElem1, aShapeId );
1150         aMesh->SetMeshElementOnShape( newElem2, aShapeId );
1151       }
1152     aMesh->RemoveElement( elem );
1153   }
1154   return true;
1155 }
1156
1157 //=======================================================================
1158 //function : BestSplit
1159 //purpose  : Find better diagonal for cutting.
1160 //=======================================================================
1161
1162 int SMESH_MeshEditor::BestSplit (const SMDS_MeshElement*              theQuad,
1163                                  SMESH::Controls::NumericalFunctorPtr theCrit)
1164 {
1165   myLastCreatedElems.Clear();
1166   myLastCreatedNodes.Clear();
1167
1168   if (!theCrit.get())
1169     return -1;
1170
1171   if (!theQuad || theQuad->GetType() != SMDSAbs_Face )
1172     return -1;
1173
1174   if( theQuad->NbNodes()==4 ||
1175       (theQuad->NbNodes()==8 && theQuad->IsQuadratic()) ) {
1176
1177     // retrieve element nodes
1178     const SMDS_MeshNode* aNodes [4];
1179     SMDS_ElemIteratorPtr itN = theQuad->nodesIterator();
1180     int i = 0;
1181     //while (itN->more())
1182     while (i<4) {
1183       aNodes[ i++ ] = static_cast<const SMDS_MeshNode*>( itN->next() );
1184     }
1185     // compare two sets of possible triangles
1186     double aBadRate1, aBadRate2; // to what extent a set is bad
1187     SMDS_FaceOfNodes tr1 ( aNodes[0], aNodes[1], aNodes[2] );
1188     SMDS_FaceOfNodes tr2 ( aNodes[2], aNodes[3], aNodes[0] );
1189     aBadRate1 = getBadRate( &tr1, theCrit ) + getBadRate( &tr2, theCrit );
1190
1191     SMDS_FaceOfNodes tr3 ( aNodes[1], aNodes[2], aNodes[3] );
1192     SMDS_FaceOfNodes tr4 ( aNodes[3], aNodes[0], aNodes[1] );
1193     aBadRate2 = getBadRate( &tr3, theCrit ) + getBadRate( &tr4, theCrit );
1194
1195     if (aBadRate1 <= aBadRate2) // tr1 + tr2 is better
1196       return 1; // diagonal 1-3
1197
1198     return 2; // diagonal 2-4
1199   }
1200   return -1;
1201 }
1202
1203 namespace
1204 {
1205   // Methods of splitting volumes into tetra
1206
1207   const int theHexTo5_1[5*4+1] =
1208     {
1209       0, 1, 2, 5,    0, 4, 5, 7,     0, 2, 3, 7,    2, 5, 6, 7,     0, 5, 2, 7,   -1
1210     };
1211   const int theHexTo5_2[5*4+1] =
1212     {
1213       1, 2, 3, 6,    1, 4, 5, 6,     0, 1, 3, 4,    3, 4, 6, 7,     1, 3, 4, 6,   -1
1214     };
1215   const int* theHexTo5[2] = { theHexTo5_1, theHexTo5_2 };
1216
1217   const int theHexTo6_1[6*4+1] =
1218     {
1219       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
1220     };
1221   const int theHexTo6_2[6*4+1] =
1222     {
1223       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
1224     };
1225   const int theHexTo6_3[6*4+1] =
1226     {
1227       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
1228     };
1229   const int theHexTo6_4[6*4+1] =
1230     {
1231       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
1232     };
1233   const int* theHexTo6[4] = { theHexTo6_1, theHexTo6_2, theHexTo6_3, theHexTo6_4 };
1234
1235   const int thePyraTo2_1[2*4+1] =
1236     {
1237       0, 1, 2, 4,    0, 2, 3, 4,   -1
1238     };
1239   const int thePyraTo2_2[2*4+1] =
1240     {
1241       1, 2, 3, 4,    1, 3, 0, 4,   -1
1242     };
1243   const int* thePyraTo2[2] = { thePyraTo2_1, thePyraTo2_2 };
1244
1245   const int thePentaTo3_1[3*4+1] =
1246     {
1247       0, 1, 2, 3,    1, 3, 4, 2,     2, 3, 4, 5,    -1
1248     };
1249   const int thePentaTo3_2[3*4+1] =
1250     {
1251       1, 2, 0, 4,    2, 4, 5, 0,     0, 4, 5, 3,    -1
1252     };
1253   const int thePentaTo3_3[3*4+1] =
1254     {
1255       2, 0, 1, 5,    0, 5, 3, 1,     1, 5, 3, 4,    -1
1256     };
1257   const int thePentaTo3_4[3*4+1] =
1258     {
1259       0, 1, 2, 3,    1, 3, 4, 5,     2, 3, 1, 5,    -1
1260     };
1261   const int thePentaTo3_5[3*4+1] =
1262     {
1263       1, 2, 0, 4,    2, 4, 5, 3,     0, 4, 2, 3,    -1
1264     };
1265   const int thePentaTo3_6[3*4+1] =
1266     {
1267       2, 0, 1, 5,    0, 5, 3, 4,     1, 5, 0, 4,    -1
1268     };
1269   const int* thePentaTo3[6] = { thePentaTo3_1, thePentaTo3_2, thePentaTo3_3,
1270                                 thePentaTo3_4, thePentaTo3_5, thePentaTo3_6 };
1271
1272   struct TTriangleFacet //!< stores indices of three nodes of tetra facet
1273   {
1274     int _n1, _n2, _n3;
1275     TTriangleFacet(int n1, int n2, int n3): _n1(n1), _n2(n2), _n3(n3) {}
1276     bool contains(int n) const { return ( n == _n1 || n == _n2 || n == _n3 ); }
1277     bool hasAdjacentTetra( const SMDS_MeshElement* elem ) const;
1278   };
1279   struct TSplitMethod
1280   {
1281     int        _nbTetra;
1282     const int* _connectivity; //!< foursomes of tetra connectivy finished by -1
1283     bool       _baryNode;     //!< additional node is to be created at cell barycenter
1284     bool       _ownConn;      //!< to delete _connectivity in destructor
1285     map<int, const SMDS_MeshNode*> _faceBaryNode; //!< map face index to node at BC of face
1286
1287     TSplitMethod( int nbTet=0, const int* conn=0, bool addNode=false)
1288       : _nbTetra(nbTet), _connectivity(conn), _baryNode(addNode), _ownConn(false) {}
1289     ~TSplitMethod() { if ( _ownConn ) delete [] _connectivity; _connectivity = 0; }
1290     bool hasFacet( const TTriangleFacet& facet ) const
1291     {
1292       const int* tetConn = _connectivity;
1293       for ( ; tetConn[0] >= 0; tetConn += 4 )
1294         if (( facet.contains( tetConn[0] ) +
1295               facet.contains( tetConn[1] ) +
1296               facet.contains( tetConn[2] ) +
1297               facet.contains( tetConn[3] )) == 3 )
1298           return true;
1299       return false;
1300     }
1301   };
1302
1303   //=======================================================================
1304   /*!
1305    * \brief return TSplitMethod for the given element
1306    */
1307   //=======================================================================
1308
1309   TSplitMethod getSplitMethod( SMDS_VolumeTool& vol, const int theMethodFlags)
1310   {
1311     const int iQ = vol.Element()->IsQuadratic() ? 2 : 1;
1312
1313     // at HEXA_TO_24 method, each face of volume is split into triangles each based on
1314     // an edge and a face barycenter; tertaherdons are based on triangles and
1315     // a volume barycenter
1316     const bool is24TetMode = ( theMethodFlags == SMESH_MeshEditor::HEXA_TO_24 );
1317
1318     // Find out how adjacent volumes are split
1319
1320     vector < list< TTriangleFacet > > triaSplitsByFace( vol.NbFaces() ); // splits of each side
1321     int hasAdjacentSplits = 0, maxTetConnSize = 0;
1322     for ( int iF = 0; iF < vol.NbFaces(); ++iF )
1323     {
1324       int nbNodes = vol.NbFaceNodes( iF ) / iQ;
1325       maxTetConnSize += 4 * ( nbNodes - (is24TetMode ? 0 : 2));
1326       if ( nbNodes < 4 ) continue;
1327
1328       list< TTriangleFacet >& triaSplits = triaSplitsByFace[ iF ];
1329       const int* nInd = vol.GetFaceNodesIndices( iF );
1330       if ( nbNodes == 4 )
1331       {
1332         TTriangleFacet t012( nInd[0*iQ], nInd[1*iQ], nInd[2*iQ] );
1333         TTriangleFacet t123( nInd[1*iQ], nInd[2*iQ], nInd[3*iQ] );
1334         if      ( t012.hasAdjacentTetra( vol.Element() )) triaSplits.push_back( t012 );
1335         else if ( t123.hasAdjacentTetra( vol.Element() )) triaSplits.push_back( t123 );
1336       }
1337       else
1338       {
1339         int iCom = 0; // common node of triangle faces to split into
1340         for ( int iVar = 0; iVar < nbNodes; ++iVar, ++iCom )
1341         {
1342           TTriangleFacet t012( nInd[ iQ * ( iCom             )],
1343                                nInd[ iQ * ( (iCom+1)%nbNodes )],
1344                                nInd[ iQ * ( (iCom+2)%nbNodes )]);
1345           TTriangleFacet t023( nInd[ iQ * ( iCom             )],
1346                                nInd[ iQ * ( (iCom+2)%nbNodes )],
1347                                nInd[ iQ * ( (iCom+3)%nbNodes )]);
1348           if ( t012.hasAdjacentTetra( vol.Element() ) && t023.hasAdjacentTetra( vol.Element() ))
1349           {
1350             triaSplits.push_back( t012 );
1351             triaSplits.push_back( t023 );
1352             break;
1353           }
1354         }
1355       }
1356       if ( !triaSplits.empty() )
1357         hasAdjacentSplits = true;
1358     }
1359
1360     // Among variants of split method select one compliant with adjacent volumes
1361
1362     TSplitMethod method;
1363     if ( !vol.Element()->IsPoly() && !is24TetMode )
1364     {
1365       int nbVariants = 2, nbTet = 0;
1366       const int** connVariants = 0;
1367       switch ( vol.Element()->GetEntityType() )
1368       {
1369       case SMDSEntity_Hexa:
1370       case SMDSEntity_Quad_Hexa:
1371         if ( theMethodFlags == SMESH_MeshEditor::HEXA_TO_5 )
1372           connVariants = theHexTo5, nbTet = 5;
1373         else
1374           connVariants = theHexTo6, nbTet = 6, nbVariants = 4;
1375         break;
1376       case SMDSEntity_Pyramid:
1377       case SMDSEntity_Quad_Pyramid:
1378         connVariants = thePyraTo2;  nbTet = 2;
1379         break;
1380       case SMDSEntity_Penta:
1381       case SMDSEntity_Quad_Penta:
1382         connVariants = thePentaTo3; nbTet = 3; nbVariants = 6;
1383         break;
1384       default:
1385         nbVariants = 0;
1386       }
1387       for ( int variant = 0; variant < nbVariants && method._nbTetra == 0; ++variant )
1388       {
1389         // check method compliancy with adjacent tetras,
1390         // all found splits must be among facets of tetras described by this method
1391         method = TSplitMethod( nbTet, connVariants[variant] );
1392         if ( hasAdjacentSplits && method._nbTetra > 0 )
1393         {
1394           bool facetCreated = true;
1395           for ( int iF = 0; facetCreated && iF < triaSplitsByFace.size(); ++iF )
1396           {
1397             list< TTriangleFacet >::const_iterator facet = triaSplitsByFace[iF].begin();
1398             for ( ; facetCreated && facet != triaSplitsByFace[iF].end(); ++facet )
1399               facetCreated = method.hasFacet( *facet );
1400           }
1401           if ( !facetCreated )
1402             method = TSplitMethod(0); // incompatible method
1403         }
1404       }
1405     }
1406     if ( method._nbTetra < 1 )
1407     {
1408       // No standard method is applicable, use a generic solution:
1409       // each facet of a volume is split into triangles and
1410       // each of triangles and a volume barycenter form a tetrahedron.
1411
1412       int* connectivity = new int[ maxTetConnSize + 1 ];
1413       method._connectivity = connectivity;
1414       method._ownConn = true;
1415       method._baryNode = true;
1416
1417       int connSize = 0;
1418       int baryCenInd = vol.NbNodes();
1419       for ( int iF = 0; iF < vol.NbFaces(); ++iF )
1420       {
1421         const int nbNodes = vol.NbFaceNodes( iF ) / iQ;
1422         const int*   nInd = vol.GetFaceNodesIndices( iF );
1423         // find common node of triangle facets of tetra to create
1424         int iCommon = 0; // index in linear numeration
1425         const list< TTriangleFacet >& triaSplits = triaSplitsByFace[ iF ];
1426         if ( !triaSplits.empty() )
1427         {
1428           // by found facets
1429           const TTriangleFacet* facet = &triaSplits.front();
1430           for ( ; iCommon < nbNodes-1 ; ++iCommon )
1431             if ( facet->contains( nInd[ iQ * iCommon ]) &&
1432                  facet->contains( nInd[ iQ * ((iCommon+2)%nbNodes) ]))
1433               break;
1434         }
1435         else if ( nbNodes > 3 && !is24TetMode )
1436         {
1437           // find the best method of splitting into triangles by aspect ratio
1438           SMESH::Controls::NumericalFunctorPtr aspectRatio( new SMESH::Controls::AspectRatio);
1439           map< double, int > badness2iCommon;
1440           const SMDS_MeshNode** nodes = vol.GetFaceNodes( iF );
1441           int nbVariants = ( nbNodes == 4 ? 2 : nbNodes );
1442           for ( int iVar = 0; iVar < nbVariants; ++iVar, ++iCommon )
1443             for ( int iLast = iCommon+2; iLast < iCommon+nbNodes; ++iLast )
1444             {
1445               SMDS_FaceOfNodes tria ( nodes[ iQ*( iCommon         )],
1446                                       nodes[ iQ*((iLast-1)%nbNodes)],
1447                                       nodes[ iQ*((iLast  )%nbNodes)]);
1448               double badness = getBadRate( &tria, aspectRatio );
1449               badness2iCommon.insert( make_pair( badness, iCommon ));
1450             }
1451           // use iCommon with lowest badness
1452           iCommon = badness2iCommon.begin()->second;
1453         }
1454         if ( iCommon >= nbNodes )
1455           iCommon = 0; // something wrong
1456
1457         // fill connectivity of tetrahedra based on a current face
1458         int nbTet = nbNodes - 2;
1459         if ( is24TetMode && nbNodes > 3 && triaSplits.empty())
1460         {
1461           method._faceBaryNode.insert( make_pair( iF, (const SMDS_MeshNode*)0 ));
1462           int faceBaryCenInd = baryCenInd + method._faceBaryNode.size();
1463           nbTet = nbNodes;
1464           for ( int i = 0; i < nbTet; ++i )
1465           {
1466             int i1 = i, i2 = (i+1) % nbNodes;
1467             if ( !vol.IsFaceExternal( iF )) swap( i1, i2 );
1468             connectivity[ connSize++ ] = nInd[ iQ * i1 ];
1469             connectivity[ connSize++ ] = nInd[ iQ * i2 ];
1470             connectivity[ connSize++ ] = faceBaryCenInd;
1471             connectivity[ connSize++ ] = baryCenInd;
1472           }
1473         }
1474         else
1475         {
1476           for ( int i = 0; i < nbTet; ++i )
1477           {
1478             int i1 = (iCommon+1+i) % nbNodes, i2 = (iCommon+2+i) % nbNodes;
1479             if ( !vol.IsFaceExternal( iF )) swap( i1, i2 );
1480             connectivity[ connSize++ ] = nInd[ iQ * iCommon ];
1481             connectivity[ connSize++ ] = nInd[ iQ * i1 ];
1482             connectivity[ connSize++ ] = nInd[ iQ * i2 ];
1483             connectivity[ connSize++ ] = baryCenInd;
1484           }
1485         }
1486         method._nbTetra += nbTet;
1487       }
1488       connectivity[ connSize++ ] = -1;
1489     }
1490     return method;
1491   }
1492   //================================================================================
1493   /*!
1494    * \brief Check if there is a tetraherdon adjacent to the given element via this facet
1495    */
1496   //================================================================================
1497
1498   bool TTriangleFacet::hasAdjacentTetra( const SMDS_MeshElement* elem ) const
1499   {
1500     // find the tetrahedron including the three nodes of facet
1501     const SMDS_MeshNode* n1 = elem->GetNode(_n1);
1502     const SMDS_MeshNode* n2 = elem->GetNode(_n2);
1503     const SMDS_MeshNode* n3 = elem->GetNode(_n3);
1504     SMDS_ElemIteratorPtr volIt1 = n1->GetInverseElementIterator(SMDSAbs_Volume);
1505     while ( volIt1->more() )
1506     {
1507       const SMDS_MeshElement* v = volIt1->next();
1508       if ( v->GetEntityType() != ( v->IsQuadratic() ? SMDSEntity_Quad_Tetra : SMDSEntity_Tetra ))
1509         continue;
1510       SMDS_ElemIteratorPtr volIt2 = n2->GetInverseElementIterator(SMDSAbs_Volume);
1511       while ( volIt2->more() )
1512         if ( v != volIt2->next() )
1513           continue;
1514       SMDS_ElemIteratorPtr volIt3 = n3->GetInverseElementIterator(SMDSAbs_Volume);
1515       while ( volIt3->more() )
1516         if ( v == volIt3->next() )
1517           return true;
1518     }
1519     return false;
1520   }
1521
1522   //=======================================================================
1523   /*!
1524    * \brief A key of a face of volume
1525    */
1526   //=======================================================================
1527
1528   struct TVolumeFaceKey: pair< int, pair< int, int> >
1529   {
1530     TVolumeFaceKey( SMDS_VolumeTool& vol, int iF )
1531     {
1532       TIDSortedNodeSet sortedNodes;
1533       const int iQ = vol.Element()->IsQuadratic() ? 2 : 1;
1534       int nbNodes = vol.NbFaceNodes( iF );
1535       const SMDS_MeshNode** fNodes = vol.GetFaceNodes( iF );
1536       for ( int i = 0; i < nbNodes; i += iQ )
1537         sortedNodes.insert( fNodes[i] );
1538       TIDSortedNodeSet::iterator n = sortedNodes.begin();
1539       first = (*(n++))->GetID();
1540       second.first = (*(n++))->GetID();
1541       second.second = (*(n++))->GetID();
1542     }
1543   };
1544 } // namespace
1545
1546 //=======================================================================
1547 //function : SplitVolumesIntoTetra
1548 //purpose  : Split volumic elements into tetrahedra.
1549 //=======================================================================
1550
1551 void SMESH_MeshEditor::SplitVolumesIntoTetra (const TIDSortedElemSet & theElems,
1552                                               const int                theMethodFlags)
1553 {
1554   // std-like iterator on coordinates of nodes of mesh element
1555   typedef SMDS_StdIterator< TNodeXYZ, SMDS_ElemIteratorPtr > NXyzIterator;
1556   NXyzIterator xyzEnd;
1557
1558   SMDS_VolumeTool    volTool;
1559   SMESH_MesherHelper helper( *GetMesh());
1560
1561   SMESHDS_SubMesh* subMesh = GetMeshDS()->MeshElements(1);
1562   SMESHDS_SubMesh* fSubMesh = subMesh;
1563   
1564   SMESH_SequenceOfElemPtr newNodes, newElems;
1565
1566   // map face of volume to it's baricenrtic node
1567   map< TVolumeFaceKey, const SMDS_MeshNode* > volFace2BaryNode;
1568   double bc[3];
1569
1570   TIDSortedElemSet::const_iterator elem = theElems.begin();
1571   for ( ; elem != theElems.end(); ++elem )
1572   {
1573     SMDSAbs_EntityType geomType = (*elem)->GetEntityType();
1574     if ( geomType <= SMDSEntity_Quad_Tetra )
1575       continue; // tetra or face or ...
1576
1577     if ( !volTool.Set( *elem )) continue; // not volume? strange...
1578
1579     TSplitMethod splitMethod = getSplitMethod( volTool, theMethodFlags );
1580     if ( splitMethod._nbTetra < 1 ) continue;
1581
1582     // find submesh to add new tetras to
1583     if ( !subMesh || !subMesh->Contains( *elem ))
1584     {
1585       int shapeID = FindShape( *elem );
1586       helper.SetSubShape( shapeID ); // helper will add tetras to the found submesh
1587       subMesh = GetMeshDS()->MeshElements( shapeID );
1588     }
1589     int iQ;
1590     if ( (*elem)->IsQuadratic() )
1591     {
1592       iQ = 2;
1593       // add quadratic links to the helper
1594       for ( int iF = 0; iF < volTool.NbFaces(); ++iF )
1595       {
1596         const SMDS_MeshNode** fNodes = volTool.GetFaceNodes( iF );
1597         for ( int iN = 0; iN < volTool.NbFaceNodes( iF ); iN += iQ )
1598           helper.AddTLinkNode( fNodes[iF], fNodes[iF+2], fNodes[iF+1] );
1599       }
1600       helper.SetIsQuadratic( true );
1601     }
1602     else
1603     {
1604       iQ = 1;
1605       helper.SetIsQuadratic( false );
1606     }
1607     vector<const SMDS_MeshNode*> nodes( (*elem)->begin_nodes(), (*elem)->end_nodes() );
1608     if ( splitMethod._baryNode )
1609     {
1610       // make a node at barycenter
1611       volTool.GetBaryCenter( bc[0], bc[1], bc[2] );
1612       SMDS_MeshNode* gcNode = helper.AddNode( bc[0], bc[1], bc[2] );
1613       nodes.push_back( gcNode );
1614       newNodes.Append( gcNode );
1615     }
1616     if ( !splitMethod._faceBaryNode.empty() )
1617     {
1618       // make or find baricentric nodes of faces
1619       map<int, const SMDS_MeshNode*>::iterator iF_n = splitMethod._faceBaryNode.begin();
1620       for ( ; iF_n != splitMethod._faceBaryNode.end(); ++iF_n )
1621       {
1622         map< TVolumeFaceKey, const SMDS_MeshNode* >::iterator f_n =
1623           volFace2BaryNode.insert
1624           ( make_pair( TVolumeFaceKey( volTool,iF_n->first ), (const SMDS_MeshNode*)0) ).first;
1625         if ( !f_n->second )
1626         {
1627           volTool.GetFaceBaryCenter( iF_n->first, bc[0], bc[1], bc[2] );
1628           newNodes.Append( f_n->second = helper.AddNode( bc[0], bc[1], bc[2] ));
1629         }
1630         nodes.push_back( iF_n->second = f_n->second );
1631       }
1632     }
1633
1634     // make tetras
1635     helper.SetElementsOnShape( true );
1636     vector<const SMDS_MeshElement* > tetras( splitMethod._nbTetra ); // splits of a volume
1637     const int* tetConn = splitMethod._connectivity;
1638     for ( int i = 0; i < splitMethod._nbTetra; ++i, tetConn += 4 )
1639       newElems.Append( tetras[ i ] = helper.AddVolume( nodes[ tetConn[0] ],
1640                                                        nodes[ tetConn[1] ],
1641                                                        nodes[ tetConn[2] ],
1642                                                        nodes[ tetConn[3] ]));
1643
1644     ReplaceElemInGroups( *elem, tetras, GetMeshDS() );
1645
1646     // Split faces on sides of the split volume
1647
1648     const SMDS_MeshNode** volNodes = volTool.GetNodes();
1649     for ( int iF = 0; iF < volTool.NbFaces(); ++iF )
1650     {
1651       const int nbNodes = volTool.NbFaceNodes( iF ) / iQ;
1652       if ( nbNodes < 4 ) continue;
1653
1654       // find an existing face
1655       vector<const SMDS_MeshNode*> fNodes( volTool.GetFaceNodes( iF ),
1656                                            volTool.GetFaceNodes( iF ) + nbNodes*iQ );
1657       while ( const SMDS_MeshElement* face = GetMeshDS()->FindFace( fNodes ))
1658       {
1659         // make triangles
1660         helper.SetElementsOnShape( false );
1661         vector< const SMDS_MeshElement* > triangles;
1662
1663         map<int, const SMDS_MeshNode*>::iterator iF_n = splitMethod._faceBaryNode.find(iF);
1664         if ( iF_n != splitMethod._faceBaryNode.end() )
1665         {
1666           for ( int iN = 0; iN < nbNodes*iQ; iN += iQ )
1667           {
1668             const SMDS_MeshNode* n1 = fNodes[iN];
1669             const SMDS_MeshNode *n2 = fNodes[(iN+iQ)%nbNodes*iQ];
1670             const SMDS_MeshNode *n3 = iF_n->second;
1671             if ( !volTool.IsFaceExternal( iF ))
1672               swap( n2, n3 );
1673             triangles.push_back( helper.AddFace( n1,n2,n3 ));
1674           }
1675         }
1676         else
1677         {
1678           // among possible triangles create ones discribed by split method
1679           const int* nInd = volTool.GetFaceNodesIndices( iF );
1680           int nbVariants = ( nbNodes == 4 ? 2 : nbNodes );
1681           int iCom = 0; // common node of triangle faces to split into
1682           list< TTriangleFacet > facets;
1683           for ( int iVar = 0; iVar < nbVariants; ++iVar, ++iCom )
1684           {
1685             TTriangleFacet t012( nInd[ iQ * ( iCom                )],
1686                                  nInd[ iQ * ( (iCom+1)%nbNodes )],
1687                                  nInd[ iQ * ( (iCom+2)%nbNodes )]);
1688             TTriangleFacet t023( nInd[ iQ * ( iCom                )],
1689                                  nInd[ iQ * ( (iCom+2)%nbNodes )],
1690                                  nInd[ iQ * ( (iCom+3)%nbNodes )]);
1691             if ( splitMethod.hasFacet( t012 ) && splitMethod.hasFacet( t023 ))
1692             {
1693               facets.push_back( t012 );
1694               facets.push_back( t023 );
1695               for ( int iLast = iCom+4; iLast < iCom+nbNodes; ++iLast )
1696                 facets.push_back( TTriangleFacet( nInd[ iQ * ( iCom             )],
1697                                                   nInd[ iQ * ((iLast-1)%nbNodes )],
1698                                                   nInd[ iQ * ((iLast  )%nbNodes )]));
1699               break;
1700             }
1701           }
1702           list< TTriangleFacet >::iterator facet = facets.begin();
1703           for ( ; facet != facets.end(); ++facet )
1704           {
1705             if ( !volTool.IsFaceExternal( iF ))
1706               swap( facet->_n2, facet->_n3 );
1707             triangles.push_back( helper.AddFace( volNodes[ facet->_n1 ],
1708                                                  volNodes[ facet->_n2 ],
1709                                                  volNodes[ facet->_n3 ]));
1710           }
1711         }
1712         // find submesh to add new triangles in
1713         if ( !fSubMesh || !fSubMesh->Contains( face ))
1714         {
1715           int shapeID = FindShape( face );
1716           fSubMesh = GetMeshDS()->MeshElements( shapeID );
1717         }
1718         for ( int i = 0; i < triangles.size(); ++i )
1719         {
1720           if ( !triangles.back() ) continue;
1721           if ( fSubMesh )
1722             fSubMesh->AddElement( triangles.back());
1723           newElems.Append( triangles.back() );
1724         }
1725         ReplaceElemInGroups( face, triangles, GetMeshDS() );
1726         GetMeshDS()->RemoveFreeElement( face, fSubMesh, /*fromGroups=*/false );
1727       }
1728
1729     } // loop on volume faces to split them into triangles
1730
1731     GetMeshDS()->RemoveFreeElement( *elem, subMesh, /*fromGroups=*/false );
1732
1733   } // loop on volumes to split
1734
1735   myLastCreatedNodes = newNodes;
1736   myLastCreatedElems = newElems;
1737 }
1738
1739 //=======================================================================
1740 //function : AddToSameGroups
1741 //purpose  : add elemToAdd to the groups the elemInGroups belongs to
1742 //=======================================================================
1743
1744 void SMESH_MeshEditor::AddToSameGroups (const SMDS_MeshElement* elemToAdd,
1745                                         const SMDS_MeshElement* elemInGroups,
1746                                         SMESHDS_Mesh *          aMesh)
1747 {
1748   const set<SMESHDS_GroupBase*>& groups = aMesh->GetGroups();
1749   if (!groups.empty()) {
1750     set<SMESHDS_GroupBase*>::const_iterator grIt = groups.begin();
1751     for ( ; grIt != groups.end(); grIt++ ) {
1752       SMESHDS_Group* group = dynamic_cast<SMESHDS_Group*>( *grIt );
1753       if ( group && group->Contains( elemInGroups ))
1754         group->SMDSGroup().Add( elemToAdd );
1755     }
1756   }
1757 }
1758
1759
1760 //=======================================================================
1761 //function : RemoveElemFromGroups
1762 //purpose  : Remove removeelem to the groups the elemInGroups belongs to
1763 //=======================================================================
1764 void SMESH_MeshEditor::RemoveElemFromGroups (const SMDS_MeshElement* removeelem,
1765                                              SMESHDS_Mesh *          aMesh)
1766 {
1767   const set<SMESHDS_GroupBase*>& groups = aMesh->GetGroups();
1768   if (!groups.empty())
1769   {
1770     set<SMESHDS_GroupBase*>::const_iterator GrIt = groups.begin();
1771     for (; GrIt != groups.end(); GrIt++)
1772     {
1773       SMESHDS_Group* grp = dynamic_cast<SMESHDS_Group*>(*GrIt);
1774       if (!grp || grp->IsEmpty()) continue;
1775       grp->SMDSGroup().Remove(removeelem);
1776     }
1777   }
1778 }
1779
1780 //================================================================================
1781 /*!
1782  * \brief Replace elemToRm by elemToAdd in the all groups
1783  */
1784 //================================================================================
1785
1786 void SMESH_MeshEditor::ReplaceElemInGroups (const SMDS_MeshElement* elemToRm,
1787                                             const SMDS_MeshElement* elemToAdd,
1788                                             SMESHDS_Mesh *          aMesh)
1789 {
1790   const set<SMESHDS_GroupBase*>& groups = aMesh->GetGroups();
1791   if (!groups.empty()) {
1792     set<SMESHDS_GroupBase*>::const_iterator grIt = groups.begin();
1793     for ( ; grIt != groups.end(); grIt++ ) {
1794       SMESHDS_Group* group = dynamic_cast<SMESHDS_Group*>( *grIt );
1795       if ( group && group->SMDSGroup().Remove( elemToRm ) && elemToAdd )
1796         group->SMDSGroup().Add( elemToAdd );
1797     }
1798   }
1799 }
1800
1801 //================================================================================
1802 /*!
1803  * \brief Replace elemToRm by elemToAdd in the all groups
1804  */
1805 //================================================================================
1806
1807 void SMESH_MeshEditor::ReplaceElemInGroups (const SMDS_MeshElement*                elemToRm,
1808                                             const vector<const SMDS_MeshElement*>& elemToAdd,
1809                                             SMESHDS_Mesh *                         aMesh)
1810 {
1811   const set<SMESHDS_GroupBase*>& groups = aMesh->GetGroups();
1812   if (!groups.empty())
1813   {
1814     set<SMESHDS_GroupBase*>::const_iterator grIt = groups.begin();
1815     for ( ; grIt != groups.end(); grIt++ ) {
1816       SMESHDS_Group* group = dynamic_cast<SMESHDS_Group*>( *grIt );
1817       if ( group && group->SMDSGroup().Remove( elemToRm ) )
1818         for ( int i = 0; i < elemToAdd.size(); ++i )
1819           group->SMDSGroup().Add( elemToAdd[ i ] );
1820     }
1821   }
1822 }
1823
1824 //=======================================================================
1825 //function : QuadToTri
1826 //purpose  : Cut quadrangles into triangles.
1827 //           theCrit is used to select a diagonal to cut
1828 //=======================================================================
1829
1830 bool SMESH_MeshEditor::QuadToTri (TIDSortedElemSet & theElems,
1831                                   const bool         the13Diag)
1832 {
1833   myLastCreatedElems.Clear();
1834   myLastCreatedNodes.Clear();
1835
1836   MESSAGE( "::QuadToTri()" );
1837
1838   SMESHDS_Mesh * aMesh = GetMeshDS();
1839
1840   Handle(Geom_Surface) surface;
1841   SMESH_MesherHelper   helper( *GetMesh() );
1842
1843   TIDSortedElemSet::iterator itElem;
1844   for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
1845     const SMDS_MeshElement* elem = *itElem;
1846     if ( !elem || elem->GetType() != SMDSAbs_Face )
1847       continue;
1848     bool isquad = elem->NbNodes()==4 || elem->NbNodes()==8;
1849     if(!isquad) continue;
1850
1851     if(elem->NbNodes()==4) {
1852       // retrieve element nodes
1853       const SMDS_MeshNode* aNodes [4];
1854       SMDS_ElemIteratorPtr itN = elem->nodesIterator();
1855       int i = 0;
1856       while ( itN->more() )
1857         aNodes[ i++ ] = static_cast<const SMDS_MeshNode*>( itN->next() );
1858
1859       int aShapeId = FindShape( elem );
1860       const SMDS_MeshElement* newElem1 = 0;
1861       const SMDS_MeshElement* newElem2 = 0;
1862       if ( the13Diag ) {
1863         newElem1 = aMesh->AddFace( aNodes[2], aNodes[0], aNodes[1] );
1864         newElem2 = aMesh->AddFace( aNodes[2], aNodes[3], aNodes[0] );
1865       }
1866       else {
1867         newElem1 = aMesh->AddFace( aNodes[3], aNodes[0], aNodes[1] );
1868         newElem2 = aMesh->AddFace( aNodes[3], aNodes[1], aNodes[2] );
1869       }
1870       myLastCreatedElems.Append(newElem1);
1871       myLastCreatedElems.Append(newElem2);
1872       // put a new triangle on the same shape and add to the same groups
1873       if ( aShapeId )
1874         {
1875           aMesh->SetMeshElementOnShape( newElem1, aShapeId );
1876           aMesh->SetMeshElementOnShape( newElem2, aShapeId );
1877         }
1878       AddToSameGroups( newElem1, elem, aMesh );
1879       AddToSameGroups( newElem2, elem, aMesh );
1880       //aMesh->RemoveFreeElement(elem, aMesh->MeshElements(aShapeId), true);
1881       aMesh->RemoveElement( elem );
1882     }
1883
1884     // Quadratic quadrangle
1885
1886     if( elem->NbNodes()==8 && elem->IsQuadratic() ) {
1887
1888       // get surface elem is on
1889       int aShapeId = FindShape( elem );
1890       if ( aShapeId != helper.GetSubShapeID() ) {
1891         surface.Nullify();
1892         TopoDS_Shape shape;
1893         if ( aShapeId > 0 )
1894           shape = aMesh->IndexToShape( aShapeId );
1895         if ( !shape.IsNull() && shape.ShapeType() == TopAbs_FACE ) {
1896           TopoDS_Face face = TopoDS::Face( shape );
1897           surface = BRep_Tool::Surface( face );
1898           if ( !surface.IsNull() )
1899             helper.SetSubShape( shape );
1900         }
1901       }
1902
1903       const SMDS_MeshNode* aNodes [8];
1904       const SMDS_MeshNode* inFaceNode = 0;
1905       SMDS_ElemIteratorPtr itN = elem->nodesIterator();
1906       int i = 0;
1907       while ( itN->more() ) {
1908         aNodes[ i++ ] = static_cast<const SMDS_MeshNode*>( itN->next() );
1909         if ( !inFaceNode && helper.GetNodeUVneedInFaceNode() &&
1910              aNodes[ i-1 ]->GetPosition()->GetTypeOfPosition() == SMDS_TOP_FACE )
1911         {
1912           inFaceNode = aNodes[ i-1 ];
1913         }
1914       }
1915
1916       // find middle point for (0,1,2,3)
1917       // and create a node in this point;
1918       gp_XYZ p( 0,0,0 );
1919       if ( surface.IsNull() ) {
1920         for(i=0; i<4; i++)
1921           p += gp_XYZ(aNodes[i]->X(), aNodes[i]->Y(), aNodes[i]->Z() );
1922         p /= 4;
1923       }
1924       else {
1925         TopoDS_Face geomFace = TopoDS::Face( helper.GetSubShape() );
1926         gp_XY uv( 0,0 );
1927         for(i=0; i<4; i++)
1928           uv += helper.GetNodeUV( geomFace, aNodes[i], inFaceNode );
1929         uv /= 4.;
1930         p = surface->Value( uv.X(), uv.Y() ).XYZ();
1931       }
1932       const SMDS_MeshNode* newN = aMesh->AddNode( p.X(), p.Y(), p.Z() );
1933       myLastCreatedNodes.Append(newN);
1934
1935       // create a new element
1936       const SMDS_MeshElement* newElem1 = 0;
1937       const SMDS_MeshElement* newElem2 = 0;
1938       const SMDS_MeshNode* N[6];
1939       if ( the13Diag ) {
1940         N[0] = aNodes[0];
1941         N[1] = aNodes[1];
1942         N[2] = aNodes[2];
1943         N[3] = aNodes[4];
1944         N[4] = aNodes[5];
1945         N[5] = newN;
1946         newElem1 = aMesh->AddFace(aNodes[2], aNodes[3], aNodes[0],
1947                                   aNodes[6], aNodes[7], newN );
1948         newElem2 = aMesh->AddFace(aNodes[2], aNodes[0], aNodes[1],
1949                                   newN,      aNodes[4], aNodes[5] );
1950       }
1951       else {
1952         N[0] = aNodes[1];
1953         N[1] = aNodes[2];
1954         N[2] = aNodes[3];
1955         N[3] = aNodes[5];
1956         N[4] = aNodes[6];
1957         N[5] = newN;
1958         newElem1 = aMesh->AddFace(aNodes[3], aNodes[0], aNodes[1],
1959                                   aNodes[7], aNodes[4], newN );
1960         newElem2 = aMesh->AddFace(aNodes[3], aNodes[1], aNodes[2],
1961                                   newN,      aNodes[5], aNodes[6] );
1962       }
1963       myLastCreatedElems.Append(newElem1);
1964       myLastCreatedElems.Append(newElem2);
1965       // put a new triangle on the same shape and add to the same groups
1966       if ( aShapeId )
1967         {
1968           aMesh->SetMeshElementOnShape( newElem1, aShapeId );
1969           aMesh->SetMeshElementOnShape( newElem2, aShapeId );
1970         }
1971       AddToSameGroups( newElem1, elem, aMesh );
1972       AddToSameGroups( newElem2, elem, aMesh );
1973       aMesh->RemoveElement( elem );
1974     }
1975   }
1976
1977   return true;
1978 }
1979
1980 //=======================================================================
1981 //function : getAngle
1982 //purpose  :
1983 //=======================================================================
1984
1985 double getAngle(const SMDS_MeshElement * tr1,
1986                 const SMDS_MeshElement * tr2,
1987                 const SMDS_MeshNode *    n1,
1988                 const SMDS_MeshNode *    n2)
1989 {
1990   double angle = 2*PI; // bad angle
1991
1992   // get normals
1993   SMESH::Controls::TSequenceOfXYZ P1, P2;
1994   if ( !SMESH::Controls::NumericalFunctor::GetPoints( tr1, P1 ) ||
1995        !SMESH::Controls::NumericalFunctor::GetPoints( tr2, P2 ))
1996     return angle;
1997   gp_Vec N1,N2;
1998   if(!tr1->IsQuadratic())
1999     N1 = gp_Vec( P1(2) - P1(1) ) ^ gp_Vec( P1(3) - P1(1) );
2000   else
2001     N1 = gp_Vec( P1(3) - P1(1) ) ^ gp_Vec( P1(5) - P1(1) );
2002   if ( N1.SquareMagnitude() <= gp::Resolution() )
2003     return angle;
2004   if(!tr2->IsQuadratic())
2005     N2 = gp_Vec( P2(2) - P2(1) ) ^ gp_Vec( P2(3) - P2(1) );
2006   else
2007     N2 = gp_Vec( P2(3) - P2(1) ) ^ gp_Vec( P2(5) - P2(1) );
2008   if ( N2.SquareMagnitude() <= gp::Resolution() )
2009     return angle;
2010
2011   // find the first diagonal node n1 in the triangles:
2012   // take in account a diagonal link orientation
2013   const SMDS_MeshElement *nFirst[2], *tr[] = { tr1, tr2 };
2014   for ( int t = 0; t < 2; t++ ) {
2015     SMDS_ElemIteratorPtr it = tr[ t ]->nodesIterator();
2016     int i = 0, iDiag = -1;
2017     while ( it->more()) {
2018       const SMDS_MeshElement *n = it->next();
2019       if ( n == n1 || n == n2 ) {
2020         if ( iDiag < 0)
2021           iDiag = i;
2022         else {
2023           if ( i - iDiag == 1 )
2024             nFirst[ t ] = ( n == n1 ? n2 : n1 );
2025           else
2026             nFirst[ t ] = n;
2027           break;
2028         }
2029       }
2030       i++;
2031     }
2032   }
2033   if ( nFirst[ 0 ] == nFirst[ 1 ] )
2034     N2.Reverse();
2035
2036   angle = N1.Angle( N2 );
2037   //SCRUTE( angle );
2038   return angle;
2039 }
2040
2041 // =================================================
2042 // class generating a unique ID for a pair of nodes
2043 // and able to return nodes by that ID
2044 // =================================================
2045 class LinkID_Gen {
2046 public:
2047
2048   LinkID_Gen( const SMESHDS_Mesh* theMesh )
2049     :myMesh( theMesh ), myMaxID( theMesh->MaxNodeID() + 1)
2050   {}
2051
2052   long GetLinkID (const SMDS_MeshNode * n1,
2053                   const SMDS_MeshNode * n2) const
2054   {
2055     return ( Min(n1->GetID(),n2->GetID()) * myMaxID + Max(n1->GetID(),n2->GetID()));
2056   }
2057
2058   bool GetNodes (const long             theLinkID,
2059                  const SMDS_MeshNode* & theNode1,
2060                  const SMDS_MeshNode* & theNode2) const
2061   {
2062     theNode1 = myMesh->FindNode( theLinkID / myMaxID );
2063     if ( !theNode1 ) return false;
2064     theNode2 = myMesh->FindNode( theLinkID % myMaxID );
2065     if ( !theNode2 ) return false;
2066     return true;
2067   }
2068
2069 private:
2070   LinkID_Gen();
2071   const SMESHDS_Mesh* myMesh;
2072   long                myMaxID;
2073 };
2074
2075
2076 //=======================================================================
2077 //function : TriToQuad
2078 //purpose  : Fuse neighbour triangles into quadrangles.
2079 //           theCrit is used to select a neighbour to fuse with.
2080 //           theMaxAngle is a max angle between element normals at which
2081 //           fusion is still performed.
2082 //=======================================================================
2083
2084 bool SMESH_MeshEditor::TriToQuad (TIDSortedElemSet &                   theElems,
2085                                   SMESH::Controls::NumericalFunctorPtr theCrit,
2086                                   const double                         theMaxAngle)
2087 {
2088   myLastCreatedElems.Clear();
2089   myLastCreatedNodes.Clear();
2090
2091   MESSAGE( "::TriToQuad()" );
2092
2093   if ( !theCrit.get() )
2094     return false;
2095
2096   SMESHDS_Mesh * aMesh = GetMeshDS();
2097
2098   // Prepare data for algo: build
2099   // 1. map of elements with their linkIDs
2100   // 2. map of linkIDs with their elements
2101
2102   map< SMESH_TLink, list< const SMDS_MeshElement* > > mapLi_listEl;
2103   map< SMESH_TLink, list< const SMDS_MeshElement* > >::iterator itLE;
2104   map< const SMDS_MeshElement*, set< SMESH_TLink > >  mapEl_setLi;
2105   map< const SMDS_MeshElement*, set< SMESH_TLink > >::iterator itEL;
2106
2107   TIDSortedElemSet::iterator itElem;
2108   for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
2109     const SMDS_MeshElement* elem = *itElem;
2110     if(!elem || elem->GetType() != SMDSAbs_Face ) continue;
2111     bool IsTria = elem->NbNodes()==3 || (elem->NbNodes()==6 && elem->IsQuadratic());
2112     if(!IsTria) continue;
2113
2114     // retrieve element nodes
2115     const SMDS_MeshNode* aNodes [4];
2116     SMDS_ElemIteratorPtr itN = elem->nodesIterator();
2117     int i = 0;
2118     while ( i<3 )
2119       aNodes[ i++ ] = cast2Node( itN->next() );
2120     aNodes[ 3 ] = aNodes[ 0 ];
2121
2122     // fill maps
2123     for ( i = 0; i < 3; i++ ) {
2124       SMESH_TLink link( aNodes[i], aNodes[i+1] );
2125       // check if elements sharing a link can be fused
2126       itLE = mapLi_listEl.find( link );
2127       if ( itLE != mapLi_listEl.end() ) {
2128         if ((*itLE).second.size() > 1 ) // consider only 2 elems adjacent by a link
2129           continue;
2130         const SMDS_MeshElement* elem2 = (*itLE).second.front();
2131         //if ( FindShape( elem ) != FindShape( elem2 ))
2132         //  continue; // do not fuse triangles laying on different shapes
2133         if ( getAngle( elem, elem2, aNodes[i], aNodes[i+1] ) > theMaxAngle )
2134           continue; // avoid making badly shaped quads
2135         (*itLE).second.push_back( elem );
2136       }
2137       else {
2138         mapLi_listEl[ link ].push_back( elem );
2139       }
2140       mapEl_setLi [ elem ].insert( link );
2141     }
2142   }
2143   // Clean the maps from the links shared by a sole element, ie
2144   // links to which only one element is bound in mapLi_listEl
2145
2146   for ( itLE = mapLi_listEl.begin(); itLE != mapLi_listEl.end(); itLE++ ) {
2147     int nbElems = (*itLE).second.size();
2148     if ( nbElems < 2  ) {
2149       const SMDS_MeshElement* elem = (*itLE).second.front();
2150       SMESH_TLink link = (*itLE).first;
2151       mapEl_setLi[ elem ].erase( link );
2152       if ( mapEl_setLi[ elem ].empty() )
2153         mapEl_setLi.erase( elem );
2154     }
2155   }
2156
2157   // Algo: fuse triangles into quadrangles
2158
2159   while ( ! mapEl_setLi.empty() ) {
2160     // Look for the start element:
2161     // the element having the least nb of shared links
2162     const SMDS_MeshElement* startElem = 0;
2163     int minNbLinks = 4;
2164     for ( itEL = mapEl_setLi.begin(); itEL != mapEl_setLi.end(); itEL++ ) {
2165       int nbLinks = (*itEL).second.size();
2166       if ( nbLinks < minNbLinks ) {
2167         startElem = (*itEL).first;
2168         minNbLinks = nbLinks;
2169         if ( minNbLinks == 1 )
2170           break;
2171       }
2172     }
2173
2174     // search elements to fuse starting from startElem or links of elements
2175     // fused earlyer - startLinks
2176     list< SMESH_TLink > startLinks;
2177     while ( startElem || !startLinks.empty() ) {
2178       while ( !startElem && !startLinks.empty() ) {
2179         // Get an element to start, by a link
2180         SMESH_TLink linkId = startLinks.front();
2181         startLinks.pop_front();
2182         itLE = mapLi_listEl.find( linkId );
2183         if ( itLE != mapLi_listEl.end() ) {
2184           list< const SMDS_MeshElement* > & listElem = (*itLE).second;
2185           list< const SMDS_MeshElement* >::iterator itE = listElem.begin();
2186           for ( ; itE != listElem.end() ; itE++ )
2187             if ( mapEl_setLi.find( (*itE) ) != mapEl_setLi.end() )
2188               startElem = (*itE);
2189           mapLi_listEl.erase( itLE );
2190         }
2191       }
2192
2193       if ( startElem ) {
2194         // Get candidates to be fused
2195         const SMDS_MeshElement *tr1 = startElem, *tr2 = 0, *tr3 = 0;
2196         const SMESH_TLink *link12, *link13;
2197         startElem = 0;
2198         ASSERT( mapEl_setLi.find( tr1 ) != mapEl_setLi.end() );
2199         set< SMESH_TLink >& setLi = mapEl_setLi[ tr1 ];
2200         ASSERT( !setLi.empty() );
2201         set< SMESH_TLink >::iterator itLi;
2202         for ( itLi = setLi.begin(); itLi != setLi.end(); itLi++ )
2203         {
2204           const SMESH_TLink & link = (*itLi);
2205           itLE = mapLi_listEl.find( link );
2206           if ( itLE == mapLi_listEl.end() )
2207             continue;
2208
2209           const SMDS_MeshElement* elem = (*itLE).second.front();
2210           if ( elem == tr1 )
2211             elem = (*itLE).second.back();
2212           mapLi_listEl.erase( itLE );
2213           if ( mapEl_setLi.find( elem ) == mapEl_setLi.end())
2214             continue;
2215           if ( tr2 ) {
2216             tr3 = elem;
2217             link13 = &link;
2218           }
2219           else {
2220             tr2 = elem;
2221             link12 = &link;
2222           }
2223
2224           // add other links of elem to list of links to re-start from
2225           set< SMESH_TLink >& links = mapEl_setLi[ elem ];
2226           set< SMESH_TLink >::iterator it;
2227           for ( it = links.begin(); it != links.end(); it++ ) {
2228             const SMESH_TLink& link2 = (*it);
2229             if ( link2 != link )
2230               startLinks.push_back( link2 );
2231           }
2232         }
2233
2234         // Get nodes of possible quadrangles
2235         const SMDS_MeshNode *n12 [4], *n13 [4];
2236         bool Ok12 = false, Ok13 = false;
2237         const SMDS_MeshNode *linkNode1, *linkNode2;
2238         if(tr2) {
2239           linkNode1 = link12->first;
2240           linkNode2 = link12->second;
2241           if ( tr2 && getQuadrangleNodes( n12, linkNode1, linkNode2, tr1, tr2 ))
2242             Ok12 = true;
2243         }
2244         if(tr3) {
2245           linkNode1 = link13->first;
2246           linkNode2 = link13->second;
2247           if ( tr3 && getQuadrangleNodes( n13, linkNode1, linkNode2, tr1, tr3 ))
2248             Ok13 = true;
2249         }
2250
2251         // Choose a pair to fuse
2252         if ( Ok12 && Ok13 ) {
2253           SMDS_FaceOfNodes quad12 ( n12[ 0 ], n12[ 1 ], n12[ 2 ], n12[ 3 ] );
2254           SMDS_FaceOfNodes quad13 ( n13[ 0 ], n13[ 1 ], n13[ 2 ], n13[ 3 ] );
2255           double aBadRate12 = getBadRate( &quad12, theCrit );
2256           double aBadRate13 = getBadRate( &quad13, theCrit );
2257           if (  aBadRate13 < aBadRate12 )
2258             Ok12 = false;
2259           else
2260             Ok13 = false;
2261         }
2262
2263         // Make quadrangles
2264         // and remove fused elems and removed links from the maps
2265         mapEl_setLi.erase( tr1 );
2266         if ( Ok12 ) {
2267           mapEl_setLi.erase( tr2 );
2268           mapLi_listEl.erase( *link12 );
2269           if(tr1->NbNodes()==3) {
2270             const SMDS_MeshElement* newElem = 0;
2271             newElem = aMesh->AddFace(n12[0], n12[1], n12[2], n12[3] );
2272             myLastCreatedElems.Append(newElem);
2273             AddToSameGroups( newElem, tr1, aMesh );
2274             int aShapeId = tr1->getshapeId();
2275             if ( aShapeId )
2276               {
2277                 aMesh->SetMeshElementOnShape( newElem, aShapeId );
2278               }
2279             aMesh->RemoveElement( tr1 );
2280             aMesh->RemoveElement( tr2 );
2281           }
2282           else {
2283             const SMDS_MeshNode* N1 [6];
2284             const SMDS_MeshNode* N2 [6];
2285             GetNodesFromTwoTria(tr1,tr2,N1,N2);
2286             // now we receive following N1 and N2 (using numeration as above image)
2287             // tria1 : (1 2 4 5 9 7)  and  tria2 : (3 4 2 8 9 6)
2288             // i.e. first nodes from both arrays determ new diagonal
2289             const SMDS_MeshNode* aNodes[8];
2290             aNodes[0] = N1[0];
2291             aNodes[1] = N1[1];
2292             aNodes[2] = N2[0];
2293             aNodes[3] = N2[1];
2294             aNodes[4] = N1[3];
2295             aNodes[5] = N2[5];
2296             aNodes[6] = N2[3];
2297             aNodes[7] = N1[5];
2298             const SMDS_MeshElement* newElem = 0;
2299             newElem = aMesh->AddFace(aNodes[0], aNodes[1], aNodes[2], aNodes[3],
2300                                      aNodes[4], aNodes[5], aNodes[6], aNodes[7]);
2301             myLastCreatedElems.Append(newElem);
2302             AddToSameGroups( newElem, tr1, aMesh );
2303             int aShapeId = tr1->getshapeId();
2304             if ( aShapeId )
2305               {
2306                 aMesh->SetMeshElementOnShape( newElem, aShapeId );
2307               }
2308             aMesh->RemoveElement( tr1 );
2309             aMesh->RemoveElement( tr2 );
2310             // remove middle node (9)
2311             GetMeshDS()->RemoveNode( N1[4] );
2312           }
2313         }
2314         else if ( Ok13 ) {
2315           mapEl_setLi.erase( tr3 );
2316           mapLi_listEl.erase( *link13 );
2317           if(tr1->NbNodes()==3) {
2318             const SMDS_MeshElement* newElem = 0;
2319             newElem = aMesh->AddFace(n13[0], n13[1], n13[2], n13[3] );
2320             myLastCreatedElems.Append(newElem);
2321             AddToSameGroups( newElem, tr1, aMesh );
2322             int aShapeId = tr1->getshapeId();
2323             if ( aShapeId )
2324               {
2325                 aMesh->SetMeshElementOnShape( newElem, aShapeId );
2326               }
2327             aMesh->RemoveElement( tr1 );
2328             aMesh->RemoveElement( tr3 );
2329           }
2330           else {
2331             const SMDS_MeshNode* N1 [6];
2332             const SMDS_MeshNode* N2 [6];
2333             GetNodesFromTwoTria(tr1,tr3,N1,N2);
2334             // now we receive following N1 and N2 (using numeration as above image)
2335             // tria1 : (1 2 4 5 9 7)  and  tria2 : (3 4 2 8 9 6)
2336             // i.e. first nodes from both arrays determ new diagonal
2337             const SMDS_MeshNode* aNodes[8];
2338             aNodes[0] = N1[0];
2339             aNodes[1] = N1[1];
2340             aNodes[2] = N2[0];
2341             aNodes[3] = N2[1];
2342             aNodes[4] = N1[3];
2343             aNodes[5] = N2[5];
2344             aNodes[6] = N2[3];
2345             aNodes[7] = N1[5];
2346             const SMDS_MeshElement* newElem = 0;
2347             newElem = aMesh->AddFace(aNodes[0], aNodes[1], aNodes[2], aNodes[3],
2348                                      aNodes[4], aNodes[5], aNodes[6], aNodes[7]);
2349             myLastCreatedElems.Append(newElem);
2350             AddToSameGroups( newElem, tr1, aMesh );
2351             int aShapeId = tr1->getshapeId();
2352             if ( aShapeId )
2353               {
2354                 aMesh->SetMeshElementOnShape( newElem, aShapeId );
2355               }
2356             aMesh->RemoveElement( tr1 );
2357             aMesh->RemoveElement( tr3 );
2358             // remove middle node (9)
2359             GetMeshDS()->RemoveNode( N1[4] );
2360           }
2361         }
2362
2363         // Next element to fuse: the rejected one
2364         if ( tr3 )
2365           startElem = Ok12 ? tr3 : tr2;
2366
2367       } // if ( startElem )
2368     } // while ( startElem || !startLinks.empty() )
2369   } // while ( ! mapEl_setLi.empty() )
2370
2371   return true;
2372 }
2373
2374
2375 /*#define DUMPSO(txt) \
2376 //  cout << txt << endl;
2377 //=============================================================================
2378 //
2379 //
2380 //
2381 //=============================================================================
2382 static void swap( int i1, int i2, int idNodes[], gp_Pnt P[] )
2383 {
2384 if ( i1 == i2 )
2385 return;
2386 int tmp = idNodes[ i1 ];
2387 idNodes[ i1 ] = idNodes[ i2 ];
2388 idNodes[ i2 ] = tmp;
2389 gp_Pnt Ptmp = P[ i1 ];
2390 P[ i1 ] = P[ i2 ];
2391 P[ i2 ] = Ptmp;
2392 DUMPSO( i1 << "(" << idNodes[ i2 ] << ") <-> " << i2 << "(" << idNodes[ i1 ] << ")");
2393 }
2394
2395 //=======================================================================
2396 //function : SortQuadNodes
2397 //purpose  : Set 4 nodes of a quadrangle face in a good order.
2398 //           Swap 1<->2 or 2<->3 nodes and correspondingly return
2399 //           1 or 2 else 0.
2400 //=======================================================================
2401
2402 int SMESH_MeshEditor::SortQuadNodes (const SMDS_Mesh * theMesh,
2403 int               idNodes[] )
2404 {
2405   gp_Pnt P[4];
2406   int i;
2407   for ( i = 0; i < 4; i++ ) {
2408     const SMDS_MeshNode *n = theMesh->FindNode( idNodes[i] );
2409     if ( !n ) return 0;
2410     P[ i ].SetCoord( n->X(), n->Y(), n->Z() );
2411   }
2412
2413   gp_Vec V1(P[0], P[1]);
2414   gp_Vec V2(P[0], P[2]);
2415   gp_Vec V3(P[0], P[3]);
2416
2417   gp_Vec Cross1 = V1 ^ V2;
2418   gp_Vec Cross2 = V2 ^ V3;
2419
2420   i = 0;
2421   if (Cross1.Dot(Cross2) < 0)
2422   {
2423     Cross1 = V2 ^ V1;
2424     Cross2 = V1 ^ V3;
2425
2426     if (Cross1.Dot(Cross2) < 0)
2427       i = 2;
2428     else
2429       i = 1;
2430     swap ( i, i + 1, idNodes, P );
2431
2432     //     for ( int ii = 0; ii < 4; ii++ ) {
2433     //       const SMDS_MeshNode *n = theMesh->FindNode( idNodes[ii] );
2434     //       DUMPSO( ii << "(" << idNodes[ii] <<") : "<<n->X()<<" "<<n->Y()<<" "<<n->Z());
2435     //     }
2436   }
2437   return i;
2438 }
2439
2440 //=======================================================================
2441 //function : SortHexaNodes
2442 //purpose  : Set 8 nodes of a hexahedron in a good order.
2443 //           Return success status
2444 //=======================================================================
2445
2446 bool SMESH_MeshEditor::SortHexaNodes (const SMDS_Mesh * theMesh,
2447                                       int               idNodes[] )
2448 {
2449   gp_Pnt P[8];
2450   int i;
2451   DUMPSO( "INPUT: ========================================");
2452   for ( i = 0; i < 8; i++ ) {
2453     const SMDS_MeshNode *n = theMesh->FindNode( idNodes[i] );
2454     if ( !n ) return false;
2455     P[ i ].SetCoord( n->X(), n->Y(), n->Z() );
2456     DUMPSO( i << "(" << idNodes[i] <<") : "<<n->X()<<" "<<n->Y()<<" "<<n->Z());
2457   }
2458   DUMPSO( "========================================");
2459
2460
2461   set<int> faceNodes;  // ids of bottom face nodes, to be found
2462   set<int> checkedId1; // ids of tried 2-nd nodes
2463   Standard_Real leastDist = DBL_MAX; // dist of the 4-th node from 123 plane
2464   const Standard_Real tol = 1.e-6;   // tolerance to find nodes in plane
2465   int iMin, iLoop1 = 0;
2466
2467   // Loop to try the 2-nd nodes
2468
2469   while ( leastDist > DBL_MIN && ++iLoop1 < 8 )
2470   {
2471     // Find not checked 2-nd node
2472     for ( i = 1; i < 8; i++ )
2473       if ( checkedId1.find( idNodes[i] ) == checkedId1.end() ) {
2474         int id1 = idNodes[i];
2475         swap ( 1, i, idNodes, P );
2476         checkedId1.insert ( id1 );
2477         break;
2478       }
2479
2480     // Find the 3-d node so that 1-2-3 triangle to be on a hexa face,
2481     // ie that all but meybe one (id3 which is on the same face) nodes
2482     // lay on the same side from the triangle plane.
2483
2484     bool manyInPlane = false; // more than 4 nodes lay in plane
2485     int iLoop2 = 0;
2486     while ( ++iLoop2 < 6 ) {
2487
2488       // get 1-2-3 plane coeffs
2489       Standard_Real A, B, C, D;
2490       gp_Vec N = gp_Vec (P[0], P[1]).Crossed( gp_Vec (P[0], P[2]) );
2491       if ( N.SquareMagnitude() > gp::Resolution() )
2492       {
2493         gp_Pln pln ( P[0], N );
2494         pln.Coefficients( A, B, C, D );
2495
2496         // find the node (iMin) closest to pln
2497         Standard_Real dist[ 8 ], minDist = DBL_MAX;
2498         set<int> idInPln;
2499         for ( i = 3; i < 8; i++ ) {
2500           dist[i] = A * P[i].X() + B * P[i].Y() + C * P[i].Z() + D;
2501           if ( fabs( dist[i] ) < minDist ) {
2502             minDist = fabs( dist[i] );
2503             iMin = i;
2504           }
2505           if ( fabs( dist[i] ) <= tol )
2506             idInPln.insert( idNodes[i] );
2507         }
2508
2509         // there should not be more than 4 nodes in bottom plane
2510         if ( idInPln.size() > 1 )
2511         {
2512           DUMPSO( "### idInPln.size() = " << idInPln.size());
2513           // idInPlane does not contain the first 3 nodes
2514           if ( manyInPlane || idInPln.size() == 5)
2515             return false; // all nodes in one plane
2516           manyInPlane = true;
2517
2518           // set the 1-st node to be not in plane
2519           for ( i = 3; i < 8; i++ ) {
2520             if ( idInPln.find( idNodes[ i ] ) == idInPln.end() ) {
2521               DUMPSO( "### Reset 0-th node");
2522               swap( 0, i, idNodes, P );
2523               break;
2524             }
2525           }
2526
2527           // reset to re-check second nodes
2528           leastDist = DBL_MAX;
2529           faceNodes.clear();
2530           checkedId1.clear();
2531           iLoop1 = 0;
2532           break; // from iLoop2;
2533         }
2534
2535         // check that the other 4 nodes are on the same side
2536         bool sameSide = true;
2537         bool isNeg = dist[ iMin == 3 ? 4 : 3 ] <= 0.;
2538         for ( i = 3; sameSide && i < 8; i++ ) {
2539           if ( i != iMin )
2540             sameSide = ( isNeg == dist[i] <= 0.);
2541         }
2542
2543         // keep best solution
2544         if ( sameSide && minDist < leastDist ) {
2545           leastDist = minDist;
2546           faceNodes.clear();
2547           faceNodes.insert( idNodes[ 1 ] );
2548           faceNodes.insert( idNodes[ 2 ] );
2549           faceNodes.insert( idNodes[ iMin ] );
2550           DUMPSO( "loop " << iLoop2 << " id2 " << idNodes[ 1 ] << " id3 " << idNodes[ 2 ]
2551                   << " leastDist = " << leastDist);
2552           if ( leastDist <= DBL_MIN )
2553             break;
2554         }
2555       }
2556
2557       // set next 3-d node to check
2558       int iNext = 2 + iLoop2;
2559       if ( iNext < 8 ) {
2560         DUMPSO( "Try 2-nd");
2561         swap ( 2, iNext, idNodes, P );
2562       }
2563     } // while ( iLoop2 < 6 )
2564   } // iLoop1
2565
2566   if ( faceNodes.empty() ) return false;
2567
2568   // Put the faceNodes in proper places
2569   for ( i = 4; i < 8; i++ ) {
2570     if ( faceNodes.find( idNodes[ i ] ) != faceNodes.end() ) {
2571       // find a place to put
2572       int iTo = 1;
2573       while ( faceNodes.find( idNodes[ iTo ] ) != faceNodes.end() )
2574         iTo++;
2575       DUMPSO( "Set faceNodes");
2576       swap ( iTo, i, idNodes, P );
2577     }
2578   }
2579
2580
2581   // Set nodes of the found bottom face in good order
2582   DUMPSO( " Found bottom face: ");
2583   i = SortQuadNodes( theMesh, idNodes );
2584   if ( i ) {
2585     gp_Pnt Ptmp = P[ i ];
2586     P[ i ] = P[ i+1 ];
2587     P[ i+1 ] = Ptmp;
2588   }
2589   //   else
2590   //     for ( int ii = 0; ii < 4; ii++ ) {
2591   //       const SMDS_MeshNode *n = theMesh->FindNode( idNodes[ii] );
2592   //       DUMPSO( ii << "(" << idNodes[ii] <<") : "<<n->X()<<" "<<n->Y()<<" "<<n->Z());
2593   //    }
2594
2595   // Gravity center of the top and bottom faces
2596   gp_Pnt aGCb = ( P[0].XYZ() + P[1].XYZ() + P[2].XYZ() + P[3].XYZ() ) / 4.;
2597   gp_Pnt aGCt = ( P[4].XYZ() + P[5].XYZ() + P[6].XYZ() + P[7].XYZ() ) / 4.;
2598
2599   // Get direction from the bottom to the top face
2600   gp_Vec upDir ( aGCb, aGCt );
2601   Standard_Real upDirSize = upDir.Magnitude();
2602   if ( upDirSize <= gp::Resolution() ) return false;
2603   upDir / upDirSize;
2604
2605   // Assure that the bottom face normal points up
2606   gp_Vec Nb = gp_Vec (P[0], P[1]).Crossed( gp_Vec (P[0], P[2]) );
2607   Nb += gp_Vec (P[0], P[2]).Crossed( gp_Vec (P[0], P[3]) );
2608   if ( Nb.Dot( upDir ) < 0 ) {
2609     DUMPSO( "Reverse bottom face");
2610     swap( 1, 3, idNodes, P );
2611   }
2612
2613   // Find 5-th node - the one closest to the 1-st among the last 4 nodes.
2614   Standard_Real minDist = DBL_MAX;
2615   for ( i = 4; i < 8; i++ ) {
2616     // projection of P[i] to the plane defined by P[0] and upDir
2617     gp_Pnt Pp = P[i].Translated( upDir * ( upDir.Dot( gp_Vec( P[i], P[0] ))));
2618     Standard_Real sqDist = P[0].SquareDistance( Pp );
2619     if ( sqDist < minDist ) {
2620       minDist = sqDist;
2621       iMin = i;
2622     }
2623   }
2624   DUMPSO( "Set 4-th");
2625   swap ( 4, iMin, idNodes, P );
2626
2627   // Set nodes of the top face in good order
2628   DUMPSO( "Sort top face");
2629   i = SortQuadNodes( theMesh, &idNodes[4] );
2630   if ( i ) {
2631     i += 4;
2632     gp_Pnt Ptmp = P[ i ];
2633     P[ i ] = P[ i+1 ];
2634     P[ i+1 ] = Ptmp;
2635   }
2636
2637   // Assure that direction of the top face normal is from the bottom face
2638   gp_Vec Nt = gp_Vec (P[4], P[5]).Crossed( gp_Vec (P[4], P[6]) );
2639   Nt += gp_Vec (P[4], P[6]).Crossed( gp_Vec (P[4], P[7]) );
2640   if ( Nt.Dot( upDir ) < 0 ) {
2641     DUMPSO( "Reverse top face");
2642     swap( 5, 7, idNodes, P );
2643   }
2644
2645   //   DUMPSO( "OUTPUT: ========================================");
2646   //   for ( i = 0; i < 8; i++ ) {
2647   //     float *p = ugrid->GetPoint(idNodes[i]);
2648   //     DUMPSO( i << "(" << idNodes[i] << ") : " << p[0] << " " << p[1] << " " << p[2]);
2649   //   }
2650
2651   return true;
2652 }*/
2653
2654 //================================================================================
2655 /*!
2656  * \brief Return nodes linked to the given one
2657  * \param theNode - the node
2658  * \param linkedNodes - the found nodes
2659  * \param type - the type of elements to check
2660  *
2661  * Medium nodes are ignored
2662  */
2663 //================================================================================
2664
2665 void SMESH_MeshEditor::GetLinkedNodes( const SMDS_MeshNode* theNode,
2666                                        TIDSortedElemSet &   linkedNodes,
2667                                        SMDSAbs_ElementType  type )
2668 {
2669   SMDS_ElemIteratorPtr elemIt = theNode->GetInverseElementIterator(type);
2670   while ( elemIt->more() )
2671   {
2672     const SMDS_MeshElement* elem = elemIt->next();
2673     SMDS_ElemIteratorPtr nodeIt = elem->nodesIterator();
2674     if ( elem->GetType() == SMDSAbs_Volume )
2675     {
2676       SMDS_VolumeTool vol( elem );
2677       while ( nodeIt->more() ) {
2678         const SMDS_MeshNode* n = cast2Node( nodeIt->next() );
2679         if ( theNode != n && vol.IsLinked( theNode, n ))
2680           linkedNodes.insert( n );
2681       }
2682     }
2683     else
2684     {
2685       for ( int i = 0; nodeIt->more(); ++i ) {
2686         const SMDS_MeshNode* n = cast2Node( nodeIt->next() );
2687         if ( n == theNode ) {
2688           int iBefore = i - 1;
2689           int iAfter  = i + 1;
2690           if ( elem->IsQuadratic() ) {
2691             int nb = elem->NbNodes() / 2;
2692             iAfter  = SMESH_MesherHelper::WrapIndex( iAfter, nb );
2693             iBefore = SMESH_MesherHelper::WrapIndex( iBefore, nb );
2694           }
2695           linkedNodes.insert( elem->GetNodeWrap( iAfter ));
2696           linkedNodes.insert( elem->GetNodeWrap( iBefore ));
2697         }
2698       }
2699     }
2700   }
2701 }
2702
2703 //=======================================================================
2704 //function : laplacianSmooth
2705 //purpose  : pulls theNode toward the center of surrounding nodes directly
2706 //           connected to that node along an element edge
2707 //=======================================================================
2708
2709 void laplacianSmooth(const SMDS_MeshNode*                 theNode,
2710                      const Handle(Geom_Surface)&          theSurface,
2711                      map< const SMDS_MeshNode*, gp_XY* >& theUVMap)
2712 {
2713   // find surrounding nodes
2714
2715   TIDSortedElemSet nodeSet;
2716   SMESH_MeshEditor::GetLinkedNodes( theNode, nodeSet, SMDSAbs_Face );
2717
2718   // compute new coodrs
2719
2720   double coord[] = { 0., 0., 0. };
2721   TIDSortedElemSet::iterator nodeSetIt = nodeSet.begin();
2722   for ( ; nodeSetIt != nodeSet.end(); nodeSetIt++ ) {
2723     const SMDS_MeshNode* node = cast2Node(*nodeSetIt);
2724     if ( theSurface.IsNull() ) { // smooth in 3D
2725       coord[0] += node->X();
2726       coord[1] += node->Y();
2727       coord[2] += node->Z();
2728     }
2729     else { // smooth in 2D
2730       ASSERT( theUVMap.find( node ) != theUVMap.end() );
2731       gp_XY* uv = theUVMap[ node ];
2732       coord[0] += uv->X();
2733       coord[1] += uv->Y();
2734     }
2735   }
2736   int nbNodes = nodeSet.size();
2737   if ( !nbNodes )
2738     return;
2739   coord[0] /= nbNodes;
2740   coord[1] /= nbNodes;
2741
2742   if ( !theSurface.IsNull() ) {
2743     ASSERT( theUVMap.find( theNode ) != theUVMap.end() );
2744     theUVMap[ theNode ]->SetCoord( coord[0], coord[1] );
2745     gp_Pnt p3d = theSurface->Value( coord[0], coord[1] );
2746     coord[0] = p3d.X();
2747     coord[1] = p3d.Y();
2748     coord[2] = p3d.Z();
2749   }
2750   else
2751     coord[2] /= nbNodes;
2752
2753   // move node
2754
2755   const_cast< SMDS_MeshNode* >( theNode )->setXYZ(coord[0],coord[1],coord[2]);
2756 }
2757
2758 //=======================================================================
2759 //function : centroidalSmooth
2760 //purpose  : pulls theNode toward the element-area-weighted centroid of the
2761 //           surrounding elements
2762 //=======================================================================
2763
2764 void centroidalSmooth(const SMDS_MeshNode*                 theNode,
2765                       const Handle(Geom_Surface)&          theSurface,
2766                       map< const SMDS_MeshNode*, gp_XY* >& theUVMap)
2767 {
2768   gp_XYZ aNewXYZ(0.,0.,0.);
2769   SMESH::Controls::Area anAreaFunc;
2770   double totalArea = 0.;
2771   int nbElems = 0;
2772
2773   // compute new XYZ
2774
2775   SMDS_ElemIteratorPtr elemIt = theNode->GetInverseElementIterator(SMDSAbs_Face);
2776   while ( elemIt->more() )
2777   {
2778     const SMDS_MeshElement* elem = elemIt->next();
2779     nbElems++;
2780
2781     gp_XYZ elemCenter(0.,0.,0.);
2782     SMESH::Controls::TSequenceOfXYZ aNodePoints;
2783     SMDS_ElemIteratorPtr itN = elem->nodesIterator();
2784     int nn = elem->NbNodes();
2785     if(elem->IsQuadratic()) nn = nn/2;
2786     int i=0;
2787     //while ( itN->more() ) {
2788     while ( i<nn ) {
2789       const SMDS_MeshNode* aNode = static_cast<const SMDS_MeshNode*>( itN->next() );
2790       i++;
2791       gp_XYZ aP( aNode->X(), aNode->Y(), aNode->Z() );
2792       aNodePoints.push_back( aP );
2793       if ( !theSurface.IsNull() ) { // smooth in 2D
2794         ASSERT( theUVMap.find( aNode ) != theUVMap.end() );
2795         gp_XY* uv = theUVMap[ aNode ];
2796         aP.SetCoord( uv->X(), uv->Y(), 0. );
2797       }
2798       elemCenter += aP;
2799     }
2800     double elemArea = anAreaFunc.GetValue( aNodePoints );
2801     totalArea += elemArea;
2802     elemCenter /= nn;
2803     aNewXYZ += elemCenter * elemArea;
2804   }
2805   aNewXYZ /= totalArea;
2806   if ( !theSurface.IsNull() ) {
2807     theUVMap[ theNode ]->SetCoord( aNewXYZ.X(), aNewXYZ.Y() );
2808     aNewXYZ = theSurface->Value( aNewXYZ.X(), aNewXYZ.Y() ).XYZ();
2809   }
2810
2811   // move node
2812
2813   const_cast< SMDS_MeshNode* >( theNode )->setXYZ(aNewXYZ.X(),aNewXYZ.Y(),aNewXYZ.Z());
2814 }
2815
2816 //=======================================================================
2817 //function : getClosestUV
2818 //purpose  : return UV of closest projection
2819 //=======================================================================
2820
2821 static bool getClosestUV (Extrema_GenExtPS& projector,
2822                           const gp_Pnt&     point,
2823                           gp_XY &           result)
2824 {
2825   projector.Perform( point );
2826   if ( projector.IsDone() ) {
2827     double u, v, minVal = DBL_MAX;
2828     for ( int i = projector.NbExt(); i > 0; i-- )
2829       if ( projector.Value( i ) < minVal ) {
2830         minVal = projector.Value( i );
2831         projector.Point( i ).Parameter( u, v );
2832       }
2833     result.SetCoord( u, v );
2834     return true;
2835   }
2836   return false;
2837 }
2838
2839 //=======================================================================
2840 //function : Smooth
2841 //purpose  : Smooth theElements during theNbIterations or until a worst
2842 //           element has aspect ratio <= theTgtAspectRatio.
2843 //           Aspect Ratio varies in range [1.0, inf].
2844 //           If theElements is empty, the whole mesh is smoothed.
2845 //           theFixedNodes contains additionally fixed nodes. Nodes built
2846 //           on edges and boundary nodes are always fixed.
2847 //=======================================================================
2848
2849 void SMESH_MeshEditor::Smooth (TIDSortedElemSet &          theElems,
2850                                set<const SMDS_MeshNode*> & theFixedNodes,
2851                                const SmoothMethod          theSmoothMethod,
2852                                const int                   theNbIterations,
2853                                double                      theTgtAspectRatio,
2854                                const bool                  the2D)
2855 {
2856   myLastCreatedElems.Clear();
2857   myLastCreatedNodes.Clear();
2858
2859   MESSAGE((theSmoothMethod==LAPLACIAN ? "LAPLACIAN" : "CENTROIDAL") << "--::Smooth()");
2860
2861   if ( theTgtAspectRatio < 1.0 )
2862     theTgtAspectRatio = 1.0;
2863
2864   const double disttol = 1.e-16;
2865
2866   SMESH::Controls::AspectRatio aQualityFunc;
2867
2868   SMESHDS_Mesh* aMesh = GetMeshDS();
2869
2870   if ( theElems.empty() ) {
2871     // add all faces to theElems
2872     SMDS_FaceIteratorPtr fIt = aMesh->facesIterator();
2873     while ( fIt->more() ) {
2874       const SMDS_MeshElement* face = fIt->next();
2875       theElems.insert( face );
2876     }
2877   }
2878   // get all face ids theElems are on
2879   set< int > faceIdSet;
2880   TIDSortedElemSet::iterator itElem;
2881   if ( the2D )
2882     for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
2883       int fId = FindShape( *itElem );
2884       // check that corresponding submesh exists and a shape is face
2885       if (fId &&
2886           faceIdSet.find( fId ) == faceIdSet.end() &&
2887           aMesh->MeshElements( fId )) {
2888         TopoDS_Shape F = aMesh->IndexToShape( fId );
2889         if ( !F.IsNull() && F.ShapeType() == TopAbs_FACE )
2890           faceIdSet.insert( fId );
2891       }
2892     }
2893   faceIdSet.insert( 0 ); // to smooth elements that are not on any TopoDS_Face
2894
2895   // ===============================================
2896   // smooth elements on each TopoDS_Face separately
2897   // ===============================================
2898
2899   set< int >::reverse_iterator fId = faceIdSet.rbegin(); // treate 0 fId at the end
2900   for ( ; fId != faceIdSet.rend(); ++fId ) {
2901     // get face surface and submesh
2902     Handle(Geom_Surface) surface;
2903     SMESHDS_SubMesh* faceSubMesh = 0;
2904     TopoDS_Face face;
2905     double fToler2 = 0, vPeriod = 0., uPeriod = 0., f,l;
2906     double u1 = 0, u2 = 0, v1 = 0, v2 = 0;
2907     bool isUPeriodic = false, isVPeriodic = false;
2908     if ( *fId ) {
2909       face = TopoDS::Face( aMesh->IndexToShape( *fId ));
2910       surface = BRep_Tool::Surface( face );
2911       faceSubMesh = aMesh->MeshElements( *fId );
2912       fToler2 = BRep_Tool::Tolerance( face );
2913       fToler2 *= fToler2 * 10.;
2914       isUPeriodic = surface->IsUPeriodic();
2915       if ( isUPeriodic )
2916         vPeriod = surface->UPeriod();
2917       isVPeriodic = surface->IsVPeriodic();
2918       if ( isVPeriodic )
2919         uPeriod = surface->VPeriod();
2920       surface->Bounds( u1, u2, v1, v2 );
2921     }
2922     // ---------------------------------------------------------
2923     // for elements on a face, find movable and fixed nodes and
2924     // compute UV for them
2925     // ---------------------------------------------------------
2926     bool checkBoundaryNodes = false;
2927     bool isQuadratic = false;
2928     set<const SMDS_MeshNode*> setMovableNodes;
2929     map< const SMDS_MeshNode*, gp_XY* > uvMap, uvMap2;
2930     list< gp_XY > listUV; // uvs the 2 uvMaps refer to
2931     list< const SMDS_MeshElement* > elemsOnFace;
2932
2933     Extrema_GenExtPS projector;
2934     GeomAdaptor_Surface surfAdaptor;
2935     if ( !surface.IsNull() ) {
2936       surfAdaptor.Load( surface );
2937       projector.Initialize( surfAdaptor, 20,20, 1e-5,1e-5 );
2938     }
2939     int nbElemOnFace = 0;
2940     itElem = theElems.begin();
2941     // loop on not yet smoothed elements: look for elems on a face
2942     while ( itElem != theElems.end() ) {
2943       if ( faceSubMesh && nbElemOnFace == faceSubMesh->NbElements() )
2944         break; // all elements found
2945
2946       const SMDS_MeshElement* elem = *itElem;
2947       if ( !elem || elem->GetType() != SMDSAbs_Face || elem->NbNodes() < 3 ||
2948            ( faceSubMesh && !faceSubMesh->Contains( elem ))) {
2949         ++itElem;
2950         continue;
2951       }
2952       elemsOnFace.push_back( elem );
2953       theElems.erase( itElem++ );
2954       nbElemOnFace++;
2955
2956       if ( !isQuadratic )
2957         isQuadratic = elem->IsQuadratic();
2958
2959       // get movable nodes of elem
2960       const SMDS_MeshNode* node;
2961       SMDS_TypeOfPosition posType;
2962       SMDS_ElemIteratorPtr itN = elem->nodesIterator();
2963       int nn = 0, nbn =  elem->NbNodes();
2964       if(elem->IsQuadratic())
2965         nbn = nbn/2;
2966       while ( nn++ < nbn ) {
2967         node = static_cast<const SMDS_MeshNode*>( itN->next() );
2968         const SMDS_PositionPtr& pos = node->GetPosition();
2969         posType = pos ? pos->GetTypeOfPosition() : SMDS_TOP_3DSPACE;
2970         if (posType != SMDS_TOP_EDGE &&
2971             posType != SMDS_TOP_VERTEX &&
2972             theFixedNodes.find( node ) == theFixedNodes.end())
2973         {
2974           // check if all faces around the node are on faceSubMesh
2975           // because a node on edge may be bound to face
2976           SMDS_ElemIteratorPtr eIt = node->GetInverseElementIterator(SMDSAbs_Face);
2977           bool all = true;
2978           if ( faceSubMesh ) {
2979             while ( eIt->more() && all ) {
2980               const SMDS_MeshElement* e = eIt->next();
2981               all = faceSubMesh->Contains( e );
2982             }
2983           }
2984           if ( all )
2985             setMovableNodes.insert( node );
2986           else
2987             checkBoundaryNodes = true;
2988         }
2989         if ( posType == SMDS_TOP_3DSPACE )
2990           checkBoundaryNodes = true;
2991       }
2992
2993       if ( surface.IsNull() )
2994         continue;
2995
2996       // get nodes to check UV
2997       list< const SMDS_MeshNode* > uvCheckNodes;
2998       itN = elem->nodesIterator();
2999       nn = 0; nbn =  elem->NbNodes();
3000       if(elem->IsQuadratic())
3001         nbn = nbn/2;
3002       while ( nn++ < nbn ) {
3003         node = static_cast<const SMDS_MeshNode*>( itN->next() );
3004         if ( uvMap.find( node ) == uvMap.end() )
3005           uvCheckNodes.push_back( node );
3006         // add nodes of elems sharing node
3007         //         SMDS_ElemIteratorPtr eIt = node->GetInverseElementIterator(SMDSAbs_Face);
3008         //         while ( eIt->more() ) {
3009         //           const SMDS_MeshElement* e = eIt->next();
3010         //           if ( e != elem ) {
3011         //             SMDS_ElemIteratorPtr nIt = e->nodesIterator();
3012         //             while ( nIt->more() ) {
3013         //               const SMDS_MeshNode* n =
3014         //                 static_cast<const SMDS_MeshNode*>( nIt->next() );
3015         //               if ( uvMap.find( n ) == uvMap.end() )
3016         //                 uvCheckNodes.push_back( n );
3017         //             }
3018         //           }
3019         //         }
3020       }
3021       // check UV on face
3022       list< const SMDS_MeshNode* >::iterator n = uvCheckNodes.begin();
3023       for ( ; n != uvCheckNodes.end(); ++n ) {
3024         node = *n;
3025         gp_XY uv( 0, 0 );
3026         const SMDS_PositionPtr& pos = node->GetPosition();
3027         posType = pos ? pos->GetTypeOfPosition() : SMDS_TOP_3DSPACE;
3028         // get existing UV
3029         switch ( posType ) {
3030         case SMDS_TOP_FACE: {
3031           SMDS_FacePosition* fPos = ( SMDS_FacePosition* ) pos;
3032           uv.SetCoord( fPos->GetUParameter(), fPos->GetVParameter() );
3033           break;
3034         }
3035         case SMDS_TOP_EDGE: {
3036           TopoDS_Shape S = aMesh->IndexToShape( node->getshapeId() );
3037           Handle(Geom2d_Curve) pcurve;
3038           if ( !S.IsNull() && S.ShapeType() == TopAbs_EDGE )
3039             pcurve = BRep_Tool::CurveOnSurface( TopoDS::Edge( S ), face, f,l );
3040           if ( !pcurve.IsNull() ) {
3041             double u = (( SMDS_EdgePosition* ) pos )->GetUParameter();
3042             uv = pcurve->Value( u ).XY();
3043           }
3044           break;
3045         }
3046         case SMDS_TOP_VERTEX: {
3047           TopoDS_Shape S = aMesh->IndexToShape( node->getshapeId() );
3048           if ( !S.IsNull() && S.ShapeType() == TopAbs_VERTEX )
3049             uv = BRep_Tool::Parameters( TopoDS::Vertex( S ), face ).XY();
3050           break;
3051         }
3052         default:;
3053         }
3054         // check existing UV
3055         bool project = true;
3056         gp_Pnt pNode ( node->X(), node->Y(), node->Z() );
3057         double dist1 = DBL_MAX, dist2 = 0;
3058         if ( posType != SMDS_TOP_3DSPACE ) {
3059           dist1 = pNode.SquareDistance( surface->Value( uv.X(), uv.Y() ));
3060           project = dist1 > fToler2;
3061         }
3062         if ( project ) { // compute new UV
3063           gp_XY newUV;
3064           if ( !getClosestUV( projector, pNode, newUV )) {
3065             MESSAGE("Node Projection Failed " << node);
3066           }
3067           else {
3068             if ( isUPeriodic )
3069               newUV.SetX( ElCLib::InPeriod( newUV.X(), u1, u2 ));
3070             if ( isVPeriodic )
3071               newUV.SetY( ElCLib::InPeriod( newUV.Y(), v1, v2 ));
3072             // check new UV
3073             if ( posType != SMDS_TOP_3DSPACE )
3074               dist2 = pNode.SquareDistance( surface->Value( newUV.X(), newUV.Y() ));
3075             if ( dist2 < dist1 )
3076               uv = newUV;
3077           }
3078         }
3079         // store UV in the map
3080         listUV.push_back( uv );
3081         uvMap.insert( make_pair( node, &listUV.back() ));
3082       }
3083     } // loop on not yet smoothed elements
3084
3085     if ( !faceSubMesh || nbElemOnFace != faceSubMesh->NbElements() )
3086       checkBoundaryNodes = true;
3087
3088     // fix nodes on mesh boundary
3089
3090     if ( checkBoundaryNodes ) {
3091       map< NLink, int > linkNbMap; // how many times a link encounters in elemsOnFace
3092       map< NLink, int >::iterator link_nb;
3093       // put all elements links to linkNbMap
3094       list< const SMDS_MeshElement* >::iterator elemIt = elemsOnFace.begin();
3095       for ( ; elemIt != elemsOnFace.end(); ++elemIt ) {
3096         const SMDS_MeshElement* elem = (*elemIt);
3097         int nbn =  elem->NbNodes();
3098         if(elem->IsQuadratic())
3099           nbn = nbn/2;
3100         // loop on elem links: insert them in linkNbMap
3101         const SMDS_MeshNode* curNode, *prevNode = elem->GetNodeWrap( nbn );
3102         for ( int iN = 0; iN < nbn; ++iN ) {
3103           curNode = elem->GetNode( iN );
3104           NLink link;
3105           if ( curNode < prevNode ) link = make_pair( curNode , prevNode );
3106           else                      link = make_pair( prevNode , curNode );
3107           prevNode = curNode;
3108           link_nb = linkNbMap.find( link );
3109           if ( link_nb == linkNbMap.end() )
3110             linkNbMap.insert( make_pair ( link, 1 ));
3111           else
3112             link_nb->second++;
3113         }
3114       }
3115       // remove nodes that are in links encountered only once from setMovableNodes
3116       for ( link_nb = linkNbMap.begin(); link_nb != linkNbMap.end(); ++link_nb ) {
3117         if ( link_nb->second == 1 ) {
3118           setMovableNodes.erase( link_nb->first.first );
3119           setMovableNodes.erase( link_nb->first.second );
3120         }
3121       }
3122     }
3123
3124     // -----------------------------------------------------
3125     // for nodes on seam edge, compute one more UV ( uvMap2 );
3126     // find movable nodes linked to nodes on seam and which
3127     // are to be smoothed using the second UV ( uvMap2 )
3128     // -----------------------------------------------------
3129
3130     set<const SMDS_MeshNode*> nodesNearSeam; // to smooth using uvMap2
3131     if ( !surface.IsNull() ) {
3132       TopExp_Explorer eExp( face, TopAbs_EDGE );
3133       for ( ; eExp.More(); eExp.Next() ) {
3134         TopoDS_Edge edge = TopoDS::Edge( eExp.Current() );
3135         if ( !BRep_Tool::IsClosed( edge, face ))
3136           continue;
3137         SMESHDS_SubMesh* sm = aMesh->MeshElements( edge );
3138         if ( !sm ) continue;
3139         // find out which parameter varies for a node on seam
3140         double f,l;
3141         gp_Pnt2d uv1, uv2;
3142         Handle(Geom2d_Curve) pcurve = BRep_Tool::CurveOnSurface( edge, face, f, l );
3143         if ( pcurve.IsNull() ) continue;
3144         uv1 = pcurve->Value( f );
3145         edge.Reverse();
3146         pcurve = BRep_Tool::CurveOnSurface( edge, face, f, l );
3147         if ( pcurve.IsNull() ) continue;
3148         uv2 = pcurve->Value( f );
3149         int iPar = Abs( uv1.X() - uv2.X() ) > Abs( uv1.Y() - uv2.Y() ) ? 1 : 2;
3150         // assure uv1 < uv2
3151         if ( uv1.Coord( iPar ) > uv2.Coord( iPar )) {
3152           gp_Pnt2d tmp = uv1; uv1 = uv2; uv2 = tmp;
3153         }
3154         // get nodes on seam and its vertices
3155         list< const SMDS_MeshNode* > seamNodes;
3156         SMDS_NodeIteratorPtr nSeamIt = sm->GetNodes();
3157         while ( nSeamIt->more() ) {
3158           const SMDS_MeshNode* node = nSeamIt->next();
3159           if ( !isQuadratic || !IsMedium( node ))
3160             seamNodes.push_back( node );
3161         }
3162         TopExp_Explorer vExp( edge, TopAbs_VERTEX );
3163         for ( ; vExp.More(); vExp.Next() ) {
3164           sm = aMesh->MeshElements( vExp.Current() );
3165           if ( sm ) {
3166             nSeamIt = sm->GetNodes();
3167             while ( nSeamIt->more() )
3168               seamNodes.push_back( nSeamIt->next() );
3169           }
3170         }
3171         // loop on nodes on seam
3172         list< const SMDS_MeshNode* >::iterator noSeIt = seamNodes.begin();
3173         for ( ; noSeIt != seamNodes.end(); ++noSeIt ) {
3174           const SMDS_MeshNode* nSeam = *noSeIt;
3175           map< const SMDS_MeshNode*, gp_XY* >::iterator n_uv = uvMap.find( nSeam );
3176           if ( n_uv == uvMap.end() )
3177             continue;
3178           // set the first UV
3179           n_uv->second->SetCoord( iPar, uv1.Coord( iPar ));
3180           // set the second UV
3181           listUV.push_back( *n_uv->second );
3182           listUV.back().SetCoord( iPar, uv2.Coord( iPar ));
3183           if ( uvMap2.empty() )
3184             uvMap2 = uvMap; // copy the uvMap contents
3185           uvMap2[ nSeam ] = &listUV.back();
3186
3187           // collect movable nodes linked to ones on seam in nodesNearSeam
3188           SMDS_ElemIteratorPtr eIt = nSeam->GetInverseElementIterator(SMDSAbs_Face);
3189           while ( eIt->more() ) {
3190             const SMDS_MeshElement* e = eIt->next();
3191             int nbUseMap1 = 0, nbUseMap2 = 0;
3192             SMDS_ElemIteratorPtr nIt = e->nodesIterator();
3193             int nn = 0, nbn =  e->NbNodes();
3194             if(e->IsQuadratic()) nbn = nbn/2;
3195             while ( nn++ < nbn )
3196             {
3197               const SMDS_MeshNode* n =
3198                 static_cast<const SMDS_MeshNode*>( nIt->next() );
3199               if (n == nSeam ||
3200                   setMovableNodes.find( n ) == setMovableNodes.end() )
3201                 continue;
3202               // add only nodes being closer to uv2 than to uv1
3203               gp_Pnt pMid (0.5 * ( n->X() + nSeam->X() ),
3204                            0.5 * ( n->Y() + nSeam->Y() ),
3205                            0.5 * ( n->Z() + nSeam->Z() ));
3206               gp_XY uv;
3207               getClosestUV( projector, pMid, uv );
3208               if ( uv.Coord( iPar ) > uvMap[ n ]->Coord( iPar ) ) {
3209                 nodesNearSeam.insert( n );
3210                 nbUseMap2++;
3211               }
3212               else
3213                 nbUseMap1++;
3214             }
3215             // for centroidalSmooth all element nodes must
3216             // be on one side of a seam
3217             if ( theSmoothMethod == CENTROIDAL && nbUseMap1 && nbUseMap2 ) {
3218               SMDS_ElemIteratorPtr nIt = e->nodesIterator();
3219               nn = 0;
3220               while ( nn++ < nbn ) {
3221                 const SMDS_MeshNode* n =
3222                   static_cast<const SMDS_MeshNode*>( nIt->next() );
3223                 setMovableNodes.erase( n );
3224               }
3225             }
3226           }
3227         } // loop on nodes on seam
3228       } // loop on edge of a face
3229     } // if ( !face.IsNull() )
3230
3231     if ( setMovableNodes.empty() ) {
3232       MESSAGE( "Face id : " << *fId << " - NO SMOOTHING: no nodes to move!!!");
3233       continue; // goto next face
3234     }
3235
3236     // -------------
3237     // SMOOTHING //
3238     // -------------
3239
3240     int it = -1;
3241     double maxRatio = -1., maxDisplacement = -1.;
3242     set<const SMDS_MeshNode*>::iterator nodeToMove;
3243     for ( it = 0; it < theNbIterations; it++ ) {
3244       maxDisplacement = 0.;
3245       nodeToMove = setMovableNodes.begin();
3246       for ( ; nodeToMove != setMovableNodes.end(); nodeToMove++ ) {
3247         const SMDS_MeshNode* node = (*nodeToMove);
3248         gp_XYZ aPrevPos ( node->X(), node->Y(), node->Z() );
3249
3250         // smooth
3251         bool map2 = ( nodesNearSeam.find( node ) != nodesNearSeam.end() );
3252         if ( theSmoothMethod == LAPLACIAN )
3253           laplacianSmooth( node, surface, map2 ? uvMap2 : uvMap );
3254         else
3255           centroidalSmooth( node, surface, map2 ? uvMap2 : uvMap );
3256
3257         // node displacement
3258         gp_XYZ aNewPos ( node->X(), node->Y(), node->Z() );
3259         Standard_Real aDispl = (aPrevPos - aNewPos).SquareModulus();
3260         if ( aDispl > maxDisplacement )
3261           maxDisplacement = aDispl;
3262       }
3263       // no node movement => exit
3264       //if ( maxDisplacement < 1.e-16 ) {
3265       if ( maxDisplacement < disttol ) {
3266         MESSAGE("-- no node movement --");
3267         break;
3268       }
3269
3270       // check elements quality
3271       maxRatio  = 0;
3272       list< const SMDS_MeshElement* >::iterator elemIt = elemsOnFace.begin();
3273       for ( ; elemIt != elemsOnFace.end(); ++elemIt ) {
3274         const SMDS_MeshElement* elem = (*elemIt);
3275         if ( !elem || elem->GetType() != SMDSAbs_Face )
3276           continue;
3277         SMESH::Controls::TSequenceOfXYZ aPoints;
3278         if ( aQualityFunc.GetPoints( elem, aPoints )) {
3279           double aValue = aQualityFunc.GetValue( aPoints );
3280           if ( aValue > maxRatio )
3281             maxRatio = aValue;
3282         }
3283       }
3284       if ( maxRatio <= theTgtAspectRatio ) {
3285         MESSAGE("-- quality achived --");
3286         break;
3287       }
3288       if (it+1 == theNbIterations) {
3289         MESSAGE("-- Iteration limit exceeded --");
3290       }
3291     } // smoothing iterations
3292
3293     MESSAGE(" Face id: " << *fId <<
3294             " Nb iterstions: " << it <<
3295             " Displacement: " << maxDisplacement <<
3296             " Aspect Ratio " << maxRatio);
3297
3298     // ---------------------------------------
3299     // new nodes positions are computed,
3300     // record movement in DS and set new UV
3301     // ---------------------------------------
3302     nodeToMove = setMovableNodes.begin();
3303     for ( ; nodeToMove != setMovableNodes.end(); nodeToMove++ ) {
3304       SMDS_MeshNode* node = const_cast< SMDS_MeshNode* > (*nodeToMove);
3305       aMesh->MoveNode( node, node->X(), node->Y(), node->Z() );
3306       map< const SMDS_MeshNode*, gp_XY* >::iterator node_uv = uvMap.find( node );
3307       if ( node_uv != uvMap.end() ) {
3308         gp_XY* uv = node_uv->second;
3309         node->SetPosition
3310           ( SMDS_PositionPtr( new SMDS_FacePosition( uv->X(), uv->Y() )));
3311       }
3312     }
3313
3314     // move medium nodes of quadratic elements
3315     if ( isQuadratic )
3316     {
3317       SMESH_MesherHelper helper( *GetMesh() );
3318       if ( !face.IsNull() )
3319         helper.SetSubShape( face );
3320       list< const SMDS_MeshElement* >::iterator elemIt = elemsOnFace.begin();
3321       for ( ; elemIt != elemsOnFace.end(); ++elemIt ) {
3322         const SMDS_VtkFace* QF =
3323           dynamic_cast<const SMDS_VtkFace*> (*elemIt);
3324         if(QF && QF->IsQuadratic()) {
3325           vector<const SMDS_MeshNode*> Ns;
3326           Ns.reserve(QF->NbNodes()+1);
3327           SMDS_ElemIteratorPtr anIter = QF->interlacedNodesElemIterator();
3328           while ( anIter->more() )
3329             Ns.push_back( cast2Node(anIter->next()) );
3330           Ns.push_back( Ns[0] );
3331           double x, y, z;
3332           for(int i=0; i<QF->NbNodes(); i=i+2) {
3333             if ( !surface.IsNull() ) {
3334               gp_XY uv1 = helper.GetNodeUV( face, Ns[i], Ns[i+2] );
3335               gp_XY uv2 = helper.GetNodeUV( face, Ns[i+2], Ns[i] );
3336               gp_XY uv = ( uv1 + uv2 ) / 2.;
3337               gp_Pnt xyz = surface->Value( uv.X(), uv.Y() );
3338               x = xyz.X(); y = xyz.Y(); z = xyz.Z();
3339             }
3340             else {
3341               x = (Ns[i]->X() + Ns[i+2]->X())/2;
3342               y = (Ns[i]->Y() + Ns[i+2]->Y())/2;
3343               z = (Ns[i]->Z() + Ns[i+2]->Z())/2;
3344             }
3345             if( fabs( Ns[i+1]->X() - x ) > disttol ||
3346                 fabs( Ns[i+1]->Y() - y ) > disttol ||
3347                 fabs( Ns[i+1]->Z() - z ) > disttol ) {
3348               // we have to move i+1 node
3349               aMesh->MoveNode( Ns[i+1], x, y, z );
3350             }
3351           }
3352         }
3353       }
3354     }
3355
3356   } // loop on face ids
3357
3358 }
3359
3360 //=======================================================================
3361 //function : isReverse
3362 //purpose  : Return true if normal of prevNodes is not co-directied with
3363 //           gp_Vec(prevNodes[iNotSame],nextNodes[iNotSame]).
3364 //           iNotSame is where prevNodes and nextNodes are different
3365 //=======================================================================
3366
3367 static bool isReverse(vector<const SMDS_MeshNode*> prevNodes,
3368                       vector<const SMDS_MeshNode*> nextNodes,
3369                       const int            nbNodes,
3370                       const int            iNotSame)
3371 {
3372   int iBeforeNotSame = ( iNotSame == 0 ? nbNodes - 1 : iNotSame - 1 );
3373   int iAfterNotSame  = ( iNotSame + 1 == nbNodes ? 0 : iNotSame + 1 );
3374
3375   const SMDS_MeshNode* nB = prevNodes[ iBeforeNotSame ];
3376   const SMDS_MeshNode* nA = prevNodes[ iAfterNotSame ];
3377   const SMDS_MeshNode* nP = prevNodes[ iNotSame ];
3378   const SMDS_MeshNode* nN = nextNodes[ iNotSame ];
3379
3380   gp_Pnt pB ( nB->X(), nB->Y(), nB->Z() );
3381   gp_Pnt pA ( nA->X(), nA->Y(), nA->Z() );
3382   gp_Pnt pP ( nP->X(), nP->Y(), nP->Z() );
3383   gp_Pnt pN ( nN->X(), nN->Y(), nN->Z() );
3384
3385   gp_Vec vB ( pP, pB ), vA ( pP, pA ), vN ( pP, pN );
3386
3387   return (vA ^ vB) * vN < 0.0;
3388 }
3389
3390 //=======================================================================
3391 /*!
3392  * \brief Create elements by sweeping an element
3393  * \param elem - element to sweep
3394  * \param newNodesItVec - nodes generated from each node of the element
3395  * \param newElems - generated elements
3396  * \param nbSteps - number of sweeping steps
3397  * \param srcElements - to append elem for each generated element
3398  */
3399 //=======================================================================
3400
3401 void SMESH_MeshEditor::sweepElement(const SMDS_MeshElement*               elem,
3402                                     const vector<TNodeOfNodeListMapItr> & newNodesItVec,
3403                                     list<const SMDS_MeshElement*>&        newElems,
3404                                     const int                             nbSteps,
3405                                     SMESH_SequenceOfElemPtr&              srcElements)
3406 {
3407   //MESSAGE("sweepElement " << nbSteps);
3408   SMESHDS_Mesh* aMesh = GetMeshDS();
3409
3410   // Loop on elem nodes:
3411   // find new nodes and detect same nodes indices
3412   int nbNodes = elem->NbNodes();
3413   vector < list< const SMDS_MeshNode* >::const_iterator > itNN( nbNodes );
3414   vector<const SMDS_MeshNode*> prevNod( nbNodes );
3415   vector<const SMDS_MeshNode*> nextNod( nbNodes );
3416   vector<const SMDS_MeshNode*> midlNod( nbNodes );
3417
3418   int iNode, nbSame = 0, iNotSameNode = 0, iSameNode = 0;
3419   vector<int> sames(nbNodes);
3420   vector<bool> issimple(nbNodes);
3421
3422   for ( iNode = 0; iNode < nbNodes; iNode++ ) {
3423     TNodeOfNodeListMapItr nnIt = newNodesItVec[ iNode ];
3424     const SMDS_MeshNode*                 node         = nnIt->first;
3425     const list< const SMDS_MeshNode* > & listNewNodes = nnIt->second;
3426     if ( listNewNodes.empty() ) {
3427       return;
3428     }
3429
3430     issimple[iNode] = (listNewNodes.size()==nbSteps); // is node medium
3431
3432     itNN[ iNode ] = listNewNodes.begin();
3433     prevNod[ iNode ] = node;
3434     nextNod[ iNode ] = listNewNodes.front();
3435     if( !elem->IsQuadratic() || !issimple[iNode] ) {
3436       if ( prevNod[ iNode ] != nextNod [ iNode ])
3437         iNotSameNode = iNode;
3438       else {
3439         iSameNode = iNode;
3440         //nbSame++;
3441         sames[nbSame++] = iNode;
3442       }
3443     }
3444   }
3445
3446   //cerr<<"  nbSame = "<<nbSame<<endl;
3447   if ( nbSame == nbNodes || nbSame > 2) {
3448     MESSAGE( " Too many same nodes of element " << elem->GetID() );
3449     //INFOS( " Too many same nodes of element " << elem->GetID() );
3450     return;
3451   }
3452
3453   //  if( elem->IsQuadratic() && nbSame>0 ) {
3454   //    MESSAGE( "Can not rotate quadratic element " << elem->GetID() );
3455   //    return;
3456   //  }
3457
3458   int iBeforeSame = 0, iAfterSame = 0, iOpposSame = 0;
3459   int nbBaseNodes = ( elem->IsQuadratic() ? nbNodes/2 : nbNodes );
3460   if ( nbSame > 0 ) {
3461     iBeforeSame = ( iSameNode == 0 ? nbBaseNodes - 1 : iSameNode - 1 );
3462     iAfterSame  = ( iSameNode + 1 == nbBaseNodes ? 0 : iSameNode + 1 );
3463     iOpposSame  = ( iSameNode - 2 < 0  ? iSameNode + 2 : iSameNode - 2 );
3464   }
3465
3466   //if(nbNodes==8)
3467   //cout<<" prevNod[0]="<< prevNod[0]<<" prevNod[1]="<< prevNod[1]
3468   //    <<" prevNod[2]="<< prevNod[2]<<" prevNod[3]="<< prevNod[4]
3469   //    <<" prevNod[4]="<< prevNod[4]<<" prevNod[5]="<< prevNod[5]
3470   //    <<" prevNod[6]="<< prevNod[6]<<" prevNod[7]="<< prevNod[7]<<endl;
3471
3472   // check element orientation
3473   int i0 = 0, i2 = 2;
3474   if ( nbNodes > 2 && !isReverse( prevNod, nextNod, nbNodes, iNotSameNode )) {
3475     //MESSAGE("Reversed elem " << elem );
3476     i0 = 2;
3477     i2 = 0;
3478     if ( nbSame > 0 )
3479       std::swap( iBeforeSame, iAfterSame );
3480   }
3481
3482   // make new elements
3483   const SMDS_MeshElement* lastElem = elem;
3484   for (int iStep = 0; iStep < nbSteps; iStep++ ) {
3485     // get next nodes
3486     for ( iNode = 0; iNode < nbNodes; iNode++ ) {
3487       if(issimple[iNode]) {
3488         nextNod[ iNode ] = *itNN[ iNode ];
3489         itNN[ iNode ]++;
3490       }
3491       else {
3492         if( elem->GetType()==SMDSAbs_Node ) {
3493           // we have to use two nodes
3494           midlNod[ iNode ] = *itNN[ iNode ];
3495           itNN[ iNode ]++;
3496           nextNod[ iNode ] = *itNN[ iNode ];
3497           itNN[ iNode ]++;
3498         }
3499         else if(!elem->IsQuadratic() || lastElem->IsMediumNode(prevNod[iNode]) ) {
3500           // we have to use each second node
3501           //itNN[ iNode ]++;
3502           nextNod[ iNode ] = *itNN[ iNode ];
3503           itNN[ iNode ]++;
3504         }
3505         else {
3506           // we have to use two nodes
3507           midlNod[ iNode ] = *itNN[ iNode ];
3508           itNN[ iNode ]++;
3509           nextNod[ iNode ] = *itNN[ iNode ];
3510           itNN[ iNode ]++;
3511         }
3512       }
3513     }
3514     SMDS_MeshElement* aNewElem = 0;
3515     if(!elem->IsPoly()) {
3516       switch ( nbNodes ) {
3517       case 0:
3518         return;
3519       case 1: { // NODE
3520         if ( nbSame == 0 ) {
3521           if(issimple[0])
3522             aNewElem = aMesh->AddEdge( prevNod[ 0 ], nextNod[ 0 ] );
3523           else
3524             aNewElem = aMesh->AddEdge( prevNod[ 0 ], nextNod[ 0 ], midlNod[ 0 ] );
3525         }
3526         break;
3527       }
3528       case 2: { // EDGE
3529         if ( nbSame == 0 )
3530           aNewElem = aMesh->AddFace(prevNod[ 0 ], prevNod[ 1 ],
3531                                     nextNod[ 1 ], nextNod[ 0 ] );
3532         else
3533           aNewElem = aMesh->AddFace(prevNod[ 0 ], prevNod[ 1 ],
3534                                     nextNod[ iNotSameNode ] );
3535         break;
3536       }
3537
3538       case 3: { // TRIANGLE or quadratic edge
3539         if(elem->GetType() == SMDSAbs_Face) { // TRIANGLE
3540
3541           if ( nbSame == 0 )       // --- pentahedron
3542             aNewElem = aMesh->AddVolume (prevNod[ i0 ], prevNod[ 1 ], prevNod[ i2 ],
3543                                          nextNod[ i0 ], nextNod[ 1 ], nextNod[ i2 ] );
3544
3545           else if ( nbSame == 1 )  // --- pyramid
3546             aNewElem = aMesh->AddVolume (prevNod[ iBeforeSame ],  prevNod[ iAfterSame ],
3547                                          nextNod[ iAfterSame ], nextNod[ iBeforeSame ],
3548                                          nextNod[ iSameNode ]);
3549
3550           else // 2 same nodes:      --- tetrahedron
3551             aNewElem = aMesh->AddVolume (prevNod[ i0 ], prevNod[ 1 ], prevNod[ i2 ],
3552                                          nextNod[ iNotSameNode ]);
3553         }
3554         else { // quadratic edge
3555           if(nbSame==0) {     // quadratic quadrangle
3556             aNewElem = aMesh->AddFace(prevNod[0], nextNod[0], nextNod[1], prevNod[1],
3557                                       midlNod[0], nextNod[2], midlNod[1], prevNod[2]);
3558           }
3559           else if(nbSame==1) { // quadratic triangle
3560             if(sames[0]==2) {
3561               return; // medium node on axis
3562             }
3563             else if(sames[0]==0) {
3564               aNewElem = aMesh->AddFace(prevNod[0], nextNod[1], prevNod[1],
3565                                         nextNod[2], midlNod[1], prevNod[2]);
3566             }
3567             else { // sames[0]==1
3568               aNewElem = aMesh->AddFace(prevNod[0], nextNod[0], prevNod[1],
3569                                         midlNod[0], nextNod[2], prevNod[2]);
3570             }
3571           }
3572           else {
3573             return;
3574           }
3575         }
3576         break;
3577       }
3578       case 4: { // QUADRANGLE
3579
3580         if ( nbSame == 0 )       // --- hexahedron
3581           aNewElem = aMesh->AddVolume (prevNod[ i0 ], prevNod[ 1 ], prevNod[ i2 ], prevNod[ 3 ],
3582                                        nextNod[ i0 ], nextNod[ 1 ], nextNod[ i2 ], nextNod[ 3 ]);
3583
3584         else if ( nbSame == 1 ) { // --- pyramid + pentahedron
3585           aNewElem = aMesh->AddVolume (prevNod[ iBeforeSame ],  prevNod[ iAfterSame ],
3586                                        nextNod[ iAfterSame ], nextNod[ iBeforeSame ],
3587                                        nextNod[ iSameNode ]);
3588           newElems.push_back( aNewElem );
3589           aNewElem = aMesh->AddVolume (prevNod[ iAfterSame ], prevNod[ iOpposSame ],
3590                                        prevNod[ iBeforeSame ],  nextNod[ iAfterSame ],
3591                                        nextNod[ iOpposSame ],  nextNod[ iBeforeSame ] );
3592         }
3593         else if ( nbSame == 2 ) { // pentahedron
3594           if ( prevNod[ iBeforeSame ] == nextNod[ iBeforeSame ] )
3595             // iBeforeSame is same too
3596             aNewElem = aMesh->AddVolume (prevNod[ iBeforeSame ], prevNod[ iOpposSame ],
3597                                          nextNod[ iOpposSame ], prevNod[ iSameNode ],
3598                                          prevNod[ iAfterSame ],  nextNod[ iAfterSame ]);
3599           else
3600             // iAfterSame is same too
3601             aNewElem = aMesh->AddVolume (prevNod[ iSameNode ], prevNod[ iBeforeSame ],
3602                                          nextNod[ iBeforeSame ], prevNod[ iAfterSame ],
3603                                          prevNod[ iOpposSame ],  nextNod[ iOpposSame ]);
3604         }
3605         break;
3606       }
3607       case 6: { // quadratic triangle
3608         // create pentahedron with 15 nodes
3609         if(nbSame==0) {
3610           if(i0>0) { // reversed case
3611             aNewElem = aMesh->AddVolume (prevNod[0], prevNod[2], prevNod[1],
3612                                          nextNod[0], nextNod[2], nextNod[1],
3613                                          prevNod[5], prevNod[4], prevNod[3],
3614                                          nextNod[5], nextNod[4], nextNod[3],
3615                                          midlNod[0], midlNod[2], midlNod[1]);
3616           }
3617           else { // not reversed case
3618             aNewElem = aMesh->AddVolume (prevNod[0], prevNod[1], prevNod[2],
3619                                          nextNod[0], nextNod[1], nextNod[2],
3620                                          prevNod[3], prevNod[4], prevNod[5],
3621                                          nextNod[3], nextNod[4], nextNod[5],
3622                                          midlNod[0], midlNod[1], midlNod[2]);
3623           }
3624         }
3625         else if(nbSame==1) {
3626           // 2d order pyramid of 13 nodes
3627           //SMDS_MeshVolume* AddVolumeWithID(int n1, int n2, int n3, int n4, int n5,
3628           //                                 int n12,int n23,int n34,int n41,
3629           //                                 int n15,int n25,int n35,int n45, int ID);
3630           int n5 = iSameNode;
3631           int n1,n4,n41,n15,n45;
3632           if(i0>0) { // reversed case
3633             n1 = ( n5 + 1 == nbBaseNodes ? 0 : n5 + 1 );
3634             n4 = ( n5 == 0 ? nbBaseNodes - 1 : n5 - 1 );
3635             n41 = n1 + 3;
3636             n15 = n5 + 3;
3637             n45 = n4 + 3;
3638           }
3639           else {
3640             n1 = ( n5 == 0 ? nbBaseNodes - 1 : n5 - 1 );
3641             n4 = ( n5 + 1 == nbBaseNodes ? 0 : n5 + 1 );
3642             n41 = n4 + 3;
3643             n15 = n1 + 3;
3644             n45 = n5 + 3;
3645           }
3646           aNewElem = aMesh->AddVolume(prevNod[n1], nextNod[n1],
3647                                       nextNod[n4], prevNod[n4], prevNod[n5],
3648                                       midlNod[n1], nextNod[n41],
3649                                       midlNod[n4], prevNod[n41],
3650                                       prevNod[n15], nextNod[n15],
3651                                       nextNod[n45], prevNod[n45]);
3652         }
3653         else if(nbSame==2) {
3654           // 2d order tetrahedron of 10 nodes
3655           //SMDS_MeshVolume* AddVolumeWithID(int n1, int n2, int n3, int n4,
3656           //                                 int n12,int n23,int n31,
3657           //                                 int n14,int n24,int n34, int ID);
3658           int n1 = iNotSameNode;
3659           int n2,n3,n12,n23,n31;
3660           if(i0>0) { // reversed case
3661             n2 = ( n1 == 0 ? nbBaseNodes - 1 : n1 - 1 );
3662             n3 = ( n1 + 1 == nbBaseNodes ? 0 : n1 + 1 );
3663             n12 = n2 + 3;
3664             n23 = n3 + 3;
3665             n31 = n1 + 3;
3666           }
3667           else {
3668             n2 = ( n1 + 1 == nbBaseNodes ? 0 : n1 + 1 );
3669             n3 = ( n1 == 0 ? nbBaseNodes - 1 : n1 - 1 );
3670             n12 = n1 + 3;
3671             n23 = n2 + 3;
3672             n31 = n3 + 3;
3673           }
3674           aNewElem = aMesh->AddVolume (prevNod[n1], prevNod[n2], prevNod[n3], nextNod[n1],
3675                                        prevNod[n12], prevNod[n23], prevNod[n31],
3676                                        midlNod[n1], nextNod[n12], nextNod[n31]);
3677         }
3678         break;
3679       }
3680       case 8: { // quadratic quadrangle
3681         if(nbSame==0) {
3682           // create hexahedron with 20 nodes
3683           if(i0>0) { // reversed case
3684             aNewElem = aMesh->AddVolume (prevNod[0], prevNod[3], prevNod[2], prevNod[1],
3685                                          nextNod[0], nextNod[3], nextNod[2], nextNod[1],
3686                                          prevNod[7], prevNod[6], prevNod[5], prevNod[4],
3687                                          nextNod[7], nextNod[6], nextNod[5], nextNod[4],
3688                                          midlNod[0], midlNod[3], midlNod[2], midlNod[1]);
3689           }
3690           else { // not reversed case
3691             aNewElem = aMesh->AddVolume (prevNod[0], prevNod[1], prevNod[2], prevNod[3],
3692                                          nextNod[0], nextNod[1], nextNod[2], nextNod[3],
3693                                          prevNod[4], prevNod[5], prevNod[6], prevNod[7],
3694                                          nextNod[4], nextNod[5], nextNod[6], nextNod[7],
3695                                          midlNod[0], midlNod[1], midlNod[2], midlNod[3]);
3696           }
3697         }
3698         else if(nbSame==1) { 
3699           // --- pyramid + pentahedron - can not be created since it is needed 
3700           // additional middle node ot the center of face
3701           INFOS( " Sweep for face " << elem->GetID() << " can not be created" );
3702           return;
3703         }
3704         else if(nbSame==2) {
3705           // 2d order Pentahedron with 15 nodes
3706           //SMDS_MeshVolume* AddVolumeWithID(int n1, int n2, int n3, int n4, int n5, int n6,
3707           //                                 int n12,int n23,int n31,int n45,int n56,int n64,
3708           //                                 int n14,int n25,int n36, int ID);
3709           int n1,n2,n4,n5;
3710           if ( prevNod[ iBeforeSame ] == nextNod[ iBeforeSame ] ) {
3711             // iBeforeSame is same too
3712             n1 = iBeforeSame;
3713             n2 = iOpposSame;
3714             n4 = iSameNode;
3715             n5 = iAfterSame;
3716           }
3717           else {
3718             // iAfterSame is same too
3719             n1 = iSameNode;
3720             n2 = iBeforeSame;
3721             n4 = iAfterSame;
3722             n5 = iOpposSame;
3723           }
3724           int n12,n45,n14,n25;
3725           if(i0>0) { //reversed case
3726             n12 = n1 + 4;
3727             n45 = n5 + 4;
3728             n14 = n4 + 4;
3729             n25 = n2 + 4;
3730           }
3731           else {
3732             n12 = n2 + 4;
3733             n45 = n4 + 4;
3734             n14 = n1 + 4;
3735             n25 = n5 + 4;
3736           }
3737           aNewElem = aMesh->AddVolume (prevNod[n1], prevNod[n2], nextNod[n2],
3738                                        prevNod[n4], prevNod[n5], nextNod[n5],
3739                                        prevNod[n12], midlNod[n2], nextNod[n12],
3740                                        prevNod[n45], midlNod[n5], nextNod[n45],
3741                                        prevNod[n14], prevNod[n25], nextNod[n25]);
3742         }
3743         break;
3744       }
3745       default: {
3746         // realized for extrusion only
3747         //vector<const SMDS_MeshNode*> polyedre_nodes (nbNodes*2 + 4*nbNodes);
3748         //vector<int> quantities (nbNodes + 2);
3749
3750         //quantities[0] = nbNodes; // bottom of prism
3751         //for (int inode = 0; inode < nbNodes; inode++) {
3752         //  polyedre_nodes[inode] = prevNod[inode];
3753         //}
3754
3755         //quantities[1] = nbNodes; // top of prism
3756         //for (int inode = 0; inode < nbNodes; inode++) {
3757         //  polyedre_nodes[nbNodes + inode] = nextNod[inode];
3758         //}
3759
3760         //for (int iface = 0; iface < nbNodes; iface++) {
3761         //  quantities[iface + 2] = 4;
3762         //  int inextface = (iface == nbNodes - 1) ? 0 : iface + 1;
3763         //  polyedre_nodes[2*nbNodes + 4*iface + 0] = prevNod[iface];
3764         //  polyedre_nodes[2*nbNodes + 4*iface + 1] = prevNod[inextface];
3765         //  polyedre_nodes[2*nbNodes + 4*iface + 2] = nextNod[inextface];
3766         //  polyedre_nodes[2*nbNodes + 4*iface + 3] = nextNod[iface];
3767         //}
3768         //aNewElem = aMesh->AddPolyhedralVolume (polyedre_nodes, quantities);
3769         break;
3770       }
3771       }
3772     }
3773
3774     if(!aNewElem) {
3775       // realized for extrusion only
3776       vector<const SMDS_MeshNode*> polyedre_nodes (nbNodes*2 + 4*nbNodes);
3777       vector<int> quantities (nbNodes + 2);
3778
3779       quantities[0] = nbNodes; // bottom of prism
3780       for (int inode = 0; inode < nbNodes; inode++) {
3781         polyedre_nodes[inode] = prevNod[inode];
3782       }
3783
3784       quantities[1] = nbNodes; // top of prism
3785       for (int inode = 0; inode < nbNodes; inode++) {
3786         polyedre_nodes[nbNodes + inode] = nextNod[inode];
3787       }
3788
3789       for (int iface = 0; iface < nbNodes; iface++) {
3790         quantities[iface + 2] = 4;
3791         int inextface = (iface == nbNodes - 1) ? 0 : iface + 1;
3792         polyedre_nodes[2*nbNodes + 4*iface + 0] = prevNod[iface];
3793         polyedre_nodes[2*nbNodes + 4*iface + 1] = prevNod[inextface];
3794         polyedre_nodes[2*nbNodes + 4*iface + 2] = nextNod[inextface];
3795         polyedre_nodes[2*nbNodes + 4*iface + 3] = nextNod[iface];
3796       }
3797       aNewElem = aMesh->AddPolyhedralVolume (polyedre_nodes, quantities);
3798     }
3799
3800     if ( aNewElem ) {
3801       newElems.push_back( aNewElem );
3802       myLastCreatedElems.Append(aNewElem);
3803       srcElements.Append( elem );
3804       lastElem = aNewElem;
3805     }
3806
3807     // set new prev nodes
3808     for ( iNode = 0; iNode < nbNodes; iNode++ )
3809       prevNod[ iNode ] = nextNod[ iNode ];
3810
3811   } // for steps
3812 }
3813
3814 //=======================================================================
3815 /*!
3816  * \brief Create 1D and 2D elements around swept elements
3817  * \param mapNewNodes - source nodes and ones generated from them
3818  * \param newElemsMap - source elements and ones generated from them
3819  * \param elemNewNodesMap - nodes generated from each node of each element
3820  * \param elemSet - all swept elements
3821  * \param nbSteps - number of sweeping steps
3822  * \param srcElements - to append elem for each generated element
3823  */
3824 //=======================================================================
3825
3826 void SMESH_MeshEditor::makeWalls (TNodeOfNodeListMap &     mapNewNodes,
3827                                   TElemOfElemListMap &     newElemsMap,
3828                                   TElemOfVecOfNnlmiMap &   elemNewNodesMap,
3829                                   TIDSortedElemSet&        elemSet,
3830                                   const int                nbSteps,
3831                                   SMESH_SequenceOfElemPtr& srcElements)
3832 {
3833   MESSAGE("makeWalls");
3834   ASSERT( newElemsMap.size() == elemNewNodesMap.size() );
3835   SMESHDS_Mesh* aMesh = GetMeshDS();
3836
3837   // Find nodes belonging to only one initial element - sweep them to get edges.
3838
3839   TNodeOfNodeListMapItr nList = mapNewNodes.begin();
3840   for ( ; nList != mapNewNodes.end(); nList++ ) {
3841     const SMDS_MeshNode* node =
3842       static_cast<const SMDS_MeshNode*>( nList->first );
3843     SMDS_ElemIteratorPtr eIt = node->GetInverseElementIterator();
3844     int nbInitElems = 0;
3845     const SMDS_MeshElement* el = 0;
3846     SMDSAbs_ElementType highType = SMDSAbs_Edge; // count most complex elements only
3847     while ( eIt->more() && nbInitElems < 2 ) {
3848       el = eIt->next();
3849       SMDSAbs_ElementType type = el->GetType();
3850       if ( type == SMDSAbs_Volume || type < highType ) continue;
3851       if ( type > highType ) {
3852         nbInitElems = 0;
3853         highType = type;
3854       }
3855       if ( elemSet.find(el) != elemSet.end() )
3856         nbInitElems++;
3857     }
3858     if ( nbInitElems < 2 ) {
3859       bool NotCreateEdge = el && el->IsQuadratic() && el->IsMediumNode(node);
3860       if(!NotCreateEdge) {
3861         vector<TNodeOfNodeListMapItr> newNodesItVec( 1, nList );
3862         list<const SMDS_MeshElement*> newEdges;
3863         sweepElement( node, newNodesItVec, newEdges, nbSteps, srcElements );
3864       }
3865     }
3866   }
3867
3868   // Make a ceiling for each element ie an equal element of last new nodes.
3869   // Find free links of faces - make edges and sweep them into faces.
3870
3871   TElemOfElemListMap::iterator   itElem      = newElemsMap.begin();
3872   TElemOfVecOfNnlmiMap::iterator itElemNodes = elemNewNodesMap.begin();
3873   for ( ; itElem != newElemsMap.end(); itElem++, itElemNodes++ ) {
3874     const SMDS_MeshElement* elem = itElem->first;
3875     vector<TNodeOfNodeListMapItr>& vecNewNodes = itElemNodes->second;
3876
3877     if ( elem->GetType() == SMDSAbs_Edge ) {
3878       // create a ceiling edge
3879       if (!elem->IsQuadratic()) {
3880         if ( !aMesh->FindEdge( vecNewNodes[ 0 ]->second.back(),
3881                                vecNewNodes[ 1 ]->second.back())) {
3882           myLastCreatedElems.Append(aMesh->AddEdge(vecNewNodes[ 0 ]->second.back(),
3883                                                    vecNewNodes[ 1 ]->second.back()));
3884           srcElements.Append( myLastCreatedElems.Last() );
3885         }
3886       }
3887       else {
3888         if ( !aMesh->FindEdge( vecNewNodes[ 0 ]->second.back(),
3889                                vecNewNodes[ 1 ]->second.back(),
3890                                vecNewNodes[ 2 ]->second.back())) {
3891           myLastCreatedElems.Append(aMesh->AddEdge(vecNewNodes[ 0 ]->second.back(),
3892                                                    vecNewNodes[ 1 ]->second.back(),
3893                                                    vecNewNodes[ 2 ]->second.back()));
3894           srcElements.Append( myLastCreatedElems.Last() );
3895         }
3896       }
3897     }
3898     if ( elem->GetType() != SMDSAbs_Face )
3899       continue;
3900
3901     if(itElem->second.size()==0) continue;
3902
3903     bool hasFreeLinks = false;
3904
3905     TIDSortedElemSet avoidSet;
3906     avoidSet.insert( elem );
3907
3908     set<const SMDS_MeshNode*> aFaceLastNodes;
3909     int iNode, nbNodes = vecNewNodes.size();
3910     if(!elem->IsQuadratic()) {
3911       // loop on the face nodes
3912       for ( iNode = 0; iNode < nbNodes; iNode++ ) {
3913         aFaceLastNodes.insert( vecNewNodes[ iNode ]->second.back() );
3914         // look for free links of the face
3915         int iNext = ( iNode + 1 == nbNodes ) ? 0 : iNode + 1;
3916         const SMDS_MeshNode* n1 = vecNewNodes[ iNode ]->first;
3917         const SMDS_MeshNode* n2 = vecNewNodes[ iNext ]->first;
3918         // check if a link is free
3919         if ( ! SMESH_MeshEditor::FindFaceInSet ( n1, n2, elemSet, avoidSet )) {
3920           hasFreeLinks = true;
3921           // make an edge and a ceiling for a new edge
3922           if ( !aMesh->FindEdge( n1, n2 )) {
3923             myLastCreatedElems.Append(aMesh->AddEdge( n1, n2 )); // free link edge
3924             srcElements.Append( myLastCreatedElems.Last() );
3925           }
3926           n1 = vecNewNodes[ iNode ]->second.back();
3927           n2 = vecNewNodes[ iNext ]->second.back();
3928           if ( !aMesh->FindEdge( n1, n2 )) {
3929             myLastCreatedElems.Append(aMesh->AddEdge( n1, n2 )); // ceiling edge
3930             srcElements.Append( myLastCreatedElems.Last() );
3931           }
3932         }
3933       }
3934     }
3935     else { // elem is quadratic face
3936       int nbn = nbNodes/2;
3937       for ( iNode = 0; iNode < nbn; iNode++ ) {
3938         aFaceLastNodes.insert( vecNewNodes[ iNode ]->second.back() );
3939         int iNext = ( iNode + 1 == nbn ) ? 0 : iNode + 1;
3940         const SMDS_MeshNode* n1 = vecNewNodes[ iNode ]->first;
3941         const SMDS_MeshNode* n2 = vecNewNodes[ iNext ]->first;
3942         // check if a link is free
3943         if ( ! SMESH_MeshEditor::FindFaceInSet ( n1, n2, elemSet, avoidSet )) {
3944           hasFreeLinks = true;
3945           // make an edge and a ceiling for a new edge
3946           // find medium node
3947           const SMDS_MeshNode* n3 = vecNewNodes[ iNode+nbn ]->first;
3948           if ( !aMesh->FindEdge( n1, n2, n3 )) {
3949             myLastCreatedElems.Append(aMesh->AddEdge( n1, n2, n3 )); // free link edge
3950             srcElements.Append( myLastCreatedElems.Last() );
3951           }
3952           n1 = vecNewNodes[ iNode ]->second.back();
3953           n2 = vecNewNodes[ iNext ]->second.back();
3954           n3 = vecNewNodes[ iNode+nbn ]->second.back();
3955           if ( !aMesh->FindEdge( n1, n2, n3 )) {
3956             myLastCreatedElems.Append(aMesh->AddEdge( n1, n2, n3 )); // ceiling edge
3957             srcElements.Append( myLastCreatedElems.Last() );
3958           }
3959         }
3960       }
3961       for ( iNode = nbn; iNode < 2*nbn; iNode++ ) {
3962         aFaceLastNodes.insert( vecNewNodes[ iNode ]->second.back() );
3963       }
3964     }
3965
3966     // sweep free links into faces
3967
3968     if ( hasFreeLinks )  {
3969       list<const SMDS_MeshElement*> & newVolumes = itElem->second;
3970       int iVol, volNb, nbVolumesByStep = newVolumes.size() / nbSteps;
3971
3972       set<const SMDS_MeshNode*> initNodeSet, topNodeSet, faceNodeSet;
3973       for ( iNode = 0; iNode < nbNodes; iNode++ ) {
3974         initNodeSet.insert( vecNewNodes[ iNode ]->first );
3975         topNodeSet .insert( vecNewNodes[ iNode ]->second.back() );
3976       }
3977       for ( volNb = 0; volNb < nbVolumesByStep; volNb++ ) {
3978         list<const SMDS_MeshElement*>::iterator v = newVolumes.begin();
3979         iVol = 0;
3980         while ( iVol++ < volNb ) v++;
3981         // find indices of free faces of a volume and their source edges
3982         list< int > freeInd;
3983         list< const SMDS_MeshElement* > srcEdges; // source edges of free faces
3984         SMDS_VolumeTool vTool( *v );
3985         int iF, nbF = vTool.NbFaces();
3986         for ( iF = 0; iF < nbF; iF ++ ) {
3987           if (vTool.IsFreeFace( iF ) &&
3988               vTool.GetFaceNodes( iF, faceNodeSet ) &&
3989               initNodeSet != faceNodeSet) // except an initial face
3990           {
3991             if ( nbSteps == 1 && faceNodeSet == topNodeSet )
3992               continue;
3993             freeInd.push_back( iF );
3994             // find source edge of a free face iF
3995             vector<const SMDS_MeshNode*> commonNodes; // shared by the initial and free faces
3996             commonNodes.resize( initNodeSet.size(), NULL ); // avoid spoiling memory
3997             std::set_intersection( faceNodeSet.begin(), faceNodeSet.end(),
3998                                    initNodeSet.begin(), initNodeSet.end(),
3999                                    commonNodes.begin());
4000             if ( (*v)->IsQuadratic() )
4001               srcEdges.push_back(aMesh->FindEdge (commonNodes[0],commonNodes[1],commonNodes[2]));
4002             else
4003               srcEdges.push_back(aMesh->FindEdge (commonNodes[0],commonNodes[1]));
4004 #ifdef _DEBUG_
4005             if ( !srcEdges.back() )
4006             {
4007               cout << "SMESH_MeshEditor::makeWalls(), no source edge found for a free face #"
4008                    << iF << " of volume #" << vTool.ID() << endl;
4009             }
4010 #endif
4011           }
4012         }
4013         if ( freeInd.empty() )
4014           continue;
4015
4016         // create faces for all steps;
4017         // if such a face has been already created by sweep of edge,
4018         // assure that its orientation is OK
4019         for ( int iStep = 0; iStep < nbSteps; iStep++ )  {
4020           vTool.Set( *v );
4021           vTool.SetExternalNormal();
4022           list< int >::iterator ind = freeInd.begin();
4023           list< const SMDS_MeshElement* >::iterator srcEdge = srcEdges.begin();
4024           for ( ; ind != freeInd.end(); ++ind, ++srcEdge ) // loop on free faces
4025           {
4026             const SMDS_MeshNode** nodes = vTool.GetFaceNodes( *ind );
4027             int nbn = vTool.NbFaceNodes( *ind );
4028             switch ( nbn ) {
4029             case 3: { ///// triangle
4030               const SMDS_MeshFace * f = aMesh->FindFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ]);
4031               if ( !f )
4032                 myLastCreatedElems.Append(aMesh->AddFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ] ));
4033               else if ( nodes[ 1 ] != f->GetNodeWrap( f->GetNodeIndex( nodes[ 0 ] ) + 1 ))
4034                 {
4035                   myLastCreatedElems.Append(aMesh->AddFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ] ));
4036                   aMesh->RemoveElement(f);
4037                 }
4038               break;
4039             }
4040             case 4: { ///// quadrangle
4041               const SMDS_MeshFace * f = aMesh->FindFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ], nodes[ 3 ]);
4042               if ( !f )
4043                 myLastCreatedElems.Append(aMesh->AddFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ], nodes[ 3 ] ));
4044               else if ( nodes[ 1 ] != f->GetNodeWrap( f->GetNodeIndex( nodes[ 0 ] ) + 1 ))
4045                 {
4046                   myLastCreatedElems.Append(aMesh->AddFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ], nodes[ 3 ] ));
4047                   aMesh->RemoveElement(f);
4048                 }
4049               break;
4050             }
4051             default:
4052               if( (*v)->IsQuadratic() ) {
4053                 if(nbn==6) { /////// quadratic triangle
4054                   const SMDS_MeshFace * f = aMesh->FindFace( nodes[0], nodes[2], nodes[4],
4055                                                              nodes[1], nodes[3], nodes[5] );
4056                   if ( !f ) {
4057                     myLastCreatedElems.Append(aMesh->AddFace(nodes[0], nodes[2], nodes[4],
4058                                                              nodes[1], nodes[3], nodes[5]));
4059                   }
4060                   else if ( nodes[ 2 ] != f->GetNodeWrap( f->GetNodeIndex( nodes[ 0 ] ) + 1 )) {
4061                     const SMDS_MeshNode** tmpnodes = new const SMDS_MeshNode*[6];
4062                     tmpnodes[0] = nodes[0];
4063                     tmpnodes[1] = nodes[2];
4064                     tmpnodes[2] = nodes[4];
4065                     tmpnodes[3] = nodes[1];
4066                     tmpnodes[4] = nodes[3];
4067                     tmpnodes[5] = nodes[5];
4068                     myLastCreatedElems.Append(aMesh->AddFace(nodes[0], nodes[2], nodes[4],
4069                                                              nodes[1], nodes[3], nodes[5]));
4070                     aMesh->RemoveElement(f);
4071                   }
4072                 }
4073                 else {       /////// quadratic quadrangle
4074                   const SMDS_MeshFace * f = aMesh->FindFace( nodes[0], nodes[2], nodes[4], nodes[6],
4075                                                              nodes[1], nodes[3], nodes[5], nodes[7] );
4076                   if ( !f ) {
4077                     myLastCreatedElems.Append(aMesh->AddFace(nodes[0], nodes[2], nodes[4], nodes[6],
4078                                                              nodes[1], nodes[3], nodes[5], nodes[7]));
4079                   }
4080                   else if ( nodes[ 2 ] != f->GetNodeWrap( f->GetNodeIndex( nodes[ 0 ] ) + 1 )) {
4081                     const SMDS_MeshNode** tmpnodes = new const SMDS_MeshNode*[8];
4082                     tmpnodes[0] = nodes[0];
4083                     tmpnodes[1] = nodes[2];
4084                     tmpnodes[2] = nodes[4];
4085                     tmpnodes[3] = nodes[6];
4086                     tmpnodes[4] = nodes[1];
4087                     tmpnodes[5] = nodes[3];
4088                     tmpnodes[6] = nodes[5];
4089                     tmpnodes[7] = nodes[7];
4090                     myLastCreatedElems.Append(aMesh->AddFace(nodes[0], nodes[2], nodes[4], nodes[6],
4091                                                              nodes[1], nodes[3], nodes[5], nodes[7]));
4092                     aMesh->RemoveElement(f);
4093                   }
4094                 }
4095               }
4096               else { //////// polygon
4097                 vector<const SMDS_MeshNode*> polygon_nodes ( nodes, &nodes[nbn] );
4098                 const SMDS_MeshFace * f = aMesh->FindFace( polygon_nodes );
4099                 if ( !f )
4100                   myLastCreatedElems.Append(aMesh->AddPolygonalFace(polygon_nodes));
4101                 else if ( nodes[ 1 ] != f->GetNodeWrap( f->GetNodeIndex( nodes[ 0 ] ) + 1 ))
4102                   {
4103                   // TODO problem ChangeElementNodes : not the same number of nodes, not the same type
4104                   MESSAGE("ChangeElementNodes");
4105                   aMesh->ChangeElementNodes( f, nodes, nbn );
4106                   }
4107               }
4108             }
4109             while ( srcElements.Length() < myLastCreatedElems.Length() )
4110               srcElements.Append( *srcEdge );
4111
4112           }  // loop on free faces
4113
4114           // go to the next volume
4115           iVol = 0;
4116           while ( iVol++ < nbVolumesByStep ) v++;
4117         }
4118       }
4119     } // sweep free links into faces
4120
4121     // Make a ceiling face with a normal external to a volume
4122
4123     SMDS_VolumeTool lastVol( itElem->second.back() );
4124
4125     int iF = lastVol.GetFaceIndex( aFaceLastNodes );
4126     if ( iF >= 0 ) {
4127       lastVol.SetExternalNormal();
4128       const SMDS_MeshNode** nodes = lastVol.GetFaceNodes( iF );
4129       int nbn = lastVol.NbFaceNodes( iF );
4130       switch ( nbn ) {
4131       case 3:
4132         if (!hasFreeLinks ||
4133             !aMesh->FindFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ]))
4134           myLastCreatedElems.Append(aMesh->AddFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ] ));
4135         break;
4136       case 4:
4137         if (!hasFreeLinks ||
4138             !aMesh->FindFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ], nodes[ 3 ]))
4139           myLastCreatedElems.Append(aMesh->AddFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ], nodes[ 3 ] ));
4140         break;
4141       default:
4142         if(itElem->second.back()->IsQuadratic()) {
4143           if(nbn==6) {
4144             if (!hasFreeLinks ||
4145                 !aMesh->FindFace(nodes[0], nodes[2], nodes[4],
4146                                  nodes[1], nodes[3], nodes[5]) ) {
4147               myLastCreatedElems.Append(aMesh->AddFace(nodes[0], nodes[2], nodes[4],
4148                                                        nodes[1], nodes[3], nodes[5]));
4149             }
4150           }
4151           else { // nbn==8
4152             if (!hasFreeLinks ||
4153                 !aMesh->FindFace(nodes[0], nodes[2], nodes[4], nodes[6],
4154                                  nodes[1], nodes[3], nodes[5], nodes[7]) )
4155               myLastCreatedElems.Append(aMesh->AddFace(nodes[0], nodes[2], nodes[4], nodes[6],
4156                                                        nodes[1], nodes[3], nodes[5], nodes[7]));
4157           }
4158         }
4159         else {
4160           vector<const SMDS_MeshNode*> polygon_nodes ( nodes, &nodes[nbn] );
4161           if (!hasFreeLinks || !aMesh->FindFace(polygon_nodes))
4162             myLastCreatedElems.Append(aMesh->AddPolygonalFace(polygon_nodes));
4163         }
4164       } // switch
4165
4166       while ( srcElements.Length() < myLastCreatedElems.Length() )
4167         srcElements.Append( myLastCreatedElems.Last() );
4168     }
4169   } // loop on swept elements
4170 }
4171
4172 //=======================================================================
4173 //function : RotationSweep
4174 //purpose  :
4175 //=======================================================================
4176
4177 SMESH_MeshEditor::PGroupIDs
4178 SMESH_MeshEditor::RotationSweep(TIDSortedElemSet & theElems,
4179                                 const gp_Ax1&      theAxis,
4180                                 const double       theAngle,
4181                                 const int          theNbSteps,
4182                                 const double       theTol,
4183                                 const bool         theMakeGroups,
4184                                 const bool         theMakeWalls)
4185 {
4186   myLastCreatedElems.Clear();
4187   myLastCreatedNodes.Clear();
4188
4189   // source elements for each generated one
4190   SMESH_SequenceOfElemPtr srcElems, srcNodes;
4191
4192   MESSAGE( "RotationSweep()");
4193   gp_Trsf aTrsf;
4194   aTrsf.SetRotation( theAxis, theAngle );
4195   gp_Trsf aTrsf2;
4196   aTrsf2.SetRotation( theAxis, theAngle/2. );
4197
4198   gp_Lin aLine( theAxis );
4199   double aSqTol = theTol * theTol;
4200
4201   SMESHDS_Mesh* aMesh = GetMeshDS();
4202
4203   TNodeOfNodeListMap mapNewNodes;
4204   TElemOfVecOfNnlmiMap mapElemNewNodes;
4205   TElemOfElemListMap newElemsMap;
4206
4207   // loop on theElems
4208   TIDSortedElemSet::iterator itElem;
4209   for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
4210     const SMDS_MeshElement* elem = *itElem;
4211     if ( !elem || elem->GetType() == SMDSAbs_Volume )
4212       continue;
4213     vector<TNodeOfNodeListMapItr> & newNodesItVec = mapElemNewNodes[ elem ];
4214     newNodesItVec.reserve( elem->NbNodes() );
4215
4216     // loop on elem nodes
4217     SMDS_ElemIteratorPtr itN = elem->nodesIterator();
4218     while ( itN->more() ) {
4219       // check if a node has been already sweeped
4220       const SMDS_MeshNode* node = cast2Node( itN->next() );
4221
4222       gp_XYZ aXYZ( node->X(), node->Y(), node->Z() );
4223       double coord[3];
4224       aXYZ.Coord( coord[0], coord[1], coord[2] );
4225       bool isOnAxis = ( aLine.SquareDistance( aXYZ ) <= aSqTol );
4226
4227       TNodeOfNodeListMapItr nIt = mapNewNodes.find( node );
4228       if ( nIt == mapNewNodes.end() ) {
4229         nIt = mapNewNodes.insert( make_pair( node, list<const SMDS_MeshNode*>() )).first;
4230         list<const SMDS_MeshNode*>& listNewNodes = nIt->second;
4231
4232         // make new nodes
4233         //gp_XYZ aXYZ( node->X(), node->Y(), node->Z() );
4234         //double coord[3];
4235         //aXYZ.Coord( coord[0], coord[1], coord[2] );
4236         //bool isOnAxis = ( aLine.SquareDistance( aXYZ ) <= aSqTol );
4237         const SMDS_MeshNode * newNode = node;
4238         for ( int i = 0; i < theNbSteps; i++ ) {
4239           if ( !isOnAxis ) {
4240             if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
4241               // create two nodes
4242               aTrsf2.Transforms( coord[0], coord[1], coord[2] );
4243               //aTrsf.Transforms( coord[0], coord[1], coord[2] );
4244               newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
4245               myLastCreatedNodes.Append(newNode);
4246               srcNodes.Append( node );
4247               listNewNodes.push_back( newNode );
4248               aTrsf2.Transforms( coord[0], coord[1], coord[2] );
4249               //aTrsf.Transforms( coord[0], coord[1], coord[2] );
4250             }
4251             else {
4252               aTrsf.Transforms( coord[0], coord[1], coord[2] );
4253             }
4254             newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
4255             myLastCreatedNodes.Append(newNode);
4256             srcNodes.Append( node );
4257             listNewNodes.push_back( newNode );
4258           }
4259           else {
4260             listNewNodes.push_back( newNode );
4261             if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
4262               listNewNodes.push_back( newNode );
4263             }
4264           }
4265         }
4266       }
4267       /*
4268         else {
4269         // if current elem is quadratic and current node is not medium
4270         // we have to check - may be it is needed to insert additional nodes
4271         if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
4272         list< const SMDS_MeshNode* > & listNewNodes = nIt->second;
4273         if(listNewNodes.size()==theNbSteps) {
4274         listNewNodes.clear();
4275         // make new nodes
4276         //gp_XYZ aXYZ( node->X(), node->Y(), node->Z() );
4277         //double coord[3];
4278         //aXYZ.Coord( coord[0], coord[1], coord[2] );
4279         const SMDS_MeshNode * newNode = node;
4280         if ( !isOnAxis ) {
4281         for(int i = 0; i<theNbSteps; i++) {
4282         aTrsf2.Transforms( coord[0], coord[1], coord[2] );
4283         newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
4284         cout<<"    3 AddNode:  "<<newNode;
4285         myLastCreatedNodes.Append(newNode);
4286         listNewNodes.push_back( newNode );
4287         srcNodes.Append( node );
4288         aTrsf2.Transforms( coord[0], coord[1], coord[2] );
4289         newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
4290         cout<<"    4 AddNode:  "<<newNode;
4291         myLastCreatedNodes.Append(newNode);
4292         srcNodes.Append( node );
4293         listNewNodes.push_back( newNode );
4294         }
4295         }
4296         else {
4297         listNewNodes.push_back( newNode );
4298         }
4299         }
4300         }
4301         }
4302       */
4303       newNodesItVec.push_back( nIt );
4304     }
4305     // make new elements
4306     sweepElement( elem, newNodesItVec, newElemsMap[elem], theNbSteps, srcElems );
4307   }
4308
4309   if ( theMakeWalls )
4310     makeWalls( mapNewNodes, newElemsMap, mapElemNewNodes, theElems, theNbSteps, srcElems );
4311
4312   PGroupIDs newGroupIDs;
4313   if ( theMakeGroups )
4314     newGroupIDs = generateGroups( srcNodes, srcElems, "rotated");
4315
4316   return newGroupIDs;
4317 }
4318
4319
4320 //=======================================================================
4321 //function : CreateNode
4322 //purpose  :
4323 //=======================================================================
4324 const SMDS_MeshNode* SMESH_MeshEditor::CreateNode(const double x,
4325                                                   const double y,
4326                                                   const double z,
4327                                                   const double tolnode,
4328                                                   SMESH_SequenceOfNode& aNodes)
4329 {
4330   myLastCreatedElems.Clear();
4331   myLastCreatedNodes.Clear();
4332
4333   gp_Pnt P1(x,y,z);
4334   SMESHDS_Mesh * aMesh = myMesh->GetMeshDS();
4335
4336   // try to search in sequence of existing nodes
4337   // if aNodes.Length()>0 we 'nave to use given sequence
4338   // else - use all nodes of mesh
4339   if(aNodes.Length()>0) {
4340     int i;
4341     for(i=1; i<=aNodes.Length(); i++) {
4342       gp_Pnt P2(aNodes.Value(i)->X(),aNodes.Value(i)->Y(),aNodes.Value(i)->Z());
4343       if(P1.Distance(P2)<tolnode)
4344         return aNodes.Value(i);
4345     }
4346   }
4347   else {
4348     SMDS_NodeIteratorPtr itn = aMesh->nodesIterator();
4349     while(itn->more()) {
4350       const SMDS_MeshNode* aN = static_cast<const SMDS_MeshNode*> (itn->next());
4351       gp_Pnt P2(aN->X(),aN->Y(),aN->Z());
4352       if(P1.Distance(P2)<tolnode)
4353         return aN;
4354     }
4355   }
4356
4357   // create new node and return it
4358   const SMDS_MeshNode* NewNode = aMesh->AddNode(x,y,z);
4359   myLastCreatedNodes.Append(NewNode);
4360   return NewNode;
4361 }
4362
4363
4364 //=======================================================================
4365 //function : ExtrusionSweep
4366 //purpose  :
4367 //=======================================================================
4368
4369 SMESH_MeshEditor::PGroupIDs
4370 SMESH_MeshEditor::ExtrusionSweep (TIDSortedElemSet &  theElems,
4371                                   const gp_Vec&       theStep,
4372                                   const int           theNbSteps,
4373                                   TElemOfElemListMap& newElemsMap,
4374                                   const bool          theMakeGroups,
4375                                   const int           theFlags,
4376                                   const double        theTolerance)
4377 {
4378   ExtrusParam aParams;
4379   aParams.myDir = gp_Dir(theStep);
4380   aParams.myNodes.Clear();
4381   aParams.mySteps = new TColStd_HSequenceOfReal;
4382   int i;
4383   for(i=1; i<=theNbSteps; i++)
4384     aParams.mySteps->Append(theStep.Magnitude());
4385
4386   return
4387     ExtrusionSweep(theElems,aParams,newElemsMap,theMakeGroups,theFlags,theTolerance);
4388 }
4389
4390
4391 //=======================================================================
4392 //function : ExtrusionSweep
4393 //purpose  :
4394 //=======================================================================
4395
4396 SMESH_MeshEditor::PGroupIDs
4397 SMESH_MeshEditor::ExtrusionSweep (TIDSortedElemSet &  theElems,
4398                                   ExtrusParam&        theParams,
4399                                   TElemOfElemListMap& newElemsMap,
4400                                   const bool          theMakeGroups,
4401                                   const int           theFlags,
4402                                   const double        theTolerance)
4403 {
4404   MESSAGE("ExtrusionSweep " << theMakeGroups << " " << theFlags << " " << theTolerance);
4405   myLastCreatedElems.Clear();
4406   myLastCreatedNodes.Clear();
4407
4408   // source elements for each generated one
4409   SMESH_SequenceOfElemPtr srcElems, srcNodes;
4410
4411   SMESHDS_Mesh* aMesh = GetMeshDS();
4412
4413   int nbsteps = theParams.mySteps->Length();
4414
4415   TNodeOfNodeListMap mapNewNodes;
4416   //TNodeOfNodeVecMap mapNewNodes;
4417   TElemOfVecOfNnlmiMap mapElemNewNodes;
4418   //TElemOfVecOfMapNodesMap mapElemNewNodes;
4419
4420   // loop on theElems
4421   TIDSortedElemSet::iterator itElem;
4422   for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
4423     // check element type
4424     const SMDS_MeshElement* elem = *itElem;
4425     if ( !elem  || elem->GetType() == SMDSAbs_Volume )
4426       continue;
4427
4428     vector<TNodeOfNodeListMapItr> & newNodesItVec = mapElemNewNodes[ elem ];
4429     //vector<TNodeOfNodeVecMapItr> & newNodesItVec = mapElemNewNodes[ elem ];
4430     newNodesItVec.reserve( elem->NbNodes() );
4431
4432     // loop on elem nodes
4433     SMDS_ElemIteratorPtr itN = elem->nodesIterator();
4434     while ( itN->more() )
4435     {
4436       // check if a node has been already sweeped
4437       const SMDS_MeshNode* node = cast2Node( itN->next() );
4438       TNodeOfNodeListMap::iterator nIt = mapNewNodes.find( node );
4439       //TNodeOfNodeVecMap::iterator nIt = mapNewNodes.find( node );
4440       if ( nIt == mapNewNodes.end() ) {
4441         nIt = mapNewNodes.insert( make_pair( node, list<const SMDS_MeshNode*>() )).first;
4442         //nIt = mapNewNodes.insert( make_pair( node, vector<const SMDS_MeshNode*>() )).first;
4443         list<const SMDS_MeshNode*>& listNewNodes = nIt->second;
4444         //vector<const SMDS_MeshNode*>& vecNewNodes = nIt->second;
4445         //vecNewNodes.reserve(nbsteps);
4446
4447         // make new nodes
4448         double coord[] = { node->X(), node->Y(), node->Z() };
4449         //int nbsteps = theParams.mySteps->Length();
4450         for ( int i = 0; i < nbsteps; i++ ) {
4451           if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
4452             // create additional node
4453             double x = coord[0] + theParams.myDir.X()*theParams.mySteps->Value(i+1)/2.;
4454             double y = coord[1] + theParams.myDir.Y()*theParams.mySteps->Value(i+1)/2.;
4455             double z = coord[2] + theParams.myDir.Z()*theParams.mySteps->Value(i+1)/2.;
4456             if( theFlags & EXTRUSION_FLAG_SEW ) {
4457               const SMDS_MeshNode * newNode = CreateNode(x, y, z,
4458                                                          theTolerance, theParams.myNodes);
4459               listNewNodes.push_back( newNode );
4460             }
4461             else {
4462               const SMDS_MeshNode * newNode = aMesh->AddNode(x, y, z);
4463               myLastCreatedNodes.Append(newNode);
4464               srcNodes.Append( node );
4465               listNewNodes.push_back( newNode );
4466             }
4467           }
4468           //aTrsf.Transforms( coord[0], coord[1], coord[2] );
4469           coord[0] = coord[0] + theParams.myDir.X()*theParams.mySteps->Value(i+1);
4470           coord[1] = coord[1] + theParams.myDir.Y()*theParams.mySteps->Value(i+1);
4471           coord[2] = coord[2] + theParams.myDir.Z()*theParams.mySteps->Value(i+1);
4472           if( theFlags & EXTRUSION_FLAG_SEW ) {
4473             const SMDS_MeshNode * newNode = CreateNode(coord[0], coord[1], coord[2],
4474                                                        theTolerance, theParams.myNodes);
4475             listNewNodes.push_back( newNode );
4476             //vecNewNodes[i]=newNode;
4477           }
4478           else {
4479             const SMDS_MeshNode * newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
4480             myLastCreatedNodes.Append(newNode);
4481             srcNodes.Append( node );
4482             listNewNodes.push_back( newNode );
4483             //vecNewNodes[i]=newNode;
4484           }
4485         }
4486       }
4487       else {
4488         // if current elem is quadratic and current node is not medium
4489         // we have to check - may be it is needed to insert additional nodes
4490         if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
4491           list< const SMDS_MeshNode* > & listNewNodes = nIt->second;
4492           if(listNewNodes.size()==nbsteps) {
4493             listNewNodes.clear();
4494             double coord[] = { node->X(), node->Y(), node->Z() };
4495             for ( int i = 0; i < nbsteps; i++ ) {
4496               double x = coord[0] + theParams.myDir.X()*theParams.mySteps->Value(i+1);
4497               double y = coord[1] + theParams.myDir.Y()*theParams.mySteps->Value(i+1);
4498               double z = coord[2] + theParams.myDir.Z()*theParams.mySteps->Value(i+1);
4499               if( theFlags & EXTRUSION_FLAG_SEW ) {
4500                 const SMDS_MeshNode * newNode = CreateNode(x, y, z,
4501                                                            theTolerance, theParams.myNodes);
4502                 listNewNodes.push_back( newNode );
4503               }
4504               else {
4505                 const SMDS_MeshNode * newNode = aMesh->AddNode(x, y, z);
4506                 myLastCreatedNodes.Append(newNode);
4507                 srcNodes.Append( node );
4508                 listNewNodes.push_back( newNode );
4509               }
4510               coord[0] = coord[0] + theParams.myDir.X()*theParams.mySteps->Value(i+1);
4511               coord[1] = coord[1] + theParams.myDir.Y()*theParams.mySteps->Value(i+1);
4512               coord[2] = coord[2] + theParams.myDir.Z()*theParams.mySteps->Value(i+1);
4513               if( theFlags & EXTRUSION_FLAG_SEW ) {
4514                 const SMDS_MeshNode * newNode = CreateNode(coord[0], coord[1], coord[2],
4515                                                            theTolerance, theParams.myNodes);
4516                 listNewNodes.push_back( newNode );
4517               }
4518               else {
4519                 const SMDS_MeshNode * newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
4520                 myLastCreatedNodes.Append(newNode);
4521                 srcNodes.Append( node );
4522                 listNewNodes.push_back( newNode );
4523               }
4524             }
4525           }
4526         }
4527       }
4528       newNodesItVec.push_back( nIt );
4529     }
4530     // make new elements
4531     sweepElement( elem, newNodesItVec, newElemsMap[elem], nbsteps, srcElems );
4532   }
4533
4534   if( theFlags & EXTRUSION_FLAG_BOUNDARY ) {
4535     makeWalls( mapNewNodes, newElemsMap, mapElemNewNodes, theElems, nbsteps, srcElems );
4536   }
4537   PGroupIDs newGroupIDs;
4538   if ( theMakeGroups )
4539     newGroupIDs = generateGroups( srcNodes, srcElems, "extruded");
4540
4541   return newGroupIDs;
4542 }
4543
4544 /*
4545 //=======================================================================
4546 //class    : SMESH_MeshEditor_PathPoint
4547 //purpose  : auxiliary class
4548 //=======================================================================
4549 class SMESH_MeshEditor_PathPoint {
4550 public:
4551 SMESH_MeshEditor_PathPoint() {
4552 myPnt.SetCoord(99., 99., 99.);
4553 myTgt.SetCoord(1.,0.,0.);
4554 myAngle=0.;
4555 myPrm=0.;
4556 }
4557 void SetPnt(const gp_Pnt& aP3D){
4558 myPnt=aP3D;
4559 }
4560 void SetTangent(const gp_Dir& aTgt){
4561 myTgt=aTgt;
4562 }
4563 void SetAngle(const double& aBeta){
4564 myAngle=aBeta;
4565 }
4566 void SetParameter(const double& aPrm){
4567 myPrm=aPrm;
4568 }
4569 const gp_Pnt& Pnt()const{
4570 return myPnt;
4571 }
4572 const gp_Dir& Tangent()const{
4573 return myTgt;
4574 }
4575 double Angle()const{
4576 return myAngle;
4577 }
4578 double Parameter()const{
4579 return myPrm;
4580 }
4581
4582 protected:
4583 gp_Pnt myPnt;
4584 gp_Dir myTgt;
4585 double myAngle;
4586 double myPrm;
4587 };
4588 */
4589
4590 //=======================================================================
4591 //function : ExtrusionAlongTrack
4592 //purpose  :
4593 //=======================================================================
4594 SMESH_MeshEditor::Extrusion_Error
4595 SMESH_MeshEditor::ExtrusionAlongTrack (TIDSortedElemSet &   theElements,
4596                                        SMESH_subMesh*       theTrack,
4597                                        const SMDS_MeshNode* theN1,
4598                                        const bool           theHasAngles,
4599                                        list<double>&        theAngles,
4600                                        const bool           theLinearVariation,
4601                                        const bool           theHasRefPoint,
4602                                        const gp_Pnt&        theRefPoint,
4603                                        const bool           theMakeGroups)
4604 {
4605   MESSAGE("ExtrusionAlongTrack");
4606   myLastCreatedElems.Clear();
4607   myLastCreatedNodes.Clear();
4608
4609   int aNbE;
4610   std::list<double> aPrms;
4611   TIDSortedElemSet::iterator itElem;
4612
4613   gp_XYZ aGC;
4614   TopoDS_Edge aTrackEdge;
4615   TopoDS_Vertex aV1, aV2;
4616
4617   SMDS_ElemIteratorPtr aItE;
4618   SMDS_NodeIteratorPtr aItN;
4619   SMDSAbs_ElementType aTypeE;
4620
4621   TNodeOfNodeListMap mapNewNodes;
4622
4623   // 1. Check data
4624   aNbE = theElements.size();
4625   // nothing to do
4626   if ( !aNbE )
4627     return EXTR_NO_ELEMENTS;
4628
4629   // 1.1 Track Pattern
4630   ASSERT( theTrack );
4631
4632   SMESHDS_SubMesh* pSubMeshDS = theTrack->GetSubMeshDS();
4633
4634   aItE = pSubMeshDS->GetElements();
4635   while ( aItE->more() ) {
4636     const SMDS_MeshElement* pE = aItE->next();
4637     aTypeE = pE->GetType();
4638     // Pattern must contain links only
4639     if ( aTypeE != SMDSAbs_Edge )
4640       return EXTR_PATH_NOT_EDGE;
4641   }
4642
4643   list<SMESH_MeshEditor_PathPoint> fullList;
4644
4645   const TopoDS_Shape& aS = theTrack->GetSubShape();
4646   // Sub shape for the Pattern must be an Edge or Wire
4647   if( aS.ShapeType() == TopAbs_EDGE ) {
4648     aTrackEdge = TopoDS::Edge( aS );
4649     // the Edge must not be degenerated
4650     if ( BRep_Tool::Degenerated( aTrackEdge ) )
4651       return EXTR_BAD_PATH_SHAPE;
4652     TopExp::Vertices( aTrackEdge, aV1, aV2 );
4653     aItN = theTrack->GetFather()->GetSubMesh( aV1 )->GetSubMeshDS()->GetNodes();
4654     const SMDS_MeshNode* aN1 = aItN->next();
4655     aItN = theTrack->GetFather()->GetSubMesh( aV2 )->GetSubMeshDS()->GetNodes();
4656     const SMDS_MeshNode* aN2 = aItN->next();
4657     // starting node must be aN1 or aN2
4658     if ( !( aN1 == theN1 || aN2 == theN1 ) )
4659       return EXTR_BAD_STARTING_NODE;
4660     aItN = pSubMeshDS->GetNodes();
4661     while ( aItN->more() ) {
4662       const SMDS_MeshNode* pNode = aItN->next();
4663       const SMDS_EdgePosition* pEPos =
4664         static_cast<const SMDS_EdgePosition*>( pNode->GetPosition() );
4665       double aT = pEPos->GetUParameter();
4666       aPrms.push_back( aT );
4667     }
4668     //Extrusion_Error err =
4669     MakeEdgePathPoints(aPrms, aTrackEdge, (aN1==theN1), fullList);
4670   }
4671   else if( aS.ShapeType() == TopAbs_WIRE ) {
4672     list< SMESH_subMesh* > LSM;
4673     TopTools_SequenceOfShape Edges;
4674     SMESH_subMeshIteratorPtr itSM = theTrack->getDependsOnIterator(false,true);
4675     while(itSM->more()) {
4676       SMESH_subMesh* SM = itSM->next();
4677       LSM.push_back(SM);
4678       const TopoDS_Shape& aS = SM->GetSubShape();
4679       Edges.Append(aS);
4680     }
4681     list< list<SMESH_MeshEditor_PathPoint> > LLPPs;
4682     int startNid = theN1->GetID();
4683     TColStd_MapOfInteger UsedNums;
4684     int NbEdges = Edges.Length();
4685     int i = 1;
4686     for(; i<=NbEdges; i++) {
4687       int k = 0;
4688       list< SMESH_subMesh* >::iterator itLSM = LSM.begin();
4689       for(; itLSM!=LSM.end(); itLSM++) {
4690         k++;
4691         if(UsedNums.Contains(k)) continue;
4692         aTrackEdge = TopoDS::Edge( Edges.Value(k) );
4693         SMESH_subMesh* locTrack = *itLSM;
4694         SMESHDS_SubMesh* locMeshDS = locTrack->GetSubMeshDS();
4695         TopExp::Vertices( aTrackEdge, aV1, aV2 );
4696         aItN = locTrack->GetFather()->GetSubMesh(aV1)->GetSubMeshDS()->GetNodes();
4697         const SMDS_MeshNode* aN1 = aItN->next();
4698         aItN = locTrack->GetFather()->GetSubMesh(aV2)->GetSubMeshDS()->GetNodes();
4699         const SMDS_MeshNode* aN2 = aItN->next();
4700         // starting node must be aN1 or aN2
4701         if ( !( aN1->GetID() == startNid || aN2->GetID() == startNid ) ) continue;
4702         // 2. Collect parameters on the track edge
4703         aPrms.clear();
4704         aItN = locMeshDS->GetNodes();
4705         while ( aItN->more() ) {
4706           const SMDS_MeshNode* pNode = aItN->next();
4707           const SMDS_EdgePosition* pEPos =
4708             static_cast<const SMDS_EdgePosition*>( pNode->GetPosition() );
4709           double aT = pEPos->GetUParameter();
4710           aPrms.push_back( aT );
4711         }
4712         list<SMESH_MeshEditor_PathPoint> LPP;
4713         //Extrusion_Error err =
4714         MakeEdgePathPoints(aPrms, aTrackEdge,(aN1->GetID()==startNid), LPP);
4715         LLPPs.push_back(LPP);
4716         UsedNums.Add(k);
4717         // update startN for search following egde
4718         if( aN1->GetID() == startNid ) startNid = aN2->GetID();
4719         else startNid = aN1->GetID();
4720         break;
4721       }
4722     }
4723     list< list<SMESH_MeshEditor_PathPoint> >::iterator itLLPP = LLPPs.begin();
4724     list<SMESH_MeshEditor_PathPoint> firstList = *itLLPP;
4725     list<SMESH_MeshEditor_PathPoint>::iterator itPP = firstList.begin();
4726     for(; itPP!=firstList.end(); itPP++) {
4727       fullList.push_back( *itPP );
4728     }
4729     SMESH_MeshEditor_PathPoint PP1 = fullList.back();
4730     fullList.pop_back();
4731     itLLPP++;
4732     for(; itLLPP!=LLPPs.end(); itLLPP++) {
4733       list<SMESH_MeshEditor_PathPoint> currList = *itLLPP;
4734       itPP = currList.begin();
4735       SMESH_MeshEditor_PathPoint PP2 = currList.front();
4736       gp_Dir D1 = PP1.Tangent();
4737       gp_Dir D2 = PP2.Tangent();
4738       gp_Dir Dnew( gp_Vec( (D1.X()+D2.X())/2, (D1.Y()+D2.Y())/2,
4739                            (D1.Z()+D2.Z())/2 ) );
4740       PP1.SetTangent(Dnew);
4741       fullList.push_back(PP1);
4742       itPP++;
4743       for(; itPP!=firstList.end(); itPP++) {
4744         fullList.push_back( *itPP );
4745       }
4746       PP1 = fullList.back();
4747       fullList.pop_back();
4748     }
4749     // if wire not closed
4750     fullList.push_back(PP1);
4751     // else ???
4752   }
4753   else {
4754     return EXTR_BAD_PATH_SHAPE;
4755   }
4756
4757   return MakeExtrElements(theElements, fullList, theHasAngles, theAngles, theLinearVariation,
4758                           theHasRefPoint, theRefPoint, theMakeGroups);
4759 }
4760
4761
4762 //=======================================================================
4763 //function : ExtrusionAlongTrack
4764 //purpose  :
4765 //=======================================================================
4766 SMESH_MeshEditor::Extrusion_Error
4767 SMESH_MeshEditor::ExtrusionAlongTrack (TIDSortedElemSet &   theElements,
4768                                        SMESH_Mesh*          theTrack,
4769                                        const SMDS_MeshNode* theN1,
4770                                        const bool           theHasAngles,
4771                                        list<double>&        theAngles,
4772                                        const bool           theLinearVariation,
4773                                        const bool           theHasRefPoint,
4774                                        const gp_Pnt&        theRefPoint,
4775                                        const bool           theMakeGroups)
4776 {
4777   myLastCreatedElems.Clear();
4778   myLastCreatedNodes.Clear();
4779
4780   int aNbE;
4781   std::list<double> aPrms;
4782   TIDSortedElemSet::iterator itElem;
4783
4784   gp_XYZ aGC;
4785   TopoDS_Edge aTrackEdge;
4786   TopoDS_Vertex aV1, aV2;
4787
4788   SMDS_ElemIteratorPtr aItE;
4789   SMDS_NodeIteratorPtr aItN;
4790   SMDSAbs_ElementType aTypeE;
4791
4792   TNodeOfNodeListMap mapNewNodes;
4793
4794   // 1. Check data
4795   aNbE = theElements.size();
4796   // nothing to do
4797   if ( !aNbE )
4798     return EXTR_NO_ELEMENTS;
4799
4800   // 1.1 Track Pattern
4801   ASSERT( theTrack );
4802
4803   SMESHDS_Mesh* pMeshDS = theTrack->GetMeshDS();
4804
4805   aItE = pMeshDS->elementsIterator();
4806   while ( aItE->more() ) {
4807     const SMDS_MeshElement* pE = aItE->next();
4808     aTypeE = pE->GetType();
4809     // Pattern must contain links only
4810     if ( aTypeE != SMDSAbs_Edge )
4811       return EXTR_PATH_NOT_EDGE;
4812   }
4813
4814   list<SMESH_MeshEditor_PathPoint> fullList;
4815
4816   const TopoDS_Shape& aS = theTrack->GetShapeToMesh();
4817   // Sub shape for the Pattern must be an Edge or Wire
4818   if( aS.ShapeType() == TopAbs_EDGE ) {
4819     aTrackEdge = TopoDS::Edge( aS );
4820     // the Edge must not be degenerated
4821     if ( BRep_Tool::Degenerated( aTrackEdge ) )
4822       return EXTR_BAD_PATH_SHAPE;
4823     TopExp::Vertices( aTrackEdge, aV1, aV2 );
4824     aItN = theTrack->GetSubMesh( aV1 )->GetSubMeshDS()->GetNodes();
4825     const SMDS_MeshNode* aN1 = aItN->next();
4826     aItN = theTrack->GetSubMesh( aV2 )->GetSubMeshDS()->GetNodes();
4827     const SMDS_MeshNode* aN2 = aItN->next();
4828     // starting node must be aN1 or aN2
4829     if ( !( aN1 == theN1 || aN2 == theN1 ) )
4830       return EXTR_BAD_STARTING_NODE;
4831     aItN = pMeshDS->nodesIterator();
4832     while ( aItN->more() ) {
4833       const SMDS_MeshNode* pNode = aItN->next();
4834       if( pNode==aN1 || pNode==aN2 ) continue;
4835       const SMDS_EdgePosition* pEPos =
4836         static_cast<const SMDS_EdgePosition*>( pNode->GetPosition() );
4837       double aT = pEPos->GetUParameter();
4838       aPrms.push_back( aT );
4839     }
4840     //Extrusion_Error err =
4841     MakeEdgePathPoints(aPrms, aTrackEdge, (aN1==theN1), fullList);
4842   }
4843   else if( aS.ShapeType() == TopAbs_WIRE ) {
4844     list< SMESH_subMesh* > LSM;
4845     TopTools_SequenceOfShape Edges;
4846     TopExp_Explorer eExp(aS, TopAbs_EDGE);
4847     for(; eExp.More(); eExp.Next()) {
4848       TopoDS_Edge E = TopoDS::Edge( eExp.Current() );
4849       if( BRep_Tool::Degenerated(E) ) continue;
4850       SMESH_subMesh* SM = theTrack->GetSubMesh(E);
4851       if(SM) {
4852         LSM.push_back(SM);
4853         Edges.Append(E);
4854       }
4855     }
4856     list< list<SMESH_MeshEditor_PathPoint> > LLPPs;
4857     int startNid = theN1->GetID();
4858     TColStd_MapOfInteger UsedNums;
4859     int NbEdges = Edges.Length();
4860     int i = 1;
4861     for(; i<=NbEdges; i++) {
4862       int k = 0;
4863       list< SMESH_subMesh* >::iterator itLSM = LSM.begin();
4864       for(; itLSM!=LSM.end(); itLSM++) {
4865         k++;
4866         if(UsedNums.Contains(k)) continue;
4867         aTrackEdge = TopoDS::Edge( Edges.Value(k) );
4868         SMESH_subMesh* locTrack = *itLSM;
4869         SMESHDS_SubMesh* locMeshDS = locTrack->GetSubMeshDS();
4870         TopExp::Vertices( aTrackEdge, aV1, aV2 );
4871         aItN = locTrack->GetFather()->GetSubMesh(aV1)->GetSubMeshDS()->GetNodes();
4872         const SMDS_MeshNode* aN1 = aItN->next();
4873         aItN = locTrack->GetFather()->GetSubMesh(aV2)->GetSubMeshDS()->GetNodes();
4874         const SMDS_MeshNode* aN2 = aItN->next();
4875         // starting node must be aN1 or aN2
4876         if ( !( aN1->GetID() == startNid || aN2->GetID() == startNid ) ) continue;
4877         // 2. Collect parameters on the track edge
4878         aPrms.clear();
4879         aItN = locMeshDS->GetNodes();
4880         while ( aItN->more() ) {
4881           const SMDS_MeshNode* pNode = aItN->next();
4882           const SMDS_EdgePosition* pEPos =
4883             static_cast<const SMDS_EdgePosition*>( pNode->GetPosition() );
4884           double aT = pEPos->GetUParameter();
4885           aPrms.push_back( aT );
4886         }
4887         list<SMESH_MeshEditor_PathPoint> LPP;
4888         //Extrusion_Error err =
4889         MakeEdgePathPoints(aPrms, aTrackEdge,(aN1->GetID()==startNid), LPP);
4890         LLPPs.push_back(LPP);
4891         UsedNums.Add(k);
4892         // update startN for search following egde
4893         if( aN1->GetID() == startNid ) startNid = aN2->GetID();
4894         else startNid = aN1->GetID();
4895         break;
4896       }
4897     }
4898     list< list<SMESH_MeshEditor_PathPoint> >::iterator itLLPP = LLPPs.begin();
4899     list<SMESH_MeshEditor_PathPoint> firstList = *itLLPP;
4900     list<SMESH_MeshEditor_PathPoint>::iterator itPP = firstList.begin();
4901     for(; itPP!=firstList.end(); itPP++) {
4902       fullList.push_back( *itPP );
4903     }
4904     SMESH_MeshEditor_PathPoint PP1 = fullList.back();
4905     fullList.pop_back();
4906     itLLPP++;
4907     for(; itLLPP!=LLPPs.end(); itLLPP++) {
4908       list<SMESH_MeshEditor_PathPoint> currList = *itLLPP;
4909       itPP = currList.begin();
4910       SMESH_MeshEditor_PathPoint PP2 = currList.front();
4911       gp_Pnt P1 = PP1.Pnt();
4912       //cout<<"    PP1: Pnt("<<P1.X()<<","<<P1.Y()<<","<<P1.Z()<<")"<<endl;
4913       gp_Pnt P2 = PP2.Pnt();
4914       gp_Dir D1 = PP1.Tangent();
4915       gp_Dir D2 = PP2.Tangent();
4916       gp_Dir Dnew( gp_Vec( (D1.X()+D2.X())/2, (D1.Y()+D2.Y())/2,
4917                            (D1.Z()+D2.Z())/2 ) );
4918       PP1.SetTangent(Dnew);
4919       fullList.push_back(PP1);
4920       itPP++;
4921       for(; itPP!=currList.end(); itPP++) {
4922         fullList.push_back( *itPP );
4923       }
4924       PP1 = fullList.back();
4925       fullList.pop_back();
4926     }
4927     // if wire not closed
4928     fullList.push_back(PP1);
4929     // else ???
4930   }
4931   else {
4932     return EXTR_BAD_PATH_SHAPE;
4933   }
4934
4935   return MakeExtrElements(theElements, fullList, theHasAngles, theAngles, theLinearVariation,
4936                           theHasRefPoint, theRefPoint, theMakeGroups);
4937 }
4938
4939
4940 //=======================================================================
4941 //function : MakeEdgePathPoints
4942 //purpose  : auxilary for ExtrusionAlongTrack
4943 //=======================================================================
4944 SMESH_MeshEditor::Extrusion_Error
4945 SMESH_MeshEditor::MakeEdgePathPoints(std::list<double>& aPrms,
4946                                      const TopoDS_Edge& aTrackEdge,
4947                                      bool FirstIsStart,
4948                                      list<SMESH_MeshEditor_PathPoint>& LPP)
4949 {
4950   Standard_Real aTx1, aTx2, aL2, aTolVec, aTolVec2;
4951   aTolVec=1.e-7;
4952   aTolVec2=aTolVec*aTolVec;
4953   double aT1, aT2;
4954   TopoDS_Vertex aV1, aV2;
4955   TopExp::Vertices( aTrackEdge, aV1, aV2 );
4956   aT1=BRep_Tool::Parameter( aV1, aTrackEdge );
4957   aT2=BRep_Tool::Parameter( aV2, aTrackEdge );
4958   // 2. Collect parameters on the track edge
4959   aPrms.push_front( aT1 );
4960   aPrms.push_back( aT2 );
4961   // sort parameters
4962   aPrms.sort();
4963   if( FirstIsStart ) {
4964     if ( aT1 > aT2 ) {
4965       aPrms.reverse();
4966     }
4967   }
4968   else {
4969     if ( aT2 > aT1 ) {
4970       aPrms.reverse();
4971     }
4972   }
4973   // 3. Path Points
4974   SMESH_MeshEditor_PathPoint aPP;
4975   Handle(Geom_Curve) aC3D = BRep_Tool::Curve( aTrackEdge, aTx1, aTx2 );
4976   std::list<double>::iterator aItD = aPrms.begin();
4977   for(; aItD != aPrms.end(); ++aItD) {
4978     double aT = *aItD;
4979     gp_Pnt aP3D;
4980     gp_Vec aVec;
4981     aC3D->D1( aT, aP3D, aVec );
4982     aL2 = aVec.SquareMagnitude();
4983     if ( aL2 < aTolVec2 )
4984       return EXTR_CANT_GET_TANGENT;
4985     gp_Dir aTgt( aVec );
4986     aPP.SetPnt( aP3D );
4987     aPP.SetTangent( aTgt );
4988     aPP.SetParameter( aT );
4989     LPP.push_back(aPP);
4990   }
4991   return EXTR_OK;
4992 }
4993
4994
4995 //=======================================================================
4996 //function : MakeExtrElements
4997 //purpose  : auxilary for ExtrusionAlongTrack
4998 //=======================================================================
4999 SMESH_MeshEditor::Extrusion_Error
5000 SMESH_MeshEditor::MakeExtrElements(TIDSortedElemSet&  theElements,
5001                                    list<SMESH_MeshEditor_PathPoint>& fullList,
5002                                    const bool theHasAngles,
5003                                    list<double>& theAngles,
5004                                    const bool theLinearVariation,
5005                                    const bool theHasRefPoint,
5006                                    const gp_Pnt& theRefPoint,
5007                                    const bool theMakeGroups)
5008 {
5009   MESSAGE("MakeExtrElements");
5010   //cout<<"MakeExtrElements  fullList.size() = "<<fullList.size()<<endl;
5011   int aNbTP = fullList.size();
5012   vector<SMESH_MeshEditor_PathPoint> aPPs(aNbTP);
5013   // Angles
5014   if( theHasAngles && theAngles.size()>0 && theLinearVariation ) {
5015     LinearAngleVariation(aNbTP-1, theAngles);
5016   }
5017   vector<double> aAngles( aNbTP );
5018   int j = 0;
5019   for(; j<aNbTP; ++j) {
5020     aAngles[j] = 0.;
5021   }
5022   if ( theHasAngles ) {
5023     double anAngle;;
5024     std::list<double>::iterator aItD = theAngles.begin();
5025     for ( j=1; (aItD != theAngles.end()) && (j<aNbTP); ++aItD, ++j ) {
5026       anAngle = *aItD;
5027       aAngles[j] = anAngle;
5028     }
5029   }
5030   // fill vector of path points with angles
5031   //aPPs.resize(fullList.size());
5032   j = -1;
5033   list<SMESH_MeshEditor_PathPoint>::iterator itPP = fullList.begin();
5034   for(; itPP!=fullList.end(); itPP++) {
5035     j++;
5036     SMESH_MeshEditor_PathPoint PP = *itPP;
5037     PP.SetAngle(aAngles[j]);
5038     aPPs[j] = PP;
5039   }
5040
5041   TNodeOfNodeListMap mapNewNodes;
5042   TElemOfVecOfNnlmiMap mapElemNewNodes;
5043   TElemOfElemListMap newElemsMap;
5044   TIDSortedElemSet::iterator itElem;
5045   double aX, aY, aZ;
5046   int aNb;
5047   SMDSAbs_ElementType aTypeE;
5048   // source elements for each generated one
5049   SMESH_SequenceOfElemPtr srcElems, srcNodes;
5050
5051   // 3. Center of rotation aV0
5052   gp_Pnt aV0 = theRefPoint;
5053   gp_XYZ aGC;
5054   if ( !theHasRefPoint ) {
5055     aNb = 0;
5056     aGC.SetCoord( 0.,0.,0. );
5057
5058     itElem = theElements.begin();
5059     for ( ; itElem != theElements.end(); itElem++ ) {
5060       const SMDS_MeshElement* elem = *itElem;
5061
5062       SMDS_ElemIteratorPtr itN = elem->nodesIterator();
5063       while ( itN->more() ) {
5064         const SMDS_MeshNode* node = static_cast<const SMDS_MeshNode*>( itN->next() );
5065         aX = node->X();
5066         aY = node->Y();
5067         aZ = node->Z();
5068
5069         if ( mapNewNodes.find( node ) == mapNewNodes.end() ) {
5070           list<const SMDS_MeshNode*> aLNx;
5071           mapNewNodes[node] = aLNx;
5072           //
5073           gp_XYZ aXYZ( aX, aY, aZ );
5074           aGC += aXYZ;
5075           ++aNb;
5076         }
5077       }
5078     }
5079     aGC /= aNb;
5080     aV0.SetXYZ( aGC );
5081   } // if (!theHasRefPoint) {
5082   mapNewNodes.clear();
5083
5084   // 4. Processing the elements
5085   SMESHDS_Mesh* aMesh = GetMeshDS();
5086
5087   for ( itElem = theElements.begin(); itElem != theElements.end(); itElem++ ) {
5088     // check element type
5089     const SMDS_MeshElement* elem = *itElem;
5090     aTypeE = elem->GetType();
5091     if ( !elem || ( aTypeE != SMDSAbs_Face && aTypeE != SMDSAbs_Edge ) )
5092       continue;
5093
5094     vector<TNodeOfNodeListMapItr> & newNodesItVec = mapElemNewNodes[ elem ];
5095     newNodesItVec.reserve( elem->NbNodes() );
5096
5097     // loop on elem nodes
5098     int nodeIndex = -1;
5099     SMDS_ElemIteratorPtr itN = elem->nodesIterator();
5100     while ( itN->more() )
5101     {
5102       ++nodeIndex;
5103       // check if a node has been already processed
5104       const SMDS_MeshNode* node =
5105         static_cast<const SMDS_MeshNode*>( itN->next() );
5106       TNodeOfNodeListMap::iterator nIt = mapNewNodes.find( node );
5107       if ( nIt == mapNewNodes.end() ) {
5108         nIt = mapNewNodes.insert( make_pair( node, list<const SMDS_MeshNode*>() )).first;
5109         list<const SMDS_MeshNode*>& listNewNodes = nIt->second;
5110
5111         // make new nodes
5112         aX = node->X();  aY = node->Y(); aZ = node->Z();
5113
5114         Standard_Real aAngle1x, aAngleT1T0, aTolAng;
5115         gp_Pnt aP0x, aP1x, aPN0, aPN1, aV0x, aV1x;
5116         gp_Ax1 anAx1, anAxT1T0;
5117         gp_Dir aDT1x, aDT0x, aDT1T0;
5118
5119         aTolAng=1.e-4;
5120
5121         aV0x = aV0;
5122         aPN0.SetCoord(aX, aY, aZ);
5123
5124         const SMESH_MeshEditor_PathPoint& aPP0 = aPPs[0];
5125         aP0x = aPP0.Pnt();
5126         aDT0x= aPP0.Tangent();
5127         //cout<<"j = 0   PP: Pnt("<<aP0x.X()<<","<<aP0x.Y()<<","<<aP0x.Z()<<")"<<endl;
5128
5129         for ( j = 1; j < aNbTP; ++j ) {
5130           const SMESH_MeshEditor_PathPoint& aPP1 = aPPs[j];
5131           aP1x = aPP1.Pnt();
5132           aDT1x = aPP1.Tangent();
5133           aAngle1x = aPP1.Angle();
5134
5135           gp_Trsf aTrsf, aTrsfRot, aTrsfRotT1T0;
5136           // Translation
5137           gp_Vec aV01x( aP0x, aP1x );
5138           aTrsf.SetTranslation( aV01x );
5139
5140           // traslated point
5141           aV1x = aV0x.Transformed( aTrsf );
5142           aPN1 = aPN0.Transformed( aTrsf );
5143
5144           // rotation 1 [ T1,T0 ]
5145           aAngleT1T0=-aDT1x.Angle( aDT0x );
5146           if (fabs(aAngleT1T0) > aTolAng) {
5147             aDT1T0=aDT1x^aDT0x;
5148             anAxT1T0.SetLocation( aV1x );
5149             anAxT1T0.SetDirection( aDT1T0 );
5150             aTrsfRotT1T0.SetRotation( anAxT1T0, aAngleT1T0 );
5151
5152             aPN1 = aPN1.Transformed( aTrsfRotT1T0 );
5153           }
5154
5155           // rotation 2
5156           if ( theHasAngles ) {
5157             anAx1.SetLocation( aV1x );
5158             anAx1.SetDirection( aDT1x );
5159             aTrsfRot.SetRotation( anAx1, aAngle1x );
5160
5161             aPN1 = aPN1.Transformed( aTrsfRot );
5162           }
5163
5164           // make new node
5165           //MESSAGE("elem->IsQuadratic " << elem->IsQuadratic() << " " << elem->IsMediumNode(node));
5166           if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
5167             // create additional node
5168             double x = ( aPN1.X() + aPN0.X() )/2.;
5169             double y = ( aPN1.Y() + aPN0.Y() )/2.;
5170             double z = ( aPN1.Z() + aPN0.Z() )/2.;
5171             const SMDS_MeshNode* newNode = aMesh->AddNode(x,y,z);
5172             myLastCreatedNodes.Append(newNode);
5173             srcNodes.Append( node );
5174             listNewNodes.push_back( newNode );
5175           }
5176           aX = aPN1.X();
5177           aY = aPN1.Y();
5178           aZ = aPN1.Z();
5179           const SMDS_MeshNode* newNode = aMesh->AddNode( aX, aY, aZ );
5180           myLastCreatedNodes.Append(newNode);
5181           srcNodes.Append( node );
5182           listNewNodes.push_back( newNode );
5183
5184           aPN0 = aPN1;
5185           aP0x = aP1x;
5186           aV0x = aV1x;
5187           aDT0x = aDT1x;
5188         }
5189       }
5190
5191       else {
5192         // if current elem is quadratic and current node is not medium
5193         // we have to check - may be it is needed to insert additional nodes
5194         if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
5195           list< const SMDS_MeshNode* > & listNewNodes = nIt->second;
5196           if(listNewNodes.size()==aNbTP-1) {
5197             vector<const SMDS_MeshNode*> aNodes(2*(aNbTP-1));
5198             gp_XYZ P(node->X(), node->Y(), node->Z());
5199             list< const SMDS_MeshNode* >::iterator it = listNewNodes.begin();
5200             int i;
5201             for(i=0; i<aNbTP-1; i++) {
5202               const SMDS_MeshNode* N = *it;
5203               double x = ( N->X() + P.X() )/2.;
5204               double y = ( N->Y() + P.Y() )/2.;
5205               double z = ( N->Z() + P.Z() )/2.;
5206               const SMDS_MeshNode* newN = aMesh->AddNode(x,y,z);
5207               srcNodes.Append( node );
5208               myLastCreatedNodes.Append(newN);
5209               aNodes[2*i] = newN;
5210               aNodes[2*i+1] = N;
5211               P = gp_XYZ(N->X(),N->Y(),N->Z());
5212             }
5213             listNewNodes.clear();
5214             for(i=0; i<2*(aNbTP-1); i++) {
5215               listNewNodes.push_back(aNodes[i]);
5216             }
5217           }
5218         }
5219       }
5220
5221       newNodesItVec.push_back( nIt );
5222     }
5223     // make new elements
5224     //sweepElement( aMesh, elem, newNodesItVec, newElemsMap[elem],
5225     //              newNodesItVec[0]->second.size(), myLastCreatedElems );
5226     sweepElement( elem, newNodesItVec, newElemsMap[elem], aNbTP-1, srcElems );
5227   }
5228
5229   makeWalls( mapNewNodes, newElemsMap, mapElemNewNodes, theElements, aNbTP-1, srcElems );
5230
5231   if ( theMakeGroups )
5232     generateGroups( srcNodes, srcElems, "extruded");
5233
5234   return EXTR_OK;
5235 }
5236
5237
5238 //=======================================================================
5239 //function : LinearAngleVariation
5240 //purpose  : auxilary for ExtrusionAlongTrack
5241 //=======================================================================
5242 void SMESH_MeshEditor::LinearAngleVariation(const int nbSteps,
5243                                             list<double>& Angles)
5244 {
5245   int nbAngles = Angles.size();
5246   if( nbSteps > nbAngles ) {
5247     vector<double> theAngles(nbAngles);
5248     list<double>::iterator it = Angles.begin();
5249     int i = -1;
5250     for(; it!=Angles.end(); it++) {
5251       i++;
5252       theAngles[i] = (*it);
5253     }
5254     list<double> res;
5255     double rAn2St = double( nbAngles ) / double( nbSteps );
5256     double angPrev = 0, angle;
5257     for ( int iSt = 0; iSt < nbSteps; ++iSt ) {
5258       double angCur = rAn2St * ( iSt+1 );
5259       double angCurFloor  = floor( angCur );
5260       double angPrevFloor = floor( angPrev );
5261       if ( angPrevFloor == angCurFloor )
5262         angle = rAn2St * theAngles[ int( angCurFloor ) ];
5263       else {
5264         int iP = int( angPrevFloor );
5265         double angPrevCeil = ceil(angPrev);
5266         angle = ( angPrevCeil - angPrev ) * theAngles[ iP ];
5267
5268         int iC = int( angCurFloor );
5269         if ( iC < nbAngles )
5270           angle += ( angCur - angCurFloor ) * theAngles[ iC ];
5271
5272         iP = int( angPrevCeil );
5273         while ( iC-- > iP )
5274           angle += theAngles[ iC ];
5275       }
5276       res.push_back(angle);
5277       angPrev = angCur;
5278     }
5279     Angles.clear();
5280     it = res.begin();
5281     for(; it!=res.end(); it++)
5282       Angles.push_back( *it );
5283   }
5284 }
5285
5286
5287 //================================================================================
5288 /*!
5289  * \brief Move or copy theElements applying theTrsf to their nodes
5290  *  \param theElems - elements to transform, if theElems is empty then apply to all mesh nodes
5291  *  \param theTrsf - transformation to apply
5292  *  \param theCopy - if true, create translated copies of theElems
5293  *  \param theMakeGroups - if true and theCopy, create translated groups
5294  *  \param theTargetMesh - mesh to copy translated elements into
5295  *  \retval SMESH_MeshEditor::PGroupIDs - list of ids of created groups
5296  */
5297 //================================================================================
5298
5299 SMESH_MeshEditor::PGroupIDs
5300 SMESH_MeshEditor::Transform (TIDSortedElemSet & theElems,
5301                              const gp_Trsf&     theTrsf,
5302                              const bool         theCopy,
5303                              const bool         theMakeGroups,
5304                              SMESH_Mesh*        theTargetMesh)
5305 {
5306   myLastCreatedElems.Clear();
5307   myLastCreatedNodes.Clear();
5308
5309   bool needReverse = false;
5310   string groupPostfix;
5311   switch ( theTrsf.Form() ) {
5312   case gp_PntMirror:
5313   case gp_Ax1Mirror:
5314   case gp_Ax2Mirror:
5315     needReverse = true;
5316     groupPostfix = "mirrored";
5317     break;
5318   case gp_Rotation:
5319     groupPostfix = "rotated";
5320     break;
5321   case gp_Translation:
5322     groupPostfix = "translated";
5323     break;
5324   case gp_Scale:
5325   case gp_CompoundTrsf: // different scale by axis
5326     groupPostfix = "scaled";
5327     break;
5328   default:
5329     needReverse = false;
5330     groupPostfix = "transformed";
5331   }
5332
5333   SMESH_MeshEditor targetMeshEditor( theTargetMesh );
5334   SMESHDS_Mesh* aTgtMesh = theTargetMesh ? theTargetMesh->GetMeshDS() : 0;
5335   SMESHDS_Mesh* aMesh    = GetMeshDS();
5336
5337
5338   // map old node to new one
5339   TNodeNodeMap nodeMap;
5340
5341   // elements sharing moved nodes; those of them which have all
5342   // nodes mirrored but are not in theElems are to be reversed
5343   TIDSortedElemSet inverseElemSet;
5344
5345   // source elements for each generated one
5346   SMESH_SequenceOfElemPtr srcElems, srcNodes;
5347
5348   // issue 021015: EDF 1578 SMESH: Free nodes are removed when translating a mesh
5349   TIDSortedElemSet orphanNode;
5350
5351   if ( theElems.empty() ) // transform the whole mesh
5352   {
5353     // add all elements
5354     SMDS_ElemIteratorPtr eIt = aMesh->elementsIterator();
5355     while ( eIt->more() ) theElems.insert( eIt->next() );
5356     // add orphan nodes
5357     SMDS_NodeIteratorPtr nIt = aMesh->nodesIterator();
5358     while ( nIt->more() )
5359     {
5360       const SMDS_MeshNode* node = nIt->next();
5361       if ( node->NbInverseElements() == 0)
5362         orphanNode.insert( node );
5363     }
5364   }
5365
5366   // loop on elements to transform nodes : first orphan nodes then elems
5367   TIDSortedElemSet::iterator itElem;
5368   TIDSortedElemSet *elements[] = {&orphanNode, &theElems };
5369   for (int i=0; i<2; i++)
5370   for ( itElem = elements[i]->begin(); itElem != elements[i]->end(); itElem++ ) {
5371     const SMDS_MeshElement* elem = *itElem;
5372     if ( !elem )
5373       continue;
5374
5375     // loop on elem nodes
5376     SMDS_ElemIteratorPtr itN = elem->nodesIterator();
5377     while ( itN->more() ) {
5378
5379       const SMDS_MeshNode* node = cast2Node( itN->next() );
5380       // check if a node has been already transformed
5381       pair<TNodeNodeMap::iterator,bool> n2n_isnew =
5382         nodeMap.insert( make_pair ( node, node ));
5383       if ( !n2n_isnew.second )
5384         continue;
5385
5386       double coord[3];
5387       coord[0] = node->X();
5388       coord[1] = node->Y();
5389       coord[2] = node->Z();
5390       theTrsf.Transforms( coord[0], coord[1], coord[2] );
5391       if ( theTargetMesh ) {
5392         const SMDS_MeshNode * newNode = aTgtMesh->AddNode( coord[0], coord[1], coord[2] );
5393         n2n_isnew.first->second = newNode;
5394         myLastCreatedNodes.Append(newNode);
5395         srcNodes.Append( node );
5396       }
5397       else if ( theCopy ) {
5398         const SMDS_MeshNode * newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
5399         n2n_isnew.first->second = newNode;
5400         myLastCreatedNodes.Append(newNode);
5401         srcNodes.Append( node );
5402       }
5403       else {
5404         aMesh->MoveNode( node, coord[0], coord[1], coord[2] );
5405         // node position on shape becomes invalid
5406         const_cast< SMDS_MeshNode* > ( node )->SetPosition
5407           ( SMDS_SpacePosition::originSpacePosition() );
5408       }
5409
5410       // keep inverse elements
5411       if ( !theCopy && !theTargetMesh && needReverse ) {
5412         SMDS_ElemIteratorPtr invElemIt = node->GetInverseElementIterator();
5413         while ( invElemIt->more() ) {
5414           const SMDS_MeshElement* iel = invElemIt->next();
5415           inverseElemSet.insert( iel );
5416         }
5417       }
5418     }
5419   }
5420
5421   // either create new elements or reverse mirrored ones
5422   if ( !theCopy && !needReverse && !theTargetMesh )
5423     return PGroupIDs();
5424
5425   TIDSortedElemSet::iterator invElemIt = inverseElemSet.begin();
5426   for ( ; invElemIt != inverseElemSet.end(); invElemIt++ )
5427     theElems.insert( *invElemIt );
5428
5429   // replicate or reverse elements
5430   // TODO revoir ordre reverse vtk
5431   enum {
5432     REV_TETRA   = 0,  //  = nbNodes - 4
5433     REV_PYRAMID = 1,  //  = nbNodes - 4
5434     REV_PENTA   = 2,  //  = nbNodes - 4
5435     REV_FACE    = 3,
5436     REV_HEXA    = 4,  //  = nbNodes - 4
5437     FORWARD     = 5
5438   };
5439   int index[][8] = {
5440     { 2, 1, 0, 3, 4, 0, 0, 0 },  // REV_TETRA
5441     { 2, 1, 0, 3, 4, 0, 0, 0 },  // REV_PYRAMID
5442     { 2, 1, 0, 5, 4, 3, 0, 0 },  // REV_PENTA
5443     { 2, 1, 0, 3, 0, 0, 0, 0 },  // REV_FACE
5444     { 2, 1, 0, 3, 6, 5, 4, 7 },  // REV_HEXA
5445     { 0, 1, 2, 3, 4, 5, 6, 7 }   // FORWARD
5446   };
5447
5448   for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ )
5449   {
5450     const SMDS_MeshElement* elem = *itElem;
5451     if ( !elem || elem->GetType() == SMDSAbs_Node )
5452       continue;
5453
5454     int nbNodes = elem->NbNodes();
5455     int elemType = elem->GetType();
5456
5457     if (elem->IsPoly()) {
5458       // Polygon or Polyhedral Volume
5459       switch ( elemType ) {
5460       case SMDSAbs_Face:
5461         {
5462           vector<const SMDS_MeshNode*> poly_nodes (nbNodes);
5463           int iNode = 0;
5464           SMDS_ElemIteratorPtr itN = elem->nodesIterator();
5465           while (itN->more()) {
5466             const SMDS_MeshNode* node =
5467               static_cast<const SMDS_MeshNode*>(itN->next());
5468             TNodeNodeMap::iterator nodeMapIt = nodeMap.find(node);
5469             if (nodeMapIt == nodeMap.end())
5470               break; // not all nodes transformed
5471             if (needReverse) {
5472               // reverse mirrored faces and volumes
5473               poly_nodes[nbNodes - iNode - 1] = (*nodeMapIt).second;
5474             } else {
5475               poly_nodes[iNode] = (*nodeMapIt).second;
5476             }
5477             iNode++;
5478           }
5479           if ( iNode != nbNodes )
5480             continue; // not all nodes transformed
5481
5482           if ( theTargetMesh ) {
5483             myLastCreatedElems.Append(aTgtMesh->AddPolygonalFace(poly_nodes));
5484             srcElems.Append( elem );
5485           }
5486           else if ( theCopy ) {
5487             myLastCreatedElems.Append(aMesh->AddPolygonalFace(poly_nodes));
5488             srcElems.Append( elem );
5489           }
5490           else {
5491             aMesh->ChangePolygonNodes(elem, poly_nodes);
5492           }
5493         }
5494         break;
5495       case SMDSAbs_Volume:
5496         {
5497           // ATTENTION: Reversing is not yet done!!!
5498           const SMDS_VtkVolume* aPolyedre =
5499             dynamic_cast<const SMDS_VtkVolume*>( elem );
5500           if (!aPolyedre) {
5501             MESSAGE("Warning: bad volumic element");
5502             continue;
5503           }
5504
5505           vector<const SMDS_MeshNode*> poly_nodes;
5506           vector<int> quantities;
5507
5508           bool allTransformed = true;
5509           int nbFaces = aPolyedre->NbFaces();
5510           for (int iface = 1; iface <= nbFaces && allTransformed; iface++) {
5511             int nbFaceNodes = aPolyedre->NbFaceNodes(iface);
5512             for (int inode = 1; inode <= nbFaceNodes && allTransformed; inode++) {
5513               const SMDS_MeshNode* node = aPolyedre->GetFaceNode(iface, inode);
5514               TNodeNodeMap::iterator nodeMapIt = nodeMap.find(node);
5515               if (nodeMapIt == nodeMap.end()) {
5516                 allTransformed = false; // not all nodes transformed
5517               } else {
5518                 poly_nodes.push_back((*nodeMapIt).second);
5519               }
5520             }
5521             quantities.push_back(nbFaceNodes);
5522           }
5523           if ( !allTransformed )
5524             continue; // not all nodes transformed
5525
5526           if ( theTargetMesh ) {
5527             myLastCreatedElems.Append(aTgtMesh->AddPolyhedralVolume(poly_nodes, quantities));
5528             srcElems.Append( elem );
5529           }
5530           else if ( theCopy ) {
5531             myLastCreatedElems.Append(aMesh->AddPolyhedralVolume(poly_nodes, quantities));
5532             srcElems.Append( elem );
5533           }
5534           else {
5535             aMesh->ChangePolyhedronNodes(elem, poly_nodes, quantities);
5536           }
5537         }
5538         break;
5539       default:;
5540       }
5541       continue;
5542     }
5543
5544     // Regular elements
5545     int* i = index[ FORWARD ];
5546     if ( needReverse && nbNodes > 2) {// reverse mirrored faces and volumes
5547       if ( elemType == SMDSAbs_Face )
5548         i = index[ REV_FACE ];
5549       else
5550         i = index[ nbNodes - 4 ];
5551     }
5552     if(elem->IsQuadratic()) {
5553       static int anIds[] = {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19};
5554       i = anIds;
5555       if(needReverse) {
5556         if(nbNodes==3) { // quadratic edge
5557           static int anIds[] = {1,0,2};
5558           i = anIds;
5559         }
5560         else if(nbNodes==6) { // quadratic triangle
5561           static int anIds[] = {0,2,1,5,4,3};
5562           i = anIds;
5563         }
5564         else if(nbNodes==8) { // quadratic quadrangle
5565           static int anIds[] = {0,3,2,1,7,6,5,4};
5566           i = anIds;
5567         }
5568         else if(nbNodes==10) { // quadratic tetrahedron of 10 nodes
5569           static int anIds[] = {0,2,1,3,6,5,4,7,9,8};
5570           i = anIds;
5571         }
5572         else if(nbNodes==13) { // quadratic pyramid of 13 nodes
5573           static int anIds[] = {0,3,2,1,4,8,7,6,5,9,12,11,10};
5574           i = anIds;
5575         }
5576         else if(nbNodes==15) { // quadratic pentahedron with 15 nodes
5577           static int anIds[] = {0,2,1,3,5,4,8,7,6,11,10,9,12,14,13};
5578           i = anIds;
5579         }
5580         else { // nbNodes==20 - quadratic hexahedron with 20 nodes
5581           static int anIds[] = {0,3,2,1,4,7,6,5,11,10,9,8,15,14,13,12,16,19,18,17};
5582           i = anIds;
5583         }
5584       }
5585     }
5586
5587     // find transformed nodes
5588     vector<const SMDS_MeshNode*> nodes(nbNodes);
5589     int iNode = 0;
5590     SMDS_ElemIteratorPtr itN = elem->nodesIterator();
5591     while ( itN->more() ) {
5592       const SMDS_MeshNode* node =
5593         static_cast<const SMDS_MeshNode*>( itN->next() );
5594       TNodeNodeMap::iterator nodeMapIt = nodeMap.find( node );
5595       if ( nodeMapIt == nodeMap.end() )
5596         break; // not all nodes transformed
5597       nodes[ i [ iNode++ ]] = (*nodeMapIt).second;
5598     }
5599     if ( iNode != nbNodes )
5600       continue; // not all nodes transformed
5601
5602     if ( theTargetMesh ) {
5603       if ( SMDS_MeshElement* copy =
5604            targetMeshEditor.AddElement( nodes, elem->GetType(), elem->IsPoly() )) {
5605         myLastCreatedElems.Append( copy );
5606         srcElems.Append( elem );
5607       }
5608     }
5609     else if ( theCopy ) {
5610       if ( AddElement( nodes, elem->GetType(), elem->IsPoly() ))
5611         srcElems.Append( elem );
5612     }
5613     else {
5614       // reverse element as it was reversed by transformation
5615       if ( nbNodes > 2 )
5616         aMesh->ChangeElementNodes( elem, &nodes[0], nbNodes );
5617     }
5618   }
5619
5620   PGroupIDs newGroupIDs;
5621
5622   if ( theMakeGroups && theCopy ||
5623        theMakeGroups && theTargetMesh )
5624     newGroupIDs = generateGroups( srcNodes, srcElems, groupPostfix, theTargetMesh );
5625
5626   return newGroupIDs;
5627 }
5628
5629
5630 ////=======================================================================
5631 ////function : Scale
5632 ////purpose  :
5633 ////=======================================================================
5634 //
5635 //SMESH_MeshEditor::PGroupIDs
5636 //SMESH_MeshEditor::Scale (TIDSortedElemSet & theElems,
5637 //                         const gp_Pnt&            thePoint,
5638 //                         const std::list<double>& theScaleFact,
5639 //                         const bool         theCopy,
5640 //                         const bool         theMakeGroups,
5641 //                         SMESH_Mesh*        theTargetMesh)
5642 //{
5643 //  MESSAGE("Scale");
5644 //  myLastCreatedElems.Clear();
5645 //  myLastCreatedNodes.Clear();
5646 //
5647 //  SMESH_MeshEditor targetMeshEditor( theTargetMesh );
5648 //  SMESHDS_Mesh* aTgtMesh = theTargetMesh ? theTargetMesh->GetMeshDS() : 0;
5649 //  SMESHDS_Mesh* aMesh    = GetMeshDS();
5650 //
5651 //  double scaleX=1.0, scaleY=1.0, scaleZ=1.0;
5652 //  std::list<double>::const_iterator itS = theScaleFact.begin();
5653 //  scaleX = (*itS);
5654 //  if(theScaleFact.size()==1) {
5655 //    scaleY = (*itS);
5656 //    scaleZ= (*itS);
5657 //  }
5658 //  if(theScaleFact.size()==2) {
5659 //    itS++;
5660 //    scaleY = (*itS);
5661 //    scaleZ= (*itS);
5662 //  }
5663 //  if(theScaleFact.size()>2) {
5664 //    itS++;
5665 //    scaleY = (*itS);
5666 //    itS++;
5667 //    scaleZ= (*itS);
5668 //  }
5669 //
5670 //  // map old node to new one
5671 //  TNodeNodeMap nodeMap;
5672 //
5673 //  // elements sharing moved nodes; those of them which have all
5674 //  // nodes mirrored but are not in theElems are to be reversed
5675 //  TIDSortedElemSet inverseElemSet;
5676 //
5677 //  // source elements for each generated one
5678 //  SMESH_SequenceOfElemPtr srcElems, srcNodes;
5679 //
5680 //  // loop on theElems
5681 //  TIDSortedElemSet::iterator itElem;
5682 //  for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
5683 //    const SMDS_MeshElement* elem = *itElem;
5684 //    if ( !elem )
5685 //      continue;
5686 //
5687 //    // loop on elem nodes
5688 //    SMDS_ElemIteratorPtr itN = elem->nodesIterator();
5689 //    while ( itN->more() ) {
5690 //
5691 //      // check if a node has been already transformed
5692 //      const SMDS_MeshNode* node = cast2Node( itN->next() );
5693 //      pair<TNodeNodeMap::iterator,bool> n2n_isnew =
5694 //        nodeMap.insert( make_pair ( node, node ));
5695 //      if ( !n2n_isnew.second )
5696 //        continue;
5697 //
5698 //      //double coord[3];
5699 //      //coord[0] = node->X();
5700 //      //coord[1] = node->Y();
5701 //      //coord[2] = node->Z();
5702 //      //theTrsf.Transforms( coord[0], coord[1], coord[2] );
5703 //      double dx = (node->X() - thePoint.X()) * scaleX;
5704 //      double dy = (node->Y() - thePoint.Y()) * scaleY;
5705 //      double dz = (node->Z() - thePoint.Z()) * scaleZ;
5706 //      if ( theTargetMesh ) {
5707 //        //const SMDS_MeshNode * newNode = aTgtMesh->AddNode( coord[0], coord[1], coord[2] );
5708 //        const SMDS_MeshNode * newNode =
5709 //          aTgtMesh->AddNode( thePoint.X()+dx, thePoint.Y()+dy, thePoint.Z()+dz );
5710 //        n2n_isnew.first->second = newNode;
5711 //        myLastCreatedNodes.Append(newNode);
5712 //        srcNodes.Append( node );
5713 //      }
5714 //      else if ( theCopy ) {
5715 //        //const SMDS_MeshNode * newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
5716 //        const SMDS_MeshNode * newNode =
5717 //          aMesh->AddNode( thePoint.X()+dx, thePoint.Y()+dy, thePoint.Z()+dz );
5718 //        n2n_isnew.first->second = newNode;
5719 //        myLastCreatedNodes.Append(newNode);
5720 //        srcNodes.Append( node );
5721 //      }
5722 //      else {
5723 //        //aMesh->MoveNode( node, coord[0], coord[1], coord[2] );
5724 //        aMesh->MoveNode( node, thePoint.X()+dx, thePoint.Y()+dy, thePoint.Z()+dz );
5725 //        // node position on shape becomes invalid
5726 //        const_cast< SMDS_MeshNode* > ( node )->SetPosition
5727 //          ( SMDS_SpacePosition::originSpacePosition() );
5728 //      }
5729 //
5730 //      // keep inverse elements
5731 //      //if ( !theCopy && !theTargetMesh && needReverse ) {
5732 //      //  SMDS_ElemIteratorPtr invElemIt = node->GetInverseElementIterator();
5733 //      //  while ( invElemIt->more() ) {
5734 //      //    const SMDS_MeshElement* iel = invElemIt->next();
5735 //      //    inverseElemSet.insert( iel );
5736 //      //  }
5737 //      //}
5738 //    }
5739 //  }
5740 //
5741 //  // either create new elements or reverse mirrored ones
5742 //  //if ( !theCopy && !needReverse && !theTargetMesh )
5743 //  if ( !theCopy && !theTargetMesh )
5744 //    return PGroupIDs();
5745 //
5746 //  TIDSortedElemSet::iterator invElemIt = inverseElemSet.begin();
5747 //  for ( ; invElemIt != inverseElemSet.end(); invElemIt++ )
5748 //    theElems.insert( *invElemIt );
5749 //
5750 //  // replicate or reverse elements
5751 //
5752 //  enum {
5753 //    REV_TETRA   = 0,  //  = nbNodes - 4
5754 //    REV_PYRAMID = 1,  //  = nbNodes - 4
5755 //    REV_PENTA   = 2,  //  = nbNodes - 4
5756 //    REV_FACE    = 3,
5757 //    REV_HEXA    = 4,  //  = nbNodes - 4
5758 //    FORWARD     = 5
5759 //  };
5760 //  int index[][8] = {
5761 //    { 2, 1, 0, 3, 4, 0, 0, 0 },  // REV_TETRA
5762 //    { 2, 1, 0, 3, 4, 0, 0, 0 },  // REV_PYRAMID
5763 //    { 2, 1, 0, 5, 4, 3, 0, 0 },  // REV_PENTA
5764 //    { 2, 1, 0, 3, 0, 0, 0, 0 },  // REV_FACE
5765 //    { 2, 1, 0, 3, 6, 5, 4, 7 },  // REV_HEXA
5766 //    { 0, 1, 2, 3, 4, 5, 6, 7 }   // FORWARD
5767 //  };
5768 //
5769 //  for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ )
5770 //  {
5771 //    const SMDS_MeshElement* elem = *itElem;
5772 //    if ( !elem || elem->GetType() == SMDSAbs_Node )
5773 //      continue;
5774 //
5775 //    int nbNodes = elem->NbNodes();
5776 //    int elemType = elem->GetType();
5777 //
5778 //    if (elem->IsPoly()) {
5779 //      // Polygon or Polyhedral Volume
5780 //      switch ( elemType ) {
5781 //      case SMDSAbs_Face:
5782 //        {
5783 //          vector<const SMDS_MeshNode*> poly_nodes (nbNodes);
5784 //          int iNode = 0;
5785 //          SMDS_ElemIteratorPtr itN = elem->nodesIterator();
5786 //          while (itN->more()) {
5787 //            const SMDS_MeshNode* node =
5788 //              static_cast<const SMDS_MeshNode*>(itN->next());
5789 //            TNodeNodeMap::iterator nodeMapIt = nodeMap.find(node);
5790 //            if (nodeMapIt == nodeMap.end())
5791 //              break; // not all nodes transformed
5792 //            //if (needReverse) {
5793 //            //  // reverse mirrored faces and volumes
5794 //            //  poly_nodes[nbNodes - iNode - 1] = (*nodeMapIt).second;
5795 //            //} else {
5796 //            poly_nodes[iNode] = (*nodeMapIt).second;
5797 //            //}
5798 //            iNode++;
5799 //          }
5800 //          if ( iNode != nbNodes )
5801 //            continue; // not all nodes transformed
5802 //
5803 //          if ( theTargetMesh ) {
5804 //            myLastCreatedElems.Append(aTgtMesh->AddPolygonalFace(poly_nodes));
5805 //            srcElems.Append( elem );
5806 //          }
5807 //          else if ( theCopy ) {
5808 //            myLastCreatedElems.Append(aMesh->AddPolygonalFace(poly_nodes));
5809 //            srcElems.Append( elem );
5810 //          }
5811 //          else {
5812 //            aMesh->ChangePolygonNodes(elem, poly_nodes);
5813 //          }
5814 //        }
5815 //        break;
5816 //      case SMDSAbs_Volume:
5817 //        {
5818 //          // ATTENTION: Reversing is not yet done!!!
5819 //          const SMDS_VtkVolume* aPolyedre =
5820 //            dynamic_cast<const SMDS_VtkVolume*>( elem );
5821 //          if (!aPolyedre) {
5822 //            MESSAGE("Warning: bad volumic element");
5823 //            continue;
5824 //          }
5825 //
5826 //          vector<const SMDS_MeshNode*> poly_nodes;
5827 //          vector<int> quantities;
5828 //
5829 //          bool allTransformed = true;
5830 //          int nbFaces = aPolyedre->NbFaces();
5831 //          for (int iface = 1; iface <= nbFaces && allTransformed; iface++) {
5832 //            int nbFaceNodes = aPolyedre->NbFaceNodes(iface);
5833 //            for (int inode = 1; inode <= nbFaceNodes && allTransformed; inode++) {
5834 //              const SMDS_MeshNode* node = aPolyedre->GetFaceNode(iface, inode);
5835 //              TNodeNodeMap::iterator nodeMapIt = nodeMap.find(node);
5836 //              if (nodeMapIt == nodeMap.end()) {
5837 //                allTransformed = false; // not all nodes transformed
5838 //              } else {
5839 //                poly_nodes.push_back((*nodeMapIt).second);
5840 //              }
5841 //            }
5842 //            quantities.push_back(nbFaceNodes);
5843 //          }
5844 //          if ( !allTransformed )
5845 //            continue; // not all nodes transformed
5846 //
5847 //          if ( theTargetMesh ) {
5848 //            myLastCreatedElems.Append(aTgtMesh->AddPolyhedralVolume(poly_nodes, quantities));
5849 //            srcElems.Append( elem );
5850 //          }
5851 //          else if ( theCopy ) {
5852 //            myLastCreatedElems.Append(aMesh->AddPolyhedralVolume(poly_nodes, quantities));
5853 //            srcElems.Append( elem );
5854 //          }
5855 //          else {
5856 //            aMesh->ChangePolyhedronNodes(elem, poly_nodes, quantities);
5857 //          }
5858 //        }
5859 //        break;
5860 //      default:;
5861 //      }
5862 //      continue;
5863 //    }
5864 //
5865 //    // Regular elements
5866 //    int* i = index[ FORWARD ];
5867 //    //if ( needReverse && nbNodes > 2) // reverse mirrored faces and volumes
5868 //    //  if ( elemType == SMDSAbs_Face )
5869 //    //    i = index[ REV_FACE ];
5870 //    //  else
5871 //    //    i = index[ nbNodes - 4 ];
5872 //
5873 //    if(elem->IsQuadratic()) {
5874 //      static int anIds[] = {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19};
5875 //      i = anIds;
5876 //      //if(needReverse) {
5877 //      //  if(nbNodes==3) { // quadratic edge
5878 //      //    static int anIds[] = {1,0,2};
5879 //      //    i = anIds;
5880 //      //  }
5881 //      //  else if(nbNodes==6) { // quadratic triangle
5882 //      //    static int anIds[] = {0,2,1,5,4,3};
5883 //      //    i = anIds;
5884 //      //  }
5885 //      //  else if(nbNodes==8) { // quadratic quadrangle
5886 //      //    static int anIds[] = {0,3,2,1,7,6,5,4};
5887 //      //    i = anIds;
5888 //      //  }
5889 //      //  else if(nbNodes==10) { // quadratic tetrahedron of 10 nodes
5890 //      //    static int anIds[] = {0,2,1,3,6,5,4,7,9,8};
5891 //      //    i = anIds;
5892 //      //  }
5893 //      //  else if(nbNodes==13) { // quadratic pyramid of 13 nodes
5894 //      //    static int anIds[] = {0,3,2,1,4,8,7,6,5,9,12,11,10};
5895 //      //    i = anIds;
5896 //      //  }
5897 //      //  else if(nbNodes==15) { // quadratic pentahedron with 15 nodes
5898 //      //    static int anIds[] = {0,2,1,3,5,4,8,7,6,11,10,9,12,14,13};
5899 //      //    i = anIds;
5900 //      //  }
5901 //      //  else { // nbNodes==20 - quadratic hexahedron with 20 nodes
5902 //      //    static int anIds[] = {0,3,2,1,4,7,6,5,11,10,9,8,15,14,13,12,16,19,18,17};
5903 //      //    i = anIds;
5904 //      //  }
5905 //      //}
5906 //    }
5907 //
5908 //    // find transformed nodes
5909 //    vector<const SMDS_MeshNode*> nodes(nbNodes);
5910 //    int iNode = 0;
5911 //    SMDS_ElemIteratorPtr itN = elem->nodesIterator();
5912 //    while ( itN->more() ) {
5913 //      const SMDS_MeshNode* node =
5914 //        static_cast<const SMDS_MeshNode*>( itN->next() );
5915 //      TNodeNodeMap::iterator nodeMapIt = nodeMap.find( node );
5916 //      if ( nodeMapIt == nodeMap.end() )
5917 //        break; // not all nodes transformed
5918 //      nodes[ i [ iNode++ ]] = (*nodeMapIt).second;
5919 //    }
5920 //    if ( iNode != nbNodes )
5921 //      continue; // not all nodes transformed
5922 //
5923 //    if ( theTargetMesh ) {
5924 //      if ( SMDS_MeshElement* copy =
5925 //           targetMeshEditor.AddElement( nodes, elem->GetType(), elem->IsPoly() )) {
5926 //        myLastCreatedElems.Append( copy );
5927 //        srcElems.Append( elem );
5928 //      }
5929 //    }
5930 //    else if ( theCopy ) {
5931 //      if ( SMDS_MeshElement* copy = AddElement( nodes, elem->GetType(), elem->IsPoly() )) {
5932 //        myLastCreatedElems.Append( copy );
5933 //        srcElems.Append( elem );
5934 //      }
5935 //    }
5936 //    else {
5937 //      // reverse element as it was reversed by transformation
5938 //      if ( nbNodes > 2 )
5939 //        aMesh->ChangeElementNodes( elem, &nodes[0], nbNodes );
5940 //    }
5941 //  }
5942 //
5943 //  PGroupIDs newGroupIDs;
5944 //
5945 //  if ( theMakeGroups && theCopy ||
5946 //       theMakeGroups && theTargetMesh ) {
5947 //    string groupPostfix = "scaled";
5948 //    newGroupIDs = generateGroups( srcNodes, srcElems, groupPostfix, theTargetMesh );
5949 //  }
5950 //
5951 //  return newGroupIDs;
5952 //}
5953
5954
5955 //=======================================================================
5956 /*!
5957  * \brief Create groups of elements made during transformation
5958  * \param nodeGens - nodes making corresponding myLastCreatedNodes
5959  * \param elemGens - elements making corresponding myLastCreatedElems
5960  * \param postfix - to append to names of new groups
5961  */
5962 //=======================================================================
5963
5964 SMESH_MeshEditor::PGroupIDs
5965 SMESH_MeshEditor::generateGroups(const SMESH_SequenceOfElemPtr& nodeGens,
5966                                  const SMESH_SequenceOfElemPtr& elemGens,
5967                                  const std::string&             postfix,
5968                                  SMESH_Mesh*                    targetMesh)
5969 {
5970   PGroupIDs newGroupIDs( new list<int> );
5971   SMESH_Mesh* mesh = targetMesh ? targetMesh : GetMesh();
5972
5973   // Sort existing groups by types and collect their names
5974
5975   // to store an old group and a generated new one
5976   typedef pair< SMESHDS_GroupBase*, SMDS_MeshGroup* > TOldNewGroup;
5977   vector< list< TOldNewGroup > > groupsByType( SMDSAbs_NbElementTypes );
5978   // group names
5979   set< string > groupNames;
5980   //
5981   SMDS_MeshGroup* nullNewGroup = (SMDS_MeshGroup*) 0;
5982   SMESH_Mesh::GroupIteratorPtr groupIt = GetMesh()->GetGroups();
5983   while ( groupIt->more() ) {
5984     SMESH_Group * group = groupIt->next();
5985     if ( !group ) continue;
5986     SMESHDS_GroupBase* groupDS = group->GetGroupDS();
5987     if ( !groupDS || groupDS->IsEmpty() ) continue;
5988     groupNames.insert( group->GetName() );
5989     groupDS->SetStoreName( group->GetName() );
5990     groupsByType[ groupDS->GetType() ].push_back( make_pair( groupDS, nullNewGroup ));
5991   }
5992
5993   // Groups creation
5994
5995   // loop on nodes and elements
5996   for ( int isNodes = 0; isNodes < 2; ++isNodes )
5997   {
5998     const SMESH_SequenceOfElemPtr& gens  = isNodes ? nodeGens : elemGens;
5999     const SMESH_SequenceOfElemPtr& elems = isNodes ? myLastCreatedNodes : myLastCreatedElems;
6000     if ( gens.Length() != elems.Length() )
6001       throw SALOME_Exception(LOCALIZED("invalid args"));
6002
6003     // loop on created elements
6004     for (int iElem = 1; iElem <= elems.Length(); ++iElem )
6005     {
6006       const SMDS_MeshElement* sourceElem = gens( iElem );
6007       if ( !sourceElem ) {
6008         MESSAGE("generateGroups(): NULL source element");
6009         continue;
6010       }
6011       list< TOldNewGroup > & groupsOldNew = groupsByType[ sourceElem->GetType() ];
6012       if ( groupsOldNew.empty() ) {
6013         while ( iElem < gens.Length() && gens( iElem+1 ) == sourceElem )
6014           ++iElem; // skip all elements made by sourceElem
6015         continue;
6016       }
6017       // collect all elements made by sourceElem
6018       list< const SMDS_MeshElement* > resultElems;
6019       if ( const SMDS_MeshElement* resElem = elems( iElem ))
6020         if ( resElem != sourceElem )
6021           resultElems.push_back( resElem );
6022       while ( iElem < gens.Length() && gens( iElem+1 ) == sourceElem )
6023         if ( const SMDS_MeshElement* resElem = elems( ++iElem ))
6024           if ( resElem != sourceElem )
6025             resultElems.push_back( resElem );
6026       // do not generate element groups from node ones
6027       if ( sourceElem->GetType() == SMDSAbs_Node &&
6028            elems( iElem )->GetType() != SMDSAbs_Node )
6029         continue;
6030
6031       // add resultElems to groups made by ones the sourceElem belongs to
6032       list< TOldNewGroup >::iterator gOldNew, gLast = groupsOldNew.end();
6033       for ( gOldNew = groupsOldNew.begin(); gOldNew != gLast; ++gOldNew )
6034       {
6035         SMESHDS_GroupBase* oldGroup = gOldNew->first;
6036         if ( oldGroup->Contains( sourceElem )) // sourceElem in oldGroup
6037         {
6038           SMDS_MeshGroup* & newGroup = gOldNew->second;
6039           if ( !newGroup )// create a new group
6040           {
6041             // make a name
6042             string name = oldGroup->GetStoreName();
6043             if ( !targetMesh ) {
6044               name += "_";
6045               name += postfix;
6046               int nb = 0;
6047               while ( !groupNames.insert( name ).second ) // name exists
6048               {
6049                 if ( nb == 0 ) {
6050                   name += "_1";
6051                 }
6052                 else {
6053                   TCollection_AsciiString nbStr(nb+1);
6054                   name.resize( name.rfind('_')+1 );
6055                   name += nbStr.ToCString();
6056                 }
6057                 ++nb;
6058               }
6059             }
6060             // make a group
6061             int id;
6062             SMESH_Group* group = mesh->AddGroup( resultElems.back()->GetType(),
6063                                                  name.c_str(), id );
6064             SMESHDS_Group* groupDS = static_cast<SMESHDS_Group*>(group->GetGroupDS());
6065             newGroup = & groupDS->SMDSGroup();
6066             newGroupIDs->push_back( id );
6067           }
6068
6069           // fill in a new group
6070           list< const SMDS_MeshElement* >::iterator resLast = resultElems.end(), resElemIt;
6071           for ( resElemIt = resultElems.begin(); resElemIt != resLast; ++resElemIt )
6072             newGroup->Add( *resElemIt );
6073         }
6074       }
6075     } // loop on created elements
6076   }// loop on nodes and elements
6077
6078   return newGroupIDs;
6079 }
6080
6081 //================================================================================
6082 /*!
6083  * \brief Return list of group of nodes close to each other within theTolerance
6084  *        Search among theNodes or in the whole mesh if theNodes is empty using
6085  *        an Octree algorithm
6086  */
6087 //================================================================================
6088
6089 void SMESH_MeshEditor::FindCoincidentNodes (TIDSortedNodeSet &   theNodes,
6090                                             const double         theTolerance,
6091                                             TListOfListOfNodes & theGroupsOfNodes)
6092 {
6093   myLastCreatedElems.Clear();
6094   myLastCreatedNodes.Clear();
6095
6096   if ( theNodes.empty() )
6097   { // get all nodes in the mesh
6098     SMDS_NodeIteratorPtr nIt = GetMeshDS()->nodesIterator(/*idInceasingOrder=*/true);
6099     while ( nIt->more() )
6100       theNodes.insert( theNodes.end(),nIt->next());
6101   }
6102
6103   SMESH_OctreeNode::FindCoincidentNodes ( theNodes, &theGroupsOfNodes, theTolerance);
6104 }
6105
6106
6107 //=======================================================================
6108 /*!
6109  * \brief Implementation of search for the node closest to point
6110  */
6111 //=======================================================================
6112
6113 struct SMESH_NodeSearcherImpl: public SMESH_NodeSearcher
6114 {
6115   //---------------------------------------------------------------------
6116   /*!
6117    * \brief Constructor
6118    */
6119   SMESH_NodeSearcherImpl( const SMESHDS_Mesh* theMesh )
6120   {
6121     myMesh = ( SMESHDS_Mesh* ) theMesh;
6122
6123     TIDSortedNodeSet nodes;
6124     if ( theMesh ) {
6125       SMDS_NodeIteratorPtr nIt = theMesh->nodesIterator(/*idInceasingOrder=*/true);
6126       while ( nIt->more() )
6127         nodes.insert( nodes.end(), nIt->next() );
6128     }
6129     myOctreeNode = new SMESH_OctreeNode(nodes) ;
6130
6131     // get max size of a leaf box
6132     SMESH_OctreeNode* tree = myOctreeNode;
6133     while ( !tree->isLeaf() )
6134     {
6135       SMESH_OctreeNodeIteratorPtr cIt = tree->GetChildrenIterator();
6136       if ( cIt->more() )
6137         tree = cIt->next();
6138     }
6139     myHalfLeafSize = tree->maxSize() / 2.;
6140   }
6141
6142   //---------------------------------------------------------------------
6143   /*!
6144    * \brief Move node and update myOctreeNode accordingly
6145    */
6146   void MoveNode( const SMDS_MeshNode* node, const gp_Pnt& toPnt )
6147   {
6148     myOctreeNode->UpdateByMoveNode( node, toPnt );
6149     myMesh->MoveNode( node, toPnt.X(), toPnt.Y(), toPnt.Z() );
6150   }
6151
6152   //---------------------------------------------------------------------
6153   /*!
6154    * \brief Do it's job
6155    */
6156   const SMDS_MeshNode* FindClosestTo( const gp_Pnt& thePnt )
6157   {
6158     map<double, const SMDS_MeshNode*> dist2Nodes;
6159     myOctreeNode->NodesAround( thePnt.Coord(), dist2Nodes, myHalfLeafSize );
6160     if ( !dist2Nodes.empty() )
6161       return dist2Nodes.begin()->second;
6162     list<const SMDS_MeshNode*> nodes;
6163     //myOctreeNode->NodesAround( &tgtNode, &nodes, myHalfLeafSize );
6164
6165     double minSqDist = DBL_MAX;
6166     if ( nodes.empty() )  // get all nodes of OctreeNode's closest to thePnt
6167     {
6168       // sort leafs by their distance from thePnt
6169       typedef map< double, SMESH_OctreeNode* > TDistTreeMap;
6170       TDistTreeMap treeMap;
6171       list< SMESH_OctreeNode* > treeList;
6172       list< SMESH_OctreeNode* >::iterator trIt;
6173       treeList.push_back( myOctreeNode );
6174
6175       gp_XYZ pointNode( thePnt.X(), thePnt.Y(), thePnt.Z() );
6176       bool pointInside = myOctreeNode->isInside( pointNode, myHalfLeafSize );
6177       for ( trIt = treeList.begin(); trIt != treeList.end(); ++trIt)
6178       {
6179         SMESH_OctreeNode* tree = *trIt;
6180         if ( !tree->isLeaf() ) // put children to the queue
6181         {
6182           if ( pointInside && !tree->isInside( pointNode, myHalfLeafSize )) continue;
6183           SMESH_OctreeNodeIteratorPtr cIt = tree->GetChildrenIterator();
6184           while ( cIt->more() )
6185             treeList.push_back( cIt->next() );
6186         }
6187         else if ( tree->NbNodes() ) // put a tree to the treeMap
6188         {
6189           const Bnd_B3d& box = tree->getBox();
6190           double sqDist = thePnt.SquareDistance( 0.5 * ( box.CornerMin() + box.CornerMax() ));
6191           pair<TDistTreeMap::iterator,bool> it_in = treeMap.insert( make_pair( sqDist, tree ));
6192           if ( !it_in.second ) // not unique distance to box center
6193             treeMap.insert( it_in.first, make_pair( sqDist + 1e-13*treeMap.size(), tree ));
6194         }
6195       }
6196       // find distance after which there is no sense to check tree's
6197       double sqLimit = DBL_MAX;
6198       TDistTreeMap::iterator sqDist_tree = treeMap.begin();
6199       if ( treeMap.size() > 5 ) {
6200         SMESH_OctreeNode* closestTree = sqDist_tree->second;
6201         const Bnd_B3d& box = closestTree->getBox();
6202         double limit = sqrt( sqDist_tree->first ) + sqrt ( box.SquareExtent() );
6203         sqLimit = limit * limit;
6204       }
6205       // get all nodes from trees
6206       for ( ; sqDist_tree != treeMap.end(); ++sqDist_tree) {
6207         if ( sqDist_tree->first > sqLimit )
6208           break;
6209         SMESH_OctreeNode* tree = sqDist_tree->second;
6210         tree->NodesAround( tree->GetNodeIterator()->next(), &nodes );
6211       }
6212     }
6213     // find closest among nodes
6214     minSqDist = DBL_MAX;
6215     const SMDS_MeshNode* closestNode = 0;
6216     list<const SMDS_MeshNode*>::iterator nIt = nodes.begin();
6217     for ( ; nIt != nodes.end(); ++nIt ) {
6218       double sqDist = thePnt.SquareDistance( SMESH_MeshEditor::TNodeXYZ( *nIt ) );
6219       if ( minSqDist > sqDist ) {
6220         closestNode = *nIt;
6221         minSqDist = sqDist;
6222       }
6223     }
6224     return closestNode;
6225   }
6226
6227   //---------------------------------------------------------------------
6228   /*!
6229    * \brief Destructor
6230    */
6231   ~SMESH_NodeSearcherImpl() { delete myOctreeNode; }
6232
6233   //---------------------------------------------------------------------
6234   /*!
6235    * \brief Return the node tree
6236    */
6237   const SMESH_OctreeNode* getTree() const { return myOctreeNode; }
6238
6239 private:
6240   SMESH_OctreeNode* myOctreeNode;
6241   SMESHDS_Mesh*     myMesh;
6242   double            myHalfLeafSize; // max size of a leaf box
6243 };
6244
6245 //=======================================================================
6246 /*!
6247  * \brief Return SMESH_NodeSearcher
6248  */
6249 //=======================================================================
6250
6251 SMESH_NodeSearcher* SMESH_MeshEditor::GetNodeSearcher() 
6252 {
6253   return new SMESH_NodeSearcherImpl( GetMeshDS() );
6254 }
6255
6256 // ========================================================================
6257 namespace // Utils used in SMESH_ElementSearcherImpl::FindElementsByPoint()
6258 {
6259   const int MaxNbElemsInLeaf = 10; // maximal number of elements in a leaf of tree
6260   const int MaxLevel         = 7;  // maximal tree height -> nb terminal boxes: 8^7 = 2097152
6261   const double NodeRadius = 1e-9;  // to enlarge bnd box of element
6262
6263   //=======================================================================
6264   /*!
6265    * \brief Octal tree of bounding boxes of elements
6266    */
6267   //=======================================================================
6268
6269   class ElementBndBoxTree : public SMESH_Octree
6270   {
6271   public:
6272
6273     ElementBndBoxTree(const SMDS_Mesh& mesh, SMDSAbs_ElementType elemType, double tolerance = NodeRadius );
6274     void getElementsNearPoint( const gp_Pnt& point, TIDSortedElemSet& foundElems);
6275     void getElementsNearLine ( const gp_Ax1& line, TIDSortedElemSet& foundElems);
6276     ~ElementBndBoxTree();
6277
6278   protected:
6279     ElementBndBoxTree() {}
6280     SMESH_Octree* allocateOctreeChild() const { return new ElementBndBoxTree; }
6281     void buildChildrenData();
6282     Bnd_B3d* buildRootBox();
6283   private:
6284     //!< Bounding box of element
6285     struct ElementBox : public Bnd_B3d
6286     {
6287       const SMDS_MeshElement* _element;
6288       int                     _refCount; // an ElementBox can be included in several tree branches
6289       ElementBox(const SMDS_MeshElement* elem, double tolerance);
6290     };
6291     vector< ElementBox* > _elements;
6292   };
6293
6294   //================================================================================
6295   /*!
6296    * \brief ElementBndBoxTree creation
6297    */
6298   //================================================================================
6299
6300   ElementBndBoxTree::ElementBndBoxTree(const SMDS_Mesh& mesh, SMDSAbs_ElementType elemType, double tolerance)
6301     :SMESH_Octree( new SMESH_Octree::Limit( MaxLevel, /*minSize=*/0. ))
6302   {
6303     int nbElems = mesh.GetMeshInfo().NbElements( elemType );
6304     _elements.reserve( nbElems );
6305
6306     SMDS_ElemIteratorPtr elemIt = mesh.elementsIterator( elemType );
6307     while ( elemIt->more() )
6308       _elements.push_back( new ElementBox( elemIt->next(),tolerance  ));
6309
6310     if ( _elements.size() > MaxNbElemsInLeaf )
6311       compute();
6312     else
6313       myIsLeaf = true;
6314   }
6315
6316   //================================================================================
6317   /*!
6318    * \brief Destructor
6319    */
6320   //================================================================================
6321
6322   ElementBndBoxTree::~ElementBndBoxTree()
6323   {
6324     for ( int i = 0; i < _elements.size(); ++i )
6325       if ( --_elements[i]->_refCount <= 0 )
6326         delete _elements[i];
6327   }
6328
6329   //================================================================================
6330   /*!
6331    * \brief Return the maximal box
6332    */
6333   //================================================================================
6334
6335   Bnd_B3d* ElementBndBoxTree::buildRootBox()
6336   {
6337     Bnd_B3d* box = new Bnd_B3d;
6338     for ( int i = 0; i < _elements.size(); ++i )
6339       box->Add( *_elements[i] );
6340     return box;
6341   }
6342
6343   //================================================================================
6344   /*!
6345    * \brief Redistrubute element boxes among children
6346    */
6347   //================================================================================
6348
6349   void ElementBndBoxTree::buildChildrenData()
6350   {
6351     for ( int i = 0; i < _elements.size(); ++i )
6352     {
6353       for (int j = 0; j < 8; j++)
6354       {
6355         if ( !_elements[i]->IsOut( myChildren[j]->getBox() ))
6356         {
6357           _elements[i]->_refCount++;
6358           ((ElementBndBoxTree*)myChildren[j])->_elements.push_back( _elements[i]);
6359         }
6360       }
6361       _elements[i]->_refCount--;
6362     }
6363     _elements.clear();
6364
6365     for (int j = 0; j < 8; j++)
6366     {
6367       ElementBndBoxTree* child = static_cast<ElementBndBoxTree*>( myChildren[j]);
6368       if ( child->_elements.size() <= MaxNbElemsInLeaf )
6369         child->myIsLeaf = true;
6370
6371       if ( child->_elements.capacity() - child->_elements.size() > 1000 )
6372         child->_elements.resize( child->_elements.size() ); // compact
6373     }
6374   }
6375
6376   //================================================================================
6377   /*!
6378    * \brief Return elements which can include the point
6379    */
6380   //================================================================================
6381
6382   void ElementBndBoxTree::getElementsNearPoint( const gp_Pnt&     point,
6383                                                 TIDSortedElemSet& foundElems)
6384   {
6385     if ( level() && getBox().IsOut( point.XYZ() ))
6386       return;
6387
6388     if ( isLeaf() )
6389     {
6390       for ( int i = 0; i < _elements.size(); ++i )
6391         if ( !_elements[i]->IsOut( point.XYZ() ))
6392           foundElems.insert( _elements[i]->_element );
6393     }
6394     else
6395     {
6396       for (int i = 0; i < 8; i++)
6397         ((ElementBndBoxTree*) myChildren[i])->getElementsNearPoint( point, foundElems );
6398     }
6399   }
6400
6401   //================================================================================
6402   /*!
6403    * \brief Return elements which can be intersected by the line
6404    */
6405   //================================================================================
6406
6407   void ElementBndBoxTree::getElementsNearLine( const gp_Ax1&     line,
6408                                                TIDSortedElemSet& foundElems)
6409   {
6410     if ( level() && getBox().IsOut( line ))
6411       return;
6412
6413     if ( isLeaf() )
6414     {
6415       for ( int i = 0; i < _elements.size(); ++i )
6416         if ( !_elements[i]->IsOut( line ))
6417           foundElems.insert( _elements[i]->_element );
6418     }
6419     else
6420     {
6421       for (int i = 0; i < 8; i++)
6422         ((ElementBndBoxTree*) myChildren[i])->getElementsNearLine( line, foundElems );
6423     }
6424   }
6425
6426   //================================================================================
6427   /*!
6428    * \brief Construct the element box
6429    */
6430   //================================================================================
6431
6432   ElementBndBoxTree::ElementBox::ElementBox(const SMDS_MeshElement* elem, double tolerance)
6433   {
6434     _element  = elem;
6435     _refCount = 1;
6436     SMDS_ElemIteratorPtr nIt = elem->nodesIterator();
6437     while ( nIt->more() )
6438       Add( SMESH_MeshEditor::TNodeXYZ( cast2Node( nIt->next() )));
6439     Enlarge( tolerance );
6440   }
6441
6442 } // namespace
6443
6444 //=======================================================================
6445 /*!
6446  * \brief Implementation of search for the elements by point and
6447  *        of classification of point in 2D mesh
6448  */
6449 //=======================================================================
6450
6451 struct SMESH_ElementSearcherImpl: public SMESH_ElementSearcher
6452 {
6453   SMESHDS_Mesh*                _mesh;
6454   ElementBndBoxTree*           _ebbTree;
6455   SMESH_NodeSearcherImpl*      _nodeSearcher;
6456   SMDSAbs_ElementType          _elementType;
6457   double                       _tolerance;
6458   bool                         _outerFacesFound;
6459   set<const SMDS_MeshElement*> _outerFaces; // empty means "no internal faces at all"
6460
6461   SMESH_ElementSearcherImpl( SMESHDS_Mesh& mesh )
6462     : _mesh(&mesh),_ebbTree(0),_nodeSearcher(0), _tolerance(-1), _outerFacesFound(false) {}
6463   ~SMESH_ElementSearcherImpl()
6464   {
6465     if ( _ebbTree )      delete _ebbTree;      _ebbTree      = 0;
6466     if ( _nodeSearcher ) delete _nodeSearcher; _nodeSearcher = 0;
6467   }
6468   virtual int FindElementsByPoint(const gp_Pnt&                      point,
6469                                   SMDSAbs_ElementType                type,
6470                                   vector< const SMDS_MeshElement* >& foundElements);
6471   virtual TopAbs_State GetPointState(const gp_Pnt& point);
6472
6473   void GetElementsNearLine( const gp_Ax1&                      line,
6474                             SMDSAbs_ElementType                type,
6475                             vector< const SMDS_MeshElement* >& foundElems);
6476   double getTolerance();
6477   bool getIntersParamOnLine(const gp_Lin& line, const SMDS_MeshElement* face,
6478                             const double tolerance, double & param);
6479   void findOuterBoundary(const SMDS_MeshElement* anyOuterFace);
6480   bool isOuterBoundary(const SMDS_MeshElement* face) const
6481   {
6482     return _outerFaces.empty() || _outerFaces.count(face);
6483   }
6484   struct TInters //!< data of intersection of the line and the mesh face (used in GetPointState())
6485   {
6486     const SMDS_MeshElement* _face;
6487     gp_Vec                  _faceNorm;
6488     bool                    _coincides; //!< the line lays in face plane
6489     TInters(const SMDS_MeshElement* face, const gp_Vec& faceNorm, bool coinc=false)
6490       : _face(face), _faceNorm( faceNorm ), _coincides( coinc ) {}
6491   };
6492   struct TFaceLink //!< link and faces sharing it (used in findOuterBoundary())
6493   {
6494     SMESH_TLink      _link;
6495     TIDSortedElemSet _faces;
6496     TFaceLink( const SMDS_MeshNode* n1, const SMDS_MeshNode* n2, const SMDS_MeshElement* face)
6497       : _link( n1, n2 ), _faces( &face, &face + 1) {}
6498   };
6499 };
6500
6501 ostream& operator<< (ostream& out, const SMESH_ElementSearcherImpl::TInters& i)
6502 {
6503   return out << "TInters(face=" << ( i._face ? i._face->GetID() : 0)
6504              << ", _coincides="<<i._coincides << ")";
6505 }
6506
6507 //=======================================================================
6508 /*!
6509  * \brief define tolerance for search
6510  */
6511 //=======================================================================
6512
6513 double SMESH_ElementSearcherImpl::getTolerance()
6514 {
6515   if ( _tolerance < 0 )
6516   {
6517     const SMDS_MeshInfo& meshInfo = _mesh->GetMeshInfo();
6518
6519     _tolerance = 0;
6520     if ( _nodeSearcher && meshInfo.NbNodes() > 1 )
6521     {
6522       double boxSize = _nodeSearcher->getTree()->maxSize();
6523       _tolerance = 1e-8 * boxSize/* / meshInfo.NbNodes()*/;
6524     }
6525     else if ( _ebbTree && meshInfo.NbElements() > 0 )
6526     {
6527       double boxSize = _ebbTree->maxSize();
6528       _tolerance = 1e-8 * boxSize/* / meshInfo.NbElements()*/;
6529     }
6530     if ( _tolerance == 0 )
6531     {
6532       // define tolerance by size of a most complex element
6533       int complexType = SMDSAbs_Volume;
6534       while ( complexType > SMDSAbs_All &&
6535               meshInfo.NbElements( SMDSAbs_ElementType( complexType )) < 1 )
6536         --complexType;
6537       if ( complexType == SMDSAbs_All ) return 0; // empty mesh
6538       double elemSize;
6539       if ( complexType == int( SMDSAbs_Node ))
6540       {
6541         SMDS_NodeIteratorPtr nodeIt = _mesh->nodesIterator();
6542         elemSize = 1;
6543         if ( meshInfo.NbNodes() > 2 )
6544           elemSize = SMESH_MeshEditor::TNodeXYZ( nodeIt->next() ).Distance( nodeIt->next() );
6545       }
6546       else
6547       {
6548         SMDS_ElemIteratorPtr elemIt =
6549             _mesh->elementsIterator( SMDSAbs_ElementType( complexType ));
6550         const SMDS_MeshElement* elem = elemIt->next();
6551         SMDS_ElemIteratorPtr nodeIt = elem->nodesIterator();
6552         SMESH_MeshEditor::TNodeXYZ n1( cast2Node( nodeIt->next() ));
6553         while ( nodeIt->more() )
6554         {
6555           double dist = n1.Distance( cast2Node( nodeIt->next() ));
6556           elemSize = max( dist, elemSize );
6557         }
6558       }
6559       _tolerance = 1e-4 * elemSize;
6560     }
6561   }
6562   return _tolerance;
6563 }
6564
6565 //================================================================================
6566 /*!
6567  * \brief Find intersection of the line and an edge of face and return parameter on line
6568  */
6569 //================================================================================
6570
6571 bool SMESH_ElementSearcherImpl::getIntersParamOnLine(const gp_Lin&           line,
6572                                                      const SMDS_MeshElement* face,
6573                                                      const double            tol,
6574                                                      double &                param)
6575 {
6576   int nbInts = 0;
6577   param = 0;
6578
6579   GeomAPI_ExtremaCurveCurve anExtCC;
6580   Handle(Geom_Curve) lineCurve = new Geom_Line( line );
6581   
6582   int nbNodes = face->IsQuadratic() ? face->NbNodes()/2 : face->NbNodes();
6583   for ( int i = 0; i < nbNodes && nbInts < 2; ++i )
6584   {
6585     GC_MakeSegment edge( SMESH_MeshEditor::TNodeXYZ( face->GetNode( i )),
6586                          SMESH_MeshEditor::TNodeXYZ( face->GetNode( (i+1)%nbNodes) )); 
6587     anExtCC.Init( lineCurve, edge);
6588     if ( anExtCC.NbExtrema() > 0 && anExtCC.LowerDistance() <= tol)
6589     {
6590       Quantity_Parameter pl, pe;
6591       anExtCC.LowerDistanceParameters( pl, pe );
6592       param += pl;
6593       if ( ++nbInts == 2 )
6594         break;
6595     }
6596   }
6597   if ( nbInts > 0 ) param /= nbInts;
6598   return nbInts > 0;
6599 }
6600 //================================================================================
6601 /*!
6602  * \brief Find all faces belonging to the outer boundary of mesh
6603  */
6604 //================================================================================
6605
6606 void SMESH_ElementSearcherImpl::findOuterBoundary(const SMDS_MeshElement* outerFace)
6607 {
6608   if ( _outerFacesFound ) return;
6609
6610   // Collect all outer faces by passing from one outer face to another via their links
6611   // and BTW find out if there are internal faces at all.
6612
6613   // checked links and links where outer boundary meets internal one
6614   set< SMESH_TLink > visitedLinks, seamLinks;
6615
6616   // links to treat with already visited faces sharing them
6617   list < TFaceLink > startLinks;
6618
6619   // load startLinks with the first outerFace
6620   startLinks.push_back( TFaceLink( outerFace->GetNode(0), outerFace->GetNode(1), outerFace));
6621   _outerFaces.insert( outerFace );
6622
6623   TIDSortedElemSet emptySet;
6624   while ( !startLinks.empty() )
6625   {
6626     const SMESH_TLink& link  = startLinks.front()._link;
6627     TIDSortedElemSet&  faces = startLinks.front()._faces;
6628
6629     outerFace = *faces.begin();
6630     // find other faces sharing the link
6631     const SMDS_MeshElement* f;
6632     while (( f = SMESH_MeshEditor::FindFaceInSet(link.node1(), link.node2(), emptySet, faces )))
6633       faces.insert( f );
6634
6635     // select another outer face among the found 
6636     const SMDS_MeshElement* outerFace2 = 0;
6637     if ( faces.size() == 2 )
6638     {
6639       outerFace2 = (outerFace == *faces.begin() ? *faces.rbegin() : *faces.begin());
6640     }
6641     else if ( faces.size() > 2 )
6642     {
6643       seamLinks.insert( link );
6644
6645       // link direction within the outerFace
6646       gp_Vec n1n2( SMESH_MeshEditor::TNodeXYZ( link.node1()),
6647                    SMESH_MeshEditor::TNodeXYZ( link.node2()));
6648       int i1 = outerFace->GetNodeIndex( link.node1() );
6649       int i2 = outerFace->GetNodeIndex( link.node2() );
6650       bool rev = ( abs(i2-i1) == 1 ? i1 > i2 : i2 > i1 );
6651       if ( rev ) n1n2.Reverse();
6652       // outerFace normal
6653       gp_XYZ ofNorm, fNorm;
6654       if ( SMESH_Algo::FaceNormal( outerFace, ofNorm, /*normalized=*/false ))
6655       {
6656         // direction from the link inside outerFace
6657         gp_Vec dirInOF = gp_Vec( ofNorm ) ^ n1n2;
6658         // sort all other faces by angle with the dirInOF
6659         map< double, const SMDS_MeshElement* > angle2Face;
6660         set< const SMDS_MeshElement*, TIDCompare >::const_iterator face = faces.begin();
6661         for ( ; face != faces.end(); ++face )
6662         {
6663           if ( !SMESH_Algo::FaceNormal( *face, fNorm, /*normalized=*/false ))
6664             continue;
6665           gp_Vec dirInF = gp_Vec( fNorm ) ^ n1n2;
6666           double angle = dirInOF.AngleWithRef( dirInF, n1n2 );
6667           if ( angle < 0 ) angle += 2*PI;
6668           angle2Face.insert( make_pair( angle, *face ));
6669         }
6670         if ( !angle2Face.empty() )
6671           outerFace2 = angle2Face.begin()->second;
6672       }
6673     }
6674     // store the found outer face and add its links to continue seaching from
6675     if ( outerFace2 )
6676     {
6677       _outerFaces.insert( outerFace );
6678       int nbNodes = outerFace2->NbNodes()/( outerFace2->IsQuadratic() ? 2 : 1 );
6679       for ( int i = 0; i < nbNodes; ++i )
6680       {
6681         SMESH_TLink link2( outerFace2->GetNode(i), outerFace2->GetNode((i+1)%nbNodes));
6682         if ( visitedLinks.insert( link2 ).second )
6683           startLinks.push_back( TFaceLink( link2.node1(), link2.node2(), outerFace2 ));
6684       }
6685     }
6686     startLinks.pop_front();
6687   }
6688   _outerFacesFound = true;
6689
6690   if ( !seamLinks.empty() )
6691   {
6692     // There are internal boundaries touching the outher one,
6693     // find all faces of internal boundaries in order to find
6694     // faces of boundaries of holes, if any.
6695     
6696   }
6697   else
6698   {
6699     _outerFaces.clear();
6700   }
6701 }
6702
6703 //=======================================================================
6704 /*!
6705  * \brief Find elements of given type where the given point is IN or ON.
6706  *        Returns nb of found elements and elements them-selves.
6707  *
6708  * 'ALL' type means elements of any type excluding nodes and 0D elements
6709  */
6710 //=======================================================================
6711
6712 int SMESH_ElementSearcherImpl::
6713 FindElementsByPoint(const gp_Pnt&                      point,
6714                     SMDSAbs_ElementType                type,
6715                     vector< const SMDS_MeshElement* >& foundElements)
6716 {
6717   foundElements.clear();
6718
6719   double tolerance = getTolerance();
6720
6721   // =================================================================================
6722   if ( type == SMDSAbs_Node || type == SMDSAbs_0DElement )
6723   {
6724     if ( !_nodeSearcher )
6725       _nodeSearcher = new SMESH_NodeSearcherImpl( _mesh );
6726
6727     const SMDS_MeshNode* closeNode = _nodeSearcher->FindClosestTo( point );
6728     if ( !closeNode ) return foundElements.size();
6729
6730     if ( point.Distance( SMESH_MeshEditor::TNodeXYZ( closeNode )) > tolerance )
6731       return foundElements.size(); // to far from any node
6732
6733     if ( type == SMDSAbs_Node )
6734     {
6735       foundElements.push_back( closeNode );
6736     }
6737     else
6738     {
6739       SMDS_ElemIteratorPtr elemIt = closeNode->GetInverseElementIterator( SMDSAbs_0DElement );
6740       while ( elemIt->more() )
6741         foundElements.push_back( elemIt->next() );
6742     }
6743   }
6744   // =================================================================================
6745   else // elements more complex than 0D
6746   {
6747     if ( !_ebbTree || _elementType != type )
6748     {
6749       if ( _ebbTree ) delete _ebbTree;
6750       _ebbTree = new ElementBndBoxTree( *_mesh, _elementType = type, tolerance );
6751     }
6752     TIDSortedElemSet suspectElems;
6753     _ebbTree->getElementsNearPoint( point, suspectElems );
6754     TIDSortedElemSet::iterator elem = suspectElems.begin();
6755     for ( ; elem != suspectElems.end(); ++elem )
6756       if ( !SMESH_MeshEditor::isOut( *elem, point, tolerance ))
6757         foundElements.push_back( *elem );
6758   }
6759   return foundElements.size();
6760 }
6761
6762 //================================================================================
6763 /*!
6764  * \brief Classify the given point in the closed 2D mesh
6765  */
6766 //================================================================================
6767
6768 TopAbs_State SMESH_ElementSearcherImpl::GetPointState(const gp_Pnt& point)
6769 {
6770   double tolerance = getTolerance();
6771   if ( !_ebbTree || _elementType != SMDSAbs_Face )
6772   {
6773     if ( _ebbTree ) delete _ebbTree;
6774     _ebbTree = new ElementBndBoxTree( *_mesh, _elementType = SMDSAbs_Face );
6775   }
6776   // Algo: analyse transition of a line starting at the point through mesh boundary;
6777   // try three lines parallel to axis of the coordinate system and perform rough
6778   // analysis. If solution is not clear perform thorough analysis.
6779
6780   const int nbAxes = 3;
6781   gp_Dir axisDir[ nbAxes ] = { gp::DX(), gp::DY(), gp::DZ() };
6782   map< double, TInters >   paramOnLine2TInters[ nbAxes ];
6783   list< TInters > tangentInters[ nbAxes ]; // of faces whose plane includes the line
6784   multimap< int, int > nbInt2Axis; // to find the simplest case
6785   for ( int axis = 0; axis < nbAxes; ++axis )
6786   {
6787     gp_Ax1 lineAxis( point, axisDir[axis]);
6788     gp_Lin line    ( lineAxis );
6789
6790     TIDSortedElemSet suspectFaces; // faces possibly intersecting the line
6791     _ebbTree->getElementsNearLine( lineAxis, suspectFaces );
6792
6793     // Intersect faces with the line
6794
6795     map< double, TInters > & u2inters = paramOnLine2TInters[ axis ];
6796     TIDSortedElemSet::iterator face = suspectFaces.begin();
6797     for ( ; face != suspectFaces.end(); ++face )
6798     {
6799       // get face plane
6800       gp_XYZ fNorm;
6801       if ( !SMESH_Algo::FaceNormal( *face, fNorm, /*normalized=*/false)) continue;
6802       gp_Pln facePlane( SMESH_MeshEditor::TNodeXYZ( (*face)->GetNode(0)), fNorm );
6803
6804       // perform intersection
6805       IntAna_IntConicQuad intersection( line, IntAna_Quadric( facePlane ));
6806       if ( !intersection.IsDone() )
6807         continue;
6808       if ( intersection.IsInQuadric() )
6809       {
6810         tangentInters[ axis ].push_back( TInters( *face, fNorm, true ));
6811       }
6812       else if ( ! intersection.IsParallel() && intersection.NbPoints() > 0 )
6813       {
6814         gp_Pnt intersectionPoint = intersection.Point(1);
6815         if ( !SMESH_MeshEditor::isOut( *face, intersectionPoint, tolerance ))
6816           u2inters.insert(make_pair( intersection.ParamOnConic(1), TInters( *face, fNorm )));
6817       }
6818     }
6819     // Analyse intersections roughly
6820
6821     int nbInter = u2inters.size();
6822     if ( nbInter == 0 )
6823       return TopAbs_OUT; 
6824
6825     double f = u2inters.begin()->first, l = u2inters.rbegin()->first;
6826     if ( nbInter == 1 ) // not closed mesh
6827       return fabs( f ) < tolerance ? TopAbs_ON : TopAbs_UNKNOWN;
6828
6829     if ( fabs( f ) < tolerance || fabs( l ) < tolerance )
6830       return TopAbs_ON;
6831
6832     if ( (f<0) == (l<0) )
6833       return TopAbs_OUT;
6834
6835     int nbIntBeforePoint = std::distance( u2inters.begin(), u2inters.lower_bound(0));
6836     int nbIntAfterPoint  = nbInter - nbIntBeforePoint;
6837     if ( nbIntBeforePoint == 1 || nbIntAfterPoint == 1 )
6838       return TopAbs_IN;
6839
6840     nbInt2Axis.insert( make_pair( min( nbIntBeforePoint, nbIntAfterPoint ), axis ));
6841
6842     if ( _outerFacesFound ) break; // pass to thorough analysis
6843
6844   } // three attempts - loop on CS axes
6845
6846   // Analyse intersections thoroughly.
6847   // We make two loops maximum, on the first one we only exclude touching intersections,
6848   // on the second, if situation is still unclear, we gather and use information on
6849   // position of faces (internal or outer). If faces position is already gathered,
6850   // we make the second loop right away.
6851
6852   for ( int hasPositionInfo = _outerFacesFound; hasPositionInfo < 2; ++hasPositionInfo )
6853   {
6854     multimap< int, int >::const_iterator nb_axis = nbInt2Axis.begin();
6855     for ( ; nb_axis != nbInt2Axis.end(); ++nb_axis )
6856     {
6857       int axis = nb_axis->second;
6858       map< double, TInters > & u2inters = paramOnLine2TInters[ axis ];
6859
6860       gp_Ax1 lineAxis( point, axisDir[axis]);
6861       gp_Lin line    ( lineAxis );
6862
6863       // add tangent intersections to u2inters
6864       double param;
6865       list< TInters >::const_iterator tgtInt = tangentInters[ axis ].begin();
6866       for ( ; tgtInt != tangentInters[ axis ].end(); ++tgtInt )
6867         if ( getIntersParamOnLine( line, tgtInt->_face, tolerance, param ))
6868           u2inters.insert(make_pair( param, *tgtInt ));
6869       tangentInters[ axis ].clear();
6870
6871       // Count intersections before and after the point excluding touching ones.
6872       // If hasPositionInfo we count intersections of outer boundary only
6873
6874       int nbIntBeforePoint = 0, nbIntAfterPoint = 0;
6875       double f = numeric_limits<double>::max(), l = -numeric_limits<double>::max();
6876       map< double, TInters >::iterator u_int1 = u2inters.begin(), u_int2 = u_int1;
6877       bool ok = ! u_int1->second._coincides;
6878       while ( ok && u_int1 != u2inters.end() )
6879       {
6880         double u = u_int1->first;
6881         bool touchingInt = false;
6882         if ( ++u_int2 != u2inters.end() )
6883         {
6884           // skip intersections at the same point (if the line passes through edge or node)
6885           int nbSamePnt = 0;
6886           while ( u_int2 != u2inters.end() && fabs( u_int2->first - u ) < tolerance )
6887           {
6888             ++nbSamePnt;
6889             ++u_int2;
6890           }
6891
6892           // skip tangent intersections
6893           int nbTgt = 0;
6894           const SMDS_MeshElement* prevFace = u_int1->second._face;
6895           while ( ok && u_int2->second._coincides )
6896           {
6897             if ( SMESH_Algo::GetCommonNodes(prevFace , u_int2->second._face).empty() )
6898               ok = false;
6899             else
6900             {
6901               nbTgt++;
6902               u_int2++;
6903               ok = ( u_int2 != u2inters.end() );
6904             }
6905           }
6906           if ( !ok ) break;
6907
6908           // skip intersections at the same point after tangent intersections
6909           if ( nbTgt > 0 )
6910           {
6911             double u2 = u_int2->first;
6912             ++u_int2;
6913             while ( u_int2 != u2inters.end() && fabs( u_int2->first - u2 ) < tolerance )
6914             {
6915               ++nbSamePnt;
6916               ++u_int2;
6917             }
6918           }
6919           // decide if we skipped a touching intersection
6920           if ( nbSamePnt + nbTgt > 0 )
6921           {
6922             double minDot = numeric_limits<double>::max(), maxDot = -numeric_limits<double>::max();
6923             map< double, TInters >::iterator u_int = u_int1;
6924             for ( ; u_int != u_int2; ++u_int )
6925             {
6926               if ( u_int->second._coincides ) continue;
6927               double dot = u_int->second._faceNorm * line.Direction();
6928               if ( dot > maxDot ) maxDot = dot;
6929               if ( dot < minDot ) minDot = dot;
6930             }
6931             touchingInt = ( minDot*maxDot < 0 );
6932           }
6933         }
6934         if ( !touchingInt )
6935         {
6936           if ( !hasPositionInfo || isOuterBoundary( u_int1->second._face ))
6937           {
6938             if ( u < 0 )
6939               ++nbIntBeforePoint;
6940             else
6941               ++nbIntAfterPoint;
6942           }
6943           if ( u < f ) f = u;
6944           if ( u > l ) l = u;
6945         }
6946
6947         u_int1 = u_int2; // to next intersection
6948
6949       } // loop on intersections with one line
6950
6951       if ( ok )
6952       {
6953         if ( fabs( f ) < tolerance || fabs( l ) < tolerance )
6954           return TopAbs_ON;
6955
6956         if ( nbIntBeforePoint == 0  || nbIntAfterPoint == 0)
6957           return TopAbs_OUT; 
6958
6959         if ( nbIntBeforePoint + nbIntAfterPoint == 1 ) // not closed mesh
6960           return fabs( f ) < tolerance ? TopAbs_ON : TopAbs_UNKNOWN;
6961
6962         if ( nbIntBeforePoint == 1 || nbIntAfterPoint == 1 )
6963           return TopAbs_IN;
6964
6965         if ( (f<0) == (l<0) )
6966           return TopAbs_OUT;
6967
6968         if ( hasPositionInfo )
6969           return nbIntBeforePoint % 2 ? TopAbs_IN : TopAbs_OUT;
6970       }
6971     } // loop on intersections of the tree lines - thorough analysis
6972
6973     if ( !hasPositionInfo )
6974     {
6975       // gather info on faces position - is face in the outer boundary or not
6976       map< double, TInters > & u2inters = paramOnLine2TInters[ 0 ];
6977       findOuterBoundary( u2inters.begin()->second._face );
6978     }
6979
6980   } // two attempts - with and w/o faces position info in the mesh
6981
6982   return TopAbs_UNKNOWN;
6983 }
6984
6985 //=======================================================================
6986 /*!
6987  * \brief Return elements possibly intersecting the line
6988  */
6989 //=======================================================================
6990
6991 void SMESH_ElementSearcherImpl::GetElementsNearLine( const gp_Ax1&                      line,
6992                                                      SMDSAbs_ElementType                type,
6993                                                      vector< const SMDS_MeshElement* >& foundElems)
6994 {
6995   if ( !_ebbTree || _elementType != type )
6996   {
6997     if ( _ebbTree ) delete _ebbTree;
6998     _ebbTree = new ElementBndBoxTree( *_mesh, _elementType = type );
6999   }
7000   TIDSortedElemSet suspectFaces; // elements possibly intersecting the line
7001   _ebbTree->getElementsNearLine( line, suspectFaces );
7002   foundElems.assign( suspectFaces.begin(), suspectFaces.end());
7003 }
7004
7005 //=======================================================================
7006 /*!
7007  * \brief Return SMESH_ElementSearcher
7008  */
7009 //=======================================================================
7010
7011 SMESH_ElementSearcher* SMESH_MeshEditor::GetElementSearcher()
7012 {
7013   return new SMESH_ElementSearcherImpl( *GetMeshDS() );
7014 }
7015
7016 //=======================================================================
7017 /*!
7018  * \brief Return true if the point is IN or ON of the element
7019  */
7020 //=======================================================================
7021
7022 bool SMESH_MeshEditor::isOut( const SMDS_MeshElement* element, const gp_Pnt& point, double tol )
7023 {
7024   if ( element->GetType() == SMDSAbs_Volume)
7025   {
7026     return SMDS_VolumeTool( element ).IsOut( point.X(), point.Y(), point.Z(), tol );
7027   }
7028
7029   // get ordered nodes
7030
7031   vector< gp_XYZ > xyz;
7032   vector<const SMDS_MeshNode*> nodeList;
7033
7034   SMDS_ElemIteratorPtr nodeIt = element->nodesIterator();
7035   if ( element->IsQuadratic() ) {
7036     if (const SMDS_VtkFace* f=dynamic_cast<const SMDS_VtkFace*>(element))
7037       nodeIt = f->interlacedNodesElemIterator();
7038     else if (const SMDS_VtkEdge*  e =dynamic_cast<const SMDS_VtkEdge*>(element))
7039       nodeIt = e->interlacedNodesElemIterator();
7040   }
7041   while ( nodeIt->more() )
7042     {
7043       const SMDS_MeshNode* node = cast2Node( nodeIt->next() );
7044       xyz.push_back( TNodeXYZ(node) );
7045       nodeList.push_back(node);
7046     }
7047
7048   int i, nbNodes = element->NbNodes();
7049
7050   if ( element->GetType() == SMDSAbs_Face ) // --------------------------------------------------
7051   {
7052     // compute face normal
7053     gp_Vec faceNorm(0,0,0);
7054     xyz.push_back( xyz.front() );
7055     nodeList.push_back( nodeList.front() );
7056     for ( i = 0; i < nbNodes; ++i )
7057     {
7058       gp_Vec edge1( xyz[i+1], xyz[i]);
7059       gp_Vec edge2( xyz[i+1], xyz[(i+2)%nbNodes] );
7060       faceNorm += edge1 ^ edge2;
7061     }
7062     double normSize = faceNorm.Magnitude();
7063     if ( normSize <= tol )
7064     {
7065       // degenerated face: point is out if it is out of all face edges
7066       for ( i = 0; i < nbNodes; ++i )
7067       {
7068         SMDS_LinearEdge edge( nodeList[i], nodeList[i+1] );
7069         if ( !isOut( &edge, point, tol ))
7070           return false;
7071       }
7072       return true;
7073     }
7074     faceNorm /= normSize;
7075
7076     // check if the point lays on face plane
7077     gp_Vec n2p( xyz[0], point );
7078     if ( fabs( n2p * faceNorm ) > tol )
7079       return true; // not on face plane
7080
7081     // check if point is out of face boundary:
7082     // define it by closest transition of a ray point->infinity through face boundary
7083     // on the face plane.
7084     // First, find normal of a plane perpendicular to face plane, to be used as a cutting tool
7085     // to find intersections of the ray with the boundary.
7086     gp_Vec ray = n2p;
7087     gp_Vec plnNorm = ray ^ faceNorm;
7088     normSize = plnNorm.Magnitude();
7089     if ( normSize <= tol ) return false; // point coincides with the first node
7090     plnNorm /= normSize;
7091     // for each node of the face, compute its signed distance to the plane
7092     vector<double> dist( nbNodes + 1);
7093     for ( i = 0; i < nbNodes; ++i )
7094     {
7095       gp_Vec n2p( xyz[i], point );
7096       dist[i] = n2p * plnNorm;
7097     }
7098     dist.back() = dist.front();
7099     // find the closest intersection
7100     int    iClosest = -1;
7101     double rClosest, distClosest = 1e100;;
7102     gp_Pnt pClosest;
7103     for ( i = 0; i < nbNodes; ++i )
7104     {
7105       double r;
7106       if ( fabs( dist[i]) < tol )
7107         r = 0.;
7108       else if ( fabs( dist[i+1]) < tol )
7109         r = 1.;
7110       else if ( dist[i] * dist[i+1] < 0 )
7111         r = dist[i] / ( dist[i] - dist[i+1] );
7112       else
7113         continue; // no intersection
7114       gp_Pnt pInt = xyz[i] * (1.-r) + xyz[i+1] * r;
7115       gp_Vec p2int ( point, pInt);
7116       if ( p2int * ray > -tol ) // right half-space
7117       {
7118         double intDist = p2int.SquareMagnitude();
7119         if ( intDist < distClosest )
7120         {
7121           iClosest = i;
7122           rClosest = r;
7123           pClosest = pInt;
7124           distClosest = intDist;
7125         }
7126       }
7127     }
7128     if ( iClosest < 0 )
7129       return true; // no intesections - out
7130
7131     // analyse transition
7132     gp_Vec edge( xyz[iClosest], xyz[iClosest+1] );
7133     gp_Vec edgeNorm = -( edge ^ faceNorm ); // normal to intersected edge pointing out of face
7134     gp_Vec p2int ( point, pClosest );
7135     bool out = (edgeNorm * p2int) < -tol;
7136     if ( rClosest > 0. && rClosest < 1. ) // not node intersection
7137       return out;
7138
7139     // ray pass through a face node; analyze transition through an adjacent edge
7140     gp_Pnt p1 = xyz[ (rClosest == 0.) ? ((iClosest+nbNodes-1) % nbNodes) : (iClosest+1) ];
7141     gp_Pnt p2 = xyz[ (rClosest == 0.) ? iClosest : ((iClosest+2) % nbNodes) ];
7142     gp_Vec edgeAdjacent( p1, p2 );
7143     gp_Vec edgeNorm2 = -( edgeAdjacent ^ faceNorm );
7144     bool out2 = (edgeNorm2 * p2int) < -tol;
7145
7146     bool covexCorner = ( edgeNorm * edgeAdjacent * (rClosest==1. ? 1. : -1.)) < 0;
7147     return covexCorner ? (out || out2) : (out && out2);
7148   }
7149   if ( element->GetType() == SMDSAbs_Edge ) // --------------------------------------------------
7150   {
7151     // point is out of edge if it is NOT ON any straight part of edge
7152     // (we consider quadratic edge as being composed of two straight parts)
7153     for ( i = 1; i < nbNodes; ++i )
7154     {
7155       gp_Vec edge( xyz[i-1], xyz[i]);
7156       gp_Vec n1p ( xyz[i-1], point);
7157       double dist = ( edge ^ n1p ).Magnitude() / edge.Magnitude();
7158       if ( dist > tol )
7159         continue;
7160       gp_Vec n2p( xyz[i], point );
7161       if ( fabs( edge.Magnitude() - n1p.Magnitude() - n2p.Magnitude()) > tol )
7162         continue;
7163       return false; // point is ON this part
7164     }
7165     return true;
7166   }
7167   // Node or 0D element -------------------------------------------------------------------------
7168   {
7169     gp_Vec n2p ( xyz[0], point );
7170     return n2p.Magnitude() <= tol;
7171   }
7172   return true;
7173 }
7174
7175 //=======================================================================
7176 //function : SimplifyFace
7177 //purpose  :
7178 //=======================================================================
7179 int SMESH_MeshEditor::SimplifyFace (const vector<const SMDS_MeshNode *> faceNodes,
7180                                     vector<const SMDS_MeshNode *>&      poly_nodes,
7181                                     vector<int>&                        quantities) const
7182 {
7183   int nbNodes = faceNodes.size();
7184
7185   if (nbNodes < 3)
7186     return 0;
7187
7188   set<const SMDS_MeshNode*> nodeSet;
7189
7190   // get simple seq of nodes
7191   //const SMDS_MeshNode* simpleNodes[ nbNodes ];
7192   vector<const SMDS_MeshNode*> simpleNodes( nbNodes );
7193   int iSimple = 0, nbUnique = 0;
7194
7195   simpleNodes[iSimple++] = faceNodes[0];
7196   nbUnique++;
7197   for (int iCur = 1; iCur < nbNodes; iCur++) {
7198     if (faceNodes[iCur] != simpleNodes[iSimple - 1]) {
7199       simpleNodes[iSimple++] = faceNodes[iCur];
7200       if (nodeSet.insert( faceNodes[iCur] ).second)
7201         nbUnique++;
7202     }
7203   }
7204   int nbSimple = iSimple;
7205   if (simpleNodes[nbSimple - 1] == simpleNodes[0]) {
7206     nbSimple--;
7207     iSimple--;
7208   }
7209
7210   if (nbUnique < 3)
7211     return 0;
7212
7213   // separate loops
7214   int nbNew = 0;
7215   bool foundLoop = (nbSimple > nbUnique);
7216   while (foundLoop) {
7217     foundLoop = false;
7218     set<const SMDS_MeshNode*> loopSet;
7219     for (iSimple = 0; iSimple < nbSimple && !foundLoop; iSimple++) {
7220       const SMDS_MeshNode* n = simpleNodes[iSimple];
7221       if (!loopSet.insert( n ).second) {
7222         foundLoop = true;
7223
7224         // separate loop
7225         int iC = 0, curLast = iSimple;
7226         for (; iC < curLast; iC++) {
7227           if (simpleNodes[iC] == n) break;
7228         }
7229         int loopLen = curLast - iC;
7230         if (loopLen > 2) {
7231           // create sub-element
7232           nbNew++;
7233           quantities.push_back(loopLen);
7234           for (; iC < curLast; iC++) {
7235             poly_nodes.push_back(simpleNodes[iC]);
7236           }
7237         }
7238         // shift the rest nodes (place from the first loop position)
7239         for (iC = curLast + 1; iC < nbSimple; iC++) {
7240           simpleNodes[iC - loopLen] = simpleNodes[iC];
7241         }
7242         nbSimple -= loopLen;
7243         iSimple -= loopLen;
7244       }
7245     } // for (iSimple = 0; iSimple < nbSimple; iSimple++)
7246   } // while (foundLoop)
7247
7248   if (iSimple > 2) {
7249     nbNew++;
7250     quantities.push_back(iSimple);
7251     for (int i = 0; i < iSimple; i++)
7252       poly_nodes.push_back(simpleNodes[i]);
7253   }
7254
7255   return nbNew;
7256 }
7257
7258 //=======================================================================
7259 //function : MergeNodes
7260 //purpose  : In each group, the cdr of nodes are substituted by the first one
7261 //           in all elements.
7262 //=======================================================================
7263
7264 void SMESH_MeshEditor::MergeNodes (TListOfListOfNodes & theGroupsOfNodes)
7265 {
7266   MESSAGE("MergeNodes");
7267   myLastCreatedElems.Clear();
7268   myLastCreatedNodes.Clear();
7269
7270   SMESHDS_Mesh* aMesh = GetMeshDS();
7271
7272   TNodeNodeMap nodeNodeMap; // node to replace - new node
7273   set<const SMDS_MeshElement*> elems; // all elements with changed nodes
7274   list< int > rmElemIds, rmNodeIds;
7275
7276   // Fill nodeNodeMap and elems
7277
7278   TListOfListOfNodes::iterator grIt = theGroupsOfNodes.begin();
7279   for ( ; grIt != theGroupsOfNodes.end(); grIt++ ) {
7280     list<const SMDS_MeshNode*>& nodes = *grIt;
7281     list<const SMDS_MeshNode*>::iterator nIt = nodes.begin();
7282     const SMDS_MeshNode* nToKeep = *nIt;
7283     //MESSAGE("node to keep " << nToKeep->GetID());
7284     for ( ++nIt; nIt != nodes.end(); nIt++ ) {
7285       const SMDS_MeshNode* nToRemove = *nIt;
7286       nodeNodeMap.insert( TNodeNodeMap::value_type( nToRemove, nToKeep ));
7287       if ( nToRemove != nToKeep ) {
7288         //MESSAGE("  node to remove " << nToRemove->GetID());
7289         rmNodeIds.push_back( nToRemove->GetID() );
7290         AddToSameGroups( nToKeep, nToRemove, aMesh );
7291       }
7292
7293       SMDS_ElemIteratorPtr invElemIt = nToRemove->GetInverseElementIterator();
7294       while ( invElemIt->more() ) {
7295         const SMDS_MeshElement* elem = invElemIt->next();
7296         elems.insert(elem);
7297       }
7298     }
7299   }
7300   // Change element nodes or remove an element
7301
7302   set<const SMDS_MeshElement*>::iterator eIt = elems.begin();
7303   for ( ; eIt != elems.end(); eIt++ ) {
7304     const SMDS_MeshElement* elem = *eIt;
7305     //MESSAGE(" ---- inverse elem on node to remove " << elem->GetID());
7306     int nbNodes = elem->NbNodes();
7307     int aShapeId = FindShape( elem );
7308
7309     set<const SMDS_MeshNode*> nodeSet;
7310     vector< const SMDS_MeshNode*> curNodes( nbNodes ), uniqueNodes( nbNodes );
7311     int iUnique = 0, iCur = 0, nbRepl = 0;
7312     vector<int> iRepl( nbNodes );
7313
7314     // get new seq of nodes
7315     SMDS_ElemIteratorPtr itN = elem->nodesIterator();
7316     while ( itN->more() ) {
7317       const SMDS_MeshNode* n =
7318         static_cast<const SMDS_MeshNode*>( itN->next() );
7319
7320       TNodeNodeMap::iterator nnIt = nodeNodeMap.find( n );
7321       if ( nnIt != nodeNodeMap.end() ) { // n sticks
7322         n = (*nnIt).second;
7323         // BUG 0020185: begin
7324         {
7325           bool stopRecur = false;
7326           set<const SMDS_MeshNode*> nodesRecur;
7327           nodesRecur.insert(n);
7328           while (!stopRecur) {
7329             TNodeNodeMap::iterator nnIt_i = nodeNodeMap.find( n );
7330             if ( nnIt_i != nodeNodeMap.end() ) { // n sticks
7331               n = (*nnIt_i).second;
7332               if (!nodesRecur.insert(n).second) {
7333                 // error: recursive dependancy
7334                 stopRecur = true;
7335               }
7336             }
7337             else
7338               stopRecur = true;
7339           }
7340         }
7341         // BUG 0020185: end
7342         iRepl[ nbRepl++ ] = iCur;
7343       }
7344       curNodes[ iCur ] = n;
7345       bool isUnique = nodeSet.insert( n ).second;
7346       if ( isUnique )
7347         uniqueNodes[ iUnique++ ] = n;
7348       iCur++;
7349     }
7350
7351     // Analyse element topology after replacement
7352
7353     bool isOk = true;
7354     int nbUniqueNodes = nodeSet.size();
7355     //MESSAGE("nbNodes nbUniqueNodes " << nbNodes << " " << nbUniqueNodes);
7356     if ( nbNodes != nbUniqueNodes ) { // some nodes stick
7357       // Polygons and Polyhedral volumes
7358       if (elem->IsPoly()) {
7359
7360         if (elem->GetType() == SMDSAbs_Face) {
7361           // Polygon
7362           vector<const SMDS_MeshNode *> face_nodes (nbNodes);
7363           int inode = 0;
7364           for (; inode < nbNodes; inode++) {
7365             face_nodes[inode] = curNodes[inode];
7366           }
7367
7368           vector<const SMDS_MeshNode *> polygons_nodes;
7369           vector<int> quantities;
7370           int nbNew = SimplifyFace(face_nodes, polygons_nodes, quantities);
7371
7372           if (nbNew > 0) {
7373             inode = 0;
7374             for (int iface = 0; iface < nbNew - 1; iface++) {
7375               int nbNodes = quantities[iface];
7376               vector<const SMDS_MeshNode *> poly_nodes (nbNodes);
7377               for (int ii = 0; ii < nbNodes; ii++, inode++) {
7378                 poly_nodes[ii] = polygons_nodes[inode];
7379               }
7380               SMDS_MeshElement* newElem = aMesh->AddPolygonalFace(poly_nodes);
7381               myLastCreatedElems.Append(newElem);
7382               if (aShapeId)
7383                 aMesh->SetMeshElementOnShape(newElem, aShapeId);
7384             }
7385
7386             MESSAGE("ChangeElementNodes MergeNodes Polygon");
7387             //aMesh->ChangeElementNodes(elem, &polygons_nodes[inode], quantities[nbNew - 1]);
7388             vector<const SMDS_MeshNode *> polynodes(polygons_nodes.begin()+inode,polygons_nodes.end());
7389             int quid =0;
7390             if (nbNew > 0) quid = nbNew - 1;
7391             vector<int> newquant(quantities.begin()+quid, quantities.end());
7392             const SMDS_MeshElement* newElem = 0;
7393             newElem = aMesh->AddPolyhedralVolume(polynodes, newquant);
7394             myLastCreatedElems.Append(newElem);
7395             if ( aShapeId && newElem )
7396               aMesh->SetMeshElementOnShape( newElem, aShapeId );
7397             rmElemIds.push_back(elem->GetID());
7398           }
7399           else {
7400             rmElemIds.push_back(elem->GetID());
7401           }
7402
7403         }
7404         else if (elem->GetType() == SMDSAbs_Volume) {
7405           // Polyhedral volume
7406           if (nbUniqueNodes < 4) {
7407             rmElemIds.push_back(elem->GetID());
7408           }
7409           else {
7410             // each face has to be analyzed in order to check volume validity
7411             const SMDS_VtkVolume* aPolyedre =
7412               dynamic_cast<const SMDS_VtkVolume*>( elem );
7413             if (aPolyedre) {
7414               int nbFaces = aPolyedre->NbFaces();
7415
7416               vector<const SMDS_MeshNode *> poly_nodes;
7417               vector<int> quantities;
7418
7419               for (int iface = 1; iface <= nbFaces; iface++) {
7420                 int nbFaceNodes = aPolyedre->NbFaceNodes(iface);
7421                 vector<const SMDS_MeshNode *> faceNodes (nbFaceNodes);
7422
7423                 for (int inode = 1; inode <= nbFaceNodes; inode++) {
7424                   const SMDS_MeshNode * faceNode = aPolyedre->GetFaceNode(iface, inode);
7425                   TNodeNodeMap::iterator nnIt = nodeNodeMap.find(faceNode);
7426                   if (nnIt != nodeNodeMap.end()) { // faceNode sticks
7427                     faceNode = (*nnIt).second;
7428                   }
7429                   faceNodes[inode - 1] = faceNode;
7430                 }
7431
7432                 SimplifyFace(faceNodes, poly_nodes, quantities);
7433               }
7434
7435               if (quantities.size() > 3) {
7436                 // to be done: remove coincident faces
7437               }
7438
7439               if (quantities.size() > 3)
7440                 {
7441                   MESSAGE("ChangeElementNodes MergeNodes Polyhedron");
7442                   //aMesh->ChangePolyhedronNodes(elem, poly_nodes, quantities);
7443                   const SMDS_MeshElement* newElem = 0;
7444                   newElem = aMesh->AddPolyhedralVolume(poly_nodes, quantities);
7445                   myLastCreatedElems.Append(newElem);
7446                   if ( aShapeId && newElem )
7447                     aMesh->SetMeshElementOnShape( newElem, aShapeId );
7448                   rmElemIds.push_back(elem->GetID());
7449                 }
7450             }
7451             else {
7452               rmElemIds.push_back(elem->GetID());
7453             }
7454           }
7455         }
7456         else {
7457         }
7458
7459         continue;
7460       }
7461
7462       // Regular elements
7463       // TODO not all the possible cases are solved. Find something more generic?
7464       switch ( nbNodes ) {
7465       case 2: ///////////////////////////////////// EDGE
7466         isOk = false; break;
7467       case 3: ///////////////////////////////////// TRIANGLE
7468         isOk = false; break;
7469       case 4:
7470         if ( elem->GetType() == SMDSAbs_Volume ) // TETRAHEDRON
7471           isOk = false;
7472         else { //////////////////////////////////// QUADRANGLE
7473           if ( nbUniqueNodes < 3 )
7474             isOk = false;
7475           else if ( nbRepl == 2 && iRepl[ 1 ] - iRepl[ 0 ] == 2 )
7476             isOk = false; // opposite nodes stick
7477           //MESSAGE("isOk " << isOk);
7478         }
7479         break;
7480       case 6: ///////////////////////////////////// PENTAHEDRON
7481         if ( nbUniqueNodes == 4 ) {
7482           // ---------------------------------> tetrahedron
7483           if (nbRepl == 3 &&
7484               iRepl[ 0 ] > 2 && iRepl[ 1 ] > 2 && iRepl[ 2 ] > 2 ) {
7485             // all top nodes stick: reverse a bottom
7486             uniqueNodes[ 0 ] = curNodes [ 1 ];
7487             uniqueNodes[ 1 ] = curNodes [ 0 ];
7488           }
7489           else if (nbRepl == 3 &&
7490                    iRepl[ 0 ] < 3 && iRepl[ 1 ] < 3 && iRepl[ 2 ] < 3 ) {
7491             // all bottom nodes stick: set a top before
7492             uniqueNodes[ 3 ] = uniqueNodes [ 0 ];
7493             uniqueNodes[ 0 ] = curNodes [ 3 ];
7494             uniqueNodes[ 1 ] = curNodes [ 4 ];
7495             uniqueNodes[ 2 ] = curNodes [ 5 ];
7496           }
7497           else if (nbRepl == 4 &&
7498                    iRepl[ 2 ] - iRepl [ 0 ] == 3 && iRepl[ 3 ] - iRepl [ 1 ] == 3 ) {
7499             // a lateral face turns into a line: reverse a bottom
7500             uniqueNodes[ 0 ] = curNodes [ 1 ];
7501             uniqueNodes[ 1 ] = curNodes [ 0 ];
7502           }
7503           else
7504             isOk = false;
7505         }
7506         else if ( nbUniqueNodes == 5 ) {
7507           // PENTAHEDRON --------------------> 2 tetrahedrons
7508           if ( nbRepl == 2 && iRepl[ 1 ] - iRepl [ 0 ] == 3 ) {
7509             // a bottom node sticks with a linked top one
7510             // 1.
7511             SMDS_MeshElement* newElem =
7512               aMesh->AddVolume(curNodes[ 3 ],
7513                                curNodes[ 4 ],
7514                                curNodes[ 5 ],
7515                                curNodes[ iRepl[ 0 ] == 2 ? 1 : 2 ]);
7516             myLastCreatedElems.Append(newElem);
7517             if ( aShapeId )
7518               aMesh->SetMeshElementOnShape( newElem, aShapeId );
7519             // 2. : reverse a bottom
7520             uniqueNodes[ 0 ] = curNodes [ 1 ];
7521             uniqueNodes[ 1 ] = curNodes [ 0 ];
7522             nbUniqueNodes = 4;
7523           }
7524           else
7525             isOk = false;
7526         }
7527         else
7528           isOk = false;
7529         break;
7530       case 8: {
7531         if(elem->IsQuadratic()) { // Quadratic quadrangle
7532           //   1    5    2
7533           //    +---+---+
7534           //    |       |
7535           //    |       |
7536           //   4+       +6
7537           //    |       |
7538           //    |       |
7539           //    +---+---+
7540           //   0    7    3
7541           isOk = false;
7542           if(nbRepl==2) {
7543             MESSAGE("nbRepl=2: " << iRepl[0] << " " << iRepl[1]);
7544           }
7545           if(nbRepl==3) {
7546             MESSAGE("nbRepl=3: " << iRepl[0] << " " << iRepl[1]  << " " << iRepl[2]);
7547             nbUniqueNodes = 6;
7548             if( iRepl[0]==0 && iRepl[1]==1 && iRepl[2]==4 ) {
7549               uniqueNodes[0] = curNodes[0];
7550               uniqueNodes[1] = curNodes[2];
7551               uniqueNodes[2] = curNodes[3];
7552               uniqueNodes[3] = curNodes[5];
7553               uniqueNodes[4] = curNodes[6];
7554               uniqueNodes[5] = curNodes[7];
7555               isOk = true;
7556             }
7557             if( iRepl[0]==0 && iRepl[1]==3 && iRepl[2]==7 ) {
7558               uniqueNodes[0] = curNodes[0];
7559               uniqueNodes[1] = curNodes[1];
7560               uniqueNodes[2] = curNodes[2];
7561               uniqueNodes[3] = curNodes[4];
7562               uniqueNodes[4] = curNodes[5];
7563               uniqueNodes[5] = curNodes[6];
7564               isOk = true;
7565             }
7566             if( iRepl[0]==0 && iRepl[1]==4 && iRepl[2]==7 ) {
7567               uniqueNodes[0] = curNodes[1];
7568               uniqueNodes[1] = curNodes[2];
7569               uniqueNodes[2] = curNodes[3];
7570               uniqueNodes[3] = curNodes[5];
7571               uniqueNodes[4] = curNodes[6];
7572               uniqueNodes[5] = curNodes[0];
7573               isOk = true;
7574             }
7575             if( iRepl[0]==1 && iRepl[1]==2 && iRepl[2]==5 ) {
7576               uniqueNodes[0] = curNodes[0];
7577               uniqueNodes[1] = curNodes[1];
7578               uniqueNodes[2] = curNodes[3];
7579               uniqueNodes[3] = curNodes[4];
7580               uniqueNodes[4] = curNodes[6];
7581               uniqueNodes[5] = curNodes[7];
7582               isOk = true;
7583             }
7584             if( iRepl[0]==1 && iRepl[1]==4 && iRepl[2]==5 ) {
7585               uniqueNodes[0] = curNodes[0];
7586               uniqueNodes[1] = curNodes[2];
7587               uniqueNodes[2] = curNodes[3];
7588               uniqueNodes[3] = curNodes[1];
7589               uniqueNodes[4] = curNodes[6];
7590               uniqueNodes[5] = curNodes[7];
7591               isOk = true;
7592             }
7593             if( iRepl[0]==2 && iRepl[1]==3 && iRepl[2]==6 ) {
7594               uniqueNodes[0] = curNodes[0];
7595               uniqueNodes[1] = curNodes[1];
7596               uniqueNodes[2] = curNodes[2];
7597               uniqueNodes[3] = curNodes[4];
7598               uniqueNodes[4] = curNodes[5];
7599               uniqueNodes[5] = curNodes[7];
7600               isOk = true;
7601             }
7602             if( iRepl[0]==2 && iRepl[1]==5 && iRepl[2]==6 ) {
7603               uniqueNodes[0] = curNodes[0];
7604               uniqueNodes[1] = curNodes[1];
7605               uniqueNodes[2] = curNodes[3];
7606               uniqueNodes[3] = curNodes[4];
7607               uniqueNodes[4] = curNodes[2];
7608               uniqueNodes[5] = curNodes[7];
7609               isOk = true;
7610             }
7611             if( iRepl[0]==3 && iRepl[1]==6 && iRepl[2]==7 ) {
7612               uniqueNodes[0] = curNodes[0];
7613               uniqueNodes[1] = curNodes[1];
7614               uniqueNodes[2] = curNodes[2];
7615               uniqueNodes[3] = curNodes[4];
7616               uniqueNodes[4] = curNodes[5];
7617               uniqueNodes[5] = curNodes[3];
7618               isOk = true;
7619             }
7620           }
7621           if(nbRepl==4) {
7622             MESSAGE("nbRepl=4: " << iRepl[0] << " " << iRepl[1]  << " " << iRepl[2] << " " << iRepl[3]);
7623           }
7624           if(nbRepl==5) {
7625             MESSAGE("nbRepl=5: " << iRepl[0] << " " << iRepl[1]  << " " << iRepl[2] << " " << iRepl[3] << " " << iRepl[4]);
7626           }
7627           break;
7628         }
7629         //////////////////////////////////// HEXAHEDRON
7630         isOk = false;
7631         SMDS_VolumeTool hexa (elem);
7632         hexa.SetExternalNormal();
7633         if ( nbUniqueNodes == 4 && nbRepl == 6 ) {
7634           //////////////////////// ---> tetrahedron
7635           for ( int iFace = 0; iFace < 6; iFace++ ) {
7636             const int *ind = hexa.GetFaceNodesIndices( iFace ); // indices of face nodes
7637             if (curNodes[ind[ 0 ]] == curNodes[ind[ 1 ]] &&
7638                 curNodes[ind[ 0 ]] == curNodes[ind[ 2 ]] &&
7639                 curNodes[ind[ 0 ]] == curNodes[ind[ 3 ]] ) {
7640               // one face turns into a point ...
7641               int iOppFace = hexa.GetOppFaceIndex( iFace );
7642               ind = hexa.GetFaceNodesIndices( iOppFace );
7643               int nbStick = 0;
7644               iUnique = 2; // reverse a tetrahedron bottom
7645               for ( iCur = 0; iCur < 4 && nbStick < 2; iCur++ ) {
7646                 if ( curNodes[ind[ iCur ]] == curNodes[ind[ iCur + 1 ]] )
7647                   nbStick++;
7648                 else if ( iUnique >= 0 )
7649                   uniqueNodes[ iUnique-- ] = curNodes[ind[ iCur ]];
7650               }
7651               if ( nbStick == 1 ) {
7652                 // ... and the opposite one - into a triangle.
7653                 // set a top node
7654                 ind = hexa.GetFaceNodesIndices( iFace );
7655                 uniqueNodes[ 3 ] = curNodes[ind[ 0 ]];
7656                 isOk = true;
7657               }
7658               break;
7659             }
7660           }
7661         }
7662         else if (nbUniqueNodes == 5 && nbRepl == 4 ) {
7663           //////////////////// HEXAHEDRON ---> 2 tetrahedrons
7664           for ( int iFace = 0; iFace < 6; iFace++ ) {
7665             const int *ind = hexa.GetFaceNodesIndices( iFace ); // indices of face nodes
7666             if (curNodes[ind[ 0 ]] == curNodes[ind[ 1 ]] &&
7667                 curNodes[ind[ 0 ]] == curNodes[ind[ 2 ]] &&
7668                 curNodes[ind[ 0 ]] == curNodes[ind[ 3 ]] ) {
7669               // one face turns into a point ...
7670               int iOppFace = hexa.GetOppFaceIndex( iFace );
7671               ind = hexa.GetFaceNodesIndices( iOppFace );
7672               int nbStick = 0;
7673               iUnique = 2;  // reverse a tetrahedron 1 bottom
7674               for ( iCur = 0; iCur < 4 && nbStick == 0; iCur++ ) {
7675                 if ( curNodes[ind[ iCur ]] == curNodes[ind[ iCur + 1 ]] )
7676                   nbStick++;
7677                 else if ( iUnique >= 0 )
7678                   uniqueNodes[ iUnique-- ] = curNodes[ind[ iCur ]];
7679               }
7680               if ( nbStick == 0 ) {
7681                 // ... and the opposite one is a quadrangle
7682                 // set a top node
7683                 const int* indTop = hexa.GetFaceNodesIndices( iFace );
7684                 uniqueNodes[ 3 ] = curNodes[indTop[ 0 ]];
7685                 nbUniqueNodes = 4;
7686                 // tetrahedron 2
7687                 SMDS_MeshElement* newElem =
7688                   aMesh->AddVolume(curNodes[ind[ 0 ]],
7689                                    curNodes[ind[ 3 ]],
7690                                    curNodes[ind[ 2 ]],
7691                                    curNodes[indTop[ 0 ]]);
7692                 myLastCreatedElems.Append(newElem);
7693                 if ( aShapeId )
7694                   aMesh->SetMeshElementOnShape( newElem, aShapeId );
7695                 isOk = true;
7696               }
7697               break;
7698             }
7699           }
7700         }
7701         else if ( nbUniqueNodes == 6 && nbRepl == 4 ) {
7702           ////////////////// HEXAHEDRON ---> 2 tetrahedrons or 1 prism
7703           // find indices of quad and tri faces
7704           int iQuadFace[ 6 ], iTriFace[ 6 ], nbQuad = 0, nbTri = 0, iFace;
7705           for ( iFace = 0; iFace < 6; iFace++ ) {
7706             const int *ind = hexa.GetFaceNodesIndices( iFace ); // indices of face nodes
7707             nodeSet.clear();
7708             for ( iCur = 0; iCur < 4; iCur++ )
7709               nodeSet.insert( curNodes[ind[ iCur ]] );
7710             nbUniqueNodes = nodeSet.size();
7711             if ( nbUniqueNodes == 3 )
7712               iTriFace[ nbTri++ ] = iFace;
7713             else if ( nbUniqueNodes == 4 )
7714               iQuadFace[ nbQuad++ ] = iFace;
7715           }
7716           if (nbQuad == 2 && nbTri == 4 &&
7717               hexa.GetOppFaceIndex( iQuadFace[ 0 ] ) == iQuadFace[ 1 ]) {
7718             // 2 opposite quadrangles stuck with a diagonal;
7719             // sample groups of merged indices: (0-4)(2-6)
7720             // --------------------------------------------> 2 tetrahedrons
7721             const int *ind1 = hexa.GetFaceNodesIndices( iQuadFace[ 0 ]); // indices of quad1 nodes
7722             const int *ind2 = hexa.GetFaceNodesIndices( iQuadFace[ 1 ]);
7723             int i0, i1d, i2, i3d, i0t, i2t; // d-daigonal, t-top
7724             if (curNodes[ind1[ 0 ]] == curNodes[ind2[ 0 ]] &&
7725                 curNodes[ind1[ 2 ]] == curNodes[ind2[ 2 ]]) {
7726               // stuck with 0-2 diagonal
7727               i0  = ind1[ 3 ];
7728               i1d = ind1[ 0 ];
7729               i2  = ind1[ 1 ];
7730               i3d = ind1[ 2 ];
7731               i0t = ind2[ 1 ];
7732               i2t = ind2[ 3 ];
7733             }
7734             else if (curNodes[ind1[ 1 ]] == curNodes[ind2[ 3 ]] &&
7735                      curNodes[ind1[ 3 ]] == curNodes[ind2[ 1 ]]) {
7736               // stuck with 1-3 diagonal
7737               i0  = ind1[ 0 ];
7738               i1d = ind1[ 1 ];
7739               i2  = ind1[ 2 ];
7740               i3d = ind1[ 3 ];
7741               i0t = ind2[ 0 ];
7742               i2t = ind2[ 1 ];
7743             }
7744             else {
7745               ASSERT(0);
7746             }
7747             // tetrahedron 1
7748             uniqueNodes[ 0 ] = curNodes [ i0 ];
7749             uniqueNodes[ 1 ] = curNodes [ i1d ];
7750             uniqueNodes[ 2 ] = curNodes [ i3d ];
7751             uniqueNodes[ 3 ] = curNodes [ i0t ];
7752             nbUniqueNodes = 4;
7753             // tetrahedron 2
7754             SMDS_MeshElement* newElem = aMesh->AddVolume(curNodes[ i1d ],
7755                                                          curNodes[ i2 ],
7756                                                          curNodes[ i3d ],
7757                                                          curNodes[ i2t ]);
7758             myLastCreatedElems.Append(newElem);
7759             if ( aShapeId )
7760               aMesh->SetMeshElementOnShape( newElem, aShapeId );
7761             isOk = true;
7762           }
7763           else if (( nbTri == 2 && nbQuad == 3 ) || // merged (0-4)(1-5)
7764                    ( nbTri == 4 && nbQuad == 2 )) { // merged (7-4)(1-5)
7765             // --------------------------------------------> prism
7766             // find 2 opposite triangles
7767             nbUniqueNodes = 6;
7768             for ( iFace = 0; iFace + 1 < nbTri; iFace++ ) {
7769               if ( hexa.GetOppFaceIndex( iTriFace[ iFace ] ) == iTriFace[ iFace + 1 ]) {
7770                 // find indices of kept and replaced nodes
7771                 // and fill unique nodes of 2 opposite triangles
7772                 const int *ind1 = hexa.GetFaceNodesIndices( iTriFace[ iFace ]);
7773                 const int *ind2 = hexa.GetFaceNodesIndices( iTriFace[ iFace + 1 ]);
7774                 const SMDS_MeshNode** hexanodes = hexa.GetNodes();
7775                 // fill unique nodes
7776                 iUnique = 0;
7777                 isOk = true;
7778                 for ( iCur = 0; iCur < 4 && isOk; iCur++ ) {
7779                   const SMDS_MeshNode* n     = curNodes[ind1[ iCur ]];
7780                   const SMDS_MeshNode* nInit = hexanodes[ind1[ iCur ]];
7781                   if ( n == nInit ) {
7782                     // iCur of a linked node of the opposite face (make normals co-directed):
7783                     int iCurOpp = ( iCur == 1 || iCur == 3 ) ? 4 - iCur : iCur;
7784                     // check that correspondent corners of triangles are linked
7785                     if ( !hexa.IsLinked( ind1[ iCur ], ind2[ iCurOpp ] ))
7786                       isOk = false;
7787                     else {
7788                       uniqueNodes[ iUnique ] = n;
7789                       uniqueNodes[ iUnique + 3 ] = curNodes[ind2[ iCurOpp ]];
7790                       iUnique++;
7791                     }
7792                   }
7793                 }
7794                 break;
7795               }
7796             }
7797           }
7798         } // if ( nbUniqueNodes == 6 && nbRepl == 4 )
7799         break;
7800       } // HEXAHEDRON
7801
7802       default:
7803         isOk = false;
7804       } // switch ( nbNodes )
7805
7806     } // if ( nbNodes != nbUniqueNodes ) // some nodes stick
7807
7808     if ( isOk ) {
7809       if (elem->IsPoly() && elem->GetType() == SMDSAbs_Volume) {
7810         // Change nodes of polyedre
7811         const SMDS_VtkVolume* aPolyedre =
7812           dynamic_cast<const SMDS_VtkVolume*>( elem );
7813         if (aPolyedre) {
7814           int nbFaces = aPolyedre->NbFaces();
7815
7816           vector<const SMDS_MeshNode *> poly_nodes;
7817           vector<int> quantities (nbFaces);
7818
7819           for (int iface = 1; iface <= nbFaces; iface++) {
7820             int inode, nbFaceNodes = aPolyedre->NbFaceNodes(iface);
7821             quantities[iface - 1] = nbFaceNodes;
7822
7823             for (inode = 1; inode <= nbFaceNodes; inode++) {
7824               const SMDS_MeshNode* curNode = aPolyedre->GetFaceNode(iface, inode);
7825
7826               TNodeNodeMap::iterator nnIt = nodeNodeMap.find( curNode );
7827               if (nnIt != nodeNodeMap.end()) { // curNode sticks
7828                 curNode = (*nnIt).second;
7829               }
7830               poly_nodes.push_back(curNode);
7831             }
7832           }
7833           aMesh->ChangePolyhedronNodes( elem, poly_nodes, quantities );
7834         }
7835       }
7836       else {
7837         //int elemId = elem->GetID();
7838         //MESSAGE("Change regular element or polygon " << elemId);
7839         SMDSAbs_ElementType etyp = elem->GetType();
7840         uniqueNodes.resize(nbUniqueNodes);
7841         SMDS_MeshElement* newElem = this->AddElement(uniqueNodes, etyp, false);
7842         if (newElem)
7843           {
7844             myLastCreatedElems.Append(newElem);
7845             if ( aShapeId )
7846               aMesh->SetMeshElementOnShape( newElem, aShapeId );
7847           }
7848         aMesh->RemoveElement(elem);
7849       }
7850     }
7851     else {
7852       // Remove invalid regular element or invalid polygon
7853       //MESSAGE("Remove invalid " << elem->GetID());
7854       rmElemIds.push_back( elem->GetID() );
7855     }
7856
7857   } // loop on elements
7858
7859   // Remove bad elements, then equal nodes (order important)
7860
7861   Remove( rmElemIds, false );
7862   Remove( rmNodeIds, true );
7863
7864 }
7865
7866
7867 // ========================================================
7868 // class   : SortableElement
7869 // purpose : allow sorting elements basing on their nodes
7870 // ========================================================
7871 class SortableElement : public set <const SMDS_MeshElement*>
7872 {
7873 public:
7874
7875   SortableElement( const SMDS_MeshElement* theElem )
7876   {
7877     myElem = theElem;
7878     SMDS_ElemIteratorPtr nodeIt = theElem->nodesIterator();
7879     while ( nodeIt->more() )
7880       this->insert( nodeIt->next() );
7881   }
7882
7883   const SMDS_MeshElement* Get() const
7884   { return myElem; }
7885
7886   void Set(const SMDS_MeshElement* e) const
7887   { myElem = e; }
7888
7889
7890 private:
7891   mutable const SMDS_MeshElement* myElem;
7892 };
7893
7894 //=======================================================================
7895 //function : FindEqualElements
7896 //purpose  : Return list of group of elements built on the same nodes.
7897 //           Search among theElements or in the whole mesh if theElements is empty
7898 //=======================================================================
7899 void SMESH_MeshEditor::FindEqualElements(set<const SMDS_MeshElement*> & theElements,
7900                                          TListOfListOfElementsID &      theGroupsOfElementsID)
7901 {
7902   myLastCreatedElems.Clear();
7903   myLastCreatedNodes.Clear();
7904
7905   typedef set<const SMDS_MeshElement*> TElemsSet;
7906   typedef map< SortableElement, int > TMapOfNodeSet;
7907   typedef list<int> TGroupOfElems;
7908
7909   TElemsSet elems;
7910   if ( theElements.empty() )
7911   { // get all elements in the mesh
7912     SMDS_ElemIteratorPtr eIt = GetMeshDS()->elementsIterator();
7913     while ( eIt->more() )
7914       elems.insert( elems.end(), eIt->next());
7915   }
7916   else
7917     elems = theElements;
7918
7919   vector< TGroupOfElems > arrayOfGroups;
7920   TGroupOfElems groupOfElems;
7921   TMapOfNodeSet mapOfNodeSet;
7922
7923   TElemsSet::iterator elemIt = elems.begin();
7924   for ( int i = 0, j=0; elemIt != elems.end(); ++elemIt, ++j ) {
7925     const SMDS_MeshElement* curElem = *elemIt;
7926     SortableElement SE(curElem);
7927     int ind = -1;
7928     // check uniqueness
7929     pair< TMapOfNodeSet::iterator, bool> pp = mapOfNodeSet.insert(make_pair(SE, i));
7930     if( !(pp.second) ) {
7931       TMapOfNodeSet::iterator& itSE = pp.first;
7932       ind = (*itSE).second;
7933       arrayOfGroups[ind].push_back(curElem->GetID());
7934     }
7935     else {
7936       groupOfElems.clear();
7937       groupOfElems.push_back(curElem->GetID());
7938       arrayOfGroups.push_back(groupOfElems);
7939       i++;
7940     }
7941   }
7942
7943   vector< TGroupOfElems >::iterator groupIt = arrayOfGroups.begin();
7944   for ( ; groupIt != arrayOfGroups.end(); ++groupIt ) {
7945     groupOfElems = *groupIt;
7946     if ( groupOfElems.size() > 1 ) {
7947       groupOfElems.sort();
7948       theGroupsOfElementsID.push_back(groupOfElems);
7949     }
7950   }
7951 }
7952
7953 //=======================================================================
7954 //function : MergeElements
7955 //purpose  : In each given group, substitute all elements by the first one.
7956 //=======================================================================
7957
7958 void SMESH_MeshEditor::MergeElements(TListOfListOfElementsID & theGroupsOfElementsID)
7959 {
7960   myLastCreatedElems.Clear();
7961   myLastCreatedNodes.Clear();
7962
7963   typedef list<int> TListOfIDs;
7964   TListOfIDs rmElemIds; // IDs of elems to remove
7965
7966   SMESHDS_Mesh* aMesh = GetMeshDS();
7967
7968   TListOfListOfElementsID::iterator groupsIt = theGroupsOfElementsID.begin();
7969   while ( groupsIt != theGroupsOfElementsID.end() ) {
7970     TListOfIDs& aGroupOfElemID = *groupsIt;
7971     aGroupOfElemID.sort();
7972     int elemIDToKeep = aGroupOfElemID.front();
7973     const SMDS_MeshElement* elemToKeep = aMesh->FindElement(elemIDToKeep);
7974     aGroupOfElemID.pop_front();
7975     TListOfIDs::iterator idIt = aGroupOfElemID.begin();
7976     while ( idIt != aGroupOfElemID.end() ) {
7977       int elemIDToRemove = *idIt;
7978       const SMDS_MeshElement* elemToRemove = aMesh->FindElement(elemIDToRemove);
7979       // add the kept element in groups of removed one (PAL15188)
7980       AddToSameGroups( elemToKeep, elemToRemove, aMesh );
7981       rmElemIds.push_back( elemIDToRemove );
7982       ++idIt;
7983     }
7984     ++groupsIt;
7985   }
7986
7987   Remove( rmElemIds, false );
7988 }
7989
7990 //=======================================================================
7991 //function : MergeEqualElements
7992 //purpose  : Remove all but one of elements built on the same nodes.
7993 //=======================================================================
7994
7995 void SMESH_MeshEditor::MergeEqualElements()
7996 {
7997   set<const SMDS_MeshElement*> aMeshElements; /* empty input -
7998                                                  to merge equal elements in the whole mesh */
7999   TListOfListOfElementsID aGroupsOfElementsID;
8000   FindEqualElements(aMeshElements, aGroupsOfElementsID);
8001   MergeElements(aGroupsOfElementsID);
8002 }
8003
8004 //=======================================================================
8005 //function : FindFaceInSet
8006 //purpose  : Return a face having linked nodes n1 and n2 and which is
8007 //           - not in avoidSet,
8008 //           - in elemSet provided that !elemSet.empty()
8009 //           i1 and i2 optionally returns indices of n1 and n2
8010 //=======================================================================
8011
8012 const SMDS_MeshElement*
8013 SMESH_MeshEditor::FindFaceInSet(const SMDS_MeshNode*    n1,
8014                                 const SMDS_MeshNode*    n2,
8015                                 const TIDSortedElemSet& elemSet,
8016                                 const TIDSortedElemSet& avoidSet,
8017                                 int*                    n1ind,
8018                                 int*                    n2ind)
8019
8020 {
8021   int i1, i2;
8022   const SMDS_MeshElement* face = 0;
8023
8024   SMDS_ElemIteratorPtr invElemIt = n1->GetInverseElementIterator(SMDSAbs_Face);
8025   //MESSAGE("n1->GetInverseElementIterator(SMDSAbs_Face) " << invElemIt);
8026   while ( invElemIt->more() && !face ) // loop on inverse faces of n1
8027   {
8028     //MESSAGE("in while ( invElemIt->more() && !face )");
8029     const SMDS_MeshElement* elem = invElemIt->next();
8030     if (avoidSet.count( elem ))
8031       continue;
8032     if ( !elemSet.empty() && !elemSet.count( elem ))
8033       continue;
8034     // index of n1
8035     i1 = elem->GetNodeIndex( n1 );
8036     // find a n2 linked to n1
8037     int nbN = elem->IsQuadratic() ? elem->NbNodes()/2 : elem->NbNodes();
8038     for ( int di = -1; di < 2 && !face; di += 2 )
8039     {
8040       i2 = (i1+di+nbN) % nbN;
8041       if ( elem->GetNode( i2 ) == n2 )
8042         face = elem;
8043     }
8044     if ( !face && elem->IsQuadratic())
8045     {
8046       // analysis for quadratic elements using all nodes
8047       const SMDS_VtkFace* F =
8048         dynamic_cast<const SMDS_VtkFace*>(elem);
8049       if (!F) throw SALOME_Exception(LOCALIZED("not an SMDS_VtkFace"));
8050       // use special nodes iterator
8051       SMDS_ElemIteratorPtr anIter = F->interlacedNodesElemIterator();
8052       const SMDS_MeshNode* prevN = cast2Node( anIter->next() );
8053       for ( i1 = -1, i2 = 0; anIter->more() && !face; i1++, i2++ )
8054       {
8055         const SMDS_MeshNode* n = cast2Node( anIter->next() );
8056         if ( n1 == prevN && n2 == n )
8057         {
8058           face = elem;
8059         }
8060         else if ( n2 == prevN && n1 == n )
8061         {
8062           face = elem; swap( i1, i2 );
8063         }
8064         prevN = n;
8065       }
8066     }
8067   }
8068   if ( n1ind ) *n1ind = i1;
8069   if ( n2ind ) *n2ind = i2;
8070   return face;
8071 }
8072
8073 //=======================================================================
8074 //function : findAdjacentFace
8075 //purpose  :
8076 //=======================================================================
8077
8078 static const SMDS_MeshElement* findAdjacentFace(const SMDS_MeshNode* n1,
8079                                                 const SMDS_MeshNode* n2,
8080                                                 const SMDS_MeshElement* elem)
8081 {
8082   TIDSortedElemSet elemSet, avoidSet;
8083   if ( elem )
8084     avoidSet.insert ( elem );
8085   return SMESH_MeshEditor::FindFaceInSet( n1, n2, elemSet, avoidSet );
8086 }
8087
8088 //=======================================================================
8089 //function : FindFreeBorder
8090 //purpose  :
8091 //=======================================================================
8092
8093 #define ControlFreeBorder SMESH::Controls::FreeEdges::IsFreeEdge
8094
8095 bool SMESH_MeshEditor::FindFreeBorder (const SMDS_MeshNode*             theFirstNode,
8096                                        const SMDS_MeshNode*             theSecondNode,
8097                                        const SMDS_MeshNode*             theLastNode,
8098                                        list< const SMDS_MeshNode* > &   theNodes,
8099                                        list< const SMDS_MeshElement* >& theFaces)
8100 {
8101   if ( !theFirstNode || !theSecondNode )
8102     return false;
8103   // find border face between theFirstNode and theSecondNode
8104   const SMDS_MeshElement* curElem = findAdjacentFace( theFirstNode, theSecondNode, 0 );
8105   if ( !curElem )
8106     return false;
8107
8108   theFaces.push_back( curElem );
8109   theNodes.push_back( theFirstNode );
8110   theNodes.push_back( theSecondNode );
8111
8112   //vector<const SMDS_MeshNode*> nodes;
8113   const SMDS_MeshNode *nIgnore = theFirstNode, *nStart = theSecondNode;
8114   TIDSortedElemSet foundElems;
8115   bool needTheLast = ( theLastNode != 0 );
8116
8117   while ( nStart != theLastNode ) {
8118     if ( nStart == theFirstNode )
8119       return !needTheLast;
8120
8121     // find all free border faces sharing form nStart
8122
8123     list< const SMDS_MeshElement* > curElemList;
8124     list< const SMDS_MeshNode* > nStartList;
8125     SMDS_ElemIteratorPtr invElemIt = nStart->GetInverseElementIterator(SMDSAbs_Face);
8126     while ( invElemIt->more() ) {
8127       const SMDS_MeshElement* e = invElemIt->next();
8128       if ( e == curElem || foundElems.insert( e ).second ) {
8129         // get nodes
8130         int iNode = 0, nbNodes = e->NbNodes();
8131         //const SMDS_MeshNode* nodes[nbNodes+1];
8132         vector<const SMDS_MeshNode*> nodes(nbNodes+1);
8133
8134         if(e->IsQuadratic()) {
8135           const SMDS_VtkFace* F =
8136             dynamic_cast<const SMDS_VtkFace*>(e);
8137           if (!F) throw SALOME_Exception(LOCALIZED("not an SMDS_VtkFace"));
8138           // use special nodes iterator
8139           SMDS_ElemIteratorPtr anIter = F->interlacedNodesElemIterator();
8140           while( anIter->more() ) {
8141             nodes[ iNode++ ] = cast2Node(anIter->next());
8142           }
8143         }
8144         else {
8145           SMDS_ElemIteratorPtr nIt = e->nodesIterator();
8146           while ( nIt->more() )
8147             nodes[ iNode++ ] = static_cast<const SMDS_MeshNode*>( nIt->next() );
8148         }
8149         nodes[ iNode ] = nodes[ 0 ];
8150         // check 2 links
8151         for ( iNode = 0; iNode < nbNodes; iNode++ )
8152           if (((nodes[ iNode ] == nStart && nodes[ iNode + 1] != nIgnore ) ||
8153                (nodes[ iNode + 1] == nStart && nodes[ iNode ] != nIgnore )) &&
8154               ControlFreeBorder( &nodes[ iNode ], e->GetID() ))
8155           {
8156             nStartList.push_back( nodes[ iNode + ( nodes[ iNode ] == nStart ? 1 : 0 )]);
8157             curElemList.push_back( e );
8158           }
8159       }
8160     }
8161     // analyse the found
8162
8163     int nbNewBorders = curElemList.size();
8164     if ( nbNewBorders == 0 ) {
8165       // no free border furthermore
8166       return !needTheLast;
8167     }
8168     else if ( nbNewBorders == 1 ) {
8169       // one more element found
8170       nIgnore = nStart;
8171       nStart = nStartList.front();
8172       curElem = curElemList.front();
8173       theFaces.push_back( curElem );
8174       theNodes.push_back( nStart );
8175     }
8176     else {
8177       // several continuations found
8178       list< const SMDS_MeshElement* >::iterator curElemIt;
8179       list< const SMDS_MeshNode* >::iterator nStartIt;
8180       // check if one of them reached the last node
8181       if ( needTheLast ) {
8182         for (curElemIt = curElemList.begin(), nStartIt = nStartList.begin();
8183              curElemIt!= curElemList.end();
8184              curElemIt++, nStartIt++ )
8185           if ( *nStartIt == theLastNode ) {
8186             theFaces.push_back( *curElemIt );
8187             theNodes.push_back( *nStartIt );
8188             return true;
8189           }
8190       }
8191       // find the best free border by the continuations
8192       list<const SMDS_MeshNode*>    contNodes[ 2 ], *cNL;
8193       list<const SMDS_MeshElement*> contFaces[ 2 ], *cFL;
8194       for (curElemIt = curElemList.begin(), nStartIt = nStartList.begin();
8195            curElemIt!= curElemList.end();
8196            curElemIt++, nStartIt++ )
8197       {
8198         cNL = & contNodes[ contNodes[0].empty() ? 0 : 1 ];
8199         cFL = & contFaces[ contFaces[0].empty() ? 0 : 1 ];
8200         // find one more free border
8201         if ( ! FindFreeBorder( nStart, *nStartIt, theLastNode, *cNL, *cFL )) {
8202           cNL->clear();
8203           cFL->clear();
8204         }
8205         else if ( !contNodes[0].empty() && !contNodes[1].empty() ) {
8206           // choice: clear a worse one
8207           int iLongest = ( contNodes[0].size() < contNodes[1].size() ? 1 : 0 );
8208           int iWorse = ( needTheLast ? 1 - iLongest : iLongest );
8209           contNodes[ iWorse ].clear();
8210           contFaces[ iWorse ].clear();
8211         }
8212       }
8213       if ( contNodes[0].empty() && contNodes[1].empty() )
8214         return false;
8215
8216       // append the best free border
8217       cNL = & contNodes[ contNodes[0].empty() ? 1 : 0 ];
8218       cFL = & contFaces[ contFaces[0].empty() ? 1 : 0 ];
8219       theNodes.pop_back(); // remove nIgnore
8220       theNodes.pop_back(); // remove nStart
8221       theFaces.pop_back(); // remove curElem
8222       list< const SMDS_MeshNode* >::iterator nIt = cNL->begin();
8223       list< const SMDS_MeshElement* >::iterator fIt = cFL->begin();
8224       for ( ; nIt != cNL->end(); nIt++ ) theNodes.push_back( *nIt );
8225       for ( ; fIt != cFL->end(); fIt++ ) theFaces.push_back( *fIt );
8226       return true;
8227
8228     } // several continuations found
8229   } // while ( nStart != theLastNode )
8230
8231   return true;
8232 }
8233
8234 //=======================================================================
8235 //function : CheckFreeBorderNodes
8236 //purpose  : Return true if the tree nodes are on a free border
8237 //=======================================================================
8238
8239 bool SMESH_MeshEditor::CheckFreeBorderNodes(const SMDS_MeshNode* theNode1,
8240                                             const SMDS_MeshNode* theNode2,
8241                                             const SMDS_MeshNode* theNode3)
8242 {
8243   list< const SMDS_MeshNode* > nodes;
8244   list< const SMDS_MeshElement* > faces;
8245   return FindFreeBorder( theNode1, theNode2, theNode3, nodes, faces);
8246 }
8247
8248 //=======================================================================
8249 //function : SewFreeBorder
8250 //purpose  :
8251 //=======================================================================
8252
8253 SMESH_MeshEditor::Sew_Error
8254 SMESH_MeshEditor::SewFreeBorder (const SMDS_MeshNode* theBordFirstNode,
8255                                  const SMDS_MeshNode* theBordSecondNode,
8256                                  const SMDS_MeshNode* theBordLastNode,
8257                                  const SMDS_MeshNode* theSideFirstNode,
8258                                  const SMDS_MeshNode* theSideSecondNode,
8259                                  const SMDS_MeshNode* theSideThirdNode,
8260                                  const bool           theSideIsFreeBorder,
8261                                  const bool           toCreatePolygons,
8262                                  const bool           toCreatePolyedrs)
8263 {
8264   myLastCreatedElems.Clear();
8265   myLastCreatedNodes.Clear();
8266
8267   MESSAGE("::SewFreeBorder()");
8268   Sew_Error aResult = SEW_OK;
8269
8270   // ====================================
8271   //    find side nodes and elements
8272   // ====================================
8273
8274   list< const SMDS_MeshNode* > nSide[ 2 ];
8275   list< const SMDS_MeshElement* > eSide[ 2 ];
8276   list< const SMDS_MeshNode* >::iterator nIt[ 2 ];
8277   list< const SMDS_MeshElement* >::iterator eIt[ 2 ];
8278
8279   // Free border 1
8280   // --------------
8281   if (!FindFreeBorder(theBordFirstNode,theBordSecondNode,theBordLastNode,
8282                       nSide[0], eSide[0])) {
8283     MESSAGE(" Free Border 1 not found " );
8284     aResult = SEW_BORDER1_NOT_FOUND;
8285   }
8286   if (theSideIsFreeBorder) {
8287     // Free border 2
8288     // --------------
8289     if (!FindFreeBorder(theSideFirstNode, theSideSecondNode, theSideThirdNode,
8290                         nSide[1], eSide[1])) {
8291       MESSAGE(" Free Border 2 not found " );
8292       aResult = ( aResult != SEW_OK ? SEW_BOTH_BORDERS_NOT_FOUND : SEW_BORDER2_NOT_FOUND );
8293     }
8294   }
8295   if ( aResult != SEW_OK )
8296     return aResult;
8297
8298   if (!theSideIsFreeBorder) {
8299     // Side 2
8300     // --------------
8301
8302     // -------------------------------------------------------------------------
8303     // Algo:
8304     // 1. If nodes to merge are not coincident, move nodes of the free border
8305     //    from the coord sys defined by the direction from the first to last
8306     //    nodes of the border to the correspondent sys of the side 2
8307     // 2. On the side 2, find the links most co-directed with the correspondent
8308     //    links of the free border
8309     // -------------------------------------------------------------------------
8310
8311     // 1. Since sewing may break if there are volumes to split on the side 2,
8312     //    we wont move nodes but just compute new coordinates for them
8313     typedef map<const SMDS_MeshNode*, gp_XYZ> TNodeXYZMap;
8314     TNodeXYZMap nBordXYZ;
8315     list< const SMDS_MeshNode* >& bordNodes = nSide[ 0 ];
8316     list< const SMDS_MeshNode* >::iterator nBordIt;
8317
8318     gp_XYZ Pb1( theBordFirstNode->X(), theBordFirstNode->Y(), theBordFirstNode->Z() );
8319     gp_XYZ Pb2( theBordLastNode->X(), theBordLastNode->Y(), theBordLastNode->Z() );
8320     gp_XYZ Ps1( theSideFirstNode->X(), theSideFirstNode->Y(), theSideFirstNode->Z() );
8321     gp_XYZ Ps2( theSideSecondNode->X(), theSideSecondNode->Y(), theSideSecondNode->Z() );
8322     double tol2 = 1.e-8;
8323     gp_Vec Vbs1( Pb1 - Ps1 ),Vbs2( Pb2 - Ps2 );
8324     if ( Vbs1.SquareMagnitude() > tol2 || Vbs2.SquareMagnitude() > tol2 ) {
8325       // Need node movement.
8326
8327       // find X and Z axes to create trsf
8328       gp_Vec Zb( Pb1 - Pb2 ), Zs( Ps1 - Ps2 );
8329       gp_Vec X = Zs ^ Zb;
8330       if ( X.SquareMagnitude() <= gp::Resolution() * gp::Resolution() )
8331         // Zb || Zs
8332         X = gp_Ax2( gp::Origin(), Zb ).XDirection();
8333
8334       // coord systems
8335       gp_Ax3 toBordAx( Pb1, Zb, X );
8336       gp_Ax3 fromSideAx( Ps1, Zs, X );
8337       gp_Ax3 toGlobalAx( gp::Origin(), gp::DZ(), gp::DX() );
8338       // set trsf
8339       gp_Trsf toBordSys, fromSide2Sys;
8340       toBordSys.SetTransformation( toBordAx );
8341       fromSide2Sys.SetTransformation( fromSideAx, toGlobalAx );
8342       fromSide2Sys.SetScaleFactor( Zs.Magnitude() / Zb.Magnitude() );
8343
8344       // move
8345       for ( nBordIt = bordNodes.begin(); nBordIt != bordNodes.end(); nBordIt++ ) {
8346         const SMDS_MeshNode* n = *nBordIt;
8347         gp_XYZ xyz( n->X(),n->Y(),n->Z() );
8348         toBordSys.Transforms( xyz );
8349         fromSide2Sys.Transforms( xyz );
8350         nBordXYZ.insert( TNodeXYZMap::value_type( n, xyz ));
8351       }
8352     }
8353     else {
8354       // just insert nodes XYZ in the nBordXYZ map
8355       for ( nBordIt = bordNodes.begin(); nBordIt != bordNodes.end(); nBordIt++ ) {
8356         const SMDS_MeshNode* n = *nBordIt;
8357         nBordXYZ.insert( TNodeXYZMap::value_type( n, gp_XYZ( n->X(),n->Y(),n->Z() )));
8358       }
8359     }
8360
8361     // 2. On the side 2, find the links most co-directed with the correspondent
8362     //    links of the free border
8363
8364     list< const SMDS_MeshElement* >& sideElems = eSide[ 1 ];
8365     list< const SMDS_MeshNode* >& sideNodes = nSide[ 1 ];
8366     sideNodes.push_back( theSideFirstNode );
8367
8368     bool hasVolumes = false;
8369     LinkID_Gen aLinkID_Gen( GetMeshDS() );
8370     set<long> foundSideLinkIDs, checkedLinkIDs;
8371     SMDS_VolumeTool volume;
8372     //const SMDS_MeshNode* faceNodes[ 4 ];
8373
8374     const SMDS_MeshNode*    sideNode;
8375     const SMDS_MeshElement* sideElem;
8376     const SMDS_MeshNode* prevSideNode = theSideFirstNode;
8377     const SMDS_MeshNode* prevBordNode = theBordFirstNode;
8378     nBordIt = bordNodes.begin();
8379     nBordIt++;
8380     // border node position and border link direction to compare with
8381     gp_XYZ bordPos = nBordXYZ[ *nBordIt ];
8382     gp_XYZ bordDir = bordPos - nBordXYZ[ prevBordNode ];
8383     // choose next side node by link direction or by closeness to
8384     // the current border node:
8385     bool searchByDir = ( *nBordIt != theBordLastNode );
8386     do {
8387       // find the next node on the Side 2
8388       sideNode = 0;
8389       double maxDot = -DBL_MAX, minDist = DBL_MAX;
8390       long linkID;
8391       checkedLinkIDs.clear();
8392       gp_XYZ prevXYZ( prevSideNode->X(), prevSideNode->Y(), prevSideNode->Z() );
8393
8394       // loop on inverse elements of current node (prevSideNode) on the Side 2
8395       SMDS_ElemIteratorPtr invElemIt = prevSideNode->GetInverseElementIterator();
8396       while ( invElemIt->more() )
8397       {
8398         const SMDS_MeshElement* elem = invElemIt->next();
8399         // prepare data for a loop on links coming to prevSideNode, of a face or a volume
8400         int iPrevNode, iNode = 0, nbNodes = elem->NbNodes();
8401         vector< const SMDS_MeshNode* > faceNodes( nbNodes, (const SMDS_MeshNode*)0 );
8402         bool isVolume = volume.Set( elem );
8403         const SMDS_MeshNode** nodes = isVolume ? volume.GetNodes() : & faceNodes[0];
8404         if ( isVolume ) // --volume
8405           hasVolumes = true;
8406         else if ( elem->GetType()==SMDSAbs_Face ) { // --face
8407           // retrieve all face nodes and find iPrevNode - an index of the prevSideNode
8408           if(elem->IsQuadratic()) {
8409             const SMDS_VtkFace* F =
8410               dynamic_cast<const SMDS_VtkFace*>(elem);
8411             if (!F) throw SALOME_Exception(LOCALIZED("not an SMDS_VtkFace"));
8412             // use special nodes iterator
8413             SMDS_ElemIteratorPtr anIter = F->interlacedNodesElemIterator();
8414             while( anIter->more() ) {
8415               nodes[ iNode ] = cast2Node(anIter->next());
8416               if ( nodes[ iNode++ ] == prevSideNode )
8417                 iPrevNode = iNode - 1;
8418             }
8419           }
8420           else {
8421             SMDS_ElemIteratorPtr nIt = elem->nodesIterator();
8422             while ( nIt->more() ) {
8423               nodes[ iNode ] = cast2Node( nIt->next() );
8424               if ( nodes[ iNode++ ] == prevSideNode )
8425                 iPrevNode = iNode - 1;
8426             }
8427           }
8428           // there are 2 links to check
8429           nbNodes = 2;
8430         }
8431         else // --edge
8432           continue;
8433         // loop on links, to be precise, on the second node of links
8434         for ( iNode = 0; iNode < nbNodes; iNode++ ) {
8435           const SMDS_MeshNode* n = nodes[ iNode ];
8436           if ( isVolume ) {
8437             if ( !volume.IsLinked( n, prevSideNode ))
8438               continue;
8439           }
8440           else {
8441             if ( iNode ) // a node before prevSideNode
8442               n = nodes[ iPrevNode == 0 ? elem->NbNodes() - 1 : iPrevNode - 1 ];
8443             else         // a node after prevSideNode
8444               n = nodes[ iPrevNode + 1 == elem->NbNodes() ? 0 : iPrevNode + 1 ];
8445           }
8446           // check if this link was already used
8447           long iLink = aLinkID_Gen.GetLinkID( prevSideNode, n );
8448           bool isJustChecked = !checkedLinkIDs.insert( iLink ).second;
8449           if (!isJustChecked &&
8450               foundSideLinkIDs.find( iLink ) == foundSideLinkIDs.end() )
8451           {
8452             // test a link geometrically
8453             gp_XYZ nextXYZ ( n->X(), n->Y(), n->Z() );
8454             bool linkIsBetter = false;
8455             double dot = 0.0, dist = 0.0;
8456             if ( searchByDir ) { // choose most co-directed link
8457               dot = bordDir * ( nextXYZ - prevXYZ ).Normalized();
8458               linkIsBetter = ( dot > maxDot );
8459             }
8460             else { // choose link with the node closest to bordPos
8461               dist = ( nextXYZ - bordPos ).SquareModulus();
8462               linkIsBetter = ( dist < minDist );
8463             }
8464             if ( linkIsBetter ) {
8465               maxDot = dot;
8466               minDist = dist;
8467               linkID = iLink;
8468               sideNode = n;
8469               sideElem = elem;
8470             }
8471           }
8472         }
8473       } // loop on inverse elements of prevSideNode
8474
8475       if ( !sideNode ) {
8476         MESSAGE(" Cant find path by links of the Side 2 ");
8477         return SEW_BAD_SIDE_NODES;
8478       }
8479       sideNodes.push_back( sideNode );
8480       sideElems.push_back( sideElem );
8481       foundSideLinkIDs.insert ( linkID );
8482       prevSideNode = sideNode;
8483
8484       if ( *nBordIt == theBordLastNode )
8485         searchByDir = false;
8486       else {
8487         // find the next border link to compare with
8488         gp_XYZ sidePos( sideNode->X(), sideNode->Y(), sideNode->Z() );
8489         searchByDir = ( bordDir * ( sidePos - bordPos ) <= 0 );
8490         // move to next border node if sideNode is before forward border node (bordPos)
8491         while ( *nBordIt != theBordLastNode && !searchByDir ) {
8492           prevBordNode = *nBordIt;
8493           nBordIt++;
8494           bordPos = nBordXYZ[ *nBordIt ];
8495           bordDir = bordPos - nBordXYZ[ prevBordNode ];
8496           searchByDir = ( bordDir * ( sidePos - bordPos ) <= 0 );
8497         }
8498       }
8499     }
8500     while ( sideNode != theSideSecondNode );
8501
8502     if ( hasVolumes && sideNodes.size () != bordNodes.size() && !toCreatePolyedrs) {
8503       MESSAGE("VOLUME SPLITTING IS FORBIDDEN");
8504       return SEW_VOLUMES_TO_SPLIT; // volume splitting is forbidden
8505     }
8506   } // end nodes search on the side 2
8507
8508   // ============================
8509   // sew the border to the side 2
8510   // ============================
8511
8512   int nbNodes[]  = { nSide[0].size(), nSide[1].size() };
8513   int maxNbNodes = Max( nbNodes[0], nbNodes[1] );
8514
8515   TListOfListOfNodes nodeGroupsToMerge;
8516   if ( nbNodes[0] == nbNodes[1] ||
8517        ( theSideIsFreeBorder && !theSideThirdNode)) {
8518
8519     // all nodes are to be merged
8520
8521     for (nIt[0] = nSide[0].begin(), nIt[1] = nSide[1].begin();
8522          nIt[0] != nSide[0].end() && nIt[1] != nSide[1].end();
8523          nIt[0]++, nIt[1]++ )
8524     {
8525       nodeGroupsToMerge.push_back( list<const SMDS_MeshNode*>() );
8526       nodeGroupsToMerge.back().push_back( *nIt[1] ); // to keep
8527       nodeGroupsToMerge.back().push_back( *nIt[0] ); // to remove
8528     }
8529   }
8530   else {
8531
8532     // insert new nodes into the border and the side to get equal nb of segments
8533
8534     // get normalized parameters of nodes on the borders
8535     //double param[ 2 ][ maxNbNodes ];
8536     double* param[ 2 ];
8537     param[0] = new double [ maxNbNodes ];
8538     param[1] = new double [ maxNbNodes ];
8539     int iNode, iBord;
8540     for ( iBord = 0; iBord < 2; iBord++ ) { // loop on 2 borders
8541       list< const SMDS_MeshNode* >& nodes = nSide[ iBord ];
8542       list< const SMDS_MeshNode* >::iterator nIt = nodes.begin();
8543       const SMDS_MeshNode* nPrev = *nIt;
8544       double bordLength = 0;
8545       for ( iNode = 0; nIt != nodes.end(); nIt++, iNode++ ) { // loop on border nodes
8546         const SMDS_MeshNode* nCur = *nIt;
8547         gp_XYZ segment (nCur->X() - nPrev->X(),
8548                         nCur->Y() - nPrev->Y(),
8549                         nCur->Z() - nPrev->Z());
8550         double segmentLen = segment.Modulus();
8551         bordLength += segmentLen;
8552         param[ iBord ][ iNode ] = bordLength;
8553         nPrev = nCur;
8554       }
8555       // normalize within [0,1]
8556       for ( iNode = 0; iNode < nbNodes[ iBord ]; iNode++ ) {
8557         param[ iBord ][ iNode ] /= bordLength;
8558       }
8559     }
8560
8561     // loop on border segments
8562     const SMDS_MeshNode *nPrev[ 2 ] = { 0, 0 };
8563     int i[ 2 ] = { 0, 0 };
8564     nIt[0] = nSide[0].begin(); eIt[0] = eSide[0].begin();
8565     nIt[1] = nSide[1].begin(); eIt[1] = eSide[1].begin();
8566
8567     TElemOfNodeListMap insertMap;
8568     TElemOfNodeListMap::iterator insertMapIt;
8569     // insertMap is
8570     // key:   elem to insert nodes into
8571     // value: 2 nodes to insert between + nodes to be inserted
8572     do {
8573       bool next[ 2 ] = { false, false };
8574
8575       // find min adjacent segment length after sewing
8576       double nextParam = 10., prevParam = 0;
8577       for ( iBord = 0; iBord < 2; iBord++ ) { // loop on 2 borders
8578         if ( i[ iBord ] + 1 < nbNodes[ iBord ])
8579           nextParam = Min( nextParam, param[iBord][ i[iBord] + 1 ]);
8580         if ( i[ iBord ] > 0 )
8581           prevParam = Max( prevParam, param[iBord][ i[iBord] - 1 ]);
8582       }
8583       double minParam = Min( param[ 0 ][ i[0] ], param[ 1 ][ i[1] ]);
8584       double maxParam = Max( param[ 0 ][ i[0] ], param[ 1 ][ i[1] ]);
8585       double minSegLen = Min( nextParam - minParam, maxParam - prevParam );
8586
8587       // choose to insert or to merge nodes
8588       double du = param[ 1 ][ i[1] ] - param[ 0 ][ i[0] ];
8589       if ( Abs( du ) <= minSegLen * 0.2 ) {
8590         // merge
8591         // ------
8592         nodeGroupsToMerge.push_back( list<const SMDS_MeshNode*>() );
8593         const SMDS_MeshNode* n0 = *nIt[0];
8594         const SMDS_MeshNode* n1 = *nIt[1];
8595         nodeGroupsToMerge.back().push_back( n1 );
8596         nodeGroupsToMerge.back().push_back( n0 );
8597         // position of node of the border changes due to merge
8598         param[ 0 ][ i[0] ] += du;
8599         // move n1 for the sake of elem shape evaluation during insertion.
8600         // n1 will be removed by MergeNodes() anyway
8601         const_cast<SMDS_MeshNode*>( n0 )->setXYZ( n1->X(), n1->Y(), n1->Z() );
8602         next[0] = next[1] = true;
8603       }
8604       else {
8605         // insert
8606         // ------
8607         int intoBord = ( du < 0 ) ? 0 : 1;
8608         const SMDS_MeshElement* elem = *eIt[ intoBord ];
8609         const SMDS_MeshNode*    n1   = nPrev[ intoBord ];
8610         const SMDS_MeshNode*    n2   = *nIt[ intoBord ];
8611         const SMDS_MeshNode*    nIns = *nIt[ 1 - intoBord ];
8612         if ( intoBord == 1 ) {
8613           // move node of the border to be on a link of elem of the side
8614           gp_XYZ p1 (n1->X(), n1->Y(), n1->Z());
8615           gp_XYZ p2 (n2->X(), n2->Y(), n2->Z());
8616           double ratio = du / ( param[ 1 ][ i[1] ] - param[ 1 ][ i[1]-1 ]);
8617           gp_XYZ p = p2 * ( 1 - ratio ) + p1 * ratio;
8618           GetMeshDS()->MoveNode( nIns, p.X(), p.Y(), p.Z() );
8619         }
8620         insertMapIt = insertMap.find( elem );
8621         bool notFound = ( insertMapIt == insertMap.end() );
8622         bool otherLink = ( !notFound && (*insertMapIt).second.front() != n1 );
8623         if ( otherLink ) {
8624           // insert into another link of the same element:
8625           // 1. perform insertion into the other link of the elem
8626           list<const SMDS_MeshNode*> & nodeList = (*insertMapIt).second;
8627           const SMDS_MeshNode* n12 = nodeList.front(); nodeList.pop_front();
8628           const SMDS_MeshNode* n22 = nodeList.front(); nodeList.pop_front();
8629           InsertNodesIntoLink( elem, n12, n22, nodeList, toCreatePolygons );
8630           // 2. perform insertion into the link of adjacent faces
8631           while (true) {
8632             const SMDS_MeshElement* adjElem = findAdjacentFace( n12, n22, elem );
8633             if ( adjElem )
8634               InsertNodesIntoLink( adjElem, n12, n22, nodeList, toCreatePolygons );
8635             else
8636               break;
8637           }
8638           if (toCreatePolyedrs) {
8639             // perform insertion into the links of adjacent volumes
8640             UpdateVolumes(n12, n22, nodeList);
8641           }
8642           // 3. find an element appeared on n1 and n2 after the insertion
8643           insertMap.erase( elem );
8644           elem = findAdjacentFace( n1, n2, 0 );
8645         }
8646         if ( notFound || otherLink ) {
8647           // add element and nodes of the side into the insertMap
8648           insertMapIt = insertMap.insert
8649             ( TElemOfNodeListMap::value_type( elem, list<const SMDS_MeshNode*>() )).first;
8650           (*insertMapIt).second.push_back( n1 );
8651           (*insertMapIt).second.push_back( n2 );
8652         }
8653         // add node to be inserted into elem
8654         (*insertMapIt).second.push_back( nIns );
8655         next[ 1 - intoBord ] = true;
8656       }
8657
8658       // go to the next segment
8659       for ( iBord = 0; iBord < 2; iBord++ ) { // loop on 2 borders
8660         if ( next[ iBord ] ) {
8661           if ( i[ iBord ] != 0 && eIt[ iBord ] != eSide[ iBord ].end())
8662             eIt[ iBord ]++;
8663           nPrev[ iBord ] = *nIt[ iBord ];
8664           nIt[ iBord ]++; i[ iBord ]++;
8665         }
8666       }
8667     }
8668     while ( nIt[0] != nSide[0].end() && nIt[1] != nSide[1].end());
8669
8670     // perform insertion of nodes into elements
8671
8672     for (insertMapIt = insertMap.begin();
8673          insertMapIt != insertMap.end();
8674          insertMapIt++ )
8675     {
8676       const SMDS_MeshElement* elem = (*insertMapIt).first;
8677       list<const SMDS_MeshNode*> & nodeList = (*insertMapIt).second;
8678       const SMDS_MeshNode* n1 = nodeList.front(); nodeList.pop_front();
8679       const SMDS_MeshNode* n2 = nodeList.front(); nodeList.pop_front();
8680
8681       InsertNodesIntoLink( elem, n1, n2, nodeList, toCreatePolygons );
8682
8683       if ( !theSideIsFreeBorder ) {
8684         // look for and insert nodes into the faces adjacent to elem
8685         while (true) {
8686           const SMDS_MeshElement* adjElem = findAdjacentFace( n1, n2, elem );
8687           if ( adjElem )
8688             InsertNodesIntoLink( adjElem, n1, n2, nodeList, toCreatePolygons );
8689           else
8690             break;
8691         }
8692       }
8693       if (toCreatePolyedrs) {
8694         // perform insertion into the links of adjacent volumes
8695         UpdateVolumes(n1, n2, nodeList);
8696       }
8697     }
8698
8699     delete param[0];
8700     delete param[1];
8701   } // end: insert new nodes
8702
8703   MergeNodes ( nodeGroupsToMerge );
8704
8705   return aResult;
8706 }
8707
8708 //=======================================================================
8709 //function : InsertNodesIntoLink
8710 //purpose  : insert theNodesToInsert into theFace between theBetweenNode1
8711 //           and theBetweenNode2 and split theElement
8712 //=======================================================================
8713
8714 void SMESH_MeshEditor::InsertNodesIntoLink(const SMDS_MeshElement*     theFace,
8715                                            const SMDS_MeshNode*        theBetweenNode1,
8716                                            const SMDS_MeshNode*        theBetweenNode2,
8717                                            list<const SMDS_MeshNode*>& theNodesToInsert,
8718                                            const bool                  toCreatePoly)
8719 {
8720   if ( theFace->GetType() != SMDSAbs_Face ) return;
8721
8722   // find indices of 2 link nodes and of the rest nodes
8723   int iNode = 0, il1, il2, i3, i4;
8724   il1 = il2 = i3 = i4 = -1;
8725   //const SMDS_MeshNode* nodes[ theFace->NbNodes() ];
8726   vector<const SMDS_MeshNode*> nodes( theFace->NbNodes() );
8727
8728   if(theFace->IsQuadratic()) {
8729     const SMDS_VtkFace* F =
8730       dynamic_cast<const SMDS_VtkFace*>(theFace);
8731     if (!F) throw SALOME_Exception(LOCALIZED("not an SMDS_VtkFace"));
8732     // use special nodes iterator
8733     SMDS_ElemIteratorPtr anIter = F->interlacedNodesElemIterator();
8734     while( anIter->more() ) {
8735       const SMDS_MeshNode* n = cast2Node(anIter->next());
8736       if ( n == theBetweenNode1 )
8737         il1 = iNode;
8738       else if ( n == theBetweenNode2 )
8739         il2 = iNode;
8740       else if ( i3 < 0 )
8741         i3 = iNode;
8742       else
8743         i4 = iNode;
8744       nodes[ iNode++ ] = n;
8745     }
8746   }
8747   else {
8748     SMDS_ElemIteratorPtr nodeIt = theFace->nodesIterator();
8749     while ( nodeIt->more() ) {
8750       const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
8751       if ( n == theBetweenNode1 )
8752         il1 = iNode;
8753       else if ( n == theBetweenNode2 )
8754         il2 = iNode;
8755       else if ( i3 < 0 )
8756         i3 = iNode;
8757       else
8758         i4 = iNode;
8759       nodes[ iNode++ ] = n;
8760     }
8761   }
8762   if ( il1 < 0 || il2 < 0 || i3 < 0 )
8763     return ;
8764
8765   // arrange link nodes to go one after another regarding the face orientation
8766   bool reverse = ( Abs( il2 - il1 ) == 1 ? il2 < il1 : il1 < il2 );
8767   list<const SMDS_MeshNode *> aNodesToInsert = theNodesToInsert;
8768   if ( reverse ) {
8769     iNode = il1;
8770     il1 = il2;
8771     il2 = iNode;
8772     aNodesToInsert.reverse();
8773   }
8774   // check that not link nodes of a quadrangles are in good order
8775   int nbFaceNodes = theFace->NbNodes();
8776   if ( nbFaceNodes == 4 && i4 - i3 != 1 ) {
8777     iNode = i3;
8778     i3 = i4;
8779     i4 = iNode;
8780   }
8781
8782   if (toCreatePoly || theFace->IsPoly()) {
8783
8784     iNode = 0;
8785     vector<const SMDS_MeshNode *> poly_nodes (nbFaceNodes + aNodesToInsert.size());
8786
8787     // add nodes of face up to first node of link
8788     bool isFLN = false;
8789
8790     if(theFace->IsQuadratic()) {
8791       const SMDS_VtkFace* F =
8792         dynamic_cast<const SMDS_VtkFace*>(theFace);
8793       if (!F) throw SALOME_Exception(LOCALIZED("not an SMDS_VtkFace"));
8794       // use special nodes iterator
8795       SMDS_ElemIteratorPtr anIter = F->interlacedNodesElemIterator();
8796       while( anIter->more()  && !isFLN ) {
8797         const SMDS_MeshNode* n = cast2Node(anIter->next());
8798         poly_nodes[iNode++] = n;
8799         if (n == nodes[il1]) {
8800           isFLN = true;
8801         }
8802       }
8803       // add nodes to insert
8804       list<const SMDS_MeshNode*>::iterator nIt = aNodesToInsert.begin();
8805       for (; nIt != aNodesToInsert.end(); nIt++) {
8806         poly_nodes[iNode++] = *nIt;
8807       }
8808       // add nodes of face starting from last node of link
8809       while ( anIter->more() ) {
8810         poly_nodes[iNode++] = cast2Node(anIter->next());
8811       }
8812     }
8813     else {
8814       SMDS_ElemIteratorPtr nodeIt = theFace->nodesIterator();
8815       while ( nodeIt->more() && !isFLN ) {
8816         const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
8817         poly_nodes[iNode++] = n;
8818         if (n == nodes[il1]) {
8819           isFLN = true;
8820         }
8821       }
8822       // add nodes to insert
8823       list<const SMDS_MeshNode*>::iterator nIt = aNodesToInsert.begin();
8824       for (; nIt != aNodesToInsert.end(); nIt++) {
8825         poly_nodes[iNode++] = *nIt;
8826       }
8827       // add nodes of face starting from last node of link
8828       while ( nodeIt->more() ) {
8829         const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
8830         poly_nodes[iNode++] = n;
8831       }
8832     }
8833
8834     // edit or replace the face
8835     SMESHDS_Mesh *aMesh = GetMeshDS();
8836
8837     if (theFace->IsPoly()) {
8838       aMesh->ChangePolygonNodes(theFace, poly_nodes);
8839     }
8840     else {
8841       int aShapeId = FindShape( theFace );
8842
8843       SMDS_MeshElement* newElem = aMesh->AddPolygonalFace(poly_nodes);
8844       myLastCreatedElems.Append(newElem);
8845       if ( aShapeId && newElem )
8846         aMesh->SetMeshElementOnShape( newElem, aShapeId );
8847
8848       aMesh->RemoveElement(theFace);
8849     }
8850     return;
8851   }
8852
8853   SMESHDS_Mesh *aMesh = GetMeshDS();
8854   if( !theFace->IsQuadratic() ) {
8855
8856     // put aNodesToInsert between theBetweenNode1 and theBetweenNode2
8857     int nbLinkNodes = 2 + aNodesToInsert.size();
8858     //const SMDS_MeshNode* linkNodes[ nbLinkNodes ];
8859     vector<const SMDS_MeshNode*> linkNodes( nbLinkNodes );
8860     linkNodes[ 0 ] = nodes[ il1 ];
8861     linkNodes[ nbLinkNodes - 1 ] = nodes[ il2 ];
8862     list<const SMDS_MeshNode*>::iterator nIt = aNodesToInsert.begin();
8863     for ( iNode = 1; nIt != aNodesToInsert.end(); nIt++ ) {
8864       linkNodes[ iNode++ ] = *nIt;
8865     }
8866     // decide how to split a quadrangle: compare possible variants
8867     // and choose which of splits to be a quadrangle
8868     int i1, i2, iSplit, nbSplits = nbLinkNodes - 1, iBestQuad;
8869     if ( nbFaceNodes == 3 ) {
8870       iBestQuad = nbSplits;
8871       i4 = i3;
8872     }
8873     else if ( nbFaceNodes == 4 ) {
8874       SMESH::Controls::NumericalFunctorPtr aCrit( new SMESH::Controls::AspectRatio);
8875       double aBestRate = DBL_MAX;
8876       for ( int iQuad = 0; iQuad < nbSplits; iQuad++ ) {
8877         i1 = 0; i2 = 1;
8878         double aBadRate = 0;
8879         // evaluate elements quality
8880         for ( iSplit = 0; iSplit < nbSplits; iSplit++ ) {
8881           if ( iSplit == iQuad ) {
8882             SMDS_FaceOfNodes quad (linkNodes[ i1++ ],
8883                                    linkNodes[ i2++ ],
8884                                    nodes[ i3 ],
8885                                    nodes[ i4 ]);
8886             aBadRate += getBadRate( &quad, aCrit );
8887           }
8888           else {
8889             SMDS_FaceOfNodes tria (linkNodes[ i1++ ],
8890                                    linkNodes[ i2++ ],
8891                                    nodes[ iSplit < iQuad ? i4 : i3 ]);
8892             aBadRate += getBadRate( &tria, aCrit );
8893           }
8894         }
8895         // choice
8896         if ( aBadRate < aBestRate ) {
8897           iBestQuad = iQuad;
8898           aBestRate = aBadRate;
8899         }
8900       }
8901     }
8902
8903     // create new elements
8904     int aShapeId = FindShape( theFace );
8905
8906     i1 = 0; i2 = 1;
8907     for ( iSplit = 0; iSplit < nbSplits - 1; iSplit++ ) {
8908       SMDS_MeshElement* newElem = 0;
8909       if ( iSplit == iBestQuad )
8910         newElem = aMesh->AddFace (linkNodes[ i1++ ],
8911                                   linkNodes[ i2++ ],
8912                                   nodes[ i3 ],
8913                                   nodes[ i4 ]);
8914       else
8915         newElem = aMesh->AddFace (linkNodes[ i1++ ],
8916                                   linkNodes[ i2++ ],
8917                                   nodes[ iSplit < iBestQuad ? i4 : i3 ]);
8918       myLastCreatedElems.Append(newElem);
8919       if ( aShapeId && newElem )
8920         aMesh->SetMeshElementOnShape( newElem, aShapeId );
8921     }
8922
8923     // change nodes of theFace
8924     const SMDS_MeshNode* newNodes[ 4 ];
8925     newNodes[ 0 ] = linkNodes[ i1 ];
8926     newNodes[ 1 ] = linkNodes[ i2 ];
8927     newNodes[ 2 ] = nodes[ iSplit >= iBestQuad ? i3 : i4 ];
8928     newNodes[ 3 ] = nodes[ i4 ];
8929     //aMesh->ChangeElementNodes( theFace, newNodes, iSplit == iBestQuad ? 4 : 3 );
8930     const SMDS_MeshElement* newElem = 0;
8931     if (iSplit == iBestQuad)
8932       newElem = aMesh->AddFace( newNodes[0], newNodes[1], newNodes[2], newNodes[3] );
8933     else
8934       newElem = aMesh->AddFace( newNodes[0], newNodes[1], newNodes[2] );
8935     myLastCreatedElems.Append(newElem);
8936     if ( aShapeId && newElem )
8937       aMesh->SetMeshElementOnShape( newElem, aShapeId );
8938 } // end if(!theFace->IsQuadratic())
8939   else { // theFace is quadratic
8940     // we have to split theFace on simple triangles and one simple quadrangle
8941     int tmp = il1/2;
8942     int nbshift = tmp*2;
8943     // shift nodes in nodes[] by nbshift
8944     int i,j;
8945     for(i=0; i<nbshift; i++) {
8946       const SMDS_MeshNode* n = nodes[0];
8947       for(j=0; j<nbFaceNodes-1; j++) {
8948         nodes[j] = nodes[j+1];
8949       }
8950       nodes[nbFaceNodes-1] = n;
8951     }
8952     il1 = il1 - nbshift;
8953     // now have to insert nodes between n0 and n1 or n1 and n2 (see below)
8954     //   n0      n1     n2    n0      n1     n2
8955     //     +-----+-----+        +-----+-----+
8956     //      \         /         |           |
8957     //       \       /          |           |
8958     //      n5+     +n3       n7+           +n3
8959     //         \   /            |           |
8960     //          \ /             |           |
8961     //           +              +-----+-----+
8962     //           n4           n6      n5     n4
8963
8964     // create new elements
8965     int aShapeId = FindShape( theFace );
8966
8967     int n1,n2,n3;
8968     if(nbFaceNodes==6) { // quadratic triangle
8969       SMDS_MeshElement* newElem =
8970         aMesh->AddFace(nodes[3],nodes[4],nodes[5]);
8971       myLastCreatedElems.Append(newElem);
8972       if ( aShapeId && newElem )
8973         aMesh->SetMeshElementOnShape( newElem, aShapeId );
8974       if(theFace->IsMediumNode(nodes[il1])) {
8975         // create quadrangle
8976         newElem = aMesh->AddFace(nodes[0],nodes[1],nodes[3],nodes[5]);
8977         myLastCreatedElems.Append(newElem);
8978         if ( aShapeId && newElem )
8979           aMesh->SetMeshElementOnShape( newElem, aShapeId );
8980         n1 = 1;
8981         n2 = 2;
8982         n3 = 3;
8983       }
8984       else {
8985         // create quadrangle
8986         newElem = aMesh->AddFace(nodes[1],nodes[2],nodes[3],nodes[5]);
8987         myLastCreatedElems.Append(newElem);
8988         if ( aShapeId && newElem )
8989           aMesh->SetMeshElementOnShape( newElem, aShapeId );
8990         n1 = 0;
8991         n2 = 1;
8992         n3 = 5;
8993       }
8994     }
8995     else { // nbFaceNodes==8 - quadratic quadrangle
8996       SMDS_MeshElement* newElem =
8997         aMesh->AddFace(nodes[3],nodes[4],nodes[5]);
8998       myLastCreatedElems.Append(newElem);
8999       if ( aShapeId && newElem )
9000         aMesh->SetMeshElementOnShape( newElem, aShapeId );
9001       newElem = aMesh->AddFace(nodes[5],nodes[6],nodes[7]);
9002       myLastCreatedElems.Append(newElem);
9003       if ( aShapeId && newElem )
9004         aMesh->SetMeshElementOnShape( newElem, aShapeId );
9005       newElem = aMesh->AddFace(nodes[5],nodes[7],nodes[3]);
9006       myLastCreatedElems.Append(newElem);
9007       if ( aShapeId && newElem )
9008         aMesh->SetMeshElementOnShape( newElem, aShapeId );
9009       if(theFace->IsMediumNode(nodes[il1])) {
9010         // create quadrangle
9011         newElem = aMesh->AddFace(nodes[0],nodes[1],nodes[3],nodes[7]);
9012         myLastCreatedElems.Append(newElem);
9013         if ( aShapeId && newElem )
9014           aMesh->SetMeshElementOnShape( newElem, aShapeId );
9015         n1 = 1;
9016         n2 = 2;
9017         n3 = 3;
9018       }
9019       else {
9020         // create quadrangle
9021         newElem = aMesh->AddFace(nodes[1],nodes[2],nodes[3],nodes[7]);
9022         myLastCreatedElems.Append(newElem);
9023         if ( aShapeId && newElem )
9024           aMesh->SetMeshElementOnShape( newElem, aShapeId );
9025         n1 = 0;
9026         n2 = 1;
9027         n3 = 7;
9028       }
9029     }
9030     // create needed triangles using n1,n2,n3 and inserted nodes
9031     int nbn = 2 + aNodesToInsert.size();
9032     //const SMDS_MeshNode* aNodes[nbn];
9033     vector<const SMDS_MeshNode*> aNodes(nbn);
9034     aNodes[0] = nodes[n1];
9035     aNodes[nbn-1] = nodes[n2];
9036     list<const SMDS_MeshNode*>::iterator nIt = aNodesToInsert.begin();
9037     for ( iNode = 1; nIt != aNodesToInsert.end(); nIt++ ) {
9038       aNodes[iNode++] = *nIt;
9039     }
9040     for(i=1; i<nbn; i++) {
9041       SMDS_MeshElement* newElem =
9042         aMesh->AddFace(aNodes[i-1],aNodes[i],nodes[n3]);
9043       myLastCreatedElems.Append(newElem);
9044       if ( aShapeId && newElem )
9045         aMesh->SetMeshElementOnShape( newElem, aShapeId );
9046     }
9047   }
9048   // remove old face
9049   aMesh->RemoveElement(theFace);
9050 }
9051
9052 //=======================================================================
9053 //function : UpdateVolumes
9054 //purpose  :
9055 //=======================================================================
9056 void SMESH_MeshEditor::UpdateVolumes (const SMDS_MeshNode*        theBetweenNode1,
9057                                       const SMDS_MeshNode*        theBetweenNode2,
9058                                       list<const SMDS_MeshNode*>& theNodesToInsert)
9059 {
9060   myLastCreatedElems.Clear();
9061   myLastCreatedNodes.Clear();
9062
9063   SMDS_ElemIteratorPtr invElemIt = theBetweenNode1->GetInverseElementIterator(SMDSAbs_Volume);
9064   while (invElemIt->more()) { // loop on inverse elements of theBetweenNode1
9065     const SMDS_MeshElement* elem = invElemIt->next();
9066
9067     // check, if current volume has link theBetweenNode1 - theBetweenNode2
9068     SMDS_VolumeTool aVolume (elem);
9069     if (!aVolume.IsLinked(theBetweenNode1, theBetweenNode2))
9070       continue;
9071
9072     // insert new nodes in all faces of the volume, sharing link theBetweenNode1 - theBetweenNode2
9073     int iface, nbFaces = aVolume.NbFaces();
9074     vector<const SMDS_MeshNode *> poly_nodes;
9075     vector<int> quantities (nbFaces);
9076
9077     for (iface = 0; iface < nbFaces; iface++) {
9078       int nbFaceNodes = aVolume.NbFaceNodes(iface), nbInserted = 0;
9079       // faceNodes will contain (nbFaceNodes + 1) nodes, last = first
9080       const SMDS_MeshNode** faceNodes = aVolume.GetFaceNodes(iface);
9081
9082       for (int inode = 0; inode < nbFaceNodes; inode++) {
9083         poly_nodes.push_back(faceNodes[inode]);
9084
9085         if (nbInserted == 0) {
9086           if (faceNodes[inode] == theBetweenNode1) {
9087             if (faceNodes[inode + 1] == theBetweenNode2) {
9088               nbInserted = theNodesToInsert.size();
9089
9090               // add nodes to insert
9091               list<const SMDS_MeshNode*>::iterator nIt = theNodesToInsert.begin();
9092               for (; nIt != theNodesToInsert.end(); nIt++) {
9093                 poly_nodes.push_back(*nIt);
9094               }
9095             }
9096           }
9097           else if (faceNodes[inode] == theBetweenNode2) {
9098             if (faceNodes[inode + 1] == theBetweenNode1) {
9099               nbInserted = theNodesToInsert.size();
9100
9101               // add nodes to insert in reversed order
9102               list<const SMDS_MeshNode*>::iterator nIt = theNodesToInsert.end();
9103               nIt--;
9104               for (; nIt != theNodesToInsert.begin(); nIt--) {
9105                 poly_nodes.push_back(*nIt);
9106               }
9107               poly_nodes.push_back(*nIt);
9108             }
9109           }
9110           else {
9111           }
9112         }
9113       }
9114       quantities[iface] = nbFaceNodes + nbInserted;
9115     }
9116
9117     // Replace or update the volume
9118     SMESHDS_Mesh *aMesh = GetMeshDS();
9119
9120     if (elem->IsPoly()) {
9121       aMesh->ChangePolyhedronNodes(elem, poly_nodes, quantities);
9122
9123     }
9124     else {
9125       int aShapeId = FindShape( elem );
9126
9127       SMDS_MeshElement* newElem =
9128         aMesh->AddPolyhedralVolume(poly_nodes, quantities);
9129       myLastCreatedElems.Append(newElem);
9130       if (aShapeId && newElem)
9131         aMesh->SetMeshElementOnShape(newElem, aShapeId);
9132
9133       aMesh->RemoveElement(elem);
9134     }
9135   }
9136 }
9137
9138 //=======================================================================
9139 /*!
9140  * \brief Convert elements contained in a submesh to quadratic
9141  * \retval int - nb of checked elements
9142  */
9143 //=======================================================================
9144
9145 int SMESH_MeshEditor::convertElemToQuadratic(SMESHDS_SubMesh *   theSm,
9146                                              SMESH_MesherHelper& theHelper,
9147                                              const bool          theForce3d)
9148 {
9149   int nbElem = 0;
9150   if( !theSm ) return nbElem;
9151
9152   vector<int> nbNodeInFaces;
9153   SMDS_ElemIteratorPtr ElemItr = theSm->GetElements();
9154   while(ElemItr->more())
9155   {
9156     nbElem++;
9157     const SMDS_MeshElement* elem = ElemItr->next();
9158     if( !elem || elem->IsQuadratic() ) continue;
9159
9160     int id = elem->GetID();
9161     //MESSAGE("elem " << id);
9162     id = 0; // get a free number for new elements
9163     int nbNodes = elem->NbNodes();
9164     SMDSAbs_ElementType aType = elem->GetType();
9165
9166     vector<const SMDS_MeshNode *> nodes (elem->begin_nodes(), elem->end_nodes());
9167     if ( elem->GetEntityType() == SMDSEntity_Polyhedra )
9168       nbNodeInFaces = static_cast<const SMDS_VtkVolume* >( elem )->GetQuantities();
9169
9170     const SMDS_MeshElement* NewElem = 0;
9171
9172     switch( aType )
9173     {
9174     case SMDSAbs_Edge :
9175       {
9176         NewElem = theHelper.AddEdge(nodes[0], nodes[1], id, theForce3d);
9177         break;
9178       }
9179     case SMDSAbs_Face :
9180       {
9181         switch(nbNodes)
9182         {
9183         case 3:
9184           NewElem = theHelper.AddFace(nodes[0], nodes[1], nodes[2], id, theForce3d);
9185           break;
9186         case 4:
9187           NewElem = theHelper.AddFace(nodes[0], nodes[1], nodes[2], nodes[3], id, theForce3d);
9188           break;
9189         default:
9190           NewElem = theHelper.AddPolygonalFace(nodes, id, theForce3d);
9191           continue;
9192         }
9193         break;
9194       }
9195     case SMDSAbs_Volume :
9196       {
9197         switch(nbNodes)
9198         {
9199         case 4:
9200           NewElem = theHelper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3], id, theForce3d);
9201           break;
9202         case 5:
9203           NewElem = theHelper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3], nodes[4], id, theForce3d);
9204           break;
9205         case 6:
9206           NewElem = theHelper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3], nodes[4], nodes[5], id, theForce3d);
9207           break;
9208         case 8:
9209           NewElem = theHelper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3],
9210                                         nodes[4], nodes[5], nodes[6], nodes[7], id, theForce3d);
9211           break;
9212         default:
9213           NewElem = theHelper.AddPolyhedralVolume(nodes, nbNodeInFaces, id, theForce3d);
9214         }
9215         break;
9216       }
9217     default :
9218       continue;
9219     }
9220     ReplaceElemInGroups( elem, NewElem, GetMeshDS());
9221     if( NewElem )
9222       theSm->AddElement( NewElem );
9223
9224     GetMeshDS()->RemoveFreeElement(elem, theSm, /*fromGroups=*/false);
9225   }
9226 //  if (!GetMeshDS()->isCompacted())
9227 //    GetMeshDS()->compactMesh();
9228   return nbElem;
9229 }
9230
9231 //=======================================================================
9232 //function : ConvertToQuadratic
9233 //purpose  :
9234 //=======================================================================
9235 void SMESH_MeshEditor::ConvertToQuadratic(const bool theForce3d)
9236 {
9237   SMESHDS_Mesh* meshDS = GetMeshDS();
9238
9239   SMESH_MesherHelper aHelper(*myMesh);
9240   aHelper.SetIsQuadratic( true );
9241
9242   int nbCheckedElems = 0;
9243   if ( myMesh->HasShapeToMesh() )
9244   {
9245     if ( SMESH_subMesh *aSubMesh = myMesh->GetSubMeshContaining(myMesh->GetShapeToMesh()))
9246     {
9247       SMESH_subMeshIteratorPtr smIt = aSubMesh->getDependsOnIterator(true,false);
9248       while ( smIt->more() ) {
9249         SMESH_subMesh* sm = smIt->next();
9250         if ( SMESHDS_SubMesh *smDS = sm->GetSubMeshDS() ) {
9251           aHelper.SetSubShape( sm->GetSubShape() );
9252           nbCheckedElems += convertElemToQuadratic(smDS, aHelper, theForce3d);
9253         }
9254       }
9255     }
9256   }
9257   int totalNbElems = meshDS->NbEdges() + meshDS->NbFaces() + meshDS->NbVolumes();
9258   if ( nbCheckedElems < totalNbElems ) // not all elements are in submeshes
9259   {
9260     SMESHDS_SubMesh *smDS = 0;
9261     SMDS_EdgeIteratorPtr aEdgeItr = meshDS->edgesIterator();
9262     while(aEdgeItr->more())
9263     {
9264       const SMDS_MeshEdge* edge = aEdgeItr->next();
9265       if(edge && !edge->IsQuadratic())
9266       {
9267         int id = edge->GetID();
9268         //MESSAGE("edge->GetID() " << id);
9269         const SMDS_MeshNode* n1 = edge->GetNode(0);
9270         const SMDS_MeshNode* n2 = edge->GetNode(1);
9271
9272         meshDS->RemoveFreeElement(edge, smDS, /*fromGroups=*/false);
9273
9274         const SMDS_MeshEdge* NewEdge = aHelper.AddEdge(n1, n2, id, theForce3d);
9275         ReplaceElemInGroups( edge, NewEdge, GetMeshDS());
9276       }
9277     }
9278     SMDS_FaceIteratorPtr aFaceItr = meshDS->facesIterator();
9279     while(aFaceItr->more())
9280     {
9281       const SMDS_MeshFace* face = aFaceItr->next();
9282       if(!face || face->IsQuadratic() ) continue;
9283
9284       int id = face->GetID();
9285       int nbNodes = face->NbNodes();
9286       vector<const SMDS_MeshNode *> nodes ( face->begin_nodes(), face->end_nodes());
9287
9288       meshDS->RemoveFreeElement(face, smDS, /*fromGroups=*/false);
9289
9290       SMDS_MeshFace * NewFace = 0;
9291       switch(nbNodes)
9292       {
9293       case 3:
9294         NewFace = aHelper.AddFace(nodes[0], nodes[1], nodes[2], id, theForce3d);
9295         break;
9296       case 4:
9297         NewFace = aHelper.AddFace(nodes[0], nodes[1], nodes[2], nodes[3], id, theForce3d);
9298         break;
9299       default:
9300         NewFace = aHelper.AddPolygonalFace(nodes, id, theForce3d);
9301       }
9302       ReplaceElemInGroups( face, NewFace, GetMeshDS());
9303     }
9304     vector<int> nbNodeInFaces;
9305     SMDS_VolumeIteratorPtr aVolumeItr = meshDS->volumesIterator();
9306     while(aVolumeItr->more())
9307     {
9308       const SMDS_MeshVolume* volume = aVolumeItr->next();
9309       if(!volume || volume->IsQuadratic() ) continue;
9310
9311       int id = volume->GetID();
9312       int nbNodes = volume->NbNodes();
9313       vector<const SMDS_MeshNode *> nodes (volume->begin_nodes(), volume->end_nodes());
9314       if ( volume->GetEntityType() == SMDSEntity_Polyhedra )
9315         nbNodeInFaces = static_cast<const SMDS_VtkVolume* >(volume)->GetQuantities();
9316
9317       meshDS->RemoveFreeElement(volume, smDS, /*fromGroups=*/false);
9318
9319       SMDS_MeshVolume * NewVolume = 0;
9320       switch(nbNodes)
9321       {
9322       case 4:
9323         NewVolume = aHelper.AddVolume(nodes[0], nodes[1], nodes[2],
9324                                       nodes[3], id, theForce3d );
9325         break;
9326       case 5:
9327         NewVolume = aHelper.AddVolume(nodes[0], nodes[1], nodes[2],
9328                                       nodes[3], nodes[4], id, theForce3d);
9329         break;
9330       case 6:
9331         NewVolume = aHelper.AddVolume(nodes[0], nodes[1], nodes[2],
9332                                       nodes[3], nodes[4], nodes[5], id, theForce3d);
9333         break;
9334       case 8:
9335         NewVolume = aHelper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3],
9336                                       nodes[4], nodes[5], nodes[6], nodes[7], id, theForce3d);
9337         break;
9338       default:
9339         NewVolume = aHelper.AddPolyhedralVolume(nodes, nbNodeInFaces, id, theForce3d);
9340       }
9341       ReplaceElemInGroups(volume, NewVolume, meshDS);
9342     }
9343   }
9344
9345   if ( !theForce3d  && !getenv("NO_FixQuadraticElements"))
9346   { // setenv NO_FixQuadraticElements to know if FixQuadraticElements() is guilty of bad conversion
9347     aHelper.SetSubShape(0); // apply FixQuadraticElements() to the whole mesh
9348     aHelper.FixQuadraticElements();
9349   }
9350   if (!GetMeshDS()->isCompacted())
9351     GetMeshDS()->compactMesh();
9352 }
9353
9354 //=======================================================================
9355 /*!
9356  * \brief Convert quadratic elements to linear ones and remove quadratic nodes
9357  * \retval int - nb of checked elements
9358  */
9359 //=======================================================================
9360
9361 int SMESH_MeshEditor::removeQuadElem(SMESHDS_SubMesh *    theSm,
9362                                      SMDS_ElemIteratorPtr theItr,
9363                                      const int            theShapeID)
9364 {
9365   int nbElem = 0;
9366   SMESHDS_Mesh* meshDS = GetMeshDS();
9367   const bool notFromGroups = false;
9368
9369   while( theItr->more() )
9370   {
9371     const SMDS_MeshElement* elem = theItr->next();
9372     nbElem++;
9373     if( elem && elem->IsQuadratic())
9374     {
9375       int id = elem->GetID();
9376       int nbNodes = elem->NbNodes();
9377       vector<const SMDS_MeshNode *> nodes, mediumNodes;
9378       nodes.reserve( nbNodes );
9379       mediumNodes.reserve( nbNodes );
9380
9381       for(int i = 0; i < nbNodes; i++)
9382       {
9383         const SMDS_MeshNode* n = elem->GetNode(i);
9384
9385         if( elem->IsMediumNode( n ) )
9386           mediumNodes.push_back( n );
9387         else
9388           nodes.push_back( n );
9389       }
9390       if( nodes.empty() ) continue;
9391       SMDSAbs_ElementType aType = elem->GetType();
9392
9393       //remove old quadratic element
9394       meshDS->RemoveFreeElement( elem, theSm, notFromGroups );
9395
9396       SMDS_MeshElement * NewElem = AddElement( nodes, aType, false, id );
9397       ReplaceElemInGroups(elem, NewElem, meshDS);
9398       if( theSm && NewElem )
9399         theSm->AddElement( NewElem );
9400
9401       // remove medium nodes
9402       vector<const SMDS_MeshNode*>::iterator nIt = mediumNodes.begin();
9403       for ( ; nIt != mediumNodes.end(); ++nIt ) {
9404         const SMDS_MeshNode* n = *nIt;
9405         if ( n->NbInverseElements() == 0 ) {
9406           if ( n->getshapeId() != theShapeID )
9407             meshDS->RemoveFreeNode( n, meshDS->MeshElements
9408                                     ( n->getshapeId() ));
9409           else
9410             meshDS->RemoveFreeNode( n, theSm );
9411         }
9412       }
9413     }
9414   }
9415   return nbElem;
9416 }
9417
9418 //=======================================================================
9419 //function : ConvertFromQuadratic
9420 //purpose  :
9421 //=======================================================================
9422 bool  SMESH_MeshEditor::ConvertFromQuadratic()
9423 {
9424   int nbCheckedElems = 0;
9425   if ( myMesh->HasShapeToMesh() )
9426   {
9427     if ( SMESH_subMesh *aSubMesh = myMesh->GetSubMeshContaining(myMesh->GetShapeToMesh()))
9428     {
9429       SMESH_subMeshIteratorPtr smIt = aSubMesh->getDependsOnIterator(true,false);
9430       while ( smIt->more() ) {
9431         SMESH_subMesh* sm = smIt->next();
9432         if ( SMESHDS_SubMesh *smDS = sm->GetSubMeshDS() )
9433           nbCheckedElems += removeQuadElem( smDS, smDS->GetElements(), sm->GetId() );
9434       }
9435     }
9436   }
9437
9438   int totalNbElems =
9439     GetMeshDS()->NbEdges() + GetMeshDS()->NbFaces() + GetMeshDS()->NbVolumes();
9440   if ( nbCheckedElems < totalNbElems ) // not all elements are in submeshes
9441   {
9442     SMESHDS_SubMesh *aSM = 0;
9443     removeQuadElem( aSM, GetMeshDS()->elementsIterator(), 0 );
9444   }
9445
9446   return true;
9447 }
9448
9449 //=======================================================================
9450 //function : SewSideElements
9451 //purpose  :
9452 //=======================================================================
9453
9454 SMESH_MeshEditor::Sew_Error
9455 SMESH_MeshEditor::SewSideElements (TIDSortedElemSet&    theSide1,
9456                                    TIDSortedElemSet&    theSide2,
9457                                    const SMDS_MeshNode* theFirstNode1,
9458                                    const SMDS_MeshNode* theFirstNode2,
9459                                    const SMDS_MeshNode* theSecondNode1,
9460                                    const SMDS_MeshNode* theSecondNode2)
9461 {
9462   myLastCreatedElems.Clear();
9463   myLastCreatedNodes.Clear();
9464
9465   MESSAGE ("::::SewSideElements()");
9466   if ( theSide1.size() != theSide2.size() )
9467     return SEW_DIFF_NB_OF_ELEMENTS;
9468
9469   Sew_Error aResult = SEW_OK;
9470   // Algo:
9471   // 1. Build set of faces representing each side
9472   // 2. Find which nodes of the side 1 to merge with ones on the side 2
9473   // 3. Replace nodes in elements of the side 1 and remove replaced nodes
9474
9475   // =======================================================================
9476   // 1. Build set of faces representing each side:
9477   // =======================================================================
9478   // a. build set of nodes belonging to faces
9479   // b. complete set of faces: find missing faces whose nodes are in set of nodes
9480   // c. create temporary faces representing side of volumes if correspondent
9481   //    face does not exist
9482
9483   SMESHDS_Mesh* aMesh = GetMeshDS();
9484   // TODO algoritm not OK with vtkUnstructuredGrid: 2 meshes can't share nodes
9485   //SMDS_Mesh aTmpFacesMesh; // try to use the same mesh
9486   set<const SMDS_MeshElement*> faceSet1, faceSet2;
9487   set<const SMDS_MeshElement*> volSet1,  volSet2;
9488   set<const SMDS_MeshNode*>    nodeSet1, nodeSet2;
9489   set<const SMDS_MeshElement*> * faceSetPtr[] = { &faceSet1, &faceSet2 };
9490   set<const SMDS_MeshElement*>  * volSetPtr[] = { &volSet1,  &volSet2  };
9491   set<const SMDS_MeshNode*>    * nodeSetPtr[] = { &nodeSet1, &nodeSet2 };
9492   TIDSortedElemSet * elemSetPtr[] = { &theSide1, &theSide2 };
9493   int iSide, iFace, iNode;
9494
9495   list<const SMDS_MeshElement* > tempFaceList;
9496   for ( iSide = 0; iSide < 2; iSide++ ) {
9497     set<const SMDS_MeshNode*>    * nodeSet = nodeSetPtr[ iSide ];
9498     TIDSortedElemSet * elemSet = elemSetPtr[ iSide ];
9499     set<const SMDS_MeshElement*> * faceSet = faceSetPtr[ iSide ];
9500     set<const SMDS_MeshElement*> * volSet  = volSetPtr [ iSide ];
9501     set<const SMDS_MeshElement*>::iterator vIt;
9502     TIDSortedElemSet::iterator eIt;
9503     set<const SMDS_MeshNode*>::iterator    nIt;
9504
9505     // check that given nodes belong to given elements
9506     const SMDS_MeshNode* n1 = ( iSide == 0 ) ? theFirstNode1 : theFirstNode2;
9507     const SMDS_MeshNode* n2 = ( iSide == 0 ) ? theSecondNode1 : theSecondNode2;
9508     int firstIndex = -1, secondIndex = -1;
9509     for (eIt = elemSet->begin(); eIt != elemSet->end(); eIt++ ) {
9510       const SMDS_MeshElement* elem = *eIt;
9511       if ( firstIndex  < 0 ) firstIndex  = elem->GetNodeIndex( n1 );
9512       if ( secondIndex < 0 ) secondIndex = elem->GetNodeIndex( n2 );
9513       if ( firstIndex > -1 && secondIndex > -1 ) break;
9514     }
9515     if ( firstIndex < 0 || secondIndex < 0 ) {
9516       // we can simply return until temporary faces created
9517       return (iSide == 0 ) ? SEW_BAD_SIDE1_NODES : SEW_BAD_SIDE2_NODES;
9518     }
9519
9520     // -----------------------------------------------------------
9521     // 1a. Collect nodes of existing faces
9522     //     and build set of face nodes in order to detect missing
9523     //     faces corresponding to sides of volumes
9524     // -----------------------------------------------------------
9525
9526     set< set <const SMDS_MeshNode*> > setOfFaceNodeSet;
9527
9528     // loop on the given element of a side
9529     for (eIt = elemSet->begin(); eIt != elemSet->end(); eIt++ ) {
9530       //const SMDS_MeshElement* elem = *eIt;
9531       const SMDS_MeshElement* elem = *eIt;
9532       if ( elem->GetType() == SMDSAbs_Face ) {
9533         faceSet->insert( elem );
9534         set <const SMDS_MeshNode*> faceNodeSet;
9535         SMDS_ElemIteratorPtr nodeIt = elem->nodesIterator();
9536         while ( nodeIt->more() ) {
9537           const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
9538           nodeSet->insert( n );
9539           faceNodeSet.insert( n );
9540         }
9541         setOfFaceNodeSet.insert( faceNodeSet );
9542       }
9543       else if ( elem->GetType() == SMDSAbs_Volume )
9544         volSet->insert( elem );
9545     }
9546     // ------------------------------------------------------------------------------
9547     // 1b. Complete set of faces: find missing faces whose nodes are in set of nodes
9548     // ------------------------------------------------------------------------------
9549
9550     for ( nIt = nodeSet->begin(); nIt != nodeSet->end(); nIt++ ) { // loop on nodes of iSide
9551       SMDS_ElemIteratorPtr fIt = (*nIt)->GetInverseElementIterator(SMDSAbs_Face);
9552       while ( fIt->more() ) { // loop on faces sharing a node
9553         const SMDS_MeshElement* f = fIt->next();
9554         if ( faceSet->find( f ) == faceSet->end() ) {
9555           // check if all nodes are in nodeSet and
9556           // complete setOfFaceNodeSet if they are
9557           set <const SMDS_MeshNode*> faceNodeSet;
9558           SMDS_ElemIteratorPtr nodeIt = f->nodesIterator();
9559           bool allInSet = true;
9560           while ( nodeIt->more() && allInSet ) { // loop on nodes of a face
9561             const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
9562             if ( nodeSet->find( n ) == nodeSet->end() )
9563               allInSet = false;
9564             else
9565               faceNodeSet.insert( n );
9566           }
9567           if ( allInSet ) {
9568             faceSet->insert( f );
9569             setOfFaceNodeSet.insert( faceNodeSet );
9570           }
9571         }
9572       }
9573     }
9574
9575     // -------------------------------------------------------------------------
9576     // 1c. Create temporary faces representing sides of volumes if correspondent
9577     //     face does not exist
9578     // -------------------------------------------------------------------------
9579
9580     if ( !volSet->empty() ) {
9581       //int nodeSetSize = nodeSet->size();
9582
9583       // loop on given volumes
9584       for ( vIt = volSet->begin(); vIt != volSet->end(); vIt++ ) {
9585         SMDS_VolumeTool vol (*vIt);
9586         // loop on volume faces: find free faces
9587         // --------------------------------------
9588         list<const SMDS_MeshElement* > freeFaceList;
9589         for ( iFace = 0; iFace < vol.NbFaces(); iFace++ ) {
9590           if ( !vol.IsFreeFace( iFace ))
9591             continue;
9592           // check if there is already a face with same nodes in a face set
9593           const SMDS_MeshElement* aFreeFace = 0;
9594           const SMDS_MeshNode** fNodes = vol.GetFaceNodes( iFace );
9595           int nbNodes = vol.NbFaceNodes( iFace );
9596           set <const SMDS_MeshNode*> faceNodeSet;
9597           vol.GetFaceNodes( iFace, faceNodeSet );
9598           bool isNewFace = setOfFaceNodeSet.insert( faceNodeSet ).second;
9599           if ( isNewFace ) {
9600             // no such a face is given but it still can exist, check it
9601             if ( nbNodes == 3 ) {
9602               aFreeFace = aMesh->FindFace( fNodes[0],fNodes[1],fNodes[2] );
9603             }
9604             else if ( nbNodes == 4 ) {
9605               aFreeFace = aMesh->FindFace( fNodes[0],fNodes[1],fNodes[2],fNodes[3] );
9606             }
9607             else {
9608               vector<const SMDS_MeshNode *> poly_nodes ( fNodes, & fNodes[nbNodes]);
9609               aFreeFace = aMesh->FindFace(poly_nodes);
9610             }
9611           }
9612           if ( !aFreeFace ) {
9613             // create a temporary face
9614             if ( nbNodes == 3 ) {
9615               //aFreeFace = aTmpFacesMesh.AddFace( fNodes[0],fNodes[1],fNodes[2] );
9616               aFreeFace = aMesh->AddFace( fNodes[0],fNodes[1],fNodes[2] );
9617             }
9618             else if ( nbNodes == 4 ) {
9619               //aFreeFace = aTmpFacesMesh.AddFace( fNodes[0],fNodes[1],fNodes[2],fNodes[3] );
9620               aFreeFace = aMesh->AddFace( fNodes[0],fNodes[1],fNodes[2],fNodes[3] );
9621             }
9622             else {
9623               vector<const SMDS_MeshNode *> poly_nodes ( fNodes, & fNodes[nbNodes]);
9624               //aFreeFace = aTmpFacesMesh.AddPolygonalFace(poly_nodes);
9625               aFreeFace = aMesh->AddPolygonalFace(poly_nodes);
9626             }
9627           }
9628           if ( aFreeFace ) {
9629             freeFaceList.push_back( aFreeFace );
9630             tempFaceList.push_back( aFreeFace );
9631           }
9632
9633         } // loop on faces of a volume
9634
9635         // choose one of several free faces
9636         // --------------------------------------
9637         if ( freeFaceList.size() > 1 ) {
9638           // choose a face having max nb of nodes shared by other elems of a side
9639           int maxNbNodes = -1/*, nbExcludedFaces = 0*/;
9640           list<const SMDS_MeshElement* >::iterator fIt = freeFaceList.begin();
9641           while ( fIt != freeFaceList.end() ) { // loop on free faces
9642             int nbSharedNodes = 0;
9643             SMDS_ElemIteratorPtr nodeIt = (*fIt)->nodesIterator();
9644             while ( nodeIt->more() ) { // loop on free face nodes
9645               const SMDS_MeshNode* n =
9646                 static_cast<const SMDS_MeshNode*>( nodeIt->next() );
9647               SMDS_ElemIteratorPtr invElemIt = n->GetInverseElementIterator();
9648               while ( invElemIt->more() ) {
9649                 const SMDS_MeshElement* e = invElemIt->next();
9650                 if ( faceSet->find( e ) != faceSet->end() )
9651                   nbSharedNodes++;
9652                 if ( elemSet->find( e ) != elemSet->end() )
9653                   nbSharedNodes++;
9654               }
9655             }
9656             if ( nbSharedNodes >= maxNbNodes ) {
9657               maxNbNodes = nbSharedNodes;
9658               fIt++;
9659             }
9660             else
9661               freeFaceList.erase( fIt++ ); // here fIt++ occurs before erase
9662           }
9663           if ( freeFaceList.size() > 1 )
9664           {
9665             // could not choose one face, use another way
9666             // choose a face most close to the bary center of the opposite side
9667             gp_XYZ aBC( 0., 0., 0. );
9668             set <const SMDS_MeshNode*> addedNodes;
9669             TIDSortedElemSet * elemSet2 = elemSetPtr[ 1 - iSide ];
9670             eIt = elemSet2->begin();
9671             for ( eIt = elemSet2->begin(); eIt != elemSet2->end(); eIt++ ) {
9672               SMDS_ElemIteratorPtr nodeIt = (*eIt)->nodesIterator();
9673               while ( nodeIt->more() ) { // loop on free face nodes
9674                 const SMDS_MeshNode* n =
9675                   static_cast<const SMDS_MeshNode*>( nodeIt->next() );
9676                 if ( addedNodes.insert( n ).second )
9677                   aBC += gp_XYZ( n->X(),n->Y(),n->Z() );
9678               }
9679             }
9680             aBC /= addedNodes.size();
9681             double minDist = DBL_MAX;
9682             fIt = freeFaceList.begin();
9683             while ( fIt != freeFaceList.end() ) { // loop on free faces
9684               double dist = 0;
9685               SMDS_ElemIteratorPtr nodeIt = (*fIt)->nodesIterator();
9686               while ( nodeIt->more() ) { // loop on free face nodes
9687                 const SMDS_MeshNode* n =
9688                   static_cast<const SMDS_MeshNode*>( nodeIt->next() );
9689                 gp_XYZ p( n->X(),n->Y(),n->Z() );
9690                 dist += ( aBC - p ).SquareModulus();
9691               }
9692               if ( dist < minDist ) {
9693                 minDist = dist;
9694                 freeFaceList.erase( freeFaceList.begin(), fIt++ );
9695               }
9696               else
9697                 fIt = freeFaceList.erase( fIt++ );
9698             }
9699           }
9700         } // choose one of several free faces of a volume
9701
9702         if ( freeFaceList.size() == 1 ) {
9703           const SMDS_MeshElement* aFreeFace = freeFaceList.front();
9704           faceSet->insert( aFreeFace );
9705           // complete a node set with nodes of a found free face
9706           //           for ( iNode = 0; iNode < ; iNode++ )
9707           //             nodeSet->insert( fNodes[ iNode ] );
9708         }
9709
9710       } // loop on volumes of a side
9711
9712       //       // complete a set of faces if new nodes in a nodeSet appeared
9713       //       // ----------------------------------------------------------
9714       //       if ( nodeSetSize != nodeSet->size() ) {
9715       //         for ( ; nIt != nodeSet->end(); nIt++ ) { // loop on nodes of iSide
9716       //           SMDS_ElemIteratorPtr fIt = (*nIt)->GetInverseElementIterator(SMDSAbs_Face);
9717       //           while ( fIt->more() ) { // loop on faces sharing a node
9718       //             const SMDS_MeshElement* f = fIt->next();
9719       //             if ( faceSet->find( f ) == faceSet->end() ) {
9720       //               // check if all nodes are in nodeSet and
9721       //               // complete setOfFaceNodeSet if they are
9722       //               set <const SMDS_MeshNode*> faceNodeSet;
9723       //               SMDS_ElemIteratorPtr nodeIt = f->nodesIterator();
9724       //               bool allInSet = true;
9725       //               while ( nodeIt->more() && allInSet ) { // loop on nodes of a face
9726       //                 const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
9727       //                 if ( nodeSet->find( n ) == nodeSet->end() )
9728       //                   allInSet = false;
9729       //                 else
9730       //                   faceNodeSet.insert( n );
9731       //               }
9732       //               if ( allInSet ) {
9733       //                 faceSet->insert( f );
9734       //                 setOfFaceNodeSet.insert( faceNodeSet );
9735       //               }
9736       //             }
9737       //           }
9738       //         }
9739       //       }
9740     } // Create temporary faces, if there are volumes given
9741   } // loop on sides
9742
9743   if ( faceSet1.size() != faceSet2.size() ) {
9744     // delete temporary faces: they are in reverseElements of actual nodes
9745 //    SMDS_FaceIteratorPtr tmpFaceIt = aTmpFacesMesh.facesIterator();
9746 //    while ( tmpFaceIt->more() )
9747 //      aTmpFacesMesh.RemoveElement( tmpFaceIt->next() );
9748 //    list<const SMDS_MeshElement* >::iterator tmpFaceIt = tempFaceList.begin();
9749 //    for (; tmpFaceIt !=tempFaceList.end(); ++tmpFaceIt)
9750 //      aMesh->RemoveElement(*tmpFaceIt);
9751     MESSAGE("Diff nb of faces");
9752     return SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
9753   }
9754
9755   // ============================================================
9756   // 2. Find nodes to merge:
9757   //              bind a node to remove to a node to put instead
9758   // ============================================================
9759
9760   TNodeNodeMap nReplaceMap; // bind a node to remove to a node to put instead
9761   if ( theFirstNode1 != theFirstNode2 )
9762     nReplaceMap.insert( TNodeNodeMap::value_type( theFirstNode1, theFirstNode2 ));
9763   if ( theSecondNode1 != theSecondNode2 )
9764     nReplaceMap.insert( TNodeNodeMap::value_type( theSecondNode1, theSecondNode2 ));
9765
9766   LinkID_Gen aLinkID_Gen( GetMeshDS() );
9767   set< long > linkIdSet; // links to process
9768   linkIdSet.insert( aLinkID_Gen.GetLinkID( theFirstNode1, theSecondNode1 ));
9769
9770   typedef pair< const SMDS_MeshNode*, const SMDS_MeshNode* > NLink;
9771   list< NLink > linkList[2];
9772   linkList[0].push_back( NLink( theFirstNode1, theSecondNode1 ));
9773   linkList[1].push_back( NLink( theFirstNode2, theSecondNode2 ));
9774   // loop on links in linkList; find faces by links and append links
9775   // of the found faces to linkList
9776   list< NLink >::iterator linkIt[] = { linkList[0].begin(), linkList[1].begin() } ;
9777   for ( ; linkIt[0] != linkList[0].end(); linkIt[0]++, linkIt[1]++ ) {
9778     NLink link[] = { *linkIt[0], *linkIt[1] };
9779     long linkID = aLinkID_Gen.GetLinkID( link[0].first, link[0].second );
9780     if ( linkIdSet.find( linkID ) == linkIdSet.end() )
9781       continue;
9782
9783     // by links, find faces in the face sets,
9784     // and find indices of link nodes in the found faces;
9785     // in a face set, there is only one or no face sharing a link
9786     // ---------------------------------------------------------------
9787
9788     const SMDS_MeshElement* face[] = { 0, 0 };
9789     //const SMDS_MeshNode* faceNodes[ 2 ][ 5 ];
9790     vector<const SMDS_MeshNode*> fnodes1(9);
9791     vector<const SMDS_MeshNode*> fnodes2(9);
9792     //const SMDS_MeshNode* notLinkNodes[ 2 ][ 2 ] = {{ 0, 0 },{ 0, 0 }} ;
9793     vector<const SMDS_MeshNode*> notLinkNodes1(6);
9794     vector<const SMDS_MeshNode*> notLinkNodes2(6);
9795     int iLinkNode[2][2];
9796     for ( iSide = 0; iSide < 2; iSide++ ) { // loop on 2 sides
9797       const SMDS_MeshNode* n1 = link[iSide].first;
9798       const SMDS_MeshNode* n2 = link[iSide].second;
9799       set<const SMDS_MeshElement*> * faceSet = faceSetPtr[ iSide ];
9800       set< const SMDS_MeshElement* > fMap;
9801       for ( int i = 0; i < 2; i++ ) { // loop on 2 nodes of a link
9802         const SMDS_MeshNode* n = i ? n1 : n2; // a node of a link
9803         SMDS_ElemIteratorPtr fIt = n->GetInverseElementIterator(SMDSAbs_Face);
9804         while ( fIt->more() ) { // loop on faces sharing a node
9805           const SMDS_MeshElement* f = fIt->next();
9806           if (faceSet->find( f ) != faceSet->end() && // f is in face set
9807               ! fMap.insert( f ).second ) // f encounters twice
9808           {
9809             if ( face[ iSide ] ) {
9810               MESSAGE( "2 faces per link " );
9811               aResult = iSide ? SEW_BAD_SIDE2_NODES : SEW_BAD_SIDE1_NODES;
9812               break;
9813             }
9814             face[ iSide ] = f;
9815             faceSet->erase( f );
9816             // get face nodes and find ones of a link
9817             iNode = 0;
9818             int nbl = -1;
9819             if(f->IsPoly()) {
9820               if(iSide==0) {
9821                 fnodes1.resize(f->NbNodes()+1);
9822                 notLinkNodes1.resize(f->NbNodes()-2);
9823               }
9824               else {
9825                 fnodes2.resize(f->NbNodes()+1);
9826                 notLinkNodes2.resize(f->NbNodes()-2);
9827               }
9828             }
9829             if(!f->IsQuadratic()) {
9830               SMDS_ElemIteratorPtr nIt = f->nodesIterator();
9831               while ( nIt->more() ) {
9832                 const SMDS_MeshNode* n =
9833                   static_cast<const SMDS_MeshNode*>( nIt->next() );
9834                 if ( n == n1 ) {
9835                   iLinkNode[ iSide ][ 0 ] = iNode;
9836                 }
9837                 else if ( n == n2 ) {
9838                   iLinkNode[ iSide ][ 1 ] = iNode;
9839                 }
9840                 //else if ( notLinkNodes[ iSide ][ 0 ] )
9841                 //  notLinkNodes[ iSide ][ 1 ] = n;
9842                 //else
9843                 //  notLinkNodes[ iSide ][ 0 ] = n;
9844                 else {
9845                   nbl++;
9846                   if(iSide==0)
9847                     notLinkNodes1[nbl] = n;
9848                   //notLinkNodes1.push_back(n);
9849                   else
9850                     notLinkNodes2[nbl] = n;
9851                   //notLinkNodes2.push_back(n);
9852                 }
9853                 //faceNodes[ iSide ][ iNode++ ] = n;
9854                 if(iSide==0) {
9855                   fnodes1[iNode++] = n;
9856                 }
9857                 else {
9858                   fnodes2[iNode++] = n;
9859                 }
9860               }
9861             }
9862             else { // f->IsQuadratic()
9863               const SMDS_VtkFace* F =
9864                 dynamic_cast<const SMDS_VtkFace*>(f);
9865               if (!F) throw SALOME_Exception(LOCALIZED("not an SMDS_VtkFace"));
9866               // use special nodes iterator
9867               SMDS_ElemIteratorPtr anIter = F->interlacedNodesElemIterator();
9868               while ( anIter->more() ) {
9869                 const SMDS_MeshNode* n =
9870                   static_cast<const SMDS_MeshNode*>( anIter->next() );
9871                 if ( n == n1 ) {
9872                   iLinkNode[ iSide ][ 0 ] = iNode;
9873                 }
9874                 else if ( n == n2 ) {
9875                   iLinkNode[ iSide ][ 1 ] = iNode;
9876                 }
9877                 else {
9878                   nbl++;
9879                   if(iSide==0) {
9880                     notLinkNodes1[nbl] = n;
9881                   }
9882                   else {
9883                     notLinkNodes2[nbl] = n;
9884                   }
9885                 }
9886                 if(iSide==0) {
9887                   fnodes1[iNode++] = n;
9888                 }
9889                 else {
9890                   fnodes2[iNode++] = n;
9891                 }
9892               }
9893             }
9894             //faceNodes[ iSide ][ iNode ] = faceNodes[ iSide ][ 0 ];
9895             if(iSide==0) {
9896               fnodes1[iNode] = fnodes1[0];
9897             }
9898             else {
9899               fnodes2[iNode] = fnodes1[0];
9900             }
9901           }
9902         }
9903       }
9904     }
9905
9906     // check similarity of elements of the sides
9907     if (aResult == SEW_OK && ( face[0] && !face[1] ) || ( !face[0] && face[1] )) {
9908       MESSAGE("Correspondent face not found on side " << ( face[0] ? 1 : 0 ));
9909       if ( nReplaceMap.size() == 2 ) { // faces on input nodes not found
9910         aResult = ( face[0] ? SEW_BAD_SIDE2_NODES : SEW_BAD_SIDE1_NODES );
9911       }
9912       else {
9913         aResult = SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
9914       }
9915       break; // do not return because it s necessary to remove tmp faces
9916     }
9917
9918     // set nodes to merge
9919     // -------------------
9920
9921     if ( face[0] && face[1] )  {
9922       int nbNodes = face[0]->NbNodes();
9923       if ( nbNodes != face[1]->NbNodes() ) {
9924         MESSAGE("Diff nb of face nodes");
9925         aResult = SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
9926         break; // do not return because it s necessary to remove tmp faces
9927       }
9928       bool reverse[] = { false, false }; // order of notLinkNodes of quadrangle
9929       if ( nbNodes == 3 ) {
9930         //nReplaceMap.insert( TNodeNodeMap::value_type
9931         //                   ( notLinkNodes[0][0], notLinkNodes[1][0] ));
9932         nReplaceMap.insert( TNodeNodeMap::value_type
9933                             ( notLinkNodes1[0], notLinkNodes2[0] ));
9934       }
9935       else {
9936         for ( iSide = 0; iSide < 2; iSide++ ) { // loop on 2 sides
9937           // analyse link orientation in faces
9938           int i1 = iLinkNode[ iSide ][ 0 ];
9939           int i2 = iLinkNode[ iSide ][ 1 ];
9940           reverse[ iSide ] = Abs( i1 - i2 ) == 1 ? i1 > i2 : i2 > i1;
9941           // if notLinkNodes are the first and the last ones, then
9942           // their order does not correspond to the link orientation
9943           if (( i1 == 1 && i2 == 2 ) ||
9944               ( i1 == 2 && i2 == 1 ))
9945             reverse[ iSide ] = !reverse[ iSide ];
9946         }
9947         if ( reverse[0] == reverse[1] ) {
9948           //nReplaceMap.insert( TNodeNodeMap::value_type
9949           //                   ( notLinkNodes[0][0], notLinkNodes[1][0] ));
9950           //nReplaceMap.insert( TNodeNodeMap::value_type
9951           //                   ( notLinkNodes[0][1], notLinkNodes[1][1] ));
9952           for(int nn=0; nn<nbNodes-2; nn++) {
9953             nReplaceMap.insert( TNodeNodeMap::value_type
9954                                 ( notLinkNodes1[nn], notLinkNodes2[nn] ));
9955           }
9956         }
9957         else {
9958           //nReplaceMap.insert( TNodeNodeMap::value_type
9959           //                   ( notLinkNodes[0][0], notLinkNodes[1][1] ));
9960           //nReplaceMap.insert( TNodeNodeMap::value_type
9961           //                   ( notLinkNodes[0][1], notLinkNodes[1][0] ));
9962           for(int nn=0; nn<nbNodes-2; nn++) {
9963             nReplaceMap.insert( TNodeNodeMap::value_type
9964                                 ( notLinkNodes1[nn], notLinkNodes2[nbNodes-3-nn] ));
9965           }
9966         }
9967       }
9968
9969       // add other links of the faces to linkList
9970       // -----------------------------------------
9971
9972       //const SMDS_MeshNode** nodes = faceNodes[ 0 ];
9973       for ( iNode = 0; iNode < nbNodes; iNode++ )  {
9974         //linkID = aLinkID_Gen.GetLinkID( nodes[iNode], nodes[iNode+1] );
9975         linkID = aLinkID_Gen.GetLinkID( fnodes1[iNode], fnodes1[iNode+1] );
9976         pair< set<long>::iterator, bool > iter_isnew = linkIdSet.insert( linkID );
9977         if ( !iter_isnew.second ) { // already in a set: no need to process
9978           linkIdSet.erase( iter_isnew.first );
9979         }
9980         else // new in set == encountered for the first time: add
9981         {
9982           //const SMDS_MeshNode* n1 = nodes[ iNode ];
9983           //const SMDS_MeshNode* n2 = nodes[ iNode + 1];
9984           const SMDS_MeshNode* n1 = fnodes1[ iNode ];
9985           const SMDS_MeshNode* n2 = fnodes1[ iNode + 1];
9986           linkList[0].push_back ( NLink( n1, n2 ));
9987           linkList[1].push_back ( NLink( nReplaceMap[n1], nReplaceMap[n2] ));
9988         }
9989       }
9990     } // 2 faces found
9991   } // loop on link lists
9992
9993   if ( aResult == SEW_OK &&
9994        ( linkIt[0] != linkList[0].end() ||
9995          !faceSetPtr[0]->empty() || !faceSetPtr[1]->empty() )) {
9996     MESSAGE( (linkIt[0] != linkList[0].end()) <<" "<< (faceSetPtr[0]->empty()) <<
9997              " " << (faceSetPtr[1]->empty()));
9998     aResult = SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
9999   }
10000
10001   // ====================================================================
10002   // 3. Replace nodes in elements of the side 1 and remove replaced nodes
10003   // ====================================================================
10004
10005   // delete temporary faces: they are in reverseElements of actual nodes
10006 //  SMDS_FaceIteratorPtr tmpFaceIt = aTmpFacesMesh.facesIterator();
10007 //  while ( tmpFaceIt->more() )
10008 //    aTmpFacesMesh.RemoveElement( tmpFaceIt->next() );
10009 //  list<const SMDS_MeshElement* >::iterator tmpFaceIt = tempFaceList.begin();
10010 //  for (; tmpFaceIt !=tempFaceList.end(); ++tmpFaceIt)
10011 //    aMesh->RemoveElement(*tmpFaceIt);
10012
10013   if ( aResult != SEW_OK)
10014     return aResult;
10015
10016   list< int > nodeIDsToRemove/*, elemIDsToRemove*/;
10017   // loop on nodes replacement map
10018   TNodeNodeMap::iterator nReplaceMapIt = nReplaceMap.begin(), nnIt;
10019   for ( ; nReplaceMapIt != nReplaceMap.end(); nReplaceMapIt++ )
10020     if ( (*nReplaceMapIt).first != (*nReplaceMapIt).second ) {
10021       const SMDS_MeshNode* nToRemove = (*nReplaceMapIt).first;
10022       nodeIDsToRemove.push_back( nToRemove->GetID() );
10023       // loop on elements sharing nToRemove
10024       SMDS_ElemIteratorPtr invElemIt = nToRemove->GetInverseElementIterator();
10025       while ( invElemIt->more() ) {
10026         const SMDS_MeshElement* e = invElemIt->next();
10027         // get a new suite of nodes: make replacement
10028         int nbReplaced = 0, i = 0, nbNodes = e->NbNodes();
10029         vector< const SMDS_MeshNode*> nodes( nbNodes );
10030         SMDS_ElemIteratorPtr nIt = e->nodesIterator();
10031         while ( nIt->more() ) {
10032           const SMDS_MeshNode* n =
10033             static_cast<const SMDS_MeshNode*>( nIt->next() );
10034           nnIt = nReplaceMap.find( n );
10035           if ( nnIt != nReplaceMap.end() ) {
10036             nbReplaced++;
10037             n = (*nnIt).second;
10038           }
10039           nodes[ i++ ] = n;
10040         }
10041         //       if ( nbReplaced == nbNodes && e->GetType() == SMDSAbs_Face )
10042         //         elemIDsToRemove.push_back( e->GetID() );
10043         //       else
10044         if ( nbReplaced )
10045           {
10046             SMDSAbs_ElementType etyp = e->GetType();
10047             SMDS_MeshElement* newElem = this->AddElement(nodes, etyp, false);
10048             if (newElem)
10049               {
10050                 myLastCreatedElems.Append(newElem);
10051                 AddToSameGroups(newElem, e, aMesh);
10052                 int aShapeId = e->getshapeId();
10053                 if ( aShapeId )
10054                   {
10055                     aMesh->SetMeshElementOnShape( newElem, aShapeId );
10056                   }
10057               }
10058             aMesh->RemoveElement(e);
10059           }
10060       }
10061     }
10062
10063   Remove( nodeIDsToRemove, true );
10064
10065   return aResult;
10066 }
10067
10068 //================================================================================
10069 /*!
10070  * \brief Find corresponding nodes in two sets of faces
10071  * \param theSide1 - first face set
10072  * \param theSide2 - second first face
10073  * \param theFirstNode1 - a boundary node of set 1
10074  * \param theFirstNode2 - a node of set 2 corresponding to theFirstNode1
10075  * \param theSecondNode1 - a boundary node of set 1 linked with theFirstNode1
10076  * \param theSecondNode2 - a node of set 2 corresponding to theSecondNode1
10077  * \param nReplaceMap - output map of corresponding nodes
10078  * \retval bool  - is a success or not
10079  */
10080 //================================================================================
10081
10082 #ifdef _DEBUG_
10083 //#define DEBUG_MATCHING_NODES
10084 #endif
10085
10086 SMESH_MeshEditor::Sew_Error
10087 SMESH_MeshEditor::FindMatchingNodes(set<const SMDS_MeshElement*>& theSide1,
10088                                     set<const SMDS_MeshElement*>& theSide2,
10089                                     const SMDS_MeshNode*          theFirstNode1,
10090                                     const SMDS_MeshNode*          theFirstNode2,
10091                                     const SMDS_MeshNode*          theSecondNode1,
10092                                     const SMDS_MeshNode*          theSecondNode2,
10093                                     TNodeNodeMap &                nReplaceMap)
10094 {
10095   set<const SMDS_MeshElement*> * faceSetPtr[] = { &theSide1, &theSide2 };
10096
10097   nReplaceMap.clear();
10098   if ( theFirstNode1 != theFirstNode2 )
10099     nReplaceMap.insert( make_pair( theFirstNode1, theFirstNode2 ));
10100   if ( theSecondNode1 != theSecondNode2 )
10101     nReplaceMap.insert( make_pair( theSecondNode1, theSecondNode2 ));
10102
10103   set< SMESH_TLink > linkSet; // set of nodes where order of nodes is ignored
10104   linkSet.insert( SMESH_TLink( theFirstNode1, theSecondNode1 ));
10105
10106   list< NLink > linkList[2];
10107   linkList[0].push_back( NLink( theFirstNode1, theSecondNode1 ));
10108   linkList[1].push_back( NLink( theFirstNode2, theSecondNode2 ));
10109
10110   // loop on links in linkList; find faces by links and append links
10111   // of the found faces to linkList
10112   list< NLink >::iterator linkIt[] = { linkList[0].begin(), linkList[1].begin() } ;
10113   for ( ; linkIt[0] != linkList[0].end(); linkIt[0]++, linkIt[1]++ ) {
10114     NLink link[] = { *linkIt[0], *linkIt[1] };
10115     if ( linkSet.find( link[0] ) == linkSet.end() )
10116       continue;
10117
10118     // by links, find faces in the face sets,
10119     // and find indices of link nodes in the found faces;
10120     // in a face set, there is only one or no face sharing a link
10121     // ---------------------------------------------------------------
10122
10123     const SMDS_MeshElement* face[] = { 0, 0 };
10124     list<const SMDS_MeshNode*> notLinkNodes[2];
10125     //bool reverse[] = { false, false }; // order of notLinkNodes
10126     int nbNodes[2];
10127     for ( int iSide = 0; iSide < 2; iSide++ ) // loop on 2 sides
10128     {
10129       const SMDS_MeshNode* n1 = link[iSide].first;
10130       const SMDS_MeshNode* n2 = link[iSide].second;
10131       set<const SMDS_MeshElement*> * faceSet = faceSetPtr[ iSide ];
10132       set< const SMDS_MeshElement* > facesOfNode1;
10133       for ( int iNode = 0; iNode < 2; iNode++ ) // loop on 2 nodes of a link
10134       {
10135         // during a loop of the first node, we find all faces around n1,
10136         // during a loop of the second node, we find one face sharing both n1 and n2
10137         const SMDS_MeshNode* n = iNode ? n1 : n2; // a node of a link
10138         SMDS_ElemIteratorPtr fIt = n->GetInverseElementIterator(SMDSAbs_Face);
10139         while ( fIt->more() ) { // loop on faces sharing a node
10140           const SMDS_MeshElement* f = fIt->next();
10141           if (faceSet->find( f ) != faceSet->end() && // f is in face set
10142               ! facesOfNode1.insert( f ).second ) // f encounters twice
10143           {
10144             if ( face[ iSide ] ) {
10145               MESSAGE( "2 faces per link " );
10146               return ( iSide ? SEW_BAD_SIDE2_NODES : SEW_BAD_SIDE1_NODES );
10147             }
10148             face[ iSide ] = f;
10149             faceSet->erase( f );
10150
10151             // get not link nodes
10152             int nbN = f->NbNodes();
10153             if ( f->IsQuadratic() )
10154               nbN /= 2;
10155             nbNodes[ iSide ] = nbN;
10156             list< const SMDS_MeshNode* > & nodes = notLinkNodes[ iSide ];
10157             int i1 = f->GetNodeIndex( n1 );
10158             int i2 = f->GetNodeIndex( n2 );
10159             int iEnd = nbN, iBeg = -1, iDelta = 1;
10160             bool reverse = ( Abs( i1 - i2 ) == 1 ? i1 > i2 : i2 > i1 );
10161             if ( reverse ) {
10162               std::swap( iEnd, iBeg ); iDelta = -1;
10163             }
10164             int i = i2;
10165             while ( true ) {
10166               i += iDelta;
10167               if ( i == iEnd ) i = iBeg + iDelta;
10168               if ( i == i1 ) break;
10169               nodes.push_back ( f->GetNode( i ) );
10170             }
10171           }
10172         }
10173       }
10174     }
10175     // check similarity of elements of the sides
10176     if (( face[0] && !face[1] ) || ( !face[0] && face[1] )) {
10177       MESSAGE("Correspondent face not found on side " << ( face[0] ? 1 : 0 ));
10178       if ( nReplaceMap.size() == 2 ) { // faces on input nodes not found
10179         return ( face[0] ? SEW_BAD_SIDE2_NODES : SEW_BAD_SIDE1_NODES );
10180       }
10181       else {
10182         return SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
10183       }
10184     }
10185
10186     // set nodes to merge
10187     // -------------------
10188
10189     if ( face[0] && face[1] )  {
10190       if ( nbNodes[0] != nbNodes[1] ) {
10191         MESSAGE("Diff nb of face nodes");
10192         return SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
10193       }
10194 #ifdef DEBUG_MATCHING_NODES
10195       MESSAGE ( " Link 1: " << link[0].first->GetID() <<" "<< link[0].second->GetID()
10196                 << " F 1: " << face[0] << "| Link 2: " << link[1].first->GetID() <<" "
10197                 << link[1].second->GetID() << " F 2: " << face[1] << " | Bind: " ) ;
10198 #endif
10199       int nbN = nbNodes[0];
10200       {
10201         list<const SMDS_MeshNode*>::iterator n1 = notLinkNodes[0].begin();
10202         list<const SMDS_MeshNode*>::iterator n2 = notLinkNodes[1].begin();
10203         for ( int i = 0 ; i < nbN - 2; ++i ) {
10204 #ifdef DEBUG_MATCHING_NODES
10205           MESSAGE ( (*n1)->GetID() << " to " << (*n2)->GetID() );
10206 #endif
10207           nReplaceMap.insert( make_pair( *(n1++), *(n2++) ));
10208         }
10209       }
10210
10211       // add other links of the face 1 to linkList
10212       // -----------------------------------------
10213
10214       const SMDS_MeshElement* f0 = face[0];
10215       const SMDS_MeshNode* n1 = f0->GetNode( nbN - 1 );
10216       for ( int i = 0; i < nbN; i++ )
10217       {
10218         const SMDS_MeshNode* n2 = f0->GetNode( i );
10219         pair< set< SMESH_TLink >::iterator, bool > iter_isnew =
10220           linkSet.insert( SMESH_TLink( n1, n2 ));
10221         if ( !iter_isnew.second ) { // already in a set: no need to process
10222           linkSet.erase( iter_isnew.first );
10223         }
10224         else // new in set == encountered for the first time: add
10225         {
10226 #ifdef DEBUG_MATCHING_NODES
10227           MESSAGE ( "Add link 1: " << n1->GetID() << " " << n2->GetID() << " "
10228                     << " | link 2: " << nReplaceMap[n1]->GetID() << " " << nReplaceMap[n2]->GetID() << " " );
10229 #endif
10230           linkList[0].push_back ( NLink( n1, n2 ));
10231           linkList[1].push_back ( NLink( nReplaceMap[n1], nReplaceMap[n2] ));
10232         }
10233         n1 = n2;
10234       }
10235     } // 2 faces found
10236   } // loop on link lists
10237
10238   return SEW_OK;
10239 }
10240
10241 //================================================================================
10242 /*!
10243   \brief Creates a hole in a mesh by doubling the nodes of some particular elements
10244   \param theElems - the list of elements (edges or faces) to be replicated
10245   The nodes for duplication could be found from these elements
10246   \param theNodesNot - list of nodes to NOT replicate
10247   \param theAffectedElems - the list of elements (cells and edges) to which the 
10248   replicated nodes should be associated to.
10249   \return TRUE if operation has been completed successfully, FALSE otherwise
10250 */
10251 //================================================================================
10252
10253 bool SMESH_MeshEditor::DoubleNodes( const TIDSortedElemSet& theElems,
10254                                     const TIDSortedElemSet& theNodesNot,
10255                                     const TIDSortedElemSet& theAffectedElems )
10256 {
10257   myLastCreatedElems.Clear();
10258   myLastCreatedNodes.Clear();
10259
10260   if ( theElems.size() == 0 )
10261     return false;
10262
10263   SMESHDS_Mesh* aMeshDS = GetMeshDS();
10264   if ( !aMeshDS )
10265     return false;
10266
10267   bool res = false;
10268   std::map< const SMDS_MeshNode*, const SMDS_MeshNode* > anOldNodeToNewNode;
10269   // duplicate elements and nodes
10270   res = doubleNodes( aMeshDS, theElems, theNodesNot, anOldNodeToNewNode, true );
10271   // replce nodes by duplications
10272   res = doubleNodes( aMeshDS, theAffectedElems, theNodesNot, anOldNodeToNewNode, false );
10273   return res;
10274 }
10275
10276 //================================================================================
10277 /*!
10278   \brief Creates a hole in a mesh by doubling the nodes of some particular elements
10279   \param theMeshDS - mesh instance
10280   \param theElems - the elements replicated or modified (nodes should be changed)
10281   \param theNodesNot - nodes to NOT replicate
10282   \param theNodeNodeMap - relation of old node to new created node
10283   \param theIsDoubleElem - flag os to replicate element or modify
10284   \return TRUE if operation has been completed successfully, FALSE otherwise
10285 */
10286 //================================================================================
10287
10288 bool SMESH_MeshEditor::doubleNodes( SMESHDS_Mesh*     theMeshDS,
10289                                     const TIDSortedElemSet& theElems,
10290                                     const TIDSortedElemSet& theNodesNot,
10291                                     std::map< const SMDS_MeshNode*,
10292                                     const SMDS_MeshNode* >& theNodeNodeMap,
10293                                     const bool theIsDoubleElem )
10294 {
10295   MESSAGE("doubleNodes");
10296   // iterate on through element and duplicate them (by nodes duplication)
10297   bool res = false;
10298   TIDSortedElemSet::const_iterator elemItr = theElems.begin();
10299   for ( ;  elemItr != theElems.end(); ++elemItr )
10300   {
10301     const SMDS_MeshElement* anElem = *elemItr;
10302     if (!anElem)
10303       continue;
10304
10305     bool isDuplicate = false;
10306     // duplicate nodes to duplicate element
10307     std::vector<const SMDS_MeshNode*> newNodes( anElem->NbNodes() );
10308     SMDS_ElemIteratorPtr anIter = anElem->nodesIterator();
10309     int ind = 0;
10310     while ( anIter->more() ) 
10311     { 
10312
10313       SMDS_MeshNode* aCurrNode = (SMDS_MeshNode*)anIter->next();
10314       SMDS_MeshNode* aNewNode = aCurrNode;
10315       if ( theNodeNodeMap.find( aCurrNode ) != theNodeNodeMap.end() )
10316         aNewNode = (SMDS_MeshNode*)theNodeNodeMap[ aCurrNode ];
10317       else if ( theIsDoubleElem && theNodesNot.find( aCurrNode ) == theNodesNot.end() )
10318       {
10319         // duplicate node
10320         aNewNode = theMeshDS->AddNode( aCurrNode->X(), aCurrNode->Y(), aCurrNode->Z() );
10321         theNodeNodeMap[ aCurrNode ] = aNewNode;
10322         myLastCreatedNodes.Append( aNewNode );
10323       }
10324       isDuplicate |= (aCurrNode != aNewNode);
10325       newNodes[ ind++ ] = aNewNode;
10326     }
10327     if ( !isDuplicate )
10328       continue;
10329
10330     if ( theIsDoubleElem )
10331       AddElement(newNodes, anElem->GetType(), anElem->IsPoly());
10332     else
10333       {
10334       MESSAGE("ChangeElementNodes");
10335       theMeshDS->ChangeElementNodes( anElem, &newNodes[ 0 ], anElem->NbNodes() );
10336       }
10337     res = true;
10338   }
10339   return res;
10340 }
10341
10342 //================================================================================
10343 /*!
10344   \brief Creates a hole in a mesh by doubling the nodes of some particular elements
10345   \param theNodes - identifiers of nodes to be doubled
10346   \param theModifiedElems - identifiers of elements to be updated by the new (doubled) 
10347          nodes. If list of element identifiers is empty then nodes are doubled but 
10348          they not assigned to elements
10349   \return TRUE if operation has been completed successfully, FALSE otherwise
10350 */
10351 //================================================================================
10352
10353 bool SMESH_MeshEditor::DoubleNodes( const std::list< int >& theListOfNodes, 
10354                                     const std::list< int >& theListOfModifiedElems )
10355 {
10356   MESSAGE("DoubleNodes");
10357   myLastCreatedElems.Clear();
10358   myLastCreatedNodes.Clear();
10359
10360   if ( theListOfNodes.size() == 0 )
10361     return false;
10362
10363   SMESHDS_Mesh* aMeshDS = GetMeshDS();
10364   if ( !aMeshDS )
10365     return false;
10366
10367   // iterate through nodes and duplicate them
10368
10369   std::map< const SMDS_MeshNode*, const SMDS_MeshNode* > anOldNodeToNewNode;
10370
10371   std::list< int >::const_iterator aNodeIter;
10372   for ( aNodeIter = theListOfNodes.begin(); aNodeIter != theListOfNodes.end(); ++aNodeIter )
10373   {
10374     int aCurr = *aNodeIter;
10375     SMDS_MeshNode* aNode = (SMDS_MeshNode*)aMeshDS->FindNode( aCurr );
10376     if ( !aNode )
10377       continue;
10378
10379     // duplicate node
10380
10381     const SMDS_MeshNode* aNewNode = aMeshDS->AddNode( aNode->X(), aNode->Y(), aNode->Z() );
10382     if ( aNewNode )
10383     {
10384       anOldNodeToNewNode[ aNode ] = aNewNode;
10385       myLastCreatedNodes.Append( aNewNode );
10386     }
10387   }
10388
10389   // Create map of new nodes for modified elements
10390
10391   std::map< SMDS_MeshElement*, vector<const SMDS_MeshNode*> > anElemToNodes;
10392
10393   std::list< int >::const_iterator anElemIter;
10394   for ( anElemIter = theListOfModifiedElems.begin(); 
10395         anElemIter != theListOfModifiedElems.end(); ++anElemIter )
10396   {
10397     int aCurr = *anElemIter;
10398     SMDS_MeshElement* anElem = (SMDS_MeshElement*)aMeshDS->FindElement( aCurr );
10399     if ( !anElem )
10400       continue;
10401
10402     vector<const SMDS_MeshNode*> aNodeArr( anElem->NbNodes() );
10403
10404     SMDS_ElemIteratorPtr anIter = anElem->nodesIterator();
10405     int ind = 0;
10406     while ( anIter->more() ) 
10407     { 
10408       SMDS_MeshNode* aCurrNode = (SMDS_MeshNode*)anIter->next();
10409       if ( aCurr && anOldNodeToNewNode.find( aCurrNode ) != anOldNodeToNewNode.end() )
10410       {
10411         const SMDS_MeshNode* aNewNode = anOldNodeToNewNode[ aCurrNode ];
10412         aNodeArr[ ind++ ] = aNewNode;
10413       }
10414       else
10415         aNodeArr[ ind++ ] = aCurrNode;
10416     }
10417     anElemToNodes[ anElem ] = aNodeArr;
10418   }
10419
10420   // Change nodes of elements  
10421
10422   std::map< SMDS_MeshElement*, vector<const SMDS_MeshNode*> >::iterator
10423     anElemToNodesIter = anElemToNodes.begin();
10424   for ( ; anElemToNodesIter != anElemToNodes.end(); ++anElemToNodesIter )
10425   {
10426     const SMDS_MeshElement* anElem = anElemToNodesIter->first;
10427     vector<const SMDS_MeshNode*> aNodeArr = anElemToNodesIter->second;
10428     if ( anElem )
10429       {
10430       MESSAGE("ChangeElementNodes");
10431       aMeshDS->ChangeElementNodes( anElem, &aNodeArr[ 0 ], anElem->NbNodes() );
10432       }
10433   }
10434
10435   return true;
10436 }
10437
10438 namespace {
10439
10440   //================================================================================
10441   /*!
10442   \brief Check if element located inside shape
10443   \return TRUE if IN or ON shape, FALSE otherwise
10444   */
10445   //================================================================================
10446
10447   template<class Classifier>
10448   bool isInside(const SMDS_MeshElement* theElem,
10449                 Classifier&             theClassifier,
10450                 const double            theTol)
10451   {
10452     gp_XYZ centerXYZ (0, 0, 0);
10453     SMDS_ElemIteratorPtr aNodeItr = theElem->nodesIterator();
10454     while (aNodeItr->more())
10455       centerXYZ += SMESH_MeshEditor::TNodeXYZ(cast2Node( aNodeItr->next()));
10456
10457     gp_Pnt aPnt = centerXYZ / theElem->NbNodes();
10458     theClassifier.Perform(aPnt, theTol);
10459     TopAbs_State aState = theClassifier.State();
10460     return (aState == TopAbs_IN || aState == TopAbs_ON );
10461   }
10462
10463   //================================================================================
10464   /*!
10465    * \brief Classifier of the 3D point on the TopoDS_Face
10466    *        with interaface suitable for isInside()
10467    */
10468   //================================================================================
10469
10470   struct _FaceClassifier
10471   {
10472     Extrema_ExtPS       _extremum;
10473     BRepAdaptor_Surface _surface;
10474     TopAbs_State        _state;
10475
10476     _FaceClassifier(const TopoDS_Face& face):_extremum(),_surface(face),_state(TopAbs_OUT)
10477     {
10478       _extremum.Initialize( _surface,
10479                             _surface.FirstUParameter(), _surface.LastUParameter(),
10480                             _surface.FirstVParameter(), _surface.LastVParameter(),
10481                             _surface.Tolerance(), _surface.Tolerance() );
10482     }
10483     void Perform(const gp_Pnt& aPnt, double theTol)
10484     {
10485       _state = TopAbs_OUT;
10486       _extremum.Perform(aPnt);
10487       if ( _extremum.IsDone() )
10488         for ( int iSol = 1; iSol <= _extremum.NbExt() && _state == TopAbs_OUT; ++iSol)
10489           _state = ( _extremum.Value(iSol) <= theTol ? TopAbs_IN : TopAbs_OUT );
10490     }
10491     TopAbs_State State() const
10492     {
10493       return _state;
10494     }
10495   };
10496 }
10497
10498 //================================================================================
10499 /*!
10500   \brief Creates a hole in a mesh by doubling the nodes of some particular elements
10501   \param theElems - group of of elements (edges or faces) to be replicated
10502   \param theNodesNot - group of nodes not to replicate
10503   \param theShape - shape to detect affected elements (element which geometric center
10504   located on or inside shape).
10505   The replicated nodes should be associated to affected elements.
10506   \return TRUE if operation has been completed successfully, FALSE otherwise
10507 */
10508 //================================================================================
10509
10510 bool SMESH_MeshEditor::DoubleNodesInRegion( const TIDSortedElemSet& theElems,
10511                                             const TIDSortedElemSet& theNodesNot,
10512                                             const TopoDS_Shape&     theShape )
10513 {
10514   if ( theShape.IsNull() )
10515     return false;
10516
10517   const double aTol = Precision::Confusion();
10518   auto_ptr< BRepClass3d_SolidClassifier> bsc3d;
10519   auto_ptr<_FaceClassifier>              aFaceClassifier;
10520   if ( theShape.ShapeType() == TopAbs_SOLID )
10521   {
10522     bsc3d.reset( new BRepClass3d_SolidClassifier(theShape));;
10523     bsc3d->PerformInfinitePoint(aTol);
10524   }
10525   else if (theShape.ShapeType() == TopAbs_FACE )
10526   {
10527     aFaceClassifier.reset( new _FaceClassifier(TopoDS::Face(theShape)));
10528   }
10529
10530   // iterates on indicated elements and get elements by back references from their nodes
10531   TIDSortedElemSet anAffected;
10532   TIDSortedElemSet::const_iterator elemItr = theElems.begin();
10533   for ( ;  elemItr != theElems.end(); ++elemItr )
10534   {
10535     SMDS_MeshElement* anElem = (SMDS_MeshElement*)*elemItr;
10536     if (!anElem)
10537       continue;
10538
10539     SMDS_ElemIteratorPtr nodeItr = anElem->nodesIterator();
10540     while ( nodeItr->more() )
10541     {
10542       const SMDS_MeshNode* aNode = cast2Node(nodeItr->next());
10543       if ( !aNode || theNodesNot.find(aNode) != theNodesNot.end() )
10544         continue;
10545       SMDS_ElemIteratorPtr backElemItr = aNode->GetInverseElementIterator();
10546       while ( backElemItr->more() )
10547       {
10548         const SMDS_MeshElement* curElem = backElemItr->next();
10549         if ( curElem && theElems.find(curElem) == theElems.end() &&
10550              ( bsc3d.get() ?
10551                isInside( curElem, *bsc3d, aTol ) :
10552                isInside( curElem, *aFaceClassifier, aTol )))
10553           anAffected.insert( curElem );
10554       }
10555     }
10556   }
10557   return DoubleNodes( theElems, theNodesNot, anAffected );
10558 }
10559
10560 /*!
10561  * \brief Double nodes on shared faces between groups of volumes and create flat elements on demand.
10562  * The list of groups must describe a partition of the mesh volumes.
10563  * The nodes of the internal faces at the boundaries of the groups are doubled.
10564  * In option, the internal faces are replaced by flat elements.
10565  * Triangles are transformed in prisms, and quadrangles in hexahedrons.
10566  * @param theElems - list of groups of volumes, where a group of volume is a set of
10567  * SMDS_MeshElements sorted by Id.
10568  * @param createJointElems - if TRUE, create the elements
10569  * @return TRUE if operation has been completed successfully, FALSE otherwise
10570  */
10571 bool SMESH_MeshEditor::DoubleNodesOnGroupBoundaries( const std::vector<TIDSortedElemSet>& theElems,
10572                                                      bool createJointElems)
10573 {
10574   MESSAGE("------------------------------------------------------");
10575   MESSAGE("SMESH_MeshEditor::CreateJointElementsOnGroupBoundaries");
10576   MESSAGE("------------------------------------------------------");
10577
10578   SMESHDS_Mesh *meshDS = this->myMesh->GetMeshDS();
10579   meshDS->BuildDownWardConnectivity(false);
10580   CHRONO(50);
10581   SMDS_UnstructuredGrid *grid = meshDS->getGrid();
10582
10583   // --- build the list of faces shared by 2 domains (group of elements), with their domain and volume indexes
10584   //     build the list of nodes shared by 2 or more domains, with their domain indexes
10585
10586   std::map<DownIdType, std::map<int,int>, DownIdCompare> faceDomains; // 2x(id domain --> id volume)
10587   std::map<int, std::map<int,int> > nodeDomains; //oldId ->  (domainId -> newId)
10588   faceDomains.clear();
10589   nodeDomains.clear();
10590   std::map<int,int> emptyMap;
10591   emptyMap.clear();
10592
10593   for (int idom = 0; idom < theElems.size(); idom++)
10594     {
10595
10596       // --- build a map (face to duplicate --> volume to modify)
10597       //     with all the faces shared by 2 domains (group of elements)
10598       //     and corresponding volume of this domain, for each shared face.
10599       //     a volume has a face shared by 2 domains if it has a neighbor which is not in is domain.
10600
10601       const TIDSortedElemSet& domain = theElems[idom];
10602       TIDSortedElemSet::const_iterator elemItr = domain.begin();
10603       for (; elemItr != domain.end(); ++elemItr)
10604         {
10605           SMDS_MeshElement* anElem = (SMDS_MeshElement*) *elemItr;
10606           if (!anElem)
10607             continue;
10608           int vtkId = anElem->getVtkId();
10609           int neighborsVtkIds[NBMAXNEIGHBORS];
10610           int downIds[NBMAXNEIGHBORS];
10611           unsigned char downTypes[NBMAXNEIGHBORS];
10612           int nbNeighbors = grid->GetNeighbors(neighborsVtkIds, downIds, downTypes, vtkId);
10613           for (int n = 0; n < nbNeighbors; n++)
10614             {
10615               int smdsId = meshDS->fromVtkToSmds(neighborsVtkIds[n]);
10616               const SMDS_MeshElement* elem = meshDS->FindElement(smdsId);
10617               if (! domain.count(elem)) // neighbor is in another domain : face is shared
10618                 {
10619                   DownIdType face(downIds[n], downTypes[n]);
10620                   if (!faceDomains.count(face))
10621                     faceDomains[face] = emptyMap; // create an empty entry for face
10622                   if (!faceDomains[face].count(idom))
10623                     {
10624                       faceDomains[face][idom] = vtkId; // volume associated to face in this domain
10625                     }
10626                 }
10627             }
10628         }
10629     }
10630
10631   MESSAGE("Number of shared faces " << faceDomains.size());
10632
10633   // --- for each shared face, get the nodes
10634   //     for each node, for each domain of the face, create a clone of the node
10635
10636   std::map<DownIdType, std::map<int,int>, DownIdCompare>::iterator itface = faceDomains.begin();
10637   for( ; itface != faceDomains.end();++itface )
10638     {
10639       DownIdType face = itface->first;
10640       std::map<int,int> domvol = itface->second;
10641       std::set<int> oldNodes;
10642       oldNodes.clear();
10643       grid->GetNodeIds(oldNodes, face.cellId, face.cellType);
10644       std::set<int>::iterator itn = oldNodes.begin();
10645       for (;itn != oldNodes.end(); ++itn)
10646         {
10647           int oldId = *itn;
10648           if (!nodeDomains.count(oldId))
10649             nodeDomains[oldId] = emptyMap; // create an empty entry for node
10650           std::map<int,int>::iterator itdom = domvol.begin();
10651           for(; itdom != domvol.end(); ++itdom)
10652             {
10653               int idom = itdom->first;
10654               if ( nodeDomains[oldId].empty() )
10655                 nodeDomains[oldId][idom] = oldId; // keep the old node in the first domain
10656               else
10657                 {
10658                   double *coords = grid->GetPoint(oldId);
10659                   SMDS_MeshNode *newNode = meshDS->AddNode(coords[0], coords[1], coords[2]);
10660                   int newId = newNode->getVtkId();
10661                   nodeDomains[oldId][idom] = newId; // cloned node for other domains
10662                 }
10663             }
10664         }
10665     }
10666
10667   // --- iterate on shared faces (volumes to modify, face to extrude)
10668   //     get node id's of the face (id SMDS = id VTK)
10669   //     create flat element with old and new nodes if requested
10670
10671   if (createJointElems)
10672     {
10673       itface = faceDomains.begin();
10674       for( ; itface != faceDomains.end();++itface )
10675         {
10676           DownIdType face = itface->first;
10677           std::set<int> oldNodes;
10678           std::set<int>::iterator itn;
10679           oldNodes.clear();
10680           grid->GetNodeIds(oldNodes, face.cellId, face.cellType);
10681           std::map<int,int> localClonedNodeIds;
10682
10683           std::map<int,int> domvol = itface->second;
10684           std::map<int,int>::iterator itdom = domvol.begin();
10685           int dom1 = itdom->first;
10686           int vtkVolId = itdom->second;
10687           itdom++;
10688           int dom2 = itdom->first;
10689
10690           localClonedNodeIds.clear();
10691           for (itn = oldNodes.begin(); itn != oldNodes.end(); ++itn)
10692             {
10693               int oldId = *itn;
10694               int refid = oldId;
10695               if (nodeDomains[oldId].count(dom1))
10696                 refid = nodeDomains[oldId][dom1];
10697               else
10698                 MESSAGE("--- problem domain node " << dom1 << " " << oldId);
10699               int newid = oldId;
10700               if (nodeDomains[oldId].count(dom2))
10701                 newid = nodeDomains[oldId][dom2];
10702               else
10703                 MESSAGE("--- problem domain node " << dom2 << " " << oldId);
10704               localClonedNodeIds[oldId] = newid;
10705             }
10706           meshDS->extrudeVolumeFromFace(vtkVolId, localClonedNodeIds);
10707         }
10708     }
10709
10710   // --- iterate on shared faces (volumes to modify, face to extrude)
10711   //     get node id's of the face
10712   //     replace old nodes by new nodes in volumes, and update inverse connectivity
10713
10714   itface = faceDomains.begin();
10715   for( ; itface != faceDomains.end();++itface )
10716     {
10717       DownIdType face = itface->first;
10718       std::set<int> oldNodes;
10719       std::set<int>::iterator itn;
10720       oldNodes.clear();
10721       grid->GetNodeIds(oldNodes, face.cellId, face.cellType);
10722       std::map<int,int> localClonedNodeIds;
10723
10724       std::map<int,int> domvol = itface->second;
10725       std::map<int,int>::iterator itdom = domvol.begin();
10726       for(; itdom != domvol.end(); ++itdom)
10727         {
10728           int idom = itdom->first;
10729           int vtkVolId = itdom->second;
10730           localClonedNodeIds.clear();
10731           for (itn = oldNodes.begin(); itn != oldNodes.end(); ++itn)
10732             {
10733               int oldId = *itn;
10734               if (nodeDomains[oldId].count(idom))
10735                 localClonedNodeIds[oldId] = nodeDomains[oldId][idom];
10736             }
10737           meshDS->ModifyCellNodes(vtkVolId, localClonedNodeIds);
10738         }
10739     }
10740   grid->BuildLinks();
10741
10742   // TODO replace also old nodes by new nodes in faces and edges
10743   CHRONOSTOP(50);
10744   counters::stats();
10745   return true;
10746 }
10747
10748 //================================================================================
10749 /*!
10750  * \brief Generates skin mesh (containing 2D cells) from 3D mesh
10751  * The created 2D mesh elements based on nodes of free faces of boundary volumes
10752  * \return TRUE if operation has been completed successfully, FALSE otherwise
10753  */
10754 //================================================================================
10755
10756 bool SMESH_MeshEditor::Make2DMeshFrom3D()
10757 {
10758   // iterates on volume elements and detect all free faces on them
10759   SMESHDS_Mesh* aMesh = GetMeshDS();
10760   if (!aMesh)
10761     return false;
10762   //bool res = false;
10763   int nbFree = 0, nbExisted = 0, nbCreated = 0;
10764   SMDS_VolumeIteratorPtr vIt = aMesh->volumesIterator();
10765   while(vIt->more())
10766   {
10767     const SMDS_MeshVolume* volume = vIt->next();
10768     SMDS_VolumeTool vTool( volume );
10769     vTool.SetExternalNormal();
10770     const bool isPoly = volume->IsPoly();
10771     const bool isQuad = volume->IsQuadratic();
10772     for ( int iface = 0, n = vTool.NbFaces(); iface < n; iface++ )
10773     {
10774       if (!vTool.IsFreeFace(iface))
10775         continue;
10776       nbFree++;
10777       vector<const SMDS_MeshNode *> nodes;
10778       int nbFaceNodes = vTool.NbFaceNodes(iface);
10779       const SMDS_MeshNode** faceNodes = vTool.GetFaceNodes(iface);
10780       int inode = 0;
10781       for ( ; inode < nbFaceNodes; inode += isQuad ? 2 : 1)
10782         nodes.push_back(faceNodes[inode]);
10783       if (isQuad)
10784         for ( inode = 1; inode < nbFaceNodes; inode += 2)
10785           nodes.push_back(faceNodes[inode]);
10786
10787       // add new face based on volume nodes
10788       if (aMesh->FindFace( nodes ) ) {
10789         nbExisted++;
10790         continue; // face already exsist
10791       }
10792       AddElement(nodes, SMDSAbs_Face, isPoly && iface == 1);
10793       nbCreated++;
10794     }
10795   }
10796   return ( nbFree==(nbExisted+nbCreated) );
10797 }
10798
10799 namespace
10800 {
10801   inline const SMDS_MeshNode* getNodeWithSameID(SMESHDS_Mesh* mesh, const SMDS_MeshNode* node)
10802   {
10803     if ( const SMDS_MeshNode* n = mesh->FindNode( node->GetID() ))
10804       return n;
10805     return mesh->AddNodeWithID( node->X(),node->Y(),node->Z(), node->GetID() );
10806   }
10807 }
10808 //================================================================================
10809 /*!
10810  * \brief Creates missing boundary elements
10811  *  \param elements - elements whose boundary is to be checked
10812  *  \param dimension - defines type of boundary elements to create
10813  *  \param group - a group to store created boundary elements in
10814  *  \param targetMesh - a mesh to store created boundary elements in
10815  *  \param toCopyElements - if true, the checked elements will be copied into the targetMesh
10816  *  \param toCopyExistingBondary - if true, not only new but also pre-existing
10817  *                                boundary elements will be copied into the targetMesh
10818  */
10819 //================================================================================
10820
10821 void SMESH_MeshEditor::MakeBoundaryMesh(const TIDSortedElemSet& elements,
10822                                         Bnd_Dimension           dimension,
10823                                         SMESH_Group*            group/*=0*/,
10824                                         SMESH_Mesh*             targetMesh/*=0*/,
10825                                         bool                    toCopyElements/*=false*/,
10826                                         bool                    toCopyExistingBondary/*=false*/)
10827 {
10828   SMDSAbs_ElementType missType = (dimension == BND_2DFROM3D) ? SMDSAbs_Face : SMDSAbs_Edge;
10829   SMDSAbs_ElementType elemType = (dimension == BND_1DFROM2D) ? SMDSAbs_Face : SMDSAbs_Volume;
10830   // hope that all elements are of the same type, do not check them all
10831   if ( !elements.empty() && (*elements.begin())->GetType() != elemType )
10832     throw SALOME_Exception(LOCALIZED("wrong element type"));
10833
10834   if ( !targetMesh )
10835     toCopyElements = toCopyExistingBondary = false;
10836
10837   SMESH_MeshEditor tgtEditor( targetMesh ? targetMesh : myMesh );
10838   SMESHDS_Mesh* aMesh = GetMeshDS(), *tgtMeshDS = tgtEditor.GetMeshDS();
10839
10840   SMDS_VolumeTool vTool;
10841   TIDSortedElemSet emptySet, avoidSet;
10842   int inode;
10843
10844   typedef vector<const SMDS_MeshNode*> TConnectivity;
10845
10846   SMDS_ElemIteratorPtr eIt;
10847   if (elements.empty())
10848     eIt = aMesh->elementsIterator(elemType);
10849   else
10850     eIt = SMDS_ElemIteratorPtr( new TSetIterator( elements.begin(), elements.end() ));
10851
10852   while (eIt->more())
10853   {
10854     const SMDS_MeshElement* elem = eIt->next();
10855     const int iQuad = elem->IsQuadratic();
10856
10857     // 1. For an elem, get present bnd elements and connectivities of missing bnd elements
10858     vector<const SMDS_MeshElement*> presentBndElems;
10859     vector<TConnectivity>           missingBndElems;
10860     TConnectivity nodes;
10861     if ( vTool.Set(elem) ) // elem is a volume ------------------------------------------
10862     {
10863       vTool.SetExternalNormal();
10864       for ( int iface = 0, n = vTool.NbFaces(); iface < n; iface++ )
10865       {
10866         if (!vTool.IsFreeFace(iface))
10867           continue;
10868         int nbFaceNodes = vTool.NbFaceNodes(iface);
10869         const SMDS_MeshNode** nn = vTool.GetFaceNodes(iface);
10870         if ( missType == SMDSAbs_Edge ) // boundary edges
10871         {
10872           nodes.resize( 2+iQuad );
10873           for ( int i = 0; i < nbFaceNodes; i += 1+iQuad)
10874           {
10875             for ( int j = 0; j < nodes.size(); ++j )
10876               nodes[j] =nn[i+j];
10877             if ( const SMDS_MeshElement* edge =
10878                  aMesh->FindElement(nodes,SMDSAbs_Edge,/*noMedium=*/0))
10879               presentBndElems.push_back( edge );
10880             else
10881               missingBndElems.push_back( nodes );
10882           }
10883         }
10884         else // boundary face
10885         {
10886           nodes.clear();
10887           for ( inode = 0; inode < nbFaceNodes; inode += 1+iQuad)
10888             nodes.push_back( nn[inode] );
10889           if (iQuad)
10890             for ( inode = 1; inode < nbFaceNodes; inode += 2)
10891               nodes.push_back( nn[inode] );
10892
10893           if (const SMDS_MeshFace * f = aMesh->FindFace( nodes ) )
10894             presentBndElems.push_back( f );
10895           else
10896             missingBndElems.push_back( nodes );
10897         }
10898       }
10899     }
10900     else                     // elem is a face ------------------------------------------
10901     {
10902       avoidSet.clear(), avoidSet.insert( elem );
10903       int nbNodes = elem->NbCornerNodes();
10904       nodes.resize( 2 /*+ iQuad*/);
10905       for ( int i = 0; i < nbNodes; i++ )
10906       {
10907         nodes[0] = elem->GetNode(i);
10908         nodes[1] = elem->GetNode((i+1)%nbNodes);
10909         if ( FindFaceInSet( nodes[0], nodes[1], emptySet, avoidSet))
10910           continue; // not free link
10911
10912         //if ( iQuad )
10913         //nodes[2] = elem->GetNode( i + nbNodes );
10914         if ( const SMDS_MeshElement* edge =
10915              aMesh->FindElement(nodes,SMDSAbs_Edge,/*noMedium=*/true))
10916           presentBndElems.push_back( edge );
10917         else
10918           missingBndElems.push_back( nodes );
10919       }
10920     }
10921
10922     // 2. Add missing boundary elements
10923     if ( targetMesh != myMesh )
10924       // instead of making a map of nodes in this mesh and targetMesh,
10925       // we create nodes with same IDs. We can renumber them later, if needed
10926       for ( int i = 0; i < missingBndElems.size(); ++i )
10927       {
10928         TConnectivity& srcNodes = missingBndElems[i];
10929         TConnectivity  nodes( srcNodes.size() );
10930         for ( inode = 0; inode < nodes.size(); ++inode )
10931           nodes[inode] = getNodeWithSameID( tgtMeshDS, srcNodes[inode] );
10932         tgtEditor.AddElement(nodes, missType, elem->IsPoly() && nodes.size()/(iQuad+1)>4);
10933       }
10934     else
10935       for ( int i = 0; i < missingBndElems.size(); ++i )
10936       {
10937         TConnectivity&  nodes = missingBndElems[i];
10938         tgtEditor.AddElement(nodes, missType, elem->IsPoly() && nodes.size()/(iQuad+1)>4);
10939       }
10940
10941     // 3. Copy present boundary elements
10942     if ( toCopyExistingBondary )
10943       for ( int i = 0 ; i < presentBndElems.size(); ++i )
10944       {
10945         const SMDS_MeshElement* e = presentBndElems[i];
10946         TConnectivity nodes( e->NbNodes() );
10947         for ( inode = 0; inode < nodes.size(); ++inode )
10948           nodes[inode] = getNodeWithSameID( tgtMeshDS, e->GetNode(inode) );
10949         tgtEditor.AddElement(nodes, missType, e->IsPoly());
10950         // leave only missing elements in tgtEditor.myLastCreatedElems
10951         tgtEditor.myLastCreatedElems.Remove( tgtEditor.myLastCreatedElems.Size() );
10952       }
10953   } // loop on given elements
10954
10955   // 4. Fill group with missing boundary elements
10956   if ( group )
10957   {
10958     if ( SMESHDS_Group* g = dynamic_cast<SMESHDS_Group*>( group->GetGroupDS() ))
10959       for ( int i = 0; i < tgtEditor.myLastCreatedElems.Size(); ++i )
10960         g->SMDSGroup().Add( tgtEditor.myLastCreatedElems( i+1 ));
10961   }
10962   tgtEditor.myLastCreatedElems.Clear();
10963
10964   // 5. Copy given elements
10965   if ( toCopyElements )
10966   {
10967     if (elements.empty())
10968       eIt = aMesh->elementsIterator(elemType);
10969     else
10970       eIt = SMDS_ElemIteratorPtr( new TSetIterator( elements.begin(), elements.end() ));
10971     while (eIt->more())
10972     {
10973       const SMDS_MeshElement* elem = eIt->next();
10974       TConnectivity nodes( elem->NbNodes() );
10975       for ( inode = 0; inode < nodes.size(); ++inode )
10976         nodes[inode] = getNodeWithSameID( tgtMeshDS, elem->GetNode(inode) );
10977       tgtEditor.AddElement(nodes, elemType, elem->IsPoly());
10978
10979       tgtEditor.myLastCreatedElems.Clear();
10980     }
10981   }
10982   return;
10983 }