Salome HOME
794c69c5eef5b3b3cbe46080461a62ee65097199
[modules/smesh.git] / src / SMESH / SMESH_MeshEditor.cxx
1 //  Copyright (C) 2007-2010  CEA/DEN, EDF R&D, OPEN CASCADE
2 //
3 //  Copyright (C) 2003-2007  OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN,
4 //  CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS
5 //
6 //  This library is free software; you can redistribute it and/or
7 //  modify it under the terms of the GNU Lesser General Public
8 //  License as published by the Free Software Foundation; either
9 //  version 2.1 of the License.
10 //
11 //  This library is distributed in the hope that it will be useful,
12 //  but WITHOUT ANY WARRANTY; without even the implied warranty of
13 //  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14 //  Lesser General Public License for more details.
15 //
16 //  You should have received a copy of the GNU Lesser General Public
17 //  License along with this library; if not, write to the Free Software
18 //  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
19 //
20 //  See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
21 //
22
23 //  SMESH SMESH : idl implementation based on 'SMESH' unit's classes
24 // File      : SMESH_MeshEditor.cxx
25 // Created   : Mon Apr 12 16:10:22 2004
26 // Author    : Edward AGAPOV (eap)
27 //
28 #define CHRONODEF
29 #include "SMESH_MeshEditor.hxx"
30
31 #include "SMDS_FaceOfNodes.hxx"
32 #include "SMDS_VolumeTool.hxx"
33 #include "SMDS_EdgePosition.hxx"
34 #include "SMDS_PolyhedralVolumeOfNodes.hxx"
35 #include "SMDS_FacePosition.hxx"
36 #include "SMDS_SpacePosition.hxx"
37 //#include "SMDS_QuadraticFaceOfNodes.hxx"
38 #include "SMDS_MeshGroup.hxx"
39 #include "SMDS_LinearEdge.hxx"
40 #include "SMDS_Downward.hxx"
41 #include "SMDS_SetIterator.hxx"
42
43 #include "SMESHDS_Group.hxx"
44 #include "SMESHDS_Mesh.hxx"
45
46 #include "SMESH_Algo.hxx"
47 #include "SMESH_ControlsDef.hxx"
48 #include "SMESH_Group.hxx"
49 #include "SMESH_MesherHelper.hxx"
50 #include "SMESH_OctreeNode.hxx"
51 #include "SMESH_subMesh.hxx"
52
53 #include "utilities.h"
54
55 #include <BRepAdaptor_Surface.hxx>
56 #include <BRepClass3d_SolidClassifier.hxx>
57 #include <BRep_Tool.hxx>
58 #include <ElCLib.hxx>
59 #include <Extrema_GenExtPS.hxx>
60 #include <Extrema_POnCurv.hxx>
61 #include <Extrema_POnSurf.hxx>
62 #include <GC_MakeSegment.hxx>
63 #include <Geom2d_Curve.hxx>
64 #include <GeomAPI_ExtremaCurveCurve.hxx>
65 #include <GeomAdaptor_Surface.hxx>
66 #include <Geom_Curve.hxx>
67 #include <Geom_Line.hxx>
68 #include <Geom_Surface.hxx>
69 #include <IntAna_IntConicQuad.hxx>
70 #include <IntAna_Quadric.hxx>
71 #include <Precision.hxx>
72 #include <TColStd_ListOfInteger.hxx>
73 #include <TopAbs_State.hxx>
74 #include <TopExp.hxx>
75 #include <TopExp_Explorer.hxx>
76 #include <TopTools_ListIteratorOfListOfShape.hxx>
77 #include <TopTools_ListOfShape.hxx>
78 #include <TopTools_SequenceOfShape.hxx>
79 #include <TopoDS.hxx>
80 #include <TopoDS_Face.hxx>
81 #include <gp.hxx>
82 #include <gp_Ax1.hxx>
83 #include <gp_Dir.hxx>
84 #include <gp_Lin.hxx>
85 #include <gp_Pln.hxx>
86 #include <gp_Trsf.hxx>
87 #include <gp_Vec.hxx>
88 #include <gp_XY.hxx>
89 #include <gp_XYZ.hxx>
90
91 #include <math.h>
92
93 #include <map>
94 #include <set>
95 #include <numeric>
96 #include <limits>
97
98 #define cast2Node(elem) static_cast<const SMDS_MeshNode*>( elem )
99
100 using namespace std;
101 using namespace SMESH::Controls;
102
103 typedef map<const SMDS_MeshElement*, list<const SMDS_MeshNode*> >    TElemOfNodeListMap;
104 typedef map<const SMDS_MeshElement*, list<const SMDS_MeshElement*> > TElemOfElemListMap;
105
106 typedef SMDS_SetIterator< SMDS_pElement, TIDSortedElemSet::const_iterator> TSetIterator;
107
108 //=======================================================================
109 //function : SMESH_MeshEditor
110 //purpose  :
111 //=======================================================================
112
113 SMESH_MeshEditor::SMESH_MeshEditor( SMESH_Mesh* theMesh )
114   :myMesh( theMesh ) // theMesh may be NULL
115 {
116 }
117
118 //=======================================================================
119 /*!
120  * \brief Add element
121  */
122 //=======================================================================
123
124 SMDS_MeshElement*
125 SMESH_MeshEditor::AddElement(const vector<const SMDS_MeshNode*> & node,
126                              const SMDSAbs_ElementType            type,
127                              const bool                           isPoly,
128                              const int                            ID)
129 {
130   //MESSAGE("AddElement " <<node.size() << " " << type << " " << isPoly << " " << ID);
131   SMDS_MeshElement* e = 0;
132   int nbnode = node.size();
133   SMESHDS_Mesh* mesh = GetMeshDS();
134   switch ( type ) {
135   case SMDSAbs_Face:
136     if ( !isPoly ) {
137       if      (nbnode == 3) {
138         if ( ID >= 1 ) e = mesh->AddFaceWithID(node[0], node[1], node[2], ID);
139         else           e = mesh->AddFace      (node[0], node[1], node[2] );
140       }
141       else if (nbnode == 4) {
142         if ( ID >= 1 ) e = mesh->AddFaceWithID(node[0], node[1], node[2], node[3], ID);
143         else           e = mesh->AddFace      (node[0], node[1], node[2], node[3] );
144       }
145       else if (nbnode == 6) {
146         if ( ID >= 1 ) e = mesh->AddFaceWithID(node[0], node[1], node[2], node[3],
147                                                node[4], node[5], ID);
148         else           e = mesh->AddFace      (node[0], node[1], node[2], node[3],
149                                                node[4], node[5] );
150       }
151       else if (nbnode == 8) {
152         if ( ID >= 1 ) e = mesh->AddFaceWithID(node[0], node[1], node[2], node[3],
153                                                node[4], node[5], node[6], node[7], ID);
154         else           e = mesh->AddFace      (node[0], node[1], node[2], node[3],
155                                                node[4], node[5], node[6], node[7] );
156       }
157     } else {
158       if ( ID >= 1 ) e = mesh->AddPolygonalFaceWithID(node, ID);
159       else           e = mesh->AddPolygonalFace      (node    );
160     }
161     break;
162
163   case SMDSAbs_Volume:
164     if ( !isPoly ) {
165       if      (nbnode == 4) {
166         if ( ID >= 1 ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3], ID);
167         else           e = mesh->AddVolume      (node[0], node[1], node[2], node[3] );
168       }
169       else if (nbnode == 5) {
170         if ( ID >= 1 ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
171                                                  node[4], ID);
172         else           e = mesh->AddVolume      (node[0], node[1], node[2], node[3],
173                                                  node[4] );
174       }
175       else if (nbnode == 6) {
176         if ( ID >= 1 ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
177                                                  node[4], node[5], ID);
178         else           e = mesh->AddVolume      (node[0], node[1], node[2], node[3],
179                                                  node[4], node[5] );
180       }
181       else if (nbnode == 8) {
182         if ( ID >= 1 ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
183                                                  node[4], node[5], node[6], node[7], ID);
184         else           e = mesh->AddVolume      (node[0], node[1], node[2], node[3],
185                                                  node[4], node[5], node[6], node[7] );
186       }
187       else if (nbnode == 10) {
188         if ( ID >= 1 ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
189                                                  node[4], node[5], node[6], node[7],
190                                                  node[8], node[9], ID);
191         else           e = mesh->AddVolume      (node[0], node[1], node[2], node[3],
192                                                  node[4], node[5], node[6], node[7],
193                                                  node[8], node[9] );
194       }
195       else if (nbnode == 13) {
196         if ( ID >= 1 ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
197                                                  node[4], node[5], node[6], node[7],
198                                                  node[8], node[9], node[10],node[11],
199                                                  node[12],ID);
200         else           e = mesh->AddVolume      (node[0], node[1], node[2], node[3],
201                                                  node[4], node[5], node[6], node[7],
202                                                  node[8], node[9], node[10],node[11],
203                                                  node[12] );
204       }
205       else if (nbnode == 15) {
206         if ( ID >= 1 ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
207                                                  node[4], node[5], node[6], node[7],
208                                                  node[8], node[9], node[10],node[11],
209                                                  node[12],node[13],node[14],ID);
210         else           e = mesh->AddVolume      (node[0], node[1], node[2], node[3],
211                                                  node[4], node[5], node[6], node[7],
212                                                  node[8], node[9], node[10],node[11],
213                                                  node[12],node[13],node[14] );
214       }
215       else if (nbnode == 20) {
216         if ( ID >= 1 ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
217                                                  node[4], node[5], node[6], node[7],
218                                                  node[8], node[9], node[10],node[11],
219                                                  node[12],node[13],node[14],node[15],
220                                                  node[16],node[17],node[18],node[19],ID);
221         else           e = mesh->AddVolume      (node[0], node[1], node[2], node[3],
222                                                  node[4], node[5], node[6], node[7],
223                                                  node[8], node[9], node[10],node[11],
224                                                  node[12],node[13],node[14],node[15],
225                                                  node[16],node[17],node[18],node[19] );
226       }
227     }
228     break;
229
230   case SMDSAbs_Edge:
231     if ( nbnode == 2 ) {
232       if ( ID >= 1 ) e = mesh->AddEdgeWithID(node[0], node[1], ID);
233       else           e = mesh->AddEdge      (node[0], node[1] );
234     }
235     else if ( nbnode == 3 ) {
236       if ( ID >= 1 ) e = mesh->AddEdgeWithID(node[0], node[1], node[2], ID);
237       else           e = mesh->AddEdge      (node[0], node[1], node[2] );
238     }
239     break;
240
241   case SMDSAbs_0DElement:
242     if ( nbnode == 1 ) {
243       if ( ID >= 1 ) e = mesh->Add0DElementWithID(node[0], ID);
244       else           e = mesh->Add0DElement      (node[0] );
245     }
246     break;
247
248   case SMDSAbs_Node:
249     if ( ID >= 1 ) e = mesh->AddNodeWithID(node[0]->X(), node[0]->Y(), node[0]->Z(), ID);
250     else           e = mesh->AddNode      (node[0]->X(), node[0]->Y(), node[0]->Z());
251     break;
252
253   default:;
254   }
255   if ( e ) myLastCreatedElems.Append( e );
256   return e;
257 }
258
259 //=======================================================================
260 /*!
261  * \brief Add element
262  */
263 //=======================================================================
264
265 SMDS_MeshElement* SMESH_MeshEditor::AddElement(const vector<int> &       nodeIDs,
266                                                const SMDSAbs_ElementType type,
267                                                const bool                isPoly,
268                                                const int                 ID)
269 {
270   vector<const SMDS_MeshNode*> nodes;
271   nodes.reserve( nodeIDs.size() );
272   vector<int>::const_iterator id = nodeIDs.begin();
273   while ( id != nodeIDs.end() ) {
274     if ( const SMDS_MeshNode* node = GetMeshDS()->FindNode( *id++ ))
275       nodes.push_back( node );
276     else
277       return 0;
278   }
279   return AddElement( nodes, type, isPoly, ID );
280 }
281
282 //=======================================================================
283 //function : Remove
284 //purpose  : Remove a node or an element.
285 //           Modify a compute state of sub-meshes which become empty
286 //=======================================================================
287
288 int SMESH_MeshEditor::Remove (const list< int >& theIDs,
289                               const bool         isNodes )
290 {
291   myLastCreatedElems.Clear();
292   myLastCreatedNodes.Clear();
293
294   SMESHDS_Mesh* aMesh = GetMeshDS();
295   set< SMESH_subMesh *> smmap;
296
297   int removed = 0;
298   list<int>::const_iterator it = theIDs.begin();
299   for ( ; it != theIDs.end(); it++ ) {
300     const SMDS_MeshElement * elem;
301     if ( isNodes )
302       elem = aMesh->FindNode( *it );
303     else
304       elem = aMesh->FindElement( *it );
305     if ( !elem )
306       continue;
307
308     // Notify VERTEX sub-meshes about modification
309     if ( isNodes ) {
310       const SMDS_MeshNode* node = cast2Node( elem );
311       if ( node->GetPosition()->GetTypeOfPosition() == SMDS_TOP_VERTEX )
312         if ( int aShapeID = node->getshapeId() )
313           if ( SMESH_subMesh * sm = GetMesh()->GetSubMeshContaining( aShapeID ) )
314             smmap.insert( sm );
315     }
316     // Find sub-meshes to notify about modification
317     //     SMDS_ElemIteratorPtr nodeIt = elem->nodesIterator();
318     //     while ( nodeIt->more() ) {
319     //       const SMDS_MeshNode* node = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
320     //       const SMDS_PositionPtr& aPosition = node->GetPosition();
321     //       if ( aPosition.get() ) {
322     //         if ( int aShapeID = aPosition->GetShapeId() ) {
323     //           if ( SMESH_subMesh * sm = GetMesh()->GetSubMeshContaining( aShapeID ) )
324     //             smmap.insert( sm );
325     //         }
326     //       }
327     //     }
328
329     // Do remove
330     if ( isNodes )
331       aMesh->RemoveNode( static_cast< const SMDS_MeshNode* >( elem ));
332     else
333       aMesh->RemoveElement( elem );
334     removed++;
335   }
336
337   // Notify sub-meshes about modification
338   if ( !smmap.empty() ) {
339     set< SMESH_subMesh *>::iterator smIt;
340     for ( smIt = smmap.begin(); smIt != smmap.end(); smIt++ )
341       (*smIt)->ComputeStateEngine( SMESH_subMesh::MESH_ENTITY_REMOVED );
342   }
343
344   //   // Check if the whole mesh becomes empty
345   //   if ( SMESH_subMesh * sm = GetMesh()->GetSubMeshContaining( 1 ) )
346   //     sm->ComputeStateEngine( SMESH_subMesh::CHECK_COMPUTE_STATE );
347
348   return removed;
349 }
350
351 //=======================================================================
352 //function : FindShape
353 //purpose  : Return an index of the shape theElem is on
354 //           or zero if a shape not found
355 //=======================================================================
356
357 int SMESH_MeshEditor::FindShape (const SMDS_MeshElement * theElem)
358 {
359   myLastCreatedElems.Clear();
360   myLastCreatedNodes.Clear();
361
362   SMESHDS_Mesh * aMesh = GetMeshDS();
363   if ( aMesh->ShapeToMesh().IsNull() )
364     return 0;
365
366   if ( theElem->GetType() == SMDSAbs_Node )
367     {
368       int aShapeID = theElem->getshapeId();
369       if (aShapeID <= 0)
370         return 0;
371       else
372         return aShapeID;
373     }
374
375   TopoDS_Shape aShape; // the shape a node is on
376   SMDS_ElemIteratorPtr nodeIt = theElem->nodesIterator();
377   while ( nodeIt->more() ) {
378     const SMDS_MeshNode* node = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
379     int aShapeID = node->getshapeId();
380     if (aShapeID > 0) {
381       SMESHDS_SubMesh * sm = aMesh->MeshElements( aShapeID );
382       if ( sm ) {
383         if ( sm->Contains( theElem ))
384           return aShapeID;
385         if ( aShape.IsNull() )
386           aShape = aMesh->IndexToShape( aShapeID );
387       }
388       else {
389         //MESSAGE ( "::FindShape() No SubShape for aShapeID " << aShapeID );
390       }
391     }
392   }
393
394   // None of nodes is on a proper shape,
395   // find the shape among ancestors of aShape on which a node is
396   if ( aShape.IsNull() ) {
397     //MESSAGE ("::FindShape() - NONE node is on shape")
398     return 0;
399   }
400   TopTools_ListIteratorOfListOfShape ancIt( GetMesh()->GetAncestors( aShape ));
401   for ( ; ancIt.More(); ancIt.Next() ) {
402     SMESHDS_SubMesh * sm = aMesh->MeshElements( ancIt.Value() );
403     if ( sm && sm->Contains( theElem ))
404       return aMesh->ShapeToIndex( ancIt.Value() );
405   }
406
407   //MESSAGE ("::FindShape() - SHAPE NOT FOUND")
408   return 0;
409 }
410
411 //=======================================================================
412 //function : IsMedium
413 //purpose  :
414 //=======================================================================
415
416 bool SMESH_MeshEditor::IsMedium(const SMDS_MeshNode*      node,
417                                 const SMDSAbs_ElementType typeToCheck)
418 {
419   bool isMedium = false;
420   SMDS_ElemIteratorPtr it = node->GetInverseElementIterator(typeToCheck);
421   while (it->more() && !isMedium ) {
422     const SMDS_MeshElement* elem = it->next();
423     isMedium = elem->IsMediumNode(node);
424   }
425   return isMedium;
426 }
427
428 //=======================================================================
429 //function : ShiftNodesQuadTria
430 //purpose  : auxilary
431 //           Shift nodes in the array corresponded to quadratic triangle
432 //           example: (0,1,2,3,4,5) -> (1,2,0,4,5,3)
433 //=======================================================================
434 static void ShiftNodesQuadTria(const SMDS_MeshNode* aNodes[])
435 {
436   const SMDS_MeshNode* nd1 = aNodes[0];
437   aNodes[0] = aNodes[1];
438   aNodes[1] = aNodes[2];
439   aNodes[2] = nd1;
440   const SMDS_MeshNode* nd2 = aNodes[3];
441   aNodes[3] = aNodes[4];
442   aNodes[4] = aNodes[5];
443   aNodes[5] = nd2;
444 }
445
446 //=======================================================================
447 //function : GetNodesFromTwoTria
448 //purpose  : auxilary
449 //           Shift nodes in the array corresponded to quadratic triangle
450 //           example: (0,1,2,3,4,5) -> (1,2,0,4,5,3)
451 //=======================================================================
452 static bool GetNodesFromTwoTria(const SMDS_MeshElement * theTria1,
453                                 const SMDS_MeshElement * theTria2,
454                                 const SMDS_MeshNode* N1[],
455                                 const SMDS_MeshNode* N2[])
456 {
457   SMDS_ElemIteratorPtr it = theTria1->nodesIterator();
458   int i=0;
459   while(i<6) {
460     N1[i] = static_cast<const SMDS_MeshNode*>( it->next() );
461     i++;
462   }
463   if(it->more()) return false;
464   it = theTria2->nodesIterator();
465   i=0;
466   while(i<6) {
467     N2[i] = static_cast<const SMDS_MeshNode*>( it->next() );
468     i++;
469   }
470   if(it->more()) return false;
471
472   int sames[3] = {-1,-1,-1};
473   int nbsames = 0;
474   int j;
475   for(i=0; i<3; i++) {
476     for(j=0; j<3; j++) {
477       if(N1[i]==N2[j]) {
478         sames[i] = j;
479         nbsames++;
480         break;
481       }
482     }
483   }
484   if(nbsames!=2) return false;
485   if(sames[0]>-1) {
486     ShiftNodesQuadTria(N1);
487     if(sames[1]>-1) {
488       ShiftNodesQuadTria(N1);
489     }
490   }
491   i = sames[0] + sames[1] + sames[2];
492   for(; i<2; i++) {
493     ShiftNodesQuadTria(N2);
494   }
495   // now we receive following N1 and N2 (using numeration as above image)
496   // tria1 : (1 2 4 5 9 7)  and  tria2 : (3 4 2 8 9 6)
497   // i.e. first nodes from both arrays determ new diagonal
498   return true;
499 }
500
501 //=======================================================================
502 //function : InverseDiag
503 //purpose  : Replace two neighbour triangles with ones built on the same 4 nodes
504 //           but having other common link.
505 //           Return False if args are improper
506 //=======================================================================
507
508 bool SMESH_MeshEditor::InverseDiag (const SMDS_MeshElement * theTria1,
509                                     const SMDS_MeshElement * theTria2 )
510 {
511   MESSAGE("InverseDiag");
512   myLastCreatedElems.Clear();
513   myLastCreatedNodes.Clear();
514
515   if (!theTria1 || !theTria2)
516     return false;
517
518   const SMDS_VtkFace* F1 = dynamic_cast<const SMDS_VtkFace*>( theTria1 );
519   if (!F1) return false;
520   const SMDS_VtkFace* F2 = dynamic_cast<const SMDS_VtkFace*>( theTria2 );
521   if (!F2) return false;
522   if ((theTria1->GetEntityType() == SMDSEntity_Triangle) &&
523       (theTria2->GetEntityType() == SMDSEntity_Triangle)) {
524
525     //  1 +--+ A  theTria1: ( 1 A B ) A->2 ( 1 2 B ) 1 +--+ A
526     //    | /|    theTria2: ( B A 2 ) B->1 ( 1 A 2 )   |\ |
527     //    |/ |                                         | \|
528     //  B +--+ 2                                     B +--+ 2
529
530     // put nodes in array and find out indices of the same ones
531     const SMDS_MeshNode* aNodes [6];
532     int sameInd [] = { 0, 0, 0, 0, 0, 0 };
533     int i = 0;
534     SMDS_ElemIteratorPtr it = theTria1->nodesIterator();
535     while ( it->more() ) {
536       aNodes[ i ] = static_cast<const SMDS_MeshNode*>( it->next() );
537
538       if ( i > 2 ) // theTria2
539         // find same node of theTria1
540         for ( int j = 0; j < 3; j++ )
541           if ( aNodes[ i ] == aNodes[ j ]) {
542             sameInd[ j ] = i;
543             sameInd[ i ] = j;
544             break;
545           }
546       // next
547       i++;
548       if ( i == 3 ) {
549         if ( it->more() )
550           return false; // theTria1 is not a triangle
551         it = theTria2->nodesIterator();
552       }
553       if ( i == 6 && it->more() )
554         return false; // theTria2 is not a triangle
555     }
556
557     // find indices of 1,2 and of A,B in theTria1
558     int iA = 0, iB = 0, i1 = 0, i2 = 0;
559     for ( i = 0; i < 6; i++ ) {
560       if ( sameInd [ i ] == 0 ) {
561         if ( i < 3 ) i1 = i;
562         else         i2 = i;
563       }
564       else if (i < 3) {
565         if ( iA ) iB = i;
566         else      iA = i;
567       }
568     }
569     // nodes 1 and 2 should not be the same
570     if ( aNodes[ i1 ] == aNodes[ i2 ] )
571       return false;
572
573     // theTria1: A->2
574     aNodes[ iA ] = aNodes[ i2 ];
575     // theTria2: B->1
576     aNodes[ sameInd[ iB ]] = aNodes[ i1 ];
577
578     GetMeshDS()->ChangeElementNodes( theTria1, aNodes, 3 );
579     GetMeshDS()->ChangeElementNodes( theTria2, &aNodes[ 3 ], 3 );
580
581     return true;
582
583   } // end if(F1 && F2)
584
585   // check case of quadratic faces
586   if (theTria1->GetEntityType() != SMDSEntity_Quad_Triangle)
587     return false;
588   if (theTria2->GetEntityType() != SMDSEntity_Quad_Triangle)
589     return false;
590
591   //       5
592   //  1 +--+--+ 2  theTria1: (1 2 4 5 9 7) or (2 4 1 9 7 5) or (4 1 2 7 5 9)
593   //    |    /|    theTria2: (2 3 4 6 8 9) or (3 4 2 8 9 6) or (4 2 3 9 6 8)
594   //    |   / |
595   //  7 +  +  + 6
596   //    | /9  |
597   //    |/    |
598   //  4 +--+--+ 3
599   //       8
600
601   const SMDS_MeshNode* N1 [6];
602   const SMDS_MeshNode* N2 [6];
603   if(!GetNodesFromTwoTria(theTria1,theTria2,N1,N2))
604     return false;
605   // now we receive following N1 and N2 (using numeration as above image)
606   // tria1 : (1 2 4 5 9 7)  and  tria2 : (3 4 2 8 9 6)
607   // i.e. first nodes from both arrays determ new diagonal
608
609   const SMDS_MeshNode* N1new [6];
610   const SMDS_MeshNode* N2new [6];
611   N1new[0] = N1[0];
612   N1new[1] = N2[0];
613   N1new[2] = N2[1];
614   N1new[3] = N1[4];
615   N1new[4] = N2[3];
616   N1new[5] = N1[5];
617   N2new[0] = N1[0];
618   N2new[1] = N1[1];
619   N2new[2] = N2[0];
620   N2new[3] = N1[3];
621   N2new[4] = N2[5];
622   N2new[5] = N1[4];
623   // replaces nodes in faces
624   GetMeshDS()->ChangeElementNodes( theTria1, N1new, 6 );
625   GetMeshDS()->ChangeElementNodes( theTria2, N2new, 6 );
626
627   return true;
628 }
629
630 //=======================================================================
631 //function : findTriangles
632 //purpose  : find triangles sharing theNode1-theNode2 link
633 //=======================================================================
634
635 static bool findTriangles(const SMDS_MeshNode *    theNode1,
636                           const SMDS_MeshNode *    theNode2,
637                           const SMDS_MeshElement*& theTria1,
638                           const SMDS_MeshElement*& theTria2)
639 {
640   if ( !theNode1 || !theNode2 ) return false;
641
642   theTria1 = theTria2 = 0;
643
644   set< const SMDS_MeshElement* > emap;
645   SMDS_ElemIteratorPtr it = theNode1->GetInverseElementIterator(SMDSAbs_Face);
646   while (it->more()) {
647     const SMDS_MeshElement* elem = it->next();
648     if ( elem->NbNodes() == 3 )
649       emap.insert( elem );
650   }
651   it = theNode2->GetInverseElementIterator(SMDSAbs_Face);
652   while (it->more()) {
653     const SMDS_MeshElement* elem = it->next();
654     if ( emap.find( elem ) != emap.end() ) {
655       if ( theTria1 ) {
656         // theTria1 must be element with minimum ID
657         if( theTria1->GetID() < elem->GetID() ) {
658           theTria2 = elem;
659         }
660         else {
661           theTria2 = theTria1;
662           theTria1 = elem;
663         }
664         break;
665       }
666       else {
667         theTria1 = elem;
668       }
669     }
670   }
671   return ( theTria1 && theTria2 );
672 }
673
674 //=======================================================================
675 //function : InverseDiag
676 //purpose  : Replace two neighbour triangles sharing theNode1-theNode2 link
677 //           with ones built on the same 4 nodes but having other common link.
678 //           Return false if proper faces not found
679 //=======================================================================
680
681 bool SMESH_MeshEditor::InverseDiag (const SMDS_MeshNode * theNode1,
682                                     const SMDS_MeshNode * theNode2)
683 {
684   myLastCreatedElems.Clear();
685   myLastCreatedNodes.Clear();
686
687   MESSAGE( "::InverseDiag()" );
688
689   const SMDS_MeshElement *tr1, *tr2;
690   if ( !findTriangles( theNode1, theNode2, tr1, tr2 ))
691     return false;
692
693   const SMDS_VtkFace* F1 = dynamic_cast<const SMDS_VtkFace*>( tr1 );
694   if (!F1) return false;
695   const SMDS_VtkFace* F2 = dynamic_cast<const SMDS_VtkFace*>( tr2 );
696   if (!F2) return false;
697   if ((tr1->GetEntityType() == SMDSEntity_Triangle) &&
698       (tr2->GetEntityType() == SMDSEntity_Triangle)) {
699
700     //  1 +--+ A  tr1: ( 1 A B ) A->2 ( 1 2 B ) 1 +--+ A
701     //    | /|    tr2: ( B A 2 ) B->1 ( 1 A 2 )   |\ |
702     //    |/ |                                    | \|
703     //  B +--+ 2                                B +--+ 2
704
705     // put nodes in array
706     // and find indices of 1,2 and of A in tr1 and of B in tr2
707     int i, iA1 = 0, i1 = 0;
708     const SMDS_MeshNode* aNodes1 [3];
709     SMDS_ElemIteratorPtr it;
710     for (i = 0, it = tr1->nodesIterator(); it->more(); i++ ) {
711       aNodes1[ i ] = static_cast<const SMDS_MeshNode*>( it->next() );
712       if ( aNodes1[ i ] == theNode1 )
713         iA1 = i; // node A in tr1
714       else if ( aNodes1[ i ] != theNode2 )
715         i1 = i;  // node 1
716     }
717     int iB2 = 0, i2 = 0;
718     const SMDS_MeshNode* aNodes2 [3];
719     for (i = 0, it = tr2->nodesIterator(); it->more(); i++ ) {
720       aNodes2[ i ] = static_cast<const SMDS_MeshNode*>( it->next() );
721       if ( aNodes2[ i ] == theNode2 )
722         iB2 = i; // node B in tr2
723       else if ( aNodes2[ i ] != theNode1 )
724         i2 = i;  // node 2
725     }
726
727     // nodes 1 and 2 should not be the same
728     if ( aNodes1[ i1 ] == aNodes2[ i2 ] )
729       return false;
730
731     // tr1: A->2
732     aNodes1[ iA1 ] = aNodes2[ i2 ];
733     // tr2: B->1
734     aNodes2[ iB2 ] = aNodes1[ i1 ];
735
736     GetMeshDS()->ChangeElementNodes( tr1, aNodes1, 3 );
737     GetMeshDS()->ChangeElementNodes( tr2, aNodes2, 3 );
738
739     return true;
740   }
741
742   // check case of quadratic faces
743   return InverseDiag(tr1,tr2);
744 }
745
746 //=======================================================================
747 //function : getQuadrangleNodes
748 //purpose  : fill theQuadNodes - nodes of a quadrangle resulting from
749 //           fusion of triangles tr1 and tr2 having shared link on
750 //           theNode1 and theNode2
751 //=======================================================================
752
753 bool getQuadrangleNodes(const SMDS_MeshNode *    theQuadNodes [],
754                         const SMDS_MeshNode *    theNode1,
755                         const SMDS_MeshNode *    theNode2,
756                         const SMDS_MeshElement * tr1,
757                         const SMDS_MeshElement * tr2 )
758 {
759   if( tr1->NbNodes() != tr2->NbNodes() )
760     return false;
761   // find the 4-th node to insert into tr1
762   const SMDS_MeshNode* n4 = 0;
763   SMDS_ElemIteratorPtr it = tr2->nodesIterator();
764   int i=0;
765   while ( !n4 && i<3 ) {
766     const SMDS_MeshNode * n = cast2Node( it->next() );
767     i++;
768     bool isDiag = ( n == theNode1 || n == theNode2 );
769     if ( !isDiag )
770       n4 = n;
771   }
772   // Make an array of nodes to be in a quadrangle
773   int iNode = 0, iFirstDiag = -1;
774   it = tr1->nodesIterator();
775   i=0;
776   while ( i<3 ) {
777     const SMDS_MeshNode * n = cast2Node( it->next() );
778     i++;
779     bool isDiag = ( n == theNode1 || n == theNode2 );
780     if ( isDiag ) {
781       if ( iFirstDiag < 0 )
782         iFirstDiag = iNode;
783       else if ( iNode - iFirstDiag == 1 )
784         theQuadNodes[ iNode++ ] = n4; // insert the 4-th node between diagonal nodes
785     }
786     else if ( n == n4 ) {
787       return false; // tr1 and tr2 should not have all the same nodes
788     }
789     theQuadNodes[ iNode++ ] = n;
790   }
791   if ( iNode == 3 ) // diagonal nodes have 0 and 2 indices
792     theQuadNodes[ iNode ] = n4;
793
794   return true;
795 }
796
797 //=======================================================================
798 //function : DeleteDiag
799 //purpose  : Replace two neighbour triangles sharing theNode1-theNode2 link
800 //           with a quadrangle built on the same 4 nodes.
801 //           Return false if proper faces not found
802 //=======================================================================
803
804 bool SMESH_MeshEditor::DeleteDiag (const SMDS_MeshNode * theNode1,
805                                    const SMDS_MeshNode * theNode2)
806 {
807   myLastCreatedElems.Clear();
808   myLastCreatedNodes.Clear();
809
810   MESSAGE( "::DeleteDiag()" );
811
812   const SMDS_MeshElement *tr1, *tr2;
813   if ( !findTriangles( theNode1, theNode2, tr1, tr2 ))
814     return false;
815
816   const SMDS_VtkFace* F1 = dynamic_cast<const SMDS_VtkFace*>( tr1 );
817   if (!F1) return false;
818   const SMDS_VtkFace* F2 = dynamic_cast<const SMDS_VtkFace*>( tr2 );
819   if (!F2) return false;
820   SMESHDS_Mesh * aMesh = GetMeshDS();
821
822   if ((tr1->GetEntityType() == SMDSEntity_Triangle) &&
823       (tr2->GetEntityType() == SMDSEntity_Triangle)) {
824
825     const SMDS_MeshNode* aNodes [ 4 ];
826     if ( ! getQuadrangleNodes( aNodes, theNode1, theNode2, tr1, tr2 ))
827       return false;
828
829     const SMDS_MeshElement* newElem = 0;
830     newElem = aMesh->AddFace( aNodes[0], aNodes[1], aNodes[2], aNodes[3] );
831     myLastCreatedElems.Append(newElem);
832     AddToSameGroups( newElem, tr1, aMesh );
833     int aShapeId = tr1->getshapeId();
834     if ( aShapeId )
835       {
836         aMesh->SetMeshElementOnShape( newElem, aShapeId );
837       }
838     aMesh->RemoveElement( tr1 );
839     aMesh->RemoveElement( tr2 );
840
841     return true;
842   }
843
844   // check case of quadratic faces
845   if (tr1->GetEntityType() != SMDSEntity_Quad_Triangle)
846     return false;
847   if (tr2->GetEntityType() != SMDSEntity_Quad_Triangle)
848     return false;
849
850   //       5
851   //  1 +--+--+ 2  tr1: (1 2 4 5 9 7) or (2 4 1 9 7 5) or (4 1 2 7 5 9)
852   //    |    /|    tr2: (2 3 4 6 8 9) or (3 4 2 8 9 6) or (4 2 3 9 6 8)
853   //    |   / |
854   //  7 +  +  + 6
855   //    | /9  |
856   //    |/    |
857   //  4 +--+--+ 3
858   //       8
859
860   const SMDS_MeshNode* N1 [6];
861   const SMDS_MeshNode* N2 [6];
862   if(!GetNodesFromTwoTria(tr1,tr2,N1,N2))
863     return false;
864   // now we receive following N1 and N2 (using numeration as above image)
865   // tria1 : (1 2 4 5 9 7)  and  tria2 : (3 4 2 8 9 6)
866   // i.e. first nodes from both arrays determ new diagonal
867
868   const SMDS_MeshNode* aNodes[8];
869   aNodes[0] = N1[0];
870   aNodes[1] = N1[1];
871   aNodes[2] = N2[0];
872   aNodes[3] = N2[1];
873   aNodes[4] = N1[3];
874   aNodes[5] = N2[5];
875   aNodes[6] = N2[3];
876   aNodes[7] = N1[5];
877
878   const SMDS_MeshElement* newElem = 0;
879   newElem = aMesh->AddFace( aNodes[0], aNodes[1], aNodes[2], aNodes[3],
880                             aNodes[4], aNodes[5], aNodes[6], aNodes[7]);
881   myLastCreatedElems.Append(newElem);
882   AddToSameGroups( newElem, tr1, aMesh );
883   int aShapeId = tr1->getshapeId();
884   if ( aShapeId )
885     {
886       aMesh->SetMeshElementOnShape( newElem, aShapeId );
887     }
888   aMesh->RemoveElement( tr1 );
889   aMesh->RemoveElement( tr2 );
890
891   // remove middle node (9)
892   GetMeshDS()->RemoveNode( N1[4] );
893
894   return true;
895 }
896
897 //=======================================================================
898 //function : Reorient
899 //purpose  : Reverse theElement orientation
900 //=======================================================================
901
902 bool SMESH_MeshEditor::Reorient (const SMDS_MeshElement * theElem)
903 {
904   MESSAGE("Reorient");
905   myLastCreatedElems.Clear();
906   myLastCreatedNodes.Clear();
907
908   if (!theElem)
909     return false;
910   SMDS_ElemIteratorPtr it = theElem->nodesIterator();
911   if ( !it || !it->more() )
912     return false;
913
914   switch ( theElem->GetType() ) {
915
916   case SMDSAbs_Edge:
917   case SMDSAbs_Face: {
918     if(!theElem->IsQuadratic()) {
919       int i = theElem->NbNodes();
920       vector<const SMDS_MeshNode*> aNodes( i );
921       while ( it->more() )
922         aNodes[ --i ]= static_cast<const SMDS_MeshNode*>( it->next() );
923       return GetMeshDS()->ChangeElementNodes( theElem, &aNodes[0], theElem->NbNodes() );
924     }
925     else {
926       // quadratic elements
927       if(theElem->GetType()==SMDSAbs_Edge) {
928         vector<const SMDS_MeshNode*> aNodes(3);
929         aNodes[1]= static_cast<const SMDS_MeshNode*>( it->next() );
930         aNodes[0]= static_cast<const SMDS_MeshNode*>( it->next() );
931         aNodes[2]= static_cast<const SMDS_MeshNode*>( it->next() );
932         return GetMeshDS()->ChangeElementNodes( theElem, &aNodes[0], 3 );
933       }
934       else {
935         int nbn = theElem->NbNodes();
936         vector<const SMDS_MeshNode*> aNodes(nbn);
937         aNodes[0]= static_cast<const SMDS_MeshNode*>( it->next() );
938         int i=1;
939         for(; i<nbn/2; i++) {
940           aNodes[nbn/2-i]= static_cast<const SMDS_MeshNode*>( it->next() );
941         }
942         for(i=0; i<nbn/2; i++) {
943           aNodes[nbn-i-1]= static_cast<const SMDS_MeshNode*>( it->next() );
944         }
945         return GetMeshDS()->ChangeElementNodes( theElem, &aNodes[0], nbn );
946       }
947     }
948   }
949   case SMDSAbs_Volume: {
950     if (theElem->IsPoly()) {
951       // TODO reorient vtk polyhedron
952       MESSAGE("reorient vtk polyhedron ?");
953       const SMDS_VtkVolume* aPolyedre =
954         dynamic_cast<const SMDS_VtkVolume*>( theElem );
955       if (!aPolyedre) {
956         MESSAGE("Warning: bad volumic element");
957         return false;
958       }
959
960       int nbFaces = aPolyedre->NbFaces();
961       vector<const SMDS_MeshNode *> poly_nodes;
962       vector<int> quantities (nbFaces);
963
964       // reverse each face of the polyedre
965       for (int iface = 1; iface <= nbFaces; iface++) {
966         int inode, nbFaceNodes = aPolyedre->NbFaceNodes(iface);
967         quantities[iface - 1] = nbFaceNodes;
968
969         for (inode = nbFaceNodes; inode >= 1; inode--) {
970           const SMDS_MeshNode* curNode = aPolyedre->GetFaceNode(iface, inode);
971           poly_nodes.push_back(curNode);
972         }
973       }
974
975       return GetMeshDS()->ChangePolyhedronNodes( theElem, poly_nodes, quantities );
976
977     }
978     else {
979       SMDS_VolumeTool vTool;
980       if ( !vTool.Set( theElem ))
981         return false;
982       vTool.Inverse();
983       MESSAGE("ChangeElementNodes reorient: check vTool.Inverse");
984       return GetMeshDS()->ChangeElementNodes( theElem, vTool.GetNodes(), vTool.NbNodes() );
985     }
986   }
987   default:;
988   }
989
990   return false;
991 }
992
993 //=======================================================================
994 //function : getBadRate
995 //purpose  :
996 //=======================================================================
997
998 static double getBadRate (const SMDS_MeshElement*               theElem,
999                           SMESH::Controls::NumericalFunctorPtr& theCrit)
1000 {
1001   SMESH::Controls::TSequenceOfXYZ P;
1002   if ( !theElem || !theCrit->GetPoints( theElem, P ))
1003     return 1e100;
1004   return theCrit->GetBadRate( theCrit->GetValue( P ), theElem->NbNodes() );
1005   //return theCrit->GetBadRate( theCrit->GetValue( theElem->GetID() ), theElem->NbNodes() );
1006 }
1007
1008 //=======================================================================
1009 //function : QuadToTri
1010 //purpose  : Cut quadrangles into triangles.
1011 //           theCrit is used to select a diagonal to cut
1012 //=======================================================================
1013
1014 bool SMESH_MeshEditor::QuadToTri (TIDSortedElemSet &                   theElems,
1015                                   SMESH::Controls::NumericalFunctorPtr theCrit)
1016 {
1017   myLastCreatedElems.Clear();
1018   myLastCreatedNodes.Clear();
1019
1020   MESSAGE( "::QuadToTri()" );
1021
1022   if ( !theCrit.get() )
1023     return false;
1024
1025   SMESHDS_Mesh * aMesh = GetMeshDS();
1026
1027   Handle(Geom_Surface) surface;
1028   SMESH_MesherHelper   helper( *GetMesh() );
1029
1030   TIDSortedElemSet::iterator itElem;
1031   for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
1032     const SMDS_MeshElement* elem = *itElem;
1033     if ( !elem || elem->GetType() != SMDSAbs_Face )
1034       continue;
1035     if ( elem->NbNodes() != ( elem->IsQuadratic() ? 8 : 4 ))
1036       continue;
1037
1038     // retrieve element nodes
1039     const SMDS_MeshNode* aNodes [8];
1040     SMDS_ElemIteratorPtr itN = elem->nodesIterator();
1041     int i = 0;
1042     while ( itN->more() )
1043       aNodes[ i++ ] = static_cast<const SMDS_MeshNode*>( itN->next() );
1044
1045     // compare two sets of possible triangles
1046     double aBadRate1, aBadRate2; // to what extent a set is bad
1047     SMDS_FaceOfNodes tr1 ( aNodes[0], aNodes[1], aNodes[2] );
1048     SMDS_FaceOfNodes tr2 ( aNodes[2], aNodes[3], aNodes[0] );
1049     aBadRate1 = getBadRate( &tr1, theCrit ) + getBadRate( &tr2, theCrit );
1050
1051     SMDS_FaceOfNodes tr3 ( aNodes[1], aNodes[2], aNodes[3] );
1052     SMDS_FaceOfNodes tr4 ( aNodes[3], aNodes[0], aNodes[1] );
1053     aBadRate2 = getBadRate( &tr3, theCrit ) + getBadRate( &tr4, theCrit );
1054
1055     int aShapeId = FindShape( elem );
1056     const SMDS_MeshElement* newElem1 = 0;
1057     const SMDS_MeshElement* newElem2 = 0;
1058
1059     if( !elem->IsQuadratic() ) {
1060
1061       // split liner quadrangle
1062       if ( aBadRate1 <= aBadRate2 ) {
1063         // tr1 + tr2 is better
1064         newElem1 = aMesh->AddFace( aNodes[2], aNodes[3], aNodes[0] );
1065         newElem2 = aMesh->AddFace( aNodes[2], aNodes[0], aNodes[1] );
1066       }
1067       else {
1068         // tr3 + tr4 is better
1069         newElem1 = aMesh->AddFace( aNodes[3], aNodes[0], aNodes[1] );
1070         newElem2 = aMesh->AddFace( aNodes[3], aNodes[1], aNodes[2] );
1071       }
1072     }
1073     else {
1074
1075       // split quadratic quadrangle
1076
1077       // get surface elem is on
1078       if ( aShapeId != helper.GetSubShapeID() ) {
1079         surface.Nullify();
1080         TopoDS_Shape shape;
1081         if ( aShapeId > 0 )
1082           shape = aMesh->IndexToShape( aShapeId );
1083         if ( !shape.IsNull() && shape.ShapeType() == TopAbs_FACE ) {
1084           TopoDS_Face face = TopoDS::Face( shape );
1085           surface = BRep_Tool::Surface( face );
1086           if ( !surface.IsNull() )
1087             helper.SetSubShape( shape );
1088         }
1089       }
1090       // get elem nodes
1091       const SMDS_MeshNode* aNodes [8];
1092       const SMDS_MeshNode* inFaceNode = 0;
1093       SMDS_ElemIteratorPtr itN = elem->nodesIterator();
1094       int i = 0;
1095       while ( itN->more() ) {
1096         aNodes[ i++ ] = static_cast<const SMDS_MeshNode*>( itN->next() );
1097         if ( !inFaceNode && helper.GetNodeUVneedInFaceNode() &&
1098              aNodes[ i-1 ]->GetPosition()->GetTypeOfPosition() == SMDS_TOP_FACE )
1099         {
1100           inFaceNode = aNodes[ i-1 ];
1101         }
1102       }
1103       // find middle point for (0,1,2,3)
1104       // and create a node in this point;
1105       gp_XYZ p( 0,0,0 );
1106       if ( surface.IsNull() ) {
1107         for(i=0; i<4; i++)
1108           p += gp_XYZ(aNodes[i]->X(), aNodes[i]->Y(), aNodes[i]->Z() );
1109         p /= 4;
1110       }
1111       else {
1112         TopoDS_Face face = TopoDS::Face( helper.GetSubShape() );
1113         gp_XY uv( 0,0 );
1114         for(i=0; i<4; i++)
1115           uv += helper.GetNodeUV( face, aNodes[i], inFaceNode );
1116         uv /= 4.;
1117         p = surface->Value( uv.X(), uv.Y() ).XYZ();
1118       }
1119       const SMDS_MeshNode* newN = aMesh->AddNode( p.X(), p.Y(), p.Z() );
1120       myLastCreatedNodes.Append(newN);
1121
1122       // create a new element
1123       const SMDS_MeshNode* N[6];
1124       if ( aBadRate1 <= aBadRate2 ) {
1125         N[0] = aNodes[0];
1126         N[1] = aNodes[1];
1127         N[2] = aNodes[2];
1128         N[3] = aNodes[4];
1129         N[4] = aNodes[5];
1130         N[5] = newN;
1131         newElem1 = aMesh->AddFace(aNodes[2], aNodes[3], aNodes[0],
1132                                   aNodes[6], aNodes[7], newN );
1133         newElem2 = aMesh->AddFace(aNodes[2], aNodes[0], aNodes[1],
1134                                   newN,      aNodes[4], aNodes[5] );
1135       }
1136       else {
1137         N[0] = aNodes[1];
1138         N[1] = aNodes[2];
1139         N[2] = aNodes[3];
1140         N[3] = aNodes[5];
1141         N[4] = aNodes[6];
1142         N[5] = newN;
1143         newElem1 = aMesh->AddFace(aNodes[3], aNodes[0], aNodes[1],
1144                                   aNodes[7], aNodes[4], newN );
1145         newElem2 = aMesh->AddFace(aNodes[3], aNodes[1], aNodes[2],
1146                                   newN,      aNodes[5], aNodes[6] );
1147       }
1148     } // quadratic case
1149
1150     // care of a new element
1151
1152     myLastCreatedElems.Append(newElem1);
1153     myLastCreatedElems.Append(newElem2);
1154     AddToSameGroups( newElem1, elem, aMesh );
1155     AddToSameGroups( newElem2, elem, aMesh );
1156
1157     // put a new triangle on the same shape
1158     if ( aShapeId )
1159       {
1160         aMesh->SetMeshElementOnShape( newElem1, aShapeId );
1161         aMesh->SetMeshElementOnShape( newElem2, aShapeId );
1162       }
1163     aMesh->RemoveElement( elem );
1164   }
1165   return true;
1166 }
1167
1168 //=======================================================================
1169 //function : BestSplit
1170 //purpose  : Find better diagonal for cutting.
1171 //=======================================================================
1172
1173 int SMESH_MeshEditor::BestSplit (const SMDS_MeshElement*              theQuad,
1174                                  SMESH::Controls::NumericalFunctorPtr theCrit)
1175 {
1176   myLastCreatedElems.Clear();
1177   myLastCreatedNodes.Clear();
1178
1179   if (!theCrit.get())
1180     return -1;
1181
1182   if (!theQuad || theQuad->GetType() != SMDSAbs_Face )
1183     return -1;
1184
1185   if( theQuad->NbNodes()==4 ||
1186       (theQuad->NbNodes()==8 && theQuad->IsQuadratic()) ) {
1187
1188     // retrieve element nodes
1189     const SMDS_MeshNode* aNodes [4];
1190     SMDS_ElemIteratorPtr itN = theQuad->nodesIterator();
1191     int i = 0;
1192     //while (itN->more())
1193     while (i<4) {
1194       aNodes[ i++ ] = static_cast<const SMDS_MeshNode*>( itN->next() );
1195     }
1196     // compare two sets of possible triangles
1197     double aBadRate1, aBadRate2; // to what extent a set is bad
1198     SMDS_FaceOfNodes tr1 ( aNodes[0], aNodes[1], aNodes[2] );
1199     SMDS_FaceOfNodes tr2 ( aNodes[2], aNodes[3], aNodes[0] );
1200     aBadRate1 = getBadRate( &tr1, theCrit ) + getBadRate( &tr2, theCrit );
1201
1202     SMDS_FaceOfNodes tr3 ( aNodes[1], aNodes[2], aNodes[3] );
1203     SMDS_FaceOfNodes tr4 ( aNodes[3], aNodes[0], aNodes[1] );
1204     aBadRate2 = getBadRate( &tr3, theCrit ) + getBadRate( &tr4, theCrit );
1205
1206     if (aBadRate1 <= aBadRate2) // tr1 + tr2 is better
1207       return 1; // diagonal 1-3
1208
1209     return 2; // diagonal 2-4
1210   }
1211   return -1;
1212 }
1213
1214 namespace
1215 {
1216   // Methods of splitting volumes into tetra
1217
1218   const int theHexTo5_1[5*4+1] =
1219     {
1220       0, 1, 2, 5,    0, 4, 5, 7,     0, 2, 3, 7,    2, 5, 6, 7,     0, 5, 2, 7,   -1
1221     };
1222   const int theHexTo5_2[5*4+1] =
1223     {
1224       1, 2, 3, 6,    1, 4, 5, 6,     0, 1, 3, 4,    3, 4, 6, 7,     1, 3, 4, 6,   -1
1225     };
1226   const int* theHexTo5[2] = { theHexTo5_1, theHexTo5_2 };
1227
1228   const int theHexTo6_1[6*4+1] =
1229     {
1230       1, 5, 6, 0,    0, 1, 2, 6,     0, 4, 5, 6,    0, 4, 6, 7,     0, 2, 3, 6,   0, 3, 7, 6,  -1
1231     };
1232   const int theHexTo6_2[6*4+1] =
1233     {
1234       2, 6, 7, 1,    1, 2, 3, 7,     1, 5, 6, 7,    1, 5, 7, 4,     1, 3, 0, 7,   1, 0, 4, 7,  -1
1235     };
1236   const int theHexTo6_3[6*4+1] =
1237     {
1238       3, 7, 4, 2,    2, 3, 0, 4,     2, 6, 7, 4,    2, 6, 4, 5,     2, 0, 1, 4,   2, 1, 5, 4,  -1
1239     };
1240   const int theHexTo6_4[6*4+1] =
1241     {
1242       0, 4, 5, 3,    3, 0, 1, 5,     3, 7, 4, 5,    3, 7, 5, 6,     3, 1, 2, 5,   3, 2, 6, 5,  -1
1243     };
1244   const int* theHexTo6[4] = { theHexTo6_1, theHexTo6_2, theHexTo6_3, theHexTo6_4 };
1245
1246   const int thePyraTo2_1[2*4+1] =
1247     {
1248       0, 1, 2, 4,    0, 2, 3, 4,   -1
1249     };
1250   const int thePyraTo2_2[2*4+1] =
1251     {
1252       1, 2, 3, 4,    1, 3, 0, 4,   -1
1253     };
1254   const int* thePyraTo2[2] = { thePyraTo2_1, thePyraTo2_2 };
1255
1256   const int thePentaTo3_1[3*4+1] =
1257     {
1258       0, 1, 2, 3,    1, 3, 4, 2,     2, 3, 4, 5,    -1
1259     };
1260   const int thePentaTo3_2[3*4+1] =
1261     {
1262       1, 2, 0, 4,    2, 4, 5, 0,     0, 4, 5, 3,    -1
1263     };
1264   const int thePentaTo3_3[3*4+1] =
1265     {
1266       2, 0, 1, 5,    0, 5, 3, 1,     1, 5, 3, 4,    -1
1267     };
1268   const int thePentaTo3_4[3*4+1] =
1269     {
1270       0, 1, 2, 3,    1, 3, 4, 5,     2, 3, 1, 5,    -1
1271     };
1272   const int thePentaTo3_5[3*4+1] =
1273     {
1274       1, 2, 0, 4,    2, 4, 5, 3,     0, 4, 2, 3,    -1
1275     };
1276   const int thePentaTo3_6[3*4+1] =
1277     {
1278       2, 0, 1, 5,    0, 5, 3, 4,     1, 5, 0, 4,    -1
1279     };
1280   const int* thePentaTo3[6] = { thePentaTo3_1, thePentaTo3_2, thePentaTo3_3,
1281                                 thePentaTo3_4, thePentaTo3_5, thePentaTo3_6 };
1282
1283   struct TTriangleFacet //!< stores indices of three nodes of tetra facet
1284   {
1285     int _n1, _n2, _n3;
1286     TTriangleFacet(int n1, int n2, int n3): _n1(n1), _n2(n2), _n3(n3) {}
1287     bool contains(int n) const { return ( n == _n1 || n == _n2 || n == _n3 ); }
1288     bool hasAdjacentTetra( const SMDS_MeshElement* elem ) const;
1289   };
1290   struct TSplitMethod
1291   {
1292     int        _nbTetra;
1293     const int* _connectivity; //!< foursomes of tetra connectivy finished by -1
1294     bool       _baryNode;     //!< additional node is to be created at cell barycenter
1295     bool       _ownConn;      //!< to delete _connectivity in destructor
1296     map<int, const SMDS_MeshNode*> _faceBaryNode; //!< map face index to node at BC of face
1297
1298     TSplitMethod( int nbTet=0, const int* conn=0, bool addNode=false)
1299       : _nbTetra(nbTet), _connectivity(conn), _baryNode(addNode), _ownConn(false) {}
1300     ~TSplitMethod() { if ( _ownConn ) delete [] _connectivity; _connectivity = 0; }
1301     bool hasFacet( const TTriangleFacet& facet ) const
1302     {
1303       const int* tetConn = _connectivity;
1304       for ( ; tetConn[0] >= 0; tetConn += 4 )
1305         if (( facet.contains( tetConn[0] ) +
1306               facet.contains( tetConn[1] ) +
1307               facet.contains( tetConn[2] ) +
1308               facet.contains( tetConn[3] )) == 3 )
1309           return true;
1310       return false;
1311     }
1312   };
1313
1314   //=======================================================================
1315   /*!
1316    * \brief return TSplitMethod for the given element
1317    */
1318   //=======================================================================
1319
1320   TSplitMethod getSplitMethod( SMDS_VolumeTool& vol, const int theMethodFlags)
1321   {
1322     const int iQ = vol.Element()->IsQuadratic() ? 2 : 1;
1323
1324     // at HEXA_TO_24 method, each face of volume is split into triangles each based on
1325     // an edge and a face barycenter; tertaherdons are based on triangles and
1326     // a volume barycenter
1327     const bool is24TetMode = ( theMethodFlags == SMESH_MeshEditor::HEXA_TO_24 );
1328
1329     // Find out how adjacent volumes are split
1330
1331     vector < list< TTriangleFacet > > triaSplitsByFace( vol.NbFaces() ); // splits of each side
1332     int hasAdjacentSplits = 0, maxTetConnSize = 0;
1333     for ( int iF = 0; iF < vol.NbFaces(); ++iF )
1334     {
1335       int nbNodes = vol.NbFaceNodes( iF ) / iQ;
1336       maxTetConnSize += 4 * ( nbNodes - (is24TetMode ? 0 : 2));
1337       if ( nbNodes < 4 ) continue;
1338
1339       list< TTriangleFacet >& triaSplits = triaSplitsByFace[ iF ];
1340       const int* nInd = vol.GetFaceNodesIndices( iF );
1341       if ( nbNodes == 4 )
1342       {
1343         TTriangleFacet t012( nInd[0*iQ], nInd[1*iQ], nInd[2*iQ] );
1344         TTriangleFacet t123( nInd[1*iQ], nInd[2*iQ], nInd[3*iQ] );
1345         if      ( t012.hasAdjacentTetra( vol.Element() )) triaSplits.push_back( t012 );
1346         else if ( t123.hasAdjacentTetra( vol.Element() )) triaSplits.push_back( t123 );
1347       }
1348       else
1349       {
1350         int iCom = 0; // common node of triangle faces to split into
1351         for ( int iVar = 0; iVar < nbNodes; ++iVar, ++iCom )
1352         {
1353           TTriangleFacet t012( nInd[ iQ * ( iCom             )],
1354                                nInd[ iQ * ( (iCom+1)%nbNodes )],
1355                                nInd[ iQ * ( (iCom+2)%nbNodes )]);
1356           TTriangleFacet t023( nInd[ iQ * ( iCom             )],
1357                                nInd[ iQ * ( (iCom+2)%nbNodes )],
1358                                nInd[ iQ * ( (iCom+3)%nbNodes )]);
1359           if ( t012.hasAdjacentTetra( vol.Element() ) && t023.hasAdjacentTetra( vol.Element() ))
1360           {
1361             triaSplits.push_back( t012 );
1362             triaSplits.push_back( t023 );
1363             break;
1364           }
1365         }
1366       }
1367       if ( !triaSplits.empty() )
1368         hasAdjacentSplits = true;
1369     }
1370
1371     // Among variants of split method select one compliant with adjacent volumes
1372
1373     TSplitMethod method;
1374     if ( !vol.Element()->IsPoly() && !is24TetMode )
1375     {
1376       int nbVariants = 2, nbTet = 0;
1377       const int** connVariants = 0;
1378       switch ( vol.Element()->GetEntityType() )
1379       {
1380       case SMDSEntity_Hexa:
1381       case SMDSEntity_Quad_Hexa:
1382         if ( theMethodFlags == SMESH_MeshEditor::HEXA_TO_5 )
1383           connVariants = theHexTo5, nbTet = 5;
1384         else
1385           connVariants = theHexTo6, nbTet = 6, nbVariants = 4;
1386         break;
1387       case SMDSEntity_Pyramid:
1388       case SMDSEntity_Quad_Pyramid:
1389         connVariants = thePyraTo2;  nbTet = 2;
1390         break;
1391       case SMDSEntity_Penta:
1392       case SMDSEntity_Quad_Penta:
1393         connVariants = thePentaTo3; nbTet = 3; nbVariants = 6;
1394         break;
1395       default:
1396         nbVariants = 0;
1397       }
1398       for ( int variant = 0; variant < nbVariants && method._nbTetra == 0; ++variant )
1399       {
1400         // check method compliancy with adjacent tetras,
1401         // all found splits must be among facets of tetras described by this method
1402         method = TSplitMethod( nbTet, connVariants[variant] );
1403         if ( hasAdjacentSplits && method._nbTetra > 0 )
1404         {
1405           bool facetCreated = true;
1406           for ( int iF = 0; facetCreated && iF < triaSplitsByFace.size(); ++iF )
1407           {
1408             list< TTriangleFacet >::const_iterator facet = triaSplitsByFace[iF].begin();
1409             for ( ; facetCreated && facet != triaSplitsByFace[iF].end(); ++facet )
1410               facetCreated = method.hasFacet( *facet );
1411           }
1412           if ( !facetCreated )
1413             method = TSplitMethod(0); // incompatible method
1414         }
1415       }
1416     }
1417     if ( method._nbTetra < 1 )
1418     {
1419       // No standard method is applicable, use a generic solution:
1420       // each facet of a volume is split into triangles and
1421       // each of triangles and a volume barycenter form a tetrahedron.
1422
1423       int* connectivity = new int[ maxTetConnSize + 1 ];
1424       method._connectivity = connectivity;
1425       method._ownConn = true;
1426       method._baryNode = true;
1427
1428       int connSize = 0;
1429       int baryCenInd = vol.NbNodes();
1430       for ( int iF = 0; iF < vol.NbFaces(); ++iF )
1431       {
1432         const int nbNodes = vol.NbFaceNodes( iF ) / iQ;
1433         const int*   nInd = vol.GetFaceNodesIndices( iF );
1434         // find common node of triangle facets of tetra to create
1435         int iCommon = 0; // index in linear numeration
1436         const list< TTriangleFacet >& triaSplits = triaSplitsByFace[ iF ];
1437         if ( !triaSplits.empty() )
1438         {
1439           // by found facets
1440           const TTriangleFacet* facet = &triaSplits.front();
1441           for ( ; iCommon < nbNodes-1 ; ++iCommon )
1442             if ( facet->contains( nInd[ iQ * iCommon ]) &&
1443                  facet->contains( nInd[ iQ * ((iCommon+2)%nbNodes) ]))
1444               break;
1445         }
1446         else if ( nbNodes > 3 && !is24TetMode )
1447         {
1448           // find the best method of splitting into triangles by aspect ratio
1449           SMESH::Controls::NumericalFunctorPtr aspectRatio( new SMESH::Controls::AspectRatio);
1450           map< double, int > badness2iCommon;
1451           const SMDS_MeshNode** nodes = vol.GetFaceNodes( iF );
1452           int nbVariants = ( nbNodes == 4 ? 2 : nbNodes );
1453           for ( int iVar = 0; iVar < nbVariants; ++iVar, ++iCommon )
1454             for ( int iLast = iCommon+2; iLast < iCommon+nbNodes; ++iLast )
1455             {
1456               SMDS_FaceOfNodes tria ( nodes[ iQ*( iCommon         )],
1457                                       nodes[ iQ*((iLast-1)%nbNodes)],
1458                                       nodes[ iQ*((iLast  )%nbNodes)]);
1459               double badness = getBadRate( &tria, aspectRatio );
1460               badness2iCommon.insert( make_pair( badness, iCommon ));
1461             }
1462           // use iCommon with lowest badness
1463           iCommon = badness2iCommon.begin()->second;
1464         }
1465         if ( iCommon >= nbNodes )
1466           iCommon = 0; // something wrong
1467
1468         // fill connectivity of tetrahedra based on a current face
1469         int nbTet = nbNodes - 2;
1470         if ( is24TetMode && nbNodes > 3 && triaSplits.empty())
1471         {
1472           method._faceBaryNode.insert( make_pair( iF, (const SMDS_MeshNode*)0 ));
1473           int faceBaryCenInd = baryCenInd + method._faceBaryNode.size();
1474           nbTet = nbNodes;
1475           for ( int i = 0; i < nbTet; ++i )
1476           {
1477             int i1 = i, i2 = (i+1) % nbNodes;
1478             if ( !vol.IsFaceExternal( iF )) swap( i1, i2 );
1479             connectivity[ connSize++ ] = nInd[ iQ * i1 ];
1480             connectivity[ connSize++ ] = nInd[ iQ * i2 ];
1481             connectivity[ connSize++ ] = faceBaryCenInd;
1482             connectivity[ connSize++ ] = baryCenInd;
1483           }
1484         }
1485         else
1486         {
1487           for ( int i = 0; i < nbTet; ++i )
1488           {
1489             int i1 = (iCommon+1+i) % nbNodes, i2 = (iCommon+2+i) % nbNodes;
1490             if ( !vol.IsFaceExternal( iF )) swap( i1, i2 );
1491             connectivity[ connSize++ ] = nInd[ iQ * iCommon ];
1492             connectivity[ connSize++ ] = nInd[ iQ * i1 ];
1493             connectivity[ connSize++ ] = nInd[ iQ * i2 ];
1494             connectivity[ connSize++ ] = baryCenInd;
1495           }
1496         }
1497         method._nbTetra += nbTet;
1498       }
1499       connectivity[ connSize++ ] = -1;
1500     }
1501     return method;
1502   }
1503   //================================================================================
1504   /*!
1505    * \brief Check if there is a tetraherdon adjacent to the given element via this facet
1506    */
1507   //================================================================================
1508
1509   bool TTriangleFacet::hasAdjacentTetra( const SMDS_MeshElement* elem ) const
1510   {
1511     // find the tetrahedron including the three nodes of facet
1512     const SMDS_MeshNode* n1 = elem->GetNode(_n1);
1513     const SMDS_MeshNode* n2 = elem->GetNode(_n2);
1514     const SMDS_MeshNode* n3 = elem->GetNode(_n3);
1515     SMDS_ElemIteratorPtr volIt1 = n1->GetInverseElementIterator(SMDSAbs_Volume);
1516     while ( volIt1->more() )
1517     {
1518       const SMDS_MeshElement* v = volIt1->next();
1519       if ( v->GetEntityType() != ( v->IsQuadratic() ? SMDSEntity_Quad_Tetra : SMDSEntity_Tetra ))
1520         continue;
1521       SMDS_ElemIteratorPtr volIt2 = n2->GetInverseElementIterator(SMDSAbs_Volume);
1522       while ( volIt2->more() )
1523         if ( v != volIt2->next() )
1524           continue;
1525       SMDS_ElemIteratorPtr volIt3 = n3->GetInverseElementIterator(SMDSAbs_Volume);
1526       while ( volIt3->more() )
1527         if ( v == volIt3->next() )
1528           return true;
1529     }
1530     return false;
1531   }
1532
1533   //=======================================================================
1534   /*!
1535    * \brief A key of a face of volume
1536    */
1537   //=======================================================================
1538
1539   struct TVolumeFaceKey: pair< int, pair< int, int> >
1540   {
1541     TVolumeFaceKey( SMDS_VolumeTool& vol, int iF )
1542     {
1543       TIDSortedNodeSet sortedNodes;
1544       const int iQ = vol.Element()->IsQuadratic() ? 2 : 1;
1545       int nbNodes = vol.NbFaceNodes( iF );
1546       const SMDS_MeshNode** fNodes = vol.GetFaceNodes( iF );
1547       for ( int i = 0; i < nbNodes; i += iQ )
1548         sortedNodes.insert( fNodes[i] );
1549       TIDSortedNodeSet::iterator n = sortedNodes.begin();
1550       first = (*(n++))->GetID();
1551       second.first = (*(n++))->GetID();
1552       second.second = (*(n++))->GetID();
1553     }
1554   };
1555 } // namespace
1556
1557 //=======================================================================
1558 //function : SplitVolumesIntoTetra
1559 //purpose  : Split volumic elements into tetrahedra.
1560 //=======================================================================
1561
1562 void SMESH_MeshEditor::SplitVolumesIntoTetra (const TIDSortedElemSet & theElems,
1563                                               const int                theMethodFlags)
1564 {
1565   // std-like iterator on coordinates of nodes of mesh element
1566   typedef SMDS_StdIterator< SMESH_TNodeXYZ, SMDS_ElemIteratorPtr > NXyzIterator;
1567   NXyzIterator xyzEnd;
1568
1569   SMDS_VolumeTool    volTool;
1570   SMESH_MesherHelper helper( *GetMesh());
1571
1572   SMESHDS_SubMesh* subMesh = 0;//GetMeshDS()->MeshElements(1);
1573   SMESHDS_SubMesh* fSubMesh = 0;//subMesh;
1574   
1575   SMESH_SequenceOfElemPtr newNodes, newElems;
1576
1577   // map face of volume to it's baricenrtic node
1578   map< TVolumeFaceKey, const SMDS_MeshNode* > volFace2BaryNode;
1579   double bc[3];
1580
1581   TIDSortedElemSet::const_iterator elem = theElems.begin();
1582   for ( ; elem != theElems.end(); ++elem )
1583   {
1584     SMDSAbs_EntityType geomType = (*elem)->GetEntityType();
1585     if ( geomType <= SMDSEntity_Quad_Tetra )
1586       continue; // tetra or face or ...
1587
1588     if ( !volTool.Set( *elem )) continue; // not volume? strange...
1589
1590     TSplitMethod splitMethod = getSplitMethod( volTool, theMethodFlags );
1591     if ( splitMethod._nbTetra < 1 ) continue;
1592
1593     // find submesh to add new tetras to
1594     if ( !subMesh || !subMesh->Contains( *elem ))
1595     {
1596       int shapeID = FindShape( *elem );
1597       helper.SetSubShape( shapeID ); // helper will add tetras to the found submesh
1598       subMesh = GetMeshDS()->MeshElements( shapeID );
1599     }
1600     int iQ;
1601     if ( (*elem)->IsQuadratic() )
1602     {
1603       iQ = 2;
1604       // add quadratic links to the helper
1605       for ( int iF = 0; iF < volTool.NbFaces(); ++iF )
1606       {
1607         const SMDS_MeshNode** fNodes = volTool.GetFaceNodes( iF );
1608         for ( int iN = 0; iN < volTool.NbFaceNodes( iF ); iN += iQ )
1609           helper.AddTLinkNode( fNodes[iF], fNodes[iF+2], fNodes[iF+1] );
1610       }
1611       helper.SetIsQuadratic( true );
1612     }
1613     else
1614     {
1615       iQ = 1;
1616       helper.SetIsQuadratic( false );
1617     }
1618     vector<const SMDS_MeshNode*> nodes( (*elem)->begin_nodes(), (*elem)->end_nodes() );
1619     if ( splitMethod._baryNode )
1620     {
1621       // make a node at barycenter
1622       volTool.GetBaryCenter( bc[0], bc[1], bc[2] );
1623       SMDS_MeshNode* gcNode = helper.AddNode( bc[0], bc[1], bc[2] );
1624       nodes.push_back( gcNode );
1625       newNodes.Append( gcNode );
1626     }
1627     if ( !splitMethod._faceBaryNode.empty() )
1628     {
1629       // make or find baricentric nodes of faces
1630       map<int, const SMDS_MeshNode*>::iterator iF_n = splitMethod._faceBaryNode.begin();
1631       for ( ; iF_n != splitMethod._faceBaryNode.end(); ++iF_n )
1632       {
1633         map< TVolumeFaceKey, const SMDS_MeshNode* >::iterator f_n =
1634           volFace2BaryNode.insert
1635           ( make_pair( TVolumeFaceKey( volTool,iF_n->first ), (const SMDS_MeshNode*)0) ).first;
1636         if ( !f_n->second )
1637         {
1638           volTool.GetFaceBaryCenter( iF_n->first, bc[0], bc[1], bc[2] );
1639           newNodes.Append( f_n->second = helper.AddNode( bc[0], bc[1], bc[2] ));
1640         }
1641         nodes.push_back( iF_n->second = f_n->second );
1642       }
1643     }
1644
1645     // make tetras
1646     helper.SetElementsOnShape( true );
1647     vector<const SMDS_MeshElement* > tetras( splitMethod._nbTetra ); // splits of a volume
1648     const int* tetConn = splitMethod._connectivity;
1649     for ( int i = 0; i < splitMethod._nbTetra; ++i, tetConn += 4 )
1650       newElems.Append( tetras[ i ] = helper.AddVolume( nodes[ tetConn[0] ],
1651                                                        nodes[ tetConn[1] ],
1652                                                        nodes[ tetConn[2] ],
1653                                                        nodes[ tetConn[3] ]));
1654
1655     ReplaceElemInGroups( *elem, tetras, GetMeshDS() );
1656
1657     // Split faces on sides of the split volume
1658
1659     const SMDS_MeshNode** volNodes = volTool.GetNodes();
1660     for ( int iF = 0; iF < volTool.NbFaces(); ++iF )
1661     {
1662       const int nbNodes = volTool.NbFaceNodes( iF ) / iQ;
1663       if ( nbNodes < 4 ) continue;
1664
1665       // find an existing face
1666       vector<const SMDS_MeshNode*> fNodes( volTool.GetFaceNodes( iF ),
1667                                            volTool.GetFaceNodes( iF ) + nbNodes*iQ );
1668       while ( const SMDS_MeshElement* face = GetMeshDS()->FindFace( fNodes ))
1669       {
1670         // make triangles
1671         helper.SetElementsOnShape( false );
1672         vector< const SMDS_MeshElement* > triangles;
1673
1674         map<int, const SMDS_MeshNode*>::iterator iF_n = splitMethod._faceBaryNode.find(iF);
1675         if ( iF_n != splitMethod._faceBaryNode.end() )
1676         {
1677           for ( int iN = 0; iN < nbNodes*iQ; iN += iQ )
1678           {
1679             const SMDS_MeshNode* n1 = fNodes[iN];
1680             const SMDS_MeshNode *n2 = fNodes[(iN+iQ)%nbNodes*iQ];
1681             const SMDS_MeshNode *n3 = iF_n->second;
1682             if ( !volTool.IsFaceExternal( iF ))
1683               swap( n2, n3 );
1684             triangles.push_back( helper.AddFace( n1,n2,n3 ));
1685           }
1686         }
1687         else
1688         {
1689           // among possible triangles create ones discribed by split method
1690           const int* nInd = volTool.GetFaceNodesIndices( iF );
1691           int nbVariants = ( nbNodes == 4 ? 2 : nbNodes );
1692           int iCom = 0; // common node of triangle faces to split into
1693           list< TTriangleFacet > facets;
1694           for ( int iVar = 0; iVar < nbVariants; ++iVar, ++iCom )
1695           {
1696             TTriangleFacet t012( nInd[ iQ * ( iCom                )],
1697                                  nInd[ iQ * ( (iCom+1)%nbNodes )],
1698                                  nInd[ iQ * ( (iCom+2)%nbNodes )]);
1699             TTriangleFacet t023( nInd[ iQ * ( iCom                )],
1700                                  nInd[ iQ * ( (iCom+2)%nbNodes )],
1701                                  nInd[ iQ * ( (iCom+3)%nbNodes )]);
1702             if ( splitMethod.hasFacet( t012 ) && splitMethod.hasFacet( t023 ))
1703             {
1704               facets.push_back( t012 );
1705               facets.push_back( t023 );
1706               for ( int iLast = iCom+4; iLast < iCom+nbNodes; ++iLast )
1707                 facets.push_back( TTriangleFacet( nInd[ iQ * ( iCom             )],
1708                                                   nInd[ iQ * ((iLast-1)%nbNodes )],
1709                                                   nInd[ iQ * ((iLast  )%nbNodes )]));
1710               break;
1711             }
1712           }
1713           list< TTriangleFacet >::iterator facet = facets.begin();
1714           for ( ; facet != facets.end(); ++facet )
1715           {
1716             if ( !volTool.IsFaceExternal( iF ))
1717               swap( facet->_n2, facet->_n3 );
1718             triangles.push_back( helper.AddFace( volNodes[ facet->_n1 ],
1719                                                  volNodes[ facet->_n2 ],
1720                                                  volNodes[ facet->_n3 ]));
1721           }
1722         }
1723         // find submesh to add new triangles in
1724         if ( !fSubMesh || !fSubMesh->Contains( face ))
1725         {
1726           int shapeID = FindShape( face );
1727           fSubMesh = GetMeshDS()->MeshElements( shapeID );
1728         }
1729         for ( int i = 0; i < triangles.size(); ++i )
1730         {
1731           if ( !triangles[i] ) continue;
1732           if ( fSubMesh )
1733             fSubMesh->AddElement( triangles[i]);
1734           newElems.Append( triangles[i] );
1735         }
1736         ReplaceElemInGroups( face, triangles, GetMeshDS() );
1737         GetMeshDS()->RemoveFreeElement( face, fSubMesh, /*fromGroups=*/false );
1738       }
1739
1740     } // loop on volume faces to split them into triangles
1741
1742     GetMeshDS()->RemoveFreeElement( *elem, subMesh, /*fromGroups=*/false );
1743
1744   } // loop on volumes to split
1745
1746   myLastCreatedNodes = newNodes;
1747   myLastCreatedElems = newElems;
1748 }
1749
1750 //=======================================================================
1751 //function : AddToSameGroups
1752 //purpose  : add elemToAdd to the groups the elemInGroups belongs to
1753 //=======================================================================
1754
1755 void SMESH_MeshEditor::AddToSameGroups (const SMDS_MeshElement* elemToAdd,
1756                                         const SMDS_MeshElement* elemInGroups,
1757                                         SMESHDS_Mesh *          aMesh)
1758 {
1759   const set<SMESHDS_GroupBase*>& groups = aMesh->GetGroups();
1760   if (!groups.empty()) {
1761     set<SMESHDS_GroupBase*>::const_iterator grIt = groups.begin();
1762     for ( ; grIt != groups.end(); grIt++ ) {
1763       SMESHDS_Group* group = dynamic_cast<SMESHDS_Group*>( *grIt );
1764       if ( group && group->Contains( elemInGroups ))
1765         group->SMDSGroup().Add( elemToAdd );
1766     }
1767   }
1768 }
1769
1770
1771 //=======================================================================
1772 //function : RemoveElemFromGroups
1773 //purpose  : Remove removeelem to the groups the elemInGroups belongs to
1774 //=======================================================================
1775 void SMESH_MeshEditor::RemoveElemFromGroups (const SMDS_MeshElement* removeelem,
1776                                              SMESHDS_Mesh *          aMesh)
1777 {
1778   const set<SMESHDS_GroupBase*>& groups = aMesh->GetGroups();
1779   if (!groups.empty())
1780   {
1781     set<SMESHDS_GroupBase*>::const_iterator GrIt = groups.begin();
1782     for (; GrIt != groups.end(); GrIt++)
1783     {
1784       SMESHDS_Group* grp = dynamic_cast<SMESHDS_Group*>(*GrIt);
1785       if (!grp || grp->IsEmpty()) continue;
1786       grp->SMDSGroup().Remove(removeelem);
1787     }
1788   }
1789 }
1790
1791 //================================================================================
1792 /*!
1793  * \brief Replace elemToRm by elemToAdd in the all groups
1794  */
1795 //================================================================================
1796
1797 void SMESH_MeshEditor::ReplaceElemInGroups (const SMDS_MeshElement* elemToRm,
1798                                             const SMDS_MeshElement* elemToAdd,
1799                                             SMESHDS_Mesh *          aMesh)
1800 {
1801   const set<SMESHDS_GroupBase*>& groups = aMesh->GetGroups();
1802   if (!groups.empty()) {
1803     set<SMESHDS_GroupBase*>::const_iterator grIt = groups.begin();
1804     for ( ; grIt != groups.end(); grIt++ ) {
1805       SMESHDS_Group* group = dynamic_cast<SMESHDS_Group*>( *grIt );
1806       if ( group && group->SMDSGroup().Remove( elemToRm ) && elemToAdd )
1807         group->SMDSGroup().Add( elemToAdd );
1808     }
1809   }
1810 }
1811
1812 //================================================================================
1813 /*!
1814  * \brief Replace elemToRm by elemToAdd in the all groups
1815  */
1816 //================================================================================
1817
1818 void SMESH_MeshEditor::ReplaceElemInGroups (const SMDS_MeshElement*                elemToRm,
1819                                             const vector<const SMDS_MeshElement*>& elemToAdd,
1820                                             SMESHDS_Mesh *                         aMesh)
1821 {
1822   const set<SMESHDS_GroupBase*>& groups = aMesh->GetGroups();
1823   if (!groups.empty())
1824   {
1825     set<SMESHDS_GroupBase*>::const_iterator grIt = groups.begin();
1826     for ( ; grIt != groups.end(); grIt++ ) {
1827       SMESHDS_Group* group = dynamic_cast<SMESHDS_Group*>( *grIt );
1828       if ( group && group->SMDSGroup().Remove( elemToRm ) )
1829         for ( int i = 0; i < elemToAdd.size(); ++i )
1830           group->SMDSGroup().Add( elemToAdd[ i ] );
1831     }
1832   }
1833 }
1834
1835 //=======================================================================
1836 //function : QuadToTri
1837 //purpose  : Cut quadrangles into triangles.
1838 //           theCrit is used to select a diagonal to cut
1839 //=======================================================================
1840
1841 bool SMESH_MeshEditor::QuadToTri (TIDSortedElemSet & theElems,
1842                                   const bool         the13Diag)
1843 {
1844   myLastCreatedElems.Clear();
1845   myLastCreatedNodes.Clear();
1846
1847   MESSAGE( "::QuadToTri()" );
1848
1849   SMESHDS_Mesh * aMesh = GetMeshDS();
1850
1851   Handle(Geom_Surface) surface;
1852   SMESH_MesherHelper   helper( *GetMesh() );
1853
1854   TIDSortedElemSet::iterator itElem;
1855   for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
1856     const SMDS_MeshElement* elem = *itElem;
1857     if ( !elem || elem->GetType() != SMDSAbs_Face )
1858       continue;
1859     bool isquad = elem->NbNodes()==4 || elem->NbNodes()==8;
1860     if(!isquad) continue;
1861
1862     if(elem->NbNodes()==4) {
1863       // retrieve element nodes
1864       const SMDS_MeshNode* aNodes [4];
1865       SMDS_ElemIteratorPtr itN = elem->nodesIterator();
1866       int i = 0;
1867       while ( itN->more() )
1868         aNodes[ i++ ] = static_cast<const SMDS_MeshNode*>( itN->next() );
1869
1870       int aShapeId = FindShape( elem );
1871       const SMDS_MeshElement* newElem1 = 0;
1872       const SMDS_MeshElement* newElem2 = 0;
1873       if ( the13Diag ) {
1874         newElem1 = aMesh->AddFace( aNodes[2], aNodes[0], aNodes[1] );
1875         newElem2 = aMesh->AddFace( aNodes[2], aNodes[3], aNodes[0] );
1876       }
1877       else {
1878         newElem1 = aMesh->AddFace( aNodes[3], aNodes[0], aNodes[1] );
1879         newElem2 = aMesh->AddFace( aNodes[3], aNodes[1], aNodes[2] );
1880       }
1881       myLastCreatedElems.Append(newElem1);
1882       myLastCreatedElems.Append(newElem2);
1883       // put a new triangle on the same shape and add to the same groups
1884       if ( aShapeId )
1885         {
1886           aMesh->SetMeshElementOnShape( newElem1, aShapeId );
1887           aMesh->SetMeshElementOnShape( newElem2, aShapeId );
1888         }
1889       AddToSameGroups( newElem1, elem, aMesh );
1890       AddToSameGroups( newElem2, elem, aMesh );
1891       //aMesh->RemoveFreeElement(elem, aMesh->MeshElements(aShapeId), true);
1892       aMesh->RemoveElement( elem );
1893     }
1894
1895     // Quadratic quadrangle
1896
1897     if( elem->NbNodes()==8 && elem->IsQuadratic() ) {
1898
1899       // get surface elem is on
1900       int aShapeId = FindShape( elem );
1901       if ( aShapeId != helper.GetSubShapeID() ) {
1902         surface.Nullify();
1903         TopoDS_Shape shape;
1904         if ( aShapeId > 0 )
1905           shape = aMesh->IndexToShape( aShapeId );
1906         if ( !shape.IsNull() && shape.ShapeType() == TopAbs_FACE ) {
1907           TopoDS_Face face = TopoDS::Face( shape );
1908           surface = BRep_Tool::Surface( face );
1909           if ( !surface.IsNull() )
1910             helper.SetSubShape( shape );
1911         }
1912       }
1913
1914       const SMDS_MeshNode* aNodes [8];
1915       const SMDS_MeshNode* inFaceNode = 0;
1916       SMDS_ElemIteratorPtr itN = elem->nodesIterator();
1917       int i = 0;
1918       while ( itN->more() ) {
1919         aNodes[ i++ ] = static_cast<const SMDS_MeshNode*>( itN->next() );
1920         if ( !inFaceNode && helper.GetNodeUVneedInFaceNode() &&
1921              aNodes[ i-1 ]->GetPosition()->GetTypeOfPosition() == SMDS_TOP_FACE )
1922         {
1923           inFaceNode = aNodes[ i-1 ];
1924         }
1925       }
1926
1927       // find middle point for (0,1,2,3)
1928       // and create a node in this point;
1929       gp_XYZ p( 0,0,0 );
1930       if ( surface.IsNull() ) {
1931         for(i=0; i<4; i++)
1932           p += gp_XYZ(aNodes[i]->X(), aNodes[i]->Y(), aNodes[i]->Z() );
1933         p /= 4;
1934       }
1935       else {
1936         TopoDS_Face geomFace = TopoDS::Face( helper.GetSubShape() );
1937         gp_XY uv( 0,0 );
1938         for(i=0; i<4; i++)
1939           uv += helper.GetNodeUV( geomFace, aNodes[i], inFaceNode );
1940         uv /= 4.;
1941         p = surface->Value( uv.X(), uv.Y() ).XYZ();
1942       }
1943       const SMDS_MeshNode* newN = aMesh->AddNode( p.X(), p.Y(), p.Z() );
1944       myLastCreatedNodes.Append(newN);
1945
1946       // create a new element
1947       const SMDS_MeshElement* newElem1 = 0;
1948       const SMDS_MeshElement* newElem2 = 0;
1949       const SMDS_MeshNode* N[6];
1950       if ( the13Diag ) {
1951         N[0] = aNodes[0];
1952         N[1] = aNodes[1];
1953         N[2] = aNodes[2];
1954         N[3] = aNodes[4];
1955         N[4] = aNodes[5];
1956         N[5] = newN;
1957         newElem1 = aMesh->AddFace(aNodes[2], aNodes[3], aNodes[0],
1958                                   aNodes[6], aNodes[7], newN );
1959         newElem2 = aMesh->AddFace(aNodes[2], aNodes[0], aNodes[1],
1960                                   newN,      aNodes[4], aNodes[5] );
1961       }
1962       else {
1963         N[0] = aNodes[1];
1964         N[1] = aNodes[2];
1965         N[2] = aNodes[3];
1966         N[3] = aNodes[5];
1967         N[4] = aNodes[6];
1968         N[5] = newN;
1969         newElem1 = aMesh->AddFace(aNodes[3], aNodes[0], aNodes[1],
1970                                   aNodes[7], aNodes[4], newN );
1971         newElem2 = aMesh->AddFace(aNodes[3], aNodes[1], aNodes[2],
1972                                   newN,      aNodes[5], aNodes[6] );
1973       }
1974       myLastCreatedElems.Append(newElem1);
1975       myLastCreatedElems.Append(newElem2);
1976       // put a new triangle on the same shape and add to the same groups
1977       if ( aShapeId )
1978         {
1979           aMesh->SetMeshElementOnShape( newElem1, aShapeId );
1980           aMesh->SetMeshElementOnShape( newElem2, aShapeId );
1981         }
1982       AddToSameGroups( newElem1, elem, aMesh );
1983       AddToSameGroups( newElem2, elem, aMesh );
1984       aMesh->RemoveElement( elem );
1985     }
1986   }
1987
1988   return true;
1989 }
1990
1991 //=======================================================================
1992 //function : getAngle
1993 //purpose  :
1994 //=======================================================================
1995
1996 double getAngle(const SMDS_MeshElement * tr1,
1997                 const SMDS_MeshElement * tr2,
1998                 const SMDS_MeshNode *    n1,
1999                 const SMDS_MeshNode *    n2)
2000 {
2001   double angle = 2*PI; // bad angle
2002
2003   // get normals
2004   SMESH::Controls::TSequenceOfXYZ P1, P2;
2005   if ( !SMESH::Controls::NumericalFunctor::GetPoints( tr1, P1 ) ||
2006        !SMESH::Controls::NumericalFunctor::GetPoints( tr2, P2 ))
2007     return angle;
2008   gp_Vec N1,N2;
2009   if(!tr1->IsQuadratic())
2010     N1 = gp_Vec( P1(2) - P1(1) ) ^ gp_Vec( P1(3) - P1(1) );
2011   else
2012     N1 = gp_Vec( P1(3) - P1(1) ) ^ gp_Vec( P1(5) - P1(1) );
2013   if ( N1.SquareMagnitude() <= gp::Resolution() )
2014     return angle;
2015   if(!tr2->IsQuadratic())
2016     N2 = gp_Vec( P2(2) - P2(1) ) ^ gp_Vec( P2(3) - P2(1) );
2017   else
2018     N2 = gp_Vec( P2(3) - P2(1) ) ^ gp_Vec( P2(5) - P2(1) );
2019   if ( N2.SquareMagnitude() <= gp::Resolution() )
2020     return angle;
2021
2022   // find the first diagonal node n1 in the triangles:
2023   // take in account a diagonal link orientation
2024   const SMDS_MeshElement *nFirst[2], *tr[] = { tr1, tr2 };
2025   for ( int t = 0; t < 2; t++ ) {
2026     SMDS_ElemIteratorPtr it = tr[ t ]->nodesIterator();
2027     int i = 0, iDiag = -1;
2028     while ( it->more()) {
2029       const SMDS_MeshElement *n = it->next();
2030       if ( n == n1 || n == n2 ) {
2031         if ( iDiag < 0)
2032           iDiag = i;
2033         else {
2034           if ( i - iDiag == 1 )
2035             nFirst[ t ] = ( n == n1 ? n2 : n1 );
2036           else
2037             nFirst[ t ] = n;
2038           break;
2039         }
2040       }
2041       i++;
2042     }
2043   }
2044   if ( nFirst[ 0 ] == nFirst[ 1 ] )
2045     N2.Reverse();
2046
2047   angle = N1.Angle( N2 );
2048   //SCRUTE( angle );
2049   return angle;
2050 }
2051
2052 // =================================================
2053 // class generating a unique ID for a pair of nodes
2054 // and able to return nodes by that ID
2055 // =================================================
2056 class LinkID_Gen {
2057 public:
2058
2059   LinkID_Gen( const SMESHDS_Mesh* theMesh )
2060     :myMesh( theMesh ), myMaxID( theMesh->MaxNodeID() + 1)
2061   {}
2062
2063   long GetLinkID (const SMDS_MeshNode * n1,
2064                   const SMDS_MeshNode * n2) const
2065   {
2066     return ( Min(n1->GetID(),n2->GetID()) * myMaxID + Max(n1->GetID(),n2->GetID()));
2067   }
2068
2069   bool GetNodes (const long             theLinkID,
2070                  const SMDS_MeshNode* & theNode1,
2071                  const SMDS_MeshNode* & theNode2) const
2072   {
2073     theNode1 = myMesh->FindNode( theLinkID / myMaxID );
2074     if ( !theNode1 ) return false;
2075     theNode2 = myMesh->FindNode( theLinkID % myMaxID );
2076     if ( !theNode2 ) return false;
2077     return true;
2078   }
2079
2080 private:
2081   LinkID_Gen();
2082   const SMESHDS_Mesh* myMesh;
2083   long                myMaxID;
2084 };
2085
2086
2087 //=======================================================================
2088 //function : TriToQuad
2089 //purpose  : Fuse neighbour triangles into quadrangles.
2090 //           theCrit is used to select a neighbour to fuse with.
2091 //           theMaxAngle is a max angle between element normals at which
2092 //           fusion is still performed.
2093 //=======================================================================
2094
2095 bool SMESH_MeshEditor::TriToQuad (TIDSortedElemSet &                   theElems,
2096                                   SMESH::Controls::NumericalFunctorPtr theCrit,
2097                                   const double                         theMaxAngle)
2098 {
2099   myLastCreatedElems.Clear();
2100   myLastCreatedNodes.Clear();
2101
2102   MESSAGE( "::TriToQuad()" );
2103
2104   if ( !theCrit.get() )
2105     return false;
2106
2107   SMESHDS_Mesh * aMesh = GetMeshDS();
2108
2109   // Prepare data for algo: build
2110   // 1. map of elements with their linkIDs
2111   // 2. map of linkIDs with their elements
2112
2113   map< SMESH_TLink, list< const SMDS_MeshElement* > > mapLi_listEl;
2114   map< SMESH_TLink, list< const SMDS_MeshElement* > >::iterator itLE;
2115   map< const SMDS_MeshElement*, set< SMESH_TLink > >  mapEl_setLi;
2116   map< const SMDS_MeshElement*, set< SMESH_TLink > >::iterator itEL;
2117
2118   TIDSortedElemSet::iterator itElem;
2119   for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
2120     const SMDS_MeshElement* elem = *itElem;
2121     if(!elem || elem->GetType() != SMDSAbs_Face ) continue;
2122     bool IsTria = elem->NbNodes()==3 || (elem->NbNodes()==6 && elem->IsQuadratic());
2123     if(!IsTria) continue;
2124
2125     // retrieve element nodes
2126     const SMDS_MeshNode* aNodes [4];
2127     SMDS_ElemIteratorPtr itN = elem->nodesIterator();
2128     int i = 0;
2129     while ( i<3 )
2130       aNodes[ i++ ] = cast2Node( itN->next() );
2131     aNodes[ 3 ] = aNodes[ 0 ];
2132
2133     // fill maps
2134     for ( i = 0; i < 3; i++ ) {
2135       SMESH_TLink link( aNodes[i], aNodes[i+1] );
2136       // check if elements sharing a link can be fused
2137       itLE = mapLi_listEl.find( link );
2138       if ( itLE != mapLi_listEl.end() ) {
2139         if ((*itLE).second.size() > 1 ) // consider only 2 elems adjacent by a link
2140           continue;
2141         const SMDS_MeshElement* elem2 = (*itLE).second.front();
2142         //if ( FindShape( elem ) != FindShape( elem2 ))
2143         //  continue; // do not fuse triangles laying on different shapes
2144         if ( getAngle( elem, elem2, aNodes[i], aNodes[i+1] ) > theMaxAngle )
2145           continue; // avoid making badly shaped quads
2146         (*itLE).second.push_back( elem );
2147       }
2148       else {
2149         mapLi_listEl[ link ].push_back( elem );
2150       }
2151       mapEl_setLi [ elem ].insert( link );
2152     }
2153   }
2154   // Clean the maps from the links shared by a sole element, ie
2155   // links to which only one element is bound in mapLi_listEl
2156
2157   for ( itLE = mapLi_listEl.begin(); itLE != mapLi_listEl.end(); itLE++ ) {
2158     int nbElems = (*itLE).second.size();
2159     if ( nbElems < 2  ) {
2160       const SMDS_MeshElement* elem = (*itLE).second.front();
2161       SMESH_TLink link = (*itLE).first;
2162       mapEl_setLi[ elem ].erase( link );
2163       if ( mapEl_setLi[ elem ].empty() )
2164         mapEl_setLi.erase( elem );
2165     }
2166   }
2167
2168   // Algo: fuse triangles into quadrangles
2169
2170   while ( ! mapEl_setLi.empty() ) {
2171     // Look for the start element:
2172     // the element having the least nb of shared links
2173     const SMDS_MeshElement* startElem = 0;
2174     int minNbLinks = 4;
2175     for ( itEL = mapEl_setLi.begin(); itEL != mapEl_setLi.end(); itEL++ ) {
2176       int nbLinks = (*itEL).second.size();
2177       if ( nbLinks < minNbLinks ) {
2178         startElem = (*itEL).first;
2179         minNbLinks = nbLinks;
2180         if ( minNbLinks == 1 )
2181           break;
2182       }
2183     }
2184
2185     // search elements to fuse starting from startElem or links of elements
2186     // fused earlyer - startLinks
2187     list< SMESH_TLink > startLinks;
2188     while ( startElem || !startLinks.empty() ) {
2189       while ( !startElem && !startLinks.empty() ) {
2190         // Get an element to start, by a link
2191         SMESH_TLink linkId = startLinks.front();
2192         startLinks.pop_front();
2193         itLE = mapLi_listEl.find( linkId );
2194         if ( itLE != mapLi_listEl.end() ) {
2195           list< const SMDS_MeshElement* > & listElem = (*itLE).second;
2196           list< const SMDS_MeshElement* >::iterator itE = listElem.begin();
2197           for ( ; itE != listElem.end() ; itE++ )
2198             if ( mapEl_setLi.find( (*itE) ) != mapEl_setLi.end() )
2199               startElem = (*itE);
2200           mapLi_listEl.erase( itLE );
2201         }
2202       }
2203
2204       if ( startElem ) {
2205         // Get candidates to be fused
2206         const SMDS_MeshElement *tr1 = startElem, *tr2 = 0, *tr3 = 0;
2207         const SMESH_TLink *link12, *link13;
2208         startElem = 0;
2209         ASSERT( mapEl_setLi.find( tr1 ) != mapEl_setLi.end() );
2210         set< SMESH_TLink >& setLi = mapEl_setLi[ tr1 ];
2211         ASSERT( !setLi.empty() );
2212         set< SMESH_TLink >::iterator itLi;
2213         for ( itLi = setLi.begin(); itLi != setLi.end(); itLi++ )
2214         {
2215           const SMESH_TLink & link = (*itLi);
2216           itLE = mapLi_listEl.find( link );
2217           if ( itLE == mapLi_listEl.end() )
2218             continue;
2219
2220           const SMDS_MeshElement* elem = (*itLE).second.front();
2221           if ( elem == tr1 )
2222             elem = (*itLE).second.back();
2223           mapLi_listEl.erase( itLE );
2224           if ( mapEl_setLi.find( elem ) == mapEl_setLi.end())
2225             continue;
2226           if ( tr2 ) {
2227             tr3 = elem;
2228             link13 = &link;
2229           }
2230           else {
2231             tr2 = elem;
2232             link12 = &link;
2233           }
2234
2235           // add other links of elem to list of links to re-start from
2236           set< SMESH_TLink >& links = mapEl_setLi[ elem ];
2237           set< SMESH_TLink >::iterator it;
2238           for ( it = links.begin(); it != links.end(); it++ ) {
2239             const SMESH_TLink& link2 = (*it);
2240             if ( link2 != link )
2241               startLinks.push_back( link2 );
2242           }
2243         }
2244
2245         // Get nodes of possible quadrangles
2246         const SMDS_MeshNode *n12 [4], *n13 [4];
2247         bool Ok12 = false, Ok13 = false;
2248         const SMDS_MeshNode *linkNode1, *linkNode2;
2249         if(tr2) {
2250           linkNode1 = link12->first;
2251           linkNode2 = link12->second;
2252           if ( tr2 && getQuadrangleNodes( n12, linkNode1, linkNode2, tr1, tr2 ))
2253             Ok12 = true;
2254         }
2255         if(tr3) {
2256           linkNode1 = link13->first;
2257           linkNode2 = link13->second;
2258           if ( tr3 && getQuadrangleNodes( n13, linkNode1, linkNode2, tr1, tr3 ))
2259             Ok13 = true;
2260         }
2261
2262         // Choose a pair to fuse
2263         if ( Ok12 && Ok13 ) {
2264           SMDS_FaceOfNodes quad12 ( n12[ 0 ], n12[ 1 ], n12[ 2 ], n12[ 3 ] );
2265           SMDS_FaceOfNodes quad13 ( n13[ 0 ], n13[ 1 ], n13[ 2 ], n13[ 3 ] );
2266           double aBadRate12 = getBadRate( &quad12, theCrit );
2267           double aBadRate13 = getBadRate( &quad13, theCrit );
2268           if (  aBadRate13 < aBadRate12 )
2269             Ok12 = false;
2270           else
2271             Ok13 = false;
2272         }
2273
2274         // Make quadrangles
2275         // and remove fused elems and removed links from the maps
2276         mapEl_setLi.erase( tr1 );
2277         if ( Ok12 ) {
2278           mapEl_setLi.erase( tr2 );
2279           mapLi_listEl.erase( *link12 );
2280           if(tr1->NbNodes()==3) {
2281             const SMDS_MeshElement* newElem = 0;
2282             newElem = aMesh->AddFace(n12[0], n12[1], n12[2], n12[3] );
2283             myLastCreatedElems.Append(newElem);
2284             AddToSameGroups( newElem, tr1, aMesh );
2285             int aShapeId = tr1->getshapeId();
2286             if ( aShapeId )
2287               {
2288                 aMesh->SetMeshElementOnShape( newElem, aShapeId );
2289               }
2290             aMesh->RemoveElement( tr1 );
2291             aMesh->RemoveElement( tr2 );
2292           }
2293           else {
2294             const SMDS_MeshNode* N1 [6];
2295             const SMDS_MeshNode* N2 [6];
2296             GetNodesFromTwoTria(tr1,tr2,N1,N2);
2297             // now we receive following N1 and N2 (using numeration as above image)
2298             // tria1 : (1 2 4 5 9 7)  and  tria2 : (3 4 2 8 9 6)
2299             // i.e. first nodes from both arrays determ new diagonal
2300             const SMDS_MeshNode* aNodes[8];
2301             aNodes[0] = N1[0];
2302             aNodes[1] = N1[1];
2303             aNodes[2] = N2[0];
2304             aNodes[3] = N2[1];
2305             aNodes[4] = N1[3];
2306             aNodes[5] = N2[5];
2307             aNodes[6] = N2[3];
2308             aNodes[7] = N1[5];
2309             const SMDS_MeshElement* newElem = 0;
2310             newElem = aMesh->AddFace(aNodes[0], aNodes[1], aNodes[2], aNodes[3],
2311                                      aNodes[4], aNodes[5], aNodes[6], aNodes[7]);
2312             myLastCreatedElems.Append(newElem);
2313             AddToSameGroups( newElem, tr1, aMesh );
2314             int aShapeId = tr1->getshapeId();
2315             if ( aShapeId )
2316               {
2317                 aMesh->SetMeshElementOnShape( newElem, aShapeId );
2318               }
2319             aMesh->RemoveElement( tr1 );
2320             aMesh->RemoveElement( tr2 );
2321             // remove middle node (9)
2322             GetMeshDS()->RemoveNode( N1[4] );
2323           }
2324         }
2325         else if ( Ok13 ) {
2326           mapEl_setLi.erase( tr3 );
2327           mapLi_listEl.erase( *link13 );
2328           if(tr1->NbNodes()==3) {
2329             const SMDS_MeshElement* newElem = 0;
2330             newElem = aMesh->AddFace(n13[0], n13[1], n13[2], n13[3] );
2331             myLastCreatedElems.Append(newElem);
2332             AddToSameGroups( newElem, tr1, aMesh );
2333             int aShapeId = tr1->getshapeId();
2334             if ( aShapeId )
2335               {
2336                 aMesh->SetMeshElementOnShape( newElem, aShapeId );
2337               }
2338             aMesh->RemoveElement( tr1 );
2339             aMesh->RemoveElement( tr3 );
2340           }
2341           else {
2342             const SMDS_MeshNode* N1 [6];
2343             const SMDS_MeshNode* N2 [6];
2344             GetNodesFromTwoTria(tr1,tr3,N1,N2);
2345             // now we receive following N1 and N2 (using numeration as above image)
2346             // tria1 : (1 2 4 5 9 7)  and  tria2 : (3 4 2 8 9 6)
2347             // i.e. first nodes from both arrays determ new diagonal
2348             const SMDS_MeshNode* aNodes[8];
2349             aNodes[0] = N1[0];
2350             aNodes[1] = N1[1];
2351             aNodes[2] = N2[0];
2352             aNodes[3] = N2[1];
2353             aNodes[4] = N1[3];
2354             aNodes[5] = N2[5];
2355             aNodes[6] = N2[3];
2356             aNodes[7] = N1[5];
2357             const SMDS_MeshElement* newElem = 0;
2358             newElem = aMesh->AddFace(aNodes[0], aNodes[1], aNodes[2], aNodes[3],
2359                                      aNodes[4], aNodes[5], aNodes[6], aNodes[7]);
2360             myLastCreatedElems.Append(newElem);
2361             AddToSameGroups( newElem, tr1, aMesh );
2362             int aShapeId = tr1->getshapeId();
2363             if ( aShapeId )
2364               {
2365                 aMesh->SetMeshElementOnShape( newElem, aShapeId );
2366               }
2367             aMesh->RemoveElement( tr1 );
2368             aMesh->RemoveElement( tr3 );
2369             // remove middle node (9)
2370             GetMeshDS()->RemoveNode( N1[4] );
2371           }
2372         }
2373
2374         // Next element to fuse: the rejected one
2375         if ( tr3 )
2376           startElem = Ok12 ? tr3 : tr2;
2377
2378       } // if ( startElem )
2379     } // while ( startElem || !startLinks.empty() )
2380   } // while ( ! mapEl_setLi.empty() )
2381
2382   return true;
2383 }
2384
2385
2386 /*#define DUMPSO(txt) \
2387 //  cout << txt << endl;
2388 //=============================================================================
2389 //
2390 //
2391 //
2392 //=============================================================================
2393 static void swap( int i1, int i2, int idNodes[], gp_Pnt P[] )
2394 {
2395 if ( i1 == i2 )
2396 return;
2397 int tmp = idNodes[ i1 ];
2398 idNodes[ i1 ] = idNodes[ i2 ];
2399 idNodes[ i2 ] = tmp;
2400 gp_Pnt Ptmp = P[ i1 ];
2401 P[ i1 ] = P[ i2 ];
2402 P[ i2 ] = Ptmp;
2403 DUMPSO( i1 << "(" << idNodes[ i2 ] << ") <-> " << i2 << "(" << idNodes[ i1 ] << ")");
2404 }
2405
2406 //=======================================================================
2407 //function : SortQuadNodes
2408 //purpose  : Set 4 nodes of a quadrangle face in a good order.
2409 //           Swap 1<->2 or 2<->3 nodes and correspondingly return
2410 //           1 or 2 else 0.
2411 //=======================================================================
2412
2413 int SMESH_MeshEditor::SortQuadNodes (const SMDS_Mesh * theMesh,
2414 int               idNodes[] )
2415 {
2416   gp_Pnt P[4];
2417   int i;
2418   for ( i = 0; i < 4; i++ ) {
2419     const SMDS_MeshNode *n = theMesh->FindNode( idNodes[i] );
2420     if ( !n ) return 0;
2421     P[ i ].SetCoord( n->X(), n->Y(), n->Z() );
2422   }
2423
2424   gp_Vec V1(P[0], P[1]);
2425   gp_Vec V2(P[0], P[2]);
2426   gp_Vec V3(P[0], P[3]);
2427
2428   gp_Vec Cross1 = V1 ^ V2;
2429   gp_Vec Cross2 = V2 ^ V3;
2430
2431   i = 0;
2432   if (Cross1.Dot(Cross2) < 0)
2433   {
2434     Cross1 = V2 ^ V1;
2435     Cross2 = V1 ^ V3;
2436
2437     if (Cross1.Dot(Cross2) < 0)
2438       i = 2;
2439     else
2440       i = 1;
2441     swap ( i, i + 1, idNodes, P );
2442
2443     //     for ( int ii = 0; ii < 4; ii++ ) {
2444     //       const SMDS_MeshNode *n = theMesh->FindNode( idNodes[ii] );
2445     //       DUMPSO( ii << "(" << idNodes[ii] <<") : "<<n->X()<<" "<<n->Y()<<" "<<n->Z());
2446     //     }
2447   }
2448   return i;
2449 }
2450
2451 //=======================================================================
2452 //function : SortHexaNodes
2453 //purpose  : Set 8 nodes of a hexahedron in a good order.
2454 //           Return success status
2455 //=======================================================================
2456
2457 bool SMESH_MeshEditor::SortHexaNodes (const SMDS_Mesh * theMesh,
2458                                       int               idNodes[] )
2459 {
2460   gp_Pnt P[8];
2461   int i;
2462   DUMPSO( "INPUT: ========================================");
2463   for ( i = 0; i < 8; i++ ) {
2464     const SMDS_MeshNode *n = theMesh->FindNode( idNodes[i] );
2465     if ( !n ) return false;
2466     P[ i ].SetCoord( n->X(), n->Y(), n->Z() );
2467     DUMPSO( i << "(" << idNodes[i] <<") : "<<n->X()<<" "<<n->Y()<<" "<<n->Z());
2468   }
2469   DUMPSO( "========================================");
2470
2471
2472   set<int> faceNodes;  // ids of bottom face nodes, to be found
2473   set<int> checkedId1; // ids of tried 2-nd nodes
2474   Standard_Real leastDist = DBL_MAX; // dist of the 4-th node from 123 plane
2475   const Standard_Real tol = 1.e-6;   // tolerance to find nodes in plane
2476   int iMin, iLoop1 = 0;
2477
2478   // Loop to try the 2-nd nodes
2479
2480   while ( leastDist > DBL_MIN && ++iLoop1 < 8 )
2481   {
2482     // Find not checked 2-nd node
2483     for ( i = 1; i < 8; i++ )
2484       if ( checkedId1.find( idNodes[i] ) == checkedId1.end() ) {
2485         int id1 = idNodes[i];
2486         swap ( 1, i, idNodes, P );
2487         checkedId1.insert ( id1 );
2488         break;
2489       }
2490
2491     // Find the 3-d node so that 1-2-3 triangle to be on a hexa face,
2492     // ie that all but meybe one (id3 which is on the same face) nodes
2493     // lay on the same side from the triangle plane.
2494
2495     bool manyInPlane = false; // more than 4 nodes lay in plane
2496     int iLoop2 = 0;
2497     while ( ++iLoop2 < 6 ) {
2498
2499       // get 1-2-3 plane coeffs
2500       Standard_Real A, B, C, D;
2501       gp_Vec N = gp_Vec (P[0], P[1]).Crossed( gp_Vec (P[0], P[2]) );
2502       if ( N.SquareMagnitude() > gp::Resolution() )
2503       {
2504         gp_Pln pln ( P[0], N );
2505         pln.Coefficients( A, B, C, D );
2506
2507         // find the node (iMin) closest to pln
2508         Standard_Real dist[ 8 ], minDist = DBL_MAX;
2509         set<int> idInPln;
2510         for ( i = 3; i < 8; i++ ) {
2511           dist[i] = A * P[i].X() + B * P[i].Y() + C * P[i].Z() + D;
2512           if ( fabs( dist[i] ) < minDist ) {
2513             minDist = fabs( dist[i] );
2514             iMin = i;
2515           }
2516           if ( fabs( dist[i] ) <= tol )
2517             idInPln.insert( idNodes[i] );
2518         }
2519
2520         // there should not be more than 4 nodes in bottom plane
2521         if ( idInPln.size() > 1 )
2522         {
2523           DUMPSO( "### idInPln.size() = " << idInPln.size());
2524           // idInPlane does not contain the first 3 nodes
2525           if ( manyInPlane || idInPln.size() == 5)
2526             return false; // all nodes in one plane
2527           manyInPlane = true;
2528
2529           // set the 1-st node to be not in plane
2530           for ( i = 3; i < 8; i++ ) {
2531             if ( idInPln.find( idNodes[ i ] ) == idInPln.end() ) {
2532               DUMPSO( "### Reset 0-th node");
2533               swap( 0, i, idNodes, P );
2534               break;
2535             }
2536           }
2537
2538           // reset to re-check second nodes
2539           leastDist = DBL_MAX;
2540           faceNodes.clear();
2541           checkedId1.clear();
2542           iLoop1 = 0;
2543           break; // from iLoop2;
2544         }
2545
2546         // check that the other 4 nodes are on the same side
2547         bool sameSide = true;
2548         bool isNeg = dist[ iMin == 3 ? 4 : 3 ] <= 0.;
2549         for ( i = 3; sameSide && i < 8; i++ ) {
2550           if ( i != iMin )
2551             sameSide = ( isNeg == dist[i] <= 0.);
2552         }
2553
2554         // keep best solution
2555         if ( sameSide && minDist < leastDist ) {
2556           leastDist = minDist;
2557           faceNodes.clear();
2558           faceNodes.insert( idNodes[ 1 ] );
2559           faceNodes.insert( idNodes[ 2 ] );
2560           faceNodes.insert( idNodes[ iMin ] );
2561           DUMPSO( "loop " << iLoop2 << " id2 " << idNodes[ 1 ] << " id3 " << idNodes[ 2 ]
2562                   << " leastDist = " << leastDist);
2563           if ( leastDist <= DBL_MIN )
2564             break;
2565         }
2566       }
2567
2568       // set next 3-d node to check
2569       int iNext = 2 + iLoop2;
2570       if ( iNext < 8 ) {
2571         DUMPSO( "Try 2-nd");
2572         swap ( 2, iNext, idNodes, P );
2573       }
2574     } // while ( iLoop2 < 6 )
2575   } // iLoop1
2576
2577   if ( faceNodes.empty() ) return false;
2578
2579   // Put the faceNodes in proper places
2580   for ( i = 4; i < 8; i++ ) {
2581     if ( faceNodes.find( idNodes[ i ] ) != faceNodes.end() ) {
2582       // find a place to put
2583       int iTo = 1;
2584       while ( faceNodes.find( idNodes[ iTo ] ) != faceNodes.end() )
2585         iTo++;
2586       DUMPSO( "Set faceNodes");
2587       swap ( iTo, i, idNodes, P );
2588     }
2589   }
2590
2591
2592   // Set nodes of the found bottom face in good order
2593   DUMPSO( " Found bottom face: ");
2594   i = SortQuadNodes( theMesh, idNodes );
2595   if ( i ) {
2596     gp_Pnt Ptmp = P[ i ];
2597     P[ i ] = P[ i+1 ];
2598     P[ i+1 ] = Ptmp;
2599   }
2600   //   else
2601   //     for ( int ii = 0; ii < 4; ii++ ) {
2602   //       const SMDS_MeshNode *n = theMesh->FindNode( idNodes[ii] );
2603   //       DUMPSO( ii << "(" << idNodes[ii] <<") : "<<n->X()<<" "<<n->Y()<<" "<<n->Z());
2604   //    }
2605
2606   // Gravity center of the top and bottom faces
2607   gp_Pnt aGCb = ( P[0].XYZ() + P[1].XYZ() + P[2].XYZ() + P[3].XYZ() ) / 4.;
2608   gp_Pnt aGCt = ( P[4].XYZ() + P[5].XYZ() + P[6].XYZ() + P[7].XYZ() ) / 4.;
2609
2610   // Get direction from the bottom to the top face
2611   gp_Vec upDir ( aGCb, aGCt );
2612   Standard_Real upDirSize = upDir.Magnitude();
2613   if ( upDirSize <= gp::Resolution() ) return false;
2614   upDir / upDirSize;
2615
2616   // Assure that the bottom face normal points up
2617   gp_Vec Nb = gp_Vec (P[0], P[1]).Crossed( gp_Vec (P[0], P[2]) );
2618   Nb += gp_Vec (P[0], P[2]).Crossed( gp_Vec (P[0], P[3]) );
2619   if ( Nb.Dot( upDir ) < 0 ) {
2620     DUMPSO( "Reverse bottom face");
2621     swap( 1, 3, idNodes, P );
2622   }
2623
2624   // Find 5-th node - the one closest to the 1-st among the last 4 nodes.
2625   Standard_Real minDist = DBL_MAX;
2626   for ( i = 4; i < 8; i++ ) {
2627     // projection of P[i] to the plane defined by P[0] and upDir
2628     gp_Pnt Pp = P[i].Translated( upDir * ( upDir.Dot( gp_Vec( P[i], P[0] ))));
2629     Standard_Real sqDist = P[0].SquareDistance( Pp );
2630     if ( sqDist < minDist ) {
2631       minDist = sqDist;
2632       iMin = i;
2633     }
2634   }
2635   DUMPSO( "Set 4-th");
2636   swap ( 4, iMin, idNodes, P );
2637
2638   // Set nodes of the top face in good order
2639   DUMPSO( "Sort top face");
2640   i = SortQuadNodes( theMesh, &idNodes[4] );
2641   if ( i ) {
2642     i += 4;
2643     gp_Pnt Ptmp = P[ i ];
2644     P[ i ] = P[ i+1 ];
2645     P[ i+1 ] = Ptmp;
2646   }
2647
2648   // Assure that direction of the top face normal is from the bottom face
2649   gp_Vec Nt = gp_Vec (P[4], P[5]).Crossed( gp_Vec (P[4], P[6]) );
2650   Nt += gp_Vec (P[4], P[6]).Crossed( gp_Vec (P[4], P[7]) );
2651   if ( Nt.Dot( upDir ) < 0 ) {
2652     DUMPSO( "Reverse top face");
2653     swap( 5, 7, idNodes, P );
2654   }
2655
2656   //   DUMPSO( "OUTPUT: ========================================");
2657   //   for ( i = 0; i < 8; i++ ) {
2658   //     float *p = ugrid->GetPoint(idNodes[i]);
2659   //     DUMPSO( i << "(" << idNodes[i] << ") : " << p[0] << " " << p[1] << " " << p[2]);
2660   //   }
2661
2662   return true;
2663 }*/
2664
2665 //================================================================================
2666 /*!
2667  * \brief Return nodes linked to the given one
2668  * \param theNode - the node
2669  * \param linkedNodes - the found nodes
2670  * \param type - the type of elements to check
2671  *
2672  * Medium nodes are ignored
2673  */
2674 //================================================================================
2675
2676 void SMESH_MeshEditor::GetLinkedNodes( const SMDS_MeshNode* theNode,
2677                                        TIDSortedElemSet &   linkedNodes,
2678                                        SMDSAbs_ElementType  type )
2679 {
2680   SMDS_ElemIteratorPtr elemIt = theNode->GetInverseElementIterator(type);
2681   while ( elemIt->more() )
2682   {
2683     const SMDS_MeshElement* elem = elemIt->next();
2684     if(elem->GetType() == SMDSAbs_0DElement)
2685       continue;
2686     
2687     SMDS_ElemIteratorPtr nodeIt = elem->nodesIterator();
2688     if ( elem->GetType() == SMDSAbs_Volume )
2689     {
2690       SMDS_VolumeTool vol( elem );
2691       while ( nodeIt->more() ) {
2692         const SMDS_MeshNode* n = cast2Node( nodeIt->next() );
2693         if ( theNode != n && vol.IsLinked( theNode, n ))
2694           linkedNodes.insert( n );
2695       }
2696     }
2697     else
2698     {
2699       for ( int i = 0; nodeIt->more(); ++i ) {
2700         const SMDS_MeshNode* n = cast2Node( nodeIt->next() );
2701         if ( n == theNode ) {
2702           int iBefore = i - 1;
2703           int iAfter  = i + 1;
2704           if ( elem->IsQuadratic() ) {
2705             int nb = elem->NbNodes() / 2;
2706             iAfter  = SMESH_MesherHelper::WrapIndex( iAfter, nb );
2707             iBefore = SMESH_MesherHelper::WrapIndex( iBefore, nb );
2708           }
2709           linkedNodes.insert( elem->GetNodeWrap( iAfter ));
2710           linkedNodes.insert( elem->GetNodeWrap( iBefore ));
2711         }
2712       }
2713     }
2714   }
2715 }
2716
2717 //=======================================================================
2718 //function : laplacianSmooth
2719 //purpose  : pulls theNode toward the center of surrounding nodes directly
2720 //           connected to that node along an element edge
2721 //=======================================================================
2722
2723 void laplacianSmooth(const SMDS_MeshNode*                 theNode,
2724                      const Handle(Geom_Surface)&          theSurface,
2725                      map< const SMDS_MeshNode*, gp_XY* >& theUVMap)
2726 {
2727   // find surrounding nodes
2728
2729   TIDSortedElemSet nodeSet;
2730   SMESH_MeshEditor::GetLinkedNodes( theNode, nodeSet, SMDSAbs_Face );
2731
2732   // compute new coodrs
2733
2734   double coord[] = { 0., 0., 0. };
2735   TIDSortedElemSet::iterator nodeSetIt = nodeSet.begin();
2736   for ( ; nodeSetIt != nodeSet.end(); nodeSetIt++ ) {
2737     const SMDS_MeshNode* node = cast2Node(*nodeSetIt);
2738     if ( theSurface.IsNull() ) { // smooth in 3D
2739       coord[0] += node->X();
2740       coord[1] += node->Y();
2741       coord[2] += node->Z();
2742     }
2743     else { // smooth in 2D
2744       ASSERT( theUVMap.find( node ) != theUVMap.end() );
2745       gp_XY* uv = theUVMap[ node ];
2746       coord[0] += uv->X();
2747       coord[1] += uv->Y();
2748     }
2749   }
2750   int nbNodes = nodeSet.size();
2751   if ( !nbNodes )
2752     return;
2753   coord[0] /= nbNodes;
2754   coord[1] /= nbNodes;
2755
2756   if ( !theSurface.IsNull() ) {
2757     ASSERT( theUVMap.find( theNode ) != theUVMap.end() );
2758     theUVMap[ theNode ]->SetCoord( coord[0], coord[1] );
2759     gp_Pnt p3d = theSurface->Value( coord[0], coord[1] );
2760     coord[0] = p3d.X();
2761     coord[1] = p3d.Y();
2762     coord[2] = p3d.Z();
2763   }
2764   else
2765     coord[2] /= nbNodes;
2766
2767   // move node
2768
2769   const_cast< SMDS_MeshNode* >( theNode )->setXYZ(coord[0],coord[1],coord[2]);
2770 }
2771
2772 //=======================================================================
2773 //function : centroidalSmooth
2774 //purpose  : pulls theNode toward the element-area-weighted centroid of the
2775 //           surrounding elements
2776 //=======================================================================
2777
2778 void centroidalSmooth(const SMDS_MeshNode*                 theNode,
2779                       const Handle(Geom_Surface)&          theSurface,
2780                       map< const SMDS_MeshNode*, gp_XY* >& theUVMap)
2781 {
2782   gp_XYZ aNewXYZ(0.,0.,0.);
2783   SMESH::Controls::Area anAreaFunc;
2784   double totalArea = 0.;
2785   int nbElems = 0;
2786
2787   // compute new XYZ
2788
2789   SMDS_ElemIteratorPtr elemIt = theNode->GetInverseElementIterator(SMDSAbs_Face);
2790   while ( elemIt->more() )
2791   {
2792     const SMDS_MeshElement* elem = elemIt->next();
2793     nbElems++;
2794
2795     gp_XYZ elemCenter(0.,0.,0.);
2796     SMESH::Controls::TSequenceOfXYZ aNodePoints;
2797     SMDS_ElemIteratorPtr itN = elem->nodesIterator();
2798     int nn = elem->NbNodes();
2799     if(elem->IsQuadratic()) nn = nn/2;
2800     int i=0;
2801     //while ( itN->more() ) {
2802     while ( i<nn ) {
2803       const SMDS_MeshNode* aNode = static_cast<const SMDS_MeshNode*>( itN->next() );
2804       i++;
2805       gp_XYZ aP( aNode->X(), aNode->Y(), aNode->Z() );
2806       aNodePoints.push_back( aP );
2807       if ( !theSurface.IsNull() ) { // smooth in 2D
2808         ASSERT( theUVMap.find( aNode ) != theUVMap.end() );
2809         gp_XY* uv = theUVMap[ aNode ];
2810         aP.SetCoord( uv->X(), uv->Y(), 0. );
2811       }
2812       elemCenter += aP;
2813     }
2814     double elemArea = anAreaFunc.GetValue( aNodePoints );
2815     totalArea += elemArea;
2816     elemCenter /= nn;
2817     aNewXYZ += elemCenter * elemArea;
2818   }
2819   aNewXYZ /= totalArea;
2820   if ( !theSurface.IsNull() ) {
2821     theUVMap[ theNode ]->SetCoord( aNewXYZ.X(), aNewXYZ.Y() );
2822     aNewXYZ = theSurface->Value( aNewXYZ.X(), aNewXYZ.Y() ).XYZ();
2823   }
2824
2825   // move node
2826
2827   const_cast< SMDS_MeshNode* >( theNode )->setXYZ(aNewXYZ.X(),aNewXYZ.Y(),aNewXYZ.Z());
2828 }
2829
2830 //=======================================================================
2831 //function : getClosestUV
2832 //purpose  : return UV of closest projection
2833 //=======================================================================
2834
2835 static bool getClosestUV (Extrema_GenExtPS& projector,
2836                           const gp_Pnt&     point,
2837                           gp_XY &           result)
2838 {
2839   projector.Perform( point );
2840   if ( projector.IsDone() ) {
2841     double u, v, minVal = DBL_MAX;
2842     for ( int i = projector.NbExt(); i > 0; i-- )
2843       if ( projector.Value( i ) < minVal ) {
2844         minVal = projector.Value( i );
2845         projector.Point( i ).Parameter( u, v );
2846       }
2847     result.SetCoord( u, v );
2848     return true;
2849   }
2850   return false;
2851 }
2852
2853 //=======================================================================
2854 //function : Smooth
2855 //purpose  : Smooth theElements during theNbIterations or until a worst
2856 //           element has aspect ratio <= theTgtAspectRatio.
2857 //           Aspect Ratio varies in range [1.0, inf].
2858 //           If theElements is empty, the whole mesh is smoothed.
2859 //           theFixedNodes contains additionally fixed nodes. Nodes built
2860 //           on edges and boundary nodes are always fixed.
2861 //=======================================================================
2862
2863 void SMESH_MeshEditor::Smooth (TIDSortedElemSet &          theElems,
2864                                set<const SMDS_MeshNode*> & theFixedNodes,
2865                                const SmoothMethod          theSmoothMethod,
2866                                const int                   theNbIterations,
2867                                double                      theTgtAspectRatio,
2868                                const bool                  the2D)
2869 {
2870   myLastCreatedElems.Clear();
2871   myLastCreatedNodes.Clear();
2872
2873   MESSAGE((theSmoothMethod==LAPLACIAN ? "LAPLACIAN" : "CENTROIDAL") << "--::Smooth()");
2874
2875   if ( theTgtAspectRatio < 1.0 )
2876     theTgtAspectRatio = 1.0;
2877
2878   const double disttol = 1.e-16;
2879
2880   SMESH::Controls::AspectRatio aQualityFunc;
2881
2882   SMESHDS_Mesh* aMesh = GetMeshDS();
2883
2884   if ( theElems.empty() ) {
2885     // add all faces to theElems
2886     SMDS_FaceIteratorPtr fIt = aMesh->facesIterator();
2887     while ( fIt->more() ) {
2888       const SMDS_MeshElement* face = fIt->next();
2889       theElems.insert( face );
2890     }
2891   }
2892   // get all face ids theElems are on
2893   set< int > faceIdSet;
2894   TIDSortedElemSet::iterator itElem;
2895   if ( the2D )
2896     for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
2897       int fId = FindShape( *itElem );
2898       // check that corresponding submesh exists and a shape is face
2899       if (fId &&
2900           faceIdSet.find( fId ) == faceIdSet.end() &&
2901           aMesh->MeshElements( fId )) {
2902         TopoDS_Shape F = aMesh->IndexToShape( fId );
2903         if ( !F.IsNull() && F.ShapeType() == TopAbs_FACE )
2904           faceIdSet.insert( fId );
2905       }
2906     }
2907   faceIdSet.insert( 0 ); // to smooth elements that are not on any TopoDS_Face
2908
2909   // ===============================================
2910   // smooth elements on each TopoDS_Face separately
2911   // ===============================================
2912
2913   set< int >::reverse_iterator fId = faceIdSet.rbegin(); // treate 0 fId at the end
2914   for ( ; fId != faceIdSet.rend(); ++fId ) {
2915     // get face surface and submesh
2916     Handle(Geom_Surface) surface;
2917     SMESHDS_SubMesh* faceSubMesh = 0;
2918     TopoDS_Face face;
2919     double fToler2 = 0, vPeriod = 0., uPeriod = 0., f,l;
2920     double u1 = 0, u2 = 0, v1 = 0, v2 = 0;
2921     bool isUPeriodic = false, isVPeriodic = false;
2922     if ( *fId ) {
2923       face = TopoDS::Face( aMesh->IndexToShape( *fId ));
2924       surface = BRep_Tool::Surface( face );
2925       faceSubMesh = aMesh->MeshElements( *fId );
2926       fToler2 = BRep_Tool::Tolerance( face );
2927       fToler2 *= fToler2 * 10.;
2928       isUPeriodic = surface->IsUPeriodic();
2929       if ( isUPeriodic )
2930         vPeriod = surface->UPeriod();
2931       isVPeriodic = surface->IsVPeriodic();
2932       if ( isVPeriodic )
2933         uPeriod = surface->VPeriod();
2934       surface->Bounds( u1, u2, v1, v2 );
2935     }
2936     // ---------------------------------------------------------
2937     // for elements on a face, find movable and fixed nodes and
2938     // compute UV for them
2939     // ---------------------------------------------------------
2940     bool checkBoundaryNodes = false;
2941     bool isQuadratic = false;
2942     set<const SMDS_MeshNode*> setMovableNodes;
2943     map< const SMDS_MeshNode*, gp_XY* > uvMap, uvMap2;
2944     list< gp_XY > listUV; // uvs the 2 uvMaps refer to
2945     list< const SMDS_MeshElement* > elemsOnFace;
2946
2947     Extrema_GenExtPS projector;
2948     GeomAdaptor_Surface surfAdaptor;
2949     if ( !surface.IsNull() ) {
2950       surfAdaptor.Load( surface );
2951       projector.Initialize( surfAdaptor, 20,20, 1e-5,1e-5 );
2952     }
2953     int nbElemOnFace = 0;
2954     itElem = theElems.begin();
2955     // loop on not yet smoothed elements: look for elems on a face
2956     while ( itElem != theElems.end() ) {
2957       if ( faceSubMesh && nbElemOnFace == faceSubMesh->NbElements() )
2958         break; // all elements found
2959
2960       const SMDS_MeshElement* elem = *itElem;
2961       if ( !elem || elem->GetType() != SMDSAbs_Face || elem->NbNodes() < 3 ||
2962            ( faceSubMesh && !faceSubMesh->Contains( elem ))) {
2963         ++itElem;
2964         continue;
2965       }
2966       elemsOnFace.push_back( elem );
2967       theElems.erase( itElem++ );
2968       nbElemOnFace++;
2969
2970       if ( !isQuadratic )
2971         isQuadratic = elem->IsQuadratic();
2972
2973       // get movable nodes of elem
2974       const SMDS_MeshNode* node;
2975       SMDS_TypeOfPosition posType;
2976       SMDS_ElemIteratorPtr itN = elem->nodesIterator();
2977       int nn = 0, nbn =  elem->NbNodes();
2978       if(elem->IsQuadratic())
2979         nbn = nbn/2;
2980       while ( nn++ < nbn ) {
2981         node = static_cast<const SMDS_MeshNode*>( itN->next() );
2982         const SMDS_PositionPtr& pos = node->GetPosition();
2983         posType = pos ? pos->GetTypeOfPosition() : SMDS_TOP_3DSPACE;
2984         if (posType != SMDS_TOP_EDGE &&
2985             posType != SMDS_TOP_VERTEX &&
2986             theFixedNodes.find( node ) == theFixedNodes.end())
2987         {
2988           // check if all faces around the node are on faceSubMesh
2989           // because a node on edge may be bound to face
2990           SMDS_ElemIteratorPtr eIt = node->GetInverseElementIterator(SMDSAbs_Face);
2991           bool all = true;
2992           if ( faceSubMesh ) {
2993             while ( eIt->more() && all ) {
2994               const SMDS_MeshElement* e = eIt->next();
2995               all = faceSubMesh->Contains( e );
2996             }
2997           }
2998           if ( all )
2999             setMovableNodes.insert( node );
3000           else
3001             checkBoundaryNodes = true;
3002         }
3003         if ( posType == SMDS_TOP_3DSPACE )
3004           checkBoundaryNodes = true;
3005       }
3006
3007       if ( surface.IsNull() )
3008         continue;
3009
3010       // get nodes to check UV
3011       list< const SMDS_MeshNode* > uvCheckNodes;
3012       itN = elem->nodesIterator();
3013       nn = 0; nbn =  elem->NbNodes();
3014       if(elem->IsQuadratic())
3015         nbn = nbn/2;
3016       while ( nn++ < nbn ) {
3017         node = static_cast<const SMDS_MeshNode*>( itN->next() );
3018         if ( uvMap.find( node ) == uvMap.end() )
3019           uvCheckNodes.push_back( node );
3020         // add nodes of elems sharing node
3021         //         SMDS_ElemIteratorPtr eIt = node->GetInverseElementIterator(SMDSAbs_Face);
3022         //         while ( eIt->more() ) {
3023         //           const SMDS_MeshElement* e = eIt->next();
3024         //           if ( e != elem ) {
3025         //             SMDS_ElemIteratorPtr nIt = e->nodesIterator();
3026         //             while ( nIt->more() ) {
3027         //               const SMDS_MeshNode* n =
3028         //                 static_cast<const SMDS_MeshNode*>( nIt->next() );
3029         //               if ( uvMap.find( n ) == uvMap.end() )
3030         //                 uvCheckNodes.push_back( n );
3031         //             }
3032         //           }
3033         //         }
3034       }
3035       // check UV on face
3036       list< const SMDS_MeshNode* >::iterator n = uvCheckNodes.begin();
3037       for ( ; n != uvCheckNodes.end(); ++n ) {
3038         node = *n;
3039         gp_XY uv( 0, 0 );
3040         const SMDS_PositionPtr& pos = node->GetPosition();
3041         posType = pos ? pos->GetTypeOfPosition() : SMDS_TOP_3DSPACE;
3042         // get existing UV
3043         switch ( posType ) {
3044         case SMDS_TOP_FACE: {
3045           SMDS_FacePosition* fPos = ( SMDS_FacePosition* ) pos;
3046           uv.SetCoord( fPos->GetUParameter(), fPos->GetVParameter() );
3047           break;
3048         }
3049         case SMDS_TOP_EDGE: {
3050           TopoDS_Shape S = aMesh->IndexToShape( node->getshapeId() );
3051           Handle(Geom2d_Curve) pcurve;
3052           if ( !S.IsNull() && S.ShapeType() == TopAbs_EDGE )
3053             pcurve = BRep_Tool::CurveOnSurface( TopoDS::Edge( S ), face, f,l );
3054           if ( !pcurve.IsNull() ) {
3055             double u = (( SMDS_EdgePosition* ) pos )->GetUParameter();
3056             uv = pcurve->Value( u ).XY();
3057           }
3058           break;
3059         }
3060         case SMDS_TOP_VERTEX: {
3061           TopoDS_Shape S = aMesh->IndexToShape( node->getshapeId() );
3062           if ( !S.IsNull() && S.ShapeType() == TopAbs_VERTEX )
3063             uv = BRep_Tool::Parameters( TopoDS::Vertex( S ), face ).XY();
3064           break;
3065         }
3066         default:;
3067         }
3068         // check existing UV
3069         bool project = true;
3070         gp_Pnt pNode ( node->X(), node->Y(), node->Z() );
3071         double dist1 = DBL_MAX, dist2 = 0;
3072         if ( posType != SMDS_TOP_3DSPACE ) {
3073           dist1 = pNode.SquareDistance( surface->Value( uv.X(), uv.Y() ));
3074           project = dist1 > fToler2;
3075         }
3076         if ( project ) { // compute new UV
3077           gp_XY newUV;
3078           if ( !getClosestUV( projector, pNode, newUV )) {
3079             MESSAGE("Node Projection Failed " << node);
3080           }
3081           else {
3082             if ( isUPeriodic )
3083               newUV.SetX( ElCLib::InPeriod( newUV.X(), u1, u2 ));
3084             if ( isVPeriodic )
3085               newUV.SetY( ElCLib::InPeriod( newUV.Y(), v1, v2 ));
3086             // check new UV
3087             if ( posType != SMDS_TOP_3DSPACE )
3088               dist2 = pNode.SquareDistance( surface->Value( newUV.X(), newUV.Y() ));
3089             if ( dist2 < dist1 )
3090               uv = newUV;
3091           }
3092         }
3093         // store UV in the map
3094         listUV.push_back( uv );
3095         uvMap.insert( make_pair( node, &listUV.back() ));
3096       }
3097     } // loop on not yet smoothed elements
3098
3099     if ( !faceSubMesh || nbElemOnFace != faceSubMesh->NbElements() )
3100       checkBoundaryNodes = true;
3101
3102     // fix nodes on mesh boundary
3103
3104     if ( checkBoundaryNodes ) {
3105       map< NLink, int > linkNbMap; // how many times a link encounters in elemsOnFace
3106       map< NLink, int >::iterator link_nb;
3107       // put all elements links to linkNbMap
3108       list< const SMDS_MeshElement* >::iterator elemIt = elemsOnFace.begin();
3109       for ( ; elemIt != elemsOnFace.end(); ++elemIt ) {
3110         const SMDS_MeshElement* elem = (*elemIt);
3111         int nbn =  elem->NbNodes();
3112         if(elem->IsQuadratic())
3113           nbn = nbn/2;
3114         // loop on elem links: insert them in linkNbMap
3115         const SMDS_MeshNode* curNode, *prevNode = elem->GetNodeWrap( nbn );
3116         for ( int iN = 0; iN < nbn; ++iN ) {
3117           curNode = elem->GetNode( iN );
3118           NLink link;
3119           if ( curNode < prevNode ) link = make_pair( curNode , prevNode );
3120           else                      link = make_pair( prevNode , curNode );
3121           prevNode = curNode;
3122           link_nb = linkNbMap.find( link );
3123           if ( link_nb == linkNbMap.end() )
3124             linkNbMap.insert( make_pair ( link, 1 ));
3125           else
3126             link_nb->second++;
3127         }
3128       }
3129       // remove nodes that are in links encountered only once from setMovableNodes
3130       for ( link_nb = linkNbMap.begin(); link_nb != linkNbMap.end(); ++link_nb ) {
3131         if ( link_nb->second == 1 ) {
3132           setMovableNodes.erase( link_nb->first.first );
3133           setMovableNodes.erase( link_nb->first.second );
3134         }
3135       }
3136     }
3137
3138     // -----------------------------------------------------
3139     // for nodes on seam edge, compute one more UV ( uvMap2 );
3140     // find movable nodes linked to nodes on seam and which
3141     // are to be smoothed using the second UV ( uvMap2 )
3142     // -----------------------------------------------------
3143
3144     set<const SMDS_MeshNode*> nodesNearSeam; // to smooth using uvMap2
3145     if ( !surface.IsNull() ) {
3146       TopExp_Explorer eExp( face, TopAbs_EDGE );
3147       for ( ; eExp.More(); eExp.Next() ) {
3148         TopoDS_Edge edge = TopoDS::Edge( eExp.Current() );
3149         if ( !BRep_Tool::IsClosed( edge, face ))
3150           continue;
3151         SMESHDS_SubMesh* sm = aMesh->MeshElements( edge );
3152         if ( !sm ) continue;
3153         // find out which parameter varies for a node on seam
3154         double f,l;
3155         gp_Pnt2d uv1, uv2;
3156         Handle(Geom2d_Curve) pcurve = BRep_Tool::CurveOnSurface( edge, face, f, l );
3157         if ( pcurve.IsNull() ) continue;
3158         uv1 = pcurve->Value( f );
3159         edge.Reverse();
3160         pcurve = BRep_Tool::CurveOnSurface( edge, face, f, l );
3161         if ( pcurve.IsNull() ) continue;
3162         uv2 = pcurve->Value( f );
3163         int iPar = Abs( uv1.X() - uv2.X() ) > Abs( uv1.Y() - uv2.Y() ) ? 1 : 2;
3164         // assure uv1 < uv2
3165         if ( uv1.Coord( iPar ) > uv2.Coord( iPar )) {
3166           gp_Pnt2d tmp = uv1; uv1 = uv2; uv2 = tmp;
3167         }
3168         // get nodes on seam and its vertices
3169         list< const SMDS_MeshNode* > seamNodes;
3170         SMDS_NodeIteratorPtr nSeamIt = sm->GetNodes();
3171         while ( nSeamIt->more() ) {
3172           const SMDS_MeshNode* node = nSeamIt->next();
3173           if ( !isQuadratic || !IsMedium( node ))
3174             seamNodes.push_back( node );
3175         }
3176         TopExp_Explorer vExp( edge, TopAbs_VERTEX );
3177         for ( ; vExp.More(); vExp.Next() ) {
3178           sm = aMesh->MeshElements( vExp.Current() );
3179           if ( sm ) {
3180             nSeamIt = sm->GetNodes();
3181             while ( nSeamIt->more() )
3182               seamNodes.push_back( nSeamIt->next() );
3183           }
3184         }
3185         // loop on nodes on seam
3186         list< const SMDS_MeshNode* >::iterator noSeIt = seamNodes.begin();
3187         for ( ; noSeIt != seamNodes.end(); ++noSeIt ) {
3188           const SMDS_MeshNode* nSeam = *noSeIt;
3189           map< const SMDS_MeshNode*, gp_XY* >::iterator n_uv = uvMap.find( nSeam );
3190           if ( n_uv == uvMap.end() )
3191             continue;
3192           // set the first UV
3193           n_uv->second->SetCoord( iPar, uv1.Coord( iPar ));
3194           // set the second UV
3195           listUV.push_back( *n_uv->second );
3196           listUV.back().SetCoord( iPar, uv2.Coord( iPar ));
3197           if ( uvMap2.empty() )
3198             uvMap2 = uvMap; // copy the uvMap contents
3199           uvMap2[ nSeam ] = &listUV.back();
3200
3201           // collect movable nodes linked to ones on seam in nodesNearSeam
3202           SMDS_ElemIteratorPtr eIt = nSeam->GetInverseElementIterator(SMDSAbs_Face);
3203           while ( eIt->more() ) {
3204             const SMDS_MeshElement* e = eIt->next();
3205             int nbUseMap1 = 0, nbUseMap2 = 0;
3206             SMDS_ElemIteratorPtr nIt = e->nodesIterator();
3207             int nn = 0, nbn =  e->NbNodes();
3208             if(e->IsQuadratic()) nbn = nbn/2;
3209             while ( nn++ < nbn )
3210             {
3211               const SMDS_MeshNode* n =
3212                 static_cast<const SMDS_MeshNode*>( nIt->next() );
3213               if (n == nSeam ||
3214                   setMovableNodes.find( n ) == setMovableNodes.end() )
3215                 continue;
3216               // add only nodes being closer to uv2 than to uv1
3217               gp_Pnt pMid (0.5 * ( n->X() + nSeam->X() ),
3218                            0.5 * ( n->Y() + nSeam->Y() ),
3219                            0.5 * ( n->Z() + nSeam->Z() ));
3220               gp_XY uv;
3221               getClosestUV( projector, pMid, uv );
3222               if ( uv.Coord( iPar ) > uvMap[ n ]->Coord( iPar ) ) {
3223                 nodesNearSeam.insert( n );
3224                 nbUseMap2++;
3225               }
3226               else
3227                 nbUseMap1++;
3228             }
3229             // for centroidalSmooth all element nodes must
3230             // be on one side of a seam
3231             if ( theSmoothMethod == CENTROIDAL && nbUseMap1 && nbUseMap2 ) {
3232               SMDS_ElemIteratorPtr nIt = e->nodesIterator();
3233               nn = 0;
3234               while ( nn++ < nbn ) {
3235                 const SMDS_MeshNode* n =
3236                   static_cast<const SMDS_MeshNode*>( nIt->next() );
3237                 setMovableNodes.erase( n );
3238               }
3239             }
3240           }
3241         } // loop on nodes on seam
3242       } // loop on edge of a face
3243     } // if ( !face.IsNull() )
3244
3245     if ( setMovableNodes.empty() ) {
3246       MESSAGE( "Face id : " << *fId << " - NO SMOOTHING: no nodes to move!!!");
3247       continue; // goto next face
3248     }
3249
3250     // -------------
3251     // SMOOTHING //
3252     // -------------
3253
3254     int it = -1;
3255     double maxRatio = -1., maxDisplacement = -1.;
3256     set<const SMDS_MeshNode*>::iterator nodeToMove;
3257     for ( it = 0; it < theNbIterations; it++ ) {
3258       maxDisplacement = 0.;
3259       nodeToMove = setMovableNodes.begin();
3260       for ( ; nodeToMove != setMovableNodes.end(); nodeToMove++ ) {
3261         const SMDS_MeshNode* node = (*nodeToMove);
3262         gp_XYZ aPrevPos ( node->X(), node->Y(), node->Z() );
3263
3264         // smooth
3265         bool map2 = ( nodesNearSeam.find( node ) != nodesNearSeam.end() );
3266         if ( theSmoothMethod == LAPLACIAN )
3267           laplacianSmooth( node, surface, map2 ? uvMap2 : uvMap );
3268         else
3269           centroidalSmooth( node, surface, map2 ? uvMap2 : uvMap );
3270
3271         // node displacement
3272         gp_XYZ aNewPos ( node->X(), node->Y(), node->Z() );
3273         Standard_Real aDispl = (aPrevPos - aNewPos).SquareModulus();
3274         if ( aDispl > maxDisplacement )
3275           maxDisplacement = aDispl;
3276       }
3277       // no node movement => exit
3278       //if ( maxDisplacement < 1.e-16 ) {
3279       if ( maxDisplacement < disttol ) {
3280         MESSAGE("-- no node movement --");
3281         break;
3282       }
3283
3284       // check elements quality
3285       maxRatio  = 0;
3286       list< const SMDS_MeshElement* >::iterator elemIt = elemsOnFace.begin();
3287       for ( ; elemIt != elemsOnFace.end(); ++elemIt ) {
3288         const SMDS_MeshElement* elem = (*elemIt);
3289         if ( !elem || elem->GetType() != SMDSAbs_Face )
3290           continue;
3291         SMESH::Controls::TSequenceOfXYZ aPoints;
3292         if ( aQualityFunc.GetPoints( elem, aPoints )) {
3293           double aValue = aQualityFunc.GetValue( aPoints );
3294           if ( aValue > maxRatio )
3295             maxRatio = aValue;
3296         }
3297       }
3298       if ( maxRatio <= theTgtAspectRatio ) {
3299         MESSAGE("-- quality achived --");
3300         break;
3301       }
3302       if (it+1 == theNbIterations) {
3303         MESSAGE("-- Iteration limit exceeded --");
3304       }
3305     } // smoothing iterations
3306
3307     MESSAGE(" Face id: " << *fId <<
3308             " Nb iterstions: " << it <<
3309             " Displacement: " << maxDisplacement <<
3310             " Aspect Ratio " << maxRatio);
3311
3312     // ---------------------------------------
3313     // new nodes positions are computed,
3314     // record movement in DS and set new UV
3315     // ---------------------------------------
3316     nodeToMove = setMovableNodes.begin();
3317     for ( ; nodeToMove != setMovableNodes.end(); nodeToMove++ ) {
3318       SMDS_MeshNode* node = const_cast< SMDS_MeshNode* > (*nodeToMove);
3319       aMesh->MoveNode( node, node->X(), node->Y(), node->Z() );
3320       map< const SMDS_MeshNode*, gp_XY* >::iterator node_uv = uvMap.find( node );
3321       if ( node_uv != uvMap.end() ) {
3322         gp_XY* uv = node_uv->second;
3323         node->SetPosition
3324           ( SMDS_PositionPtr( new SMDS_FacePosition( uv->X(), uv->Y() )));
3325       }
3326     }
3327
3328     // move medium nodes of quadratic elements
3329     if ( isQuadratic )
3330     {
3331       SMESH_MesherHelper helper( *GetMesh() );
3332       if ( !face.IsNull() )
3333         helper.SetSubShape( face );
3334       list< const SMDS_MeshElement* >::iterator elemIt = elemsOnFace.begin();
3335       for ( ; elemIt != elemsOnFace.end(); ++elemIt ) {
3336         const SMDS_VtkFace* QF =
3337           dynamic_cast<const SMDS_VtkFace*> (*elemIt);
3338         if(QF && QF->IsQuadratic()) {
3339           vector<const SMDS_MeshNode*> Ns;
3340           Ns.reserve(QF->NbNodes()+1);
3341           SMDS_ElemIteratorPtr anIter = QF->interlacedNodesElemIterator();
3342           while ( anIter->more() )
3343             Ns.push_back( cast2Node(anIter->next()) );
3344           Ns.push_back( Ns[0] );
3345           double x, y, z;
3346           for(int i=0; i<QF->NbNodes(); i=i+2) {
3347             if ( !surface.IsNull() ) {
3348               gp_XY uv1 = helper.GetNodeUV( face, Ns[i], Ns[i+2] );
3349               gp_XY uv2 = helper.GetNodeUV( face, Ns[i+2], Ns[i] );
3350               gp_XY uv = ( uv1 + uv2 ) / 2.;
3351               gp_Pnt xyz = surface->Value( uv.X(), uv.Y() );
3352               x = xyz.X(); y = xyz.Y(); z = xyz.Z();
3353             }
3354             else {
3355               x = (Ns[i]->X() + Ns[i+2]->X())/2;
3356               y = (Ns[i]->Y() + Ns[i+2]->Y())/2;
3357               z = (Ns[i]->Z() + Ns[i+2]->Z())/2;
3358             }
3359             if( fabs( Ns[i+1]->X() - x ) > disttol ||
3360                 fabs( Ns[i+1]->Y() - y ) > disttol ||
3361                 fabs( Ns[i+1]->Z() - z ) > disttol ) {
3362               // we have to move i+1 node
3363               aMesh->MoveNode( Ns[i+1], x, y, z );
3364             }
3365           }
3366         }
3367       }
3368     }
3369
3370   } // loop on face ids
3371
3372 }
3373
3374 //=======================================================================
3375 //function : isReverse
3376 //purpose  : Return true if normal of prevNodes is not co-directied with
3377 //           gp_Vec(prevNodes[iNotSame],nextNodes[iNotSame]).
3378 //           iNotSame is where prevNodes and nextNodes are different
3379 //=======================================================================
3380
3381 static bool isReverse(vector<const SMDS_MeshNode*> prevNodes,
3382                       vector<const SMDS_MeshNode*> nextNodes,
3383                       const int            nbNodes,
3384                       const int            iNotSame)
3385 {
3386   int iBeforeNotSame = ( iNotSame == 0 ? nbNodes - 1 : iNotSame - 1 );
3387   int iAfterNotSame  = ( iNotSame + 1 == nbNodes ? 0 : iNotSame + 1 );
3388
3389   const SMDS_MeshNode* nB = prevNodes[ iBeforeNotSame ];
3390   const SMDS_MeshNode* nA = prevNodes[ iAfterNotSame ];
3391   const SMDS_MeshNode* nP = prevNodes[ iNotSame ];
3392   const SMDS_MeshNode* nN = nextNodes[ iNotSame ];
3393
3394   gp_Pnt pB ( nB->X(), nB->Y(), nB->Z() );
3395   gp_Pnt pA ( nA->X(), nA->Y(), nA->Z() );
3396   gp_Pnt pP ( nP->X(), nP->Y(), nP->Z() );
3397   gp_Pnt pN ( nN->X(), nN->Y(), nN->Z() );
3398
3399   gp_Vec vB ( pP, pB ), vA ( pP, pA ), vN ( pP, pN );
3400
3401   return (vA ^ vB) * vN < 0.0;
3402 }
3403
3404 //=======================================================================
3405 /*!
3406  * \brief Create elements by sweeping an element
3407  * \param elem - element to sweep
3408  * \param newNodesItVec - nodes generated from each node of the element
3409  * \param newElems - generated elements
3410  * \param nbSteps - number of sweeping steps
3411  * \param srcElements - to append elem for each generated element
3412  */
3413 //=======================================================================
3414
3415 void SMESH_MeshEditor::sweepElement(const SMDS_MeshElement*               elem,
3416                                     const vector<TNodeOfNodeListMapItr> & newNodesItVec,
3417                                     list<const SMDS_MeshElement*>&        newElems,
3418                                     const int                             nbSteps,
3419                                     SMESH_SequenceOfElemPtr&              srcElements)
3420 {
3421   //MESSAGE("sweepElement " << nbSteps);
3422   SMESHDS_Mesh* aMesh = GetMeshDS();
3423
3424   // Loop on elem nodes:
3425   // find new nodes and detect same nodes indices
3426   int nbNodes = elem->NbNodes();
3427   vector < list< const SMDS_MeshNode* >::const_iterator > itNN( nbNodes );
3428   vector<const SMDS_MeshNode*> prevNod( nbNodes );
3429   vector<const SMDS_MeshNode*> nextNod( nbNodes );
3430   vector<const SMDS_MeshNode*> midlNod( nbNodes );
3431
3432   int iNode, nbSame = 0, iNotSameNode = 0, iSameNode = 0;
3433   vector<int> sames(nbNodes);
3434   vector<bool> issimple(nbNodes);
3435
3436   for ( iNode = 0; iNode < nbNodes; iNode++ ) {
3437     TNodeOfNodeListMapItr nnIt = newNodesItVec[ iNode ];
3438     const SMDS_MeshNode*                 node         = nnIt->first;
3439     const list< const SMDS_MeshNode* > & listNewNodes = nnIt->second;
3440     if ( listNewNodes.empty() ) {
3441       return;
3442     }
3443
3444     issimple[iNode] = (listNewNodes.size()==nbSteps); // is node medium
3445
3446     itNN[ iNode ] = listNewNodes.begin();
3447     prevNod[ iNode ] = node;
3448     nextNod[ iNode ] = listNewNodes.front();
3449     if( !elem->IsQuadratic() || !issimple[iNode] ) {
3450       if ( prevNod[ iNode ] != nextNod [ iNode ])
3451         iNotSameNode = iNode;
3452       else {
3453         iSameNode = iNode;
3454         //nbSame++;
3455         sames[nbSame++] = iNode;
3456       }
3457     }
3458   }
3459
3460   //cerr<<"  nbSame = "<<nbSame<<endl;
3461   if ( nbSame == nbNodes || nbSame > 2) {
3462     MESSAGE( " Too many same nodes of element " << elem->GetID() );
3463     //INFOS( " Too many same nodes of element " << elem->GetID() );
3464     return;
3465   }
3466
3467   //  if( elem->IsQuadratic() && nbSame>0 ) {
3468   //    MESSAGE( "Can not rotate quadratic element " << elem->GetID() );
3469   //    return;
3470   //  }
3471
3472   int iBeforeSame = 0, iAfterSame = 0, iOpposSame = 0;
3473   int nbBaseNodes = ( elem->IsQuadratic() ? nbNodes/2 : nbNodes );
3474   if ( nbSame > 0 ) {
3475     iBeforeSame = ( iSameNode == 0 ? nbBaseNodes - 1 : iSameNode - 1 );
3476     iAfterSame  = ( iSameNode + 1 == nbBaseNodes ? 0 : iSameNode + 1 );
3477     iOpposSame  = ( iSameNode - 2 < 0  ? iSameNode + 2 : iSameNode - 2 );
3478   }
3479
3480   //if(nbNodes==8)
3481   //cout<<" prevNod[0]="<< prevNod[0]<<" prevNod[1]="<< prevNod[1]
3482   //    <<" prevNod[2]="<< prevNod[2]<<" prevNod[3]="<< prevNod[4]
3483   //    <<" prevNod[4]="<< prevNod[4]<<" prevNod[5]="<< prevNod[5]
3484   //    <<" prevNod[6]="<< prevNod[6]<<" prevNod[7]="<< prevNod[7]<<endl;
3485
3486   // check element orientation
3487   int i0 = 0, i2 = 2;
3488   if ( nbNodes > 2 && !isReverse( prevNod, nextNod, nbNodes, iNotSameNode )) {
3489     //MESSAGE("Reversed elem " << elem );
3490     i0 = 2;
3491     i2 = 0;
3492     if ( nbSame > 0 )
3493       std::swap( iBeforeSame, iAfterSame );
3494   }
3495
3496   // make new elements
3497   const SMDS_MeshElement* lastElem = elem;
3498   for (int iStep = 0; iStep < nbSteps; iStep++ ) {
3499     // get next nodes
3500     for ( iNode = 0; iNode < nbNodes; iNode++ ) {
3501       if(issimple[iNode]) {
3502         nextNod[ iNode ] = *itNN[ iNode ];
3503         itNN[ iNode ]++;
3504       }
3505       else {
3506         if( elem->GetType()==SMDSAbs_Node ) {
3507           // we have to use two nodes
3508           midlNod[ iNode ] = *itNN[ iNode ];
3509           itNN[ iNode ]++;
3510           nextNod[ iNode ] = *itNN[ iNode ];
3511           itNN[ iNode ]++;
3512         }
3513         else if(!elem->IsQuadratic() || lastElem->IsMediumNode(prevNod[iNode]) ) {
3514           // we have to use each second node
3515           //itNN[ iNode ]++;
3516           nextNod[ iNode ] = *itNN[ iNode ];
3517           itNN[ iNode ]++;
3518         }
3519         else {
3520           // we have to use two nodes
3521           midlNod[ iNode ] = *itNN[ iNode ];
3522           itNN[ iNode ]++;
3523           nextNod[ iNode ] = *itNN[ iNode ];
3524           itNN[ iNode ]++;
3525         }
3526       }
3527     }
3528     SMDS_MeshElement* aNewElem = 0;
3529     if(!elem->IsPoly()) {
3530       switch ( nbNodes ) {
3531       case 0:
3532         return;
3533       case 1: { // NODE
3534         if ( nbSame == 0 ) {
3535           if(issimple[0])
3536             aNewElem = aMesh->AddEdge( prevNod[ 0 ], nextNod[ 0 ] );
3537           else
3538             aNewElem = aMesh->AddEdge( prevNod[ 0 ], nextNod[ 0 ], midlNod[ 0 ] );
3539         }
3540         break;
3541       }
3542       case 2: { // EDGE
3543         if ( nbSame == 0 )
3544           aNewElem = aMesh->AddFace(prevNod[ 0 ], prevNod[ 1 ],
3545                                     nextNod[ 1 ], nextNod[ 0 ] );
3546         else
3547           aNewElem = aMesh->AddFace(prevNod[ 0 ], prevNod[ 1 ],
3548                                     nextNod[ iNotSameNode ] );
3549         break;
3550       }
3551
3552       case 3: { // TRIANGLE or quadratic edge
3553         if(elem->GetType() == SMDSAbs_Face) { // TRIANGLE
3554
3555           if ( nbSame == 0 )       // --- pentahedron
3556             aNewElem = aMesh->AddVolume (prevNod[ i0 ], prevNod[ 1 ], prevNod[ i2 ],
3557                                          nextNod[ i0 ], nextNod[ 1 ], nextNod[ i2 ] );
3558
3559           else if ( nbSame == 1 )  // --- pyramid
3560             aNewElem = aMesh->AddVolume (prevNod[ iBeforeSame ],  prevNod[ iAfterSame ],
3561                                          nextNod[ iAfterSame ], nextNod[ iBeforeSame ],
3562                                          nextNod[ iSameNode ]);
3563
3564           else // 2 same nodes:      --- tetrahedron
3565             aNewElem = aMesh->AddVolume (prevNod[ i0 ], prevNod[ 1 ], prevNod[ i2 ],
3566                                          nextNod[ iNotSameNode ]);
3567         }
3568         else { // quadratic edge
3569           if(nbSame==0) {     // quadratic quadrangle
3570             aNewElem = aMesh->AddFace(prevNod[0], nextNod[0], nextNod[1], prevNod[1],
3571                                       midlNod[0], nextNod[2], midlNod[1], prevNod[2]);
3572           }
3573           else if(nbSame==1) { // quadratic triangle
3574             if(sames[0]==2) {
3575               return; // medium node on axis
3576             }
3577             else if(sames[0]==0) {
3578               aNewElem = aMesh->AddFace(prevNod[0], nextNod[1], prevNod[1],
3579                                         nextNod[2], midlNod[1], prevNod[2]);
3580             }
3581             else { // sames[0]==1
3582               aNewElem = aMesh->AddFace(prevNod[0], nextNod[0], prevNod[1],
3583                                         midlNod[0], nextNod[2], prevNod[2]);
3584             }
3585           }
3586           else {
3587             return;
3588           }
3589         }
3590         break;
3591       }
3592       case 4: { // QUADRANGLE
3593
3594         if ( nbSame == 0 )       // --- hexahedron
3595           aNewElem = aMesh->AddVolume (prevNod[ i0 ], prevNod[ 1 ], prevNod[ i2 ], prevNod[ 3 ],
3596                                        nextNod[ i0 ], nextNod[ 1 ], nextNod[ i2 ], nextNod[ 3 ]);
3597
3598         else if ( nbSame == 1 ) { // --- pyramid + pentahedron
3599           aNewElem = aMesh->AddVolume (prevNod[ iBeforeSame ],  prevNod[ iAfterSame ],
3600                                        nextNod[ iAfterSame ], nextNod[ iBeforeSame ],
3601                                        nextNod[ iSameNode ]);
3602           newElems.push_back( aNewElem );
3603           aNewElem = aMesh->AddVolume (prevNod[ iAfterSame ], prevNod[ iOpposSame ],
3604                                        prevNod[ iBeforeSame ],  nextNod[ iAfterSame ],
3605                                        nextNod[ iOpposSame ],  nextNod[ iBeforeSame ] );
3606         }
3607         else if ( nbSame == 2 ) { // pentahedron
3608           if ( prevNod[ iBeforeSame ] == nextNod[ iBeforeSame ] )
3609             // iBeforeSame is same too
3610             aNewElem = aMesh->AddVolume (prevNod[ iBeforeSame ], prevNod[ iOpposSame ],
3611                                          nextNod[ iOpposSame ], prevNod[ iSameNode ],
3612                                          prevNod[ iAfterSame ],  nextNod[ iAfterSame ]);
3613           else
3614             // iAfterSame is same too
3615             aNewElem = aMesh->AddVolume (prevNod[ iSameNode ], prevNod[ iBeforeSame ],
3616                                          nextNod[ iBeforeSame ], prevNod[ iAfterSame ],
3617                                          prevNod[ iOpposSame ],  nextNod[ iOpposSame ]);
3618         }
3619         break;
3620       }
3621       case 6: { // quadratic triangle
3622         // create pentahedron with 15 nodes
3623         if(nbSame==0) {
3624           if(i0>0) { // reversed case
3625             aNewElem = aMesh->AddVolume (prevNod[0], prevNod[2], prevNod[1],
3626                                          nextNod[0], nextNod[2], nextNod[1],
3627                                          prevNod[5], prevNod[4], prevNod[3],
3628                                          nextNod[5], nextNod[4], nextNod[3],
3629                                          midlNod[0], midlNod[2], midlNod[1]);
3630           }
3631           else { // not reversed case
3632             aNewElem = aMesh->AddVolume (prevNod[0], prevNod[1], prevNod[2],
3633                                          nextNod[0], nextNod[1], nextNod[2],
3634                                          prevNod[3], prevNod[4], prevNod[5],
3635                                          nextNod[3], nextNod[4], nextNod[5],
3636                                          midlNod[0], midlNod[1], midlNod[2]);
3637           }
3638         }
3639         else if(nbSame==1) {
3640           // 2d order pyramid of 13 nodes
3641           //SMDS_MeshVolume* AddVolumeWithID(int n1, int n2, int n3, int n4, int n5,
3642           //                                 int n12,int n23,int n34,int n41,
3643           //                                 int n15,int n25,int n35,int n45, int ID);
3644           int n5 = iSameNode;
3645           int n1,n4,n41,n15,n45;
3646           if(i0>0) { // reversed case
3647             n1 = ( n5 + 1 == nbBaseNodes ? 0 : n5 + 1 );
3648             n4 = ( n5 == 0 ? nbBaseNodes - 1 : n5 - 1 );
3649             n41 = n1 + 3;
3650             n15 = n5 + 3;
3651             n45 = n4 + 3;
3652           }
3653           else {
3654             n1 = ( n5 == 0 ? nbBaseNodes - 1 : n5 - 1 );
3655             n4 = ( n5 + 1 == nbBaseNodes ? 0 : n5 + 1 );
3656             n41 = n4 + 3;
3657             n15 = n1 + 3;
3658             n45 = n5 + 3;
3659           }
3660           aNewElem = aMesh->AddVolume(prevNod[n1], nextNod[n1],
3661                                       nextNod[n4], prevNod[n4], prevNod[n5],
3662                                       midlNod[n1], nextNod[n41],
3663                                       midlNod[n4], prevNod[n41],
3664                                       prevNod[n15], nextNod[n15],
3665                                       nextNod[n45], prevNod[n45]);
3666         }
3667         else if(nbSame==2) {
3668           // 2d order tetrahedron of 10 nodes
3669           //SMDS_MeshVolume* AddVolumeWithID(int n1, int n2, int n3, int n4,
3670           //                                 int n12,int n23,int n31,
3671           //                                 int n14,int n24,int n34, int ID);
3672           int n1 = iNotSameNode;
3673           int n2,n3,n12,n23,n31;
3674           if(i0>0) { // reversed case
3675             n2 = ( n1 == 0 ? nbBaseNodes - 1 : n1 - 1 );
3676             n3 = ( n1 + 1 == nbBaseNodes ? 0 : n1 + 1 );
3677             n12 = n2 + 3;
3678             n23 = n3 + 3;
3679             n31 = n1 + 3;
3680           }
3681           else {
3682             n2 = ( n1 + 1 == nbBaseNodes ? 0 : n1 + 1 );
3683             n3 = ( n1 == 0 ? nbBaseNodes - 1 : n1 - 1 );
3684             n12 = n1 + 3;
3685             n23 = n2 + 3;
3686             n31 = n3 + 3;
3687           }
3688           aNewElem = aMesh->AddVolume (prevNod[n1], prevNod[n2], prevNod[n3], nextNod[n1],
3689                                        prevNod[n12], prevNod[n23], prevNod[n31],
3690                                        midlNod[n1], nextNod[n12], nextNod[n31]);
3691         }
3692         break;
3693       }
3694       case 8: { // quadratic quadrangle
3695         if(nbSame==0) {
3696           // create hexahedron with 20 nodes
3697           if(i0>0) { // reversed case
3698             aNewElem = aMesh->AddVolume (prevNod[0], prevNod[3], prevNod[2], prevNod[1],
3699                                          nextNod[0], nextNod[3], nextNod[2], nextNod[1],
3700                                          prevNod[7], prevNod[6], prevNod[5], prevNod[4],
3701                                          nextNod[7], nextNod[6], nextNod[5], nextNod[4],
3702                                          midlNod[0], midlNod[3], midlNod[2], midlNod[1]);
3703           }
3704           else { // not reversed case
3705             aNewElem = aMesh->AddVolume (prevNod[0], prevNod[1], prevNod[2], prevNod[3],
3706                                          nextNod[0], nextNod[1], nextNod[2], nextNod[3],
3707                                          prevNod[4], prevNod[5], prevNod[6], prevNod[7],
3708                                          nextNod[4], nextNod[5], nextNod[6], nextNod[7],
3709                                          midlNod[0], midlNod[1], midlNod[2], midlNod[3]);
3710           }
3711         }
3712         else if(nbSame==1) { 
3713           // --- pyramid + pentahedron - can not be created since it is needed 
3714           // additional middle node ot the center of face
3715           INFOS( " Sweep for face " << elem->GetID() << " can not be created" );
3716           return;
3717         }
3718         else if(nbSame==2) {
3719           // 2d order Pentahedron with 15 nodes
3720           //SMDS_MeshVolume* AddVolumeWithID(int n1, int n2, int n3, int n4, int n5, int n6,
3721           //                                 int n12,int n23,int n31,int n45,int n56,int n64,
3722           //                                 int n14,int n25,int n36, int ID);
3723           int n1,n2,n4,n5;
3724           if ( prevNod[ iBeforeSame ] == nextNod[ iBeforeSame ] ) {
3725             // iBeforeSame is same too
3726             n1 = iBeforeSame;
3727             n2 = iOpposSame;
3728             n4 = iSameNode;
3729             n5 = iAfterSame;
3730           }
3731           else {
3732             // iAfterSame is same too
3733             n1 = iSameNode;
3734             n2 = iBeforeSame;
3735             n4 = iAfterSame;
3736             n5 = iOpposSame;
3737           }
3738           int n12,n45,n14,n25;
3739           if(i0>0) { //reversed case
3740             n12 = n1 + 4;
3741             n45 = n5 + 4;
3742             n14 = n4 + 4;
3743             n25 = n2 + 4;
3744           }
3745           else {
3746             n12 = n2 + 4;
3747             n45 = n4 + 4;
3748             n14 = n1 + 4;
3749             n25 = n5 + 4;
3750           }
3751           aNewElem = aMesh->AddVolume (prevNod[n1], prevNod[n2], nextNod[n2],
3752                                        prevNod[n4], prevNod[n5], nextNod[n5],
3753                                        prevNod[n12], midlNod[n2], nextNod[n12],
3754                                        prevNod[n45], midlNod[n5], nextNod[n45],
3755                                        prevNod[n14], prevNod[n25], nextNod[n25]);
3756         }
3757         break;
3758       }
3759       default: {
3760         // realized for extrusion only
3761         //vector<const SMDS_MeshNode*> polyedre_nodes (nbNodes*2 + 4*nbNodes);
3762         //vector<int> quantities (nbNodes + 2);
3763
3764         //quantities[0] = nbNodes; // bottom of prism
3765         //for (int inode = 0; inode < nbNodes; inode++) {
3766         //  polyedre_nodes[inode] = prevNod[inode];
3767         //}
3768
3769         //quantities[1] = nbNodes; // top of prism
3770         //for (int inode = 0; inode < nbNodes; inode++) {
3771         //  polyedre_nodes[nbNodes + inode] = nextNod[inode];
3772         //}
3773
3774         //for (int iface = 0; iface < nbNodes; iface++) {
3775         //  quantities[iface + 2] = 4;
3776         //  int inextface = (iface == nbNodes - 1) ? 0 : iface + 1;
3777         //  polyedre_nodes[2*nbNodes + 4*iface + 0] = prevNod[iface];
3778         //  polyedre_nodes[2*nbNodes + 4*iface + 1] = prevNod[inextface];
3779         //  polyedre_nodes[2*nbNodes + 4*iface + 2] = nextNod[inextface];
3780         //  polyedre_nodes[2*nbNodes + 4*iface + 3] = nextNod[iface];
3781         //}
3782         //aNewElem = aMesh->AddPolyhedralVolume (polyedre_nodes, quantities);
3783         break;
3784       }
3785       }
3786     }
3787
3788     if(!aNewElem) {
3789       // realized for extrusion only
3790       vector<const SMDS_MeshNode*> polyedre_nodes (nbNodes*2 + 4*nbNodes);
3791       vector<int> quantities (nbNodes + 2);
3792
3793       quantities[0] = nbNodes; // bottom of prism
3794       for (int inode = 0; inode < nbNodes; inode++) {
3795         polyedre_nodes[inode] = prevNod[inode];
3796       }
3797
3798       quantities[1] = nbNodes; // top of prism
3799       for (int inode = 0; inode < nbNodes; inode++) {
3800         polyedre_nodes[nbNodes + inode] = nextNod[inode];
3801       }
3802
3803       for (int iface = 0; iface < nbNodes; iface++) {
3804         quantities[iface + 2] = 4;
3805         int inextface = (iface == nbNodes - 1) ? 0 : iface + 1;
3806         polyedre_nodes[2*nbNodes + 4*iface + 0] = prevNod[iface];
3807         polyedre_nodes[2*nbNodes + 4*iface + 1] = prevNod[inextface];
3808         polyedre_nodes[2*nbNodes + 4*iface + 2] = nextNod[inextface];
3809         polyedre_nodes[2*nbNodes + 4*iface + 3] = nextNod[iface];
3810       }
3811       aNewElem = aMesh->AddPolyhedralVolume (polyedre_nodes, quantities);
3812     }
3813
3814     if ( aNewElem ) {
3815       newElems.push_back( aNewElem );
3816       myLastCreatedElems.Append(aNewElem);
3817       srcElements.Append( elem );
3818       lastElem = aNewElem;
3819     }
3820
3821     // set new prev nodes
3822     for ( iNode = 0; iNode < nbNodes; iNode++ )
3823       prevNod[ iNode ] = nextNod[ iNode ];
3824
3825   } // for steps
3826 }
3827
3828 //=======================================================================
3829 /*!
3830  * \brief Create 1D and 2D elements around swept elements
3831  * \param mapNewNodes - source nodes and ones generated from them
3832  * \param newElemsMap - source elements and ones generated from them
3833  * \param elemNewNodesMap - nodes generated from each node of each element
3834  * \param elemSet - all swept elements
3835  * \param nbSteps - number of sweeping steps
3836  * \param srcElements - to append elem for each generated element
3837  */
3838 //=======================================================================
3839
3840 void SMESH_MeshEditor::makeWalls (TNodeOfNodeListMap &     mapNewNodes,
3841                                   TElemOfElemListMap &     newElemsMap,
3842                                   TElemOfVecOfNnlmiMap &   elemNewNodesMap,
3843                                   TIDSortedElemSet&        elemSet,
3844                                   const int                nbSteps,
3845                                   SMESH_SequenceOfElemPtr& srcElements)
3846 {
3847   MESSAGE("makeWalls");
3848   ASSERT( newElemsMap.size() == elemNewNodesMap.size() );
3849   SMESHDS_Mesh* aMesh = GetMeshDS();
3850
3851   // Find nodes belonging to only one initial element - sweep them to get edges.
3852
3853   TNodeOfNodeListMapItr nList = mapNewNodes.begin();
3854   for ( ; nList != mapNewNodes.end(); nList++ ) {
3855     const SMDS_MeshNode* node =
3856       static_cast<const SMDS_MeshNode*>( nList->first );
3857     SMDS_ElemIteratorPtr eIt = node->GetInverseElementIterator();
3858     int nbInitElems = 0;
3859     const SMDS_MeshElement* el = 0;
3860     SMDSAbs_ElementType highType = SMDSAbs_Edge; // count most complex elements only
3861     while ( eIt->more() && nbInitElems < 2 ) {
3862       el = eIt->next();
3863       SMDSAbs_ElementType type = el->GetType();
3864       if ( type == SMDSAbs_Volume || type < highType ) continue;
3865       if ( type > highType ) {
3866         nbInitElems = 0;
3867         highType = type;
3868       }
3869       if ( elemSet.find(el) != elemSet.end() )
3870         nbInitElems++;
3871     }
3872     if ( nbInitElems < 2 ) {
3873       bool NotCreateEdge = el && el->IsQuadratic() && el->IsMediumNode(node);
3874       if(!NotCreateEdge) {
3875         vector<TNodeOfNodeListMapItr> newNodesItVec( 1, nList );
3876         list<const SMDS_MeshElement*> newEdges;
3877         sweepElement( node, newNodesItVec, newEdges, nbSteps, srcElements );
3878       }
3879     }
3880   }
3881
3882   // Make a ceiling for each element ie an equal element of last new nodes.
3883   // Find free links of faces - make edges and sweep them into faces.
3884
3885   TElemOfElemListMap::iterator   itElem      = newElemsMap.begin();
3886   TElemOfVecOfNnlmiMap::iterator itElemNodes = elemNewNodesMap.begin();
3887   for ( ; itElem != newElemsMap.end(); itElem++, itElemNodes++ ) {
3888     const SMDS_MeshElement* elem = itElem->first;
3889     vector<TNodeOfNodeListMapItr>& vecNewNodes = itElemNodes->second;
3890
3891     if(itElem->second.size()==0) continue;
3892
3893     if ( elem->GetType() == SMDSAbs_Edge ) {
3894       // create a ceiling edge
3895       if (!elem->IsQuadratic()) {
3896         if ( !aMesh->FindEdge( vecNewNodes[ 0 ]->second.back(),
3897                                vecNewNodes[ 1 ]->second.back())) {
3898           myLastCreatedElems.Append(aMesh->AddEdge(vecNewNodes[ 0 ]->second.back(),
3899                                                    vecNewNodes[ 1 ]->second.back()));
3900           srcElements.Append( myLastCreatedElems.Last() );
3901         }
3902       }
3903       else {
3904         if ( !aMesh->FindEdge( vecNewNodes[ 0 ]->second.back(),
3905                                vecNewNodes[ 1 ]->second.back(),
3906                                vecNewNodes[ 2 ]->second.back())) {
3907           myLastCreatedElems.Append(aMesh->AddEdge(vecNewNodes[ 0 ]->second.back(),
3908                                                    vecNewNodes[ 1 ]->second.back(),
3909                                                    vecNewNodes[ 2 ]->second.back()));
3910           srcElements.Append( myLastCreatedElems.Last() );
3911         }
3912       }
3913     }
3914     if ( elem->GetType() != SMDSAbs_Face )
3915       continue;
3916
3917     bool hasFreeLinks = false;
3918
3919     TIDSortedElemSet avoidSet;
3920     avoidSet.insert( elem );
3921
3922     set<const SMDS_MeshNode*> aFaceLastNodes;
3923     int iNode, nbNodes = vecNewNodes.size();
3924     if(!elem->IsQuadratic()) {
3925       // loop on the face nodes
3926       for ( iNode = 0; iNode < nbNodes; iNode++ ) {
3927         aFaceLastNodes.insert( vecNewNodes[ iNode ]->second.back() );
3928         // look for free links of the face
3929         int iNext = ( iNode + 1 == nbNodes ) ? 0 : iNode + 1;
3930         const SMDS_MeshNode* n1 = vecNewNodes[ iNode ]->first;
3931         const SMDS_MeshNode* n2 = vecNewNodes[ iNext ]->first;
3932         // check if a link is free
3933         if ( ! SMESH_MeshEditor::FindFaceInSet ( n1, n2, elemSet, avoidSet )) {
3934           hasFreeLinks = true;
3935           // make an edge and a ceiling for a new edge
3936           if ( !aMesh->FindEdge( n1, n2 )) {
3937             myLastCreatedElems.Append(aMesh->AddEdge( n1, n2 )); // free link edge
3938             srcElements.Append( myLastCreatedElems.Last() );
3939           }
3940           n1 = vecNewNodes[ iNode ]->second.back();
3941           n2 = vecNewNodes[ iNext ]->second.back();
3942           if ( !aMesh->FindEdge( n1, n2 )) {
3943             myLastCreatedElems.Append(aMesh->AddEdge( n1, n2 )); // ceiling edge
3944             srcElements.Append( myLastCreatedElems.Last() );
3945           }
3946         }
3947       }
3948     }
3949     else { // elem is quadratic face
3950       int nbn = nbNodes/2;
3951       for ( iNode = 0; iNode < nbn; iNode++ ) {
3952         aFaceLastNodes.insert( vecNewNodes[ iNode ]->second.back() );
3953         int iNext = ( iNode + 1 == nbn ) ? 0 : iNode + 1;
3954         const SMDS_MeshNode* n1 = vecNewNodes[ iNode ]->first;
3955         const SMDS_MeshNode* n2 = vecNewNodes[ iNext ]->first;
3956         // check if a link is free
3957         if ( ! SMESH_MeshEditor::FindFaceInSet ( n1, n2, elemSet, avoidSet )) {
3958           hasFreeLinks = true;
3959           // make an edge and a ceiling for a new edge
3960           // find medium node
3961           const SMDS_MeshNode* n3 = vecNewNodes[ iNode+nbn ]->first;
3962           if ( !aMesh->FindEdge( n1, n2, n3 )) {
3963             myLastCreatedElems.Append(aMesh->AddEdge( n1, n2, n3 )); // free link edge
3964             srcElements.Append( myLastCreatedElems.Last() );
3965           }
3966           n1 = vecNewNodes[ iNode ]->second.back();
3967           n2 = vecNewNodes[ iNext ]->second.back();
3968           n3 = vecNewNodes[ iNode+nbn ]->second.back();
3969           if ( !aMesh->FindEdge( n1, n2, n3 )) {
3970             myLastCreatedElems.Append(aMesh->AddEdge( n1, n2, n3 )); // ceiling edge
3971             srcElements.Append( myLastCreatedElems.Last() );
3972           }
3973         }
3974       }
3975       for ( iNode = nbn; iNode < 2*nbn; iNode++ ) {
3976         aFaceLastNodes.insert( vecNewNodes[ iNode ]->second.back() );
3977       }
3978     }
3979
3980     // sweep free links into faces
3981
3982     if ( hasFreeLinks )  {
3983       list<const SMDS_MeshElement*> & newVolumes = itElem->second;
3984       int iVol, volNb, nbVolumesByStep = newVolumes.size() / nbSteps;
3985
3986       set<const SMDS_MeshNode*> initNodeSet, topNodeSet, faceNodeSet;
3987       for ( iNode = 0; iNode < nbNodes; iNode++ ) {
3988         initNodeSet.insert( vecNewNodes[ iNode ]->first );
3989         topNodeSet .insert( vecNewNodes[ iNode ]->second.back() );
3990       }
3991       for ( volNb = 0; volNb < nbVolumesByStep; volNb++ ) {
3992         list<const SMDS_MeshElement*>::iterator v = newVolumes.begin();
3993         iVol = 0;
3994         while ( iVol++ < volNb ) v++;
3995         // find indices of free faces of a volume and their source edges
3996         list< int > freeInd;
3997         list< const SMDS_MeshElement* > srcEdges; // source edges of free faces
3998         SMDS_VolumeTool vTool( *v );
3999         int iF, nbF = vTool.NbFaces();
4000         for ( iF = 0; iF < nbF; iF ++ ) {
4001           if (vTool.IsFreeFace( iF ) &&
4002               vTool.GetFaceNodes( iF, faceNodeSet ) &&
4003               initNodeSet != faceNodeSet) // except an initial face
4004           {
4005             if ( nbSteps == 1 && faceNodeSet == topNodeSet )
4006               continue;
4007             freeInd.push_back( iF );
4008             // find source edge of a free face iF
4009             vector<const SMDS_MeshNode*> commonNodes; // shared by the initial and free faces
4010             commonNodes.resize( initNodeSet.size(), NULL ); // avoid spoiling memory
4011             std::set_intersection( faceNodeSet.begin(), faceNodeSet.end(),
4012                                    initNodeSet.begin(), initNodeSet.end(),
4013                                    commonNodes.begin());
4014             if ( (*v)->IsQuadratic() )
4015               srcEdges.push_back(aMesh->FindEdge (commonNodes[0],commonNodes[1],commonNodes[2]));
4016             else
4017               srcEdges.push_back(aMesh->FindEdge (commonNodes[0],commonNodes[1]));
4018 #ifdef _DEBUG_
4019             if ( !srcEdges.back() )
4020             {
4021               cout << "SMESH_MeshEditor::makeWalls(), no source edge found for a free face #"
4022                    << iF << " of volume #" << vTool.ID() << endl;
4023             }
4024 #endif
4025           }
4026         }
4027         if ( freeInd.empty() )
4028           continue;
4029
4030         // create faces for all steps;
4031         // if such a face has been already created by sweep of edge,
4032         // assure that its orientation is OK
4033         for ( int iStep = 0; iStep < nbSteps; iStep++ )  {
4034           vTool.Set( *v );
4035           vTool.SetExternalNormal();
4036           list< int >::iterator ind = freeInd.begin();
4037           list< const SMDS_MeshElement* >::iterator srcEdge = srcEdges.begin();
4038           for ( ; ind != freeInd.end(); ++ind, ++srcEdge ) // loop on free faces
4039           {
4040             const SMDS_MeshNode** nodes = vTool.GetFaceNodes( *ind );
4041             int nbn = vTool.NbFaceNodes( *ind );
4042             switch ( nbn ) {
4043             case 3: { ///// triangle
4044               const SMDS_MeshFace * f = aMesh->FindFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ]);
4045               if ( !f )
4046                 myLastCreatedElems.Append(aMesh->AddFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ] ));
4047               else if ( nodes[ 1 ] != f->GetNodeWrap( f->GetNodeIndex( nodes[ 0 ] ) + 1 ))
4048                 {
4049                   myLastCreatedElems.Append(aMesh->AddFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ] ));
4050                   aMesh->RemoveElement(f);
4051                 }
4052               break;
4053             }
4054             case 4: { ///// quadrangle
4055               const SMDS_MeshFace * f = aMesh->FindFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ], nodes[ 3 ]);
4056               if ( !f )
4057                 myLastCreatedElems.Append(aMesh->AddFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ], nodes[ 3 ] ));
4058               else if ( nodes[ 1 ] != f->GetNodeWrap( f->GetNodeIndex( nodes[ 0 ] ) + 1 ))
4059                 {
4060                   myLastCreatedElems.Append(aMesh->AddFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ], nodes[ 3 ] ));
4061                   aMesh->RemoveElement(f);
4062                 }
4063               break;
4064             }
4065             default:
4066               if( (*v)->IsQuadratic() ) {
4067                 if(nbn==6) { /////// quadratic triangle
4068                   const SMDS_MeshFace * f = aMesh->FindFace( nodes[0], nodes[2], nodes[4],
4069                                                              nodes[1], nodes[3], nodes[5] );
4070                   if ( !f ) {
4071                     myLastCreatedElems.Append(aMesh->AddFace(nodes[0], nodes[2], nodes[4],
4072                                                              nodes[1], nodes[3], nodes[5]));
4073                   }
4074                   else if ( nodes[ 2 ] != f->GetNodeWrap( f->GetNodeIndex( nodes[ 0 ] ) + 1 )) {
4075                     const SMDS_MeshNode** tmpnodes = new const SMDS_MeshNode*[6];
4076                     tmpnodes[0] = nodes[0];
4077                     tmpnodes[1] = nodes[2];
4078                     tmpnodes[2] = nodes[4];
4079                     tmpnodes[3] = nodes[1];
4080                     tmpnodes[4] = nodes[3];
4081                     tmpnodes[5] = nodes[5];
4082                     myLastCreatedElems.Append(aMesh->AddFace(nodes[0], nodes[2], nodes[4],
4083                                                              nodes[1], nodes[3], nodes[5]));
4084                     aMesh->RemoveElement(f);
4085                   }
4086                 }
4087                 else {       /////// quadratic quadrangle
4088                   const SMDS_MeshFace * f = aMesh->FindFace( nodes[0], nodes[2], nodes[4], nodes[6],
4089                                                              nodes[1], nodes[3], nodes[5], nodes[7] );
4090                   if ( !f ) {
4091                     myLastCreatedElems.Append(aMesh->AddFace(nodes[0], nodes[2], nodes[4], nodes[6],
4092                                                              nodes[1], nodes[3], nodes[5], nodes[7]));
4093                   }
4094                   else if ( nodes[ 2 ] != f->GetNodeWrap( f->GetNodeIndex( nodes[ 0 ] ) + 1 )) {
4095                     const SMDS_MeshNode** tmpnodes = new const SMDS_MeshNode*[8];
4096                     tmpnodes[0] = nodes[0];
4097                     tmpnodes[1] = nodes[2];
4098                     tmpnodes[2] = nodes[4];
4099                     tmpnodes[3] = nodes[6];
4100                     tmpnodes[4] = nodes[1];
4101                     tmpnodes[5] = nodes[3];
4102                     tmpnodes[6] = nodes[5];
4103                     tmpnodes[7] = nodes[7];
4104                     myLastCreatedElems.Append(aMesh->AddFace(nodes[0], nodes[2], nodes[4], nodes[6],
4105                                                              nodes[1], nodes[3], nodes[5], nodes[7]));
4106                     aMesh->RemoveElement(f);
4107                   }
4108                 }
4109               }
4110               else { //////// polygon
4111                 vector<const SMDS_MeshNode*> polygon_nodes ( nodes, &nodes[nbn] );
4112                 const SMDS_MeshFace * f = aMesh->FindFace( polygon_nodes );
4113                 if ( !f )
4114                   myLastCreatedElems.Append(aMesh->AddPolygonalFace(polygon_nodes));
4115                 else if ( nodes[ 1 ] != f->GetNodeWrap( f->GetNodeIndex( nodes[ 0 ] ) + 1 ))
4116                   {
4117                   // TODO problem ChangeElementNodes : not the same number of nodes, not the same type
4118                   MESSAGE("ChangeElementNodes");
4119                   aMesh->ChangeElementNodes( f, nodes, nbn );
4120                   }
4121               }
4122             }
4123             while ( srcElements.Length() < myLastCreatedElems.Length() )
4124               srcElements.Append( *srcEdge );
4125
4126           }  // loop on free faces
4127
4128           // go to the next volume
4129           iVol = 0;
4130           while ( iVol++ < nbVolumesByStep ) v++;
4131         }
4132       }
4133     } // sweep free links into faces
4134
4135     // Make a ceiling face with a normal external to a volume
4136
4137     SMDS_VolumeTool lastVol( itElem->second.back() );
4138
4139     int iF = lastVol.GetFaceIndex( aFaceLastNodes );
4140     if ( iF >= 0 ) {
4141       lastVol.SetExternalNormal();
4142       const SMDS_MeshNode** nodes = lastVol.GetFaceNodes( iF );
4143       int nbn = lastVol.NbFaceNodes( iF );
4144       switch ( nbn ) {
4145       case 3:
4146         if (!hasFreeLinks ||
4147             !aMesh->FindFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ]))
4148           myLastCreatedElems.Append(aMesh->AddFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ] ));
4149         break;
4150       case 4:
4151         if (!hasFreeLinks ||
4152             !aMesh->FindFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ], nodes[ 3 ]))
4153           myLastCreatedElems.Append(aMesh->AddFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ], nodes[ 3 ] ));
4154         break;
4155       default:
4156         if(itElem->second.back()->IsQuadratic()) {
4157           if(nbn==6) {
4158             if (!hasFreeLinks ||
4159                 !aMesh->FindFace(nodes[0], nodes[2], nodes[4],
4160                                  nodes[1], nodes[3], nodes[5]) ) {
4161               myLastCreatedElems.Append(aMesh->AddFace(nodes[0], nodes[2], nodes[4],
4162                                                        nodes[1], nodes[3], nodes[5]));
4163             }
4164           }
4165           else { // nbn==8
4166             if (!hasFreeLinks ||
4167                 !aMesh->FindFace(nodes[0], nodes[2], nodes[4], nodes[6],
4168                                  nodes[1], nodes[3], nodes[5], nodes[7]) )
4169               myLastCreatedElems.Append(aMesh->AddFace(nodes[0], nodes[2], nodes[4], nodes[6],
4170                                                        nodes[1], nodes[3], nodes[5], nodes[7]));
4171           }
4172         }
4173         else {
4174           vector<const SMDS_MeshNode*> polygon_nodes ( nodes, &nodes[nbn] );
4175           if (!hasFreeLinks || !aMesh->FindFace(polygon_nodes))
4176             myLastCreatedElems.Append(aMesh->AddPolygonalFace(polygon_nodes));
4177         }
4178       } // switch
4179
4180       while ( srcElements.Length() < myLastCreatedElems.Length() )
4181         srcElements.Append( myLastCreatedElems.Last() );
4182     }
4183   } // loop on swept elements
4184 }
4185
4186 //=======================================================================
4187 //function : RotationSweep
4188 //purpose  :
4189 //=======================================================================
4190
4191 SMESH_MeshEditor::PGroupIDs
4192 SMESH_MeshEditor::RotationSweep(TIDSortedElemSet & theElems,
4193                                 const gp_Ax1&      theAxis,
4194                                 const double       theAngle,
4195                                 const int          theNbSteps,
4196                                 const double       theTol,
4197                                 const bool         theMakeGroups,
4198                                 const bool         theMakeWalls)
4199 {
4200   myLastCreatedElems.Clear();
4201   myLastCreatedNodes.Clear();
4202
4203   // source elements for each generated one
4204   SMESH_SequenceOfElemPtr srcElems, srcNodes;
4205
4206   MESSAGE( "RotationSweep()");
4207   gp_Trsf aTrsf;
4208   aTrsf.SetRotation( theAxis, theAngle );
4209   gp_Trsf aTrsf2;
4210   aTrsf2.SetRotation( theAxis, theAngle/2. );
4211
4212   gp_Lin aLine( theAxis );
4213   double aSqTol = theTol * theTol;
4214
4215   SMESHDS_Mesh* aMesh = GetMeshDS();
4216
4217   TNodeOfNodeListMap mapNewNodes;
4218   TElemOfVecOfNnlmiMap mapElemNewNodes;
4219   TElemOfElemListMap newElemsMap;
4220
4221   // loop on theElems
4222   TIDSortedElemSet::iterator itElem;
4223   for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
4224     const SMDS_MeshElement* elem = *itElem;
4225     if ( !elem || elem->GetType() == SMDSAbs_Volume )
4226       continue;
4227     vector<TNodeOfNodeListMapItr> & newNodesItVec = mapElemNewNodes[ elem ];
4228     newNodesItVec.reserve( elem->NbNodes() );
4229
4230     // loop on elem nodes
4231     SMDS_ElemIteratorPtr itN = elem->nodesIterator();
4232     while ( itN->more() ) {
4233       // check if a node has been already sweeped
4234       const SMDS_MeshNode* node = cast2Node( itN->next() );
4235
4236       gp_XYZ aXYZ( node->X(), node->Y(), node->Z() );
4237       double coord[3];
4238       aXYZ.Coord( coord[0], coord[1], coord[2] );
4239       bool isOnAxis = ( aLine.SquareDistance( aXYZ ) <= aSqTol );
4240
4241       TNodeOfNodeListMapItr nIt = mapNewNodes.find( node );
4242       if ( nIt == mapNewNodes.end() ) {
4243         nIt = mapNewNodes.insert( make_pair( node, list<const SMDS_MeshNode*>() )).first;
4244         list<const SMDS_MeshNode*>& listNewNodes = nIt->second;
4245
4246         // make new nodes
4247         //gp_XYZ aXYZ( node->X(), node->Y(), node->Z() );
4248         //double coord[3];
4249         //aXYZ.Coord( coord[0], coord[1], coord[2] );
4250         //bool isOnAxis = ( aLine.SquareDistance( aXYZ ) <= aSqTol );
4251         const SMDS_MeshNode * newNode = node;
4252         for ( int i = 0; i < theNbSteps; i++ ) {
4253           if ( !isOnAxis ) {
4254             if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
4255               // create two nodes
4256               aTrsf2.Transforms( coord[0], coord[1], coord[2] );
4257               //aTrsf.Transforms( coord[0], coord[1], coord[2] );
4258               newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
4259               myLastCreatedNodes.Append(newNode);
4260               srcNodes.Append( node );
4261               listNewNodes.push_back( newNode );
4262               aTrsf2.Transforms( coord[0], coord[1], coord[2] );
4263               //aTrsf.Transforms( coord[0], coord[1], coord[2] );
4264             }
4265             else {
4266               aTrsf.Transforms( coord[0], coord[1], coord[2] );
4267             }
4268             newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
4269             myLastCreatedNodes.Append(newNode);
4270             srcNodes.Append( node );
4271             listNewNodes.push_back( newNode );
4272           }
4273           else {
4274             listNewNodes.push_back( newNode );
4275             if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
4276               listNewNodes.push_back( newNode );
4277             }
4278           }
4279         }
4280       }
4281       /*
4282         else {
4283         // if current elem is quadratic and current node is not medium
4284         // we have to check - may be it is needed to insert additional nodes
4285         if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
4286         list< const SMDS_MeshNode* > & listNewNodes = nIt->second;
4287         if(listNewNodes.size()==theNbSteps) {
4288         listNewNodes.clear();
4289         // make new nodes
4290         //gp_XYZ aXYZ( node->X(), node->Y(), node->Z() );
4291         //double coord[3];
4292         //aXYZ.Coord( coord[0], coord[1], coord[2] );
4293         const SMDS_MeshNode * newNode = node;
4294         if ( !isOnAxis ) {
4295         for(int i = 0; i<theNbSteps; i++) {
4296         aTrsf2.Transforms( coord[0], coord[1], coord[2] );
4297         newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
4298         cout<<"    3 AddNode:  "<<newNode;
4299         myLastCreatedNodes.Append(newNode);
4300         listNewNodes.push_back( newNode );
4301         srcNodes.Append( node );
4302         aTrsf2.Transforms( coord[0], coord[1], coord[2] );
4303         newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
4304         cout<<"    4 AddNode:  "<<newNode;
4305         myLastCreatedNodes.Append(newNode);
4306         srcNodes.Append( node );
4307         listNewNodes.push_back( newNode );
4308         }
4309         }
4310         else {
4311         listNewNodes.push_back( newNode );
4312         }
4313         }
4314         }
4315         }
4316       */
4317       newNodesItVec.push_back( nIt );
4318     }
4319     // make new elements
4320     sweepElement( elem, newNodesItVec, newElemsMap[elem], theNbSteps, srcElems );
4321   }
4322
4323   if ( theMakeWalls )
4324     makeWalls( mapNewNodes, newElemsMap, mapElemNewNodes, theElems, theNbSteps, srcElems );
4325
4326   PGroupIDs newGroupIDs;
4327   if ( theMakeGroups )
4328     newGroupIDs = generateGroups( srcNodes, srcElems, "rotated");
4329
4330   return newGroupIDs;
4331 }
4332
4333
4334 //=======================================================================
4335 //function : CreateNode
4336 //purpose  :
4337 //=======================================================================
4338 const SMDS_MeshNode* SMESH_MeshEditor::CreateNode(const double x,
4339                                                   const double y,
4340                                                   const double z,
4341                                                   const double tolnode,
4342                                                   SMESH_SequenceOfNode& aNodes)
4343 {
4344   myLastCreatedElems.Clear();
4345   myLastCreatedNodes.Clear();
4346
4347   gp_Pnt P1(x,y,z);
4348   SMESHDS_Mesh * aMesh = myMesh->GetMeshDS();
4349
4350   // try to search in sequence of existing nodes
4351   // if aNodes.Length()>0 we 'nave to use given sequence
4352   // else - use all nodes of mesh
4353   if(aNodes.Length()>0) {
4354     int i;
4355     for(i=1; i<=aNodes.Length(); i++) {
4356       gp_Pnt P2(aNodes.Value(i)->X(),aNodes.Value(i)->Y(),aNodes.Value(i)->Z());
4357       if(P1.Distance(P2)<tolnode)
4358         return aNodes.Value(i);
4359     }
4360   }
4361   else {
4362     SMDS_NodeIteratorPtr itn = aMesh->nodesIterator();
4363     while(itn->more()) {
4364       const SMDS_MeshNode* aN = static_cast<const SMDS_MeshNode*> (itn->next());
4365       gp_Pnt P2(aN->X(),aN->Y(),aN->Z());
4366       if(P1.Distance(P2)<tolnode)
4367         return aN;
4368     }
4369   }
4370
4371   // create new node and return it
4372   const SMDS_MeshNode* NewNode = aMesh->AddNode(x,y,z);
4373   myLastCreatedNodes.Append(NewNode);
4374   return NewNode;
4375 }
4376
4377
4378 //=======================================================================
4379 //function : ExtrusionSweep
4380 //purpose  :
4381 //=======================================================================
4382
4383 SMESH_MeshEditor::PGroupIDs
4384 SMESH_MeshEditor::ExtrusionSweep (TIDSortedElemSet &  theElems,
4385                                   const gp_Vec&       theStep,
4386                                   const int           theNbSteps,
4387                                   TElemOfElemListMap& newElemsMap,
4388                                   const bool          theMakeGroups,
4389                                   const int           theFlags,
4390                                   const double        theTolerance)
4391 {
4392   ExtrusParam aParams;
4393   aParams.myDir = gp_Dir(theStep);
4394   aParams.myNodes.Clear();
4395   aParams.mySteps = new TColStd_HSequenceOfReal;
4396   int i;
4397   for(i=1; i<=theNbSteps; i++)
4398     aParams.mySteps->Append(theStep.Magnitude());
4399
4400   return
4401     ExtrusionSweep(theElems,aParams,newElemsMap,theMakeGroups,theFlags,theTolerance);
4402 }
4403
4404
4405 //=======================================================================
4406 //function : ExtrusionSweep
4407 //purpose  :
4408 //=======================================================================
4409
4410 SMESH_MeshEditor::PGroupIDs
4411 SMESH_MeshEditor::ExtrusionSweep (TIDSortedElemSet &  theElems,
4412                                   ExtrusParam&        theParams,
4413                                   TElemOfElemListMap& newElemsMap,
4414                                   const bool          theMakeGroups,
4415                                   const int           theFlags,
4416                                   const double        theTolerance)
4417 {
4418   MESSAGE("ExtrusionSweep " << theMakeGroups << " " << theFlags << " " << theTolerance);
4419   myLastCreatedElems.Clear();
4420   myLastCreatedNodes.Clear();
4421
4422   // source elements for each generated one
4423   SMESH_SequenceOfElemPtr srcElems, srcNodes;
4424
4425   SMESHDS_Mesh* aMesh = GetMeshDS();
4426
4427   int nbsteps = theParams.mySteps->Length();
4428
4429   TNodeOfNodeListMap mapNewNodes;
4430   //TNodeOfNodeVecMap mapNewNodes;
4431   TElemOfVecOfNnlmiMap mapElemNewNodes;
4432   //TElemOfVecOfMapNodesMap mapElemNewNodes;
4433
4434   // loop on theElems
4435   TIDSortedElemSet::iterator itElem;
4436   for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
4437     // check element type
4438     const SMDS_MeshElement* elem = *itElem;
4439     if ( !elem  || elem->GetType() == SMDSAbs_Volume )
4440       continue;
4441
4442     vector<TNodeOfNodeListMapItr> & newNodesItVec = mapElemNewNodes[ elem ];
4443     //vector<TNodeOfNodeVecMapItr> & newNodesItVec = mapElemNewNodes[ elem ];
4444     newNodesItVec.reserve( elem->NbNodes() );
4445
4446     // loop on elem nodes
4447     SMDS_ElemIteratorPtr itN = elem->nodesIterator();
4448     while ( itN->more() )
4449     {
4450       // check if a node has been already sweeped
4451       const SMDS_MeshNode* node = cast2Node( itN->next() );
4452       TNodeOfNodeListMap::iterator nIt = mapNewNodes.find( node );
4453       //TNodeOfNodeVecMap::iterator nIt = mapNewNodes.find( node );
4454       if ( nIt == mapNewNodes.end() ) {
4455         nIt = mapNewNodes.insert( make_pair( node, list<const SMDS_MeshNode*>() )).first;
4456         //nIt = mapNewNodes.insert( make_pair( node, vector<const SMDS_MeshNode*>() )).first;
4457         list<const SMDS_MeshNode*>& listNewNodes = nIt->second;
4458         //vector<const SMDS_MeshNode*>& vecNewNodes = nIt->second;
4459         //vecNewNodes.reserve(nbsteps);
4460
4461         // make new nodes
4462         double coord[] = { node->X(), node->Y(), node->Z() };
4463         //int nbsteps = theParams.mySteps->Length();
4464         for ( int i = 0; i < nbsteps; i++ ) {
4465           if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
4466             // create additional node
4467             double x = coord[0] + theParams.myDir.X()*theParams.mySteps->Value(i+1)/2.;
4468             double y = coord[1] + theParams.myDir.Y()*theParams.mySteps->Value(i+1)/2.;
4469             double z = coord[2] + theParams.myDir.Z()*theParams.mySteps->Value(i+1)/2.;
4470             if( theFlags & EXTRUSION_FLAG_SEW ) {
4471               const SMDS_MeshNode * newNode = CreateNode(x, y, z,
4472                                                          theTolerance, theParams.myNodes);
4473               listNewNodes.push_back( newNode );
4474             }
4475             else {
4476               const SMDS_MeshNode * newNode = aMesh->AddNode(x, y, z);
4477               myLastCreatedNodes.Append(newNode);
4478               srcNodes.Append( node );
4479               listNewNodes.push_back( newNode );
4480             }
4481           }
4482           //aTrsf.Transforms( coord[0], coord[1], coord[2] );
4483           coord[0] = coord[0] + theParams.myDir.X()*theParams.mySteps->Value(i+1);
4484           coord[1] = coord[1] + theParams.myDir.Y()*theParams.mySteps->Value(i+1);
4485           coord[2] = coord[2] + theParams.myDir.Z()*theParams.mySteps->Value(i+1);
4486           if( theFlags & EXTRUSION_FLAG_SEW ) {
4487             const SMDS_MeshNode * newNode = CreateNode(coord[0], coord[1], coord[2],
4488                                                        theTolerance, theParams.myNodes);
4489             listNewNodes.push_back( newNode );
4490             //vecNewNodes[i]=newNode;
4491           }
4492           else {
4493             const SMDS_MeshNode * newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
4494             myLastCreatedNodes.Append(newNode);
4495             srcNodes.Append( node );
4496             listNewNodes.push_back( newNode );
4497             //vecNewNodes[i]=newNode;
4498           }
4499         }
4500       }
4501       else {
4502         // if current elem is quadratic and current node is not medium
4503         // we have to check - may be it is needed to insert additional nodes
4504         if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
4505           list< const SMDS_MeshNode* > & listNewNodes = nIt->second;
4506           if(listNewNodes.size()==nbsteps) {
4507             listNewNodes.clear();
4508             double coord[] = { node->X(), node->Y(), node->Z() };
4509             for ( int i = 0; i < nbsteps; i++ ) {
4510               double x = coord[0] + theParams.myDir.X()*theParams.mySteps->Value(i+1);
4511               double y = coord[1] + theParams.myDir.Y()*theParams.mySteps->Value(i+1);
4512               double z = coord[2] + theParams.myDir.Z()*theParams.mySteps->Value(i+1);
4513               if( theFlags & EXTRUSION_FLAG_SEW ) {
4514                 const SMDS_MeshNode * newNode = CreateNode(x, y, z,
4515                                                            theTolerance, theParams.myNodes);
4516                 listNewNodes.push_back( newNode );
4517               }
4518               else {
4519                 const SMDS_MeshNode * newNode = aMesh->AddNode(x, y, z);
4520                 myLastCreatedNodes.Append(newNode);
4521                 srcNodes.Append( node );
4522                 listNewNodes.push_back( newNode );
4523               }
4524               coord[0] = coord[0] + theParams.myDir.X()*theParams.mySteps->Value(i+1);
4525               coord[1] = coord[1] + theParams.myDir.Y()*theParams.mySteps->Value(i+1);
4526               coord[2] = coord[2] + theParams.myDir.Z()*theParams.mySteps->Value(i+1);
4527               if( theFlags & EXTRUSION_FLAG_SEW ) {
4528                 const SMDS_MeshNode * newNode = CreateNode(coord[0], coord[1], coord[2],
4529                                                            theTolerance, theParams.myNodes);
4530                 listNewNodes.push_back( newNode );
4531               }
4532               else {
4533                 const SMDS_MeshNode * newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
4534                 myLastCreatedNodes.Append(newNode);
4535                 srcNodes.Append( node );
4536                 listNewNodes.push_back( newNode );
4537               }
4538             }
4539           }
4540         }
4541       }
4542       newNodesItVec.push_back( nIt );
4543     }
4544     // make new elements
4545     sweepElement( elem, newNodesItVec, newElemsMap[elem], nbsteps, srcElems );
4546   }
4547
4548   if( theFlags & EXTRUSION_FLAG_BOUNDARY ) {
4549     makeWalls( mapNewNodes, newElemsMap, mapElemNewNodes, theElems, nbsteps, srcElems );
4550   }
4551   PGroupIDs newGroupIDs;
4552   if ( theMakeGroups )
4553     newGroupIDs = generateGroups( srcNodes, srcElems, "extruded");
4554
4555   return newGroupIDs;
4556 }
4557
4558 /*
4559 //=======================================================================
4560 //class    : SMESH_MeshEditor_PathPoint
4561 //purpose  : auxiliary class
4562 //=======================================================================
4563 class SMESH_MeshEditor_PathPoint {
4564 public:
4565 SMESH_MeshEditor_PathPoint() {
4566 myPnt.SetCoord(99., 99., 99.);
4567 myTgt.SetCoord(1.,0.,0.);
4568 myAngle=0.;
4569 myPrm=0.;
4570 }
4571 void SetPnt(const gp_Pnt& aP3D){
4572 myPnt=aP3D;
4573 }
4574 void SetTangent(const gp_Dir& aTgt){
4575 myTgt=aTgt;
4576 }
4577 void SetAngle(const double& aBeta){
4578 myAngle=aBeta;
4579 }
4580 void SetParameter(const double& aPrm){
4581 myPrm=aPrm;
4582 }
4583 const gp_Pnt& Pnt()const{
4584 return myPnt;
4585 }
4586 const gp_Dir& Tangent()const{
4587 return myTgt;
4588 }
4589 double Angle()const{
4590 return myAngle;
4591 }
4592 double Parameter()const{
4593 return myPrm;
4594 }
4595
4596 protected:
4597 gp_Pnt myPnt;
4598 gp_Dir myTgt;
4599 double myAngle;
4600 double myPrm;
4601 };
4602 */
4603
4604 //=======================================================================
4605 //function : ExtrusionAlongTrack
4606 //purpose  :
4607 //=======================================================================
4608 SMESH_MeshEditor::Extrusion_Error
4609 SMESH_MeshEditor::ExtrusionAlongTrack (TIDSortedElemSet &   theElements,
4610                                        SMESH_subMesh*       theTrack,
4611                                        const SMDS_MeshNode* theN1,
4612                                        const bool           theHasAngles,
4613                                        list<double>&        theAngles,
4614                                        const bool           theLinearVariation,
4615                                        const bool           theHasRefPoint,
4616                                        const gp_Pnt&        theRefPoint,
4617                                        const bool           theMakeGroups)
4618 {
4619   MESSAGE("ExtrusionAlongTrack");
4620   myLastCreatedElems.Clear();
4621   myLastCreatedNodes.Clear();
4622
4623   int aNbE;
4624   std::list<double> aPrms;
4625   TIDSortedElemSet::iterator itElem;
4626
4627   gp_XYZ aGC;
4628   TopoDS_Edge aTrackEdge;
4629   TopoDS_Vertex aV1, aV2;
4630
4631   SMDS_ElemIteratorPtr aItE;
4632   SMDS_NodeIteratorPtr aItN;
4633   SMDSAbs_ElementType aTypeE;
4634
4635   TNodeOfNodeListMap mapNewNodes;
4636
4637   // 1. Check data
4638   aNbE = theElements.size();
4639   // nothing to do
4640   if ( !aNbE )
4641     return EXTR_NO_ELEMENTS;
4642
4643   // 1.1 Track Pattern
4644   ASSERT( theTrack );
4645
4646   SMESHDS_SubMesh* pSubMeshDS = theTrack->GetSubMeshDS();
4647
4648   aItE = pSubMeshDS->GetElements();
4649   while ( aItE->more() ) {
4650     const SMDS_MeshElement* pE = aItE->next();
4651     aTypeE = pE->GetType();
4652     // Pattern must contain links only
4653     if ( aTypeE != SMDSAbs_Edge )
4654       return EXTR_PATH_NOT_EDGE;
4655   }
4656
4657   list<SMESH_MeshEditor_PathPoint> fullList;
4658
4659   const TopoDS_Shape& aS = theTrack->GetSubShape();
4660   // Sub shape for the Pattern must be an Edge or Wire
4661   if( aS.ShapeType() == TopAbs_EDGE ) {
4662     aTrackEdge = TopoDS::Edge( aS );
4663     // the Edge must not be degenerated
4664     if ( BRep_Tool::Degenerated( aTrackEdge ) )
4665       return EXTR_BAD_PATH_SHAPE;
4666     TopExp::Vertices( aTrackEdge, aV1, aV2 );
4667     aItN = theTrack->GetFather()->GetSubMesh( aV1 )->GetSubMeshDS()->GetNodes();
4668     const SMDS_MeshNode* aN1 = aItN->next();
4669     aItN = theTrack->GetFather()->GetSubMesh( aV2 )->GetSubMeshDS()->GetNodes();
4670     const SMDS_MeshNode* aN2 = aItN->next();
4671     // starting node must be aN1 or aN2
4672     if ( !( aN1 == theN1 || aN2 == theN1 ) )
4673       return EXTR_BAD_STARTING_NODE;
4674     aItN = pSubMeshDS->GetNodes();
4675     while ( aItN->more() ) {
4676       const SMDS_MeshNode* pNode = aItN->next();
4677       const SMDS_EdgePosition* pEPos =
4678         static_cast<const SMDS_EdgePosition*>( pNode->GetPosition() );
4679       double aT = pEPos->GetUParameter();
4680       aPrms.push_back( aT );
4681     }
4682     //Extrusion_Error err =
4683     MakeEdgePathPoints(aPrms, aTrackEdge, (aN1==theN1), fullList);
4684   }
4685   else if( aS.ShapeType() == TopAbs_WIRE ) {
4686     list< SMESH_subMesh* > LSM;
4687     TopTools_SequenceOfShape Edges;
4688     SMESH_subMeshIteratorPtr itSM = theTrack->getDependsOnIterator(false,true);
4689     while(itSM->more()) {
4690       SMESH_subMesh* SM = itSM->next();
4691       LSM.push_back(SM);
4692       const TopoDS_Shape& aS = SM->GetSubShape();
4693       Edges.Append(aS);
4694     }
4695     list< list<SMESH_MeshEditor_PathPoint> > LLPPs;
4696     int startNid = theN1->GetID();
4697     TColStd_MapOfInteger UsedNums;
4698     int NbEdges = Edges.Length();
4699     int i = 1;
4700     for(; i<=NbEdges; i++) {
4701       int k = 0;
4702       list< SMESH_subMesh* >::iterator itLSM = LSM.begin();
4703       for(; itLSM!=LSM.end(); itLSM++) {
4704         k++;
4705         if(UsedNums.Contains(k)) continue;
4706         aTrackEdge = TopoDS::Edge( Edges.Value(k) );
4707         SMESH_subMesh* locTrack = *itLSM;
4708         SMESHDS_SubMesh* locMeshDS = locTrack->GetSubMeshDS();
4709         TopExp::Vertices( aTrackEdge, aV1, aV2 );
4710         aItN = locTrack->GetFather()->GetSubMesh(aV1)->GetSubMeshDS()->GetNodes();
4711         const SMDS_MeshNode* aN1 = aItN->next();
4712         aItN = locTrack->GetFather()->GetSubMesh(aV2)->GetSubMeshDS()->GetNodes();
4713         const SMDS_MeshNode* aN2 = aItN->next();
4714         // starting node must be aN1 or aN2
4715         if ( !( aN1->GetID() == startNid || aN2->GetID() == startNid ) ) continue;
4716         // 2. Collect parameters on the track edge
4717         aPrms.clear();
4718         aItN = locMeshDS->GetNodes();
4719         while ( aItN->more() ) {
4720           const SMDS_MeshNode* pNode = aItN->next();
4721           const SMDS_EdgePosition* pEPos =
4722             static_cast<const SMDS_EdgePosition*>( pNode->GetPosition() );
4723           double aT = pEPos->GetUParameter();
4724           aPrms.push_back( aT );
4725         }
4726         list<SMESH_MeshEditor_PathPoint> LPP;
4727         //Extrusion_Error err =
4728         MakeEdgePathPoints(aPrms, aTrackEdge,(aN1->GetID()==startNid), LPP);
4729         LLPPs.push_back(LPP);
4730         UsedNums.Add(k);
4731         // update startN for search following egde
4732         if( aN1->GetID() == startNid ) startNid = aN2->GetID();
4733         else startNid = aN1->GetID();
4734         break;
4735       }
4736     }
4737     list< list<SMESH_MeshEditor_PathPoint> >::iterator itLLPP = LLPPs.begin();
4738     list<SMESH_MeshEditor_PathPoint> firstList = *itLLPP;
4739     list<SMESH_MeshEditor_PathPoint>::iterator itPP = firstList.begin();
4740     for(; itPP!=firstList.end(); itPP++) {
4741       fullList.push_back( *itPP );
4742     }
4743     SMESH_MeshEditor_PathPoint PP1 = fullList.back();
4744     fullList.pop_back();
4745     itLLPP++;
4746     for(; itLLPP!=LLPPs.end(); itLLPP++) {
4747       list<SMESH_MeshEditor_PathPoint> currList = *itLLPP;
4748       itPP = currList.begin();
4749       SMESH_MeshEditor_PathPoint PP2 = currList.front();
4750       gp_Dir D1 = PP1.Tangent();
4751       gp_Dir D2 = PP2.Tangent();
4752       gp_Dir Dnew( gp_Vec( (D1.X()+D2.X())/2, (D1.Y()+D2.Y())/2,
4753                            (D1.Z()+D2.Z())/2 ) );
4754       PP1.SetTangent(Dnew);
4755       fullList.push_back(PP1);
4756       itPP++;
4757       for(; itPP!=firstList.end(); itPP++) {
4758         fullList.push_back( *itPP );
4759       }
4760       PP1 = fullList.back();
4761       fullList.pop_back();
4762     }
4763     // if wire not closed
4764     fullList.push_back(PP1);
4765     // else ???
4766   }
4767   else {
4768     return EXTR_BAD_PATH_SHAPE;
4769   }
4770
4771   return MakeExtrElements(theElements, fullList, theHasAngles, theAngles, theLinearVariation,
4772                           theHasRefPoint, theRefPoint, theMakeGroups);
4773 }
4774
4775
4776 //=======================================================================
4777 //function : ExtrusionAlongTrack
4778 //purpose  :
4779 //=======================================================================
4780 SMESH_MeshEditor::Extrusion_Error
4781 SMESH_MeshEditor::ExtrusionAlongTrack (TIDSortedElemSet &   theElements,
4782                                        SMESH_Mesh*          theTrack,
4783                                        const SMDS_MeshNode* theN1,
4784                                        const bool           theHasAngles,
4785                                        list<double>&        theAngles,
4786                                        const bool           theLinearVariation,
4787                                        const bool           theHasRefPoint,
4788                                        const gp_Pnt&        theRefPoint,
4789                                        const bool           theMakeGroups)
4790 {
4791   myLastCreatedElems.Clear();
4792   myLastCreatedNodes.Clear();
4793
4794   int aNbE;
4795   std::list<double> aPrms;
4796   TIDSortedElemSet::iterator itElem;
4797
4798   gp_XYZ aGC;
4799   TopoDS_Edge aTrackEdge;
4800   TopoDS_Vertex aV1, aV2;
4801
4802   SMDS_ElemIteratorPtr aItE;
4803   SMDS_NodeIteratorPtr aItN;
4804   SMDSAbs_ElementType aTypeE;
4805
4806   TNodeOfNodeListMap mapNewNodes;
4807
4808   // 1. Check data
4809   aNbE = theElements.size();
4810   // nothing to do
4811   if ( !aNbE )
4812     return EXTR_NO_ELEMENTS;
4813
4814   // 1.1 Track Pattern
4815   ASSERT( theTrack );
4816
4817   SMESHDS_Mesh* pMeshDS = theTrack->GetMeshDS();
4818
4819   aItE = pMeshDS->elementsIterator();
4820   while ( aItE->more() ) {
4821     const SMDS_MeshElement* pE = aItE->next();
4822     aTypeE = pE->GetType();
4823     // Pattern must contain links only
4824     if ( aTypeE != SMDSAbs_Edge )
4825       return EXTR_PATH_NOT_EDGE;
4826   }
4827
4828   list<SMESH_MeshEditor_PathPoint> fullList;
4829
4830   const TopoDS_Shape& aS = theTrack->GetShapeToMesh();
4831   // Sub shape for the Pattern must be an Edge or Wire
4832   if( aS.ShapeType() == TopAbs_EDGE ) {
4833     aTrackEdge = TopoDS::Edge( aS );
4834     // the Edge must not be degenerated
4835     if ( BRep_Tool::Degenerated( aTrackEdge ) )
4836       return EXTR_BAD_PATH_SHAPE;
4837     TopExp::Vertices( aTrackEdge, aV1, aV2 );
4838     aItN = theTrack->GetSubMesh( aV1 )->GetSubMeshDS()->GetNodes();
4839     const SMDS_MeshNode* aN1 = aItN->next();
4840     aItN = theTrack->GetSubMesh( aV2 )->GetSubMeshDS()->GetNodes();
4841     const SMDS_MeshNode* aN2 = aItN->next();
4842     // starting node must be aN1 or aN2
4843     if ( !( aN1 == theN1 || aN2 == theN1 ) )
4844       return EXTR_BAD_STARTING_NODE;
4845     aItN = pMeshDS->nodesIterator();
4846     while ( aItN->more() ) {
4847       const SMDS_MeshNode* pNode = aItN->next();
4848       if( pNode==aN1 || pNode==aN2 ) continue;
4849       const SMDS_EdgePosition* pEPos =
4850         static_cast<const SMDS_EdgePosition*>( pNode->GetPosition() );
4851       double aT = pEPos->GetUParameter();
4852       aPrms.push_back( aT );
4853     }
4854     //Extrusion_Error err =
4855     MakeEdgePathPoints(aPrms, aTrackEdge, (aN1==theN1), fullList);
4856   }
4857   else if( aS.ShapeType() == TopAbs_WIRE ) {
4858     list< SMESH_subMesh* > LSM;
4859     TopTools_SequenceOfShape Edges;
4860     TopExp_Explorer eExp(aS, TopAbs_EDGE);
4861     for(; eExp.More(); eExp.Next()) {
4862       TopoDS_Edge E = TopoDS::Edge( eExp.Current() );
4863       if( BRep_Tool::Degenerated(E) ) continue;
4864       SMESH_subMesh* SM = theTrack->GetSubMesh(E);
4865       if(SM) {
4866         LSM.push_back(SM);
4867         Edges.Append(E);
4868       }
4869     }
4870     list< list<SMESH_MeshEditor_PathPoint> > LLPPs;
4871     int startNid = theN1->GetID();
4872     TColStd_MapOfInteger UsedNums;
4873     int NbEdges = Edges.Length();
4874     int i = 1;
4875     for(; i<=NbEdges; i++) {
4876       int k = 0;
4877       list< SMESH_subMesh* >::iterator itLSM = LSM.begin();
4878       for(; itLSM!=LSM.end(); itLSM++) {
4879         k++;
4880         if(UsedNums.Contains(k)) continue;
4881         aTrackEdge = TopoDS::Edge( Edges.Value(k) );
4882         SMESH_subMesh* locTrack = *itLSM;
4883         SMESHDS_SubMesh* locMeshDS = locTrack->GetSubMeshDS();
4884         TopExp::Vertices( aTrackEdge, aV1, aV2 );
4885         aItN = locTrack->GetFather()->GetSubMesh(aV1)->GetSubMeshDS()->GetNodes();
4886         const SMDS_MeshNode* aN1 = aItN->next();
4887         aItN = locTrack->GetFather()->GetSubMesh(aV2)->GetSubMeshDS()->GetNodes();
4888         const SMDS_MeshNode* aN2 = aItN->next();
4889         // starting node must be aN1 or aN2
4890         if ( !( aN1->GetID() == startNid || aN2->GetID() == startNid ) ) continue;
4891         // 2. Collect parameters on the track edge
4892         aPrms.clear();
4893         aItN = locMeshDS->GetNodes();
4894         while ( aItN->more() ) {
4895           const SMDS_MeshNode* pNode = aItN->next();
4896           const SMDS_EdgePosition* pEPos =
4897             static_cast<const SMDS_EdgePosition*>( pNode->GetPosition() );
4898           double aT = pEPos->GetUParameter();
4899           aPrms.push_back( aT );
4900         }
4901         list<SMESH_MeshEditor_PathPoint> LPP;
4902         //Extrusion_Error err =
4903         MakeEdgePathPoints(aPrms, aTrackEdge,(aN1->GetID()==startNid), LPP);
4904         LLPPs.push_back(LPP);
4905         UsedNums.Add(k);
4906         // update startN for search following egde
4907         if( aN1->GetID() == startNid ) startNid = aN2->GetID();
4908         else startNid = aN1->GetID();
4909         break;
4910       }
4911     }
4912     list< list<SMESH_MeshEditor_PathPoint> >::iterator itLLPP = LLPPs.begin();
4913     list<SMESH_MeshEditor_PathPoint> firstList = *itLLPP;
4914     list<SMESH_MeshEditor_PathPoint>::iterator itPP = firstList.begin();
4915     for(; itPP!=firstList.end(); itPP++) {
4916       fullList.push_back( *itPP );
4917     }
4918     SMESH_MeshEditor_PathPoint PP1 = fullList.back();
4919     fullList.pop_back();
4920     itLLPP++;
4921     for(; itLLPP!=LLPPs.end(); itLLPP++) {
4922       list<SMESH_MeshEditor_PathPoint> currList = *itLLPP;
4923       itPP = currList.begin();
4924       SMESH_MeshEditor_PathPoint PP2 = currList.front();
4925       gp_Pnt P1 = PP1.Pnt();
4926       //cout<<"    PP1: Pnt("<<P1.X()<<","<<P1.Y()<<","<<P1.Z()<<")"<<endl;
4927       gp_Pnt P2 = PP2.Pnt();
4928       gp_Dir D1 = PP1.Tangent();
4929       gp_Dir D2 = PP2.Tangent();
4930       gp_Dir Dnew( gp_Vec( (D1.X()+D2.X())/2, (D1.Y()+D2.Y())/2,
4931                            (D1.Z()+D2.Z())/2 ) );
4932       PP1.SetTangent(Dnew);
4933       fullList.push_back(PP1);
4934       itPP++;
4935       for(; itPP!=currList.end(); itPP++) {
4936         fullList.push_back( *itPP );
4937       }
4938       PP1 = fullList.back();
4939       fullList.pop_back();
4940     }
4941     // if wire not closed
4942     fullList.push_back(PP1);
4943     // else ???
4944   }
4945   else {
4946     return EXTR_BAD_PATH_SHAPE;
4947   }
4948
4949   return MakeExtrElements(theElements, fullList, theHasAngles, theAngles, theLinearVariation,
4950                           theHasRefPoint, theRefPoint, theMakeGroups);
4951 }
4952
4953
4954 //=======================================================================
4955 //function : MakeEdgePathPoints
4956 //purpose  : auxilary for ExtrusionAlongTrack
4957 //=======================================================================
4958 SMESH_MeshEditor::Extrusion_Error
4959 SMESH_MeshEditor::MakeEdgePathPoints(std::list<double>& aPrms,
4960                                      const TopoDS_Edge& aTrackEdge,
4961                                      bool FirstIsStart,
4962                                      list<SMESH_MeshEditor_PathPoint>& LPP)
4963 {
4964   Standard_Real aTx1, aTx2, aL2, aTolVec, aTolVec2;
4965   aTolVec=1.e-7;
4966   aTolVec2=aTolVec*aTolVec;
4967   double aT1, aT2;
4968   TopoDS_Vertex aV1, aV2;
4969   TopExp::Vertices( aTrackEdge, aV1, aV2 );
4970   aT1=BRep_Tool::Parameter( aV1, aTrackEdge );
4971   aT2=BRep_Tool::Parameter( aV2, aTrackEdge );
4972   // 2. Collect parameters on the track edge
4973   aPrms.push_front( aT1 );
4974   aPrms.push_back( aT2 );
4975   // sort parameters
4976   aPrms.sort();
4977   if( FirstIsStart ) {
4978     if ( aT1 > aT2 ) {
4979       aPrms.reverse();
4980     }
4981   }
4982   else {
4983     if ( aT2 > aT1 ) {
4984       aPrms.reverse();
4985     }
4986   }
4987   // 3. Path Points
4988   SMESH_MeshEditor_PathPoint aPP;
4989   Handle(Geom_Curve) aC3D = BRep_Tool::Curve( aTrackEdge, aTx1, aTx2 );
4990   std::list<double>::iterator aItD = aPrms.begin();
4991   for(; aItD != aPrms.end(); ++aItD) {
4992     double aT = *aItD;
4993     gp_Pnt aP3D;
4994     gp_Vec aVec;
4995     aC3D->D1( aT, aP3D, aVec );
4996     aL2 = aVec.SquareMagnitude();
4997     if ( aL2 < aTolVec2 )
4998       return EXTR_CANT_GET_TANGENT;
4999     gp_Dir aTgt( aVec );
5000     aPP.SetPnt( aP3D );
5001     aPP.SetTangent( aTgt );
5002     aPP.SetParameter( aT );
5003     LPP.push_back(aPP);
5004   }
5005   return EXTR_OK;
5006 }
5007
5008
5009 //=======================================================================
5010 //function : MakeExtrElements
5011 //purpose  : auxilary for ExtrusionAlongTrack
5012 //=======================================================================
5013 SMESH_MeshEditor::Extrusion_Error
5014 SMESH_MeshEditor::MakeExtrElements(TIDSortedElemSet&  theElements,
5015                                    list<SMESH_MeshEditor_PathPoint>& fullList,
5016                                    const bool theHasAngles,
5017                                    list<double>& theAngles,
5018                                    const bool theLinearVariation,
5019                                    const bool theHasRefPoint,
5020                                    const gp_Pnt& theRefPoint,
5021                                    const bool theMakeGroups)
5022 {
5023   MESSAGE("MakeExtrElements");
5024   //cout<<"MakeExtrElements  fullList.size() = "<<fullList.size()<<endl;
5025   int aNbTP = fullList.size();
5026   vector<SMESH_MeshEditor_PathPoint> aPPs(aNbTP);
5027   // Angles
5028   if( theHasAngles && theAngles.size()>0 && theLinearVariation ) {
5029     LinearAngleVariation(aNbTP-1, theAngles);
5030   }
5031   vector<double> aAngles( aNbTP );
5032   int j = 0;
5033   for(; j<aNbTP; ++j) {
5034     aAngles[j] = 0.;
5035   }
5036   if ( theHasAngles ) {
5037     double anAngle;;
5038     std::list<double>::iterator aItD = theAngles.begin();
5039     for ( j=1; (aItD != theAngles.end()) && (j<aNbTP); ++aItD, ++j ) {
5040       anAngle = *aItD;
5041       aAngles[j] = anAngle;
5042     }
5043   }
5044   // fill vector of path points with angles
5045   //aPPs.resize(fullList.size());
5046   j = -1;
5047   list<SMESH_MeshEditor_PathPoint>::iterator itPP = fullList.begin();
5048   for(; itPP!=fullList.end(); itPP++) {
5049     j++;
5050     SMESH_MeshEditor_PathPoint PP = *itPP;
5051     PP.SetAngle(aAngles[j]);
5052     aPPs[j] = PP;
5053   }
5054
5055   TNodeOfNodeListMap mapNewNodes;
5056   TElemOfVecOfNnlmiMap mapElemNewNodes;
5057   TElemOfElemListMap newElemsMap;
5058   TIDSortedElemSet::iterator itElem;
5059   double aX, aY, aZ;
5060   int aNb;
5061   SMDSAbs_ElementType aTypeE;
5062   // source elements for each generated one
5063   SMESH_SequenceOfElemPtr srcElems, srcNodes;
5064
5065   // 3. Center of rotation aV0
5066   gp_Pnt aV0 = theRefPoint;
5067   gp_XYZ aGC;
5068   if ( !theHasRefPoint ) {
5069     aNb = 0;
5070     aGC.SetCoord( 0.,0.,0. );
5071
5072     itElem = theElements.begin();
5073     for ( ; itElem != theElements.end(); itElem++ ) {
5074       const SMDS_MeshElement* elem = *itElem;
5075
5076       SMDS_ElemIteratorPtr itN = elem->nodesIterator();
5077       while ( itN->more() ) {
5078         const SMDS_MeshNode* node = static_cast<const SMDS_MeshNode*>( itN->next() );
5079         aX = node->X();
5080         aY = node->Y();
5081         aZ = node->Z();
5082
5083         if ( mapNewNodes.find( node ) == mapNewNodes.end() ) {
5084           list<const SMDS_MeshNode*> aLNx;
5085           mapNewNodes[node] = aLNx;
5086           //
5087           gp_XYZ aXYZ( aX, aY, aZ );
5088           aGC += aXYZ;
5089           ++aNb;
5090         }
5091       }
5092     }
5093     aGC /= aNb;
5094     aV0.SetXYZ( aGC );
5095   } // if (!theHasRefPoint) {
5096   mapNewNodes.clear();
5097
5098   // 4. Processing the elements
5099   SMESHDS_Mesh* aMesh = GetMeshDS();
5100
5101   for ( itElem = theElements.begin(); itElem != theElements.end(); itElem++ ) {
5102     // check element type
5103     const SMDS_MeshElement* elem = *itElem;
5104     aTypeE = elem->GetType();
5105     if ( !elem || ( aTypeE != SMDSAbs_Face && aTypeE != SMDSAbs_Edge ) )
5106       continue;
5107
5108     vector<TNodeOfNodeListMapItr> & newNodesItVec = mapElemNewNodes[ elem ];
5109     newNodesItVec.reserve( elem->NbNodes() );
5110
5111     // loop on elem nodes
5112     int nodeIndex = -1;
5113     SMDS_ElemIteratorPtr itN = elem->nodesIterator();
5114     while ( itN->more() )
5115     {
5116       ++nodeIndex;
5117       // check if a node has been already processed
5118       const SMDS_MeshNode* node =
5119         static_cast<const SMDS_MeshNode*>( itN->next() );
5120       TNodeOfNodeListMap::iterator nIt = mapNewNodes.find( node );
5121       if ( nIt == mapNewNodes.end() ) {
5122         nIt = mapNewNodes.insert( make_pair( node, list<const SMDS_MeshNode*>() )).first;
5123         list<const SMDS_MeshNode*>& listNewNodes = nIt->second;
5124
5125         // make new nodes
5126         aX = node->X();  aY = node->Y(); aZ = node->Z();
5127
5128         Standard_Real aAngle1x, aAngleT1T0, aTolAng;
5129         gp_Pnt aP0x, aP1x, aPN0, aPN1, aV0x, aV1x;
5130         gp_Ax1 anAx1, anAxT1T0;
5131         gp_Dir aDT1x, aDT0x, aDT1T0;
5132
5133         aTolAng=1.e-4;
5134
5135         aV0x = aV0;
5136         aPN0.SetCoord(aX, aY, aZ);
5137
5138         const SMESH_MeshEditor_PathPoint& aPP0 = aPPs[0];
5139         aP0x = aPP0.Pnt();
5140         aDT0x= aPP0.Tangent();
5141         //cout<<"j = 0   PP: Pnt("<<aP0x.X()<<","<<aP0x.Y()<<","<<aP0x.Z()<<")"<<endl;
5142
5143         for ( j = 1; j < aNbTP; ++j ) {
5144           const SMESH_MeshEditor_PathPoint& aPP1 = aPPs[j];
5145           aP1x = aPP1.Pnt();
5146           aDT1x = aPP1.Tangent();
5147           aAngle1x = aPP1.Angle();
5148
5149           gp_Trsf aTrsf, aTrsfRot, aTrsfRotT1T0;
5150           // Translation
5151           gp_Vec aV01x( aP0x, aP1x );
5152           aTrsf.SetTranslation( aV01x );
5153
5154           // traslated point
5155           aV1x = aV0x.Transformed( aTrsf );
5156           aPN1 = aPN0.Transformed( aTrsf );
5157
5158           // rotation 1 [ T1,T0 ]
5159           aAngleT1T0=-aDT1x.Angle( aDT0x );
5160           if (fabs(aAngleT1T0) > aTolAng) {
5161             aDT1T0=aDT1x^aDT0x;
5162             anAxT1T0.SetLocation( aV1x );
5163             anAxT1T0.SetDirection( aDT1T0 );
5164             aTrsfRotT1T0.SetRotation( anAxT1T0, aAngleT1T0 );
5165
5166             aPN1 = aPN1.Transformed( aTrsfRotT1T0 );
5167           }
5168
5169           // rotation 2
5170           if ( theHasAngles ) {
5171             anAx1.SetLocation( aV1x );
5172             anAx1.SetDirection( aDT1x );
5173             aTrsfRot.SetRotation( anAx1, aAngle1x );
5174
5175             aPN1 = aPN1.Transformed( aTrsfRot );
5176           }
5177
5178           // make new node
5179           //MESSAGE("elem->IsQuadratic " << elem->IsQuadratic() << " " << elem->IsMediumNode(node));
5180           if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
5181             // create additional node
5182             double x = ( aPN1.X() + aPN0.X() )/2.;
5183             double y = ( aPN1.Y() + aPN0.Y() )/2.;
5184             double z = ( aPN1.Z() + aPN0.Z() )/2.;
5185             const SMDS_MeshNode* newNode = aMesh->AddNode(x,y,z);
5186             myLastCreatedNodes.Append(newNode);
5187             srcNodes.Append( node );
5188             listNewNodes.push_back( newNode );
5189           }
5190           aX = aPN1.X();
5191           aY = aPN1.Y();
5192           aZ = aPN1.Z();
5193           const SMDS_MeshNode* newNode = aMesh->AddNode( aX, aY, aZ );
5194           myLastCreatedNodes.Append(newNode);
5195           srcNodes.Append( node );
5196           listNewNodes.push_back( newNode );
5197
5198           aPN0 = aPN1;
5199           aP0x = aP1x;
5200           aV0x = aV1x;
5201           aDT0x = aDT1x;
5202         }
5203       }
5204
5205       else {
5206         // if current elem is quadratic and current node is not medium
5207         // we have to check - may be it is needed to insert additional nodes
5208         if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
5209           list< const SMDS_MeshNode* > & listNewNodes = nIt->second;
5210           if(listNewNodes.size()==aNbTP-1) {
5211             vector<const SMDS_MeshNode*> aNodes(2*(aNbTP-1));
5212             gp_XYZ P(node->X(), node->Y(), node->Z());
5213             list< const SMDS_MeshNode* >::iterator it = listNewNodes.begin();
5214             int i;
5215             for(i=0; i<aNbTP-1; i++) {
5216               const SMDS_MeshNode* N = *it;
5217               double x = ( N->X() + P.X() )/2.;
5218               double y = ( N->Y() + P.Y() )/2.;
5219               double z = ( N->Z() + P.Z() )/2.;
5220               const SMDS_MeshNode* newN = aMesh->AddNode(x,y,z);
5221               srcNodes.Append( node );
5222               myLastCreatedNodes.Append(newN);
5223               aNodes[2*i] = newN;
5224               aNodes[2*i+1] = N;
5225               P = gp_XYZ(N->X(),N->Y(),N->Z());
5226             }
5227             listNewNodes.clear();
5228             for(i=0; i<2*(aNbTP-1); i++) {
5229               listNewNodes.push_back(aNodes[i]);
5230             }
5231           }
5232         }
5233       }
5234
5235       newNodesItVec.push_back( nIt );
5236     }
5237     // make new elements
5238     //sweepElement( aMesh, elem, newNodesItVec, newElemsMap[elem],
5239     //              newNodesItVec[0]->second.size(), myLastCreatedElems );
5240     sweepElement( elem, newNodesItVec, newElemsMap[elem], aNbTP-1, srcElems );
5241   }
5242
5243   makeWalls( mapNewNodes, newElemsMap, mapElemNewNodes, theElements, aNbTP-1, srcElems );
5244
5245   if ( theMakeGroups )
5246     generateGroups( srcNodes, srcElems, "extruded");
5247
5248   return EXTR_OK;
5249 }
5250
5251
5252 //=======================================================================
5253 //function : LinearAngleVariation
5254 //purpose  : auxilary for ExtrusionAlongTrack
5255 //=======================================================================
5256 void SMESH_MeshEditor::LinearAngleVariation(const int nbSteps,
5257                                             list<double>& Angles)
5258 {
5259   int nbAngles = Angles.size();
5260   if( nbSteps > nbAngles ) {
5261     vector<double> theAngles(nbAngles);
5262     list<double>::iterator it = Angles.begin();
5263     int i = -1;
5264     for(; it!=Angles.end(); it++) {
5265       i++;
5266       theAngles[i] = (*it);
5267     }
5268     list<double> res;
5269     double rAn2St = double( nbAngles ) / double( nbSteps );
5270     double angPrev = 0, angle;
5271     for ( int iSt = 0; iSt < nbSteps; ++iSt ) {
5272       double angCur = rAn2St * ( iSt+1 );
5273       double angCurFloor  = floor( angCur );
5274       double angPrevFloor = floor( angPrev );
5275       if ( angPrevFloor == angCurFloor )
5276         angle = rAn2St * theAngles[ int( angCurFloor ) ];
5277       else {
5278         int iP = int( angPrevFloor );
5279         double angPrevCeil = ceil(angPrev);
5280         angle = ( angPrevCeil - angPrev ) * theAngles[ iP ];
5281
5282         int iC = int( angCurFloor );
5283         if ( iC < nbAngles )
5284           angle += ( angCur - angCurFloor ) * theAngles[ iC ];
5285
5286         iP = int( angPrevCeil );
5287         while ( iC-- > iP )
5288           angle += theAngles[ iC ];
5289       }
5290       res.push_back(angle);
5291       angPrev = angCur;
5292     }
5293     Angles.clear();
5294     it = res.begin();
5295     for(; it!=res.end(); it++)
5296       Angles.push_back( *it );
5297   }
5298 }
5299
5300
5301 //================================================================================
5302 /*!
5303  * \brief Move or copy theElements applying theTrsf to their nodes
5304  *  \param theElems - elements to transform, if theElems is empty then apply to all mesh nodes
5305  *  \param theTrsf - transformation to apply
5306  *  \param theCopy - if true, create translated copies of theElems
5307  *  \param theMakeGroups - if true and theCopy, create translated groups
5308  *  \param theTargetMesh - mesh to copy translated elements into
5309  *  \retval SMESH_MeshEditor::PGroupIDs - list of ids of created groups
5310  */
5311 //================================================================================
5312
5313 SMESH_MeshEditor::PGroupIDs
5314 SMESH_MeshEditor::Transform (TIDSortedElemSet & theElems,
5315                              const gp_Trsf&     theTrsf,
5316                              const bool         theCopy,
5317                              const bool         theMakeGroups,
5318                              SMESH_Mesh*        theTargetMesh)
5319 {
5320   myLastCreatedElems.Clear();
5321   myLastCreatedNodes.Clear();
5322
5323   bool needReverse = false;
5324   string groupPostfix;
5325   switch ( theTrsf.Form() ) {
5326   case gp_PntMirror:
5327     MESSAGE("gp_PntMirror");
5328     needReverse = true;
5329     groupPostfix = "mirrored";
5330     break;
5331   case gp_Ax1Mirror:
5332     MESSAGE("gp_Ax1Mirror");
5333     groupPostfix = "mirrored";
5334     break;
5335   case gp_Ax2Mirror:
5336     MESSAGE("gp_Ax2Mirror");
5337     needReverse = true;
5338     groupPostfix = "mirrored";
5339     break;
5340   case gp_Rotation:
5341     MESSAGE("gp_Rotation");
5342     groupPostfix = "rotated";
5343     break;
5344   case gp_Translation:
5345     MESSAGE("gp_Translation");
5346     groupPostfix = "translated";
5347     break;
5348   case gp_Scale:
5349     MESSAGE("gp_Scale");
5350     groupPostfix = "scaled";
5351     break;
5352   case gp_CompoundTrsf: // different scale by axis
5353     MESSAGE("gp_CompoundTrsf");
5354     groupPostfix = "scaled";
5355     break;
5356   default:
5357     MESSAGE("default");
5358     needReverse = false;
5359     groupPostfix = "transformed";
5360   }
5361
5362   SMESH_MeshEditor targetMeshEditor( theTargetMesh );
5363   SMESHDS_Mesh* aTgtMesh = theTargetMesh ? theTargetMesh->GetMeshDS() : 0;
5364   SMESHDS_Mesh* aMesh    = GetMeshDS();
5365
5366
5367   // map old node to new one
5368   TNodeNodeMap nodeMap;
5369
5370   // elements sharing moved nodes; those of them which have all
5371   // nodes mirrored but are not in theElems are to be reversed
5372   TIDSortedElemSet inverseElemSet;
5373
5374   // source elements for each generated one
5375   SMESH_SequenceOfElemPtr srcElems, srcNodes;
5376
5377   // issue 021015: EDF 1578 SMESH: Free nodes are removed when translating a mesh
5378   TIDSortedElemSet orphanNode;
5379
5380   if ( theElems.empty() ) // transform the whole mesh
5381   {
5382     // add all elements
5383     SMDS_ElemIteratorPtr eIt = aMesh->elementsIterator();
5384     while ( eIt->more() ) theElems.insert( eIt->next() );
5385     // add orphan nodes
5386     SMDS_NodeIteratorPtr nIt = aMesh->nodesIterator();
5387     while ( nIt->more() )
5388     {
5389       const SMDS_MeshNode* node = nIt->next();
5390       if ( node->NbInverseElements() == 0)
5391         orphanNode.insert( node );
5392     }
5393   }
5394
5395   // loop on elements to transform nodes : first orphan nodes then elems
5396   TIDSortedElemSet::iterator itElem;
5397   TIDSortedElemSet *elements[] = {&orphanNode, &theElems };
5398   for (int i=0; i<2; i++)
5399   for ( itElem = elements[i]->begin(); itElem != elements[i]->end(); itElem++ ) {
5400     const SMDS_MeshElement* elem = *itElem;
5401     if ( !elem )
5402       continue;
5403
5404     // loop on elem nodes
5405     SMDS_ElemIteratorPtr itN = elem->nodesIterator();
5406     while ( itN->more() ) {
5407
5408       const SMDS_MeshNode* node = cast2Node( itN->next() );
5409       // check if a node has been already transformed
5410       pair<TNodeNodeMap::iterator,bool> n2n_isnew =
5411         nodeMap.insert( make_pair ( node, node ));
5412       if ( !n2n_isnew.second )
5413         continue;
5414
5415       double coord[3];
5416       coord[0] = node->X();
5417       coord[1] = node->Y();
5418       coord[2] = node->Z();
5419       theTrsf.Transforms( coord[0], coord[1], coord[2] );
5420       if ( theTargetMesh ) {
5421         const SMDS_MeshNode * newNode = aTgtMesh->AddNode( coord[0], coord[1], coord[2] );
5422         n2n_isnew.first->second = newNode;
5423         myLastCreatedNodes.Append(newNode);
5424         srcNodes.Append( node );
5425       }
5426       else if ( theCopy ) {
5427         const SMDS_MeshNode * newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
5428         n2n_isnew.first->second = newNode;
5429         myLastCreatedNodes.Append(newNode);
5430         srcNodes.Append( node );
5431       }
5432       else {
5433         aMesh->MoveNode( node, coord[0], coord[1], coord[2] );
5434         // node position on shape becomes invalid
5435         const_cast< SMDS_MeshNode* > ( node )->SetPosition
5436           ( SMDS_SpacePosition::originSpacePosition() );
5437       }
5438
5439       // keep inverse elements
5440       if ( !theCopy && !theTargetMesh && needReverse ) {
5441         SMDS_ElemIteratorPtr invElemIt = node->GetInverseElementIterator();
5442         while ( invElemIt->more() ) {
5443           const SMDS_MeshElement* iel = invElemIt->next();
5444           inverseElemSet.insert( iel );
5445         }
5446       }
5447     }
5448   }
5449
5450   // either create new elements or reverse mirrored ones
5451   if ( !theCopy && !needReverse && !theTargetMesh )
5452     return PGroupIDs();
5453
5454   TIDSortedElemSet::iterator invElemIt = inverseElemSet.begin();
5455   for ( ; invElemIt != inverseElemSet.end(); invElemIt++ )
5456     theElems.insert( *invElemIt );
5457
5458   // replicate or reverse elements
5459   // TODO revoir ordre reverse vtk
5460   enum {
5461     REV_TETRA   = 0,  //  = nbNodes - 4
5462     REV_PYRAMID = 1,  //  = nbNodes - 4
5463     REV_PENTA   = 2,  //  = nbNodes - 4
5464     REV_FACE    = 3,
5465     REV_HEXA    = 4,  //  = nbNodes - 4
5466     FORWARD     = 5
5467   };
5468   int index[][8] = {
5469     { 2, 1, 0, 3, 4, 0, 0, 0 },  // REV_TETRA
5470     { 2, 1, 0, 3, 4, 0, 0, 0 },  // REV_PYRAMID
5471     { 2, 1, 0, 5, 4, 3, 0, 0 },  // REV_PENTA
5472     { 2, 1, 0, 3, 0, 0, 0, 0 },  // REV_FACE
5473     { 2, 1, 0, 3, 6, 5, 4, 7 },  // REV_HEXA
5474     { 0, 1, 2, 3, 4, 5, 6, 7 }   // FORWARD
5475   };
5476
5477   for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ )
5478   {
5479     const SMDS_MeshElement* elem = *itElem;
5480     if ( !elem || elem->GetType() == SMDSAbs_Node )
5481       continue;
5482
5483     int nbNodes = elem->NbNodes();
5484     int elemType = elem->GetType();
5485
5486     if (elem->IsPoly()) {
5487       // Polygon or Polyhedral Volume
5488       switch ( elemType ) {
5489       case SMDSAbs_Face:
5490         {
5491           vector<const SMDS_MeshNode*> poly_nodes (nbNodes);
5492           int iNode = 0;
5493           SMDS_ElemIteratorPtr itN = elem->nodesIterator();
5494           while (itN->more()) {
5495             const SMDS_MeshNode* node =
5496               static_cast<const SMDS_MeshNode*>(itN->next());
5497             TNodeNodeMap::iterator nodeMapIt = nodeMap.find(node);
5498             if (nodeMapIt == nodeMap.end())
5499               break; // not all nodes transformed
5500             if (needReverse) {
5501               // reverse mirrored faces and volumes
5502               poly_nodes[nbNodes - iNode - 1] = (*nodeMapIt).second;
5503             } else {
5504               poly_nodes[iNode] = (*nodeMapIt).second;
5505             }
5506             iNode++;
5507           }
5508           if ( iNode != nbNodes )
5509             continue; // not all nodes transformed
5510
5511           if ( theTargetMesh ) {
5512             myLastCreatedElems.Append(aTgtMesh->AddPolygonalFace(poly_nodes));
5513             srcElems.Append( elem );
5514           }
5515           else if ( theCopy ) {
5516             myLastCreatedElems.Append(aMesh->AddPolygonalFace(poly_nodes));
5517             srcElems.Append( elem );
5518           }
5519           else {
5520             aMesh->ChangePolygonNodes(elem, poly_nodes);
5521           }
5522         }
5523         break;
5524       case SMDSAbs_Volume:
5525         {
5526           // ATTENTION: Reversing is not yet done!!!
5527           const SMDS_VtkVolume* aPolyedre =
5528             dynamic_cast<const SMDS_VtkVolume*>( elem );
5529           if (!aPolyedre) {
5530             MESSAGE("Warning: bad volumic element");
5531             continue;
5532           }
5533
5534           vector<const SMDS_MeshNode*> poly_nodes;
5535           vector<int> quantities;
5536
5537           bool allTransformed = true;
5538           int nbFaces = aPolyedre->NbFaces();
5539           for (int iface = 1; iface <= nbFaces && allTransformed; iface++) {
5540             int nbFaceNodes = aPolyedre->NbFaceNodes(iface);
5541             for (int inode = 1; inode <= nbFaceNodes && allTransformed; inode++) {
5542               const SMDS_MeshNode* node = aPolyedre->GetFaceNode(iface, inode);
5543               TNodeNodeMap::iterator nodeMapIt = nodeMap.find(node);
5544               if (nodeMapIt == nodeMap.end()) {
5545                 allTransformed = false; // not all nodes transformed
5546               } else {
5547                 poly_nodes.push_back((*nodeMapIt).second);
5548               }
5549             }
5550             quantities.push_back(nbFaceNodes);
5551           }
5552           if ( !allTransformed )
5553             continue; // not all nodes transformed
5554
5555           if ( theTargetMesh ) {
5556             myLastCreatedElems.Append(aTgtMesh->AddPolyhedralVolume(poly_nodes, quantities));
5557             srcElems.Append( elem );
5558           }
5559           else if ( theCopy ) {
5560             myLastCreatedElems.Append(aMesh->AddPolyhedralVolume(poly_nodes, quantities));
5561             srcElems.Append( elem );
5562           }
5563           else {
5564             aMesh->ChangePolyhedronNodes(elem, poly_nodes, quantities);
5565           }
5566         }
5567         break;
5568       default:;
5569       }
5570       continue;
5571     }
5572
5573     // Regular elements
5574     int* i = index[ FORWARD ];
5575     if ( needReverse && nbNodes > 2) {// reverse mirrored faces and volumes
5576       if ( elemType == SMDSAbs_Face )
5577         i = index[ REV_FACE ];
5578       else
5579         i = index[ nbNodes - 4 ];
5580     }
5581     if(elem->IsQuadratic()) {
5582       static int anIds[] = {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19};
5583       i = anIds;
5584       if(needReverse) {
5585         if(nbNodes==3) { // quadratic edge
5586           static int anIds[] = {1,0,2};
5587           i = anIds;
5588         }
5589         else if(nbNodes==6) { // quadratic triangle
5590           static int anIds[] = {0,2,1,5,4,3};
5591           i = anIds;
5592         }
5593         else if(nbNodes==8) { // quadratic quadrangle
5594           static int anIds[] = {0,3,2,1,7,6,5,4};
5595           i = anIds;
5596         }
5597         else if(nbNodes==10) { // quadratic tetrahedron of 10 nodes
5598           static int anIds[] = {0,2,1,3,6,5,4,7,9,8};
5599           i = anIds;
5600         }
5601         else if(nbNodes==13) { // quadratic pyramid of 13 nodes
5602           static int anIds[] = {0,3,2,1,4,8,7,6,5,9,12,11,10};
5603           i = anIds;
5604         }
5605         else if(nbNodes==15) { // quadratic pentahedron with 15 nodes
5606           static int anIds[] = {0,2,1,3,5,4,8,7,6,11,10,9,12,14,13};
5607           i = anIds;
5608         }
5609         else { // nbNodes==20 - quadratic hexahedron with 20 nodes
5610           static int anIds[] = {0,3,2,1,4,7,6,5,11,10,9,8,15,14,13,12,16,19,18,17};
5611           i = anIds;
5612         }
5613       }
5614     }
5615
5616     // find transformed nodes
5617     vector<const SMDS_MeshNode*> nodes(nbNodes);
5618     int iNode = 0;
5619     SMDS_ElemIteratorPtr itN = elem->nodesIterator();
5620     while ( itN->more() ) {
5621       const SMDS_MeshNode* node =
5622         static_cast<const SMDS_MeshNode*>( itN->next() );
5623       TNodeNodeMap::iterator nodeMapIt = nodeMap.find( node );
5624       if ( nodeMapIt == nodeMap.end() )
5625         break; // not all nodes transformed
5626       nodes[ i [ iNode++ ]] = (*nodeMapIt).second;
5627     }
5628     if ( iNode != nbNodes )
5629       continue; // not all nodes transformed
5630
5631     if ( theTargetMesh ) {
5632       if ( SMDS_MeshElement* copy =
5633            targetMeshEditor.AddElement( nodes, elem->GetType(), elem->IsPoly() )) {
5634         myLastCreatedElems.Append( copy );
5635         srcElems.Append( elem );
5636       }
5637     }
5638     else if ( theCopy ) {
5639       if ( AddElement( nodes, elem->GetType(), elem->IsPoly() ))
5640         srcElems.Append( elem );
5641     }
5642     else {
5643       // reverse element as it was reversed by transformation
5644       if ( nbNodes > 2 )
5645         aMesh->ChangeElementNodes( elem, &nodes[0], nbNodes );
5646     }
5647   }
5648
5649   PGroupIDs newGroupIDs;
5650
5651   if ( theMakeGroups && theCopy ||
5652        theMakeGroups && theTargetMesh )
5653     newGroupIDs = generateGroups( srcNodes, srcElems, groupPostfix, theTargetMesh );
5654
5655   return newGroupIDs;
5656 }
5657
5658
5659 ////=======================================================================
5660 ////function : Scale
5661 ////purpose  :
5662 ////=======================================================================
5663 //
5664 //SMESH_MeshEditor::PGroupIDs
5665 //SMESH_MeshEditor::Scale (TIDSortedElemSet & theElems,
5666 //                         const gp_Pnt&            thePoint,
5667 //                         const std::list<double>& theScaleFact,
5668 //                         const bool         theCopy,
5669 //                         const bool         theMakeGroups,
5670 //                         SMESH_Mesh*        theTargetMesh)
5671 //{
5672 //  MESSAGE("Scale");
5673 //  myLastCreatedElems.Clear();
5674 //  myLastCreatedNodes.Clear();
5675 //
5676 //  SMESH_MeshEditor targetMeshEditor( theTargetMesh );
5677 //  SMESHDS_Mesh* aTgtMesh = theTargetMesh ? theTargetMesh->GetMeshDS() : 0;
5678 //  SMESHDS_Mesh* aMesh    = GetMeshDS();
5679 //
5680 //  double scaleX=1.0, scaleY=1.0, scaleZ=1.0;
5681 //  std::list<double>::const_iterator itS = theScaleFact.begin();
5682 //  scaleX = (*itS);
5683 //  if(theScaleFact.size()==1) {
5684 //    scaleY = (*itS);
5685 //    scaleZ= (*itS);
5686 //  }
5687 //  if(theScaleFact.size()==2) {
5688 //    itS++;
5689 //    scaleY = (*itS);
5690 //    scaleZ= (*itS);
5691 //  }
5692 //  if(theScaleFact.size()>2) {
5693 //    itS++;
5694 //    scaleY = (*itS);
5695 //    itS++;
5696 //    scaleZ= (*itS);
5697 //  }
5698 //
5699 //  // map old node to new one
5700 //  TNodeNodeMap nodeMap;
5701 //
5702 //  // elements sharing moved nodes; those of them which have all
5703 //  // nodes mirrored but are not in theElems are to be reversed
5704 //  TIDSortedElemSet inverseElemSet;
5705 //
5706 //  // source elements for each generated one
5707 //  SMESH_SequenceOfElemPtr srcElems, srcNodes;
5708 //
5709 //  // loop on theElems
5710 //  TIDSortedElemSet::iterator itElem;
5711 //  for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
5712 //    const SMDS_MeshElement* elem = *itElem;
5713 //    if ( !elem )
5714 //      continue;
5715 //
5716 //    // loop on elem nodes
5717 //    SMDS_ElemIteratorPtr itN = elem->nodesIterator();
5718 //    while ( itN->more() ) {
5719 //
5720 //      // check if a node has been already transformed
5721 //      const SMDS_MeshNode* node = cast2Node( itN->next() );
5722 //      pair<TNodeNodeMap::iterator,bool> n2n_isnew =
5723 //        nodeMap.insert( make_pair ( node, node ));
5724 //      if ( !n2n_isnew.second )
5725 //        continue;
5726 //
5727 //      //double coord[3];
5728 //      //coord[0] = node->X();
5729 //      //coord[1] = node->Y();
5730 //      //coord[2] = node->Z();
5731 //      //theTrsf.Transforms( coord[0], coord[1], coord[2] );
5732 //      double dx = (node->X() - thePoint.X()) * scaleX;
5733 //      double dy = (node->Y() - thePoint.Y()) * scaleY;
5734 //      double dz = (node->Z() - thePoint.Z()) * scaleZ;
5735 //      if ( theTargetMesh ) {
5736 //        //const SMDS_MeshNode * newNode = aTgtMesh->AddNode( coord[0], coord[1], coord[2] );
5737 //        const SMDS_MeshNode * newNode =
5738 //          aTgtMesh->AddNode( thePoint.X()+dx, thePoint.Y()+dy, thePoint.Z()+dz );
5739 //        n2n_isnew.first->second = newNode;
5740 //        myLastCreatedNodes.Append(newNode);
5741 //        srcNodes.Append( node );
5742 //      }
5743 //      else if ( theCopy ) {
5744 //        //const SMDS_MeshNode * newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
5745 //        const SMDS_MeshNode * newNode =
5746 //          aMesh->AddNode( thePoint.X()+dx, thePoint.Y()+dy, thePoint.Z()+dz );
5747 //        n2n_isnew.first->second = newNode;
5748 //        myLastCreatedNodes.Append(newNode);
5749 //        srcNodes.Append( node );
5750 //      }
5751 //      else {
5752 //        //aMesh->MoveNode( node, coord[0], coord[1], coord[2] );
5753 //        aMesh->MoveNode( node, thePoint.X()+dx, thePoint.Y()+dy, thePoint.Z()+dz );
5754 //        // node position on shape becomes invalid
5755 //        const_cast< SMDS_MeshNode* > ( node )->SetPosition
5756 //          ( SMDS_SpacePosition::originSpacePosition() );
5757 //      }
5758 //
5759 //      // keep inverse elements
5760 //      //if ( !theCopy && !theTargetMesh && needReverse ) {
5761 //      //  SMDS_ElemIteratorPtr invElemIt = node->GetInverseElementIterator();
5762 //      //  while ( invElemIt->more() ) {
5763 //      //    const SMDS_MeshElement* iel = invElemIt->next();
5764 //      //    inverseElemSet.insert( iel );
5765 //      //  }
5766 //      //}
5767 //    }
5768 //  }
5769 //
5770 //  // either create new elements or reverse mirrored ones
5771 //  //if ( !theCopy && !needReverse && !theTargetMesh )
5772 //  if ( !theCopy && !theTargetMesh )
5773 //    return PGroupIDs();
5774 //
5775 //  TIDSortedElemSet::iterator invElemIt = inverseElemSet.begin();
5776 //  for ( ; invElemIt != inverseElemSet.end(); invElemIt++ )
5777 //    theElems.insert( *invElemIt );
5778 //
5779 //  // replicate or reverse elements
5780 //
5781 //  enum {
5782 //    REV_TETRA   = 0,  //  = nbNodes - 4
5783 //    REV_PYRAMID = 1,  //  = nbNodes - 4
5784 //    REV_PENTA   = 2,  //  = nbNodes - 4
5785 //    REV_FACE    = 3,
5786 //    REV_HEXA    = 4,  //  = nbNodes - 4
5787 //    FORWARD     = 5
5788 //  };
5789 //  int index[][8] = {
5790 //    { 2, 1, 0, 3, 4, 0, 0, 0 },  // REV_TETRA
5791 //    { 2, 1, 0, 3, 4, 0, 0, 0 },  // REV_PYRAMID
5792 //    { 2, 1, 0, 5, 4, 3, 0, 0 },  // REV_PENTA
5793 //    { 2, 1, 0, 3, 0, 0, 0, 0 },  // REV_FACE
5794 //    { 2, 1, 0, 3, 6, 5, 4, 7 },  // REV_HEXA
5795 //    { 0, 1, 2, 3, 4, 5, 6, 7 }   // FORWARD
5796 //  };
5797 //
5798 //  for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ )
5799 //  {
5800 //    const SMDS_MeshElement* elem = *itElem;
5801 //    if ( !elem || elem->GetType() == SMDSAbs_Node )
5802 //      continue;
5803 //
5804 //    int nbNodes = elem->NbNodes();
5805 //    int elemType = elem->GetType();
5806 //
5807 //    if (elem->IsPoly()) {
5808 //      // Polygon or Polyhedral Volume
5809 //      switch ( elemType ) {
5810 //      case SMDSAbs_Face:
5811 //        {
5812 //          vector<const SMDS_MeshNode*> poly_nodes (nbNodes);
5813 //          int iNode = 0;
5814 //          SMDS_ElemIteratorPtr itN = elem->nodesIterator();
5815 //          while (itN->more()) {
5816 //            const SMDS_MeshNode* node =
5817 //              static_cast<const SMDS_MeshNode*>(itN->next());
5818 //            TNodeNodeMap::iterator nodeMapIt = nodeMap.find(node);
5819 //            if (nodeMapIt == nodeMap.end())
5820 //              break; // not all nodes transformed
5821 //            //if (needReverse) {
5822 //            //  // reverse mirrored faces and volumes
5823 //            //  poly_nodes[nbNodes - iNode - 1] = (*nodeMapIt).second;
5824 //            //} else {
5825 //            poly_nodes[iNode] = (*nodeMapIt).second;
5826 //            //}
5827 //            iNode++;
5828 //          }
5829 //          if ( iNode != nbNodes )
5830 //            continue; // not all nodes transformed
5831 //
5832 //          if ( theTargetMesh ) {
5833 //            myLastCreatedElems.Append(aTgtMesh->AddPolygonalFace(poly_nodes));
5834 //            srcElems.Append( elem );
5835 //          }
5836 //          else if ( theCopy ) {
5837 //            myLastCreatedElems.Append(aMesh->AddPolygonalFace(poly_nodes));
5838 //            srcElems.Append( elem );
5839 //          }
5840 //          else {
5841 //            aMesh->ChangePolygonNodes(elem, poly_nodes);
5842 //          }
5843 //        }
5844 //        break;
5845 //      case SMDSAbs_Volume:
5846 //        {
5847 //          // ATTENTION: Reversing is not yet done!!!
5848 //          const SMDS_VtkVolume* aPolyedre =
5849 //            dynamic_cast<const SMDS_VtkVolume*>( elem );
5850 //          if (!aPolyedre) {
5851 //            MESSAGE("Warning: bad volumic element");
5852 //            continue;
5853 //          }
5854 //
5855 //          vector<const SMDS_MeshNode*> poly_nodes;
5856 //          vector<int> quantities;
5857 //
5858 //          bool allTransformed = true;
5859 //          int nbFaces = aPolyedre->NbFaces();
5860 //          for (int iface = 1; iface <= nbFaces && allTransformed; iface++) {
5861 //            int nbFaceNodes = aPolyedre->NbFaceNodes(iface);
5862 //            for (int inode = 1; inode <= nbFaceNodes && allTransformed; inode++) {
5863 //              const SMDS_MeshNode* node = aPolyedre->GetFaceNode(iface, inode);
5864 //              TNodeNodeMap::iterator nodeMapIt = nodeMap.find(node);
5865 //              if (nodeMapIt == nodeMap.end()) {
5866 //                allTransformed = false; // not all nodes transformed
5867 //              } else {
5868 //                poly_nodes.push_back((*nodeMapIt).second);
5869 //              }
5870 //            }
5871 //            quantities.push_back(nbFaceNodes);
5872 //          }
5873 //          if ( !allTransformed )
5874 //            continue; // not all nodes transformed
5875 //
5876 //          if ( theTargetMesh ) {
5877 //            myLastCreatedElems.Append(aTgtMesh->AddPolyhedralVolume(poly_nodes, quantities));
5878 //            srcElems.Append( elem );
5879 //          }
5880 //          else if ( theCopy ) {
5881 //            myLastCreatedElems.Append(aMesh->AddPolyhedralVolume(poly_nodes, quantities));
5882 //            srcElems.Append( elem );
5883 //          }
5884 //          else {
5885 //            aMesh->ChangePolyhedronNodes(elem, poly_nodes, quantities);
5886 //          }
5887 //        }
5888 //        break;
5889 //      default:;
5890 //      }
5891 //      continue;
5892 //    }
5893 //
5894 //    // Regular elements
5895 //    int* i = index[ FORWARD ];
5896 //    //if ( needReverse && nbNodes > 2) // reverse mirrored faces and volumes
5897 //    //  if ( elemType == SMDSAbs_Face )
5898 //    //    i = index[ REV_FACE ];
5899 //    //  else
5900 //    //    i = index[ nbNodes - 4 ];
5901 //
5902 //    if(elem->IsQuadratic()) {
5903 //      static int anIds[] = {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19};
5904 //      i = anIds;
5905 //      //if(needReverse) {
5906 //      //  if(nbNodes==3) { // quadratic edge
5907 //      //    static int anIds[] = {1,0,2};
5908 //      //    i = anIds;
5909 //      //  }
5910 //      //  else if(nbNodes==6) { // quadratic triangle
5911 //      //    static int anIds[] = {0,2,1,5,4,3};
5912 //      //    i = anIds;
5913 //      //  }
5914 //      //  else if(nbNodes==8) { // quadratic quadrangle
5915 //      //    static int anIds[] = {0,3,2,1,7,6,5,4};
5916 //      //    i = anIds;
5917 //      //  }
5918 //      //  else if(nbNodes==10) { // quadratic tetrahedron of 10 nodes
5919 //      //    static int anIds[] = {0,2,1,3,6,5,4,7,9,8};
5920 //      //    i = anIds;
5921 //      //  }
5922 //      //  else if(nbNodes==13) { // quadratic pyramid of 13 nodes
5923 //      //    static int anIds[] = {0,3,2,1,4,8,7,6,5,9,12,11,10};
5924 //      //    i = anIds;
5925 //      //  }
5926 //      //  else if(nbNodes==15) { // quadratic pentahedron with 15 nodes
5927 //      //    static int anIds[] = {0,2,1,3,5,4,8,7,6,11,10,9,12,14,13};
5928 //      //    i = anIds;
5929 //      //  }
5930 //      //  else { // nbNodes==20 - quadratic hexahedron with 20 nodes
5931 //      //    static int anIds[] = {0,3,2,1,4,7,6,5,11,10,9,8,15,14,13,12,16,19,18,17};
5932 //      //    i = anIds;
5933 //      //  }
5934 //      //}
5935 //    }
5936 //
5937 //    // find transformed nodes
5938 //    vector<const SMDS_MeshNode*> nodes(nbNodes);
5939 //    int iNode = 0;
5940 //    SMDS_ElemIteratorPtr itN = elem->nodesIterator();
5941 //    while ( itN->more() ) {
5942 //      const SMDS_MeshNode* node =
5943 //        static_cast<const SMDS_MeshNode*>( itN->next() );
5944 //      TNodeNodeMap::iterator nodeMapIt = nodeMap.find( node );
5945 //      if ( nodeMapIt == nodeMap.end() )
5946 //        break; // not all nodes transformed
5947 //      nodes[ i [ iNode++ ]] = (*nodeMapIt).second;
5948 //    }
5949 //    if ( iNode != nbNodes )
5950 //      continue; // not all nodes transformed
5951 //
5952 //    if ( theTargetMesh ) {
5953 //      if ( SMDS_MeshElement* copy =
5954 //           targetMeshEditor.AddElement( nodes, elem->GetType(), elem->IsPoly() )) {
5955 //        myLastCreatedElems.Append( copy );
5956 //        srcElems.Append( elem );
5957 //      }
5958 //    }
5959 //    else if ( theCopy ) {
5960 //      if ( SMDS_MeshElement* copy = AddElement( nodes, elem->GetType(), elem->IsPoly() )) {
5961 //        myLastCreatedElems.Append( copy );
5962 //        srcElems.Append( elem );
5963 //      }
5964 //    }
5965 //    else {
5966 //      // reverse element as it was reversed by transformation
5967 //      if ( nbNodes > 2 )
5968 //        aMesh->ChangeElementNodes( elem, &nodes[0], nbNodes );
5969 //    }
5970 //  }
5971 //
5972 //  PGroupIDs newGroupIDs;
5973 //
5974 //  if ( theMakeGroups && theCopy ||
5975 //       theMakeGroups && theTargetMesh ) {
5976 //    string groupPostfix = "scaled";
5977 //    newGroupIDs = generateGroups( srcNodes, srcElems, groupPostfix, theTargetMesh );
5978 //  }
5979 //
5980 //  return newGroupIDs;
5981 //}
5982
5983
5984 //=======================================================================
5985 /*!
5986  * \brief Create groups of elements made during transformation
5987  * \param nodeGens - nodes making corresponding myLastCreatedNodes
5988  * \param elemGens - elements making corresponding myLastCreatedElems
5989  * \param postfix - to append to names of new groups
5990  */
5991 //=======================================================================
5992
5993 SMESH_MeshEditor::PGroupIDs
5994 SMESH_MeshEditor::generateGroups(const SMESH_SequenceOfElemPtr& nodeGens,
5995                                  const SMESH_SequenceOfElemPtr& elemGens,
5996                                  const std::string&             postfix,
5997                                  SMESH_Mesh*                    targetMesh)
5998 {
5999   PGroupIDs newGroupIDs( new list<int> );
6000   SMESH_Mesh* mesh = targetMesh ? targetMesh : GetMesh();
6001
6002   // Sort existing groups by types and collect their names
6003
6004   // to store an old group and a generated new one
6005   typedef pair< SMESHDS_GroupBase*, SMDS_MeshGroup* > TOldNewGroup;
6006   vector< list< TOldNewGroup > > groupsByType( SMDSAbs_NbElementTypes );
6007   // group names
6008   set< string > groupNames;
6009   //
6010   SMDS_MeshGroup* nullNewGroup = (SMDS_MeshGroup*) 0;
6011   SMESH_Mesh::GroupIteratorPtr groupIt = GetMesh()->GetGroups();
6012   while ( groupIt->more() ) {
6013     SMESH_Group * group = groupIt->next();
6014     if ( !group ) continue;
6015     SMESHDS_GroupBase* groupDS = group->GetGroupDS();
6016     if ( !groupDS || groupDS->IsEmpty() ) continue;
6017     groupNames.insert( group->GetName() );
6018     groupDS->SetStoreName( group->GetName() );
6019     groupsByType[ groupDS->GetType() ].push_back( make_pair( groupDS, nullNewGroup ));
6020   }
6021
6022   // Groups creation
6023
6024   // loop on nodes and elements
6025   for ( int isNodes = 0; isNodes < 2; ++isNodes )
6026   {
6027     const SMESH_SequenceOfElemPtr& gens  = isNodes ? nodeGens : elemGens;
6028     const SMESH_SequenceOfElemPtr& elems = isNodes ? myLastCreatedNodes : myLastCreatedElems;
6029     if ( gens.Length() != elems.Length() )
6030       throw SALOME_Exception(LOCALIZED("invalid args"));
6031
6032     // loop on created elements
6033     for (int iElem = 1; iElem <= elems.Length(); ++iElem )
6034     {
6035       const SMDS_MeshElement* sourceElem = gens( iElem );
6036       if ( !sourceElem ) {
6037         MESSAGE("generateGroups(): NULL source element");
6038         continue;
6039       }
6040       list< TOldNewGroup > & groupsOldNew = groupsByType[ sourceElem->GetType() ];
6041       if ( groupsOldNew.empty() ) {
6042         while ( iElem < gens.Length() && gens( iElem+1 ) == sourceElem )
6043           ++iElem; // skip all elements made by sourceElem
6044         continue;
6045       }
6046       // collect all elements made by sourceElem
6047       list< const SMDS_MeshElement* > resultElems;
6048       if ( const SMDS_MeshElement* resElem = elems( iElem ))
6049         if ( resElem != sourceElem )
6050           resultElems.push_back( resElem );
6051       while ( iElem < gens.Length() && gens( iElem+1 ) == sourceElem )
6052         if ( const SMDS_MeshElement* resElem = elems( ++iElem ))
6053           if ( resElem != sourceElem )
6054             resultElems.push_back( resElem );
6055       // do not generate element groups from node ones
6056       if ( sourceElem->GetType() == SMDSAbs_Node &&
6057            elems( iElem )->GetType() != SMDSAbs_Node )
6058         continue;
6059
6060       // add resultElems to groups made by ones the sourceElem belongs to
6061       list< TOldNewGroup >::iterator gOldNew, gLast = groupsOldNew.end();
6062       for ( gOldNew = groupsOldNew.begin(); gOldNew != gLast; ++gOldNew )
6063       {
6064         SMESHDS_GroupBase* oldGroup = gOldNew->first;
6065         if ( oldGroup->Contains( sourceElem )) // sourceElem in oldGroup
6066         {
6067           SMDS_MeshGroup* & newGroup = gOldNew->second;
6068           if ( !newGroup )// create a new group
6069           {
6070             // make a name
6071             string name = oldGroup->GetStoreName();
6072             if ( !targetMesh ) {
6073               name += "_";
6074               name += postfix;
6075               int nb = 0;
6076               while ( !groupNames.insert( name ).second ) // name exists
6077               {
6078                 if ( nb == 0 ) {
6079                   name += "_1";
6080                 }
6081                 else {
6082                   TCollection_AsciiString nbStr(nb+1);
6083                   name.resize( name.rfind('_')+1 );
6084                   name += nbStr.ToCString();
6085                 }
6086                 ++nb;
6087               }
6088             }
6089             // make a group
6090             int id;
6091             SMESH_Group* group = mesh->AddGroup( resultElems.back()->GetType(),
6092                                                  name.c_str(), id );
6093             SMESHDS_Group* groupDS = static_cast<SMESHDS_Group*>(group->GetGroupDS());
6094             newGroup = & groupDS->SMDSGroup();
6095             newGroupIDs->push_back( id );
6096           }
6097
6098           // fill in a new group
6099           list< const SMDS_MeshElement* >::iterator resLast = resultElems.end(), resElemIt;
6100           for ( resElemIt = resultElems.begin(); resElemIt != resLast; ++resElemIt )
6101             newGroup->Add( *resElemIt );
6102         }
6103       }
6104     } // loop on created elements
6105   }// loop on nodes and elements
6106
6107   return newGroupIDs;
6108 }
6109
6110 //================================================================================
6111 /*!
6112  * \brief Return list of group of nodes close to each other within theTolerance
6113  *        Search among theNodes or in the whole mesh if theNodes is empty using
6114  *        an Octree algorithm
6115  */
6116 //================================================================================
6117
6118 void SMESH_MeshEditor::FindCoincidentNodes (TIDSortedNodeSet &   theNodes,
6119                                             const double         theTolerance,
6120                                             TListOfListOfNodes & theGroupsOfNodes)
6121 {
6122   myLastCreatedElems.Clear();
6123   myLastCreatedNodes.Clear();
6124
6125   if ( theNodes.empty() )
6126   { // get all nodes in the mesh
6127     SMDS_NodeIteratorPtr nIt = GetMeshDS()->nodesIterator(/*idInceasingOrder=*/true);
6128     while ( nIt->more() )
6129       theNodes.insert( theNodes.end(),nIt->next());
6130   }
6131
6132   SMESH_OctreeNode::FindCoincidentNodes ( theNodes, &theGroupsOfNodes, theTolerance);
6133 }
6134
6135
6136 //=======================================================================
6137 /*!
6138  * \brief Implementation of search for the node closest to point
6139  */
6140 //=======================================================================
6141
6142 struct SMESH_NodeSearcherImpl: public SMESH_NodeSearcher
6143 {
6144   //---------------------------------------------------------------------
6145   /*!
6146    * \brief Constructor
6147    */
6148   SMESH_NodeSearcherImpl( const SMESHDS_Mesh* theMesh )
6149   {
6150     myMesh = ( SMESHDS_Mesh* ) theMesh;
6151
6152     TIDSortedNodeSet nodes;
6153     if ( theMesh ) {
6154       SMDS_NodeIteratorPtr nIt = theMesh->nodesIterator(/*idInceasingOrder=*/true);
6155       while ( nIt->more() )
6156         nodes.insert( nodes.end(), nIt->next() );
6157     }
6158     myOctreeNode = new SMESH_OctreeNode(nodes) ;
6159
6160     // get max size of a leaf box
6161     SMESH_OctreeNode* tree = myOctreeNode;
6162     while ( !tree->isLeaf() )
6163     {
6164       SMESH_OctreeNodeIteratorPtr cIt = tree->GetChildrenIterator();
6165       if ( cIt->more() )
6166         tree = cIt->next();
6167     }
6168     myHalfLeafSize = tree->maxSize() / 2.;
6169   }
6170
6171   //---------------------------------------------------------------------
6172   /*!
6173    * \brief Move node and update myOctreeNode accordingly
6174    */
6175   void MoveNode( const SMDS_MeshNode* node, const gp_Pnt& toPnt )
6176   {
6177     myOctreeNode->UpdateByMoveNode( node, toPnt );
6178     myMesh->MoveNode( node, toPnt.X(), toPnt.Y(), toPnt.Z() );
6179   }
6180
6181   //---------------------------------------------------------------------
6182   /*!
6183    * \brief Do it's job
6184    */
6185   const SMDS_MeshNode* FindClosestTo( const gp_Pnt& thePnt )
6186   {
6187     map<double, const SMDS_MeshNode*> dist2Nodes;
6188     myOctreeNode->NodesAround( thePnt.Coord(), dist2Nodes, myHalfLeafSize );
6189     if ( !dist2Nodes.empty() )
6190       return dist2Nodes.begin()->second;
6191     list<const SMDS_MeshNode*> nodes;
6192     //myOctreeNode->NodesAround( &tgtNode, &nodes, myHalfLeafSize );
6193
6194     double minSqDist = DBL_MAX;
6195     if ( nodes.empty() )  // get all nodes of OctreeNode's closest to thePnt
6196     {
6197       // sort leafs by their distance from thePnt
6198       typedef map< double, SMESH_OctreeNode* > TDistTreeMap;
6199       TDistTreeMap treeMap;
6200       list< SMESH_OctreeNode* > treeList;
6201       list< SMESH_OctreeNode* >::iterator trIt;
6202       treeList.push_back( myOctreeNode );
6203
6204       gp_XYZ pointNode( thePnt.X(), thePnt.Y(), thePnt.Z() );
6205       bool pointInside = myOctreeNode->isInside( pointNode, myHalfLeafSize );
6206       for ( trIt = treeList.begin(); trIt != treeList.end(); ++trIt)
6207       {
6208         SMESH_OctreeNode* tree = *trIt;
6209         if ( !tree->isLeaf() ) // put children to the queue
6210         {
6211           if ( pointInside && !tree->isInside( pointNode, myHalfLeafSize )) continue;
6212           SMESH_OctreeNodeIteratorPtr cIt = tree->GetChildrenIterator();
6213           while ( cIt->more() )
6214             treeList.push_back( cIt->next() );
6215         }
6216         else if ( tree->NbNodes() ) // put a tree to the treeMap
6217         {
6218           const Bnd_B3d& box = tree->getBox();
6219           double sqDist = thePnt.SquareDistance( 0.5 * ( box.CornerMin() + box.CornerMax() ));
6220           pair<TDistTreeMap::iterator,bool> it_in = treeMap.insert( make_pair( sqDist, tree ));
6221           if ( !it_in.second ) // not unique distance to box center
6222             treeMap.insert( it_in.first, make_pair( sqDist + 1e-13*treeMap.size(), tree ));
6223         }
6224       }
6225       // find distance after which there is no sense to check tree's
6226       double sqLimit = DBL_MAX;
6227       TDistTreeMap::iterator sqDist_tree = treeMap.begin();
6228       if ( treeMap.size() > 5 ) {
6229         SMESH_OctreeNode* closestTree = sqDist_tree->second;
6230         const Bnd_B3d& box = closestTree->getBox();
6231         double limit = sqrt( sqDist_tree->first ) + sqrt ( box.SquareExtent() );
6232         sqLimit = limit * limit;
6233       }
6234       // get all nodes from trees
6235       for ( ; sqDist_tree != treeMap.end(); ++sqDist_tree) {
6236         if ( sqDist_tree->first > sqLimit )
6237           break;
6238         SMESH_OctreeNode* tree = sqDist_tree->second;
6239         tree->NodesAround( tree->GetNodeIterator()->next(), &nodes );
6240       }
6241     }
6242     // find closest among nodes
6243     minSqDist = DBL_MAX;
6244     const SMDS_MeshNode* closestNode = 0;
6245     list<const SMDS_MeshNode*>::iterator nIt = nodes.begin();
6246     for ( ; nIt != nodes.end(); ++nIt ) {
6247       double sqDist = thePnt.SquareDistance( SMESH_TNodeXYZ( *nIt ) );
6248       if ( minSqDist > sqDist ) {
6249         closestNode = *nIt;
6250         minSqDist = sqDist;
6251       }
6252     }
6253     return closestNode;
6254   }
6255
6256   //---------------------------------------------------------------------
6257   /*!
6258    * \brief Destructor
6259    */
6260   ~SMESH_NodeSearcherImpl() { delete myOctreeNode; }
6261
6262   //---------------------------------------------------------------------
6263   /*!
6264    * \brief Return the node tree
6265    */
6266   const SMESH_OctreeNode* getTree() const { return myOctreeNode; }
6267
6268 private:
6269   SMESH_OctreeNode* myOctreeNode;
6270   SMESHDS_Mesh*     myMesh;
6271   double            myHalfLeafSize; // max size of a leaf box
6272 };
6273
6274 //=======================================================================
6275 /*!
6276  * \brief Return SMESH_NodeSearcher
6277  */
6278 //=======================================================================
6279
6280 SMESH_NodeSearcher* SMESH_MeshEditor::GetNodeSearcher() 
6281 {
6282   return new SMESH_NodeSearcherImpl( GetMeshDS() );
6283 }
6284
6285 // ========================================================================
6286 namespace // Utils used in SMESH_ElementSearcherImpl::FindElementsByPoint()
6287 {
6288   const int MaxNbElemsInLeaf = 10; // maximal number of elements in a leaf of tree
6289   const int MaxLevel         = 7;  // maximal tree height -> nb terminal boxes: 8^7 = 2097152
6290   const double NodeRadius = 1e-9;  // to enlarge bnd box of element
6291
6292   //=======================================================================
6293   /*!
6294    * \brief Octal tree of bounding boxes of elements
6295    */
6296   //=======================================================================
6297
6298   class ElementBndBoxTree : public SMESH_Octree
6299   {
6300   public:
6301
6302     ElementBndBoxTree(const SMDS_Mesh& mesh, SMDSAbs_ElementType elemType, SMDS_ElemIteratorPtr theElemIt = SMDS_ElemIteratorPtr(), double tolerance = NodeRadius );
6303     void getElementsNearPoint( const gp_Pnt& point, TIDSortedElemSet& foundElems);
6304     void getElementsNearLine ( const gp_Ax1& line, TIDSortedElemSet& foundElems);
6305     ~ElementBndBoxTree();
6306
6307   protected:
6308     ElementBndBoxTree() {}
6309     SMESH_Octree* allocateOctreeChild() const { return new ElementBndBoxTree; }
6310     void buildChildrenData();
6311     Bnd_B3d* buildRootBox();
6312   private:
6313     //!< Bounding box of element
6314     struct ElementBox : public Bnd_B3d
6315     {
6316       const SMDS_MeshElement* _element;
6317       int                     _refCount; // an ElementBox can be included in several tree branches
6318       ElementBox(const SMDS_MeshElement* elem, double tolerance);
6319     };
6320     vector< ElementBox* > _elements;
6321   };
6322
6323   //================================================================================
6324   /*!
6325    * \brief ElementBndBoxTree creation
6326    */
6327   //================================================================================
6328
6329   ElementBndBoxTree::ElementBndBoxTree(const SMDS_Mesh& mesh, SMDSAbs_ElementType elemType, SMDS_ElemIteratorPtr theElemIt, double tolerance)
6330     :SMESH_Octree( new SMESH_Octree::Limit( MaxLevel, /*minSize=*/0. ))
6331   {
6332     int nbElems = mesh.GetMeshInfo().NbElements( elemType );
6333     _elements.reserve( nbElems );
6334
6335     SMDS_ElemIteratorPtr elemIt = theElemIt ? theElemIt : mesh.elementsIterator( elemType );
6336     while ( elemIt->more() )
6337       _elements.push_back( new ElementBox( elemIt->next(),tolerance  ));
6338
6339     if ( _elements.size() > MaxNbElemsInLeaf )
6340       compute();
6341     else
6342       myIsLeaf = true;
6343   }
6344
6345   //================================================================================
6346   /*!
6347    * \brief Destructor
6348    */
6349   //================================================================================
6350
6351   ElementBndBoxTree::~ElementBndBoxTree()
6352   {
6353     for ( int i = 0; i < _elements.size(); ++i )
6354       if ( --_elements[i]->_refCount <= 0 )
6355         delete _elements[i];
6356   }
6357
6358   //================================================================================
6359   /*!
6360    * \brief Return the maximal box
6361    */
6362   //================================================================================
6363
6364   Bnd_B3d* ElementBndBoxTree::buildRootBox()
6365   {
6366     Bnd_B3d* box = new Bnd_B3d;
6367     for ( int i = 0; i < _elements.size(); ++i )
6368       box->Add( *_elements[i] );
6369     return box;
6370   }
6371
6372   //================================================================================
6373   /*!
6374    * \brief Redistrubute element boxes among children
6375    */
6376   //================================================================================
6377
6378   void ElementBndBoxTree::buildChildrenData()
6379   {
6380     for ( int i = 0; i < _elements.size(); ++i )
6381     {
6382       for (int j = 0; j < 8; j++)
6383       {
6384         if ( !_elements[i]->IsOut( myChildren[j]->getBox() ))
6385         {
6386           _elements[i]->_refCount++;
6387           ((ElementBndBoxTree*)myChildren[j])->_elements.push_back( _elements[i]);
6388         }
6389       }
6390       _elements[i]->_refCount--;
6391     }
6392     _elements.clear();
6393
6394     for (int j = 0; j < 8; j++)
6395     {
6396       ElementBndBoxTree* child = static_cast<ElementBndBoxTree*>( myChildren[j]);
6397       if ( child->_elements.size() <= MaxNbElemsInLeaf )
6398         child->myIsLeaf = true;
6399
6400       if ( child->_elements.capacity() - child->_elements.size() > 1000 )
6401         child->_elements.resize( child->_elements.size() ); // compact
6402     }
6403   }
6404
6405   //================================================================================
6406   /*!
6407    * \brief Return elements which can include the point
6408    */
6409   //================================================================================
6410
6411   void ElementBndBoxTree::getElementsNearPoint( const gp_Pnt&     point,
6412                                                 TIDSortedElemSet& foundElems)
6413   {
6414     if ( level() && getBox().IsOut( point.XYZ() ))
6415       return;
6416
6417     if ( isLeaf() )
6418     {
6419       for ( int i = 0; i < _elements.size(); ++i )
6420         if ( !_elements[i]->IsOut( point.XYZ() ))
6421           foundElems.insert( _elements[i]->_element );
6422     }
6423     else
6424     {
6425       for (int i = 0; i < 8; i++)
6426         ((ElementBndBoxTree*) myChildren[i])->getElementsNearPoint( point, foundElems );
6427     }
6428   }
6429
6430   //================================================================================
6431   /*!
6432    * \brief Return elements which can be intersected by the line
6433    */
6434   //================================================================================
6435
6436   void ElementBndBoxTree::getElementsNearLine( const gp_Ax1&     line,
6437                                                TIDSortedElemSet& foundElems)
6438   {
6439     if ( level() && getBox().IsOut( line ))
6440       return;
6441
6442     if ( isLeaf() )
6443     {
6444       for ( int i = 0; i < _elements.size(); ++i )
6445         if ( !_elements[i]->IsOut( line ))
6446           foundElems.insert( _elements[i]->_element );
6447     }
6448     else
6449     {
6450       for (int i = 0; i < 8; i++)
6451         ((ElementBndBoxTree*) myChildren[i])->getElementsNearLine( line, foundElems );
6452     }
6453   }
6454
6455   //================================================================================
6456   /*!
6457    * \brief Construct the element box
6458    */
6459   //================================================================================
6460
6461   ElementBndBoxTree::ElementBox::ElementBox(const SMDS_MeshElement* elem, double tolerance)
6462   {
6463     _element  = elem;
6464     _refCount = 1;
6465     SMDS_ElemIteratorPtr nIt = elem->nodesIterator();
6466     while ( nIt->more() )
6467       Add( SMESH_TNodeXYZ( cast2Node( nIt->next() )));
6468     Enlarge( tolerance );
6469   }
6470
6471 } // namespace
6472
6473 //=======================================================================
6474 /*!
6475  * \brief Implementation of search for the elements by point and
6476  *        of classification of point in 2D mesh
6477  */
6478 //=======================================================================
6479
6480 struct SMESH_ElementSearcherImpl: public SMESH_ElementSearcher
6481 {
6482   SMESHDS_Mesh*                _mesh;
6483   SMDS_ElemIteratorPtr         _meshPartIt;
6484   ElementBndBoxTree*           _ebbTree;
6485   SMESH_NodeSearcherImpl*      _nodeSearcher;
6486   SMDSAbs_ElementType          _elementType;
6487   double                       _tolerance;
6488   bool                         _outerFacesFound;
6489   set<const SMDS_MeshElement*> _outerFaces; // empty means "no internal faces at all"
6490
6491   SMESH_ElementSearcherImpl( SMESHDS_Mesh& mesh, SMDS_ElemIteratorPtr elemIt=SMDS_ElemIteratorPtr())
6492     : _mesh(&mesh),_meshPartIt(elemIt),_ebbTree(0),_nodeSearcher(0),_tolerance(-1),_outerFacesFound(false) {}
6493   ~SMESH_ElementSearcherImpl()
6494   {
6495     if ( _ebbTree )      delete _ebbTree;      _ebbTree      = 0;
6496     if ( _nodeSearcher ) delete _nodeSearcher; _nodeSearcher = 0;
6497   }
6498   virtual int FindElementsByPoint(const gp_Pnt&                      point,
6499                                   SMDSAbs_ElementType                type,
6500                                   vector< const SMDS_MeshElement* >& foundElements);
6501   virtual TopAbs_State GetPointState(const gp_Pnt& point);
6502
6503   void GetElementsNearLine( const gp_Ax1&                      line,
6504                             SMDSAbs_ElementType                type,
6505                             vector< const SMDS_MeshElement* >& foundElems);
6506   double getTolerance();
6507   bool getIntersParamOnLine(const gp_Lin& line, const SMDS_MeshElement* face,
6508                             const double tolerance, double & param);
6509   void findOuterBoundary(const SMDS_MeshElement* anyOuterFace);
6510   bool isOuterBoundary(const SMDS_MeshElement* face) const
6511   {
6512     return _outerFaces.empty() || _outerFaces.count(face);
6513   }
6514   struct TInters //!< data of intersection of the line and the mesh face (used in GetPointState())
6515   {
6516     const SMDS_MeshElement* _face;
6517     gp_Vec                  _faceNorm;
6518     bool                    _coincides; //!< the line lays in face plane
6519     TInters(const SMDS_MeshElement* face, const gp_Vec& faceNorm, bool coinc=false)
6520       : _face(face), _faceNorm( faceNorm ), _coincides( coinc ) {}
6521   };
6522   struct TFaceLink //!< link and faces sharing it (used in findOuterBoundary())
6523   {
6524     SMESH_TLink      _link;
6525     TIDSortedElemSet _faces;
6526     TFaceLink( const SMDS_MeshNode* n1, const SMDS_MeshNode* n2, const SMDS_MeshElement* face)
6527       : _link( n1, n2 ), _faces( &face, &face + 1) {}
6528   };
6529 };
6530
6531 ostream& operator<< (ostream& out, const SMESH_ElementSearcherImpl::TInters& i)
6532 {
6533   return out << "TInters(face=" << ( i._face ? i._face->GetID() : 0)
6534              << ", _coincides="<<i._coincides << ")";
6535 }
6536
6537 //=======================================================================
6538 /*!
6539  * \brief define tolerance for search
6540  */
6541 //=======================================================================
6542
6543 double SMESH_ElementSearcherImpl::getTolerance()
6544 {
6545   if ( _tolerance < 0 )
6546   {
6547     const SMDS_MeshInfo& meshInfo = _mesh->GetMeshInfo();
6548
6549     _tolerance = 0;
6550     if ( _nodeSearcher && meshInfo.NbNodes() > 1 )
6551     {
6552       double boxSize = _nodeSearcher->getTree()->maxSize();
6553       _tolerance = 1e-8 * boxSize/* / meshInfo.NbNodes()*/;
6554     }
6555     else if ( _ebbTree && meshInfo.NbElements() > 0 )
6556     {
6557       double boxSize = _ebbTree->maxSize();
6558       _tolerance = 1e-8 * boxSize/* / meshInfo.NbElements()*/;
6559     }
6560     if ( _tolerance == 0 )
6561     {
6562       // define tolerance by size of a most complex element
6563       int complexType = SMDSAbs_Volume;
6564       while ( complexType > SMDSAbs_All &&
6565               meshInfo.NbElements( SMDSAbs_ElementType( complexType )) < 1 )
6566         --complexType;
6567       if ( complexType == SMDSAbs_All ) return 0; // empty mesh
6568       double elemSize;
6569       if ( complexType == int( SMDSAbs_Node ))
6570       {
6571         SMDS_NodeIteratorPtr nodeIt = _mesh->nodesIterator();
6572         elemSize = 1;
6573         if ( meshInfo.NbNodes() > 2 )
6574           elemSize = SMESH_TNodeXYZ( nodeIt->next() ).Distance( nodeIt->next() );
6575       }
6576       else
6577       {
6578         SMDS_ElemIteratorPtr elemIt =
6579             _mesh->elementsIterator( SMDSAbs_ElementType( complexType ));
6580         const SMDS_MeshElement* elem = elemIt->next();
6581         SMDS_ElemIteratorPtr nodeIt = elem->nodesIterator();
6582         SMESH_TNodeXYZ n1( cast2Node( nodeIt->next() ));
6583         elemSize = 0;
6584         while ( nodeIt->more() )
6585         {
6586           double dist = n1.Distance( cast2Node( nodeIt->next() ));
6587           elemSize = max( dist, elemSize );
6588         }
6589       }
6590       _tolerance = 1e-4 * elemSize;
6591     }
6592   }
6593   return _tolerance;
6594 }
6595
6596 //================================================================================
6597 /*!
6598  * \brief Find intersection of the line and an edge of face and return parameter on line
6599  */
6600 //================================================================================
6601
6602 bool SMESH_ElementSearcherImpl::getIntersParamOnLine(const gp_Lin&           line,
6603                                                      const SMDS_MeshElement* face,
6604                                                      const double            tol,
6605                                                      double &                param)
6606 {
6607   int nbInts = 0;
6608   param = 0;
6609
6610   GeomAPI_ExtremaCurveCurve anExtCC;
6611   Handle(Geom_Curve) lineCurve = new Geom_Line( line );
6612   
6613   int nbNodes = face->IsQuadratic() ? face->NbNodes()/2 : face->NbNodes();
6614   for ( int i = 0; i < nbNodes && nbInts < 2; ++i )
6615   {
6616     GC_MakeSegment edge( SMESH_TNodeXYZ( face->GetNode( i )),
6617                          SMESH_TNodeXYZ( face->GetNode( (i+1)%nbNodes) )); 
6618     anExtCC.Init( lineCurve, edge);
6619     if ( anExtCC.NbExtrema() > 0 && anExtCC.LowerDistance() <= tol)
6620     {
6621       Quantity_Parameter pl, pe;
6622       anExtCC.LowerDistanceParameters( pl, pe );
6623       param += pl;
6624       if ( ++nbInts == 2 )
6625         break;
6626     }
6627   }
6628   if ( nbInts > 0 ) param /= nbInts;
6629   return nbInts > 0;
6630 }
6631 //================================================================================
6632 /*!
6633  * \brief Find all faces belonging to the outer boundary of mesh
6634  */
6635 //================================================================================
6636
6637 void SMESH_ElementSearcherImpl::findOuterBoundary(const SMDS_MeshElement* outerFace)
6638 {
6639   if ( _outerFacesFound ) return;
6640
6641   // Collect all outer faces by passing from one outer face to another via their links
6642   // and BTW find out if there are internal faces at all.
6643
6644   // checked links and links where outer boundary meets internal one
6645   set< SMESH_TLink > visitedLinks, seamLinks;
6646
6647   // links to treat with already visited faces sharing them
6648   list < TFaceLink > startLinks;
6649
6650   // load startLinks with the first outerFace
6651   startLinks.push_back( TFaceLink( outerFace->GetNode(0), outerFace->GetNode(1), outerFace));
6652   _outerFaces.insert( outerFace );
6653
6654   TIDSortedElemSet emptySet;
6655   while ( !startLinks.empty() )
6656   {
6657     const SMESH_TLink& link  = startLinks.front()._link;
6658     TIDSortedElemSet&  faces = startLinks.front()._faces;
6659
6660     outerFace = *faces.begin();
6661     // find other faces sharing the link
6662     const SMDS_MeshElement* f;
6663     while (( f = SMESH_MeshEditor::FindFaceInSet(link.node1(), link.node2(), emptySet, faces )))
6664       faces.insert( f );
6665
6666     // select another outer face among the found 
6667     const SMDS_MeshElement* outerFace2 = 0;
6668     if ( faces.size() == 2 )
6669     {
6670       outerFace2 = (outerFace == *faces.begin() ? *faces.rbegin() : *faces.begin());
6671     }
6672     else if ( faces.size() > 2 )
6673     {
6674       seamLinks.insert( link );
6675
6676       // link direction within the outerFace
6677       gp_Vec n1n2( SMESH_TNodeXYZ( link.node1()),
6678                    SMESH_TNodeXYZ( link.node2()));
6679       int i1 = outerFace->GetNodeIndex( link.node1() );
6680       int i2 = outerFace->GetNodeIndex( link.node2() );
6681       bool rev = ( abs(i2-i1) == 1 ? i1 > i2 : i2 > i1 );
6682       if ( rev ) n1n2.Reverse();
6683       // outerFace normal
6684       gp_XYZ ofNorm, fNorm;
6685       if ( SMESH_Algo::FaceNormal( outerFace, ofNorm, /*normalized=*/false ))
6686       {
6687         // direction from the link inside outerFace
6688         gp_Vec dirInOF = gp_Vec( ofNorm ) ^ n1n2;
6689         // sort all other faces by angle with the dirInOF
6690         map< double, const SMDS_MeshElement* > angle2Face;
6691         set< const SMDS_MeshElement*, TIDCompare >::const_iterator face = faces.begin();
6692         for ( ; face != faces.end(); ++face )
6693         {
6694           if ( !SMESH_Algo::FaceNormal( *face, fNorm, /*normalized=*/false ))
6695             continue;
6696           gp_Vec dirInF = gp_Vec( fNorm ) ^ n1n2;
6697           double angle = dirInOF.AngleWithRef( dirInF, n1n2 );
6698           if ( angle < 0 ) angle += 2*PI;
6699           angle2Face.insert( make_pair( angle, *face ));
6700         }
6701         if ( !angle2Face.empty() )
6702           outerFace2 = angle2Face.begin()->second;
6703       }
6704     }
6705     // store the found outer face and add its links to continue seaching from
6706     if ( outerFace2 )
6707     {
6708       _outerFaces.insert( outerFace );
6709       int nbNodes = outerFace2->NbNodes()/( outerFace2->IsQuadratic() ? 2 : 1 );
6710       for ( int i = 0; i < nbNodes; ++i )
6711       {
6712         SMESH_TLink link2( outerFace2->GetNode(i), outerFace2->GetNode((i+1)%nbNodes));
6713         if ( visitedLinks.insert( link2 ).second )
6714           startLinks.push_back( TFaceLink( link2.node1(), link2.node2(), outerFace2 ));
6715       }
6716     }
6717     startLinks.pop_front();
6718   }
6719   _outerFacesFound = true;
6720
6721   if ( !seamLinks.empty() )
6722   {
6723     // There are internal boundaries touching the outher one,
6724     // find all faces of internal boundaries in order to find
6725     // faces of boundaries of holes, if any.
6726     
6727   }
6728   else
6729   {
6730     _outerFaces.clear();
6731   }
6732 }
6733
6734 //=======================================================================
6735 /*!
6736  * \brief Find elements of given type where the given point is IN or ON.
6737  *        Returns nb of found elements and elements them-selves.
6738  *
6739  * 'ALL' type means elements of any type excluding nodes and 0D elements
6740  */
6741 //=======================================================================
6742
6743 int SMESH_ElementSearcherImpl::
6744 FindElementsByPoint(const gp_Pnt&                      point,
6745                     SMDSAbs_ElementType                type,
6746                     vector< const SMDS_MeshElement* >& foundElements)
6747 {
6748   foundElements.clear();
6749
6750   double tolerance = getTolerance();
6751
6752   // =================================================================================
6753   if ( type == SMDSAbs_Node || type == SMDSAbs_0DElement )
6754   {
6755     if ( !_nodeSearcher )
6756       _nodeSearcher = new SMESH_NodeSearcherImpl( _mesh );
6757
6758     const SMDS_MeshNode* closeNode = _nodeSearcher->FindClosestTo( point );
6759     if ( !closeNode ) return foundElements.size();
6760
6761     if ( point.Distance( SMESH_TNodeXYZ( closeNode )) > tolerance )
6762       return foundElements.size(); // to far from any node
6763
6764     if ( type == SMDSAbs_Node )
6765     {
6766       foundElements.push_back( closeNode );
6767     }
6768     else
6769     {
6770       SMDS_ElemIteratorPtr elemIt = closeNode->GetInverseElementIterator( SMDSAbs_0DElement );
6771       while ( elemIt->more() )
6772         foundElements.push_back( elemIt->next() );
6773     }
6774   }
6775   // =================================================================================
6776   else // elements more complex than 0D
6777   {
6778     if ( !_ebbTree || _elementType != type )
6779     {
6780       if ( _ebbTree ) delete _ebbTree;
6781       _ebbTree = new ElementBndBoxTree( *_mesh, _elementType = type, _meshPartIt, tolerance );
6782     }
6783     TIDSortedElemSet suspectElems;
6784     _ebbTree->getElementsNearPoint( point, suspectElems );
6785     TIDSortedElemSet::iterator elem = suspectElems.begin();
6786     for ( ; elem != suspectElems.end(); ++elem )
6787       if ( !SMESH_MeshEditor::isOut( *elem, point, tolerance ))
6788         foundElements.push_back( *elem );
6789   }
6790   return foundElements.size();
6791 }
6792
6793 //================================================================================
6794 /*!
6795  * \brief Classify the given point in the closed 2D mesh
6796  */
6797 //================================================================================
6798
6799 TopAbs_State SMESH_ElementSearcherImpl::GetPointState(const gp_Pnt& point)
6800 {
6801   double tolerance = getTolerance();
6802   if ( !_ebbTree || _elementType != SMDSAbs_Face )
6803   {
6804     if ( _ebbTree ) delete _ebbTree;
6805     _ebbTree = new ElementBndBoxTree( *_mesh, _elementType = SMDSAbs_Face, _meshPartIt );
6806   }
6807   // Algo: analyse transition of a line starting at the point through mesh boundary;
6808   // try three lines parallel to axis of the coordinate system and perform rough
6809   // analysis. If solution is not clear perform thorough analysis.
6810
6811   const int nbAxes = 3;
6812   gp_Dir axisDir[ nbAxes ] = { gp::DX(), gp::DY(), gp::DZ() };
6813   map< double, TInters >   paramOnLine2TInters[ nbAxes ];
6814   list< TInters > tangentInters[ nbAxes ]; // of faces whose plane includes the line
6815   multimap< int, int > nbInt2Axis; // to find the simplest case
6816   for ( int axis = 0; axis < nbAxes; ++axis )
6817   {
6818     gp_Ax1 lineAxis( point, axisDir[axis]);
6819     gp_Lin line    ( lineAxis );
6820
6821     TIDSortedElemSet suspectFaces; // faces possibly intersecting the line
6822     _ebbTree->getElementsNearLine( lineAxis, suspectFaces );
6823
6824     // Intersect faces with the line
6825
6826     map< double, TInters > & u2inters = paramOnLine2TInters[ axis ];
6827     TIDSortedElemSet::iterator face = suspectFaces.begin();
6828     for ( ; face != suspectFaces.end(); ++face )
6829     {
6830       // get face plane
6831       gp_XYZ fNorm;
6832       if ( !SMESH_Algo::FaceNormal( *face, fNorm, /*normalized=*/false)) continue;
6833       gp_Pln facePlane( SMESH_TNodeXYZ( (*face)->GetNode(0)), fNorm );
6834
6835       // perform intersection
6836       IntAna_IntConicQuad intersection( line, IntAna_Quadric( facePlane ));
6837       if ( !intersection.IsDone() )
6838         continue;
6839       if ( intersection.IsInQuadric() )
6840       {
6841         tangentInters[ axis ].push_back( TInters( *face, fNorm, true ));
6842       }
6843       else if ( ! intersection.IsParallel() && intersection.NbPoints() > 0 )
6844       {
6845         gp_Pnt intersectionPoint = intersection.Point(1);
6846         if ( !SMESH_MeshEditor::isOut( *face, intersectionPoint, tolerance ))
6847           u2inters.insert(make_pair( intersection.ParamOnConic(1), TInters( *face, fNorm )));
6848       }
6849     }
6850     // Analyse intersections roughly
6851
6852     int nbInter = u2inters.size();
6853     if ( nbInter == 0 )
6854       return TopAbs_OUT; 
6855
6856     double f = u2inters.begin()->first, l = u2inters.rbegin()->first;
6857     if ( nbInter == 1 ) // not closed mesh
6858       return fabs( f ) < tolerance ? TopAbs_ON : TopAbs_UNKNOWN;
6859
6860     if ( fabs( f ) < tolerance || fabs( l ) < tolerance )
6861       return TopAbs_ON;
6862
6863     if ( (f<0) == (l<0) )
6864       return TopAbs_OUT;
6865
6866     int nbIntBeforePoint = std::distance( u2inters.begin(), u2inters.lower_bound(0));
6867     int nbIntAfterPoint  = nbInter - nbIntBeforePoint;
6868     if ( nbIntBeforePoint == 1 || nbIntAfterPoint == 1 )
6869       return TopAbs_IN;
6870
6871     nbInt2Axis.insert( make_pair( min( nbIntBeforePoint, nbIntAfterPoint ), axis ));
6872
6873     if ( _outerFacesFound ) break; // pass to thorough analysis
6874
6875   } // three attempts - loop on CS axes
6876
6877   // Analyse intersections thoroughly.
6878   // We make two loops maximum, on the first one we only exclude touching intersections,
6879   // on the second, if situation is still unclear, we gather and use information on
6880   // position of faces (internal or outer). If faces position is already gathered,
6881   // we make the second loop right away.
6882
6883   for ( int hasPositionInfo = _outerFacesFound; hasPositionInfo < 2; ++hasPositionInfo )
6884   {
6885     multimap< int, int >::const_iterator nb_axis = nbInt2Axis.begin();
6886     for ( ; nb_axis != nbInt2Axis.end(); ++nb_axis )
6887     {
6888       int axis = nb_axis->second;
6889       map< double, TInters > & u2inters = paramOnLine2TInters[ axis ];
6890
6891       gp_Ax1 lineAxis( point, axisDir[axis]);
6892       gp_Lin line    ( lineAxis );
6893
6894       // add tangent intersections to u2inters
6895       double param;
6896       list< TInters >::const_iterator tgtInt = tangentInters[ axis ].begin();
6897       for ( ; tgtInt != tangentInters[ axis ].end(); ++tgtInt )
6898         if ( getIntersParamOnLine( line, tgtInt->_face, tolerance, param ))
6899           u2inters.insert(make_pair( param, *tgtInt ));
6900       tangentInters[ axis ].clear();
6901
6902       // Count intersections before and after the point excluding touching ones.
6903       // If hasPositionInfo we count intersections of outer boundary only
6904
6905       int nbIntBeforePoint = 0, nbIntAfterPoint = 0;
6906       double f = numeric_limits<double>::max(), l = -numeric_limits<double>::max();
6907       map< double, TInters >::iterator u_int1 = u2inters.begin(), u_int2 = u_int1;
6908       bool ok = ! u_int1->second._coincides;
6909       while ( ok && u_int1 != u2inters.end() )
6910       {
6911         double u = u_int1->first;
6912         bool touchingInt = false;
6913         if ( ++u_int2 != u2inters.end() )
6914         {
6915           // skip intersections at the same point (if the line passes through edge or node)
6916           int nbSamePnt = 0;
6917           while ( u_int2 != u2inters.end() && fabs( u_int2->first - u ) < tolerance )
6918           {
6919             ++nbSamePnt;
6920             ++u_int2;
6921           }
6922
6923           // skip tangent intersections
6924           int nbTgt = 0;
6925           const SMDS_MeshElement* prevFace = u_int1->second._face;
6926           while ( ok && u_int2->second._coincides )
6927           {
6928             if ( SMESH_Algo::GetCommonNodes(prevFace , u_int2->second._face).empty() )
6929               ok = false;
6930             else
6931             {
6932               nbTgt++;
6933               u_int2++;
6934               ok = ( u_int2 != u2inters.end() );
6935             }
6936           }
6937           if ( !ok ) break;
6938
6939           // skip intersections at the same point after tangent intersections
6940           if ( nbTgt > 0 )
6941           {
6942             double u2 = u_int2->first;
6943             ++u_int2;
6944             while ( u_int2 != u2inters.end() && fabs( u_int2->first - u2 ) < tolerance )
6945             {
6946               ++nbSamePnt;
6947               ++u_int2;
6948             }
6949           }
6950           // decide if we skipped a touching intersection
6951           if ( nbSamePnt + nbTgt > 0 )
6952           {
6953             double minDot = numeric_limits<double>::max(), maxDot = -numeric_limits<double>::max();
6954             map< double, TInters >::iterator u_int = u_int1;
6955             for ( ; u_int != u_int2; ++u_int )
6956             {
6957               if ( u_int->second._coincides ) continue;
6958               double dot = u_int->second._faceNorm * line.Direction();
6959               if ( dot > maxDot ) maxDot = dot;
6960               if ( dot < minDot ) minDot = dot;
6961             }
6962             touchingInt = ( minDot*maxDot < 0 );
6963           }
6964         }
6965         if ( !touchingInt )
6966         {
6967           if ( !hasPositionInfo || isOuterBoundary( u_int1->second._face ))
6968           {
6969             if ( u < 0 )
6970               ++nbIntBeforePoint;
6971             else
6972               ++nbIntAfterPoint;
6973           }
6974           if ( u < f ) f = u;
6975           if ( u > l ) l = u;
6976         }
6977
6978         u_int1 = u_int2; // to next intersection
6979
6980       } // loop on intersections with one line
6981
6982       if ( ok )
6983       {
6984         if ( fabs( f ) < tolerance || fabs( l ) < tolerance )
6985           return TopAbs_ON;
6986
6987         if ( nbIntBeforePoint == 0  || nbIntAfterPoint == 0)
6988           return TopAbs_OUT; 
6989
6990         if ( nbIntBeforePoint + nbIntAfterPoint == 1 ) // not closed mesh
6991           return fabs( f ) < tolerance ? TopAbs_ON : TopAbs_UNKNOWN;
6992
6993         if ( nbIntBeforePoint == 1 || nbIntAfterPoint == 1 )
6994           return TopAbs_IN;
6995
6996         if ( (f<0) == (l<0) )
6997           return TopAbs_OUT;
6998
6999         if ( hasPositionInfo )
7000           return nbIntBeforePoint % 2 ? TopAbs_IN : TopAbs_OUT;
7001       }
7002     } // loop on intersections of the tree lines - thorough analysis
7003
7004     if ( !hasPositionInfo )
7005     {
7006       // gather info on faces position - is face in the outer boundary or not
7007       map< double, TInters > & u2inters = paramOnLine2TInters[ 0 ];
7008       findOuterBoundary( u2inters.begin()->second._face );
7009     }
7010
7011   } // two attempts - with and w/o faces position info in the mesh
7012
7013   return TopAbs_UNKNOWN;
7014 }
7015
7016 //=======================================================================
7017 /*!
7018  * \brief Return elements possibly intersecting the line
7019  */
7020 //=======================================================================
7021
7022 void SMESH_ElementSearcherImpl::GetElementsNearLine( const gp_Ax1&                      line,
7023                                                      SMDSAbs_ElementType                type,
7024                                                      vector< const SMDS_MeshElement* >& foundElems)
7025 {
7026   if ( !_ebbTree || _elementType != type )
7027   {
7028     if ( _ebbTree ) delete _ebbTree;
7029     _ebbTree = new ElementBndBoxTree( *_mesh, _elementType = type, _meshPartIt );
7030   }
7031   TIDSortedElemSet suspectFaces; // elements possibly intersecting the line
7032   _ebbTree->getElementsNearLine( line, suspectFaces );
7033   foundElems.assign( suspectFaces.begin(), suspectFaces.end());
7034 }
7035
7036 //=======================================================================
7037 /*!
7038  * \brief Return SMESH_ElementSearcher
7039  */
7040 //=======================================================================
7041
7042 SMESH_ElementSearcher* SMESH_MeshEditor::GetElementSearcher()
7043 {
7044   return new SMESH_ElementSearcherImpl( *GetMeshDS() );
7045 }
7046
7047 //=======================================================================
7048 /*!
7049  * \brief Return SMESH_ElementSearcher
7050  */
7051 //=======================================================================
7052
7053 SMESH_ElementSearcher* SMESH_MeshEditor::GetElementSearcher(SMDS_ElemIteratorPtr elemIt)
7054 {
7055   return new SMESH_ElementSearcherImpl( *GetMeshDS(), elemIt );
7056 }
7057
7058 //=======================================================================
7059 /*!
7060  * \brief Return true if the point is IN or ON of the element
7061  */
7062 //=======================================================================
7063
7064 bool SMESH_MeshEditor::isOut( const SMDS_MeshElement* element, const gp_Pnt& point, double tol )
7065 {
7066   if ( element->GetType() == SMDSAbs_Volume)
7067   {
7068     return SMDS_VolumeTool( element ).IsOut( point.X(), point.Y(), point.Z(), tol );
7069   }
7070
7071   // get ordered nodes
7072
7073   vector< gp_XYZ > xyz;
7074   vector<const SMDS_MeshNode*> nodeList;
7075
7076   SMDS_ElemIteratorPtr nodeIt = element->nodesIterator();
7077   if ( element->IsQuadratic() ) {
7078     if (const SMDS_VtkFace* f=dynamic_cast<const SMDS_VtkFace*>(element))
7079       nodeIt = f->interlacedNodesElemIterator();
7080     else if (const SMDS_VtkEdge*  e =dynamic_cast<const SMDS_VtkEdge*>(element))
7081       nodeIt = e->interlacedNodesElemIterator();
7082   }
7083   while ( nodeIt->more() )
7084     {
7085       const SMDS_MeshNode* node = cast2Node( nodeIt->next() );
7086       xyz.push_back( SMESH_TNodeXYZ(node) );
7087       nodeList.push_back(node);
7088     }
7089
7090   int i, nbNodes = element->NbNodes();
7091
7092   if ( element->GetType() == SMDSAbs_Face ) // --------------------------------------------------
7093   {
7094     // compute face normal
7095     gp_Vec faceNorm(0,0,0);
7096     xyz.push_back( xyz.front() );
7097     nodeList.push_back( nodeList.front() );
7098     for ( i = 0; i < nbNodes; ++i )
7099     {
7100       gp_Vec edge1( xyz[i+1], xyz[i]);
7101       gp_Vec edge2( xyz[i+1], xyz[(i+2)%nbNodes] );
7102       faceNorm += edge1 ^ edge2;
7103     }
7104     double normSize = faceNorm.Magnitude();
7105     if ( normSize <= tol )
7106     {
7107       // degenerated face: point is out if it is out of all face edges
7108       for ( i = 0; i < nbNodes; ++i )
7109       {
7110         SMDS_LinearEdge edge( nodeList[i], nodeList[i+1] );
7111         if ( !isOut( &edge, point, tol ))
7112           return false;
7113       }
7114       return true;
7115     }
7116     faceNorm /= normSize;
7117
7118     // check if the point lays on face plane
7119     gp_Vec n2p( xyz[0], point );
7120     if ( fabs( n2p * faceNorm ) > tol )
7121       return true; // not on face plane
7122
7123     // check if point is out of face boundary:
7124     // define it by closest transition of a ray point->infinity through face boundary
7125     // on the face plane.
7126     // First, find normal of a plane perpendicular to face plane, to be used as a cutting tool
7127     // to find intersections of the ray with the boundary.
7128     gp_Vec ray = n2p;
7129     gp_Vec plnNorm = ray ^ faceNorm;
7130     normSize = plnNorm.Magnitude();
7131     if ( normSize <= tol ) return false; // point coincides with the first node
7132     plnNorm /= normSize;
7133     // for each node of the face, compute its signed distance to the plane
7134     vector<double> dist( nbNodes + 1);
7135     for ( i = 0; i < nbNodes; ++i )
7136     {
7137       gp_Vec n2p( xyz[i], point );
7138       dist[i] = n2p * plnNorm;
7139     }
7140     dist.back() = dist.front();
7141     // find the closest intersection
7142     int    iClosest = -1;
7143     double rClosest, distClosest = 1e100;;
7144     gp_Pnt pClosest;
7145     for ( i = 0; i < nbNodes; ++i )
7146     {
7147       double r;
7148       if ( fabs( dist[i]) < tol )
7149         r = 0.;
7150       else if ( fabs( dist[i+1]) < tol )
7151         r = 1.;
7152       else if ( dist[i] * dist[i+1] < 0 )
7153         r = dist[i] / ( dist[i] - dist[i+1] );
7154       else
7155         continue; // no intersection
7156       gp_Pnt pInt = xyz[i] * (1.-r) + xyz[i+1] * r;
7157       gp_Vec p2int ( point, pInt);
7158       if ( p2int * ray > -tol ) // right half-space
7159       {
7160         double intDist = p2int.SquareMagnitude();
7161         if ( intDist < distClosest )
7162         {
7163           iClosest = i;
7164           rClosest = r;
7165           pClosest = pInt;
7166           distClosest = intDist;
7167         }
7168       }
7169     }
7170     if ( iClosest < 0 )
7171       return true; // no intesections - out
7172
7173     // analyse transition
7174     gp_Vec edge( xyz[iClosest], xyz[iClosest+1] );
7175     gp_Vec edgeNorm = -( edge ^ faceNorm ); // normal to intersected edge pointing out of face
7176     gp_Vec p2int ( point, pClosest );
7177     bool out = (edgeNorm * p2int) < -tol;
7178     if ( rClosest > 0. && rClosest < 1. ) // not node intersection
7179       return out;
7180
7181     // ray pass through a face node; analyze transition through an adjacent edge
7182     gp_Pnt p1 = xyz[ (rClosest == 0.) ? ((iClosest+nbNodes-1) % nbNodes) : (iClosest+1) ];
7183     gp_Pnt p2 = xyz[ (rClosest == 0.) ? iClosest : ((iClosest+2) % nbNodes) ];
7184     gp_Vec edgeAdjacent( p1, p2 );
7185     gp_Vec edgeNorm2 = -( edgeAdjacent ^ faceNorm );
7186     bool out2 = (edgeNorm2 * p2int) < -tol;
7187
7188     bool covexCorner = ( edgeNorm * edgeAdjacent * (rClosest==1. ? 1. : -1.)) < 0;
7189     return covexCorner ? (out || out2) : (out && out2);
7190   }
7191   if ( element->GetType() == SMDSAbs_Edge ) // --------------------------------------------------
7192   {
7193     // point is out of edge if it is NOT ON any straight part of edge
7194     // (we consider quadratic edge as being composed of two straight parts)
7195     for ( i = 1; i < nbNodes; ++i )
7196     {
7197       gp_Vec edge( xyz[i-1], xyz[i]);
7198       gp_Vec n1p ( xyz[i-1], point);
7199       double dist = ( edge ^ n1p ).Magnitude() / edge.Magnitude();
7200       if ( dist > tol )
7201         continue;
7202       gp_Vec n2p( xyz[i], point );
7203       if ( fabs( edge.Magnitude() - n1p.Magnitude() - n2p.Magnitude()) > tol )
7204         continue;
7205       return false; // point is ON this part
7206     }
7207     return true;
7208   }
7209   // Node or 0D element -------------------------------------------------------------------------
7210   {
7211     gp_Vec n2p ( xyz[0], point );
7212     return n2p.Magnitude() <= tol;
7213   }
7214   return true;
7215 }
7216
7217 //=======================================================================
7218 //function : SimplifyFace
7219 //purpose  :
7220 //=======================================================================
7221 int SMESH_MeshEditor::SimplifyFace (const vector<const SMDS_MeshNode *> faceNodes,
7222                                     vector<const SMDS_MeshNode *>&      poly_nodes,
7223                                     vector<int>&                        quantities) const
7224 {
7225   int nbNodes = faceNodes.size();
7226
7227   if (nbNodes < 3)
7228     return 0;
7229
7230   set<const SMDS_MeshNode*> nodeSet;
7231
7232   // get simple seq of nodes
7233   //const SMDS_MeshNode* simpleNodes[ nbNodes ];
7234   vector<const SMDS_MeshNode*> simpleNodes( nbNodes );
7235   int iSimple = 0, nbUnique = 0;
7236
7237   simpleNodes[iSimple++] = faceNodes[0];
7238   nbUnique++;
7239   for (int iCur = 1; iCur < nbNodes; iCur++) {
7240     if (faceNodes[iCur] != simpleNodes[iSimple - 1]) {
7241       simpleNodes[iSimple++] = faceNodes[iCur];
7242       if (nodeSet.insert( faceNodes[iCur] ).second)
7243         nbUnique++;
7244     }
7245   }
7246   int nbSimple = iSimple;
7247   if (simpleNodes[nbSimple - 1] == simpleNodes[0]) {
7248     nbSimple--;
7249     iSimple--;
7250   }
7251
7252   if (nbUnique < 3)
7253     return 0;
7254
7255   // separate loops
7256   int nbNew = 0;
7257   bool foundLoop = (nbSimple > nbUnique);
7258   while (foundLoop) {
7259     foundLoop = false;
7260     set<const SMDS_MeshNode*> loopSet;
7261     for (iSimple = 0; iSimple < nbSimple && !foundLoop; iSimple++) {
7262       const SMDS_MeshNode* n = simpleNodes[iSimple];
7263       if (!loopSet.insert( n ).second) {
7264         foundLoop = true;
7265
7266         // separate loop
7267         int iC = 0, curLast = iSimple;
7268         for (; iC < curLast; iC++) {
7269           if (simpleNodes[iC] == n) break;
7270         }
7271         int loopLen = curLast - iC;
7272         if (loopLen > 2) {
7273           // create sub-element
7274           nbNew++;
7275           quantities.push_back(loopLen);
7276           for (; iC < curLast; iC++) {
7277             poly_nodes.push_back(simpleNodes[iC]);
7278           }
7279         }
7280         // shift the rest nodes (place from the first loop position)
7281         for (iC = curLast + 1; iC < nbSimple; iC++) {
7282           simpleNodes[iC - loopLen] = simpleNodes[iC];
7283         }
7284         nbSimple -= loopLen;
7285         iSimple -= loopLen;
7286       }
7287     } // for (iSimple = 0; iSimple < nbSimple; iSimple++)
7288   } // while (foundLoop)
7289
7290   if (iSimple > 2) {
7291     nbNew++;
7292     quantities.push_back(iSimple);
7293     for (int i = 0; i < iSimple; i++)
7294       poly_nodes.push_back(simpleNodes[i]);
7295   }
7296
7297   return nbNew;
7298 }
7299
7300 //=======================================================================
7301 //function : MergeNodes
7302 //purpose  : In each group, the cdr of nodes are substituted by the first one
7303 //           in all elements.
7304 //=======================================================================
7305
7306 void SMESH_MeshEditor::MergeNodes (TListOfListOfNodes & theGroupsOfNodes)
7307 {
7308   MESSAGE("MergeNodes");
7309   myLastCreatedElems.Clear();
7310   myLastCreatedNodes.Clear();
7311
7312   SMESHDS_Mesh* aMesh = GetMeshDS();
7313
7314   TNodeNodeMap nodeNodeMap; // node to replace - new node
7315   set<const SMDS_MeshElement*> elems; // all elements with changed nodes
7316   list< int > rmElemIds, rmNodeIds;
7317
7318   // Fill nodeNodeMap and elems
7319
7320   TListOfListOfNodes::iterator grIt = theGroupsOfNodes.begin();
7321   for ( ; grIt != theGroupsOfNodes.end(); grIt++ ) {
7322     list<const SMDS_MeshNode*>& nodes = *grIt;
7323     list<const SMDS_MeshNode*>::iterator nIt = nodes.begin();
7324     const SMDS_MeshNode* nToKeep = *nIt;
7325     //MESSAGE("node to keep " << nToKeep->GetID());
7326     for ( ++nIt; nIt != nodes.end(); nIt++ ) {
7327       const SMDS_MeshNode* nToRemove = *nIt;
7328       nodeNodeMap.insert( TNodeNodeMap::value_type( nToRemove, nToKeep ));
7329       if ( nToRemove != nToKeep ) {
7330         //MESSAGE("  node to remove " << nToRemove->GetID());
7331         rmNodeIds.push_back( nToRemove->GetID() );
7332         AddToSameGroups( nToKeep, nToRemove, aMesh );
7333       }
7334
7335       SMDS_ElemIteratorPtr invElemIt = nToRemove->GetInverseElementIterator();
7336       while ( invElemIt->more() ) {
7337         const SMDS_MeshElement* elem = invElemIt->next();
7338         elems.insert(elem);
7339       }
7340     }
7341   }
7342   // Change element nodes or remove an element
7343
7344   set<const SMDS_MeshElement*>::iterator eIt = elems.begin();
7345   for ( ; eIt != elems.end(); eIt++ ) {
7346     const SMDS_MeshElement* elem = *eIt;
7347     //MESSAGE(" ---- inverse elem on node to remove " << elem->GetID());
7348     int nbNodes = elem->NbNodes();
7349     int aShapeId = FindShape( elem );
7350
7351     set<const SMDS_MeshNode*> nodeSet;
7352     vector< const SMDS_MeshNode*> curNodes( nbNodes ), uniqueNodes( nbNodes );
7353     int iUnique = 0, iCur = 0, nbRepl = 0;
7354     vector<int> iRepl( nbNodes );
7355
7356     // get new seq of nodes
7357     SMDS_ElemIteratorPtr itN = elem->nodesIterator();
7358     while ( itN->more() ) {
7359       const SMDS_MeshNode* n =
7360         static_cast<const SMDS_MeshNode*>( itN->next() );
7361
7362       TNodeNodeMap::iterator nnIt = nodeNodeMap.find( n );
7363       if ( nnIt != nodeNodeMap.end() ) { // n sticks
7364         n = (*nnIt).second;
7365         // BUG 0020185: begin
7366         {
7367           bool stopRecur = false;
7368           set<const SMDS_MeshNode*> nodesRecur;
7369           nodesRecur.insert(n);
7370           while (!stopRecur) {
7371             TNodeNodeMap::iterator nnIt_i = nodeNodeMap.find( n );
7372             if ( nnIt_i != nodeNodeMap.end() ) { // n sticks
7373               n = (*nnIt_i).second;
7374               if (!nodesRecur.insert(n).second) {
7375                 // error: recursive dependancy
7376                 stopRecur = true;
7377               }
7378             }
7379             else
7380               stopRecur = true;
7381           }
7382         }
7383         // BUG 0020185: end
7384         iRepl[ nbRepl++ ] = iCur;
7385       }
7386       curNodes[ iCur ] = n;
7387       bool isUnique = nodeSet.insert( n ).second;
7388       if ( isUnique )
7389         uniqueNodes[ iUnique++ ] = n;
7390       iCur++;
7391     }
7392
7393     // Analyse element topology after replacement
7394
7395     bool isOk = true;
7396     int nbUniqueNodes = nodeSet.size();
7397     //MESSAGE("nbNodes nbUniqueNodes " << nbNodes << " " << nbUniqueNodes);
7398     if ( nbNodes != nbUniqueNodes ) { // some nodes stick
7399       // Polygons and Polyhedral volumes
7400       if (elem->IsPoly()) {
7401
7402         if (elem->GetType() == SMDSAbs_Face) {
7403           // Polygon
7404           vector<const SMDS_MeshNode *> face_nodes (nbNodes);
7405           int inode = 0;
7406           for (; inode < nbNodes; inode++) {
7407             face_nodes[inode] = curNodes[inode];
7408           }
7409
7410           vector<const SMDS_MeshNode *> polygons_nodes;
7411           vector<int> quantities;
7412           int nbNew = SimplifyFace(face_nodes, polygons_nodes, quantities);
7413           if (nbNew > 0) {
7414             inode = 0;
7415             for (int iface = 0; iface < nbNew; iface++) {
7416               int nbNodes = quantities[iface];
7417               vector<const SMDS_MeshNode *> poly_nodes (nbNodes);
7418               for (int ii = 0; ii < nbNodes; ii++, inode++) {
7419                 poly_nodes[ii] = polygons_nodes[inode];
7420               }
7421               SMDS_MeshElement* newElem = aMesh->AddPolygonalFace(poly_nodes);
7422               myLastCreatedElems.Append(newElem);
7423               if (aShapeId)
7424                 aMesh->SetMeshElementOnShape(newElem, aShapeId);
7425             }
7426
7427             MESSAGE("ChangeElementNodes MergeNodes Polygon");
7428             //aMesh->ChangeElementNodes(elem, &polygons_nodes[inode], quantities[nbNew - 1]);
7429             vector<const SMDS_MeshNode *> polynodes(polygons_nodes.begin()+inode,polygons_nodes.end());
7430             int quid =0;
7431             if (nbNew > 0) quid = nbNew - 1;
7432             vector<int> newquant(quantities.begin()+quid, quantities.end());
7433             const SMDS_MeshElement* newElem = 0;
7434             newElem = aMesh->AddPolyhedralVolume(polynodes, newquant);
7435             myLastCreatedElems.Append(newElem);
7436             if ( aShapeId && newElem )
7437               aMesh->SetMeshElementOnShape( newElem, aShapeId );
7438             rmElemIds.push_back(elem->GetID());
7439           }
7440           else {
7441             rmElemIds.push_back(elem->GetID());
7442           }
7443
7444         }
7445         else if (elem->GetType() == SMDSAbs_Volume) {
7446           // Polyhedral volume
7447           if (nbUniqueNodes < 4) {
7448             rmElemIds.push_back(elem->GetID());
7449           }
7450           else {
7451             // each face has to be analyzed in order to check volume validity
7452             const SMDS_VtkVolume* aPolyedre =
7453               dynamic_cast<const SMDS_VtkVolume*>( elem );
7454             if (aPolyedre) {
7455               int nbFaces = aPolyedre->NbFaces();
7456
7457               vector<const SMDS_MeshNode *> poly_nodes;
7458               vector<int> quantities;
7459
7460               for (int iface = 1; iface <= nbFaces; iface++) {
7461                 int nbFaceNodes = aPolyedre->NbFaceNodes(iface);
7462                 vector<const SMDS_MeshNode *> faceNodes (nbFaceNodes);
7463
7464                 for (int inode = 1; inode <= nbFaceNodes; inode++) {
7465                   const SMDS_MeshNode * faceNode = aPolyedre->GetFaceNode(iface, inode);
7466                   TNodeNodeMap::iterator nnIt = nodeNodeMap.find(faceNode);
7467                   if (nnIt != nodeNodeMap.end()) { // faceNode sticks
7468                     faceNode = (*nnIt).second;
7469                   }
7470                   faceNodes[inode - 1] = faceNode;
7471                 }
7472
7473                 SimplifyFace(faceNodes, poly_nodes, quantities);
7474               }
7475
7476               if (quantities.size() > 3) {
7477                 // to be done: remove coincident faces
7478               }
7479
7480               if (quantities.size() > 3)
7481                 {
7482                   MESSAGE("ChangeElementNodes MergeNodes Polyhedron");
7483                   //aMesh->ChangePolyhedronNodes(elem, poly_nodes, quantities);
7484                   const SMDS_MeshElement* newElem = 0;
7485                   newElem = aMesh->AddPolyhedralVolume(poly_nodes, quantities);
7486                   myLastCreatedElems.Append(newElem);
7487                   if ( aShapeId && newElem )
7488                     aMesh->SetMeshElementOnShape( newElem, aShapeId );
7489                   rmElemIds.push_back(elem->GetID());
7490                 }
7491             }
7492             else {
7493               rmElemIds.push_back(elem->GetID());
7494             }
7495           }
7496         }
7497         else {
7498         }
7499
7500         continue;
7501       }
7502
7503       // Regular elements
7504       // TODO not all the possible cases are solved. Find something more generic?
7505       switch ( nbNodes ) {
7506       case 2: ///////////////////////////////////// EDGE
7507         isOk = false; break;
7508       case 3: ///////////////////////////////////// TRIANGLE
7509         isOk = false; break;
7510       case 4:
7511         if ( elem->GetType() == SMDSAbs_Volume ) // TETRAHEDRON
7512           isOk = false;
7513         else { //////////////////////////////////// QUADRANGLE
7514           if ( nbUniqueNodes < 3 )
7515             isOk = false;
7516           else if ( nbRepl == 2 && iRepl[ 1 ] - iRepl[ 0 ] == 2 )
7517             isOk = false; // opposite nodes stick
7518           //MESSAGE("isOk " << isOk);
7519         }
7520         break;
7521       case 6: ///////////////////////////////////// PENTAHEDRON
7522         if ( nbUniqueNodes == 4 ) {
7523           // ---------------------------------> tetrahedron
7524           if (nbRepl == 3 &&
7525               iRepl[ 0 ] > 2 && iRepl[ 1 ] > 2 && iRepl[ 2 ] > 2 ) {
7526             // all top nodes stick: reverse a bottom
7527             uniqueNodes[ 0 ] = curNodes [ 1 ];
7528             uniqueNodes[ 1 ] = curNodes [ 0 ];
7529           }
7530           else if (nbRepl == 3 &&
7531                    iRepl[ 0 ] < 3 && iRepl[ 1 ] < 3 && iRepl[ 2 ] < 3 ) {
7532             // all bottom nodes stick: set a top before
7533             uniqueNodes[ 3 ] = uniqueNodes [ 0 ];
7534             uniqueNodes[ 0 ] = curNodes [ 3 ];
7535             uniqueNodes[ 1 ] = curNodes [ 4 ];
7536             uniqueNodes[ 2 ] = curNodes [ 5 ];
7537           }
7538           else if (nbRepl == 4 &&
7539                    iRepl[ 2 ] - iRepl [ 0 ] == 3 && iRepl[ 3 ] - iRepl [ 1 ] == 3 ) {
7540             // a lateral face turns into a line: reverse a bottom
7541             uniqueNodes[ 0 ] = curNodes [ 1 ];
7542             uniqueNodes[ 1 ] = curNodes [ 0 ];
7543           }
7544           else
7545             isOk = false;
7546         }
7547         else if ( nbUniqueNodes == 5 ) {
7548           // PENTAHEDRON --------------------> 2 tetrahedrons
7549           if ( nbRepl == 2 && iRepl[ 1 ] - iRepl [ 0 ] == 3 ) {
7550             // a bottom node sticks with a linked top one
7551             // 1.
7552             SMDS_MeshElement* newElem =
7553               aMesh->AddVolume(curNodes[ 3 ],
7554                                curNodes[ 4 ],
7555                                curNodes[ 5 ],
7556                                curNodes[ iRepl[ 0 ] == 2 ? 1 : 2 ]);
7557             myLastCreatedElems.Append(newElem);
7558             if ( aShapeId )
7559               aMesh->SetMeshElementOnShape( newElem, aShapeId );
7560             // 2. : reverse a bottom
7561             uniqueNodes[ 0 ] = curNodes [ 1 ];
7562             uniqueNodes[ 1 ] = curNodes [ 0 ];
7563             nbUniqueNodes = 4;
7564           }
7565           else
7566             isOk = false;
7567         }
7568         else
7569           isOk = false;
7570         break;
7571       case 8: {
7572         if(elem->IsQuadratic()) { // Quadratic quadrangle
7573           //   1    5    2
7574           //    +---+---+
7575           //    |       |
7576           //    |       |
7577           //   4+       +6
7578           //    |       |
7579           //    |       |
7580           //    +---+---+
7581           //   0    7    3
7582           isOk = false;
7583           if(nbRepl==2) {
7584             MESSAGE("nbRepl=2: " << iRepl[0] << " " << iRepl[1]);
7585           }
7586           if(nbRepl==3) {
7587             MESSAGE("nbRepl=3: " << iRepl[0] << " " << iRepl[1]  << " " << iRepl[2]);
7588             nbUniqueNodes = 6;
7589             if( iRepl[0]==0 && iRepl[1]==1 && iRepl[2]==4 ) {
7590               uniqueNodes[0] = curNodes[0];
7591               uniqueNodes[1] = curNodes[2];
7592               uniqueNodes[2] = curNodes[3];
7593               uniqueNodes[3] = curNodes[5];
7594               uniqueNodes[4] = curNodes[6];
7595               uniqueNodes[5] = curNodes[7];
7596               isOk = true;
7597             }
7598             if( iRepl[0]==0 && iRepl[1]==3 && iRepl[2]==7 ) {
7599               uniqueNodes[0] = curNodes[0];
7600               uniqueNodes[1] = curNodes[1];
7601               uniqueNodes[2] = curNodes[2];
7602               uniqueNodes[3] = curNodes[4];
7603               uniqueNodes[4] = curNodes[5];
7604               uniqueNodes[5] = curNodes[6];
7605               isOk = true;
7606             }
7607             if( iRepl[0]==0 && iRepl[1]==4 && iRepl[2]==7 ) {
7608               uniqueNodes[0] = curNodes[1];
7609               uniqueNodes[1] = curNodes[2];
7610               uniqueNodes[2] = curNodes[3];
7611               uniqueNodes[3] = curNodes[5];
7612               uniqueNodes[4] = curNodes[6];
7613               uniqueNodes[5] = curNodes[0];
7614               isOk = true;
7615             }
7616             if( iRepl[0]==1 && iRepl[1]==2 && iRepl[2]==5 ) {
7617               uniqueNodes[0] = curNodes[0];
7618               uniqueNodes[1] = curNodes[1];
7619               uniqueNodes[2] = curNodes[3];
7620               uniqueNodes[3] = curNodes[4];
7621               uniqueNodes[4] = curNodes[6];
7622               uniqueNodes[5] = curNodes[7];
7623               isOk = true;
7624             }
7625             if( iRepl[0]==1 && iRepl[1]==4 && iRepl[2]==5 ) {
7626               uniqueNodes[0] = curNodes[0];
7627               uniqueNodes[1] = curNodes[2];
7628               uniqueNodes[2] = curNodes[3];
7629               uniqueNodes[3] = curNodes[1];
7630               uniqueNodes[4] = curNodes[6];
7631               uniqueNodes[5] = curNodes[7];
7632               isOk = true;
7633             }
7634             if( iRepl[0]==2 && iRepl[1]==3 && iRepl[2]==6 ) {
7635               uniqueNodes[0] = curNodes[0];
7636               uniqueNodes[1] = curNodes[1];
7637               uniqueNodes[2] = curNodes[2];
7638               uniqueNodes[3] = curNodes[4];
7639               uniqueNodes[4] = curNodes[5];
7640               uniqueNodes[5] = curNodes[7];
7641               isOk = true;
7642             }
7643             if( iRepl[0]==2 && iRepl[1]==5 && iRepl[2]==6 ) {
7644               uniqueNodes[0] = curNodes[0];
7645               uniqueNodes[1] = curNodes[1];
7646               uniqueNodes[2] = curNodes[3];
7647               uniqueNodes[3] = curNodes[4];
7648               uniqueNodes[4] = curNodes[2];
7649               uniqueNodes[5] = curNodes[7];
7650               isOk = true;
7651             }
7652             if( iRepl[0]==3 && iRepl[1]==6 && iRepl[2]==7 ) {
7653               uniqueNodes[0] = curNodes[0];
7654               uniqueNodes[1] = curNodes[1];
7655               uniqueNodes[2] = curNodes[2];
7656               uniqueNodes[3] = curNodes[4];
7657               uniqueNodes[4] = curNodes[5];
7658               uniqueNodes[5] = curNodes[3];
7659               isOk = true;
7660             }
7661           }
7662           if(nbRepl==4) {
7663             MESSAGE("nbRepl=4: " << iRepl[0] << " " << iRepl[1]  << " " << iRepl[2] << " " << iRepl[3]);
7664           }
7665           if(nbRepl==5) {
7666             MESSAGE("nbRepl=5: " << iRepl[0] << " " << iRepl[1]  << " " << iRepl[2] << " " << iRepl[3] << " " << iRepl[4]);
7667           }
7668           break;
7669         }
7670         //////////////////////////////////// HEXAHEDRON
7671         isOk = false;
7672         SMDS_VolumeTool hexa (elem);
7673         hexa.SetExternalNormal();
7674         if ( nbUniqueNodes == 4 && nbRepl == 6 ) {
7675           //////////////////////// ---> tetrahedron
7676           for ( int iFace = 0; iFace < 6; iFace++ ) {
7677             const int *ind = hexa.GetFaceNodesIndices( iFace ); // indices of face nodes
7678             if (curNodes[ind[ 0 ]] == curNodes[ind[ 1 ]] &&
7679                 curNodes[ind[ 0 ]] == curNodes[ind[ 2 ]] &&
7680                 curNodes[ind[ 0 ]] == curNodes[ind[ 3 ]] ) {
7681               // one face turns into a point ...
7682               int iOppFace = hexa.GetOppFaceIndex( iFace );
7683               ind = hexa.GetFaceNodesIndices( iOppFace );
7684               int nbStick = 0;
7685               iUnique = 2; // reverse a tetrahedron bottom
7686               for ( iCur = 0; iCur < 4 && nbStick < 2; iCur++ ) {
7687                 if ( curNodes[ind[ iCur ]] == curNodes[ind[ iCur + 1 ]] )
7688                   nbStick++;
7689                 else if ( iUnique >= 0 )
7690                   uniqueNodes[ iUnique-- ] = curNodes[ind[ iCur ]];
7691               }
7692               if ( nbStick == 1 ) {
7693                 // ... and the opposite one - into a triangle.
7694                 // set a top node
7695                 ind = hexa.GetFaceNodesIndices( iFace );
7696                 uniqueNodes[ 3 ] = curNodes[ind[ 0 ]];
7697                 isOk = true;
7698               }
7699               break;
7700             }
7701           }
7702         }
7703         else if (nbUniqueNodes == 5 && nbRepl == 4 ) {
7704           //////////////////// HEXAHEDRON ---> 2 tetrahedrons
7705           for ( int iFace = 0; iFace < 6; iFace++ ) {
7706             const int *ind = hexa.GetFaceNodesIndices( iFace ); // indices of face nodes
7707             if (curNodes[ind[ 0 ]] == curNodes[ind[ 1 ]] &&
7708                 curNodes[ind[ 0 ]] == curNodes[ind[ 2 ]] &&
7709                 curNodes[ind[ 0 ]] == curNodes[ind[ 3 ]] ) {
7710               // one face turns into a point ...
7711               int iOppFace = hexa.GetOppFaceIndex( iFace );
7712               ind = hexa.GetFaceNodesIndices( iOppFace );
7713               int nbStick = 0;
7714               iUnique = 2;  // reverse a tetrahedron 1 bottom
7715               for ( iCur = 0; iCur < 4 && nbStick == 0; iCur++ ) {
7716                 if ( curNodes[ind[ iCur ]] == curNodes[ind[ iCur + 1 ]] )
7717                   nbStick++;
7718                 else if ( iUnique >= 0 )
7719                   uniqueNodes[ iUnique-- ] = curNodes[ind[ iCur ]];
7720               }
7721               if ( nbStick == 0 ) {
7722                 // ... and the opposite one is a quadrangle
7723                 // set a top node
7724                 const int* indTop = hexa.GetFaceNodesIndices( iFace );
7725                 uniqueNodes[ 3 ] = curNodes[indTop[ 0 ]];
7726                 nbUniqueNodes = 4;
7727                 // tetrahedron 2
7728                 SMDS_MeshElement* newElem =
7729                   aMesh->AddVolume(curNodes[ind[ 0 ]],
7730                                    curNodes[ind[ 3 ]],
7731                                    curNodes[ind[ 2 ]],
7732                                    curNodes[indTop[ 0 ]]);
7733                 myLastCreatedElems.Append(newElem);
7734                 if ( aShapeId )
7735                   aMesh->SetMeshElementOnShape( newElem, aShapeId );
7736                 isOk = true;
7737               }
7738               break;
7739             }
7740           }
7741         }
7742         else if ( nbUniqueNodes == 6 && nbRepl == 4 ) {
7743           ////////////////// HEXAHEDRON ---> 2 tetrahedrons or 1 prism
7744           // find indices of quad and tri faces
7745           int iQuadFace[ 6 ], iTriFace[ 6 ], nbQuad = 0, nbTri = 0, iFace;
7746           for ( iFace = 0; iFace < 6; iFace++ ) {
7747             const int *ind = hexa.GetFaceNodesIndices( iFace ); // indices of face nodes
7748             nodeSet.clear();
7749             for ( iCur = 0; iCur < 4; iCur++ )
7750               nodeSet.insert( curNodes[ind[ iCur ]] );
7751             nbUniqueNodes = nodeSet.size();
7752             if ( nbUniqueNodes == 3 )
7753               iTriFace[ nbTri++ ] = iFace;
7754             else if ( nbUniqueNodes == 4 )
7755               iQuadFace[ nbQuad++ ] = iFace;
7756           }
7757           if (nbQuad == 2 && nbTri == 4 &&
7758               hexa.GetOppFaceIndex( iQuadFace[ 0 ] ) == iQuadFace[ 1 ]) {
7759             // 2 opposite quadrangles stuck with a diagonal;
7760             // sample groups of merged indices: (0-4)(2-6)
7761             // --------------------------------------------> 2 tetrahedrons
7762             const int *ind1 = hexa.GetFaceNodesIndices( iQuadFace[ 0 ]); // indices of quad1 nodes
7763             const int *ind2 = hexa.GetFaceNodesIndices( iQuadFace[ 1 ]);
7764             int i0, i1d, i2, i3d, i0t, i2t; // d-daigonal, t-top
7765             if (curNodes[ind1[ 0 ]] == curNodes[ind2[ 0 ]] &&
7766                 curNodes[ind1[ 2 ]] == curNodes[ind2[ 2 ]]) {
7767               // stuck with 0-2 diagonal
7768               i0  = ind1[ 3 ];
7769               i1d = ind1[ 0 ];
7770               i2  = ind1[ 1 ];
7771               i3d = ind1[ 2 ];
7772               i0t = ind2[ 1 ];
7773               i2t = ind2[ 3 ];
7774             }
7775             else if (curNodes[ind1[ 1 ]] == curNodes[ind2[ 3 ]] &&
7776                      curNodes[ind1[ 3 ]] == curNodes[ind2[ 1 ]]) {
7777               // stuck with 1-3 diagonal
7778               i0  = ind1[ 0 ];
7779               i1d = ind1[ 1 ];
7780               i2  = ind1[ 2 ];
7781               i3d = ind1[ 3 ];
7782               i0t = ind2[ 0 ];
7783               i2t = ind2[ 1 ];
7784             }
7785             else {
7786               ASSERT(0);
7787             }
7788             // tetrahedron 1
7789             uniqueNodes[ 0 ] = curNodes [ i0 ];
7790             uniqueNodes[ 1 ] = curNodes [ i1d ];
7791             uniqueNodes[ 2 ] = curNodes [ i3d ];
7792             uniqueNodes[ 3 ] = curNodes [ i0t ];
7793             nbUniqueNodes = 4;
7794             // tetrahedron 2
7795             SMDS_MeshElement* newElem = aMesh->AddVolume(curNodes[ i1d ],
7796                                                          curNodes[ i2 ],
7797                                                          curNodes[ i3d ],
7798                                                          curNodes[ i2t ]);
7799             myLastCreatedElems.Append(newElem);
7800             if ( aShapeId )
7801               aMesh->SetMeshElementOnShape( newElem, aShapeId );
7802             isOk = true;
7803           }
7804           else if (( nbTri == 2 && nbQuad == 3 ) || // merged (0-4)(1-5)
7805                    ( nbTri == 4 && nbQuad == 2 )) { // merged (7-4)(1-5)
7806             // --------------------------------------------> prism
7807             // find 2 opposite triangles
7808             nbUniqueNodes = 6;
7809             for ( iFace = 0; iFace + 1 < nbTri; iFace++ ) {
7810               if ( hexa.GetOppFaceIndex( iTriFace[ iFace ] ) == iTriFace[ iFace + 1 ]) {
7811                 // find indices of kept and replaced nodes
7812                 // and fill unique nodes of 2 opposite triangles
7813                 const int *ind1 = hexa.GetFaceNodesIndices( iTriFace[ iFace ]);
7814                 const int *ind2 = hexa.GetFaceNodesIndices( iTriFace[ iFace + 1 ]);
7815                 const SMDS_MeshNode** hexanodes = hexa.GetNodes();
7816                 // fill unique nodes
7817                 iUnique = 0;
7818                 isOk = true;
7819                 for ( iCur = 0; iCur < 4 && isOk; iCur++ ) {
7820                   const SMDS_MeshNode* n     = curNodes[ind1[ iCur ]];
7821                   const SMDS_MeshNode* nInit = hexanodes[ind1[ iCur ]];
7822                   if ( n == nInit ) {
7823                     // iCur of a linked node of the opposite face (make normals co-directed):
7824                     int iCurOpp = ( iCur == 1 || iCur == 3 ) ? 4 - iCur : iCur;
7825                     // check that correspondent corners of triangles are linked
7826                     if ( !hexa.IsLinked( ind1[ iCur ], ind2[ iCurOpp ] ))
7827                       isOk = false;
7828                     else {
7829                       uniqueNodes[ iUnique ] = n;
7830                       uniqueNodes[ iUnique + 3 ] = curNodes[ind2[ iCurOpp ]];
7831                       iUnique++;
7832                     }
7833                   }
7834                 }
7835                 break;
7836               }
7837             }
7838           }
7839         } // if ( nbUniqueNodes == 6 && nbRepl == 4 )
7840         break;
7841       } // HEXAHEDRON
7842
7843       default:
7844         isOk = false;
7845       } // switch ( nbNodes )
7846
7847     } // if ( nbNodes != nbUniqueNodes ) // some nodes stick
7848
7849     if ( isOk ) {
7850       if (elem->IsPoly() && elem->GetType() == SMDSAbs_Volume) {
7851         // Change nodes of polyedre
7852         const SMDS_VtkVolume* aPolyedre =
7853           dynamic_cast<const SMDS_VtkVolume*>( elem );
7854         if (aPolyedre) {
7855           int nbFaces = aPolyedre->NbFaces();
7856
7857           vector<const SMDS_MeshNode *> poly_nodes;
7858           vector<int> quantities (nbFaces);
7859
7860           for (int iface = 1; iface <= nbFaces; iface++) {
7861             int inode, nbFaceNodes = aPolyedre->NbFaceNodes(iface);
7862             quantities[iface - 1] = nbFaceNodes;
7863
7864             for (inode = 1; inode <= nbFaceNodes; inode++) {
7865               const SMDS_MeshNode* curNode = aPolyedre->GetFaceNode(iface, inode);
7866
7867               TNodeNodeMap::iterator nnIt = nodeNodeMap.find( curNode );
7868               if (nnIt != nodeNodeMap.end()) { // curNode sticks
7869                 curNode = (*nnIt).second;
7870               }
7871               poly_nodes.push_back(curNode);
7872             }
7873           }
7874           aMesh->ChangePolyhedronNodes( elem, poly_nodes, quantities );
7875         }
7876       }
7877       else {
7878         //int elemId = elem->GetID();
7879         //MESSAGE("Change regular element or polygon " << elemId);
7880         SMDSAbs_ElementType etyp = elem->GetType();
7881         uniqueNodes.resize(nbUniqueNodes);
7882         SMDS_MeshElement* newElem = 0;
7883         if (elem->GetEntityType() == SMDSEntity_Polygon)
7884           newElem = this->AddElement(uniqueNodes, etyp, true);
7885         else
7886           newElem = this->AddElement(uniqueNodes, etyp, false);
7887         if (newElem)
7888           {
7889             myLastCreatedElems.Append(newElem);
7890             if ( aShapeId )
7891               aMesh->SetMeshElementOnShape( newElem, aShapeId );
7892           }
7893         aMesh->RemoveElement(elem);
7894       }
7895     }
7896     else {
7897       // Remove invalid regular element or invalid polygon
7898       //MESSAGE("Remove invalid " << elem->GetID());
7899       rmElemIds.push_back( elem->GetID() );
7900     }
7901
7902   } // loop on elements
7903
7904   // Remove bad elements, then equal nodes (order important)
7905
7906   Remove( rmElemIds, false );
7907   Remove( rmNodeIds, true );
7908
7909 }
7910
7911
7912 // ========================================================
7913 // class   : SortableElement
7914 // purpose : allow sorting elements basing on their nodes
7915 // ========================================================
7916 class SortableElement : public set <const SMDS_MeshElement*>
7917 {
7918 public:
7919
7920   SortableElement( const SMDS_MeshElement* theElem )
7921   {
7922     myElem = theElem;
7923     SMDS_ElemIteratorPtr nodeIt = theElem->nodesIterator();
7924     while ( nodeIt->more() )
7925       this->insert( nodeIt->next() );
7926   }
7927
7928   const SMDS_MeshElement* Get() const
7929   { return myElem; }
7930
7931   void Set(const SMDS_MeshElement* e) const
7932   { myElem = e; }
7933
7934
7935 private:
7936   mutable const SMDS_MeshElement* myElem;
7937 };
7938
7939 //=======================================================================
7940 //function : FindEqualElements
7941 //purpose  : Return list of group of elements built on the same nodes.
7942 //           Search among theElements or in the whole mesh if theElements is empty
7943 //=======================================================================
7944 void SMESH_MeshEditor::FindEqualElements(set<const SMDS_MeshElement*> & theElements,
7945                                          TListOfListOfElementsID &      theGroupsOfElementsID)
7946 {
7947   myLastCreatedElems.Clear();
7948   myLastCreatedNodes.Clear();
7949
7950   typedef set<const SMDS_MeshElement*> TElemsSet;
7951   typedef map< SortableElement, int > TMapOfNodeSet;
7952   typedef list<int> TGroupOfElems;
7953
7954   TElemsSet elems;
7955   if ( theElements.empty() )
7956   { // get all elements in the mesh
7957     SMDS_ElemIteratorPtr eIt = GetMeshDS()->elementsIterator();
7958     while ( eIt->more() )
7959       elems.insert( elems.end(), eIt->next());
7960   }
7961   else
7962     elems = theElements;
7963
7964   vector< TGroupOfElems > arrayOfGroups;
7965   TGroupOfElems groupOfElems;
7966   TMapOfNodeSet mapOfNodeSet;
7967
7968   TElemsSet::iterator elemIt = elems.begin();
7969   for ( int i = 0, j=0; elemIt != elems.end(); ++elemIt, ++j ) {
7970     const SMDS_MeshElement* curElem = *elemIt;
7971     SortableElement SE(curElem);
7972     int ind = -1;
7973     // check uniqueness
7974     pair< TMapOfNodeSet::iterator, bool> pp = mapOfNodeSet.insert(make_pair(SE, i));
7975     if( !(pp.second) ) {
7976       TMapOfNodeSet::iterator& itSE = pp.first;
7977       ind = (*itSE).second;
7978       arrayOfGroups[ind].push_back(curElem->GetID());
7979     }
7980     else {
7981       groupOfElems.clear();
7982       groupOfElems.push_back(curElem->GetID());
7983       arrayOfGroups.push_back(groupOfElems);
7984       i++;
7985     }
7986   }
7987
7988   vector< TGroupOfElems >::iterator groupIt = arrayOfGroups.begin();
7989   for ( ; groupIt != arrayOfGroups.end(); ++groupIt ) {
7990     groupOfElems = *groupIt;
7991     if ( groupOfElems.size() > 1 ) {
7992       groupOfElems.sort();
7993       theGroupsOfElementsID.push_back(groupOfElems);
7994     }
7995   }
7996 }
7997
7998 //=======================================================================
7999 //function : MergeElements
8000 //purpose  : In each given group, substitute all elements by the first one.
8001 //=======================================================================
8002
8003 void SMESH_MeshEditor::MergeElements(TListOfListOfElementsID & theGroupsOfElementsID)
8004 {
8005   myLastCreatedElems.Clear();
8006   myLastCreatedNodes.Clear();
8007
8008   typedef list<int> TListOfIDs;
8009   TListOfIDs rmElemIds; // IDs of elems to remove
8010
8011   SMESHDS_Mesh* aMesh = GetMeshDS();
8012
8013   TListOfListOfElementsID::iterator groupsIt = theGroupsOfElementsID.begin();
8014   while ( groupsIt != theGroupsOfElementsID.end() ) {
8015     TListOfIDs& aGroupOfElemID = *groupsIt;
8016     aGroupOfElemID.sort();
8017     int elemIDToKeep = aGroupOfElemID.front();
8018     const SMDS_MeshElement* elemToKeep = aMesh->FindElement(elemIDToKeep);
8019     aGroupOfElemID.pop_front();
8020     TListOfIDs::iterator idIt = aGroupOfElemID.begin();
8021     while ( idIt != aGroupOfElemID.end() ) {
8022       int elemIDToRemove = *idIt;
8023       const SMDS_MeshElement* elemToRemove = aMesh->FindElement(elemIDToRemove);
8024       // add the kept element in groups of removed one (PAL15188)
8025       AddToSameGroups( elemToKeep, elemToRemove, aMesh );
8026       rmElemIds.push_back( elemIDToRemove );
8027       ++idIt;
8028     }
8029     ++groupsIt;
8030   }
8031
8032   Remove( rmElemIds, false );
8033 }
8034
8035 //=======================================================================
8036 //function : MergeEqualElements
8037 //purpose  : Remove all but one of elements built on the same nodes.
8038 //=======================================================================
8039
8040 void SMESH_MeshEditor::MergeEqualElements()
8041 {
8042   set<const SMDS_MeshElement*> aMeshElements; /* empty input -
8043                                                  to merge equal elements in the whole mesh */
8044   TListOfListOfElementsID aGroupsOfElementsID;
8045   FindEqualElements(aMeshElements, aGroupsOfElementsID);
8046   MergeElements(aGroupsOfElementsID);
8047 }
8048
8049 //=======================================================================
8050 //function : FindFaceInSet
8051 //purpose  : Return a face having linked nodes n1 and n2 and which is
8052 //           - not in avoidSet,
8053 //           - in elemSet provided that !elemSet.empty()
8054 //           i1 and i2 optionally returns indices of n1 and n2
8055 //=======================================================================
8056
8057 const SMDS_MeshElement*
8058 SMESH_MeshEditor::FindFaceInSet(const SMDS_MeshNode*    n1,
8059                                 const SMDS_MeshNode*    n2,
8060                                 const TIDSortedElemSet& elemSet,
8061                                 const TIDSortedElemSet& avoidSet,
8062                                 int*                    n1ind,
8063                                 int*                    n2ind)
8064
8065 {
8066   int i1, i2;
8067   const SMDS_MeshElement* face = 0;
8068
8069   SMDS_ElemIteratorPtr invElemIt = n1->GetInverseElementIterator(SMDSAbs_Face);
8070   //MESSAGE("n1->GetInverseElementIterator(SMDSAbs_Face) " << invElemIt);
8071   while ( invElemIt->more() && !face ) // loop on inverse faces of n1
8072   {
8073     //MESSAGE("in while ( invElemIt->more() && !face )");
8074     const SMDS_MeshElement* elem = invElemIt->next();
8075     if (avoidSet.count( elem ))
8076       continue;
8077     if ( !elemSet.empty() && !elemSet.count( elem ))
8078       continue;
8079     // index of n1
8080     i1 = elem->GetNodeIndex( n1 );
8081     // find a n2 linked to n1
8082     int nbN = elem->IsQuadratic() ? elem->NbNodes()/2 : elem->NbNodes();
8083     for ( int di = -1; di < 2 && !face; di += 2 )
8084     {
8085       i2 = (i1+di+nbN) % nbN;
8086       if ( elem->GetNode( i2 ) == n2 )
8087         face = elem;
8088     }
8089     if ( !face && elem->IsQuadratic())
8090     {
8091       // analysis for quadratic elements using all nodes
8092       const SMDS_VtkFace* F =
8093         dynamic_cast<const SMDS_VtkFace*>(elem);
8094       if (!F) throw SALOME_Exception(LOCALIZED("not an SMDS_VtkFace"));
8095       // use special nodes iterator
8096       SMDS_ElemIteratorPtr anIter = F->interlacedNodesElemIterator();
8097       const SMDS_MeshNode* prevN = cast2Node( anIter->next() );
8098       for ( i1 = -1, i2 = 0; anIter->more() && !face; i1++, i2++ )
8099       {
8100         const SMDS_MeshNode* n = cast2Node( anIter->next() );
8101         if ( n1 == prevN && n2 == n )
8102         {
8103           face = elem;
8104         }
8105         else if ( n2 == prevN && n1 == n )
8106         {
8107           face = elem; swap( i1, i2 );
8108         }
8109         prevN = n;
8110       }
8111     }
8112   }
8113   if ( n1ind ) *n1ind = i1;
8114   if ( n2ind ) *n2ind = i2;
8115   return face;
8116 }
8117
8118 //=======================================================================
8119 //function : findAdjacentFace
8120 //purpose  :
8121 //=======================================================================
8122
8123 static const SMDS_MeshElement* findAdjacentFace(const SMDS_MeshNode* n1,
8124                                                 const SMDS_MeshNode* n2,
8125                                                 const SMDS_MeshElement* elem)
8126 {
8127   TIDSortedElemSet elemSet, avoidSet;
8128   if ( elem )
8129     avoidSet.insert ( elem );
8130   return SMESH_MeshEditor::FindFaceInSet( n1, n2, elemSet, avoidSet );
8131 }
8132
8133 //=======================================================================
8134 //function : FindFreeBorder
8135 //purpose  :
8136 //=======================================================================
8137
8138 #define ControlFreeBorder SMESH::Controls::FreeEdges::IsFreeEdge
8139
8140 bool SMESH_MeshEditor::FindFreeBorder (const SMDS_MeshNode*             theFirstNode,
8141                                        const SMDS_MeshNode*             theSecondNode,
8142                                        const SMDS_MeshNode*             theLastNode,
8143                                        list< const SMDS_MeshNode* > &   theNodes,
8144                                        list< const SMDS_MeshElement* >& theFaces)
8145 {
8146   if ( !theFirstNode || !theSecondNode )
8147     return false;
8148   // find border face between theFirstNode and theSecondNode
8149   const SMDS_MeshElement* curElem = findAdjacentFace( theFirstNode, theSecondNode, 0 );
8150   if ( !curElem )
8151     return false;
8152
8153   theFaces.push_back( curElem );
8154   theNodes.push_back( theFirstNode );
8155   theNodes.push_back( theSecondNode );
8156
8157   //vector<const SMDS_MeshNode*> nodes;
8158   const SMDS_MeshNode *nIgnore = theFirstNode, *nStart = theSecondNode;
8159   TIDSortedElemSet foundElems;
8160   bool needTheLast = ( theLastNode != 0 );
8161
8162   while ( nStart != theLastNode ) {
8163     if ( nStart == theFirstNode )
8164       return !needTheLast;
8165
8166     // find all free border faces sharing form nStart
8167
8168     list< const SMDS_MeshElement* > curElemList;
8169     list< const SMDS_MeshNode* > nStartList;
8170     SMDS_ElemIteratorPtr invElemIt = nStart->GetInverseElementIterator(SMDSAbs_Face);
8171     while ( invElemIt->more() ) {
8172       const SMDS_MeshElement* e = invElemIt->next();
8173       if ( e == curElem || foundElems.insert( e ).second ) {
8174         // get nodes
8175         int iNode = 0, nbNodes = e->NbNodes();
8176         //const SMDS_MeshNode* nodes[nbNodes+1];
8177         vector<const SMDS_MeshNode*> nodes(nbNodes+1);
8178
8179         if(e->IsQuadratic()) {
8180           const SMDS_VtkFace* F =
8181             dynamic_cast<const SMDS_VtkFace*>(e);
8182           if (!F) throw SALOME_Exception(LOCALIZED("not an SMDS_VtkFace"));
8183           // use special nodes iterator
8184           SMDS_ElemIteratorPtr anIter = F->interlacedNodesElemIterator();
8185           while( anIter->more() ) {
8186             nodes[ iNode++ ] = cast2Node(anIter->next());
8187           }
8188         }
8189         else {
8190           SMDS_ElemIteratorPtr nIt = e->nodesIterator();
8191           while ( nIt->more() )
8192             nodes[ iNode++ ] = static_cast<const SMDS_MeshNode*>( nIt->next() );
8193         }
8194         nodes[ iNode ] = nodes[ 0 ];
8195         // check 2 links
8196         for ( iNode = 0; iNode < nbNodes; iNode++ )
8197           if (((nodes[ iNode ] == nStart && nodes[ iNode + 1] != nIgnore ) ||
8198                (nodes[ iNode + 1] == nStart && nodes[ iNode ] != nIgnore )) &&
8199               ControlFreeBorder( &nodes[ iNode ], e->GetID() ))
8200           {
8201             nStartList.push_back( nodes[ iNode + ( nodes[ iNode ] == nStart ? 1 : 0 )]);
8202             curElemList.push_back( e );
8203           }
8204       }
8205     }
8206     // analyse the found
8207
8208     int nbNewBorders = curElemList.size();
8209     if ( nbNewBorders == 0 ) {
8210       // no free border furthermore
8211       return !needTheLast;
8212     }
8213     else if ( nbNewBorders == 1 ) {
8214       // one more element found
8215       nIgnore = nStart;
8216       nStart = nStartList.front();
8217       curElem = curElemList.front();
8218       theFaces.push_back( curElem );
8219       theNodes.push_back( nStart );
8220     }
8221     else {
8222       // several continuations found
8223       list< const SMDS_MeshElement* >::iterator curElemIt;
8224       list< const SMDS_MeshNode* >::iterator nStartIt;
8225       // check if one of them reached the last node
8226       if ( needTheLast ) {
8227         for (curElemIt = curElemList.begin(), nStartIt = nStartList.begin();
8228              curElemIt!= curElemList.end();
8229              curElemIt++, nStartIt++ )
8230           if ( *nStartIt == theLastNode ) {
8231             theFaces.push_back( *curElemIt );
8232             theNodes.push_back( *nStartIt );
8233             return true;
8234           }
8235       }
8236       // find the best free border by the continuations
8237       list<const SMDS_MeshNode*>    contNodes[ 2 ], *cNL;
8238       list<const SMDS_MeshElement*> contFaces[ 2 ], *cFL;
8239       for (curElemIt = curElemList.begin(), nStartIt = nStartList.begin();
8240            curElemIt!= curElemList.end();
8241            curElemIt++, nStartIt++ )
8242       {
8243         cNL = & contNodes[ contNodes[0].empty() ? 0 : 1 ];
8244         cFL = & contFaces[ contFaces[0].empty() ? 0 : 1 ];
8245         // find one more free border
8246         if ( ! FindFreeBorder( nStart, *nStartIt, theLastNode, *cNL, *cFL )) {
8247           cNL->clear();
8248           cFL->clear();
8249         }
8250         else if ( !contNodes[0].empty() && !contNodes[1].empty() ) {
8251           // choice: clear a worse one
8252           int iLongest = ( contNodes[0].size() < contNodes[1].size() ? 1 : 0 );
8253           int iWorse = ( needTheLast ? 1 - iLongest : iLongest );
8254           contNodes[ iWorse ].clear();
8255           contFaces[ iWorse ].clear();
8256         }
8257       }
8258       if ( contNodes[0].empty() && contNodes[1].empty() )
8259         return false;
8260
8261       // append the best free border
8262       cNL = & contNodes[ contNodes[0].empty() ? 1 : 0 ];
8263       cFL = & contFaces[ contFaces[0].empty() ? 1 : 0 ];
8264       theNodes.pop_back(); // remove nIgnore
8265       theNodes.pop_back(); // remove nStart
8266       theFaces.pop_back(); // remove curElem
8267       list< const SMDS_MeshNode* >::iterator nIt = cNL->begin();
8268       list< const SMDS_MeshElement* >::iterator fIt = cFL->begin();
8269       for ( ; nIt != cNL->end(); nIt++ ) theNodes.push_back( *nIt );
8270       for ( ; fIt != cFL->end(); fIt++ ) theFaces.push_back( *fIt );
8271       return true;
8272
8273     } // several continuations found
8274   } // while ( nStart != theLastNode )
8275
8276   return true;
8277 }
8278
8279 //=======================================================================
8280 //function : CheckFreeBorderNodes
8281 //purpose  : Return true if the tree nodes are on a free border
8282 //=======================================================================
8283
8284 bool SMESH_MeshEditor::CheckFreeBorderNodes(const SMDS_MeshNode* theNode1,
8285                                             const SMDS_MeshNode* theNode2,
8286                                             const SMDS_MeshNode* theNode3)
8287 {
8288   list< const SMDS_MeshNode* > nodes;
8289   list< const SMDS_MeshElement* > faces;
8290   return FindFreeBorder( theNode1, theNode2, theNode3, nodes, faces);
8291 }
8292
8293 //=======================================================================
8294 //function : SewFreeBorder
8295 //purpose  :
8296 //=======================================================================
8297
8298 SMESH_MeshEditor::Sew_Error
8299 SMESH_MeshEditor::SewFreeBorder (const SMDS_MeshNode* theBordFirstNode,
8300                                  const SMDS_MeshNode* theBordSecondNode,
8301                                  const SMDS_MeshNode* theBordLastNode,
8302                                  const SMDS_MeshNode* theSideFirstNode,
8303                                  const SMDS_MeshNode* theSideSecondNode,
8304                                  const SMDS_MeshNode* theSideThirdNode,
8305                                  const bool           theSideIsFreeBorder,
8306                                  const bool           toCreatePolygons,
8307                                  const bool           toCreatePolyedrs)
8308 {
8309   myLastCreatedElems.Clear();
8310   myLastCreatedNodes.Clear();
8311
8312   MESSAGE("::SewFreeBorder()");
8313   Sew_Error aResult = SEW_OK;
8314
8315   // ====================================
8316   //    find side nodes and elements
8317   // ====================================
8318
8319   list< const SMDS_MeshNode* > nSide[ 2 ];
8320   list< const SMDS_MeshElement* > eSide[ 2 ];
8321   list< const SMDS_MeshNode* >::iterator nIt[ 2 ];
8322   list< const SMDS_MeshElement* >::iterator eIt[ 2 ];
8323
8324   // Free border 1
8325   // --------------
8326   if (!FindFreeBorder(theBordFirstNode,theBordSecondNode,theBordLastNode,
8327                       nSide[0], eSide[0])) {
8328     MESSAGE(" Free Border 1 not found " );
8329     aResult = SEW_BORDER1_NOT_FOUND;
8330   }
8331   if (theSideIsFreeBorder) {
8332     // Free border 2
8333     // --------------
8334     if (!FindFreeBorder(theSideFirstNode, theSideSecondNode, theSideThirdNode,
8335                         nSide[1], eSide[1])) {
8336       MESSAGE(" Free Border 2 not found " );
8337       aResult = ( aResult != SEW_OK ? SEW_BOTH_BORDERS_NOT_FOUND : SEW_BORDER2_NOT_FOUND );
8338     }
8339   }
8340   if ( aResult != SEW_OK )
8341     return aResult;
8342
8343   if (!theSideIsFreeBorder) {
8344     // Side 2
8345     // --------------
8346
8347     // -------------------------------------------------------------------------
8348     // Algo:
8349     // 1. If nodes to merge are not coincident, move nodes of the free border
8350     //    from the coord sys defined by the direction from the first to last
8351     //    nodes of the border to the correspondent sys of the side 2
8352     // 2. On the side 2, find the links most co-directed with the correspondent
8353     //    links of the free border
8354     // -------------------------------------------------------------------------
8355
8356     // 1. Since sewing may break if there are volumes to split on the side 2,
8357     //    we wont move nodes but just compute new coordinates for them
8358     typedef map<const SMDS_MeshNode*, gp_XYZ> TNodeXYZMap;
8359     TNodeXYZMap nBordXYZ;
8360     list< const SMDS_MeshNode* >& bordNodes = nSide[ 0 ];
8361     list< const SMDS_MeshNode* >::iterator nBordIt;
8362
8363     gp_XYZ Pb1( theBordFirstNode->X(), theBordFirstNode->Y(), theBordFirstNode->Z() );
8364     gp_XYZ Pb2( theBordLastNode->X(), theBordLastNode->Y(), theBordLastNode->Z() );
8365     gp_XYZ Ps1( theSideFirstNode->X(), theSideFirstNode->Y(), theSideFirstNode->Z() );
8366     gp_XYZ Ps2( theSideSecondNode->X(), theSideSecondNode->Y(), theSideSecondNode->Z() );
8367     double tol2 = 1.e-8;
8368     gp_Vec Vbs1( Pb1 - Ps1 ),Vbs2( Pb2 - Ps2 );
8369     if ( Vbs1.SquareMagnitude() > tol2 || Vbs2.SquareMagnitude() > tol2 ) {
8370       // Need node movement.
8371
8372       // find X and Z axes to create trsf
8373       gp_Vec Zb( Pb1 - Pb2 ), Zs( Ps1 - Ps2 );
8374       gp_Vec X = Zs ^ Zb;
8375       if ( X.SquareMagnitude() <= gp::Resolution() * gp::Resolution() )
8376         // Zb || Zs
8377         X = gp_Ax2( gp::Origin(), Zb ).XDirection();
8378
8379       // coord systems
8380       gp_Ax3 toBordAx( Pb1, Zb, X );
8381       gp_Ax3 fromSideAx( Ps1, Zs, X );
8382       gp_Ax3 toGlobalAx( gp::Origin(), gp::DZ(), gp::DX() );
8383       // set trsf
8384       gp_Trsf toBordSys, fromSide2Sys;
8385       toBordSys.SetTransformation( toBordAx );
8386       fromSide2Sys.SetTransformation( fromSideAx, toGlobalAx );
8387       fromSide2Sys.SetScaleFactor( Zs.Magnitude() / Zb.Magnitude() );
8388
8389       // move
8390       for ( nBordIt = bordNodes.begin(); nBordIt != bordNodes.end(); nBordIt++ ) {
8391         const SMDS_MeshNode* n = *nBordIt;
8392         gp_XYZ xyz( n->X(),n->Y(),n->Z() );
8393         toBordSys.Transforms( xyz );
8394         fromSide2Sys.Transforms( xyz );
8395         nBordXYZ.insert( TNodeXYZMap::value_type( n, xyz ));
8396       }
8397     }
8398     else {
8399       // just insert nodes XYZ in the nBordXYZ map
8400       for ( nBordIt = bordNodes.begin(); nBordIt != bordNodes.end(); nBordIt++ ) {
8401         const SMDS_MeshNode* n = *nBordIt;
8402         nBordXYZ.insert( TNodeXYZMap::value_type( n, gp_XYZ( n->X(),n->Y(),n->Z() )));
8403       }
8404     }
8405
8406     // 2. On the side 2, find the links most co-directed with the correspondent
8407     //    links of the free border
8408
8409     list< const SMDS_MeshElement* >& sideElems = eSide[ 1 ];
8410     list< const SMDS_MeshNode* >& sideNodes = nSide[ 1 ];
8411     sideNodes.push_back( theSideFirstNode );
8412
8413     bool hasVolumes = false;
8414     LinkID_Gen aLinkID_Gen( GetMeshDS() );
8415     set<long> foundSideLinkIDs, checkedLinkIDs;
8416     SMDS_VolumeTool volume;
8417     //const SMDS_MeshNode* faceNodes[ 4 ];
8418
8419     const SMDS_MeshNode*    sideNode;
8420     const SMDS_MeshElement* sideElem;
8421     const SMDS_MeshNode* prevSideNode = theSideFirstNode;
8422     const SMDS_MeshNode* prevBordNode = theBordFirstNode;
8423     nBordIt = bordNodes.begin();
8424     nBordIt++;
8425     // border node position and border link direction to compare with
8426     gp_XYZ bordPos = nBordXYZ[ *nBordIt ];
8427     gp_XYZ bordDir = bordPos - nBordXYZ[ prevBordNode ];
8428     // choose next side node by link direction or by closeness to
8429     // the current border node:
8430     bool searchByDir = ( *nBordIt != theBordLastNode );
8431     do {
8432       // find the next node on the Side 2
8433       sideNode = 0;
8434       double maxDot = -DBL_MAX, minDist = DBL_MAX;
8435       long linkID;
8436       checkedLinkIDs.clear();
8437       gp_XYZ prevXYZ( prevSideNode->X(), prevSideNode->Y(), prevSideNode->Z() );
8438
8439       // loop on inverse elements of current node (prevSideNode) on the Side 2
8440       SMDS_ElemIteratorPtr invElemIt = prevSideNode->GetInverseElementIterator();
8441       while ( invElemIt->more() )
8442       {
8443         const SMDS_MeshElement* elem = invElemIt->next();
8444         // prepare data for a loop on links coming to prevSideNode, of a face or a volume
8445         int iPrevNode, iNode = 0, nbNodes = elem->NbNodes();
8446         vector< const SMDS_MeshNode* > faceNodes( nbNodes, (const SMDS_MeshNode*)0 );
8447         bool isVolume = volume.Set( elem );
8448         const SMDS_MeshNode** nodes = isVolume ? volume.GetNodes() : & faceNodes[0];
8449         if ( isVolume ) // --volume
8450           hasVolumes = true;
8451         else if ( elem->GetType()==SMDSAbs_Face ) { // --face
8452           // retrieve all face nodes and find iPrevNode - an index of the prevSideNode
8453           if(elem->IsQuadratic()) {
8454             const SMDS_VtkFace* F =
8455               dynamic_cast<const SMDS_VtkFace*>(elem);
8456             if (!F) throw SALOME_Exception(LOCALIZED("not an SMDS_VtkFace"));
8457             // use special nodes iterator
8458             SMDS_ElemIteratorPtr anIter = F->interlacedNodesElemIterator();
8459             while( anIter->more() ) {
8460               nodes[ iNode ] = cast2Node(anIter->next());
8461               if ( nodes[ iNode++ ] == prevSideNode )
8462                 iPrevNode = iNode - 1;
8463             }
8464           }
8465           else {
8466             SMDS_ElemIteratorPtr nIt = elem->nodesIterator();
8467             while ( nIt->more() ) {
8468               nodes[ iNode ] = cast2Node( nIt->next() );
8469               if ( nodes[ iNode++ ] == prevSideNode )
8470                 iPrevNode = iNode - 1;
8471             }
8472           }
8473           // there are 2 links to check
8474           nbNodes = 2;
8475         }
8476         else // --edge
8477           continue;
8478         // loop on links, to be precise, on the second node of links
8479         for ( iNode = 0; iNode < nbNodes; iNode++ ) {
8480           const SMDS_MeshNode* n = nodes[ iNode ];
8481           if ( isVolume ) {
8482             if ( !volume.IsLinked( n, prevSideNode ))
8483               continue;
8484           }
8485           else {
8486             if ( iNode ) // a node before prevSideNode
8487               n = nodes[ iPrevNode == 0 ? elem->NbNodes() - 1 : iPrevNode - 1 ];
8488             else         // a node after prevSideNode
8489               n = nodes[ iPrevNode + 1 == elem->NbNodes() ? 0 : iPrevNode + 1 ];
8490           }
8491           // check if this link was already used
8492           long iLink = aLinkID_Gen.GetLinkID( prevSideNode, n );
8493           bool isJustChecked = !checkedLinkIDs.insert( iLink ).second;
8494           if (!isJustChecked &&
8495               foundSideLinkIDs.find( iLink ) == foundSideLinkIDs.end() )
8496           {
8497             // test a link geometrically
8498             gp_XYZ nextXYZ ( n->X(), n->Y(), n->Z() );
8499             bool linkIsBetter = false;
8500             double dot = 0.0, dist = 0.0;
8501             if ( searchByDir ) { // choose most co-directed link
8502               dot = bordDir * ( nextXYZ - prevXYZ ).Normalized();
8503               linkIsBetter = ( dot > maxDot );
8504             }
8505             else { // choose link with the node closest to bordPos
8506               dist = ( nextXYZ - bordPos ).SquareModulus();
8507               linkIsBetter = ( dist < minDist );
8508             }
8509             if ( linkIsBetter ) {
8510               maxDot = dot;
8511               minDist = dist;
8512               linkID = iLink;
8513               sideNode = n;
8514               sideElem = elem;
8515             }
8516           }
8517         }
8518       } // loop on inverse elements of prevSideNode
8519
8520       if ( !sideNode ) {
8521         MESSAGE(" Cant find path by links of the Side 2 ");
8522         return SEW_BAD_SIDE_NODES;
8523       }
8524       sideNodes.push_back( sideNode );
8525       sideElems.push_back( sideElem );
8526       foundSideLinkIDs.insert ( linkID );
8527       prevSideNode = sideNode;
8528
8529       if ( *nBordIt == theBordLastNode )
8530         searchByDir = false;
8531       else {
8532         // find the next border link to compare with
8533         gp_XYZ sidePos( sideNode->X(), sideNode->Y(), sideNode->Z() );
8534         searchByDir = ( bordDir * ( sidePos - bordPos ) <= 0 );
8535         // move to next border node if sideNode is before forward border node (bordPos)
8536         while ( *nBordIt != theBordLastNode && !searchByDir ) {
8537           prevBordNode = *nBordIt;
8538           nBordIt++;
8539           bordPos = nBordXYZ[ *nBordIt ];
8540           bordDir = bordPos - nBordXYZ[ prevBordNode ];
8541           searchByDir = ( bordDir * ( sidePos - bordPos ) <= 0 );
8542         }
8543       }
8544     }
8545     while ( sideNode != theSideSecondNode );
8546
8547     if ( hasVolumes && sideNodes.size () != bordNodes.size() && !toCreatePolyedrs) {
8548       MESSAGE("VOLUME SPLITTING IS FORBIDDEN");
8549       return SEW_VOLUMES_TO_SPLIT; // volume splitting is forbidden
8550     }
8551   } // end nodes search on the side 2
8552
8553   // ============================
8554   // sew the border to the side 2
8555   // ============================
8556
8557   int nbNodes[]  = { nSide[0].size(), nSide[1].size() };
8558   int maxNbNodes = Max( nbNodes[0], nbNodes[1] );
8559
8560   TListOfListOfNodes nodeGroupsToMerge;
8561   if ( nbNodes[0] == nbNodes[1] ||
8562        ( theSideIsFreeBorder && !theSideThirdNode)) {
8563
8564     // all nodes are to be merged
8565
8566     for (nIt[0] = nSide[0].begin(), nIt[1] = nSide[1].begin();
8567          nIt[0] != nSide[0].end() && nIt[1] != nSide[1].end();
8568          nIt[0]++, nIt[1]++ )
8569     {
8570       nodeGroupsToMerge.push_back( list<const SMDS_MeshNode*>() );
8571       nodeGroupsToMerge.back().push_back( *nIt[1] ); // to keep
8572       nodeGroupsToMerge.back().push_back( *nIt[0] ); // to remove
8573     }
8574   }
8575   else {
8576
8577     // insert new nodes into the border and the side to get equal nb of segments
8578
8579     // get normalized parameters of nodes on the borders
8580     //double param[ 2 ][ maxNbNodes ];
8581     double* param[ 2 ];
8582     param[0] = new double [ maxNbNodes ];
8583     param[1] = new double [ maxNbNodes ];
8584     int iNode, iBord;
8585     for ( iBord = 0; iBord < 2; iBord++ ) { // loop on 2 borders
8586       list< const SMDS_MeshNode* >& nodes = nSide[ iBord ];
8587       list< const SMDS_MeshNode* >::iterator nIt = nodes.begin();
8588       const SMDS_MeshNode* nPrev = *nIt;
8589       double bordLength = 0;
8590       for ( iNode = 0; nIt != nodes.end(); nIt++, iNode++ ) { // loop on border nodes
8591         const SMDS_MeshNode* nCur = *nIt;
8592         gp_XYZ segment (nCur->X() - nPrev->X(),
8593                         nCur->Y() - nPrev->Y(),
8594                         nCur->Z() - nPrev->Z());
8595         double segmentLen = segment.Modulus();
8596         bordLength += segmentLen;
8597         param[ iBord ][ iNode ] = bordLength;
8598         nPrev = nCur;
8599       }
8600       // normalize within [0,1]
8601       for ( iNode = 0; iNode < nbNodes[ iBord ]; iNode++ ) {
8602         param[ iBord ][ iNode ] /= bordLength;
8603       }
8604     }
8605
8606     // loop on border segments
8607     const SMDS_MeshNode *nPrev[ 2 ] = { 0, 0 };
8608     int i[ 2 ] = { 0, 0 };
8609     nIt[0] = nSide[0].begin(); eIt[0] = eSide[0].begin();
8610     nIt[1] = nSide[1].begin(); eIt[1] = eSide[1].begin();
8611
8612     TElemOfNodeListMap insertMap;
8613     TElemOfNodeListMap::iterator insertMapIt;
8614     // insertMap is
8615     // key:   elem to insert nodes into
8616     // value: 2 nodes to insert between + nodes to be inserted
8617     do {
8618       bool next[ 2 ] = { false, false };
8619
8620       // find min adjacent segment length after sewing
8621       double nextParam = 10., prevParam = 0;
8622       for ( iBord = 0; iBord < 2; iBord++ ) { // loop on 2 borders
8623         if ( i[ iBord ] + 1 < nbNodes[ iBord ])
8624           nextParam = Min( nextParam, param[iBord][ i[iBord] + 1 ]);
8625         if ( i[ iBord ] > 0 )
8626           prevParam = Max( prevParam, param[iBord][ i[iBord] - 1 ]);
8627       }
8628       double minParam = Min( param[ 0 ][ i[0] ], param[ 1 ][ i[1] ]);
8629       double maxParam = Max( param[ 0 ][ i[0] ], param[ 1 ][ i[1] ]);
8630       double minSegLen = Min( nextParam - minParam, maxParam - prevParam );
8631
8632       // choose to insert or to merge nodes
8633       double du = param[ 1 ][ i[1] ] - param[ 0 ][ i[0] ];
8634       if ( Abs( du ) <= minSegLen * 0.2 ) {
8635         // merge
8636         // ------
8637         nodeGroupsToMerge.push_back( list<const SMDS_MeshNode*>() );
8638         const SMDS_MeshNode* n0 = *nIt[0];
8639         const SMDS_MeshNode* n1 = *nIt[1];
8640         nodeGroupsToMerge.back().push_back( n1 );
8641         nodeGroupsToMerge.back().push_back( n0 );
8642         // position of node of the border changes due to merge
8643         param[ 0 ][ i[0] ] += du;
8644         // move n1 for the sake of elem shape evaluation during insertion.
8645         // n1 will be removed by MergeNodes() anyway
8646         const_cast<SMDS_MeshNode*>( n0 )->setXYZ( n1->X(), n1->Y(), n1->Z() );
8647         next[0] = next[1] = true;
8648       }
8649       else {
8650         // insert
8651         // ------
8652         int intoBord = ( du < 0 ) ? 0 : 1;
8653         const SMDS_MeshElement* elem = *eIt[ intoBord ];
8654         const SMDS_MeshNode*    n1   = nPrev[ intoBord ];
8655         const SMDS_MeshNode*    n2   = *nIt[ intoBord ];
8656         const SMDS_MeshNode*    nIns = *nIt[ 1 - intoBord ];
8657         if ( intoBord == 1 ) {
8658           // move node of the border to be on a link of elem of the side
8659           gp_XYZ p1 (n1->X(), n1->Y(), n1->Z());
8660           gp_XYZ p2 (n2->X(), n2->Y(), n2->Z());
8661           double ratio = du / ( param[ 1 ][ i[1] ] - param[ 1 ][ i[1]-1 ]);
8662           gp_XYZ p = p2 * ( 1 - ratio ) + p1 * ratio;
8663           GetMeshDS()->MoveNode( nIns, p.X(), p.Y(), p.Z() );
8664         }
8665         insertMapIt = insertMap.find( elem );
8666         bool notFound = ( insertMapIt == insertMap.end() );
8667         bool otherLink = ( !notFound && (*insertMapIt).second.front() != n1 );
8668         if ( otherLink ) {
8669           // insert into another link of the same element:
8670           // 1. perform insertion into the other link of the elem
8671           list<const SMDS_MeshNode*> & nodeList = (*insertMapIt).second;
8672           const SMDS_MeshNode* n12 = nodeList.front(); nodeList.pop_front();
8673           const SMDS_MeshNode* n22 = nodeList.front(); nodeList.pop_front();
8674           InsertNodesIntoLink( elem, n12, n22, nodeList, toCreatePolygons );
8675           // 2. perform insertion into the link of adjacent faces
8676           while (true) {
8677             const SMDS_MeshElement* adjElem = findAdjacentFace( n12, n22, elem );
8678             if ( adjElem )
8679               InsertNodesIntoLink( adjElem, n12, n22, nodeList, toCreatePolygons );
8680             else
8681               break;
8682           }
8683           if (toCreatePolyedrs) {
8684             // perform insertion into the links of adjacent volumes
8685             UpdateVolumes(n12, n22, nodeList);
8686           }
8687           // 3. find an element appeared on n1 and n2 after the insertion
8688           insertMap.erase( elem );
8689           elem = findAdjacentFace( n1, n2, 0 );
8690         }
8691         if ( notFound || otherLink ) {
8692           // add element and nodes of the side into the insertMap
8693           insertMapIt = insertMap.insert
8694             ( TElemOfNodeListMap::value_type( elem, list<const SMDS_MeshNode*>() )).first;
8695           (*insertMapIt).second.push_back( n1 );
8696           (*insertMapIt).second.push_back( n2 );
8697         }
8698         // add node to be inserted into elem
8699         (*insertMapIt).second.push_back( nIns );
8700         next[ 1 - intoBord ] = true;
8701       }
8702
8703       // go to the next segment
8704       for ( iBord = 0; iBord < 2; iBord++ ) { // loop on 2 borders
8705         if ( next[ iBord ] ) {
8706           if ( i[ iBord ] != 0 && eIt[ iBord ] != eSide[ iBord ].end())
8707             eIt[ iBord ]++;
8708           nPrev[ iBord ] = *nIt[ iBord ];
8709           nIt[ iBord ]++; i[ iBord ]++;
8710         }
8711       }
8712     }
8713     while ( nIt[0] != nSide[0].end() && nIt[1] != nSide[1].end());
8714
8715     // perform insertion of nodes into elements
8716
8717     for (insertMapIt = insertMap.begin();
8718          insertMapIt != insertMap.end();
8719          insertMapIt++ )
8720     {
8721       const SMDS_MeshElement* elem = (*insertMapIt).first;
8722       list<const SMDS_MeshNode*> & nodeList = (*insertMapIt).second;
8723       const SMDS_MeshNode* n1 = nodeList.front(); nodeList.pop_front();
8724       const SMDS_MeshNode* n2 = nodeList.front(); nodeList.pop_front();
8725
8726       InsertNodesIntoLink( elem, n1, n2, nodeList, toCreatePolygons );
8727
8728       if ( !theSideIsFreeBorder ) {
8729         // look for and insert nodes into the faces adjacent to elem
8730         while (true) {
8731           const SMDS_MeshElement* adjElem = findAdjacentFace( n1, n2, elem );
8732           if ( adjElem )
8733             InsertNodesIntoLink( adjElem, n1, n2, nodeList, toCreatePolygons );
8734           else
8735             break;
8736         }
8737       }
8738       if (toCreatePolyedrs) {
8739         // perform insertion into the links of adjacent volumes
8740         UpdateVolumes(n1, n2, nodeList);
8741       }
8742     }
8743
8744     delete param[0];
8745     delete param[1];
8746   } // end: insert new nodes
8747
8748   MergeNodes ( nodeGroupsToMerge );
8749
8750   return aResult;
8751 }
8752
8753 //=======================================================================
8754 //function : InsertNodesIntoLink
8755 //purpose  : insert theNodesToInsert into theFace between theBetweenNode1
8756 //           and theBetweenNode2 and split theElement
8757 //=======================================================================
8758
8759 void SMESH_MeshEditor::InsertNodesIntoLink(const SMDS_MeshElement*     theFace,
8760                                            const SMDS_MeshNode*        theBetweenNode1,
8761                                            const SMDS_MeshNode*        theBetweenNode2,
8762                                            list<const SMDS_MeshNode*>& theNodesToInsert,
8763                                            const bool                  toCreatePoly)
8764 {
8765   if ( theFace->GetType() != SMDSAbs_Face ) return;
8766
8767   // find indices of 2 link nodes and of the rest nodes
8768   int iNode = 0, il1, il2, i3, i4;
8769   il1 = il2 = i3 = i4 = -1;
8770   //const SMDS_MeshNode* nodes[ theFace->NbNodes() ];
8771   vector<const SMDS_MeshNode*> nodes( theFace->NbNodes() );
8772
8773   if(theFace->IsQuadratic()) {
8774     const SMDS_VtkFace* F =
8775       dynamic_cast<const SMDS_VtkFace*>(theFace);
8776     if (!F) throw SALOME_Exception(LOCALIZED("not an SMDS_VtkFace"));
8777     // use special nodes iterator
8778     SMDS_ElemIteratorPtr anIter = F->interlacedNodesElemIterator();
8779     while( anIter->more() ) {
8780       const SMDS_MeshNode* n = cast2Node(anIter->next());
8781       if ( n == theBetweenNode1 )
8782         il1 = iNode;
8783       else if ( n == theBetweenNode2 )
8784         il2 = iNode;
8785       else if ( i3 < 0 )
8786         i3 = iNode;
8787       else
8788         i4 = iNode;
8789       nodes[ iNode++ ] = n;
8790     }
8791   }
8792   else {
8793     SMDS_ElemIteratorPtr nodeIt = theFace->nodesIterator();
8794     while ( nodeIt->more() ) {
8795       const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
8796       if ( n == theBetweenNode1 )
8797         il1 = iNode;
8798       else if ( n == theBetweenNode2 )
8799         il2 = iNode;
8800       else if ( i3 < 0 )
8801         i3 = iNode;
8802       else
8803         i4 = iNode;
8804       nodes[ iNode++ ] = n;
8805     }
8806   }
8807   if ( il1 < 0 || il2 < 0 || i3 < 0 )
8808     return ;
8809
8810   // arrange link nodes to go one after another regarding the face orientation
8811   bool reverse = ( Abs( il2 - il1 ) == 1 ? il2 < il1 : il1 < il2 );
8812   list<const SMDS_MeshNode *> aNodesToInsert = theNodesToInsert;
8813   if ( reverse ) {
8814     iNode = il1;
8815     il1 = il2;
8816     il2 = iNode;
8817     aNodesToInsert.reverse();
8818   }
8819   // check that not link nodes of a quadrangles are in good order
8820   int nbFaceNodes = theFace->NbNodes();
8821   if ( nbFaceNodes == 4 && i4 - i3 != 1 ) {
8822     iNode = i3;
8823     i3 = i4;
8824     i4 = iNode;
8825   }
8826
8827   if (toCreatePoly || theFace->IsPoly()) {
8828
8829     iNode = 0;
8830     vector<const SMDS_MeshNode *> poly_nodes (nbFaceNodes + aNodesToInsert.size());
8831
8832     // add nodes of face up to first node of link
8833     bool isFLN = false;
8834
8835     if(theFace->IsQuadratic()) {
8836       const SMDS_VtkFace* F =
8837         dynamic_cast<const SMDS_VtkFace*>(theFace);
8838       if (!F) throw SALOME_Exception(LOCALIZED("not an SMDS_VtkFace"));
8839       // use special nodes iterator
8840       SMDS_ElemIteratorPtr anIter = F->interlacedNodesElemIterator();
8841       while( anIter->more()  && !isFLN ) {
8842         const SMDS_MeshNode* n = cast2Node(anIter->next());
8843         poly_nodes[iNode++] = n;
8844         if (n == nodes[il1]) {
8845           isFLN = true;
8846         }
8847       }
8848       // add nodes to insert
8849       list<const SMDS_MeshNode*>::iterator nIt = aNodesToInsert.begin();
8850       for (; nIt != aNodesToInsert.end(); nIt++) {
8851         poly_nodes[iNode++] = *nIt;
8852       }
8853       // add nodes of face starting from last node of link
8854       while ( anIter->more() ) {
8855         poly_nodes[iNode++] = cast2Node(anIter->next());
8856       }
8857     }
8858     else {
8859       SMDS_ElemIteratorPtr nodeIt = theFace->nodesIterator();
8860       while ( nodeIt->more() && !isFLN ) {
8861         const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
8862         poly_nodes[iNode++] = n;
8863         if (n == nodes[il1]) {
8864           isFLN = true;
8865         }
8866       }
8867       // add nodes to insert
8868       list<const SMDS_MeshNode*>::iterator nIt = aNodesToInsert.begin();
8869       for (; nIt != aNodesToInsert.end(); nIt++) {
8870         poly_nodes[iNode++] = *nIt;
8871       }
8872       // add nodes of face starting from last node of link
8873       while ( nodeIt->more() ) {
8874         const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
8875         poly_nodes[iNode++] = n;
8876       }
8877     }
8878
8879     // edit or replace the face
8880     SMESHDS_Mesh *aMesh = GetMeshDS();
8881
8882     if (theFace->IsPoly()) {
8883       aMesh->ChangePolygonNodes(theFace, poly_nodes);
8884     }
8885     else {
8886       int aShapeId = FindShape( theFace );
8887
8888       SMDS_MeshElement* newElem = aMesh->AddPolygonalFace(poly_nodes);
8889       myLastCreatedElems.Append(newElem);
8890       if ( aShapeId && newElem )
8891         aMesh->SetMeshElementOnShape( newElem, aShapeId );
8892
8893       aMesh->RemoveElement(theFace);
8894     }
8895     return;
8896   }
8897
8898   SMESHDS_Mesh *aMesh = GetMeshDS();
8899   if( !theFace->IsQuadratic() ) {
8900
8901     // put aNodesToInsert between theBetweenNode1 and theBetweenNode2
8902     int nbLinkNodes = 2 + aNodesToInsert.size();
8903     //const SMDS_MeshNode* linkNodes[ nbLinkNodes ];
8904     vector<const SMDS_MeshNode*> linkNodes( nbLinkNodes );
8905     linkNodes[ 0 ] = nodes[ il1 ];
8906     linkNodes[ nbLinkNodes - 1 ] = nodes[ il2 ];
8907     list<const SMDS_MeshNode*>::iterator nIt = aNodesToInsert.begin();
8908     for ( iNode = 1; nIt != aNodesToInsert.end(); nIt++ ) {
8909       linkNodes[ iNode++ ] = *nIt;
8910     }
8911     // decide how to split a quadrangle: compare possible variants
8912     // and choose which of splits to be a quadrangle
8913     int i1, i2, iSplit, nbSplits = nbLinkNodes - 1, iBestQuad;
8914     if ( nbFaceNodes == 3 ) {
8915       iBestQuad = nbSplits;
8916       i4 = i3;
8917     }
8918     else if ( nbFaceNodes == 4 ) {
8919       SMESH::Controls::NumericalFunctorPtr aCrit( new SMESH::Controls::AspectRatio);
8920       double aBestRate = DBL_MAX;
8921       for ( int iQuad = 0; iQuad < nbSplits; iQuad++ ) {
8922         i1 = 0; i2 = 1;
8923         double aBadRate = 0;
8924         // evaluate elements quality
8925         for ( iSplit = 0; iSplit < nbSplits; iSplit++ ) {
8926           if ( iSplit == iQuad ) {
8927             SMDS_FaceOfNodes quad (linkNodes[ i1++ ],
8928                                    linkNodes[ i2++ ],
8929                                    nodes[ i3 ],
8930                                    nodes[ i4 ]);
8931             aBadRate += getBadRate( &quad, aCrit );
8932           }
8933           else {
8934             SMDS_FaceOfNodes tria (linkNodes[ i1++ ],
8935                                    linkNodes[ i2++ ],
8936                                    nodes[ iSplit < iQuad ? i4 : i3 ]);
8937             aBadRate += getBadRate( &tria, aCrit );
8938           }
8939         }
8940         // choice
8941         if ( aBadRate < aBestRate ) {
8942           iBestQuad = iQuad;
8943           aBestRate = aBadRate;
8944         }
8945       }
8946     }
8947
8948     // create new elements
8949     int aShapeId = FindShape( theFace );
8950
8951     i1 = 0; i2 = 1;
8952     for ( iSplit = 0; iSplit < nbSplits - 1; iSplit++ ) {
8953       SMDS_MeshElement* newElem = 0;
8954       if ( iSplit == iBestQuad )
8955         newElem = aMesh->AddFace (linkNodes[ i1++ ],
8956                                   linkNodes[ i2++ ],
8957                                   nodes[ i3 ],
8958                                   nodes[ i4 ]);
8959       else
8960         newElem = aMesh->AddFace (linkNodes[ i1++ ],
8961                                   linkNodes[ i2++ ],
8962                                   nodes[ iSplit < iBestQuad ? i4 : i3 ]);
8963       myLastCreatedElems.Append(newElem);
8964       if ( aShapeId && newElem )
8965         aMesh->SetMeshElementOnShape( newElem, aShapeId );
8966     }
8967
8968     // change nodes of theFace
8969     const SMDS_MeshNode* newNodes[ 4 ];
8970     newNodes[ 0 ] = linkNodes[ i1 ];
8971     newNodes[ 1 ] = linkNodes[ i2 ];
8972     newNodes[ 2 ] = nodes[ iSplit >= iBestQuad ? i3 : i4 ];
8973     newNodes[ 3 ] = nodes[ i4 ];
8974     //aMesh->ChangeElementNodes( theFace, newNodes, iSplit == iBestQuad ? 4 : 3 );
8975     const SMDS_MeshElement* newElem = 0;
8976     if (iSplit == iBestQuad)
8977       newElem = aMesh->AddFace( newNodes[0], newNodes[1], newNodes[2], newNodes[3] );
8978     else
8979       newElem = aMesh->AddFace( newNodes[0], newNodes[1], newNodes[2] );
8980     myLastCreatedElems.Append(newElem);
8981     if ( aShapeId && newElem )
8982       aMesh->SetMeshElementOnShape( newElem, aShapeId );
8983 } // end if(!theFace->IsQuadratic())
8984   else { // theFace is quadratic
8985     // we have to split theFace on simple triangles and one simple quadrangle
8986     int tmp = il1/2;
8987     int nbshift = tmp*2;
8988     // shift nodes in nodes[] by nbshift
8989     int i,j;
8990     for(i=0; i<nbshift; i++) {
8991       const SMDS_MeshNode* n = nodes[0];
8992       for(j=0; j<nbFaceNodes-1; j++) {
8993         nodes[j] = nodes[j+1];
8994       }
8995       nodes[nbFaceNodes-1] = n;
8996     }
8997     il1 = il1 - nbshift;
8998     // now have to insert nodes between n0 and n1 or n1 and n2 (see below)
8999     //   n0      n1     n2    n0      n1     n2
9000     //     +-----+-----+        +-----+-----+
9001     //      \         /         |           |
9002     //       \       /          |           |
9003     //      n5+     +n3       n7+           +n3
9004     //         \   /            |           |
9005     //          \ /             |           |
9006     //           +              +-----+-----+
9007     //           n4           n6      n5     n4
9008
9009     // create new elements
9010     int aShapeId = FindShape( theFace );
9011
9012     int n1,n2,n3;
9013     if(nbFaceNodes==6) { // quadratic triangle
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       if(theFace->IsMediumNode(nodes[il1])) {
9020         // create quadrangle
9021         newElem = aMesh->AddFace(nodes[0],nodes[1],nodes[3],nodes[5]);
9022         myLastCreatedElems.Append(newElem);
9023         if ( aShapeId && newElem )
9024           aMesh->SetMeshElementOnShape( newElem, aShapeId );
9025         n1 = 1;
9026         n2 = 2;
9027         n3 = 3;
9028       }
9029       else {
9030         // create quadrangle
9031         newElem = aMesh->AddFace(nodes[1],nodes[2],nodes[3],nodes[5]);
9032         myLastCreatedElems.Append(newElem);
9033         if ( aShapeId && newElem )
9034           aMesh->SetMeshElementOnShape( newElem, aShapeId );
9035         n1 = 0;
9036         n2 = 1;
9037         n3 = 5;
9038       }
9039     }
9040     else { // nbFaceNodes==8 - quadratic quadrangle
9041       SMDS_MeshElement* newElem =
9042         aMesh->AddFace(nodes[3],nodes[4],nodes[5]);
9043       myLastCreatedElems.Append(newElem);
9044       if ( aShapeId && newElem )
9045         aMesh->SetMeshElementOnShape( newElem, aShapeId );
9046       newElem = aMesh->AddFace(nodes[5],nodes[6],nodes[7]);
9047       myLastCreatedElems.Append(newElem);
9048       if ( aShapeId && newElem )
9049         aMesh->SetMeshElementOnShape( newElem, aShapeId );
9050       newElem = aMesh->AddFace(nodes[5],nodes[7],nodes[3]);
9051       myLastCreatedElems.Append(newElem);
9052       if ( aShapeId && newElem )
9053         aMesh->SetMeshElementOnShape( newElem, aShapeId );
9054       if(theFace->IsMediumNode(nodes[il1])) {
9055         // create quadrangle
9056         newElem = aMesh->AddFace(nodes[0],nodes[1],nodes[3],nodes[7]);
9057         myLastCreatedElems.Append(newElem);
9058         if ( aShapeId && newElem )
9059           aMesh->SetMeshElementOnShape( newElem, aShapeId );
9060         n1 = 1;
9061         n2 = 2;
9062         n3 = 3;
9063       }
9064       else {
9065         // create quadrangle
9066         newElem = aMesh->AddFace(nodes[1],nodes[2],nodes[3],nodes[7]);
9067         myLastCreatedElems.Append(newElem);
9068         if ( aShapeId && newElem )
9069           aMesh->SetMeshElementOnShape( newElem, aShapeId );
9070         n1 = 0;
9071         n2 = 1;
9072         n3 = 7;
9073       }
9074     }
9075     // create needed triangles using n1,n2,n3 and inserted nodes
9076     int nbn = 2 + aNodesToInsert.size();
9077     //const SMDS_MeshNode* aNodes[nbn];
9078     vector<const SMDS_MeshNode*> aNodes(nbn);
9079     aNodes[0] = nodes[n1];
9080     aNodes[nbn-1] = nodes[n2];
9081     list<const SMDS_MeshNode*>::iterator nIt = aNodesToInsert.begin();
9082     for ( iNode = 1; nIt != aNodesToInsert.end(); nIt++ ) {
9083       aNodes[iNode++] = *nIt;
9084     }
9085     for(i=1; i<nbn; i++) {
9086       SMDS_MeshElement* newElem =
9087         aMesh->AddFace(aNodes[i-1],aNodes[i],nodes[n3]);
9088       myLastCreatedElems.Append(newElem);
9089       if ( aShapeId && newElem )
9090         aMesh->SetMeshElementOnShape( newElem, aShapeId );
9091     }
9092   }
9093   // remove old face
9094   aMesh->RemoveElement(theFace);
9095 }
9096
9097 //=======================================================================
9098 //function : UpdateVolumes
9099 //purpose  :
9100 //=======================================================================
9101 void SMESH_MeshEditor::UpdateVolumes (const SMDS_MeshNode*        theBetweenNode1,
9102                                       const SMDS_MeshNode*        theBetweenNode2,
9103                                       list<const SMDS_MeshNode*>& theNodesToInsert)
9104 {
9105   myLastCreatedElems.Clear();
9106   myLastCreatedNodes.Clear();
9107
9108   SMDS_ElemIteratorPtr invElemIt = theBetweenNode1->GetInverseElementIterator(SMDSAbs_Volume);
9109   while (invElemIt->more()) { // loop on inverse elements of theBetweenNode1
9110     const SMDS_MeshElement* elem = invElemIt->next();
9111
9112     // check, if current volume has link theBetweenNode1 - theBetweenNode2
9113     SMDS_VolumeTool aVolume (elem);
9114     if (!aVolume.IsLinked(theBetweenNode1, theBetweenNode2))
9115       continue;
9116
9117     // insert new nodes in all faces of the volume, sharing link theBetweenNode1 - theBetweenNode2
9118     int iface, nbFaces = aVolume.NbFaces();
9119     vector<const SMDS_MeshNode *> poly_nodes;
9120     vector<int> quantities (nbFaces);
9121
9122     for (iface = 0; iface < nbFaces; iface++) {
9123       int nbFaceNodes = aVolume.NbFaceNodes(iface), nbInserted = 0;
9124       // faceNodes will contain (nbFaceNodes + 1) nodes, last = first
9125       const SMDS_MeshNode** faceNodes = aVolume.GetFaceNodes(iface);
9126
9127       for (int inode = 0; inode < nbFaceNodes; inode++) {
9128         poly_nodes.push_back(faceNodes[inode]);
9129
9130         if (nbInserted == 0) {
9131           if (faceNodes[inode] == theBetweenNode1) {
9132             if (faceNodes[inode + 1] == theBetweenNode2) {
9133               nbInserted = theNodesToInsert.size();
9134
9135               // add nodes to insert
9136               list<const SMDS_MeshNode*>::iterator nIt = theNodesToInsert.begin();
9137               for (; nIt != theNodesToInsert.end(); nIt++) {
9138                 poly_nodes.push_back(*nIt);
9139               }
9140             }
9141           }
9142           else if (faceNodes[inode] == theBetweenNode2) {
9143             if (faceNodes[inode + 1] == theBetweenNode1) {
9144               nbInserted = theNodesToInsert.size();
9145
9146               // add nodes to insert in reversed order
9147               list<const SMDS_MeshNode*>::iterator nIt = theNodesToInsert.end();
9148               nIt--;
9149               for (; nIt != theNodesToInsert.begin(); nIt--) {
9150                 poly_nodes.push_back(*nIt);
9151               }
9152               poly_nodes.push_back(*nIt);
9153             }
9154           }
9155           else {
9156           }
9157         }
9158       }
9159       quantities[iface] = nbFaceNodes + nbInserted;
9160     }
9161
9162     // Replace or update the volume
9163     SMESHDS_Mesh *aMesh = GetMeshDS();
9164
9165     if (elem->IsPoly()) {
9166       aMesh->ChangePolyhedronNodes(elem, poly_nodes, quantities);
9167
9168     }
9169     else {
9170       int aShapeId = FindShape( elem );
9171
9172       SMDS_MeshElement* newElem =
9173         aMesh->AddPolyhedralVolume(poly_nodes, quantities);
9174       myLastCreatedElems.Append(newElem);
9175       if (aShapeId && newElem)
9176         aMesh->SetMeshElementOnShape(newElem, aShapeId);
9177
9178       aMesh->RemoveElement(elem);
9179     }
9180   }
9181 }
9182
9183 //=======================================================================
9184 /*!
9185  * \brief Convert elements contained in a submesh to quadratic
9186  * \retval int - nb of checked elements
9187  */
9188 //=======================================================================
9189
9190 int SMESH_MeshEditor::convertElemToQuadratic(SMESHDS_SubMesh *   theSm,
9191                                              SMESH_MesherHelper& theHelper,
9192                                              const bool          theForce3d)
9193 {
9194   int nbElem = 0;
9195   if( !theSm ) return nbElem;
9196
9197   vector<int> nbNodeInFaces;
9198   SMDS_ElemIteratorPtr ElemItr = theSm->GetElements();
9199   while(ElemItr->more())
9200   {
9201     nbElem++;
9202     const SMDS_MeshElement* elem = ElemItr->next();
9203     if( !elem || elem->IsQuadratic() ) continue;
9204
9205     int id = elem->GetID();
9206     //MESSAGE("elem " << id);
9207     id = 0; // get a free number for new elements
9208     int nbNodes = elem->NbNodes();
9209     SMDSAbs_ElementType aType = elem->GetType();
9210
9211     vector<const SMDS_MeshNode *> nodes (elem->begin_nodes(), elem->end_nodes());
9212     if ( elem->GetEntityType() == SMDSEntity_Polyhedra )
9213       nbNodeInFaces = static_cast<const SMDS_VtkVolume* >( elem )->GetQuantities();
9214
9215     const SMDS_MeshElement* NewElem = 0;
9216
9217     switch( aType )
9218     {
9219     case SMDSAbs_Edge :
9220       {
9221         NewElem = theHelper.AddEdge(nodes[0], nodes[1], id, theForce3d);
9222         break;
9223       }
9224     case SMDSAbs_Face :
9225       {
9226         switch(nbNodes)
9227         {
9228         case 3:
9229           NewElem = theHelper.AddFace(nodes[0], nodes[1], nodes[2], id, theForce3d);
9230           break;
9231         case 4:
9232           NewElem = theHelper.AddFace(nodes[0], nodes[1], nodes[2], nodes[3], id, theForce3d);
9233           break;
9234         default:
9235           NewElem = theHelper.AddPolygonalFace(nodes, id, theForce3d);
9236           continue;
9237         }
9238         break;
9239       }
9240     case SMDSAbs_Volume :
9241       {
9242         switch(nbNodes)
9243         {
9244         case 4:
9245           NewElem = theHelper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3], id, theForce3d);
9246           break;
9247         case 5:
9248           NewElem = theHelper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3], nodes[4], id, theForce3d);
9249           break;
9250         case 6:
9251           NewElem = theHelper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3], nodes[4], nodes[5], id, theForce3d);
9252           break;
9253         case 8:
9254           NewElem = theHelper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3],
9255                                         nodes[4], nodes[5], nodes[6], nodes[7], id, theForce3d);
9256           break;
9257         default:
9258           NewElem = theHelper.AddPolyhedralVolume(nodes, nbNodeInFaces, id, theForce3d);
9259         }
9260         break;
9261       }
9262     default :
9263       continue;
9264     }
9265     ReplaceElemInGroups( elem, NewElem, GetMeshDS());
9266     if( NewElem )
9267       theSm->AddElement( NewElem );
9268
9269     GetMeshDS()->RemoveFreeElement(elem, theSm, /*fromGroups=*/false);
9270   }
9271 //  if (!GetMeshDS()->isCompacted())
9272 //    GetMeshDS()->compactMesh();
9273   return nbElem;
9274 }
9275
9276 //=======================================================================
9277 //function : ConvertToQuadratic
9278 //purpose  :
9279 //=======================================================================
9280 void SMESH_MeshEditor::ConvertToQuadratic(const bool theForce3d)
9281 {
9282   SMESHDS_Mesh* meshDS = GetMeshDS();
9283
9284   SMESH_MesherHelper aHelper(*myMesh);
9285   aHelper.SetIsQuadratic( true );
9286
9287   int nbCheckedElems = 0;
9288   if ( myMesh->HasShapeToMesh() )
9289   {
9290     if ( SMESH_subMesh *aSubMesh = myMesh->GetSubMeshContaining(myMesh->GetShapeToMesh()))
9291     {
9292       SMESH_subMeshIteratorPtr smIt = aSubMesh->getDependsOnIterator(true,false);
9293       while ( smIt->more() ) {
9294         SMESH_subMesh* sm = smIt->next();
9295         if ( SMESHDS_SubMesh *smDS = sm->GetSubMeshDS() ) {
9296           aHelper.SetSubShape( sm->GetSubShape() );
9297           nbCheckedElems += convertElemToQuadratic(smDS, aHelper, theForce3d);
9298         }
9299       }
9300     }
9301   }
9302   int totalNbElems = meshDS->NbEdges() + meshDS->NbFaces() + meshDS->NbVolumes();
9303   if ( nbCheckedElems < totalNbElems ) // not all elements are in submeshes
9304   {
9305     SMESHDS_SubMesh *smDS = 0;
9306     SMDS_EdgeIteratorPtr aEdgeItr = meshDS->edgesIterator();
9307     while(aEdgeItr->more())
9308     {
9309       const SMDS_MeshEdge* edge = aEdgeItr->next();
9310       if(edge && !edge->IsQuadratic())
9311       {
9312         int id = edge->GetID();
9313         //MESSAGE("edge->GetID() " << id);
9314         const SMDS_MeshNode* n1 = edge->GetNode(0);
9315         const SMDS_MeshNode* n2 = edge->GetNode(1);
9316
9317         meshDS->RemoveFreeElement(edge, smDS, /*fromGroups=*/false);
9318
9319         const SMDS_MeshEdge* NewEdge = aHelper.AddEdge(n1, n2, id, theForce3d);
9320         ReplaceElemInGroups( edge, NewEdge, GetMeshDS());
9321       }
9322     }
9323     SMDS_FaceIteratorPtr aFaceItr = meshDS->facesIterator();
9324     while(aFaceItr->more())
9325     {
9326       const SMDS_MeshFace* face = aFaceItr->next();
9327       if(!face || face->IsQuadratic() ) continue;
9328
9329       int id = face->GetID();
9330       int nbNodes = face->NbNodes();
9331       vector<const SMDS_MeshNode *> nodes ( face->begin_nodes(), face->end_nodes());
9332
9333       meshDS->RemoveFreeElement(face, smDS, /*fromGroups=*/false);
9334
9335       SMDS_MeshFace * NewFace = 0;
9336       switch(nbNodes)
9337       {
9338       case 3:
9339         NewFace = aHelper.AddFace(nodes[0], nodes[1], nodes[2], id, theForce3d);
9340         break;
9341       case 4:
9342         NewFace = aHelper.AddFace(nodes[0], nodes[1], nodes[2], nodes[3], id, theForce3d);
9343         break;
9344       default:
9345         NewFace = aHelper.AddPolygonalFace(nodes, id, theForce3d);
9346       }
9347       ReplaceElemInGroups( face, NewFace, GetMeshDS());
9348     }
9349     vector<int> nbNodeInFaces;
9350     SMDS_VolumeIteratorPtr aVolumeItr = meshDS->volumesIterator();
9351     while(aVolumeItr->more())
9352     {
9353       const SMDS_MeshVolume* volume = aVolumeItr->next();
9354       if(!volume || volume->IsQuadratic() ) continue;
9355
9356       int id = volume->GetID();
9357       int nbNodes = volume->NbNodes();
9358       vector<const SMDS_MeshNode *> nodes (volume->begin_nodes(), volume->end_nodes());
9359       if ( volume->GetEntityType() == SMDSEntity_Polyhedra )
9360         nbNodeInFaces = static_cast<const SMDS_VtkVolume* >(volume)->GetQuantities();
9361
9362       meshDS->RemoveFreeElement(volume, smDS, /*fromGroups=*/false);
9363
9364       SMDS_MeshVolume * NewVolume = 0;
9365       switch(nbNodes)
9366       {
9367       case 4:
9368         NewVolume = aHelper.AddVolume(nodes[0], nodes[1], nodes[2],
9369                                       nodes[3], id, theForce3d );
9370         break;
9371       case 5:
9372         NewVolume = aHelper.AddVolume(nodes[0], nodes[1], nodes[2],
9373                                       nodes[3], nodes[4], id, theForce3d);
9374         break;
9375       case 6:
9376         NewVolume = aHelper.AddVolume(nodes[0], nodes[1], nodes[2],
9377                                       nodes[3], nodes[4], nodes[5], id, theForce3d);
9378         break;
9379       case 8:
9380         NewVolume = aHelper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3],
9381                                       nodes[4], nodes[5], nodes[6], nodes[7], id, theForce3d);
9382         break;
9383       default:
9384         NewVolume = aHelper.AddPolyhedralVolume(nodes, nbNodeInFaces, id, theForce3d);
9385       }
9386       ReplaceElemInGroups(volume, NewVolume, meshDS);
9387     }
9388   }
9389
9390   if ( !theForce3d  && !getenv("NO_FixQuadraticElements"))
9391   { // setenv NO_FixQuadraticElements to know if FixQuadraticElements() is guilty of bad conversion
9392     aHelper.SetSubShape(0); // apply FixQuadraticElements() to the whole mesh
9393     aHelper.FixQuadraticElements();
9394   }
9395   if (!GetMeshDS()->isCompacted())
9396     GetMeshDS()->compactMesh();
9397 }
9398
9399 //=======================================================================
9400 /*!
9401  * \brief Convert quadratic elements to linear ones and remove quadratic nodes
9402  * \retval int - nb of checked elements
9403  */
9404 //=======================================================================
9405
9406 int SMESH_MeshEditor::removeQuadElem(SMESHDS_SubMesh *    theSm,
9407                                      SMDS_ElemIteratorPtr theItr,
9408                                      const int            theShapeID)
9409 {
9410   int nbElem = 0;
9411   SMESHDS_Mesh* meshDS = GetMeshDS();
9412   const bool notFromGroups = false;
9413
9414   while( theItr->more() )
9415   {
9416     const SMDS_MeshElement* elem = theItr->next();
9417     nbElem++;
9418     if( elem && elem->IsQuadratic())
9419     {
9420       int id = elem->GetID();
9421       int nbNodes = elem->NbNodes();
9422       vector<const SMDS_MeshNode *> nodes, mediumNodes;
9423       nodes.reserve( nbNodes );
9424       mediumNodes.reserve( nbNodes );
9425
9426       for(int i = 0; i < nbNodes; i++)
9427       {
9428         const SMDS_MeshNode* n = elem->GetNode(i);
9429
9430         if( elem->IsMediumNode( n ) )
9431           mediumNodes.push_back( n );
9432         else
9433           nodes.push_back( n );
9434       }
9435       if( nodes.empty() ) continue;
9436       SMDSAbs_ElementType aType = elem->GetType();
9437
9438       //remove old quadratic element
9439       meshDS->RemoveFreeElement( elem, theSm, notFromGroups );
9440
9441       SMDS_MeshElement * NewElem = AddElement( nodes, aType, false, id );
9442       ReplaceElemInGroups(elem, NewElem, meshDS);
9443       if( theSm && NewElem )
9444         theSm->AddElement( NewElem );
9445
9446       // remove medium nodes
9447       vector<const SMDS_MeshNode*>::iterator nIt = mediumNodes.begin();
9448       for ( ; nIt != mediumNodes.end(); ++nIt ) {
9449         const SMDS_MeshNode* n = *nIt;
9450         if ( n->NbInverseElements() == 0 ) {
9451           if ( n->getshapeId() != theShapeID )
9452             meshDS->RemoveFreeNode( n, meshDS->MeshElements
9453                                     ( n->getshapeId() ));
9454           else
9455             meshDS->RemoveFreeNode( n, theSm );
9456         }
9457       }
9458     }
9459   }
9460   return nbElem;
9461 }
9462
9463 //=======================================================================
9464 //function : ConvertFromQuadratic
9465 //purpose  :
9466 //=======================================================================
9467 bool  SMESH_MeshEditor::ConvertFromQuadratic()
9468 {
9469   int nbCheckedElems = 0;
9470   if ( myMesh->HasShapeToMesh() )
9471   {
9472     if ( SMESH_subMesh *aSubMesh = myMesh->GetSubMeshContaining(myMesh->GetShapeToMesh()))
9473     {
9474       SMESH_subMeshIteratorPtr smIt = aSubMesh->getDependsOnIterator(true,false);
9475       while ( smIt->more() ) {
9476         SMESH_subMesh* sm = smIt->next();
9477         if ( SMESHDS_SubMesh *smDS = sm->GetSubMeshDS() )
9478           nbCheckedElems += removeQuadElem( smDS, smDS->GetElements(), sm->GetId() );
9479       }
9480     }
9481   }
9482
9483   int totalNbElems =
9484     GetMeshDS()->NbEdges() + GetMeshDS()->NbFaces() + GetMeshDS()->NbVolumes();
9485   if ( nbCheckedElems < totalNbElems ) // not all elements are in submeshes
9486   {
9487     SMESHDS_SubMesh *aSM = 0;
9488     removeQuadElem( aSM, GetMeshDS()->elementsIterator(), 0 );
9489   }
9490
9491   return true;
9492 }
9493
9494 //=======================================================================
9495 //function : SewSideElements
9496 //purpose  :
9497 //=======================================================================
9498
9499 SMESH_MeshEditor::Sew_Error
9500 SMESH_MeshEditor::SewSideElements (TIDSortedElemSet&    theSide1,
9501                                    TIDSortedElemSet&    theSide2,
9502                                    const SMDS_MeshNode* theFirstNode1,
9503                                    const SMDS_MeshNode* theFirstNode2,
9504                                    const SMDS_MeshNode* theSecondNode1,
9505                                    const SMDS_MeshNode* theSecondNode2)
9506 {
9507   myLastCreatedElems.Clear();
9508   myLastCreatedNodes.Clear();
9509
9510   MESSAGE ("::::SewSideElements()");
9511   if ( theSide1.size() != theSide2.size() )
9512     return SEW_DIFF_NB_OF_ELEMENTS;
9513
9514   Sew_Error aResult = SEW_OK;
9515   // Algo:
9516   // 1. Build set of faces representing each side
9517   // 2. Find which nodes of the side 1 to merge with ones on the side 2
9518   // 3. Replace nodes in elements of the side 1 and remove replaced nodes
9519
9520   // =======================================================================
9521   // 1. Build set of faces representing each side:
9522   // =======================================================================
9523   // a. build set of nodes belonging to faces
9524   // b. complete set of faces: find missing faces whose nodes are in set of nodes
9525   // c. create temporary faces representing side of volumes if correspondent
9526   //    face does not exist
9527
9528   SMESHDS_Mesh* aMesh = GetMeshDS();
9529   // TODO algoritm not OK with vtkUnstructuredGrid: 2 meshes can't share nodes
9530   //SMDS_Mesh aTmpFacesMesh; // try to use the same mesh
9531   set<const SMDS_MeshElement*> faceSet1, faceSet2;
9532   set<const SMDS_MeshElement*> volSet1,  volSet2;
9533   set<const SMDS_MeshNode*>    nodeSet1, nodeSet2;
9534   set<const SMDS_MeshElement*> * faceSetPtr[] = { &faceSet1, &faceSet2 };
9535   set<const SMDS_MeshElement*>  * volSetPtr[] = { &volSet1,  &volSet2  };
9536   set<const SMDS_MeshNode*>    * nodeSetPtr[] = { &nodeSet1, &nodeSet2 };
9537   TIDSortedElemSet * elemSetPtr[] = { &theSide1, &theSide2 };
9538   int iSide, iFace, iNode;
9539
9540   list<const SMDS_MeshElement* > tempFaceList;
9541   for ( iSide = 0; iSide < 2; iSide++ ) {
9542     set<const SMDS_MeshNode*>    * nodeSet = nodeSetPtr[ iSide ];
9543     TIDSortedElemSet * elemSet = elemSetPtr[ iSide ];
9544     set<const SMDS_MeshElement*> * faceSet = faceSetPtr[ iSide ];
9545     set<const SMDS_MeshElement*> * volSet  = volSetPtr [ iSide ];
9546     set<const SMDS_MeshElement*>::iterator vIt;
9547     TIDSortedElemSet::iterator eIt;
9548     set<const SMDS_MeshNode*>::iterator    nIt;
9549
9550     // check that given nodes belong to given elements
9551     const SMDS_MeshNode* n1 = ( iSide == 0 ) ? theFirstNode1 : theFirstNode2;
9552     const SMDS_MeshNode* n2 = ( iSide == 0 ) ? theSecondNode1 : theSecondNode2;
9553     int firstIndex = -1, secondIndex = -1;
9554     for (eIt = elemSet->begin(); eIt != elemSet->end(); eIt++ ) {
9555       const SMDS_MeshElement* elem = *eIt;
9556       if ( firstIndex  < 0 ) firstIndex  = elem->GetNodeIndex( n1 );
9557       if ( secondIndex < 0 ) secondIndex = elem->GetNodeIndex( n2 );
9558       if ( firstIndex > -1 && secondIndex > -1 ) break;
9559     }
9560     if ( firstIndex < 0 || secondIndex < 0 ) {
9561       // we can simply return until temporary faces created
9562       return (iSide == 0 ) ? SEW_BAD_SIDE1_NODES : SEW_BAD_SIDE2_NODES;
9563     }
9564
9565     // -----------------------------------------------------------
9566     // 1a. Collect nodes of existing faces
9567     //     and build set of face nodes in order to detect missing
9568     //     faces corresponding to sides of volumes
9569     // -----------------------------------------------------------
9570
9571     set< set <const SMDS_MeshNode*> > setOfFaceNodeSet;
9572
9573     // loop on the given element of a side
9574     for (eIt = elemSet->begin(); eIt != elemSet->end(); eIt++ ) {
9575       //const SMDS_MeshElement* elem = *eIt;
9576       const SMDS_MeshElement* elem = *eIt;
9577       if ( elem->GetType() == SMDSAbs_Face ) {
9578         faceSet->insert( elem );
9579         set <const SMDS_MeshNode*> faceNodeSet;
9580         SMDS_ElemIteratorPtr nodeIt = elem->nodesIterator();
9581         while ( nodeIt->more() ) {
9582           const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
9583           nodeSet->insert( n );
9584           faceNodeSet.insert( n );
9585         }
9586         setOfFaceNodeSet.insert( faceNodeSet );
9587       }
9588       else if ( elem->GetType() == SMDSAbs_Volume )
9589         volSet->insert( elem );
9590     }
9591     // ------------------------------------------------------------------------------
9592     // 1b. Complete set of faces: find missing faces whose nodes are in set of nodes
9593     // ------------------------------------------------------------------------------
9594
9595     for ( nIt = nodeSet->begin(); nIt != nodeSet->end(); nIt++ ) { // loop on nodes of iSide
9596       SMDS_ElemIteratorPtr fIt = (*nIt)->GetInverseElementIterator(SMDSAbs_Face);
9597       while ( fIt->more() ) { // loop on faces sharing a node
9598         const SMDS_MeshElement* f = fIt->next();
9599         if ( faceSet->find( f ) == faceSet->end() ) {
9600           // check if all nodes are in nodeSet and
9601           // complete setOfFaceNodeSet if they are
9602           set <const SMDS_MeshNode*> faceNodeSet;
9603           SMDS_ElemIteratorPtr nodeIt = f->nodesIterator();
9604           bool allInSet = true;
9605           while ( nodeIt->more() && allInSet ) { // loop on nodes of a face
9606             const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
9607             if ( nodeSet->find( n ) == nodeSet->end() )
9608               allInSet = false;
9609             else
9610               faceNodeSet.insert( n );
9611           }
9612           if ( allInSet ) {
9613             faceSet->insert( f );
9614             setOfFaceNodeSet.insert( faceNodeSet );
9615           }
9616         }
9617       }
9618     }
9619
9620     // -------------------------------------------------------------------------
9621     // 1c. Create temporary faces representing sides of volumes if correspondent
9622     //     face does not exist
9623     // -------------------------------------------------------------------------
9624
9625     if ( !volSet->empty() ) {
9626       //int nodeSetSize = nodeSet->size();
9627
9628       // loop on given volumes
9629       for ( vIt = volSet->begin(); vIt != volSet->end(); vIt++ ) {
9630         SMDS_VolumeTool vol (*vIt);
9631         // loop on volume faces: find free faces
9632         // --------------------------------------
9633         list<const SMDS_MeshElement* > freeFaceList;
9634         for ( iFace = 0; iFace < vol.NbFaces(); iFace++ ) {
9635           if ( !vol.IsFreeFace( iFace ))
9636             continue;
9637           // check if there is already a face with same nodes in a face set
9638           const SMDS_MeshElement* aFreeFace = 0;
9639           const SMDS_MeshNode** fNodes = vol.GetFaceNodes( iFace );
9640           int nbNodes = vol.NbFaceNodes( iFace );
9641           set <const SMDS_MeshNode*> faceNodeSet;
9642           vol.GetFaceNodes( iFace, faceNodeSet );
9643           bool isNewFace = setOfFaceNodeSet.insert( faceNodeSet ).second;
9644           if ( isNewFace ) {
9645             // no such a face is given but it still can exist, check it
9646             if ( nbNodes == 3 ) {
9647               aFreeFace = aMesh->FindFace( fNodes[0],fNodes[1],fNodes[2] );
9648             }
9649             else if ( nbNodes == 4 ) {
9650               aFreeFace = aMesh->FindFace( fNodes[0],fNodes[1],fNodes[2],fNodes[3] );
9651             }
9652             else {
9653               vector<const SMDS_MeshNode *> poly_nodes ( fNodes, & fNodes[nbNodes]);
9654               aFreeFace = aMesh->FindFace(poly_nodes);
9655             }
9656           }
9657           if ( !aFreeFace ) {
9658             // create a temporary face
9659             if ( nbNodes == 3 ) {
9660               //aFreeFace = aTmpFacesMesh.AddFace( fNodes[0],fNodes[1],fNodes[2] );
9661               aFreeFace = aMesh->AddFace( fNodes[0],fNodes[1],fNodes[2] );
9662             }
9663             else if ( nbNodes == 4 ) {
9664               //aFreeFace = aTmpFacesMesh.AddFace( fNodes[0],fNodes[1],fNodes[2],fNodes[3] );
9665               aFreeFace = aMesh->AddFace( fNodes[0],fNodes[1],fNodes[2],fNodes[3] );
9666             }
9667             else {
9668               vector<const SMDS_MeshNode *> poly_nodes ( fNodes, & fNodes[nbNodes]);
9669               //aFreeFace = aTmpFacesMesh.AddPolygonalFace(poly_nodes);
9670               aFreeFace = aMesh->AddPolygonalFace(poly_nodes);
9671             }
9672           }
9673           if ( aFreeFace ) {
9674             freeFaceList.push_back( aFreeFace );
9675             tempFaceList.push_back( aFreeFace );
9676           }
9677
9678         } // loop on faces of a volume
9679
9680         // choose one of several free faces
9681         // --------------------------------------
9682         if ( freeFaceList.size() > 1 ) {
9683           // choose a face having max nb of nodes shared by other elems of a side
9684           int maxNbNodes = -1/*, nbExcludedFaces = 0*/;
9685           list<const SMDS_MeshElement* >::iterator fIt = freeFaceList.begin();
9686           while ( fIt != freeFaceList.end() ) { // loop on free faces
9687             int nbSharedNodes = 0;
9688             SMDS_ElemIteratorPtr nodeIt = (*fIt)->nodesIterator();
9689             while ( nodeIt->more() ) { // loop on free face nodes
9690               const SMDS_MeshNode* n =
9691                 static_cast<const SMDS_MeshNode*>( nodeIt->next() );
9692               SMDS_ElemIteratorPtr invElemIt = n->GetInverseElementIterator();
9693               while ( invElemIt->more() ) {
9694                 const SMDS_MeshElement* e = invElemIt->next();
9695                 if ( faceSet->find( e ) != faceSet->end() )
9696                   nbSharedNodes++;
9697                 if ( elemSet->find( e ) != elemSet->end() )
9698                   nbSharedNodes++;
9699               }
9700             }
9701             if ( nbSharedNodes >= maxNbNodes ) {
9702               maxNbNodes = nbSharedNodes;
9703               fIt++;
9704             }
9705             else
9706               freeFaceList.erase( fIt++ ); // here fIt++ occurs before erase
9707           }
9708           if ( freeFaceList.size() > 1 )
9709           {
9710             // could not choose one face, use another way
9711             // choose a face most close to the bary center of the opposite side
9712             gp_XYZ aBC( 0., 0., 0. );
9713             set <const SMDS_MeshNode*> addedNodes;
9714             TIDSortedElemSet * elemSet2 = elemSetPtr[ 1 - iSide ];
9715             eIt = elemSet2->begin();
9716             for ( eIt = elemSet2->begin(); eIt != elemSet2->end(); eIt++ ) {
9717               SMDS_ElemIteratorPtr nodeIt = (*eIt)->nodesIterator();
9718               while ( nodeIt->more() ) { // loop on free face nodes
9719                 const SMDS_MeshNode* n =
9720                   static_cast<const SMDS_MeshNode*>( nodeIt->next() );
9721                 if ( addedNodes.insert( n ).second )
9722                   aBC += gp_XYZ( n->X(),n->Y(),n->Z() );
9723               }
9724             }
9725             aBC /= addedNodes.size();
9726             double minDist = DBL_MAX;
9727             fIt = freeFaceList.begin();
9728             while ( fIt != freeFaceList.end() ) { // loop on free faces
9729               double dist = 0;
9730               SMDS_ElemIteratorPtr nodeIt = (*fIt)->nodesIterator();
9731               while ( nodeIt->more() ) { // loop on free face nodes
9732                 const SMDS_MeshNode* n =
9733                   static_cast<const SMDS_MeshNode*>( nodeIt->next() );
9734                 gp_XYZ p( n->X(),n->Y(),n->Z() );
9735                 dist += ( aBC - p ).SquareModulus();
9736               }
9737               if ( dist < minDist ) {
9738                 minDist = dist;
9739                 freeFaceList.erase( freeFaceList.begin(), fIt++ );
9740               }
9741               else
9742                 fIt = freeFaceList.erase( fIt++ );
9743             }
9744           }
9745         } // choose one of several free faces of a volume
9746
9747         if ( freeFaceList.size() == 1 ) {
9748           const SMDS_MeshElement* aFreeFace = freeFaceList.front();
9749           faceSet->insert( aFreeFace );
9750           // complete a node set with nodes of a found free face
9751           //           for ( iNode = 0; iNode < ; iNode++ )
9752           //             nodeSet->insert( fNodes[ iNode ] );
9753         }
9754
9755       } // loop on volumes of a side
9756
9757       //       // complete a set of faces if new nodes in a nodeSet appeared
9758       //       // ----------------------------------------------------------
9759       //       if ( nodeSetSize != nodeSet->size() ) {
9760       //         for ( ; nIt != nodeSet->end(); nIt++ ) { // loop on nodes of iSide
9761       //           SMDS_ElemIteratorPtr fIt = (*nIt)->GetInverseElementIterator(SMDSAbs_Face);
9762       //           while ( fIt->more() ) { // loop on faces sharing a node
9763       //             const SMDS_MeshElement* f = fIt->next();
9764       //             if ( faceSet->find( f ) == faceSet->end() ) {
9765       //               // check if all nodes are in nodeSet and
9766       //               // complete setOfFaceNodeSet if they are
9767       //               set <const SMDS_MeshNode*> faceNodeSet;
9768       //               SMDS_ElemIteratorPtr nodeIt = f->nodesIterator();
9769       //               bool allInSet = true;
9770       //               while ( nodeIt->more() && allInSet ) { // loop on nodes of a face
9771       //                 const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
9772       //                 if ( nodeSet->find( n ) == nodeSet->end() )
9773       //                   allInSet = false;
9774       //                 else
9775       //                   faceNodeSet.insert( n );
9776       //               }
9777       //               if ( allInSet ) {
9778       //                 faceSet->insert( f );
9779       //                 setOfFaceNodeSet.insert( faceNodeSet );
9780       //               }
9781       //             }
9782       //           }
9783       //         }
9784       //       }
9785     } // Create temporary faces, if there are volumes given
9786   } // loop on sides
9787
9788   if ( faceSet1.size() != faceSet2.size() ) {
9789     // delete temporary faces: they are in reverseElements of actual nodes
9790 //    SMDS_FaceIteratorPtr tmpFaceIt = aTmpFacesMesh.facesIterator();
9791 //    while ( tmpFaceIt->more() )
9792 //      aTmpFacesMesh.RemoveElement( tmpFaceIt->next() );
9793 //    list<const SMDS_MeshElement* >::iterator tmpFaceIt = tempFaceList.begin();
9794 //    for (; tmpFaceIt !=tempFaceList.end(); ++tmpFaceIt)
9795 //      aMesh->RemoveElement(*tmpFaceIt);
9796     MESSAGE("Diff nb of faces");
9797     return SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
9798   }
9799
9800   // ============================================================
9801   // 2. Find nodes to merge:
9802   //              bind a node to remove to a node to put instead
9803   // ============================================================
9804
9805   TNodeNodeMap nReplaceMap; // bind a node to remove to a node to put instead
9806   if ( theFirstNode1 != theFirstNode2 )
9807     nReplaceMap.insert( TNodeNodeMap::value_type( theFirstNode1, theFirstNode2 ));
9808   if ( theSecondNode1 != theSecondNode2 )
9809     nReplaceMap.insert( TNodeNodeMap::value_type( theSecondNode1, theSecondNode2 ));
9810
9811   LinkID_Gen aLinkID_Gen( GetMeshDS() );
9812   set< long > linkIdSet; // links to process
9813   linkIdSet.insert( aLinkID_Gen.GetLinkID( theFirstNode1, theSecondNode1 ));
9814
9815   typedef pair< const SMDS_MeshNode*, const SMDS_MeshNode* > NLink;
9816   list< NLink > linkList[2];
9817   linkList[0].push_back( NLink( theFirstNode1, theSecondNode1 ));
9818   linkList[1].push_back( NLink( theFirstNode2, theSecondNode2 ));
9819   // loop on links in linkList; find faces by links and append links
9820   // of the found faces to linkList
9821   list< NLink >::iterator linkIt[] = { linkList[0].begin(), linkList[1].begin() } ;
9822   for ( ; linkIt[0] != linkList[0].end(); linkIt[0]++, linkIt[1]++ ) {
9823     NLink link[] = { *linkIt[0], *linkIt[1] };
9824     long linkID = aLinkID_Gen.GetLinkID( link[0].first, link[0].second );
9825     if ( linkIdSet.find( linkID ) == linkIdSet.end() )
9826       continue;
9827
9828     // by links, find faces in the face sets,
9829     // and find indices of link nodes in the found faces;
9830     // in a face set, there is only one or no face sharing a link
9831     // ---------------------------------------------------------------
9832
9833     const SMDS_MeshElement* face[] = { 0, 0 };
9834     //const SMDS_MeshNode* faceNodes[ 2 ][ 5 ];
9835     vector<const SMDS_MeshNode*> fnodes1(9);
9836     vector<const SMDS_MeshNode*> fnodes2(9);
9837     //const SMDS_MeshNode* notLinkNodes[ 2 ][ 2 ] = {{ 0, 0 },{ 0, 0 }} ;
9838     vector<const SMDS_MeshNode*> notLinkNodes1(6);
9839     vector<const SMDS_MeshNode*> notLinkNodes2(6);
9840     int iLinkNode[2][2];
9841     for ( iSide = 0; iSide < 2; iSide++ ) { // loop on 2 sides
9842       const SMDS_MeshNode* n1 = link[iSide].first;
9843       const SMDS_MeshNode* n2 = link[iSide].second;
9844       set<const SMDS_MeshElement*> * faceSet = faceSetPtr[ iSide ];
9845       set< const SMDS_MeshElement* > fMap;
9846       for ( int i = 0; i < 2; i++ ) { // loop on 2 nodes of a link
9847         const SMDS_MeshNode* n = i ? n1 : n2; // a node of a link
9848         SMDS_ElemIteratorPtr fIt = n->GetInverseElementIterator(SMDSAbs_Face);
9849         while ( fIt->more() ) { // loop on faces sharing a node
9850           const SMDS_MeshElement* f = fIt->next();
9851           if (faceSet->find( f ) != faceSet->end() && // f is in face set
9852               ! fMap.insert( f ).second ) // f encounters twice
9853           {
9854             if ( face[ iSide ] ) {
9855               MESSAGE( "2 faces per link " );
9856               aResult = iSide ? SEW_BAD_SIDE2_NODES : SEW_BAD_SIDE1_NODES;
9857               break;
9858             }
9859             face[ iSide ] = f;
9860             faceSet->erase( f );
9861             // get face nodes and find ones of a link
9862             iNode = 0;
9863             int nbl = -1;
9864             if(f->IsPoly()) {
9865               if(iSide==0) {
9866                 fnodes1.resize(f->NbNodes()+1);
9867                 notLinkNodes1.resize(f->NbNodes()-2);
9868               }
9869               else {
9870                 fnodes2.resize(f->NbNodes()+1);
9871                 notLinkNodes2.resize(f->NbNodes()-2);
9872               }
9873             }
9874             if(!f->IsQuadratic()) {
9875               SMDS_ElemIteratorPtr nIt = f->nodesIterator();
9876               while ( nIt->more() ) {
9877                 const SMDS_MeshNode* n =
9878                   static_cast<const SMDS_MeshNode*>( nIt->next() );
9879                 if ( n == n1 ) {
9880                   iLinkNode[ iSide ][ 0 ] = iNode;
9881                 }
9882                 else if ( n == n2 ) {
9883                   iLinkNode[ iSide ][ 1 ] = iNode;
9884                 }
9885                 //else if ( notLinkNodes[ iSide ][ 0 ] )
9886                 //  notLinkNodes[ iSide ][ 1 ] = n;
9887                 //else
9888                 //  notLinkNodes[ iSide ][ 0 ] = n;
9889                 else {
9890                   nbl++;
9891                   if(iSide==0)
9892                     notLinkNodes1[nbl] = n;
9893                   //notLinkNodes1.push_back(n);
9894                   else
9895                     notLinkNodes2[nbl] = n;
9896                   //notLinkNodes2.push_back(n);
9897                 }
9898                 //faceNodes[ iSide ][ iNode++ ] = n;
9899                 if(iSide==0) {
9900                   fnodes1[iNode++] = n;
9901                 }
9902                 else {
9903                   fnodes2[iNode++] = n;
9904                 }
9905               }
9906             }
9907             else { // f->IsQuadratic()
9908               const SMDS_VtkFace* F =
9909                 dynamic_cast<const SMDS_VtkFace*>(f);
9910               if (!F) throw SALOME_Exception(LOCALIZED("not an SMDS_VtkFace"));
9911               // use special nodes iterator
9912               SMDS_ElemIteratorPtr anIter = F->interlacedNodesElemIterator();
9913               while ( anIter->more() ) {
9914                 const SMDS_MeshNode* n =
9915                   static_cast<const SMDS_MeshNode*>( anIter->next() );
9916                 if ( n == n1 ) {
9917                   iLinkNode[ iSide ][ 0 ] = iNode;
9918                 }
9919                 else if ( n == n2 ) {
9920                   iLinkNode[ iSide ][ 1 ] = iNode;
9921                 }
9922                 else {
9923                   nbl++;
9924                   if(iSide==0) {
9925                     notLinkNodes1[nbl] = n;
9926                   }
9927                   else {
9928                     notLinkNodes2[nbl] = n;
9929                   }
9930                 }
9931                 if(iSide==0) {
9932                   fnodes1[iNode++] = n;
9933                 }
9934                 else {
9935                   fnodes2[iNode++] = n;
9936                 }
9937               }
9938             }
9939             //faceNodes[ iSide ][ iNode ] = faceNodes[ iSide ][ 0 ];
9940             if(iSide==0) {
9941               fnodes1[iNode] = fnodes1[0];
9942             }
9943             else {
9944               fnodes2[iNode] = fnodes1[0];
9945             }
9946           }
9947         }
9948       }
9949     }
9950
9951     // check similarity of elements of the sides
9952     if (aResult == SEW_OK && ( face[0] && !face[1] ) || ( !face[0] && face[1] )) {
9953       MESSAGE("Correspondent face not found on side " << ( face[0] ? 1 : 0 ));
9954       if ( nReplaceMap.size() == 2 ) { // faces on input nodes not found
9955         aResult = ( face[0] ? SEW_BAD_SIDE2_NODES : SEW_BAD_SIDE1_NODES );
9956       }
9957       else {
9958         aResult = SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
9959       }
9960       break; // do not return because it s necessary to remove tmp faces
9961     }
9962
9963     // set nodes to merge
9964     // -------------------
9965
9966     if ( face[0] && face[1] )  {
9967       int nbNodes = face[0]->NbNodes();
9968       if ( nbNodes != face[1]->NbNodes() ) {
9969         MESSAGE("Diff nb of face nodes");
9970         aResult = SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
9971         break; // do not return because it s necessary to remove tmp faces
9972       }
9973       bool reverse[] = { false, false }; // order of notLinkNodes of quadrangle
9974       if ( nbNodes == 3 ) {
9975         //nReplaceMap.insert( TNodeNodeMap::value_type
9976         //                   ( notLinkNodes[0][0], notLinkNodes[1][0] ));
9977         nReplaceMap.insert( TNodeNodeMap::value_type
9978                             ( notLinkNodes1[0], notLinkNodes2[0] ));
9979       }
9980       else {
9981         for ( iSide = 0; iSide < 2; iSide++ ) { // loop on 2 sides
9982           // analyse link orientation in faces
9983           int i1 = iLinkNode[ iSide ][ 0 ];
9984           int i2 = iLinkNode[ iSide ][ 1 ];
9985           reverse[ iSide ] = Abs( i1 - i2 ) == 1 ? i1 > i2 : i2 > i1;
9986           // if notLinkNodes are the first and the last ones, then
9987           // their order does not correspond to the link orientation
9988           if (( i1 == 1 && i2 == 2 ) ||
9989               ( i1 == 2 && i2 == 1 ))
9990             reverse[ iSide ] = !reverse[ iSide ];
9991         }
9992         if ( reverse[0] == reverse[1] ) {
9993           //nReplaceMap.insert( TNodeNodeMap::value_type
9994           //                   ( notLinkNodes[0][0], notLinkNodes[1][0] ));
9995           //nReplaceMap.insert( TNodeNodeMap::value_type
9996           //                   ( notLinkNodes[0][1], notLinkNodes[1][1] ));
9997           for(int nn=0; nn<nbNodes-2; nn++) {
9998             nReplaceMap.insert( TNodeNodeMap::value_type
9999                                 ( notLinkNodes1[nn], notLinkNodes2[nn] ));
10000           }
10001         }
10002         else {
10003           //nReplaceMap.insert( TNodeNodeMap::value_type
10004           //                   ( notLinkNodes[0][0], notLinkNodes[1][1] ));
10005           //nReplaceMap.insert( TNodeNodeMap::value_type
10006           //                   ( notLinkNodes[0][1], notLinkNodes[1][0] ));
10007           for(int nn=0; nn<nbNodes-2; nn++) {
10008             nReplaceMap.insert( TNodeNodeMap::value_type
10009                                 ( notLinkNodes1[nn], notLinkNodes2[nbNodes-3-nn] ));
10010           }
10011         }
10012       }
10013
10014       // add other links of the faces to linkList
10015       // -----------------------------------------
10016
10017       //const SMDS_MeshNode** nodes = faceNodes[ 0 ];
10018       for ( iNode = 0; iNode < nbNodes; iNode++ )  {
10019         //linkID = aLinkID_Gen.GetLinkID( nodes[iNode], nodes[iNode+1] );
10020         linkID = aLinkID_Gen.GetLinkID( fnodes1[iNode], fnodes1[iNode+1] );
10021         pair< set<long>::iterator, bool > iter_isnew = linkIdSet.insert( linkID );
10022         if ( !iter_isnew.second ) { // already in a set: no need to process
10023           linkIdSet.erase( iter_isnew.first );
10024         }
10025         else // new in set == encountered for the first time: add
10026         {
10027           //const SMDS_MeshNode* n1 = nodes[ iNode ];
10028           //const SMDS_MeshNode* n2 = nodes[ iNode + 1];
10029           const SMDS_MeshNode* n1 = fnodes1[ iNode ];
10030           const SMDS_MeshNode* n2 = fnodes1[ iNode + 1];
10031           linkList[0].push_back ( NLink( n1, n2 ));
10032           linkList[1].push_back ( NLink( nReplaceMap[n1], nReplaceMap[n2] ));
10033         }
10034       }
10035     } // 2 faces found
10036   } // loop on link lists
10037
10038   if ( aResult == SEW_OK &&
10039        ( linkIt[0] != linkList[0].end() ||
10040          !faceSetPtr[0]->empty() || !faceSetPtr[1]->empty() )) {
10041     MESSAGE( (linkIt[0] != linkList[0].end()) <<" "<< (faceSetPtr[0]->empty()) <<
10042              " " << (faceSetPtr[1]->empty()));
10043     aResult = SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
10044   }
10045
10046   // ====================================================================
10047   // 3. Replace nodes in elements of the side 1 and remove replaced nodes
10048   // ====================================================================
10049
10050   // delete temporary faces: they are in reverseElements of actual nodes
10051 //  SMDS_FaceIteratorPtr tmpFaceIt = aTmpFacesMesh.facesIterator();
10052 //  while ( tmpFaceIt->more() )
10053 //    aTmpFacesMesh.RemoveElement( tmpFaceIt->next() );
10054 //  list<const SMDS_MeshElement* >::iterator tmpFaceIt = tempFaceList.begin();
10055 //  for (; tmpFaceIt !=tempFaceList.end(); ++tmpFaceIt)
10056 //    aMesh->RemoveElement(*tmpFaceIt);
10057
10058   if ( aResult != SEW_OK)
10059     return aResult;
10060
10061   list< int > nodeIDsToRemove/*, elemIDsToRemove*/;
10062   // loop on nodes replacement map
10063   TNodeNodeMap::iterator nReplaceMapIt = nReplaceMap.begin(), nnIt;
10064   for ( ; nReplaceMapIt != nReplaceMap.end(); nReplaceMapIt++ )
10065     if ( (*nReplaceMapIt).first != (*nReplaceMapIt).second ) {
10066       const SMDS_MeshNode* nToRemove = (*nReplaceMapIt).first;
10067       nodeIDsToRemove.push_back( nToRemove->GetID() );
10068       // loop on elements sharing nToRemove
10069       SMDS_ElemIteratorPtr invElemIt = nToRemove->GetInverseElementIterator();
10070       while ( invElemIt->more() ) {
10071         const SMDS_MeshElement* e = invElemIt->next();
10072         // get a new suite of nodes: make replacement
10073         int nbReplaced = 0, i = 0, nbNodes = e->NbNodes();
10074         vector< const SMDS_MeshNode*> nodes( nbNodes );
10075         SMDS_ElemIteratorPtr nIt = e->nodesIterator();
10076         while ( nIt->more() ) {
10077           const SMDS_MeshNode* n =
10078             static_cast<const SMDS_MeshNode*>( nIt->next() );
10079           nnIt = nReplaceMap.find( n );
10080           if ( nnIt != nReplaceMap.end() ) {
10081             nbReplaced++;
10082             n = (*nnIt).second;
10083           }
10084           nodes[ i++ ] = n;
10085         }
10086         //       if ( nbReplaced == nbNodes && e->GetType() == SMDSAbs_Face )
10087         //         elemIDsToRemove.push_back( e->GetID() );
10088         //       else
10089         if ( nbReplaced )
10090           {
10091             SMDSAbs_ElementType etyp = e->GetType();
10092             SMDS_MeshElement* newElem = this->AddElement(nodes, etyp, false);
10093             if (newElem)
10094               {
10095                 myLastCreatedElems.Append(newElem);
10096                 AddToSameGroups(newElem, e, aMesh);
10097                 int aShapeId = e->getshapeId();
10098                 if ( aShapeId )
10099                   {
10100                     aMesh->SetMeshElementOnShape( newElem, aShapeId );
10101                   }
10102               }
10103             aMesh->RemoveElement(e);
10104           }
10105       }
10106     }
10107
10108   Remove( nodeIDsToRemove, true );
10109
10110   return aResult;
10111 }
10112
10113 //================================================================================
10114 /*!
10115  * \brief Find corresponding nodes in two sets of faces
10116  * \param theSide1 - first face set
10117  * \param theSide2 - second first face
10118  * \param theFirstNode1 - a boundary node of set 1
10119  * \param theFirstNode2 - a node of set 2 corresponding to theFirstNode1
10120  * \param theSecondNode1 - a boundary node of set 1 linked with theFirstNode1
10121  * \param theSecondNode2 - a node of set 2 corresponding to theSecondNode1
10122  * \param nReplaceMap - output map of corresponding nodes
10123  * \retval bool  - is a success or not
10124  */
10125 //================================================================================
10126
10127 #ifdef _DEBUG_
10128 //#define DEBUG_MATCHING_NODES
10129 #endif
10130
10131 SMESH_MeshEditor::Sew_Error
10132 SMESH_MeshEditor::FindMatchingNodes(set<const SMDS_MeshElement*>& theSide1,
10133                                     set<const SMDS_MeshElement*>& theSide2,
10134                                     const SMDS_MeshNode*          theFirstNode1,
10135                                     const SMDS_MeshNode*          theFirstNode2,
10136                                     const SMDS_MeshNode*          theSecondNode1,
10137                                     const SMDS_MeshNode*          theSecondNode2,
10138                                     TNodeNodeMap &                nReplaceMap)
10139 {
10140   set<const SMDS_MeshElement*> * faceSetPtr[] = { &theSide1, &theSide2 };
10141
10142   nReplaceMap.clear();
10143   if ( theFirstNode1 != theFirstNode2 )
10144     nReplaceMap.insert( make_pair( theFirstNode1, theFirstNode2 ));
10145   if ( theSecondNode1 != theSecondNode2 )
10146     nReplaceMap.insert( make_pair( theSecondNode1, theSecondNode2 ));
10147
10148   set< SMESH_TLink > linkSet; // set of nodes where order of nodes is ignored
10149   linkSet.insert( SMESH_TLink( theFirstNode1, theSecondNode1 ));
10150
10151   list< NLink > linkList[2];
10152   linkList[0].push_back( NLink( theFirstNode1, theSecondNode1 ));
10153   linkList[1].push_back( NLink( theFirstNode2, theSecondNode2 ));
10154
10155   // loop on links in linkList; find faces by links and append links
10156   // of the found faces to linkList
10157   list< NLink >::iterator linkIt[] = { linkList[0].begin(), linkList[1].begin() } ;
10158   for ( ; linkIt[0] != linkList[0].end(); linkIt[0]++, linkIt[1]++ ) {
10159     NLink link[] = { *linkIt[0], *linkIt[1] };
10160     if ( linkSet.find( link[0] ) == linkSet.end() )
10161       continue;
10162
10163     // by links, find faces in the face sets,
10164     // and find indices of link nodes in the found faces;
10165     // in a face set, there is only one or no face sharing a link
10166     // ---------------------------------------------------------------
10167
10168     const SMDS_MeshElement* face[] = { 0, 0 };
10169     list<const SMDS_MeshNode*> notLinkNodes[2];
10170     //bool reverse[] = { false, false }; // order of notLinkNodes
10171     int nbNodes[2];
10172     for ( int iSide = 0; iSide < 2; iSide++ ) // loop on 2 sides
10173     {
10174       const SMDS_MeshNode* n1 = link[iSide].first;
10175       const SMDS_MeshNode* n2 = link[iSide].second;
10176       set<const SMDS_MeshElement*> * faceSet = faceSetPtr[ iSide ];
10177       set< const SMDS_MeshElement* > facesOfNode1;
10178       for ( int iNode = 0; iNode < 2; iNode++ ) // loop on 2 nodes of a link
10179       {
10180         // during a loop of the first node, we find all faces around n1,
10181         // during a loop of the second node, we find one face sharing both n1 and n2
10182         const SMDS_MeshNode* n = iNode ? n1 : n2; // a node of a link
10183         SMDS_ElemIteratorPtr fIt = n->GetInverseElementIterator(SMDSAbs_Face);
10184         while ( fIt->more() ) { // loop on faces sharing a node
10185           const SMDS_MeshElement* f = fIt->next();
10186           if (faceSet->find( f ) != faceSet->end() && // f is in face set
10187               ! facesOfNode1.insert( f ).second ) // f encounters twice
10188           {
10189             if ( face[ iSide ] ) {
10190               MESSAGE( "2 faces per link " );
10191               return ( iSide ? SEW_BAD_SIDE2_NODES : SEW_BAD_SIDE1_NODES );
10192             }
10193             face[ iSide ] = f;
10194             faceSet->erase( f );
10195
10196             // get not link nodes
10197             int nbN = f->NbNodes();
10198             if ( f->IsQuadratic() )
10199               nbN /= 2;
10200             nbNodes[ iSide ] = nbN;
10201             list< const SMDS_MeshNode* > & nodes = notLinkNodes[ iSide ];
10202             int i1 = f->GetNodeIndex( n1 );
10203             int i2 = f->GetNodeIndex( n2 );
10204             int iEnd = nbN, iBeg = -1, iDelta = 1;
10205             bool reverse = ( Abs( i1 - i2 ) == 1 ? i1 > i2 : i2 > i1 );
10206             if ( reverse ) {
10207               std::swap( iEnd, iBeg ); iDelta = -1;
10208             }
10209             int i = i2;
10210             while ( true ) {
10211               i += iDelta;
10212               if ( i == iEnd ) i = iBeg + iDelta;
10213               if ( i == i1 ) break;
10214               nodes.push_back ( f->GetNode( i ) );
10215             }
10216           }
10217         }
10218       }
10219     }
10220     // check similarity of elements of the sides
10221     if (( face[0] && !face[1] ) || ( !face[0] && face[1] )) {
10222       MESSAGE("Correspondent face not found on side " << ( face[0] ? 1 : 0 ));
10223       if ( nReplaceMap.size() == 2 ) { // faces on input nodes not found
10224         return ( face[0] ? SEW_BAD_SIDE2_NODES : SEW_BAD_SIDE1_NODES );
10225       }
10226       else {
10227         return SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
10228       }
10229     }
10230
10231     // set nodes to merge
10232     // -------------------
10233
10234     if ( face[0] && face[1] )  {
10235       if ( nbNodes[0] != nbNodes[1] ) {
10236         MESSAGE("Diff nb of face nodes");
10237         return SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
10238       }
10239 #ifdef DEBUG_MATCHING_NODES
10240       MESSAGE ( " Link 1: " << link[0].first->GetID() <<" "<< link[0].second->GetID()
10241                 << " F 1: " << face[0] << "| Link 2: " << link[1].first->GetID() <<" "
10242                 << link[1].second->GetID() << " F 2: " << face[1] << " | Bind: " ) ;
10243 #endif
10244       int nbN = nbNodes[0];
10245       {
10246         list<const SMDS_MeshNode*>::iterator n1 = notLinkNodes[0].begin();
10247         list<const SMDS_MeshNode*>::iterator n2 = notLinkNodes[1].begin();
10248         for ( int i = 0 ; i < nbN - 2; ++i ) {
10249 #ifdef DEBUG_MATCHING_NODES
10250           MESSAGE ( (*n1)->GetID() << " to " << (*n2)->GetID() );
10251 #endif
10252           nReplaceMap.insert( make_pair( *(n1++), *(n2++) ));
10253         }
10254       }
10255
10256       // add other links of the face 1 to linkList
10257       // -----------------------------------------
10258
10259       const SMDS_MeshElement* f0 = face[0];
10260       const SMDS_MeshNode* n1 = f0->GetNode( nbN - 1 );
10261       for ( int i = 0; i < nbN; i++ )
10262       {
10263         const SMDS_MeshNode* n2 = f0->GetNode( i );
10264         pair< set< SMESH_TLink >::iterator, bool > iter_isnew =
10265           linkSet.insert( SMESH_TLink( n1, n2 ));
10266         if ( !iter_isnew.second ) { // already in a set: no need to process
10267           linkSet.erase( iter_isnew.first );
10268         }
10269         else // new in set == encountered for the first time: add
10270         {
10271 #ifdef DEBUG_MATCHING_NODES
10272           MESSAGE ( "Add link 1: " << n1->GetID() << " " << n2->GetID() << " "
10273                     << " | link 2: " << nReplaceMap[n1]->GetID() << " " << nReplaceMap[n2]->GetID() << " " );
10274 #endif
10275           linkList[0].push_back ( NLink( n1, n2 ));
10276           linkList[1].push_back ( NLink( nReplaceMap[n1], nReplaceMap[n2] ));
10277         }
10278         n1 = n2;
10279       }
10280     } // 2 faces found
10281   } // loop on link lists
10282
10283   return SEW_OK;
10284 }
10285
10286 //================================================================================
10287 /*!
10288   \brief Creates a hole in a mesh by doubling the nodes of some particular elements
10289   \param theElems - the list of elements (edges or faces) to be replicated
10290   The nodes for duplication could be found from these elements
10291   \param theNodesNot - list of nodes to NOT replicate
10292   \param theAffectedElems - the list of elements (cells and edges) to which the 
10293   replicated nodes should be associated to.
10294   \return TRUE if operation has been completed successfully, FALSE otherwise
10295 */
10296 //================================================================================
10297
10298 bool SMESH_MeshEditor::DoubleNodes( const TIDSortedElemSet& theElems,
10299                                     const TIDSortedElemSet& theNodesNot,
10300                                     const TIDSortedElemSet& theAffectedElems )
10301 {
10302   myLastCreatedElems.Clear();
10303   myLastCreatedNodes.Clear();
10304
10305   if ( theElems.size() == 0 )
10306     return false;
10307
10308   SMESHDS_Mesh* aMeshDS = GetMeshDS();
10309   if ( !aMeshDS )
10310     return false;
10311
10312   bool res = false;
10313   std::map< const SMDS_MeshNode*, const SMDS_MeshNode* > anOldNodeToNewNode;
10314   // duplicate elements and nodes
10315   res = doubleNodes( aMeshDS, theElems, theNodesNot, anOldNodeToNewNode, true );
10316   // replce nodes by duplications
10317   res = doubleNodes( aMeshDS, theAffectedElems, theNodesNot, anOldNodeToNewNode, false );
10318   return res;
10319 }
10320
10321 //================================================================================
10322 /*!
10323   \brief Creates a hole in a mesh by doubling the nodes of some particular elements
10324   \param theMeshDS - mesh instance
10325   \param theElems - the elements replicated or modified (nodes should be changed)
10326   \param theNodesNot - nodes to NOT replicate
10327   \param theNodeNodeMap - relation of old node to new created node
10328   \param theIsDoubleElem - flag os to replicate element or modify
10329   \return TRUE if operation has been completed successfully, FALSE otherwise
10330 */
10331 //================================================================================
10332
10333 bool SMESH_MeshEditor::doubleNodes( SMESHDS_Mesh*     theMeshDS,
10334                                     const TIDSortedElemSet& theElems,
10335                                     const TIDSortedElemSet& theNodesNot,
10336                                     std::map< const SMDS_MeshNode*,
10337                                     const SMDS_MeshNode* >& theNodeNodeMap,
10338                                     const bool theIsDoubleElem )
10339 {
10340   MESSAGE("doubleNodes");
10341   // iterate on through element and duplicate them (by nodes duplication)
10342   bool res = false;
10343   TIDSortedElemSet::const_iterator elemItr = theElems.begin();
10344   for ( ;  elemItr != theElems.end(); ++elemItr )
10345   {
10346     const SMDS_MeshElement* anElem = *elemItr;
10347     if (!anElem)
10348       continue;
10349
10350     bool isDuplicate = false;
10351     // duplicate nodes to duplicate element
10352     std::vector<const SMDS_MeshNode*> newNodes( anElem->NbNodes() );
10353     SMDS_ElemIteratorPtr anIter = anElem->nodesIterator();
10354     int ind = 0;
10355     while ( anIter->more() ) 
10356     { 
10357
10358       SMDS_MeshNode* aCurrNode = (SMDS_MeshNode*)anIter->next();
10359       SMDS_MeshNode* aNewNode = aCurrNode;
10360       if ( theNodeNodeMap.find( aCurrNode ) != theNodeNodeMap.end() )
10361         aNewNode = (SMDS_MeshNode*)theNodeNodeMap[ aCurrNode ];
10362       else if ( theIsDoubleElem && theNodesNot.find( aCurrNode ) == theNodesNot.end() )
10363       {
10364         // duplicate node
10365         aNewNode = theMeshDS->AddNode( aCurrNode->X(), aCurrNode->Y(), aCurrNode->Z() );
10366         theNodeNodeMap[ aCurrNode ] = aNewNode;
10367         myLastCreatedNodes.Append( aNewNode );
10368       }
10369       isDuplicate |= (aCurrNode != aNewNode);
10370       newNodes[ ind++ ] = aNewNode;
10371     }
10372     if ( !isDuplicate )
10373       continue;
10374
10375     if ( theIsDoubleElem )
10376       AddElement(newNodes, anElem->GetType(), anElem->IsPoly());
10377     else
10378       {
10379       MESSAGE("ChangeElementNodes");
10380       theMeshDS->ChangeElementNodes( anElem, &newNodes[ 0 ], anElem->NbNodes() );
10381       }
10382     res = true;
10383   }
10384   return res;
10385 }
10386
10387 //================================================================================
10388 /*!
10389   \brief Creates a hole in a mesh by doubling the nodes of some particular elements
10390   \param theNodes - identifiers of nodes to be doubled
10391   \param theModifiedElems - identifiers of elements to be updated by the new (doubled) 
10392          nodes. If list of element identifiers is empty then nodes are doubled but 
10393          they not assigned to elements
10394   \return TRUE if operation has been completed successfully, FALSE otherwise
10395 */
10396 //================================================================================
10397
10398 bool SMESH_MeshEditor::DoubleNodes( const std::list< int >& theListOfNodes, 
10399                                     const std::list< int >& theListOfModifiedElems )
10400 {
10401   MESSAGE("DoubleNodes");
10402   myLastCreatedElems.Clear();
10403   myLastCreatedNodes.Clear();
10404
10405   if ( theListOfNodes.size() == 0 )
10406     return false;
10407
10408   SMESHDS_Mesh* aMeshDS = GetMeshDS();
10409   if ( !aMeshDS )
10410     return false;
10411
10412   // iterate through nodes and duplicate them
10413
10414   std::map< const SMDS_MeshNode*, const SMDS_MeshNode* > anOldNodeToNewNode;
10415
10416   std::list< int >::const_iterator aNodeIter;
10417   for ( aNodeIter = theListOfNodes.begin(); aNodeIter != theListOfNodes.end(); ++aNodeIter )
10418   {
10419     int aCurr = *aNodeIter;
10420     SMDS_MeshNode* aNode = (SMDS_MeshNode*)aMeshDS->FindNode( aCurr );
10421     if ( !aNode )
10422       continue;
10423
10424     // duplicate node
10425
10426     const SMDS_MeshNode* aNewNode = aMeshDS->AddNode( aNode->X(), aNode->Y(), aNode->Z() );
10427     if ( aNewNode )
10428     {
10429       anOldNodeToNewNode[ aNode ] = aNewNode;
10430       myLastCreatedNodes.Append( aNewNode );
10431     }
10432   }
10433
10434   // Create map of new nodes for modified elements
10435
10436   std::map< SMDS_MeshElement*, vector<const SMDS_MeshNode*> > anElemToNodes;
10437
10438   std::list< int >::const_iterator anElemIter;
10439   for ( anElemIter = theListOfModifiedElems.begin(); 
10440         anElemIter != theListOfModifiedElems.end(); ++anElemIter )
10441   {
10442     int aCurr = *anElemIter;
10443     SMDS_MeshElement* anElem = (SMDS_MeshElement*)aMeshDS->FindElement( aCurr );
10444     if ( !anElem )
10445       continue;
10446
10447     vector<const SMDS_MeshNode*> aNodeArr( anElem->NbNodes() );
10448
10449     SMDS_ElemIteratorPtr anIter = anElem->nodesIterator();
10450     int ind = 0;
10451     while ( anIter->more() ) 
10452     { 
10453       SMDS_MeshNode* aCurrNode = (SMDS_MeshNode*)anIter->next();
10454       if ( aCurr && anOldNodeToNewNode.find( aCurrNode ) != anOldNodeToNewNode.end() )
10455       {
10456         const SMDS_MeshNode* aNewNode = anOldNodeToNewNode[ aCurrNode ];
10457         aNodeArr[ ind++ ] = aNewNode;
10458       }
10459       else
10460         aNodeArr[ ind++ ] = aCurrNode;
10461     }
10462     anElemToNodes[ anElem ] = aNodeArr;
10463   }
10464
10465   // Change nodes of elements  
10466
10467   std::map< SMDS_MeshElement*, vector<const SMDS_MeshNode*> >::iterator
10468     anElemToNodesIter = anElemToNodes.begin();
10469   for ( ; anElemToNodesIter != anElemToNodes.end(); ++anElemToNodesIter )
10470   {
10471     const SMDS_MeshElement* anElem = anElemToNodesIter->first;
10472     vector<const SMDS_MeshNode*> aNodeArr = anElemToNodesIter->second;
10473     if ( anElem )
10474       {
10475       MESSAGE("ChangeElementNodes");
10476       aMeshDS->ChangeElementNodes( anElem, &aNodeArr[ 0 ], anElem->NbNodes() );
10477       }
10478   }
10479
10480   return true;
10481 }
10482
10483 namespace {
10484
10485   //================================================================================
10486   /*!
10487   \brief Check if element located inside shape
10488   \return TRUE if IN or ON shape, FALSE otherwise
10489   */
10490   //================================================================================
10491
10492   template<class Classifier>
10493   bool isInside(const SMDS_MeshElement* theElem,
10494                 Classifier&             theClassifier,
10495                 const double            theTol)
10496   {
10497     gp_XYZ centerXYZ (0, 0, 0);
10498     SMDS_ElemIteratorPtr aNodeItr = theElem->nodesIterator();
10499     while (aNodeItr->more())
10500       centerXYZ += SMESH_TNodeXYZ(cast2Node( aNodeItr->next()));
10501
10502     gp_Pnt aPnt = centerXYZ / theElem->NbNodes();
10503     theClassifier.Perform(aPnt, theTol);
10504     TopAbs_State aState = theClassifier.State();
10505     return (aState == TopAbs_IN || aState == TopAbs_ON );
10506   }
10507
10508   //================================================================================
10509   /*!
10510    * \brief Classifier of the 3D point on the TopoDS_Face
10511    *        with interaface suitable for isInside()
10512    */
10513   //================================================================================
10514
10515   struct _FaceClassifier
10516   {
10517     Extrema_ExtPS       _extremum;
10518     BRepAdaptor_Surface _surface;
10519     TopAbs_State        _state;
10520
10521     _FaceClassifier(const TopoDS_Face& face):_extremum(),_surface(face),_state(TopAbs_OUT)
10522     {
10523       _extremum.Initialize( _surface,
10524                             _surface.FirstUParameter(), _surface.LastUParameter(),
10525                             _surface.FirstVParameter(), _surface.LastVParameter(),
10526                             _surface.Tolerance(), _surface.Tolerance() );
10527     }
10528     void Perform(const gp_Pnt& aPnt, double theTol)
10529     {
10530       _state = TopAbs_OUT;
10531       _extremum.Perform(aPnt);
10532       if ( _extremum.IsDone() )
10533         for ( int iSol = 1; iSol <= _extremum.NbExt() && _state == TopAbs_OUT; ++iSol)
10534           _state = ( _extremum.Value(iSol) <= theTol ? TopAbs_IN : TopAbs_OUT );
10535     }
10536     TopAbs_State State() const
10537     {
10538       return _state;
10539     }
10540   };
10541 }
10542
10543 //================================================================================
10544 /*!
10545   \brief Creates a hole in a mesh by doubling the nodes of some particular elements
10546   \param theElems - group of of elements (edges or faces) to be replicated
10547   \param theNodesNot - group of nodes not to replicate
10548   \param theShape - shape to detect affected elements (element which geometric center
10549   located on or inside shape).
10550   The replicated nodes should be associated to affected elements.
10551   \return TRUE if operation has been completed successfully, FALSE otherwise
10552 */
10553 //================================================================================
10554
10555 bool SMESH_MeshEditor::DoubleNodesInRegion( const TIDSortedElemSet& theElems,
10556                                             const TIDSortedElemSet& theNodesNot,
10557                                             const TopoDS_Shape&     theShape )
10558 {
10559   if ( theShape.IsNull() )
10560     return false;
10561
10562   const double aTol = Precision::Confusion();
10563   auto_ptr< BRepClass3d_SolidClassifier> bsc3d;
10564   auto_ptr<_FaceClassifier>              aFaceClassifier;
10565   if ( theShape.ShapeType() == TopAbs_SOLID )
10566   {
10567     bsc3d.reset( new BRepClass3d_SolidClassifier(theShape));;
10568     bsc3d->PerformInfinitePoint(aTol);
10569   }
10570   else if (theShape.ShapeType() == TopAbs_FACE )
10571   {
10572     aFaceClassifier.reset( new _FaceClassifier(TopoDS::Face(theShape)));
10573   }
10574
10575   // iterates on indicated elements and get elements by back references from their nodes
10576   TIDSortedElemSet anAffected;
10577   TIDSortedElemSet::const_iterator elemItr = theElems.begin();
10578   for ( ;  elemItr != theElems.end(); ++elemItr )
10579   {
10580     SMDS_MeshElement* anElem = (SMDS_MeshElement*)*elemItr;
10581     if (!anElem)
10582       continue;
10583
10584     SMDS_ElemIteratorPtr nodeItr = anElem->nodesIterator();
10585     while ( nodeItr->more() )
10586     {
10587       const SMDS_MeshNode* aNode = cast2Node(nodeItr->next());
10588       if ( !aNode || theNodesNot.find(aNode) != theNodesNot.end() )
10589         continue;
10590       SMDS_ElemIteratorPtr backElemItr = aNode->GetInverseElementIterator();
10591       while ( backElemItr->more() )
10592       {
10593         const SMDS_MeshElement* curElem = backElemItr->next();
10594         if ( curElem && theElems.find(curElem) == theElems.end() &&
10595              ( bsc3d.get() ?
10596                isInside( curElem, *bsc3d, aTol ) :
10597                isInside( curElem, *aFaceClassifier, aTol )))
10598           anAffected.insert( curElem );
10599       }
10600     }
10601   }
10602   return DoubleNodes( theElems, theNodesNot, anAffected );
10603 }
10604
10605 /*!
10606  * \brief Double nodes on shared faces between groups of volumes and create flat elements on demand.
10607  * The list of groups must describe a partition of the mesh volumes.
10608  * The nodes of the internal faces at the boundaries of the groups are doubled.
10609  * In option, the internal faces are replaced by flat elements.
10610  * Triangles are transformed in prisms, and quadrangles in hexahedrons.
10611  * @param theElems - list of groups of volumes, where a group of volume is a set of
10612  * SMDS_MeshElements sorted by Id.
10613  * @param createJointElems - if TRUE, create the elements
10614  * @return TRUE if operation has been completed successfully, FALSE otherwise
10615  */
10616 bool SMESH_MeshEditor::DoubleNodesOnGroupBoundaries( const std::vector<TIDSortedElemSet>& theElems,
10617                                                      bool createJointElems)
10618 {
10619   MESSAGE("----------------------------------------------");
10620   MESSAGE("SMESH_MeshEditor::doubleNodesOnGroupBoundaries");
10621   MESSAGE("----------------------------------------------");
10622
10623   SMESHDS_Mesh *meshDS = this->myMesh->GetMeshDS();
10624   meshDS->BuildDownWardConnectivity(false);
10625   CHRONO(50);
10626   SMDS_UnstructuredGrid *grid = meshDS->getGrid();
10627
10628   // --- build the list of faces shared by 2 domains (group of elements), with their domain and volume indexes
10629   //     build the list of cells with only a node or an edge on the border, with their domain and volume indexes
10630   //     build the list of nodes shared by 2 or more domains, with their domain indexes
10631
10632   std::map<DownIdType, std::map<int,int>, DownIdCompare> faceDomains; // face --> (id domain --> id volume)
10633   std::map<int,int>celldom; // cell vtkId --> domain
10634   std::map<DownIdType, std::map<int,int>, DownIdCompare> cellDomains;  // oldNode --> (id domain --> id cell)
10635   std::map<int, std::map<int,int> > nodeDomains; // oldId -->  (domainId --> newId)
10636   faceDomains.clear();
10637   celldom.clear();
10638   cellDomains.clear();
10639   nodeDomains.clear();
10640   std::map<int,int> emptyMap;
10641   emptyMap.clear();
10642
10643   for (int idom = 0; idom < theElems.size(); idom++)
10644     {
10645
10646       // --- build a map (face to duplicate --> volume to modify)
10647       //     with all the faces shared by 2 domains (group of elements)
10648       //     and corresponding volume of this domain, for each shared face.
10649       //     a volume has a face shared by 2 domains if it has a neighbor which is not in is domain.
10650
10651       const TIDSortedElemSet& domain = theElems[idom];
10652       TIDSortedElemSet::const_iterator elemItr = domain.begin();
10653       for (; elemItr != domain.end(); ++elemItr)
10654         {
10655           SMDS_MeshElement* anElem = (SMDS_MeshElement*) *elemItr;
10656           if (!anElem)
10657             continue;
10658           int vtkId = anElem->getVtkId();
10659           int neighborsVtkIds[NBMAXNEIGHBORS];
10660           int downIds[NBMAXNEIGHBORS];
10661           unsigned char downTypes[NBMAXNEIGHBORS];
10662           int nbNeighbors = grid->GetNeighbors(neighborsVtkIds, downIds, downTypes, vtkId);
10663           for (int n = 0; n < nbNeighbors; n++)
10664             {
10665               int smdsId = meshDS->fromVtkToSmds(neighborsVtkIds[n]);
10666               const SMDS_MeshElement* elem = meshDS->FindElement(smdsId);
10667               if (! domain.count(elem)) // neighbor is in another domain : face is shared
10668                 {
10669                   DownIdType face(downIds[n], downTypes[n]);
10670                   if (!faceDomains.count(face))
10671                     faceDomains[face] = emptyMap; // create an empty entry for face
10672                   if (!faceDomains[face].count(idom))
10673                     {
10674                       faceDomains[face][idom] = vtkId; // volume associated to face in this domain
10675                       celldom[vtkId] = idom;
10676                     }
10677                 }
10678             }
10679         }
10680     }
10681
10682   MESSAGE("Number of shared faces " << faceDomains.size());
10683   std::map<DownIdType, std::map<int, int>, DownIdCompare>::iterator itface;
10684
10685   // --- explore the shared faces domain by domain,
10686   //     explore the nodes of the face and see if they belong to a cell in the domain,
10687   //     which has only a node or an edge on the border (not a shared face)
10688
10689   for (int idomain = 0; idomain < theElems.size(); idomain++)
10690     {
10691       const TIDSortedElemSet& domain = theElems[idomain];
10692       itface = faceDomains.begin();
10693       for (; itface != faceDomains.end(); ++itface)
10694         {
10695           std::map<int, int> domvol = itface->second;
10696           if (!domvol.count(idomain))
10697             continue;
10698           DownIdType face = itface->first;
10699           //MESSAGE(" --- face " << face.cellId);
10700           std::set<int> oldNodes;
10701           oldNodes.clear();
10702           grid->GetNodeIds(oldNodes, face.cellId, face.cellType);
10703           std::set<int>::iterator itn = oldNodes.begin();
10704           for (; itn != oldNodes.end(); ++itn)
10705             {
10706               int oldId = *itn;
10707               //MESSAGE("     node " << oldId);
10708               std::set<int> cells;
10709               cells.clear();
10710               vtkCellLinks::Link l = grid->GetCellLinks()->GetLink(oldId);
10711               for (int i=0; i<l.ncells; i++)
10712                 {
10713                   int vtkId = l.cells[i];
10714                   const SMDS_MeshElement* anElem = GetMeshDS()->FindElement(GetMeshDS()->fromVtkToSmds(vtkId));
10715                   if (!domain.count(anElem))
10716                     continue;
10717                   int vtkType = grid->GetCellType(vtkId);
10718                   int downId = grid->CellIdToDownId(vtkId);
10719                   DownIdType aCell(downId, vtkType);
10720                   if (celldom.count(vtkId))
10721                     continue;
10722                   cellDomains[aCell][idomain] = vtkId;
10723                   celldom[vtkId] = idomain;
10724                 }
10725             }
10726         }
10727     }
10728
10729   // --- explore the shared faces domain by domain, to duplicate the nodes in a coherent way
10730   //     for each shared face, get the nodes
10731   //     for each node, for each domain of the face, create a clone of the node
10732
10733   for (int idomain = 0; idomain < theElems.size(); idomain++)
10734     {
10735       itface = faceDomains.begin();
10736       for (; itface != faceDomains.end(); ++itface)
10737         {
10738           std::map<int, int> domvol = itface->second;
10739           if (!domvol.count(idomain))
10740             continue;
10741           DownIdType face = itface->first;
10742           //MESSAGE(" --- face " << face.cellId);
10743           std::set<int> oldNodes;
10744           oldNodes.clear();
10745           grid->GetNodeIds(oldNodes, face.cellId, face.cellType);
10746           std::set<int>::iterator itn = oldNodes.begin();
10747           for (; itn != oldNodes.end(); ++itn)
10748             {
10749               int oldId = *itn;
10750               //MESSAGE("     node " << oldId);
10751               if (!nodeDomains.count(oldId))
10752                 nodeDomains[oldId] = emptyMap; // create an empty entry for node
10753               if (nodeDomains[oldId].empty())
10754                 nodeDomains[oldId][idomain] = oldId; // keep the old node in the first domain
10755               std::map<int, int>::iterator itdom = domvol.begin();
10756               for (; itdom != domvol.end(); ++itdom)
10757                 {
10758                   int idom = itdom->first;
10759                   //MESSAGE("         domain " << idom);
10760                   if (!nodeDomains[oldId].count(idom))
10761                     {
10762                       double *coords = grid->GetPoint(oldId);
10763                       SMDS_MeshNode *newNode = meshDS->AddNode(coords[0], coords[1], coords[2]);
10764                       int newId = newNode->getVtkId();
10765                       nodeDomains[oldId][idom] = newId; // cloned node for other domains
10766                       //MESSAGE("         newNode " << newId);
10767                     }
10768                 }
10769             }
10770         }
10771     }
10772
10773   // --- iterate on shared faces (volumes to modify, face to extrude)
10774   //     get node id's of the face (id SMDS = id VTK)
10775   //     create flat element with old and new nodes if requested
10776
10777   if (createJointElems)
10778     {
10779       itface = faceDomains.begin();
10780       for( ; itface != faceDomains.end();++itface )
10781         {
10782           DownIdType face = itface->first;
10783           std::set<int> oldNodes;
10784           std::set<int>::iterator itn;
10785           oldNodes.clear();
10786           grid->GetNodeIds(oldNodes, face.cellId, face.cellType);
10787
10788           std::map<int,int> domvol = itface->second;
10789           std::map<int,int>::iterator itdom = domvol.begin();
10790           int dom1 = itdom->first;
10791           int vtkVolId = itdom->second;
10792           itdom++;
10793           int dom2 = itdom->first;
10794           meshDS->extrudeVolumeFromFace(vtkVolId, dom1, dom2, oldNodes, nodeDomains);
10795         }
10796     }
10797
10798   // --- iterate on shared faces (volumes to modify, face to extrude)
10799   //     get node id's of the face
10800   //     replace old nodes by new nodes in volumes, and update inverse connectivity
10801
10802   MESSAGE("cellDomains " << cellDomains.size());
10803   faceDomains.insert(cellDomains.begin(), cellDomains.end());
10804   itface = faceDomains.begin();
10805   for( ; itface != faceDomains.end();++itface )
10806     {
10807       DownIdType face = itface->first;
10808       std::set<int> oldNodes;
10809       std::set<int>::iterator itn;
10810       oldNodes.clear();
10811       grid->GetNodeIds(oldNodes, face.cellId, face.cellType);
10812       std::map<int,int> localClonedNodeIds;
10813
10814       std::map<int,int> domvol = itface->second;
10815       std::map<int,int>::iterator itdom = domvol.begin();
10816       for(; itdom != domvol.end(); ++itdom)
10817         {
10818           int idom = itdom->first;
10819           int vtkVolId = itdom->second;
10820           localClonedNodeIds.clear();
10821           for (itn = oldNodes.begin(); itn != oldNodes.end(); ++itn)
10822             {
10823               int oldId = *itn;
10824               if (nodeDomains[oldId].count(idom))
10825                 localClonedNodeIds[oldId] = nodeDomains[oldId][idom];
10826             }
10827           meshDS->ModifyCellNodes(vtkVolId, localClonedNodeIds);
10828         }
10829     }
10830   grid->BuildLinks();
10831
10832   // TODO replace also old nodes by new nodes in faces and edges
10833   CHRONOSTOP(50);
10834   counters::stats();
10835   return true;
10836 }
10837
10838 //================================================================================
10839 /*!
10840  * \brief Generates skin mesh (containing 2D cells) from 3D mesh
10841  * The created 2D mesh elements based on nodes of free faces of boundary volumes
10842  * \return TRUE if operation has been completed successfully, FALSE otherwise
10843  */
10844 //================================================================================
10845
10846 bool SMESH_MeshEditor::Make2DMeshFrom3D()
10847 {
10848   // iterates on volume elements and detect all free faces on them
10849   SMESHDS_Mesh* aMesh = GetMeshDS();
10850   if (!aMesh)
10851     return false;
10852   //bool res = false;
10853   int nbFree = 0, nbExisted = 0, nbCreated = 0;
10854   SMDS_VolumeIteratorPtr vIt = aMesh->volumesIterator();
10855   while(vIt->more())
10856   {
10857     const SMDS_MeshVolume* volume = vIt->next();
10858     SMDS_VolumeTool vTool( volume );
10859     vTool.SetExternalNormal();
10860     const bool isPoly = volume->IsPoly();
10861     const bool isQuad = volume->IsQuadratic();
10862     for ( int iface = 0, n = vTool.NbFaces(); iface < n; iface++ )
10863     {
10864       if (!vTool.IsFreeFace(iface))
10865         continue;
10866       nbFree++;
10867       vector<const SMDS_MeshNode *> nodes;
10868       int nbFaceNodes = vTool.NbFaceNodes(iface);
10869       const SMDS_MeshNode** faceNodes = vTool.GetFaceNodes(iface);
10870       int inode = 0;
10871       for ( ; inode < nbFaceNodes; inode += isQuad ? 2 : 1)
10872         nodes.push_back(faceNodes[inode]);
10873       if (isQuad)
10874         for ( inode = 1; inode < nbFaceNodes; inode += 2)
10875           nodes.push_back(faceNodes[inode]);
10876
10877       // add new face based on volume nodes
10878       if (aMesh->FindFace( nodes ) ) {
10879         nbExisted++;
10880         continue; // face already exsist
10881       }
10882       AddElement(nodes, SMDSAbs_Face, isPoly && iface == 1);
10883       nbCreated++;
10884     }
10885   }
10886   return ( nbFree==(nbExisted+nbCreated) );
10887 }
10888
10889 namespace
10890 {
10891   inline const SMDS_MeshNode* getNodeWithSameID(SMESHDS_Mesh* mesh, const SMDS_MeshNode* node)
10892   {
10893     if ( const SMDS_MeshNode* n = mesh->FindNode( node->GetID() ))
10894       return n;
10895     return mesh->AddNodeWithID( node->X(),node->Y(),node->Z(), node->GetID() );
10896   }
10897 }
10898 //================================================================================
10899 /*!
10900  * \brief Creates missing boundary elements
10901  *  \param elements - elements whose boundary is to be checked
10902  *  \param dimension - defines type of boundary elements to create
10903  *  \param group - a group to store created boundary elements in
10904  *  \param targetMesh - a mesh to store created boundary elements in
10905  *  \param toCopyElements - if true, the checked elements will be copied into the targetMesh
10906  *  \param toCopyExistingBondary - if true, not only new but also pre-existing
10907  *                                boundary elements will be copied into the targetMesh
10908  *  \param toAddExistingBondary - if true, not only new but also pre-existing
10909  *                                boundary elements will be added into the new group
10910  *  \param aroundElements - if true, elements will be created on boundary of given
10911  *                          elements else, on boundary of the whole mesh. This
10912  *                          option works for 2D elements only.
10913  * \return nb of added boundary elements
10914  */
10915 //================================================================================
10916
10917 int SMESH_MeshEditor::MakeBoundaryMesh(const TIDSortedElemSet& elements,
10918                                        Bnd_Dimension           dimension,
10919                                        SMESH_Group*            group/*=0*/,
10920                                        SMESH_Mesh*             targetMesh/*=0*/,
10921                                        bool                    toCopyElements/*=false*/,
10922                                        bool                    toCopyExistingBondary/*=false*/,
10923                                        bool                    toAddExistingBondary/*= false*/,
10924                                        bool                    aroundElements/*= false*/)
10925 {
10926   SMDSAbs_ElementType missType = (dimension == BND_2DFROM3D) ? SMDSAbs_Face : SMDSAbs_Edge;
10927   SMDSAbs_ElementType elemType = (dimension == BND_1DFROM2D) ? SMDSAbs_Face : SMDSAbs_Volume;
10928   // hope that all elements are of the same type, do not check them all
10929   if ( !elements.empty() && (*elements.begin())->GetType() != elemType )
10930     throw SALOME_Exception(LOCALIZED("wrong element type"));
10931
10932   if ( aroundElements && elemType == SMDSAbs_Volume )
10933     throw SALOME_Exception(LOCALIZED("wrong element type for aroundElements==true"));
10934
10935   if ( !targetMesh )
10936     toCopyElements = toCopyExistingBondary = false;
10937
10938   SMESH_MeshEditor tgtEditor( targetMesh ? targetMesh : myMesh );
10939   SMESHDS_Mesh* aMesh = GetMeshDS(), *tgtMeshDS = tgtEditor.GetMeshDS();
10940   int nbAddedBnd = 0;
10941
10942   // editor adding present bnd elements and optionally holding elements to add to the group
10943   SMESH_MeshEditor* presentEditor;
10944   SMESH_MeshEditor tgtEditor2( tgtEditor.GetMesh() );
10945   presentEditor = toAddExistingBondary ? &tgtEditor : &tgtEditor2;
10946
10947   SMDS_VolumeTool vTool;
10948   TIDSortedElemSet avoidSet;
10949   const TIDSortedElemSet emptySet, *elemSet = aroundElements ? &elements : &emptySet;
10950   int inode;
10951
10952   typedef vector<const SMDS_MeshNode*> TConnectivity;
10953
10954   SMDS_ElemIteratorPtr eIt;
10955   if (elements.empty())
10956     eIt = aMesh->elementsIterator(elemType);
10957   else
10958     eIt = SMDS_ElemIteratorPtr( new TSetIterator( elements.begin(), elements.end() ));
10959
10960   while (eIt->more())
10961   {
10962     const SMDS_MeshElement* elem = eIt->next();
10963     const int iQuad = elem->IsQuadratic();
10964
10965     // ------------------------------------------------------------------------------------
10966     // 1. For an elem, get present bnd elements and connectivities of missing bnd elements
10967     // ------------------------------------------------------------------------------------
10968     vector<const SMDS_MeshElement*> presentBndElems;
10969     vector<TConnectivity>           missingBndElems;
10970     TConnectivity nodes;
10971     if ( vTool.Set(elem) ) // elem is a volume ------------------------------------------
10972     {
10973       vTool.SetExternalNormal();
10974       for ( int iface = 0, n = vTool.NbFaces(); iface < n; iface++ )
10975       {
10976         if (!vTool.IsFreeFace(iface))
10977           continue;
10978         int nbFaceNodes = vTool.NbFaceNodes(iface);
10979         const SMDS_MeshNode** nn = vTool.GetFaceNodes(iface);
10980         if ( missType == SMDSAbs_Edge ) // boundary edges
10981         {
10982           nodes.resize( 2+iQuad );
10983           for ( int i = 0; i < nbFaceNodes; i += 1+iQuad)
10984           {
10985             for ( int j = 0; j < nodes.size(); ++j )
10986               nodes[j] =nn[i+j];
10987             if ( const SMDS_MeshElement* edge =
10988                  aMesh->FindElement(nodes,SMDSAbs_Edge,/*noMedium=*/0))
10989               presentBndElems.push_back( edge );
10990             else
10991               missingBndElems.push_back( nodes );
10992           }
10993         }
10994         else // boundary face
10995         {
10996           nodes.clear();
10997           for ( inode = 0; inode < nbFaceNodes; inode += 1+iQuad)
10998             nodes.push_back( nn[inode] );
10999           if (iQuad)
11000             for ( inode = 1; inode < nbFaceNodes; inode += 2)
11001               nodes.push_back( nn[inode] );
11002
11003           if (const SMDS_MeshFace * f = aMesh->FindFace( nodes ) )
11004             presentBndElems.push_back( f );
11005           else
11006             missingBndElems.push_back( nodes );
11007         }
11008       }
11009     }
11010     else                     // elem is a face ------------------------------------------
11011     {
11012       avoidSet.clear(), avoidSet.insert( elem );
11013       int nbNodes = elem->NbCornerNodes();
11014       nodes.resize( 2 /*+ iQuad*/);
11015       for ( int i = 0; i < nbNodes; i++ )
11016       {
11017         nodes[0] = elem->GetNode(i);
11018         nodes[1] = elem->GetNode((i+1)%nbNodes);
11019         if ( FindFaceInSet( nodes[0], nodes[1], *elemSet, avoidSet))
11020           continue; // not free link
11021
11022         //if ( iQuad )
11023         //nodes[2] = elem->GetNode( i + nbNodes );
11024         if ( const SMDS_MeshElement* edge =
11025              aMesh->FindElement(nodes,SMDSAbs_Edge,/*noMedium=*/true))
11026           presentBndElems.push_back( edge );
11027         else
11028           missingBndElems.push_back( nodes );
11029       }
11030     }
11031
11032     // ---------------------------------
11033     // 2. Add missing boundary elements
11034     // ---------------------------------
11035     if ( targetMesh != myMesh )
11036       // instead of making a map of nodes in this mesh and targetMesh,
11037       // we create nodes with same IDs. We can renumber them later, if needed
11038       for ( int i = 0; i < missingBndElems.size(); ++i )
11039       {
11040         TConnectivity& srcNodes = missingBndElems[i];
11041         TConnectivity  nodes( srcNodes.size() );
11042         for ( inode = 0; inode < nodes.size(); ++inode )
11043           nodes[inode] = getNodeWithSameID( tgtMeshDS, srcNodes[inode] );
11044         if ( aroundElements && tgtEditor.GetMeshDS()->FindElement( nodes,
11045                                                                    missType,
11046                                                                    /*noMedium=*/true))
11047           continue;
11048         tgtEditor.AddElement(nodes, missType, elem->IsPoly() && nodes.size()/(iQuad+1)>4);
11049         ++nbAddedBnd;
11050       }
11051     else
11052       for ( int i = 0; i < missingBndElems.size(); ++i )
11053       {
11054         TConnectivity& nodes = missingBndElems[i];
11055         if ( aroundElements && tgtEditor.GetMeshDS()->FindElement( nodes,
11056                                                                    missType,
11057                                                                    /*noMedium=*/true))
11058           continue;
11059         tgtEditor.AddElement(nodes, missType, elem->IsPoly() && nodes.size()/(iQuad+1)>4);
11060         ++nbAddedBnd;
11061       }
11062
11063     // ----------------------------------
11064     // 3. Copy present boundary elements
11065     // ----------------------------------
11066     if ( toCopyExistingBondary )
11067       for ( int i = 0 ; i < presentBndElems.size(); ++i )
11068       {
11069         const SMDS_MeshElement* e = presentBndElems[i];
11070         TConnectivity nodes( e->NbNodes() );
11071         for ( inode = 0; inode < nodes.size(); ++inode )
11072           nodes[inode] = getNodeWithSameID( tgtMeshDS, e->GetNode(inode) );
11073         presentEditor->AddElement(nodes, missType, e->IsPoly());
11074       }
11075     else // store present elements to add them to a group
11076       for ( int i = 0 ; i < presentBndElems.size(); ++i )
11077       {
11078         presentEditor->myLastCreatedElems.Append(presentBndElems[i]);
11079       }
11080       
11081   } // loop on given elements
11082
11083   // ---------------------------------------------
11084   // 4. Fill group with boundary elements
11085   // ---------------------------------------------
11086   if ( group )
11087   {
11088     if ( SMESHDS_Group* g = dynamic_cast<SMESHDS_Group*>( group->GetGroupDS() ))
11089       for ( int i = 0; i < tgtEditor.myLastCreatedElems.Size(); ++i )
11090         g->SMDSGroup().Add( tgtEditor.myLastCreatedElems( i+1 ));
11091   }
11092   tgtEditor.myLastCreatedElems.Clear();
11093   tgtEditor2.myLastCreatedElems.Clear();
11094
11095   // -----------------------
11096   // 5. Copy given elements
11097   // -----------------------
11098   if ( toCopyElements && targetMesh != myMesh )
11099   {
11100     if (elements.empty())
11101       eIt = aMesh->elementsIterator(elemType);
11102     else
11103       eIt = SMDS_ElemIteratorPtr( new TSetIterator( elements.begin(), elements.end() ));
11104     while (eIt->more())
11105     {
11106       const SMDS_MeshElement* elem = eIt->next();
11107       TConnectivity nodes( elem->NbNodes() );
11108       for ( inode = 0; inode < nodes.size(); ++inode )
11109         nodes[inode] = getNodeWithSameID( tgtMeshDS, elem->GetNode(inode) );
11110       tgtEditor.AddElement(nodes, elemType, elem->IsPoly());
11111
11112       tgtEditor.myLastCreatedElems.Clear();
11113     }
11114   }
11115   return nbAddedBnd;
11116 }