Salome HOME
PR: correct some warnings
[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 //  list<SMDS_MeshNode>          orphanCopy; // copies of orphan nodes
5350 //  vector<const SMDS_MeshNode*> orphanNode; // original orphan nodes
5351 //
5352 //  if ( theElems.empty() ) // transform the whole mesh
5353 //  {
5354 //    // add all elements
5355 //    SMDS_ElemIteratorPtr eIt = aMesh->elementsIterator();
5356 //    while ( eIt->more() ) theElems.insert( eIt->next() );
5357 //    // add orphan nodes
5358 //    SMDS_MeshElementIDFactory idFactory;
5359 //    SMDS_NodeIteratorPtr nIt = aMesh->nodesIterator();
5360 //    while ( nIt->more() )
5361 //    {
5362 //      const SMDS_MeshNode* node = nIt->next();
5363 //      if ( node->NbInverseElements() == 0 && !theElems.insert( node ).second )
5364 //      {
5365 //        // node was not inserted into theElems because an element with the same ID
5366 //        // is already there. As a work around we insert a copy of node with
5367 //        // an ID = -<index in orphanNode>
5368 //        orphanCopy.push_back( *node ); // copy node
5369 //        SMDS_MeshNode* nodeCopy = &orphanCopy.back();
5370 //        int uniqueID = -orphanNode.size();
5371 //        orphanNode.push_back( node );
5372 //        idFactory.BindID( uniqueID, nodeCopy );
5373 //        theElems.insert( nodeCopy );
5374 //      }
5375 //    }
5376 //  }
5377   // loop on theElems to transorm nodes
5378   TIDSortedElemSet::iterator itElem;
5379   for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
5380     const SMDS_MeshElement* elem = *itElem;
5381     if ( !elem )
5382       continue;
5383
5384     // loop on elem nodes
5385     SMDS_ElemIteratorPtr itN = elem->nodesIterator();
5386     while ( itN->more() ) {
5387
5388       const SMDS_MeshNode* node = cast2Node( itN->next() );
5389 //      if ( node->GetID() < 0 )
5390 //        node = orphanNode[ -node->GetID() ];
5391       // check if a node has been already transformed
5392       pair<TNodeNodeMap::iterator,bool> n2n_isnew =
5393         nodeMap.insert( make_pair ( node, node ));
5394       if ( !n2n_isnew.second )
5395         continue;
5396
5397       double coord[3];
5398       coord[0] = node->X();
5399       coord[1] = node->Y();
5400       coord[2] = node->Z();
5401       theTrsf.Transforms( coord[0], coord[1], coord[2] );
5402       if ( theTargetMesh ) {
5403         const SMDS_MeshNode * newNode = aTgtMesh->AddNode( coord[0], coord[1], coord[2] );
5404         n2n_isnew.first->second = newNode;
5405         myLastCreatedNodes.Append(newNode);
5406         srcNodes.Append( node );
5407       }
5408       else if ( theCopy ) {
5409         const SMDS_MeshNode * newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
5410         n2n_isnew.first->second = newNode;
5411         myLastCreatedNodes.Append(newNode);
5412         srcNodes.Append( node );
5413       }
5414       else {
5415         aMesh->MoveNode( node, coord[0], coord[1], coord[2] );
5416         // node position on shape becomes invalid
5417         const_cast< SMDS_MeshNode* > ( node )->SetPosition
5418           ( SMDS_SpacePosition::originSpacePosition() );
5419       }
5420
5421       // keep inverse elements
5422       if ( !theCopy && !theTargetMesh && needReverse ) {
5423         SMDS_ElemIteratorPtr invElemIt = node->GetInverseElementIterator();
5424         while ( invElemIt->more() ) {
5425           const SMDS_MeshElement* iel = invElemIt->next();
5426           inverseElemSet.insert( iel );
5427         }
5428       }
5429     }
5430   }
5431
5432   // either create new elements or reverse mirrored ones
5433   if ( !theCopy && !needReverse && !theTargetMesh )
5434     return PGroupIDs();
5435
5436   TIDSortedElemSet::iterator invElemIt = inverseElemSet.begin();
5437   for ( ; invElemIt != inverseElemSet.end(); invElemIt++ )
5438     theElems.insert( *invElemIt );
5439
5440   // replicate or reverse elements
5441   // TODO revoir ordre reverse vtk
5442   enum {
5443     REV_TETRA   = 0,  //  = nbNodes - 4
5444     REV_PYRAMID = 1,  //  = nbNodes - 4
5445     REV_PENTA   = 2,  //  = nbNodes - 4
5446     REV_FACE    = 3,
5447     REV_HEXA    = 4,  //  = nbNodes - 4
5448     FORWARD     = 5
5449   };
5450   int index[][8] = {
5451     { 2, 1, 0, 3, 4, 0, 0, 0 },  // REV_TETRA
5452     { 2, 1, 0, 3, 4, 0, 0, 0 },  // REV_PYRAMID
5453     { 2, 1, 0, 5, 4, 3, 0, 0 },  // REV_PENTA
5454     { 2, 1, 0, 3, 0, 0, 0, 0 },  // REV_FACE
5455     { 2, 1, 0, 3, 6, 5, 4, 7 },  // REV_HEXA
5456     { 0, 1, 2, 3, 4, 5, 6, 7 }   // FORWARD
5457   };
5458
5459   for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ )
5460   {
5461     const SMDS_MeshElement* elem = *itElem;
5462     if ( !elem || elem->GetType() == SMDSAbs_Node )
5463       continue;
5464
5465     int nbNodes = elem->NbNodes();
5466     int elemType = elem->GetType();
5467
5468     if (elem->IsPoly()) {
5469       // Polygon or Polyhedral Volume
5470       switch ( elemType ) {
5471       case SMDSAbs_Face:
5472         {
5473           vector<const SMDS_MeshNode*> poly_nodes (nbNodes);
5474           int iNode = 0;
5475           SMDS_ElemIteratorPtr itN = elem->nodesIterator();
5476           while (itN->more()) {
5477             const SMDS_MeshNode* node =
5478               static_cast<const SMDS_MeshNode*>(itN->next());
5479             TNodeNodeMap::iterator nodeMapIt = nodeMap.find(node);
5480             if (nodeMapIt == nodeMap.end())
5481               break; // not all nodes transformed
5482             if (needReverse) {
5483               // reverse mirrored faces and volumes
5484               poly_nodes[nbNodes - iNode - 1] = (*nodeMapIt).second;
5485             } else {
5486               poly_nodes[iNode] = (*nodeMapIt).second;
5487             }
5488             iNode++;
5489           }
5490           if ( iNode != nbNodes )
5491             continue; // not all nodes transformed
5492
5493           if ( theTargetMesh ) {
5494             myLastCreatedElems.Append(aTgtMesh->AddPolygonalFace(poly_nodes));
5495             srcElems.Append( elem );
5496           }
5497           else if ( theCopy ) {
5498             myLastCreatedElems.Append(aMesh->AddPolygonalFace(poly_nodes));
5499             srcElems.Append( elem );
5500           }
5501           else {
5502             aMesh->ChangePolygonNodes(elem, poly_nodes);
5503           }
5504         }
5505         break;
5506       case SMDSAbs_Volume:
5507         {
5508           // ATTENTION: Reversing is not yet done!!!
5509           const SMDS_VtkVolume* aPolyedre =
5510             dynamic_cast<const SMDS_VtkVolume*>( elem );
5511           if (!aPolyedre) {
5512             MESSAGE("Warning: bad volumic element");
5513             continue;
5514           }
5515
5516           vector<const SMDS_MeshNode*> poly_nodes;
5517           vector<int> quantities;
5518
5519           bool allTransformed = true;
5520           int nbFaces = aPolyedre->NbFaces();
5521           for (int iface = 1; iface <= nbFaces && allTransformed; iface++) {
5522             int nbFaceNodes = aPolyedre->NbFaceNodes(iface);
5523             for (int inode = 1; inode <= nbFaceNodes && allTransformed; inode++) {
5524               const SMDS_MeshNode* node = aPolyedre->GetFaceNode(iface, inode);
5525               TNodeNodeMap::iterator nodeMapIt = nodeMap.find(node);
5526               if (nodeMapIt == nodeMap.end()) {
5527                 allTransformed = false; // not all nodes transformed
5528               } else {
5529                 poly_nodes.push_back((*nodeMapIt).second);
5530               }
5531             }
5532             quantities.push_back(nbFaceNodes);
5533           }
5534           if ( !allTransformed )
5535             continue; // not all nodes transformed
5536
5537           if ( theTargetMesh ) {
5538             myLastCreatedElems.Append(aTgtMesh->AddPolyhedralVolume(poly_nodes, quantities));
5539             srcElems.Append( elem );
5540           }
5541           else if ( theCopy ) {
5542             myLastCreatedElems.Append(aMesh->AddPolyhedralVolume(poly_nodes, quantities));
5543             srcElems.Append( elem );
5544           }
5545           else {
5546             aMesh->ChangePolyhedronNodes(elem, poly_nodes, quantities);
5547           }
5548         }
5549         break;
5550       default:;
5551       }
5552       continue;
5553     }
5554
5555     // Regular elements
5556     int* i = index[ FORWARD ];
5557     if ( needReverse && nbNodes > 2) {// reverse mirrored faces and volumes
5558       if ( elemType == SMDSAbs_Face )
5559         i = index[ REV_FACE ];
5560       else
5561         i = index[ nbNodes - 4 ];
5562     }
5563     if(elem->IsQuadratic()) {
5564       static int anIds[] = {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19};
5565       i = anIds;
5566       if(needReverse) {
5567         if(nbNodes==3) { // quadratic edge
5568           static int anIds[] = {1,0,2};
5569           i = anIds;
5570         }
5571         else if(nbNodes==6) { // quadratic triangle
5572           static int anIds[] = {0,2,1,5,4,3};
5573           i = anIds;
5574         }
5575         else if(nbNodes==8) { // quadratic quadrangle
5576           static int anIds[] = {0,3,2,1,7,6,5,4};
5577           i = anIds;
5578         }
5579         else if(nbNodes==10) { // quadratic tetrahedron of 10 nodes
5580           static int anIds[] = {0,2,1,3,6,5,4,7,9,8};
5581           i = anIds;
5582         }
5583         else if(nbNodes==13) { // quadratic pyramid of 13 nodes
5584           static int anIds[] = {0,3,2,1,4,8,7,6,5,9,12,11,10};
5585           i = anIds;
5586         }
5587         else if(nbNodes==15) { // quadratic pentahedron with 15 nodes
5588           static int anIds[] = {0,2,1,3,5,4,8,7,6,11,10,9,12,14,13};
5589           i = anIds;
5590         }
5591         else { // nbNodes==20 - quadratic hexahedron with 20 nodes
5592           static int anIds[] = {0,3,2,1,4,7,6,5,11,10,9,8,15,14,13,12,16,19,18,17};
5593           i = anIds;
5594         }
5595       }
5596     }
5597
5598     // find transformed nodes
5599     vector<const SMDS_MeshNode*> nodes(nbNodes);
5600     int iNode = 0;
5601     SMDS_ElemIteratorPtr itN = elem->nodesIterator();
5602     while ( itN->more() ) {
5603       const SMDS_MeshNode* node =
5604         static_cast<const SMDS_MeshNode*>( itN->next() );
5605       TNodeNodeMap::iterator nodeMapIt = nodeMap.find( node );
5606       if ( nodeMapIt == nodeMap.end() )
5607         break; // not all nodes transformed
5608       nodes[ i [ iNode++ ]] = (*nodeMapIt).second;
5609     }
5610     if ( iNode != nbNodes )
5611       continue; // not all nodes transformed
5612
5613     if ( theTargetMesh ) {
5614       if ( SMDS_MeshElement* copy =
5615            targetMeshEditor.AddElement( nodes, elem->GetType(), elem->IsPoly() )) {
5616         myLastCreatedElems.Append( copy );
5617         srcElems.Append( elem );
5618       }
5619     }
5620     else if ( theCopy ) {
5621       if ( AddElement( nodes, elem->GetType(), elem->IsPoly() ))
5622         srcElems.Append( elem );
5623     }
5624     else {
5625       // reverse element as it was reversed by transformation
5626       if ( nbNodes > 2 )
5627         aMesh->ChangeElementNodes( elem, &nodes[0], nbNodes );
5628     }
5629   }
5630
5631   PGroupIDs newGroupIDs;
5632
5633   if ( theMakeGroups && theCopy ||
5634        theMakeGroups && theTargetMesh )
5635     newGroupIDs = generateGroups( srcNodes, srcElems, groupPostfix, theTargetMesh );
5636
5637   return newGroupIDs;
5638 }
5639
5640
5641 ////=======================================================================
5642 ////function : Scale
5643 ////purpose  :
5644 ////=======================================================================
5645 //
5646 //SMESH_MeshEditor::PGroupIDs
5647 //SMESH_MeshEditor::Scale (TIDSortedElemSet & theElems,
5648 //                         const gp_Pnt&            thePoint,
5649 //                         const std::list<double>& theScaleFact,
5650 //                         const bool         theCopy,
5651 //                         const bool         theMakeGroups,
5652 //                         SMESH_Mesh*        theTargetMesh)
5653 //{
5654 //  MESSAGE("Scale");
5655 //  myLastCreatedElems.Clear();
5656 //  myLastCreatedNodes.Clear();
5657 //
5658 //  SMESH_MeshEditor targetMeshEditor( theTargetMesh );
5659 //  SMESHDS_Mesh* aTgtMesh = theTargetMesh ? theTargetMesh->GetMeshDS() : 0;
5660 //  SMESHDS_Mesh* aMesh    = GetMeshDS();
5661 //
5662 //  double scaleX=1.0, scaleY=1.0, scaleZ=1.0;
5663 //  std::list<double>::const_iterator itS = theScaleFact.begin();
5664 //  scaleX = (*itS);
5665 //  if(theScaleFact.size()==1) {
5666 //    scaleY = (*itS);
5667 //    scaleZ= (*itS);
5668 //  }
5669 //  if(theScaleFact.size()==2) {
5670 //    itS++;
5671 //    scaleY = (*itS);
5672 //    scaleZ= (*itS);
5673 //  }
5674 //  if(theScaleFact.size()>2) {
5675 //    itS++;
5676 //    scaleY = (*itS);
5677 //    itS++;
5678 //    scaleZ= (*itS);
5679 //  }
5680 //
5681 //  // map old node to new one
5682 //  TNodeNodeMap nodeMap;
5683 //
5684 //  // elements sharing moved nodes; those of them which have all
5685 //  // nodes mirrored but are not in theElems are to be reversed
5686 //  TIDSortedElemSet inverseElemSet;
5687 //
5688 //  // source elements for each generated one
5689 //  SMESH_SequenceOfElemPtr srcElems, srcNodes;
5690 //
5691 //  // loop on theElems
5692 //  TIDSortedElemSet::iterator itElem;
5693 //  for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
5694 //    const SMDS_MeshElement* elem = *itElem;
5695 //    if ( !elem )
5696 //      continue;
5697 //
5698 //    // loop on elem nodes
5699 //    SMDS_ElemIteratorPtr itN = elem->nodesIterator();
5700 //    while ( itN->more() ) {
5701 //
5702 //      // check if a node has been already transformed
5703 //      const SMDS_MeshNode* node = cast2Node( itN->next() );
5704 //      pair<TNodeNodeMap::iterator,bool> n2n_isnew =
5705 //        nodeMap.insert( make_pair ( node, node ));
5706 //      if ( !n2n_isnew.second )
5707 //        continue;
5708 //
5709 //      //double coord[3];
5710 //      //coord[0] = node->X();
5711 //      //coord[1] = node->Y();
5712 //      //coord[2] = node->Z();
5713 //      //theTrsf.Transforms( coord[0], coord[1], coord[2] );
5714 //      double dx = (node->X() - thePoint.X()) * scaleX;
5715 //      double dy = (node->Y() - thePoint.Y()) * scaleY;
5716 //      double dz = (node->Z() - thePoint.Z()) * scaleZ;
5717 //      if ( theTargetMesh ) {
5718 //        //const SMDS_MeshNode * newNode = aTgtMesh->AddNode( coord[0], coord[1], coord[2] );
5719 //        const SMDS_MeshNode * newNode =
5720 //          aTgtMesh->AddNode( thePoint.X()+dx, thePoint.Y()+dy, thePoint.Z()+dz );
5721 //        n2n_isnew.first->second = newNode;
5722 //        myLastCreatedNodes.Append(newNode);
5723 //        srcNodes.Append( node );
5724 //      }
5725 //      else if ( theCopy ) {
5726 //        //const SMDS_MeshNode * newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
5727 //        const SMDS_MeshNode * newNode =
5728 //          aMesh->AddNode( thePoint.X()+dx, thePoint.Y()+dy, thePoint.Z()+dz );
5729 //        n2n_isnew.first->second = newNode;
5730 //        myLastCreatedNodes.Append(newNode);
5731 //        srcNodes.Append( node );
5732 //      }
5733 //      else {
5734 //        //aMesh->MoveNode( node, coord[0], coord[1], coord[2] );
5735 //        aMesh->MoveNode( node, thePoint.X()+dx, thePoint.Y()+dy, thePoint.Z()+dz );
5736 //        // node position on shape becomes invalid
5737 //        const_cast< SMDS_MeshNode* > ( node )->SetPosition
5738 //          ( SMDS_SpacePosition::originSpacePosition() );
5739 //      }
5740 //
5741 //      // keep inverse elements
5742 //      //if ( !theCopy && !theTargetMesh && needReverse ) {
5743 //      //  SMDS_ElemIteratorPtr invElemIt = node->GetInverseElementIterator();
5744 //      //  while ( invElemIt->more() ) {
5745 //      //    const SMDS_MeshElement* iel = invElemIt->next();
5746 //      //    inverseElemSet.insert( iel );
5747 //      //  }
5748 //      //}
5749 //    }
5750 //  }
5751 //
5752 //  // either create new elements or reverse mirrored ones
5753 //  //if ( !theCopy && !needReverse && !theTargetMesh )
5754 //  if ( !theCopy && !theTargetMesh )
5755 //    return PGroupIDs();
5756 //
5757 //  TIDSortedElemSet::iterator invElemIt = inverseElemSet.begin();
5758 //  for ( ; invElemIt != inverseElemSet.end(); invElemIt++ )
5759 //    theElems.insert( *invElemIt );
5760 //
5761 //  // replicate or reverse elements
5762 //
5763 //  enum {
5764 //    REV_TETRA   = 0,  //  = nbNodes - 4
5765 //    REV_PYRAMID = 1,  //  = nbNodes - 4
5766 //    REV_PENTA   = 2,  //  = nbNodes - 4
5767 //    REV_FACE    = 3,
5768 //    REV_HEXA    = 4,  //  = nbNodes - 4
5769 //    FORWARD     = 5
5770 //  };
5771 //  int index[][8] = {
5772 //    { 2, 1, 0, 3, 4, 0, 0, 0 },  // REV_TETRA
5773 //    { 2, 1, 0, 3, 4, 0, 0, 0 },  // REV_PYRAMID
5774 //    { 2, 1, 0, 5, 4, 3, 0, 0 },  // REV_PENTA
5775 //    { 2, 1, 0, 3, 0, 0, 0, 0 },  // REV_FACE
5776 //    { 2, 1, 0, 3, 6, 5, 4, 7 },  // REV_HEXA
5777 //    { 0, 1, 2, 3, 4, 5, 6, 7 }   // FORWARD
5778 //  };
5779 //
5780 //  for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ )
5781 //  {
5782 //    const SMDS_MeshElement* elem = *itElem;
5783 //    if ( !elem || elem->GetType() == SMDSAbs_Node )
5784 //      continue;
5785 //
5786 //    int nbNodes = elem->NbNodes();
5787 //    int elemType = elem->GetType();
5788 //
5789 //    if (elem->IsPoly()) {
5790 //      // Polygon or Polyhedral Volume
5791 //      switch ( elemType ) {
5792 //      case SMDSAbs_Face:
5793 //        {
5794 //          vector<const SMDS_MeshNode*> poly_nodes (nbNodes);
5795 //          int iNode = 0;
5796 //          SMDS_ElemIteratorPtr itN = elem->nodesIterator();
5797 //          while (itN->more()) {
5798 //            const SMDS_MeshNode* node =
5799 //              static_cast<const SMDS_MeshNode*>(itN->next());
5800 //            TNodeNodeMap::iterator nodeMapIt = nodeMap.find(node);
5801 //            if (nodeMapIt == nodeMap.end())
5802 //              break; // not all nodes transformed
5803 //            //if (needReverse) {
5804 //            //  // reverse mirrored faces and volumes
5805 //            //  poly_nodes[nbNodes - iNode - 1] = (*nodeMapIt).second;
5806 //            //} else {
5807 //            poly_nodes[iNode] = (*nodeMapIt).second;
5808 //            //}
5809 //            iNode++;
5810 //          }
5811 //          if ( iNode != nbNodes )
5812 //            continue; // not all nodes transformed
5813 //
5814 //          if ( theTargetMesh ) {
5815 //            myLastCreatedElems.Append(aTgtMesh->AddPolygonalFace(poly_nodes));
5816 //            srcElems.Append( elem );
5817 //          }
5818 //          else if ( theCopy ) {
5819 //            myLastCreatedElems.Append(aMesh->AddPolygonalFace(poly_nodes));
5820 //            srcElems.Append( elem );
5821 //          }
5822 //          else {
5823 //            aMesh->ChangePolygonNodes(elem, poly_nodes);
5824 //          }
5825 //        }
5826 //        break;
5827 //      case SMDSAbs_Volume:
5828 //        {
5829 //          // ATTENTION: Reversing is not yet done!!!
5830 //          const SMDS_VtkVolume* aPolyedre =
5831 //            dynamic_cast<const SMDS_VtkVolume*>( elem );
5832 //          if (!aPolyedre) {
5833 //            MESSAGE("Warning: bad volumic element");
5834 //            continue;
5835 //          }
5836 //
5837 //          vector<const SMDS_MeshNode*> poly_nodes;
5838 //          vector<int> quantities;
5839 //
5840 //          bool allTransformed = true;
5841 //          int nbFaces = aPolyedre->NbFaces();
5842 //          for (int iface = 1; iface <= nbFaces && allTransformed; iface++) {
5843 //            int nbFaceNodes = aPolyedre->NbFaceNodes(iface);
5844 //            for (int inode = 1; inode <= nbFaceNodes && allTransformed; inode++) {
5845 //              const SMDS_MeshNode* node = aPolyedre->GetFaceNode(iface, inode);
5846 //              TNodeNodeMap::iterator nodeMapIt = nodeMap.find(node);
5847 //              if (nodeMapIt == nodeMap.end()) {
5848 //                allTransformed = false; // not all nodes transformed
5849 //              } else {
5850 //                poly_nodes.push_back((*nodeMapIt).second);
5851 //              }
5852 //            }
5853 //            quantities.push_back(nbFaceNodes);
5854 //          }
5855 //          if ( !allTransformed )
5856 //            continue; // not all nodes transformed
5857 //
5858 //          if ( theTargetMesh ) {
5859 //            myLastCreatedElems.Append(aTgtMesh->AddPolyhedralVolume(poly_nodes, quantities));
5860 //            srcElems.Append( elem );
5861 //          }
5862 //          else if ( theCopy ) {
5863 //            myLastCreatedElems.Append(aMesh->AddPolyhedralVolume(poly_nodes, quantities));
5864 //            srcElems.Append( elem );
5865 //          }
5866 //          else {
5867 //            aMesh->ChangePolyhedronNodes(elem, poly_nodes, quantities);
5868 //          }
5869 //        }
5870 //        break;
5871 //      default:;
5872 //      }
5873 //      continue;
5874 //    }
5875 //
5876 //    // Regular elements
5877 //    int* i = index[ FORWARD ];
5878 //    //if ( needReverse && nbNodes > 2) // reverse mirrored faces and volumes
5879 //    //  if ( elemType == SMDSAbs_Face )
5880 //    //    i = index[ REV_FACE ];
5881 //    //  else
5882 //    //    i = index[ nbNodes - 4 ];
5883 //
5884 //    if(elem->IsQuadratic()) {
5885 //      static int anIds[] = {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19};
5886 //      i = anIds;
5887 //      //if(needReverse) {
5888 //      //  if(nbNodes==3) { // quadratic edge
5889 //      //    static int anIds[] = {1,0,2};
5890 //      //    i = anIds;
5891 //      //  }
5892 //      //  else if(nbNodes==6) { // quadratic triangle
5893 //      //    static int anIds[] = {0,2,1,5,4,3};
5894 //      //    i = anIds;
5895 //      //  }
5896 //      //  else if(nbNodes==8) { // quadratic quadrangle
5897 //      //    static int anIds[] = {0,3,2,1,7,6,5,4};
5898 //      //    i = anIds;
5899 //      //  }
5900 //      //  else if(nbNodes==10) { // quadratic tetrahedron of 10 nodes
5901 //      //    static int anIds[] = {0,2,1,3,6,5,4,7,9,8};
5902 //      //    i = anIds;
5903 //      //  }
5904 //      //  else if(nbNodes==13) { // quadratic pyramid of 13 nodes
5905 //      //    static int anIds[] = {0,3,2,1,4,8,7,6,5,9,12,11,10};
5906 //      //    i = anIds;
5907 //      //  }
5908 //      //  else if(nbNodes==15) { // quadratic pentahedron with 15 nodes
5909 //      //    static int anIds[] = {0,2,1,3,5,4,8,7,6,11,10,9,12,14,13};
5910 //      //    i = anIds;
5911 //      //  }
5912 //      //  else { // nbNodes==20 - quadratic hexahedron with 20 nodes
5913 //      //    static int anIds[] = {0,3,2,1,4,7,6,5,11,10,9,8,15,14,13,12,16,19,18,17};
5914 //      //    i = anIds;
5915 //      //  }
5916 //      //}
5917 //    }
5918 //
5919 //    // find transformed nodes
5920 //    vector<const SMDS_MeshNode*> nodes(nbNodes);
5921 //    int iNode = 0;
5922 //    SMDS_ElemIteratorPtr itN = elem->nodesIterator();
5923 //    while ( itN->more() ) {
5924 //      const SMDS_MeshNode* node =
5925 //        static_cast<const SMDS_MeshNode*>( itN->next() );
5926 //      TNodeNodeMap::iterator nodeMapIt = nodeMap.find( node );
5927 //      if ( nodeMapIt == nodeMap.end() )
5928 //        break; // not all nodes transformed
5929 //      nodes[ i [ iNode++ ]] = (*nodeMapIt).second;
5930 //    }
5931 //    if ( iNode != nbNodes )
5932 //      continue; // not all nodes transformed
5933 //
5934 //    if ( theTargetMesh ) {
5935 //      if ( SMDS_MeshElement* copy =
5936 //           targetMeshEditor.AddElement( nodes, elem->GetType(), elem->IsPoly() )) {
5937 //        myLastCreatedElems.Append( copy );
5938 //        srcElems.Append( elem );
5939 //      }
5940 //    }
5941 //    else if ( theCopy ) {
5942 //      if ( SMDS_MeshElement* copy = AddElement( nodes, elem->GetType(), elem->IsPoly() )) {
5943 //        myLastCreatedElems.Append( copy );
5944 //        srcElems.Append( elem );
5945 //      }
5946 //    }
5947 //    else {
5948 //      // reverse element as it was reversed by transformation
5949 //      if ( nbNodes > 2 )
5950 //        aMesh->ChangeElementNodes( elem, &nodes[0], nbNodes );
5951 //    }
5952 //  }
5953 //
5954 //  PGroupIDs newGroupIDs;
5955 //
5956 //  if ( theMakeGroups && theCopy ||
5957 //       theMakeGroups && theTargetMesh ) {
5958 //    string groupPostfix = "scaled";
5959 //    newGroupIDs = generateGroups( srcNodes, srcElems, groupPostfix, theTargetMesh );
5960 //  }
5961 //
5962 //  return newGroupIDs;
5963 //}
5964
5965
5966 //=======================================================================
5967 /*!
5968  * \brief Create groups of elements made during transformation
5969  * \param nodeGens - nodes making corresponding myLastCreatedNodes
5970  * \param elemGens - elements making corresponding myLastCreatedElems
5971  * \param postfix - to append to names of new groups
5972  */
5973 //=======================================================================
5974
5975 SMESH_MeshEditor::PGroupIDs
5976 SMESH_MeshEditor::generateGroups(const SMESH_SequenceOfElemPtr& nodeGens,
5977                                  const SMESH_SequenceOfElemPtr& elemGens,
5978                                  const std::string&             postfix,
5979                                  SMESH_Mesh*                    targetMesh)
5980 {
5981   PGroupIDs newGroupIDs( new list<int> );
5982   SMESH_Mesh* mesh = targetMesh ? targetMesh : GetMesh();
5983
5984   // Sort existing groups by types and collect their names
5985
5986   // to store an old group and a generated new one
5987   typedef pair< SMESHDS_GroupBase*, SMDS_MeshGroup* > TOldNewGroup;
5988   vector< list< TOldNewGroup > > groupsByType( SMDSAbs_NbElementTypes );
5989   // group names
5990   set< string > groupNames;
5991   //
5992   SMDS_MeshGroup* nullNewGroup = (SMDS_MeshGroup*) 0;
5993   SMESH_Mesh::GroupIteratorPtr groupIt = GetMesh()->GetGroups();
5994   while ( groupIt->more() ) {
5995     SMESH_Group * group = groupIt->next();
5996     if ( !group ) continue;
5997     SMESHDS_GroupBase* groupDS = group->GetGroupDS();
5998     if ( !groupDS || groupDS->IsEmpty() ) continue;
5999     groupNames.insert( group->GetName() );
6000     groupDS->SetStoreName( group->GetName() );
6001     groupsByType[ groupDS->GetType() ].push_back( make_pair( groupDS, nullNewGroup ));
6002   }
6003
6004   // Groups creation
6005
6006   // loop on nodes and elements
6007   for ( int isNodes = 0; isNodes < 2; ++isNodes )
6008   {
6009     const SMESH_SequenceOfElemPtr& gens  = isNodes ? nodeGens : elemGens;
6010     const SMESH_SequenceOfElemPtr& elems = isNodes ? myLastCreatedNodes : myLastCreatedElems;
6011     if ( gens.Length() != elems.Length() )
6012       throw SALOME_Exception(LOCALIZED("invalid args"));
6013
6014     // loop on created elements
6015     for (int iElem = 1; iElem <= elems.Length(); ++iElem )
6016     {
6017       const SMDS_MeshElement* sourceElem = gens( iElem );
6018       if ( !sourceElem ) {
6019         MESSAGE("generateGroups(): NULL source element");
6020         continue;
6021       }
6022       list< TOldNewGroup > & groupsOldNew = groupsByType[ sourceElem->GetType() ];
6023       if ( groupsOldNew.empty() ) {
6024         while ( iElem < gens.Length() && gens( iElem+1 ) == sourceElem )
6025           ++iElem; // skip all elements made by sourceElem
6026         continue;
6027       }
6028       // collect all elements made by sourceElem
6029       list< const SMDS_MeshElement* > resultElems;
6030       if ( const SMDS_MeshElement* resElem = elems( iElem ))
6031         if ( resElem != sourceElem )
6032           resultElems.push_back( resElem );
6033       while ( iElem < gens.Length() && gens( iElem+1 ) == sourceElem )
6034         if ( const SMDS_MeshElement* resElem = elems( ++iElem ))
6035           if ( resElem != sourceElem )
6036             resultElems.push_back( resElem );
6037       // do not generate element groups from node ones
6038       if ( sourceElem->GetType() == SMDSAbs_Node &&
6039            elems( iElem )->GetType() != SMDSAbs_Node )
6040         continue;
6041
6042       // add resultElems to groups made by ones the sourceElem belongs to
6043       list< TOldNewGroup >::iterator gOldNew, gLast = groupsOldNew.end();
6044       for ( gOldNew = groupsOldNew.begin(); gOldNew != gLast; ++gOldNew )
6045       {
6046         SMESHDS_GroupBase* oldGroup = gOldNew->first;
6047         if ( oldGroup->Contains( sourceElem )) // sourceElem in oldGroup
6048         {
6049           SMDS_MeshGroup* & newGroup = gOldNew->second;
6050           if ( !newGroup )// create a new group
6051           {
6052             // make a name
6053             string name = oldGroup->GetStoreName();
6054             if ( !targetMesh ) {
6055               name += "_";
6056               name += postfix;
6057               int nb = 0;
6058               while ( !groupNames.insert( name ).second ) // name exists
6059               {
6060                 if ( nb == 0 ) {
6061                   name += "_1";
6062                 }
6063                 else {
6064                   TCollection_AsciiString nbStr(nb+1);
6065                   name.resize( name.rfind('_')+1 );
6066                   name += nbStr.ToCString();
6067                 }
6068                 ++nb;
6069               }
6070             }
6071             // make a group
6072             int id;
6073             SMESH_Group* group = mesh->AddGroup( resultElems.back()->GetType(),
6074                                                  name.c_str(), id );
6075             SMESHDS_Group* groupDS = static_cast<SMESHDS_Group*>(group->GetGroupDS());
6076             newGroup = & groupDS->SMDSGroup();
6077             newGroupIDs->push_back( id );
6078           }
6079
6080           // fill in a new group
6081           list< const SMDS_MeshElement* >::iterator resLast = resultElems.end(), resElemIt;
6082           for ( resElemIt = resultElems.begin(); resElemIt != resLast; ++resElemIt )
6083             newGroup->Add( *resElemIt );
6084         }
6085       }
6086     } // loop on created elements
6087   }// loop on nodes and elements
6088
6089   return newGroupIDs;
6090 }
6091
6092 //================================================================================
6093 /*!
6094  * \brief Return list of group of nodes close to each other within theTolerance
6095  *        Search among theNodes or in the whole mesh if theNodes is empty using
6096  *        an Octree algorithm
6097  */
6098 //================================================================================
6099
6100 void SMESH_MeshEditor::FindCoincidentNodes (TIDSortedNodeSet &   theNodes,
6101                                             const double         theTolerance,
6102                                             TListOfListOfNodes & theGroupsOfNodes)
6103 {
6104   myLastCreatedElems.Clear();
6105   myLastCreatedNodes.Clear();
6106
6107   if ( theNodes.empty() )
6108   { // get all nodes in the mesh
6109     SMDS_NodeIteratorPtr nIt = GetMeshDS()->nodesIterator(/*idInceasingOrder=*/true);
6110     while ( nIt->more() )
6111       theNodes.insert( theNodes.end(),nIt->next());
6112   }
6113
6114   SMESH_OctreeNode::FindCoincidentNodes ( theNodes, &theGroupsOfNodes, theTolerance);
6115 }
6116
6117
6118 //=======================================================================
6119 /*!
6120  * \brief Implementation of search for the node closest to point
6121  */
6122 //=======================================================================
6123
6124 struct SMESH_NodeSearcherImpl: public SMESH_NodeSearcher
6125 {
6126   //---------------------------------------------------------------------
6127   /*!
6128    * \brief Constructor
6129    */
6130   SMESH_NodeSearcherImpl( const SMESHDS_Mesh* theMesh )
6131   {
6132     myMesh = ( SMESHDS_Mesh* ) theMesh;
6133
6134     TIDSortedNodeSet nodes;
6135     if ( theMesh ) {
6136       SMDS_NodeIteratorPtr nIt = theMesh->nodesIterator(/*idInceasingOrder=*/true);
6137       while ( nIt->more() )
6138         nodes.insert( nodes.end(), nIt->next() );
6139     }
6140     myOctreeNode = new SMESH_OctreeNode(nodes) ;
6141
6142     // get max size of a leaf box
6143     SMESH_OctreeNode* tree = myOctreeNode;
6144     while ( !tree->isLeaf() )
6145     {
6146       SMESH_OctreeNodeIteratorPtr cIt = tree->GetChildrenIterator();
6147       if ( cIt->more() )
6148         tree = cIt->next();
6149     }
6150     myHalfLeafSize = tree->maxSize() / 2.;
6151   }
6152
6153   //---------------------------------------------------------------------
6154   /*!
6155    * \brief Move node and update myOctreeNode accordingly
6156    */
6157   void MoveNode( const SMDS_MeshNode* node, const gp_Pnt& toPnt )
6158   {
6159     myOctreeNode->UpdateByMoveNode( node, toPnt );
6160     myMesh->MoveNode( node, toPnt.X(), toPnt.Y(), toPnt.Z() );
6161   }
6162
6163   //---------------------------------------------------------------------
6164   /*!
6165    * \brief Do it's job
6166    */
6167   const SMDS_MeshNode* FindClosestTo( const gp_Pnt& thePnt )
6168   {
6169     map<double, const SMDS_MeshNode*> dist2Nodes;
6170     myOctreeNode->NodesAround( thePnt.Coord(), dist2Nodes, myHalfLeafSize );
6171     if ( !dist2Nodes.empty() )
6172       return dist2Nodes.begin()->second;
6173     list<const SMDS_MeshNode*> nodes;
6174     //myOctreeNode->NodesAround( &tgtNode, &nodes, myHalfLeafSize );
6175
6176     double minSqDist = DBL_MAX;
6177     if ( nodes.empty() )  // get all nodes of OctreeNode's closest to thePnt
6178     {
6179       // sort leafs by their distance from thePnt
6180       typedef map< double, SMESH_OctreeNode* > TDistTreeMap;
6181       TDistTreeMap treeMap;
6182       list< SMESH_OctreeNode* > treeList;
6183       list< SMESH_OctreeNode* >::iterator trIt;
6184       treeList.push_back( myOctreeNode );
6185
6186       gp_XYZ pointNode( thePnt.X(), thePnt.Y(), thePnt.Z() );
6187       bool pointInside = myOctreeNode->isInside( pointNode, myHalfLeafSize );
6188       for ( trIt = treeList.begin(); trIt != treeList.end(); ++trIt)
6189       {
6190         SMESH_OctreeNode* tree = *trIt;
6191         if ( !tree->isLeaf() ) // put children to the queue
6192         {
6193           if ( pointInside && !tree->isInside( pointNode, myHalfLeafSize )) continue;
6194           SMESH_OctreeNodeIteratorPtr cIt = tree->GetChildrenIterator();
6195           while ( cIt->more() )
6196             treeList.push_back( cIt->next() );
6197         }
6198         else if ( tree->NbNodes() ) // put a tree to the treeMap
6199         {
6200           const Bnd_B3d& box = tree->getBox();
6201           double sqDist = thePnt.SquareDistance( 0.5 * ( box.CornerMin() + box.CornerMax() ));
6202           pair<TDistTreeMap::iterator,bool> it_in = treeMap.insert( make_pair( sqDist, tree ));
6203           if ( !it_in.second ) // not unique distance to box center
6204             treeMap.insert( it_in.first, make_pair( sqDist + 1e-13*treeMap.size(), tree ));
6205         }
6206       }
6207       // find distance after which there is no sense to check tree's
6208       double sqLimit = DBL_MAX;
6209       TDistTreeMap::iterator sqDist_tree = treeMap.begin();
6210       if ( treeMap.size() > 5 ) {
6211         SMESH_OctreeNode* closestTree = sqDist_tree->second;
6212         const Bnd_B3d& box = closestTree->getBox();
6213         double limit = sqrt( sqDist_tree->first ) + sqrt ( box.SquareExtent() );
6214         sqLimit = limit * limit;
6215       }
6216       // get all nodes from trees
6217       for ( ; sqDist_tree != treeMap.end(); ++sqDist_tree) {
6218         if ( sqDist_tree->first > sqLimit )
6219           break;
6220         SMESH_OctreeNode* tree = sqDist_tree->second;
6221         tree->NodesAround( tree->GetNodeIterator()->next(), &nodes );
6222       }
6223     }
6224     // find closest among nodes
6225     minSqDist = DBL_MAX;
6226     const SMDS_MeshNode* closestNode = 0;
6227     list<const SMDS_MeshNode*>::iterator nIt = nodes.begin();
6228     for ( ; nIt != nodes.end(); ++nIt ) {
6229       double sqDist = thePnt.SquareDistance( SMESH_MeshEditor::TNodeXYZ( *nIt ) );
6230       if ( minSqDist > sqDist ) {
6231         closestNode = *nIt;
6232         minSqDist = sqDist;
6233       }
6234     }
6235     return closestNode;
6236   }
6237
6238   //---------------------------------------------------------------------
6239   /*!
6240    * \brief Destructor
6241    */
6242   ~SMESH_NodeSearcherImpl() { delete myOctreeNode; }
6243
6244   //---------------------------------------------------------------------
6245   /*!
6246    * \brief Return the node tree
6247    */
6248   const SMESH_OctreeNode* getTree() const { return myOctreeNode; }
6249
6250 private:
6251   SMESH_OctreeNode* myOctreeNode;
6252   SMESHDS_Mesh*     myMesh;
6253   double            myHalfLeafSize; // max size of a leaf box
6254 };
6255
6256 //=======================================================================
6257 /*!
6258  * \brief Return SMESH_NodeSearcher
6259  */
6260 //=======================================================================
6261
6262 SMESH_NodeSearcher* SMESH_MeshEditor::GetNodeSearcher() 
6263 {
6264   return new SMESH_NodeSearcherImpl( GetMeshDS() );
6265 }
6266
6267 // ========================================================================
6268 namespace // Utils used in SMESH_ElementSearcherImpl::FindElementsByPoint()
6269 {
6270   const int MaxNbElemsInLeaf = 10; // maximal number of elements in a leaf of tree
6271   const int MaxLevel         = 7;  // maximal tree height -> nb terminal boxes: 8^7 = 2097152
6272   const double NodeRadius = 1e-9;  // to enlarge bnd box of element
6273
6274   //=======================================================================
6275   /*!
6276    * \brief Octal tree of bounding boxes of elements
6277    */
6278   //=======================================================================
6279
6280   class ElementBndBoxTree : public SMESH_Octree
6281   {
6282   public:
6283
6284     ElementBndBoxTree(const SMDS_Mesh& mesh, SMDSAbs_ElementType elemType, double tolerance = NodeRadius );
6285     void getElementsNearPoint( const gp_Pnt& point, TIDSortedElemSet& foundElems);
6286     void getElementsNearLine ( const gp_Ax1& line, TIDSortedElemSet& foundElems);
6287     ~ElementBndBoxTree();
6288
6289   protected:
6290     ElementBndBoxTree() {}
6291     SMESH_Octree* allocateOctreeChild() const { return new ElementBndBoxTree; }
6292     void buildChildrenData();
6293     Bnd_B3d* buildRootBox();
6294   private:
6295     //!< Bounding box of element
6296     struct ElementBox : public Bnd_B3d
6297     {
6298       const SMDS_MeshElement* _element;
6299       int                     _refCount; // an ElementBox can be included in several tree branches
6300       ElementBox(const SMDS_MeshElement* elem, double tolerance);
6301     };
6302     vector< ElementBox* > _elements;
6303   };
6304
6305   //================================================================================
6306   /*!
6307    * \brief ElementBndBoxTree creation
6308    */
6309   //================================================================================
6310
6311   ElementBndBoxTree::ElementBndBoxTree(const SMDS_Mesh& mesh, SMDSAbs_ElementType elemType, double tolerance)
6312     :SMESH_Octree( new SMESH_Octree::Limit( MaxLevel, /*minSize=*/0. ))
6313   {
6314     int nbElems = mesh.GetMeshInfo().NbElements( elemType );
6315     _elements.reserve( nbElems );
6316
6317     SMDS_ElemIteratorPtr elemIt = mesh.elementsIterator( elemType );
6318     while ( elemIt->more() )
6319       _elements.push_back( new ElementBox( elemIt->next(),tolerance  ));
6320
6321     if ( _elements.size() > MaxNbElemsInLeaf )
6322       compute();
6323     else
6324       myIsLeaf = true;
6325   }
6326
6327   //================================================================================
6328   /*!
6329    * \brief Destructor
6330    */
6331   //================================================================================
6332
6333   ElementBndBoxTree::~ElementBndBoxTree()
6334   {
6335     for ( int i = 0; i < _elements.size(); ++i )
6336       if ( --_elements[i]->_refCount <= 0 )
6337         delete _elements[i];
6338   }
6339
6340   //================================================================================
6341   /*!
6342    * \brief Return the maximal box
6343    */
6344   //================================================================================
6345
6346   Bnd_B3d* ElementBndBoxTree::buildRootBox()
6347   {
6348     Bnd_B3d* box = new Bnd_B3d;
6349     for ( int i = 0; i < _elements.size(); ++i )
6350       box->Add( *_elements[i] );
6351     return box;
6352   }
6353
6354   //================================================================================
6355   /*!
6356    * \brief Redistrubute element boxes among children
6357    */
6358   //================================================================================
6359
6360   void ElementBndBoxTree::buildChildrenData()
6361   {
6362     for ( int i = 0; i < _elements.size(); ++i )
6363     {
6364       for (int j = 0; j < 8; j++)
6365       {
6366         if ( !_elements[i]->IsOut( myChildren[j]->getBox() ))
6367         {
6368           _elements[i]->_refCount++;
6369           ((ElementBndBoxTree*)myChildren[j])->_elements.push_back( _elements[i]);
6370         }
6371       }
6372       _elements[i]->_refCount--;
6373     }
6374     _elements.clear();
6375
6376     for (int j = 0; j < 8; j++)
6377     {
6378       ElementBndBoxTree* child = static_cast<ElementBndBoxTree*>( myChildren[j]);
6379       if ( child->_elements.size() <= MaxNbElemsInLeaf )
6380         child->myIsLeaf = true;
6381
6382       if ( child->_elements.capacity() - child->_elements.size() > 1000 )
6383         child->_elements.resize( child->_elements.size() ); // compact
6384     }
6385   }
6386
6387   //================================================================================
6388   /*!
6389    * \brief Return elements which can include the point
6390    */
6391   //================================================================================
6392
6393   void ElementBndBoxTree::getElementsNearPoint( const gp_Pnt&     point,
6394                                                 TIDSortedElemSet& foundElems)
6395   {
6396     if ( level() && getBox().IsOut( point.XYZ() ))
6397       return;
6398
6399     if ( isLeaf() )
6400     {
6401       for ( int i = 0; i < _elements.size(); ++i )
6402         if ( !_elements[i]->IsOut( point.XYZ() ))
6403           foundElems.insert( _elements[i]->_element );
6404     }
6405     else
6406     {
6407       for (int i = 0; i < 8; i++)
6408         ((ElementBndBoxTree*) myChildren[i])->getElementsNearPoint( point, foundElems );
6409     }
6410   }
6411
6412   //================================================================================
6413   /*!
6414    * \brief Return elements which can be intersected by the line
6415    */
6416   //================================================================================
6417
6418   void ElementBndBoxTree::getElementsNearLine( const gp_Ax1&     line,
6419                                                TIDSortedElemSet& foundElems)
6420   {
6421     if ( level() && getBox().IsOut( line ))
6422       return;
6423
6424     if ( isLeaf() )
6425     {
6426       for ( int i = 0; i < _elements.size(); ++i )
6427         if ( !_elements[i]->IsOut( line ))
6428           foundElems.insert( _elements[i]->_element );
6429     }
6430     else
6431     {
6432       for (int i = 0; i < 8; i++)
6433         ((ElementBndBoxTree*) myChildren[i])->getElementsNearLine( line, foundElems );
6434     }
6435   }
6436
6437   //================================================================================
6438   /*!
6439    * \brief Construct the element box
6440    */
6441   //================================================================================
6442
6443   ElementBndBoxTree::ElementBox::ElementBox(const SMDS_MeshElement* elem, double tolerance)
6444   {
6445     _element  = elem;
6446     _refCount = 1;
6447     SMDS_ElemIteratorPtr nIt = elem->nodesIterator();
6448     while ( nIt->more() )
6449       Add( SMESH_MeshEditor::TNodeXYZ( cast2Node( nIt->next() )));
6450     Enlarge( tolerance );
6451   }
6452
6453 } // namespace
6454
6455 //=======================================================================
6456 /*!
6457  * \brief Implementation of search for the elements by point and
6458  *        of classification of point in 2D mesh
6459  */
6460 //=======================================================================
6461
6462 struct SMESH_ElementSearcherImpl: public SMESH_ElementSearcher
6463 {
6464   SMESHDS_Mesh*                _mesh;
6465   ElementBndBoxTree*           _ebbTree;
6466   SMESH_NodeSearcherImpl*      _nodeSearcher;
6467   SMDSAbs_ElementType          _elementType;
6468   double                       _tolerance;
6469   bool                         _outerFacesFound;
6470   set<const SMDS_MeshElement*> _outerFaces; // empty means "no internal faces at all"
6471
6472   SMESH_ElementSearcherImpl( SMESHDS_Mesh& mesh )
6473     : _mesh(&mesh),_ebbTree(0),_nodeSearcher(0), _tolerance(-1), _outerFacesFound(false) {}
6474   ~SMESH_ElementSearcherImpl()
6475   {
6476     if ( _ebbTree )      delete _ebbTree;      _ebbTree      = 0;
6477     if ( _nodeSearcher ) delete _nodeSearcher; _nodeSearcher = 0;
6478   }
6479   virtual int FindElementsByPoint(const gp_Pnt&                      point,
6480                                   SMDSAbs_ElementType                type,
6481                                   vector< const SMDS_MeshElement* >& foundElements);
6482   virtual TopAbs_State GetPointState(const gp_Pnt& point);
6483
6484   void GetElementsNearLine( const gp_Ax1&                      line,
6485                             SMDSAbs_ElementType                type,
6486                             vector< const SMDS_MeshElement* >& foundElems);
6487   double getTolerance();
6488   bool getIntersParamOnLine(const gp_Lin& line, const SMDS_MeshElement* face,
6489                             const double tolerance, double & param);
6490   void findOuterBoundary(const SMDS_MeshElement* anyOuterFace);
6491   bool isOuterBoundary(const SMDS_MeshElement* face) const
6492   {
6493     return _outerFaces.empty() || _outerFaces.count(face);
6494   }
6495   struct TInters //!< data of intersection of the line and the mesh face (used in GetPointState())
6496   {
6497     const SMDS_MeshElement* _face;
6498     gp_Vec                  _faceNorm;
6499     bool                    _coincides; //!< the line lays in face plane
6500     TInters(const SMDS_MeshElement* face, const gp_Vec& faceNorm, bool coinc=false)
6501       : _face(face), _faceNorm( faceNorm ), _coincides( coinc ) {}
6502   };
6503   struct TFaceLink //!< link and faces sharing it (used in findOuterBoundary())
6504   {
6505     SMESH_TLink      _link;
6506     TIDSortedElemSet _faces;
6507     TFaceLink( const SMDS_MeshNode* n1, const SMDS_MeshNode* n2, const SMDS_MeshElement* face)
6508       : _link( n1, n2 ), _faces( &face, &face + 1) {}
6509   };
6510 };
6511
6512 ostream& operator<< (ostream& out, const SMESH_ElementSearcherImpl::TInters& i)
6513 {
6514   return out << "TInters(face=" << ( i._face ? i._face->GetID() : 0)
6515              << ", _coincides="<<i._coincides << ")";
6516 }
6517
6518 //=======================================================================
6519 /*!
6520  * \brief define tolerance for search
6521  */
6522 //=======================================================================
6523
6524 double SMESH_ElementSearcherImpl::getTolerance()
6525 {
6526   if ( _tolerance < 0 )
6527   {
6528     const SMDS_MeshInfo& meshInfo = _mesh->GetMeshInfo();
6529
6530     _tolerance = 0;
6531     if ( _nodeSearcher && meshInfo.NbNodes() > 1 )
6532     {
6533       double boxSize = _nodeSearcher->getTree()->maxSize();
6534       _tolerance = 1e-8 * boxSize/* / meshInfo.NbNodes()*/;
6535     }
6536     else if ( _ebbTree && meshInfo.NbElements() > 0 )
6537     {
6538       double boxSize = _ebbTree->maxSize();
6539       _tolerance = 1e-8 * boxSize/* / meshInfo.NbElements()*/;
6540     }
6541     if ( _tolerance == 0 )
6542     {
6543       // define tolerance by size of a most complex element
6544       int complexType = SMDSAbs_Volume;
6545       while ( complexType > SMDSAbs_All &&
6546               meshInfo.NbElements( SMDSAbs_ElementType( complexType )) < 1 )
6547         --complexType;
6548       if ( complexType == SMDSAbs_All ) return 0; // empty mesh
6549       double elemSize;
6550       if ( complexType == int( SMDSAbs_Node ))
6551       {
6552         SMDS_NodeIteratorPtr nodeIt = _mesh->nodesIterator();
6553         elemSize = 1;
6554         if ( meshInfo.NbNodes() > 2 )
6555           elemSize = SMESH_MeshEditor::TNodeXYZ( nodeIt->next() ).Distance( nodeIt->next() );
6556       }
6557       else
6558       {
6559         SMDS_ElemIteratorPtr elemIt =
6560             _mesh->elementsIterator( SMDSAbs_ElementType( complexType ));
6561         const SMDS_MeshElement* elem = elemIt->next();
6562         SMDS_ElemIteratorPtr nodeIt = elem->nodesIterator();
6563         SMESH_MeshEditor::TNodeXYZ n1( cast2Node( nodeIt->next() ));
6564         while ( nodeIt->more() )
6565         {
6566           double dist = n1.Distance( cast2Node( nodeIt->next() ));
6567           elemSize = max( dist, elemSize );
6568         }
6569       }
6570       _tolerance = 1e-4 * elemSize;
6571     }
6572   }
6573   return _tolerance;
6574 }
6575
6576 //================================================================================
6577 /*!
6578  * \brief Find intersection of the line and an edge of face and return parameter on line
6579  */
6580 //================================================================================
6581
6582 bool SMESH_ElementSearcherImpl::getIntersParamOnLine(const gp_Lin&           line,
6583                                                      const SMDS_MeshElement* face,
6584                                                      const double            tol,
6585                                                      double &                param)
6586 {
6587   int nbInts = 0;
6588   param = 0;
6589
6590   GeomAPI_ExtremaCurveCurve anExtCC;
6591   Handle(Geom_Curve) lineCurve = new Geom_Line( line );
6592   
6593   int nbNodes = face->IsQuadratic() ? face->NbNodes()/2 : face->NbNodes();
6594   for ( int i = 0; i < nbNodes && nbInts < 2; ++i )
6595   {
6596     GC_MakeSegment edge( SMESH_MeshEditor::TNodeXYZ( face->GetNode( i )),
6597                          SMESH_MeshEditor::TNodeXYZ( face->GetNode( (i+1)%nbNodes) )); 
6598     anExtCC.Init( lineCurve, edge);
6599     if ( anExtCC.NbExtrema() > 0 && anExtCC.LowerDistance() <= tol)
6600     {
6601       Quantity_Parameter pl, pe;
6602       anExtCC.LowerDistanceParameters( pl, pe );
6603       param += pl;
6604       if ( ++nbInts == 2 )
6605         break;
6606     }
6607   }
6608   if ( nbInts > 0 ) param /= nbInts;
6609   return nbInts > 0;
6610 }
6611 //================================================================================
6612 /*!
6613  * \brief Find all faces belonging to the outer boundary of mesh
6614  */
6615 //================================================================================
6616
6617 void SMESH_ElementSearcherImpl::findOuterBoundary(const SMDS_MeshElement* outerFace)
6618 {
6619   if ( _outerFacesFound ) return;
6620
6621   // Collect all outer faces by passing from one outer face to another via their links
6622   // and BTW find out if there are internal faces at all.
6623
6624   // checked links and links where outer boundary meets internal one
6625   set< SMESH_TLink > visitedLinks, seamLinks;
6626
6627   // links to treat with already visited faces sharing them
6628   list < TFaceLink > startLinks;
6629
6630   // load startLinks with the first outerFace
6631   startLinks.push_back( TFaceLink( outerFace->GetNode(0), outerFace->GetNode(1), outerFace));
6632   _outerFaces.insert( outerFace );
6633
6634   TIDSortedElemSet emptySet;
6635   while ( !startLinks.empty() )
6636   {
6637     const SMESH_TLink& link  = startLinks.front()._link;
6638     TIDSortedElemSet&  faces = startLinks.front()._faces;
6639
6640     outerFace = *faces.begin();
6641     // find other faces sharing the link
6642     const SMDS_MeshElement* f;
6643     while (( f = SMESH_MeshEditor::FindFaceInSet(link.node1(), link.node2(), emptySet, faces )))
6644       faces.insert( f );
6645
6646     // select another outer face among the found 
6647     const SMDS_MeshElement* outerFace2 = 0;
6648     if ( faces.size() == 2 )
6649     {
6650       outerFace2 = (outerFace == *faces.begin() ? *faces.rbegin() : *faces.begin());
6651     }
6652     else if ( faces.size() > 2 )
6653     {
6654       seamLinks.insert( link );
6655
6656       // link direction within the outerFace
6657       gp_Vec n1n2( SMESH_MeshEditor::TNodeXYZ( link.node1()),
6658                    SMESH_MeshEditor::TNodeXYZ( link.node2()));
6659       int i1 = outerFace->GetNodeIndex( link.node1() );
6660       int i2 = outerFace->GetNodeIndex( link.node2() );
6661       bool rev = ( abs(i2-i1) == 1 ? i1 > i2 : i2 > i1 );
6662       if ( rev ) n1n2.Reverse();
6663       // outerFace normal
6664       gp_XYZ ofNorm, fNorm;
6665       if ( SMESH_Algo::FaceNormal( outerFace, ofNorm, /*normalized=*/false ))
6666       {
6667         // direction from the link inside outerFace
6668         gp_Vec dirInOF = gp_Vec( ofNorm ) ^ n1n2;
6669         // sort all other faces by angle with the dirInOF
6670         map< double, const SMDS_MeshElement* > angle2Face;
6671         set< const SMDS_MeshElement*, TIDCompare >::const_iterator face = faces.begin();
6672         for ( ; face != faces.end(); ++face )
6673         {
6674           if ( !SMESH_Algo::FaceNormal( *face, fNorm, /*normalized=*/false ))
6675             continue;
6676           gp_Vec dirInF = gp_Vec( fNorm ) ^ n1n2;
6677           double angle = dirInOF.AngleWithRef( dirInF, n1n2 );
6678           if ( angle < 0 ) angle += 2*PI;
6679           angle2Face.insert( make_pair( angle, *face ));
6680         }
6681         if ( !angle2Face.empty() )
6682           outerFace2 = angle2Face.begin()->second;
6683       }
6684     }
6685     // store the found outer face and add its links to continue seaching from
6686     if ( outerFace2 )
6687     {
6688       _outerFaces.insert( outerFace );
6689       int nbNodes = outerFace2->NbNodes()/( outerFace2->IsQuadratic() ? 2 : 1 );
6690       for ( int i = 0; i < nbNodes; ++i )
6691       {
6692         SMESH_TLink link2( outerFace2->GetNode(i), outerFace2->GetNode((i+1)%nbNodes));
6693         if ( visitedLinks.insert( link2 ).second )
6694           startLinks.push_back( TFaceLink( link2.node1(), link2.node2(), outerFace2 ));
6695       }
6696     }
6697     startLinks.pop_front();
6698   }
6699   _outerFacesFound = true;
6700
6701   if ( !seamLinks.empty() )
6702   {
6703     // There are internal boundaries touching the outher one,
6704     // find all faces of internal boundaries in order to find
6705     // faces of boundaries of holes, if any.
6706     
6707   }
6708   else
6709   {
6710     _outerFaces.clear();
6711   }
6712 }
6713
6714 //=======================================================================
6715 /*!
6716  * \brief Find elements of given type where the given point is IN or ON.
6717  *        Returns nb of found elements and elements them-selves.
6718  *
6719  * 'ALL' type means elements of any type excluding nodes and 0D elements
6720  */
6721 //=======================================================================
6722
6723 int SMESH_ElementSearcherImpl::
6724 FindElementsByPoint(const gp_Pnt&                      point,
6725                     SMDSAbs_ElementType                type,
6726                     vector< const SMDS_MeshElement* >& foundElements)
6727 {
6728   foundElements.clear();
6729
6730   double tolerance = getTolerance();
6731
6732   // =================================================================================
6733   if ( type == SMDSAbs_Node || type == SMDSAbs_0DElement )
6734   {
6735     if ( !_nodeSearcher )
6736       _nodeSearcher = new SMESH_NodeSearcherImpl( _mesh );
6737
6738     const SMDS_MeshNode* closeNode = _nodeSearcher->FindClosestTo( point );
6739     if ( !closeNode ) return foundElements.size();
6740
6741     if ( point.Distance( SMESH_MeshEditor::TNodeXYZ( closeNode )) > tolerance )
6742       return foundElements.size(); // to far from any node
6743
6744     if ( type == SMDSAbs_Node )
6745     {
6746       foundElements.push_back( closeNode );
6747     }
6748     else
6749     {
6750       SMDS_ElemIteratorPtr elemIt = closeNode->GetInverseElementIterator( SMDSAbs_0DElement );
6751       while ( elemIt->more() )
6752         foundElements.push_back( elemIt->next() );
6753     }
6754   }
6755   // =================================================================================
6756   else // elements more complex than 0D
6757   {
6758     if ( !_ebbTree || _elementType != type )
6759     {
6760       if ( _ebbTree ) delete _ebbTree;
6761       _ebbTree = new ElementBndBoxTree( *_mesh, _elementType = type, tolerance );
6762     }
6763     TIDSortedElemSet suspectElems;
6764     _ebbTree->getElementsNearPoint( point, suspectElems );
6765     TIDSortedElemSet::iterator elem = suspectElems.begin();
6766     for ( ; elem != suspectElems.end(); ++elem )
6767       if ( !SMESH_MeshEditor::isOut( *elem, point, tolerance ))
6768         foundElements.push_back( *elem );
6769   }
6770   return foundElements.size();
6771 }
6772
6773 //================================================================================
6774 /*!
6775  * \brief Classify the given point in the closed 2D mesh
6776  */
6777 //================================================================================
6778
6779 TopAbs_State SMESH_ElementSearcherImpl::GetPointState(const gp_Pnt& point)
6780 {
6781   double tolerance = getTolerance();
6782   if ( !_ebbTree || _elementType != SMDSAbs_Face )
6783   {
6784     if ( _ebbTree ) delete _ebbTree;
6785     _ebbTree = new ElementBndBoxTree( *_mesh, _elementType = SMDSAbs_Face );
6786   }
6787   // Algo: analyse transition of a line starting at the point through mesh boundary;
6788   // try three lines parallel to axis of the coordinate system and perform rough
6789   // analysis. If solution is not clear perform thorough analysis.
6790
6791   const int nbAxes = 3;
6792   gp_Dir axisDir[ nbAxes ] = { gp::DX(), gp::DY(), gp::DZ() };
6793   map< double, TInters >   paramOnLine2TInters[ nbAxes ];
6794   list< TInters > tangentInters[ nbAxes ]; // of faces whose plane includes the line
6795   multimap< int, int > nbInt2Axis; // to find the simplest case
6796   for ( int axis = 0; axis < nbAxes; ++axis )
6797   {
6798     gp_Ax1 lineAxis( point, axisDir[axis]);
6799     gp_Lin line    ( lineAxis );
6800
6801     TIDSortedElemSet suspectFaces; // faces possibly intersecting the line
6802     _ebbTree->getElementsNearLine( lineAxis, suspectFaces );
6803
6804     // Intersect faces with the line
6805
6806     map< double, TInters > & u2inters = paramOnLine2TInters[ axis ];
6807     TIDSortedElemSet::iterator face = suspectFaces.begin();
6808     for ( ; face != suspectFaces.end(); ++face )
6809     {
6810       // get face plane
6811       gp_XYZ fNorm;
6812       if ( !SMESH_Algo::FaceNormal( *face, fNorm, /*normalized=*/false)) continue;
6813       gp_Pln facePlane( SMESH_MeshEditor::TNodeXYZ( (*face)->GetNode(0)), fNorm );
6814
6815       // perform intersection
6816       IntAna_IntConicQuad intersection( line, IntAna_Quadric( facePlane ));
6817       if ( !intersection.IsDone() )
6818         continue;
6819       if ( intersection.IsInQuadric() )
6820       {
6821         tangentInters[ axis ].push_back( TInters( *face, fNorm, true ));
6822       }
6823       else if ( ! intersection.IsParallel() && intersection.NbPoints() > 0 )
6824       {
6825         gp_Pnt intersectionPoint = intersection.Point(1);
6826         if ( !SMESH_MeshEditor::isOut( *face, intersectionPoint, tolerance ))
6827           u2inters.insert(make_pair( intersection.ParamOnConic(1), TInters( *face, fNorm )));
6828       }
6829     }
6830     // Analyse intersections roughly
6831
6832     int nbInter = u2inters.size();
6833     if ( nbInter == 0 )
6834       return TopAbs_OUT; 
6835
6836     double f = u2inters.begin()->first, l = u2inters.rbegin()->first;
6837     if ( nbInter == 1 ) // not closed mesh
6838       return fabs( f ) < tolerance ? TopAbs_ON : TopAbs_UNKNOWN;
6839
6840     if ( fabs( f ) < tolerance || fabs( l ) < tolerance )
6841       return TopAbs_ON;
6842
6843     if ( (f<0) == (l<0) )
6844       return TopAbs_OUT;
6845
6846     int nbIntBeforePoint = std::distance( u2inters.begin(), u2inters.lower_bound(0));
6847     int nbIntAfterPoint  = nbInter - nbIntBeforePoint;
6848     if ( nbIntBeforePoint == 1 || nbIntAfterPoint == 1 )
6849       return TopAbs_IN;
6850
6851     nbInt2Axis.insert( make_pair( min( nbIntBeforePoint, nbIntAfterPoint ), axis ));
6852
6853     if ( _outerFacesFound ) break; // pass to thorough analysis
6854
6855   } // three attempts - loop on CS axes
6856
6857   // Analyse intersections thoroughly.
6858   // We make two loops maximum, on the first one we only exclude touching intersections,
6859   // on the second, if situation is still unclear, we gather and use information on
6860   // position of faces (internal or outer). If faces position is already gathered,
6861   // we make the second loop right away.
6862
6863   for ( int hasPositionInfo = _outerFacesFound; hasPositionInfo < 2; ++hasPositionInfo )
6864   {
6865     multimap< int, int >::const_iterator nb_axis = nbInt2Axis.begin();
6866     for ( ; nb_axis != nbInt2Axis.end(); ++nb_axis )
6867     {
6868       int axis = nb_axis->second;
6869       map< double, TInters > & u2inters = paramOnLine2TInters[ axis ];
6870
6871       gp_Ax1 lineAxis( point, axisDir[axis]);
6872       gp_Lin line    ( lineAxis );
6873
6874       // add tangent intersections to u2inters
6875       double param;
6876       list< TInters >::const_iterator tgtInt = tangentInters[ axis ].begin();
6877       for ( ; tgtInt != tangentInters[ axis ].end(); ++tgtInt )
6878         if ( getIntersParamOnLine( line, tgtInt->_face, tolerance, param ))
6879           u2inters.insert(make_pair( param, *tgtInt ));
6880       tangentInters[ axis ].clear();
6881
6882       // Count intersections before and after the point excluding touching ones.
6883       // If hasPositionInfo we count intersections of outer boundary only
6884
6885       int nbIntBeforePoint = 0, nbIntAfterPoint = 0;
6886       double f = numeric_limits<double>::max(), l = -numeric_limits<double>::max();
6887       map< double, TInters >::iterator u_int1 = u2inters.begin(), u_int2 = u_int1;
6888       bool ok = ! u_int1->second._coincides;
6889       while ( ok && u_int1 != u2inters.end() )
6890       {
6891         double u = u_int1->first;
6892         bool touchingInt = false;
6893         if ( ++u_int2 != u2inters.end() )
6894         {
6895           // skip intersections at the same point (if the line passes through edge or node)
6896           int nbSamePnt = 0;
6897           while ( u_int2 != u2inters.end() && fabs( u_int2->first - u ) < tolerance )
6898           {
6899             ++nbSamePnt;
6900             ++u_int2;
6901           }
6902
6903           // skip tangent intersections
6904           int nbTgt = 0;
6905           const SMDS_MeshElement* prevFace = u_int1->second._face;
6906           while ( ok && u_int2->second._coincides )
6907           {
6908             if ( SMESH_Algo::GetCommonNodes(prevFace , u_int2->second._face).empty() )
6909               ok = false;
6910             else
6911             {
6912               nbTgt++;
6913               u_int2++;
6914               ok = ( u_int2 != u2inters.end() );
6915             }
6916           }
6917           if ( !ok ) break;
6918
6919           // skip intersections at the same point after tangent intersections
6920           if ( nbTgt > 0 )
6921           {
6922             double u2 = u_int2->first;
6923             ++u_int2;
6924             while ( u_int2 != u2inters.end() && fabs( u_int2->first - u2 ) < tolerance )
6925             {
6926               ++nbSamePnt;
6927               ++u_int2;
6928             }
6929           }
6930           // decide if we skipped a touching intersection
6931           if ( nbSamePnt + nbTgt > 0 )
6932           {
6933             double minDot = numeric_limits<double>::max(), maxDot = -numeric_limits<double>::max();
6934             map< double, TInters >::iterator u_int = u_int1;
6935             for ( ; u_int != u_int2; ++u_int )
6936             {
6937               if ( u_int->second._coincides ) continue;
6938               double dot = u_int->second._faceNorm * line.Direction();
6939               if ( dot > maxDot ) maxDot = dot;
6940               if ( dot < minDot ) minDot = dot;
6941             }
6942             touchingInt = ( minDot*maxDot < 0 );
6943           }
6944         }
6945         if ( !touchingInt )
6946         {
6947           if ( !hasPositionInfo || isOuterBoundary( u_int1->second._face ))
6948           {
6949             if ( u < 0 )
6950               ++nbIntBeforePoint;
6951             else
6952               ++nbIntAfterPoint;
6953           }
6954           if ( u < f ) f = u;
6955           if ( u > l ) l = u;
6956         }
6957
6958         u_int1 = u_int2; // to next intersection
6959
6960       } // loop on intersections with one line
6961
6962       if ( ok )
6963       {
6964         if ( fabs( f ) < tolerance || fabs( l ) < tolerance )
6965           return TopAbs_ON;
6966
6967         if ( nbIntBeforePoint == 0  || nbIntAfterPoint == 0)
6968           return TopAbs_OUT; 
6969
6970         if ( nbIntBeforePoint + nbIntAfterPoint == 1 ) // not closed mesh
6971           return fabs( f ) < tolerance ? TopAbs_ON : TopAbs_UNKNOWN;
6972
6973         if ( nbIntBeforePoint == 1 || nbIntAfterPoint == 1 )
6974           return TopAbs_IN;
6975
6976         if ( (f<0) == (l<0) )
6977           return TopAbs_OUT;
6978
6979         if ( hasPositionInfo )
6980           return nbIntBeforePoint % 2 ? TopAbs_IN : TopAbs_OUT;
6981       }
6982     } // loop on intersections of the tree lines - thorough analysis
6983
6984     if ( !hasPositionInfo )
6985     {
6986       // gather info on faces position - is face in the outer boundary or not
6987       map< double, TInters > & u2inters = paramOnLine2TInters[ 0 ];
6988       findOuterBoundary( u2inters.begin()->second._face );
6989     }
6990
6991   } // two attempts - with and w/o faces position info in the mesh
6992
6993   return TopAbs_UNKNOWN;
6994 }
6995
6996 //=======================================================================
6997 /*!
6998  * \brief Return elements possibly intersecting the line
6999  */
7000 //=======================================================================
7001
7002 void SMESH_ElementSearcherImpl::GetElementsNearLine( const gp_Ax1&                      line,
7003                                                      SMDSAbs_ElementType                type,
7004                                                      vector< const SMDS_MeshElement* >& foundElems)
7005 {
7006   if ( !_ebbTree || _elementType != type )
7007   {
7008     if ( _ebbTree ) delete _ebbTree;
7009     _ebbTree = new ElementBndBoxTree( *_mesh, _elementType = type );
7010   }
7011   TIDSortedElemSet suspectFaces; // elements possibly intersecting the line
7012   _ebbTree->getElementsNearLine( line, suspectFaces );
7013   foundElems.assign( suspectFaces.begin(), suspectFaces.end());
7014 }
7015
7016 //=======================================================================
7017 /*!
7018  * \brief Return SMESH_ElementSearcher
7019  */
7020 //=======================================================================
7021
7022 SMESH_ElementSearcher* SMESH_MeshEditor::GetElementSearcher()
7023 {
7024   return new SMESH_ElementSearcherImpl( *GetMeshDS() );
7025 }
7026
7027 //=======================================================================
7028 /*!
7029  * \brief Return true if the point is IN or ON of the element
7030  */
7031 //=======================================================================
7032
7033 bool SMESH_MeshEditor::isOut( const SMDS_MeshElement* element, const gp_Pnt& point, double tol )
7034 {
7035   if ( element->GetType() == SMDSAbs_Volume)
7036   {
7037     return SMDS_VolumeTool( element ).IsOut( point.X(), point.Y(), point.Z(), tol );
7038   }
7039
7040   // get ordered nodes
7041
7042   vector< gp_XYZ > xyz;
7043   vector<const SMDS_MeshNode*> nodeList;
7044
7045   SMDS_ElemIteratorPtr nodeIt = element->nodesIterator();
7046   if ( element->IsQuadratic() ) {
7047     if (const SMDS_VtkFace* f=dynamic_cast<const SMDS_VtkFace*>(element))
7048       nodeIt = f->interlacedNodesElemIterator();
7049     else if (const SMDS_VtkEdge*  e =dynamic_cast<const SMDS_VtkEdge*>(element))
7050       nodeIt = e->interlacedNodesElemIterator();
7051   }
7052   while ( nodeIt->more() )
7053     {
7054       const SMDS_MeshNode* node = cast2Node( nodeIt->next() );
7055       xyz.push_back( TNodeXYZ(node) );
7056       nodeList.push_back(node);
7057     }
7058
7059   int i, nbNodes = element->NbNodes();
7060
7061   if ( element->GetType() == SMDSAbs_Face ) // --------------------------------------------------
7062   {
7063     // compute face normal
7064     gp_Vec faceNorm(0,0,0);
7065     xyz.push_back( xyz.front() );
7066     nodeList.push_back( nodeList.front() );
7067     for ( i = 0; i < nbNodes; ++i )
7068     {
7069       gp_Vec edge1( xyz[i+1], xyz[i]);
7070       gp_Vec edge2( xyz[i+1], xyz[(i+2)%nbNodes] );
7071       faceNorm += edge1 ^ edge2;
7072     }
7073     double normSize = faceNorm.Magnitude();
7074     if ( normSize <= tol )
7075     {
7076       // degenerated face: point is out if it is out of all face edges
7077       for ( i = 0; i < nbNodes; ++i )
7078       {
7079         SMDS_LinearEdge edge( nodeList[i], nodeList[i+1] );
7080         if ( !isOut( &edge, point, tol ))
7081           return false;
7082       }
7083       return true;
7084     }
7085     faceNorm /= normSize;
7086
7087     // check if the point lays on face plane
7088     gp_Vec n2p( xyz[0], point );
7089     if ( fabs( n2p * faceNorm ) > tol )
7090       return true; // not on face plane
7091
7092     // check if point is out of face boundary:
7093     // define it by closest transition of a ray point->infinity through face boundary
7094     // on the face plane.
7095     // First, find normal of a plane perpendicular to face plane, to be used as a cutting tool
7096     // to find intersections of the ray with the boundary.
7097     gp_Vec ray = n2p;
7098     gp_Vec plnNorm = ray ^ faceNorm;
7099     normSize = plnNorm.Magnitude();
7100     if ( normSize <= tol ) return false; // point coincides with the first node
7101     plnNorm /= normSize;
7102     // for each node of the face, compute its signed distance to the plane
7103     vector<double> dist( nbNodes + 1);
7104     for ( i = 0; i < nbNodes; ++i )
7105     {
7106       gp_Vec n2p( xyz[i], point );
7107       dist[i] = n2p * plnNorm;
7108     }
7109     dist.back() = dist.front();
7110     // find the closest intersection
7111     int    iClosest = -1;
7112     double rClosest, distClosest = 1e100;;
7113     gp_Pnt pClosest;
7114     for ( i = 0; i < nbNodes; ++i )
7115     {
7116       double r;
7117       if ( fabs( dist[i]) < tol )
7118         r = 0.;
7119       else if ( fabs( dist[i+1]) < tol )
7120         r = 1.;
7121       else if ( dist[i] * dist[i+1] < 0 )
7122         r = dist[i] / ( dist[i] - dist[i+1] );
7123       else
7124         continue; // no intersection
7125       gp_Pnt pInt = xyz[i] * (1.-r) + xyz[i+1] * r;
7126       gp_Vec p2int ( point, pInt);
7127       if ( p2int * ray > -tol ) // right half-space
7128       {
7129         double intDist = p2int.SquareMagnitude();
7130         if ( intDist < distClosest )
7131         {
7132           iClosest = i;
7133           rClosest = r;
7134           pClosest = pInt;
7135           distClosest = intDist;
7136         }
7137       }
7138     }
7139     if ( iClosest < 0 )
7140       return true; // no intesections - out
7141
7142     // analyse transition
7143     gp_Vec edge( xyz[iClosest], xyz[iClosest+1] );
7144     gp_Vec edgeNorm = -( edge ^ faceNorm ); // normal to intersected edge pointing out of face
7145     gp_Vec p2int ( point, pClosest );
7146     bool out = (edgeNorm * p2int) < -tol;
7147     if ( rClosest > 0. && rClosest < 1. ) // not node intersection
7148       return out;
7149
7150     // ray pass through a face node; analyze transition through an adjacent edge
7151     gp_Pnt p1 = xyz[ (rClosest == 0.) ? ((iClosest+nbNodes-1) % nbNodes) : (iClosest+1) ];
7152     gp_Pnt p2 = xyz[ (rClosest == 0.) ? iClosest : ((iClosest+2) % nbNodes) ];
7153     gp_Vec edgeAdjacent( p1, p2 );
7154     gp_Vec edgeNorm2 = -( edgeAdjacent ^ faceNorm );
7155     bool out2 = (edgeNorm2 * p2int) < -tol;
7156
7157     bool covexCorner = ( edgeNorm * edgeAdjacent * (rClosest==1. ? 1. : -1.)) < 0;
7158     return covexCorner ? (out || out2) : (out && out2);
7159   }
7160   if ( element->GetType() == SMDSAbs_Edge ) // --------------------------------------------------
7161   {
7162     // point is out of edge if it is NOT ON any straight part of edge
7163     // (we consider quadratic edge as being composed of two straight parts)
7164     for ( i = 1; i < nbNodes; ++i )
7165     {
7166       gp_Vec edge( xyz[i-1], xyz[i]);
7167       gp_Vec n1p ( xyz[i-1], point);
7168       double dist = ( edge ^ n1p ).Magnitude() / edge.Magnitude();
7169       if ( dist > tol )
7170         continue;
7171       gp_Vec n2p( xyz[i], point );
7172       if ( fabs( edge.Magnitude() - n1p.Magnitude() - n2p.Magnitude()) > tol )
7173         continue;
7174       return false; // point is ON this part
7175     }
7176     return true;
7177   }
7178   // Node or 0D element -------------------------------------------------------------------------
7179   {
7180     gp_Vec n2p ( xyz[0], point );
7181     return n2p.Magnitude() <= tol;
7182   }
7183   return true;
7184 }
7185
7186 //=======================================================================
7187 //function : SimplifyFace
7188 //purpose  :
7189 //=======================================================================
7190 int SMESH_MeshEditor::SimplifyFace (const vector<const SMDS_MeshNode *> faceNodes,
7191                                     vector<const SMDS_MeshNode *>&      poly_nodes,
7192                                     vector<int>&                        quantities) const
7193 {
7194   int nbNodes = faceNodes.size();
7195
7196   if (nbNodes < 3)
7197     return 0;
7198
7199   set<const SMDS_MeshNode*> nodeSet;
7200
7201   // get simple seq of nodes
7202   //const SMDS_MeshNode* simpleNodes[ nbNodes ];
7203   vector<const SMDS_MeshNode*> simpleNodes( nbNodes );
7204   int iSimple = 0, nbUnique = 0;
7205
7206   simpleNodes[iSimple++] = faceNodes[0];
7207   nbUnique++;
7208   for (int iCur = 1; iCur < nbNodes; iCur++) {
7209     if (faceNodes[iCur] != simpleNodes[iSimple - 1]) {
7210       simpleNodes[iSimple++] = faceNodes[iCur];
7211       if (nodeSet.insert( faceNodes[iCur] ).second)
7212         nbUnique++;
7213     }
7214   }
7215   int nbSimple = iSimple;
7216   if (simpleNodes[nbSimple - 1] == simpleNodes[0]) {
7217     nbSimple--;
7218     iSimple--;
7219   }
7220
7221   if (nbUnique < 3)
7222     return 0;
7223
7224   // separate loops
7225   int nbNew = 0;
7226   bool foundLoop = (nbSimple > nbUnique);
7227   while (foundLoop) {
7228     foundLoop = false;
7229     set<const SMDS_MeshNode*> loopSet;
7230     for (iSimple = 0; iSimple < nbSimple && !foundLoop; iSimple++) {
7231       const SMDS_MeshNode* n = simpleNodes[iSimple];
7232       if (!loopSet.insert( n ).second) {
7233         foundLoop = true;
7234
7235         // separate loop
7236         int iC = 0, curLast = iSimple;
7237         for (; iC < curLast; iC++) {
7238           if (simpleNodes[iC] == n) break;
7239         }
7240         int loopLen = curLast - iC;
7241         if (loopLen > 2) {
7242           // create sub-element
7243           nbNew++;
7244           quantities.push_back(loopLen);
7245           for (; iC < curLast; iC++) {
7246             poly_nodes.push_back(simpleNodes[iC]);
7247           }
7248         }
7249         // shift the rest nodes (place from the first loop position)
7250         for (iC = curLast + 1; iC < nbSimple; iC++) {
7251           simpleNodes[iC - loopLen] = simpleNodes[iC];
7252         }
7253         nbSimple -= loopLen;
7254         iSimple -= loopLen;
7255       }
7256     } // for (iSimple = 0; iSimple < nbSimple; iSimple++)
7257   } // while (foundLoop)
7258
7259   if (iSimple > 2) {
7260     nbNew++;
7261     quantities.push_back(iSimple);
7262     for (int i = 0; i < iSimple; i++)
7263       poly_nodes.push_back(simpleNodes[i]);
7264   }
7265
7266   return nbNew;
7267 }
7268
7269 //=======================================================================
7270 //function : MergeNodes
7271 //purpose  : In each group, the cdr of nodes are substituted by the first one
7272 //           in all elements.
7273 //=======================================================================
7274
7275 void SMESH_MeshEditor::MergeNodes (TListOfListOfNodes & theGroupsOfNodes)
7276 {
7277   MESSAGE("MergeNodes");
7278   myLastCreatedElems.Clear();
7279   myLastCreatedNodes.Clear();
7280
7281   SMESHDS_Mesh* aMesh = GetMeshDS();
7282
7283   TNodeNodeMap nodeNodeMap; // node to replace - new node
7284   set<const SMDS_MeshElement*> elems; // all elements with changed nodes
7285   list< int > rmElemIds, rmNodeIds;
7286
7287   // Fill nodeNodeMap and elems
7288
7289   TListOfListOfNodes::iterator grIt = theGroupsOfNodes.begin();
7290   for ( ; grIt != theGroupsOfNodes.end(); grIt++ ) {
7291     list<const SMDS_MeshNode*>& nodes = *grIt;
7292     list<const SMDS_MeshNode*>::iterator nIt = nodes.begin();
7293     const SMDS_MeshNode* nToKeep = *nIt;
7294     //MESSAGE("node to keep " << nToKeep->GetID());
7295     for ( ++nIt; nIt != nodes.end(); nIt++ ) {
7296       const SMDS_MeshNode* nToRemove = *nIt;
7297       nodeNodeMap.insert( TNodeNodeMap::value_type( nToRemove, nToKeep ));
7298       if ( nToRemove != nToKeep ) {
7299         //MESSAGE("  node to remove " << nToRemove->GetID());
7300         rmNodeIds.push_back( nToRemove->GetID() );
7301         AddToSameGroups( nToKeep, nToRemove, aMesh );
7302       }
7303
7304       SMDS_ElemIteratorPtr invElemIt = nToRemove->GetInverseElementIterator();
7305       while ( invElemIt->more() ) {
7306         const SMDS_MeshElement* elem = invElemIt->next();
7307         elems.insert(elem);
7308       }
7309     }
7310   }
7311   // Change element nodes or remove an element
7312
7313   set<const SMDS_MeshElement*>::iterator eIt = elems.begin();
7314   for ( ; eIt != elems.end(); eIt++ ) {
7315     const SMDS_MeshElement* elem = *eIt;
7316     //MESSAGE(" ---- inverse elem on node to remove " << elem->GetID());
7317     int nbNodes = elem->NbNodes();
7318     int aShapeId = FindShape( elem );
7319
7320     set<const SMDS_MeshNode*> nodeSet;
7321     vector< const SMDS_MeshNode*> curNodes( nbNodes ), uniqueNodes( nbNodes );
7322     int iUnique = 0, iCur = 0, nbRepl = 0;
7323     vector<int> iRepl( nbNodes );
7324
7325     // get new seq of nodes
7326     SMDS_ElemIteratorPtr itN = elem->nodesIterator();
7327     while ( itN->more() ) {
7328       const SMDS_MeshNode* n =
7329         static_cast<const SMDS_MeshNode*>( itN->next() );
7330
7331       TNodeNodeMap::iterator nnIt = nodeNodeMap.find( n );
7332       if ( nnIt != nodeNodeMap.end() ) { // n sticks
7333         n = (*nnIt).second;
7334         // BUG 0020185: begin
7335         {
7336           bool stopRecur = false;
7337           set<const SMDS_MeshNode*> nodesRecur;
7338           nodesRecur.insert(n);
7339           while (!stopRecur) {
7340             TNodeNodeMap::iterator nnIt_i = nodeNodeMap.find( n );
7341             if ( nnIt_i != nodeNodeMap.end() ) { // n sticks
7342               n = (*nnIt_i).second;
7343               if (!nodesRecur.insert(n).second) {
7344                 // error: recursive dependancy
7345                 stopRecur = true;
7346               }
7347             }
7348             else
7349               stopRecur = true;
7350           }
7351         }
7352         // BUG 0020185: end
7353         iRepl[ nbRepl++ ] = iCur;
7354       }
7355       curNodes[ iCur ] = n;
7356       bool isUnique = nodeSet.insert( n ).second;
7357       if ( isUnique )
7358         uniqueNodes[ iUnique++ ] = n;
7359       iCur++;
7360     }
7361
7362     // Analyse element topology after replacement
7363
7364     bool isOk = true;
7365     int nbUniqueNodes = nodeSet.size();
7366     //MESSAGE("nbNodes nbUniqueNodes " << nbNodes << " " << nbUniqueNodes);
7367     if ( nbNodes != nbUniqueNodes ) { // some nodes stick
7368       // Polygons and Polyhedral volumes
7369       if (elem->IsPoly()) {
7370
7371         if (elem->GetType() == SMDSAbs_Face) {
7372           // Polygon
7373           vector<const SMDS_MeshNode *> face_nodes (nbNodes);
7374           int inode = 0;
7375           for (; inode < nbNodes; inode++) {
7376             face_nodes[inode] = curNodes[inode];
7377           }
7378
7379           vector<const SMDS_MeshNode *> polygons_nodes;
7380           vector<int> quantities;
7381           int nbNew = SimplifyFace(face_nodes, polygons_nodes, quantities);
7382
7383           if (nbNew > 0) {
7384             inode = 0;
7385             for (int iface = 0; iface < nbNew - 1; iface++) {
7386               int nbNodes = quantities[iface];
7387               vector<const SMDS_MeshNode *> poly_nodes (nbNodes);
7388               for (int ii = 0; ii < nbNodes; ii++, inode++) {
7389                 poly_nodes[ii] = polygons_nodes[inode];
7390               }
7391               SMDS_MeshElement* newElem = aMesh->AddPolygonalFace(poly_nodes);
7392               myLastCreatedElems.Append(newElem);
7393               if (aShapeId)
7394                 aMesh->SetMeshElementOnShape(newElem, aShapeId);
7395             }
7396
7397             MESSAGE("ChangeElementNodes MergeNodes Polygon");
7398             //aMesh->ChangeElementNodes(elem, &polygons_nodes[inode], quantities[nbNew - 1]);
7399             vector<const SMDS_MeshNode *> polynodes(polygons_nodes.begin()+inode,polygons_nodes.end());
7400             int quid =0;
7401             if (nbNew > 0) quid = nbNew - 1;
7402             vector<int> newquant(quantities.begin()+quid, quantities.end());
7403             const SMDS_MeshElement* newElem = 0;
7404             newElem = aMesh->AddPolyhedralVolume(polynodes, newquant);
7405             myLastCreatedElems.Append(newElem);
7406             if ( aShapeId && newElem )
7407               aMesh->SetMeshElementOnShape( newElem, aShapeId );
7408             rmElemIds.push_back(elem->GetID());
7409           }
7410           else {
7411             rmElemIds.push_back(elem->GetID());
7412           }
7413
7414         }
7415         else if (elem->GetType() == SMDSAbs_Volume) {
7416           // Polyhedral volume
7417           if (nbUniqueNodes < 4) {
7418             rmElemIds.push_back(elem->GetID());
7419           }
7420           else {
7421             // each face has to be analyzed in order to check volume validity
7422             const SMDS_VtkVolume* aPolyedre =
7423               dynamic_cast<const SMDS_VtkVolume*>( elem );
7424             if (aPolyedre) {
7425               int nbFaces = aPolyedre->NbFaces();
7426
7427               vector<const SMDS_MeshNode *> poly_nodes;
7428               vector<int> quantities;
7429
7430               for (int iface = 1; iface <= nbFaces; iface++) {
7431                 int nbFaceNodes = aPolyedre->NbFaceNodes(iface);
7432                 vector<const SMDS_MeshNode *> faceNodes (nbFaceNodes);
7433
7434                 for (int inode = 1; inode <= nbFaceNodes; inode++) {
7435                   const SMDS_MeshNode * faceNode = aPolyedre->GetFaceNode(iface, inode);
7436                   TNodeNodeMap::iterator nnIt = nodeNodeMap.find(faceNode);
7437                   if (nnIt != nodeNodeMap.end()) { // faceNode sticks
7438                     faceNode = (*nnIt).second;
7439                   }
7440                   faceNodes[inode - 1] = faceNode;
7441                 }
7442
7443                 SimplifyFace(faceNodes, poly_nodes, quantities);
7444               }
7445
7446               if (quantities.size() > 3) {
7447                 // to be done: remove coincident faces
7448               }
7449
7450               if (quantities.size() > 3)
7451                 {
7452                   MESSAGE("ChangeElementNodes MergeNodes Polyhedron");
7453                   //aMesh->ChangePolyhedronNodes(elem, poly_nodes, quantities);
7454                   const SMDS_MeshElement* newElem = 0;
7455                   newElem = aMesh->AddPolyhedralVolume(poly_nodes, quantities);
7456                   myLastCreatedElems.Append(newElem);
7457                   if ( aShapeId && newElem )
7458                     aMesh->SetMeshElementOnShape( newElem, aShapeId );
7459                   rmElemIds.push_back(elem->GetID());
7460                 }
7461             }
7462             else {
7463               rmElemIds.push_back(elem->GetID());
7464             }
7465           }
7466         }
7467         else {
7468         }
7469
7470         continue;
7471       }
7472
7473       // Regular elements
7474       // TODO not all the possible cases are solved. Find something more generic?
7475       switch ( nbNodes ) {
7476       case 2: ///////////////////////////////////// EDGE
7477         isOk = false; break;
7478       case 3: ///////////////////////////////////// TRIANGLE
7479         isOk = false; break;
7480       case 4:
7481         if ( elem->GetType() == SMDSAbs_Volume ) // TETRAHEDRON
7482           isOk = false;
7483         else { //////////////////////////////////// QUADRANGLE
7484           if ( nbUniqueNodes < 3 )
7485             isOk = false;
7486           else if ( nbRepl == 2 && iRepl[ 1 ] - iRepl[ 0 ] == 2 )
7487             isOk = false; // opposite nodes stick
7488           //MESSAGE("isOk " << isOk);
7489         }
7490         break;
7491       case 6: ///////////////////////////////////// PENTAHEDRON
7492         if ( nbUniqueNodes == 4 ) {
7493           // ---------------------------------> tetrahedron
7494           if (nbRepl == 3 &&
7495               iRepl[ 0 ] > 2 && iRepl[ 1 ] > 2 && iRepl[ 2 ] > 2 ) {
7496             // all top nodes stick: reverse a bottom
7497             uniqueNodes[ 0 ] = curNodes [ 1 ];
7498             uniqueNodes[ 1 ] = curNodes [ 0 ];
7499           }
7500           else if (nbRepl == 3 &&
7501                    iRepl[ 0 ] < 3 && iRepl[ 1 ] < 3 && iRepl[ 2 ] < 3 ) {
7502             // all bottom nodes stick: set a top before
7503             uniqueNodes[ 3 ] = uniqueNodes [ 0 ];
7504             uniqueNodes[ 0 ] = curNodes [ 3 ];
7505             uniqueNodes[ 1 ] = curNodes [ 4 ];
7506             uniqueNodes[ 2 ] = curNodes [ 5 ];
7507           }
7508           else if (nbRepl == 4 &&
7509                    iRepl[ 2 ] - iRepl [ 0 ] == 3 && iRepl[ 3 ] - iRepl [ 1 ] == 3 ) {
7510             // a lateral face turns into a line: reverse a bottom
7511             uniqueNodes[ 0 ] = curNodes [ 1 ];
7512             uniqueNodes[ 1 ] = curNodes [ 0 ];
7513           }
7514           else
7515             isOk = false;
7516         }
7517         else if ( nbUniqueNodes == 5 ) {
7518           // PENTAHEDRON --------------------> 2 tetrahedrons
7519           if ( nbRepl == 2 && iRepl[ 1 ] - iRepl [ 0 ] == 3 ) {
7520             // a bottom node sticks with a linked top one
7521             // 1.
7522             SMDS_MeshElement* newElem =
7523               aMesh->AddVolume(curNodes[ 3 ],
7524                                curNodes[ 4 ],
7525                                curNodes[ 5 ],
7526                                curNodes[ iRepl[ 0 ] == 2 ? 1 : 2 ]);
7527             myLastCreatedElems.Append(newElem);
7528             if ( aShapeId )
7529               aMesh->SetMeshElementOnShape( newElem, aShapeId );
7530             // 2. : reverse a bottom
7531             uniqueNodes[ 0 ] = curNodes [ 1 ];
7532             uniqueNodes[ 1 ] = curNodes [ 0 ];
7533             nbUniqueNodes = 4;
7534           }
7535           else
7536             isOk = false;
7537         }
7538         else
7539           isOk = false;
7540         break;
7541       case 8: {
7542         if(elem->IsQuadratic()) { // Quadratic quadrangle
7543           //   1    5    2
7544           //    +---+---+
7545           //    |       |
7546           //    |       |
7547           //   4+       +6
7548           //    |       |
7549           //    |       |
7550           //    +---+---+
7551           //   0    7    3
7552           isOk = false;
7553           if(nbRepl==2) {
7554             MESSAGE("nbRepl=2: " << iRepl[0] << " " << iRepl[1]);
7555           }
7556           if(nbRepl==3) {
7557             MESSAGE("nbRepl=3: " << iRepl[0] << " " << iRepl[1]  << " " << iRepl[2]);
7558             nbUniqueNodes = 6;
7559             if( iRepl[0]==0 && iRepl[1]==1 && iRepl[2]==4 ) {
7560               uniqueNodes[0] = curNodes[0];
7561               uniqueNodes[1] = curNodes[2];
7562               uniqueNodes[2] = curNodes[3];
7563               uniqueNodes[3] = curNodes[5];
7564               uniqueNodes[4] = curNodes[6];
7565               uniqueNodes[5] = curNodes[7];
7566               isOk = true;
7567             }
7568             if( iRepl[0]==0 && iRepl[1]==3 && iRepl[2]==7 ) {
7569               uniqueNodes[0] = curNodes[0];
7570               uniqueNodes[1] = curNodes[1];
7571               uniqueNodes[2] = curNodes[2];
7572               uniqueNodes[3] = curNodes[4];
7573               uniqueNodes[4] = curNodes[5];
7574               uniqueNodes[5] = curNodes[6];
7575               isOk = true;
7576             }
7577             if( iRepl[0]==0 && iRepl[1]==4 && iRepl[2]==7 ) {
7578               uniqueNodes[0] = curNodes[1];
7579               uniqueNodes[1] = curNodes[2];
7580               uniqueNodes[2] = curNodes[3];
7581               uniqueNodes[3] = curNodes[5];
7582               uniqueNodes[4] = curNodes[6];
7583               uniqueNodes[5] = curNodes[0];
7584               isOk = true;
7585             }
7586             if( iRepl[0]==1 && iRepl[1]==2 && iRepl[2]==5 ) {
7587               uniqueNodes[0] = curNodes[0];
7588               uniqueNodes[1] = curNodes[1];
7589               uniqueNodes[2] = curNodes[3];
7590               uniqueNodes[3] = curNodes[4];
7591               uniqueNodes[4] = curNodes[6];
7592               uniqueNodes[5] = curNodes[7];
7593               isOk = true;
7594             }
7595             if( iRepl[0]==1 && iRepl[1]==4 && iRepl[2]==5 ) {
7596               uniqueNodes[0] = curNodes[0];
7597               uniqueNodes[1] = curNodes[2];
7598               uniqueNodes[2] = curNodes[3];
7599               uniqueNodes[3] = curNodes[1];
7600               uniqueNodes[4] = curNodes[6];
7601               uniqueNodes[5] = curNodes[7];
7602               isOk = true;
7603             }
7604             if( iRepl[0]==2 && iRepl[1]==3 && iRepl[2]==6 ) {
7605               uniqueNodes[0] = curNodes[0];
7606               uniqueNodes[1] = curNodes[1];
7607               uniqueNodes[2] = curNodes[2];
7608               uniqueNodes[3] = curNodes[4];
7609               uniqueNodes[4] = curNodes[5];
7610               uniqueNodes[5] = curNodes[7];
7611               isOk = true;
7612             }
7613             if( iRepl[0]==2 && iRepl[1]==5 && iRepl[2]==6 ) {
7614               uniqueNodes[0] = curNodes[0];
7615               uniqueNodes[1] = curNodes[1];
7616               uniqueNodes[2] = curNodes[3];
7617               uniqueNodes[3] = curNodes[4];
7618               uniqueNodes[4] = curNodes[2];
7619               uniqueNodes[5] = curNodes[7];
7620               isOk = true;
7621             }
7622             if( iRepl[0]==3 && iRepl[1]==6 && iRepl[2]==7 ) {
7623               uniqueNodes[0] = curNodes[0];
7624               uniqueNodes[1] = curNodes[1];
7625               uniqueNodes[2] = curNodes[2];
7626               uniqueNodes[3] = curNodes[4];
7627               uniqueNodes[4] = curNodes[5];
7628               uniqueNodes[5] = curNodes[3];
7629               isOk = true;
7630             }
7631           }
7632           if(nbRepl==4) {
7633             MESSAGE("nbRepl=4: " << iRepl[0] << " " << iRepl[1]  << " " << iRepl[2] << " " << iRepl[3]);
7634           }
7635           if(nbRepl==5) {
7636             MESSAGE("nbRepl=5: " << iRepl[0] << " " << iRepl[1]  << " " << iRepl[2] << " " << iRepl[3] << " " << iRepl[4]);
7637           }
7638           break;
7639         }
7640         //////////////////////////////////// HEXAHEDRON
7641         isOk = false;
7642         SMDS_VolumeTool hexa (elem);
7643         hexa.SetExternalNormal();
7644         if ( nbUniqueNodes == 4 && nbRepl == 6 ) {
7645           //////////////////////// ---> tetrahedron
7646           for ( int iFace = 0; iFace < 6; iFace++ ) {
7647             const int *ind = hexa.GetFaceNodesIndices( iFace ); // indices of face nodes
7648             if (curNodes[ind[ 0 ]] == curNodes[ind[ 1 ]] &&
7649                 curNodes[ind[ 0 ]] == curNodes[ind[ 2 ]] &&
7650                 curNodes[ind[ 0 ]] == curNodes[ind[ 3 ]] ) {
7651               // one face turns into a point ...
7652               int iOppFace = hexa.GetOppFaceIndex( iFace );
7653               ind = hexa.GetFaceNodesIndices( iOppFace );
7654               int nbStick = 0;
7655               iUnique = 2; // reverse a tetrahedron bottom
7656               for ( iCur = 0; iCur < 4 && nbStick < 2; iCur++ ) {
7657                 if ( curNodes[ind[ iCur ]] == curNodes[ind[ iCur + 1 ]] )
7658                   nbStick++;
7659                 else if ( iUnique >= 0 )
7660                   uniqueNodes[ iUnique-- ] = curNodes[ind[ iCur ]];
7661               }
7662               if ( nbStick == 1 ) {
7663                 // ... and the opposite one - into a triangle.
7664                 // set a top node
7665                 ind = hexa.GetFaceNodesIndices( iFace );
7666                 uniqueNodes[ 3 ] = curNodes[ind[ 0 ]];
7667                 isOk = true;
7668               }
7669               break;
7670             }
7671           }
7672         }
7673         else if (nbUniqueNodes == 5 && nbRepl == 4 ) {
7674           //////////////////// HEXAHEDRON ---> 2 tetrahedrons
7675           for ( int iFace = 0; iFace < 6; iFace++ ) {
7676             const int *ind = hexa.GetFaceNodesIndices( iFace ); // indices of face nodes
7677             if (curNodes[ind[ 0 ]] == curNodes[ind[ 1 ]] &&
7678                 curNodes[ind[ 0 ]] == curNodes[ind[ 2 ]] &&
7679                 curNodes[ind[ 0 ]] == curNodes[ind[ 3 ]] ) {
7680               // one face turns into a point ...
7681               int iOppFace = hexa.GetOppFaceIndex( iFace );
7682               ind = hexa.GetFaceNodesIndices( iOppFace );
7683               int nbStick = 0;
7684               iUnique = 2;  // reverse a tetrahedron 1 bottom
7685               for ( iCur = 0; iCur < 4 && nbStick == 0; iCur++ ) {
7686                 if ( curNodes[ind[ iCur ]] == curNodes[ind[ iCur + 1 ]] )
7687                   nbStick++;
7688                 else if ( iUnique >= 0 )
7689                   uniqueNodes[ iUnique-- ] = curNodes[ind[ iCur ]];
7690               }
7691               if ( nbStick == 0 ) {
7692                 // ... and the opposite one is a quadrangle
7693                 // set a top node
7694                 const int* indTop = hexa.GetFaceNodesIndices( iFace );
7695                 uniqueNodes[ 3 ] = curNodes[indTop[ 0 ]];
7696                 nbUniqueNodes = 4;
7697                 // tetrahedron 2
7698                 SMDS_MeshElement* newElem =
7699                   aMesh->AddVolume(curNodes[ind[ 0 ]],
7700                                    curNodes[ind[ 3 ]],
7701                                    curNodes[ind[ 2 ]],
7702                                    curNodes[indTop[ 0 ]]);
7703                 myLastCreatedElems.Append(newElem);
7704                 if ( aShapeId )
7705                   aMesh->SetMeshElementOnShape( newElem, aShapeId );
7706                 isOk = true;
7707               }
7708               break;
7709             }
7710           }
7711         }
7712         else if ( nbUniqueNodes == 6 && nbRepl == 4 ) {
7713           ////////////////// HEXAHEDRON ---> 2 tetrahedrons or 1 prism
7714           // find indices of quad and tri faces
7715           int iQuadFace[ 6 ], iTriFace[ 6 ], nbQuad = 0, nbTri = 0, iFace;
7716           for ( iFace = 0; iFace < 6; iFace++ ) {
7717             const int *ind = hexa.GetFaceNodesIndices( iFace ); // indices of face nodes
7718             nodeSet.clear();
7719             for ( iCur = 0; iCur < 4; iCur++ )
7720               nodeSet.insert( curNodes[ind[ iCur ]] );
7721             nbUniqueNodes = nodeSet.size();
7722             if ( nbUniqueNodes == 3 )
7723               iTriFace[ nbTri++ ] = iFace;
7724             else if ( nbUniqueNodes == 4 )
7725               iQuadFace[ nbQuad++ ] = iFace;
7726           }
7727           if (nbQuad == 2 && nbTri == 4 &&
7728               hexa.GetOppFaceIndex( iQuadFace[ 0 ] ) == iQuadFace[ 1 ]) {
7729             // 2 opposite quadrangles stuck with a diagonal;
7730             // sample groups of merged indices: (0-4)(2-6)
7731             // --------------------------------------------> 2 tetrahedrons
7732             const int *ind1 = hexa.GetFaceNodesIndices( iQuadFace[ 0 ]); // indices of quad1 nodes
7733             const int *ind2 = hexa.GetFaceNodesIndices( iQuadFace[ 1 ]);
7734             int i0, i1d, i2, i3d, i0t, i2t; // d-daigonal, t-top
7735             if (curNodes[ind1[ 0 ]] == curNodes[ind2[ 0 ]] &&
7736                 curNodes[ind1[ 2 ]] == curNodes[ind2[ 2 ]]) {
7737               // stuck with 0-2 diagonal
7738               i0  = ind1[ 3 ];
7739               i1d = ind1[ 0 ];
7740               i2  = ind1[ 1 ];
7741               i3d = ind1[ 2 ];
7742               i0t = ind2[ 1 ];
7743               i2t = ind2[ 3 ];
7744             }
7745             else if (curNodes[ind1[ 1 ]] == curNodes[ind2[ 3 ]] &&
7746                      curNodes[ind1[ 3 ]] == curNodes[ind2[ 1 ]]) {
7747               // stuck with 1-3 diagonal
7748               i0  = ind1[ 0 ];
7749               i1d = ind1[ 1 ];
7750               i2  = ind1[ 2 ];
7751               i3d = ind1[ 3 ];
7752               i0t = ind2[ 0 ];
7753               i2t = ind2[ 1 ];
7754             }
7755             else {
7756               ASSERT(0);
7757             }
7758             // tetrahedron 1
7759             uniqueNodes[ 0 ] = curNodes [ i0 ];
7760             uniqueNodes[ 1 ] = curNodes [ i1d ];
7761             uniqueNodes[ 2 ] = curNodes [ i3d ];
7762             uniqueNodes[ 3 ] = curNodes [ i0t ];
7763             nbUniqueNodes = 4;
7764             // tetrahedron 2
7765             SMDS_MeshElement* newElem = aMesh->AddVolume(curNodes[ i1d ],
7766                                                          curNodes[ i2 ],
7767                                                          curNodes[ i3d ],
7768                                                          curNodes[ i2t ]);
7769             myLastCreatedElems.Append(newElem);
7770             if ( aShapeId )
7771               aMesh->SetMeshElementOnShape( newElem, aShapeId );
7772             isOk = true;
7773           }
7774           else if (( nbTri == 2 && nbQuad == 3 ) || // merged (0-4)(1-5)
7775                    ( nbTri == 4 && nbQuad == 2 )) { // merged (7-4)(1-5)
7776             // --------------------------------------------> prism
7777             // find 2 opposite triangles
7778             nbUniqueNodes = 6;
7779             for ( iFace = 0; iFace + 1 < nbTri; iFace++ ) {
7780               if ( hexa.GetOppFaceIndex( iTriFace[ iFace ] ) == iTriFace[ iFace + 1 ]) {
7781                 // find indices of kept and replaced nodes
7782                 // and fill unique nodes of 2 opposite triangles
7783                 const int *ind1 = hexa.GetFaceNodesIndices( iTriFace[ iFace ]);
7784                 const int *ind2 = hexa.GetFaceNodesIndices( iTriFace[ iFace + 1 ]);
7785                 const SMDS_MeshNode** hexanodes = hexa.GetNodes();
7786                 // fill unique nodes
7787                 iUnique = 0;
7788                 isOk = true;
7789                 for ( iCur = 0; iCur < 4 && isOk; iCur++ ) {
7790                   const SMDS_MeshNode* n     = curNodes[ind1[ iCur ]];
7791                   const SMDS_MeshNode* nInit = hexanodes[ind1[ iCur ]];
7792                   if ( n == nInit ) {
7793                     // iCur of a linked node of the opposite face (make normals co-directed):
7794                     int iCurOpp = ( iCur == 1 || iCur == 3 ) ? 4 - iCur : iCur;
7795                     // check that correspondent corners of triangles are linked
7796                     if ( !hexa.IsLinked( ind1[ iCur ], ind2[ iCurOpp ] ))
7797                       isOk = false;
7798                     else {
7799                       uniqueNodes[ iUnique ] = n;
7800                       uniqueNodes[ iUnique + 3 ] = curNodes[ind2[ iCurOpp ]];
7801                       iUnique++;
7802                     }
7803                   }
7804                 }
7805                 break;
7806               }
7807             }
7808           }
7809         } // if ( nbUniqueNodes == 6 && nbRepl == 4 )
7810         break;
7811       } // HEXAHEDRON
7812
7813       default:
7814         isOk = false;
7815       } // switch ( nbNodes )
7816
7817     } // if ( nbNodes != nbUniqueNodes ) // some nodes stick
7818
7819     if ( isOk ) {
7820       if (elem->IsPoly() && elem->GetType() == SMDSAbs_Volume) {
7821         // Change nodes of polyedre
7822         const SMDS_VtkVolume* aPolyedre =
7823           dynamic_cast<const SMDS_VtkVolume*>( elem );
7824         if (aPolyedre) {
7825           int nbFaces = aPolyedre->NbFaces();
7826
7827           vector<const SMDS_MeshNode *> poly_nodes;
7828           vector<int> quantities (nbFaces);
7829
7830           for (int iface = 1; iface <= nbFaces; iface++) {
7831             int inode, nbFaceNodes = aPolyedre->NbFaceNodes(iface);
7832             quantities[iface - 1] = nbFaceNodes;
7833
7834             for (inode = 1; inode <= nbFaceNodes; inode++) {
7835               const SMDS_MeshNode* curNode = aPolyedre->GetFaceNode(iface, inode);
7836
7837               TNodeNodeMap::iterator nnIt = nodeNodeMap.find( curNode );
7838               if (nnIt != nodeNodeMap.end()) { // curNode sticks
7839                 curNode = (*nnIt).second;
7840               }
7841               poly_nodes.push_back(curNode);
7842             }
7843           }
7844           aMesh->ChangePolyhedronNodes( elem, poly_nodes, quantities );
7845         }
7846       }
7847       else {
7848         //int elemId = elem->GetID();
7849         //MESSAGE("Change regular element or polygon " << elemId);
7850         SMDSAbs_ElementType etyp = elem->GetType();
7851         uniqueNodes.resize(nbUniqueNodes);
7852         SMDS_MeshElement* newElem = this->AddElement(uniqueNodes, etyp, false);
7853         if (newElem)
7854           {
7855             myLastCreatedElems.Append(newElem);
7856             if ( aShapeId )
7857               aMesh->SetMeshElementOnShape( newElem, aShapeId );
7858           }
7859         aMesh->RemoveElement(elem);
7860       }
7861     }
7862     else {
7863       // Remove invalid regular element or invalid polygon
7864       //MESSAGE("Remove invalid " << elem->GetID());
7865       rmElemIds.push_back( elem->GetID() );
7866     }
7867
7868   } // loop on elements
7869
7870   // Remove bad elements, then equal nodes (order important)
7871
7872   Remove( rmElemIds, false );
7873   Remove( rmNodeIds, true );
7874
7875 }
7876
7877
7878 // ========================================================
7879 // class   : SortableElement
7880 // purpose : allow sorting elements basing on their nodes
7881 // ========================================================
7882 class SortableElement : public set <const SMDS_MeshElement*>
7883 {
7884 public:
7885
7886   SortableElement( const SMDS_MeshElement* theElem )
7887   {
7888     myElem = theElem;
7889     SMDS_ElemIteratorPtr nodeIt = theElem->nodesIterator();
7890     while ( nodeIt->more() )
7891       this->insert( nodeIt->next() );
7892   }
7893
7894   const SMDS_MeshElement* Get() const
7895   { return myElem; }
7896
7897   void Set(const SMDS_MeshElement* e) const
7898   { myElem = e; }
7899
7900
7901 private:
7902   mutable const SMDS_MeshElement* myElem;
7903 };
7904
7905 //=======================================================================
7906 //function : FindEqualElements
7907 //purpose  : Return list of group of elements built on the same nodes.
7908 //           Search among theElements or in the whole mesh if theElements is empty
7909 //=======================================================================
7910 void SMESH_MeshEditor::FindEqualElements(set<const SMDS_MeshElement*> & theElements,
7911                                          TListOfListOfElementsID &      theGroupsOfElementsID)
7912 {
7913   myLastCreatedElems.Clear();
7914   myLastCreatedNodes.Clear();
7915
7916   typedef set<const SMDS_MeshElement*> TElemsSet;
7917   typedef map< SortableElement, int > TMapOfNodeSet;
7918   typedef list<int> TGroupOfElems;
7919
7920   TElemsSet elems;
7921   if ( theElements.empty() )
7922   { // get all elements in the mesh
7923     SMDS_ElemIteratorPtr eIt = GetMeshDS()->elementsIterator();
7924     while ( eIt->more() )
7925       elems.insert( elems.end(), eIt->next());
7926   }
7927   else
7928     elems = theElements;
7929
7930   vector< TGroupOfElems > arrayOfGroups;
7931   TGroupOfElems groupOfElems;
7932   TMapOfNodeSet mapOfNodeSet;
7933
7934   TElemsSet::iterator elemIt = elems.begin();
7935   for ( int i = 0, j=0; elemIt != elems.end(); ++elemIt, ++j ) {
7936     const SMDS_MeshElement* curElem = *elemIt;
7937     SortableElement SE(curElem);
7938     int ind = -1;
7939     // check uniqueness
7940     pair< TMapOfNodeSet::iterator, bool> pp = mapOfNodeSet.insert(make_pair(SE, i));
7941     if( !(pp.second) ) {
7942       TMapOfNodeSet::iterator& itSE = pp.first;
7943       ind = (*itSE).second;
7944       arrayOfGroups[ind].push_back(curElem->GetID());
7945     }
7946     else {
7947       groupOfElems.clear();
7948       groupOfElems.push_back(curElem->GetID());
7949       arrayOfGroups.push_back(groupOfElems);
7950       i++;
7951     }
7952   }
7953
7954   vector< TGroupOfElems >::iterator groupIt = arrayOfGroups.begin();
7955   for ( ; groupIt != arrayOfGroups.end(); ++groupIt ) {
7956     groupOfElems = *groupIt;
7957     if ( groupOfElems.size() > 1 ) {
7958       groupOfElems.sort();
7959       theGroupsOfElementsID.push_back(groupOfElems);
7960     }
7961   }
7962 }
7963
7964 //=======================================================================
7965 //function : MergeElements
7966 //purpose  : In each given group, substitute all elements by the first one.
7967 //=======================================================================
7968
7969 void SMESH_MeshEditor::MergeElements(TListOfListOfElementsID & theGroupsOfElementsID)
7970 {
7971   myLastCreatedElems.Clear();
7972   myLastCreatedNodes.Clear();
7973
7974   typedef list<int> TListOfIDs;
7975   TListOfIDs rmElemIds; // IDs of elems to remove
7976
7977   SMESHDS_Mesh* aMesh = GetMeshDS();
7978
7979   TListOfListOfElementsID::iterator groupsIt = theGroupsOfElementsID.begin();
7980   while ( groupsIt != theGroupsOfElementsID.end() ) {
7981     TListOfIDs& aGroupOfElemID = *groupsIt;
7982     aGroupOfElemID.sort();
7983     int elemIDToKeep = aGroupOfElemID.front();
7984     const SMDS_MeshElement* elemToKeep = aMesh->FindElement(elemIDToKeep);
7985     aGroupOfElemID.pop_front();
7986     TListOfIDs::iterator idIt = aGroupOfElemID.begin();
7987     while ( idIt != aGroupOfElemID.end() ) {
7988       int elemIDToRemove = *idIt;
7989       const SMDS_MeshElement* elemToRemove = aMesh->FindElement(elemIDToRemove);
7990       // add the kept element in groups of removed one (PAL15188)
7991       AddToSameGroups( elemToKeep, elemToRemove, aMesh );
7992       rmElemIds.push_back( elemIDToRemove );
7993       ++idIt;
7994     }
7995     ++groupsIt;
7996   }
7997
7998   Remove( rmElemIds, false );
7999 }
8000
8001 //=======================================================================
8002 //function : MergeEqualElements
8003 //purpose  : Remove all but one of elements built on the same nodes.
8004 //=======================================================================
8005
8006 void SMESH_MeshEditor::MergeEqualElements()
8007 {
8008   set<const SMDS_MeshElement*> aMeshElements; /* empty input -
8009                                                  to merge equal elements in the whole mesh */
8010   TListOfListOfElementsID aGroupsOfElementsID;
8011   FindEqualElements(aMeshElements, aGroupsOfElementsID);
8012   MergeElements(aGroupsOfElementsID);
8013 }
8014
8015 //=======================================================================
8016 //function : FindFaceInSet
8017 //purpose  : Return a face having linked nodes n1 and n2 and which is
8018 //           - not in avoidSet,
8019 //           - in elemSet provided that !elemSet.empty()
8020 //           i1 and i2 optionally returns indices of n1 and n2
8021 //=======================================================================
8022
8023 const SMDS_MeshElement*
8024 SMESH_MeshEditor::FindFaceInSet(const SMDS_MeshNode*    n1,
8025                                 const SMDS_MeshNode*    n2,
8026                                 const TIDSortedElemSet& elemSet,
8027                                 const TIDSortedElemSet& avoidSet,
8028                                 int*                    n1ind,
8029                                 int*                    n2ind)
8030
8031 {
8032   int i1, i2;
8033   const SMDS_MeshElement* face = 0;
8034
8035   SMDS_ElemIteratorPtr invElemIt = n1->GetInverseElementIterator(SMDSAbs_Face);
8036   //MESSAGE("n1->GetInverseElementIterator(SMDSAbs_Face) " << invElemIt);
8037   while ( invElemIt->more() && !face ) // loop on inverse faces of n1
8038   {
8039     //MESSAGE("in while ( invElemIt->more() && !face )");
8040     const SMDS_MeshElement* elem = invElemIt->next();
8041     if (avoidSet.count( elem ))
8042       continue;
8043     if ( !elemSet.empty() && !elemSet.count( elem ))
8044       continue;
8045     // index of n1
8046     i1 = elem->GetNodeIndex( n1 );
8047     // find a n2 linked to n1
8048     int nbN = elem->IsQuadratic() ? elem->NbNodes()/2 : elem->NbNodes();
8049     for ( int di = -1; di < 2 && !face; di += 2 )
8050     {
8051       i2 = (i1+di+nbN) % nbN;
8052       if ( elem->GetNode( i2 ) == n2 )
8053         face = elem;
8054     }
8055     if ( !face && elem->IsQuadratic())
8056     {
8057       // analysis for quadratic elements using all nodes
8058       const SMDS_VtkFace* F =
8059         dynamic_cast<const SMDS_VtkFace*>(elem);
8060       if (!F) throw SALOME_Exception(LOCALIZED("not an SMDS_VtkFace"));
8061       // use special nodes iterator
8062       SMDS_ElemIteratorPtr anIter = F->interlacedNodesElemIterator();
8063       const SMDS_MeshNode* prevN = cast2Node( anIter->next() );
8064       for ( i1 = -1, i2 = 0; anIter->more() && !face; i1++, i2++ )
8065       {
8066         const SMDS_MeshNode* n = cast2Node( anIter->next() );
8067         if ( n1 == prevN && n2 == n )
8068         {
8069           face = elem;
8070         }
8071         else if ( n2 == prevN && n1 == n )
8072         {
8073           face = elem; swap( i1, i2 );
8074         }
8075         prevN = n;
8076       }
8077     }
8078   }
8079   if ( n1ind ) *n1ind = i1;
8080   if ( n2ind ) *n2ind = i2;
8081   return face;
8082 }
8083
8084 //=======================================================================
8085 //function : findAdjacentFace
8086 //purpose  :
8087 //=======================================================================
8088
8089 static const SMDS_MeshElement* findAdjacentFace(const SMDS_MeshNode* n1,
8090                                                 const SMDS_MeshNode* n2,
8091                                                 const SMDS_MeshElement* elem)
8092 {
8093   TIDSortedElemSet elemSet, avoidSet;
8094   if ( elem )
8095     avoidSet.insert ( elem );
8096   return SMESH_MeshEditor::FindFaceInSet( n1, n2, elemSet, avoidSet );
8097 }
8098
8099 //=======================================================================
8100 //function : FindFreeBorder
8101 //purpose  :
8102 //=======================================================================
8103
8104 #define ControlFreeBorder SMESH::Controls::FreeEdges::IsFreeEdge
8105
8106 bool SMESH_MeshEditor::FindFreeBorder (const SMDS_MeshNode*             theFirstNode,
8107                                        const SMDS_MeshNode*             theSecondNode,
8108                                        const SMDS_MeshNode*             theLastNode,
8109                                        list< const SMDS_MeshNode* > &   theNodes,
8110                                        list< const SMDS_MeshElement* >& theFaces)
8111 {
8112   if ( !theFirstNode || !theSecondNode )
8113     return false;
8114   // find border face between theFirstNode and theSecondNode
8115   const SMDS_MeshElement* curElem = findAdjacentFace( theFirstNode, theSecondNode, 0 );
8116   if ( !curElem )
8117     return false;
8118
8119   theFaces.push_back( curElem );
8120   theNodes.push_back( theFirstNode );
8121   theNodes.push_back( theSecondNode );
8122
8123   //vector<const SMDS_MeshNode*> nodes;
8124   const SMDS_MeshNode *nIgnore = theFirstNode, *nStart = theSecondNode;
8125   TIDSortedElemSet foundElems;
8126   bool needTheLast = ( theLastNode != 0 );
8127
8128   while ( nStart != theLastNode ) {
8129     if ( nStart == theFirstNode )
8130       return !needTheLast;
8131
8132     // find all free border faces sharing form nStart
8133
8134     list< const SMDS_MeshElement* > curElemList;
8135     list< const SMDS_MeshNode* > nStartList;
8136     SMDS_ElemIteratorPtr invElemIt = nStart->GetInverseElementIterator(SMDSAbs_Face);
8137     while ( invElemIt->more() ) {
8138       const SMDS_MeshElement* e = invElemIt->next();
8139       if ( e == curElem || foundElems.insert( e ).second ) {
8140         // get nodes
8141         int iNode = 0, nbNodes = e->NbNodes();
8142         //const SMDS_MeshNode* nodes[nbNodes+1];
8143         vector<const SMDS_MeshNode*> nodes(nbNodes+1);
8144
8145         if(e->IsQuadratic()) {
8146           const SMDS_VtkFace* F =
8147             dynamic_cast<const SMDS_VtkFace*>(e);
8148           if (!F) throw SALOME_Exception(LOCALIZED("not an SMDS_VtkFace"));
8149           // use special nodes iterator
8150           SMDS_ElemIteratorPtr anIter = F->interlacedNodesElemIterator();
8151           while( anIter->more() ) {
8152             nodes[ iNode++ ] = cast2Node(anIter->next());
8153           }
8154         }
8155         else {
8156           SMDS_ElemIteratorPtr nIt = e->nodesIterator();
8157           while ( nIt->more() )
8158             nodes[ iNode++ ] = static_cast<const SMDS_MeshNode*>( nIt->next() );
8159         }
8160         nodes[ iNode ] = nodes[ 0 ];
8161         // check 2 links
8162         for ( iNode = 0; iNode < nbNodes; iNode++ )
8163           if (((nodes[ iNode ] == nStart && nodes[ iNode + 1] != nIgnore ) ||
8164                (nodes[ iNode + 1] == nStart && nodes[ iNode ] != nIgnore )) &&
8165               ControlFreeBorder( &nodes[ iNode ], e->GetID() ))
8166           {
8167             nStartList.push_back( nodes[ iNode + ( nodes[ iNode ] == nStart ? 1 : 0 )]);
8168             curElemList.push_back( e );
8169           }
8170       }
8171     }
8172     // analyse the found
8173
8174     int nbNewBorders = curElemList.size();
8175     if ( nbNewBorders == 0 ) {
8176       // no free border furthermore
8177       return !needTheLast;
8178     }
8179     else if ( nbNewBorders == 1 ) {
8180       // one more element found
8181       nIgnore = nStart;
8182       nStart = nStartList.front();
8183       curElem = curElemList.front();
8184       theFaces.push_back( curElem );
8185       theNodes.push_back( nStart );
8186     }
8187     else {
8188       // several continuations found
8189       list< const SMDS_MeshElement* >::iterator curElemIt;
8190       list< const SMDS_MeshNode* >::iterator nStartIt;
8191       // check if one of them reached the last node
8192       if ( needTheLast ) {
8193         for (curElemIt = curElemList.begin(), nStartIt = nStartList.begin();
8194              curElemIt!= curElemList.end();
8195              curElemIt++, nStartIt++ )
8196           if ( *nStartIt == theLastNode ) {
8197             theFaces.push_back( *curElemIt );
8198             theNodes.push_back( *nStartIt );
8199             return true;
8200           }
8201       }
8202       // find the best free border by the continuations
8203       list<const SMDS_MeshNode*>    contNodes[ 2 ], *cNL;
8204       list<const SMDS_MeshElement*> contFaces[ 2 ], *cFL;
8205       for (curElemIt = curElemList.begin(), nStartIt = nStartList.begin();
8206            curElemIt!= curElemList.end();
8207            curElemIt++, nStartIt++ )
8208       {
8209         cNL = & contNodes[ contNodes[0].empty() ? 0 : 1 ];
8210         cFL = & contFaces[ contFaces[0].empty() ? 0 : 1 ];
8211         // find one more free border
8212         if ( ! FindFreeBorder( nStart, *nStartIt, theLastNode, *cNL, *cFL )) {
8213           cNL->clear();
8214           cFL->clear();
8215         }
8216         else if ( !contNodes[0].empty() && !contNodes[1].empty() ) {
8217           // choice: clear a worse one
8218           int iLongest = ( contNodes[0].size() < contNodes[1].size() ? 1 : 0 );
8219           int iWorse = ( needTheLast ? 1 - iLongest : iLongest );
8220           contNodes[ iWorse ].clear();
8221           contFaces[ iWorse ].clear();
8222         }
8223       }
8224       if ( contNodes[0].empty() && contNodes[1].empty() )
8225         return false;
8226
8227       // append the best free border
8228       cNL = & contNodes[ contNodes[0].empty() ? 1 : 0 ];
8229       cFL = & contFaces[ contFaces[0].empty() ? 1 : 0 ];
8230       theNodes.pop_back(); // remove nIgnore
8231       theNodes.pop_back(); // remove nStart
8232       theFaces.pop_back(); // remove curElem
8233       list< const SMDS_MeshNode* >::iterator nIt = cNL->begin();
8234       list< const SMDS_MeshElement* >::iterator fIt = cFL->begin();
8235       for ( ; nIt != cNL->end(); nIt++ ) theNodes.push_back( *nIt );
8236       for ( ; fIt != cFL->end(); fIt++ ) theFaces.push_back( *fIt );
8237       return true;
8238
8239     } // several continuations found
8240   } // while ( nStart != theLastNode )
8241
8242   return true;
8243 }
8244
8245 //=======================================================================
8246 //function : CheckFreeBorderNodes
8247 //purpose  : Return true if the tree nodes are on a free border
8248 //=======================================================================
8249
8250 bool SMESH_MeshEditor::CheckFreeBorderNodes(const SMDS_MeshNode* theNode1,
8251                                             const SMDS_MeshNode* theNode2,
8252                                             const SMDS_MeshNode* theNode3)
8253 {
8254   list< const SMDS_MeshNode* > nodes;
8255   list< const SMDS_MeshElement* > faces;
8256   return FindFreeBorder( theNode1, theNode2, theNode3, nodes, faces);
8257 }
8258
8259 //=======================================================================
8260 //function : SewFreeBorder
8261 //purpose  :
8262 //=======================================================================
8263
8264 SMESH_MeshEditor::Sew_Error
8265 SMESH_MeshEditor::SewFreeBorder (const SMDS_MeshNode* theBordFirstNode,
8266                                  const SMDS_MeshNode* theBordSecondNode,
8267                                  const SMDS_MeshNode* theBordLastNode,
8268                                  const SMDS_MeshNode* theSideFirstNode,
8269                                  const SMDS_MeshNode* theSideSecondNode,
8270                                  const SMDS_MeshNode* theSideThirdNode,
8271                                  const bool           theSideIsFreeBorder,
8272                                  const bool           toCreatePolygons,
8273                                  const bool           toCreatePolyedrs)
8274 {
8275   myLastCreatedElems.Clear();
8276   myLastCreatedNodes.Clear();
8277
8278   MESSAGE("::SewFreeBorder()");
8279   Sew_Error aResult = SEW_OK;
8280
8281   // ====================================
8282   //    find side nodes and elements
8283   // ====================================
8284
8285   list< const SMDS_MeshNode* > nSide[ 2 ];
8286   list< const SMDS_MeshElement* > eSide[ 2 ];
8287   list< const SMDS_MeshNode* >::iterator nIt[ 2 ];
8288   list< const SMDS_MeshElement* >::iterator eIt[ 2 ];
8289
8290   // Free border 1
8291   // --------------
8292   if (!FindFreeBorder(theBordFirstNode,theBordSecondNode,theBordLastNode,
8293                       nSide[0], eSide[0])) {
8294     MESSAGE(" Free Border 1 not found " );
8295     aResult = SEW_BORDER1_NOT_FOUND;
8296   }
8297   if (theSideIsFreeBorder) {
8298     // Free border 2
8299     // --------------
8300     if (!FindFreeBorder(theSideFirstNode, theSideSecondNode, theSideThirdNode,
8301                         nSide[1], eSide[1])) {
8302       MESSAGE(" Free Border 2 not found " );
8303       aResult = ( aResult != SEW_OK ? SEW_BOTH_BORDERS_NOT_FOUND : SEW_BORDER2_NOT_FOUND );
8304     }
8305   }
8306   if ( aResult != SEW_OK )
8307     return aResult;
8308
8309   if (!theSideIsFreeBorder) {
8310     // Side 2
8311     // --------------
8312
8313     // -------------------------------------------------------------------------
8314     // Algo:
8315     // 1. If nodes to merge are not coincident, move nodes of the free border
8316     //    from the coord sys defined by the direction from the first to last
8317     //    nodes of the border to the correspondent sys of the side 2
8318     // 2. On the side 2, find the links most co-directed with the correspondent
8319     //    links of the free border
8320     // -------------------------------------------------------------------------
8321
8322     // 1. Since sewing may break if there are volumes to split on the side 2,
8323     //    we wont move nodes but just compute new coordinates for them
8324     typedef map<const SMDS_MeshNode*, gp_XYZ> TNodeXYZMap;
8325     TNodeXYZMap nBordXYZ;
8326     list< const SMDS_MeshNode* >& bordNodes = nSide[ 0 ];
8327     list< const SMDS_MeshNode* >::iterator nBordIt;
8328
8329     gp_XYZ Pb1( theBordFirstNode->X(), theBordFirstNode->Y(), theBordFirstNode->Z() );
8330     gp_XYZ Pb2( theBordLastNode->X(), theBordLastNode->Y(), theBordLastNode->Z() );
8331     gp_XYZ Ps1( theSideFirstNode->X(), theSideFirstNode->Y(), theSideFirstNode->Z() );
8332     gp_XYZ Ps2( theSideSecondNode->X(), theSideSecondNode->Y(), theSideSecondNode->Z() );
8333     double tol2 = 1.e-8;
8334     gp_Vec Vbs1( Pb1 - Ps1 ),Vbs2( Pb2 - Ps2 );
8335     if ( Vbs1.SquareMagnitude() > tol2 || Vbs2.SquareMagnitude() > tol2 ) {
8336       // Need node movement.
8337
8338       // find X and Z axes to create trsf
8339       gp_Vec Zb( Pb1 - Pb2 ), Zs( Ps1 - Ps2 );
8340       gp_Vec X = Zs ^ Zb;
8341       if ( X.SquareMagnitude() <= gp::Resolution() * gp::Resolution() )
8342         // Zb || Zs
8343         X = gp_Ax2( gp::Origin(), Zb ).XDirection();
8344
8345       // coord systems
8346       gp_Ax3 toBordAx( Pb1, Zb, X );
8347       gp_Ax3 fromSideAx( Ps1, Zs, X );
8348       gp_Ax3 toGlobalAx( gp::Origin(), gp::DZ(), gp::DX() );
8349       // set trsf
8350       gp_Trsf toBordSys, fromSide2Sys;
8351       toBordSys.SetTransformation( toBordAx );
8352       fromSide2Sys.SetTransformation( fromSideAx, toGlobalAx );
8353       fromSide2Sys.SetScaleFactor( Zs.Magnitude() / Zb.Magnitude() );
8354
8355       // move
8356       for ( nBordIt = bordNodes.begin(); nBordIt != bordNodes.end(); nBordIt++ ) {
8357         const SMDS_MeshNode* n = *nBordIt;
8358         gp_XYZ xyz( n->X(),n->Y(),n->Z() );
8359         toBordSys.Transforms( xyz );
8360         fromSide2Sys.Transforms( xyz );
8361         nBordXYZ.insert( TNodeXYZMap::value_type( n, xyz ));
8362       }
8363     }
8364     else {
8365       // just insert nodes XYZ in the nBordXYZ map
8366       for ( nBordIt = bordNodes.begin(); nBordIt != bordNodes.end(); nBordIt++ ) {
8367         const SMDS_MeshNode* n = *nBordIt;
8368         nBordXYZ.insert( TNodeXYZMap::value_type( n, gp_XYZ( n->X(),n->Y(),n->Z() )));
8369       }
8370     }
8371
8372     // 2. On the side 2, find the links most co-directed with the correspondent
8373     //    links of the free border
8374
8375     list< const SMDS_MeshElement* >& sideElems = eSide[ 1 ];
8376     list< const SMDS_MeshNode* >& sideNodes = nSide[ 1 ];
8377     sideNodes.push_back( theSideFirstNode );
8378
8379     bool hasVolumes = false;
8380     LinkID_Gen aLinkID_Gen( GetMeshDS() );
8381     set<long> foundSideLinkIDs, checkedLinkIDs;
8382     SMDS_VolumeTool volume;
8383     //const SMDS_MeshNode* faceNodes[ 4 ];
8384
8385     const SMDS_MeshNode*    sideNode;
8386     const SMDS_MeshElement* sideElem;
8387     const SMDS_MeshNode* prevSideNode = theSideFirstNode;
8388     const SMDS_MeshNode* prevBordNode = theBordFirstNode;
8389     nBordIt = bordNodes.begin();
8390     nBordIt++;
8391     // border node position and border link direction to compare with
8392     gp_XYZ bordPos = nBordXYZ[ *nBordIt ];
8393     gp_XYZ bordDir = bordPos - nBordXYZ[ prevBordNode ];
8394     // choose next side node by link direction or by closeness to
8395     // the current border node:
8396     bool searchByDir = ( *nBordIt != theBordLastNode );
8397     do {
8398       // find the next node on the Side 2
8399       sideNode = 0;
8400       double maxDot = -DBL_MAX, minDist = DBL_MAX;
8401       long linkID;
8402       checkedLinkIDs.clear();
8403       gp_XYZ prevXYZ( prevSideNode->X(), prevSideNode->Y(), prevSideNode->Z() );
8404
8405       // loop on inverse elements of current node (prevSideNode) on the Side 2
8406       SMDS_ElemIteratorPtr invElemIt = prevSideNode->GetInverseElementIterator();
8407       while ( invElemIt->more() )
8408       {
8409         const SMDS_MeshElement* elem = invElemIt->next();
8410         // prepare data for a loop on links coming to prevSideNode, of a face or a volume
8411         int iPrevNode, iNode = 0, nbNodes = elem->NbNodes();
8412         vector< const SMDS_MeshNode* > faceNodes( nbNodes, (const SMDS_MeshNode*)0 );
8413         bool isVolume = volume.Set( elem );
8414         const SMDS_MeshNode** nodes = isVolume ? volume.GetNodes() : & faceNodes[0];
8415         if ( isVolume ) // --volume
8416           hasVolumes = true;
8417         else if ( elem->GetType()==SMDSAbs_Face ) { // --face
8418           // retrieve all face nodes and find iPrevNode - an index of the prevSideNode
8419           if(elem->IsQuadratic()) {
8420             const SMDS_VtkFace* F =
8421               dynamic_cast<const SMDS_VtkFace*>(elem);
8422             if (!F) throw SALOME_Exception(LOCALIZED("not an SMDS_VtkFace"));
8423             // use special nodes iterator
8424             SMDS_ElemIteratorPtr anIter = F->interlacedNodesElemIterator();
8425             while( anIter->more() ) {
8426               nodes[ iNode ] = cast2Node(anIter->next());
8427               if ( nodes[ iNode++ ] == prevSideNode )
8428                 iPrevNode = iNode - 1;
8429             }
8430           }
8431           else {
8432             SMDS_ElemIteratorPtr nIt = elem->nodesIterator();
8433             while ( nIt->more() ) {
8434               nodes[ iNode ] = cast2Node( nIt->next() );
8435               if ( nodes[ iNode++ ] == prevSideNode )
8436                 iPrevNode = iNode - 1;
8437             }
8438           }
8439           // there are 2 links to check
8440           nbNodes = 2;
8441         }
8442         else // --edge
8443           continue;
8444         // loop on links, to be precise, on the second node of links
8445         for ( iNode = 0; iNode < nbNodes; iNode++ ) {
8446           const SMDS_MeshNode* n = nodes[ iNode ];
8447           if ( isVolume ) {
8448             if ( !volume.IsLinked( n, prevSideNode ))
8449               continue;
8450           }
8451           else {
8452             if ( iNode ) // a node before prevSideNode
8453               n = nodes[ iPrevNode == 0 ? elem->NbNodes() - 1 : iPrevNode - 1 ];
8454             else         // a node after prevSideNode
8455               n = nodes[ iPrevNode + 1 == elem->NbNodes() ? 0 : iPrevNode + 1 ];
8456           }
8457           // check if this link was already used
8458           long iLink = aLinkID_Gen.GetLinkID( prevSideNode, n );
8459           bool isJustChecked = !checkedLinkIDs.insert( iLink ).second;
8460           if (!isJustChecked &&
8461               foundSideLinkIDs.find( iLink ) == foundSideLinkIDs.end() )
8462           {
8463             // test a link geometrically
8464             gp_XYZ nextXYZ ( n->X(), n->Y(), n->Z() );
8465             bool linkIsBetter = false;
8466             double dot = 0.0, dist = 0.0;
8467             if ( searchByDir ) { // choose most co-directed link
8468               dot = bordDir * ( nextXYZ - prevXYZ ).Normalized();
8469               linkIsBetter = ( dot > maxDot );
8470             }
8471             else { // choose link with the node closest to bordPos
8472               dist = ( nextXYZ - bordPos ).SquareModulus();
8473               linkIsBetter = ( dist < minDist );
8474             }
8475             if ( linkIsBetter ) {
8476               maxDot = dot;
8477               minDist = dist;
8478               linkID = iLink;
8479               sideNode = n;
8480               sideElem = elem;
8481             }
8482           }
8483         }
8484       } // loop on inverse elements of prevSideNode
8485
8486       if ( !sideNode ) {
8487         MESSAGE(" Cant find path by links of the Side 2 ");
8488         return SEW_BAD_SIDE_NODES;
8489       }
8490       sideNodes.push_back( sideNode );
8491       sideElems.push_back( sideElem );
8492       foundSideLinkIDs.insert ( linkID );
8493       prevSideNode = sideNode;
8494
8495       if ( *nBordIt == theBordLastNode )
8496         searchByDir = false;
8497       else {
8498         // find the next border link to compare with
8499         gp_XYZ sidePos( sideNode->X(), sideNode->Y(), sideNode->Z() );
8500         searchByDir = ( bordDir * ( sidePos - bordPos ) <= 0 );
8501         // move to next border node if sideNode is before forward border node (bordPos)
8502         while ( *nBordIt != theBordLastNode && !searchByDir ) {
8503           prevBordNode = *nBordIt;
8504           nBordIt++;
8505           bordPos = nBordXYZ[ *nBordIt ];
8506           bordDir = bordPos - nBordXYZ[ prevBordNode ];
8507           searchByDir = ( bordDir * ( sidePos - bordPos ) <= 0 );
8508         }
8509       }
8510     }
8511     while ( sideNode != theSideSecondNode );
8512
8513     if ( hasVolumes && sideNodes.size () != bordNodes.size() && !toCreatePolyedrs) {
8514       MESSAGE("VOLUME SPLITTING IS FORBIDDEN");
8515       return SEW_VOLUMES_TO_SPLIT; // volume splitting is forbidden
8516     }
8517   } // end nodes search on the side 2
8518
8519   // ============================
8520   // sew the border to the side 2
8521   // ============================
8522
8523   int nbNodes[]  = { nSide[0].size(), nSide[1].size() };
8524   int maxNbNodes = Max( nbNodes[0], nbNodes[1] );
8525
8526   TListOfListOfNodes nodeGroupsToMerge;
8527   if ( nbNodes[0] == nbNodes[1] ||
8528        ( theSideIsFreeBorder && !theSideThirdNode)) {
8529
8530     // all nodes are to be merged
8531
8532     for (nIt[0] = nSide[0].begin(), nIt[1] = nSide[1].begin();
8533          nIt[0] != nSide[0].end() && nIt[1] != nSide[1].end();
8534          nIt[0]++, nIt[1]++ )
8535     {
8536       nodeGroupsToMerge.push_back( list<const SMDS_MeshNode*>() );
8537       nodeGroupsToMerge.back().push_back( *nIt[1] ); // to keep
8538       nodeGroupsToMerge.back().push_back( *nIt[0] ); // to remove
8539     }
8540   }
8541   else {
8542
8543     // insert new nodes into the border and the side to get equal nb of segments
8544
8545     // get normalized parameters of nodes on the borders
8546     //double param[ 2 ][ maxNbNodes ];
8547     double* param[ 2 ];
8548     param[0] = new double [ maxNbNodes ];
8549     param[1] = new double [ maxNbNodes ];
8550     int iNode, iBord;
8551     for ( iBord = 0; iBord < 2; iBord++ ) { // loop on 2 borders
8552       list< const SMDS_MeshNode* >& nodes = nSide[ iBord ];
8553       list< const SMDS_MeshNode* >::iterator nIt = nodes.begin();
8554       const SMDS_MeshNode* nPrev = *nIt;
8555       double bordLength = 0;
8556       for ( iNode = 0; nIt != nodes.end(); nIt++, iNode++ ) { // loop on border nodes
8557         const SMDS_MeshNode* nCur = *nIt;
8558         gp_XYZ segment (nCur->X() - nPrev->X(),
8559                         nCur->Y() - nPrev->Y(),
8560                         nCur->Z() - nPrev->Z());
8561         double segmentLen = segment.Modulus();
8562         bordLength += segmentLen;
8563         param[ iBord ][ iNode ] = bordLength;
8564         nPrev = nCur;
8565       }
8566       // normalize within [0,1]
8567       for ( iNode = 0; iNode < nbNodes[ iBord ]; iNode++ ) {
8568         param[ iBord ][ iNode ] /= bordLength;
8569       }
8570     }
8571
8572     // loop on border segments
8573     const SMDS_MeshNode *nPrev[ 2 ] = { 0, 0 };
8574     int i[ 2 ] = { 0, 0 };
8575     nIt[0] = nSide[0].begin(); eIt[0] = eSide[0].begin();
8576     nIt[1] = nSide[1].begin(); eIt[1] = eSide[1].begin();
8577
8578     TElemOfNodeListMap insertMap;
8579     TElemOfNodeListMap::iterator insertMapIt;
8580     // insertMap is
8581     // key:   elem to insert nodes into
8582     // value: 2 nodes to insert between + nodes to be inserted
8583     do {
8584       bool next[ 2 ] = { false, false };
8585
8586       // find min adjacent segment length after sewing
8587       double nextParam = 10., prevParam = 0;
8588       for ( iBord = 0; iBord < 2; iBord++ ) { // loop on 2 borders
8589         if ( i[ iBord ] + 1 < nbNodes[ iBord ])
8590           nextParam = Min( nextParam, param[iBord][ i[iBord] + 1 ]);
8591         if ( i[ iBord ] > 0 )
8592           prevParam = Max( prevParam, param[iBord][ i[iBord] - 1 ]);
8593       }
8594       double minParam = Min( param[ 0 ][ i[0] ], param[ 1 ][ i[1] ]);
8595       double maxParam = Max( param[ 0 ][ i[0] ], param[ 1 ][ i[1] ]);
8596       double minSegLen = Min( nextParam - minParam, maxParam - prevParam );
8597
8598       // choose to insert or to merge nodes
8599       double du = param[ 1 ][ i[1] ] - param[ 0 ][ i[0] ];
8600       if ( Abs( du ) <= minSegLen * 0.2 ) {
8601         // merge
8602         // ------
8603         nodeGroupsToMerge.push_back( list<const SMDS_MeshNode*>() );
8604         const SMDS_MeshNode* n0 = *nIt[0];
8605         const SMDS_MeshNode* n1 = *nIt[1];
8606         nodeGroupsToMerge.back().push_back( n1 );
8607         nodeGroupsToMerge.back().push_back( n0 );
8608         // position of node of the border changes due to merge
8609         param[ 0 ][ i[0] ] += du;
8610         // move n1 for the sake of elem shape evaluation during insertion.
8611         // n1 will be removed by MergeNodes() anyway
8612         const_cast<SMDS_MeshNode*>( n0 )->setXYZ( n1->X(), n1->Y(), n1->Z() );
8613         next[0] = next[1] = true;
8614       }
8615       else {
8616         // insert
8617         // ------
8618         int intoBord = ( du < 0 ) ? 0 : 1;
8619         const SMDS_MeshElement* elem = *eIt[ intoBord ];
8620         const SMDS_MeshNode*    n1   = nPrev[ intoBord ];
8621         const SMDS_MeshNode*    n2   = *nIt[ intoBord ];
8622         const SMDS_MeshNode*    nIns = *nIt[ 1 - intoBord ];
8623         if ( intoBord == 1 ) {
8624           // move node of the border to be on a link of elem of the side
8625           gp_XYZ p1 (n1->X(), n1->Y(), n1->Z());
8626           gp_XYZ p2 (n2->X(), n2->Y(), n2->Z());
8627           double ratio = du / ( param[ 1 ][ i[1] ] - param[ 1 ][ i[1]-1 ]);
8628           gp_XYZ p = p2 * ( 1 - ratio ) + p1 * ratio;
8629           GetMeshDS()->MoveNode( nIns, p.X(), p.Y(), p.Z() );
8630         }
8631         insertMapIt = insertMap.find( elem );
8632         bool notFound = ( insertMapIt == insertMap.end() );
8633         bool otherLink = ( !notFound && (*insertMapIt).second.front() != n1 );
8634         if ( otherLink ) {
8635           // insert into another link of the same element:
8636           // 1. perform insertion into the other link of the elem
8637           list<const SMDS_MeshNode*> & nodeList = (*insertMapIt).second;
8638           const SMDS_MeshNode* n12 = nodeList.front(); nodeList.pop_front();
8639           const SMDS_MeshNode* n22 = nodeList.front(); nodeList.pop_front();
8640           InsertNodesIntoLink( elem, n12, n22, nodeList, toCreatePolygons );
8641           // 2. perform insertion into the link of adjacent faces
8642           while (true) {
8643             const SMDS_MeshElement* adjElem = findAdjacentFace( n12, n22, elem );
8644             if ( adjElem )
8645               InsertNodesIntoLink( adjElem, n12, n22, nodeList, toCreatePolygons );
8646             else
8647               break;
8648           }
8649           if (toCreatePolyedrs) {
8650             // perform insertion into the links of adjacent volumes
8651             UpdateVolumes(n12, n22, nodeList);
8652           }
8653           // 3. find an element appeared on n1 and n2 after the insertion
8654           insertMap.erase( elem );
8655           elem = findAdjacentFace( n1, n2, 0 );
8656         }
8657         if ( notFound || otherLink ) {
8658           // add element and nodes of the side into the insertMap
8659           insertMapIt = insertMap.insert
8660             ( TElemOfNodeListMap::value_type( elem, list<const SMDS_MeshNode*>() )).first;
8661           (*insertMapIt).second.push_back( n1 );
8662           (*insertMapIt).second.push_back( n2 );
8663         }
8664         // add node to be inserted into elem
8665         (*insertMapIt).second.push_back( nIns );
8666         next[ 1 - intoBord ] = true;
8667       }
8668
8669       // go to the next segment
8670       for ( iBord = 0; iBord < 2; iBord++ ) { // loop on 2 borders
8671         if ( next[ iBord ] ) {
8672           if ( i[ iBord ] != 0 && eIt[ iBord ] != eSide[ iBord ].end())
8673             eIt[ iBord ]++;
8674           nPrev[ iBord ] = *nIt[ iBord ];
8675           nIt[ iBord ]++; i[ iBord ]++;
8676         }
8677       }
8678     }
8679     while ( nIt[0] != nSide[0].end() && nIt[1] != nSide[1].end());
8680
8681     // perform insertion of nodes into elements
8682
8683     for (insertMapIt = insertMap.begin();
8684          insertMapIt != insertMap.end();
8685          insertMapIt++ )
8686     {
8687       const SMDS_MeshElement* elem = (*insertMapIt).first;
8688       list<const SMDS_MeshNode*> & nodeList = (*insertMapIt).second;
8689       const SMDS_MeshNode* n1 = nodeList.front(); nodeList.pop_front();
8690       const SMDS_MeshNode* n2 = nodeList.front(); nodeList.pop_front();
8691
8692       InsertNodesIntoLink( elem, n1, n2, nodeList, toCreatePolygons );
8693
8694       if ( !theSideIsFreeBorder ) {
8695         // look for and insert nodes into the faces adjacent to elem
8696         while (true) {
8697           const SMDS_MeshElement* adjElem = findAdjacentFace( n1, n2, elem );
8698           if ( adjElem )
8699             InsertNodesIntoLink( adjElem, n1, n2, nodeList, toCreatePolygons );
8700           else
8701             break;
8702         }
8703       }
8704       if (toCreatePolyedrs) {
8705         // perform insertion into the links of adjacent volumes
8706         UpdateVolumes(n1, n2, nodeList);
8707       }
8708     }
8709
8710     delete param[0];
8711     delete param[1];
8712   } // end: insert new nodes
8713
8714   MergeNodes ( nodeGroupsToMerge );
8715
8716   return aResult;
8717 }
8718
8719 //=======================================================================
8720 //function : InsertNodesIntoLink
8721 //purpose  : insert theNodesToInsert into theFace between theBetweenNode1
8722 //           and theBetweenNode2 and split theElement
8723 //=======================================================================
8724
8725 void SMESH_MeshEditor::InsertNodesIntoLink(const SMDS_MeshElement*     theFace,
8726                                            const SMDS_MeshNode*        theBetweenNode1,
8727                                            const SMDS_MeshNode*        theBetweenNode2,
8728                                            list<const SMDS_MeshNode*>& theNodesToInsert,
8729                                            const bool                  toCreatePoly)
8730 {
8731   if ( theFace->GetType() != SMDSAbs_Face ) return;
8732
8733   // find indices of 2 link nodes and of the rest nodes
8734   int iNode = 0, il1, il2, i3, i4;
8735   il1 = il2 = i3 = i4 = -1;
8736   //const SMDS_MeshNode* nodes[ theFace->NbNodes() ];
8737   vector<const SMDS_MeshNode*> nodes( theFace->NbNodes() );
8738
8739   if(theFace->IsQuadratic()) {
8740     const SMDS_VtkFace* F =
8741       dynamic_cast<const SMDS_VtkFace*>(theFace);
8742     if (!F) throw SALOME_Exception(LOCALIZED("not an SMDS_VtkFace"));
8743     // use special nodes iterator
8744     SMDS_ElemIteratorPtr anIter = F->interlacedNodesElemIterator();
8745     while( anIter->more() ) {
8746       const SMDS_MeshNode* n = cast2Node(anIter->next());
8747       if ( n == theBetweenNode1 )
8748         il1 = iNode;
8749       else if ( n == theBetweenNode2 )
8750         il2 = iNode;
8751       else if ( i3 < 0 )
8752         i3 = iNode;
8753       else
8754         i4 = iNode;
8755       nodes[ iNode++ ] = n;
8756     }
8757   }
8758   else {
8759     SMDS_ElemIteratorPtr nodeIt = theFace->nodesIterator();
8760     while ( nodeIt->more() ) {
8761       const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
8762       if ( n == theBetweenNode1 )
8763         il1 = iNode;
8764       else if ( n == theBetweenNode2 )
8765         il2 = iNode;
8766       else if ( i3 < 0 )
8767         i3 = iNode;
8768       else
8769         i4 = iNode;
8770       nodes[ iNode++ ] = n;
8771     }
8772   }
8773   if ( il1 < 0 || il2 < 0 || i3 < 0 )
8774     return ;
8775
8776   // arrange link nodes to go one after another regarding the face orientation
8777   bool reverse = ( Abs( il2 - il1 ) == 1 ? il2 < il1 : il1 < il2 );
8778   list<const SMDS_MeshNode *> aNodesToInsert = theNodesToInsert;
8779   if ( reverse ) {
8780     iNode = il1;
8781     il1 = il2;
8782     il2 = iNode;
8783     aNodesToInsert.reverse();
8784   }
8785   // check that not link nodes of a quadrangles are in good order
8786   int nbFaceNodes = theFace->NbNodes();
8787   if ( nbFaceNodes == 4 && i4 - i3 != 1 ) {
8788     iNode = i3;
8789     i3 = i4;
8790     i4 = iNode;
8791   }
8792
8793   if (toCreatePoly || theFace->IsPoly()) {
8794
8795     iNode = 0;
8796     vector<const SMDS_MeshNode *> poly_nodes (nbFaceNodes + aNodesToInsert.size());
8797
8798     // add nodes of face up to first node of link
8799     bool isFLN = false;
8800
8801     if(theFace->IsQuadratic()) {
8802       const SMDS_VtkFace* F =
8803         dynamic_cast<const SMDS_VtkFace*>(theFace);
8804       if (!F) throw SALOME_Exception(LOCALIZED("not an SMDS_VtkFace"));
8805       // use special nodes iterator
8806       SMDS_ElemIteratorPtr anIter = F->interlacedNodesElemIterator();
8807       while( anIter->more()  && !isFLN ) {
8808         const SMDS_MeshNode* n = cast2Node(anIter->next());
8809         poly_nodes[iNode++] = n;
8810         if (n == nodes[il1]) {
8811           isFLN = true;
8812         }
8813       }
8814       // add nodes to insert
8815       list<const SMDS_MeshNode*>::iterator nIt = aNodesToInsert.begin();
8816       for (; nIt != aNodesToInsert.end(); nIt++) {
8817         poly_nodes[iNode++] = *nIt;
8818       }
8819       // add nodes of face starting from last node of link
8820       while ( anIter->more() ) {
8821         poly_nodes[iNode++] = cast2Node(anIter->next());
8822       }
8823     }
8824     else {
8825       SMDS_ElemIteratorPtr nodeIt = theFace->nodesIterator();
8826       while ( nodeIt->more() && !isFLN ) {
8827         const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
8828         poly_nodes[iNode++] = n;
8829         if (n == nodes[il1]) {
8830           isFLN = true;
8831         }
8832       }
8833       // add nodes to insert
8834       list<const SMDS_MeshNode*>::iterator nIt = aNodesToInsert.begin();
8835       for (; nIt != aNodesToInsert.end(); nIt++) {
8836         poly_nodes[iNode++] = *nIt;
8837       }
8838       // add nodes of face starting from last node of link
8839       while ( nodeIt->more() ) {
8840         const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
8841         poly_nodes[iNode++] = n;
8842       }
8843     }
8844
8845     // edit or replace the face
8846     SMESHDS_Mesh *aMesh = GetMeshDS();
8847
8848     if (theFace->IsPoly()) {
8849       aMesh->ChangePolygonNodes(theFace, poly_nodes);
8850     }
8851     else {
8852       int aShapeId = FindShape( theFace );
8853
8854       SMDS_MeshElement* newElem = aMesh->AddPolygonalFace(poly_nodes);
8855       myLastCreatedElems.Append(newElem);
8856       if ( aShapeId && newElem )
8857         aMesh->SetMeshElementOnShape( newElem, aShapeId );
8858
8859       aMesh->RemoveElement(theFace);
8860     }
8861     return;
8862   }
8863
8864   SMESHDS_Mesh *aMesh = GetMeshDS();
8865   if( !theFace->IsQuadratic() ) {
8866
8867     // put aNodesToInsert between theBetweenNode1 and theBetweenNode2
8868     int nbLinkNodes = 2 + aNodesToInsert.size();
8869     //const SMDS_MeshNode* linkNodes[ nbLinkNodes ];
8870     vector<const SMDS_MeshNode*> linkNodes( nbLinkNodes );
8871     linkNodes[ 0 ] = nodes[ il1 ];
8872     linkNodes[ nbLinkNodes - 1 ] = nodes[ il2 ];
8873     list<const SMDS_MeshNode*>::iterator nIt = aNodesToInsert.begin();
8874     for ( iNode = 1; nIt != aNodesToInsert.end(); nIt++ ) {
8875       linkNodes[ iNode++ ] = *nIt;
8876     }
8877     // decide how to split a quadrangle: compare possible variants
8878     // and choose which of splits to be a quadrangle
8879     int i1, i2, iSplit, nbSplits = nbLinkNodes - 1, iBestQuad;
8880     if ( nbFaceNodes == 3 ) {
8881       iBestQuad = nbSplits;
8882       i4 = i3;
8883     }
8884     else if ( nbFaceNodes == 4 ) {
8885       SMESH::Controls::NumericalFunctorPtr aCrit( new SMESH::Controls::AspectRatio);
8886       double aBestRate = DBL_MAX;
8887       for ( int iQuad = 0; iQuad < nbSplits; iQuad++ ) {
8888         i1 = 0; i2 = 1;
8889         double aBadRate = 0;
8890         // evaluate elements quality
8891         for ( iSplit = 0; iSplit < nbSplits; iSplit++ ) {
8892           if ( iSplit == iQuad ) {
8893             SMDS_FaceOfNodes quad (linkNodes[ i1++ ],
8894                                    linkNodes[ i2++ ],
8895                                    nodes[ i3 ],
8896                                    nodes[ i4 ]);
8897             aBadRate += getBadRate( &quad, aCrit );
8898           }
8899           else {
8900             SMDS_FaceOfNodes tria (linkNodes[ i1++ ],
8901                                    linkNodes[ i2++ ],
8902                                    nodes[ iSplit < iQuad ? i4 : i3 ]);
8903             aBadRate += getBadRate( &tria, aCrit );
8904           }
8905         }
8906         // choice
8907         if ( aBadRate < aBestRate ) {
8908           iBestQuad = iQuad;
8909           aBestRate = aBadRate;
8910         }
8911       }
8912     }
8913
8914     // create new elements
8915     int aShapeId = FindShape( theFace );
8916
8917     i1 = 0; i2 = 1;
8918     for ( iSplit = 0; iSplit < nbSplits - 1; iSplit++ ) {
8919       SMDS_MeshElement* newElem = 0;
8920       if ( iSplit == iBestQuad )
8921         newElem = aMesh->AddFace (linkNodes[ i1++ ],
8922                                   linkNodes[ i2++ ],
8923                                   nodes[ i3 ],
8924                                   nodes[ i4 ]);
8925       else
8926         newElem = aMesh->AddFace (linkNodes[ i1++ ],
8927                                   linkNodes[ i2++ ],
8928                                   nodes[ iSplit < iBestQuad ? i4 : i3 ]);
8929       myLastCreatedElems.Append(newElem);
8930       if ( aShapeId && newElem )
8931         aMesh->SetMeshElementOnShape( newElem, aShapeId );
8932     }
8933
8934     // change nodes of theFace
8935     const SMDS_MeshNode* newNodes[ 4 ];
8936     newNodes[ 0 ] = linkNodes[ i1 ];
8937     newNodes[ 1 ] = linkNodes[ i2 ];
8938     newNodes[ 2 ] = nodes[ iSplit >= iBestQuad ? i3 : i4 ];
8939     newNodes[ 3 ] = nodes[ i4 ];
8940     //aMesh->ChangeElementNodes( theFace, newNodes, iSplit == iBestQuad ? 4 : 3 );
8941     const SMDS_MeshElement* newElem = 0;
8942     if (iSplit == iBestQuad)
8943       newElem = aMesh->AddFace( newNodes[0], newNodes[1], newNodes[2], newNodes[3] );
8944     else
8945       newElem = aMesh->AddFace( newNodes[0], newNodes[1], newNodes[2] );
8946     myLastCreatedElems.Append(newElem);
8947     if ( aShapeId && newElem )
8948       aMesh->SetMeshElementOnShape( newElem, aShapeId );
8949 } // end if(!theFace->IsQuadratic())
8950   else { // theFace is quadratic
8951     // we have to split theFace on simple triangles and one simple quadrangle
8952     int tmp = il1/2;
8953     int nbshift = tmp*2;
8954     // shift nodes in nodes[] by nbshift
8955     int i,j;
8956     for(i=0; i<nbshift; i++) {
8957       const SMDS_MeshNode* n = nodes[0];
8958       for(j=0; j<nbFaceNodes-1; j++) {
8959         nodes[j] = nodes[j+1];
8960       }
8961       nodes[nbFaceNodes-1] = n;
8962     }
8963     il1 = il1 - nbshift;
8964     // now have to insert nodes between n0 and n1 or n1 and n2 (see below)
8965     //   n0      n1     n2    n0      n1     n2
8966     //     +-----+-----+        +-----+-----+
8967     //      \         /         |           |
8968     //       \       /          |           |
8969     //      n5+     +n3       n7+           +n3
8970     //         \   /            |           |
8971     //          \ /             |           |
8972     //           +              +-----+-----+
8973     //           n4           n6      n5     n4
8974
8975     // create new elements
8976     int aShapeId = FindShape( theFace );
8977
8978     int n1,n2,n3;
8979     if(nbFaceNodes==6) { // quadratic triangle
8980       SMDS_MeshElement* newElem =
8981         aMesh->AddFace(nodes[3],nodes[4],nodes[5]);
8982       myLastCreatedElems.Append(newElem);
8983       if ( aShapeId && newElem )
8984         aMesh->SetMeshElementOnShape( newElem, aShapeId );
8985       if(theFace->IsMediumNode(nodes[il1])) {
8986         // create quadrangle
8987         newElem = aMesh->AddFace(nodes[0],nodes[1],nodes[3],nodes[5]);
8988         myLastCreatedElems.Append(newElem);
8989         if ( aShapeId && newElem )
8990           aMesh->SetMeshElementOnShape( newElem, aShapeId );
8991         n1 = 1;
8992         n2 = 2;
8993         n3 = 3;
8994       }
8995       else {
8996         // create quadrangle
8997         newElem = aMesh->AddFace(nodes[1],nodes[2],nodes[3],nodes[5]);
8998         myLastCreatedElems.Append(newElem);
8999         if ( aShapeId && newElem )
9000           aMesh->SetMeshElementOnShape( newElem, aShapeId );
9001         n1 = 0;
9002         n2 = 1;
9003         n3 = 5;
9004       }
9005     }
9006     else { // nbFaceNodes==8 - quadratic quadrangle
9007       SMDS_MeshElement* newElem =
9008         aMesh->AddFace(nodes[3],nodes[4],nodes[5]);
9009       myLastCreatedElems.Append(newElem);
9010       if ( aShapeId && newElem )
9011         aMesh->SetMeshElementOnShape( newElem, aShapeId );
9012       newElem = aMesh->AddFace(nodes[5],nodes[6],nodes[7]);
9013       myLastCreatedElems.Append(newElem);
9014       if ( aShapeId && newElem )
9015         aMesh->SetMeshElementOnShape( newElem, aShapeId );
9016       newElem = aMesh->AddFace(nodes[5],nodes[7],nodes[3]);
9017       myLastCreatedElems.Append(newElem);
9018       if ( aShapeId && newElem )
9019         aMesh->SetMeshElementOnShape( newElem, aShapeId );
9020       if(theFace->IsMediumNode(nodes[il1])) {
9021         // create quadrangle
9022         newElem = aMesh->AddFace(nodes[0],nodes[1],nodes[3],nodes[7]);
9023         myLastCreatedElems.Append(newElem);
9024         if ( aShapeId && newElem )
9025           aMesh->SetMeshElementOnShape( newElem, aShapeId );
9026         n1 = 1;
9027         n2 = 2;
9028         n3 = 3;
9029       }
9030       else {
9031         // create quadrangle
9032         newElem = aMesh->AddFace(nodes[1],nodes[2],nodes[3],nodes[7]);
9033         myLastCreatedElems.Append(newElem);
9034         if ( aShapeId && newElem )
9035           aMesh->SetMeshElementOnShape( newElem, aShapeId );
9036         n1 = 0;
9037         n2 = 1;
9038         n3 = 7;
9039       }
9040     }
9041     // create needed triangles using n1,n2,n3 and inserted nodes
9042     int nbn = 2 + aNodesToInsert.size();
9043     //const SMDS_MeshNode* aNodes[nbn];
9044     vector<const SMDS_MeshNode*> aNodes(nbn);
9045     aNodes[0] = nodes[n1];
9046     aNodes[nbn-1] = nodes[n2];
9047     list<const SMDS_MeshNode*>::iterator nIt = aNodesToInsert.begin();
9048     for ( iNode = 1; nIt != aNodesToInsert.end(); nIt++ ) {
9049       aNodes[iNode++] = *nIt;
9050     }
9051     for(i=1; i<nbn; i++) {
9052       SMDS_MeshElement* newElem =
9053         aMesh->AddFace(aNodes[i-1],aNodes[i],nodes[n3]);
9054       myLastCreatedElems.Append(newElem);
9055       if ( aShapeId && newElem )
9056         aMesh->SetMeshElementOnShape( newElem, aShapeId );
9057     }
9058   }
9059   // remove old face
9060   aMesh->RemoveElement(theFace);
9061 }
9062
9063 //=======================================================================
9064 //function : UpdateVolumes
9065 //purpose  :
9066 //=======================================================================
9067 void SMESH_MeshEditor::UpdateVolumes (const SMDS_MeshNode*        theBetweenNode1,
9068                                       const SMDS_MeshNode*        theBetweenNode2,
9069                                       list<const SMDS_MeshNode*>& theNodesToInsert)
9070 {
9071   myLastCreatedElems.Clear();
9072   myLastCreatedNodes.Clear();
9073
9074   SMDS_ElemIteratorPtr invElemIt = theBetweenNode1->GetInverseElementIterator(SMDSAbs_Volume);
9075   while (invElemIt->more()) { // loop on inverse elements of theBetweenNode1
9076     const SMDS_MeshElement* elem = invElemIt->next();
9077
9078     // check, if current volume has link theBetweenNode1 - theBetweenNode2
9079     SMDS_VolumeTool aVolume (elem);
9080     if (!aVolume.IsLinked(theBetweenNode1, theBetweenNode2))
9081       continue;
9082
9083     // insert new nodes in all faces of the volume, sharing link theBetweenNode1 - theBetweenNode2
9084     int iface, nbFaces = aVolume.NbFaces();
9085     vector<const SMDS_MeshNode *> poly_nodes;
9086     vector<int> quantities (nbFaces);
9087
9088     for (iface = 0; iface < nbFaces; iface++) {
9089       int nbFaceNodes = aVolume.NbFaceNodes(iface), nbInserted = 0;
9090       // faceNodes will contain (nbFaceNodes + 1) nodes, last = first
9091       const SMDS_MeshNode** faceNodes = aVolume.GetFaceNodes(iface);
9092
9093       for (int inode = 0; inode < nbFaceNodes; inode++) {
9094         poly_nodes.push_back(faceNodes[inode]);
9095
9096         if (nbInserted == 0) {
9097           if (faceNodes[inode] == theBetweenNode1) {
9098             if (faceNodes[inode + 1] == theBetweenNode2) {
9099               nbInserted = theNodesToInsert.size();
9100
9101               // add nodes to insert
9102               list<const SMDS_MeshNode*>::iterator nIt = theNodesToInsert.begin();
9103               for (; nIt != theNodesToInsert.end(); nIt++) {
9104                 poly_nodes.push_back(*nIt);
9105               }
9106             }
9107           }
9108           else if (faceNodes[inode] == theBetweenNode2) {
9109             if (faceNodes[inode + 1] == theBetweenNode1) {
9110               nbInserted = theNodesToInsert.size();
9111
9112               // add nodes to insert in reversed order
9113               list<const SMDS_MeshNode*>::iterator nIt = theNodesToInsert.end();
9114               nIt--;
9115               for (; nIt != theNodesToInsert.begin(); nIt--) {
9116                 poly_nodes.push_back(*nIt);
9117               }
9118               poly_nodes.push_back(*nIt);
9119             }
9120           }
9121           else {
9122           }
9123         }
9124       }
9125       quantities[iface] = nbFaceNodes + nbInserted;
9126     }
9127
9128     // Replace or update the volume
9129     SMESHDS_Mesh *aMesh = GetMeshDS();
9130
9131     if (elem->IsPoly()) {
9132       aMesh->ChangePolyhedronNodes(elem, poly_nodes, quantities);
9133
9134     }
9135     else {
9136       int aShapeId = FindShape( elem );
9137
9138       SMDS_MeshElement* newElem =
9139         aMesh->AddPolyhedralVolume(poly_nodes, quantities);
9140       myLastCreatedElems.Append(newElem);
9141       if (aShapeId && newElem)
9142         aMesh->SetMeshElementOnShape(newElem, aShapeId);
9143
9144       aMesh->RemoveElement(elem);
9145     }
9146   }
9147 }
9148
9149 //=======================================================================
9150 /*!
9151  * \brief Convert elements contained in a submesh to quadratic
9152  * \retval int - nb of checked elements
9153  */
9154 //=======================================================================
9155
9156 int SMESH_MeshEditor::convertElemToQuadratic(SMESHDS_SubMesh *   theSm,
9157                                              SMESH_MesherHelper& theHelper,
9158                                              const bool          theForce3d)
9159 {
9160   int nbElem = 0;
9161   if( !theSm ) return nbElem;
9162
9163   vector<int> nbNodeInFaces;
9164   SMDS_ElemIteratorPtr ElemItr = theSm->GetElements();
9165   while(ElemItr->more())
9166   {
9167     nbElem++;
9168     const SMDS_MeshElement* elem = ElemItr->next();
9169     if( !elem || elem->IsQuadratic() ) continue;
9170
9171     int id = elem->GetID();
9172     //MESSAGE("elem " << id);
9173     id = 0; // get a free number for new elements
9174     int nbNodes = elem->NbNodes();
9175     SMDSAbs_ElementType aType = elem->GetType();
9176
9177     vector<const SMDS_MeshNode *> nodes (elem->begin_nodes(), elem->end_nodes());
9178     if ( elem->GetEntityType() == SMDSEntity_Polyhedra )
9179       nbNodeInFaces = static_cast<const SMDS_VtkVolume* >( elem )->GetQuantities();
9180
9181     const SMDS_MeshElement* NewElem = 0;
9182
9183     switch( aType )
9184     {
9185     case SMDSAbs_Edge :
9186       {
9187         NewElem = theHelper.AddEdge(nodes[0], nodes[1], id, theForce3d);
9188         break;
9189       }
9190     case SMDSAbs_Face :
9191       {
9192         switch(nbNodes)
9193         {
9194         case 3:
9195           NewElem = theHelper.AddFace(nodes[0], nodes[1], nodes[2], id, theForce3d);
9196           break;
9197         case 4:
9198           NewElem = theHelper.AddFace(nodes[0], nodes[1], nodes[2], nodes[3], id, theForce3d);
9199           break;
9200         default:
9201           NewElem = theHelper.AddPolygonalFace(nodes, id, theForce3d);
9202           continue;
9203         }
9204         break;
9205       }
9206     case SMDSAbs_Volume :
9207       {
9208         switch(nbNodes)
9209         {
9210         case 4:
9211           NewElem = theHelper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3], id, theForce3d);
9212           break;
9213         case 5:
9214           NewElem = theHelper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3], nodes[4], id, theForce3d);
9215           break;
9216         case 6:
9217           NewElem = theHelper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3], nodes[4], nodes[5], id, theForce3d);
9218           break;
9219         case 8:
9220           NewElem = theHelper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3],
9221                                         nodes[4], nodes[5], nodes[6], nodes[7], id, theForce3d);
9222           break;
9223         default:
9224           NewElem = theHelper.AddPolyhedralVolume(nodes, nbNodeInFaces, id, theForce3d);
9225         }
9226         break;
9227       }
9228     default :
9229       continue;
9230     }
9231     ReplaceElemInGroups( elem, NewElem, GetMeshDS());
9232     if( NewElem )
9233       theSm->AddElement( NewElem );
9234
9235     GetMeshDS()->RemoveFreeElement(elem, theSm, /*fromGroups=*/false);
9236   }
9237 //  if (!GetMeshDS()->isCompacted())
9238 //    GetMeshDS()->compactMesh();
9239   return nbElem;
9240 }
9241
9242 //=======================================================================
9243 //function : ConvertToQuadratic
9244 //purpose  :
9245 //=======================================================================
9246 void SMESH_MeshEditor::ConvertToQuadratic(const bool theForce3d)
9247 {
9248   SMESHDS_Mesh* meshDS = GetMeshDS();
9249
9250   SMESH_MesherHelper aHelper(*myMesh);
9251   aHelper.SetIsQuadratic( true );
9252
9253   int nbCheckedElems = 0;
9254   if ( myMesh->HasShapeToMesh() )
9255   {
9256     if ( SMESH_subMesh *aSubMesh = myMesh->GetSubMeshContaining(myMesh->GetShapeToMesh()))
9257     {
9258       SMESH_subMeshIteratorPtr smIt = aSubMesh->getDependsOnIterator(true,false);
9259       while ( smIt->more() ) {
9260         SMESH_subMesh* sm = smIt->next();
9261         if ( SMESHDS_SubMesh *smDS = sm->GetSubMeshDS() ) {
9262           aHelper.SetSubShape( sm->GetSubShape() );
9263           nbCheckedElems += convertElemToQuadratic(smDS, aHelper, theForce3d);
9264         }
9265       }
9266     }
9267   }
9268   int totalNbElems = meshDS->NbEdges() + meshDS->NbFaces() + meshDS->NbVolumes();
9269   if ( nbCheckedElems < totalNbElems ) // not all elements are in submeshes
9270   {
9271     SMESHDS_SubMesh *smDS = 0;
9272     SMDS_EdgeIteratorPtr aEdgeItr = meshDS->edgesIterator();
9273     while(aEdgeItr->more())
9274     {
9275       const SMDS_MeshEdge* edge = aEdgeItr->next();
9276       if(edge && !edge->IsQuadratic())
9277       {
9278         int id = edge->GetID();
9279         //MESSAGE("edge->GetID() " << id);
9280         const SMDS_MeshNode* n1 = edge->GetNode(0);
9281         const SMDS_MeshNode* n2 = edge->GetNode(1);
9282
9283         meshDS->RemoveFreeElement(edge, smDS, /*fromGroups=*/false);
9284
9285         const SMDS_MeshEdge* NewEdge = aHelper.AddEdge(n1, n2, id, theForce3d);
9286         ReplaceElemInGroups( edge, NewEdge, GetMeshDS());
9287       }
9288     }
9289     SMDS_FaceIteratorPtr aFaceItr = meshDS->facesIterator();
9290     while(aFaceItr->more())
9291     {
9292       const SMDS_MeshFace* face = aFaceItr->next();
9293       if(!face || face->IsQuadratic() ) continue;
9294
9295       int id = face->GetID();
9296       int nbNodes = face->NbNodes();
9297       vector<const SMDS_MeshNode *> nodes ( face->begin_nodes(), face->end_nodes());
9298
9299       meshDS->RemoveFreeElement(face, smDS, /*fromGroups=*/false);
9300
9301       SMDS_MeshFace * NewFace = 0;
9302       switch(nbNodes)
9303       {
9304       case 3:
9305         NewFace = aHelper.AddFace(nodes[0], nodes[1], nodes[2], id, theForce3d);
9306         break;
9307       case 4:
9308         NewFace = aHelper.AddFace(nodes[0], nodes[1], nodes[2], nodes[3], id, theForce3d);
9309         break;
9310       default:
9311         NewFace = aHelper.AddPolygonalFace(nodes, id, theForce3d);
9312       }
9313       ReplaceElemInGroups( face, NewFace, GetMeshDS());
9314     }
9315     vector<int> nbNodeInFaces;
9316     SMDS_VolumeIteratorPtr aVolumeItr = meshDS->volumesIterator();
9317     while(aVolumeItr->more())
9318     {
9319       const SMDS_MeshVolume* volume = aVolumeItr->next();
9320       if(!volume || volume->IsQuadratic() ) continue;
9321
9322       int id = volume->GetID();
9323       int nbNodes = volume->NbNodes();
9324       vector<const SMDS_MeshNode *> nodes (volume->begin_nodes(), volume->end_nodes());
9325       if ( volume->GetEntityType() == SMDSEntity_Polyhedra )
9326         nbNodeInFaces = static_cast<const SMDS_VtkVolume* >(volume)->GetQuantities();
9327
9328       meshDS->RemoveFreeElement(volume, smDS, /*fromGroups=*/false);
9329
9330       SMDS_MeshVolume * NewVolume = 0;
9331       switch(nbNodes)
9332       {
9333       case 4:
9334         NewVolume = aHelper.AddVolume(nodes[0], nodes[1], nodes[2],
9335                                       nodes[3], id, theForce3d );
9336         break;
9337       case 5:
9338         NewVolume = aHelper.AddVolume(nodes[0], nodes[1], nodes[2],
9339                                       nodes[3], nodes[4], id, theForce3d);
9340         break;
9341       case 6:
9342         NewVolume = aHelper.AddVolume(nodes[0], nodes[1], nodes[2],
9343                                       nodes[3], nodes[4], nodes[5], id, theForce3d);
9344         break;
9345       case 8:
9346         NewVolume = aHelper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3],
9347                                       nodes[4], nodes[5], nodes[6], nodes[7], id, theForce3d);
9348         break;
9349       default:
9350         NewVolume = aHelper.AddPolyhedralVolume(nodes, nbNodeInFaces, id, theForce3d);
9351       }
9352       ReplaceElemInGroups(volume, NewVolume, meshDS);
9353     }
9354   }
9355
9356   if ( !theForce3d  && !getenv("NO_FixQuadraticElements"))
9357   { // setenv NO_FixQuadraticElements to know if FixQuadraticElements() is guilty of bad conversion
9358     aHelper.SetSubShape(0); // apply FixQuadraticElements() to the whole mesh
9359     aHelper.FixQuadraticElements();
9360   }
9361   if (!GetMeshDS()->isCompacted())
9362     GetMeshDS()->compactMesh();
9363 }
9364
9365 //=======================================================================
9366 /*!
9367  * \brief Convert quadratic elements to linear ones and remove quadratic nodes
9368  * \retval int - nb of checked elements
9369  */
9370 //=======================================================================
9371
9372 int SMESH_MeshEditor::removeQuadElem(SMESHDS_SubMesh *    theSm,
9373                                      SMDS_ElemIteratorPtr theItr,
9374                                      const int            theShapeID)
9375 {
9376   int nbElem = 0;
9377   SMESHDS_Mesh* meshDS = GetMeshDS();
9378   const bool notFromGroups = false;
9379
9380   while( theItr->more() )
9381   {
9382     const SMDS_MeshElement* elem = theItr->next();
9383     nbElem++;
9384     if( elem && elem->IsQuadratic())
9385     {
9386       int id = elem->GetID();
9387       int nbNodes = elem->NbNodes();
9388       vector<const SMDS_MeshNode *> nodes, mediumNodes;
9389       nodes.reserve( nbNodes );
9390       mediumNodes.reserve( nbNodes );
9391
9392       for(int i = 0; i < nbNodes; i++)
9393       {
9394         const SMDS_MeshNode* n = elem->GetNode(i);
9395
9396         if( elem->IsMediumNode( n ) )
9397           mediumNodes.push_back( n );
9398         else
9399           nodes.push_back( n );
9400       }
9401       if( nodes.empty() ) continue;
9402       SMDSAbs_ElementType aType = elem->GetType();
9403
9404       //remove old quadratic element
9405       meshDS->RemoveFreeElement( elem, theSm, notFromGroups );
9406
9407       SMDS_MeshElement * NewElem = AddElement( nodes, aType, false, id );
9408       ReplaceElemInGroups(elem, NewElem, meshDS);
9409       if( theSm && NewElem )
9410         theSm->AddElement( NewElem );
9411
9412       // remove medium nodes
9413       vector<const SMDS_MeshNode*>::iterator nIt = mediumNodes.begin();
9414       for ( ; nIt != mediumNodes.end(); ++nIt ) {
9415         const SMDS_MeshNode* n = *nIt;
9416         if ( n->NbInverseElements() == 0 ) {
9417           if ( n->getshapeId() != theShapeID )
9418             meshDS->RemoveFreeNode( n, meshDS->MeshElements
9419                                     ( n->getshapeId() ));
9420           else
9421             meshDS->RemoveFreeNode( n, theSm );
9422         }
9423       }
9424     }
9425   }
9426   return nbElem;
9427 }
9428
9429 //=======================================================================
9430 //function : ConvertFromQuadratic
9431 //purpose  :
9432 //=======================================================================
9433 bool  SMESH_MeshEditor::ConvertFromQuadratic()
9434 {
9435   int nbCheckedElems = 0;
9436   if ( myMesh->HasShapeToMesh() )
9437   {
9438     if ( SMESH_subMesh *aSubMesh = myMesh->GetSubMeshContaining(myMesh->GetShapeToMesh()))
9439     {
9440       SMESH_subMeshIteratorPtr smIt = aSubMesh->getDependsOnIterator(true,false);
9441       while ( smIt->more() ) {
9442         SMESH_subMesh* sm = smIt->next();
9443         if ( SMESHDS_SubMesh *smDS = sm->GetSubMeshDS() )
9444           nbCheckedElems += removeQuadElem( smDS, smDS->GetElements(), sm->GetId() );
9445       }
9446     }
9447   }
9448
9449   int totalNbElems =
9450     GetMeshDS()->NbEdges() + GetMeshDS()->NbFaces() + GetMeshDS()->NbVolumes();
9451   if ( nbCheckedElems < totalNbElems ) // not all elements are in submeshes
9452   {
9453     SMESHDS_SubMesh *aSM = 0;
9454     removeQuadElem( aSM, GetMeshDS()->elementsIterator(), 0 );
9455   }
9456
9457   return true;
9458 }
9459
9460 //=======================================================================
9461 //function : SewSideElements
9462 //purpose  :
9463 //=======================================================================
9464
9465 SMESH_MeshEditor::Sew_Error
9466 SMESH_MeshEditor::SewSideElements (TIDSortedElemSet&    theSide1,
9467                                    TIDSortedElemSet&    theSide2,
9468                                    const SMDS_MeshNode* theFirstNode1,
9469                                    const SMDS_MeshNode* theFirstNode2,
9470                                    const SMDS_MeshNode* theSecondNode1,
9471                                    const SMDS_MeshNode* theSecondNode2)
9472 {
9473   myLastCreatedElems.Clear();
9474   myLastCreatedNodes.Clear();
9475
9476   MESSAGE ("::::SewSideElements()");
9477   if ( theSide1.size() != theSide2.size() )
9478     return SEW_DIFF_NB_OF_ELEMENTS;
9479
9480   Sew_Error aResult = SEW_OK;
9481   // Algo:
9482   // 1. Build set of faces representing each side
9483   // 2. Find which nodes of the side 1 to merge with ones on the side 2
9484   // 3. Replace nodes in elements of the side 1 and remove replaced nodes
9485
9486   // =======================================================================
9487   // 1. Build set of faces representing each side:
9488   // =======================================================================
9489   // a. build set of nodes belonging to faces
9490   // b. complete set of faces: find missing faces whose nodes are in set of nodes
9491   // c. create temporary faces representing side of volumes if correspondent
9492   //    face does not exist
9493
9494   SMESHDS_Mesh* aMesh = GetMeshDS();
9495   // TODO algoritm not OK with vtkUnstructuredGrid: 2 meshes can't share nodes
9496   //SMDS_Mesh aTmpFacesMesh; // try to use the same mesh
9497   set<const SMDS_MeshElement*> faceSet1, faceSet2;
9498   set<const SMDS_MeshElement*> volSet1,  volSet2;
9499   set<const SMDS_MeshNode*>    nodeSet1, nodeSet2;
9500   set<const SMDS_MeshElement*> * faceSetPtr[] = { &faceSet1, &faceSet2 };
9501   set<const SMDS_MeshElement*>  * volSetPtr[] = { &volSet1,  &volSet2  };
9502   set<const SMDS_MeshNode*>    * nodeSetPtr[] = { &nodeSet1, &nodeSet2 };
9503   TIDSortedElemSet * elemSetPtr[] = { &theSide1, &theSide2 };
9504   int iSide, iFace, iNode;
9505
9506   list<const SMDS_MeshElement* > tempFaceList;
9507   for ( iSide = 0; iSide < 2; iSide++ ) {
9508     set<const SMDS_MeshNode*>    * nodeSet = nodeSetPtr[ iSide ];
9509     TIDSortedElemSet * elemSet = elemSetPtr[ iSide ];
9510     set<const SMDS_MeshElement*> * faceSet = faceSetPtr[ iSide ];
9511     set<const SMDS_MeshElement*> * volSet  = volSetPtr [ iSide ];
9512     set<const SMDS_MeshElement*>::iterator vIt;
9513     TIDSortedElemSet::iterator eIt;
9514     set<const SMDS_MeshNode*>::iterator    nIt;
9515
9516     // check that given nodes belong to given elements
9517     const SMDS_MeshNode* n1 = ( iSide == 0 ) ? theFirstNode1 : theFirstNode2;
9518     const SMDS_MeshNode* n2 = ( iSide == 0 ) ? theSecondNode1 : theSecondNode2;
9519     int firstIndex = -1, secondIndex = -1;
9520     for (eIt = elemSet->begin(); eIt != elemSet->end(); eIt++ ) {
9521       const SMDS_MeshElement* elem = *eIt;
9522       if ( firstIndex  < 0 ) firstIndex  = elem->GetNodeIndex( n1 );
9523       if ( secondIndex < 0 ) secondIndex = elem->GetNodeIndex( n2 );
9524       if ( firstIndex > -1 && secondIndex > -1 ) break;
9525     }
9526     if ( firstIndex < 0 || secondIndex < 0 ) {
9527       // we can simply return until temporary faces created
9528       return (iSide == 0 ) ? SEW_BAD_SIDE1_NODES : SEW_BAD_SIDE2_NODES;
9529     }
9530
9531     // -----------------------------------------------------------
9532     // 1a. Collect nodes of existing faces
9533     //     and build set of face nodes in order to detect missing
9534     //     faces corresponding to sides of volumes
9535     // -----------------------------------------------------------
9536
9537     set< set <const SMDS_MeshNode*> > setOfFaceNodeSet;
9538
9539     // loop on the given element of a side
9540     for (eIt = elemSet->begin(); eIt != elemSet->end(); eIt++ ) {
9541       //const SMDS_MeshElement* elem = *eIt;
9542       const SMDS_MeshElement* elem = *eIt;
9543       if ( elem->GetType() == SMDSAbs_Face ) {
9544         faceSet->insert( elem );
9545         set <const SMDS_MeshNode*> faceNodeSet;
9546         SMDS_ElemIteratorPtr nodeIt = elem->nodesIterator();
9547         while ( nodeIt->more() ) {
9548           const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
9549           nodeSet->insert( n );
9550           faceNodeSet.insert( n );
9551         }
9552         setOfFaceNodeSet.insert( faceNodeSet );
9553       }
9554       else if ( elem->GetType() == SMDSAbs_Volume )
9555         volSet->insert( elem );
9556     }
9557     // ------------------------------------------------------------------------------
9558     // 1b. Complete set of faces: find missing faces whose nodes are in set of nodes
9559     // ------------------------------------------------------------------------------
9560
9561     for ( nIt = nodeSet->begin(); nIt != nodeSet->end(); nIt++ ) { // loop on nodes of iSide
9562       SMDS_ElemIteratorPtr fIt = (*nIt)->GetInverseElementIterator(SMDSAbs_Face);
9563       while ( fIt->more() ) { // loop on faces sharing a node
9564         const SMDS_MeshElement* f = fIt->next();
9565         if ( faceSet->find( f ) == faceSet->end() ) {
9566           // check if all nodes are in nodeSet and
9567           // complete setOfFaceNodeSet if they are
9568           set <const SMDS_MeshNode*> faceNodeSet;
9569           SMDS_ElemIteratorPtr nodeIt = f->nodesIterator();
9570           bool allInSet = true;
9571           while ( nodeIt->more() && allInSet ) { // loop on nodes of a face
9572             const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
9573             if ( nodeSet->find( n ) == nodeSet->end() )
9574               allInSet = false;
9575             else
9576               faceNodeSet.insert( n );
9577           }
9578           if ( allInSet ) {
9579             faceSet->insert( f );
9580             setOfFaceNodeSet.insert( faceNodeSet );
9581           }
9582         }
9583       }
9584     }
9585
9586     // -------------------------------------------------------------------------
9587     // 1c. Create temporary faces representing sides of volumes if correspondent
9588     //     face does not exist
9589     // -------------------------------------------------------------------------
9590
9591     if ( !volSet->empty() ) {
9592       //int nodeSetSize = nodeSet->size();
9593
9594       // loop on given volumes
9595       for ( vIt = volSet->begin(); vIt != volSet->end(); vIt++ ) {
9596         SMDS_VolumeTool vol (*vIt);
9597         // loop on volume faces: find free faces
9598         // --------------------------------------
9599         list<const SMDS_MeshElement* > freeFaceList;
9600         for ( iFace = 0; iFace < vol.NbFaces(); iFace++ ) {
9601           if ( !vol.IsFreeFace( iFace ))
9602             continue;
9603           // check if there is already a face with same nodes in a face set
9604           const SMDS_MeshElement* aFreeFace = 0;
9605           const SMDS_MeshNode** fNodes = vol.GetFaceNodes( iFace );
9606           int nbNodes = vol.NbFaceNodes( iFace );
9607           set <const SMDS_MeshNode*> faceNodeSet;
9608           vol.GetFaceNodes( iFace, faceNodeSet );
9609           bool isNewFace = setOfFaceNodeSet.insert( faceNodeSet ).second;
9610           if ( isNewFace ) {
9611             // no such a face is given but it still can exist, check it
9612             if ( nbNodes == 3 ) {
9613               aFreeFace = aMesh->FindFace( fNodes[0],fNodes[1],fNodes[2] );
9614             }
9615             else if ( nbNodes == 4 ) {
9616               aFreeFace = aMesh->FindFace( fNodes[0],fNodes[1],fNodes[2],fNodes[3] );
9617             }
9618             else {
9619               vector<const SMDS_MeshNode *> poly_nodes ( fNodes, & fNodes[nbNodes]);
9620               aFreeFace = aMesh->FindFace(poly_nodes);
9621             }
9622           }
9623           if ( !aFreeFace ) {
9624             // create a temporary face
9625             if ( nbNodes == 3 ) {
9626               //aFreeFace = aTmpFacesMesh.AddFace( fNodes[0],fNodes[1],fNodes[2] );
9627               aFreeFace = aMesh->AddFace( fNodes[0],fNodes[1],fNodes[2] );
9628             }
9629             else if ( nbNodes == 4 ) {
9630               //aFreeFace = aTmpFacesMesh.AddFace( fNodes[0],fNodes[1],fNodes[2],fNodes[3] );
9631               aFreeFace = aMesh->AddFace( fNodes[0],fNodes[1],fNodes[2],fNodes[3] );
9632             }
9633             else {
9634               vector<const SMDS_MeshNode *> poly_nodes ( fNodes, & fNodes[nbNodes]);
9635               //aFreeFace = aTmpFacesMesh.AddPolygonalFace(poly_nodes);
9636               aFreeFace = aMesh->AddPolygonalFace(poly_nodes);
9637             }
9638           }
9639           if ( aFreeFace ) {
9640             freeFaceList.push_back( aFreeFace );
9641             tempFaceList.push_back( aFreeFace );
9642           }
9643
9644         } // loop on faces of a volume
9645
9646         // choose one of several free faces
9647         // --------------------------------------
9648         if ( freeFaceList.size() > 1 ) {
9649           // choose a face having max nb of nodes shared by other elems of a side
9650           int maxNbNodes = -1/*, nbExcludedFaces = 0*/;
9651           list<const SMDS_MeshElement* >::iterator fIt = freeFaceList.begin();
9652           while ( fIt != freeFaceList.end() ) { // loop on free faces
9653             int nbSharedNodes = 0;
9654             SMDS_ElemIteratorPtr nodeIt = (*fIt)->nodesIterator();
9655             while ( nodeIt->more() ) { // loop on free face nodes
9656               const SMDS_MeshNode* n =
9657                 static_cast<const SMDS_MeshNode*>( nodeIt->next() );
9658               SMDS_ElemIteratorPtr invElemIt = n->GetInverseElementIterator();
9659               while ( invElemIt->more() ) {
9660                 const SMDS_MeshElement* e = invElemIt->next();
9661                 if ( faceSet->find( e ) != faceSet->end() )
9662                   nbSharedNodes++;
9663                 if ( elemSet->find( e ) != elemSet->end() )
9664                   nbSharedNodes++;
9665               }
9666             }
9667             if ( nbSharedNodes >= maxNbNodes ) {
9668               maxNbNodes = nbSharedNodes;
9669               fIt++;
9670             }
9671             else
9672               freeFaceList.erase( fIt++ ); // here fIt++ occurs before erase
9673           }
9674           if ( freeFaceList.size() > 1 )
9675           {
9676             // could not choose one face, use another way
9677             // choose a face most close to the bary center of the opposite side
9678             gp_XYZ aBC( 0., 0., 0. );
9679             set <const SMDS_MeshNode*> addedNodes;
9680             TIDSortedElemSet * elemSet2 = elemSetPtr[ 1 - iSide ];
9681             eIt = elemSet2->begin();
9682             for ( eIt = elemSet2->begin(); eIt != elemSet2->end(); eIt++ ) {
9683               SMDS_ElemIteratorPtr nodeIt = (*eIt)->nodesIterator();
9684               while ( nodeIt->more() ) { // loop on free face nodes
9685                 const SMDS_MeshNode* n =
9686                   static_cast<const SMDS_MeshNode*>( nodeIt->next() );
9687                 if ( addedNodes.insert( n ).second )
9688                   aBC += gp_XYZ( n->X(),n->Y(),n->Z() );
9689               }
9690             }
9691             aBC /= addedNodes.size();
9692             double minDist = DBL_MAX;
9693             fIt = freeFaceList.begin();
9694             while ( fIt != freeFaceList.end() ) { // loop on free faces
9695               double dist = 0;
9696               SMDS_ElemIteratorPtr nodeIt = (*fIt)->nodesIterator();
9697               while ( nodeIt->more() ) { // loop on free face nodes
9698                 const SMDS_MeshNode* n =
9699                   static_cast<const SMDS_MeshNode*>( nodeIt->next() );
9700                 gp_XYZ p( n->X(),n->Y(),n->Z() );
9701                 dist += ( aBC - p ).SquareModulus();
9702               }
9703               if ( dist < minDist ) {
9704                 minDist = dist;
9705                 freeFaceList.erase( freeFaceList.begin(), fIt++ );
9706               }
9707               else
9708                 fIt = freeFaceList.erase( fIt++ );
9709             }
9710           }
9711         } // choose one of several free faces of a volume
9712
9713         if ( freeFaceList.size() == 1 ) {
9714           const SMDS_MeshElement* aFreeFace = freeFaceList.front();
9715           faceSet->insert( aFreeFace );
9716           // complete a node set with nodes of a found free face
9717           //           for ( iNode = 0; iNode < ; iNode++ )
9718           //             nodeSet->insert( fNodes[ iNode ] );
9719         }
9720
9721       } // loop on volumes of a side
9722
9723       //       // complete a set of faces if new nodes in a nodeSet appeared
9724       //       // ----------------------------------------------------------
9725       //       if ( nodeSetSize != nodeSet->size() ) {
9726       //         for ( ; nIt != nodeSet->end(); nIt++ ) { // loop on nodes of iSide
9727       //           SMDS_ElemIteratorPtr fIt = (*nIt)->GetInverseElementIterator(SMDSAbs_Face);
9728       //           while ( fIt->more() ) { // loop on faces sharing a node
9729       //             const SMDS_MeshElement* f = fIt->next();
9730       //             if ( faceSet->find( f ) == faceSet->end() ) {
9731       //               // check if all nodes are in nodeSet and
9732       //               // complete setOfFaceNodeSet if they are
9733       //               set <const SMDS_MeshNode*> faceNodeSet;
9734       //               SMDS_ElemIteratorPtr nodeIt = f->nodesIterator();
9735       //               bool allInSet = true;
9736       //               while ( nodeIt->more() && allInSet ) { // loop on nodes of a face
9737       //                 const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
9738       //                 if ( nodeSet->find( n ) == nodeSet->end() )
9739       //                   allInSet = false;
9740       //                 else
9741       //                   faceNodeSet.insert( n );
9742       //               }
9743       //               if ( allInSet ) {
9744       //                 faceSet->insert( f );
9745       //                 setOfFaceNodeSet.insert( faceNodeSet );
9746       //               }
9747       //             }
9748       //           }
9749       //         }
9750       //       }
9751     } // Create temporary faces, if there are volumes given
9752   } // loop on sides
9753
9754   if ( faceSet1.size() != faceSet2.size() ) {
9755     // delete temporary faces: they are in reverseElements of actual nodes
9756 //    SMDS_FaceIteratorPtr tmpFaceIt = aTmpFacesMesh.facesIterator();
9757 //    while ( tmpFaceIt->more() )
9758 //      aTmpFacesMesh.RemoveElement( tmpFaceIt->next() );
9759 //    list<const SMDS_MeshElement* >::iterator tmpFaceIt = tempFaceList.begin();
9760 //    for (; tmpFaceIt !=tempFaceList.end(); ++tmpFaceIt)
9761 //      aMesh->RemoveElement(*tmpFaceIt);
9762     MESSAGE("Diff nb of faces");
9763     return SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
9764   }
9765
9766   // ============================================================
9767   // 2. Find nodes to merge:
9768   //              bind a node to remove to a node to put instead
9769   // ============================================================
9770
9771   TNodeNodeMap nReplaceMap; // bind a node to remove to a node to put instead
9772   if ( theFirstNode1 != theFirstNode2 )
9773     nReplaceMap.insert( TNodeNodeMap::value_type( theFirstNode1, theFirstNode2 ));
9774   if ( theSecondNode1 != theSecondNode2 )
9775     nReplaceMap.insert( TNodeNodeMap::value_type( theSecondNode1, theSecondNode2 ));
9776
9777   LinkID_Gen aLinkID_Gen( GetMeshDS() );
9778   set< long > linkIdSet; // links to process
9779   linkIdSet.insert( aLinkID_Gen.GetLinkID( theFirstNode1, theSecondNode1 ));
9780
9781   typedef pair< const SMDS_MeshNode*, const SMDS_MeshNode* > NLink;
9782   list< NLink > linkList[2];
9783   linkList[0].push_back( NLink( theFirstNode1, theSecondNode1 ));
9784   linkList[1].push_back( NLink( theFirstNode2, theSecondNode2 ));
9785   // loop on links in linkList; find faces by links and append links
9786   // of the found faces to linkList
9787   list< NLink >::iterator linkIt[] = { linkList[0].begin(), linkList[1].begin() } ;
9788   for ( ; linkIt[0] != linkList[0].end(); linkIt[0]++, linkIt[1]++ ) {
9789     NLink link[] = { *linkIt[0], *linkIt[1] };
9790     long linkID = aLinkID_Gen.GetLinkID( link[0].first, link[0].second );
9791     if ( linkIdSet.find( linkID ) == linkIdSet.end() )
9792       continue;
9793
9794     // by links, find faces in the face sets,
9795     // and find indices of link nodes in the found faces;
9796     // in a face set, there is only one or no face sharing a link
9797     // ---------------------------------------------------------------
9798
9799     const SMDS_MeshElement* face[] = { 0, 0 };
9800     //const SMDS_MeshNode* faceNodes[ 2 ][ 5 ];
9801     vector<const SMDS_MeshNode*> fnodes1(9);
9802     vector<const SMDS_MeshNode*> fnodes2(9);
9803     //const SMDS_MeshNode* notLinkNodes[ 2 ][ 2 ] = {{ 0, 0 },{ 0, 0 }} ;
9804     vector<const SMDS_MeshNode*> notLinkNodes1(6);
9805     vector<const SMDS_MeshNode*> notLinkNodes2(6);
9806     int iLinkNode[2][2];
9807     for ( iSide = 0; iSide < 2; iSide++ ) { // loop on 2 sides
9808       const SMDS_MeshNode* n1 = link[iSide].first;
9809       const SMDS_MeshNode* n2 = link[iSide].second;
9810       set<const SMDS_MeshElement*> * faceSet = faceSetPtr[ iSide ];
9811       set< const SMDS_MeshElement* > fMap;
9812       for ( int i = 0; i < 2; i++ ) { // loop on 2 nodes of a link
9813         const SMDS_MeshNode* n = i ? n1 : n2; // a node of a link
9814         SMDS_ElemIteratorPtr fIt = n->GetInverseElementIterator(SMDSAbs_Face);
9815         while ( fIt->more() ) { // loop on faces sharing a node
9816           const SMDS_MeshElement* f = fIt->next();
9817           if (faceSet->find( f ) != faceSet->end() && // f is in face set
9818               ! fMap.insert( f ).second ) // f encounters twice
9819           {
9820             if ( face[ iSide ] ) {
9821               MESSAGE( "2 faces per link " );
9822               aResult = iSide ? SEW_BAD_SIDE2_NODES : SEW_BAD_SIDE1_NODES;
9823               break;
9824             }
9825             face[ iSide ] = f;
9826             faceSet->erase( f );
9827             // get face nodes and find ones of a link
9828             iNode = 0;
9829             int nbl = -1;
9830             if(f->IsPoly()) {
9831               if(iSide==0) {
9832                 fnodes1.resize(f->NbNodes()+1);
9833                 notLinkNodes1.resize(f->NbNodes()-2);
9834               }
9835               else {
9836                 fnodes2.resize(f->NbNodes()+1);
9837                 notLinkNodes2.resize(f->NbNodes()-2);
9838               }
9839             }
9840             if(!f->IsQuadratic()) {
9841               SMDS_ElemIteratorPtr nIt = f->nodesIterator();
9842               while ( nIt->more() ) {
9843                 const SMDS_MeshNode* n =
9844                   static_cast<const SMDS_MeshNode*>( nIt->next() );
9845                 if ( n == n1 ) {
9846                   iLinkNode[ iSide ][ 0 ] = iNode;
9847                 }
9848                 else if ( n == n2 ) {
9849                   iLinkNode[ iSide ][ 1 ] = iNode;
9850                 }
9851                 //else if ( notLinkNodes[ iSide ][ 0 ] )
9852                 //  notLinkNodes[ iSide ][ 1 ] = n;
9853                 //else
9854                 //  notLinkNodes[ iSide ][ 0 ] = n;
9855                 else {
9856                   nbl++;
9857                   if(iSide==0)
9858                     notLinkNodes1[nbl] = n;
9859                   //notLinkNodes1.push_back(n);
9860                   else
9861                     notLinkNodes2[nbl] = n;
9862                   //notLinkNodes2.push_back(n);
9863                 }
9864                 //faceNodes[ iSide ][ iNode++ ] = n;
9865                 if(iSide==0) {
9866                   fnodes1[iNode++] = n;
9867                 }
9868                 else {
9869                   fnodes2[iNode++] = n;
9870                 }
9871               }
9872             }
9873             else { // f->IsQuadratic()
9874               const SMDS_VtkFace* F =
9875                 dynamic_cast<const SMDS_VtkFace*>(f);
9876               if (!F) throw SALOME_Exception(LOCALIZED("not an SMDS_VtkFace"));
9877               // use special nodes iterator
9878               SMDS_ElemIteratorPtr anIter = F->interlacedNodesElemIterator();
9879               while ( anIter->more() ) {
9880                 const SMDS_MeshNode* n =
9881                   static_cast<const SMDS_MeshNode*>( anIter->next() );
9882                 if ( n == n1 ) {
9883                   iLinkNode[ iSide ][ 0 ] = iNode;
9884                 }
9885                 else if ( n == n2 ) {
9886                   iLinkNode[ iSide ][ 1 ] = iNode;
9887                 }
9888                 else {
9889                   nbl++;
9890                   if(iSide==0) {
9891                     notLinkNodes1[nbl] = n;
9892                   }
9893                   else {
9894                     notLinkNodes2[nbl] = n;
9895                   }
9896                 }
9897                 if(iSide==0) {
9898                   fnodes1[iNode++] = n;
9899                 }
9900                 else {
9901                   fnodes2[iNode++] = n;
9902                 }
9903               }
9904             }
9905             //faceNodes[ iSide ][ iNode ] = faceNodes[ iSide ][ 0 ];
9906             if(iSide==0) {
9907               fnodes1[iNode] = fnodes1[0];
9908             }
9909             else {
9910               fnodes2[iNode] = fnodes1[0];
9911             }
9912           }
9913         }
9914       }
9915     }
9916
9917     // check similarity of elements of the sides
9918     if (aResult == SEW_OK && ( face[0] && !face[1] ) || ( !face[0] && face[1] )) {
9919       MESSAGE("Correspondent face not found on side " << ( face[0] ? 1 : 0 ));
9920       if ( nReplaceMap.size() == 2 ) { // faces on input nodes not found
9921         aResult = ( face[0] ? SEW_BAD_SIDE2_NODES : SEW_BAD_SIDE1_NODES );
9922       }
9923       else {
9924         aResult = SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
9925       }
9926       break; // do not return because it s necessary to remove tmp faces
9927     }
9928
9929     // set nodes to merge
9930     // -------------------
9931
9932     if ( face[0] && face[1] )  {
9933       int nbNodes = face[0]->NbNodes();
9934       if ( nbNodes != face[1]->NbNodes() ) {
9935         MESSAGE("Diff nb of face nodes");
9936         aResult = SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
9937         break; // do not return because it s necessary to remove tmp faces
9938       }
9939       bool reverse[] = { false, false }; // order of notLinkNodes of quadrangle
9940       if ( nbNodes == 3 ) {
9941         //nReplaceMap.insert( TNodeNodeMap::value_type
9942         //                   ( notLinkNodes[0][0], notLinkNodes[1][0] ));
9943         nReplaceMap.insert( TNodeNodeMap::value_type
9944                             ( notLinkNodes1[0], notLinkNodes2[0] ));
9945       }
9946       else {
9947         for ( iSide = 0; iSide < 2; iSide++ ) { // loop on 2 sides
9948           // analyse link orientation in faces
9949           int i1 = iLinkNode[ iSide ][ 0 ];
9950           int i2 = iLinkNode[ iSide ][ 1 ];
9951           reverse[ iSide ] = Abs( i1 - i2 ) == 1 ? i1 > i2 : i2 > i1;
9952           // if notLinkNodes are the first and the last ones, then
9953           // their order does not correspond to the link orientation
9954           if (( i1 == 1 && i2 == 2 ) ||
9955               ( i1 == 2 && i2 == 1 ))
9956             reverse[ iSide ] = !reverse[ iSide ];
9957         }
9958         if ( reverse[0] == reverse[1] ) {
9959           //nReplaceMap.insert( TNodeNodeMap::value_type
9960           //                   ( notLinkNodes[0][0], notLinkNodes[1][0] ));
9961           //nReplaceMap.insert( TNodeNodeMap::value_type
9962           //                   ( notLinkNodes[0][1], notLinkNodes[1][1] ));
9963           for(int nn=0; nn<nbNodes-2; nn++) {
9964             nReplaceMap.insert( TNodeNodeMap::value_type
9965                                 ( notLinkNodes1[nn], notLinkNodes2[nn] ));
9966           }
9967         }
9968         else {
9969           //nReplaceMap.insert( TNodeNodeMap::value_type
9970           //                   ( notLinkNodes[0][0], notLinkNodes[1][1] ));
9971           //nReplaceMap.insert( TNodeNodeMap::value_type
9972           //                   ( notLinkNodes[0][1], notLinkNodes[1][0] ));
9973           for(int nn=0; nn<nbNodes-2; nn++) {
9974             nReplaceMap.insert( TNodeNodeMap::value_type
9975                                 ( notLinkNodes1[nn], notLinkNodes2[nbNodes-3-nn] ));
9976           }
9977         }
9978       }
9979
9980       // add other links of the faces to linkList
9981       // -----------------------------------------
9982
9983       //const SMDS_MeshNode** nodes = faceNodes[ 0 ];
9984       for ( iNode = 0; iNode < nbNodes; iNode++ )  {
9985         //linkID = aLinkID_Gen.GetLinkID( nodes[iNode], nodes[iNode+1] );
9986         linkID = aLinkID_Gen.GetLinkID( fnodes1[iNode], fnodes1[iNode+1] );
9987         pair< set<long>::iterator, bool > iter_isnew = linkIdSet.insert( linkID );
9988         if ( !iter_isnew.second ) { // already in a set: no need to process
9989           linkIdSet.erase( iter_isnew.first );
9990         }
9991         else // new in set == encountered for the first time: add
9992         {
9993           //const SMDS_MeshNode* n1 = nodes[ iNode ];
9994           //const SMDS_MeshNode* n2 = nodes[ iNode + 1];
9995           const SMDS_MeshNode* n1 = fnodes1[ iNode ];
9996           const SMDS_MeshNode* n2 = fnodes1[ iNode + 1];
9997           linkList[0].push_back ( NLink( n1, n2 ));
9998           linkList[1].push_back ( NLink( nReplaceMap[n1], nReplaceMap[n2] ));
9999         }
10000       }
10001     } // 2 faces found
10002   } // loop on link lists
10003
10004   if ( aResult == SEW_OK &&
10005        ( linkIt[0] != linkList[0].end() ||
10006          !faceSetPtr[0]->empty() || !faceSetPtr[1]->empty() )) {
10007     MESSAGE( (linkIt[0] != linkList[0].end()) <<" "<< (faceSetPtr[0]->empty()) <<
10008              " " << (faceSetPtr[1]->empty()));
10009     aResult = SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
10010   }
10011
10012   // ====================================================================
10013   // 3. Replace nodes in elements of the side 1 and remove replaced nodes
10014   // ====================================================================
10015
10016   // delete temporary faces: they are in reverseElements of actual nodes
10017 //  SMDS_FaceIteratorPtr tmpFaceIt = aTmpFacesMesh.facesIterator();
10018 //  while ( tmpFaceIt->more() )
10019 //    aTmpFacesMesh.RemoveElement( tmpFaceIt->next() );
10020 //  list<const SMDS_MeshElement* >::iterator tmpFaceIt = tempFaceList.begin();
10021 //  for (; tmpFaceIt !=tempFaceList.end(); ++tmpFaceIt)
10022 //    aMesh->RemoveElement(*tmpFaceIt);
10023
10024   if ( aResult != SEW_OK)
10025     return aResult;
10026
10027   list< int > nodeIDsToRemove/*, elemIDsToRemove*/;
10028   // loop on nodes replacement map
10029   TNodeNodeMap::iterator nReplaceMapIt = nReplaceMap.begin(), nnIt;
10030   for ( ; nReplaceMapIt != nReplaceMap.end(); nReplaceMapIt++ )
10031     if ( (*nReplaceMapIt).first != (*nReplaceMapIt).second ) {
10032       const SMDS_MeshNode* nToRemove = (*nReplaceMapIt).first;
10033       nodeIDsToRemove.push_back( nToRemove->GetID() );
10034       // loop on elements sharing nToRemove
10035       SMDS_ElemIteratorPtr invElemIt = nToRemove->GetInverseElementIterator();
10036       while ( invElemIt->more() ) {
10037         const SMDS_MeshElement* e = invElemIt->next();
10038         // get a new suite of nodes: make replacement
10039         int nbReplaced = 0, i = 0, nbNodes = e->NbNodes();
10040         vector< const SMDS_MeshNode*> nodes( nbNodes );
10041         SMDS_ElemIteratorPtr nIt = e->nodesIterator();
10042         while ( nIt->more() ) {
10043           const SMDS_MeshNode* n =
10044             static_cast<const SMDS_MeshNode*>( nIt->next() );
10045           nnIt = nReplaceMap.find( n );
10046           if ( nnIt != nReplaceMap.end() ) {
10047             nbReplaced++;
10048             n = (*nnIt).second;
10049           }
10050           nodes[ i++ ] = n;
10051         }
10052         //       if ( nbReplaced == nbNodes && e->GetType() == SMDSAbs_Face )
10053         //         elemIDsToRemove.push_back( e->GetID() );
10054         //       else
10055         if ( nbReplaced )
10056           {
10057             SMDSAbs_ElementType etyp = e->GetType();
10058             SMDS_MeshElement* newElem = this->AddElement(nodes, etyp, false);
10059             if (newElem)
10060               {
10061                 myLastCreatedElems.Append(newElem);
10062                 AddToSameGroups(newElem, e, aMesh);
10063                 int aShapeId = e->getshapeId();
10064                 if ( aShapeId )
10065                   {
10066                     aMesh->SetMeshElementOnShape( newElem, aShapeId );
10067                   }
10068               }
10069             aMesh->RemoveElement(e);
10070           }
10071       }
10072     }
10073
10074   Remove( nodeIDsToRemove, true );
10075
10076   return aResult;
10077 }
10078
10079 //================================================================================
10080 /*!
10081  * \brief Find corresponding nodes in two sets of faces
10082  * \param theSide1 - first face set
10083  * \param theSide2 - second first face
10084  * \param theFirstNode1 - a boundary node of set 1
10085  * \param theFirstNode2 - a node of set 2 corresponding to theFirstNode1
10086  * \param theSecondNode1 - a boundary node of set 1 linked with theFirstNode1
10087  * \param theSecondNode2 - a node of set 2 corresponding to theSecondNode1
10088  * \param nReplaceMap - output map of corresponding nodes
10089  * \retval bool  - is a success or not
10090  */
10091 //================================================================================
10092
10093 #ifdef _DEBUG_
10094 //#define DEBUG_MATCHING_NODES
10095 #endif
10096
10097 SMESH_MeshEditor::Sew_Error
10098 SMESH_MeshEditor::FindMatchingNodes(set<const SMDS_MeshElement*>& theSide1,
10099                                     set<const SMDS_MeshElement*>& theSide2,
10100                                     const SMDS_MeshNode*          theFirstNode1,
10101                                     const SMDS_MeshNode*          theFirstNode2,
10102                                     const SMDS_MeshNode*          theSecondNode1,
10103                                     const SMDS_MeshNode*          theSecondNode2,
10104                                     TNodeNodeMap &                nReplaceMap)
10105 {
10106   set<const SMDS_MeshElement*> * faceSetPtr[] = { &theSide1, &theSide2 };
10107
10108   nReplaceMap.clear();
10109   if ( theFirstNode1 != theFirstNode2 )
10110     nReplaceMap.insert( make_pair( theFirstNode1, theFirstNode2 ));
10111   if ( theSecondNode1 != theSecondNode2 )
10112     nReplaceMap.insert( make_pair( theSecondNode1, theSecondNode2 ));
10113
10114   set< SMESH_TLink > linkSet; // set of nodes where order of nodes is ignored
10115   linkSet.insert( SMESH_TLink( theFirstNode1, theSecondNode1 ));
10116
10117   list< NLink > linkList[2];
10118   linkList[0].push_back( NLink( theFirstNode1, theSecondNode1 ));
10119   linkList[1].push_back( NLink( theFirstNode2, theSecondNode2 ));
10120
10121   // loop on links in linkList; find faces by links and append links
10122   // of the found faces to linkList
10123   list< NLink >::iterator linkIt[] = { linkList[0].begin(), linkList[1].begin() } ;
10124   for ( ; linkIt[0] != linkList[0].end(); linkIt[0]++, linkIt[1]++ ) {
10125     NLink link[] = { *linkIt[0], *linkIt[1] };
10126     if ( linkSet.find( link[0] ) == linkSet.end() )
10127       continue;
10128
10129     // by links, find faces in the face sets,
10130     // and find indices of link nodes in the found faces;
10131     // in a face set, there is only one or no face sharing a link
10132     // ---------------------------------------------------------------
10133
10134     const SMDS_MeshElement* face[] = { 0, 0 };
10135     list<const SMDS_MeshNode*> notLinkNodes[2];
10136     //bool reverse[] = { false, false }; // order of notLinkNodes
10137     int nbNodes[2];
10138     for ( int iSide = 0; iSide < 2; iSide++ ) // loop on 2 sides
10139     {
10140       const SMDS_MeshNode* n1 = link[iSide].first;
10141       const SMDS_MeshNode* n2 = link[iSide].second;
10142       set<const SMDS_MeshElement*> * faceSet = faceSetPtr[ iSide ];
10143       set< const SMDS_MeshElement* > facesOfNode1;
10144       for ( int iNode = 0; iNode < 2; iNode++ ) // loop on 2 nodes of a link
10145       {
10146         // during a loop of the first node, we find all faces around n1,
10147         // during a loop of the second node, we find one face sharing both n1 and n2
10148         const SMDS_MeshNode* n = iNode ? n1 : n2; // a node of a link
10149         SMDS_ElemIteratorPtr fIt = n->GetInverseElementIterator(SMDSAbs_Face);
10150         while ( fIt->more() ) { // loop on faces sharing a node
10151           const SMDS_MeshElement* f = fIt->next();
10152           if (faceSet->find( f ) != faceSet->end() && // f is in face set
10153               ! facesOfNode1.insert( f ).second ) // f encounters twice
10154           {
10155             if ( face[ iSide ] ) {
10156               MESSAGE( "2 faces per link " );
10157               return ( iSide ? SEW_BAD_SIDE2_NODES : SEW_BAD_SIDE1_NODES );
10158             }
10159             face[ iSide ] = f;
10160             faceSet->erase( f );
10161
10162             // get not link nodes
10163             int nbN = f->NbNodes();
10164             if ( f->IsQuadratic() )
10165               nbN /= 2;
10166             nbNodes[ iSide ] = nbN;
10167             list< const SMDS_MeshNode* > & nodes = notLinkNodes[ iSide ];
10168             int i1 = f->GetNodeIndex( n1 );
10169             int i2 = f->GetNodeIndex( n2 );
10170             int iEnd = nbN, iBeg = -1, iDelta = 1;
10171             bool reverse = ( Abs( i1 - i2 ) == 1 ? i1 > i2 : i2 > i1 );
10172             if ( reverse ) {
10173               std::swap( iEnd, iBeg ); iDelta = -1;
10174             }
10175             int i = i2;
10176             while ( true ) {
10177               i += iDelta;
10178               if ( i == iEnd ) i = iBeg + iDelta;
10179               if ( i == i1 ) break;
10180               nodes.push_back ( f->GetNode( i ) );
10181             }
10182           }
10183         }
10184       }
10185     }
10186     // check similarity of elements of the sides
10187     if (( face[0] && !face[1] ) || ( !face[0] && face[1] )) {
10188       MESSAGE("Correspondent face not found on side " << ( face[0] ? 1 : 0 ));
10189       if ( nReplaceMap.size() == 2 ) { // faces on input nodes not found
10190         return ( face[0] ? SEW_BAD_SIDE2_NODES : SEW_BAD_SIDE1_NODES );
10191       }
10192       else {
10193         return SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
10194       }
10195     }
10196
10197     // set nodes to merge
10198     // -------------------
10199
10200     if ( face[0] && face[1] )  {
10201       if ( nbNodes[0] != nbNodes[1] ) {
10202         MESSAGE("Diff nb of face nodes");
10203         return SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
10204       }
10205 #ifdef DEBUG_MATCHING_NODES
10206       MESSAGE ( " Link 1: " << link[0].first->GetID() <<" "<< link[0].second->GetID()
10207                 << " F 1: " << face[0] << "| Link 2: " << link[1].first->GetID() <<" "
10208                 << link[1].second->GetID() << " F 2: " << face[1] << " | Bind: " ) ;
10209 #endif
10210       int nbN = nbNodes[0];
10211       {
10212         list<const SMDS_MeshNode*>::iterator n1 = notLinkNodes[0].begin();
10213         list<const SMDS_MeshNode*>::iterator n2 = notLinkNodes[1].begin();
10214         for ( int i = 0 ; i < nbN - 2; ++i ) {
10215 #ifdef DEBUG_MATCHING_NODES
10216           MESSAGE ( (*n1)->GetID() << " to " << (*n2)->GetID() );
10217 #endif
10218           nReplaceMap.insert( make_pair( *(n1++), *(n2++) ));
10219         }
10220       }
10221
10222       // add other links of the face 1 to linkList
10223       // -----------------------------------------
10224
10225       const SMDS_MeshElement* f0 = face[0];
10226       const SMDS_MeshNode* n1 = f0->GetNode( nbN - 1 );
10227       for ( int i = 0; i < nbN; i++ )
10228       {
10229         const SMDS_MeshNode* n2 = f0->GetNode( i );
10230         pair< set< SMESH_TLink >::iterator, bool > iter_isnew =
10231           linkSet.insert( SMESH_TLink( n1, n2 ));
10232         if ( !iter_isnew.second ) { // already in a set: no need to process
10233           linkSet.erase( iter_isnew.first );
10234         }
10235         else // new in set == encountered for the first time: add
10236         {
10237 #ifdef DEBUG_MATCHING_NODES
10238           MESSAGE ( "Add link 1: " << n1->GetID() << " " << n2->GetID() << " "
10239                     << " | link 2: " << nReplaceMap[n1]->GetID() << " " << nReplaceMap[n2]->GetID() << " " );
10240 #endif
10241           linkList[0].push_back ( NLink( n1, n2 ));
10242           linkList[1].push_back ( NLink( nReplaceMap[n1], nReplaceMap[n2] ));
10243         }
10244         n1 = n2;
10245       }
10246     } // 2 faces found
10247   } // loop on link lists
10248
10249   return SEW_OK;
10250 }
10251
10252 //================================================================================
10253 /*!
10254   \brief Creates a hole in a mesh by doubling the nodes of some particular elements
10255   \param theElems - the list of elements (edges or faces) to be replicated
10256   The nodes for duplication could be found from these elements
10257   \param theNodesNot - list of nodes to NOT replicate
10258   \param theAffectedElems - the list of elements (cells and edges) to which the 
10259   replicated nodes should be associated to.
10260   \return TRUE if operation has been completed successfully, FALSE otherwise
10261 */
10262 //================================================================================
10263
10264 bool SMESH_MeshEditor::DoubleNodes( const TIDSortedElemSet& theElems,
10265                                     const TIDSortedElemSet& theNodesNot,
10266                                     const TIDSortedElemSet& theAffectedElems )
10267 {
10268   myLastCreatedElems.Clear();
10269   myLastCreatedNodes.Clear();
10270
10271   if ( theElems.size() == 0 )
10272     return false;
10273
10274   SMESHDS_Mesh* aMeshDS = GetMeshDS();
10275   if ( !aMeshDS )
10276     return false;
10277
10278   bool res = false;
10279   std::map< const SMDS_MeshNode*, const SMDS_MeshNode* > anOldNodeToNewNode;
10280   // duplicate elements and nodes
10281   res = doubleNodes( aMeshDS, theElems, theNodesNot, anOldNodeToNewNode, true );
10282   // replce nodes by duplications
10283   res = doubleNodes( aMeshDS, theAffectedElems, theNodesNot, anOldNodeToNewNode, false );
10284   return res;
10285 }
10286
10287 //================================================================================
10288 /*!
10289   \brief Creates a hole in a mesh by doubling the nodes of some particular elements
10290   \param theMeshDS - mesh instance
10291   \param theElems - the elements replicated or modified (nodes should be changed)
10292   \param theNodesNot - nodes to NOT replicate
10293   \param theNodeNodeMap - relation of old node to new created node
10294   \param theIsDoubleElem - flag os to replicate element or modify
10295   \return TRUE if operation has been completed successfully, FALSE otherwise
10296 */
10297 //================================================================================
10298
10299 bool SMESH_MeshEditor::doubleNodes( SMESHDS_Mesh*     theMeshDS,
10300                                     const TIDSortedElemSet& theElems,
10301                                     const TIDSortedElemSet& theNodesNot,
10302                                     std::map< const SMDS_MeshNode*,
10303                                     const SMDS_MeshNode* >& theNodeNodeMap,
10304                                     const bool theIsDoubleElem )
10305 {
10306   MESSAGE("doubleNodes");
10307   // iterate on through element and duplicate them (by nodes duplication)
10308   bool res = false;
10309   TIDSortedElemSet::const_iterator elemItr = theElems.begin();
10310   for ( ;  elemItr != theElems.end(); ++elemItr )
10311   {
10312     const SMDS_MeshElement* anElem = *elemItr;
10313     if (!anElem)
10314       continue;
10315
10316     bool isDuplicate = false;
10317     // duplicate nodes to duplicate element
10318     std::vector<const SMDS_MeshNode*> newNodes( anElem->NbNodes() );
10319     SMDS_ElemIteratorPtr anIter = anElem->nodesIterator();
10320     int ind = 0;
10321     while ( anIter->more() ) 
10322     { 
10323
10324       SMDS_MeshNode* aCurrNode = (SMDS_MeshNode*)anIter->next();
10325       SMDS_MeshNode* aNewNode = aCurrNode;
10326       if ( theNodeNodeMap.find( aCurrNode ) != theNodeNodeMap.end() )
10327         aNewNode = (SMDS_MeshNode*)theNodeNodeMap[ aCurrNode ];
10328       else if ( theIsDoubleElem && theNodesNot.find( aCurrNode ) == theNodesNot.end() )
10329       {
10330         // duplicate node
10331         aNewNode = theMeshDS->AddNode( aCurrNode->X(), aCurrNode->Y(), aCurrNode->Z() );
10332         theNodeNodeMap[ aCurrNode ] = aNewNode;
10333         myLastCreatedNodes.Append( aNewNode );
10334       }
10335       isDuplicate |= (aCurrNode != aNewNode);
10336       newNodes[ ind++ ] = aNewNode;
10337     }
10338     if ( !isDuplicate )
10339       continue;
10340
10341     if ( theIsDoubleElem )
10342       AddElement(newNodes, anElem->GetType(), anElem->IsPoly());
10343     else
10344       {
10345       MESSAGE("ChangeElementNodes");
10346       theMeshDS->ChangeElementNodes( anElem, &newNodes[ 0 ], anElem->NbNodes() );
10347       }
10348     res = true;
10349   }
10350   return res;
10351 }
10352
10353 //================================================================================
10354 /*!
10355   \brief Creates a hole in a mesh by doubling the nodes of some particular elements
10356   \param theNodes - identifiers of nodes to be doubled
10357   \param theModifiedElems - identifiers of elements to be updated by the new (doubled) 
10358          nodes. If list of element identifiers is empty then nodes are doubled but 
10359          they not assigned to elements
10360   \return TRUE if operation has been completed successfully, FALSE otherwise
10361 */
10362 //================================================================================
10363
10364 bool SMESH_MeshEditor::DoubleNodes( const std::list< int >& theListOfNodes, 
10365                                     const std::list< int >& theListOfModifiedElems )
10366 {
10367   MESSAGE("DoubleNodes");
10368   myLastCreatedElems.Clear();
10369   myLastCreatedNodes.Clear();
10370
10371   if ( theListOfNodes.size() == 0 )
10372     return false;
10373
10374   SMESHDS_Mesh* aMeshDS = GetMeshDS();
10375   if ( !aMeshDS )
10376     return false;
10377
10378   // iterate through nodes and duplicate them
10379
10380   std::map< const SMDS_MeshNode*, const SMDS_MeshNode* > anOldNodeToNewNode;
10381
10382   std::list< int >::const_iterator aNodeIter;
10383   for ( aNodeIter = theListOfNodes.begin(); aNodeIter != theListOfNodes.end(); ++aNodeIter )
10384   {
10385     int aCurr = *aNodeIter;
10386     SMDS_MeshNode* aNode = (SMDS_MeshNode*)aMeshDS->FindNode( aCurr );
10387     if ( !aNode )
10388       continue;
10389
10390     // duplicate node
10391
10392     const SMDS_MeshNode* aNewNode = aMeshDS->AddNode( aNode->X(), aNode->Y(), aNode->Z() );
10393     if ( aNewNode )
10394     {
10395       anOldNodeToNewNode[ aNode ] = aNewNode;
10396       myLastCreatedNodes.Append( aNewNode );
10397     }
10398   }
10399
10400   // Create map of new nodes for modified elements
10401
10402   std::map< SMDS_MeshElement*, vector<const SMDS_MeshNode*> > anElemToNodes;
10403
10404   std::list< int >::const_iterator anElemIter;
10405   for ( anElemIter = theListOfModifiedElems.begin(); 
10406         anElemIter != theListOfModifiedElems.end(); ++anElemIter )
10407   {
10408     int aCurr = *anElemIter;
10409     SMDS_MeshElement* anElem = (SMDS_MeshElement*)aMeshDS->FindElement( aCurr );
10410     if ( !anElem )
10411       continue;
10412
10413     vector<const SMDS_MeshNode*> aNodeArr( anElem->NbNodes() );
10414
10415     SMDS_ElemIteratorPtr anIter = anElem->nodesIterator();
10416     int ind = 0;
10417     while ( anIter->more() ) 
10418     { 
10419       SMDS_MeshNode* aCurrNode = (SMDS_MeshNode*)anIter->next();
10420       if ( aCurr && anOldNodeToNewNode.find( aCurrNode ) != anOldNodeToNewNode.end() )
10421       {
10422         const SMDS_MeshNode* aNewNode = anOldNodeToNewNode[ aCurrNode ];
10423         aNodeArr[ ind++ ] = aNewNode;
10424       }
10425       else
10426         aNodeArr[ ind++ ] = aCurrNode;
10427     }
10428     anElemToNodes[ anElem ] = aNodeArr;
10429   }
10430
10431   // Change nodes of elements  
10432
10433   std::map< SMDS_MeshElement*, vector<const SMDS_MeshNode*> >::iterator
10434     anElemToNodesIter = anElemToNodes.begin();
10435   for ( ; anElemToNodesIter != anElemToNodes.end(); ++anElemToNodesIter )
10436   {
10437     const SMDS_MeshElement* anElem = anElemToNodesIter->first;
10438     vector<const SMDS_MeshNode*> aNodeArr = anElemToNodesIter->second;
10439     if ( anElem )
10440       {
10441       MESSAGE("ChangeElementNodes");
10442       aMeshDS->ChangeElementNodes( anElem, &aNodeArr[ 0 ], anElem->NbNodes() );
10443       }
10444   }
10445
10446   return true;
10447 }
10448
10449 namespace {
10450
10451   //================================================================================
10452   /*!
10453   \brief Check if element located inside shape
10454   \return TRUE if IN or ON shape, FALSE otherwise
10455   */
10456   //================================================================================
10457
10458   template<class Classifier>
10459   bool isInside(const SMDS_MeshElement* theElem,
10460                 Classifier&             theClassifier,
10461                 const double            theTol)
10462   {
10463     gp_XYZ centerXYZ (0, 0, 0);
10464     SMDS_ElemIteratorPtr aNodeItr = theElem->nodesIterator();
10465     while (aNodeItr->more())
10466       centerXYZ += SMESH_MeshEditor::TNodeXYZ(cast2Node( aNodeItr->next()));
10467
10468     gp_Pnt aPnt = centerXYZ / theElem->NbNodes();
10469     theClassifier.Perform(aPnt, theTol);
10470     TopAbs_State aState = theClassifier.State();
10471     return (aState == TopAbs_IN || aState == TopAbs_ON );
10472   }
10473
10474   //================================================================================
10475   /*!
10476    * \brief Classifier of the 3D point on the TopoDS_Face
10477    *        with interaface suitable for isInside()
10478    */
10479   //================================================================================
10480
10481   struct _FaceClassifier
10482   {
10483     Extrema_ExtPS       _extremum;
10484     BRepAdaptor_Surface _surface;
10485     TopAbs_State        _state;
10486
10487     _FaceClassifier(const TopoDS_Face& face):_extremum(),_surface(face),_state(TopAbs_OUT)
10488     {
10489       _extremum.Initialize( _surface,
10490                             _surface.FirstUParameter(), _surface.LastUParameter(),
10491                             _surface.FirstVParameter(), _surface.LastVParameter(),
10492                             _surface.Tolerance(), _surface.Tolerance() );
10493     }
10494     void Perform(const gp_Pnt& aPnt, double theTol)
10495     {
10496       _state = TopAbs_OUT;
10497       _extremum.Perform(aPnt);
10498       if ( _extremum.IsDone() )
10499         for ( int iSol = 1; iSol <= _extremum.NbExt() && _state == TopAbs_OUT; ++iSol)
10500           _state = ( _extremum.Value(iSol) <= theTol ? TopAbs_IN : TopAbs_OUT );
10501     }
10502     TopAbs_State State() const
10503     {
10504       return _state;
10505     }
10506   };
10507 }
10508
10509 //================================================================================
10510 /*!
10511   \brief Creates a hole in a mesh by doubling the nodes of some particular elements
10512   \param theElems - group of of elements (edges or faces) to be replicated
10513   \param theNodesNot - group of nodes not to replicate
10514   \param theShape - shape to detect affected elements (element which geometric center
10515   located on or inside shape).
10516   The replicated nodes should be associated to affected elements.
10517   \return TRUE if operation has been completed successfully, FALSE otherwise
10518 */
10519 //================================================================================
10520
10521 bool SMESH_MeshEditor::DoubleNodesInRegion( const TIDSortedElemSet& theElems,
10522                                             const TIDSortedElemSet& theNodesNot,
10523                                             const TopoDS_Shape&     theShape )
10524 {
10525   if ( theShape.IsNull() )
10526     return false;
10527
10528   const double aTol = Precision::Confusion();
10529   auto_ptr< BRepClass3d_SolidClassifier> bsc3d;
10530   auto_ptr<_FaceClassifier>              aFaceClassifier;
10531   if ( theShape.ShapeType() == TopAbs_SOLID )
10532   {
10533     bsc3d.reset( new BRepClass3d_SolidClassifier(theShape));;
10534     bsc3d->PerformInfinitePoint(aTol);
10535   }
10536   else if (theShape.ShapeType() == TopAbs_FACE )
10537   {
10538     aFaceClassifier.reset( new _FaceClassifier(TopoDS::Face(theShape)));
10539   }
10540
10541   // iterates on indicated elements and get elements by back references from their nodes
10542   TIDSortedElemSet anAffected;
10543   TIDSortedElemSet::const_iterator elemItr = theElems.begin();
10544   for ( ;  elemItr != theElems.end(); ++elemItr )
10545   {
10546     SMDS_MeshElement* anElem = (SMDS_MeshElement*)*elemItr;
10547     if (!anElem)
10548       continue;
10549
10550     SMDS_ElemIteratorPtr nodeItr = anElem->nodesIterator();
10551     while ( nodeItr->more() )
10552     {
10553       const SMDS_MeshNode* aNode = cast2Node(nodeItr->next());
10554       if ( !aNode || theNodesNot.find(aNode) != theNodesNot.end() )
10555         continue;
10556       SMDS_ElemIteratorPtr backElemItr = aNode->GetInverseElementIterator();
10557       while ( backElemItr->more() )
10558       {
10559         const SMDS_MeshElement* curElem = backElemItr->next();
10560         if ( curElem && theElems.find(curElem) == theElems.end() &&
10561              ( bsc3d.get() ?
10562                isInside( curElem, *bsc3d, aTol ) :
10563                isInside( curElem, *aFaceClassifier, aTol )))
10564           anAffected.insert( curElem );
10565       }
10566     }
10567   }
10568   return DoubleNodes( theElems, theNodesNot, anAffected );
10569 }
10570
10571 /*!
10572  * \brief Double nodes on shared faces between groups of volumes and create flat elements on demand.
10573  * The list of groups must describe a partition of the mesh volumes.
10574  * The nodes of the internal faces at the boundaries of the groups are doubled.
10575  * In option, the internal faces are replaced by flat elements.
10576  * Triangles are transformed in prisms, and quadrangles in hexahedrons.
10577  * @param theElems - list of groups of volumes, where a group of volume is a set of
10578  * SMDS_MeshElements sorted by Id.
10579  * @param createJointElems - if TRUE, create the elements
10580  * @return TRUE if operation has been completed successfully, FALSE otherwise
10581  */
10582 bool SMESH_MeshEditor::DoubleNodesOnGroupBoundaries( const std::vector<TIDSortedElemSet>& theElems,
10583                                                      bool createJointElems)
10584 {
10585   MESSAGE("------------------------------------------------------");
10586   MESSAGE("SMESH_MeshEditor::CreateJointElementsOnGroupBoundaries");
10587   MESSAGE("------------------------------------------------------");
10588
10589   SMESHDS_Mesh *meshDS = this->myMesh->GetMeshDS();
10590   meshDS->BuildDownWardConnectivity(false);
10591   CHRONO(50);
10592   SMDS_UnstructuredGrid *grid = meshDS->getGrid();
10593
10594   // --- build the list of faces shared by 2 domains (group of elements), with their domain and volume indexes
10595   //     build the list of nodes shared by 2 or more domains, with their domain indexes
10596
10597   std::map<DownIdType, std::map<int,int>, DownIdCompare> faceDomains; // 2x(id domain --> id volume)
10598   std::map<int, std::map<int,int> > nodeDomains; //oldId ->  (domainId -> newId)
10599   faceDomains.clear();
10600   nodeDomains.clear();
10601   std::map<int,int> emptyMap;
10602   emptyMap.clear();
10603
10604   for (int idom = 0; idom < theElems.size(); idom++)
10605     {
10606
10607       // --- build a map (face to duplicate --> volume to modify)
10608       //     with all the faces shared by 2 domains (group of elements)
10609       //     and corresponding volume of this domain, for each shared face.
10610       //     a volume has a face shared by 2 domains if it has a neighbor which is not in is domain.
10611
10612       const TIDSortedElemSet& domain = theElems[idom];
10613       TIDSortedElemSet::const_iterator elemItr = domain.begin();
10614       for (; elemItr != domain.end(); ++elemItr)
10615         {
10616           SMDS_MeshElement* anElem = (SMDS_MeshElement*) *elemItr;
10617           if (!anElem)
10618             continue;
10619           int vtkId = anElem->getVtkId();
10620           int neighborsVtkIds[NBMAXNEIGHBORS];
10621           int downIds[NBMAXNEIGHBORS];
10622           unsigned char downTypes[NBMAXNEIGHBORS];
10623           int nbNeighbors = grid->GetNeighbors(neighborsVtkIds, downIds, downTypes, vtkId);
10624           for (int n = 0; n < nbNeighbors; n++)
10625             {
10626               int smdsId = meshDS->fromVtkToSmds(neighborsVtkIds[n]);
10627               const SMDS_MeshElement* elem = meshDS->FindElement(smdsId);
10628               if (! domain.count(elem)) // neighbor is in another domain : face is shared
10629                 {
10630                   DownIdType face(downIds[n], downTypes[n]);
10631                   if (!faceDomains.count(face))
10632                     faceDomains[face] = emptyMap; // create an empty entry for face
10633                   if (!faceDomains[face].count(idom))
10634                     {
10635                       faceDomains[face][idom] = vtkId; // volume associated to face in this domain
10636                     }
10637                 }
10638             }
10639         }
10640     }
10641
10642   MESSAGE("Number of shared faces " << faceDomains.size());
10643
10644   // --- for each shared face, get the nodes
10645   //     for each node, for each domain of the face, create a clone of the node
10646
10647   std::map<DownIdType, std::map<int,int>, DownIdCompare>::iterator itface = faceDomains.begin();
10648   for( ; itface != faceDomains.end();++itface )
10649     {
10650       DownIdType face = itface->first;
10651       std::map<int,int> domvol = itface->second;
10652       std::set<int> oldNodes;
10653       oldNodes.clear();
10654       grid->GetNodeIds(oldNodes, face.cellId, face.cellType);
10655       std::set<int>::iterator itn = oldNodes.begin();
10656       for (;itn != oldNodes.end(); ++itn)
10657         {
10658           int oldId = *itn;
10659           if (!nodeDomains.count(oldId))
10660             nodeDomains[oldId] = emptyMap; // create an empty entry for node
10661           std::map<int,int>::iterator itdom = domvol.begin();
10662           for(; itdom != domvol.end(); ++itdom)
10663             {
10664               int idom = itdom->first;
10665               if ( nodeDomains[oldId].empty() )
10666                 nodeDomains[oldId][idom] = oldId; // keep the old node in the first domain
10667               else
10668                 {
10669                   double *coords = grid->GetPoint(oldId);
10670                   SMDS_MeshNode *newNode = meshDS->AddNode(coords[0], coords[1], coords[2]);
10671                   int newId = newNode->getVtkId();
10672                   nodeDomains[oldId][idom] = newId; // cloned node for other domains
10673                 }
10674             }
10675         }
10676     }
10677
10678   // --- iterate on shared faces (volumes to modify, face to extrude)
10679   //     get node id's of the face (id SMDS = id VTK)
10680   //     create flat element with old and new nodes if requested
10681
10682   if (createJointElems)
10683     {
10684       itface = faceDomains.begin();
10685       for( ; itface != faceDomains.end();++itface )
10686         {
10687           DownIdType face = itface->first;
10688           std::set<int> oldNodes;
10689           std::set<int>::iterator itn;
10690           oldNodes.clear();
10691           grid->GetNodeIds(oldNodes, face.cellId, face.cellType);
10692           std::map<int,int> localClonedNodeIds;
10693
10694           std::map<int,int> domvol = itface->second;
10695           std::map<int,int>::iterator itdom = domvol.begin();
10696           int dom1 = itdom->first;
10697           int vtkVolId = itdom->second;
10698           itdom++;
10699           int dom2 = itdom->first;
10700
10701           localClonedNodeIds.clear();
10702           for (itn = oldNodes.begin(); itn != oldNodes.end(); ++itn)
10703             {
10704               int oldId = *itn;
10705               int refid = oldId;
10706               if (nodeDomains[oldId].count(dom1))
10707                 refid = nodeDomains[oldId][dom1];
10708               else
10709                 MESSAGE("--- problem domain node " << dom1 << " " << oldId);
10710               int newid = oldId;
10711               if (nodeDomains[oldId].count(dom2))
10712                 newid = nodeDomains[oldId][dom2];
10713               else
10714                 MESSAGE("--- problem domain node " << dom2 << " " << oldId);
10715               localClonedNodeIds[oldId] = newid;
10716             }
10717           meshDS->extrudeVolumeFromFace(vtkVolId, localClonedNodeIds);
10718         }
10719     }
10720
10721   // --- iterate on shared faces (volumes to modify, face to extrude)
10722   //     get node id's of the face
10723   //     replace old nodes by new nodes in volumes, and update inverse connectivity
10724
10725   itface = faceDomains.begin();
10726   for( ; itface != faceDomains.end();++itface )
10727     {
10728       DownIdType face = itface->first;
10729       std::set<int> oldNodes;
10730       std::set<int>::iterator itn;
10731       oldNodes.clear();
10732       grid->GetNodeIds(oldNodes, face.cellId, face.cellType);
10733       std::map<int,int> localClonedNodeIds;
10734
10735       std::map<int,int> domvol = itface->second;
10736       std::map<int,int>::iterator itdom = domvol.begin();
10737       for(; itdom != domvol.end(); ++itdom)
10738         {
10739           int idom = itdom->first;
10740           int vtkVolId = itdom->second;
10741           localClonedNodeIds.clear();
10742           for (itn = oldNodes.begin(); itn != oldNodes.end(); ++itn)
10743             {
10744               int oldId = *itn;
10745               if (nodeDomains[oldId].count(idom))
10746                 localClonedNodeIds[oldId] = nodeDomains[oldId][idom];
10747             }
10748           meshDS->ModifyCellNodes(vtkVolId, localClonedNodeIds);
10749         }
10750     }
10751   grid->BuildLinks();
10752
10753   // TODO replace also old nodes by new nodes in faces and edges
10754   CHRONOSTOP(50);
10755   counters::stats();
10756   return true;
10757 }
10758
10759 //================================================================================
10760 /*!
10761  * \brief Generates skin mesh (containing 2D cells) from 3D mesh
10762  * The created 2D mesh elements based on nodes of free faces of boundary volumes
10763  * \return TRUE if operation has been completed successfully, FALSE otherwise
10764  */
10765 //================================================================================
10766
10767 bool SMESH_MeshEditor::Make2DMeshFrom3D()
10768 {
10769   // iterates on volume elements and detect all free faces on them
10770   SMESHDS_Mesh* aMesh = GetMeshDS();
10771   if (!aMesh)
10772     return false;
10773   //bool res = false;
10774   int nbFree = 0, nbExisted = 0, nbCreated = 0;
10775   SMDS_VolumeIteratorPtr vIt = aMesh->volumesIterator();
10776   while(vIt->more())
10777   {
10778     const SMDS_MeshVolume* volume = vIt->next();
10779     SMDS_VolumeTool vTool( volume );
10780     vTool.SetExternalNormal();
10781     const bool isPoly = volume->IsPoly();
10782     const bool isQuad = volume->IsQuadratic();
10783     for ( int iface = 0, n = vTool.NbFaces(); iface < n; iface++ )
10784     {
10785       if (!vTool.IsFreeFace(iface))
10786         continue;
10787       nbFree++;
10788       vector<const SMDS_MeshNode *> nodes;
10789       int nbFaceNodes = vTool.NbFaceNodes(iface);
10790       const SMDS_MeshNode** faceNodes = vTool.GetFaceNodes(iface);
10791       int inode = 0;
10792       for ( ; inode < nbFaceNodes; inode += isQuad ? 2 : 1)
10793         nodes.push_back(faceNodes[inode]);
10794       if (isQuad)
10795         for ( inode = 1; inode < nbFaceNodes; inode += 2)
10796           nodes.push_back(faceNodes[inode]);
10797
10798       // add new face based on volume nodes
10799       if (aMesh->FindFace( nodes ) ) {
10800         nbExisted++;
10801         continue; // face already exsist
10802       }
10803       AddElement(nodes, SMDSAbs_Face, isPoly && iface == 1);
10804       nbCreated++;
10805     }
10806   }
10807   return ( nbFree==(nbExisted+nbCreated) );
10808 }
10809
10810 namespace
10811 {
10812   inline const SMDS_MeshNode* getNodeWithSameID(SMESHDS_Mesh* mesh, const SMDS_MeshNode* node)
10813   {
10814     if ( const SMDS_MeshNode* n = mesh->FindNode( node->GetID() ))
10815       return n;
10816     return mesh->AddNodeWithID( node->X(),node->Y(),node->Z(), node->GetID() );
10817   }
10818 }
10819 //================================================================================
10820 /*!
10821  * \brief Creates missing boundary elements
10822  *  \param elements - elements whose boundary is to be checked
10823  *  \param dimension - defines type of boundary elements to create
10824  *  \param group - a group to store created boundary elements in
10825  *  \param targetMesh - a mesh to store created boundary elements in
10826  *  \param toCopyElements - if true, the checked elements will be copied into the targetMesh
10827  *  \param toCopyExistingBondary - if true, not only new but also pre-existing
10828  *                                boundary elements will be copied into the targetMesh
10829  */
10830 //================================================================================
10831
10832 void SMESH_MeshEditor::MakeBoundaryMesh(const TIDSortedElemSet& elements,
10833                                         Bnd_Dimension           dimension,
10834                                         SMESH_Group*            group/*=0*/,
10835                                         SMESH_Mesh*             targetMesh/*=0*/,
10836                                         bool                    toCopyElements/*=false*/,
10837                                         bool                    toCopyExistingBondary/*=false*/)
10838 {
10839   SMDSAbs_ElementType missType = (dimension == BND_2DFROM3D) ? SMDSAbs_Face : SMDSAbs_Edge;
10840   SMDSAbs_ElementType elemType = (dimension == BND_1DFROM2D) ? SMDSAbs_Face : SMDSAbs_Volume;
10841   // hope that all elements are of the same type, do not check them all
10842   if ( !elements.empty() && (*elements.begin())->GetType() != elemType )
10843     throw SALOME_Exception(LOCALIZED("wrong element type"));
10844
10845   if ( !targetMesh )
10846     toCopyElements = toCopyExistingBondary = false;
10847
10848   SMESH_MeshEditor tgtEditor( targetMesh ? targetMesh : myMesh );
10849   SMESHDS_Mesh* aMesh = GetMeshDS(), *tgtMeshDS = tgtEditor.GetMeshDS();
10850
10851   SMDS_VolumeTool vTool;
10852   TIDSortedElemSet emptySet, avoidSet;
10853   int inode;
10854
10855   typedef vector<const SMDS_MeshNode*> TConnectivity;
10856
10857   SMDS_ElemIteratorPtr eIt;
10858   if (elements.empty())
10859     eIt = aMesh->elementsIterator(elemType);
10860   else
10861     eIt = SMDS_ElemIteratorPtr( new TSetIterator( elements.begin(), elements.end() ));
10862
10863   while (eIt->more())
10864   {
10865     const SMDS_MeshElement* elem = eIt->next();
10866     const int iQuad = elem->IsQuadratic();
10867
10868     // 1. For an elem, get present bnd elements and connectivities of missing bnd elements
10869     vector<const SMDS_MeshElement*> presentBndElems;
10870     vector<TConnectivity>           missingBndElems;
10871     TConnectivity nodes;
10872     if ( vTool.Set(elem) ) // elem is a volume ------------------------------------------
10873     {
10874       vTool.SetExternalNormal();
10875       for ( int iface = 0, n = vTool.NbFaces(); iface < n; iface++ )
10876       {
10877         if (!vTool.IsFreeFace(iface))
10878           continue;
10879         int nbFaceNodes = vTool.NbFaceNodes(iface);
10880         const SMDS_MeshNode** nn = vTool.GetFaceNodes(iface);
10881         if ( missType == SMDSAbs_Edge ) // boundary edges
10882         {
10883           nodes.resize( 2+iQuad );
10884           for ( int i = 0; i < nbFaceNodes; i += 1+iQuad)
10885           {
10886             for ( int j = 0; j < nodes.size(); ++j )
10887               nodes[j] =nn[i+j];
10888             if ( const SMDS_MeshElement* edge =
10889                  aMesh->FindElement(nodes,SMDSAbs_Edge,/*noMedium=*/0))
10890               presentBndElems.push_back( edge );
10891             else
10892               missingBndElems.push_back( nodes );
10893           }
10894         }
10895         else // boundary face
10896         {
10897           nodes.clear();
10898           for ( inode = 0; inode < nbFaceNodes; inode += 1+iQuad)
10899             nodes.push_back( nn[inode] );
10900           if (iQuad)
10901             for ( inode = 1; inode < nbFaceNodes; inode += 2)
10902               nodes.push_back( nn[inode] );
10903
10904           if (const SMDS_MeshFace * f = aMesh->FindFace( nodes ) )
10905             presentBndElems.push_back( f );
10906           else
10907             missingBndElems.push_back( nodes );
10908         }
10909       }
10910     }
10911     else                     // elem is a face ------------------------------------------
10912     {
10913       avoidSet.clear(), avoidSet.insert( elem );
10914       int nbNodes = elem->NbCornerNodes();
10915       nodes.resize( 2 /*+ iQuad*/);
10916       for ( int i = 0; i < nbNodes; i++ )
10917       {
10918         nodes[0] = elem->GetNode(i);
10919         nodes[1] = elem->GetNode((i+1)%nbNodes);
10920         if ( FindFaceInSet( nodes[0], nodes[1], emptySet, avoidSet))
10921           continue; // not free link
10922
10923         //if ( iQuad )
10924         //nodes[2] = elem->GetNode( i + nbNodes );
10925         if ( const SMDS_MeshElement* edge =
10926              aMesh->FindElement(nodes,SMDSAbs_Edge,/*noMedium=*/true))
10927           presentBndElems.push_back( edge );
10928         else
10929           missingBndElems.push_back( nodes );
10930       }
10931     }
10932
10933     // 2. Add missing boundary elements
10934     if ( targetMesh != myMesh )
10935       // instead of making a map of nodes in this mesh and targetMesh,
10936       // we create nodes with same IDs. We can renumber them later, if needed
10937       for ( int i = 0; i < missingBndElems.size(); ++i )
10938       {
10939         TConnectivity& srcNodes = missingBndElems[i];
10940         TConnectivity  nodes( srcNodes.size() );
10941         for ( inode = 0; inode < nodes.size(); ++inode )
10942           nodes[inode] = getNodeWithSameID( tgtMeshDS, srcNodes[inode] );
10943         tgtEditor.AddElement(nodes, missType, elem->IsPoly() && nodes.size()/(iQuad+1)>4);
10944       }
10945     else
10946       for ( int i = 0; i < missingBndElems.size(); ++i )
10947       {
10948         TConnectivity&  nodes = missingBndElems[i];
10949         tgtEditor.AddElement(nodes, missType, elem->IsPoly() && nodes.size()/(iQuad+1)>4);
10950       }
10951
10952     // 3. Copy present boundary elements
10953     if ( toCopyExistingBondary )
10954       for ( int i = 0 ; i < presentBndElems.size(); ++i )
10955       {
10956         const SMDS_MeshElement* e = presentBndElems[i];
10957         TConnectivity nodes( e->NbNodes() );
10958         for ( inode = 0; inode < nodes.size(); ++inode )
10959           nodes[inode] = getNodeWithSameID( tgtMeshDS, e->GetNode(inode) );
10960         tgtEditor.AddElement(nodes, missType, e->IsPoly());
10961         // leave only missing elements in tgtEditor.myLastCreatedElems
10962         tgtEditor.myLastCreatedElems.Remove( tgtEditor.myLastCreatedElems.Size() );
10963       }
10964   } // loop on given elements
10965
10966   // 4. Fill group with missing boundary elements
10967   if ( group )
10968   {
10969     if ( SMESHDS_Group* g = dynamic_cast<SMESHDS_Group*>( group->GetGroupDS() ))
10970       for ( int i = 0; i < tgtEditor.myLastCreatedElems.Size(); ++i )
10971         g->SMDSGroup().Add( tgtEditor.myLastCreatedElems( i+1 ));
10972   }
10973   tgtEditor.myLastCreatedElems.Clear();
10974
10975   // 5. Copy given elements
10976   if ( toCopyElements )
10977   {
10978     if (elements.empty())
10979       eIt = aMesh->elementsIterator(elemType);
10980     else
10981       eIt = SMDS_ElemIteratorPtr( new TSetIterator( elements.begin(), elements.end() ));
10982     while (eIt->more())
10983     {
10984       const SMDS_MeshElement* elem = eIt->next();
10985       TConnectivity nodes( elem->NbNodes() );
10986       for ( inode = 0; inode < nodes.size(); ++inode )
10987         nodes[inode] = getNodeWithSameID( tgtMeshDS, elem->GetNode(inode) );
10988       tgtEditor.AddElement(nodes, elemType, elem->IsPoly());
10989
10990       tgtEditor.myLastCreatedElems.Clear();
10991     }
10992   }
10993   return;
10994 }