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