Salome HOME
Regression of SMESH_TEST/Grids/smesh/mesh_Quadratic/A6
[modules/smesh.git] / src / SMESH / SMESH_MeshEditor.cxx
1 // Copyright (C) 2007-2012  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 #include "SMESH_MeshEditor.hxx"
29
30 #include "SMDS_FaceOfNodes.hxx"
31 #include "SMDS_VolumeTool.hxx"
32 #include "SMDS_EdgePosition.hxx"
33 #include "SMDS_FacePosition.hxx"
34 #include "SMDS_SpacePosition.hxx"
35 #include "SMDS_MeshGroup.hxx"
36 #include "SMDS_LinearEdge.hxx"
37 #include "SMDS_Downward.hxx"
38 #include "SMDS_SetIterator.hxx"
39
40 #include "SMESHDS_Group.hxx"
41 #include "SMESHDS_Mesh.hxx"
42
43 #include "SMESH_Algo.hxx"
44 #include "SMESH_ControlsDef.hxx"
45 #include "SMESH_Group.hxx"
46 #include "SMESH_MesherHelper.hxx"
47 #include "SMESH_OctreeNode.hxx"
48 #include "SMESH_subMesh.hxx"
49
50 #include <Basics_OCCTVersion.hxx>
51
52 #include "utilities.h"
53
54 #include <BRepAdaptor_Surface.hxx>
55 #include <BRepBuilderAPI_MakeEdge.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 <cmath>
92
93 #include <map>
94 #include <set>
95 #include <numeric>
96 #include <limits>
97 #include <algorithm>
98 #include <sstream>
99
100 #define cast2Node(elem) static_cast<const SMDS_MeshNode*>( elem )
101
102 using namespace std;
103 using namespace SMESH::Controls;
104
105 typedef map<const SMDS_MeshElement*, list<const SMDS_MeshNode*> >    TElemOfNodeListMap;
106 typedef map<const SMDS_MeshElement*, list<const SMDS_MeshElement*> > TElemOfElemListMap;
107
108 typedef SMDS_SetIterator< SMDS_pElement, TIDSortedElemSet::const_iterator> TSetIterator;
109
110 //=======================================================================
111 //function : SMESH_MeshEditor
112 //purpose  :
113 //=======================================================================
114
115 SMESH_MeshEditor::SMESH_MeshEditor( SMESH_Mesh* theMesh )
116   :myMesh( theMesh ) // theMesh may be NULL
117 {
118 }
119
120 //=======================================================================
121 /*!
122  * \brief Add element
123  */
124 //=======================================================================
125
126 SMDS_MeshElement*
127 SMESH_MeshEditor::AddElement(const vector<const SMDS_MeshNode*> & node,
128                              const SMDSAbs_ElementType            type,
129                              const bool                           isPoly,
130                              const int                            ID)
131 {
132   //MESSAGE("AddElement " <<node.size() << " " << type << " " << isPoly << " " << ID);
133   SMDS_MeshElement* e = 0;
134   int nbnode = node.size();
135   SMESHDS_Mesh* mesh = GetMeshDS();
136   switch ( type ) {
137   case SMDSAbs_Face:
138     if ( !isPoly ) {
139       if      (nbnode == 3) {
140         if ( ID >= 1 ) e = mesh->AddFaceWithID(node[0], node[1], node[2], ID);
141         else           e = mesh->AddFace      (node[0], node[1], node[2] );
142       }
143       else if (nbnode == 4) {
144         if ( ID >= 1 ) e = mesh->AddFaceWithID(node[0], node[1], node[2], node[3], ID);
145         else           e = mesh->AddFace      (node[0], node[1], node[2], node[3] );
146       }
147       else if (nbnode == 6) {
148         if ( ID >= 1 ) e = mesh->AddFaceWithID(node[0], node[1], node[2], node[3],
149                                                node[4], node[5], ID);
150         else           e = mesh->AddFace      (node[0], node[1], node[2], node[3],
151                                                node[4], node[5] );
152       }
153       else if (nbnode == 8) {
154         if ( ID >= 1 ) e = mesh->AddFaceWithID(node[0], node[1], node[2], node[3],
155                                                node[4], node[5], node[6], node[7], ID);
156         else           e = mesh->AddFace      (node[0], node[1], node[2], node[3],
157                                                node[4], node[5], node[6], node[7] );
158       }
159       else if (nbnode == 9) {
160         if ( ID >= 1 ) e = mesh->AddFaceWithID(node[0], node[1], node[2], node[3],
161                                                node[4], node[5], node[6], node[7], node[8], ID);
162         else           e = mesh->AddFace      (node[0], node[1], node[2], node[3],
163                                                node[4], node[5], node[6], node[7], node[8] );
164       }
165     } else {
166       if ( ID >= 1 ) e = mesh->AddPolygonalFaceWithID(node, ID);
167       else           e = mesh->AddPolygonalFace      (node    );
168     }
169     break;
170
171   case SMDSAbs_Volume:
172     if ( !isPoly ) {
173       if      (nbnode == 4) {
174         if ( ID >= 1 ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3], ID);
175         else           e = mesh->AddVolume      (node[0], node[1], node[2], node[3] );
176       }
177       else if (nbnode == 5) {
178         if ( ID >= 1 ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
179                                                  node[4], ID);
180         else           e = mesh->AddVolume      (node[0], node[1], node[2], node[3],
181                                                  node[4] );
182       }
183       else if (nbnode == 6) {
184         if ( ID >= 1 ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
185                                                  node[4], node[5], ID);
186         else           e = mesh->AddVolume      (node[0], node[1], node[2], node[3],
187                                                  node[4], node[5] );
188       }
189       else if (nbnode == 8) {
190         if ( ID >= 1 ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
191                                                  node[4], node[5], node[6], node[7], ID);
192         else           e = mesh->AddVolume      (node[0], node[1], node[2], node[3],
193                                                  node[4], node[5], node[6], node[7] );
194       }
195       else if (nbnode == 10) {
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], ID);
199         else           e = mesh->AddVolume      (node[0], node[1], node[2], node[3],
200                                                  node[4], node[5], node[6], node[7],
201                                                  node[8], node[9] );
202       }
203       else if (nbnode == 12) {
204         if ( ID >= 1 ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
205                                                  node[4], node[5], node[6], node[7],
206                                                  node[8], node[9], node[10], node[11], ID);
207         else           e = mesh->AddVolume      (node[0], node[1], node[2], node[3],
208                                                  node[4], node[5], node[6], node[7],
209                                                  node[8], node[9], node[10], node[11] );
210       }
211       else if (nbnode == 13) {
212         if ( ID >= 1 ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
213                                                  node[4], node[5], node[6], node[7],
214                                                  node[8], node[9], node[10],node[11],
215                                                  node[12],ID);
216         else           e = mesh->AddVolume      (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] );
220       }
221       else if (nbnode == 15) {
222         if ( ID >= 1 ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
223                                                  node[4], node[5], node[6], node[7],
224                                                  node[8], node[9], node[10],node[11],
225                                                  node[12],node[13],node[14],ID);
226         else           e = mesh->AddVolume      (node[0], node[1], node[2], node[3],
227                                                  node[4], node[5], node[6], node[7],
228                                                  node[8], node[9], node[10],node[11],
229                                                  node[12],node[13],node[14] );
230       }
231       else if (nbnode == 20) {
232         if ( ID >= 1 ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
233                                                  node[4], node[5], node[6], node[7],
234                                                  node[8], node[9], node[10],node[11],
235                                                  node[12],node[13],node[14],node[15],
236                                                  node[16],node[17],node[18],node[19],ID);
237         else           e = mesh->AddVolume      (node[0], node[1], node[2], node[3],
238                                                  node[4], node[5], node[6], node[7],
239                                                  node[8], node[9], node[10],node[11],
240                                                  node[12],node[13],node[14],node[15],
241                                                  node[16],node[17],node[18],node[19] );
242       }
243       else if (nbnode == 27) {
244         if ( ID >= 1 ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
245                                                  node[4], node[5], node[6], node[7],
246                                                  node[8], node[9], node[10],node[11],
247                                                  node[12],node[13],node[14],node[15],
248                                                  node[16],node[17],node[18],node[19],
249                                                  node[20],node[21],node[22],node[23],
250                                                  node[24],node[25],node[26], ID);
251         else           e = mesh->AddVolume      (node[0], node[1], node[2], node[3],
252                                                  node[4], node[5], node[6], node[7],
253                                                  node[8], node[9], node[10],node[11],
254                                                  node[12],node[13],node[14],node[15],
255                                                  node[16],node[17],node[18],node[19],
256                                                  node[20],node[21],node[22],node[23],
257                                                  node[24],node[25],node[26] );
258       }
259     }
260     break;
261
262   case SMDSAbs_Edge:
263     if ( nbnode == 2 ) {
264       if ( ID >= 1 ) e = mesh->AddEdgeWithID(node[0], node[1], ID);
265       else           e = mesh->AddEdge      (node[0], node[1] );
266     }
267     else if ( nbnode == 3 ) {
268       if ( ID >= 1 ) e = mesh->AddEdgeWithID(node[0], node[1], node[2], ID);
269       else           e = mesh->AddEdge      (node[0], node[1], node[2] );
270     }
271     break;
272
273   case SMDSAbs_0DElement:
274     if ( nbnode == 1 ) {
275       if ( ID >= 1 ) e = mesh->Add0DElementWithID(node[0], ID);
276       else           e = mesh->Add0DElement      (node[0] );
277     }
278     break;
279
280   case SMDSAbs_Node:
281     if ( ID >= 1 ) e = mesh->AddNodeWithID(node[0]->X(), node[0]->Y(), node[0]->Z(), ID);
282     else           e = mesh->AddNode      (node[0]->X(), node[0]->Y(), node[0]->Z());
283     break;
284
285   default:;
286   }
287   if ( e ) myLastCreatedElems.Append( e );
288   return e;
289 }
290
291 //=======================================================================
292 /*!
293  * \brief Add element
294  */
295 //=======================================================================
296
297 SMDS_MeshElement* SMESH_MeshEditor::AddElement(const vector<int> &       nodeIDs,
298                                                const SMDSAbs_ElementType type,
299                                                const bool                isPoly,
300                                                const int                 ID)
301 {
302   vector<const SMDS_MeshNode*> nodes;
303   nodes.reserve( nodeIDs.size() );
304   vector<int>::const_iterator id = nodeIDs.begin();
305   while ( id != nodeIDs.end() ) {
306     if ( const SMDS_MeshNode* node = GetMeshDS()->FindNode( *id++ ))
307       nodes.push_back( node );
308     else
309       return 0;
310   }
311   return AddElement( nodes, type, isPoly, ID );
312 }
313
314 //=======================================================================
315 //function : Remove
316 //purpose  : Remove a node or an element.
317 //           Modify a compute state of sub-meshes which become empty
318 //=======================================================================
319
320 int SMESH_MeshEditor::Remove (const list< int >& theIDs,
321                               const bool         isNodes )
322 {
323   myLastCreatedElems.Clear();
324   myLastCreatedNodes.Clear();
325
326   SMESHDS_Mesh* aMesh = GetMeshDS();
327   set< SMESH_subMesh *> smmap;
328
329   int removed = 0;
330   list<int>::const_iterator it = theIDs.begin();
331   for ( ; it != theIDs.end(); it++ ) {
332     const SMDS_MeshElement * elem;
333     if ( isNodes )
334       elem = aMesh->FindNode( *it );
335     else
336       elem = aMesh->FindElement( *it );
337     if ( !elem )
338       continue;
339
340     // Notify VERTEX sub-meshes about modification
341     if ( isNodes ) {
342       const SMDS_MeshNode* node = cast2Node( elem );
343       if ( node->GetPosition()->GetTypeOfPosition() == SMDS_TOP_VERTEX )
344         if ( int aShapeID = node->getshapeId() )
345           if ( SMESH_subMesh * sm = GetMesh()->GetSubMeshContaining( aShapeID ) )
346             smmap.insert( sm );
347     }
348     // Find sub-meshes to notify about modification
349     //     SMDS_ElemIteratorPtr nodeIt = elem->nodesIterator();
350     //     while ( nodeIt->more() ) {
351     //       const SMDS_MeshNode* node = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
352     //       const SMDS_PositionPtr& aPosition = node->GetPosition();
353     //       if ( aPosition.get() ) {
354     //         if ( int aShapeID = aPosition->GetShapeId() ) {
355     //           if ( SMESH_subMesh * sm = GetMesh()->GetSubMeshContaining( aShapeID ) )
356     //             smmap.insert( sm );
357     //         }
358     //       }
359     //     }
360
361     // Do remove
362     if ( isNodes )
363       aMesh->RemoveNode( static_cast< const SMDS_MeshNode* >( elem ));
364     else
365       aMesh->RemoveElement( elem );
366     removed++;
367   }
368
369   // Notify sub-meshes about modification
370   if ( !smmap.empty() ) {
371     set< SMESH_subMesh *>::iterator smIt;
372     for ( smIt = smmap.begin(); smIt != smmap.end(); smIt++ )
373       (*smIt)->ComputeStateEngine( SMESH_subMesh::MESH_ENTITY_REMOVED );
374   }
375
376   //   // Check if the whole mesh becomes empty
377   //   if ( SMESH_subMesh * sm = GetMesh()->GetSubMeshContaining( 1 ) )
378   //     sm->ComputeStateEngine( SMESH_subMesh::CHECK_COMPUTE_STATE );
379
380   return removed;
381 }
382
383 //=======================================================================
384 //function : FindShape
385 //purpose  : Return an index of the shape theElem is on
386 //           or zero if a shape not found
387 //=======================================================================
388
389 int SMESH_MeshEditor::FindShape (const SMDS_MeshElement * theElem)
390 {
391   myLastCreatedElems.Clear();
392   myLastCreatedNodes.Clear();
393
394   SMESHDS_Mesh * aMesh = GetMeshDS();
395   if ( aMesh->ShapeToMesh().IsNull() )
396     return 0;
397
398   int aShapeID = theElem->getshapeId();
399   if ( aShapeID < 1 )
400     return 0;
401
402   if ( SMESHDS_SubMesh * sm = aMesh->MeshElements( aShapeID ))
403     if ( sm->Contains( theElem ))
404       return aShapeID;
405
406   if ( theElem->GetType() == SMDSAbs_Node ) {
407     MESSAGE( ":( Error: invalid myShapeId of node " << theElem->GetID() );
408   }
409   else {
410     MESSAGE( ":( Error: invalid myShapeId of element " << theElem->GetID() );
411   }
412
413   TopoDS_Shape aShape; // the shape a node of theElem is on
414   if ( theElem->GetType() != SMDSAbs_Node )
415   {
416     SMDS_ElemIteratorPtr nodeIt = theElem->nodesIterator();
417     while ( nodeIt->more() ) {
418       const SMDS_MeshNode* node = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
419       if ((aShapeID = node->getshapeId()) > 0) {
420         if ( SMESHDS_SubMesh * sm = aMesh->MeshElements( aShapeID ) ) {
421           if ( sm->Contains( theElem ))
422             return aShapeID;
423           if ( aShape.IsNull() )
424             aShape = aMesh->IndexToShape( aShapeID );
425         }
426       }
427     }
428   }
429
430   // None of nodes is on a proper shape,
431   // find the shape among ancestors of aShape on which a node is
432   if ( !aShape.IsNull() ) {
433     TopTools_ListIteratorOfListOfShape ancIt( GetMesh()->GetAncestors( aShape ));
434     for ( ; ancIt.More(); ancIt.Next() ) {
435       SMESHDS_SubMesh * sm = aMesh->MeshElements( ancIt.Value() );
436       if ( sm && sm->Contains( theElem ))
437         return aMesh->ShapeToIndex( ancIt.Value() );
438     }
439   }
440   else
441   {
442     const map<int,SMESHDS_SubMesh*>& id2sm = GetMeshDS()->SubMeshes();
443     map<int,SMESHDS_SubMesh*>::const_iterator id_sm = id2sm.begin();
444     for ( ; id_sm != id2sm.end(); ++id_sm )
445       if ( id_sm->second->Contains( theElem ))
446         return id_sm->first;
447   }
448
449   //MESSAGE ("::FindShape() - SHAPE NOT FOUND")
450   return 0;
451 }
452
453 //=======================================================================
454 //function : IsMedium
455 //purpose  :
456 //=======================================================================
457
458 bool SMESH_MeshEditor::IsMedium(const SMDS_MeshNode*      node,
459                                 const SMDSAbs_ElementType typeToCheck)
460 {
461   bool isMedium = false;
462   SMDS_ElemIteratorPtr it = node->GetInverseElementIterator(typeToCheck);
463   while (it->more() && !isMedium ) {
464     const SMDS_MeshElement* elem = it->next();
465     isMedium = elem->IsMediumNode(node);
466   }
467   return isMedium;
468 }
469
470 //=======================================================================
471 //function : ShiftNodesQuadTria
472 //purpose  : auxilary
473 //           Shift nodes in the array corresponded to quadratic triangle
474 //           example: (0,1,2,3,4,5) -> (1,2,0,4,5,3)
475 //=======================================================================
476 static void ShiftNodesQuadTria(const SMDS_MeshNode* aNodes[])
477 {
478   const SMDS_MeshNode* nd1 = aNodes[0];
479   aNodes[0] = aNodes[1];
480   aNodes[1] = aNodes[2];
481   aNodes[2] = nd1;
482   const SMDS_MeshNode* nd2 = aNodes[3];
483   aNodes[3] = aNodes[4];
484   aNodes[4] = aNodes[5];
485   aNodes[5] = nd2;
486 }
487
488 //=======================================================================
489 //function : edgeConnectivity
490 //purpose  : auxilary 
491 //           return number of the edges connected with the theNode.
492 //           if theEdges has connections with the other type of the
493 //           elements, return -1 
494 //=======================================================================
495 static int nbEdgeConnectivity(const SMDS_MeshNode* theNode)
496 {
497   SMDS_ElemIteratorPtr elemIt = theNode->GetInverseElementIterator();
498   int nb=0;
499   while(elemIt->more()) {
500     elemIt->next();
501     nb++;
502   }
503   return nb;
504 }
505
506
507 //=======================================================================
508 //function : GetNodesFromTwoTria
509 //purpose  : auxilary
510 //           Shift nodes in the array corresponded to quadratic triangle
511 //           example: (0,1,2,3,4,5) -> (1,2,0,4,5,3)
512 //=======================================================================
513 static bool GetNodesFromTwoTria(const SMDS_MeshElement * theTria1,
514                                 const SMDS_MeshElement * theTria2,
515                                 const SMDS_MeshNode* N1[],
516                                 const SMDS_MeshNode* N2[])
517 {
518   SMDS_ElemIteratorPtr it = theTria1->nodesIterator();
519   int i=0;
520   while(i<6) {
521     N1[i] = static_cast<const SMDS_MeshNode*>( it->next() );
522     i++;
523   }
524   if(it->more()) return false;
525   it = theTria2->nodesIterator();
526   i=0;
527   while(i<6) {
528     N2[i] = static_cast<const SMDS_MeshNode*>( it->next() );
529     i++;
530   }
531   if(it->more()) return false;
532
533   int sames[3] = {-1,-1,-1};
534   int nbsames = 0;
535   int j;
536   for(i=0; i<3; i++) {
537     for(j=0; j<3; j++) {
538       if(N1[i]==N2[j]) {
539         sames[i] = j;
540         nbsames++;
541         break;
542       }
543     }
544   }
545   if(nbsames!=2) return false;
546   if(sames[0]>-1) {
547     ShiftNodesQuadTria(N1);
548     if(sames[1]>-1) {
549       ShiftNodesQuadTria(N1);
550     }
551   }
552   i = sames[0] + sames[1] + sames[2];
553   for(; i<2; i++) {
554     ShiftNodesQuadTria(N2);
555   }
556   // now we receive following N1 and N2 (using numeration as above image)
557   // tria1 : (1 2 4 5 9 7)  and  tria2 : (3 4 2 8 9 6)
558   // i.e. first nodes from both arrays determ new diagonal
559   return true;
560 }
561
562 //=======================================================================
563 //function : InverseDiag
564 //purpose  : Replace two neighbour triangles with ones built on the same 4 nodes
565 //           but having other common link.
566 //           Return False if args are improper
567 //=======================================================================
568
569 bool SMESH_MeshEditor::InverseDiag (const SMDS_MeshElement * theTria1,
570                                     const SMDS_MeshElement * theTria2 )
571 {
572   MESSAGE("InverseDiag");
573   myLastCreatedElems.Clear();
574   myLastCreatedNodes.Clear();
575
576   if (!theTria1 || !theTria2)
577     return false;
578
579   const SMDS_VtkFace* F1 = dynamic_cast<const SMDS_VtkFace*>( theTria1 );
580   if (!F1) return false;
581   const SMDS_VtkFace* F2 = dynamic_cast<const SMDS_VtkFace*>( theTria2 );
582   if (!F2) return false;
583   if ((theTria1->GetEntityType() == SMDSEntity_Triangle) &&
584       (theTria2->GetEntityType() == SMDSEntity_Triangle)) {
585
586     //  1 +--+ A  theTria1: ( 1 A B ) A->2 ( 1 2 B ) 1 +--+ A
587     //    | /|    theTria2: ( B A 2 ) B->1 ( 1 A 2 )   |\ |
588     //    |/ |                                         | \|
589     //  B +--+ 2                                     B +--+ 2
590
591     // put nodes in array and find out indices of the same ones
592     const SMDS_MeshNode* aNodes [6];
593     int sameInd [] = { 0, 0, 0, 0, 0, 0 };
594     int i = 0;
595     SMDS_ElemIteratorPtr it = theTria1->nodesIterator();
596     while ( it->more() ) {
597       aNodes[ i ] = static_cast<const SMDS_MeshNode*>( it->next() );
598
599       if ( i > 2 ) // theTria2
600         // find same node of theTria1
601         for ( int j = 0; j < 3; j++ )
602           if ( aNodes[ i ] == aNodes[ j ]) {
603             sameInd[ j ] = i;
604             sameInd[ i ] = j;
605             break;
606           }
607       // next
608       i++;
609       if ( i == 3 ) {
610         if ( it->more() )
611           return false; // theTria1 is not a triangle
612         it = theTria2->nodesIterator();
613       }
614       if ( i == 6 && it->more() )
615         return false; // theTria2 is not a triangle
616     }
617
618     // find indices of 1,2 and of A,B in theTria1
619     int iA = 0, iB = 0, i1 = 0, i2 = 0;
620     for ( i = 0; i < 6; i++ ) {
621       if ( sameInd [ i ] == 0 ) {
622         if ( i < 3 ) i1 = i;
623         else         i2 = i;
624       }
625       else if (i < 3) {
626         if ( iA ) iB = i;
627         else      iA = i;
628       }
629     }
630     // nodes 1 and 2 should not be the same
631     if ( aNodes[ i1 ] == aNodes[ i2 ] )
632       return false;
633
634     // theTria1: A->2
635     aNodes[ iA ] = aNodes[ i2 ];
636     // theTria2: B->1
637     aNodes[ sameInd[ iB ]] = aNodes[ i1 ];
638
639     GetMeshDS()->ChangeElementNodes( theTria1, aNodes, 3 );
640     GetMeshDS()->ChangeElementNodes( theTria2, &aNodes[ 3 ], 3 );
641
642     return true;
643
644   } // end if(F1 && F2)
645
646   // check case of quadratic faces
647   if (theTria1->GetEntityType() != SMDSEntity_Quad_Triangle)
648     return false;
649   if (theTria2->GetEntityType() != SMDSEntity_Quad_Triangle)
650     return false;
651
652   //       5
653   //  1 +--+--+ 2  theTria1: (1 2 4 5 9 7) or (2 4 1 9 7 5) or (4 1 2 7 5 9)
654   //    |    /|    theTria2: (2 3 4 6 8 9) or (3 4 2 8 9 6) or (4 2 3 9 6 8)
655   //    |   / |
656   //  7 +  +  + 6
657   //    | /9  |
658   //    |/    |
659   //  4 +--+--+ 3
660   //       8
661
662   const SMDS_MeshNode* N1 [6];
663   const SMDS_MeshNode* N2 [6];
664   if(!GetNodesFromTwoTria(theTria1,theTria2,N1,N2))
665     return false;
666   // now we receive following N1 and N2 (using numeration as above image)
667   // tria1 : (1 2 4 5 9 7)  and  tria2 : (3 4 2 8 9 6)
668   // i.e. first nodes from both arrays determ new diagonal
669
670   const SMDS_MeshNode* N1new [6];
671   const SMDS_MeshNode* N2new [6];
672   N1new[0] = N1[0];
673   N1new[1] = N2[0];
674   N1new[2] = N2[1];
675   N1new[3] = N1[4];
676   N1new[4] = N2[3];
677   N1new[5] = N1[5];
678   N2new[0] = N1[0];
679   N2new[1] = N1[1];
680   N2new[2] = N2[0];
681   N2new[3] = N1[3];
682   N2new[4] = N2[5];
683   N2new[5] = N1[4];
684   // replaces nodes in faces
685   GetMeshDS()->ChangeElementNodes( theTria1, N1new, 6 );
686   GetMeshDS()->ChangeElementNodes( theTria2, N2new, 6 );
687
688   return true;
689 }
690
691 //=======================================================================
692 //function : findTriangles
693 //purpose  : find triangles sharing theNode1-theNode2 link
694 //=======================================================================
695
696 static bool findTriangles(const SMDS_MeshNode *    theNode1,
697                           const SMDS_MeshNode *    theNode2,
698                           const SMDS_MeshElement*& theTria1,
699                           const SMDS_MeshElement*& theTria2)
700 {
701   if ( !theNode1 || !theNode2 ) return false;
702
703   theTria1 = theTria2 = 0;
704
705   set< const SMDS_MeshElement* > emap;
706   SMDS_ElemIteratorPtr it = theNode1->GetInverseElementIterator(SMDSAbs_Face);
707   while (it->more()) {
708     const SMDS_MeshElement* elem = it->next();
709     if ( elem->NbNodes() == 3 )
710       emap.insert( elem );
711   }
712   it = theNode2->GetInverseElementIterator(SMDSAbs_Face);
713   while (it->more()) {
714     const SMDS_MeshElement* elem = it->next();
715     if ( emap.find( elem ) != emap.end() ) {
716       if ( theTria1 ) {
717         // theTria1 must be element with minimum ID
718         if( theTria1->GetID() < elem->GetID() ) {
719           theTria2 = elem;
720         }
721         else {
722           theTria2 = theTria1;
723           theTria1 = elem;
724         }
725         break;
726       }
727       else {
728         theTria1 = elem;
729       }
730     }
731   }
732   return ( theTria1 && theTria2 );
733 }
734
735 //=======================================================================
736 //function : InverseDiag
737 //purpose  : Replace two neighbour triangles sharing theNode1-theNode2 link
738 //           with ones built on the same 4 nodes but having other common link.
739 //           Return false if proper faces not found
740 //=======================================================================
741
742 bool SMESH_MeshEditor::InverseDiag (const SMDS_MeshNode * theNode1,
743                                     const SMDS_MeshNode * theNode2)
744 {
745   myLastCreatedElems.Clear();
746   myLastCreatedNodes.Clear();
747
748   MESSAGE( "::InverseDiag()" );
749
750   const SMDS_MeshElement *tr1, *tr2;
751   if ( !findTriangles( theNode1, theNode2, tr1, tr2 ))
752     return false;
753
754   const SMDS_VtkFace* F1 = dynamic_cast<const SMDS_VtkFace*>( tr1 );
755   if (!F1) return false;
756   const SMDS_VtkFace* F2 = dynamic_cast<const SMDS_VtkFace*>( tr2 );
757   if (!F2) return false;
758   if ((tr1->GetEntityType() == SMDSEntity_Triangle) &&
759       (tr2->GetEntityType() == SMDSEntity_Triangle)) {
760
761     //  1 +--+ A  tr1: ( 1 A B ) A->2 ( 1 2 B ) 1 +--+ A
762     //    | /|    tr2: ( B A 2 ) B->1 ( 1 A 2 )   |\ |
763     //    |/ |                                    | \|
764     //  B +--+ 2                                B +--+ 2
765
766     // put nodes in array
767     // and find indices of 1,2 and of A in tr1 and of B in tr2
768     int i, iA1 = 0, i1 = 0;
769     const SMDS_MeshNode* aNodes1 [3];
770     SMDS_ElemIteratorPtr it;
771     for (i = 0, it = tr1->nodesIterator(); it->more(); i++ ) {
772       aNodes1[ i ] = static_cast<const SMDS_MeshNode*>( it->next() );
773       if ( aNodes1[ i ] == theNode1 )
774         iA1 = i; // node A in tr1
775       else if ( aNodes1[ i ] != theNode2 )
776         i1 = i;  // node 1
777     }
778     int iB2 = 0, i2 = 0;
779     const SMDS_MeshNode* aNodes2 [3];
780     for (i = 0, it = tr2->nodesIterator(); it->more(); i++ ) {
781       aNodes2[ i ] = static_cast<const SMDS_MeshNode*>( it->next() );
782       if ( aNodes2[ i ] == theNode2 )
783         iB2 = i; // node B in tr2
784       else if ( aNodes2[ i ] != theNode1 )
785         i2 = i;  // node 2
786     }
787
788     // nodes 1 and 2 should not be the same
789     if ( aNodes1[ i1 ] == aNodes2[ i2 ] )
790       return false;
791
792     // tr1: A->2
793     aNodes1[ iA1 ] = aNodes2[ i2 ];
794     // tr2: B->1
795     aNodes2[ iB2 ] = aNodes1[ i1 ];
796
797     GetMeshDS()->ChangeElementNodes( tr1, aNodes1, 3 );
798     GetMeshDS()->ChangeElementNodes( tr2, aNodes2, 3 );
799
800     return true;
801   }
802
803   // check case of quadratic faces
804   return InverseDiag(tr1,tr2);
805 }
806
807 //=======================================================================
808 //function : getQuadrangleNodes
809 //purpose  : fill theQuadNodes - nodes of a quadrangle resulting from
810 //           fusion of triangles tr1 and tr2 having shared link on
811 //           theNode1 and theNode2
812 //=======================================================================
813
814 bool getQuadrangleNodes(const SMDS_MeshNode *    theQuadNodes [],
815                         const SMDS_MeshNode *    theNode1,
816                         const SMDS_MeshNode *    theNode2,
817                         const SMDS_MeshElement * tr1,
818                         const SMDS_MeshElement * tr2 )
819 {
820   if( tr1->NbNodes() != tr2->NbNodes() )
821     return false;
822   // find the 4-th node to insert into tr1
823   const SMDS_MeshNode* n4 = 0;
824   SMDS_ElemIteratorPtr it = tr2->nodesIterator();
825   int i=0;
826   while ( !n4 && i<3 ) {
827     const SMDS_MeshNode * n = cast2Node( it->next() );
828     i++;
829     bool isDiag = ( n == theNode1 || n == theNode2 );
830     if ( !isDiag )
831       n4 = n;
832   }
833   // Make an array of nodes to be in a quadrangle
834   int iNode = 0, iFirstDiag = -1;
835   it = tr1->nodesIterator();
836   i=0;
837   while ( i<3 ) {
838     const SMDS_MeshNode * n = cast2Node( it->next() );
839     i++;
840     bool isDiag = ( n == theNode1 || n == theNode2 );
841     if ( isDiag ) {
842       if ( iFirstDiag < 0 )
843         iFirstDiag = iNode;
844       else if ( iNode - iFirstDiag == 1 )
845         theQuadNodes[ iNode++ ] = n4; // insert the 4-th node between diagonal nodes
846     }
847     else if ( n == n4 ) {
848       return false; // tr1 and tr2 should not have all the same nodes
849     }
850     theQuadNodes[ iNode++ ] = n;
851   }
852   if ( iNode == 3 ) // diagonal nodes have 0 and 2 indices
853     theQuadNodes[ iNode ] = n4;
854
855   return true;
856 }
857
858 //=======================================================================
859 //function : DeleteDiag
860 //purpose  : Replace two neighbour triangles sharing theNode1-theNode2 link
861 //           with a quadrangle built on the same 4 nodes.
862 //           Return false if proper faces not found
863 //=======================================================================
864
865 bool SMESH_MeshEditor::DeleteDiag (const SMDS_MeshNode * theNode1,
866                                    const SMDS_MeshNode * theNode2)
867 {
868   myLastCreatedElems.Clear();
869   myLastCreatedNodes.Clear();
870
871   MESSAGE( "::DeleteDiag()" );
872
873   const SMDS_MeshElement *tr1, *tr2;
874   if ( !findTriangles( theNode1, theNode2, tr1, tr2 ))
875     return false;
876
877   const SMDS_VtkFace* F1 = dynamic_cast<const SMDS_VtkFace*>( tr1 );
878   if (!F1) return false;
879   const SMDS_VtkFace* F2 = dynamic_cast<const SMDS_VtkFace*>( tr2 );
880   if (!F2) return false;
881   SMESHDS_Mesh * aMesh = GetMeshDS();
882
883   if ((tr1->GetEntityType() == SMDSEntity_Triangle) &&
884       (tr2->GetEntityType() == SMDSEntity_Triangle)) {
885
886     const SMDS_MeshNode* aNodes [ 4 ];
887     if ( ! getQuadrangleNodes( aNodes, theNode1, theNode2, tr1, tr2 ))
888       return false;
889
890     const SMDS_MeshElement* newElem = 0;
891     newElem = aMesh->AddFace( aNodes[0], aNodes[1], aNodes[2], aNodes[3] );
892     myLastCreatedElems.Append(newElem);
893     AddToSameGroups( newElem, tr1, aMesh );
894     int aShapeId = tr1->getshapeId();
895     if ( aShapeId )
896       {
897         aMesh->SetMeshElementOnShape( newElem, aShapeId );
898       }
899     aMesh->RemoveElement( tr1 );
900     aMesh->RemoveElement( tr2 );
901
902     return true;
903   }
904
905   // check case of quadratic faces
906   if (tr1->GetEntityType() != SMDSEntity_Quad_Triangle)
907     return false;
908   if (tr2->GetEntityType() != SMDSEntity_Quad_Triangle)
909     return false;
910
911   //       5
912   //  1 +--+--+ 2  tr1: (1 2 4 5 9 7) or (2 4 1 9 7 5) or (4 1 2 7 5 9)
913   //    |    /|    tr2: (2 3 4 6 8 9) or (3 4 2 8 9 6) or (4 2 3 9 6 8)
914   //    |   / |
915   //  7 +  +  + 6
916   //    | /9  |
917   //    |/    |
918   //  4 +--+--+ 3
919   //       8
920
921   const SMDS_MeshNode* N1 [6];
922   const SMDS_MeshNode* N2 [6];
923   if(!GetNodesFromTwoTria(tr1,tr2,N1,N2))
924     return false;
925   // now we receive following N1 and N2 (using numeration as above image)
926   // tria1 : (1 2 4 5 9 7)  and  tria2 : (3 4 2 8 9 6)
927   // i.e. first nodes from both arrays determ new diagonal
928
929   const SMDS_MeshNode* aNodes[8];
930   aNodes[0] = N1[0];
931   aNodes[1] = N1[1];
932   aNodes[2] = N2[0];
933   aNodes[3] = N2[1];
934   aNodes[4] = N1[3];
935   aNodes[5] = N2[5];
936   aNodes[6] = N2[3];
937   aNodes[7] = N1[5];
938
939   const SMDS_MeshElement* newElem = 0;
940   newElem = aMesh->AddFace( aNodes[0], aNodes[1], aNodes[2], aNodes[3],
941                             aNodes[4], aNodes[5], aNodes[6], aNodes[7]);
942   myLastCreatedElems.Append(newElem);
943   AddToSameGroups( newElem, tr1, aMesh );
944   int aShapeId = tr1->getshapeId();
945   if ( aShapeId )
946     {
947       aMesh->SetMeshElementOnShape( newElem, aShapeId );
948     }
949   aMesh->RemoveElement( tr1 );
950   aMesh->RemoveElement( tr2 );
951
952   // remove middle node (9)
953   GetMeshDS()->RemoveNode( N1[4] );
954
955   return true;
956 }
957
958 //=======================================================================
959 //function : Reorient
960 //purpose  : Reverse theElement orientation
961 //=======================================================================
962
963 bool SMESH_MeshEditor::Reorient (const SMDS_MeshElement * theElem)
964 {
965   MESSAGE("Reorient");
966   myLastCreatedElems.Clear();
967   myLastCreatedNodes.Clear();
968
969   if (!theElem)
970     return false;
971   SMDS_ElemIteratorPtr it = theElem->nodesIterator();
972   if ( !it || !it->more() )
973     return false;
974
975   switch ( theElem->GetType() ) {
976
977   case SMDSAbs_Edge:
978   case SMDSAbs_Face: {
979     if(!theElem->IsQuadratic()) {
980       int i = theElem->NbNodes();
981       vector<const SMDS_MeshNode*> aNodes( i );
982       while ( it->more() )
983         aNodes[ --i ]= static_cast<const SMDS_MeshNode*>( it->next() );
984       return GetMeshDS()->ChangeElementNodes( theElem, &aNodes[0], theElem->NbNodes() );
985     }
986     else {
987       // quadratic elements
988       if(theElem->GetType()==SMDSAbs_Edge) {
989         vector<const SMDS_MeshNode*> aNodes(3);
990         aNodes[1]= static_cast<const SMDS_MeshNode*>( it->next() );
991         aNodes[0]= static_cast<const SMDS_MeshNode*>( it->next() );
992         aNodes[2]= static_cast<const SMDS_MeshNode*>( it->next() );
993         return GetMeshDS()->ChangeElementNodes( theElem, &aNodes[0], 3 );
994       }
995       else {
996         int nbn = theElem->NbNodes();
997         vector<const SMDS_MeshNode*> aNodes(nbn);
998         aNodes[0]= static_cast<const SMDS_MeshNode*>( it->next() );
999         int i=1;
1000         for(; i<nbn/2; i++) {
1001           aNodes[nbn/2-i]= static_cast<const SMDS_MeshNode*>( it->next() );
1002         }
1003         for(i=0; i<nbn/2; i++) {
1004           aNodes[nbn-i-1]= static_cast<const SMDS_MeshNode*>( it->next() );
1005         }
1006         return GetMeshDS()->ChangeElementNodes( theElem, &aNodes[0], nbn );
1007       }
1008     }
1009   }
1010   case SMDSAbs_Volume: {
1011     if (theElem->IsPoly()) {
1012       // TODO reorient vtk polyhedron
1013       MESSAGE("reorient vtk polyhedron ?");
1014       const SMDS_VtkVolume* aPolyedre =
1015         dynamic_cast<const SMDS_VtkVolume*>( theElem );
1016       if (!aPolyedre) {
1017         MESSAGE("Warning: bad volumic element");
1018         return false;
1019       }
1020
1021       int nbFaces = aPolyedre->NbFaces();
1022       vector<const SMDS_MeshNode *> poly_nodes;
1023       vector<int> quantities (nbFaces);
1024
1025       // reverse each face of the polyedre
1026       for (int iface = 1; iface <= nbFaces; iface++) {
1027         int inode, nbFaceNodes = aPolyedre->NbFaceNodes(iface);
1028         quantities[iface - 1] = nbFaceNodes;
1029
1030         for (inode = nbFaceNodes; inode >= 1; inode--) {
1031           const SMDS_MeshNode* curNode = aPolyedre->GetFaceNode(iface, inode);
1032           poly_nodes.push_back(curNode);
1033         }
1034       }
1035
1036       return GetMeshDS()->ChangePolyhedronNodes( theElem, poly_nodes, quantities );
1037
1038     }
1039     else {
1040       SMDS_VolumeTool vTool;
1041       if ( !vTool.Set( theElem ))
1042         return false;
1043       vTool.Inverse();
1044       MESSAGE("ChangeElementNodes reorient: check vTool.Inverse");
1045       return GetMeshDS()->ChangeElementNodes( theElem, vTool.GetNodes(), vTool.NbNodes() );
1046     }
1047   }
1048   default:;
1049   }
1050
1051   return false;
1052 }
1053
1054 //=======================================================================
1055 //function : getBadRate
1056 //purpose  :
1057 //=======================================================================
1058
1059 static double getBadRate (const SMDS_MeshElement*               theElem,
1060                           SMESH::Controls::NumericalFunctorPtr& theCrit)
1061 {
1062   SMESH::Controls::TSequenceOfXYZ P;
1063   if ( !theElem || !theCrit->GetPoints( theElem, P ))
1064     return 1e100;
1065   return theCrit->GetBadRate( theCrit->GetValue( P ), theElem->NbNodes() );
1066   //return theCrit->GetBadRate( theCrit->GetValue( theElem->GetID() ), theElem->NbNodes() );
1067 }
1068
1069 //=======================================================================
1070 //function : QuadToTri
1071 //purpose  : Cut quadrangles into triangles.
1072 //           theCrit is used to select a diagonal to cut
1073 //=======================================================================
1074
1075 bool SMESH_MeshEditor::QuadToTri (TIDSortedElemSet &                   theElems,
1076                                   SMESH::Controls::NumericalFunctorPtr theCrit)
1077 {
1078   myLastCreatedElems.Clear();
1079   myLastCreatedNodes.Clear();
1080
1081   MESSAGE( "::QuadToTri()" );
1082
1083   if ( !theCrit.get() )
1084     return false;
1085
1086   SMESHDS_Mesh * aMesh = GetMeshDS();
1087
1088   Handle(Geom_Surface) surface;
1089   SMESH_MesherHelper   helper( *GetMesh() );
1090
1091   TIDSortedElemSet::iterator itElem;
1092   for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
1093     const SMDS_MeshElement* elem = *itElem;
1094     if ( !elem || elem->GetType() != SMDSAbs_Face )
1095       continue;
1096     if ( elem->NbCornerNodes() != 4 )
1097       continue;
1098
1099     // retrieve element nodes
1100     vector< const SMDS_MeshNode* > aNodes( elem->begin_nodes(), elem->end_nodes() );
1101
1102     // compare two sets of possible triangles
1103     double aBadRate1, aBadRate2; // to what extent a set is bad
1104     SMDS_FaceOfNodes tr1 ( aNodes[0], aNodes[1], aNodes[2] );
1105     SMDS_FaceOfNodes tr2 ( aNodes[2], aNodes[3], aNodes[0] );
1106     aBadRate1 = getBadRate( &tr1, theCrit ) + getBadRate( &tr2, theCrit );
1107
1108     SMDS_FaceOfNodes tr3 ( aNodes[1], aNodes[2], aNodes[3] );
1109     SMDS_FaceOfNodes tr4 ( aNodes[3], aNodes[0], aNodes[1] );
1110     aBadRate2 = getBadRate( &tr3, theCrit ) + getBadRate( &tr4, theCrit );
1111
1112     int aShapeId = FindShape( elem );
1113     const SMDS_MeshElement* newElem1 = 0;
1114     const SMDS_MeshElement* newElem2 = 0;
1115
1116     if( !elem->IsQuadratic() ) {
1117
1118       // split liner quadrangle
1119
1120       if ( aBadRate1 <= aBadRate2 ) {
1121         // tr1 + tr2 is better
1122         newElem1 = aMesh->AddFace( aNodes[2], aNodes[3], aNodes[0] );
1123         newElem2 = aMesh->AddFace( aNodes[2], aNodes[0], aNodes[1] );
1124       }
1125       else {
1126         // tr3 + tr4 is better
1127         newElem1 = aMesh->AddFace( aNodes[3], aNodes[0], aNodes[1] );
1128         newElem2 = aMesh->AddFace( aNodes[3], aNodes[1], aNodes[2] );
1129       }
1130     }
1131     else {
1132
1133       // split quadratic quadrangle
1134
1135       // get surface elem is on
1136       if ( aShapeId != helper.GetSubShapeID() ) {
1137         surface.Nullify();
1138         TopoDS_Shape shape;
1139         if ( aShapeId > 0 )
1140           shape = aMesh->IndexToShape( aShapeId );
1141         if ( !shape.IsNull() && shape.ShapeType() == TopAbs_FACE ) {
1142           TopoDS_Face face = TopoDS::Face( shape );
1143           surface = BRep_Tool::Surface( face );
1144           if ( !surface.IsNull() )
1145             helper.SetSubShape( shape );
1146         }
1147       }
1148       // find middle point for (0,1,2,3)
1149       // and create a node in this point;
1150       const SMDS_MeshNode* newN = 0;
1151       if ( aNodes.size() == 9 )
1152       {
1153         // SMDSEntity_BiQuad_Quadrangle
1154         newN = aNodes.back();
1155       }
1156       else
1157       {
1158         gp_XYZ p( 0,0,0 );
1159         if ( surface.IsNull() )
1160         {
1161           for ( int i = 0; i < 4; i++ )
1162             p += gp_XYZ(aNodes[i]->X(), aNodes[i]->Y(), aNodes[i]->Z() );
1163           p /= 4;
1164         }
1165         else
1166         {
1167           const SMDS_MeshNode* inFaceNode = 0;
1168           if ( helper.GetNodeUVneedInFaceNode() )
1169             for ( size_t i = 0; i < aNodes.size() && !inFaceNode; ++i )
1170               if ( aNodes[ i ]->GetPosition()->GetTypeOfPosition() == SMDS_TOP_FACE )
1171                 inFaceNode = aNodes[ i ];
1172
1173           TopoDS_Face face = TopoDS::Face( helper.GetSubShape() );
1174           gp_XY uv( 0,0 );
1175           for ( int i = 0; i < 4; i++ )
1176             uv += helper.GetNodeUV( face, aNodes[i], inFaceNode );
1177           uv /= 4.;
1178           p = surface->Value( uv.X(), uv.Y() ).XYZ();
1179         }
1180         newN = aMesh->AddNode( p.X(), p.Y(), p.Z() );
1181         myLastCreatedNodes.Append(newN);
1182       }
1183       // create a new element
1184       if ( aBadRate1 <= aBadRate2 ) {
1185         newElem1 = aMesh->AddFace(aNodes[2], aNodes[3], aNodes[0],
1186                                   aNodes[6], aNodes[7], newN );
1187         newElem2 = aMesh->AddFace(aNodes[2], aNodes[0], aNodes[1],
1188                                   newN,      aNodes[4], aNodes[5] );
1189       }
1190       else {
1191         newElem1 = aMesh->AddFace(aNodes[3], aNodes[0], aNodes[1],
1192                                   aNodes[7], aNodes[4], newN );
1193         newElem2 = aMesh->AddFace(aNodes[3], aNodes[1], aNodes[2],
1194                                   newN,      aNodes[5], aNodes[6] );
1195       }
1196     } // quadratic case
1197
1198     // care of a new element
1199
1200     myLastCreatedElems.Append(newElem1);
1201     myLastCreatedElems.Append(newElem2);
1202     AddToSameGroups( newElem1, elem, aMesh );
1203     AddToSameGroups( newElem2, elem, aMesh );
1204
1205     // put a new triangle on the same shape
1206     if ( aShapeId )
1207       {
1208         aMesh->SetMeshElementOnShape( newElem1, aShapeId );
1209         aMesh->SetMeshElementOnShape( newElem2, aShapeId );
1210       }
1211     aMesh->RemoveElement( elem );
1212   }
1213   return true;
1214 }
1215
1216 //=======================================================================
1217 //function : BestSplit
1218 //purpose  : Find better diagonal for cutting.
1219 //=======================================================================
1220
1221 int SMESH_MeshEditor::BestSplit (const SMDS_MeshElement*              theQuad,
1222                                  SMESH::Controls::NumericalFunctorPtr theCrit)
1223 {
1224   myLastCreatedElems.Clear();
1225   myLastCreatedNodes.Clear();
1226
1227   if (!theCrit.get())
1228     return -1;
1229
1230   if (!theQuad || theQuad->GetType() != SMDSAbs_Face )
1231     return -1;
1232
1233   if( theQuad->NbNodes()==4 ||
1234       (theQuad->NbNodes()==8 && theQuad->IsQuadratic()) ) {
1235
1236     // retrieve element nodes
1237     const SMDS_MeshNode* aNodes [4];
1238     SMDS_ElemIteratorPtr itN = theQuad->nodesIterator();
1239     int i = 0;
1240     //while (itN->more())
1241     while (i<4) {
1242       aNodes[ i++ ] = static_cast<const SMDS_MeshNode*>( itN->next() );
1243     }
1244     // compare two sets of possible triangles
1245     double aBadRate1, aBadRate2; // to what extent a set is bad
1246     SMDS_FaceOfNodes tr1 ( aNodes[0], aNodes[1], aNodes[2] );
1247     SMDS_FaceOfNodes tr2 ( aNodes[2], aNodes[3], aNodes[0] );
1248     aBadRate1 = getBadRate( &tr1, theCrit ) + getBadRate( &tr2, theCrit );
1249
1250     SMDS_FaceOfNodes tr3 ( aNodes[1], aNodes[2], aNodes[3] );
1251     SMDS_FaceOfNodes tr4 ( aNodes[3], aNodes[0], aNodes[1] );
1252     aBadRate2 = getBadRate( &tr3, theCrit ) + getBadRate( &tr4, theCrit );
1253
1254     if (aBadRate1 <= aBadRate2) // tr1 + tr2 is better
1255       return 1; // diagonal 1-3
1256
1257     return 2; // diagonal 2-4
1258   }
1259   return -1;
1260 }
1261
1262 namespace
1263 {
1264   // Methods of splitting volumes into tetra
1265
1266   const int theHexTo5_1[5*4+1] =
1267     {
1268       0, 1, 2, 5,    0, 4, 5, 7,     0, 2, 3, 7,    2, 5, 6, 7,     0, 5, 2, 7,   -1
1269     };
1270   const int theHexTo5_2[5*4+1] =
1271     {
1272       1, 2, 3, 6,    1, 4, 5, 6,     0, 1, 3, 4,    3, 4, 6, 7,     1, 3, 4, 6,   -1
1273     };
1274   const int* theHexTo5[2] = { theHexTo5_1, theHexTo5_2 };
1275
1276   const int theHexTo6_1[6*4+1] =
1277     {
1278       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
1279     };
1280   const int theHexTo6_2[6*4+1] =
1281     {
1282       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
1283     };
1284   const int theHexTo6_3[6*4+1] =
1285     {
1286       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
1287     };
1288   const int theHexTo6_4[6*4+1] =
1289     {
1290       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
1291     };
1292   const int* theHexTo6[4] = { theHexTo6_1, theHexTo6_2, theHexTo6_3, theHexTo6_4 };
1293
1294   const int thePyraTo2_1[2*4+1] =
1295     {
1296       0, 1, 2, 4,    0, 2, 3, 4,   -1
1297     };
1298   const int thePyraTo2_2[2*4+1] =
1299     {
1300       1, 2, 3, 4,    1, 3, 0, 4,   -1
1301     };
1302   const int* thePyraTo2[2] = { thePyraTo2_1, thePyraTo2_2 };
1303
1304   const int thePentaTo3_1[3*4+1] =
1305     {
1306       0, 1, 2, 3,    1, 3, 4, 2,     2, 3, 4, 5,    -1
1307     };
1308   const int thePentaTo3_2[3*4+1] =
1309     {
1310       1, 2, 0, 4,    2, 4, 5, 0,     0, 4, 5, 3,    -1
1311     };
1312   const int thePentaTo3_3[3*4+1] =
1313     {
1314       2, 0, 1, 5,    0, 5, 3, 1,     1, 5, 3, 4,    -1
1315     };
1316   const int thePentaTo3_4[3*4+1] =
1317     {
1318       0, 1, 2, 3,    1, 3, 4, 5,     2, 3, 1, 5,    -1
1319     };
1320   const int thePentaTo3_5[3*4+1] =
1321     {
1322       1, 2, 0, 4,    2, 4, 5, 3,     0, 4, 2, 3,    -1
1323     };
1324   const int thePentaTo3_6[3*4+1] =
1325     {
1326       2, 0, 1, 5,    0, 5, 3, 4,     1, 5, 0, 4,    -1
1327     };
1328   const int* thePentaTo3[6] = { thePentaTo3_1, thePentaTo3_2, thePentaTo3_3,
1329                                 thePentaTo3_4, thePentaTo3_5, thePentaTo3_6 };
1330
1331   struct TTriangleFacet //!< stores indices of three nodes of tetra facet
1332   {
1333     int _n1, _n2, _n3;
1334     TTriangleFacet(int n1, int n2, int n3): _n1(n1), _n2(n2), _n3(n3) {}
1335     bool contains(int n) const { return ( n == _n1 || n == _n2 || n == _n3 ); }
1336     bool hasAdjacentTetra( const SMDS_MeshElement* elem ) const;
1337   };
1338   struct TSplitMethod
1339   {
1340     int        _nbTetra;
1341     const int* _connectivity; //!< foursomes of tetra connectivy finished by -1
1342     bool       _baryNode;     //!< additional node is to be created at cell barycenter
1343     bool       _ownConn;      //!< to delete _connectivity in destructor
1344     map<int, const SMDS_MeshNode*> _faceBaryNode; //!< map face index to node at BC of face
1345
1346     TSplitMethod( int nbTet=0, const int* conn=0, bool addNode=false)
1347       : _nbTetra(nbTet), _connectivity(conn), _baryNode(addNode), _ownConn(false) {}
1348     ~TSplitMethod() { if ( _ownConn ) delete [] _connectivity; _connectivity = 0; }
1349     bool hasFacet( const TTriangleFacet& facet ) const
1350     {
1351       const int* tetConn = _connectivity;
1352       for ( ; tetConn[0] >= 0; tetConn += 4 )
1353         if (( facet.contains( tetConn[0] ) +
1354               facet.contains( tetConn[1] ) +
1355               facet.contains( tetConn[2] ) +
1356               facet.contains( tetConn[3] )) == 3 )
1357           return true;
1358       return false;
1359     }
1360   };
1361
1362   //=======================================================================
1363   /*!
1364    * \brief return TSplitMethod for the given element
1365    */
1366   //=======================================================================
1367
1368   TSplitMethod getSplitMethod( SMDS_VolumeTool& vol, const int theMethodFlags)
1369   {
1370     const int iQ = vol.Element()->IsQuadratic() ? 2 : 1;
1371
1372     // at HEXA_TO_24 method, each face of volume is split into triangles each based on
1373     // an edge and a face barycenter; tertaherdons are based on triangles and
1374     // a volume barycenter
1375     const bool is24TetMode = ( theMethodFlags == SMESH_MeshEditor::HEXA_TO_24 );
1376
1377     // Find out how adjacent volumes are split
1378
1379     vector < list< TTriangleFacet > > triaSplitsByFace( vol.NbFaces() ); // splits of each side
1380     int hasAdjacentSplits = 0, maxTetConnSize = 0;
1381     for ( int iF = 0; iF < vol.NbFaces(); ++iF )
1382     {
1383       int nbNodes = vol.NbFaceNodes( iF ) / iQ;
1384       maxTetConnSize += 4 * ( nbNodes - (is24TetMode ? 0 : 2));
1385       if ( nbNodes < 4 ) continue;
1386
1387       list< TTriangleFacet >& triaSplits = triaSplitsByFace[ iF ];
1388       const int* nInd = vol.GetFaceNodesIndices( iF );
1389       if ( nbNodes == 4 )
1390       {
1391         TTriangleFacet t012( nInd[0*iQ], nInd[1*iQ], nInd[2*iQ] );
1392         TTriangleFacet t123( nInd[1*iQ], nInd[2*iQ], nInd[3*iQ] );
1393         if      ( t012.hasAdjacentTetra( vol.Element() )) triaSplits.push_back( t012 );
1394         else if ( t123.hasAdjacentTetra( vol.Element() )) triaSplits.push_back( t123 );
1395       }
1396       else
1397       {
1398         int iCom = 0; // common node of triangle faces to split into
1399         for ( int iVar = 0; iVar < nbNodes; ++iVar, ++iCom )
1400         {
1401           TTriangleFacet t012( nInd[ iQ * ( iCom             )],
1402                                nInd[ iQ * ( (iCom+1)%nbNodes )],
1403                                nInd[ iQ * ( (iCom+2)%nbNodes )]);
1404           TTriangleFacet t023( nInd[ iQ * ( iCom             )],
1405                                nInd[ iQ * ( (iCom+2)%nbNodes )],
1406                                nInd[ iQ * ( (iCom+3)%nbNodes )]);
1407           if ( t012.hasAdjacentTetra( vol.Element() ) && t023.hasAdjacentTetra( vol.Element() ))
1408           {
1409             triaSplits.push_back( t012 );
1410             triaSplits.push_back( t023 );
1411             break;
1412           }
1413         }
1414       }
1415       if ( !triaSplits.empty() )
1416         hasAdjacentSplits = true;
1417     }
1418
1419     // Among variants of split method select one compliant with adjacent volumes
1420
1421     TSplitMethod method;
1422     if ( !vol.Element()->IsPoly() && !is24TetMode )
1423     {
1424       int nbVariants = 2, nbTet = 0;
1425       const int** connVariants = 0;
1426       switch ( vol.Element()->GetEntityType() )
1427       {
1428       case SMDSEntity_Hexa:
1429       case SMDSEntity_Quad_Hexa:
1430       case SMDSEntity_TriQuad_Hexa:
1431         if ( theMethodFlags == SMESH_MeshEditor::HEXA_TO_5 )
1432           connVariants = theHexTo5, nbTet = 5;
1433         else
1434           connVariants = theHexTo6, nbTet = 6, nbVariants = 4;
1435         break;
1436       case SMDSEntity_Pyramid:
1437       case SMDSEntity_Quad_Pyramid:
1438         connVariants = thePyraTo2;  nbTet = 2;
1439         break;
1440       case SMDSEntity_Penta:
1441       case SMDSEntity_Quad_Penta:
1442         connVariants = thePentaTo3; nbTet = 3; nbVariants = 6;
1443         break;
1444       default:
1445         nbVariants = 0;
1446       }
1447       for ( int variant = 0; variant < nbVariants && method._nbTetra == 0; ++variant )
1448       {
1449         // check method compliancy with adjacent tetras,
1450         // all found splits must be among facets of tetras described by this method
1451         method = TSplitMethod( nbTet, connVariants[variant] );
1452         if ( hasAdjacentSplits && method._nbTetra > 0 )
1453         {
1454           bool facetCreated = true;
1455           for ( int iF = 0; facetCreated && iF < triaSplitsByFace.size(); ++iF )
1456           {
1457             list< TTriangleFacet >::const_iterator facet = triaSplitsByFace[iF].begin();
1458             for ( ; facetCreated && facet != triaSplitsByFace[iF].end(); ++facet )
1459               facetCreated = method.hasFacet( *facet );
1460           }
1461           if ( !facetCreated )
1462             method = TSplitMethod(0); // incompatible method
1463         }
1464       }
1465     }
1466     if ( method._nbTetra < 1 )
1467     {
1468       // No standard method is applicable, use a generic solution:
1469       // each facet of a volume is split into triangles and
1470       // each of triangles and a volume barycenter form a tetrahedron.
1471
1472       const bool isHex27 = ( vol.Element()->GetEntityType() == SMDSEntity_TriQuad_Hexa );
1473
1474       int* connectivity = new int[ maxTetConnSize + 1 ];
1475       method._connectivity = connectivity;
1476       method._ownConn = true;
1477       method._baryNode = !isHex27; // to create central node or not
1478
1479       int connSize = 0;
1480       int baryCenInd = vol.NbNodes() - int( isHex27 );
1481       for ( int iF = 0; iF < vol.NbFaces(); ++iF )
1482       {
1483         const int nbNodes = vol.NbFaceNodes( iF ) / iQ;
1484         const int*   nInd = vol.GetFaceNodesIndices( iF );
1485         // find common node of triangle facets of tetra to create
1486         int iCommon = 0; // index in linear numeration
1487         const list< TTriangleFacet >& triaSplits = triaSplitsByFace[ iF ];
1488         if ( !triaSplits.empty() )
1489         {
1490           // by found facets
1491           const TTriangleFacet* facet = &triaSplits.front();
1492           for ( ; iCommon < nbNodes-1 ; ++iCommon )
1493             if ( facet->contains( nInd[ iQ * iCommon ]) &&
1494                  facet->contains( nInd[ iQ * ((iCommon+2)%nbNodes) ]))
1495               break;
1496         }
1497         else if ( nbNodes > 3 && !is24TetMode )
1498         {
1499           // find the best method of splitting into triangles by aspect ratio
1500           SMESH::Controls::NumericalFunctorPtr aspectRatio( new SMESH::Controls::AspectRatio);
1501           map< double, int > badness2iCommon;
1502           const SMDS_MeshNode** nodes = vol.GetFaceNodes( iF );
1503           int nbVariants = ( nbNodes == 4 ? 2 : nbNodes );
1504           for ( int iVar = 0; iVar < nbVariants; ++iVar, ++iCommon )
1505           {
1506             double badness = 0;
1507             for ( int iLast = iCommon+2; iLast < iCommon+nbNodes; ++iLast )
1508             {
1509               SMDS_FaceOfNodes tria ( nodes[ iQ*( iCommon         )],
1510                                       nodes[ iQ*((iLast-1)%nbNodes)],
1511                                       nodes[ iQ*((iLast  )%nbNodes)]);
1512               badness += getBadRate( &tria, aspectRatio );
1513             }
1514             badness2iCommon.insert( make_pair( badness, iCommon ));
1515           }
1516           // use iCommon with lowest badness
1517           iCommon = badness2iCommon.begin()->second;
1518         }
1519         if ( iCommon >= nbNodes )
1520           iCommon = 0; // something wrong
1521
1522         // fill connectivity of tetrahedra based on a current face
1523         int nbTet = nbNodes - 2;
1524         if ( is24TetMode && nbNodes > 3 && triaSplits.empty())
1525         {
1526           int faceBaryCenInd;
1527           if ( isHex27 )
1528           {
1529             faceBaryCenInd = vol.GetCenterNodeIndex( iF );
1530             method._faceBaryNode[ iF ] = vol.GetNodes()[ faceBaryCenInd ];
1531           }
1532           else
1533           {
1534             method._faceBaryNode[ iF ] = 0;
1535             faceBaryCenInd = baryCenInd + method._faceBaryNode.size();
1536           }
1537           nbTet = nbNodes;
1538           for ( int i = 0; i < nbTet; ++i )
1539           {
1540             int i1 = i, i2 = (i+1) % nbNodes;
1541             if ( !vol.IsFaceExternal( iF )) swap( i1, i2 );
1542             connectivity[ connSize++ ] = nInd[ iQ * i1 ];
1543             connectivity[ connSize++ ] = nInd[ iQ * i2 ];
1544             connectivity[ connSize++ ] = faceBaryCenInd;
1545             connectivity[ connSize++ ] = baryCenInd;
1546           }
1547         }
1548         else
1549         {
1550           for ( int i = 0; i < nbTet; ++i )
1551           {
1552             int i1 = (iCommon+1+i) % nbNodes, i2 = (iCommon+2+i) % nbNodes;
1553             if ( !vol.IsFaceExternal( iF )) swap( i1, i2 );
1554             connectivity[ connSize++ ] = nInd[ iQ * iCommon ];
1555             connectivity[ connSize++ ] = nInd[ iQ * i1 ];
1556             connectivity[ connSize++ ] = nInd[ iQ * i2 ];
1557             connectivity[ connSize++ ] = baryCenInd;
1558           }
1559         }
1560         method._nbTetra += nbTet;
1561
1562       } // loop on volume faces
1563
1564       connectivity[ connSize++ ] = -1;
1565
1566     } // end of generic solution
1567
1568     return method;
1569   }
1570   //================================================================================
1571   /*!
1572    * \brief Check if there is a tetraherdon adjacent to the given element via this facet
1573    */
1574   //================================================================================
1575
1576   bool TTriangleFacet::hasAdjacentTetra( const SMDS_MeshElement* elem ) const
1577   {
1578     // find the tetrahedron including the three nodes of facet
1579     const SMDS_MeshNode* n1 = elem->GetNode(_n1);
1580     const SMDS_MeshNode* n2 = elem->GetNode(_n2);
1581     const SMDS_MeshNode* n3 = elem->GetNode(_n3);
1582     SMDS_ElemIteratorPtr volIt1 = n1->GetInverseElementIterator(SMDSAbs_Volume);
1583     while ( volIt1->more() )
1584     {
1585       const SMDS_MeshElement* v = volIt1->next();
1586       SMDSAbs_EntityType type = v->GetEntityType();
1587       if ( type != SMDSEntity_Tetra && type != SMDSEntity_Quad_Tetra )
1588         continue;
1589       if ( type == SMDSEntity_Quad_Tetra && v->GetNodeIndex( n1 ) > 3 )
1590         continue; // medium node not allowed
1591       const int ind2 = v->GetNodeIndex( n2 );
1592       if ( ind2 < 0 || 3 < ind2 )
1593         continue;
1594       const int ind3 = v->GetNodeIndex( n3 );
1595       if ( ind3 < 0 || 3 < ind3 )
1596         continue;
1597       return true;
1598     }
1599     return false;
1600   }
1601
1602   //=======================================================================
1603   /*!
1604    * \brief A key of a face of volume
1605    */
1606   //=======================================================================
1607
1608   struct TVolumeFaceKey: pair< pair< int, int>, pair< int, int> >
1609   {
1610     TVolumeFaceKey( SMDS_VolumeTool& vol, int iF )
1611     {
1612       TIDSortedNodeSet sortedNodes;
1613       const int iQ = vol.Element()->IsQuadratic() ? 2 : 1;
1614       int nbNodes = vol.NbFaceNodes( iF );
1615       const SMDS_MeshNode** fNodes = vol.GetFaceNodes( iF );
1616       for ( int i = 0; i < nbNodes; i += iQ )
1617         sortedNodes.insert( fNodes[i] );
1618       TIDSortedNodeSet::iterator n = sortedNodes.begin();
1619       first.first   = (*(n++))->GetID();
1620       first.second  = (*(n++))->GetID();
1621       second.first  = (*(n++))->GetID();
1622       second.second = ( sortedNodes.size() > 3 ) ? (*(n++))->GetID() : 0;
1623     }
1624   };
1625 } // namespace
1626
1627 //=======================================================================
1628 //function : SplitVolumesIntoTetra
1629 //purpose  : Split volume elements into tetrahedra.
1630 //=======================================================================
1631
1632 void SMESH_MeshEditor::SplitVolumesIntoTetra (const TIDSortedElemSet & theElems,
1633                                               const int                theMethodFlags)
1634 {
1635   // std-like iterator on coordinates of nodes of mesh element
1636   typedef SMDS_StdIterator< SMESH_TNodeXYZ, SMDS_ElemIteratorPtr > NXyzIterator;
1637   NXyzIterator xyzEnd;
1638
1639   SMDS_VolumeTool    volTool;
1640   SMESH_MesherHelper helper( *GetMesh());
1641
1642   SMESHDS_SubMesh* subMesh = 0;//GetMeshDS()->MeshElements(1);
1643   SMESHDS_SubMesh* fSubMesh = 0;//subMesh;
1644   
1645   SMESH_SequenceOfElemPtr newNodes, newElems;
1646
1647   // map face of volume to it's baricenrtic node
1648   map< TVolumeFaceKey, const SMDS_MeshNode* > volFace2BaryNode;
1649   double bc[3];
1650
1651   TIDSortedElemSet::const_iterator elem = theElems.begin();
1652   for ( ; elem != theElems.end(); ++elem )
1653   {
1654     if ( (*elem)->GetType() != SMDSAbs_Volume )
1655       continue;
1656     SMDSAbs_EntityType geomType = (*elem)->GetEntityType();
1657     if ( geomType == SMDSEntity_Tetra || geomType == SMDSEntity_Quad_Tetra )
1658       continue;
1659
1660     if ( !volTool.Set( *elem, /*ignoreCentralNodes=*/false )) continue; // strange...
1661
1662     TSplitMethod splitMethod = getSplitMethod( volTool, theMethodFlags );
1663     if ( splitMethod._nbTetra < 1 ) continue;
1664
1665     // find submesh to add new tetras to
1666     if ( !subMesh || !subMesh->Contains( *elem ))
1667     {
1668       int shapeID = FindShape( *elem );
1669       helper.SetSubShape( shapeID ); // helper will add tetras to the found submesh
1670       subMesh = GetMeshDS()->MeshElements( shapeID );
1671     }
1672     int iQ;
1673     if ( (*elem)->IsQuadratic() )
1674     {
1675       iQ = 2;
1676       // add quadratic links to the helper
1677       for ( int iF = 0; iF < volTool.NbFaces(); ++iF )
1678       {
1679         const SMDS_MeshNode** fNodes = volTool.GetFaceNodes( iF );
1680         int nbN = volTool.NbFaceNodes( iF ) - bool( volTool.GetCenterNodeIndex(iF) > 0 );
1681         for ( int iN = 0; iN < nbN; iN += iQ )
1682           helper.AddTLinkNode( fNodes[iN], fNodes[iN+2], fNodes[iN+1] );
1683       }
1684       helper.SetIsQuadratic( true );
1685     }
1686     else
1687     {
1688       iQ = 1;
1689       helper.SetIsQuadratic( false );
1690     }
1691     vector<const SMDS_MeshNode*> nodes( (*elem)->begin_nodes(), (*elem)->end_nodes() );
1692     helper.SetElementsOnShape( true );
1693     if ( splitMethod._baryNode )
1694     {
1695       // make a node at barycenter
1696       volTool.GetBaryCenter( bc[0], bc[1], bc[2] );
1697       SMDS_MeshNode* gcNode = helper.AddNode( bc[0], bc[1], bc[2] );
1698       nodes.push_back( gcNode );
1699       newNodes.Append( gcNode );
1700     }
1701     if ( !splitMethod._faceBaryNode.empty() )
1702     {
1703       // make or find baricentric nodes of faces
1704       map<int, const SMDS_MeshNode*>::iterator iF_n = splitMethod._faceBaryNode.begin();
1705       for ( ; iF_n != splitMethod._faceBaryNode.end(); ++iF_n )
1706       {
1707         map< TVolumeFaceKey, const SMDS_MeshNode* >::iterator f_n =
1708           volFace2BaryNode.insert
1709           ( make_pair( TVolumeFaceKey( volTool,iF_n->first ), iF_n->second )).first;
1710         if ( !f_n->second )
1711         {
1712           volTool.GetFaceBaryCenter( iF_n->first, bc[0], bc[1], bc[2] );
1713           newNodes.Append( f_n->second = helper.AddNode( bc[0], bc[1], bc[2] ));
1714         }
1715         nodes.push_back( iF_n->second = f_n->second );
1716       }
1717     }
1718
1719     // make tetras
1720     vector<const SMDS_MeshElement* > tetras( splitMethod._nbTetra ); // splits of a volume
1721     const int* tetConn = splitMethod._connectivity;
1722     for ( int i = 0; i < splitMethod._nbTetra; ++i, tetConn += 4 )
1723       newElems.Append( tetras[ i ] = helper.AddVolume( nodes[ tetConn[0] ],
1724                                                        nodes[ tetConn[1] ],
1725                                                        nodes[ tetConn[2] ],
1726                                                        nodes[ tetConn[3] ]));
1727
1728     ReplaceElemInGroups( *elem, tetras, GetMeshDS() );
1729
1730     // Split faces on sides of the split volume
1731
1732     const SMDS_MeshNode** volNodes = volTool.GetNodes();
1733     for ( int iF = 0; iF < volTool.NbFaces(); ++iF )
1734     {
1735       const int nbNodes = volTool.NbFaceNodes( iF ) / iQ;
1736       if ( nbNodes < 4 ) continue;
1737
1738       // find an existing face
1739       vector<const SMDS_MeshNode*> fNodes( volTool.GetFaceNodes( iF ),
1740                                            volTool.GetFaceNodes( iF ) + volTool.NbFaceNodes( iF ));
1741       while ( const SMDS_MeshElement* face = GetMeshDS()->FindElement( fNodes, SMDSAbs_Face,
1742                                                                        /*noMedium=*/false))
1743       {
1744         // make triangles
1745         helper.SetElementsOnShape( false );
1746         vector< const SMDS_MeshElement* > triangles;
1747
1748         // find submesh to add new triangles in
1749         if ( !fSubMesh || !fSubMesh->Contains( face ))
1750         {
1751           int shapeID = FindShape( face );
1752           fSubMesh = GetMeshDS()->MeshElements( shapeID );
1753         }
1754         map<int, const SMDS_MeshNode*>::iterator iF_n = splitMethod._faceBaryNode.find(iF);
1755         if ( iF_n != splitMethod._faceBaryNode.end() )
1756         {
1757           for ( int iN = 0; iN < nbNodes*iQ; iN += iQ )
1758           {
1759             const SMDS_MeshNode* n1 = fNodes[iN];
1760             const SMDS_MeshNode *n2 = fNodes[(iN+iQ)%(nbNodes*iQ)];
1761             const SMDS_MeshNode *n3 = iF_n->second;
1762             if ( !volTool.IsFaceExternal( iF ))
1763               swap( n2, n3 );
1764             triangles.push_back( helper.AddFace( n1,n2,n3 ));
1765
1766             if ( fSubMesh && n3->getshapeId() < 1 )
1767               fSubMesh->AddNode( n3 );
1768           }
1769         }
1770         else
1771         {
1772           // among possible triangles create ones discribed by split method
1773           const int* nInd = volTool.GetFaceNodesIndices( iF );
1774           int nbVariants = ( nbNodes == 4 ? 2 : nbNodes );
1775           int iCom = 0; // common node of triangle faces to split into
1776           list< TTriangleFacet > facets;
1777           for ( int iVar = 0; iVar < nbVariants; ++iVar, ++iCom )
1778           {
1779             TTriangleFacet t012( nInd[ iQ * ( iCom                )],
1780                                  nInd[ iQ * ( (iCom+1)%nbNodes )],
1781                                  nInd[ iQ * ( (iCom+2)%nbNodes )]);
1782             TTriangleFacet t023( nInd[ iQ * ( iCom                )],
1783                                  nInd[ iQ * ( (iCom+2)%nbNodes )],
1784                                  nInd[ iQ * ( (iCom+3)%nbNodes )]);
1785             if ( splitMethod.hasFacet( t012 ) && splitMethod.hasFacet( t023 ))
1786             {
1787               facets.push_back( t012 );
1788               facets.push_back( t023 );
1789               for ( int iLast = iCom+4; iLast < iCom+nbNodes; ++iLast )
1790                 facets.push_back( TTriangleFacet( nInd[ iQ * ( iCom             )],
1791                                                   nInd[ iQ * ((iLast-1)%nbNodes )],
1792                                                   nInd[ iQ * ((iLast  )%nbNodes )]));
1793               break;
1794             }
1795           }
1796           list< TTriangleFacet >::iterator facet = facets.begin();
1797           for ( ; facet != facets.end(); ++facet )
1798           {
1799             if ( !volTool.IsFaceExternal( iF ))
1800               swap( facet->_n2, facet->_n3 );
1801             triangles.push_back( helper.AddFace( volNodes[ facet->_n1 ],
1802                                                  volNodes[ facet->_n2 ],
1803                                                  volNodes[ facet->_n3 ]));
1804           }
1805         }
1806         for ( int i = 0; i < triangles.size(); ++i )
1807         {
1808           if ( !triangles[i] ) continue;
1809           if ( fSubMesh )
1810             fSubMesh->AddElement( triangles[i]);
1811           newElems.Append( triangles[i] );
1812         }
1813         ReplaceElemInGroups( face, triangles, GetMeshDS() );
1814         GetMeshDS()->RemoveFreeElement( face, fSubMesh, /*fromGroups=*/false );
1815       }
1816
1817     } // loop on volume faces to split them into triangles
1818
1819     GetMeshDS()->RemoveFreeElement( *elem, subMesh, /*fromGroups=*/false );
1820
1821     if ( geomType == SMDSEntity_TriQuad_Hexa )
1822     {
1823       // remove medium nodes that could become free
1824       for ( int i = 20; i < volTool.NbNodes(); ++i )
1825         if ( volNodes[i]->NbInverseElements() == 0 )
1826           GetMeshDS()->RemoveNode( volNodes[i] );
1827     }
1828   } // loop on volumes to split
1829
1830   myLastCreatedNodes = newNodes;
1831   myLastCreatedElems = newElems;
1832 }
1833
1834 //=======================================================================
1835 //function : AddToSameGroups
1836 //purpose  : add elemToAdd to the groups the elemInGroups belongs to
1837 //=======================================================================
1838
1839 void SMESH_MeshEditor::AddToSameGroups (const SMDS_MeshElement* elemToAdd,
1840                                         const SMDS_MeshElement* elemInGroups,
1841                                         SMESHDS_Mesh *          aMesh)
1842 {
1843   const set<SMESHDS_GroupBase*>& groups = aMesh->GetGroups();
1844   if (!groups.empty()) {
1845     set<SMESHDS_GroupBase*>::const_iterator grIt = groups.begin();
1846     for ( ; grIt != groups.end(); grIt++ ) {
1847       SMESHDS_Group* group = dynamic_cast<SMESHDS_Group*>( *grIt );
1848       if ( group && group->Contains( elemInGroups ))
1849         group->SMDSGroup().Add( elemToAdd );
1850     }
1851   }
1852 }
1853
1854
1855 //=======================================================================
1856 //function : RemoveElemFromGroups
1857 //purpose  : Remove removeelem to the groups the elemInGroups belongs to
1858 //=======================================================================
1859 void SMESH_MeshEditor::RemoveElemFromGroups (const SMDS_MeshElement* removeelem,
1860                                              SMESHDS_Mesh *          aMesh)
1861 {
1862   const set<SMESHDS_GroupBase*>& groups = aMesh->GetGroups();
1863   if (!groups.empty())
1864   {
1865     set<SMESHDS_GroupBase*>::const_iterator GrIt = groups.begin();
1866     for (; GrIt != groups.end(); GrIt++)
1867     {
1868       SMESHDS_Group* grp = dynamic_cast<SMESHDS_Group*>(*GrIt);
1869       if (!grp || grp->IsEmpty()) continue;
1870       grp->SMDSGroup().Remove(removeelem);
1871     }
1872   }
1873 }
1874
1875 //================================================================================
1876 /*!
1877  * \brief Replace elemToRm by elemToAdd in the all groups
1878  */
1879 //================================================================================
1880
1881 void SMESH_MeshEditor::ReplaceElemInGroups (const SMDS_MeshElement* elemToRm,
1882                                             const SMDS_MeshElement* elemToAdd,
1883                                             SMESHDS_Mesh *          aMesh)
1884 {
1885   const set<SMESHDS_GroupBase*>& groups = aMesh->GetGroups();
1886   if (!groups.empty()) {
1887     set<SMESHDS_GroupBase*>::const_iterator grIt = groups.begin();
1888     for ( ; grIt != groups.end(); grIt++ ) {
1889       SMESHDS_Group* group = dynamic_cast<SMESHDS_Group*>( *grIt );
1890       if ( group && group->SMDSGroup().Remove( elemToRm ) && elemToAdd )
1891         group->SMDSGroup().Add( elemToAdd );
1892     }
1893   }
1894 }
1895
1896 //================================================================================
1897 /*!
1898  * \brief Replace elemToRm by elemToAdd in the all groups
1899  */
1900 //================================================================================
1901
1902 void SMESH_MeshEditor::ReplaceElemInGroups (const SMDS_MeshElement*                elemToRm,
1903                                             const vector<const SMDS_MeshElement*>& elemToAdd,
1904                                             SMESHDS_Mesh *                         aMesh)
1905 {
1906   const set<SMESHDS_GroupBase*>& groups = aMesh->GetGroups();
1907   if (!groups.empty())
1908   {
1909     set<SMESHDS_GroupBase*>::const_iterator grIt = groups.begin();
1910     for ( ; grIt != groups.end(); grIt++ ) {
1911       SMESHDS_Group* group = dynamic_cast<SMESHDS_Group*>( *grIt );
1912       if ( group && group->SMDSGroup().Remove( elemToRm ) )
1913         for ( int i = 0; i < elemToAdd.size(); ++i )
1914           group->SMDSGroup().Add( elemToAdd[ i ] );
1915     }
1916   }
1917 }
1918
1919 //=======================================================================
1920 //function : QuadToTri
1921 //purpose  : Cut quadrangles into triangles.
1922 //           theCrit is used to select a diagonal to cut
1923 //=======================================================================
1924
1925 bool SMESH_MeshEditor::QuadToTri (TIDSortedElemSet & theElems,
1926                                   const bool         the13Diag)
1927 {
1928   myLastCreatedElems.Clear();
1929   myLastCreatedNodes.Clear();
1930
1931   MESSAGE( "::QuadToTri()" );
1932
1933   SMESHDS_Mesh * aMesh = GetMeshDS();
1934
1935   Handle(Geom_Surface) surface;
1936   SMESH_MesherHelper   helper( *GetMesh() );
1937
1938   TIDSortedElemSet::iterator itElem;
1939   for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
1940     const SMDS_MeshElement* elem = *itElem;
1941     if ( !elem || elem->GetType() != SMDSAbs_Face )
1942       continue;
1943     bool isquad = elem->NbNodes()==4 || elem->NbNodes()==8;
1944     if(!isquad) continue;
1945
1946     if(elem->NbNodes()==4) {
1947       // retrieve element nodes
1948       const SMDS_MeshNode* aNodes [4];
1949       SMDS_ElemIteratorPtr itN = elem->nodesIterator();
1950       int i = 0;
1951       while ( itN->more() )
1952         aNodes[ i++ ] = static_cast<const SMDS_MeshNode*>( itN->next() );
1953
1954       int aShapeId = FindShape( elem );
1955       const SMDS_MeshElement* newElem1 = 0;
1956       const SMDS_MeshElement* newElem2 = 0;
1957       if ( the13Diag ) {
1958         newElem1 = aMesh->AddFace( aNodes[2], aNodes[0], aNodes[1] );
1959         newElem2 = aMesh->AddFace( aNodes[2], aNodes[3], aNodes[0] );
1960       }
1961       else {
1962         newElem1 = aMesh->AddFace( aNodes[3], aNodes[0], aNodes[1] );
1963         newElem2 = aMesh->AddFace( aNodes[3], aNodes[1], aNodes[2] );
1964       }
1965       myLastCreatedElems.Append(newElem1);
1966       myLastCreatedElems.Append(newElem2);
1967       // put a new triangle on the same shape and add to the same groups
1968       if ( aShapeId )
1969         {
1970           aMesh->SetMeshElementOnShape( newElem1, aShapeId );
1971           aMesh->SetMeshElementOnShape( newElem2, aShapeId );
1972         }
1973       AddToSameGroups( newElem1, elem, aMesh );
1974       AddToSameGroups( newElem2, elem, aMesh );
1975       //aMesh->RemoveFreeElement(elem, aMesh->MeshElements(aShapeId), true);
1976       aMesh->RemoveElement( elem );
1977     }
1978
1979     // Quadratic quadrangle
1980
1981     if( elem->NbNodes()==8 && elem->IsQuadratic() ) {
1982
1983       // get surface elem is on
1984       int aShapeId = FindShape( elem );
1985       if ( aShapeId != helper.GetSubShapeID() ) {
1986         surface.Nullify();
1987         TopoDS_Shape shape;
1988         if ( aShapeId > 0 )
1989           shape = aMesh->IndexToShape( aShapeId );
1990         if ( !shape.IsNull() && shape.ShapeType() == TopAbs_FACE ) {
1991           TopoDS_Face face = TopoDS::Face( shape );
1992           surface = BRep_Tool::Surface( face );
1993           if ( !surface.IsNull() )
1994             helper.SetSubShape( shape );
1995         }
1996       }
1997
1998       const SMDS_MeshNode* aNodes [8];
1999       const SMDS_MeshNode* inFaceNode = 0;
2000       SMDS_ElemIteratorPtr itN = elem->nodesIterator();
2001       int i = 0;
2002       while ( itN->more() ) {
2003         aNodes[ i++ ] = static_cast<const SMDS_MeshNode*>( itN->next() );
2004         if ( !inFaceNode && helper.GetNodeUVneedInFaceNode() &&
2005              aNodes[ i-1 ]->GetPosition()->GetTypeOfPosition() == SMDS_TOP_FACE )
2006         {
2007           inFaceNode = aNodes[ i-1 ];
2008         }
2009       }
2010
2011       // find middle point for (0,1,2,3)
2012       // and create a node in this point;
2013       gp_XYZ p( 0,0,0 );
2014       if ( surface.IsNull() ) {
2015         for(i=0; i<4; i++)
2016           p += gp_XYZ(aNodes[i]->X(), aNodes[i]->Y(), aNodes[i]->Z() );
2017         p /= 4;
2018       }
2019       else {
2020         TopoDS_Face geomFace = TopoDS::Face( helper.GetSubShape() );
2021         gp_XY uv( 0,0 );
2022         for(i=0; i<4; i++)
2023           uv += helper.GetNodeUV( geomFace, aNodes[i], inFaceNode );
2024         uv /= 4.;
2025         p = surface->Value( uv.X(), uv.Y() ).XYZ();
2026       }
2027       const SMDS_MeshNode* newN = aMesh->AddNode( p.X(), p.Y(), p.Z() );
2028       myLastCreatedNodes.Append(newN);
2029
2030       // create a new element
2031       const SMDS_MeshElement* newElem1 = 0;
2032       const SMDS_MeshElement* newElem2 = 0;
2033       if ( the13Diag ) {
2034         newElem1 = aMesh->AddFace(aNodes[2], aNodes[3], aNodes[0],
2035                                   aNodes[6], aNodes[7], newN );
2036         newElem2 = aMesh->AddFace(aNodes[2], aNodes[0], aNodes[1],
2037                                   newN,      aNodes[4], aNodes[5] );
2038       }
2039       else {
2040         newElem1 = aMesh->AddFace(aNodes[3], aNodes[0], aNodes[1],
2041                                   aNodes[7], aNodes[4], newN );
2042         newElem2 = aMesh->AddFace(aNodes[3], aNodes[1], aNodes[2],
2043                                   newN,      aNodes[5], aNodes[6] );
2044       }
2045       myLastCreatedElems.Append(newElem1);
2046       myLastCreatedElems.Append(newElem2);
2047       // put a new triangle on the same shape and add to the same groups
2048       if ( aShapeId )
2049         {
2050           aMesh->SetMeshElementOnShape( newElem1, aShapeId );
2051           aMesh->SetMeshElementOnShape( newElem2, aShapeId );
2052         }
2053       AddToSameGroups( newElem1, elem, aMesh );
2054       AddToSameGroups( newElem2, elem, aMesh );
2055       aMesh->RemoveElement( elem );
2056     }
2057   }
2058
2059   return true;
2060 }
2061
2062 //=======================================================================
2063 //function : getAngle
2064 //purpose  :
2065 //=======================================================================
2066
2067 double getAngle(const SMDS_MeshElement * tr1,
2068                 const SMDS_MeshElement * tr2,
2069                 const SMDS_MeshNode *    n1,
2070                 const SMDS_MeshNode *    n2)
2071 {
2072   double angle = 2. * M_PI; // bad angle
2073
2074   // get normals
2075   SMESH::Controls::TSequenceOfXYZ P1, P2;
2076   if ( !SMESH::Controls::NumericalFunctor::GetPoints( tr1, P1 ) ||
2077        !SMESH::Controls::NumericalFunctor::GetPoints( tr2, P2 ))
2078     return angle;
2079   gp_Vec N1,N2;
2080   if(!tr1->IsQuadratic())
2081     N1 = gp_Vec( P1(2) - P1(1) ) ^ gp_Vec( P1(3) - P1(1) );
2082   else
2083     N1 = gp_Vec( P1(3) - P1(1) ) ^ gp_Vec( P1(5) - P1(1) );
2084   if ( N1.SquareMagnitude() <= gp::Resolution() )
2085     return angle;
2086   if(!tr2->IsQuadratic())
2087     N2 = gp_Vec( P2(2) - P2(1) ) ^ gp_Vec( P2(3) - P2(1) );
2088   else
2089     N2 = gp_Vec( P2(3) - P2(1) ) ^ gp_Vec( P2(5) - P2(1) );
2090   if ( N2.SquareMagnitude() <= gp::Resolution() )
2091     return angle;
2092
2093   // find the first diagonal node n1 in the triangles:
2094   // take in account a diagonal link orientation
2095   const SMDS_MeshElement *nFirst[2], *tr[] = { tr1, tr2 };
2096   for ( int t = 0; t < 2; t++ ) {
2097     SMDS_ElemIteratorPtr it = tr[ t ]->nodesIterator();
2098     int i = 0, iDiag = -1;
2099     while ( it->more()) {
2100       const SMDS_MeshElement *n = it->next();
2101       if ( n == n1 || n == n2 ) {
2102         if ( iDiag < 0)
2103           iDiag = i;
2104         else {
2105           if ( i - iDiag == 1 )
2106             nFirst[ t ] = ( n == n1 ? n2 : n1 );
2107           else
2108             nFirst[ t ] = n;
2109           break;
2110         }
2111       }
2112       i++;
2113     }
2114   }
2115   if ( nFirst[ 0 ] == nFirst[ 1 ] )
2116     N2.Reverse();
2117
2118   angle = N1.Angle( N2 );
2119   //SCRUTE( angle );
2120   return angle;
2121 }
2122
2123 // =================================================
2124 // class generating a unique ID for a pair of nodes
2125 // and able to return nodes by that ID
2126 // =================================================
2127 class LinkID_Gen {
2128 public:
2129
2130   LinkID_Gen( const SMESHDS_Mesh* theMesh )
2131     :myMesh( theMesh ), myMaxID( theMesh->MaxNodeID() + 1)
2132   {}
2133
2134   long GetLinkID (const SMDS_MeshNode * n1,
2135                   const SMDS_MeshNode * n2) const
2136   {
2137     return ( Min(n1->GetID(),n2->GetID()) * myMaxID + Max(n1->GetID(),n2->GetID()));
2138   }
2139
2140   bool GetNodes (const long             theLinkID,
2141                  const SMDS_MeshNode* & theNode1,
2142                  const SMDS_MeshNode* & theNode2) const
2143   {
2144     theNode1 = myMesh->FindNode( theLinkID / myMaxID );
2145     if ( !theNode1 ) return false;
2146     theNode2 = myMesh->FindNode( theLinkID % myMaxID );
2147     if ( !theNode2 ) return false;
2148     return true;
2149   }
2150
2151 private:
2152   LinkID_Gen();
2153   const SMESHDS_Mesh* myMesh;
2154   long                myMaxID;
2155 };
2156
2157
2158 //=======================================================================
2159 //function : TriToQuad
2160 //purpose  : Fuse neighbour triangles into quadrangles.
2161 //           theCrit is used to select a neighbour to fuse with.
2162 //           theMaxAngle is a max angle between element normals at which
2163 //           fusion is still performed.
2164 //=======================================================================
2165
2166 bool SMESH_MeshEditor::TriToQuad (TIDSortedElemSet &                   theElems,
2167                                   SMESH::Controls::NumericalFunctorPtr theCrit,
2168                                   const double                         theMaxAngle)
2169 {
2170   myLastCreatedElems.Clear();
2171   myLastCreatedNodes.Clear();
2172
2173   MESSAGE( "::TriToQuad()" );
2174
2175   if ( !theCrit.get() )
2176     return false;
2177
2178   SMESHDS_Mesh * aMesh = GetMeshDS();
2179
2180   // Prepare data for algo: build
2181   // 1. map of elements with their linkIDs
2182   // 2. map of linkIDs with their elements
2183
2184   map< SMESH_TLink, list< const SMDS_MeshElement* > > mapLi_listEl;
2185   map< SMESH_TLink, list< const SMDS_MeshElement* > >::iterator itLE;
2186   map< const SMDS_MeshElement*, set< SMESH_TLink > >  mapEl_setLi;
2187   map< const SMDS_MeshElement*, set< SMESH_TLink > >::iterator itEL;
2188
2189   TIDSortedElemSet::iterator itElem;
2190   for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
2191     const SMDS_MeshElement* elem = *itElem;
2192     if(!elem || elem->GetType() != SMDSAbs_Face ) continue;
2193     bool IsTria = elem->NbNodes()==3 || (elem->NbNodes()==6 && elem->IsQuadratic());
2194     if(!IsTria) continue;
2195
2196     // retrieve element nodes
2197     const SMDS_MeshNode* aNodes [4];
2198     SMDS_ElemIteratorPtr itN = elem->nodesIterator();
2199     int i = 0;
2200     while ( i<3 )
2201       aNodes[ i++ ] = cast2Node( itN->next() );
2202     aNodes[ 3 ] = aNodes[ 0 ];
2203
2204     // fill maps
2205     for ( i = 0; i < 3; i++ ) {
2206       SMESH_TLink link( aNodes[i], aNodes[i+1] );
2207       // check if elements sharing a link can be fused
2208       itLE = mapLi_listEl.find( link );
2209       if ( itLE != mapLi_listEl.end() ) {
2210         if ((*itLE).second.size() > 1 ) // consider only 2 elems adjacent by a link
2211           continue;
2212         const SMDS_MeshElement* elem2 = (*itLE).second.front();
2213         //if ( FindShape( elem ) != FindShape( elem2 ))
2214         //  continue; // do not fuse triangles laying on different shapes
2215         if ( getAngle( elem, elem2, aNodes[i], aNodes[i+1] ) > theMaxAngle )
2216           continue; // avoid making badly shaped quads
2217         (*itLE).second.push_back( elem );
2218       }
2219       else {
2220         mapLi_listEl[ link ].push_back( elem );
2221       }
2222       mapEl_setLi [ elem ].insert( link );
2223     }
2224   }
2225   // Clean the maps from the links shared by a sole element, ie
2226   // links to which only one element is bound in mapLi_listEl
2227
2228   for ( itLE = mapLi_listEl.begin(); itLE != mapLi_listEl.end(); itLE++ ) {
2229     int nbElems = (*itLE).second.size();
2230     if ( nbElems < 2  ) {
2231       const SMDS_MeshElement* elem = (*itLE).second.front();
2232       SMESH_TLink link = (*itLE).first;
2233       mapEl_setLi[ elem ].erase( link );
2234       if ( mapEl_setLi[ elem ].empty() )
2235         mapEl_setLi.erase( elem );
2236     }
2237   }
2238
2239   // Algo: fuse triangles into quadrangles
2240
2241   while ( ! mapEl_setLi.empty() ) {
2242     // Look for the start element:
2243     // the element having the least nb of shared links
2244     const SMDS_MeshElement* startElem = 0;
2245     int minNbLinks = 4;
2246     for ( itEL = mapEl_setLi.begin(); itEL != mapEl_setLi.end(); itEL++ ) {
2247       int nbLinks = (*itEL).second.size();
2248       if ( nbLinks < minNbLinks ) {
2249         startElem = (*itEL).first;
2250         minNbLinks = nbLinks;
2251         if ( minNbLinks == 1 )
2252           break;
2253       }
2254     }
2255
2256     // search elements to fuse starting from startElem or links of elements
2257     // fused earlyer - startLinks
2258     list< SMESH_TLink > startLinks;
2259     while ( startElem || !startLinks.empty() ) {
2260       while ( !startElem && !startLinks.empty() ) {
2261         // Get an element to start, by a link
2262         SMESH_TLink linkId = startLinks.front();
2263         startLinks.pop_front();
2264         itLE = mapLi_listEl.find( linkId );
2265         if ( itLE != mapLi_listEl.end() ) {
2266           list< const SMDS_MeshElement* > & listElem = (*itLE).second;
2267           list< const SMDS_MeshElement* >::iterator itE = listElem.begin();
2268           for ( ; itE != listElem.end() ; itE++ )
2269             if ( mapEl_setLi.find( (*itE) ) != mapEl_setLi.end() )
2270               startElem = (*itE);
2271           mapLi_listEl.erase( itLE );
2272         }
2273       }
2274
2275       if ( startElem ) {
2276         // Get candidates to be fused
2277         const SMDS_MeshElement *tr1 = startElem, *tr2 = 0, *tr3 = 0;
2278         const SMESH_TLink *link12, *link13;
2279         startElem = 0;
2280         ASSERT( mapEl_setLi.find( tr1 ) != mapEl_setLi.end() );
2281         set< SMESH_TLink >& setLi = mapEl_setLi[ tr1 ];
2282         ASSERT( !setLi.empty() );
2283         set< SMESH_TLink >::iterator itLi;
2284         for ( itLi = setLi.begin(); itLi != setLi.end(); itLi++ )
2285         {
2286           const SMESH_TLink & link = (*itLi);
2287           itLE = mapLi_listEl.find( link );
2288           if ( itLE == mapLi_listEl.end() )
2289             continue;
2290
2291           const SMDS_MeshElement* elem = (*itLE).second.front();
2292           if ( elem == tr1 )
2293             elem = (*itLE).second.back();
2294           mapLi_listEl.erase( itLE );
2295           if ( mapEl_setLi.find( elem ) == mapEl_setLi.end())
2296             continue;
2297           if ( tr2 ) {
2298             tr3 = elem;
2299             link13 = &link;
2300           }
2301           else {
2302             tr2 = elem;
2303             link12 = &link;
2304           }
2305
2306           // add other links of elem to list of links to re-start from
2307           set< SMESH_TLink >& links = mapEl_setLi[ elem ];
2308           set< SMESH_TLink >::iterator it;
2309           for ( it = links.begin(); it != links.end(); it++ ) {
2310             const SMESH_TLink& link2 = (*it);
2311             if ( link2 != link )
2312               startLinks.push_back( link2 );
2313           }
2314         }
2315
2316         // Get nodes of possible quadrangles
2317         const SMDS_MeshNode *n12 [4], *n13 [4];
2318         bool Ok12 = false, Ok13 = false;
2319         const SMDS_MeshNode *linkNode1, *linkNode2;
2320         if(tr2) {
2321           linkNode1 = link12->first;
2322           linkNode2 = link12->second;
2323           if ( tr2 && getQuadrangleNodes( n12, linkNode1, linkNode2, tr1, tr2 ))
2324             Ok12 = true;
2325         }
2326         if(tr3) {
2327           linkNode1 = link13->first;
2328           linkNode2 = link13->second;
2329           if ( tr3 && getQuadrangleNodes( n13, linkNode1, linkNode2, tr1, tr3 ))
2330             Ok13 = true;
2331         }
2332
2333         // Choose a pair to fuse
2334         if ( Ok12 && Ok13 ) {
2335           SMDS_FaceOfNodes quad12 ( n12[ 0 ], n12[ 1 ], n12[ 2 ], n12[ 3 ] );
2336           SMDS_FaceOfNodes quad13 ( n13[ 0 ], n13[ 1 ], n13[ 2 ], n13[ 3 ] );
2337           double aBadRate12 = getBadRate( &quad12, theCrit );
2338           double aBadRate13 = getBadRate( &quad13, theCrit );
2339           if (  aBadRate13 < aBadRate12 )
2340             Ok12 = false;
2341           else
2342             Ok13 = false;
2343         }
2344
2345         // Make quadrangles
2346         // and remove fused elems and removed links from the maps
2347         mapEl_setLi.erase( tr1 );
2348         if ( Ok12 ) {
2349           mapEl_setLi.erase( tr2 );
2350           mapLi_listEl.erase( *link12 );
2351           if(tr1->NbNodes()==3) {
2352             const SMDS_MeshElement* newElem = 0;
2353             newElem = aMesh->AddFace(n12[0], n12[1], n12[2], n12[3] );
2354             myLastCreatedElems.Append(newElem);
2355             AddToSameGroups( newElem, tr1, aMesh );
2356             int aShapeId = tr1->getshapeId();
2357             if ( aShapeId )
2358               {
2359                 aMesh->SetMeshElementOnShape( newElem, aShapeId );
2360               }
2361             aMesh->RemoveElement( tr1 );
2362             aMesh->RemoveElement( tr2 );
2363           }
2364           else {
2365             const SMDS_MeshNode* N1 [6];
2366             const SMDS_MeshNode* N2 [6];
2367             GetNodesFromTwoTria(tr1,tr2,N1,N2);
2368             // now we receive following N1 and N2 (using numeration as above image)
2369             // tria1 : (1 2 4 5 9 7)  and  tria2 : (3 4 2 8 9 6)
2370             // i.e. first nodes from both arrays determ new diagonal
2371             const SMDS_MeshNode* aNodes[8];
2372             aNodes[0] = N1[0];
2373             aNodes[1] = N1[1];
2374             aNodes[2] = N2[0];
2375             aNodes[3] = N2[1];
2376             aNodes[4] = N1[3];
2377             aNodes[5] = N2[5];
2378             aNodes[6] = N2[3];
2379             aNodes[7] = N1[5];
2380             const SMDS_MeshElement* newElem = 0;
2381             newElem = aMesh->AddFace(aNodes[0], aNodes[1], aNodes[2], aNodes[3],
2382                                      aNodes[4], aNodes[5], aNodes[6], aNodes[7]);
2383             myLastCreatedElems.Append(newElem);
2384             AddToSameGroups( newElem, tr1, aMesh );
2385             int aShapeId = tr1->getshapeId();
2386             if ( aShapeId )
2387               {
2388                 aMesh->SetMeshElementOnShape( newElem, aShapeId );
2389               }
2390             aMesh->RemoveElement( tr1 );
2391             aMesh->RemoveElement( tr2 );
2392             // remove middle node (9)
2393             GetMeshDS()->RemoveNode( N1[4] );
2394           }
2395         }
2396         else if ( Ok13 ) {
2397           mapEl_setLi.erase( tr3 );
2398           mapLi_listEl.erase( *link13 );
2399           if(tr1->NbNodes()==3) {
2400             const SMDS_MeshElement* newElem = 0;
2401             newElem = aMesh->AddFace(n13[0], n13[1], n13[2], n13[3] );
2402             myLastCreatedElems.Append(newElem);
2403             AddToSameGroups( newElem, tr1, aMesh );
2404             int aShapeId = tr1->getshapeId();
2405             if ( aShapeId )
2406               {
2407                 aMesh->SetMeshElementOnShape( newElem, aShapeId );
2408               }
2409             aMesh->RemoveElement( tr1 );
2410             aMesh->RemoveElement( tr3 );
2411           }
2412           else {
2413             const SMDS_MeshNode* N1 [6];
2414             const SMDS_MeshNode* N2 [6];
2415             GetNodesFromTwoTria(tr1,tr3,N1,N2);
2416             // now we receive following N1 and N2 (using numeration as above image)
2417             // tria1 : (1 2 4 5 9 7)  and  tria2 : (3 4 2 8 9 6)
2418             // i.e. first nodes from both arrays determ new diagonal
2419             const SMDS_MeshNode* aNodes[8];
2420             aNodes[0] = N1[0];
2421             aNodes[1] = N1[1];
2422             aNodes[2] = N2[0];
2423             aNodes[3] = N2[1];
2424             aNodes[4] = N1[3];
2425             aNodes[5] = N2[5];
2426             aNodes[6] = N2[3];
2427             aNodes[7] = N1[5];
2428             const SMDS_MeshElement* newElem = 0;
2429             newElem = aMesh->AddFace(aNodes[0], aNodes[1], aNodes[2], aNodes[3],
2430                                      aNodes[4], aNodes[5], aNodes[6], aNodes[7]);
2431             myLastCreatedElems.Append(newElem);
2432             AddToSameGroups( newElem, tr1, aMesh );
2433             int aShapeId = tr1->getshapeId();
2434             if ( aShapeId )
2435               {
2436                 aMesh->SetMeshElementOnShape( newElem, aShapeId );
2437               }
2438             aMesh->RemoveElement( tr1 );
2439             aMesh->RemoveElement( tr3 );
2440             // remove middle node (9)
2441             GetMeshDS()->RemoveNode( N1[4] );
2442           }
2443         }
2444
2445         // Next element to fuse: the rejected one
2446         if ( tr3 )
2447           startElem = Ok12 ? tr3 : tr2;
2448
2449       } // if ( startElem )
2450     } // while ( startElem || !startLinks.empty() )
2451   } // while ( ! mapEl_setLi.empty() )
2452
2453   return true;
2454 }
2455
2456
2457 /*#define DUMPSO(txt) \
2458 //  cout << txt << endl;
2459 //=============================================================================
2460 //
2461 //
2462 //
2463 //=============================================================================
2464 static void swap( int i1, int i2, int idNodes[], gp_Pnt P[] )
2465 {
2466 if ( i1 == i2 )
2467 return;
2468 int tmp = idNodes[ i1 ];
2469 idNodes[ i1 ] = idNodes[ i2 ];
2470 idNodes[ i2 ] = tmp;
2471 gp_Pnt Ptmp = P[ i1 ];
2472 P[ i1 ] = P[ i2 ];
2473 P[ i2 ] = Ptmp;
2474 DUMPSO( i1 << "(" << idNodes[ i2 ] << ") <-> " << i2 << "(" << idNodes[ i1 ] << ")");
2475 }
2476
2477 //=======================================================================
2478 //function : SortQuadNodes
2479 //purpose  : Set 4 nodes of a quadrangle face in a good order.
2480 //           Swap 1<->2 or 2<->3 nodes and correspondingly return
2481 //           1 or 2 else 0.
2482 //=======================================================================
2483
2484 int SMESH_MeshEditor::SortQuadNodes (const SMDS_Mesh * theMesh,
2485 int               idNodes[] )
2486 {
2487   gp_Pnt P[4];
2488   int i;
2489   for ( i = 0; i < 4; i++ ) {
2490     const SMDS_MeshNode *n = theMesh->FindNode( idNodes[i] );
2491     if ( !n ) return 0;
2492     P[ i ].SetCoord( n->X(), n->Y(), n->Z() );
2493   }
2494
2495   gp_Vec V1(P[0], P[1]);
2496   gp_Vec V2(P[0], P[2]);
2497   gp_Vec V3(P[0], P[3]);
2498
2499   gp_Vec Cross1 = V1 ^ V2;
2500   gp_Vec Cross2 = V2 ^ V3;
2501
2502   i = 0;
2503   if (Cross1.Dot(Cross2) < 0)
2504   {
2505     Cross1 = V2 ^ V1;
2506     Cross2 = V1 ^ V3;
2507
2508     if (Cross1.Dot(Cross2) < 0)
2509       i = 2;
2510     else
2511       i = 1;
2512     swap ( i, i + 1, idNodes, P );
2513
2514     //     for ( int ii = 0; ii < 4; ii++ ) {
2515     //       const SMDS_MeshNode *n = theMesh->FindNode( idNodes[ii] );
2516     //       DUMPSO( ii << "(" << idNodes[ii] <<") : "<<n->X()<<" "<<n->Y()<<" "<<n->Z());
2517     //     }
2518   }
2519   return i;
2520 }
2521
2522 //=======================================================================
2523 //function : SortHexaNodes
2524 //purpose  : Set 8 nodes of a hexahedron in a good order.
2525 //           Return success status
2526 //=======================================================================
2527
2528 bool SMESH_MeshEditor::SortHexaNodes (const SMDS_Mesh * theMesh,
2529                                       int               idNodes[] )
2530 {
2531   gp_Pnt P[8];
2532   int i;
2533   DUMPSO( "INPUT: ========================================");
2534   for ( i = 0; i < 8; i++ ) {
2535     const SMDS_MeshNode *n = theMesh->FindNode( idNodes[i] );
2536     if ( !n ) return false;
2537     P[ i ].SetCoord( n->X(), n->Y(), n->Z() );
2538     DUMPSO( i << "(" << idNodes[i] <<") : "<<n->X()<<" "<<n->Y()<<" "<<n->Z());
2539   }
2540   DUMPSO( "========================================");
2541
2542
2543   set<int> faceNodes;  // ids of bottom face nodes, to be found
2544   set<int> checkedId1; // ids of tried 2-nd nodes
2545   Standard_Real leastDist = DBL_MAX; // dist of the 4-th node from 123 plane
2546   const Standard_Real tol = 1.e-6;   // tolerance to find nodes in plane
2547   int iMin, iLoop1 = 0;
2548
2549   // Loop to try the 2-nd nodes
2550
2551   while ( leastDist > DBL_MIN && ++iLoop1 < 8 )
2552   {
2553     // Find not checked 2-nd node
2554     for ( i = 1; i < 8; i++ )
2555       if ( checkedId1.find( idNodes[i] ) == checkedId1.end() ) {
2556         int id1 = idNodes[i];
2557         swap ( 1, i, idNodes, P );
2558         checkedId1.insert ( id1 );
2559         break;
2560       }
2561
2562     // Find the 3-d node so that 1-2-3 triangle to be on a hexa face,
2563     // ie that all but meybe one (id3 which is on the same face) nodes
2564     // lay on the same side from the triangle plane.
2565
2566     bool manyInPlane = false; // more than 4 nodes lay in plane
2567     int iLoop2 = 0;
2568     while ( ++iLoop2 < 6 ) {
2569
2570       // get 1-2-3 plane coeffs
2571       Standard_Real A, B, C, D;
2572       gp_Vec N = gp_Vec (P[0], P[1]).Crossed( gp_Vec (P[0], P[2]) );
2573       if ( N.SquareMagnitude() > gp::Resolution() )
2574       {
2575         gp_Pln pln ( P[0], N );
2576         pln.Coefficients( A, B, C, D );
2577
2578         // find the node (iMin) closest to pln
2579         Standard_Real dist[ 8 ], minDist = DBL_MAX;
2580         set<int> idInPln;
2581         for ( i = 3; i < 8; i++ ) {
2582           dist[i] = A * P[i].X() + B * P[i].Y() + C * P[i].Z() + D;
2583           if ( fabs( dist[i] ) < minDist ) {
2584             minDist = fabs( dist[i] );
2585             iMin = i;
2586           }
2587           if ( fabs( dist[i] ) <= tol )
2588             idInPln.insert( idNodes[i] );
2589         }
2590
2591         // there should not be more than 4 nodes in bottom plane
2592         if ( idInPln.size() > 1 )
2593         {
2594           DUMPSO( "### idInPln.size() = " << idInPln.size());
2595           // idInPlane does not contain the first 3 nodes
2596           if ( manyInPlane || idInPln.size() == 5)
2597             return false; // all nodes in one plane
2598           manyInPlane = true;
2599
2600           // set the 1-st node to be not in plane
2601           for ( i = 3; i < 8; i++ ) {
2602             if ( idInPln.find( idNodes[ i ] ) == idInPln.end() ) {
2603               DUMPSO( "### Reset 0-th node");
2604               swap( 0, i, idNodes, P );
2605               break;
2606             }
2607           }
2608
2609           // reset to re-check second nodes
2610           leastDist = DBL_MAX;
2611           faceNodes.clear();
2612           checkedId1.clear();
2613           iLoop1 = 0;
2614           break; // from iLoop2;
2615         }
2616
2617         // check that the other 4 nodes are on the same side
2618         bool sameSide = true;
2619         bool isNeg = dist[ iMin == 3 ? 4 : 3 ] <= 0.;
2620         for ( i = 3; sameSide && i < 8; i++ ) {
2621           if ( i != iMin )
2622             sameSide = ( isNeg == dist[i] <= 0.);
2623         }
2624
2625         // keep best solution
2626         if ( sameSide && minDist < leastDist ) {
2627           leastDist = minDist;
2628           faceNodes.clear();
2629           faceNodes.insert( idNodes[ 1 ] );
2630           faceNodes.insert( idNodes[ 2 ] );
2631           faceNodes.insert( idNodes[ iMin ] );
2632           DUMPSO( "loop " << iLoop2 << " id2 " << idNodes[ 1 ] << " id3 " << idNodes[ 2 ]
2633                   << " leastDist = " << leastDist);
2634           if ( leastDist <= DBL_MIN )
2635             break;
2636         }
2637       }
2638
2639       // set next 3-d node to check
2640       int iNext = 2 + iLoop2;
2641       if ( iNext < 8 ) {
2642         DUMPSO( "Try 2-nd");
2643         swap ( 2, iNext, idNodes, P );
2644       }
2645     } // while ( iLoop2 < 6 )
2646   } // iLoop1
2647
2648   if ( faceNodes.empty() ) return false;
2649
2650   // Put the faceNodes in proper places
2651   for ( i = 4; i < 8; i++ ) {
2652     if ( faceNodes.find( idNodes[ i ] ) != faceNodes.end() ) {
2653       // find a place to put
2654       int iTo = 1;
2655       while ( faceNodes.find( idNodes[ iTo ] ) != faceNodes.end() )
2656         iTo++;
2657       DUMPSO( "Set faceNodes");
2658       swap ( iTo, i, idNodes, P );
2659     }
2660   }
2661
2662
2663   // Set nodes of the found bottom face in good order
2664   DUMPSO( " Found bottom face: ");
2665   i = SortQuadNodes( theMesh, idNodes );
2666   if ( i ) {
2667     gp_Pnt Ptmp = P[ i ];
2668     P[ i ] = P[ i+1 ];
2669     P[ i+1 ] = Ptmp;
2670   }
2671   //   else
2672   //     for ( int ii = 0; ii < 4; ii++ ) {
2673   //       const SMDS_MeshNode *n = theMesh->FindNode( idNodes[ii] );
2674   //       DUMPSO( ii << "(" << idNodes[ii] <<") : "<<n->X()<<" "<<n->Y()<<" "<<n->Z());
2675   //    }
2676
2677   // Gravity center of the top and bottom faces
2678   gp_Pnt aGCb = ( P[0].XYZ() + P[1].XYZ() + P[2].XYZ() + P[3].XYZ() ) / 4.;
2679   gp_Pnt aGCt = ( P[4].XYZ() + P[5].XYZ() + P[6].XYZ() + P[7].XYZ() ) / 4.;
2680
2681   // Get direction from the bottom to the top face
2682   gp_Vec upDir ( aGCb, aGCt );
2683   Standard_Real upDirSize = upDir.Magnitude();
2684   if ( upDirSize <= gp::Resolution() ) return false;
2685   upDir / upDirSize;
2686
2687   // Assure that the bottom face normal points up
2688   gp_Vec Nb = gp_Vec (P[0], P[1]).Crossed( gp_Vec (P[0], P[2]) );
2689   Nb += gp_Vec (P[0], P[2]).Crossed( gp_Vec (P[0], P[3]) );
2690   if ( Nb.Dot( upDir ) < 0 ) {
2691     DUMPSO( "Reverse bottom face");
2692     swap( 1, 3, idNodes, P );
2693   }
2694
2695   // Find 5-th node - the one closest to the 1-st among the last 4 nodes.
2696   Standard_Real minDist = DBL_MAX;
2697   for ( i = 4; i < 8; i++ ) {
2698     // projection of P[i] to the plane defined by P[0] and upDir
2699     gp_Pnt Pp = P[i].Translated( upDir * ( upDir.Dot( gp_Vec( P[i], P[0] ))));
2700     Standard_Real sqDist = P[0].SquareDistance( Pp );
2701     if ( sqDist < minDist ) {
2702       minDist = sqDist;
2703       iMin = i;
2704     }
2705   }
2706   DUMPSO( "Set 4-th");
2707   swap ( 4, iMin, idNodes, P );
2708
2709   // Set nodes of the top face in good order
2710   DUMPSO( "Sort top face");
2711   i = SortQuadNodes( theMesh, &idNodes[4] );
2712   if ( i ) {
2713     i += 4;
2714     gp_Pnt Ptmp = P[ i ];
2715     P[ i ] = P[ i+1 ];
2716     P[ i+1 ] = Ptmp;
2717   }
2718
2719   // Assure that direction of the top face normal is from the bottom face
2720   gp_Vec Nt = gp_Vec (P[4], P[5]).Crossed( gp_Vec (P[4], P[6]) );
2721   Nt += gp_Vec (P[4], P[6]).Crossed( gp_Vec (P[4], P[7]) );
2722   if ( Nt.Dot( upDir ) < 0 ) {
2723     DUMPSO( "Reverse top face");
2724     swap( 5, 7, idNodes, P );
2725   }
2726
2727   //   DUMPSO( "OUTPUT: ========================================");
2728   //   for ( i = 0; i < 8; i++ ) {
2729   //     float *p = ugrid->GetPoint(idNodes[i]);
2730   //     DUMPSO( i << "(" << idNodes[i] << ") : " << p[0] << " " << p[1] << " " << p[2]);
2731   //   }
2732
2733   return true;
2734 }*/
2735
2736 //================================================================================
2737 /*!
2738  * \brief Return nodes linked to the given one
2739  * \param theNode - the node
2740  * \param linkedNodes - the found nodes
2741  * \param type - the type of elements to check
2742  *
2743  * Medium nodes are ignored
2744  */
2745 //================================================================================
2746
2747 void SMESH_MeshEditor::GetLinkedNodes( const SMDS_MeshNode* theNode,
2748                                        TIDSortedElemSet &   linkedNodes,
2749                                        SMDSAbs_ElementType  type )
2750 {
2751   SMDS_ElemIteratorPtr elemIt = theNode->GetInverseElementIterator(type);
2752   while ( elemIt->more() )
2753   {
2754     const SMDS_MeshElement* elem = elemIt->next();
2755     if(elem->GetType() == SMDSAbs_0DElement)
2756       continue;
2757     
2758     SMDS_ElemIteratorPtr nodeIt = elem->nodesIterator();
2759     if ( elem->GetType() == SMDSAbs_Volume )
2760     {
2761       SMDS_VolumeTool vol( elem );
2762       while ( nodeIt->more() ) {
2763         const SMDS_MeshNode* n = cast2Node( nodeIt->next() );
2764         if ( theNode != n && vol.IsLinked( theNode, n ))
2765           linkedNodes.insert( n );
2766       }
2767     }
2768     else
2769     {
2770       for ( int i = 0; nodeIt->more(); ++i ) {
2771         const SMDS_MeshNode* n = cast2Node( nodeIt->next() );
2772         if ( n == theNode ) {
2773           int iBefore = i - 1;
2774           int iAfter  = i + 1;
2775           if ( elem->IsQuadratic() ) {
2776             int nb = elem->NbNodes() / 2;
2777             iAfter  = SMESH_MesherHelper::WrapIndex( iAfter, nb );
2778             iBefore = SMESH_MesherHelper::WrapIndex( iBefore, nb );
2779           }
2780           linkedNodes.insert( elem->GetNodeWrap( iAfter ));
2781           linkedNodes.insert( elem->GetNodeWrap( iBefore ));
2782         }
2783       }
2784     }
2785   }
2786 }
2787
2788 //=======================================================================
2789 //function : laplacianSmooth
2790 //purpose  : pulls theNode toward the center of surrounding nodes directly
2791 //           connected to that node along an element edge
2792 //=======================================================================
2793
2794 void laplacianSmooth(const SMDS_MeshNode*                 theNode,
2795                      const Handle(Geom_Surface)&          theSurface,
2796                      map< const SMDS_MeshNode*, gp_XY* >& theUVMap)
2797 {
2798   // find surrounding nodes
2799
2800   TIDSortedElemSet nodeSet;
2801   SMESH_MeshEditor::GetLinkedNodes( theNode, nodeSet, SMDSAbs_Face );
2802
2803   // compute new coodrs
2804
2805   double coord[] = { 0., 0., 0. };
2806   TIDSortedElemSet::iterator nodeSetIt = nodeSet.begin();
2807   for ( ; nodeSetIt != nodeSet.end(); nodeSetIt++ ) {
2808     const SMDS_MeshNode* node = cast2Node(*nodeSetIt);
2809     if ( theSurface.IsNull() ) { // smooth in 3D
2810       coord[0] += node->X();
2811       coord[1] += node->Y();
2812       coord[2] += node->Z();
2813     }
2814     else { // smooth in 2D
2815       ASSERT( theUVMap.find( node ) != theUVMap.end() );
2816       gp_XY* uv = theUVMap[ node ];
2817       coord[0] += uv->X();
2818       coord[1] += uv->Y();
2819     }
2820   }
2821   int nbNodes = nodeSet.size();
2822   if ( !nbNodes )
2823     return;
2824   coord[0] /= nbNodes;
2825   coord[1] /= nbNodes;
2826
2827   if ( !theSurface.IsNull() ) {
2828     ASSERT( theUVMap.find( theNode ) != theUVMap.end() );
2829     theUVMap[ theNode ]->SetCoord( coord[0], coord[1] );
2830     gp_Pnt p3d = theSurface->Value( coord[0], coord[1] );
2831     coord[0] = p3d.X();
2832     coord[1] = p3d.Y();
2833     coord[2] = p3d.Z();
2834   }
2835   else
2836     coord[2] /= nbNodes;
2837
2838   // move node
2839
2840   const_cast< SMDS_MeshNode* >( theNode )->setXYZ(coord[0],coord[1],coord[2]);
2841 }
2842
2843 //=======================================================================
2844 //function : centroidalSmooth
2845 //purpose  : pulls theNode toward the element-area-weighted centroid of the
2846 //           surrounding elements
2847 //=======================================================================
2848
2849 void centroidalSmooth(const SMDS_MeshNode*                 theNode,
2850                       const Handle(Geom_Surface)&          theSurface,
2851                       map< const SMDS_MeshNode*, gp_XY* >& theUVMap)
2852 {
2853   gp_XYZ aNewXYZ(0.,0.,0.);
2854   SMESH::Controls::Area anAreaFunc;
2855   double totalArea = 0.;
2856   int nbElems = 0;
2857
2858   // compute new XYZ
2859
2860   SMDS_ElemIteratorPtr elemIt = theNode->GetInverseElementIterator(SMDSAbs_Face);
2861   while ( elemIt->more() )
2862   {
2863     const SMDS_MeshElement* elem = elemIt->next();
2864     nbElems++;
2865
2866     gp_XYZ elemCenter(0.,0.,0.);
2867     SMESH::Controls::TSequenceOfXYZ aNodePoints;
2868     SMDS_ElemIteratorPtr itN = elem->nodesIterator();
2869     int nn = elem->NbNodes();
2870     if(elem->IsQuadratic()) nn = nn/2;
2871     int i=0;
2872     //while ( itN->more() ) {
2873     while ( i<nn ) {
2874       const SMDS_MeshNode* aNode = static_cast<const SMDS_MeshNode*>( itN->next() );
2875       i++;
2876       gp_XYZ aP( aNode->X(), aNode->Y(), aNode->Z() );
2877       aNodePoints.push_back( aP );
2878       if ( !theSurface.IsNull() ) { // smooth in 2D
2879         ASSERT( theUVMap.find( aNode ) != theUVMap.end() );
2880         gp_XY* uv = theUVMap[ aNode ];
2881         aP.SetCoord( uv->X(), uv->Y(), 0. );
2882       }
2883       elemCenter += aP;
2884     }
2885     double elemArea = anAreaFunc.GetValue( aNodePoints );
2886     totalArea += elemArea;
2887     elemCenter /= nn;
2888     aNewXYZ += elemCenter * elemArea;
2889   }
2890   aNewXYZ /= totalArea;
2891   if ( !theSurface.IsNull() ) {
2892     theUVMap[ theNode ]->SetCoord( aNewXYZ.X(), aNewXYZ.Y() );
2893     aNewXYZ = theSurface->Value( aNewXYZ.X(), aNewXYZ.Y() ).XYZ();
2894   }
2895
2896   // move node
2897
2898   const_cast< SMDS_MeshNode* >( theNode )->setXYZ(aNewXYZ.X(),aNewXYZ.Y(),aNewXYZ.Z());
2899 }
2900
2901 //=======================================================================
2902 //function : getClosestUV
2903 //purpose  : return UV of closest projection
2904 //=======================================================================
2905
2906 static bool getClosestUV (Extrema_GenExtPS& projector,
2907                           const gp_Pnt&     point,
2908                           gp_XY &           result)
2909 {
2910   projector.Perform( point );
2911   if ( projector.IsDone() ) {
2912     double u, v, minVal = DBL_MAX;
2913     for ( int i = projector.NbExt(); i > 0; i-- )
2914 #if OCC_VERSION_LARGE > 0x06040000 // Porting to OCCT6.5.1
2915       if ( projector.SquareDistance( i ) < minVal ) {
2916         minVal = projector.SquareDistance( i );
2917 #else
2918       if ( projector.Value( i ) < minVal ) {
2919         minVal = projector.Value( i );
2920 #endif
2921         projector.Point( i ).Parameter( u, v );
2922       }
2923     result.SetCoord( u, v );
2924     return true;
2925   }
2926   return false;
2927 }
2928
2929 //=======================================================================
2930 //function : Smooth
2931 //purpose  : Smooth theElements during theNbIterations or until a worst
2932 //           element has aspect ratio <= theTgtAspectRatio.
2933 //           Aspect Ratio varies in range [1.0, inf].
2934 //           If theElements is empty, the whole mesh is smoothed.
2935 //           theFixedNodes contains additionally fixed nodes. Nodes built
2936 //           on edges and boundary nodes are always fixed.
2937 //=======================================================================
2938
2939 void SMESH_MeshEditor::Smooth (TIDSortedElemSet &          theElems,
2940                                set<const SMDS_MeshNode*> & theFixedNodes,
2941                                const SmoothMethod          theSmoothMethod,
2942                                const int                   theNbIterations,
2943                                double                      theTgtAspectRatio,
2944                                const bool                  the2D)
2945 {
2946   myLastCreatedElems.Clear();
2947   myLastCreatedNodes.Clear();
2948
2949   MESSAGE((theSmoothMethod==LAPLACIAN ? "LAPLACIAN" : "CENTROIDAL") << "--::Smooth()");
2950
2951   if ( theTgtAspectRatio < 1.0 )
2952     theTgtAspectRatio = 1.0;
2953
2954   const double disttol = 1.e-16;
2955
2956   SMESH::Controls::AspectRatio aQualityFunc;
2957
2958   SMESHDS_Mesh* aMesh = GetMeshDS();
2959
2960   if ( theElems.empty() ) {
2961     // add all faces to theElems
2962     SMDS_FaceIteratorPtr fIt = aMesh->facesIterator();
2963     while ( fIt->more() ) {
2964       const SMDS_MeshElement* face = fIt->next();
2965       theElems.insert( face );
2966     }
2967   }
2968   // get all face ids theElems are on
2969   set< int > faceIdSet;
2970   TIDSortedElemSet::iterator itElem;
2971   if ( the2D )
2972     for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
2973       int fId = FindShape( *itElem );
2974       // check that corresponding submesh exists and a shape is face
2975       if (fId &&
2976           faceIdSet.find( fId ) == faceIdSet.end() &&
2977           aMesh->MeshElements( fId )) {
2978         TopoDS_Shape F = aMesh->IndexToShape( fId );
2979         if ( !F.IsNull() && F.ShapeType() == TopAbs_FACE )
2980           faceIdSet.insert( fId );
2981       }
2982     }
2983   faceIdSet.insert( 0 ); // to smooth elements that are not on any TopoDS_Face
2984
2985   // ===============================================
2986   // smooth elements on each TopoDS_Face separately
2987   // ===============================================
2988
2989   set< int >::reverse_iterator fId = faceIdSet.rbegin(); // treate 0 fId at the end
2990   for ( ; fId != faceIdSet.rend(); ++fId ) {
2991     // get face surface and submesh
2992     Handle(Geom_Surface) surface;
2993     SMESHDS_SubMesh* faceSubMesh = 0;
2994     TopoDS_Face face;
2995     double fToler2 = 0, f,l;
2996     double u1 = 0, u2 = 0, v1 = 0, v2 = 0;
2997     bool isUPeriodic = false, isVPeriodic = false;
2998     if ( *fId ) {
2999       face = TopoDS::Face( aMesh->IndexToShape( *fId ));
3000       surface = BRep_Tool::Surface( face );
3001       faceSubMesh = aMesh->MeshElements( *fId );
3002       fToler2 = BRep_Tool::Tolerance( face );
3003       fToler2 *= fToler2 * 10.;
3004       isUPeriodic = surface->IsUPeriodic();
3005       if ( isUPeriodic )
3006         surface->UPeriod();
3007       isVPeriodic = surface->IsVPeriodic();
3008       if ( isVPeriodic )
3009         surface->VPeriod();
3010       surface->Bounds( u1, u2, v1, v2 );
3011     }
3012     // ---------------------------------------------------------
3013     // for elements on a face, find movable and fixed nodes and
3014     // compute UV for them
3015     // ---------------------------------------------------------
3016     bool checkBoundaryNodes = false;
3017     bool isQuadratic = false;
3018     set<const SMDS_MeshNode*> setMovableNodes;
3019     map< const SMDS_MeshNode*, gp_XY* > uvMap, uvMap2;
3020     list< gp_XY > listUV; // uvs the 2 uvMaps refer to
3021     list< const SMDS_MeshElement* > elemsOnFace;
3022
3023     Extrema_GenExtPS projector;
3024     GeomAdaptor_Surface surfAdaptor;
3025     if ( !surface.IsNull() ) {
3026       surfAdaptor.Load( surface );
3027       projector.Initialize( surfAdaptor, 20,20, 1e-5,1e-5 );
3028     }
3029     int nbElemOnFace = 0;
3030     itElem = theElems.begin();
3031     // loop on not yet smoothed elements: look for elems on a face
3032     while ( itElem != theElems.end() ) {
3033       if ( faceSubMesh && nbElemOnFace == faceSubMesh->NbElements() )
3034         break; // all elements found
3035
3036       const SMDS_MeshElement* elem = *itElem;
3037       if ( !elem || elem->GetType() != SMDSAbs_Face || elem->NbNodes() < 3 ||
3038            ( faceSubMesh && !faceSubMesh->Contains( elem ))) {
3039         ++itElem;
3040         continue;
3041       }
3042       elemsOnFace.push_back( elem );
3043       theElems.erase( itElem++ );
3044       nbElemOnFace++;
3045
3046       if ( !isQuadratic )
3047         isQuadratic = elem->IsQuadratic();
3048
3049       // get movable nodes of elem
3050       const SMDS_MeshNode* node;
3051       SMDS_TypeOfPosition posType;
3052       SMDS_ElemIteratorPtr itN = elem->nodesIterator();
3053       int nn = 0, nbn =  elem->NbNodes();
3054       if(elem->IsQuadratic())
3055         nbn = nbn/2;
3056       while ( nn++ < nbn ) {
3057         node = static_cast<const SMDS_MeshNode*>( itN->next() );
3058         const SMDS_PositionPtr& pos = node->GetPosition();
3059         posType = pos ? pos->GetTypeOfPosition() : SMDS_TOP_3DSPACE;
3060         if (posType != SMDS_TOP_EDGE &&
3061             posType != SMDS_TOP_VERTEX &&
3062             theFixedNodes.find( node ) == theFixedNodes.end())
3063         {
3064           // check if all faces around the node are on faceSubMesh
3065           // because a node on edge may be bound to face
3066           SMDS_ElemIteratorPtr eIt = node->GetInverseElementIterator(SMDSAbs_Face);
3067           bool all = true;
3068           if ( faceSubMesh ) {
3069             while ( eIt->more() && all ) {
3070               const SMDS_MeshElement* e = eIt->next();
3071               all = faceSubMesh->Contains( e );
3072             }
3073           }
3074           if ( all )
3075             setMovableNodes.insert( node );
3076           else
3077             checkBoundaryNodes = true;
3078         }
3079         if ( posType == SMDS_TOP_3DSPACE )
3080           checkBoundaryNodes = true;
3081       }
3082
3083       if ( surface.IsNull() )
3084         continue;
3085
3086       // get nodes to check UV
3087       list< const SMDS_MeshNode* > uvCheckNodes;
3088       itN = elem->nodesIterator();
3089       nn = 0; nbn =  elem->NbNodes();
3090       if(elem->IsQuadratic())
3091         nbn = nbn/2;
3092       while ( nn++ < nbn ) {
3093         node = static_cast<const SMDS_MeshNode*>( itN->next() );
3094         if ( uvMap.find( node ) == uvMap.end() )
3095           uvCheckNodes.push_back( node );
3096         // add nodes of elems sharing node
3097         //         SMDS_ElemIteratorPtr eIt = node->GetInverseElementIterator(SMDSAbs_Face);
3098         //         while ( eIt->more() ) {
3099         //           const SMDS_MeshElement* e = eIt->next();
3100         //           if ( e != elem ) {
3101         //             SMDS_ElemIteratorPtr nIt = e->nodesIterator();
3102         //             while ( nIt->more() ) {
3103         //               const SMDS_MeshNode* n =
3104         //                 static_cast<const SMDS_MeshNode*>( nIt->next() );
3105         //               if ( uvMap.find( n ) == uvMap.end() )
3106         //                 uvCheckNodes.push_back( n );
3107         //             }
3108         //           }
3109         //         }
3110       }
3111       // check UV on face
3112       list< const SMDS_MeshNode* >::iterator n = uvCheckNodes.begin();
3113       for ( ; n != uvCheckNodes.end(); ++n ) {
3114         node = *n;
3115         gp_XY uv( 0, 0 );
3116         const SMDS_PositionPtr& pos = node->GetPosition();
3117         posType = pos ? pos->GetTypeOfPosition() : SMDS_TOP_3DSPACE;
3118         // get existing UV
3119         switch ( posType ) {
3120         case SMDS_TOP_FACE: {
3121           SMDS_FacePosition* fPos = ( SMDS_FacePosition* ) pos;
3122           uv.SetCoord( fPos->GetUParameter(), fPos->GetVParameter() );
3123           break;
3124         }
3125         case SMDS_TOP_EDGE: {
3126           TopoDS_Shape S = aMesh->IndexToShape( node->getshapeId() );
3127           Handle(Geom2d_Curve) pcurve;
3128           if ( !S.IsNull() && S.ShapeType() == TopAbs_EDGE )
3129             pcurve = BRep_Tool::CurveOnSurface( TopoDS::Edge( S ), face, f,l );
3130           if ( !pcurve.IsNull() ) {
3131             double u = (( SMDS_EdgePosition* ) pos )->GetUParameter();
3132             uv = pcurve->Value( u ).XY();
3133           }
3134           break;
3135         }
3136         case SMDS_TOP_VERTEX: {
3137           TopoDS_Shape S = aMesh->IndexToShape( node->getshapeId() );
3138           if ( !S.IsNull() && S.ShapeType() == TopAbs_VERTEX )
3139             uv = BRep_Tool::Parameters( TopoDS::Vertex( S ), face ).XY();
3140           break;
3141         }
3142         default:;
3143         }
3144         // check existing UV
3145         bool project = true;
3146         gp_Pnt pNode ( node->X(), node->Y(), node->Z() );
3147         double dist1 = DBL_MAX, dist2 = 0;
3148         if ( posType != SMDS_TOP_3DSPACE ) {
3149           dist1 = pNode.SquareDistance( surface->Value( uv.X(), uv.Y() ));
3150           project = dist1 > fToler2;
3151         }
3152         if ( project ) { // compute new UV
3153           gp_XY newUV;
3154           if ( !getClosestUV( projector, pNode, newUV )) {
3155             MESSAGE("Node Projection Failed " << node);
3156           }
3157           else {
3158             if ( isUPeriodic )
3159               newUV.SetX( ElCLib::InPeriod( newUV.X(), u1, u2 ));
3160             if ( isVPeriodic )
3161               newUV.SetY( ElCLib::InPeriod( newUV.Y(), v1, v2 ));
3162             // check new UV
3163             if ( posType != SMDS_TOP_3DSPACE )
3164               dist2 = pNode.SquareDistance( surface->Value( newUV.X(), newUV.Y() ));
3165             if ( dist2 < dist1 )
3166               uv = newUV;
3167           }
3168         }
3169         // store UV in the map
3170         listUV.push_back( uv );
3171         uvMap.insert( make_pair( node, &listUV.back() ));
3172       }
3173     } // loop on not yet smoothed elements
3174
3175     if ( !faceSubMesh || nbElemOnFace != faceSubMesh->NbElements() )
3176       checkBoundaryNodes = true;
3177
3178     // fix nodes on mesh boundary
3179
3180     if ( checkBoundaryNodes ) {
3181       map< SMESH_TLink, int > linkNbMap; // how many times a link encounters in elemsOnFace
3182       map< SMESH_TLink, int >::iterator link_nb;
3183       // put all elements links to linkNbMap
3184       list< const SMDS_MeshElement* >::iterator elemIt = elemsOnFace.begin();
3185       for ( ; elemIt != elemsOnFace.end(); ++elemIt ) {
3186         const SMDS_MeshElement* elem = (*elemIt);
3187         int nbn =  elem->NbCornerNodes();
3188         // loop on elem links: insert them in linkNbMap
3189         for ( int iN = 0; iN < nbn; ++iN ) {
3190           const SMDS_MeshNode* n1 = elem->GetNode( iN );
3191           const SMDS_MeshNode* n2 = elem->GetNode(( iN+1 ) % nbn);
3192           SMESH_TLink link( n1, n2 );
3193           link_nb = linkNbMap.insert( make_pair( link, 0 )).first;
3194           link_nb->second++;
3195         }
3196       }
3197       // remove nodes that are in links encountered only once from setMovableNodes
3198       for ( link_nb = linkNbMap.begin(); link_nb != linkNbMap.end(); ++link_nb ) {
3199         if ( link_nb->second == 1 ) {
3200           setMovableNodes.erase( link_nb->first.node1() );
3201           setMovableNodes.erase( link_nb->first.node2() );
3202         }
3203       }
3204     }
3205
3206     // -----------------------------------------------------
3207     // for nodes on seam edge, compute one more UV ( uvMap2 );
3208     // find movable nodes linked to nodes on seam and which
3209     // are to be smoothed using the second UV ( uvMap2 )
3210     // -----------------------------------------------------
3211
3212     set<const SMDS_MeshNode*> nodesNearSeam; // to smooth using uvMap2
3213     if ( !surface.IsNull() ) {
3214       TopExp_Explorer eExp( face, TopAbs_EDGE );
3215       for ( ; eExp.More(); eExp.Next() ) {
3216         TopoDS_Edge edge = TopoDS::Edge( eExp.Current() );
3217         if ( !BRep_Tool::IsClosed( edge, face ))
3218           continue;
3219         SMESHDS_SubMesh* sm = aMesh->MeshElements( edge );
3220         if ( !sm ) continue;
3221         // find out which parameter varies for a node on seam
3222         double f,l;
3223         gp_Pnt2d uv1, uv2;
3224         Handle(Geom2d_Curve) pcurve = BRep_Tool::CurveOnSurface( edge, face, f, l );
3225         if ( pcurve.IsNull() ) continue;
3226         uv1 = pcurve->Value( f );
3227         edge.Reverse();
3228         pcurve = BRep_Tool::CurveOnSurface( edge, face, f, l );
3229         if ( pcurve.IsNull() ) continue;
3230         uv2 = pcurve->Value( f );
3231         int iPar = Abs( uv1.X() - uv2.X() ) > Abs( uv1.Y() - uv2.Y() ) ? 1 : 2;
3232         // assure uv1 < uv2
3233         if ( uv1.Coord( iPar ) > uv2.Coord( iPar )) {
3234           gp_Pnt2d tmp = uv1; uv1 = uv2; uv2 = tmp;
3235         }
3236         // get nodes on seam and its vertices
3237         list< const SMDS_MeshNode* > seamNodes;
3238         SMDS_NodeIteratorPtr nSeamIt = sm->GetNodes();
3239         while ( nSeamIt->more() ) {
3240           const SMDS_MeshNode* node = nSeamIt->next();
3241           if ( !isQuadratic || !IsMedium( node ))
3242             seamNodes.push_back( node );
3243         }
3244         TopExp_Explorer vExp( edge, TopAbs_VERTEX );
3245         for ( ; vExp.More(); vExp.Next() ) {
3246           sm = aMesh->MeshElements( vExp.Current() );
3247           if ( sm ) {
3248             nSeamIt = sm->GetNodes();
3249             while ( nSeamIt->more() )
3250               seamNodes.push_back( nSeamIt->next() );
3251           }
3252         }
3253         // loop on nodes on seam
3254         list< const SMDS_MeshNode* >::iterator noSeIt = seamNodes.begin();
3255         for ( ; noSeIt != seamNodes.end(); ++noSeIt ) {
3256           const SMDS_MeshNode* nSeam = *noSeIt;
3257           map< const SMDS_MeshNode*, gp_XY* >::iterator n_uv = uvMap.find( nSeam );
3258           if ( n_uv == uvMap.end() )
3259             continue;
3260           // set the first UV
3261           n_uv->second->SetCoord( iPar, uv1.Coord( iPar ));
3262           // set the second UV
3263           listUV.push_back( *n_uv->second );
3264           listUV.back().SetCoord( iPar, uv2.Coord( iPar ));
3265           if ( uvMap2.empty() )
3266             uvMap2 = uvMap; // copy the uvMap contents
3267           uvMap2[ nSeam ] = &listUV.back();
3268
3269           // collect movable nodes linked to ones on seam in nodesNearSeam
3270           SMDS_ElemIteratorPtr eIt = nSeam->GetInverseElementIterator(SMDSAbs_Face);
3271           while ( eIt->more() ) {
3272             const SMDS_MeshElement* e = eIt->next();
3273             int nbUseMap1 = 0, nbUseMap2 = 0;
3274             SMDS_ElemIteratorPtr nIt = e->nodesIterator();
3275             int nn = 0, nbn =  e->NbNodes();
3276             if(e->IsQuadratic()) nbn = nbn/2;
3277             while ( nn++ < nbn )
3278             {
3279               const SMDS_MeshNode* n =
3280                 static_cast<const SMDS_MeshNode*>( nIt->next() );
3281               if (n == nSeam ||
3282                   setMovableNodes.find( n ) == setMovableNodes.end() )
3283                 continue;
3284               // add only nodes being closer to uv2 than to uv1
3285               gp_Pnt pMid (0.5 * ( n->X() + nSeam->X() ),
3286                            0.5 * ( n->Y() + nSeam->Y() ),
3287                            0.5 * ( n->Z() + nSeam->Z() ));
3288               gp_XY uv;
3289               getClosestUV( projector, pMid, uv );
3290               if ( uv.Coord( iPar ) > uvMap[ n ]->Coord( iPar ) ) {
3291                 nodesNearSeam.insert( n );
3292                 nbUseMap2++;
3293               }
3294               else
3295                 nbUseMap1++;
3296             }
3297             // for centroidalSmooth all element nodes must
3298             // be on one side of a seam
3299             if ( theSmoothMethod == CENTROIDAL && nbUseMap1 && nbUseMap2 ) {
3300               SMDS_ElemIteratorPtr nIt = e->nodesIterator();
3301               nn = 0;
3302               while ( nn++ < nbn ) {
3303                 const SMDS_MeshNode* n =
3304                   static_cast<const SMDS_MeshNode*>( nIt->next() );
3305                 setMovableNodes.erase( n );
3306               }
3307             }
3308           }
3309         } // loop on nodes on seam
3310       } // loop on edge of a face
3311     } // if ( !face.IsNull() )
3312
3313     if ( setMovableNodes.empty() ) {
3314       MESSAGE( "Face id : " << *fId << " - NO SMOOTHING: no nodes to move!!!");
3315       continue; // goto next face
3316     }
3317
3318     // -------------
3319     // SMOOTHING //
3320     // -------------
3321
3322     int it = -1;
3323     double maxRatio = -1., maxDisplacement = -1.;
3324     set<const SMDS_MeshNode*>::iterator nodeToMove;
3325     for ( it = 0; it < theNbIterations; it++ ) {
3326       maxDisplacement = 0.;
3327       nodeToMove = setMovableNodes.begin();
3328       for ( ; nodeToMove != setMovableNodes.end(); nodeToMove++ ) {
3329         const SMDS_MeshNode* node = (*nodeToMove);
3330         gp_XYZ aPrevPos ( node->X(), node->Y(), node->Z() );
3331
3332         // smooth
3333         bool map2 = ( nodesNearSeam.find( node ) != nodesNearSeam.end() );
3334         if ( theSmoothMethod == LAPLACIAN )
3335           laplacianSmooth( node, surface, map2 ? uvMap2 : uvMap );
3336         else
3337           centroidalSmooth( node, surface, map2 ? uvMap2 : uvMap );
3338
3339         // node displacement
3340         gp_XYZ aNewPos ( node->X(), node->Y(), node->Z() );
3341         Standard_Real aDispl = (aPrevPos - aNewPos).SquareModulus();
3342         if ( aDispl > maxDisplacement )
3343           maxDisplacement = aDispl;
3344       }
3345       // no node movement => exit
3346       //if ( maxDisplacement < 1.e-16 ) {
3347       if ( maxDisplacement < disttol ) {
3348         MESSAGE("-- no node movement --");
3349         break;
3350       }
3351
3352       // check elements quality
3353       maxRatio  = 0;
3354       list< const SMDS_MeshElement* >::iterator elemIt = elemsOnFace.begin();
3355       for ( ; elemIt != elemsOnFace.end(); ++elemIt ) {
3356         const SMDS_MeshElement* elem = (*elemIt);
3357         if ( !elem || elem->GetType() != SMDSAbs_Face )
3358           continue;
3359         SMESH::Controls::TSequenceOfXYZ aPoints;
3360         if ( aQualityFunc.GetPoints( elem, aPoints )) {
3361           double aValue = aQualityFunc.GetValue( aPoints );
3362           if ( aValue > maxRatio )
3363             maxRatio = aValue;
3364         }
3365       }
3366       if ( maxRatio <= theTgtAspectRatio ) {
3367         MESSAGE("-- quality achived --");
3368         break;
3369       }
3370       if (it+1 == theNbIterations) {
3371         MESSAGE("-- Iteration limit exceeded --");
3372       }
3373     } // smoothing iterations
3374
3375     MESSAGE(" Face id: " << *fId <<
3376             " Nb iterstions: " << it <<
3377             " Displacement: " << maxDisplacement <<
3378             " Aspect Ratio " << maxRatio);
3379
3380     // ---------------------------------------
3381     // new nodes positions are computed,
3382     // record movement in DS and set new UV
3383     // ---------------------------------------
3384     nodeToMove = setMovableNodes.begin();
3385     for ( ; nodeToMove != setMovableNodes.end(); nodeToMove++ ) {
3386       SMDS_MeshNode* node = const_cast< SMDS_MeshNode* > (*nodeToMove);
3387       aMesh->MoveNode( node, node->X(), node->Y(), node->Z() );
3388       map< const SMDS_MeshNode*, gp_XY* >::iterator node_uv = uvMap.find( node );
3389       if ( node_uv != uvMap.end() ) {
3390         gp_XY* uv = node_uv->second;
3391         node->SetPosition
3392           ( SMDS_PositionPtr( new SMDS_FacePosition( uv->X(), uv->Y() )));
3393       }
3394     }
3395
3396     // move medium nodes of quadratic elements
3397     if ( isQuadratic )
3398     {
3399       SMESH_MesherHelper helper( *GetMesh() );
3400       if ( !face.IsNull() )
3401         helper.SetSubShape( face );
3402       list< const SMDS_MeshElement* >::iterator elemIt = elemsOnFace.begin();
3403       for ( ; elemIt != elemsOnFace.end(); ++elemIt ) {
3404         const SMDS_VtkFace* QF =
3405           dynamic_cast<const SMDS_VtkFace*> (*elemIt);
3406         if(QF && QF->IsQuadratic()) {
3407           vector<const SMDS_MeshNode*> Ns;
3408           Ns.reserve(QF->NbNodes()+1);
3409           SMDS_ElemIteratorPtr anIter = QF->interlacedNodesElemIterator();
3410           while ( anIter->more() )
3411             Ns.push_back( cast2Node(anIter->next()) );
3412           Ns.push_back( Ns[0] );
3413           double x, y, z;
3414           for(int i=0; i<QF->NbNodes(); i=i+2) {
3415             if ( !surface.IsNull() ) {
3416               gp_XY uv1 = helper.GetNodeUV( face, Ns[i], Ns[i+2] );
3417               gp_XY uv2 = helper.GetNodeUV( face, Ns[i+2], Ns[i] );
3418               gp_XY uv = ( uv1 + uv2 ) / 2.;
3419               gp_Pnt xyz = surface->Value( uv.X(), uv.Y() );
3420               x = xyz.X(); y = xyz.Y(); z = xyz.Z();
3421             }
3422             else {
3423               x = (Ns[i]->X() + Ns[i+2]->X())/2;
3424               y = (Ns[i]->Y() + Ns[i+2]->Y())/2;
3425               z = (Ns[i]->Z() + Ns[i+2]->Z())/2;
3426             }
3427             if( fabs( Ns[i+1]->X() - x ) > disttol ||
3428                 fabs( Ns[i+1]->Y() - y ) > disttol ||
3429                 fabs( Ns[i+1]->Z() - z ) > disttol ) {
3430               // we have to move i+1 node
3431               aMesh->MoveNode( Ns[i+1], x, y, z );
3432             }
3433           }
3434         }
3435       }
3436     }
3437
3438   } // loop on face ids
3439
3440 }
3441
3442 //=======================================================================
3443 //function : isReverse
3444 //purpose  : Return true if normal of prevNodes is not co-directied with
3445 //           gp_Vec(prevNodes[iNotSame],nextNodes[iNotSame]).
3446 //           iNotSame is where prevNodes and nextNodes are different.
3447 //           If result is true then future volume orientation is OK
3448 //=======================================================================
3449
3450 static bool isReverse(const SMDS_MeshElement*             face,
3451                       const vector<const SMDS_MeshNode*>& prevNodes,
3452                       const vector<const SMDS_MeshNode*>& nextNodes,
3453                       const int                           iNotSame)
3454 {
3455
3456   SMESH_TNodeXYZ pP = prevNodes[ iNotSame ];
3457   SMESH_TNodeXYZ pN = nextNodes[ iNotSame ];
3458   gp_XYZ extrDir( pN - pP ), faceNorm;
3459   SMESH_Algo::FaceNormal( face, faceNorm, /*normalized=*/false );
3460
3461   return faceNorm * extrDir < 0.0;
3462 }
3463
3464 //=======================================================================
3465 /*!
3466  * \brief Create elements by sweeping an element
3467  * \param elem - element to sweep
3468  * \param newNodesItVec - nodes generated from each node of the element
3469  * \param newElems - generated elements
3470  * \param nbSteps - number of sweeping steps
3471  * \param srcElements - to append elem for each generated element
3472  */
3473 //=======================================================================
3474
3475 void SMESH_MeshEditor::sweepElement(const SMDS_MeshElement*               elem,
3476                                     const vector<TNodeOfNodeListMapItr> & newNodesItVec,
3477                                     list<const SMDS_MeshElement*>&        newElems,
3478                                     const int                             nbSteps,
3479                                     SMESH_SequenceOfElemPtr&              srcElements)
3480 {
3481   //MESSAGE("sweepElement " << nbSteps);
3482   SMESHDS_Mesh* aMesh = GetMeshDS();
3483
3484   const int           nbNodes = elem->NbNodes();          
3485   const int         nbCorners = elem->NbCornerNodes();
3486   SMDSAbs_EntityType baseType = elem->GetEntityType(); /* it can change in case of 
3487                                                           polyhedron creation !!! */
3488   // Loop on elem nodes:
3489   // find new nodes and detect same nodes indices
3490   vector < list< const SMDS_MeshNode* >::const_iterator > itNN( nbNodes );
3491   vector<const SMDS_MeshNode*> prevNod( nbNodes );
3492   vector<const SMDS_MeshNode*> nextNod( nbNodes );
3493   vector<const SMDS_MeshNode*> midlNod( nbNodes );
3494
3495   int iNode, nbSame = 0, nbDouble = 0, iNotSameNode = 0;
3496   vector<int> sames(nbNodes);
3497   vector<bool> isSingleNode(nbNodes);
3498
3499   for ( iNode = 0; iNode < nbNodes; iNode++ ) {
3500     TNodeOfNodeListMapItr                        nnIt = newNodesItVec[ iNode ];
3501     const SMDS_MeshNode*                         node = nnIt->first;
3502     const list< const SMDS_MeshNode* > & listNewNodes = nnIt->second;
3503     if ( listNewNodes.empty() )
3504       return;
3505
3506     itNN   [ iNode ] = listNewNodes.begin();
3507     prevNod[ iNode ] = node;
3508     nextNod[ iNode ] = listNewNodes.front();
3509
3510     isSingleNode[iNode] = (listNewNodes.size()==nbSteps); /* medium node of quadratic or
3511                                                              corner node of linear */
3512     if ( prevNod[ iNode ] != nextNod [ iNode ])
3513       nbDouble += !isSingleNode[iNode];
3514
3515     if( iNode < nbCorners ) { // check corners only
3516       if ( prevNod[ iNode ] == nextNod [ iNode ])
3517         sames[nbSame++] = iNode;
3518       else
3519         iNotSameNode = iNode;
3520     }
3521   }
3522
3523   if ( nbSame == nbNodes || nbSame > 2) {
3524     MESSAGE( " Too many same nodes of element " << elem->GetID() );
3525     return;
3526   }
3527
3528   if ( elem->GetType() == SMDSAbs_Face && !isReverse( elem, prevNod, nextNod, iNotSameNode ))
3529   {
3530     // fix nodes order to have bottom normal external
3531     if ( baseType == SMDSEntity_Polygon )
3532     {
3533       std::reverse( itNN.begin(), itNN.end() );
3534       std::reverse( prevNod.begin(), prevNod.end() );
3535       std::reverse( midlNod.begin(), midlNod.end() );
3536       std::reverse( nextNod.begin(), nextNod.end() );
3537       std::reverse( isSingleNode.begin(), isSingleNode.end() );
3538     }
3539     else
3540     {
3541       const vector<int>& ind = SMDS_MeshCell::reverseSmdsOrder( baseType );
3542       SMDS_MeshCell::applyInterlace( ind, itNN );
3543       SMDS_MeshCell::applyInterlace( ind, prevNod );
3544       SMDS_MeshCell::applyInterlace( ind, nextNod );
3545       SMDS_MeshCell::applyInterlace( ind, midlNod );
3546       SMDS_MeshCell::applyInterlace( ind, isSingleNode );
3547       if ( nbSame > 0 )
3548       {
3549         sames[nbSame] = iNotSameNode;
3550         for ( int j = 0; j <= nbSame; ++j )
3551           for ( size_t i = 0; i < ind.size(); ++i )
3552             if ( ind[i] == sames[j] )
3553             {
3554               sames[j] = i;
3555               break;
3556             }
3557         iNotSameNode = sames[nbSame];
3558       }
3559     }
3560   }
3561
3562   int iSameNode = 0, iBeforeSame = 0, iAfterSame = 0, iOpposSame = 0;
3563   if ( nbSame > 0 ) {
3564     iSameNode    = sames[ nbSame-1 ];
3565     iBeforeSame  = ( iSameNode + nbCorners - 1 ) % nbCorners;
3566     iAfterSame   = ( iSameNode + 1 ) % nbCorners;
3567     iOpposSame   = ( iSameNode - 2 < 0  ? iSameNode + 2 : iSameNode - 2 );
3568   }
3569
3570   // make new elements
3571   for (int iStep = 0; iStep < nbSteps; iStep++ )
3572   {
3573     // get next nodes
3574     for ( iNode = 0; iNode < nbNodes; iNode++ )
3575     {
3576       midlNod[ iNode ] = isSingleNode[iNode] ? 0 : *itNN[ iNode ]++;
3577       nextNod[ iNode ] = *itNN[ iNode ]++;
3578     }
3579
3580     SMDS_MeshElement* aNewElem = 0;
3581     /*if(!elem->IsPoly())*/ {
3582       switch ( baseType ) {
3583       case SMDSEntity_0D:
3584       case SMDSEntity_Node: { // sweep NODE
3585         if ( nbSame == 0 ) {
3586           if ( isSingleNode[0] )
3587             aNewElem = aMesh->AddEdge( prevNod[ 0 ], nextNod[ 0 ] );
3588           else
3589             aNewElem = aMesh->AddEdge( prevNod[ 0 ], nextNod[ 0 ], midlNod[ 0 ] );
3590         }
3591         else
3592           return;
3593         break;
3594       }
3595       case SMDSEntity_Edge: { // sweep EDGE
3596         if ( nbDouble == 0 )
3597         {
3598           if ( nbSame == 0 ) // ---> quadrangle
3599             aNewElem = aMesh->AddFace(prevNod[ 0 ], prevNod[ 1 ],
3600                                       nextNod[ 1 ], nextNod[ 0 ] );
3601           else               // ---> triangle
3602             aNewElem = aMesh->AddFace(prevNod[ 0 ], prevNod[ 1 ],
3603                                       nextNod[ iNotSameNode ] );
3604         }
3605         else                 // ---> polygon
3606         {
3607           vector<const SMDS_MeshNode*> poly_nodes;
3608           poly_nodes.push_back( prevNod[0] );
3609           poly_nodes.push_back( prevNod[1] );
3610           if ( prevNod[1] != nextNod[1] )
3611           {
3612             if ( midlNod[1]) poly_nodes.push_back( midlNod[1]);
3613             poly_nodes.push_back( nextNod[1] );
3614           }
3615           if ( prevNod[0] != nextNod[0] )
3616           {
3617             poly_nodes.push_back( nextNod[0] );
3618             if ( midlNod[0]) poly_nodes.push_back( midlNod[0]);
3619           }
3620           switch ( poly_nodes.size() ) {
3621           case 3:
3622             aNewElem = aMesh->AddFace( poly_nodes[ 0 ], poly_nodes[ 1 ], poly_nodes[ 2 ]);
3623             break;
3624           case 4:
3625             aNewElem = aMesh->AddFace( poly_nodes[ 0 ], poly_nodes[ 1 ],
3626                                        poly_nodes[ 2 ], poly_nodes[ 3 ]);
3627             break;
3628           default:
3629             aNewElem = aMesh->AddPolygonalFace (poly_nodes);
3630           }
3631         }
3632         break;
3633       }
3634       case SMDSEntity_Triangle: // TRIANGLE --->
3635         {
3636           if ( nbDouble > 0 ) break;
3637           if ( nbSame == 0 )       // ---> pentahedron
3638             aNewElem = aMesh->AddVolume (prevNod[ 0 ], prevNod[ 1 ], prevNod[ 2 ],
3639                                          nextNod[ 0 ], nextNod[ 1 ], nextNod[ 2 ] );
3640
3641           else if ( nbSame == 1 )  // ---> pyramid
3642             aNewElem = aMesh->AddVolume (prevNod[ iBeforeSame ], prevNod[ iAfterSame ],
3643                                          nextNod[ iAfterSame ],  nextNod[ iBeforeSame ],
3644                                          nextNod[ iSameNode ]);
3645
3646           else // 2 same nodes:       ---> tetrahedron
3647             aNewElem = aMesh->AddVolume (prevNod[ 0 ], prevNod[ 1 ], prevNod[ 2 ],
3648                                          nextNod[ iNotSameNode ]);
3649           break;
3650         }
3651       case SMDSEntity_Quad_Edge: // sweep quadratic EDGE --->
3652         {
3653           if ( nbSame == 2 )
3654             return;
3655           if ( nbDouble+nbSame == 2 )
3656           {
3657             if(nbSame==0) {      // ---> quadratic quadrangle
3658               aNewElem = aMesh->AddFace(prevNod[0], prevNod[1], nextNod[1], nextNod[0],
3659                                         prevNod[2], midlNod[1], nextNod[2], midlNod[0]);
3660             }
3661             else { //(nbSame==1) // ---> quadratic triangle
3662               if(sames[0]==2) {
3663                 return; // medium node on axis
3664               }
3665               else if(sames[0]==0)
3666                 aNewElem = aMesh->AddFace(prevNod[0], nextNod[1], prevNod[1],
3667                                           nextNod[2], midlNod[1], prevNod[2]);
3668               else // sames[0]==1
3669                 aNewElem = aMesh->AddFace(prevNod[0], nextNod[0], prevNod[1],
3670                                           midlNod[0], nextNod[2], prevNod[2]);
3671             }
3672           }
3673           else if ( nbDouble == 3 )
3674           {
3675             if ( nbSame == 0 ) {  // ---> bi-quadratic quadrangle
3676               aNewElem = aMesh->AddFace(prevNod[0], prevNod[1], nextNod[1], nextNod[0],
3677                                         prevNod[2], midlNod[1], nextNod[2], midlNod[0], midlNod[2]);
3678             }
3679           }
3680           else
3681             return;
3682           break;
3683         }
3684       case SMDSEntity_Quadrangle: { // sweep QUADRANGLE --->
3685         if ( nbDouble > 0 ) break;
3686
3687         if ( nbSame == 0 )       // ---> hexahedron
3688           aNewElem = aMesh->AddVolume (prevNod[ 0 ], prevNod[ 1 ], prevNod[ 2 ], prevNod[ 3 ],
3689                                        nextNod[ 0 ], nextNod[ 1 ], nextNod[ 2 ], nextNod[ 3 ]);
3690
3691         else if ( nbSame == 1 ) { // ---> pyramid + pentahedron
3692           aNewElem = aMesh->AddVolume (prevNod[ iBeforeSame ], prevNod[ iAfterSame ],
3693                                        nextNod[ iAfterSame ],  nextNod[ iBeforeSame ],
3694                                        nextNod[ iSameNode ]);
3695           newElems.push_back( aNewElem );
3696           aNewElem = aMesh->AddVolume (prevNod[ iAfterSame ],  prevNod[ iOpposSame ],
3697                                        prevNod[ iBeforeSame ], nextNod[ iAfterSame ],
3698                                        nextNod[ iOpposSame ],  nextNod[ iBeforeSame ] );
3699         }
3700         else if ( nbSame == 2 ) { // ---> pentahedron
3701           if ( prevNod[ iBeforeSame ] == nextNod[ iBeforeSame ] )
3702             // iBeforeSame is same too
3703             aNewElem = aMesh->AddVolume (prevNod[ iBeforeSame ], prevNod[ iOpposSame ],
3704                                          nextNod[ iOpposSame ],  prevNod[ iSameNode ],
3705                                          prevNod[ iAfterSame ],  nextNod[ iAfterSame ]);
3706           else
3707             // iAfterSame is same too
3708             aNewElem = aMesh->AddVolume (prevNod[ iSameNode ],   prevNod[ iBeforeSame ],
3709                                          nextNod[ iBeforeSame ], prevNod[ iAfterSame ],
3710                                          prevNod[ iOpposSame ],  nextNod[ iOpposSame ]);
3711         }
3712         break;
3713       }
3714       case SMDSEntity_Quad_Triangle: { // sweep Quadratic TRIANGLE --->
3715         if ( nbDouble+nbSame != 3 ) break;
3716         if(nbSame==0) {
3717           // --->  pentahedron with 15 nodes
3718           aNewElem = aMesh->AddVolume (prevNod[0], prevNod[1], prevNod[2],
3719                                        nextNod[0], nextNod[1], nextNod[2],
3720                                        prevNod[3], prevNod[4], prevNod[5],
3721                                        nextNod[3], nextNod[4], nextNod[5],
3722                                        midlNod[0], midlNod[1], midlNod[2]);
3723         }
3724         else if(nbSame==1) {
3725           // --->  2d order pyramid of 13 nodes
3726           int apex = iSameNode;
3727           int i0 = ( apex + 1 ) % nbCorners;
3728           int i1 = ( apex - 1 + nbCorners ) % nbCorners;
3729           int i0a = apex + 3;
3730           int i1a = i1 + 3;
3731           int i01 = i0 + 3;
3732           aNewElem = aMesh->AddVolume(prevNod[i1], prevNod[i0],
3733                                       nextNod[i0], nextNod[i1], prevNod[apex],
3734                                       prevNod[i01], midlNod[i0],
3735                                       nextNod[i01], midlNod[i1],
3736                                       prevNod[i1a], prevNod[i0a],
3737                                       nextNod[i0a], nextNod[i1a]);
3738         }
3739         else if(nbSame==2) {
3740           // --->  2d order tetrahedron of 10 nodes
3741           int n1 = iNotSameNode;
3742           int n2 = ( n1 + 1             ) % nbCorners;
3743           int n3 = ( n1 + nbCorners - 1 ) % nbCorners;
3744           int n12 = n1 + 3;
3745           int n23 = n2 + 3;
3746           int n31 = n3 + 3;
3747           aNewElem = aMesh->AddVolume (prevNod[n1], prevNod[n2], prevNod[n3], nextNod[n1],
3748                                        prevNod[n12], prevNod[n23], prevNod[n31],
3749                                        midlNod[n1], nextNod[n12], nextNod[n31]);
3750         }
3751         break;
3752       }
3753       case SMDSEntity_Quad_Quadrangle: { // sweep Quadratic QUADRANGLE --->
3754         if( nbSame == 0 ) {
3755           if ( nbDouble != 4 ) break;
3756           // --->  hexahedron with 20 nodes
3757           aNewElem = aMesh->AddVolume (prevNod[0], prevNod[1], prevNod[2], prevNod[3],
3758                                        nextNod[0], nextNod[1], nextNod[2], nextNod[3],
3759                                        prevNod[4], prevNod[5], prevNod[6], prevNod[7],
3760                                        nextNod[4], nextNod[5], nextNod[6], nextNod[7],
3761                                        midlNod[0], midlNod[1], midlNod[2], midlNod[3]);
3762         }
3763         else if(nbSame==1) {
3764           // ---> pyramid + pentahedron - can not be created since it is needed 
3765           // additional middle node at the center of face
3766           INFOS( " Sweep for face " << elem->GetID() << " can not be created" );
3767           return;
3768         }
3769         else if( nbSame == 2 ) {
3770           if ( nbDouble != 2 ) break;
3771           // --->  2d order Pentahedron with 15 nodes
3772           int n1,n2,n4,n5;
3773           if ( prevNod[ iBeforeSame ] == nextNod[ iBeforeSame ] ) {
3774             // iBeforeSame is same too
3775             n1 = iBeforeSame;
3776             n2 = iOpposSame;
3777             n4 = iSameNode;
3778             n5 = iAfterSame;
3779           }
3780           else {
3781             // iAfterSame is same too
3782             n1 = iSameNode;
3783             n2 = iBeforeSame;
3784             n4 = iAfterSame;
3785             n5 = iOpposSame;
3786           }
3787           int n12 = n2 + 4;
3788           int n45 = n4 + 4;
3789           int n14 = n1 + 4;
3790           int n25 = n5 + 4;
3791           aNewElem = aMesh->AddVolume (prevNod[n1], prevNod[n2], nextNod[n2],
3792                                        prevNod[n4], prevNod[n5], nextNod[n5],
3793                                        prevNod[n12], midlNod[n2], nextNod[n12],
3794                                        prevNod[n45], midlNod[n5], nextNod[n45],
3795                                        prevNod[n14], prevNod[n25], nextNod[n25]);
3796         }
3797         break;
3798       }
3799       case SMDSEntity_BiQuad_Quadrangle: { // sweep BiQuadratic QUADRANGLE --->
3800
3801         if( nbSame == 0 && nbDouble == 9 ) {
3802           // --->  tri-quadratic hexahedron with 27 nodes
3803           aNewElem = aMesh->AddVolume (prevNod[0], prevNod[1], prevNod[2], prevNod[3],
3804                                        nextNod[0], nextNod[1], nextNod[2], nextNod[3],
3805                                        prevNod[4], prevNod[5], prevNod[6], prevNod[7],
3806                                        nextNod[4], nextNod[5], nextNod[6], nextNod[7],
3807                                        midlNod[0], midlNod[1], midlNod[2], midlNod[3],
3808                                        prevNod[8], // bottom center
3809                                        midlNod[4], midlNod[5], midlNod[6], midlNod[7],
3810                                        nextNod[8], // top center
3811                                        midlNod[8]);// elem center
3812         }
3813         else
3814         {
3815           return;
3816         }
3817         break;
3818       }
3819       case SMDSEntity_Polygon: { // sweep POLYGON
3820
3821         if ( nbNodes == 6 && nbSame == 0 && nbDouble == 0 ) {
3822           // --->  hexagonal prism
3823           aNewElem = aMesh->AddVolume (prevNod[0], prevNod[1], prevNod[2],
3824                                        prevNod[3], prevNod[4], prevNod[5],
3825                                        nextNod[0], nextNod[1], nextNod[2],
3826                                        nextNod[3], nextNod[4], nextNod[5]);
3827         }
3828         break;
3829       }
3830       default:
3831         break;
3832       }
3833     }
3834
3835     if ( !aNewElem && elem->GetType() == SMDSAbs_Face ) // try to create a polyherdal prism
3836     {
3837       if ( baseType != SMDSEntity_Polygon )
3838       {
3839         const std::vector<int>& ind = SMDS_MeshCell::interlacedSmdsOrder(baseType);
3840         SMDS_MeshCell::applyInterlace( ind, prevNod );
3841         SMDS_MeshCell::applyInterlace( ind, nextNod );
3842         SMDS_MeshCell::applyInterlace( ind, midlNod );
3843         SMDS_MeshCell::applyInterlace( ind, itNN );
3844         SMDS_MeshCell::applyInterlace( ind, isSingleNode );
3845         baseType = SMDSEntity_Polygon; // WARNING: change baseType !!!!
3846       }
3847       vector<const SMDS_MeshNode*> polyedre_nodes (nbNodes*2 + 4*nbNodes);
3848       vector<int> quantities (nbNodes + 2);
3849       polyedre_nodes.clear();
3850       quantities.clear();
3851
3852       // bottom of prism
3853       for (int inode = 0; inode < nbNodes; inode++)
3854         polyedre_nodes.push_back( prevNod[inode] );
3855       quantities.push_back( nbNodes );
3856
3857       // top of prism
3858       polyedre_nodes.push_back( nextNod[0] );
3859       for (int inode = nbNodes; inode-1; --inode )
3860         polyedre_nodes.push_back( nextNod[inode-1] );
3861       quantities.push_back( nbNodes );
3862
3863       // side faces
3864       for (int iface = 0; iface < nbNodes; iface++)
3865       {
3866         const int prevNbNodes = polyedre_nodes.size();
3867         int inextface = (iface+1) % nbNodes;
3868         polyedre_nodes.push_back( prevNod[inextface] );
3869         polyedre_nodes.push_back( prevNod[iface] );
3870         if ( prevNod[iface] != nextNod[iface] )
3871         {
3872           if ( midlNod[ iface ]) polyedre_nodes.push_back( midlNod[ iface ]);
3873           polyedre_nodes.push_back( nextNod[iface] );
3874         }
3875         if ( prevNod[inextface] != nextNod[inextface] )
3876         {
3877           polyedre_nodes.push_back( nextNod[inextface] );
3878           if ( midlNod[ inextface ]) polyedre_nodes.push_back( midlNod[ inextface ]);
3879         }
3880         const int nbFaceNodes = polyedre_nodes.size() - prevNbNodes;
3881         if ( nbFaceNodes > 2 )
3882           quantities.push_back( nbFaceNodes );
3883         else // degenerated face
3884           polyedre_nodes.resize( prevNbNodes );
3885       }
3886       aNewElem = aMesh->AddPolyhedralVolume (polyedre_nodes, quantities);
3887     }
3888
3889     if ( aNewElem ) {
3890       newElems.push_back( aNewElem );
3891       myLastCreatedElems.Append(aNewElem);
3892       srcElements.Append( elem );
3893     }
3894
3895     // set new prev nodes
3896     for ( iNode = 0; iNode < nbNodes; iNode++ )
3897       prevNod[ iNode ] = nextNod[ iNode ];
3898
3899   } // for steps
3900 }
3901
3902 //=======================================================================
3903 /*!
3904  * \brief Create 1D and 2D elements around swept elements
3905  * \param mapNewNodes - source nodes and ones generated from them
3906  * \param newElemsMap - source elements and ones generated from them
3907  * \param elemNewNodesMap - nodes generated from each node of each element
3908  * \param elemSet - all swept elements
3909  * \param nbSteps - number of sweeping steps
3910  * \param srcElements - to append elem for each generated element
3911  */
3912 //=======================================================================
3913
3914 void SMESH_MeshEditor::makeWalls (TNodeOfNodeListMap &     mapNewNodes,
3915                                   TElemOfElemListMap &     newElemsMap,
3916                                   TElemOfVecOfNnlmiMap &   elemNewNodesMap,
3917                                   TIDSortedElemSet&        elemSet,
3918                                   const int                nbSteps,
3919                                   SMESH_SequenceOfElemPtr& srcElements)
3920 {
3921   ASSERT( newElemsMap.size() == elemNewNodesMap.size() );
3922   SMESHDS_Mesh* aMesh = GetMeshDS();
3923
3924   // Find nodes belonging to only one initial element - sweep them to get edges.
3925
3926   TNodeOfNodeListMapItr nList = mapNewNodes.begin();
3927   for ( ; nList != mapNewNodes.end(); nList++ )
3928   {
3929     const SMDS_MeshNode* node =
3930       static_cast<const SMDS_MeshNode*>( nList->first );
3931     SMDS_ElemIteratorPtr eIt = node->GetInverseElementIterator();
3932     int nbInitElems = 0;
3933     const SMDS_MeshElement* el = 0;
3934     SMDSAbs_ElementType highType = SMDSAbs_Edge; // count most complex elements only
3935     while ( eIt->more() && nbInitElems < 2 ) {
3936       el = eIt->next();
3937       SMDSAbs_ElementType type = el->GetType();
3938       if ( type == SMDSAbs_Volume || type < highType ) continue;
3939       if ( type > highType ) {
3940         nbInitElems = 0;
3941         highType = type;
3942       }
3943       nbInitElems += elemSet.count(el);
3944     }
3945     if ( nbInitElems < 2 ) {
3946       bool NotCreateEdge = el && el->IsMediumNode(node);
3947       if(!NotCreateEdge) {
3948         vector<TNodeOfNodeListMapItr> newNodesItVec( 1, nList );
3949         list<const SMDS_MeshElement*> newEdges;
3950         sweepElement( node, newNodesItVec, newEdges, nbSteps, srcElements );
3951       }
3952     }
3953   }
3954
3955   // Make a ceiling for each element ie an equal element of last new nodes.
3956   // Find free links of faces - make edges and sweep them into faces.
3957
3958   TElemOfElemListMap::iterator   itElem      = newElemsMap.begin();
3959   TElemOfVecOfNnlmiMap::iterator itElemNodes = elemNewNodesMap.begin();
3960   for ( ; itElem != newElemsMap.end(); itElem++, itElemNodes++ )
3961   {
3962     const SMDS_MeshElement* elem = itElem->first;
3963     vector<TNodeOfNodeListMapItr>& vecNewNodes = itElemNodes->second;
3964
3965     if(itElem->second.size()==0) continue;
3966
3967     const bool isQuadratic = elem->IsQuadratic();
3968
3969     if ( elem->GetType() == SMDSAbs_Edge ) {
3970       // create a ceiling edge
3971       if ( !isQuadratic ) {
3972         if ( !aMesh->FindEdge( vecNewNodes[ 0 ]->second.back(),
3973                                vecNewNodes[ 1 ]->second.back())) {
3974           myLastCreatedElems.Append(aMesh->AddEdge(vecNewNodes[ 0 ]->second.back(),
3975                                                    vecNewNodes[ 1 ]->second.back()));
3976           srcElements.Append( myLastCreatedElems.Last() );
3977         }
3978       }
3979       else {
3980         if ( !aMesh->FindEdge( vecNewNodes[ 0 ]->second.back(),
3981                                vecNewNodes[ 1 ]->second.back(),
3982                                vecNewNodes[ 2 ]->second.back())) {
3983           myLastCreatedElems.Append(aMesh->AddEdge(vecNewNodes[ 0 ]->second.back(),
3984                                                    vecNewNodes[ 1 ]->second.back(),
3985                                                    vecNewNodes[ 2 ]->second.back()));
3986           srcElements.Append( myLastCreatedElems.Last() );
3987         }
3988       }
3989     }
3990     if ( elem->GetType() != SMDSAbs_Face )
3991       continue;
3992
3993     bool hasFreeLinks = false;
3994
3995     TIDSortedElemSet avoidSet;
3996     avoidSet.insert( elem );
3997
3998     set<const SMDS_MeshNode*> aFaceLastNodes;
3999     int iNode, nbNodes = vecNewNodes.size();
4000     if ( !isQuadratic ) {
4001       // loop on the face nodes
4002       for ( iNode = 0; iNode < nbNodes; iNode++ ) {
4003         aFaceLastNodes.insert( vecNewNodes[ iNode ]->second.back() );
4004         // look for free links of the face
4005         int iNext = ( iNode + 1 == nbNodes ) ? 0 : iNode + 1;
4006         const SMDS_MeshNode* n1 = vecNewNodes[ iNode ]->first;
4007         const SMDS_MeshNode* n2 = vecNewNodes[ iNext ]->first;
4008         // check if a link is free
4009         if ( ! SMESH_MeshEditor::FindFaceInSet ( n1, n2, elemSet, avoidSet )) {
4010           hasFreeLinks = true;
4011           // make an edge and a ceiling for a new edge
4012           if ( !aMesh->FindEdge( n1, n2 )) {
4013             myLastCreatedElems.Append(aMesh->AddEdge( n1, n2 )); // free link edge
4014             srcElements.Append( myLastCreatedElems.Last() );
4015           }
4016           n1 = vecNewNodes[ iNode ]->second.back();
4017           n2 = vecNewNodes[ iNext ]->second.back();
4018           if ( !aMesh->FindEdge( n1, n2 )) {
4019             myLastCreatedElems.Append(aMesh->AddEdge( n1, n2 )); // ceiling edge
4020             srcElements.Append( myLastCreatedElems.Last() );
4021           }
4022         }
4023       }
4024     }
4025     else { // elem is quadratic face
4026       int nbn = nbNodes/2;
4027       for ( iNode = 0; iNode < nbn; iNode++ ) {
4028         aFaceLastNodes.insert( vecNewNodes[ iNode ]->second.back() );
4029         int iNext = ( iNode + 1 == nbn ) ? 0 : iNode + 1;
4030         const SMDS_MeshNode* n1 = vecNewNodes[ iNode ]->first;
4031         const SMDS_MeshNode* n2 = vecNewNodes[ iNext ]->first;
4032         const SMDS_MeshNode* n3 = vecNewNodes[ iNode+nbn ]->first;
4033         // check if a link is free
4034         if ( ! SMESH_MeshEditor::FindFaceInSet ( n1, n2, elemSet, avoidSet ) &&
4035              ! SMESH_MeshEditor::FindFaceInSet ( n1, n3, elemSet, avoidSet ) &&
4036              ! SMESH_MeshEditor::FindFaceInSet ( n3, n2, elemSet, avoidSet ) ) {
4037           hasFreeLinks = true;
4038           // make an edge and a ceiling for a new edge
4039           // find medium node
4040           if ( !aMesh->FindEdge( n1, n2, n3 )) {
4041             myLastCreatedElems.Append(aMesh->AddEdge( n1, n2, n3 )); // free link edge
4042             srcElements.Append( myLastCreatedElems.Last() );
4043           }
4044           n1 = vecNewNodes[ iNode ]->second.back();
4045           n2 = vecNewNodes[ iNext ]->second.back();
4046           n3 = vecNewNodes[ iNode+nbn ]->second.back();
4047           if ( !aMesh->FindEdge( n1, n2, n3 )) {
4048             myLastCreatedElems.Append(aMesh->AddEdge( n1, n2, n3 )); // ceiling edge
4049             srcElements.Append( myLastCreatedElems.Last() );
4050           }
4051         }
4052       }
4053       for ( iNode = nbn; iNode < nbNodes; iNode++ ) {
4054         aFaceLastNodes.insert( vecNewNodes[ iNode ]->second.back() );
4055       }
4056     }
4057
4058     // sweep free links into faces
4059
4060     if ( hasFreeLinks )  {
4061       list<const SMDS_MeshElement*> & newVolumes = itElem->second;
4062       int iVol, volNb, nbVolumesByStep = newVolumes.size() / nbSteps;
4063
4064       set<const SMDS_MeshNode*> initNodeSet, topNodeSet, faceNodeSet;
4065       for ( iNode = 0; iNode < nbNodes; iNode++ ) {
4066         initNodeSet.insert( vecNewNodes[ iNode ]->first );
4067         topNodeSet .insert( vecNewNodes[ iNode ]->second.back() );
4068       }
4069       for ( volNb = 0; volNb < nbVolumesByStep; volNb++ ) {
4070         list<const SMDS_MeshElement*>::iterator v = newVolumes.begin();
4071         std::advance( v, volNb );
4072         // find indices of free faces of a volume and their source edges
4073         list< int > freeInd;
4074         list< const SMDS_MeshElement* > srcEdges; // source edges of free faces
4075         SMDS_VolumeTool vTool( *v, /*ignoreCentralNodes=*/false );
4076         int iF, nbF = vTool.NbFaces();
4077         for ( iF = 0; iF < nbF; iF ++ ) {
4078           if (vTool.IsFreeFace( iF ) &&
4079               vTool.GetFaceNodes( iF, faceNodeSet ) &&
4080               initNodeSet != faceNodeSet) // except an initial face
4081           {
4082             if ( nbSteps == 1 && faceNodeSet == topNodeSet )
4083               continue;
4084             freeInd.push_back( iF );
4085             // find source edge of a free face iF
4086             vector<const SMDS_MeshNode*> commonNodes; // shared by the initial and free faces
4087             commonNodes.resize( initNodeSet.size(), NULL ); // avoid spoiling memory
4088             std::set_intersection( faceNodeSet.begin(), faceNodeSet.end(),
4089                                    initNodeSet.begin(), initNodeSet.end(),
4090                                    commonNodes.begin());
4091             if ( (*v)->IsQuadratic() )
4092               srcEdges.push_back(aMesh->FindEdge (commonNodes[0],commonNodes[1],commonNodes[2]));
4093             else
4094               srcEdges.push_back(aMesh->FindEdge (commonNodes[0],commonNodes[1]));
4095 #ifdef _DEBUG_
4096             if ( !srcEdges.back() )
4097             {
4098               cout << "SMESH_MeshEditor::makeWalls(), no source edge found for a free face #"
4099                    << iF << " of volume #" << vTool.ID() << endl;
4100             }
4101 #endif
4102           }
4103         }
4104         if ( freeInd.empty() )
4105           continue;
4106
4107         // create faces for all steps;
4108         // if such a face has been already created by sweep of edge,
4109         // assure that its orientation is OK
4110         for ( int iStep = 0; iStep < nbSteps; iStep++ ) {
4111           vTool.Set( *v, /*ignoreCentralNodes=*/false );
4112           vTool.SetExternalNormal();
4113           const int nextShift = vTool.IsForward() ? +1 : -1;
4114           list< int >::iterator ind = freeInd.begin();
4115           list< const SMDS_MeshElement* >::iterator srcEdge = srcEdges.begin();
4116           for ( ; ind != freeInd.end(); ++ind, ++srcEdge ) // loop on free faces
4117           {
4118             const SMDS_MeshNode** nodes = vTool.GetFaceNodes( *ind );
4119             int nbn = vTool.NbFaceNodes( *ind );
4120             const SMDS_MeshElement * f = 0;
4121             if ( nbn == 3 )              ///// triangle
4122             {
4123               f = aMesh->FindFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ]);
4124               if ( !f ||
4125                    nodes[ 1 ] != f->GetNodeWrap( f->GetNodeIndex( nodes[ 0 ]) + nextShift ))
4126               {
4127                 const SMDS_MeshNode* newOrder[3] = { nodes[ 1 - nextShift ],
4128                                                      nodes[ 1 ],
4129                                                      nodes[ 1 + nextShift ] };
4130                 if ( f )
4131                   aMesh->ChangeElementNodes( f, &newOrder[0], nbn );
4132                 else
4133                   myLastCreatedElems.Append(aMesh->AddFace( newOrder[ 0 ], newOrder[ 1 ],
4134                                                             newOrder[ 2 ] ));
4135               }
4136             }
4137             else if ( nbn == 4 )       ///// quadrangle
4138             {
4139               f = aMesh->FindFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ], nodes[ 3 ]);
4140               if ( !f ||
4141                    nodes[ 1 ] != f->GetNodeWrap( f->GetNodeIndex( nodes[ 0 ]) + nextShift ))
4142               {
4143                 const SMDS_MeshNode* newOrder[4] = { nodes[ 0 ], nodes[ 2-nextShift ],
4144                                                      nodes[ 2 ], nodes[ 2+nextShift ] };
4145                 if ( f )
4146                   aMesh->ChangeElementNodes( f, &newOrder[0], nbn );
4147                 else
4148                   myLastCreatedElems.Append(aMesh->AddFace( newOrder[ 0 ], newOrder[ 1 ],
4149                                                             newOrder[ 2 ], newOrder[ 3 ]));
4150               }
4151             }
4152             else if ( nbn == 6 && isQuadratic ) /////// quadratic triangle
4153             {
4154               f = aMesh->FindFace( nodes[0], nodes[2], nodes[4], nodes[1], nodes[3], nodes[5] );
4155               if ( !f ||
4156                    nodes[2] != f->GetNodeWrap( f->GetNodeIndex( nodes[0] ) + 2*nextShift ))
4157               {
4158                 const SMDS_MeshNode* newOrder[6] = { nodes[2 - 2*nextShift],
4159                                                      nodes[2],
4160                                                      nodes[2 + 2*nextShift],
4161                                                      nodes[3 - 2*nextShift],
4162                                                      nodes[3],
4163                                                      nodes[3 + 2*nextShift]};
4164                 if ( f )
4165                   aMesh->ChangeElementNodes( f, &newOrder[0], nbn );
4166                 else
4167                   myLastCreatedElems.Append(aMesh->AddFace( newOrder[ 0 ],
4168                                                             newOrder[ 1 ],
4169                                                             newOrder[ 2 ],
4170                                                             newOrder[ 3 ],
4171                                                             newOrder[ 4 ],
4172                                                             newOrder[ 5 ] ));
4173               }
4174             }
4175             else if ( nbn == 8 && isQuadratic ) /////// quadratic quadrangle
4176             {
4177               f = aMesh->FindFace( nodes[0], nodes[2], nodes[4], nodes[6],
4178                                    nodes[1], nodes[3], nodes[5], nodes[7] );
4179               if ( !f ||
4180                    nodes[ 2 ] != f->GetNodeWrap( f->GetNodeIndex( nodes[ 0 ] ) + 2*nextShift ))
4181               {
4182                 const SMDS_MeshNode* newOrder[8] = { nodes[0],
4183                                                      nodes[4 - 2*nextShift],
4184                                                      nodes[4],
4185                                                      nodes[4 + 2*nextShift],
4186                                                      nodes[1],
4187                                                      nodes[5 - 2*nextShift],
4188                                                      nodes[5],
4189                                                      nodes[5 + 2*nextShift] };
4190                 if ( f )
4191                   aMesh->ChangeElementNodes( f, &newOrder[0], nbn );
4192                 else
4193                   myLastCreatedElems.Append(aMesh->AddFace(newOrder[ 0 ], newOrder[ 1 ],
4194                                                            newOrder[ 2 ], newOrder[ 3 ],
4195                                                            newOrder[ 4 ], newOrder[ 5 ],
4196                                                            newOrder[ 6 ], newOrder[ 7 ]));
4197               }
4198             }
4199             else if ( nbn == 9 && isQuadratic ) /////// bi-quadratic quadrangle
4200             {
4201               f = aMesh->FindElement( vector<const SMDS_MeshNode*>( nodes, nodes+nbn ),
4202                                       SMDSAbs_Face, /*noMedium=*/false);
4203               if ( !f ||
4204                    nodes[ 2 ] != f->GetNodeWrap( f->GetNodeIndex( nodes[ 0 ] ) + 2*nextShift ))
4205               {
4206                 const SMDS_MeshNode* newOrder[9] = { nodes[0],
4207                                                      nodes[4 - 2*nextShift],
4208                                                      nodes[4],
4209                                                      nodes[4 + 2*nextShift],
4210                                                      nodes[1],
4211                                                      nodes[5 - 2*nextShift],
4212                                                      nodes[5],
4213                                                      nodes[5 + 2*nextShift],
4214                                                      nodes[8] };
4215                 if ( f )
4216                   aMesh->ChangeElementNodes( f, &newOrder[0], nbn );
4217                 else
4218                   myLastCreatedElems.Append(aMesh->AddFace(newOrder[ 0 ], newOrder[ 1 ],
4219                                                            newOrder[ 2 ], newOrder[ 3 ],
4220                                                            newOrder[ 4 ], newOrder[ 5 ],
4221                                                            newOrder[ 6 ], newOrder[ 7 ],
4222                                                            newOrder[ 8 ]));
4223               }
4224             }
4225             else  //////// polygon
4226             {
4227               vector<const SMDS_MeshNode*> polygon_nodes ( nodes, nodes+nbn );
4228               const SMDS_MeshFace * f = aMesh->FindFace( polygon_nodes );
4229               if ( !f ||
4230                    nodes[ 1 ] != f->GetNodeWrap( f->GetNodeIndex( nodes[ 0 ] ) + nextShift ))
4231               {
4232                 if ( !vTool.IsForward() )
4233                   std::reverse( polygon_nodes.begin(), polygon_nodes.end());
4234                 if ( f )
4235                   aMesh->ChangeElementNodes( f, &polygon_nodes[0], nbn );
4236                 else
4237                   AddElement(polygon_nodes, SMDSAbs_Face, polygon_nodes.size()>4);
4238               }
4239             }
4240
4241             while ( srcElements.Length() < myLastCreatedElems.Length() )
4242               srcElements.Append( *srcEdge );
4243
4244           }  // loop on free faces
4245
4246           // go to the next volume
4247           iVol = 0;
4248           while ( iVol++ < nbVolumesByStep ) v++;
4249
4250         } // loop on steps
4251       } // loop on volumes of one step
4252     } // sweep free links into faces
4253
4254     // Make a ceiling face with a normal external to a volume
4255
4256     SMDS_VolumeTool lastVol( itElem->second.back(), /*ignoreCentralNodes=*/false );
4257
4258     int iF = lastVol.GetFaceIndex( aFaceLastNodes );
4259     if ( iF >= 0 ) {
4260       lastVol.SetExternalNormal();
4261       const SMDS_MeshNode** nodes = lastVol.GetFaceNodes( iF );
4262       int nbn = lastVol.NbFaceNodes( iF );
4263       if ( nbn == 3 ) {
4264         if (!hasFreeLinks ||
4265             !aMesh->FindFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ]))
4266           myLastCreatedElems.Append(aMesh->AddFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ] ));
4267       }
4268       else if ( nbn == 4 )
4269       {
4270         if (!hasFreeLinks ||
4271             !aMesh->FindFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ], nodes[ 3 ]))
4272           myLastCreatedElems.Append(aMesh->AddFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ], nodes[ 3 ]));
4273       }
4274       else if ( nbn == 6 && isQuadratic )
4275       {
4276         if (!hasFreeLinks ||
4277             !aMesh->FindFace(nodes[0], nodes[2], nodes[4], nodes[1], nodes[3], nodes[5]) )
4278           myLastCreatedElems.Append(aMesh->AddFace(nodes[0], nodes[2], nodes[4],
4279                                                    nodes[1], nodes[3], nodes[5]));
4280       }
4281       else if ( nbn == 8 && isQuadratic )
4282       {
4283         if (!hasFreeLinks ||
4284             !aMesh->FindFace(nodes[0], nodes[2], nodes[4], nodes[6],
4285                              nodes[1], nodes[3], nodes[5], nodes[7]) )
4286           myLastCreatedElems.Append(aMesh->AddFace(nodes[0], nodes[2], nodes[4], nodes[6],
4287                                                    nodes[1], nodes[3], nodes[5], nodes[7]));
4288       }
4289       else if ( nbn == 9 && isQuadratic )
4290       {
4291         if (!hasFreeLinks ||
4292             !aMesh->FindElement(vector<const SMDS_MeshNode*>( nodes, nodes+nbn ),
4293                                 SMDSAbs_Face, /*noMedium=*/false) )
4294           myLastCreatedElems.Append(aMesh->AddFace(nodes[0], nodes[2], nodes[4], nodes[6],
4295                                                    nodes[1], nodes[3], nodes[5], nodes[7],
4296                                                    nodes[8]));
4297       }
4298       else {
4299         vector<const SMDS_MeshNode*> polygon_nodes ( nodes, nodes + nbn );
4300         if (!hasFreeLinks || !aMesh->FindFace(polygon_nodes))
4301           myLastCreatedElems.Append(aMesh->AddPolygonalFace(polygon_nodes));
4302       }
4303
4304       while ( srcElements.Length() < myLastCreatedElems.Length() )
4305         srcElements.Append( myLastCreatedElems.Last() );
4306     }
4307   } // loop on swept elements
4308 }
4309
4310 //=======================================================================
4311 //function : RotationSweep
4312 //purpose  :
4313 //=======================================================================
4314
4315 SMESH_MeshEditor::PGroupIDs
4316 SMESH_MeshEditor::RotationSweep(TIDSortedElemSet & theElems,
4317                                 const gp_Ax1&      theAxis,
4318                                 const double       theAngle,
4319                                 const int          theNbSteps,
4320                                 const double       theTol,
4321                                 const bool         theMakeGroups,
4322                                 const bool         theMakeWalls)
4323 {
4324   myLastCreatedElems.Clear();
4325   myLastCreatedNodes.Clear();
4326
4327   // source elements for each generated one
4328   SMESH_SequenceOfElemPtr srcElems, srcNodes;
4329
4330   MESSAGE( "RotationSweep()");
4331   gp_Trsf aTrsf;
4332   aTrsf.SetRotation( theAxis, theAngle );
4333   gp_Trsf aTrsf2;
4334   aTrsf2.SetRotation( theAxis, theAngle/2. );
4335
4336   gp_Lin aLine( theAxis );
4337   double aSqTol = theTol * theTol;
4338
4339   SMESHDS_Mesh* aMesh = GetMeshDS();
4340
4341   TNodeOfNodeListMap mapNewNodes;
4342   TElemOfVecOfNnlmiMap mapElemNewNodes;
4343   TElemOfElemListMap newElemsMap;
4344
4345   const bool isQuadraticMesh = bool( myMesh->NbEdges(ORDER_QUADRATIC) +
4346                                      myMesh->NbFaces(ORDER_QUADRATIC) +
4347                                      myMesh->NbVolumes(ORDER_QUADRATIC) );
4348   // loop on theElems
4349   TIDSortedElemSet::iterator itElem;
4350   for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
4351     const SMDS_MeshElement* elem = *itElem;
4352     if ( !elem || elem->GetType() == SMDSAbs_Volume )
4353       continue;
4354     vector<TNodeOfNodeListMapItr> & newNodesItVec = mapElemNewNodes[ elem ];
4355     newNodesItVec.reserve( elem->NbNodes() );
4356
4357     // loop on elem nodes
4358     SMDS_ElemIteratorPtr itN = elem->nodesIterator();
4359     while ( itN->more() )
4360     {
4361       // check if a node has been already sweeped
4362       const SMDS_MeshNode* node = cast2Node( itN->next() );
4363
4364       gp_XYZ aXYZ( node->X(), node->Y(), node->Z() );
4365       double coord[3];
4366       aXYZ.Coord( coord[0], coord[1], coord[2] );
4367       bool isOnAxis = ( aLine.SquareDistance( aXYZ ) <= aSqTol );
4368
4369       TNodeOfNodeListMapItr nIt =
4370         mapNewNodes.insert( make_pair( node, list<const SMDS_MeshNode*>() )).first;
4371       list<const SMDS_MeshNode*>& listNewNodes = nIt->second;
4372       if ( listNewNodes.empty() )
4373       {
4374         // check if we are to create medium nodes between corner ones
4375         bool needMediumNodes = false;
4376         if ( isQuadraticMesh )
4377         {
4378           SMDS_ElemIteratorPtr it = node->GetInverseElementIterator();
4379           while (it->more() && !needMediumNodes )
4380           {
4381             const SMDS_MeshElement* invElem = it->next();
4382             if ( invElem != elem && !theElems.count( invElem )) continue;
4383             needMediumNodes = ( invElem->IsQuadratic() && !invElem->IsMediumNode(node) );
4384             if ( !needMediumNodes && invElem->GetEntityType() == SMDSEntity_BiQuad_Quadrangle )
4385               needMediumNodes = true;
4386           }
4387         }
4388
4389         // make new nodes
4390         const SMDS_MeshNode * newNode = node;
4391         for ( int i = 0; i < theNbSteps; i++ ) {
4392           if ( !isOnAxis ) {
4393             if ( needMediumNodes )  // create a medium node
4394             {
4395               aTrsf2.Transforms( coord[0], coord[1], coord[2] );
4396               newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
4397               myLastCreatedNodes.Append(newNode);
4398               srcNodes.Append( node );
4399               listNewNodes.push_back( newNode );
4400               aTrsf2.Transforms( coord[0], coord[1], coord[2] );
4401             }
4402             else {
4403               aTrsf.Transforms( coord[0], coord[1], coord[2] );
4404             }
4405             // create a corner node
4406             newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
4407             myLastCreatedNodes.Append(newNode);
4408             srcNodes.Append( node );
4409             listNewNodes.push_back( newNode );
4410           }
4411           else {
4412             listNewNodes.push_back( newNode );
4413             // if ( needMediumNodes )
4414             //   listNewNodes.push_back( newNode );
4415           }
4416         }
4417       }
4418       newNodesItVec.push_back( nIt );
4419     }
4420     // make new elements
4421     sweepElement( elem, newNodesItVec, newElemsMap[elem], theNbSteps, srcElems );
4422   }
4423
4424   if ( theMakeWalls )
4425     makeWalls( mapNewNodes, newElemsMap, mapElemNewNodes, theElems, theNbSteps, srcElems );
4426
4427   PGroupIDs newGroupIDs;
4428   if ( theMakeGroups )
4429     newGroupIDs = generateGroups( srcNodes, srcElems, "rotated");
4430
4431   return newGroupIDs;
4432 }
4433
4434
4435 //=======================================================================
4436 //function : CreateNode
4437 //purpose  :
4438 //=======================================================================
4439 const SMDS_MeshNode* SMESH_MeshEditor::CreateNode(const double x,
4440                                                   const double y,
4441                                                   const double z,
4442                                                   const double tolnode,
4443                                                   SMESH_SequenceOfNode& aNodes)
4444 {
4445   // myLastCreatedElems.Clear();
4446   // myLastCreatedNodes.Clear();
4447
4448   gp_Pnt P1(x,y,z);
4449   SMESHDS_Mesh * aMesh = myMesh->GetMeshDS();
4450
4451   // try to search in sequence of existing nodes
4452   // if aNodes.Length()>0 we 'nave to use given sequence
4453   // else - use all nodes of mesh
4454   if(aNodes.Length()>0) {
4455     int i;
4456     for(i=1; i<=aNodes.Length(); i++) {
4457       gp_Pnt P2(aNodes.Value(i)->X(),aNodes.Value(i)->Y(),aNodes.Value(i)->Z());
4458       if(P1.Distance(P2)<tolnode)
4459         return aNodes.Value(i);
4460     }
4461   }
4462   else {
4463     SMDS_NodeIteratorPtr itn = aMesh->nodesIterator();
4464     while(itn->more()) {
4465       const SMDS_MeshNode* aN = static_cast<const SMDS_MeshNode*> (itn->next());
4466       gp_Pnt P2(aN->X(),aN->Y(),aN->Z());
4467       if(P1.Distance(P2)<tolnode)
4468         return aN;
4469     }
4470   }
4471
4472   // create new node and return it
4473   const SMDS_MeshNode* NewNode = aMesh->AddNode(x,y,z);
4474   //myLastCreatedNodes.Append(NewNode);
4475   return NewNode;
4476 }
4477
4478
4479 //=======================================================================
4480 //function : ExtrusionSweep
4481 //purpose  :
4482 //=======================================================================
4483
4484 SMESH_MeshEditor::PGroupIDs
4485 SMESH_MeshEditor::ExtrusionSweep (TIDSortedElemSet &  theElems,
4486                                   const gp_Vec&       theStep,
4487                                   const int           theNbSteps,
4488                                   TElemOfElemListMap& newElemsMap,
4489                                   const bool          theMakeGroups,
4490                                   const int           theFlags,
4491                                   const double        theTolerance)
4492 {
4493   ExtrusParam aParams;
4494   aParams.myDir = gp_Dir(theStep);
4495   aParams.myNodes.Clear();
4496   aParams.mySteps = new TColStd_HSequenceOfReal;
4497   int i;
4498   for(i=1; i<=theNbSteps; i++)
4499     aParams.mySteps->Append(theStep.Magnitude());
4500
4501   return
4502     ExtrusionSweep(theElems,aParams,newElemsMap,theMakeGroups,theFlags,theTolerance);
4503 }
4504
4505
4506 //=======================================================================
4507 //function : ExtrusionSweep
4508 //purpose  :
4509 //=======================================================================
4510
4511 SMESH_MeshEditor::PGroupIDs
4512 SMESH_MeshEditor::ExtrusionSweep (TIDSortedElemSet &  theElems,
4513                                   ExtrusParam&        theParams,
4514                                   TElemOfElemListMap& newElemsMap,
4515                                   const bool          theMakeGroups,
4516                                   const int           theFlags,
4517                                   const double        theTolerance)
4518 {
4519   myLastCreatedElems.Clear();
4520   myLastCreatedNodes.Clear();
4521
4522   // source elements for each generated one
4523   SMESH_SequenceOfElemPtr srcElems, srcNodes;
4524
4525   SMESHDS_Mesh* aMesh = GetMeshDS();
4526
4527   int nbsteps = theParams.mySteps->Length();
4528
4529   TNodeOfNodeListMap mapNewNodes;
4530   //TNodeOfNodeVecMap mapNewNodes;
4531   TElemOfVecOfNnlmiMap mapElemNewNodes;
4532   //TElemOfVecOfMapNodesMap mapElemNewNodes;
4533
4534   const bool isQuadraticMesh = bool( myMesh->NbEdges(ORDER_QUADRATIC) +
4535                                      myMesh->NbFaces(ORDER_QUADRATIC) +
4536                                      myMesh->NbVolumes(ORDER_QUADRATIC) );
4537   // loop on theElems
4538   TIDSortedElemSet::iterator itElem;
4539   for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
4540     // check element type
4541     const SMDS_MeshElement* elem = *itElem;
4542     if ( !elem  || elem->GetType() == SMDSAbs_Volume )
4543       continue;
4544
4545     vector<TNodeOfNodeListMapItr> & newNodesItVec = mapElemNewNodes[ elem ];
4546     newNodesItVec.reserve( elem->NbNodes() );
4547
4548     // loop on elem nodes
4549     SMDS_ElemIteratorPtr itN = elem->nodesIterator();
4550     while ( itN->more() )
4551     {
4552       // check if a node has been already sweeped
4553       const SMDS_MeshNode* node = cast2Node( itN->next() );
4554       TNodeOfNodeListMap::iterator nIt =
4555         mapNewNodes.insert( make_pair( node, list<const SMDS_MeshNode*>() )).first;
4556       list<const SMDS_MeshNode*>& listNewNodes = nIt->second;
4557       if ( listNewNodes.empty() )
4558       {
4559         // make new nodes
4560
4561         // check if we are to create medium nodes between corner ones
4562         bool needMediumNodes = false;
4563         if ( isQuadraticMesh )
4564         {
4565           SMDS_ElemIteratorPtr it = node->GetInverseElementIterator();
4566           while (it->more() && !needMediumNodes )
4567           {
4568             const SMDS_MeshElement* invElem = it->next();
4569             if ( invElem != elem && !theElems.count( invElem )) continue;
4570             needMediumNodes = ( invElem->IsQuadratic() && !invElem->IsMediumNode(node) );
4571             if ( !needMediumNodes && invElem->GetEntityType() == SMDSEntity_BiQuad_Quadrangle )
4572               needMediumNodes = true;
4573           }
4574         }
4575
4576         double coord[] = { node->X(), node->Y(), node->Z() };
4577         for ( int i = 0; i < nbsteps; i++ )
4578         {
4579           if ( needMediumNodes ) // create a medium node
4580           {
4581             double x = coord[0] + theParams.myDir.X()*theParams.mySteps->Value(i+1)/2.;
4582             double y = coord[1] + theParams.myDir.Y()*theParams.mySteps->Value(i+1)/2.;
4583             double z = coord[2] + theParams.myDir.Z()*theParams.mySteps->Value(i+1)/2.;
4584             if( theFlags & EXTRUSION_FLAG_SEW ) {
4585               const SMDS_MeshNode * newNode = CreateNode(x, y, z,
4586                                                          theTolerance, theParams.myNodes);
4587               listNewNodes.push_back( newNode );
4588             }
4589             else {
4590               const SMDS_MeshNode * newNode = aMesh->AddNode(x, y, z);
4591               myLastCreatedNodes.Append(newNode);
4592               srcNodes.Append( node );
4593               listNewNodes.push_back( newNode );
4594             }
4595           }
4596           // create a corner node
4597           coord[0] = coord[0] + theParams.myDir.X()*theParams.mySteps->Value(i+1);
4598           coord[1] = coord[1] + theParams.myDir.Y()*theParams.mySteps->Value(i+1);
4599           coord[2] = coord[2] + theParams.myDir.Z()*theParams.mySteps->Value(i+1);
4600           if( theFlags & EXTRUSION_FLAG_SEW ) {
4601             const SMDS_MeshNode * newNode = CreateNode(coord[0], coord[1], coord[2],
4602                                                        theTolerance, theParams.myNodes);
4603             listNewNodes.push_back( newNode );
4604           }
4605           else {
4606             const SMDS_MeshNode * newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
4607             myLastCreatedNodes.Append(newNode);
4608             srcNodes.Append( node );
4609             listNewNodes.push_back( newNode );
4610           }
4611         }
4612       }
4613       newNodesItVec.push_back( nIt );
4614     }
4615     // make new elements
4616     sweepElement( elem, newNodesItVec, newElemsMap[elem], nbsteps, srcElems );
4617   }
4618
4619   if( theFlags & EXTRUSION_FLAG_BOUNDARY ) {
4620     makeWalls( mapNewNodes, newElemsMap, mapElemNewNodes, theElems, nbsteps, srcElems );
4621   }
4622   PGroupIDs newGroupIDs;
4623   if ( theMakeGroups )
4624     newGroupIDs = generateGroups( srcNodes, srcElems, "extruded");
4625
4626   return newGroupIDs;
4627 }
4628
4629 //=======================================================================
4630 //function : ExtrusionAlongTrack
4631 //purpose  :
4632 //=======================================================================
4633 SMESH_MeshEditor::Extrusion_Error
4634 SMESH_MeshEditor::ExtrusionAlongTrack (TIDSortedElemSet &   theElements,
4635                                        SMESH_subMesh*       theTrack,
4636                                        const SMDS_MeshNode* theN1,
4637                                        const bool           theHasAngles,
4638                                        list<double>&        theAngles,
4639                                        const bool           theLinearVariation,
4640                                        const bool           theHasRefPoint,
4641                                        const gp_Pnt&        theRefPoint,
4642                                        const bool           theMakeGroups)
4643 {
4644   MESSAGE("ExtrusionAlongTrack");
4645   myLastCreatedElems.Clear();
4646   myLastCreatedNodes.Clear();
4647
4648   int aNbE;
4649   std::list<double> aPrms;
4650   TIDSortedElemSet::iterator itElem;
4651
4652   gp_XYZ aGC;
4653   TopoDS_Edge aTrackEdge;
4654   TopoDS_Vertex aV1, aV2;
4655
4656   SMDS_ElemIteratorPtr aItE;
4657   SMDS_NodeIteratorPtr aItN;
4658   SMDSAbs_ElementType aTypeE;
4659
4660   TNodeOfNodeListMap mapNewNodes;
4661
4662   // 1. Check data
4663   aNbE = theElements.size();
4664   // nothing to do
4665   if ( !aNbE )
4666     return EXTR_NO_ELEMENTS;
4667
4668   // 1.1 Track Pattern
4669   ASSERT( theTrack );
4670
4671   SMESHDS_SubMesh* pSubMeshDS = theTrack->GetSubMeshDS();
4672
4673   aItE = pSubMeshDS->GetElements();
4674   while ( aItE->more() ) {
4675     const SMDS_MeshElement* pE = aItE->next();
4676     aTypeE = pE->GetType();
4677     // Pattern must contain links only
4678     if ( aTypeE != SMDSAbs_Edge )
4679       return EXTR_PATH_NOT_EDGE;
4680   }
4681
4682   list<SMESH_MeshEditor_PathPoint> fullList;
4683
4684   const TopoDS_Shape& aS = theTrack->GetSubShape();
4685   // Sub-shape for the Pattern must be an Edge or Wire
4686   if( aS.ShapeType() == TopAbs_EDGE ) {
4687     aTrackEdge = TopoDS::Edge( aS );
4688     // the Edge must not be degenerated
4689     if ( BRep_Tool::Degenerated( aTrackEdge ) )
4690       return EXTR_BAD_PATH_SHAPE;
4691     TopExp::Vertices( aTrackEdge, aV1, aV2 );
4692     aItN = theTrack->GetFather()->GetSubMesh( aV1 )->GetSubMeshDS()->GetNodes();
4693     const SMDS_MeshNode* aN1 = aItN->next();
4694     aItN = theTrack->GetFather()->GetSubMesh( aV2 )->GetSubMeshDS()->GetNodes();
4695     const SMDS_MeshNode* aN2 = aItN->next();
4696     // starting node must be aN1 or aN2
4697     if ( !( aN1 == theN1 || aN2 == theN1 ) )
4698       return EXTR_BAD_STARTING_NODE;
4699     aItN = pSubMeshDS->GetNodes();
4700     while ( aItN->more() ) {
4701       const SMDS_MeshNode* pNode = aItN->next();
4702       const SMDS_EdgePosition* pEPos =
4703         static_cast<const SMDS_EdgePosition*>( pNode->GetPosition() );
4704       double aT = pEPos->GetUParameter();
4705       aPrms.push_back( aT );
4706     }
4707     //Extrusion_Error err =
4708     MakeEdgePathPoints(aPrms, aTrackEdge, (aN1==theN1), fullList);
4709   } else if( aS.ShapeType() == TopAbs_WIRE ) {
4710     list< SMESH_subMesh* > LSM;
4711     TopTools_SequenceOfShape Edges;
4712     SMESH_subMeshIteratorPtr itSM = theTrack->getDependsOnIterator(false,true);
4713     while(itSM->more()) {
4714       SMESH_subMesh* SM = itSM->next();
4715       LSM.push_back(SM);
4716       const TopoDS_Shape& aS = SM->GetSubShape();
4717       Edges.Append(aS);
4718     }
4719     list< list<SMESH_MeshEditor_PathPoint> > LLPPs;
4720     int startNid = theN1->GetID();
4721     TColStd_MapOfInteger UsedNums;
4722     
4723     int NbEdges = Edges.Length();
4724     int i = 1;
4725     for(; i<=NbEdges; i++) {
4726       int k = 0;
4727       list< SMESH_subMesh* >::iterator itLSM = LSM.begin();
4728       for(; itLSM!=LSM.end(); itLSM++) {
4729         k++;
4730         if(UsedNums.Contains(k)) continue;
4731         aTrackEdge = TopoDS::Edge( Edges.Value(k) );
4732         SMESH_subMesh* locTrack = *itLSM;
4733         SMESHDS_SubMesh* locMeshDS = locTrack->GetSubMeshDS();
4734         TopExp::Vertices( aTrackEdge, aV1, aV2 );
4735         aItN = locTrack->GetFather()->GetSubMesh(aV1)->GetSubMeshDS()->GetNodes();
4736         const SMDS_MeshNode* aN1 = aItN->next();
4737         aItN = locTrack->GetFather()->GetSubMesh(aV2)->GetSubMeshDS()->GetNodes();
4738         const SMDS_MeshNode* aN2 = aItN->next();
4739         // starting node must be aN1 or aN2
4740         if ( !( aN1->GetID() == startNid || aN2->GetID() == startNid ) ) continue;
4741         // 2. Collect parameters on the track edge
4742         aPrms.clear();
4743         aItN = locMeshDS->GetNodes();
4744         while ( aItN->more() ) {
4745           const SMDS_MeshNode* pNode = aItN->next();
4746           const SMDS_EdgePosition* pEPos =
4747             static_cast<const SMDS_EdgePosition*>( pNode->GetPosition() );
4748           double aT = pEPos->GetUParameter();
4749           aPrms.push_back( aT );
4750         }
4751         list<SMESH_MeshEditor_PathPoint> LPP;
4752         //Extrusion_Error err =
4753         MakeEdgePathPoints(aPrms, aTrackEdge,(aN1->GetID()==startNid), LPP);
4754         LLPPs.push_back(LPP);
4755         UsedNums.Add(k);
4756         // update startN for search following egde
4757         if( aN1->GetID() == startNid ) startNid = aN2->GetID();
4758         else startNid = aN1->GetID();
4759         break;
4760       }
4761     }
4762     list< list<SMESH_MeshEditor_PathPoint> >::iterator itLLPP = LLPPs.begin();
4763     list<SMESH_MeshEditor_PathPoint> firstList = *itLLPP;
4764     list<SMESH_MeshEditor_PathPoint>::iterator itPP = firstList.begin();
4765     for(; itPP!=firstList.end(); itPP++) {
4766       fullList.push_back( *itPP );
4767     }
4768     SMESH_MeshEditor_PathPoint PP1 = fullList.back();
4769     fullList.pop_back();
4770     itLLPP++;
4771     for(; itLLPP!=LLPPs.end(); itLLPP++) {
4772       list<SMESH_MeshEditor_PathPoint> currList = *itLLPP;
4773       itPP = currList.begin();
4774       SMESH_MeshEditor_PathPoint PP2 = currList.front();
4775       gp_Dir D1 = PP1.Tangent();
4776       gp_Dir D2 = PP2.Tangent();
4777       gp_Dir Dnew( gp_Vec( (D1.X()+D2.X())/2, (D1.Y()+D2.Y())/2,
4778                            (D1.Z()+D2.Z())/2 ) );
4779       PP1.SetTangent(Dnew);
4780       fullList.push_back(PP1);
4781       itPP++;
4782       for(; itPP!=firstList.end(); itPP++) {
4783         fullList.push_back( *itPP );
4784       }
4785       PP1 = fullList.back();
4786       fullList.pop_back();
4787     }
4788     // if wire not closed
4789     fullList.push_back(PP1);
4790     // else ???
4791   }
4792   else {
4793     return EXTR_BAD_PATH_SHAPE;
4794   }
4795
4796   return MakeExtrElements(theElements, fullList, theHasAngles, theAngles, theLinearVariation,
4797                           theHasRefPoint, theRefPoint, theMakeGroups);
4798 }
4799
4800
4801 //=======================================================================
4802 //function : ExtrusionAlongTrack
4803 //purpose  :
4804 //=======================================================================
4805 SMESH_MeshEditor::Extrusion_Error
4806 SMESH_MeshEditor::ExtrusionAlongTrack (TIDSortedElemSet &   theElements,
4807                                        SMESH_Mesh*          theTrack,
4808                                        const SMDS_MeshNode* theN1,
4809                                        const bool           theHasAngles,
4810                                        list<double>&        theAngles,
4811                                        const bool           theLinearVariation,
4812                                        const bool           theHasRefPoint,
4813                                        const gp_Pnt&        theRefPoint,
4814                                        const bool           theMakeGroups)
4815 {
4816   myLastCreatedElems.Clear();
4817   myLastCreatedNodes.Clear();
4818
4819   int aNbE;
4820   std::list<double> aPrms;
4821   TIDSortedElemSet::iterator itElem;
4822
4823   gp_XYZ aGC;
4824   TopoDS_Edge aTrackEdge;
4825   TopoDS_Vertex aV1, aV2;
4826
4827   SMDS_ElemIteratorPtr aItE;
4828   SMDS_NodeIteratorPtr aItN;
4829   SMDSAbs_ElementType aTypeE;
4830
4831   TNodeOfNodeListMap mapNewNodes;
4832
4833   // 1. Check data
4834   aNbE = theElements.size();
4835   // nothing to do
4836   if ( !aNbE )
4837     return EXTR_NO_ELEMENTS;
4838
4839   // 1.1 Track Pattern
4840   ASSERT( theTrack );
4841
4842   SMESHDS_Mesh* pMeshDS = theTrack->GetMeshDS();
4843
4844   aItE = pMeshDS->elementsIterator();
4845   while ( aItE->more() ) {
4846     const SMDS_MeshElement* pE = aItE->next();
4847     aTypeE = pE->GetType();
4848     // Pattern must contain links only
4849     if ( aTypeE != SMDSAbs_Edge )
4850       return EXTR_PATH_NOT_EDGE;
4851   }
4852
4853   list<SMESH_MeshEditor_PathPoint> fullList;
4854
4855   const TopoDS_Shape& aS = theTrack->GetShapeToMesh();
4856
4857   if( aS == SMESH_Mesh::PseudoShape() ) {
4858     //Mesh without shape
4859     const SMDS_MeshNode* currentNode = NULL;
4860     const SMDS_MeshNode* prevNode = theN1;
4861     std::vector<const SMDS_MeshNode*> aNodesList;
4862     aNodesList.push_back(theN1);
4863     int nbEdges = 0, conn=0;
4864     const SMDS_MeshElement* prevElem = NULL;
4865     const SMDS_MeshElement* currentElem = NULL;
4866     int totalNbEdges = theTrack->NbEdges();
4867     SMDS_ElemIteratorPtr nIt;
4868     bool isClosed = false;
4869
4870     //check start node
4871     if( !theTrack->GetMeshDS()->Contains(theN1) ) {
4872       return EXTR_BAD_STARTING_NODE;
4873     }
4874     
4875     conn = nbEdgeConnectivity(theN1);
4876     if(conn > 2)
4877       return EXTR_PATH_NOT_EDGE;
4878
4879     aItE = theN1->GetInverseElementIterator();
4880     prevElem = aItE->next();
4881     currentElem = prevElem;
4882     //Get all nodes
4883     if(totalNbEdges == 1 ) {
4884       nIt = currentElem->nodesIterator();
4885       currentNode = static_cast<const SMDS_MeshNode*>(nIt->next());
4886       if(currentNode == prevNode)
4887         currentNode = static_cast<const SMDS_MeshNode*>(nIt->next());
4888       aNodesList.push_back(currentNode);
4889     } else { 
4890       nIt = currentElem->nodesIterator();
4891       while( nIt->more() ) {
4892         currentNode = static_cast<const SMDS_MeshNode*>(nIt->next());
4893         if(currentNode == prevNode)
4894           currentNode = static_cast<const SMDS_MeshNode*>(nIt->next());
4895         aNodesList.push_back(currentNode);
4896         
4897         //case of the closed mesh
4898         if(currentNode == theN1) {
4899           nbEdges++;
4900           isClosed = true;
4901           break;
4902         }
4903
4904         conn = nbEdgeConnectivity(currentNode);
4905         if(conn > 2) {
4906           return EXTR_PATH_NOT_EDGE;    
4907         }else if( conn == 1 && nbEdges > 0 ) {
4908           //End of the path
4909           nbEdges++;
4910           break;
4911         }else {
4912           prevNode = currentNode;
4913           aItE = currentNode->GetInverseElementIterator();
4914           currentElem = aItE->next();
4915           if( currentElem  == prevElem)
4916             currentElem = aItE->next();
4917           nIt = currentElem->nodesIterator();
4918           prevElem = currentElem;
4919           nbEdges++;
4920         }
4921       }
4922     } 
4923     
4924     if(nbEdges != totalNbEdges)
4925       return EXTR_PATH_NOT_EDGE;
4926
4927     TopTools_SequenceOfShape Edges;
4928     double x1,x2,y1,y2,z1,z2;
4929     list< list<SMESH_MeshEditor_PathPoint> > LLPPs;
4930     int startNid = theN1->GetID();
4931     for(int i = 1; i < aNodesList.size(); i++) {
4932       x1 = aNodesList[i-1]->X();x2 = aNodesList[i]->X();
4933       y1 = aNodesList[i-1]->Y();y2 = aNodesList[i]->Y();
4934       z1 = aNodesList[i-1]->Z();z2 = aNodesList[i]->Z();
4935       TopoDS_Edge e = BRepBuilderAPI_MakeEdge(gp_Pnt(x1,y1,z1),gp_Pnt(x2,y2,z2));  
4936       list<SMESH_MeshEditor_PathPoint> LPP;
4937       aPrms.clear();
4938       MakeEdgePathPoints(aPrms, e, (aNodesList[i-1]->GetID()==startNid), LPP);
4939       LLPPs.push_back(LPP);
4940       if( aNodesList[i-1]->GetID() == startNid ) startNid = aNodesList[i]->GetID();
4941       else startNid = aNodesList[i-1]->GetID();
4942
4943     }
4944
4945     list< list<SMESH_MeshEditor_PathPoint> >::iterator itLLPP = LLPPs.begin();
4946     list<SMESH_MeshEditor_PathPoint> firstList = *itLLPP;
4947     list<SMESH_MeshEditor_PathPoint>::iterator itPP = firstList.begin();
4948     for(; itPP!=firstList.end(); itPP++) {
4949       fullList.push_back( *itPP );
4950     }
4951
4952     SMESH_MeshEditor_PathPoint PP1 = fullList.back();
4953     SMESH_MeshEditor_PathPoint PP2;
4954     fullList.pop_back();
4955     itLLPP++;
4956     for(; itLLPP!=LLPPs.end(); itLLPP++) {
4957       list<SMESH_MeshEditor_PathPoint> currList = *itLLPP;
4958       itPP = currList.begin();
4959       PP2 = currList.front();
4960       gp_Dir D1 = PP1.Tangent();
4961       gp_Dir D2 = PP2.Tangent();
4962       gp_Dir Dnew( gp_Vec( (D1.X()+D2.X())/2, (D1.Y()+D2.Y())/2,
4963                            (D1.Z()+D2.Z())/2 ) );
4964       PP1.SetTangent(Dnew);
4965       fullList.push_back(PP1);
4966       itPP++;
4967       for(; itPP!=currList.end(); itPP++) {
4968         fullList.push_back( *itPP );
4969       }
4970       PP1 = fullList.back();
4971       fullList.pop_back();
4972     }
4973     fullList.push_back(PP1);
4974     
4975   } // Sub-shape for the Pattern must be an Edge or Wire
4976   else if( aS.ShapeType() == TopAbs_EDGE ) {
4977     aTrackEdge = TopoDS::Edge( aS );
4978     // the Edge must not be degenerated
4979     if ( BRep_Tool::Degenerated( aTrackEdge ) )
4980       return EXTR_BAD_PATH_SHAPE;
4981     TopExp::Vertices( aTrackEdge, aV1, aV2 );
4982     aItN = theTrack->GetSubMesh( aV1 )->GetSubMeshDS()->GetNodes();
4983     const SMDS_MeshNode* aN1 = aItN->next();
4984     aItN = theTrack->GetSubMesh( aV2 )->GetSubMeshDS()->GetNodes();
4985     const SMDS_MeshNode* aN2 = aItN->next();
4986     // starting node must be aN1 or aN2
4987     if ( !( aN1 == theN1 || aN2 == theN1 ) )
4988       return EXTR_BAD_STARTING_NODE;
4989     aItN = pMeshDS->nodesIterator();
4990     while ( aItN->more() ) {
4991       const SMDS_MeshNode* pNode = aItN->next();
4992       if( pNode==aN1 || pNode==aN2 ) continue;
4993       const SMDS_EdgePosition* pEPos =
4994         static_cast<const SMDS_EdgePosition*>( pNode->GetPosition() );
4995       double aT = pEPos->GetUParameter();
4996       aPrms.push_back( aT );
4997     }
4998     //Extrusion_Error err =
4999     MakeEdgePathPoints(aPrms, aTrackEdge, (aN1==theN1), fullList);
5000   }
5001   else if( aS.ShapeType() == TopAbs_WIRE ) {
5002     list< SMESH_subMesh* > LSM;
5003     TopTools_SequenceOfShape Edges;
5004     TopExp_Explorer eExp(aS, TopAbs_EDGE);
5005     for(; eExp.More(); eExp.Next()) {
5006       TopoDS_Edge E = TopoDS::Edge( eExp.Current() );
5007       if( BRep_Tool::Degenerated(E) ) continue;
5008       SMESH_subMesh* SM = theTrack->GetSubMesh(E);
5009       if(SM) {
5010         LSM.push_back(SM);
5011         Edges.Append(E);
5012       }
5013     }
5014     list< list<SMESH_MeshEditor_PathPoint> > LLPPs;
5015     int startNid = theN1->GetID();
5016     TColStd_MapOfInteger UsedNums;
5017     int NbEdges = Edges.Length();
5018     int i = 1;
5019     for(; i<=NbEdges; i++) {
5020       int k = 0;
5021       list< SMESH_subMesh* >::iterator itLSM = LSM.begin();
5022       for(; itLSM!=LSM.end(); itLSM++) {
5023         k++;
5024         if(UsedNums.Contains(k)) continue;
5025         aTrackEdge = TopoDS::Edge( Edges.Value(k) );
5026         SMESH_subMesh* locTrack = *itLSM;
5027         SMESHDS_SubMesh* locMeshDS = locTrack->GetSubMeshDS();
5028         TopExp::Vertices( aTrackEdge, aV1, aV2 );
5029         aItN = locTrack->GetFather()->GetSubMesh(aV1)->GetSubMeshDS()->GetNodes();
5030         const SMDS_MeshNode* aN1 = aItN->next();
5031         aItN = locTrack->GetFather()->GetSubMesh(aV2)->GetSubMeshDS()->GetNodes();
5032         const SMDS_MeshNode* aN2 = aItN->next();
5033         // starting node must be aN1 or aN2
5034         if ( !( aN1->GetID() == startNid || aN2->GetID() == startNid ) ) continue;
5035         // 2. Collect parameters on the track edge
5036         aPrms.clear();
5037         aItN = locMeshDS->GetNodes();
5038         while ( aItN->more() ) {
5039           const SMDS_MeshNode* pNode = aItN->next();
5040           const SMDS_EdgePosition* pEPos =
5041             static_cast<const SMDS_EdgePosition*>( pNode->GetPosition() );
5042           double aT = pEPos->GetUParameter();
5043           aPrms.push_back( aT );
5044         }
5045         list<SMESH_MeshEditor_PathPoint> LPP;
5046         //Extrusion_Error err =
5047         MakeEdgePathPoints(aPrms, aTrackEdge,(aN1->GetID()==startNid), LPP);
5048         LLPPs.push_back(LPP);
5049         UsedNums.Add(k);
5050         // update startN for search following egde
5051         if( aN1->GetID() == startNid ) startNid = aN2->GetID();
5052         else startNid = aN1->GetID();
5053         break;
5054       }
5055     }
5056     list< list<SMESH_MeshEditor_PathPoint> >::iterator itLLPP = LLPPs.begin();
5057     list<SMESH_MeshEditor_PathPoint> firstList = *itLLPP;
5058     list<SMESH_MeshEditor_PathPoint>::iterator itPP = firstList.begin();
5059     for(; itPP!=firstList.end(); itPP++) {
5060       fullList.push_back( *itPP );
5061     }
5062     SMESH_MeshEditor_PathPoint PP1 = fullList.back();
5063     fullList.pop_back();
5064     itLLPP++;
5065     for(; itLLPP!=LLPPs.end(); itLLPP++) {
5066       list<SMESH_MeshEditor_PathPoint> currList = *itLLPP;
5067       itPP = currList.begin();
5068       SMESH_MeshEditor_PathPoint PP2 = currList.front();
5069       gp_Dir D1 = PP1.Tangent();
5070       gp_Dir D2 = PP2.Tangent();
5071       gp_Dir Dnew( gp_Vec( (D1.X()+D2.X())/2, (D1.Y()+D2.Y())/2,
5072                            (D1.Z()+D2.Z())/2 ) );
5073       PP1.SetTangent(Dnew);
5074       fullList.push_back(PP1);
5075       itPP++;
5076       for(; itPP!=currList.end(); itPP++) {
5077         fullList.push_back( *itPP );
5078       }
5079       PP1 = fullList.back();
5080       fullList.pop_back();
5081     }
5082     // if wire not closed
5083     fullList.push_back(PP1);
5084     // else ???
5085   }
5086   else {
5087     return EXTR_BAD_PATH_SHAPE;
5088   }
5089
5090   return MakeExtrElements(theElements, fullList, theHasAngles, theAngles, theLinearVariation,
5091                           theHasRefPoint, theRefPoint, theMakeGroups);
5092 }
5093
5094
5095 //=======================================================================
5096 //function : MakeEdgePathPoints
5097 //purpose  : auxilary for ExtrusionAlongTrack
5098 //=======================================================================
5099 SMESH_MeshEditor::Extrusion_Error
5100 SMESH_MeshEditor::MakeEdgePathPoints(std::list<double>& aPrms,
5101                                      const TopoDS_Edge& aTrackEdge,
5102                                      bool FirstIsStart,
5103                                      list<SMESH_MeshEditor_PathPoint>& LPP)
5104 {
5105   Standard_Real aTx1, aTx2, aL2, aTolVec, aTolVec2;
5106   aTolVec=1.e-7;
5107   aTolVec2=aTolVec*aTolVec;
5108   double aT1, aT2;
5109   TopoDS_Vertex aV1, aV2;
5110   TopExp::Vertices( aTrackEdge, aV1, aV2 );
5111   aT1=BRep_Tool::Parameter( aV1, aTrackEdge );
5112   aT2=BRep_Tool::Parameter( aV2, aTrackEdge );
5113   // 2. Collect parameters on the track edge
5114   aPrms.push_front( aT1 );
5115   aPrms.push_back( aT2 );
5116   // sort parameters
5117   aPrms.sort();
5118   if( FirstIsStart ) {
5119     if ( aT1 > aT2 ) {
5120       aPrms.reverse();
5121     }
5122   }
5123   else {
5124     if ( aT2 > aT1 ) {
5125       aPrms.reverse();
5126     }
5127   }
5128   // 3. Path Points
5129   SMESH_MeshEditor_PathPoint aPP;
5130   Handle(Geom_Curve) aC3D = BRep_Tool::Curve( aTrackEdge, aTx1, aTx2 );
5131   std::list<double>::iterator aItD = aPrms.begin();
5132   for(; aItD != aPrms.end(); ++aItD) {
5133     double aT = *aItD;
5134     gp_Pnt aP3D;
5135     gp_Vec aVec;
5136     aC3D->D1( aT, aP3D, aVec );
5137     aL2 = aVec.SquareMagnitude();
5138     if ( aL2 < aTolVec2 )
5139       return EXTR_CANT_GET_TANGENT;
5140     gp_Dir aTgt( aVec );
5141     aPP.SetPnt( aP3D );
5142     aPP.SetTangent( aTgt );
5143     aPP.SetParameter( aT );
5144     LPP.push_back(aPP);
5145   }
5146   return EXTR_OK;
5147 }
5148
5149
5150 //=======================================================================
5151 //function : MakeExtrElements
5152 //purpose  : auxilary for ExtrusionAlongTrack
5153 //=======================================================================
5154 SMESH_MeshEditor::Extrusion_Error
5155 SMESH_MeshEditor::MakeExtrElements(TIDSortedElemSet&  theElements,
5156                                    list<SMESH_MeshEditor_PathPoint>& fullList,
5157                                    const bool theHasAngles,
5158                                    list<double>& theAngles,
5159                                    const bool theLinearVariation,
5160                                    const bool theHasRefPoint,
5161                                    const gp_Pnt& theRefPoint,
5162                                    const bool theMakeGroups)
5163 {
5164   MESSAGE("MakeExtrElements");
5165   //cout<<"MakeExtrElements  fullList.size() = "<<fullList.size()<<endl;
5166   int aNbTP = fullList.size();
5167   vector<SMESH_MeshEditor_PathPoint> aPPs(aNbTP);
5168   // Angles
5169   if( theHasAngles && theAngles.size()>0 && theLinearVariation ) {
5170     LinearAngleVariation(aNbTP-1, theAngles);
5171   }
5172   vector<double> aAngles( aNbTP );
5173   int j = 0;
5174   for(; j<aNbTP; ++j) {
5175     aAngles[j] = 0.;
5176   }
5177   if ( theHasAngles ) {
5178     double anAngle;;
5179     std::list<double>::iterator aItD = theAngles.begin();
5180     for ( j=1; (aItD != theAngles.end()) && (j<aNbTP); ++aItD, ++j ) {
5181       anAngle = *aItD;
5182       aAngles[j] = anAngle;
5183     }
5184   }
5185   // fill vector of path points with angles
5186   //aPPs.resize(fullList.size());
5187   j = -1;
5188   list<SMESH_MeshEditor_PathPoint>::iterator itPP = fullList.begin();
5189   for(; itPP!=fullList.end(); itPP++) {
5190     j++;
5191     SMESH_MeshEditor_PathPoint PP = *itPP;
5192     PP.SetAngle(aAngles[j]);
5193     aPPs[j] = PP;
5194   }
5195
5196   TNodeOfNodeListMap mapNewNodes;
5197   TElemOfVecOfNnlmiMap mapElemNewNodes;
5198   TElemOfElemListMap newElemsMap;
5199   TIDSortedElemSet::iterator itElem;
5200   double aX, aY, aZ;
5201   int aNb;
5202   SMDSAbs_ElementType aTypeE;
5203   // source elements for each generated one
5204   SMESH_SequenceOfElemPtr srcElems, srcNodes;
5205
5206   // 3. Center of rotation aV0
5207   gp_Pnt aV0 = theRefPoint;
5208   gp_XYZ aGC;
5209   if ( !theHasRefPoint ) {
5210     aNb = 0;
5211     aGC.SetCoord( 0.,0.,0. );
5212
5213     itElem = theElements.begin();
5214     for ( ; itElem != theElements.end(); itElem++ ) {
5215       const SMDS_MeshElement* elem = *itElem;
5216
5217       SMDS_ElemIteratorPtr itN = elem->nodesIterator();
5218       while ( itN->more() ) {
5219         const SMDS_MeshNode* node = static_cast<const SMDS_MeshNode*>( itN->next() );
5220         aX = node->X();
5221         aY = node->Y();
5222         aZ = node->Z();
5223
5224         if ( mapNewNodes.find( node ) == mapNewNodes.end() ) {
5225           list<const SMDS_MeshNode*> aLNx;
5226           mapNewNodes[node] = aLNx;
5227           //
5228           gp_XYZ aXYZ( aX, aY, aZ );
5229           aGC += aXYZ;
5230           ++aNb;
5231         }
5232       }
5233     }
5234     aGC /= aNb;
5235     aV0.SetXYZ( aGC );
5236   } // if (!theHasRefPoint) {
5237   mapNewNodes.clear();
5238
5239   // 4. Processing the elements
5240   SMESHDS_Mesh* aMesh = GetMeshDS();
5241
5242   for ( itElem = theElements.begin(); itElem != theElements.end(); itElem++ ) {
5243     // check element type
5244     const SMDS_MeshElement* elem = *itElem;
5245     aTypeE = elem->GetType();
5246     if ( !elem || ( aTypeE != SMDSAbs_Face && aTypeE != SMDSAbs_Edge ) )
5247       continue;
5248
5249     vector<TNodeOfNodeListMapItr> & newNodesItVec = mapElemNewNodes[ elem ];
5250     newNodesItVec.reserve( elem->NbNodes() );
5251
5252     // loop on elem nodes
5253     int nodeIndex = -1;
5254     SMDS_ElemIteratorPtr itN = elem->nodesIterator();
5255     while ( itN->more() )
5256     {
5257       ++nodeIndex;
5258       // check if a node has been already processed
5259       const SMDS_MeshNode* node =
5260         static_cast<const SMDS_MeshNode*>( itN->next() );
5261       TNodeOfNodeListMap::iterator nIt = mapNewNodes.find( node );
5262       if ( nIt == mapNewNodes.end() ) {
5263         nIt = mapNewNodes.insert( make_pair( node, list<const SMDS_MeshNode*>() )).first;
5264         list<const SMDS_MeshNode*>& listNewNodes = nIt->second;
5265
5266         // make new nodes
5267         aX = node->X();  aY = node->Y(); aZ = node->Z();
5268
5269         Standard_Real aAngle1x, aAngleT1T0, aTolAng;
5270         gp_Pnt aP0x, aP1x, aPN0, aPN1, aV0x, aV1x;
5271         gp_Ax1 anAx1, anAxT1T0;
5272         gp_Dir aDT1x, aDT0x, aDT1T0;
5273
5274         aTolAng=1.e-4;
5275
5276         aV0x = aV0;
5277         aPN0.SetCoord(aX, aY, aZ);
5278
5279         const SMESH_MeshEditor_PathPoint& aPP0 = aPPs[0];
5280         aP0x = aPP0.Pnt();
5281         aDT0x= aPP0.Tangent();
5282         //cout<<"j = 0   PP: Pnt("<<aP0x.X()<<","<<aP0x.Y()<<","<<aP0x.Z()<<")"<<endl;
5283
5284         for ( j = 1; j < aNbTP; ++j ) {
5285           const SMESH_MeshEditor_PathPoint& aPP1 = aPPs[j];
5286           aP1x = aPP1.Pnt();
5287           aDT1x = aPP1.Tangent();
5288           aAngle1x = aPP1.Angle();
5289
5290           gp_Trsf aTrsf, aTrsfRot, aTrsfRotT1T0;
5291           // Translation
5292           gp_Vec aV01x( aP0x, aP1x );
5293           aTrsf.SetTranslation( aV01x );
5294
5295           // traslated point
5296           aV1x = aV0x.Transformed( aTrsf );
5297           aPN1 = aPN0.Transformed( aTrsf );
5298
5299           // rotation 1 [ T1,T0 ]
5300           aAngleT1T0=-aDT1x.Angle( aDT0x );
5301           if (fabs(aAngleT1T0) > aTolAng) {
5302             aDT1T0=aDT1x^aDT0x;
5303             anAxT1T0.SetLocation( aV1x );
5304             anAxT1T0.SetDirection( aDT1T0 );
5305             aTrsfRotT1T0.SetRotation( anAxT1T0, aAngleT1T0 );
5306
5307             aPN1 = aPN1.Transformed( aTrsfRotT1T0 );
5308           }
5309
5310           // rotation 2
5311           if ( theHasAngles ) {
5312             anAx1.SetLocation( aV1x );
5313             anAx1.SetDirection( aDT1x );
5314             aTrsfRot.SetRotation( anAx1, aAngle1x );
5315
5316             aPN1 = aPN1.Transformed( aTrsfRot );
5317           }
5318
5319           // make new node
5320           //MESSAGE("elem->IsQuadratic " << elem->IsQuadratic() << " " << elem->IsMediumNode(node));
5321           if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
5322             // create additional node
5323             double x = ( aPN1.X() + aPN0.X() )/2.;
5324             double y = ( aPN1.Y() + aPN0.Y() )/2.;
5325             double z = ( aPN1.Z() + aPN0.Z() )/2.;
5326             const SMDS_MeshNode* newNode = aMesh->AddNode(x,y,z);
5327             myLastCreatedNodes.Append(newNode);
5328             srcNodes.Append( node );
5329             listNewNodes.push_back( newNode );
5330           }
5331           aX = aPN1.X();
5332           aY = aPN1.Y();
5333           aZ = aPN1.Z();
5334           const SMDS_MeshNode* newNode = aMesh->AddNode( aX, aY, aZ );
5335           myLastCreatedNodes.Append(newNode);
5336           srcNodes.Append( node );
5337           listNewNodes.push_back( newNode );
5338
5339           aPN0 = aPN1;
5340           aP0x = aP1x;
5341           aV0x = aV1x;
5342           aDT0x = aDT1x;
5343         }
5344       }
5345
5346       else {
5347         // if current elem is quadratic and current node is not medium
5348         // we have to check - may be it is needed to insert additional nodes
5349         if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
5350           list< const SMDS_MeshNode* > & listNewNodes = nIt->second;
5351           if(listNewNodes.size()==aNbTP-1) {
5352             vector<const SMDS_MeshNode*> aNodes(2*(aNbTP-1));
5353             gp_XYZ P(node->X(), node->Y(), node->Z());
5354             list< const SMDS_MeshNode* >::iterator it = listNewNodes.begin();
5355             int i;
5356             for(i=0; i<aNbTP-1; i++) {
5357               const SMDS_MeshNode* N = *it;
5358               double x = ( N->X() + P.X() )/2.;
5359               double y = ( N->Y() + P.Y() )/2.;
5360               double z = ( N->Z() + P.Z() )/2.;
5361               const SMDS_MeshNode* newN = aMesh->AddNode(x,y,z);
5362               srcNodes.Append( node );
5363               myLastCreatedNodes.Append(newN);
5364               aNodes[2*i] = newN;
5365               aNodes[2*i+1] = N;
5366               P = gp_XYZ(N->X(),N->Y(),N->Z());
5367             }
5368             listNewNodes.clear();
5369             for(i=0; i<2*(aNbTP-1); i++) {
5370               listNewNodes.push_back(aNodes[i]);
5371             }
5372           }
5373         }
5374       }
5375
5376       newNodesItVec.push_back( nIt );
5377     }
5378     // make new elements
5379     //sweepElement( aMesh, elem, newNodesItVec, newElemsMap[elem],
5380     //              newNodesItVec[0]->second.size(), myLastCreatedElems );
5381     sweepElement( elem, newNodesItVec, newElemsMap[elem], aNbTP-1, srcElems );
5382   }
5383
5384   makeWalls( mapNewNodes, newElemsMap, mapElemNewNodes, theElements, aNbTP-1, srcElems );
5385
5386   if ( theMakeGroups )
5387     generateGroups( srcNodes, srcElems, "extruded");
5388
5389   return EXTR_OK;
5390 }
5391
5392
5393 //=======================================================================
5394 //function : LinearAngleVariation
5395 //purpose  : auxilary for ExtrusionAlongTrack
5396 //=======================================================================
5397 void SMESH_MeshEditor::LinearAngleVariation(const int nbSteps,
5398                                             list<double>& Angles)
5399 {
5400   int nbAngles = Angles.size();
5401   if( nbSteps > nbAngles ) {
5402     vector<double> theAngles(nbAngles);
5403     list<double>::iterator it = Angles.begin();
5404     int i = -1;
5405     for(; it!=Angles.end(); it++) {
5406       i++;
5407       theAngles[i] = (*it);
5408     }
5409     list<double> res;
5410     double rAn2St = double( nbAngles ) / double( nbSteps );
5411     double angPrev = 0, angle;
5412     for ( int iSt = 0; iSt < nbSteps; ++iSt ) {
5413       double angCur = rAn2St * ( iSt+1 );
5414       double angCurFloor  = floor( angCur );
5415       double angPrevFloor = floor( angPrev );
5416       if ( angPrevFloor == angCurFloor )
5417         angle = rAn2St * theAngles[ int( angCurFloor ) ];
5418       else {
5419         int iP = int( angPrevFloor );
5420         double angPrevCeil = ceil(angPrev);
5421         angle = ( angPrevCeil - angPrev ) * theAngles[ iP ];
5422
5423         int iC = int( angCurFloor );
5424         if ( iC < nbAngles )
5425           angle += ( angCur - angCurFloor ) * theAngles[ iC ];
5426
5427         iP = int( angPrevCeil );
5428         while ( iC-- > iP )
5429           angle += theAngles[ iC ];
5430       }
5431       res.push_back(angle);
5432       angPrev = angCur;
5433     }
5434     Angles.clear();
5435     it = res.begin();
5436     for(; it!=res.end(); it++)
5437       Angles.push_back( *it );
5438   }
5439 }
5440
5441
5442 //================================================================================
5443 /*!
5444  * \brief Move or copy theElements applying theTrsf to their nodes
5445  *  \param theElems - elements to transform, if theElems is empty then apply to all mesh nodes
5446  *  \param theTrsf - transformation to apply
5447  *  \param theCopy - if true, create translated copies of theElems
5448  *  \param theMakeGroups - if true and theCopy, create translated groups
5449  *  \param theTargetMesh - mesh to copy translated elements into
5450  *  \return SMESH_MeshEditor::PGroupIDs - list of ids of created groups
5451  */
5452 //================================================================================
5453
5454 SMESH_MeshEditor::PGroupIDs
5455 SMESH_MeshEditor::Transform (TIDSortedElemSet & theElems,
5456                              const gp_Trsf&     theTrsf,
5457                              const bool         theCopy,
5458                              const bool         theMakeGroups,
5459                              SMESH_Mesh*        theTargetMesh)
5460 {
5461   myLastCreatedElems.Clear();
5462   myLastCreatedNodes.Clear();
5463
5464   bool needReverse = false;
5465   string groupPostfix;
5466   switch ( theTrsf.Form() ) {
5467   case gp_PntMirror:
5468     MESSAGE("gp_PntMirror");
5469     needReverse = true;
5470     groupPostfix = "mirrored";
5471     break;
5472   case gp_Ax1Mirror:
5473     MESSAGE("gp_Ax1Mirror");
5474     groupPostfix = "mirrored";
5475     break;
5476   case gp_Ax2Mirror:
5477     MESSAGE("gp_Ax2Mirror");
5478     needReverse = true;
5479     groupPostfix = "mirrored";
5480     break;
5481   case gp_Rotation:
5482     MESSAGE("gp_Rotation");
5483     groupPostfix = "rotated";
5484     break;
5485   case gp_Translation:
5486     MESSAGE("gp_Translation");
5487     groupPostfix = "translated";
5488     break;
5489   case gp_Scale:
5490     MESSAGE("gp_Scale");
5491     groupPostfix = "scaled";
5492     break;
5493   case gp_CompoundTrsf: // different scale by axis
5494     MESSAGE("gp_CompoundTrsf");
5495     groupPostfix = "scaled";
5496     break;
5497   default:
5498     MESSAGE("default");
5499     needReverse = false;
5500     groupPostfix = "transformed";
5501   }
5502
5503   SMESH_MeshEditor targetMeshEditor( theTargetMesh );
5504   SMESHDS_Mesh* aTgtMesh = theTargetMesh ? theTargetMesh->GetMeshDS() : 0;
5505   SMESHDS_Mesh* aMesh    = GetMeshDS();
5506
5507
5508   // map old node to new one
5509   TNodeNodeMap nodeMap;
5510
5511   // elements sharing moved nodes; those of them which have all
5512   // nodes mirrored but are not in theElems are to be reversed
5513   TIDSortedElemSet inverseElemSet;
5514
5515   // source elements for each generated one
5516   SMESH_SequenceOfElemPtr srcElems, srcNodes;
5517
5518   // issue 021015: EDF 1578 SMESH: Free nodes are removed when translating a mesh
5519   TIDSortedElemSet orphanNode;
5520
5521   if ( theElems.empty() ) // transform the whole mesh
5522   {
5523     // add all elements
5524     SMDS_ElemIteratorPtr eIt = aMesh->elementsIterator();
5525     while ( eIt->more() ) theElems.insert( eIt->next() );
5526     // add orphan nodes
5527     SMDS_NodeIteratorPtr nIt = aMesh->nodesIterator();
5528     while ( nIt->more() )
5529     {
5530       const SMDS_MeshNode* node = nIt->next();
5531       if ( node->NbInverseElements() == 0)
5532         orphanNode.insert( node );
5533     }
5534   }
5535
5536   // loop on elements to transform nodes : first orphan nodes then elems
5537   TIDSortedElemSet::iterator itElem;
5538   TIDSortedElemSet *elements[] = {&orphanNode, &theElems };
5539   for (int i=0; i<2; i++)
5540   for ( itElem = elements[i]->begin(); itElem != elements[i]->end(); itElem++ ) {
5541     const SMDS_MeshElement* elem = *itElem;
5542     if ( !elem )
5543       continue;
5544
5545     // loop on elem nodes
5546     SMDS_ElemIteratorPtr itN = elem->nodesIterator();
5547     while ( itN->more() ) {
5548
5549       const SMDS_MeshNode* node = cast2Node( itN->next() );
5550       // check if a node has been already transformed
5551       pair<TNodeNodeMap::iterator,bool> n2n_isnew =
5552         nodeMap.insert( make_pair ( node, node ));
5553       if ( !n2n_isnew.second )
5554         continue;
5555
5556       double coord[3];
5557       coord[0] = node->X();
5558       coord[1] = node->Y();
5559       coord[2] = node->Z();
5560       theTrsf.Transforms( coord[0], coord[1], coord[2] );
5561       if ( theTargetMesh ) {
5562         const SMDS_MeshNode * newNode = aTgtMesh->AddNode( coord[0], coord[1], coord[2] );
5563         n2n_isnew.first->second = newNode;
5564         myLastCreatedNodes.Append(newNode);
5565         srcNodes.Append( node );
5566       }
5567       else if ( theCopy ) {
5568         const SMDS_MeshNode * newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
5569         n2n_isnew.first->second = newNode;
5570         myLastCreatedNodes.Append(newNode);
5571         srcNodes.Append( node );
5572       }
5573       else {
5574         aMesh->MoveNode( node, coord[0], coord[1], coord[2] );
5575         // node position on shape becomes invalid
5576         const_cast< SMDS_MeshNode* > ( node )->SetPosition
5577           ( SMDS_SpacePosition::originSpacePosition() );
5578       }
5579
5580       // keep inverse elements
5581       if ( !theCopy && !theTargetMesh && needReverse ) {
5582         SMDS_ElemIteratorPtr invElemIt = node->GetInverseElementIterator();
5583         while ( invElemIt->more() ) {
5584           const SMDS_MeshElement* iel = invElemIt->next();
5585           inverseElemSet.insert( iel );
5586         }
5587       }
5588     }
5589   }
5590
5591   // either create new elements or reverse mirrored ones
5592   if ( !theCopy && !needReverse && !theTargetMesh )
5593     return PGroupIDs();
5594
5595   TIDSortedElemSet::iterator invElemIt = inverseElemSet.begin();
5596   for ( ; invElemIt != inverseElemSet.end(); invElemIt++ )
5597     theElems.insert( *invElemIt );
5598
5599   // Replicate or reverse elements
5600
5601   std::vector<int> iForw;
5602   for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ )
5603   {
5604     const SMDS_MeshElement* elem = *itElem;
5605     if ( !elem || elem->GetType() == SMDSAbs_Node )
5606       continue;
5607
5608     int nbNodes = elem->NbNodes();
5609     int elemType = elem->GetType();
5610
5611     if (elem->IsPoly()) {
5612
5613       // polygon or polyhedral volume
5614       switch ( elemType ) {
5615       case SMDSAbs_Face:
5616         {
5617           vector<const SMDS_MeshNode*> poly_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             if (needReverse) {
5627               // reverse mirrored faces and volumes
5628               poly_nodes[nbNodes - iNode - 1] = (*nodeMapIt).second;
5629             } else {
5630               poly_nodes[iNode] = (*nodeMapIt).second;
5631             }
5632             iNode++;
5633           }
5634           if ( iNode != nbNodes )
5635             continue; // not all nodes transformed
5636
5637           if ( theTargetMesh ) {
5638             myLastCreatedElems.Append(aTgtMesh->AddPolygonalFace(poly_nodes));
5639             srcElems.Append( elem );
5640           }
5641           else if ( theCopy ) {
5642             myLastCreatedElems.Append(aMesh->AddPolygonalFace(poly_nodes));
5643             srcElems.Append( elem );
5644           }
5645           else {
5646             aMesh->ChangePolygonNodes(elem, poly_nodes);
5647           }
5648         }
5649         break;
5650       case SMDSAbs_Volume:
5651         {
5652           const SMDS_VtkVolume* aPolyedre =
5653             dynamic_cast<const SMDS_VtkVolume*>( elem );
5654           if (!aPolyedre) {
5655             MESSAGE("Warning: bad volumic element");
5656             continue;
5657           }
5658
5659           vector<const SMDS_MeshNode*> poly_nodes; poly_nodes.reserve( nbNodes );
5660           vector<int> quantities;
5661
5662           bool allTransformed = true;
5663           int nbFaces = aPolyedre->NbFaces();
5664           for (int iface = 1; iface <= nbFaces && allTransformed; iface++) {
5665             int nbFaceNodes = aPolyedre->NbFaceNodes(iface);
5666             for (int inode = 1; inode <= nbFaceNodes && allTransformed; inode++) {
5667               const SMDS_MeshNode* node = aPolyedre->GetFaceNode(iface, inode);
5668               TNodeNodeMap::iterator nodeMapIt = nodeMap.find(node);
5669               if (nodeMapIt == nodeMap.end()) {
5670                 allTransformed = false; // not all nodes transformed
5671               } else {
5672                 poly_nodes.push_back((*nodeMapIt).second);
5673               }
5674               if ( needReverse && allTransformed )
5675                 std::reverse( poly_nodes.end() - nbFaceNodes, poly_nodes.end() );
5676             }
5677             quantities.push_back(nbFaceNodes);
5678           }
5679           if ( !allTransformed )
5680             continue; // not all nodes transformed
5681
5682           if ( theTargetMesh ) {
5683             myLastCreatedElems.Append(aTgtMesh->AddPolyhedralVolume(poly_nodes, quantities));
5684             srcElems.Append( elem );
5685           }
5686           else if ( theCopy ) {
5687             myLastCreatedElems.Append(aMesh->AddPolyhedralVolume(poly_nodes, quantities));
5688             srcElems.Append( elem );
5689           }
5690           else {
5691             aMesh->ChangePolyhedronNodes(elem, poly_nodes, quantities);
5692           }
5693         }
5694         break;
5695       default:;
5696       }
5697       continue;
5698
5699     } // elem->isPoly()
5700
5701     // Regular elements
5702
5703     while ( iForw.size() < nbNodes ) iForw.push_back( iForw.size() );
5704     const std::vector<int>& iRev = SMDS_MeshCell::reverseSmdsOrder( elem->GetEntityType() );
5705     const std::vector<int>& i = needReverse ? iRev : iForw;
5706
5707     // find transformed nodes
5708     vector<const SMDS_MeshNode*> nodes(nbNodes);
5709     int iNode = 0;
5710     SMDS_ElemIteratorPtr itN = elem->nodesIterator();
5711     while ( itN->more() ) {
5712       const SMDS_MeshNode* node =
5713         static_cast<const SMDS_MeshNode*>( itN->next() );
5714       TNodeNodeMap::iterator nodeMapIt = nodeMap.find( node );
5715       if ( nodeMapIt == nodeMap.end() )
5716         break; // not all nodes transformed
5717       nodes[ i [ iNode++ ]] = (*nodeMapIt).second;
5718     }
5719     if ( iNode != nbNodes )
5720       continue; // not all nodes transformed
5721
5722     if ( theTargetMesh ) {
5723       if ( SMDS_MeshElement* copy =
5724            targetMeshEditor.AddElement( nodes, elem->GetType(), elem->IsPoly() )) {
5725         myLastCreatedElems.Append( copy );
5726         srcElems.Append( elem );
5727       }
5728     }
5729     else if ( theCopy ) {
5730       if ( AddElement( nodes, elem->GetType(), elem->IsPoly() ))
5731         srcElems.Append( elem );
5732     }
5733     else {
5734       // reverse element as it was reversed by transformation
5735       if ( nbNodes > 2 )
5736         aMesh->ChangeElementNodes( elem, &nodes[0], nbNodes );
5737     }
5738
5739   } // loop on elements
5740
5741   PGroupIDs newGroupIDs;
5742
5743   if ( ( theMakeGroups && theCopy ) ||
5744        ( theMakeGroups && theTargetMesh ) )
5745     newGroupIDs = generateGroups( srcNodes, srcElems, groupPostfix, theTargetMesh );
5746
5747   return newGroupIDs;
5748 }
5749
5750 //=======================================================================
5751 /*!
5752  * \brief Create groups of elements made during transformation
5753  * \param nodeGens - nodes making corresponding myLastCreatedNodes
5754  * \param elemGens - elements making corresponding myLastCreatedElems
5755  * \param postfix - to append to names of new groups
5756  */
5757 //=======================================================================
5758
5759 SMESH_MeshEditor::PGroupIDs
5760 SMESH_MeshEditor::generateGroups(const SMESH_SequenceOfElemPtr& nodeGens,
5761                                  const SMESH_SequenceOfElemPtr& elemGens,
5762                                  const std::string&             postfix,
5763                                  SMESH_Mesh*                    targetMesh)
5764 {
5765   PGroupIDs newGroupIDs( new list<int> );
5766   SMESH_Mesh* mesh = targetMesh ? targetMesh : GetMesh();
5767
5768   // Sort existing groups by types and collect their names
5769
5770   // to store an old group and a generated new one
5771   typedef pair< SMESHDS_GroupBase*, SMDS_MeshGroup* > TOldNewGroup;
5772   vector< list< TOldNewGroup > > groupsByType( SMDSAbs_NbElementTypes );
5773   // group names
5774   set< string > groupNames;
5775   //
5776   SMDS_MeshGroup* nullNewGroup = (SMDS_MeshGroup*) 0;
5777   SMESH_Mesh::GroupIteratorPtr groupIt = GetMesh()->GetGroups();
5778   while ( groupIt->more() ) {
5779     SMESH_Group * group = groupIt->next();
5780     if ( !group ) continue;
5781     SMESHDS_GroupBase* groupDS = group->GetGroupDS();
5782     if ( !groupDS || groupDS->IsEmpty() ) continue;
5783     groupNames.insert( group->GetName() );
5784     groupDS->SetStoreName( group->GetName() );
5785     groupsByType[ groupDS->GetType() ].push_back( make_pair( groupDS, nullNewGroup ));
5786   }
5787
5788   // Groups creation
5789
5790   // loop on nodes and elements
5791   for ( int isNodes = 0; isNodes < 2; ++isNodes )
5792   {
5793     const SMESH_SequenceOfElemPtr& gens  = isNodes ? nodeGens : elemGens;
5794     const SMESH_SequenceOfElemPtr& elems = isNodes ? myLastCreatedNodes : myLastCreatedElems;
5795     if ( gens.Length() != elems.Length() )
5796       throw SALOME_Exception(LOCALIZED("invalid args"));
5797
5798     // loop on created elements
5799     for (int iElem = 1; iElem <= elems.Length(); ++iElem )
5800     {
5801       const SMDS_MeshElement* sourceElem = gens( iElem );
5802       if ( !sourceElem ) {
5803         MESSAGE("generateGroups(): NULL source element");
5804         continue;
5805       }
5806       list< TOldNewGroup > & groupsOldNew = groupsByType[ sourceElem->GetType() ];
5807       if ( groupsOldNew.empty() ) {
5808         while ( iElem < gens.Length() && gens( iElem+1 ) == sourceElem )
5809           ++iElem; // skip all elements made by sourceElem
5810         continue;
5811       }
5812       // collect all elements made by sourceElem
5813       list< const SMDS_MeshElement* > resultElems;
5814       if ( const SMDS_MeshElement* resElem = elems( iElem ))
5815         if ( resElem != sourceElem )
5816           resultElems.push_back( resElem );
5817       while ( iElem < gens.Length() && gens( iElem+1 ) == sourceElem )
5818         if ( const SMDS_MeshElement* resElem = elems( ++iElem ))
5819           if ( resElem != sourceElem )
5820             resultElems.push_back( resElem );
5821       // do not generate element groups from node ones
5822 //      if ( sourceElem->GetType() == SMDSAbs_Node &&
5823 //           elems( iElem )->GetType() != SMDSAbs_Node )
5824 //        continue;
5825
5826       // add resultElems to groups made by ones the sourceElem belongs to
5827       list< TOldNewGroup >::iterator gOldNew, gLast = groupsOldNew.end();
5828       for ( gOldNew = groupsOldNew.begin(); gOldNew != gLast; ++gOldNew )
5829       {
5830         SMESHDS_GroupBase* oldGroup = gOldNew->first;
5831         if ( oldGroup->Contains( sourceElem )) // sourceElem in oldGroup
5832         {
5833           SMDS_MeshGroup* & newGroup = gOldNew->second;
5834           if ( !newGroup )// create a new group
5835           {
5836             // make a name
5837             string name = oldGroup->GetStoreName();
5838             if ( !targetMesh ) {
5839               name += "_";
5840               name += postfix;
5841               int nb = 0;
5842               while ( !groupNames.insert( name ).second ) // name exists
5843               {
5844                 if ( nb == 0 ) {
5845                   name += "_1";
5846                 }
5847                 else {
5848                   TCollection_AsciiString nbStr(nb+1);
5849                   name.resize( name.rfind('_')+1 );
5850                   name += nbStr.ToCString();
5851                 }
5852                 ++nb;
5853               }
5854             }
5855             // make a group
5856             int id;
5857             SMESH_Group* group = mesh->AddGroup( resultElems.back()->GetType(),
5858                                                  name.c_str(), id );
5859             SMESHDS_Group* groupDS = static_cast<SMESHDS_Group*>(group->GetGroupDS());
5860             newGroup = & groupDS->SMDSGroup();
5861             newGroupIDs->push_back( id );
5862           }
5863
5864           // fill in a new group
5865           list< const SMDS_MeshElement* >::iterator resLast = resultElems.end(), resElemIt;
5866           for ( resElemIt = resultElems.begin(); resElemIt != resLast; ++resElemIt )
5867             newGroup->Add( *resElemIt );
5868         }
5869       }
5870     } // loop on created elements
5871   }// loop on nodes and elements
5872
5873   return newGroupIDs;
5874 }
5875
5876 //================================================================================
5877 /*!
5878  * \brief Return list of group of nodes close to each other within theTolerance
5879  *        Search among theNodes or in the whole mesh if theNodes is empty using
5880  *        an Octree algorithm
5881  */
5882 //================================================================================
5883
5884 void SMESH_MeshEditor::FindCoincidentNodes (TIDSortedNodeSet &   theNodes,
5885                                             const double         theTolerance,
5886                                             TListOfListOfNodes & theGroupsOfNodes)
5887 {
5888   myLastCreatedElems.Clear();
5889   myLastCreatedNodes.Clear();
5890
5891   if ( theNodes.empty() )
5892   { // get all nodes in the mesh
5893     SMDS_NodeIteratorPtr nIt = GetMeshDS()->nodesIterator(/*idInceasingOrder=*/true);
5894     while ( nIt->more() )
5895       theNodes.insert( theNodes.end(),nIt->next());
5896   }
5897
5898   SMESH_OctreeNode::FindCoincidentNodes ( theNodes, &theGroupsOfNodes, theTolerance);
5899 }
5900
5901
5902 //=======================================================================
5903 /*!
5904  * \brief Implementation of search for the node closest to point
5905  */
5906 //=======================================================================
5907
5908 struct SMESH_NodeSearcherImpl: public SMESH_NodeSearcher
5909 {
5910   //---------------------------------------------------------------------
5911   /*!
5912    * \brief Constructor
5913    */
5914   SMESH_NodeSearcherImpl( const SMESHDS_Mesh* theMesh )
5915   {
5916     myMesh = ( SMESHDS_Mesh* ) theMesh;
5917
5918     TIDSortedNodeSet nodes;
5919     if ( theMesh ) {
5920       SMDS_NodeIteratorPtr nIt = theMesh->nodesIterator(/*idInceasingOrder=*/true);
5921       while ( nIt->more() )
5922         nodes.insert( nodes.end(), nIt->next() );
5923     }
5924     myOctreeNode = new SMESH_OctreeNode(nodes) ;
5925
5926     // get max size of a leaf box
5927     SMESH_OctreeNode* tree = myOctreeNode;
5928     while ( !tree->isLeaf() )
5929     {
5930       SMESH_OctreeNodeIteratorPtr cIt = tree->GetChildrenIterator();
5931       if ( cIt->more() )
5932         tree = cIt->next();
5933     }
5934     myHalfLeafSize = tree->maxSize() / 2.;
5935   }
5936
5937   //---------------------------------------------------------------------
5938   /*!
5939    * \brief Move node and update myOctreeNode accordingly
5940    */
5941   void MoveNode( const SMDS_MeshNode* node, const gp_Pnt& toPnt )
5942   {
5943     myOctreeNode->UpdateByMoveNode( node, toPnt );
5944     myMesh->MoveNode( node, toPnt.X(), toPnt.Y(), toPnt.Z() );
5945   }
5946
5947   //---------------------------------------------------------------------
5948   /*!
5949    * \brief Do it's job
5950    */
5951   const SMDS_MeshNode* FindClosestTo( const gp_Pnt& thePnt )
5952   {
5953     map<double, const SMDS_MeshNode*> dist2Nodes;
5954     myOctreeNode->NodesAround( thePnt.Coord(), dist2Nodes, myHalfLeafSize );
5955     if ( !dist2Nodes.empty() )
5956       return dist2Nodes.begin()->second;
5957     list<const SMDS_MeshNode*> nodes;
5958     //myOctreeNode->NodesAround( &tgtNode, &nodes, myHalfLeafSize );
5959
5960     double minSqDist = DBL_MAX;
5961     if ( nodes.empty() )  // get all nodes of OctreeNode's closest to thePnt
5962     {
5963       // sort leafs by their distance from thePnt
5964       typedef map< double, SMESH_OctreeNode* > TDistTreeMap;
5965       TDistTreeMap treeMap;
5966       list< SMESH_OctreeNode* > treeList;
5967       list< SMESH_OctreeNode* >::iterator trIt;
5968       treeList.push_back( myOctreeNode );
5969
5970       gp_XYZ pointNode( thePnt.X(), thePnt.Y(), thePnt.Z() );
5971       bool pointInside = myOctreeNode->isInside( pointNode, myHalfLeafSize );
5972       for ( trIt = treeList.begin(); trIt != treeList.end(); ++trIt)
5973       {
5974         SMESH_OctreeNode* tree = *trIt;
5975         if ( !tree->isLeaf() ) // put children to the queue
5976         {
5977           if ( pointInside && !tree->isInside( pointNode, myHalfLeafSize )) continue;
5978           SMESH_OctreeNodeIteratorPtr cIt = tree->GetChildrenIterator();
5979           while ( cIt->more() )
5980             treeList.push_back( cIt->next() );
5981         }
5982         else if ( tree->NbNodes() ) // put a tree to the treeMap
5983         {
5984           const Bnd_B3d& box = tree->getBox();
5985           double sqDist = thePnt.SquareDistance( 0.5 * ( box.CornerMin() + box.CornerMax() ));
5986           pair<TDistTreeMap::iterator,bool> it_in = treeMap.insert( make_pair( sqDist, tree ));
5987           if ( !it_in.second ) // not unique distance to box center
5988             treeMap.insert( it_in.first, make_pair( sqDist + 1e-13*treeMap.size(), tree ));
5989         }
5990       }
5991       // find distance after which there is no sense to check tree's
5992       double sqLimit = DBL_MAX;
5993       TDistTreeMap::iterator sqDist_tree = treeMap.begin();
5994       if ( treeMap.size() > 5 ) {
5995         SMESH_OctreeNode* closestTree = sqDist_tree->second;
5996         const Bnd_B3d& box = closestTree->getBox();
5997         double limit = sqrt( sqDist_tree->first ) + sqrt ( box.SquareExtent() );
5998         sqLimit = limit * limit;
5999       }
6000       // get all nodes from trees
6001       for ( ; sqDist_tree != treeMap.end(); ++sqDist_tree) {
6002         if ( sqDist_tree->first > sqLimit )
6003           break;
6004         SMESH_OctreeNode* tree = sqDist_tree->second;
6005         tree->NodesAround( tree->GetNodeIterator()->next(), &nodes );
6006       }
6007     }
6008     // find closest among nodes
6009     minSqDist = DBL_MAX;
6010     const SMDS_MeshNode* closestNode = 0;
6011     list<const SMDS_MeshNode*>::iterator nIt = nodes.begin();
6012     for ( ; nIt != nodes.end(); ++nIt ) {
6013       double sqDist = thePnt.SquareDistance( SMESH_TNodeXYZ( *nIt ) );
6014       if ( minSqDist > sqDist ) {
6015         closestNode = *nIt;
6016         minSqDist = sqDist;
6017       }
6018     }
6019     return closestNode;
6020   }
6021
6022   //---------------------------------------------------------------------
6023   /*!
6024    * \brief Destructor
6025    */
6026   ~SMESH_NodeSearcherImpl() { delete myOctreeNode; }
6027
6028   //---------------------------------------------------------------------
6029   /*!
6030    * \brief Return the node tree
6031    */
6032   const SMESH_OctreeNode* getTree() const { return myOctreeNode; }
6033
6034 private:
6035   SMESH_OctreeNode* myOctreeNode;
6036   SMESHDS_Mesh*     myMesh;
6037   double            myHalfLeafSize; // max size of a leaf box
6038 };
6039
6040 //=======================================================================
6041 /*!
6042  * \brief Return SMESH_NodeSearcher
6043  */
6044 //=======================================================================
6045
6046 SMESH_NodeSearcher* SMESH_MeshEditor::GetNodeSearcher() 
6047 {
6048   return new SMESH_NodeSearcherImpl( GetMeshDS() );
6049 }
6050
6051 // ========================================================================
6052 namespace // Utils used in SMESH_ElementSearcherImpl::FindElementsByPoint()
6053 {
6054   const int MaxNbElemsInLeaf = 10; // maximal number of elements in a leaf of tree
6055   const int MaxLevel         = 7;  // maximal tree height -> nb terminal boxes: 8^7 = 2097152
6056   const double NodeRadius = 1e-9;  // to enlarge bnd box of element
6057
6058   //=======================================================================
6059   /*!
6060    * \brief Octal tree of bounding boxes of elements
6061    */
6062   //=======================================================================
6063
6064   class ElementBndBoxTree : public SMESH_Octree
6065   {
6066   public:
6067
6068     ElementBndBoxTree(const SMDS_Mesh& mesh, SMDSAbs_ElementType elemType, SMDS_ElemIteratorPtr theElemIt = SMDS_ElemIteratorPtr(), double tolerance = NodeRadius );
6069     void getElementsNearPoint( const gp_Pnt& point, TIDSortedElemSet& foundElems);
6070     void getElementsNearLine ( const gp_Ax1& line, TIDSortedElemSet& foundElems);
6071     ~ElementBndBoxTree();
6072
6073   protected:
6074     ElementBndBoxTree() {}
6075     SMESH_Octree* allocateOctreeChild() const { return new ElementBndBoxTree; }
6076     void buildChildrenData();
6077     Bnd_B3d* buildRootBox();
6078   private:
6079     //!< Bounding box of element
6080     struct ElementBox : public Bnd_B3d
6081     {
6082       const SMDS_MeshElement* _element;
6083       int                     _refCount; // an ElementBox can be included in several tree branches
6084       ElementBox(const SMDS_MeshElement* elem, double tolerance);
6085     };
6086     vector< ElementBox* > _elements;
6087   };
6088
6089   //================================================================================
6090   /*!
6091    * \brief ElementBndBoxTree creation
6092    */
6093   //================================================================================
6094
6095   ElementBndBoxTree::ElementBndBoxTree(const SMDS_Mesh& mesh, SMDSAbs_ElementType elemType, SMDS_ElemIteratorPtr theElemIt, double tolerance)
6096     :SMESH_Octree( new SMESH_Octree::Limit( MaxLevel, /*minSize=*/0. ))
6097   {
6098     int nbElems = mesh.GetMeshInfo().NbElements( elemType );
6099     _elements.reserve( nbElems );
6100
6101     SMDS_ElemIteratorPtr elemIt = theElemIt ? theElemIt : mesh.elementsIterator( elemType );
6102     while ( elemIt->more() )
6103       _elements.push_back( new ElementBox( elemIt->next(),tolerance  ));
6104
6105     if ( _elements.size() > MaxNbElemsInLeaf )
6106       compute();
6107     else
6108       myIsLeaf = true;
6109   }
6110
6111   //================================================================================
6112   /*!
6113    * \brief Destructor
6114    */
6115   //================================================================================
6116
6117   ElementBndBoxTree::~ElementBndBoxTree()
6118   {
6119     for ( int i = 0; i < _elements.size(); ++i )
6120       if ( --_elements[i]->_refCount <= 0 )
6121         delete _elements[i];
6122   }
6123
6124   //================================================================================
6125   /*!
6126    * \brief Return the maximal box
6127    */
6128   //================================================================================
6129
6130   Bnd_B3d* ElementBndBoxTree::buildRootBox()
6131   {
6132     Bnd_B3d* box = new Bnd_B3d;
6133     for ( int i = 0; i < _elements.size(); ++i )
6134       box->Add( *_elements[i] );
6135     return box;
6136   }
6137
6138   //================================================================================
6139   /*!
6140    * \brief Redistrubute element boxes among children
6141    */
6142   //================================================================================
6143
6144   void ElementBndBoxTree::buildChildrenData()
6145   {
6146     for ( int i = 0; i < _elements.size(); ++i )
6147     {
6148       for (int j = 0; j < 8; j++)
6149       {
6150         if ( !_elements[i]->IsOut( myChildren[j]->getBox() ))
6151         {
6152           _elements[i]->_refCount++;
6153           ((ElementBndBoxTree*)myChildren[j])->_elements.push_back( _elements[i]);
6154         }
6155       }
6156       _elements[i]->_refCount--;
6157     }
6158     _elements.clear();
6159
6160     for (int j = 0; j < 8; j++)
6161     {
6162       ElementBndBoxTree* child = static_cast<ElementBndBoxTree*>( myChildren[j]);
6163       if ( child->_elements.size() <= MaxNbElemsInLeaf )
6164         child->myIsLeaf = true;
6165
6166       if ( child->_elements.capacity() - child->_elements.size() > 1000 )
6167         child->_elements.resize( child->_elements.size() ); // compact
6168     }
6169   }
6170
6171   //================================================================================
6172   /*!
6173    * \brief Return elements which can include the point
6174    */
6175   //================================================================================
6176
6177   void ElementBndBoxTree::getElementsNearPoint( const gp_Pnt&     point,
6178                                                 TIDSortedElemSet& foundElems)
6179   {
6180     if ( level() && getBox().IsOut( point.XYZ() ))
6181       return;
6182
6183     if ( isLeaf() )
6184     {
6185       for ( int i = 0; i < _elements.size(); ++i )
6186         if ( !_elements[i]->IsOut( point.XYZ() ))
6187           foundElems.insert( _elements[i]->_element );
6188     }
6189     else
6190     {
6191       for (int i = 0; i < 8; i++)
6192         ((ElementBndBoxTree*) myChildren[i])->getElementsNearPoint( point, foundElems );
6193     }
6194   }
6195
6196   //================================================================================
6197   /*!
6198    * \brief Return elements which can be intersected by the line
6199    */
6200   //================================================================================
6201
6202   void ElementBndBoxTree::getElementsNearLine( const gp_Ax1&     line,
6203                                                TIDSortedElemSet& foundElems)
6204   {
6205     if ( level() && getBox().IsOut( line ))
6206       return;
6207
6208     if ( isLeaf() )
6209     {
6210       for ( int i = 0; i < _elements.size(); ++i )
6211         if ( !_elements[i]->IsOut( line ))
6212           foundElems.insert( _elements[i]->_element );
6213     }
6214     else
6215     {
6216       for (int i = 0; i < 8; i++)
6217         ((ElementBndBoxTree*) myChildren[i])->getElementsNearLine( line, foundElems );
6218     }
6219   }
6220
6221   //================================================================================
6222   /*!
6223    * \brief Construct the element box
6224    */
6225   //================================================================================
6226
6227   ElementBndBoxTree::ElementBox::ElementBox(const SMDS_MeshElement* elem, double tolerance)
6228   {
6229     _element  = elem;
6230     _refCount = 1;
6231     SMDS_ElemIteratorPtr nIt = elem->nodesIterator();
6232     while ( nIt->more() )
6233       Add( SMESH_TNodeXYZ( cast2Node( nIt->next() )));
6234     Enlarge( tolerance );
6235   }
6236
6237 } // namespace
6238
6239 //=======================================================================
6240 /*!
6241  * \brief Implementation of search for the elements by point and
6242  *        of classification of point in 2D mesh
6243  */
6244 //=======================================================================
6245
6246 struct SMESH_ElementSearcherImpl: public SMESH_ElementSearcher
6247 {
6248   SMESHDS_Mesh*                _mesh;
6249   SMDS_ElemIteratorPtr         _meshPartIt;
6250   ElementBndBoxTree*           _ebbTree;
6251   SMESH_NodeSearcherImpl*      _nodeSearcher;
6252   SMDSAbs_ElementType          _elementType;
6253   double                       _tolerance;
6254   bool                         _outerFacesFound;
6255   set<const SMDS_MeshElement*> _outerFaces; // empty means "no internal faces at all"
6256
6257   SMESH_ElementSearcherImpl( SMESHDS_Mesh& mesh, SMDS_ElemIteratorPtr elemIt=SMDS_ElemIteratorPtr())
6258     : _mesh(&mesh),_meshPartIt(elemIt),_ebbTree(0),_nodeSearcher(0),_tolerance(-1),_outerFacesFound(false) {}
6259   ~SMESH_ElementSearcherImpl()
6260   {
6261     if ( _ebbTree )      delete _ebbTree;      _ebbTree      = 0;
6262     if ( _nodeSearcher ) delete _nodeSearcher; _nodeSearcher = 0;
6263   }
6264   virtual int FindElementsByPoint(const gp_Pnt&                      point,
6265                                   SMDSAbs_ElementType                type,
6266                                   vector< const SMDS_MeshElement* >& foundElements);
6267   virtual TopAbs_State GetPointState(const gp_Pnt& point);
6268
6269   void GetElementsNearLine( const gp_Ax1&                      line,
6270                             SMDSAbs_ElementType                type,
6271                             vector< const SMDS_MeshElement* >& foundElems);
6272   double getTolerance();
6273   bool getIntersParamOnLine(const gp_Lin& line, const SMDS_MeshElement* face,
6274                             const double tolerance, double & param);
6275   void findOuterBoundary(const SMDS_MeshElement* anyOuterFace);
6276   bool isOuterBoundary(const SMDS_MeshElement* face) const
6277   {
6278     return _outerFaces.empty() || _outerFaces.count(face);
6279   }
6280   struct TInters //!< data of intersection of the line and the mesh face (used in GetPointState())
6281   {
6282     const SMDS_MeshElement* _face;
6283     gp_Vec                  _faceNorm;
6284     bool                    _coincides; //!< the line lays in face plane
6285     TInters(const SMDS_MeshElement* face, const gp_Vec& faceNorm, bool coinc=false)
6286       : _face(face), _faceNorm( faceNorm ), _coincides( coinc ) {}
6287   };
6288   struct TFaceLink //!< link and faces sharing it (used in findOuterBoundary())
6289   {
6290     SMESH_TLink      _link;
6291     TIDSortedElemSet _faces;
6292     TFaceLink( const SMDS_MeshNode* n1, const SMDS_MeshNode* n2, const SMDS_MeshElement* face)
6293       : _link( n1, n2 ), _faces( &face, &face + 1) {}
6294   };
6295 };
6296
6297 ostream& operator<< (ostream& out, const SMESH_ElementSearcherImpl::TInters& i)
6298 {
6299   return out << "TInters(face=" << ( i._face ? i._face->GetID() : 0)
6300              << ", _coincides="<<i._coincides << ")";
6301 }
6302
6303 //=======================================================================
6304 /*!
6305  * \brief define tolerance for search
6306  */
6307 //=======================================================================
6308
6309 double SMESH_ElementSearcherImpl::getTolerance()
6310 {
6311   if ( _tolerance < 0 )
6312   {
6313     const SMDS_MeshInfo& meshInfo = _mesh->GetMeshInfo();
6314
6315     _tolerance = 0;
6316     if ( _nodeSearcher && meshInfo.NbNodes() > 1 )
6317     {
6318       double boxSize = _nodeSearcher->getTree()->maxSize();
6319       _tolerance = 1e-8 * boxSize/* / meshInfo.NbNodes()*/;
6320     }
6321     else if ( _ebbTree && meshInfo.NbElements() > 0 )
6322     {
6323       double boxSize = _ebbTree->maxSize();
6324       _tolerance = 1e-8 * boxSize/* / meshInfo.NbElements()*/;
6325     }
6326     if ( _tolerance == 0 )
6327     {
6328       // define tolerance by size of a most complex element
6329       int complexType = SMDSAbs_Volume;
6330       while ( complexType > SMDSAbs_All &&
6331               meshInfo.NbElements( SMDSAbs_ElementType( complexType )) < 1 )
6332         --complexType;
6333       if ( complexType == SMDSAbs_All ) return 0; // empty mesh
6334       double elemSize;
6335       if ( complexType == int( SMDSAbs_Node ))
6336       {
6337         SMDS_NodeIteratorPtr nodeIt = _mesh->nodesIterator();
6338         elemSize = 1;
6339         if ( meshInfo.NbNodes() > 2 )
6340           elemSize = SMESH_TNodeXYZ( nodeIt->next() ).Distance( nodeIt->next() );
6341       }
6342       else
6343       {
6344         SMDS_ElemIteratorPtr elemIt =
6345             _mesh->elementsIterator( SMDSAbs_ElementType( complexType ));
6346         const SMDS_MeshElement* elem = elemIt->next();
6347         SMDS_ElemIteratorPtr nodeIt = elem->nodesIterator();
6348         SMESH_TNodeXYZ n1( cast2Node( nodeIt->next() ));
6349         elemSize = 0;
6350         while ( nodeIt->more() )
6351         {
6352           double dist = n1.Distance( cast2Node( nodeIt->next() ));
6353           elemSize = max( dist, elemSize );
6354         }
6355       }
6356       _tolerance = 1e-4 * elemSize;
6357     }
6358   }
6359   return _tolerance;
6360 }
6361
6362 //================================================================================
6363 /*!
6364  * \brief Find intersection of the line and an edge of face and return parameter on line
6365  */
6366 //================================================================================
6367
6368 bool SMESH_ElementSearcherImpl::getIntersParamOnLine(const gp_Lin&           line,
6369                                                      const SMDS_MeshElement* face,
6370                                                      const double            tol,
6371                                                      double &                param)
6372 {
6373   int nbInts = 0;
6374   param = 0;
6375
6376   GeomAPI_ExtremaCurveCurve anExtCC;
6377   Handle(Geom_Curve) lineCurve = new Geom_Line( line );
6378   
6379   int nbNodes = face->IsQuadratic() ? face->NbNodes()/2 : face->NbNodes();
6380   for ( int i = 0; i < nbNodes && nbInts < 2; ++i )
6381   {
6382     GC_MakeSegment edge( SMESH_TNodeXYZ( face->GetNode( i )),
6383                          SMESH_TNodeXYZ( face->GetNode( (i+1)%nbNodes) )); 
6384     anExtCC.Init( lineCurve, edge);
6385     if ( anExtCC.NbExtrema() > 0 && anExtCC.LowerDistance() <= tol)
6386     {
6387       Quantity_Parameter pl, pe;
6388       anExtCC.LowerDistanceParameters( pl, pe );
6389       param += pl;
6390       if ( ++nbInts == 2 )
6391         break;
6392     }
6393   }
6394   if ( nbInts > 0 ) param /= nbInts;
6395   return nbInts > 0;
6396 }
6397 //================================================================================
6398 /*!
6399  * \brief Find all faces belonging to the outer boundary of mesh
6400  */
6401 //================================================================================
6402
6403 void SMESH_ElementSearcherImpl::findOuterBoundary(const SMDS_MeshElement* outerFace)
6404 {
6405   if ( _outerFacesFound ) return;
6406
6407   // Collect all outer faces by passing from one outer face to another via their links
6408   // and BTW find out if there are internal faces at all.
6409
6410   // checked links and links where outer boundary meets internal one
6411   set< SMESH_TLink > visitedLinks, seamLinks;
6412
6413   // links to treat with already visited faces sharing them
6414   list < TFaceLink > startLinks;
6415
6416   // load startLinks with the first outerFace
6417   startLinks.push_back( TFaceLink( outerFace->GetNode(0), outerFace->GetNode(1), outerFace));
6418   _outerFaces.insert( outerFace );
6419
6420   TIDSortedElemSet emptySet;
6421   while ( !startLinks.empty() )
6422   {
6423     const SMESH_TLink& link  = startLinks.front()._link;
6424     TIDSortedElemSet&  faces = startLinks.front()._faces;
6425
6426     outerFace = *faces.begin();
6427     // find other faces sharing the link
6428     const SMDS_MeshElement* f;
6429     while (( f = SMESH_MeshEditor::FindFaceInSet(link.node1(), link.node2(), emptySet, faces )))
6430       faces.insert( f );
6431
6432     // select another outer face among the found 
6433     const SMDS_MeshElement* outerFace2 = 0;
6434     if ( faces.size() == 2 )
6435     {
6436       outerFace2 = (outerFace == *faces.begin() ? *faces.rbegin() : *faces.begin());
6437     }
6438     else if ( faces.size() > 2 )
6439     {
6440       seamLinks.insert( link );
6441
6442       // link direction within the outerFace
6443       gp_Vec n1n2( SMESH_TNodeXYZ( link.node1()),
6444                    SMESH_TNodeXYZ( link.node2()));
6445       int i1 = outerFace->GetNodeIndex( link.node1() );
6446       int i2 = outerFace->GetNodeIndex( link.node2() );
6447       bool rev = ( abs(i2-i1) == 1 ? i1 > i2 : i2 > i1 );
6448       if ( rev ) n1n2.Reverse();
6449       // outerFace normal
6450       gp_XYZ ofNorm, fNorm;
6451       if ( SMESH_Algo::FaceNormal( outerFace, ofNorm, /*normalized=*/false ))
6452       {
6453         // direction from the link inside outerFace
6454         gp_Vec dirInOF = gp_Vec( ofNorm ) ^ n1n2;
6455         // sort all other faces by angle with the dirInOF
6456         map< double, const SMDS_MeshElement* > angle2Face;
6457         set< const SMDS_MeshElement*, TIDCompare >::const_iterator face = faces.begin();
6458         for ( ; face != faces.end(); ++face )
6459         {
6460           if ( !SMESH_Algo::FaceNormal( *face, fNorm, /*normalized=*/false ))
6461             continue;
6462           gp_Vec dirInF = gp_Vec( fNorm ) ^ n1n2;
6463           double angle = dirInOF.AngleWithRef( dirInF, n1n2 );
6464           if ( angle < 0 ) angle += 2. * M_PI;
6465           angle2Face.insert( make_pair( angle, *face ));
6466         }
6467         if ( !angle2Face.empty() )
6468           outerFace2 = angle2Face.begin()->second;
6469       }
6470     }
6471     // store the found outer face and add its links to continue seaching from
6472     if ( outerFace2 )
6473     {
6474       _outerFaces.insert( outerFace );
6475       int nbNodes = outerFace2->NbNodes()/( outerFace2->IsQuadratic() ? 2 : 1 );
6476       for ( int i = 0; i < nbNodes; ++i )
6477       {
6478         SMESH_TLink link2( outerFace2->GetNode(i), outerFace2->GetNode((i+1)%nbNodes));
6479         if ( visitedLinks.insert( link2 ).second )
6480           startLinks.push_back( TFaceLink( link2.node1(), link2.node2(), outerFace2 ));
6481       }
6482     }
6483     startLinks.pop_front();
6484   }
6485   _outerFacesFound = true;
6486
6487   if ( !seamLinks.empty() )
6488   {
6489     // There are internal boundaries touching the outher one,
6490     // find all faces of internal boundaries in order to find
6491     // faces of boundaries of holes, if any.
6492     
6493   }
6494   else
6495   {
6496     _outerFaces.clear();
6497   }
6498 }
6499
6500 //=======================================================================
6501 /*!
6502  * \brief Find elements of given type where the given point is IN or ON.
6503  *        Returns nb of found elements and elements them-selves.
6504  *
6505  * 'ALL' type means elements of any type excluding nodes and 0D elements
6506  */
6507 //=======================================================================
6508
6509 int SMESH_ElementSearcherImpl::
6510 FindElementsByPoint(const gp_Pnt&                      point,
6511                     SMDSAbs_ElementType                type,
6512                     vector< const SMDS_MeshElement* >& foundElements)
6513 {
6514   foundElements.clear();
6515
6516   double tolerance = getTolerance();
6517
6518   // =================================================================================
6519   if ( type == SMDSAbs_Node || type == SMDSAbs_0DElement )
6520   {
6521     if ( !_nodeSearcher )
6522       _nodeSearcher = new SMESH_NodeSearcherImpl( _mesh );
6523
6524     const SMDS_MeshNode* closeNode = _nodeSearcher->FindClosestTo( point );
6525     if ( !closeNode ) return foundElements.size();
6526
6527     if ( point.Distance( SMESH_TNodeXYZ( closeNode )) > tolerance )
6528       return foundElements.size(); // to far from any node
6529
6530     if ( type == SMDSAbs_Node )
6531     {
6532       foundElements.push_back( closeNode );
6533     }
6534     else
6535     {
6536       SMDS_ElemIteratorPtr elemIt = closeNode->GetInverseElementIterator( SMDSAbs_0DElement );
6537       while ( elemIt->more() )
6538         foundElements.push_back( elemIt->next() );
6539     }
6540   }
6541   // =================================================================================
6542   else // elements more complex than 0D
6543   {
6544     if ( !_ebbTree || _elementType != type )
6545     {
6546       if ( _ebbTree ) delete _ebbTree;
6547       _ebbTree = new ElementBndBoxTree( *_mesh, _elementType = type, _meshPartIt, tolerance );
6548     }
6549     TIDSortedElemSet suspectElems;
6550     _ebbTree->getElementsNearPoint( point, suspectElems );
6551     TIDSortedElemSet::iterator elem = suspectElems.begin();
6552     for ( ; elem != suspectElems.end(); ++elem )
6553       if ( !SMESH_MeshEditor::isOut( *elem, point, tolerance ))
6554         foundElements.push_back( *elem );
6555   }
6556   return foundElements.size();
6557 }
6558
6559 //================================================================================
6560 /*!
6561  * \brief Classify the given point in the closed 2D mesh
6562  */
6563 //================================================================================
6564
6565 TopAbs_State SMESH_ElementSearcherImpl::GetPointState(const gp_Pnt& point)
6566 {
6567   double tolerance = getTolerance();
6568   if ( !_ebbTree || _elementType != SMDSAbs_Face )
6569   {
6570     if ( _ebbTree ) delete _ebbTree;
6571     _ebbTree = new ElementBndBoxTree( *_mesh, _elementType = SMDSAbs_Face, _meshPartIt );
6572   }
6573   // Algo: analyse transition of a line starting at the point through mesh boundary;
6574   // try three lines parallel to axis of the coordinate system and perform rough
6575   // analysis. If solution is not clear perform thorough analysis.
6576
6577   const int nbAxes = 3;
6578   gp_Dir axisDir[ nbAxes ] = { gp::DX(), gp::DY(), gp::DZ() };
6579   map< double, TInters >   paramOnLine2TInters[ nbAxes ];
6580   list< TInters > tangentInters[ nbAxes ]; // of faces whose plane includes the line
6581   multimap< int, int > nbInt2Axis; // to find the simplest case
6582   for ( int axis = 0; axis < nbAxes; ++axis )
6583   {
6584     gp_Ax1 lineAxis( point, axisDir[axis]);
6585     gp_Lin line    ( lineAxis );
6586
6587     TIDSortedElemSet suspectFaces; // faces possibly intersecting the line
6588     _ebbTree->getElementsNearLine( lineAxis, suspectFaces );
6589
6590     // Intersect faces with the line
6591
6592     map< double, TInters > & u2inters = paramOnLine2TInters[ axis ];
6593     TIDSortedElemSet::iterator face = suspectFaces.begin();
6594     for ( ; face != suspectFaces.end(); ++face )
6595     {
6596       // get face plane
6597       gp_XYZ fNorm;
6598       if ( !SMESH_Algo::FaceNormal( *face, fNorm, /*normalized=*/false)) continue;
6599       gp_Pln facePlane( SMESH_TNodeXYZ( (*face)->GetNode(0)), fNorm );
6600
6601       // perform intersection
6602       IntAna_IntConicQuad intersection( line, IntAna_Quadric( facePlane ));
6603       if ( !intersection.IsDone() )
6604         continue;
6605       if ( intersection.IsInQuadric() )
6606       {
6607         tangentInters[ axis ].push_back( TInters( *face, fNorm, true ));
6608       }
6609       else if ( ! intersection.IsParallel() && intersection.NbPoints() > 0 )
6610       {
6611         gp_Pnt intersectionPoint = intersection.Point(1);
6612         if ( !SMESH_MeshEditor::isOut( *face, intersectionPoint, tolerance ))
6613           u2inters.insert(make_pair( intersection.ParamOnConic(1), TInters( *face, fNorm )));
6614       }
6615     }
6616     // Analyse intersections roughly
6617
6618     int nbInter = u2inters.size();
6619     if ( nbInter == 0 )
6620       return TopAbs_OUT; 
6621
6622     double f = u2inters.begin()->first, l = u2inters.rbegin()->first;
6623     if ( nbInter == 1 ) // not closed mesh
6624       return fabs( f ) < tolerance ? TopAbs_ON : TopAbs_UNKNOWN;
6625
6626     if ( fabs( f ) < tolerance || fabs( l ) < tolerance )
6627       return TopAbs_ON;
6628
6629     if ( (f<0) == (l<0) )
6630       return TopAbs_OUT;
6631
6632     int nbIntBeforePoint = std::distance( u2inters.begin(), u2inters.lower_bound(0));
6633     int nbIntAfterPoint  = nbInter - nbIntBeforePoint;
6634     if ( nbIntBeforePoint == 1 || nbIntAfterPoint == 1 )
6635       return TopAbs_IN;
6636
6637     nbInt2Axis.insert( make_pair( min( nbIntBeforePoint, nbIntAfterPoint ), axis ));
6638
6639     if ( _outerFacesFound ) break; // pass to thorough analysis
6640
6641   } // three attempts - loop on CS axes
6642
6643   // Analyse intersections thoroughly.
6644   // We make two loops maximum, on the first one we only exclude touching intersections,
6645   // on the second, if situation is still unclear, we gather and use information on
6646   // position of faces (internal or outer). If faces position is already gathered,
6647   // we make the second loop right away.
6648
6649   for ( int hasPositionInfo = _outerFacesFound; hasPositionInfo < 2; ++hasPositionInfo )
6650   {
6651     multimap< int, int >::const_iterator nb_axis = nbInt2Axis.begin();
6652     for ( ; nb_axis != nbInt2Axis.end(); ++nb_axis )
6653     {
6654       int axis = nb_axis->second;
6655       map< double, TInters > & u2inters = paramOnLine2TInters[ axis ];
6656
6657       gp_Ax1 lineAxis( point, axisDir[axis]);
6658       gp_Lin line    ( lineAxis );
6659
6660       // add tangent intersections to u2inters
6661       double param;
6662       list< TInters >::const_iterator tgtInt = tangentInters[ axis ].begin();
6663       for ( ; tgtInt != tangentInters[ axis ].end(); ++tgtInt )
6664         if ( getIntersParamOnLine( line, tgtInt->_face, tolerance, param ))
6665           u2inters.insert(make_pair( param, *tgtInt ));
6666       tangentInters[ axis ].clear();
6667
6668       // Count intersections before and after the point excluding touching ones.
6669       // If hasPositionInfo we count intersections of outer boundary only
6670
6671       int nbIntBeforePoint = 0, nbIntAfterPoint = 0;
6672       double f = numeric_limits<double>::max(), l = -numeric_limits<double>::max();
6673       map< double, TInters >::iterator u_int1 = u2inters.begin(), u_int2 = u_int1;
6674       bool ok = ! u_int1->second._coincides;
6675       while ( ok && u_int1 != u2inters.end() )
6676       {
6677         double u = u_int1->first;
6678         bool touchingInt = false;
6679         if ( ++u_int2 != u2inters.end() )
6680         {
6681           // skip intersections at the same point (if the line passes through edge or node)
6682           int nbSamePnt = 0;
6683           while ( u_int2 != u2inters.end() && fabs( u_int2->first - u ) < tolerance )
6684           {
6685             ++nbSamePnt;
6686             ++u_int2;
6687           }
6688
6689           // skip tangent intersections
6690           int nbTgt = 0;
6691           const SMDS_MeshElement* prevFace = u_int1->second._face;
6692           while ( ok && u_int2->second._coincides )
6693           {
6694             if ( SMESH_Algo::GetCommonNodes(prevFace , u_int2->second._face).empty() )
6695               ok = false;
6696             else
6697             {
6698               nbTgt++;
6699               u_int2++;
6700               ok = ( u_int2 != u2inters.end() );
6701             }
6702           }
6703           if ( !ok ) break;
6704
6705           // skip intersections at the same point after tangent intersections
6706           if ( nbTgt > 0 )
6707           {
6708             double u2 = u_int2->first;
6709             ++u_int2;
6710             while ( u_int2 != u2inters.end() && fabs( u_int2->first - u2 ) < tolerance )
6711             {
6712               ++nbSamePnt;
6713               ++u_int2;
6714             }
6715           }
6716           // decide if we skipped a touching intersection
6717           if ( nbSamePnt + nbTgt > 0 )
6718           {
6719             double minDot = numeric_limits<double>::max(), maxDot = -numeric_limits<double>::max();
6720             map< double, TInters >::iterator u_int = u_int1;
6721             for ( ; u_int != u_int2; ++u_int )
6722             {
6723               if ( u_int->second._coincides ) continue;
6724               double dot = u_int->second._faceNorm * line.Direction();
6725               if ( dot > maxDot ) maxDot = dot;
6726               if ( dot < minDot ) minDot = dot;
6727             }
6728             touchingInt = ( minDot*maxDot < 0 );
6729           }
6730         }
6731         if ( !touchingInt )
6732         {
6733           if ( !hasPositionInfo || isOuterBoundary( u_int1->second._face ))
6734           {
6735             if ( u < 0 )
6736               ++nbIntBeforePoint;
6737             else
6738               ++nbIntAfterPoint;
6739           }
6740           if ( u < f ) f = u;
6741           if ( u > l ) l = u;
6742         }
6743
6744         u_int1 = u_int2; // to next intersection
6745
6746       } // loop on intersections with one line
6747
6748       if ( ok )
6749       {
6750         if ( fabs( f ) < tolerance || fabs( l ) < tolerance )
6751           return TopAbs_ON;
6752
6753         if ( nbIntBeforePoint == 0  || nbIntAfterPoint == 0)
6754           return TopAbs_OUT; 
6755
6756         if ( nbIntBeforePoint + nbIntAfterPoint == 1 ) // not closed mesh
6757           return fabs( f ) < tolerance ? TopAbs_ON : TopAbs_UNKNOWN;
6758
6759         if ( nbIntBeforePoint == 1 || nbIntAfterPoint == 1 )
6760           return TopAbs_IN;
6761
6762         if ( (f<0) == (l<0) )
6763           return TopAbs_OUT;
6764
6765         if ( hasPositionInfo )
6766           return nbIntBeforePoint % 2 ? TopAbs_IN : TopAbs_OUT;
6767       }
6768     } // loop on intersections of the tree lines - thorough analysis
6769
6770     if ( !hasPositionInfo )
6771     {
6772       // gather info on faces position - is face in the outer boundary or not
6773       map< double, TInters > & u2inters = paramOnLine2TInters[ 0 ];
6774       findOuterBoundary( u2inters.begin()->second._face );
6775     }
6776
6777   } // two attempts - with and w/o faces position info in the mesh
6778
6779   return TopAbs_UNKNOWN;
6780 }
6781
6782 //=======================================================================
6783 /*!
6784  * \brief Return elements possibly intersecting the line
6785  */
6786 //=======================================================================
6787
6788 void SMESH_ElementSearcherImpl::GetElementsNearLine( const gp_Ax1&                      line,
6789                                                      SMDSAbs_ElementType                type,
6790                                                      vector< const SMDS_MeshElement* >& foundElems)
6791 {
6792   if ( !_ebbTree || _elementType != type )
6793   {
6794     if ( _ebbTree ) delete _ebbTree;
6795     _ebbTree = new ElementBndBoxTree( *_mesh, _elementType = type, _meshPartIt );
6796   }
6797   TIDSortedElemSet suspectFaces; // elements possibly intersecting the line
6798   _ebbTree->getElementsNearLine( line, suspectFaces );
6799   foundElems.assign( suspectFaces.begin(), suspectFaces.end());
6800 }
6801
6802 //=======================================================================
6803 /*!
6804  * \brief Return SMESH_ElementSearcher
6805  */
6806 //=======================================================================
6807
6808 SMESH_ElementSearcher* SMESH_MeshEditor::GetElementSearcher()
6809 {
6810   return new SMESH_ElementSearcherImpl( *GetMeshDS() );
6811 }
6812
6813 //=======================================================================
6814 /*!
6815  * \brief Return SMESH_ElementSearcher acting on a sub-set of elements
6816  */
6817 //=======================================================================
6818
6819 SMESH_ElementSearcher* SMESH_MeshEditor::GetElementSearcher(SMDS_ElemIteratorPtr elemIt)
6820 {
6821   return new SMESH_ElementSearcherImpl( *GetMeshDS(), elemIt );
6822 }
6823
6824 //=======================================================================
6825 /*!
6826  * \brief Return true if the point is IN or ON of the element
6827  */
6828 //=======================================================================
6829
6830 bool SMESH_MeshEditor::isOut( const SMDS_MeshElement* element, const gp_Pnt& point, double tol )
6831 {
6832   if ( element->GetType() == SMDSAbs_Volume)
6833   {
6834     return SMDS_VolumeTool( element ).IsOut( point.X(), point.Y(), point.Z(), tol );
6835   }
6836
6837   // get ordered nodes
6838
6839   vector< gp_XYZ > xyz;
6840   vector<const SMDS_MeshNode*> nodeList;
6841
6842   SMDS_ElemIteratorPtr nodeIt = element->nodesIterator();
6843   if ( element->IsQuadratic() ) {
6844     if (const SMDS_VtkFace* f=dynamic_cast<const SMDS_VtkFace*>(element))
6845       nodeIt = f->interlacedNodesElemIterator();
6846     else if (const SMDS_VtkEdge*  e =dynamic_cast<const SMDS_VtkEdge*>(element))
6847       nodeIt = e->interlacedNodesElemIterator();
6848   }
6849   while ( nodeIt->more() )
6850     {
6851       const SMDS_MeshNode* node = cast2Node( nodeIt->next() );
6852       xyz.push_back( SMESH_TNodeXYZ(node) );
6853       nodeList.push_back(node);
6854     }
6855
6856   int i, nbNodes = element->NbNodes();
6857
6858   if ( element->GetType() == SMDSAbs_Face ) // --------------------------------------------------
6859   {
6860     // compute face normal
6861     gp_Vec faceNorm(0,0,0);
6862     xyz.push_back( xyz.front() );
6863     nodeList.push_back( nodeList.front() );
6864     for ( i = 0; i < nbNodes; ++i )
6865     {
6866       gp_Vec edge1( xyz[i+1], xyz[i]);
6867       gp_Vec edge2( xyz[i+1], xyz[(i+2)%nbNodes] );
6868       faceNorm += edge1 ^ edge2;
6869     }
6870     double normSize = faceNorm.Magnitude();
6871     if ( normSize <= tol )
6872     {
6873       // degenerated face: point is out if it is out of all face edges
6874       for ( i = 0; i < nbNodes; ++i )
6875       {
6876         SMDS_LinearEdge edge( nodeList[i], nodeList[i+1] );
6877         if ( !isOut( &edge, point, tol ))
6878           return false;
6879       }
6880       return true;
6881     }
6882     faceNorm /= normSize;
6883
6884     // check if the point lays on face plane
6885     gp_Vec n2p( xyz[0], point );
6886     if ( fabs( n2p * faceNorm ) > tol )
6887       return true; // not on face plane
6888
6889     // check if point is out of face boundary:
6890     // define it by closest transition of a ray point->infinity through face boundary
6891     // on the face plane.
6892     // First, find normal of a plane perpendicular to face plane, to be used as a cutting tool
6893     // to find intersections of the ray with the boundary.
6894     gp_Vec ray = n2p;
6895     gp_Vec plnNorm = ray ^ faceNorm;
6896     normSize = plnNorm.Magnitude();
6897     if ( normSize <= tol ) return false; // point coincides with the first node
6898     plnNorm /= normSize;
6899     // for each node of the face, compute its signed distance to the plane
6900     vector<double> dist( nbNodes + 1);
6901     for ( i = 0; i < nbNodes; ++i )
6902     {
6903       gp_Vec n2p( xyz[i], point );
6904       dist[i] = n2p * plnNorm;
6905     }
6906     dist.back() = dist.front();
6907     // find the closest intersection
6908     int    iClosest = -1;
6909     double rClosest, distClosest = 1e100;;
6910     gp_Pnt pClosest;
6911     for ( i = 0; i < nbNodes; ++i )
6912     {
6913       double r;
6914       if ( fabs( dist[i]) < tol )
6915         r = 0.;
6916       else if ( fabs( dist[i+1]) < tol )
6917         r = 1.;
6918       else if ( dist[i] * dist[i+1] < 0 )
6919         r = dist[i] / ( dist[i] - dist[i+1] );
6920       else
6921         continue; // no intersection
6922       gp_Pnt pInt = xyz[i] * (1.-r) + xyz[i+1] * r;
6923       gp_Vec p2int ( point, pInt);
6924       if ( p2int * ray > -tol ) // right half-space
6925       {
6926         double intDist = p2int.SquareMagnitude();
6927         if ( intDist < distClosest )
6928         {
6929           iClosest = i;
6930           rClosest = r;
6931           pClosest = pInt;
6932           distClosest = intDist;
6933         }
6934       }
6935     }
6936     if ( iClosest < 0 )
6937       return true; // no intesections - out
6938
6939     // analyse transition
6940     gp_Vec edge( xyz[iClosest], xyz[iClosest+1] );
6941     gp_Vec edgeNorm = -( edge ^ faceNorm ); // normal to intersected edge pointing out of face
6942     gp_Vec p2int ( point, pClosest );
6943     bool out = (edgeNorm * p2int) < -tol;
6944     if ( rClosest > 0. && rClosest < 1. ) // not node intersection
6945       return out;
6946
6947     // ray pass through a face node; analyze transition through an adjacent edge
6948     gp_Pnt p1 = xyz[ (rClosest == 0.) ? ((iClosest+nbNodes-1) % nbNodes) : (iClosest+1) ];
6949     gp_Pnt p2 = xyz[ (rClosest == 0.) ? iClosest : ((iClosest+2) % nbNodes) ];
6950     gp_Vec edgeAdjacent( p1, p2 );
6951     gp_Vec edgeNorm2 = -( edgeAdjacent ^ faceNorm );
6952     bool out2 = (edgeNorm2 * p2int) < -tol;
6953
6954     bool covexCorner = ( edgeNorm * edgeAdjacent * (rClosest==1. ? 1. : -1.)) < 0;
6955     return covexCorner ? (out || out2) : (out && out2);
6956   }
6957   if ( element->GetType() == SMDSAbs_Edge ) // --------------------------------------------------
6958   {
6959     // point is out of edge if it is NOT ON any straight part of edge
6960     // (we consider quadratic edge as being composed of two straight parts)
6961     for ( i = 1; i < nbNodes; ++i )
6962     {
6963       gp_Vec edge( xyz[i-1], xyz[i]);
6964       gp_Vec n1p ( xyz[i-1], point);
6965       double dist = ( edge ^ n1p ).Magnitude() / edge.Magnitude();
6966       if ( dist > tol )
6967         continue;
6968       gp_Vec n2p( xyz[i], point );
6969       if ( fabs( edge.Magnitude() - n1p.Magnitude() - n2p.Magnitude()) > tol )
6970         continue;
6971       return false; // point is ON this part
6972     }
6973     return true;
6974   }
6975   // Node or 0D element -------------------------------------------------------------------------
6976   {
6977     gp_Vec n2p ( xyz[0], point );
6978     return n2p.Magnitude() <= tol;
6979   }
6980   return true;
6981 }
6982
6983 //=======================================================================
6984 //function : SimplifyFace
6985 //purpose  :
6986 //=======================================================================
6987 int SMESH_MeshEditor::SimplifyFace (const vector<const SMDS_MeshNode *> faceNodes,
6988                                     vector<const SMDS_MeshNode *>&      poly_nodes,
6989                                     vector<int>&                        quantities) const
6990 {
6991   int nbNodes = faceNodes.size();
6992
6993   if (nbNodes < 3)
6994     return 0;
6995
6996   set<const SMDS_MeshNode*> nodeSet;
6997
6998   // get simple seq of nodes
6999   //const SMDS_MeshNode* simpleNodes[ nbNodes ];
7000   vector<const SMDS_MeshNode*> simpleNodes( nbNodes );
7001   int iSimple = 0, nbUnique = 0;
7002
7003   simpleNodes[iSimple++] = faceNodes[0];
7004   nbUnique++;
7005   for (int iCur = 1; iCur < nbNodes; iCur++) {
7006     if (faceNodes[iCur] != simpleNodes[iSimple - 1]) {
7007       simpleNodes[iSimple++] = faceNodes[iCur];
7008       if (nodeSet.insert( faceNodes[iCur] ).second)
7009         nbUnique++;
7010     }
7011   }
7012   int nbSimple = iSimple;
7013   if (simpleNodes[nbSimple - 1] == simpleNodes[0]) {
7014     nbSimple--;
7015     iSimple--;
7016   }
7017
7018   if (nbUnique < 3)
7019     return 0;
7020
7021   // separate loops
7022   int nbNew = 0;
7023   bool foundLoop = (nbSimple > nbUnique);
7024   while (foundLoop) {
7025     foundLoop = false;
7026     set<const SMDS_MeshNode*> loopSet;
7027     for (iSimple = 0; iSimple < nbSimple && !foundLoop; iSimple++) {
7028       const SMDS_MeshNode* n = simpleNodes[iSimple];
7029       if (!loopSet.insert( n ).second) {
7030         foundLoop = true;
7031
7032         // separate loop
7033         int iC = 0, curLast = iSimple;
7034         for (; iC < curLast; iC++) {
7035           if (simpleNodes[iC] == n) break;
7036         }
7037         int loopLen = curLast - iC;
7038         if (loopLen > 2) {
7039           // create sub-element
7040           nbNew++;
7041           quantities.push_back(loopLen);
7042           for (; iC < curLast; iC++) {
7043             poly_nodes.push_back(simpleNodes[iC]);
7044           }
7045         }
7046         // shift the rest nodes (place from the first loop position)
7047         for (iC = curLast + 1; iC < nbSimple; iC++) {
7048           simpleNodes[iC - loopLen] = simpleNodes[iC];
7049         }
7050         nbSimple -= loopLen;
7051         iSimple -= loopLen;
7052       }
7053     } // for (iSimple = 0; iSimple < nbSimple; iSimple++)
7054   } // while (foundLoop)
7055
7056   if (iSimple > 2) {
7057     nbNew++;
7058     quantities.push_back(iSimple);
7059     for (int i = 0; i < iSimple; i++)
7060       poly_nodes.push_back(simpleNodes[i]);
7061   }
7062
7063   return nbNew;
7064 }
7065
7066 //=======================================================================
7067 //function : MergeNodes
7068 //purpose  : In each group, the cdr of nodes are substituted by the first one
7069 //           in all elements.
7070 //=======================================================================
7071
7072 void SMESH_MeshEditor::MergeNodes (TListOfListOfNodes & theGroupsOfNodes)
7073 {
7074   MESSAGE("MergeNodes");
7075   myLastCreatedElems.Clear();
7076   myLastCreatedNodes.Clear();
7077
7078   SMESHDS_Mesh* aMesh = GetMeshDS();
7079
7080   TNodeNodeMap nodeNodeMap; // node to replace - new node
7081   set<const SMDS_MeshElement*> elems; // all elements with changed nodes
7082   list< int > rmElemIds, rmNodeIds;
7083
7084   // Fill nodeNodeMap and elems
7085
7086   TListOfListOfNodes::iterator grIt = theGroupsOfNodes.begin();
7087   for ( ; grIt != theGroupsOfNodes.end(); grIt++ ) {
7088     list<const SMDS_MeshNode*>& nodes = *grIt;
7089     list<const SMDS_MeshNode*>::iterator nIt = nodes.begin();
7090     const SMDS_MeshNode* nToKeep = *nIt;
7091     //MESSAGE("node to keep " << nToKeep->GetID());
7092     for ( ++nIt; nIt != nodes.end(); nIt++ ) {
7093       const SMDS_MeshNode* nToRemove = *nIt;
7094       nodeNodeMap.insert( TNodeNodeMap::value_type( nToRemove, nToKeep ));
7095       if ( nToRemove != nToKeep ) {
7096         //MESSAGE("  node to remove " << nToRemove->GetID());
7097         rmNodeIds.push_back( nToRemove->GetID() );
7098         AddToSameGroups( nToKeep, nToRemove, aMesh );
7099       }
7100
7101       SMDS_ElemIteratorPtr invElemIt = nToRemove->GetInverseElementIterator();
7102       while ( invElemIt->more() ) {
7103         const SMDS_MeshElement* elem = invElemIt->next();
7104         elems.insert(elem);
7105       }
7106     }
7107   }
7108   // Change element nodes or remove an element
7109
7110   set<const SMDS_MeshElement*>::iterator eIt = elems.begin();
7111   for ( ; eIt != elems.end(); eIt++ ) {
7112     const SMDS_MeshElement* elem = *eIt;
7113     //MESSAGE(" ---- inverse elem on node to remove " << elem->GetID());
7114     int nbNodes = elem->NbNodes();
7115     int aShapeId = FindShape( elem );
7116
7117     set<const SMDS_MeshNode*> nodeSet;
7118     vector< const SMDS_MeshNode*> curNodes( nbNodes ), uniqueNodes( nbNodes );
7119     int iUnique = 0, iCur = 0, nbRepl = 0;
7120     vector<int> iRepl( nbNodes );
7121
7122     // get new seq of nodes
7123     SMDS_ElemIteratorPtr itN = elem->nodesIterator();
7124     while ( itN->more() ) {
7125       const SMDS_MeshNode* n =
7126         static_cast<const SMDS_MeshNode*>( itN->next() );
7127
7128       TNodeNodeMap::iterator nnIt = nodeNodeMap.find( n );
7129       if ( nnIt != nodeNodeMap.end() ) { // n sticks
7130         n = (*nnIt).second;
7131         // BUG 0020185: begin
7132         {
7133           bool stopRecur = false;
7134           set<const SMDS_MeshNode*> nodesRecur;
7135           nodesRecur.insert(n);
7136           while (!stopRecur) {
7137             TNodeNodeMap::iterator nnIt_i = nodeNodeMap.find( n );
7138             if ( nnIt_i != nodeNodeMap.end() ) { // n sticks
7139               n = (*nnIt_i).second;
7140               if (!nodesRecur.insert(n).second) {
7141                 // error: recursive dependancy
7142                 stopRecur = true;
7143               }
7144             }
7145             else
7146               stopRecur = true;
7147           }
7148         }
7149         // BUG 0020185: end
7150       }
7151       curNodes[ iCur ] = n;
7152       bool isUnique = nodeSet.insert( n ).second;
7153       if ( isUnique )
7154         uniqueNodes[ iUnique++ ] = n;
7155       else
7156         iRepl[ nbRepl++ ] = iCur;
7157       iCur++;
7158     }
7159
7160     // Analyse element topology after replacement
7161
7162     bool isOk = true;
7163     int nbUniqueNodes = nodeSet.size();
7164     //MESSAGE("nbNodes nbUniqueNodes " << nbNodes << " " << nbUniqueNodes);
7165     if ( nbNodes != nbUniqueNodes ) { // some nodes stick
7166       // Polygons and Polyhedral volumes
7167       if (elem->IsPoly()) {
7168
7169         if (elem->GetType() == SMDSAbs_Face) {
7170           // Polygon
7171           vector<const SMDS_MeshNode *> face_nodes (nbNodes);
7172           int inode = 0;
7173           for (; inode < nbNodes; inode++) {
7174             face_nodes[inode] = curNodes[inode];
7175           }
7176
7177           vector<const SMDS_MeshNode *> polygons_nodes;
7178           vector<int> quantities;
7179           int nbNew = SimplifyFace(face_nodes, polygons_nodes, quantities);
7180           if (nbNew > 0) {
7181             inode = 0;
7182             for (int iface = 0; iface < nbNew; iface++) {
7183               int nbNodes = quantities[iface];
7184               vector<const SMDS_MeshNode *> poly_nodes (nbNodes);
7185               for (int ii = 0; ii < nbNodes; ii++, inode++) {
7186                 poly_nodes[ii] = polygons_nodes[inode];
7187               }
7188               SMDS_MeshElement* newElem = aMesh->AddPolygonalFace(poly_nodes);
7189               myLastCreatedElems.Append(newElem);
7190               if (aShapeId)
7191                 aMesh->SetMeshElementOnShape(newElem, aShapeId);
7192             }
7193
7194             MESSAGE("ChangeElementNodes MergeNodes Polygon");
7195             //aMesh->ChangeElementNodes(elem, &polygons_nodes[inode], quantities[nbNew - 1]);
7196             vector<const SMDS_MeshNode *> polynodes(polygons_nodes.begin()+inode,polygons_nodes.end());
7197             int quid =0;
7198             if (nbNew > 0) quid = nbNew - 1;
7199             vector<int> newquant(quantities.begin()+quid, quantities.end());
7200             const SMDS_MeshElement* newElem = 0;
7201             newElem = aMesh->AddPolyhedralVolume(polynodes, newquant);
7202             myLastCreatedElems.Append(newElem);
7203             if ( aShapeId && newElem )
7204               aMesh->SetMeshElementOnShape( newElem, aShapeId );
7205             rmElemIds.push_back(elem->GetID());
7206           }
7207           else {
7208             rmElemIds.push_back(elem->GetID());
7209           }
7210
7211         }
7212         else if (elem->GetType() == SMDSAbs_Volume) {
7213           // Polyhedral volume
7214           if (nbUniqueNodes < 4) {
7215             rmElemIds.push_back(elem->GetID());
7216           }
7217           else {
7218             // each face has to be analyzed in order to check volume validity
7219             const SMDS_VtkVolume* aPolyedre =
7220               dynamic_cast<const SMDS_VtkVolume*>( elem );
7221             if (aPolyedre) {
7222               int nbFaces = aPolyedre->NbFaces();
7223
7224               vector<const SMDS_MeshNode *> poly_nodes;
7225               vector<int> quantities;
7226
7227               for (int iface = 1; iface <= nbFaces; iface++) {
7228                 int nbFaceNodes = aPolyedre->NbFaceNodes(iface);
7229                 vector<const SMDS_MeshNode *> faceNodes (nbFaceNodes);
7230
7231                 for (int inode = 1; inode <= nbFaceNodes; inode++) {
7232                   const SMDS_MeshNode * faceNode = aPolyedre->GetFaceNode(iface, inode);
7233                   TNodeNodeMap::iterator nnIt = nodeNodeMap.find(faceNode);
7234                   if (nnIt != nodeNodeMap.end()) { // faceNode sticks
7235                     faceNode = (*nnIt).second;
7236                   }
7237                   faceNodes[inode - 1] = faceNode;
7238                 }
7239
7240                 SimplifyFace(faceNodes, poly_nodes, quantities);
7241               }
7242
7243               if (quantities.size() > 3) {
7244                 // to be done: remove coincident faces
7245               }
7246
7247               if (quantities.size() > 3)
7248                 {
7249                   MESSAGE("ChangeElementNodes MergeNodes Polyhedron");
7250                   //aMesh->ChangePolyhedronNodes(elem, poly_nodes, quantities);
7251                   const SMDS_MeshElement* newElem = 0;
7252                   newElem = aMesh->AddPolyhedralVolume(poly_nodes, quantities);
7253                   myLastCreatedElems.Append(newElem);
7254                   if ( aShapeId && newElem )
7255                     aMesh->SetMeshElementOnShape( newElem, aShapeId );
7256                   rmElemIds.push_back(elem->GetID());
7257                 }
7258             }
7259             else {
7260               rmElemIds.push_back(elem->GetID());
7261             }
7262           }
7263         }
7264         else {
7265         }
7266
7267         continue;
7268       } // poly element
7269
7270       // Regular elements
7271       // TODO not all the possible cases are solved. Find something more generic?
7272       switch ( nbNodes ) {
7273       case 2: ///////////////////////////////////// EDGE
7274         isOk = false; break;
7275       case 3: ///////////////////////////////////// TRIANGLE
7276         isOk = false; break;
7277       case 4:
7278         if ( elem->GetType() == SMDSAbs_Volume ) // TETRAHEDRON
7279           isOk = false;
7280         else { //////////////////////////////////// QUADRANGLE
7281           if ( nbUniqueNodes < 3 )
7282             isOk = false;
7283           else if ( nbRepl == 2 && iRepl[ 1 ] - iRepl[ 0 ] == 2 )
7284             isOk = false; // opposite nodes stick
7285           //MESSAGE("isOk " << isOk);
7286         }
7287         break;
7288       case 6: ///////////////////////////////////// PENTAHEDRON
7289         if ( nbUniqueNodes == 4 ) {
7290           // ---------------------------------> tetrahedron
7291           if (nbRepl == 3 &&
7292               iRepl[ 0 ] > 2 && iRepl[ 1 ] > 2 && iRepl[ 2 ] > 2 ) {
7293             // all top nodes stick: reverse a bottom
7294             uniqueNodes[ 0 ] = curNodes [ 1 ];
7295             uniqueNodes[ 1 ] = curNodes [ 0 ];
7296           }
7297           else if (nbRepl == 3 &&
7298                    iRepl[ 0 ] < 3 && iRepl[ 1 ] < 3 && iRepl[ 2 ] < 3 ) {
7299             // all bottom nodes stick: set a top before
7300             uniqueNodes[ 3 ] = uniqueNodes [ 0 ];
7301             uniqueNodes[ 0 ] = curNodes [ 3 ];
7302             uniqueNodes[ 1 ] = curNodes [ 4 ];
7303             uniqueNodes[ 2 ] = curNodes [ 5 ];
7304           }
7305           else if (nbRepl == 4 &&
7306                    iRepl[ 2 ] - iRepl [ 0 ] == 3 && iRepl[ 3 ] - iRepl [ 1 ] == 3 ) {
7307             // a lateral face turns into a line: reverse a bottom
7308             uniqueNodes[ 0 ] = curNodes [ 1 ];
7309             uniqueNodes[ 1 ] = curNodes [ 0 ];
7310           }
7311           else
7312             isOk = false;
7313         }
7314         else if ( nbUniqueNodes == 5 ) {
7315           // PENTAHEDRON --------------------> 2 tetrahedrons
7316           if ( nbRepl == 2 && iRepl[ 1 ] - iRepl [ 0 ] == 3 ) {
7317             // a bottom node sticks with a linked top one
7318             // 1.
7319             SMDS_MeshElement* newElem =
7320               aMesh->AddVolume(curNodes[ 3 ],
7321                                curNodes[ 4 ],
7322                                curNodes[ 5 ],
7323                                curNodes[ iRepl[ 0 ] == 2 ? 1 : 2 ]);
7324             myLastCreatedElems.Append(newElem);
7325             if ( aShapeId )
7326               aMesh->SetMeshElementOnShape( newElem, aShapeId );
7327             // 2. : reverse a bottom
7328             uniqueNodes[ 0 ] = curNodes [ 1 ];
7329             uniqueNodes[ 1 ] = curNodes [ 0 ];
7330             nbUniqueNodes = 4;
7331           }
7332           else
7333             isOk = false;
7334         }
7335         else
7336           isOk = false;
7337         break;
7338       case 8: {
7339         if(elem->IsQuadratic()) { // Quadratic quadrangle
7340           //   1    5    2
7341           //    +---+---+
7342           //    |       |
7343           //    |       |
7344           //   4+       +6
7345           //    |       |
7346           //    |       |
7347           //    +---+---+
7348           //   0    7    3
7349           isOk = false;
7350           if(nbRepl==2) {
7351             MESSAGE("nbRepl=2: " << iRepl[0] << " " << iRepl[1]);
7352           }
7353           if(nbRepl==3) {
7354             MESSAGE("nbRepl=3: " << iRepl[0] << " " << iRepl[1]  << " " << iRepl[2]);
7355             nbUniqueNodes = 6;
7356             if( iRepl[0]==0 && iRepl[1]==1 && iRepl[2]==4 ) {
7357               uniqueNodes[0] = curNodes[0];
7358               uniqueNodes[1] = curNodes[2];
7359               uniqueNodes[2] = curNodes[3];
7360               uniqueNodes[3] = curNodes[5];
7361               uniqueNodes[4] = curNodes[6];
7362               uniqueNodes[5] = curNodes[7];
7363               isOk = true;
7364             }
7365             if( iRepl[0]==0 && iRepl[1]==3 && iRepl[2]==7 ) {
7366               uniqueNodes[0] = curNodes[0];
7367               uniqueNodes[1] = curNodes[1];
7368               uniqueNodes[2] = curNodes[2];
7369               uniqueNodes[3] = curNodes[4];
7370               uniqueNodes[4] = curNodes[5];
7371               uniqueNodes[5] = curNodes[6];
7372               isOk = true;
7373             }
7374             if( iRepl[0]==0 && iRepl[1]==4 && iRepl[2]==7 ) {
7375               uniqueNodes[0] = curNodes[1];
7376               uniqueNodes[1] = curNodes[2];
7377               uniqueNodes[2] = curNodes[3];
7378               uniqueNodes[3] = curNodes[5];
7379               uniqueNodes[4] = curNodes[6];
7380               uniqueNodes[5] = curNodes[0];
7381               isOk = true;
7382             }
7383             if( iRepl[0]==1 && iRepl[1]==2 && iRepl[2]==5 ) {
7384               uniqueNodes[0] = curNodes[0];
7385               uniqueNodes[1] = curNodes[1];
7386               uniqueNodes[2] = curNodes[3];
7387               uniqueNodes[3] = curNodes[4];
7388               uniqueNodes[4] = curNodes[6];
7389               uniqueNodes[5] = curNodes[7];
7390               isOk = true;
7391             }
7392             if( iRepl[0]==1 && iRepl[1]==4 && iRepl[2]==5 ) {
7393               uniqueNodes[0] = curNodes[0];
7394               uniqueNodes[1] = curNodes[2];
7395               uniqueNodes[2] = curNodes[3];
7396               uniqueNodes[3] = curNodes[1];
7397               uniqueNodes[4] = curNodes[6];
7398               uniqueNodes[5] = curNodes[7];
7399               isOk = true;
7400             }
7401             if( iRepl[0]==2 && iRepl[1]==3 && iRepl[2]==6 ) {
7402               uniqueNodes[0] = curNodes[0];
7403               uniqueNodes[1] = curNodes[1];
7404               uniqueNodes[2] = curNodes[2];
7405               uniqueNodes[3] = curNodes[4];
7406               uniqueNodes[4] = curNodes[5];
7407               uniqueNodes[5] = curNodes[7];
7408               isOk = true;
7409             }
7410             if( iRepl[0]==2 && iRepl[1]==5 && iRepl[2]==6 ) {
7411               uniqueNodes[0] = curNodes[0];
7412               uniqueNodes[1] = curNodes[1];
7413               uniqueNodes[2] = curNodes[3];
7414               uniqueNodes[3] = curNodes[4];
7415               uniqueNodes[4] = curNodes[2];
7416               uniqueNodes[5] = curNodes[7];
7417               isOk = true;
7418             }
7419             if( iRepl[0]==3 && iRepl[1]==6 && iRepl[2]==7 ) {
7420               uniqueNodes[0] = curNodes[0];
7421               uniqueNodes[1] = curNodes[1];
7422               uniqueNodes[2] = curNodes[2];
7423               uniqueNodes[3] = curNodes[4];
7424               uniqueNodes[4] = curNodes[5];
7425               uniqueNodes[5] = curNodes[3];
7426               isOk = true;
7427             }
7428           }
7429           if(nbRepl==4) {
7430             MESSAGE("nbRepl=4: " << iRepl[0] << " " << iRepl[1]  << " " << iRepl[2] << " " << iRepl[3]);
7431           }
7432           if(nbRepl==5) {
7433             MESSAGE("nbRepl=5: " << iRepl[0] << " " << iRepl[1]  << " " << iRepl[2] << " " << iRepl[3] << " " << iRepl[4]);
7434           }
7435           break;
7436         }
7437         //////////////////////////////////// HEXAHEDRON
7438         isOk = false;
7439         SMDS_VolumeTool hexa (elem);
7440         hexa.SetExternalNormal();
7441         if ( nbUniqueNodes == 4 && nbRepl == 4 ) {
7442           //////////////////////// HEX ---> 1 tetrahedron
7443           for ( int iFace = 0; iFace < 6; iFace++ ) {
7444             const int *ind = hexa.GetFaceNodesIndices( iFace ); // indices of face nodes
7445             if (curNodes[ind[ 0 ]] == curNodes[ind[ 1 ]] &&
7446                 curNodes[ind[ 0 ]] == curNodes[ind[ 2 ]] &&
7447                 curNodes[ind[ 0 ]] == curNodes[ind[ 3 ]] ) {
7448               // one face turns into a point ...
7449               int iOppFace = hexa.GetOppFaceIndex( iFace );
7450               ind = hexa.GetFaceNodesIndices( iOppFace );
7451               int nbStick = 0;
7452               for ( iCur = 0; iCur < 4 && nbStick < 2; iCur++ ) {
7453                 if ( curNodes[ind[ iCur ]] == curNodes[ind[ iCur + 1 ]] )
7454                   nbStick++;
7455               }
7456               if ( nbStick == 1 ) {
7457                 // ... and the opposite one - into a triangle.
7458                 // set a top node
7459                 ind = hexa.GetFaceNodesIndices( iFace );
7460                 uniqueNodes[ 3 ] = curNodes[ind[ 0 ]];
7461                 isOk = true;
7462               }
7463               break;
7464             }
7465           }
7466         }
7467         else if ( nbUniqueNodes == 6 && nbRepl == 2 ) {
7468           //////////////////////// HEX ---> 1 prism
7469           int nbTria = 0, iTria[3];
7470           const int *ind; // indices of face nodes
7471           // look for triangular faces
7472           for ( int iFace = 0; iFace < 6 && nbTria < 3; iFace++ ) {
7473             ind = hexa.GetFaceNodesIndices( iFace );
7474             TIDSortedNodeSet faceNodes;
7475             for ( iCur = 0; iCur < 4; iCur++ )
7476               faceNodes.insert( curNodes[ind[iCur]] );
7477             if ( faceNodes.size() == 3 )
7478               iTria[ nbTria++ ] = iFace;
7479           }
7480           // check if triangles are opposite
7481           if ( nbTria == 2 && iTria[0] == hexa.GetOppFaceIndex( iTria[1] ))
7482           {
7483             isOk = true;
7484             // set nodes of the bottom triangle
7485             ind = hexa.GetFaceNodesIndices( iTria[ 0 ]);
7486             vector<int> indB;
7487             for ( iCur = 0; iCur < 4; iCur++ )
7488               if ( ind[iCur] != iRepl[0] && ind[iCur] != iRepl[1])
7489                 indB.push_back( ind[iCur] );
7490             if ( !hexa.IsForward() )
7491               std::swap( indB[0], indB[2] );
7492             for ( iCur = 0; iCur < 3; iCur++ )
7493               uniqueNodes[ iCur ] = curNodes[indB[iCur]];
7494             // set nodes of the top triangle
7495             const int *indT = hexa.GetFaceNodesIndices( iTria[ 1 ]);
7496             for ( iCur = 0; iCur < 3; ++iCur )
7497               for ( int j = 0; j < 4; ++j )
7498                 if ( hexa.IsLinked( indB[ iCur ], indT[ j ] ))
7499                 {
7500                   uniqueNodes[ iCur + 3 ] = curNodes[ indT[ j ]];
7501                   break;
7502                 }
7503           }
7504           break;
7505         }
7506         else if (nbUniqueNodes == 5 && nbRepl == 4 ) {
7507           //////////////////// HEXAHEDRON ---> 2 tetrahedrons
7508           for ( int iFace = 0; iFace < 6; iFace++ ) {
7509             const int *ind = hexa.GetFaceNodesIndices( iFace ); // indices of face nodes
7510             if (curNodes[ind[ 0 ]] == curNodes[ind[ 1 ]] &&
7511                 curNodes[ind[ 0 ]] == curNodes[ind[ 2 ]] &&
7512                 curNodes[ind[ 0 ]] == curNodes[ind[ 3 ]] ) {
7513               // one face turns into a point ...
7514               int iOppFace = hexa.GetOppFaceIndex( iFace );
7515               ind = hexa.GetFaceNodesIndices( iOppFace );
7516               int nbStick = 0;
7517               iUnique = 2;  // reverse a tetrahedron 1 bottom
7518               for ( iCur = 0; iCur < 4 && nbStick == 0; iCur++ ) {
7519                 if ( curNodes[ind[ iCur ]] == curNodes[ind[ iCur + 1 ]] )
7520                   nbStick++;
7521                 else if ( iUnique >= 0 )
7522                   uniqueNodes[ iUnique-- ] = curNodes[ind[ iCur ]];
7523               }
7524               if ( nbStick == 0 ) {
7525                 // ... and the opposite one is a quadrangle
7526                 // set a top node
7527                 const int* indTop = hexa.GetFaceNodesIndices( iFace );
7528                 uniqueNodes[ 3 ] = curNodes[indTop[ 0 ]];
7529                 nbUniqueNodes = 4;
7530                 // tetrahedron 2
7531                 SMDS_MeshElement* newElem =
7532                   aMesh->AddVolume(curNodes[ind[ 0 ]],
7533                                    curNodes[ind[ 3 ]],
7534                                    curNodes[ind[ 2 ]],
7535                                    curNodes[indTop[ 0 ]]);
7536                 myLastCreatedElems.Append(newElem);
7537                 if ( aShapeId )
7538                   aMesh->SetMeshElementOnShape( newElem, aShapeId );
7539                 isOk = true;
7540               }
7541               break;
7542             }
7543           }
7544         }
7545         else if ( nbUniqueNodes == 6 && nbRepl == 4 ) {
7546           ////////////////// HEXAHEDRON ---> 2 tetrahedrons or 1 prism
7547           // find indices of quad and tri faces
7548           int iQuadFace[ 6 ], iTriFace[ 6 ], nbQuad = 0, nbTri = 0, iFace;
7549           for ( iFace = 0; iFace < 6; iFace++ ) {
7550             const int *ind = hexa.GetFaceNodesIndices( iFace ); // indices of face nodes
7551             nodeSet.clear();
7552             for ( iCur = 0; iCur < 4; iCur++ )
7553               nodeSet.insert( curNodes[ind[ iCur ]] );
7554             nbUniqueNodes = nodeSet.size();
7555             if ( nbUniqueNodes == 3 )
7556               iTriFace[ nbTri++ ] = iFace;
7557             else if ( nbUniqueNodes == 4 )
7558               iQuadFace[ nbQuad++ ] = iFace;
7559           }
7560           if (nbQuad == 2 && nbTri == 4 &&
7561               hexa.GetOppFaceIndex( iQuadFace[ 0 ] ) == iQuadFace[ 1 ]) {
7562             // 2 opposite quadrangles stuck with a diagonal;
7563             // sample groups of merged indices: (0-4)(2-6)
7564             // --------------------------------------------> 2 tetrahedrons
7565             const int *ind1 = hexa.GetFaceNodesIndices( iQuadFace[ 0 ]); // indices of quad1 nodes
7566             const int *ind2 = hexa.GetFaceNodesIndices( iQuadFace[ 1 ]);
7567             int i0, i1d, i2, i3d, i0t, i2t; // d-daigonal, t-top
7568             if (curNodes[ind1[ 0 ]] == curNodes[ind2[ 0 ]] &&
7569                 curNodes[ind1[ 2 ]] == curNodes[ind2[ 2 ]]) {
7570               // stuck with 0-2 diagonal
7571               i0  = ind1[ 3 ];
7572               i1d = ind1[ 0 ];
7573               i2  = ind1[ 1 ];
7574               i3d = ind1[ 2 ];
7575               i0t = ind2[ 1 ];
7576               i2t = ind2[ 3 ];
7577             }
7578             else if (curNodes[ind1[ 1 ]] == curNodes[ind2[ 3 ]] &&
7579                      curNodes[ind1[ 3 ]] == curNodes[ind2[ 1 ]]) {
7580               // stuck with 1-3 diagonal
7581               i0  = ind1[ 0 ];
7582               i1d = ind1[ 1 ];
7583               i2  = ind1[ 2 ];
7584               i3d = ind1[ 3 ];
7585               i0t = ind2[ 0 ];
7586               i2t = ind2[ 1 ];
7587             }
7588             else {
7589               ASSERT(0);
7590             }
7591             // tetrahedron 1
7592             uniqueNodes[ 0 ] = curNodes [ i0 ];
7593             uniqueNodes[ 1 ] = curNodes [ i1d ];
7594             uniqueNodes[ 2 ] = curNodes [ i3d ];
7595             uniqueNodes[ 3 ] = curNodes [ i0t ];
7596             nbUniqueNodes = 4;
7597             // tetrahedron 2
7598             SMDS_MeshElement* newElem = aMesh->AddVolume(curNodes[ i1d ],
7599                                                          curNodes[ i2 ],
7600                                                          curNodes[ i3d ],
7601                                                          curNodes[ i2t ]);
7602             myLastCreatedElems.Append(newElem);
7603             if ( aShapeId )
7604               aMesh->SetMeshElementOnShape( newElem, aShapeId );
7605             isOk = true;
7606           }
7607           else if (( nbTri == 2 && nbQuad == 3 ) || // merged (0-4)(1-5)
7608                    ( nbTri == 4 && nbQuad == 2 )) { // merged (7-4)(1-5)
7609             // --------------------------------------------> prism
7610             // find 2 opposite triangles
7611             nbUniqueNodes = 6;
7612             for ( iFace = 0; iFace + 1 < nbTri; iFace++ ) {
7613               if ( hexa.GetOppFaceIndex( iTriFace[ iFace ] ) == iTriFace[ iFace + 1 ]) {
7614                 // find indices of kept and replaced nodes
7615                 // and fill unique nodes of 2 opposite triangles
7616                 const int *ind1 = hexa.GetFaceNodesIndices( iTriFace[ iFace ]);
7617                 const int *ind2 = hexa.GetFaceNodesIndices( iTriFace[ iFace + 1 ]);
7618                 const SMDS_MeshNode** hexanodes = hexa.GetNodes();
7619                 // fill unique nodes
7620                 iUnique = 0;
7621                 isOk = true;
7622                 for ( iCur = 0; iCur < 4 && isOk; iCur++ ) {
7623                   const SMDS_MeshNode* n     = curNodes[ind1[ iCur ]];
7624                   const SMDS_MeshNode* nInit = hexanodes[ind1[ iCur ]];
7625                   if ( n == nInit ) {
7626                     // iCur of a linked node of the opposite face (make normals co-directed):
7627                     int iCurOpp = ( iCur == 1 || iCur == 3 ) ? 4 - iCur : iCur;
7628                     // check that correspondent corners of triangles are linked
7629                     if ( !hexa.IsLinked( ind1[ iCur ], ind2[ iCurOpp ] ))
7630                       isOk = false;
7631                     else {
7632                       uniqueNodes[ iUnique ] = n;
7633                       uniqueNodes[ iUnique + 3 ] = curNodes[ind2[ iCurOpp ]];
7634                       iUnique++;
7635                     }
7636                   }
7637                 }
7638                 break;
7639               }
7640             }
7641           }
7642         } // if ( nbUniqueNodes == 6 && nbRepl == 4 )
7643         else
7644         {
7645           MESSAGE("MergeNodes() removes hexahedron "<< elem);
7646         }
7647         break;
7648       } // HEXAHEDRON
7649
7650       default:
7651         isOk = false;
7652       } // switch ( nbNodes )
7653
7654     } // if ( nbNodes != nbUniqueNodes ) // some nodes stick
7655
7656     if ( isOk ) { // the elem remains valid after sticking nodes
7657       if (elem->IsPoly() && elem->GetType() == SMDSAbs_Volume)
7658       {
7659         // Change nodes of polyedre
7660         const SMDS_VtkVolume* aPolyedre =
7661           dynamic_cast<const SMDS_VtkVolume*>( elem );
7662         if (aPolyedre) {
7663           int nbFaces = aPolyedre->NbFaces();
7664
7665           vector<const SMDS_MeshNode *> poly_nodes;
7666           vector<int> quantities (nbFaces);
7667
7668           for (int iface = 1; iface <= nbFaces; iface++) {
7669             int inode, nbFaceNodes = aPolyedre->NbFaceNodes(iface);
7670             quantities[iface - 1] = nbFaceNodes;
7671
7672             for (inode = 1; inode <= nbFaceNodes; inode++) {
7673               const SMDS_MeshNode* curNode = aPolyedre->GetFaceNode(iface, inode);
7674
7675               TNodeNodeMap::iterator nnIt = nodeNodeMap.find( curNode );
7676               if (nnIt != nodeNodeMap.end()) { // curNode sticks
7677                 curNode = (*nnIt).second;
7678               }
7679               poly_nodes.push_back(curNode);
7680             }
7681           }
7682           aMesh->ChangePolyhedronNodes( elem, poly_nodes, quantities );
7683         }
7684       }
7685       else // replace non-polyhedron elements
7686       {
7687         const SMDSAbs_ElementType etyp = elem->GetType();
7688         const int elemId               = elem->GetID();
7689         const bool isPoly              = (elem->GetEntityType() == SMDSEntity_Polygon);
7690         uniqueNodes.resize(nbUniqueNodes);
7691
7692         SMESHDS_SubMesh * sm = aShapeId > 0 ? aMesh->MeshElements(aShapeId) : 0;
7693
7694         aMesh->RemoveFreeElement(elem, sm, /*fromGroups=*/false);
7695         SMDS_MeshElement* newElem = this->AddElement(uniqueNodes, etyp, isPoly, elemId);
7696         if ( sm && newElem )
7697           sm->AddElement( newElem );
7698         if ( elem != newElem )
7699           ReplaceElemInGroups( elem, newElem, aMesh );
7700       }
7701     }
7702     else {
7703       // Remove invalid regular element or invalid polygon
7704       rmElemIds.push_back( elem->GetID() );
7705     }
7706
7707   } // loop on elements
7708
7709   // Remove bad elements, then equal nodes (order important)
7710
7711   Remove( rmElemIds, false );
7712   Remove( rmNodeIds, true );
7713
7714 }
7715
7716
7717 // ========================================================
7718 // class   : SortableElement
7719 // purpose : allow sorting elements basing on their nodes
7720 // ========================================================
7721 class SortableElement : public set <const SMDS_MeshElement*>
7722 {
7723 public:
7724
7725   SortableElement( const SMDS_MeshElement* theElem )
7726   {
7727     myElem = theElem;
7728     SMDS_ElemIteratorPtr nodeIt = theElem->nodesIterator();
7729     while ( nodeIt->more() )
7730       this->insert( nodeIt->next() );
7731   }
7732
7733   const SMDS_MeshElement* Get() const
7734   { return myElem; }
7735
7736   void Set(const SMDS_MeshElement* e) const
7737   { myElem = e; }
7738
7739
7740 private:
7741   mutable const SMDS_MeshElement* myElem;
7742 };
7743
7744 //=======================================================================
7745 //function : FindEqualElements
7746 //purpose  : Return list of group of elements built on the same nodes.
7747 //           Search among theElements or in the whole mesh if theElements is empty
7748 //=======================================================================
7749 void SMESH_MeshEditor::FindEqualElements(set<const SMDS_MeshElement*> & theElements,
7750                                          TListOfListOfElementsID &      theGroupsOfElementsID)
7751 {
7752   myLastCreatedElems.Clear();
7753   myLastCreatedNodes.Clear();
7754
7755   typedef set<const SMDS_MeshElement*> TElemsSet;
7756   typedef map< SortableElement, int > TMapOfNodeSet;
7757   typedef list<int> TGroupOfElems;
7758
7759   TElemsSet elems;
7760   if ( theElements.empty() )
7761   { // get all elements in the mesh
7762     SMDS_ElemIteratorPtr eIt = GetMeshDS()->elementsIterator();
7763     while ( eIt->more() )
7764       elems.insert( elems.end(), eIt->next());
7765   }
7766   else
7767     elems = theElements;
7768
7769   vector< TGroupOfElems > arrayOfGroups;
7770   TGroupOfElems groupOfElems;
7771   TMapOfNodeSet mapOfNodeSet;
7772
7773   TElemsSet::iterator elemIt = elems.begin();
7774   for ( int i = 0, j=0; elemIt != elems.end(); ++elemIt, ++j ) {
7775     const SMDS_MeshElement* curElem = *elemIt;
7776     SortableElement SE(curElem);
7777     int ind = -1;
7778     // check uniqueness
7779     pair< TMapOfNodeSet::iterator, bool> pp = mapOfNodeSet.insert(make_pair(SE, i));
7780     if( !(pp.second) ) {
7781       TMapOfNodeSet::iterator& itSE = pp.first;
7782       ind = (*itSE).second;
7783       arrayOfGroups[ind].push_back(curElem->GetID());
7784     }
7785     else {
7786       groupOfElems.clear();
7787       groupOfElems.push_back(curElem->GetID());
7788       arrayOfGroups.push_back(groupOfElems);
7789       i++;
7790     }
7791   }
7792
7793   vector< TGroupOfElems >::iterator groupIt = arrayOfGroups.begin();
7794   for ( ; groupIt != arrayOfGroups.end(); ++groupIt ) {
7795     groupOfElems = *groupIt;
7796     if ( groupOfElems.size() > 1 ) {
7797       groupOfElems.sort();
7798       theGroupsOfElementsID.push_back(groupOfElems);
7799     }
7800   }
7801 }
7802
7803 //=======================================================================
7804 //function : MergeElements
7805 //purpose  : In each given group, substitute all elements by the first one.
7806 //=======================================================================
7807
7808 void SMESH_MeshEditor::MergeElements(TListOfListOfElementsID & theGroupsOfElementsID)
7809 {
7810   myLastCreatedElems.Clear();
7811   myLastCreatedNodes.Clear();
7812
7813   typedef list<int> TListOfIDs;
7814   TListOfIDs rmElemIds; // IDs of elems to remove
7815
7816   SMESHDS_Mesh* aMesh = GetMeshDS();
7817
7818   TListOfListOfElementsID::iterator groupsIt = theGroupsOfElementsID.begin();
7819   while ( groupsIt != theGroupsOfElementsID.end() ) {
7820     TListOfIDs& aGroupOfElemID = *groupsIt;
7821     aGroupOfElemID.sort();
7822     int elemIDToKeep = aGroupOfElemID.front();
7823     const SMDS_MeshElement* elemToKeep = aMesh->FindElement(elemIDToKeep);
7824     aGroupOfElemID.pop_front();
7825     TListOfIDs::iterator idIt = aGroupOfElemID.begin();
7826     while ( idIt != aGroupOfElemID.end() ) {
7827       int elemIDToRemove = *idIt;
7828       const SMDS_MeshElement* elemToRemove = aMesh->FindElement(elemIDToRemove);
7829       // add the kept element in groups of removed one (PAL15188)
7830       AddToSameGroups( elemToKeep, elemToRemove, aMesh );
7831       rmElemIds.push_back( elemIDToRemove );
7832       ++idIt;
7833     }
7834     ++groupsIt;
7835   }
7836
7837   Remove( rmElemIds, false );
7838 }
7839
7840 //=======================================================================
7841 //function : MergeEqualElements
7842 //purpose  : Remove all but one of elements built on the same nodes.
7843 //=======================================================================
7844
7845 void SMESH_MeshEditor::MergeEqualElements()
7846 {
7847   set<const SMDS_MeshElement*> aMeshElements; /* empty input -
7848                                                  to merge equal elements in the whole mesh */
7849   TListOfListOfElementsID aGroupsOfElementsID;
7850   FindEqualElements(aMeshElements, aGroupsOfElementsID);
7851   MergeElements(aGroupsOfElementsID);
7852 }
7853
7854 //=======================================================================
7855 //function : FindFaceInSet
7856 //purpose  : Return a face having linked nodes n1 and n2 and which is
7857 //           - not in avoidSet,
7858 //           - in elemSet provided that !elemSet.empty()
7859 //           i1 and i2 optionally returns indices of n1 and n2
7860 //=======================================================================
7861
7862 const SMDS_MeshElement*
7863 SMESH_MeshEditor::FindFaceInSet(const SMDS_MeshNode*    n1,
7864                                 const SMDS_MeshNode*    n2,
7865                                 const TIDSortedElemSet& elemSet,
7866                                 const TIDSortedElemSet& avoidSet,
7867                                 int*                    n1ind,
7868                                 int*                    n2ind)
7869
7870 {
7871   int i1, i2;
7872   const SMDS_MeshElement* face = 0;
7873
7874   SMDS_ElemIteratorPtr invElemIt = n1->GetInverseElementIterator(SMDSAbs_Face);
7875   //MESSAGE("n1->GetInverseElementIterator(SMDSAbs_Face) " << invElemIt);
7876   while ( invElemIt->more() && !face ) // loop on inverse faces of n1
7877   {
7878     //MESSAGE("in while ( invElemIt->more() && !face )");
7879     const SMDS_MeshElement* elem = invElemIt->next();
7880     if (avoidSet.count( elem ))
7881       continue;
7882     if ( !elemSet.empty() && !elemSet.count( elem ))
7883       continue;
7884     // index of n1
7885     i1 = elem->GetNodeIndex( n1 );
7886     // find a n2 linked to n1
7887     int nbN = elem->IsQuadratic() ? elem->NbNodes()/2 : elem->NbNodes();
7888     for ( int di = -1; di < 2 && !face; di += 2 )
7889     {
7890       i2 = (i1+di+nbN) % nbN;
7891       if ( elem->GetNode( i2 ) == n2 )
7892         face = elem;
7893     }
7894     if ( !face && elem->IsQuadratic())
7895     {
7896       // analysis for quadratic elements using all nodes
7897       const SMDS_VtkFace* F =
7898         dynamic_cast<const SMDS_VtkFace*>(elem);
7899       if (!F) throw SALOME_Exception(LOCALIZED("not an SMDS_VtkFace"));
7900       // use special nodes iterator
7901       SMDS_ElemIteratorPtr anIter = F->interlacedNodesElemIterator();
7902       const SMDS_MeshNode* prevN = cast2Node( anIter->next() );
7903       for ( i1 = -1, i2 = 0; anIter->more() && !face; i1++, i2++ )
7904       {
7905         const SMDS_MeshNode* n = cast2Node( anIter->next() );
7906         if ( n1 == prevN && n2 == n )
7907         {
7908           face = elem;
7909         }
7910         else if ( n2 == prevN && n1 == n )
7911         {
7912           face = elem; swap( i1, i2 );
7913         }
7914         prevN = n;
7915       }
7916     }
7917   }
7918   if ( n1ind ) *n1ind = i1;
7919   if ( n2ind ) *n2ind = i2;
7920   return face;
7921 }
7922
7923 //=======================================================================
7924 //function : findAdjacentFace
7925 //purpose  :
7926 //=======================================================================
7927
7928 static const SMDS_MeshElement* findAdjacentFace(const SMDS_MeshNode* n1,
7929                                                 const SMDS_MeshNode* n2,
7930                                                 const SMDS_MeshElement* elem)
7931 {
7932   TIDSortedElemSet elemSet, avoidSet;
7933   if ( elem )
7934     avoidSet.insert ( elem );
7935   return SMESH_MeshEditor::FindFaceInSet( n1, n2, elemSet, avoidSet );
7936 }
7937
7938 //=======================================================================
7939 //function : FindFreeBorder
7940 //purpose  :
7941 //=======================================================================
7942
7943 #define ControlFreeBorder SMESH::Controls::FreeEdges::IsFreeEdge
7944
7945 bool SMESH_MeshEditor::FindFreeBorder (const SMDS_MeshNode*             theFirstNode,
7946                                        const SMDS_MeshNode*             theSecondNode,
7947                                        const SMDS_MeshNode*             theLastNode,
7948                                        list< const SMDS_MeshNode* > &   theNodes,
7949                                        list< const SMDS_MeshElement* >& theFaces)
7950 {
7951   if ( !theFirstNode || !theSecondNode )
7952     return false;
7953   // find border face between theFirstNode and theSecondNode
7954   const SMDS_MeshElement* curElem = findAdjacentFace( theFirstNode, theSecondNode, 0 );
7955   if ( !curElem )
7956     return false;
7957
7958   theFaces.push_back( curElem );
7959   theNodes.push_back( theFirstNode );
7960   theNodes.push_back( theSecondNode );
7961
7962   //vector<const SMDS_MeshNode*> nodes;
7963   const SMDS_MeshNode *nIgnore = theFirstNode, *nStart = theSecondNode;
7964   TIDSortedElemSet foundElems;
7965   bool needTheLast = ( theLastNode != 0 );
7966
7967   while ( nStart != theLastNode ) {
7968     if ( nStart == theFirstNode )
7969       return !needTheLast;
7970
7971     // find all free border faces sharing form nStart
7972
7973     list< const SMDS_MeshElement* > curElemList;
7974     list< const SMDS_MeshNode* > nStartList;
7975     SMDS_ElemIteratorPtr invElemIt = nStart->GetInverseElementIterator(SMDSAbs_Face);
7976     while ( invElemIt->more() ) {
7977       const SMDS_MeshElement* e = invElemIt->next();
7978       if ( e == curElem || foundElems.insert( e ).second ) {
7979         // get nodes
7980         int iNode = 0, nbNodes = e->NbNodes();
7981         //const SMDS_MeshNode* nodes[nbNodes+1];
7982         vector<const SMDS_MeshNode*> nodes(nbNodes+1);
7983
7984         if(e->IsQuadratic()) {
7985           const SMDS_VtkFace* F =
7986             dynamic_cast<const SMDS_VtkFace*>(e);
7987           if (!F) throw SALOME_Exception(LOCALIZED("not an SMDS_VtkFace"));
7988           // use special nodes iterator
7989           SMDS_ElemIteratorPtr anIter = F->interlacedNodesElemIterator();
7990           while( anIter->more() ) {
7991             nodes[ iNode++ ] = cast2Node(anIter->next());
7992           }
7993         }
7994         else {
7995           SMDS_ElemIteratorPtr nIt = e->nodesIterator();
7996           while ( nIt->more() )
7997             nodes[ iNode++ ] = static_cast<const SMDS_MeshNode*>( nIt->next() );
7998         }
7999         nodes[ iNode ] = nodes[ 0 ];
8000         // check 2 links
8001         for ( iNode = 0; iNode < nbNodes; iNode++ )
8002           if (((nodes[ iNode ] == nStart && nodes[ iNode + 1] != nIgnore ) ||
8003                (nodes[ iNode + 1] == nStart && nodes[ iNode ] != nIgnore )) &&
8004               ControlFreeBorder( &nodes[ iNode ], e->GetID() ))
8005           {
8006             nStartList.push_back( nodes[ iNode + ( nodes[ iNode ] == nStart ? 1 : 0 )]);
8007             curElemList.push_back( e );
8008           }
8009       }
8010     }
8011     // analyse the found
8012
8013     int nbNewBorders = curElemList.size();
8014     if ( nbNewBorders == 0 ) {
8015       // no free border furthermore
8016       return !needTheLast;
8017     }
8018     else if ( nbNewBorders == 1 ) {
8019       // one more element found
8020       nIgnore = nStart;
8021       nStart = nStartList.front();
8022       curElem = curElemList.front();
8023       theFaces.push_back( curElem );
8024       theNodes.push_back( nStart );
8025     }
8026     else {
8027       // several continuations found
8028       list< const SMDS_MeshElement* >::iterator curElemIt;
8029       list< const SMDS_MeshNode* >::iterator nStartIt;
8030       // check if one of them reached the last node
8031       if ( needTheLast ) {
8032         for (curElemIt = curElemList.begin(), nStartIt = nStartList.begin();
8033              curElemIt!= curElemList.end();
8034              curElemIt++, nStartIt++ )
8035           if ( *nStartIt == theLastNode ) {
8036             theFaces.push_back( *curElemIt );
8037             theNodes.push_back( *nStartIt );
8038             return true;
8039           }
8040       }
8041       // find the best free border by the continuations
8042       list<const SMDS_MeshNode*>    contNodes[ 2 ], *cNL;
8043       list<const SMDS_MeshElement*> contFaces[ 2 ], *cFL;
8044       for (curElemIt = curElemList.begin(), nStartIt = nStartList.begin();
8045            curElemIt!= curElemList.end();
8046            curElemIt++, nStartIt++ )
8047       {
8048         cNL = & contNodes[ contNodes[0].empty() ? 0 : 1 ];
8049         cFL = & contFaces[ contFaces[0].empty() ? 0 : 1 ];
8050         // find one more free border
8051         if ( ! FindFreeBorder( nStart, *nStartIt, theLastNode, *cNL, *cFL )) {
8052           cNL->clear();
8053           cFL->clear();
8054         }
8055         else if ( !contNodes[0].empty() && !contNodes[1].empty() ) {
8056           // choice: clear a worse one
8057           int iLongest = ( contNodes[0].size() < contNodes[1].size() ? 1 : 0 );
8058           int iWorse = ( needTheLast ? 1 - iLongest : iLongest );
8059           contNodes[ iWorse ].clear();
8060           contFaces[ iWorse ].clear();
8061         }
8062       }
8063       if ( contNodes[0].empty() && contNodes[1].empty() )
8064         return false;
8065
8066       // append the best free border
8067       cNL = & contNodes[ contNodes[0].empty() ? 1 : 0 ];
8068       cFL = & contFaces[ contFaces[0].empty() ? 1 : 0 ];
8069       theNodes.pop_back(); // remove nIgnore
8070       theNodes.pop_back(); // remove nStart
8071       theFaces.pop_back(); // remove curElem
8072       list< const SMDS_MeshNode* >::iterator nIt = cNL->begin();
8073       list< const SMDS_MeshElement* >::iterator fIt = cFL->begin();
8074       for ( ; nIt != cNL->end(); nIt++ ) theNodes.push_back( *nIt );
8075       for ( ; fIt != cFL->end(); fIt++ ) theFaces.push_back( *fIt );
8076       return true;
8077
8078     } // several continuations found
8079   } // while ( nStart != theLastNode )
8080
8081   return true;
8082 }
8083
8084 //=======================================================================
8085 //function : CheckFreeBorderNodes
8086 //purpose  : Return true if the tree nodes are on a free border
8087 //=======================================================================
8088
8089 bool SMESH_MeshEditor::CheckFreeBorderNodes(const SMDS_MeshNode* theNode1,
8090                                             const SMDS_MeshNode* theNode2,
8091                                             const SMDS_MeshNode* theNode3)
8092 {
8093   list< const SMDS_MeshNode* > nodes;
8094   list< const SMDS_MeshElement* > faces;
8095   return FindFreeBorder( theNode1, theNode2, theNode3, nodes, faces);
8096 }
8097
8098 //=======================================================================
8099 //function : SewFreeBorder
8100 //purpose  :
8101 //=======================================================================
8102
8103 SMESH_MeshEditor::Sew_Error
8104 SMESH_MeshEditor::SewFreeBorder (const SMDS_MeshNode* theBordFirstNode,
8105                                  const SMDS_MeshNode* theBordSecondNode,
8106                                  const SMDS_MeshNode* theBordLastNode,
8107                                  const SMDS_MeshNode* theSideFirstNode,
8108                                  const SMDS_MeshNode* theSideSecondNode,
8109                                  const SMDS_MeshNode* theSideThirdNode,
8110                                  const bool           theSideIsFreeBorder,
8111                                  const bool           toCreatePolygons,
8112                                  const bool           toCreatePolyedrs)
8113 {
8114   myLastCreatedElems.Clear();
8115   myLastCreatedNodes.Clear();
8116
8117   MESSAGE("::SewFreeBorder()");
8118   Sew_Error aResult = SEW_OK;
8119
8120   // ====================================
8121   //    find side nodes and elements
8122   // ====================================
8123
8124   list< const SMDS_MeshNode* > nSide[ 2 ];
8125   list< const SMDS_MeshElement* > eSide[ 2 ];
8126   list< const SMDS_MeshNode* >::iterator nIt[ 2 ];
8127   list< const SMDS_MeshElement* >::iterator eIt[ 2 ];
8128
8129   // Free border 1
8130   // --------------
8131   if (!FindFreeBorder(theBordFirstNode,theBordSecondNode,theBordLastNode,
8132                       nSide[0], eSide[0])) {
8133     MESSAGE(" Free Border 1 not found " );
8134     aResult = SEW_BORDER1_NOT_FOUND;
8135   }
8136   if (theSideIsFreeBorder) {
8137     // Free border 2
8138     // --------------
8139     if (!FindFreeBorder(theSideFirstNode, theSideSecondNode, theSideThirdNode,
8140                         nSide[1], eSide[1])) {
8141       MESSAGE(" Free Border 2 not found " );
8142       aResult = ( aResult != SEW_OK ? SEW_BOTH_BORDERS_NOT_FOUND : SEW_BORDER2_NOT_FOUND );
8143     }
8144   }
8145   if ( aResult != SEW_OK )
8146     return aResult;
8147
8148   if (!theSideIsFreeBorder) {
8149     // Side 2
8150     // --------------
8151
8152     // -------------------------------------------------------------------------
8153     // Algo:
8154     // 1. If nodes to merge are not coincident, move nodes of the free border
8155     //    from the coord sys defined by the direction from the first to last
8156     //    nodes of the border to the correspondent sys of the side 2
8157     // 2. On the side 2, find the links most co-directed with the correspondent
8158     //    links of the free border
8159     // -------------------------------------------------------------------------
8160
8161     // 1. Since sewing may break if there are volumes to split on the side 2,
8162     //    we wont move nodes but just compute new coordinates for them
8163     typedef map<const SMDS_MeshNode*, gp_XYZ> TNodeXYZMap;
8164     TNodeXYZMap nBordXYZ;
8165     list< const SMDS_MeshNode* >& bordNodes = nSide[ 0 ];
8166     list< const SMDS_MeshNode* >::iterator nBordIt;
8167
8168     gp_XYZ Pb1( theBordFirstNode->X(), theBordFirstNode->Y(), theBordFirstNode->Z() );
8169     gp_XYZ Pb2( theBordLastNode->X(), theBordLastNode->Y(), theBordLastNode->Z() );
8170     gp_XYZ Ps1( theSideFirstNode->X(), theSideFirstNode->Y(), theSideFirstNode->Z() );
8171     gp_XYZ Ps2( theSideSecondNode->X(), theSideSecondNode->Y(), theSideSecondNode->Z() );
8172     double tol2 = 1.e-8;
8173     gp_Vec Vbs1( Pb1 - Ps1 ),Vbs2( Pb2 - Ps2 );
8174     if ( Vbs1.SquareMagnitude() > tol2 || Vbs2.SquareMagnitude() > tol2 ) {
8175       // Need node movement.
8176
8177       // find X and Z axes to create trsf
8178       gp_Vec Zb( Pb1 - Pb2 ), Zs( Ps1 - Ps2 );
8179       gp_Vec X = Zs ^ Zb;
8180       if ( X.SquareMagnitude() <= gp::Resolution() * gp::Resolution() )
8181         // Zb || Zs
8182         X = gp_Ax2( gp::Origin(), Zb ).XDirection();
8183
8184       // coord systems
8185       gp_Ax3 toBordAx( Pb1, Zb, X );
8186       gp_Ax3 fromSideAx( Ps1, Zs, X );
8187       gp_Ax3 toGlobalAx( gp::Origin(), gp::DZ(), gp::DX() );
8188       // set trsf
8189       gp_Trsf toBordSys, fromSide2Sys;
8190       toBordSys.SetTransformation( toBordAx );
8191       fromSide2Sys.SetTransformation( fromSideAx, toGlobalAx );
8192       fromSide2Sys.SetScaleFactor( Zs.Magnitude() / Zb.Magnitude() );
8193
8194       // move
8195       for ( nBordIt = bordNodes.begin(); nBordIt != bordNodes.end(); nBordIt++ ) {
8196         const SMDS_MeshNode* n = *nBordIt;
8197         gp_XYZ xyz( n->X(),n->Y(),n->Z() );
8198         toBordSys.Transforms( xyz );
8199         fromSide2Sys.Transforms( xyz );
8200         nBordXYZ.insert( TNodeXYZMap::value_type( n, xyz ));
8201       }
8202     }
8203     else {
8204       // just insert nodes XYZ in the nBordXYZ map
8205       for ( nBordIt = bordNodes.begin(); nBordIt != bordNodes.end(); nBordIt++ ) {
8206         const SMDS_MeshNode* n = *nBordIt;
8207         nBordXYZ.insert( TNodeXYZMap::value_type( n, gp_XYZ( n->X(),n->Y(),n->Z() )));
8208       }
8209     }
8210
8211     // 2. On the side 2, find the links most co-directed with the correspondent
8212     //    links of the free border
8213
8214     list< const SMDS_MeshElement* >& sideElems = eSide[ 1 ];
8215     list< const SMDS_MeshNode* >& sideNodes = nSide[ 1 ];
8216     sideNodes.push_back( theSideFirstNode );
8217
8218     bool hasVolumes = false;
8219     LinkID_Gen aLinkID_Gen( GetMeshDS() );
8220     set<long> foundSideLinkIDs, checkedLinkIDs;
8221     SMDS_VolumeTool volume;
8222     //const SMDS_MeshNode* faceNodes[ 4 ];
8223
8224     const SMDS_MeshNode*    sideNode;
8225     const SMDS_MeshElement* sideElem;
8226     const SMDS_MeshNode* prevSideNode = theSideFirstNode;
8227     const SMDS_MeshNode* prevBordNode = theBordFirstNode;
8228     nBordIt = bordNodes.begin();
8229     nBordIt++;
8230     // border node position and border link direction to compare with
8231     gp_XYZ bordPos = nBordXYZ[ *nBordIt ];
8232     gp_XYZ bordDir = bordPos - nBordXYZ[ prevBordNode ];
8233     // choose next side node by link direction or by closeness to
8234     // the current border node:
8235     bool searchByDir = ( *nBordIt != theBordLastNode );
8236     do {
8237       // find the next node on the Side 2
8238       sideNode = 0;
8239       double maxDot = -DBL_MAX, minDist = DBL_MAX;
8240       long linkID;
8241       checkedLinkIDs.clear();
8242       gp_XYZ prevXYZ( prevSideNode->X(), prevSideNode->Y(), prevSideNode->Z() );
8243
8244       // loop on inverse elements of current node (prevSideNode) on the Side 2
8245       SMDS_ElemIteratorPtr invElemIt = prevSideNode->GetInverseElementIterator();
8246       while ( invElemIt->more() )
8247       {
8248         const SMDS_MeshElement* elem = invElemIt->next();
8249         // prepare data for a loop on links coming to prevSideNode, of a face or a volume
8250         int iPrevNode, iNode = 0, nbNodes = elem->NbNodes();
8251         vector< const SMDS_MeshNode* > faceNodes( nbNodes, (const SMDS_MeshNode*)0 );
8252         bool isVolume = volume.Set( elem );
8253         const SMDS_MeshNode** nodes = isVolume ? volume.GetNodes() : & faceNodes[0];
8254         if ( isVolume ) // --volume
8255           hasVolumes = true;
8256         else if ( elem->GetType()==SMDSAbs_Face ) { // --face
8257           // retrieve all face nodes and find iPrevNode - an index of the prevSideNode
8258           if(elem->IsQuadratic()) {
8259             const SMDS_VtkFace* F =
8260               dynamic_cast<const SMDS_VtkFace*>(elem);
8261             if (!F) throw SALOME_Exception(LOCALIZED("not an SMDS_VtkFace"));
8262             // use special nodes iterator
8263             SMDS_ElemIteratorPtr anIter = F->interlacedNodesElemIterator();
8264             while( anIter->more() ) {
8265               nodes[ iNode ] = cast2Node(anIter->next());
8266               if ( nodes[ iNode++ ] == prevSideNode )
8267                 iPrevNode = iNode - 1;
8268             }
8269           }
8270           else {
8271             SMDS_ElemIteratorPtr nIt = elem->nodesIterator();
8272             while ( nIt->more() ) {
8273               nodes[ iNode ] = cast2Node( nIt->next() );
8274               if ( nodes[ iNode++ ] == prevSideNode )
8275                 iPrevNode = iNode - 1;
8276             }
8277           }
8278           // there are 2 links to check
8279           nbNodes = 2;
8280         }
8281         else // --edge
8282           continue;
8283         // loop on links, to be precise, on the second node of links
8284         for ( iNode = 0; iNode < nbNodes; iNode++ ) {
8285           const SMDS_MeshNode* n = nodes[ iNode ];
8286           if ( isVolume ) {
8287             if ( !volume.IsLinked( n, prevSideNode ))
8288               continue;
8289           }
8290           else {
8291             if ( iNode ) // a node before prevSideNode
8292               n = nodes[ iPrevNode == 0 ? elem->NbNodes() - 1 : iPrevNode - 1 ];
8293             else         // a node after prevSideNode
8294               n = nodes[ iPrevNode + 1 == elem->NbNodes() ? 0 : iPrevNode + 1 ];
8295           }
8296           // check if this link was already used
8297           long iLink = aLinkID_Gen.GetLinkID( prevSideNode, n );
8298           bool isJustChecked = !checkedLinkIDs.insert( iLink ).second;
8299           if (!isJustChecked &&
8300               foundSideLinkIDs.find( iLink ) == foundSideLinkIDs.end() )
8301           {
8302             // test a link geometrically
8303             gp_XYZ nextXYZ ( n->X(), n->Y(), n->Z() );
8304             bool linkIsBetter = false;
8305             double dot = 0.0, dist = 0.0;
8306             if ( searchByDir ) { // choose most co-directed link
8307               dot = bordDir * ( nextXYZ - prevXYZ ).Normalized();
8308               linkIsBetter = ( dot > maxDot );
8309             }
8310             else { // choose link with the node closest to bordPos
8311               dist = ( nextXYZ - bordPos ).SquareModulus();
8312               linkIsBetter = ( dist < minDist );
8313             }
8314             if ( linkIsBetter ) {
8315               maxDot = dot;
8316               minDist = dist;
8317               linkID = iLink;
8318               sideNode = n;
8319               sideElem = elem;
8320             }
8321           }
8322         }
8323       } // loop on inverse elements of prevSideNode
8324
8325       if ( !sideNode ) {
8326         MESSAGE(" Cant find path by links of the Side 2 ");
8327         return SEW_BAD_SIDE_NODES;
8328       }
8329       sideNodes.push_back( sideNode );
8330       sideElems.push_back( sideElem );
8331       foundSideLinkIDs.insert ( linkID );
8332       prevSideNode = sideNode;
8333
8334       if ( *nBordIt == theBordLastNode )
8335         searchByDir = false;
8336       else {
8337         // find the next border link to compare with
8338         gp_XYZ sidePos( sideNode->X(), sideNode->Y(), sideNode->Z() );
8339         searchByDir = ( bordDir * ( sidePos - bordPos ) <= 0 );
8340         // move to next border node if sideNode is before forward border node (bordPos)
8341         while ( *nBordIt != theBordLastNode && !searchByDir ) {
8342           prevBordNode = *nBordIt;
8343           nBordIt++;
8344           bordPos = nBordXYZ[ *nBordIt ];
8345           bordDir = bordPos - nBordXYZ[ prevBordNode ];
8346           searchByDir = ( bordDir * ( sidePos - bordPos ) <= 0 );
8347         }
8348       }
8349     }
8350     while ( sideNode != theSideSecondNode );
8351
8352     if ( hasVolumes && sideNodes.size () != bordNodes.size() && !toCreatePolyedrs) {
8353       MESSAGE("VOLUME SPLITTING IS FORBIDDEN");
8354       return SEW_VOLUMES_TO_SPLIT; // volume splitting is forbidden
8355     }
8356   } // end nodes search on the side 2
8357
8358   // ============================
8359   // sew the border to the side 2
8360   // ============================
8361
8362   int nbNodes[]  = { nSide[0].size(), nSide[1].size() };
8363   int maxNbNodes = Max( nbNodes[0], nbNodes[1] );
8364
8365   TListOfListOfNodes nodeGroupsToMerge;
8366   if ( nbNodes[0] == nbNodes[1] ||
8367        ( theSideIsFreeBorder && !theSideThirdNode)) {
8368
8369     // all nodes are to be merged
8370
8371     for (nIt[0] = nSide[0].begin(), nIt[1] = nSide[1].begin();
8372          nIt[0] != nSide[0].end() && nIt[1] != nSide[1].end();
8373          nIt[0]++, nIt[1]++ )
8374     {
8375       nodeGroupsToMerge.push_back( list<const SMDS_MeshNode*>() );
8376       nodeGroupsToMerge.back().push_back( *nIt[1] ); // to keep
8377       nodeGroupsToMerge.back().push_back( *nIt[0] ); // to remove
8378     }
8379   }
8380   else {
8381
8382     // insert new nodes into the border and the side to get equal nb of segments
8383
8384     // get normalized parameters of nodes on the borders
8385     //double param[ 2 ][ maxNbNodes ];
8386     double* param[ 2 ];
8387     param[0] = new double [ maxNbNodes ];
8388     param[1] = new double [ maxNbNodes ];
8389     int iNode, iBord;
8390     for ( iBord = 0; iBord < 2; iBord++ ) { // loop on 2 borders
8391       list< const SMDS_MeshNode* >& nodes = nSide[ iBord ];
8392       list< const SMDS_MeshNode* >::iterator nIt = nodes.begin();
8393       const SMDS_MeshNode* nPrev = *nIt;
8394       double bordLength = 0;
8395       for ( iNode = 0; nIt != nodes.end(); nIt++, iNode++ ) { // loop on border nodes
8396         const SMDS_MeshNode* nCur = *nIt;
8397         gp_XYZ segment (nCur->X() - nPrev->X(),
8398                         nCur->Y() - nPrev->Y(),
8399                         nCur->Z() - nPrev->Z());
8400         double segmentLen = segment.Modulus();
8401         bordLength += segmentLen;
8402         param[ iBord ][ iNode ] = bordLength;
8403         nPrev = nCur;
8404       }
8405       // normalize within [0,1]
8406       for ( iNode = 0; iNode < nbNodes[ iBord ]; iNode++ ) {
8407         param[ iBord ][ iNode ] /= bordLength;
8408       }
8409     }
8410
8411     // loop on border segments
8412     const SMDS_MeshNode *nPrev[ 2 ] = { 0, 0 };
8413     int i[ 2 ] = { 0, 0 };
8414     nIt[0] = nSide[0].begin(); eIt[0] = eSide[0].begin();
8415     nIt[1] = nSide[1].begin(); eIt[1] = eSide[1].begin();
8416
8417     TElemOfNodeListMap insertMap;
8418     TElemOfNodeListMap::iterator insertMapIt;
8419     // insertMap is
8420     // key:   elem to insert nodes into
8421     // value: 2 nodes to insert between + nodes to be inserted
8422     do {
8423       bool next[ 2 ] = { false, false };
8424
8425       // find min adjacent segment length after sewing
8426       double nextParam = 10., prevParam = 0;
8427       for ( iBord = 0; iBord < 2; iBord++ ) { // loop on 2 borders
8428         if ( i[ iBord ] + 1 < nbNodes[ iBord ])
8429           nextParam = Min( nextParam, param[iBord][ i[iBord] + 1 ]);
8430         if ( i[ iBord ] > 0 )
8431           prevParam = Max( prevParam, param[iBord][ i[iBord] - 1 ]);
8432       }
8433       double minParam = Min( param[ 0 ][ i[0] ], param[ 1 ][ i[1] ]);
8434       double maxParam = Max( param[ 0 ][ i[0] ], param[ 1 ][ i[1] ]);
8435       double minSegLen = Min( nextParam - minParam, maxParam - prevParam );
8436
8437       // choose to insert or to merge nodes
8438       double du = param[ 1 ][ i[1] ] - param[ 0 ][ i[0] ];
8439       if ( Abs( du ) <= minSegLen * 0.2 ) {
8440         // merge
8441         // ------
8442         nodeGroupsToMerge.push_back( list<const SMDS_MeshNode*>() );
8443         const SMDS_MeshNode* n0 = *nIt[0];
8444         const SMDS_MeshNode* n1 = *nIt[1];
8445         nodeGroupsToMerge.back().push_back( n1 );
8446         nodeGroupsToMerge.back().push_back( n0 );
8447         // position of node of the border changes due to merge
8448         param[ 0 ][ i[0] ] += du;
8449         // move n1 for the sake of elem shape evaluation during insertion.
8450         // n1 will be removed by MergeNodes() anyway
8451         const_cast<SMDS_MeshNode*>( n0 )->setXYZ( n1->X(), n1->Y(), n1->Z() );
8452         next[0] = next[1] = true;
8453       }
8454       else {
8455         // insert
8456         // ------
8457         int intoBord = ( du < 0 ) ? 0 : 1;
8458         const SMDS_MeshElement* elem = *eIt[ intoBord ];
8459         const SMDS_MeshNode*    n1   = nPrev[ intoBord ];
8460         const SMDS_MeshNode*    n2   = *nIt[ intoBord ];
8461         const SMDS_MeshNode*    nIns = *nIt[ 1 - intoBord ];
8462         if ( intoBord == 1 ) {
8463           // move node of the border to be on a link of elem of the side
8464           gp_XYZ p1 (n1->X(), n1->Y(), n1->Z());
8465           gp_XYZ p2 (n2->X(), n2->Y(), n2->Z());
8466           double ratio = du / ( param[ 1 ][ i[1] ] - param[ 1 ][ i[1]-1 ]);
8467           gp_XYZ p = p2 * ( 1 - ratio ) + p1 * ratio;
8468           GetMeshDS()->MoveNode( nIns, p.X(), p.Y(), p.Z() );
8469         }
8470         insertMapIt = insertMap.find( elem );
8471         bool notFound = ( insertMapIt == insertMap.end() );
8472         bool otherLink = ( !notFound && (*insertMapIt).second.front() != n1 );
8473         if ( otherLink ) {
8474           // insert into another link of the same element:
8475           // 1. perform insertion into the other link of the elem
8476           list<const SMDS_MeshNode*> & nodeList = (*insertMapIt).second;
8477           const SMDS_MeshNode* n12 = nodeList.front(); nodeList.pop_front();
8478           const SMDS_MeshNode* n22 = nodeList.front(); nodeList.pop_front();
8479           InsertNodesIntoLink( elem, n12, n22, nodeList, toCreatePolygons );
8480           // 2. perform insertion into the link of adjacent faces
8481           while (true) {
8482             const SMDS_MeshElement* adjElem = findAdjacentFace( n12, n22, elem );
8483             if ( adjElem )
8484               InsertNodesIntoLink( adjElem, n12, n22, nodeList, toCreatePolygons );
8485             else
8486               break;
8487           }
8488           if (toCreatePolyedrs) {
8489             // perform insertion into the links of adjacent volumes
8490             UpdateVolumes(n12, n22, nodeList);
8491           }
8492           // 3. find an element appeared on n1 and n2 after the insertion
8493           insertMap.erase( elem );
8494           elem = findAdjacentFace( n1, n2, 0 );
8495         }
8496         if ( notFound || otherLink ) {
8497           // add element and nodes of the side into the insertMap
8498           insertMapIt = insertMap.insert
8499             ( TElemOfNodeListMap::value_type( elem, list<const SMDS_MeshNode*>() )).first;
8500           (*insertMapIt).second.push_back( n1 );
8501           (*insertMapIt).second.push_back( n2 );
8502         }
8503         // add node to be inserted into elem
8504         (*insertMapIt).second.push_back( nIns );
8505         next[ 1 - intoBord ] = true;
8506       }
8507
8508       // go to the next segment
8509       for ( iBord = 0; iBord < 2; iBord++ ) { // loop on 2 borders
8510         if ( next[ iBord ] ) {
8511           if ( i[ iBord ] != 0 && eIt[ iBord ] != eSide[ iBord ].end())
8512             eIt[ iBord ]++;
8513           nPrev[ iBord ] = *nIt[ iBord ];
8514           nIt[ iBord ]++; i[ iBord ]++;
8515         }
8516       }
8517     }
8518     while ( nIt[0] != nSide[0].end() && nIt[1] != nSide[1].end());
8519
8520     // perform insertion of nodes into elements
8521
8522     for (insertMapIt = insertMap.begin();
8523          insertMapIt != insertMap.end();
8524          insertMapIt++ )
8525     {
8526       const SMDS_MeshElement* elem = (*insertMapIt).first;
8527       list<const SMDS_MeshNode*> & nodeList = (*insertMapIt).second;
8528       const SMDS_MeshNode* n1 = nodeList.front(); nodeList.pop_front();
8529       const SMDS_MeshNode* n2 = nodeList.front(); nodeList.pop_front();
8530
8531       InsertNodesIntoLink( elem, n1, n2, nodeList, toCreatePolygons );
8532
8533       if ( !theSideIsFreeBorder ) {
8534         // look for and insert nodes into the faces adjacent to elem
8535         while (true) {
8536           const SMDS_MeshElement* adjElem = findAdjacentFace( n1, n2, elem );
8537           if ( adjElem )
8538             InsertNodesIntoLink( adjElem, n1, n2, nodeList, toCreatePolygons );
8539           else
8540             break;
8541         }
8542       }
8543       if (toCreatePolyedrs) {
8544         // perform insertion into the links of adjacent volumes
8545         UpdateVolumes(n1, n2, nodeList);
8546       }
8547     }
8548
8549     delete param[0];
8550     delete param[1];
8551   } // end: insert new nodes
8552
8553   MergeNodes ( nodeGroupsToMerge );
8554
8555   return aResult;
8556 }
8557
8558 //=======================================================================
8559 //function : InsertNodesIntoLink
8560 //purpose  : insert theNodesToInsert into theFace between theBetweenNode1
8561 //           and theBetweenNode2 and split theElement
8562 //=======================================================================
8563
8564 void SMESH_MeshEditor::InsertNodesIntoLink(const SMDS_MeshElement*     theFace,
8565                                            const SMDS_MeshNode*        theBetweenNode1,
8566                                            const SMDS_MeshNode*        theBetweenNode2,
8567                                            list<const SMDS_MeshNode*>& theNodesToInsert,
8568                                            const bool                  toCreatePoly)
8569 {
8570   if ( theFace->GetType() != SMDSAbs_Face ) return;
8571
8572   // find indices of 2 link nodes and of the rest nodes
8573   int iNode = 0, il1, il2, i3, i4;
8574   il1 = il2 = i3 = i4 = -1;
8575   //const SMDS_MeshNode* nodes[ theFace->NbNodes() ];
8576   vector<const SMDS_MeshNode*> nodes( theFace->NbNodes() );
8577
8578   if(theFace->IsQuadratic()) {
8579     const SMDS_VtkFace* F =
8580       dynamic_cast<const SMDS_VtkFace*>(theFace);
8581     if (!F) throw SALOME_Exception(LOCALIZED("not an SMDS_VtkFace"));
8582     // use special nodes iterator
8583     SMDS_ElemIteratorPtr anIter = F->interlacedNodesElemIterator();
8584     while( anIter->more() ) {
8585       const SMDS_MeshNode* n = cast2Node(anIter->next());
8586       if ( n == theBetweenNode1 )
8587         il1 = iNode;
8588       else if ( n == theBetweenNode2 )
8589         il2 = iNode;
8590       else if ( i3 < 0 )
8591         i3 = iNode;
8592       else
8593         i4 = iNode;
8594       nodes[ iNode++ ] = n;
8595     }
8596   }
8597   else {
8598     SMDS_ElemIteratorPtr nodeIt = theFace->nodesIterator();
8599     while ( nodeIt->more() ) {
8600       const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
8601       if ( n == theBetweenNode1 )
8602         il1 = iNode;
8603       else if ( n == theBetweenNode2 )
8604         il2 = iNode;
8605       else if ( i3 < 0 )
8606         i3 = iNode;
8607       else
8608         i4 = iNode;
8609       nodes[ iNode++ ] = n;
8610     }
8611   }
8612   if ( il1 < 0 || il2 < 0 || i3 < 0 )
8613     return ;
8614
8615   // arrange link nodes to go one after another regarding the face orientation
8616   bool reverse = ( Abs( il2 - il1 ) == 1 ? il2 < il1 : il1 < il2 );
8617   list<const SMDS_MeshNode *> aNodesToInsert = theNodesToInsert;
8618   if ( reverse ) {
8619     iNode = il1;
8620     il1 = il2;
8621     il2 = iNode;
8622     aNodesToInsert.reverse();
8623   }
8624   // check that not link nodes of a quadrangles are in good order
8625   int nbFaceNodes = theFace->NbNodes();
8626   if ( nbFaceNodes == 4 && i4 - i3 != 1 ) {
8627     iNode = i3;
8628     i3 = i4;
8629     i4 = iNode;
8630   }
8631
8632   if (toCreatePoly || theFace->IsPoly()) {
8633
8634     iNode = 0;
8635     vector<const SMDS_MeshNode *> poly_nodes (nbFaceNodes + aNodesToInsert.size());
8636
8637     // add nodes of face up to first node of link
8638     bool isFLN = false;
8639
8640     if(theFace->IsQuadratic()) {
8641       const SMDS_VtkFace* F =
8642         dynamic_cast<const SMDS_VtkFace*>(theFace);
8643       if (!F) throw SALOME_Exception(LOCALIZED("not an SMDS_VtkFace"));
8644       // use special nodes iterator
8645       SMDS_ElemIteratorPtr anIter = F->interlacedNodesElemIterator();
8646       while( anIter->more()  && !isFLN ) {
8647         const SMDS_MeshNode* n = cast2Node(anIter->next());
8648         poly_nodes[iNode++] = n;
8649         if (n == nodes[il1]) {
8650           isFLN = true;
8651         }
8652       }
8653       // add nodes to insert
8654       list<const SMDS_MeshNode*>::iterator nIt = aNodesToInsert.begin();
8655       for (; nIt != aNodesToInsert.end(); nIt++) {
8656         poly_nodes[iNode++] = *nIt;
8657       }
8658       // add nodes of face starting from last node of link
8659       while ( anIter->more() ) {
8660         poly_nodes[iNode++] = cast2Node(anIter->next());
8661       }
8662     }
8663     else {
8664       SMDS_ElemIteratorPtr nodeIt = theFace->nodesIterator();
8665       while ( nodeIt->more() && !isFLN ) {
8666         const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
8667         poly_nodes[iNode++] = n;
8668         if (n == nodes[il1]) {
8669           isFLN = true;
8670         }
8671       }
8672       // add nodes to insert
8673       list<const SMDS_MeshNode*>::iterator nIt = aNodesToInsert.begin();
8674       for (; nIt != aNodesToInsert.end(); nIt++) {
8675         poly_nodes[iNode++] = *nIt;
8676       }
8677       // add nodes of face starting from last node of link
8678       while ( nodeIt->more() ) {
8679         const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
8680         poly_nodes[iNode++] = n;
8681       }
8682     }
8683
8684     // edit or replace the face
8685     SMESHDS_Mesh *aMesh = GetMeshDS();
8686
8687     if (theFace->IsPoly()) {
8688       aMesh->ChangePolygonNodes(theFace, poly_nodes);
8689     }
8690     else {
8691       int aShapeId = FindShape( theFace );
8692
8693       SMDS_MeshElement* newElem = aMesh->AddPolygonalFace(poly_nodes);
8694       myLastCreatedElems.Append(newElem);
8695       if ( aShapeId && newElem )
8696         aMesh->SetMeshElementOnShape( newElem, aShapeId );
8697
8698       aMesh->RemoveElement(theFace);
8699     }
8700     return;
8701   }
8702
8703   SMESHDS_Mesh *aMesh = GetMeshDS();
8704   if( !theFace->IsQuadratic() ) {
8705
8706     // put aNodesToInsert between theBetweenNode1 and theBetweenNode2
8707     int nbLinkNodes = 2 + aNodesToInsert.size();
8708     //const SMDS_MeshNode* linkNodes[ nbLinkNodes ];
8709     vector<const SMDS_MeshNode*> linkNodes( nbLinkNodes );
8710     linkNodes[ 0 ] = nodes[ il1 ];
8711     linkNodes[ nbLinkNodes - 1 ] = nodes[ il2 ];
8712     list<const SMDS_MeshNode*>::iterator nIt = aNodesToInsert.begin();
8713     for ( iNode = 1; nIt != aNodesToInsert.end(); nIt++ ) {
8714       linkNodes[ iNode++ ] = *nIt;
8715     }
8716     // decide how to split a quadrangle: compare possible variants
8717     // and choose which of splits to be a quadrangle
8718     int i1, i2, iSplit, nbSplits = nbLinkNodes - 1, iBestQuad;
8719     if ( nbFaceNodes == 3 ) {
8720       iBestQuad = nbSplits;
8721       i4 = i3;
8722     }
8723     else if ( nbFaceNodes == 4 ) {
8724       SMESH::Controls::NumericalFunctorPtr aCrit( new SMESH::Controls::AspectRatio);
8725       double aBestRate = DBL_MAX;
8726       for ( int iQuad = 0; iQuad < nbSplits; iQuad++ ) {
8727         i1 = 0; i2 = 1;
8728         double aBadRate = 0;
8729         // evaluate elements quality
8730         for ( iSplit = 0; iSplit < nbSplits; iSplit++ ) {
8731           if ( iSplit == iQuad ) {
8732             SMDS_FaceOfNodes quad (linkNodes[ i1++ ],
8733                                    linkNodes[ i2++ ],
8734                                    nodes[ i3 ],
8735                                    nodes[ i4 ]);
8736             aBadRate += getBadRate( &quad, aCrit );
8737           }
8738           else {
8739             SMDS_FaceOfNodes tria (linkNodes[ i1++ ],
8740                                    linkNodes[ i2++ ],
8741                                    nodes[ iSplit < iQuad ? i4 : i3 ]);
8742             aBadRate += getBadRate( &tria, aCrit );
8743           }
8744         }
8745         // choice
8746         if ( aBadRate < aBestRate ) {
8747           iBestQuad = iQuad;
8748           aBestRate = aBadRate;
8749         }
8750       }
8751     }
8752
8753     // create new elements
8754     int aShapeId = FindShape( theFace );
8755
8756     i1 = 0; i2 = 1;
8757     for ( iSplit = 0; iSplit < nbSplits - 1; iSplit++ ) {
8758       SMDS_MeshElement* newElem = 0;
8759       if ( iSplit == iBestQuad )
8760         newElem = aMesh->AddFace (linkNodes[ i1++ ],
8761                                   linkNodes[ i2++ ],
8762                                   nodes[ i3 ],
8763                                   nodes[ i4 ]);
8764       else
8765         newElem = aMesh->AddFace (linkNodes[ i1++ ],
8766                                   linkNodes[ i2++ ],
8767                                   nodes[ iSplit < iBestQuad ? i4 : i3 ]);
8768       myLastCreatedElems.Append(newElem);
8769       if ( aShapeId && newElem )
8770         aMesh->SetMeshElementOnShape( newElem, aShapeId );
8771     }
8772
8773     // change nodes of theFace
8774     const SMDS_MeshNode* newNodes[ 4 ];
8775     newNodes[ 0 ] = linkNodes[ i1 ];
8776     newNodes[ 1 ] = linkNodes[ i2 ];
8777     newNodes[ 2 ] = nodes[ iSplit >= iBestQuad ? i3 : i4 ];
8778     newNodes[ 3 ] = nodes[ i4 ];
8779     //aMesh->ChangeElementNodes( theFace, newNodes, iSplit == iBestQuad ? 4 : 3 );
8780     const SMDS_MeshElement* newElem = 0;
8781     if (iSplit == iBestQuad)
8782       newElem = aMesh->AddFace( newNodes[0], newNodes[1], newNodes[2], newNodes[3] );
8783     else
8784       newElem = aMesh->AddFace( newNodes[0], newNodes[1], newNodes[2] );
8785     myLastCreatedElems.Append(newElem);
8786     if ( aShapeId && newElem )
8787       aMesh->SetMeshElementOnShape( newElem, aShapeId );
8788 } // end if(!theFace->IsQuadratic())
8789   else { // theFace is quadratic
8790     // we have to split theFace on simple triangles and one simple quadrangle
8791     int tmp = il1/2;
8792     int nbshift = tmp*2;
8793     // shift nodes in nodes[] by nbshift
8794     int i,j;
8795     for(i=0; i<nbshift; i++) {
8796       const SMDS_MeshNode* n = nodes[0];
8797       for(j=0; j<nbFaceNodes-1; j++) {
8798         nodes[j] = nodes[j+1];
8799       }
8800       nodes[nbFaceNodes-1] = n;
8801     }
8802     il1 = il1 - nbshift;
8803     // now have to insert nodes between n0 and n1 or n1 and n2 (see below)
8804     //   n0      n1     n2    n0      n1     n2
8805     //     +-----+-----+        +-----+-----+
8806     //      \         /         |           |
8807     //       \       /          |           |
8808     //      n5+     +n3       n7+           +n3
8809     //         \   /            |           |
8810     //          \ /             |           |
8811     //           +              +-----+-----+
8812     //           n4           n6      n5     n4
8813
8814     // create new elements
8815     int aShapeId = FindShape( theFace );
8816
8817     int n1,n2,n3;
8818     if(nbFaceNodes==6) { // quadratic triangle
8819       SMDS_MeshElement* newElem =
8820         aMesh->AddFace(nodes[3],nodes[4],nodes[5]);
8821       myLastCreatedElems.Append(newElem);
8822       if ( aShapeId && newElem )
8823         aMesh->SetMeshElementOnShape( newElem, aShapeId );
8824       if(theFace->IsMediumNode(nodes[il1])) {
8825         // create quadrangle
8826         newElem = aMesh->AddFace(nodes[0],nodes[1],nodes[3],nodes[5]);
8827         myLastCreatedElems.Append(newElem);
8828         if ( aShapeId && newElem )
8829           aMesh->SetMeshElementOnShape( newElem, aShapeId );
8830         n1 = 1;
8831         n2 = 2;
8832         n3 = 3;
8833       }
8834       else {
8835         // create quadrangle
8836         newElem = aMesh->AddFace(nodes[1],nodes[2],nodes[3],nodes[5]);
8837         myLastCreatedElems.Append(newElem);
8838         if ( aShapeId && newElem )
8839           aMesh->SetMeshElementOnShape( newElem, aShapeId );
8840         n1 = 0;
8841         n2 = 1;
8842         n3 = 5;
8843       }
8844     }
8845     else { // nbFaceNodes==8 - quadratic quadrangle
8846       SMDS_MeshElement* newElem =
8847         aMesh->AddFace(nodes[3],nodes[4],nodes[5]);
8848       myLastCreatedElems.Append(newElem);
8849       if ( aShapeId && newElem )
8850         aMesh->SetMeshElementOnShape( newElem, aShapeId );
8851       newElem = aMesh->AddFace(nodes[5],nodes[6],nodes[7]);
8852       myLastCreatedElems.Append(newElem);
8853       if ( aShapeId && newElem )
8854         aMesh->SetMeshElementOnShape( newElem, aShapeId );
8855       newElem = aMesh->AddFace(nodes[5],nodes[7],nodes[3]);
8856       myLastCreatedElems.Append(newElem);
8857       if ( aShapeId && newElem )
8858         aMesh->SetMeshElementOnShape( newElem, aShapeId );
8859       if(theFace->IsMediumNode(nodes[il1])) {
8860         // create quadrangle
8861         newElem = aMesh->AddFace(nodes[0],nodes[1],nodes[3],nodes[7]);
8862         myLastCreatedElems.Append(newElem);
8863         if ( aShapeId && newElem )
8864           aMesh->SetMeshElementOnShape( newElem, aShapeId );
8865         n1 = 1;
8866         n2 = 2;
8867         n3 = 3;
8868       }
8869       else {
8870         // create quadrangle
8871         newElem = aMesh->AddFace(nodes[1],nodes[2],nodes[3],nodes[7]);
8872         myLastCreatedElems.Append(newElem);
8873         if ( aShapeId && newElem )
8874           aMesh->SetMeshElementOnShape( newElem, aShapeId );
8875         n1 = 0;
8876         n2 = 1;
8877         n3 = 7;
8878       }
8879     }
8880     // create needed triangles using n1,n2,n3 and inserted nodes
8881     int nbn = 2 + aNodesToInsert.size();
8882     //const SMDS_MeshNode* aNodes[nbn];
8883     vector<const SMDS_MeshNode*> aNodes(nbn);
8884     aNodes[0] = nodes[n1];
8885     aNodes[nbn-1] = nodes[n2];
8886     list<const SMDS_MeshNode*>::iterator nIt = aNodesToInsert.begin();
8887     for ( iNode = 1; nIt != aNodesToInsert.end(); nIt++ ) {
8888       aNodes[iNode++] = *nIt;
8889     }
8890     for(i=1; i<nbn; i++) {
8891       SMDS_MeshElement* newElem =
8892         aMesh->AddFace(aNodes[i-1],aNodes[i],nodes[n3]);
8893       myLastCreatedElems.Append(newElem);
8894       if ( aShapeId && newElem )
8895         aMesh->SetMeshElementOnShape( newElem, aShapeId );
8896     }
8897   }
8898   // remove old face
8899   aMesh->RemoveElement(theFace);
8900 }
8901
8902 //=======================================================================
8903 //function : UpdateVolumes
8904 //purpose  :
8905 //=======================================================================
8906 void SMESH_MeshEditor::UpdateVolumes (const SMDS_MeshNode*        theBetweenNode1,
8907                                       const SMDS_MeshNode*        theBetweenNode2,
8908                                       list<const SMDS_MeshNode*>& theNodesToInsert)
8909 {
8910   myLastCreatedElems.Clear();
8911   myLastCreatedNodes.Clear();
8912
8913   SMDS_ElemIteratorPtr invElemIt = theBetweenNode1->GetInverseElementIterator(SMDSAbs_Volume);
8914   while (invElemIt->more()) { // loop on inverse elements of theBetweenNode1
8915     const SMDS_MeshElement* elem = invElemIt->next();
8916
8917     // check, if current volume has link theBetweenNode1 - theBetweenNode2
8918     SMDS_VolumeTool aVolume (elem);
8919     if (!aVolume.IsLinked(theBetweenNode1, theBetweenNode2))
8920       continue;
8921
8922     // insert new nodes in all faces of the volume, sharing link theBetweenNode1 - theBetweenNode2
8923     int iface, nbFaces = aVolume.NbFaces();
8924     vector<const SMDS_MeshNode *> poly_nodes;
8925     vector<int> quantities (nbFaces);
8926
8927     for (iface = 0; iface < nbFaces; iface++) {
8928       int nbFaceNodes = aVolume.NbFaceNodes(iface), nbInserted = 0;
8929       // faceNodes will contain (nbFaceNodes + 1) nodes, last = first
8930       const SMDS_MeshNode** faceNodes = aVolume.GetFaceNodes(iface);
8931
8932       for (int inode = 0; inode < nbFaceNodes; inode++) {
8933         poly_nodes.push_back(faceNodes[inode]);
8934
8935         if (nbInserted == 0) {
8936           if (faceNodes[inode] == theBetweenNode1) {
8937             if (faceNodes[inode + 1] == theBetweenNode2) {
8938               nbInserted = theNodesToInsert.size();
8939
8940               // add nodes to insert
8941               list<const SMDS_MeshNode*>::iterator nIt = theNodesToInsert.begin();
8942               for (; nIt != theNodesToInsert.end(); nIt++) {
8943                 poly_nodes.push_back(*nIt);
8944               }
8945             }
8946           }
8947           else if (faceNodes[inode] == theBetweenNode2) {
8948             if (faceNodes[inode + 1] == theBetweenNode1) {
8949               nbInserted = theNodesToInsert.size();
8950
8951               // add nodes to insert in reversed order
8952               list<const SMDS_MeshNode*>::iterator nIt = theNodesToInsert.end();
8953               nIt--;
8954               for (; nIt != theNodesToInsert.begin(); nIt--) {
8955                 poly_nodes.push_back(*nIt);
8956               }
8957               poly_nodes.push_back(*nIt);
8958             }
8959           }
8960           else {
8961           }
8962         }
8963       }
8964       quantities[iface] = nbFaceNodes + nbInserted;
8965     }
8966
8967     // Replace or update the volume
8968     SMESHDS_Mesh *aMesh = GetMeshDS();
8969
8970     if (elem->IsPoly()) {
8971       aMesh->ChangePolyhedronNodes(elem, poly_nodes, quantities);
8972
8973     }
8974     else {
8975       int aShapeId = FindShape( elem );
8976
8977       SMDS_MeshElement* newElem =
8978         aMesh->AddPolyhedralVolume(poly_nodes, quantities);
8979       myLastCreatedElems.Append(newElem);
8980       if (aShapeId && newElem)
8981         aMesh->SetMeshElementOnShape(newElem, aShapeId);
8982
8983       aMesh->RemoveElement(elem);
8984     }
8985   }
8986 }
8987
8988 namespace
8989 {
8990   //================================================================================
8991   /*!
8992    * \brief Transform any volume into data of SMDSEntity_Polyhedra
8993    */
8994   //================================================================================
8995
8996   void volumeToPolyhedron( const SMDS_MeshElement*         elem,
8997                            vector<const SMDS_MeshNode *> & nodes,
8998                            vector<int> &                   nbNodeInFaces )
8999   {
9000     nodes.clear();
9001     nbNodeInFaces.clear();
9002     SMDS_VolumeTool vTool ( elem );
9003     for ( int iF = 0; iF < vTool.NbFaces(); ++iF )
9004     {
9005       const SMDS_MeshNode** fNodes = vTool.GetFaceNodes( iF );
9006       nodes.insert( nodes.end(), fNodes, fNodes + vTool.NbFaceNodes( iF ));
9007       nbNodeInFaces.push_back( vTool.NbFaceNodes( iF ));
9008     }
9009   }
9010 }
9011
9012 //=======================================================================
9013 /*!
9014  * \brief Convert elements contained in a submesh to quadratic
9015  * \return int - nb of checked elements
9016  */
9017 //=======================================================================
9018
9019 int SMESH_MeshEditor::convertElemToQuadratic(SMESHDS_SubMesh *   theSm,
9020                                              SMESH_MesherHelper& theHelper,
9021                                              const bool          theForce3d)
9022 {
9023   int nbElem = 0;
9024   if( !theSm ) return nbElem;
9025
9026   vector<int> nbNodeInFaces;
9027   vector<const SMDS_MeshNode *> nodes;
9028   SMDS_ElemIteratorPtr ElemItr = theSm->GetElements();
9029   while(ElemItr->more())
9030   {
9031     nbElem++;
9032     const SMDS_MeshElement* elem = ElemItr->next();
9033     if( !elem || elem->IsQuadratic() ) continue;
9034
9035     // get elem data needed to re-create it
9036     //
9037     const int id                        = elem->GetID();
9038     const int nbNodes                   = elem->NbNodes();
9039     const SMDSAbs_ElementType aType     = elem->GetType();
9040     const SMDSAbs_EntityType  aGeomType = elem->GetEntityType();
9041     nodes.assign(elem->begin_nodes(), elem->end_nodes());
9042     if ( aGeomType == SMDSEntity_Polyhedra )
9043       nbNodeInFaces = static_cast<const SMDS_VtkVolume* >( elem )->GetQuantities();
9044     else if ( aGeomType == SMDSEntity_Hexagonal_Prism )
9045       volumeToPolyhedron( elem, nodes, nbNodeInFaces );
9046
9047     // remove a linear element
9048     GetMeshDS()->RemoveFreeElement(elem, theSm, /*fromGroups=*/false);
9049
9050     const SMDS_MeshElement* NewElem = 0;
9051
9052     switch( aType )
9053     {
9054     case SMDSAbs_Edge :
9055       {
9056         NewElem = theHelper.AddEdge(nodes[0], nodes[1], id, theForce3d);
9057         break;
9058       }
9059     case SMDSAbs_Face :
9060       {
9061         switch(nbNodes)
9062         {
9063         case 3:
9064           NewElem = theHelper.AddFace(nodes[0], nodes[1], nodes[2], id, theForce3d);
9065           break;
9066         case 4:
9067           NewElem = theHelper.AddFace(nodes[0], nodes[1], nodes[2], nodes[3], id, theForce3d);
9068           break;
9069         default:
9070           NewElem = theHelper.AddPolygonalFace(nodes, id, theForce3d);
9071           continue;
9072         }
9073         break;
9074       }
9075     case SMDSAbs_Volume :
9076       {
9077         switch( aGeomType )
9078         {
9079         case SMDSEntity_Tetra:
9080           NewElem = theHelper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3], id, theForce3d);
9081           break;
9082         case SMDSEntity_Pyramid:
9083           NewElem = theHelper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3], nodes[4], id, theForce3d);
9084           break;
9085         case SMDSEntity_Penta:
9086           NewElem = theHelper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3], nodes[4], nodes[5], id, theForce3d);
9087           break;
9088         case SMDSEntity_Hexa:
9089           NewElem = theHelper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3],
9090                                         nodes[4], nodes[5], nodes[6], nodes[7], id, theForce3d);
9091           break;
9092         case SMDSEntity_Hexagonal_Prism:
9093         default:
9094           NewElem = theHelper.AddPolyhedralVolume(nodes, nbNodeInFaces, id, theForce3d);
9095         }
9096         break;
9097       }
9098     default :
9099       continue;
9100     }
9101     ReplaceElemInGroups( elem, NewElem, GetMeshDS());
9102     if( NewElem )
9103       theSm->AddElement( NewElem );
9104   }
9105   return nbElem;
9106 }
9107
9108 //=======================================================================
9109 //function : ConvertToQuadratic
9110 //purpose  :
9111 //=======================================================================
9112
9113 void SMESH_MeshEditor::ConvertToQuadratic(const bool theForce3d)
9114 {
9115   SMESHDS_Mesh* meshDS = GetMeshDS();
9116
9117   SMESH_MesherHelper aHelper(*myMesh);
9118   aHelper.SetIsQuadratic( true );
9119
9120   int nbCheckedElems = 0;
9121   if ( myMesh->HasShapeToMesh() )
9122   {
9123     if ( SMESH_subMesh *aSubMesh = myMesh->GetSubMeshContaining(myMesh->GetShapeToMesh()))
9124     {
9125       SMESH_subMeshIteratorPtr smIt = aSubMesh->getDependsOnIterator(true,false);
9126       while ( smIt->more() ) {
9127         SMESH_subMesh* sm = smIt->next();
9128         if ( SMESHDS_SubMesh *smDS = sm->GetSubMeshDS() ) {
9129           aHelper.SetSubShape( sm->GetSubShape() );
9130           nbCheckedElems += convertElemToQuadratic(smDS, aHelper, theForce3d);
9131         }
9132       }
9133     }
9134   }
9135   int totalNbElems = meshDS->NbEdges() + meshDS->NbFaces() + meshDS->NbVolumes();
9136   if ( nbCheckedElems < totalNbElems ) // not all elements are in submeshes
9137   {
9138     SMESHDS_SubMesh *smDS = 0;
9139     SMDS_EdgeIteratorPtr aEdgeItr = meshDS->edgesIterator();
9140     while(aEdgeItr->more())
9141     {
9142       const SMDS_MeshEdge* edge = aEdgeItr->next();
9143       if(edge && !edge->IsQuadratic())
9144       {
9145         int id = edge->GetID();
9146         //MESSAGE("edge->GetID() " << id);
9147         const SMDS_MeshNode* n1 = edge->GetNode(0);
9148         const SMDS_MeshNode* n2 = edge->GetNode(1);
9149
9150         meshDS->RemoveFreeElement(edge, smDS, /*fromGroups=*/false);
9151
9152         const SMDS_MeshEdge* NewEdge = aHelper.AddEdge(n1, n2, id, theForce3d);
9153         ReplaceElemInGroups( edge, NewEdge, GetMeshDS());
9154       }
9155     }
9156     SMDS_FaceIteratorPtr aFaceItr = meshDS->facesIterator();
9157     while(aFaceItr->more())
9158     {
9159       const SMDS_MeshFace* face = aFaceItr->next();
9160       if(!face || face->IsQuadratic() ) continue;
9161
9162       const int id = face->GetID();
9163       const SMDSAbs_EntityType type = face->GetEntityType();
9164       vector<const SMDS_MeshNode *> nodes ( face->begin_nodes(), face->end_nodes());
9165
9166       meshDS->RemoveFreeElement(face, smDS, /*fromGroups=*/false);
9167
9168       SMDS_MeshFace * NewFace = 0;
9169       switch( type )
9170       {
9171       case SMDSEntity_Triangle:
9172         NewFace = aHelper.AddFace(nodes[0], nodes[1], nodes[2], id, theForce3d);
9173         break;
9174       case SMDSEntity_Quadrangle:
9175         NewFace = aHelper.AddFace(nodes[0], nodes[1], nodes[2], nodes[3], id, theForce3d);
9176         break;
9177       default:
9178         NewFace = aHelper.AddPolygonalFace(nodes, id, theForce3d);
9179       }
9180       ReplaceElemInGroups( face, NewFace, GetMeshDS());
9181     }
9182     vector<int> nbNodeInFaces;
9183     SMDS_VolumeIteratorPtr aVolumeItr = meshDS->volumesIterator();
9184     while(aVolumeItr->more())
9185     {
9186       const SMDS_MeshVolume* volume = aVolumeItr->next();
9187       if(!volume || volume->IsQuadratic() ) continue;
9188
9189       const int id = volume->GetID();
9190       const SMDSAbs_EntityType type = volume->GetEntityType();
9191       vector<const SMDS_MeshNode *> nodes (volume->begin_nodes(), volume->end_nodes());
9192       if ( type == SMDSEntity_Polyhedra )
9193         nbNodeInFaces = static_cast<const SMDS_VtkVolume* >(volume)->GetQuantities();
9194       else if ( type == SMDSEntity_Hexagonal_Prism )
9195         volumeToPolyhedron( volume, nodes, nbNodeInFaces );
9196
9197       meshDS->RemoveFreeElement(volume, smDS, /*fromGroups=*/false);
9198
9199       SMDS_MeshVolume * NewVolume = 0;
9200       switch ( type )
9201       {
9202       case SMDSEntity_Tetra:
9203         NewVolume = aHelper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3], id, theForce3d );
9204         break;
9205       case SMDSEntity_Hexa:
9206         NewVolume = aHelper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3],
9207                                       nodes[4], nodes[5], nodes[6], nodes[7], id, theForce3d);
9208         break;
9209       case SMDSEntity_Pyramid:
9210         NewVolume = aHelper.AddVolume(nodes[0], nodes[1], nodes[2],
9211                                       nodes[3], nodes[4], id, theForce3d);
9212         break;
9213       case SMDSEntity_Penta:
9214         NewVolume = aHelper.AddVolume(nodes[0], nodes[1], nodes[2],
9215                                       nodes[3], nodes[4], nodes[5], id, theForce3d);
9216         break;
9217       case SMDSEntity_Hexagonal_Prism:
9218       default:
9219         NewVolume = aHelper.AddPolyhedralVolume(nodes, nbNodeInFaces, id, theForce3d);
9220       }
9221       ReplaceElemInGroups(volume, NewVolume, meshDS);
9222     }
9223   }
9224
9225   if ( !theForce3d )
9226   { // setenv NO_FixQuadraticElements to know if FixQuadraticElements() is guilty of bad conversion
9227     aHelper.SetSubShape(0); // apply FixQuadraticElements() to the whole mesh
9228     aHelper.FixQuadraticElements();
9229   }
9230 }
9231
9232 //================================================================================
9233 /*!
9234  * \brief Makes given elements quadratic
9235  *  \param theForce3d - if true, the medium nodes will be placed in the middle of link
9236  *  \param theElements - elements to make quadratic 
9237  */
9238 //================================================================================
9239
9240 void SMESH_MeshEditor::ConvertToQuadratic(const bool        theForce3d,
9241                                           TIDSortedElemSet& theElements)
9242 {
9243   if ( theElements.empty() ) return;
9244
9245   // we believe that all theElements are of the same type
9246   const SMDSAbs_ElementType elemType = (*theElements.begin())->GetType();
9247   
9248   // get all nodes shared by theElements
9249   TIDSortedNodeSet allNodes;
9250   TIDSortedElemSet::iterator eIt = theElements.begin();
9251   for ( ; eIt != theElements.end(); ++eIt )
9252     allNodes.insert( (*eIt)->begin_nodes(), (*eIt)->end_nodes() );
9253
9254   // complete theElements with elements of lower dim whose all nodes are in allNodes
9255
9256   TIDSortedElemSet quadAdjacentElems    [ SMDSAbs_NbElementTypes ]; // quadratic adjacent elements
9257   TIDSortedElemSet checkedAdjacentElems [ SMDSAbs_NbElementTypes ];
9258   TIDSortedNodeSet::iterator nIt = allNodes.begin();
9259   for ( ; nIt != allNodes.end(); ++nIt )
9260   {
9261     const SMDS_MeshNode* n = *nIt;
9262     SMDS_ElemIteratorPtr invIt = n->GetInverseElementIterator();
9263     while ( invIt->more() )
9264     {
9265       const SMDS_MeshElement* e = invIt->next();
9266       if ( e->IsQuadratic() )
9267       {
9268         quadAdjacentElems[ e->GetType() ].insert( e );
9269         continue;
9270       }
9271       if ( e->GetType() >= elemType )
9272       {
9273         continue; // same type of more complex linear element
9274       }
9275
9276       if ( !checkedAdjacentElems[ e->GetType() ].insert( e ).second )
9277         continue; // e is already checked
9278
9279       // check nodes
9280       bool allIn = true;
9281       SMDS_ElemIteratorPtr nodeIt = e->nodesIterator();
9282       while ( nodeIt->more() && allIn )
9283         allIn = allNodes.count( cast2Node( nodeIt->next() ));
9284       if ( allIn )
9285         theElements.insert(e );
9286     }
9287   }
9288
9289   SMESH_MesherHelper helper(*myMesh);
9290   helper.SetIsQuadratic( true );
9291
9292   // add links of quadratic adjacent elements to the helper
9293
9294   if ( !quadAdjacentElems[SMDSAbs_Edge].empty() )
9295     for ( eIt  = quadAdjacentElems[SMDSAbs_Edge].begin();
9296           eIt != quadAdjacentElems[SMDSAbs_Edge].end(); ++eIt )
9297     {
9298       helper.AddTLinks( static_cast< const SMDS_MeshEdge*> (*eIt) );
9299     }
9300   if ( !quadAdjacentElems[SMDSAbs_Face].empty() )
9301     for ( eIt  = quadAdjacentElems[SMDSAbs_Face].begin();
9302           eIt != quadAdjacentElems[SMDSAbs_Face].end(); ++eIt )
9303     {
9304       helper.AddTLinks( static_cast< const SMDS_MeshFace*> (*eIt) );
9305     }
9306   if ( !quadAdjacentElems[SMDSAbs_Volume].empty() )
9307     for ( eIt  = quadAdjacentElems[SMDSAbs_Volume].begin();
9308           eIt != quadAdjacentElems[SMDSAbs_Volume].end(); ++eIt )
9309     {
9310       helper.AddTLinks( static_cast< const SMDS_MeshVolume*> (*eIt) );
9311     }
9312
9313   // make quadratic elements instead of linear ones
9314
9315   SMESHDS_Mesh* meshDS = GetMeshDS();
9316   SMESHDS_SubMesh* smDS = 0;
9317   for ( eIt = theElements.begin(); eIt != theElements.end(); ++eIt )
9318   {
9319     const SMDS_MeshElement* elem = *eIt;
9320     if( elem->IsQuadratic() || elem->NbNodes() < 2 || elem->IsPoly() )
9321       continue;
9322
9323     const int id                   = elem->GetID();
9324     const SMDSAbs_ElementType type = elem->GetType();
9325     vector<const SMDS_MeshNode *> nodes ( elem->begin_nodes(), elem->end_nodes());
9326
9327     if ( !smDS || !smDS->Contains( elem ))
9328       smDS = meshDS->MeshElements( elem->getshapeId() );
9329     meshDS->RemoveFreeElement(elem, smDS, /*fromGroups=*/false);
9330
9331     SMDS_MeshElement * newElem = 0;
9332     switch( nodes.size() )
9333     {
9334     case 4: // cases for most frequently used element types go first (for optimization)
9335       if ( type == SMDSAbs_Volume )
9336         newElem = helper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3], id, theForce3d);
9337       else
9338         newElem = helper.AddFace  (nodes[0], nodes[1], nodes[2], nodes[3], id, theForce3d);
9339       break;
9340     case 8:
9341       newElem = helper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3],
9342                                  nodes[4], nodes[5], nodes[6], nodes[7], id, theForce3d);
9343       break;
9344     case 3:
9345       newElem = helper.AddFace  (nodes[0], nodes[1], nodes[2], id, theForce3d);
9346       break;
9347     case 2:
9348       newElem = helper.AddEdge(nodes[0], nodes[1], id, theForce3d);
9349       break;
9350     case 5:
9351       newElem = helper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3],
9352                                  nodes[4], id, theForce3d);
9353       break;
9354     case 6:
9355       newElem = helper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3],
9356                                  nodes[4], nodes[5], id, theForce3d);
9357       break;
9358     default:;
9359     }
9360     ReplaceElemInGroups( elem, newElem, meshDS);
9361     if( newElem && smDS )
9362       smDS->AddElement( newElem );
9363   }
9364
9365   if ( !theForce3d  && !getenv("NO_FixQuadraticElements"))
9366   { // setenv NO_FixQuadraticElements to know if FixQuadraticElements() is guilty of bad conversion
9367     helper.SetSubShape(0); // apply FixQuadraticElements() to the whole mesh
9368     helper.FixQuadraticElements();
9369   }
9370 }
9371
9372 //=======================================================================
9373 /*!
9374  * \brief Convert quadratic elements to linear ones and remove quadratic nodes
9375  * \return int - nb of checked elements
9376  */
9377 //=======================================================================
9378
9379 int SMESH_MeshEditor::removeQuadElem(SMESHDS_SubMesh *    theSm,
9380                                      SMDS_ElemIteratorPtr theItr,
9381                                      const int            theShapeID)
9382 {
9383   int nbElem = 0;
9384   SMESHDS_Mesh* meshDS = GetMeshDS();
9385
9386   while( theItr->more() )
9387   {
9388     const SMDS_MeshElement* elem = theItr->next();
9389     nbElem++;
9390     if( elem && elem->IsQuadratic())
9391     {
9392       int id                    = elem->GetID();
9393       int nbCornerNodes         = elem->NbCornerNodes();
9394       SMDSAbs_ElementType aType = elem->GetType();
9395
9396       vector<const SMDS_MeshNode *> nodes( elem->begin_nodes(), elem->end_nodes() );
9397
9398       //remove a quadratic element
9399       if ( !theSm || !theSm->Contains( elem ))
9400         theSm = meshDS->MeshElements( elem->getshapeId() );
9401       meshDS->RemoveFreeElement( elem, theSm, /*fromGroups=*/false );
9402
9403       // remove medium nodes
9404       for ( unsigned i = nbCornerNodes; i < nodes.size(); ++i )
9405         if ( nodes[i]->NbInverseElements() == 0 )
9406           meshDS->RemoveFreeNode( nodes[i], theSm );
9407
9408       // add a linear element
9409       nodes.resize( nbCornerNodes );
9410       SMDS_MeshElement * newElem = AddElement( nodes, aType, false, id );
9411       ReplaceElemInGroups(elem, newElem, meshDS);
9412       if( theSm && newElem )
9413         theSm->AddElement( newElem );
9414     }
9415   }
9416   return nbElem;
9417 }
9418
9419 //=======================================================================
9420 //function : ConvertFromQuadratic
9421 //purpose  :
9422 //=======================================================================
9423
9424 bool SMESH_MeshEditor::ConvertFromQuadratic()
9425 {
9426   int nbCheckedElems = 0;
9427   if ( myMesh->HasShapeToMesh() )
9428   {
9429     if ( SMESH_subMesh *aSubMesh = myMesh->GetSubMeshContaining(myMesh->GetShapeToMesh()))
9430     {
9431       SMESH_subMeshIteratorPtr smIt = aSubMesh->getDependsOnIterator(true,false);
9432       while ( smIt->more() ) {
9433         SMESH_subMesh* sm = smIt->next();
9434         if ( SMESHDS_SubMesh *smDS = sm->GetSubMeshDS() )
9435           nbCheckedElems += removeQuadElem( smDS, smDS->GetElements(), sm->GetId() );
9436       }
9437     }
9438   }
9439
9440   int totalNbElems =
9441     GetMeshDS()->NbEdges() + GetMeshDS()->NbFaces() + GetMeshDS()->NbVolumes();
9442   if ( nbCheckedElems < totalNbElems ) // not all elements are in submeshes
9443   {
9444     SMESHDS_SubMesh *aSM = 0;
9445     removeQuadElem( aSM, GetMeshDS()->elementsIterator(), 0 );
9446   }
9447
9448   return true;
9449 }
9450
9451 namespace
9452 {
9453   //================================================================================
9454   /*!
9455    * \brief Return true if all medium nodes of the element are in the node set
9456    */
9457   //================================================================================
9458
9459   bool allMediumNodesIn(const SMDS_MeshElement* elem, TIDSortedNodeSet& nodeSet )
9460   {
9461     for ( int i = elem->NbCornerNodes(); i < elem->NbNodes(); ++i )
9462       if ( !nodeSet.count( elem->GetNode(i) ))
9463         return false;
9464     return true;
9465   }
9466 }
9467
9468 //================================================================================
9469 /*!
9470  * \brief Makes given elements linear
9471  */
9472 //================================================================================
9473
9474 void SMESH_MeshEditor::ConvertFromQuadratic(TIDSortedElemSet& theElements)
9475 {
9476   if ( theElements.empty() ) return;
9477
9478   // collect IDs of medium nodes of theElements; some of these nodes will be removed
9479   set<int> mediumNodeIDs;
9480   TIDSortedElemSet::iterator eIt = theElements.begin();
9481   for ( ; eIt != theElements.end(); ++eIt )
9482   {
9483     const SMDS_MeshElement* e = *eIt;
9484     for ( int i = e->NbCornerNodes(); i < e->NbNodes(); ++i )
9485       mediumNodeIDs.insert( e->GetNode(i)->GetID() );
9486   }
9487
9488   // replace given elements by linear ones
9489   typedef SMDS_SetIterator<const SMDS_MeshElement*, TIDSortedElemSet::iterator> TSetIterator;
9490   SMDS_ElemIteratorPtr elemIt( new TSetIterator( theElements.begin(), theElements.end() ));
9491   removeQuadElem( /*theSm=*/0, elemIt, /*theShapeID=*/0 );
9492
9493   // we need to convert remaining elements whose all medium nodes are in mediumNodeIDs
9494   // except those elements sharing medium nodes of quadratic element whose medium nodes
9495   // are not all in mediumNodeIDs
9496
9497   // get remaining medium nodes
9498   TIDSortedNodeSet mediumNodes;
9499   set<int>::iterator nIdsIt = mediumNodeIDs.begin();
9500   for ( ; nIdsIt != mediumNodeIDs.end(); ++nIdsIt )
9501     if ( const SMDS_MeshNode* n = GetMeshDS()->FindNode( *nIdsIt ))
9502       mediumNodes.insert( mediumNodes.end(), n );
9503
9504   // find more quadratic elements to convert
9505   TIDSortedElemSet moreElemsToConvert;
9506   TIDSortedNodeSet::iterator nIt = mediumNodes.begin();
9507   for ( ; nIt != mediumNodes.end(); ++nIt )
9508   {
9509     SMDS_ElemIteratorPtr invIt = (*nIt)->GetInverseElementIterator();
9510     while ( invIt->more() )
9511     {
9512       const SMDS_MeshElement* e = invIt->next();
9513       if ( e->IsQuadratic() && allMediumNodesIn( e, mediumNodes ))
9514       {
9515         // find a more complex element including e and
9516         // whose medium nodes are not in mediumNodes
9517         bool complexFound = false;
9518         for ( int type = e->GetType() + 1; type < SMDSAbs_0DElement; ++type )
9519         {
9520           SMDS_ElemIteratorPtr invIt2 =
9521             (*nIt)->GetInverseElementIterator( SMDSAbs_ElementType( type ));
9522           while ( invIt2->more() )
9523           {
9524             const SMDS_MeshElement* eComplex = invIt2->next();
9525             if ( eComplex->IsQuadratic() && !allMediumNodesIn( eComplex, mediumNodes))
9526             {
9527               int nbCommonNodes = SMESH_Algo::GetCommonNodes( e, eComplex ).size();
9528               if ( nbCommonNodes == e->NbNodes())
9529               {
9530                 complexFound = true;
9531                 type = SMDSAbs_NbElementTypes; // to quit from the outer loop
9532                 break;
9533               }
9534             }
9535           }
9536         }
9537         if ( !complexFound )
9538           moreElemsToConvert.insert( e );
9539       }
9540     }
9541   }
9542   elemIt = SMDS_ElemIteratorPtr
9543     (new TSetIterator( moreElemsToConvert.begin(), moreElemsToConvert.end() ));
9544   removeQuadElem( /*theSm=*/0, elemIt, /*theShapeID=*/0 );
9545 }
9546
9547 //=======================================================================
9548 //function : SewSideElements
9549 //purpose  :
9550 //=======================================================================
9551
9552 SMESH_MeshEditor::Sew_Error
9553 SMESH_MeshEditor::SewSideElements (TIDSortedElemSet&    theSide1,
9554                                    TIDSortedElemSet&    theSide2,
9555                                    const SMDS_MeshNode* theFirstNode1,
9556                                    const SMDS_MeshNode* theFirstNode2,
9557                                    const SMDS_MeshNode* theSecondNode1,
9558                                    const SMDS_MeshNode* theSecondNode2)
9559 {
9560   myLastCreatedElems.Clear();
9561   myLastCreatedNodes.Clear();
9562
9563   MESSAGE ("::::SewSideElements()");
9564   if ( theSide1.size() != theSide2.size() )
9565     return SEW_DIFF_NB_OF_ELEMENTS;
9566
9567   Sew_Error aResult = SEW_OK;
9568   // Algo:
9569   // 1. Build set of faces representing each side
9570   // 2. Find which nodes of the side 1 to merge with ones on the side 2
9571   // 3. Replace nodes in elements of the side 1 and remove replaced nodes
9572
9573   // =======================================================================
9574   // 1. Build set of faces representing each side:
9575   // =======================================================================
9576   // a. build set of nodes belonging to faces
9577   // b. complete set of faces: find missing faces whose nodes are in set of nodes
9578   // c. create temporary faces representing side of volumes if correspondent
9579   //    face does not exist
9580
9581   SMESHDS_Mesh* aMesh = GetMeshDS();
9582   // TODO algoritm not OK with vtkUnstructuredGrid: 2 meshes can't share nodes
9583   //SMDS_Mesh aTmpFacesMesh; // try to use the same mesh
9584   TIDSortedElemSet             faceSet1, faceSet2;
9585   set<const SMDS_MeshElement*> volSet1,  volSet2;
9586   set<const SMDS_MeshNode*>    nodeSet1, nodeSet2;
9587   TIDSortedElemSet             * faceSetPtr[] = { &faceSet1, &faceSet2 };
9588   set<const SMDS_MeshElement*> *  volSetPtr[] = { &volSet1,  &volSet2  };
9589   set<const SMDS_MeshNode*>    * nodeSetPtr[] = { &nodeSet1, &nodeSet2 };
9590   TIDSortedElemSet             * elemSetPtr[] = { &theSide1, &theSide2 };
9591   int iSide, iFace, iNode;
9592
9593   list<const SMDS_MeshElement* > tempFaceList;
9594   for ( iSide = 0; iSide < 2; iSide++ ) {
9595     set<const SMDS_MeshNode*>    * nodeSet = nodeSetPtr[ iSide ];
9596     TIDSortedElemSet             * elemSet = elemSetPtr[ iSide ];
9597     TIDSortedElemSet             * faceSet = faceSetPtr[ iSide ];
9598     set<const SMDS_MeshElement*> * volSet  = volSetPtr [ iSide ];
9599     set<const SMDS_MeshElement*>::iterator vIt;
9600     TIDSortedElemSet::iterator eIt;
9601     set<const SMDS_MeshNode*>::iterator    nIt;
9602
9603     // check that given nodes belong to given elements
9604     const SMDS_MeshNode* n1 = ( iSide == 0 ) ? theFirstNode1 : theFirstNode2;
9605     const SMDS_MeshNode* n2 = ( iSide == 0 ) ? theSecondNode1 : theSecondNode2;
9606     int firstIndex = -1, secondIndex = -1;
9607     for (eIt = elemSet->begin(); eIt != elemSet->end(); eIt++ ) {
9608       const SMDS_MeshElement* elem = *eIt;
9609       if ( firstIndex  < 0 ) firstIndex  = elem->GetNodeIndex( n1 );
9610       if ( secondIndex < 0 ) secondIndex = elem->GetNodeIndex( n2 );
9611       if ( firstIndex > -1 && secondIndex > -1 ) break;
9612     }
9613     if ( firstIndex < 0 || secondIndex < 0 ) {
9614       // we can simply return until temporary faces created
9615       return (iSide == 0 ) ? SEW_BAD_SIDE1_NODES : SEW_BAD_SIDE2_NODES;
9616     }
9617
9618     // -----------------------------------------------------------
9619     // 1a. Collect nodes of existing faces
9620     //     and build set of face nodes in order to detect missing
9621     //     faces corresponding to sides of volumes
9622     // -----------------------------------------------------------
9623
9624     set< set <const SMDS_MeshNode*> > setOfFaceNodeSet;
9625
9626     // loop on the given element of a side
9627     for (eIt = elemSet->begin(); eIt != elemSet->end(); eIt++ ) {
9628       //const SMDS_MeshElement* elem = *eIt;
9629       const SMDS_MeshElement* elem = *eIt;
9630       if ( elem->GetType() == SMDSAbs_Face ) {
9631         faceSet->insert( elem );
9632         set <const SMDS_MeshNode*> faceNodeSet;
9633         SMDS_ElemIteratorPtr nodeIt = elem->nodesIterator();
9634         while ( nodeIt->more() ) {
9635           const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
9636           nodeSet->insert( n );
9637           faceNodeSet.insert( n );
9638         }
9639         setOfFaceNodeSet.insert( faceNodeSet );
9640       }
9641       else if ( elem->GetType() == SMDSAbs_Volume )
9642         volSet->insert( elem );
9643     }
9644     // ------------------------------------------------------------------------------
9645     // 1b. Complete set of faces: find missing faces whose nodes are in set of nodes
9646     // ------------------------------------------------------------------------------
9647
9648     for ( nIt = nodeSet->begin(); nIt != nodeSet->end(); nIt++ ) { // loop on nodes of iSide
9649       SMDS_ElemIteratorPtr fIt = (*nIt)->GetInverseElementIterator(SMDSAbs_Face);
9650       while ( fIt->more() ) { // loop on faces sharing a node
9651         const SMDS_MeshElement* f = fIt->next();
9652         if ( faceSet->find( f ) == faceSet->end() ) {
9653           // check if all nodes are in nodeSet and
9654           // complete setOfFaceNodeSet if they are
9655           set <const SMDS_MeshNode*> faceNodeSet;
9656           SMDS_ElemIteratorPtr nodeIt = f->nodesIterator();
9657           bool allInSet = true;
9658           while ( nodeIt->more() && allInSet ) { // loop on nodes of a face
9659             const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
9660             if ( nodeSet->find( n ) == nodeSet->end() )
9661               allInSet = false;
9662             else
9663               faceNodeSet.insert( n );
9664           }
9665           if ( allInSet ) {
9666             faceSet->insert( f );
9667             setOfFaceNodeSet.insert( faceNodeSet );
9668           }
9669         }
9670       }
9671     }
9672
9673     // -------------------------------------------------------------------------
9674     // 1c. Create temporary faces representing sides of volumes if correspondent
9675     //     face does not exist
9676     // -------------------------------------------------------------------------
9677
9678     if ( !volSet->empty() ) {
9679       //int nodeSetSize = nodeSet->size();
9680
9681       // loop on given volumes
9682       for ( vIt = volSet->begin(); vIt != volSet->end(); vIt++ ) {
9683         SMDS_VolumeTool vol (*vIt);
9684         // loop on volume faces: find free faces
9685         // --------------------------------------
9686         list<const SMDS_MeshElement* > freeFaceList;
9687         for ( iFace = 0; iFace < vol.NbFaces(); iFace++ ) {
9688           if ( !vol.IsFreeFace( iFace ))
9689             continue;
9690           // check if there is already a face with same nodes in a face set
9691           const SMDS_MeshElement* aFreeFace = 0;
9692           const SMDS_MeshNode** fNodes = vol.GetFaceNodes( iFace );
9693           int nbNodes = vol.NbFaceNodes( iFace );
9694           set <const SMDS_MeshNode*> faceNodeSet;
9695           vol.GetFaceNodes( iFace, faceNodeSet );
9696           bool isNewFace = setOfFaceNodeSet.insert( faceNodeSet ).second;
9697           if ( isNewFace ) {
9698             // no such a face is given but it still can exist, check it
9699             vector<const SMDS_MeshNode *> nodes ( fNodes, fNodes + nbNodes);
9700             aFreeFace = aMesh->FindElement( nodes, SMDSAbs_Face, /*noMedium=*/false );
9701           }
9702           if ( !aFreeFace ) {
9703             // create a temporary face
9704             if ( nbNodes == 3 ) {
9705               //aFreeFace = aTmpFacesMesh.AddFace( fNodes[0],fNodes[1],fNodes[2] );
9706               aFreeFace = aMesh->AddFace( fNodes[0],fNodes[1],fNodes[2] );
9707             }
9708             else if ( nbNodes == 4 ) {
9709               //aFreeFace = aTmpFacesMesh.AddFace( fNodes[0],fNodes[1],fNodes[2],fNodes[3] );
9710               aFreeFace = aMesh->AddFace( fNodes[0],fNodes[1],fNodes[2],fNodes[3] );
9711             }
9712             else {
9713               vector<const SMDS_MeshNode *> poly_nodes ( fNodes, & fNodes[nbNodes]);
9714               //aFreeFace = aTmpFacesMesh.AddPolygonalFace(poly_nodes);
9715               aFreeFace = aMesh->AddPolygonalFace(poly_nodes);
9716             }
9717             if ( aFreeFace )
9718               tempFaceList.push_back( aFreeFace );
9719           }
9720
9721           if ( aFreeFace )
9722             freeFaceList.push_back( aFreeFace );
9723
9724         } // loop on faces of a volume
9725
9726         // choose one of several free faces of a volume
9727         // --------------------------------------------
9728         if ( freeFaceList.size() > 1 ) {
9729           // choose a face having max nb of nodes shared by other elems of a side
9730           int maxNbNodes = -1;
9731           list<const SMDS_MeshElement* >::iterator fIt = freeFaceList.begin();
9732           while ( fIt != freeFaceList.end() ) { // loop on free faces
9733             int nbSharedNodes = 0;
9734             SMDS_ElemIteratorPtr nodeIt = (*fIt)->nodesIterator();
9735             while ( nodeIt->more() ) { // loop on free face nodes
9736               const SMDS_MeshNode* n =
9737                 static_cast<const SMDS_MeshNode*>( nodeIt->next() );
9738               SMDS_ElemIteratorPtr invElemIt = n->GetInverseElementIterator();
9739               while ( invElemIt->more() ) {
9740                 const SMDS_MeshElement* e = invElemIt->next();
9741                 nbSharedNodes += faceSet->count( e );
9742                 nbSharedNodes += elemSet->count( e );
9743               }
9744             }
9745             if ( nbSharedNodes > maxNbNodes ) {
9746               maxNbNodes = nbSharedNodes;
9747               freeFaceList.erase( freeFaceList.begin(), fIt++ );
9748             }
9749             else if ( nbSharedNodes == maxNbNodes ) {
9750               fIt++;
9751             }
9752             else {
9753               freeFaceList.erase( fIt++ ); // here fIt++ occurs before erase
9754             }
9755           }
9756           if ( freeFaceList.size() > 1 )
9757           {
9758             // could not choose one face, use another way
9759             // choose a face most close to the bary center of the opposite side
9760             gp_XYZ aBC( 0., 0., 0. );
9761             set <const SMDS_MeshNode*> addedNodes;
9762             TIDSortedElemSet * elemSet2 = elemSetPtr[ 1 - iSide ];
9763             eIt = elemSet2->begin();
9764             for ( eIt = elemSet2->begin(); eIt != elemSet2->end(); eIt++ ) {
9765               SMDS_ElemIteratorPtr nodeIt = (*eIt)->nodesIterator();
9766               while ( nodeIt->more() ) { // loop on free face nodes
9767                 const SMDS_MeshNode* n =
9768                   static_cast<const SMDS_MeshNode*>( nodeIt->next() );
9769                 if ( addedNodes.insert( n ).second )
9770                   aBC += gp_XYZ( n->X(),n->Y(),n->Z() );
9771               }
9772             }
9773             aBC /= addedNodes.size();
9774             double minDist = DBL_MAX;
9775             fIt = freeFaceList.begin();
9776             while ( fIt != freeFaceList.end() ) { // loop on free faces
9777               double dist = 0;
9778               SMDS_ElemIteratorPtr nodeIt = (*fIt)->nodesIterator();
9779               while ( nodeIt->more() ) { // loop on free face nodes
9780                 const SMDS_MeshNode* n =
9781                   static_cast<const SMDS_MeshNode*>( nodeIt->next() );
9782                 gp_XYZ p( n->X(),n->Y(),n->Z() );
9783                 dist += ( aBC - p ).SquareModulus();
9784               }
9785               if ( dist < minDist ) {
9786                 minDist = dist;
9787                 freeFaceList.erase( freeFaceList.begin(), fIt++ );
9788               }
9789               else
9790                 fIt = freeFaceList.erase( fIt++ );
9791             }
9792           }
9793         } // choose one of several free faces of a volume
9794
9795         if ( freeFaceList.size() == 1 ) {
9796           const SMDS_MeshElement* aFreeFace = freeFaceList.front();
9797           faceSet->insert( aFreeFace );
9798           // complete a node set with nodes of a found free face
9799           //           for ( iNode = 0; iNode < ; iNode++ )
9800           //             nodeSet->insert( fNodes[ iNode ] );
9801         }
9802
9803       } // loop on volumes of a side
9804
9805       //       // complete a set of faces if new nodes in a nodeSet appeared
9806       //       // ----------------------------------------------------------
9807       //       if ( nodeSetSize != nodeSet->size() ) {
9808       //         for ( ; nIt != nodeSet->end(); nIt++ ) { // loop on nodes of iSide
9809       //           SMDS_ElemIteratorPtr fIt = (*nIt)->GetInverseElementIterator(SMDSAbs_Face);
9810       //           while ( fIt->more() ) { // loop on faces sharing a node
9811       //             const SMDS_MeshElement* f = fIt->next();
9812       //             if ( faceSet->find( f ) == faceSet->end() ) {
9813       //               // check if all nodes are in nodeSet and
9814       //               // complete setOfFaceNodeSet if they are
9815       //               set <const SMDS_MeshNode*> faceNodeSet;
9816       //               SMDS_ElemIteratorPtr nodeIt = f->nodesIterator();
9817       //               bool allInSet = true;
9818       //               while ( nodeIt->more() && allInSet ) { // loop on nodes of a face
9819       //                 const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
9820       //                 if ( nodeSet->find( n ) == nodeSet->end() )
9821       //                   allInSet = false;
9822       //                 else
9823       //                   faceNodeSet.insert( n );
9824       //               }
9825       //               if ( allInSet ) {
9826       //                 faceSet->insert( f );
9827       //                 setOfFaceNodeSet.insert( faceNodeSet );
9828       //               }
9829       //             }
9830       //           }
9831       //         }
9832       //       }
9833     } // Create temporary faces, if there are volumes given
9834   } // loop on sides
9835
9836   if ( faceSet1.size() != faceSet2.size() ) {
9837     // delete temporary faces: they are in reverseElements of actual nodes
9838 //    SMDS_FaceIteratorPtr tmpFaceIt = aTmpFacesMesh.facesIterator();
9839 //    while ( tmpFaceIt->more() )
9840 //      aTmpFacesMesh.RemoveElement( tmpFaceIt->next() );
9841 //    list<const SMDS_MeshElement* >::iterator tmpFaceIt = tempFaceList.begin();
9842 //    for (; tmpFaceIt !=tempFaceList.end(); ++tmpFaceIt)
9843 //      aMesh->RemoveElement(*tmpFaceIt);
9844     MESSAGE("Diff nb of faces");
9845     return SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
9846   }
9847
9848   // ============================================================
9849   // 2. Find nodes to merge:
9850   //              bind a node to remove to a node to put instead
9851   // ============================================================
9852
9853   TNodeNodeMap nReplaceMap; // bind a node to remove to a node to put instead
9854   if ( theFirstNode1 != theFirstNode2 )
9855     nReplaceMap.insert( make_pair( theFirstNode1, theFirstNode2 ));
9856   if ( theSecondNode1 != theSecondNode2 )
9857     nReplaceMap.insert( make_pair( theSecondNode1, theSecondNode2 ));
9858
9859   LinkID_Gen aLinkID_Gen( GetMeshDS() );
9860   set< long > linkIdSet; // links to process
9861   linkIdSet.insert( aLinkID_Gen.GetLinkID( theFirstNode1, theSecondNode1 ));
9862
9863   typedef pair< const SMDS_MeshNode*, const SMDS_MeshNode* > NLink;
9864   list< NLink > linkList[2];
9865   linkList[0].push_back( NLink( theFirstNode1, theSecondNode1 ));
9866   linkList[1].push_back( NLink( theFirstNode2, theSecondNode2 ));
9867   // loop on links in linkList; find faces by links and append links
9868   // of the found faces to linkList
9869   list< NLink >::iterator linkIt[] = { linkList[0].begin(), linkList[1].begin() } ;
9870   for ( ; linkIt[0] != linkList[0].end(); linkIt[0]++, linkIt[1]++ )
9871   {
9872     NLink link[] = { *linkIt[0], *linkIt[1] };
9873     long linkID = aLinkID_Gen.GetLinkID( link[0].first, link[0].second );
9874     if ( !linkIdSet.count( linkID ) )
9875       continue;
9876
9877     // by links, find faces in the face sets,
9878     // and find indices of link nodes in the found faces;
9879     // in a face set, there is only one or no face sharing a link
9880     // ---------------------------------------------------------------
9881
9882     const SMDS_MeshElement* face[] = { 0, 0 };
9883     vector<const SMDS_MeshNode*> fnodes[2];
9884     int iLinkNode[2][2];
9885     TIDSortedElemSet avoidSet;
9886     for ( iSide = 0; iSide < 2; iSide++ ) { // loop on 2 sides
9887       const SMDS_MeshNode* n1 = link[iSide].first;
9888       const SMDS_MeshNode* n2 = link[iSide].second;
9889       //cout << "Side " << iSide << " ";
9890       //cout << "L( " << n1->GetID() << ", " << n2->GetID() << " ) " << endl;
9891       // find a face by two link nodes
9892       face[ iSide ] = FindFaceInSet( n1, n2, *faceSetPtr[ iSide ], avoidSet,
9893                                      &iLinkNode[iSide][0], &iLinkNode[iSide][1] );
9894       if ( face[ iSide ])
9895       {
9896         //cout << " F " << face[ iSide]->GetID() <<endl;
9897         faceSetPtr[ iSide ]->erase( face[ iSide ]);
9898         // put face nodes to fnodes
9899         if ( face[ iSide ]->IsQuadratic() )
9900         {
9901           // use interlaced nodes iterator
9902           const SMDS_VtkFace* F = dynamic_cast<const SMDS_VtkFace*>( face[ iSide ]);
9903           if (!F) throw SALOME_Exception(LOCALIZED("not an SMDS_VtkFace"));
9904           SMDS_ElemIteratorPtr nIter = F->interlacedNodesElemIterator();
9905           while ( nIter->more() )
9906             fnodes[ iSide ].push_back( cast2Node( nIter->next() ));
9907         }
9908         else
9909         {
9910           fnodes[ iSide ].assign( face[ iSide ]->begin_nodes(),
9911                                   face[ iSide ]->end_nodes() );
9912         }
9913         fnodes[ iSide ].push_back( fnodes[ iSide ].front());
9914       }
9915     }
9916
9917     // check similarity of elements of the sides
9918     if (aResult == SEW_OK && (( face[0] && !face[1] ) || ( !face[0] && face[1] ))) {
9919       MESSAGE("Correspondent face not found on side " << ( face[0] ? 1 : 0 ));
9920       if ( nReplaceMap.size() == 2 ) { // faces on input nodes not found
9921         aResult = ( face[0] ? SEW_BAD_SIDE2_NODES : SEW_BAD_SIDE1_NODES );
9922       }
9923       else {
9924         aResult = SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
9925       }
9926       break; // do not return because it's necessary to remove tmp faces
9927     }
9928
9929     // set nodes to merge
9930     // -------------------
9931
9932     if ( face[0] && face[1] )  {
9933       const int nbNodes = face[0]->NbNodes();
9934       if ( nbNodes != face[1]->NbNodes() ) {
9935         MESSAGE("Diff nb of face nodes");
9936         aResult = SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
9937         break; // do not return because it s necessary to remove tmp faces
9938       }
9939       bool reverse[] = { false, false }; // order of nodes in the link
9940       for ( iSide = 0; iSide < 2; iSide++ ) { // loop on 2 sides
9941         // analyse link orientation in faces
9942         int i1 = iLinkNode[ iSide ][ 0 ];
9943         int i2 = iLinkNode[ iSide ][ 1 ];
9944         reverse[ iSide ] = Abs( i1 - i2 ) == 1 ? i1 > i2 : i2 > i1;
9945       }
9946       int di1 = reverse[0] ? -1 : +1, i1 = iLinkNode[0][1] + di1;
9947       int di2 = reverse[1] ? -1 : +1, i2 = iLinkNode[1][1] + di2;
9948       for ( int i = nbNodes - 2; i > 0; --i, i1 += di1, i2 += di2 )
9949       {
9950         nReplaceMap.insert  ( make_pair ( fnodes[0][ ( i1 + nbNodes ) % nbNodes ],
9951                                           fnodes[1][ ( i2 + nbNodes ) % nbNodes ]));
9952       }
9953
9954       // add other links of the faces to linkList
9955       // -----------------------------------------
9956
9957       for ( iNode = 0; iNode < nbNodes; iNode++ )  {
9958         linkID = aLinkID_Gen.GetLinkID( fnodes[0][iNode], fnodes[0][iNode+1] );
9959         pair< set<long>::iterator, bool > iter_isnew = linkIdSet.insert( linkID );
9960         if ( !iter_isnew.second ) { // already in a set: no need to process
9961           linkIdSet.erase( iter_isnew.first );
9962         }
9963         else // new in set == encountered for the first time: add
9964         {
9965           const SMDS_MeshNode* n1 = fnodes[0][ iNode ];
9966           const SMDS_MeshNode* n2 = fnodes[0][ iNode + 1];
9967           linkList[0].push_back ( NLink( n1, n2 ));
9968           linkList[1].push_back ( NLink( nReplaceMap[n1], nReplaceMap[n2] ));
9969         }
9970       }
9971     } // 2 faces found
9972
9973     if ( faceSetPtr[0]->empty() || faceSetPtr[1]->empty() )
9974       break;
9975
9976   } // loop on link lists
9977
9978   if ( aResult == SEW_OK &&
9979        ( //linkIt[0] != linkList[0].end() ||
9980          !faceSetPtr[0]->empty() || !faceSetPtr[1]->empty() )) {
9981     MESSAGE( (linkIt[0] != linkList[0].end()) <<" "<< (faceSetPtr[0]->empty()) <<
9982              " " << (faceSetPtr[1]->empty()));
9983     aResult = SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
9984   }
9985
9986   // ====================================================================
9987   // 3. Replace nodes in elements of the side 1 and remove replaced nodes
9988   // ====================================================================
9989
9990   // delete temporary faces
9991 //  SMDS_FaceIteratorPtr tmpFaceIt = aTmpFacesMesh.facesIterator();
9992 //  while ( tmpFaceIt->more() )
9993 //    aTmpFacesMesh.RemoveElement( tmpFaceIt->next() );
9994   list<const SMDS_MeshElement* >::iterator tmpFaceIt = tempFaceList.begin();
9995   for (; tmpFaceIt !=tempFaceList.end(); ++tmpFaceIt)
9996     aMesh->RemoveElement(*tmpFaceIt);
9997
9998   if ( aResult != SEW_OK)
9999     return aResult;
10000
10001   list< int > nodeIDsToRemove/*, elemIDsToRemove*/;
10002   // loop on nodes replacement map
10003   TNodeNodeMap::iterator nReplaceMapIt = nReplaceMap.begin(), nnIt;
10004   for ( ; nReplaceMapIt != nReplaceMap.end(); nReplaceMapIt++ )
10005     if ( (*nReplaceMapIt).first != (*nReplaceMapIt).second ) {
10006       const SMDS_MeshNode* nToRemove = (*nReplaceMapIt).first;
10007       nodeIDsToRemove.push_back( nToRemove->GetID() );
10008       // loop on elements sharing nToRemove
10009       SMDS_ElemIteratorPtr invElemIt = nToRemove->GetInverseElementIterator();
10010       while ( invElemIt->more() ) {
10011         const SMDS_MeshElement* e = invElemIt->next();
10012         // get a new suite of nodes: make replacement
10013         int nbReplaced = 0, i = 0, nbNodes = e->NbNodes();
10014         vector< const SMDS_MeshNode*> nodes( nbNodes );
10015         SMDS_ElemIteratorPtr nIt = e->nodesIterator();
10016         while ( nIt->more() ) {
10017           const SMDS_MeshNode* n =
10018             static_cast<const SMDS_MeshNode*>( nIt->next() );
10019           nnIt = nReplaceMap.find( n );
10020           if ( nnIt != nReplaceMap.end() ) {
10021             nbReplaced++;
10022             n = (*nnIt).second;
10023           }
10024           nodes[ i++ ] = n;
10025         }
10026         //       if ( nbReplaced == nbNodes && e->GetType() == SMDSAbs_Face )
10027         //         elemIDsToRemove.push_back( e->GetID() );
10028         //       else
10029         if ( nbReplaced )
10030           {
10031             SMDSAbs_ElementType etyp = e->GetType();
10032             SMDS_MeshElement* newElem = this->AddElement(nodes, etyp, false);
10033             if (newElem)
10034               {
10035                 myLastCreatedElems.Append(newElem);
10036                 AddToSameGroups(newElem, e, aMesh);
10037                 int aShapeId = e->getshapeId();
10038                 if ( aShapeId )
10039                   {
10040                     aMesh->SetMeshElementOnShape( newElem, aShapeId );
10041                   }
10042               }
10043             aMesh->RemoveElement(e);
10044           }
10045       }
10046     }
10047
10048   Remove( nodeIDsToRemove, true );
10049
10050   return aResult;
10051 }
10052
10053 //================================================================================
10054 /*!
10055  * \brief Find corresponding nodes in two sets of faces
10056  * \param theSide1 - first face set
10057  * \param theSide2 - second first face
10058  * \param theFirstNode1 - a boundary node of set 1
10059  * \param theFirstNode2 - a node of set 2 corresponding to theFirstNode1
10060  * \param theSecondNode1 - a boundary node of set 1 linked with theFirstNode1
10061  * \param theSecondNode2 - a node of set 2 corresponding to theSecondNode1
10062  * \param nReplaceMap - output map of corresponding nodes
10063  * \return bool  - is a success or not
10064  */
10065 //================================================================================
10066
10067 #ifdef _DEBUG_
10068 //#define DEBUG_MATCHING_NODES
10069 #endif
10070
10071 SMESH_MeshEditor::Sew_Error
10072 SMESH_MeshEditor::FindMatchingNodes(set<const SMDS_MeshElement*>& theSide1,
10073                                     set<const SMDS_MeshElement*>& theSide2,
10074                                     const SMDS_MeshNode*          theFirstNode1,
10075                                     const SMDS_MeshNode*          theFirstNode2,
10076                                     const SMDS_MeshNode*          theSecondNode1,
10077                                     const SMDS_MeshNode*          theSecondNode2,
10078                                     TNodeNodeMap &                nReplaceMap)
10079 {
10080   set<const SMDS_MeshElement*> * faceSetPtr[] = { &theSide1, &theSide2 };
10081
10082   nReplaceMap.clear();
10083   if ( theFirstNode1 != theFirstNode2 )
10084     nReplaceMap.insert( make_pair( theFirstNode1, theFirstNode2 ));
10085   if ( theSecondNode1 != theSecondNode2 )
10086     nReplaceMap.insert( make_pair( theSecondNode1, theSecondNode2 ));
10087
10088   set< SMESH_TLink > linkSet; // set of nodes where order of nodes is ignored
10089   linkSet.insert( SMESH_TLink( theFirstNode1, theSecondNode1 ));
10090
10091   list< NLink > linkList[2];
10092   linkList[0].push_back( NLink( theFirstNode1, theSecondNode1 ));
10093   linkList[1].push_back( NLink( theFirstNode2, theSecondNode2 ));
10094
10095   // loop on links in linkList; find faces by links and append links
10096   // of the found faces to linkList
10097   list< NLink >::iterator linkIt[] = { linkList[0].begin(), linkList[1].begin() } ;
10098   for ( ; linkIt[0] != linkList[0].end(); linkIt[0]++, linkIt[1]++ ) {
10099     NLink link[] = { *linkIt[0], *linkIt[1] };
10100     if ( linkSet.find( link[0] ) == linkSet.end() )
10101       continue;
10102
10103     // by links, find faces in the face sets,
10104     // and find indices of link nodes in the found faces;
10105     // in a face set, there is only one or no face sharing a link
10106     // ---------------------------------------------------------------
10107
10108     const SMDS_MeshElement* face[] = { 0, 0 };
10109     list<const SMDS_MeshNode*> notLinkNodes[2];
10110     //bool reverse[] = { false, false }; // order of notLinkNodes
10111     int nbNodes[2];
10112     for ( int iSide = 0; iSide < 2; iSide++ ) // loop on 2 sides
10113     {
10114       const SMDS_MeshNode* n1 = link[iSide].first;
10115       const SMDS_MeshNode* n2 = link[iSide].second;
10116       set<const SMDS_MeshElement*> * faceSet = faceSetPtr[ iSide ];
10117       set< const SMDS_MeshElement* > facesOfNode1;
10118       for ( int iNode = 0; iNode < 2; iNode++ ) // loop on 2 nodes of a link
10119       {
10120         // during a loop of the first node, we find all faces around n1,
10121         // during a loop of the second node, we find one face sharing both n1 and n2
10122         const SMDS_MeshNode* n = iNode ? n1 : n2; // a node of a link
10123         SMDS_ElemIteratorPtr fIt = n->GetInverseElementIterator(SMDSAbs_Face);
10124         while ( fIt->more() ) { // loop on faces sharing a node
10125           const SMDS_MeshElement* f = fIt->next();
10126           if (faceSet->find( f ) != faceSet->end() && // f is in face set
10127               ! facesOfNode1.insert( f ).second ) // f encounters twice
10128           {
10129             if ( face[ iSide ] ) {
10130               MESSAGE( "2 faces per link " );
10131               return ( iSide ? SEW_BAD_SIDE2_NODES : SEW_BAD_SIDE1_NODES );
10132             }
10133             face[ iSide ] = f;
10134             faceSet->erase( f );
10135
10136             // get not link nodes
10137             int nbN = f->NbNodes();
10138             if ( f->IsQuadratic() )
10139               nbN /= 2;
10140             nbNodes[ iSide ] = nbN;
10141             list< const SMDS_MeshNode* > & nodes = notLinkNodes[ iSide ];
10142             int i1 = f->GetNodeIndex( n1 );
10143             int i2 = f->GetNodeIndex( n2 );
10144             int iEnd = nbN, iBeg = -1, iDelta = 1;
10145             bool reverse = ( Abs( i1 - i2 ) == 1 ? i1 > i2 : i2 > i1 );
10146             if ( reverse ) {
10147               std::swap( iEnd, iBeg ); iDelta = -1;
10148             }
10149             int i = i2;
10150             while ( true ) {
10151               i += iDelta;
10152               if ( i == iEnd ) i = iBeg + iDelta;
10153               if ( i == i1 ) break;
10154               nodes.push_back ( f->GetNode( i ) );
10155             }
10156           }
10157         }
10158       }
10159     }
10160     // check similarity of elements of the sides
10161     if (( face[0] && !face[1] ) || ( !face[0] && face[1] )) {
10162       MESSAGE("Correspondent face not found on side " << ( face[0] ? 1 : 0 ));
10163       if ( nReplaceMap.size() == 2 ) { // faces on input nodes not found
10164         return ( face[0] ? SEW_BAD_SIDE2_NODES : SEW_BAD_SIDE1_NODES );
10165       }
10166       else {
10167         return SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
10168       }
10169     }
10170
10171     // set nodes to merge
10172     // -------------------
10173
10174     if ( face[0] && face[1] )  {
10175       if ( nbNodes[0] != nbNodes[1] ) {
10176         MESSAGE("Diff nb of face nodes");
10177         return SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
10178       }
10179 #ifdef DEBUG_MATCHING_NODES
10180       MESSAGE ( " Link 1: " << link[0].first->GetID() <<" "<< link[0].second->GetID()
10181                 << " F 1: " << face[0] << "| Link 2: " << link[1].first->GetID() <<" "
10182                 << link[1].second->GetID() << " F 2: " << face[1] << " | Bind: " ) ;
10183 #endif
10184       int nbN = nbNodes[0];
10185       {
10186         list<const SMDS_MeshNode*>::iterator n1 = notLinkNodes[0].begin();
10187         list<const SMDS_MeshNode*>::iterator n2 = notLinkNodes[1].begin();
10188         for ( int i = 0 ; i < nbN - 2; ++i ) {
10189 #ifdef DEBUG_MATCHING_NODES
10190           MESSAGE ( (*n1)->GetID() << " to " << (*n2)->GetID() );
10191 #endif
10192           nReplaceMap.insert( make_pair( *(n1++), *(n2++) ));
10193         }
10194       }
10195
10196       // add other links of the face 1 to linkList
10197       // -----------------------------------------
10198
10199       const SMDS_MeshElement* f0 = face[0];
10200       const SMDS_MeshNode* n1 = f0->GetNode( nbN - 1 );
10201       for ( int i = 0; i < nbN; i++ )
10202       {
10203         const SMDS_MeshNode* n2 = f0->GetNode( i );
10204         pair< set< SMESH_TLink >::iterator, bool > iter_isnew =
10205           linkSet.insert( SMESH_TLink( n1, n2 ));
10206         if ( !iter_isnew.second ) { // already in a set: no need to process
10207           linkSet.erase( iter_isnew.first );
10208         }
10209         else // new in set == encountered for the first time: add
10210         {
10211 #ifdef DEBUG_MATCHING_NODES
10212           MESSAGE ( "Add link 1: " << n1->GetID() << " " << n2->GetID() << " "
10213                     << " | link 2: " << nReplaceMap[n1]->GetID() << " " << nReplaceMap[n2]->GetID() << " " );
10214 #endif
10215           linkList[0].push_back ( NLink( n1, n2 ));
10216           linkList[1].push_back ( NLink( nReplaceMap[n1], nReplaceMap[n2] ));
10217         }
10218         n1 = n2;
10219       }
10220     } // 2 faces found
10221   } // loop on link lists
10222
10223   return SEW_OK;
10224 }
10225
10226 //================================================================================
10227 /*!
10228   \brief Creates a hole in a mesh by doubling the nodes of some particular elements
10229   \param theElems - the list of elements (edges or faces) to be replicated
10230   The nodes for duplication could be found from these elements
10231   \param theNodesNot - list of nodes to NOT replicate
10232   \param theAffectedElems - the list of elements (cells and edges) to which the 
10233   replicated nodes should be associated to.
10234   \return TRUE if operation has been completed successfully, FALSE otherwise
10235 */
10236 //================================================================================
10237
10238 bool SMESH_MeshEditor::DoubleNodes( const TIDSortedElemSet& theElems,
10239                                     const TIDSortedElemSet& theNodesNot,
10240                                     const TIDSortedElemSet& theAffectedElems )
10241 {
10242   myLastCreatedElems.Clear();
10243   myLastCreatedNodes.Clear();
10244
10245   if ( theElems.size() == 0 )
10246     return false;
10247
10248   SMESHDS_Mesh* aMeshDS = GetMeshDS();
10249   if ( !aMeshDS )
10250     return false;
10251
10252   bool res = false;
10253   std::map< const SMDS_MeshNode*, const SMDS_MeshNode* > anOldNodeToNewNode;
10254   // duplicate elements and nodes
10255   res = doubleNodes( aMeshDS, theElems, theNodesNot, anOldNodeToNewNode, true );
10256   // replce nodes by duplications
10257   res = doubleNodes( aMeshDS, theAffectedElems, theNodesNot, anOldNodeToNewNode, false );
10258   return res;
10259 }
10260
10261 //================================================================================
10262 /*!
10263   \brief Creates a hole in a mesh by doubling the nodes of some particular elements
10264   \param theMeshDS - mesh instance
10265   \param theElems - the elements replicated or modified (nodes should be changed)
10266   \param theNodesNot - nodes to NOT replicate
10267   \param theNodeNodeMap - relation of old node to new created node
10268   \param theIsDoubleElem - flag os to replicate element or modify
10269   \return TRUE if operation has been completed successfully, FALSE otherwise
10270 */
10271 //================================================================================
10272
10273 bool SMESH_MeshEditor::doubleNodes( SMESHDS_Mesh*     theMeshDS,
10274                                     const TIDSortedElemSet& theElems,
10275                                     const TIDSortedElemSet& theNodesNot,
10276                                     std::map< const SMDS_MeshNode*,
10277                                     const SMDS_MeshNode* >& theNodeNodeMap,
10278                                     const bool theIsDoubleElem )
10279 {
10280   MESSAGE("doubleNodes");
10281   // iterate on through element and duplicate them (by nodes duplication)
10282   bool res = false;
10283   TIDSortedElemSet::const_iterator elemItr = theElems.begin();
10284   for ( ;  elemItr != theElems.end(); ++elemItr )
10285   {
10286     const SMDS_MeshElement* anElem = *elemItr;
10287     if (!anElem)
10288       continue;
10289
10290     bool isDuplicate = false;
10291     // duplicate nodes to duplicate element
10292     std::vector<const SMDS_MeshNode*> newNodes( anElem->NbNodes() );
10293     SMDS_ElemIteratorPtr anIter = anElem->nodesIterator();
10294     int ind = 0;
10295     while ( anIter->more() ) 
10296     { 
10297
10298       SMDS_MeshNode* aCurrNode = (SMDS_MeshNode*)anIter->next();
10299       SMDS_MeshNode* aNewNode = aCurrNode;
10300       if ( theNodeNodeMap.find( aCurrNode ) != theNodeNodeMap.end() )
10301         aNewNode = (SMDS_MeshNode*)theNodeNodeMap[ aCurrNode ];
10302       else if ( theIsDoubleElem && theNodesNot.find( aCurrNode ) == theNodesNot.end() )
10303       {
10304         // duplicate node
10305         aNewNode = theMeshDS->AddNode( aCurrNode->X(), aCurrNode->Y(), aCurrNode->Z() );
10306         theNodeNodeMap[ aCurrNode ] = aNewNode;
10307         myLastCreatedNodes.Append( aNewNode );
10308       }
10309       isDuplicate |= (aCurrNode != aNewNode);
10310       newNodes[ ind++ ] = aNewNode;
10311     }
10312     if ( !isDuplicate )
10313       continue;
10314
10315     if ( theIsDoubleElem )
10316       AddElement(newNodes, anElem->GetType(), anElem->IsPoly());
10317     else
10318       {
10319       MESSAGE("ChangeElementNodes");
10320       theMeshDS->ChangeElementNodes( anElem, &newNodes[ 0 ], anElem->NbNodes() );
10321       }
10322     res = true;
10323   }
10324   return res;
10325 }
10326
10327 //================================================================================
10328 /*!
10329   \brief Creates a hole in a mesh by doubling the nodes of some particular elements
10330   \param theNodes - identifiers of nodes to be doubled
10331   \param theModifiedElems - identifiers of elements to be updated by the new (doubled) 
10332          nodes. If list of element identifiers is empty then nodes are doubled but 
10333          they not assigned to elements
10334   \return TRUE if operation has been completed successfully, FALSE otherwise
10335 */
10336 //================================================================================
10337
10338 bool SMESH_MeshEditor::DoubleNodes( const std::list< int >& theListOfNodes, 
10339                                     const std::list< int >& theListOfModifiedElems )
10340 {
10341   MESSAGE("DoubleNodes");
10342   myLastCreatedElems.Clear();
10343   myLastCreatedNodes.Clear();
10344
10345   if ( theListOfNodes.size() == 0 )
10346     return false;
10347
10348   SMESHDS_Mesh* aMeshDS = GetMeshDS();
10349   if ( !aMeshDS )
10350     return false;
10351
10352   // iterate through nodes and duplicate them
10353
10354   std::map< const SMDS_MeshNode*, const SMDS_MeshNode* > anOldNodeToNewNode;
10355
10356   std::list< int >::const_iterator aNodeIter;
10357   for ( aNodeIter = theListOfNodes.begin(); aNodeIter != theListOfNodes.end(); ++aNodeIter )
10358   {
10359     int aCurr = *aNodeIter;
10360     SMDS_MeshNode* aNode = (SMDS_MeshNode*)aMeshDS->FindNode( aCurr );
10361     if ( !aNode )
10362       continue;
10363
10364     // duplicate node
10365
10366     const SMDS_MeshNode* aNewNode = aMeshDS->AddNode( aNode->X(), aNode->Y(), aNode->Z() );
10367     if ( aNewNode )
10368     {
10369       anOldNodeToNewNode[ aNode ] = aNewNode;
10370       myLastCreatedNodes.Append( aNewNode );
10371     }
10372   }
10373
10374   // Create map of new nodes for modified elements
10375
10376   std::map< SMDS_MeshElement*, vector<const SMDS_MeshNode*> > anElemToNodes;
10377
10378   std::list< int >::const_iterator anElemIter;
10379   for ( anElemIter = theListOfModifiedElems.begin(); 
10380         anElemIter != theListOfModifiedElems.end(); ++anElemIter )
10381   {
10382     int aCurr = *anElemIter;
10383     SMDS_MeshElement* anElem = (SMDS_MeshElement*)aMeshDS->FindElement( aCurr );
10384     if ( !anElem )
10385       continue;
10386
10387     vector<const SMDS_MeshNode*> aNodeArr( anElem->NbNodes() );
10388
10389     SMDS_ElemIteratorPtr anIter = anElem->nodesIterator();
10390     int ind = 0;
10391     while ( anIter->more() ) 
10392     { 
10393       SMDS_MeshNode* aCurrNode = (SMDS_MeshNode*)anIter->next();
10394       if ( aCurr && anOldNodeToNewNode.find( aCurrNode ) != anOldNodeToNewNode.end() )
10395       {
10396         const SMDS_MeshNode* aNewNode = anOldNodeToNewNode[ aCurrNode ];
10397         aNodeArr[ ind++ ] = aNewNode;
10398       }
10399       else
10400         aNodeArr[ ind++ ] = aCurrNode;
10401     }
10402     anElemToNodes[ anElem ] = aNodeArr;
10403   }
10404
10405   // Change nodes of elements  
10406
10407   std::map< SMDS_MeshElement*, vector<const SMDS_MeshNode*> >::iterator
10408     anElemToNodesIter = anElemToNodes.begin();
10409   for ( ; anElemToNodesIter != anElemToNodes.end(); ++anElemToNodesIter )
10410   {
10411     const SMDS_MeshElement* anElem = anElemToNodesIter->first;
10412     vector<const SMDS_MeshNode*> aNodeArr = anElemToNodesIter->second;
10413     if ( anElem )
10414       {
10415       MESSAGE("ChangeElementNodes");
10416       aMeshDS->ChangeElementNodes( anElem, &aNodeArr[ 0 ], anElem->NbNodes() );
10417       }
10418   }
10419
10420   return true;
10421 }
10422
10423 namespace {
10424
10425   //================================================================================
10426   /*!
10427   \brief Check if element located inside shape
10428   \return TRUE if IN or ON shape, FALSE otherwise
10429   */
10430   //================================================================================
10431
10432   template<class Classifier>
10433   bool isInside(const SMDS_MeshElement* theElem,
10434                 Classifier&             theClassifier,
10435                 const double            theTol)
10436   {
10437     gp_XYZ centerXYZ (0, 0, 0);
10438     SMDS_ElemIteratorPtr aNodeItr = theElem->nodesIterator();
10439     while (aNodeItr->more())
10440       centerXYZ += SMESH_TNodeXYZ(cast2Node( aNodeItr->next()));
10441
10442     gp_Pnt aPnt = centerXYZ / theElem->NbNodes();
10443     theClassifier.Perform(aPnt, theTol);
10444     TopAbs_State aState = theClassifier.State();
10445     return (aState == TopAbs_IN || aState == TopAbs_ON );
10446   }
10447
10448   //================================================================================
10449   /*!
10450    * \brief Classifier of the 3D point on the TopoDS_Face
10451    *        with interaface suitable for isInside()
10452    */
10453   //================================================================================
10454
10455   struct _FaceClassifier
10456   {
10457     Extrema_ExtPS       _extremum;
10458     BRepAdaptor_Surface _surface;
10459     TopAbs_State        _state;
10460
10461     _FaceClassifier(const TopoDS_Face& face):_extremum(),_surface(face),_state(TopAbs_OUT)
10462     {
10463       _extremum.Initialize( _surface,
10464                             _surface.FirstUParameter(), _surface.LastUParameter(),
10465                             _surface.FirstVParameter(), _surface.LastVParameter(),
10466                             _surface.Tolerance(), _surface.Tolerance() );
10467     }
10468     void Perform(const gp_Pnt& aPnt, double theTol)
10469     {
10470       _state = TopAbs_OUT;
10471       _extremum.Perform(aPnt);
10472       if ( _extremum.IsDone() )
10473         for ( int iSol = 1; iSol <= _extremum.NbExt() && _state == TopAbs_OUT; ++iSol)
10474 #if OCC_VERSION_LARGE > 0x06040000 // Porting to OCCT6.5.1
10475           _state = ( _extremum.SquareDistance(iSol) <= theTol ? TopAbs_IN : TopAbs_OUT );
10476 #else
10477           _state = ( _extremum.Value(iSol) <= theTol ? TopAbs_IN : TopAbs_OUT );
10478 #endif
10479     }
10480     TopAbs_State State() const
10481     {
10482       return _state;
10483     }
10484   };
10485 }
10486
10487 //================================================================================
10488 /*!
10489   \brief Creates a hole in a mesh by doubling the nodes of some particular elements
10490   \param theElems - group of of elements (edges or faces) to be replicated
10491   \param theNodesNot - group of nodes not to replicate
10492   \param theShape - shape to detect affected elements (element which geometric center
10493   located on or inside shape).
10494   The replicated nodes should be associated to affected elements.
10495   \return TRUE if operation has been completed successfully, FALSE otherwise
10496 */
10497 //================================================================================
10498
10499 bool SMESH_MeshEditor::DoubleNodesInRegion( const TIDSortedElemSet& theElems,
10500                                             const TIDSortedElemSet& theNodesNot,
10501                                             const TopoDS_Shape&     theShape )
10502 {
10503   if ( theShape.IsNull() )
10504     return false;
10505
10506   const double aTol = Precision::Confusion();
10507   auto_ptr< BRepClass3d_SolidClassifier> bsc3d;
10508   auto_ptr<_FaceClassifier>              aFaceClassifier;
10509   if ( theShape.ShapeType() == TopAbs_SOLID )
10510   {
10511     bsc3d.reset( new BRepClass3d_SolidClassifier(theShape));;
10512     bsc3d->PerformInfinitePoint(aTol);
10513   }
10514   else if (theShape.ShapeType() == TopAbs_FACE )
10515   {
10516     aFaceClassifier.reset( new _FaceClassifier(TopoDS::Face(theShape)));
10517   }
10518
10519   // iterates on indicated elements and get elements by back references from their nodes
10520   TIDSortedElemSet anAffected;
10521   TIDSortedElemSet::const_iterator elemItr = theElems.begin();
10522   for ( ;  elemItr != theElems.end(); ++elemItr )
10523   {
10524     SMDS_MeshElement* anElem = (SMDS_MeshElement*)*elemItr;
10525     if (!anElem)
10526       continue;
10527
10528     SMDS_ElemIteratorPtr nodeItr = anElem->nodesIterator();
10529     while ( nodeItr->more() )
10530     {
10531       const SMDS_MeshNode* aNode = cast2Node(nodeItr->next());
10532       if ( !aNode || theNodesNot.find(aNode) != theNodesNot.end() )
10533         continue;
10534       SMDS_ElemIteratorPtr backElemItr = aNode->GetInverseElementIterator();
10535       while ( backElemItr->more() )
10536       {
10537         const SMDS_MeshElement* curElem = backElemItr->next();
10538         if ( curElem && theElems.find(curElem) == theElems.end() &&
10539              ( bsc3d.get() ?
10540                isInside( curElem, *bsc3d, aTol ) :
10541                isInside( curElem, *aFaceClassifier, aTol )))
10542           anAffected.insert( curElem );
10543       }
10544     }
10545   }
10546   return DoubleNodes( theElems, theNodesNot, anAffected );
10547 }
10548
10549 /*!
10550  *  \brief compute an oriented angle between two planes defined by four points.
10551  *  The vector (p0,p1) defines the intersection of the 2 planes (p0,p1,g1) and (p0,p1,g2)
10552  *  @param p0 base of the rotation axe
10553  *  @param p1 extremity of the rotation axe
10554  *  @param g1 belongs to the first plane
10555  *  @param g2 belongs to the second plane
10556  */
10557 double SMESH_MeshEditor::OrientedAngle(const gp_Pnt& p0, const gp_Pnt& p1, const gp_Pnt& g1, const gp_Pnt& g2)
10558 {
10559 //  MESSAGE("    p0: " << p0.X() << " " << p0.Y() << " " << p0.Z());
10560 //  MESSAGE("    p1: " << p1.X() << " " << p1.Y() << " " << p1.Z());
10561 //  MESSAGE("    g1: " << g1.X() << " " << g1.Y() << " " << g1.Z());
10562 //  MESSAGE("    g2: " << g2.X() << " " << g2.Y() << " " << g2.Z());
10563   gp_Vec vref(p0, p1);
10564   gp_Vec v1(p0, g1);
10565   gp_Vec v2(p0, g2);
10566   gp_Vec n1 = vref.Crossed(v1);
10567   gp_Vec n2 = vref.Crossed(v2);
10568   return n2.AngleWithRef(n1, vref);
10569 }
10570
10571 /*!
10572  * \brief Double nodes on shared faces between groups of volumes and create flat elements on demand.
10573  * The list of groups must describe a partition of the mesh volumes.
10574  * The nodes of the internal faces at the boundaries of the groups are doubled.
10575  * In option, the internal faces are replaced by flat elements.
10576  * Triangles are transformed in prisms, and quadrangles in hexahedrons.
10577  * The flat elements are stored in groups of volumes.
10578  * @param theElems - list of groups of volumes, where a group of volume is a set of
10579  * SMDS_MeshElements sorted by Id.
10580  * @param createJointElems - if TRUE, create the elements
10581  * @return TRUE if operation has been completed successfully, FALSE otherwise
10582  */
10583 bool SMESH_MeshEditor::DoubleNodesOnGroupBoundaries( const std::vector<TIDSortedElemSet>& theElems,
10584                                                      bool createJointElems)
10585 {
10586   MESSAGE("----------------------------------------------");
10587   MESSAGE("SMESH_MeshEditor::doubleNodesOnGroupBoundaries");
10588   MESSAGE("----------------------------------------------");
10589
10590   SMESHDS_Mesh *meshDS = this->myMesh->GetMeshDS();
10591   meshDS->BuildDownWardConnectivity(true);
10592   CHRONO(50);
10593   SMDS_UnstructuredGrid *grid = meshDS->getGrid();
10594
10595   // --- build the list of faces shared by 2 domains (group of elements), with their domain and volume indexes
10596   //     build the list of cells with only a node or an edge on the border, with their domain and volume indexes
10597   //     build the list of nodes shared by 2 or more domains, with their domain indexes
10598
10599   std::map<DownIdType, std::map<int,int>, DownIdCompare> faceDomains; // face --> (id domain --> id volume)
10600   std::map<int,int>celldom; // cell vtkId --> domain
10601   std::map<DownIdType, std::map<int,int>, DownIdCompare> cellDomains;  // oldNode --> (id domain --> id cell)
10602   std::map<int, std::map<int,int> > nodeDomains; // oldId -->  (domainId --> newId)
10603   faceDomains.clear();
10604   celldom.clear();
10605   cellDomains.clear();
10606   nodeDomains.clear();
10607   std::map<int,int> emptyMap;
10608   std::set<int> emptySet;
10609   emptyMap.clear();
10610
10611   for (int idom = 0; idom < theElems.size(); idom++)
10612     {
10613
10614       // --- build a map (face to duplicate --> volume to modify)
10615       //     with all the faces shared by 2 domains (group of elements)
10616       //     and corresponding volume of this domain, for each shared face.
10617       //     a volume has a face shared by 2 domains if it has a neighbor which is not in is domain.
10618
10619       //MESSAGE("Domain " << idom);
10620       const TIDSortedElemSet& domain = theElems[idom];
10621       TIDSortedElemSet::const_iterator elemItr = domain.begin();
10622       for (; elemItr != domain.end(); ++elemItr)
10623         {
10624           SMDS_MeshElement* anElem = (SMDS_MeshElement*) *elemItr;
10625           if (!anElem)
10626             continue;
10627           int vtkId = anElem->getVtkId();
10628           //MESSAGE("  vtkId " << vtkId << " smdsId " << anElem->GetID());
10629           int neighborsVtkIds[NBMAXNEIGHBORS];
10630           int downIds[NBMAXNEIGHBORS];
10631           unsigned char downTypes[NBMAXNEIGHBORS];
10632           int nbNeighbors = grid->GetNeighbors(neighborsVtkIds, downIds, downTypes, vtkId);
10633           for (int n = 0; n < nbNeighbors; n++)
10634             {
10635               int smdsId = meshDS->fromVtkToSmds(neighborsVtkIds[n]);
10636               const SMDS_MeshElement* elem = meshDS->FindElement(smdsId);
10637               if (! domain.count(elem)) // neighbor is in another domain : face is shared
10638                 {
10639                   DownIdType face(downIds[n], downTypes[n]);
10640                   if (!faceDomains.count(face))
10641                     faceDomains[face] = emptyMap; // create an empty entry for face
10642                   if (!faceDomains[face].count(idom))
10643                     {
10644                       faceDomains[face][idom] = vtkId; // volume associated to face in this domain
10645                       celldom[vtkId] = idom;
10646                       //MESSAGE("       cell with a border " << vtkId << " domain " << idom);
10647                     }
10648                 }
10649             }
10650         }
10651     }
10652
10653   //MESSAGE("Number of shared faces " << faceDomains.size());
10654   std::map<DownIdType, std::map<int, int>, DownIdCompare>::iterator itface;
10655
10656   // --- explore the shared faces domain by domain,
10657   //     explore the nodes of the face and see if they belong to a cell in the domain,
10658   //     which has only a node or an edge on the border (not a shared face)
10659
10660   for (int idomain = 0; idomain < theElems.size(); idomain++)
10661     {
10662       //MESSAGE("Domain " << idomain);
10663       const TIDSortedElemSet& domain = theElems[idomain];
10664       itface = faceDomains.begin();
10665       for (; itface != faceDomains.end(); ++itface)
10666         {
10667           std::map<int, int> domvol = itface->second;
10668           if (!domvol.count(idomain))
10669             continue;
10670           DownIdType face = itface->first;
10671           //MESSAGE(" --- face " << face.cellId);
10672           std::set<int> oldNodes;
10673           oldNodes.clear();
10674           grid->GetNodeIds(oldNodes, face.cellId, face.cellType);
10675           std::set<int>::iterator itn = oldNodes.begin();
10676           for (; itn != oldNodes.end(); ++itn)
10677             {
10678               int oldId = *itn;
10679               //MESSAGE("     node " << oldId);
10680               std::set<int> cells;
10681               cells.clear();
10682               vtkCellLinks::Link l = grid->GetCellLinks()->GetLink(oldId);
10683               for (int i=0; i<l.ncells; i++)
10684                 {
10685                   int vtkId = l.cells[i];
10686                   const SMDS_MeshElement* anElem = GetMeshDS()->FindElement(GetMeshDS()->fromVtkToSmds(vtkId));
10687                   if (!domain.count(anElem))
10688                     continue;
10689                   int vtkType = grid->GetCellType(vtkId);
10690                   int downId = grid->CellIdToDownId(vtkId);
10691                   if (downId < 0)
10692                     {
10693                       MESSAGE("doubleNodesOnGroupBoundaries: internal algorithm problem");
10694                       continue; // not OK at this stage of the algorithm:
10695                                 //no cells created after BuildDownWardConnectivity
10696                     }
10697                   DownIdType aCell(downId, vtkType);
10698                   if (celldom.count(vtkId))
10699                     continue;
10700                   cellDomains[aCell][idomain] = vtkId;
10701                   celldom[vtkId] = idomain;
10702                   //MESSAGE("       cell " << vtkId << " domain " << idomain);
10703                 }
10704             }
10705         }
10706     }
10707
10708   // --- explore the shared faces domain by domain, to duplicate the nodes in a coherent way
10709   //     for each shared face, get the nodes
10710   //     for each node, for each domain of the face, create a clone of the node
10711
10712   // --- edges at the intersection of 3 or 4 domains, with the order of domains to build
10713   //     junction elements of type prism or hexa. the key is the pair of nodesId (lower first)
10714   //     the value is the ordered domain ids. (more than 4 domains not taken into account)
10715
10716   std::map<std::vector<int>, std::vector<int> > edgesMultiDomains; // nodes of edge --> ordered domains
10717   std::map<int, std::vector<int> > mutipleNodes; // nodes multi domains with domain order
10718   std::map<int, std::vector<int> > mutipleNodesToFace; // nodes multi domains with domain order to transform in Face (junction between 3 or more 2D domains)
10719
10720   for (int idomain = 0; idomain < theElems.size(); idomain++)
10721     {
10722       itface = faceDomains.begin();
10723       for (; itface != faceDomains.end(); ++itface)
10724         {
10725           std::map<int, int> domvol = itface->second;
10726           if (!domvol.count(idomain))
10727             continue;
10728           DownIdType face = itface->first;
10729           //MESSAGE(" --- face " << face.cellId);
10730           std::set<int> oldNodes;
10731           oldNodes.clear();
10732           grid->GetNodeIds(oldNodes, face.cellId, face.cellType);
10733           bool isMultipleDetected = false;
10734           std::set<int>::iterator itn = oldNodes.begin();
10735           for (; itn != oldNodes.end(); ++itn)
10736             {
10737               int oldId = *itn;
10738               //MESSAGE("     node " << oldId);
10739               if (!nodeDomains.count(oldId))
10740                 nodeDomains[oldId] = emptyMap; // create an empty entry for node
10741               if (nodeDomains[oldId].empty())
10742                 nodeDomains[oldId][idomain] = oldId; // keep the old node in the first domain
10743               std::map<int, int>::iterator itdom = domvol.begin();
10744               for (; itdom != domvol.end(); ++itdom)
10745                 {
10746                   int idom = itdom->first;
10747                   //MESSAGE("         domain " << idom);
10748                   if (!nodeDomains[oldId].count(idom)) // --- node to clone
10749                     {
10750                       if (nodeDomains[oldId].size() >= 2) // a multiple node
10751                         {
10752                           vector<int> orderedDoms;
10753                           //MESSAGE("multiple node " << oldId);
10754                           isMultipleDetected =true;
10755                           if (mutipleNodes.count(oldId))
10756                             orderedDoms = mutipleNodes[oldId];
10757                           else
10758                             {
10759                               map<int,int>::iterator it = nodeDomains[oldId].begin();
10760                               for (; it != nodeDomains[oldId].end(); ++it)
10761                                 orderedDoms.push_back(it->first);
10762                             }
10763                           orderedDoms.push_back(idom); // TODO order ==> push_front or back
10764                           //stringstream txt;
10765                           //for (int i=0; i<orderedDoms.size(); i++)
10766                           //  txt << orderedDoms[i] << " ";
10767                           //MESSAGE("orderedDoms " << txt.str());
10768                           mutipleNodes[oldId] = orderedDoms;
10769                         }
10770                       double *coords = grid->GetPoint(oldId);
10771                       SMDS_MeshNode *newNode = meshDS->AddNode(coords[0], coords[1], coords[2]);
10772                       int newId = newNode->getVtkId();
10773                       nodeDomains[oldId][idom] = newId; // cloned node for other domains
10774                       //MESSAGE("   newNode " << newId << " oldNode " << oldId << " size=" <<nodeDomains[oldId].size());
10775                     }
10776                   if (nodeDomains[oldId].size() >= 3)
10777                     {
10778                       //MESSAGE("confirm multiple node " << oldId);
10779                       isMultipleDetected =true;
10780                     }
10781                 }
10782             }
10783           if (isMultipleDetected) // check if an edge of the face is shared between 3 or more domains
10784             {
10785               //MESSAGE("multiple Nodes detected on a shared face");
10786               int downId = itface->first.cellId;
10787               unsigned char cellType = itface->first.cellType;
10788               // --- shared edge or shared face ?
10789               if ((cellType == VTK_LINE) || (cellType == VTK_QUADRATIC_EDGE)) // shared edge (between two faces)
10790                 {
10791                   int nodes[3];
10792                   int nbNodes = grid->getDownArray(cellType)->getNodes(downId, nodes);
10793                   for (int i=0; i< nbNodes; i=i+nbNodes-1) // i=0 , i=nbNodes-1
10794                     if (mutipleNodes.count(nodes[i]))
10795                       if (!mutipleNodesToFace.count(nodes[i]))
10796                         mutipleNodesToFace[nodes[i]] = mutipleNodes[nodes[i]];
10797                }
10798               else // shared face (between two volumes)
10799                 {
10800                   int nbEdges = grid->getDownArray(cellType)->getNumberOfDownCells(downId);
10801                   const int* downEdgeIds = grid->getDownArray(cellType)->getDownCells(downId);
10802                   const unsigned char* edgeType = grid->getDownArray(cellType)->getDownTypes(downId);
10803                   for (int ie =0; ie < nbEdges; ie++)
10804                     {
10805                       int nodes[3];
10806                       int nbNodes = grid->getDownArray(edgeType[ie])->getNodes(downEdgeIds[ie], nodes);
10807                       if (mutipleNodes.count(nodes[0]) && mutipleNodes.count(nodes[nbNodes-1]))
10808                         {
10809                           vector<int> vn0 = mutipleNodes[nodes[0]];
10810                           vector<int> vn1 = mutipleNodes[nodes[nbNodes - 1]];
10811                           sort( vn0.begin(), vn0.end() );
10812                           sort( vn1.begin(), vn1.end() );
10813                           if (vn0 == vn1)
10814                             {
10815                               //MESSAGE(" detect edgesMultiDomains " << nodes[0] << " " << nodes[nbNodes - 1]);
10816                               double *coords = grid->GetPoint(nodes[0]);
10817                               gp_Pnt p0(coords[0], coords[1], coords[2]);
10818                               coords = grid->GetPoint(nodes[nbNodes - 1]);
10819                               gp_Pnt p1(coords[0], coords[1], coords[2]);
10820                               gp_Pnt gref;
10821                               int vtkVolIds[1000];  // an edge can belong to a lot of volumes
10822                               map<int, SMDS_VtkVolume*> domvol; // domain --> a volume with the edge
10823                               map<int, double> angleDom; // oriented angles between planes defined by edge and volume centers
10824                               int nbvol = grid->GetParentVolumes(vtkVolIds, downEdgeIds[ie], edgeType[ie]);
10825                               for (int id=0; id < vn0.size(); id++)
10826                                 {
10827                                   int idom = vn0[id];
10828                                   for (int ivol=0; ivol<nbvol; ivol++)
10829                                     {
10830                                       int smdsId = meshDS->fromVtkToSmds(vtkVolIds[ivol]);
10831                                       SMDS_MeshElement* elem = (SMDS_MeshElement*)meshDS->FindElement(smdsId);
10832                                       if (theElems[idom].count(elem))
10833                                         {
10834                                           SMDS_VtkVolume* svol = dynamic_cast<SMDS_VtkVolume*>(elem);
10835                                           domvol[idom] = svol;
10836                                           //MESSAGE("  domain " << idom << " volume " << elem->GetID());
10837                                           double values[3];
10838                                           vtkIdType npts = 0;
10839                                           vtkIdType* pts = 0;
10840                                           grid->GetCellPoints(vtkVolIds[ivol], npts, pts);
10841                                           SMDS_VtkVolume::gravityCenter(grid, pts, npts, values);
10842                                           if (id ==0)
10843                                             {
10844                                               gref.SetXYZ(gp_XYZ(values[0], values[1], values[2]));
10845                                               angleDom[idom] = 0;
10846                                             }
10847                                           else
10848                                             {
10849                                               gp_Pnt g(values[0], values[1], values[2]);
10850                                               angleDom[idom] = OrientedAngle(p0, p1, gref, g); // -pi<angle<+pi
10851                                               //MESSAGE("  angle=" << angleDom[idom]);
10852                                             }
10853                                           break;
10854                                         }
10855                                     }
10856                                 }
10857                               map<double, int> sortedDom; // sort domains by angle
10858                               for (map<int, double>::iterator ia = angleDom.begin(); ia != angleDom.end(); ++ia)
10859                                 sortedDom[ia->second] = ia->first;
10860                               vector<int> vnodes;
10861                               vector<int> vdom;
10862                               for (map<double, int>::iterator ib = sortedDom.begin(); ib != sortedDom.end(); ++ib)
10863                                 {
10864                                   vdom.push_back(ib->second);
10865                                   //MESSAGE("  ordered domain " << ib->second << "  angle " << ib->first);
10866                                 }
10867                               for (int ino = 0; ino < nbNodes; ino++)
10868                                 vnodes.push_back(nodes[ino]);
10869                               edgesMultiDomains[vnodes] = vdom; // nodes vector --> ordered domains
10870                             }
10871                         }
10872                     }
10873                 }
10874             }
10875         }
10876     }
10877
10878   // --- iterate on shared faces (volumes to modify, face to extrude)
10879   //     get node id's of the face (id SMDS = id VTK)
10880   //     create flat element with old and new nodes if requested
10881
10882   // --- new quad nodes on flat quad elements: oldId --> ((domain1 X domain2) --> newId)
10883   //     (domain1 X domain2) = domain1 + MAXINT*domain2
10884
10885   std::map<int, std::map<long,int> > nodeQuadDomains;
10886   std::map<std::string, SMESH_Group*> mapOfJunctionGroups;
10887
10888   if (createJointElems)
10889     {
10890       itface = faceDomains.begin();
10891       for (; itface != faceDomains.end(); ++itface)
10892         {
10893           DownIdType face = itface->first;
10894           std::set<int> oldNodes;
10895           std::set<int>::iterator itn;
10896           oldNodes.clear();
10897           grid->GetNodeIds(oldNodes, face.cellId, face.cellType);
10898
10899           std::map<int, int> domvol = itface->second;
10900           std::map<int, int>::iterator itdom = domvol.begin();
10901           int dom1 = itdom->first;
10902           int vtkVolId = itdom->second;
10903           itdom++;
10904           int dom2 = itdom->first;
10905           SMDS_MeshCell *vol = grid->extrudeVolumeFromFace(vtkVolId, dom1, dom2, oldNodes, nodeDomains,
10906                                                              nodeQuadDomains);
10907           stringstream grpname;
10908           grpname << "j_";
10909           if (dom1 < dom2)
10910             grpname << dom1 << "_" << dom2;
10911           else
10912             grpname << dom2 << "_" << dom1;
10913           int idg;
10914           string namegrp = grpname.str();
10915           if (!mapOfJunctionGroups.count(namegrp))
10916             mapOfJunctionGroups[namegrp] = this->myMesh->AddGroup(vol->GetType(), namegrp.c_str(), idg);
10917           SMESHDS_Group *sgrp = dynamic_cast<SMESHDS_Group*>(mapOfJunctionGroups[namegrp]->GetGroupDS());
10918           if (sgrp)
10919             sgrp->Add(vol->GetID());
10920         }
10921     }
10922
10923   // --- create volumes on multiple domain intersection if requested
10924   //     iterate on mutipleNodesToFace
10925   //     iterate on edgesMultiDomains
10926
10927   if (createJointElems)
10928     {
10929       // --- iterate on mutipleNodesToFace
10930
10931       std::map<int, std::vector<int> >::iterator itn =  mutipleNodesToFace.begin();
10932       for (; itn != mutipleNodesToFace.end(); ++itn)
10933         {
10934           int node = itn->first;
10935           vector<int> orderDom = itn->second;
10936           vector<vtkIdType> orderedNodes;
10937           for (int idom = 0; idom <orderDom.size(); idom++)
10938             orderedNodes.push_back( nodeDomains[node][orderDom[idom]] );
10939             SMDS_MeshFace* face = this->GetMeshDS()->AddFaceFromVtkIds(orderedNodes);
10940
10941             stringstream grpname;
10942             grpname << "m2j_";
10943             grpname << 0 << "_" << 0;
10944             int idg;
10945             string namegrp = grpname.str();
10946             if (!mapOfJunctionGroups.count(namegrp))
10947               mapOfJunctionGroups[namegrp] = this->myMesh->AddGroup(SMDSAbs_Face, namegrp.c_str(), idg);
10948             SMESHDS_Group *sgrp = dynamic_cast<SMESHDS_Group*>(mapOfJunctionGroups[namegrp]->GetGroupDS());
10949             if (sgrp)
10950               sgrp->Add(face->GetID());
10951         }
10952
10953       // --- iterate on edgesMultiDomains
10954
10955       std::map<std::vector<int>, std::vector<int> >::iterator ite = edgesMultiDomains.begin();
10956       for (; ite != edgesMultiDomains.end(); ++ite)
10957         {
10958           vector<int> nodes = ite->first;
10959           vector<int> orderDom = ite->second;
10960           vector<vtkIdType> orderedNodes;
10961           if (nodes.size() == 2)
10962             {
10963               //MESSAGE(" use edgesMultiDomains " << nodes[0] << " " << nodes[1]);
10964               for (int ino=0; ino < nodes.size(); ino++)
10965                 if (orderDom.size() == 3)
10966                   for (int idom = 0; idom <orderDom.size(); idom++)
10967                     orderedNodes.push_back( nodeDomains[nodes[ino]][orderDom[idom]] );
10968                 else
10969                   for (int idom = orderDom.size()-1; idom >=0; idom--)
10970                     orderedNodes.push_back( nodeDomains[nodes[ino]][orderDom[idom]] );
10971               SMDS_MeshVolume* vol = this->GetMeshDS()->AddVolumeFromVtkIds(orderedNodes);
10972
10973               stringstream grpname;
10974               grpname << "mj_";
10975               grpname << 0 << "_" << 0;
10976               int idg;
10977               string namegrp = grpname.str();
10978               if (!mapOfJunctionGroups.count(namegrp))
10979                 mapOfJunctionGroups[namegrp] = this->myMesh->AddGroup(SMDSAbs_Volume, namegrp.c_str(), idg);
10980               SMESHDS_Group *sgrp = dynamic_cast<SMESHDS_Group*>(mapOfJunctionGroups[namegrp]->GetGroupDS());
10981               if (sgrp)
10982                 sgrp->Add(vol->GetID());
10983             }
10984           else
10985             {
10986               MESSAGE("Quadratic multiple joints not implemented");
10987               // TODO quadratic nodes
10988             }
10989         }
10990     }
10991
10992   // --- list the explicit faces and edges of the mesh that need to be modified,
10993   //     i.e. faces and edges built with one or more duplicated nodes.
10994   //     associate these faces or edges to their corresponding domain.
10995   //     only the first domain found is kept when a face or edge is shared
10996
10997   std::map<DownIdType, std::map<int,int>, DownIdCompare> faceOrEdgeDom; // cellToModify --> (id domain --> id cell)
10998   std::map<int,int> feDom; // vtk id of cell to modify --> id domain
10999   faceOrEdgeDom.clear();
11000   feDom.clear();
11001
11002   for (int idomain = 0; idomain < theElems.size(); idomain++)
11003     {
11004       std::map<int, std::map<int, int> >::const_iterator itnod = nodeDomains.begin();
11005       for (; itnod != nodeDomains.end(); ++itnod)
11006         {
11007           int oldId = itnod->first;
11008           //MESSAGE("     node " << oldId);
11009           vtkCellLinks::Link l = grid->GetCellLinks()->GetLink(oldId);
11010           for (int i = 0; i < l.ncells; i++)
11011             {
11012               int vtkId = l.cells[i];
11013               int vtkType = grid->GetCellType(vtkId);
11014               int downId = grid->CellIdToDownId(vtkId);
11015               if (downId < 0)
11016                 continue; // new cells: not to be modified
11017               DownIdType aCell(downId, vtkType);
11018               int volParents[1000];
11019               int nbvol = grid->GetParentVolumes(volParents, vtkId);
11020               for (int j = 0; j < nbvol; j++)
11021                 if (celldom.count(volParents[j]) && (celldom[volParents[j]] == idomain))
11022                   if (!feDom.count(vtkId))
11023                     {
11024                       feDom[vtkId] = idomain;
11025                       faceOrEdgeDom[aCell] = emptyMap;
11026                       faceOrEdgeDom[aCell][idomain] = vtkId; // affect face or edge to the first domain only
11027                       //MESSAGE("affect cell " << this->GetMeshDS()->fromVtkToSmds(vtkId) << " domain " << idomain
11028                       //        << " type " << vtkType << " downId " << downId);
11029                     }
11030             }
11031         }
11032     }
11033
11034   // --- iterate on shared faces (volumes to modify, face to extrude)
11035   //     get node id's of the face
11036   //     replace old nodes by new nodes in volumes, and update inverse connectivity
11037
11038   std::map<DownIdType, std::map<int,int>, DownIdCompare>* maps[3] = {&faceDomains, &cellDomains, &faceOrEdgeDom};
11039   for (int m=0; m<3; m++)
11040     {
11041       std::map<DownIdType, std::map<int,int>, DownIdCompare>* amap = maps[m];
11042       itface = (*amap).begin();
11043       for (; itface != (*amap).end(); ++itface)
11044         {
11045           DownIdType face = itface->first;
11046           std::set<int> oldNodes;
11047           std::set<int>::iterator itn;
11048           oldNodes.clear();
11049           grid->GetNodeIds(oldNodes, face.cellId, face.cellType);
11050           //MESSAGE("examine cell, downId " << face.cellId << " type " << int(face.cellType));
11051           std::map<int, int> localClonedNodeIds;
11052
11053           std::map<int, int> domvol = itface->second;
11054           std::map<int, int>::iterator itdom = domvol.begin();
11055           for (; itdom != domvol.end(); ++itdom)
11056             {
11057               int idom = itdom->first;
11058               int vtkVolId = itdom->second;
11059               //MESSAGE("modify nodes of cell " << this->GetMeshDS()->fromVtkToSmds(vtkVolId) << " domain " << idom);
11060               localClonedNodeIds.clear();
11061               for (itn = oldNodes.begin(); itn != oldNodes.end(); ++itn)
11062                 {
11063                   int oldId = *itn;
11064                   if (nodeDomains[oldId].count(idom))
11065                     {
11066                       localClonedNodeIds[oldId] = nodeDomains[oldId][idom];
11067                       //MESSAGE("     node " << oldId << " --> " << localClonedNodeIds[oldId]);
11068                     }
11069                 }
11070               meshDS->ModifyCellNodes(vtkVolId, localClonedNodeIds);
11071             }
11072         }
11073     }
11074
11075   meshDS->CleanDownWardConnectivity(); // Mesh has been modified, downward connectivity is no more usable, free memory
11076   grid->BuildLinks();
11077
11078   CHRONOSTOP(50);
11079   counters::stats();
11080   return true;
11081 }
11082
11083 /*!
11084  * \brief Double nodes on some external faces and create flat elements.
11085  * Flat elements are mainly used by some types of mechanic calculations.
11086  *
11087  * Each group of the list must be constituted of faces.
11088  * Triangles are transformed in prisms, and quadrangles in hexahedrons.
11089  * @param theElems - list of groups of faces, where a group of faces is a set of
11090  * SMDS_MeshElements sorted by Id.
11091  * @return TRUE if operation has been completed successfully, FALSE otherwise
11092  */
11093 bool SMESH_MeshEditor::CreateFlatElementsOnFacesGroups(const std::vector<TIDSortedElemSet>& theElems)
11094 {
11095   MESSAGE("-------------------------------------------------");
11096   MESSAGE("SMESH_MeshEditor::CreateFlatElementsOnFacesGroups");
11097   MESSAGE("-------------------------------------------------");
11098
11099   SMESHDS_Mesh *meshDS = this->myMesh->GetMeshDS();
11100
11101   // --- For each group of faces
11102   //     duplicate the nodes, create a flat element based on the face
11103   //     replace the nodes of the faces by their clones
11104
11105   std::map<const SMDS_MeshNode*, const SMDS_MeshNode*> clonedNodes;
11106   std::map<const SMDS_MeshNode*, const SMDS_MeshNode*> intermediateNodes;
11107   clonedNodes.clear();
11108   intermediateNodes.clear();
11109   std::map<std::string, SMESH_Group*> mapOfJunctionGroups;
11110   mapOfJunctionGroups.clear();
11111
11112   for (int idom = 0; idom < theElems.size(); idom++)
11113     {
11114       const TIDSortedElemSet& domain = theElems[idom];
11115       TIDSortedElemSet::const_iterator elemItr = domain.begin();
11116       for (; elemItr != domain.end(); ++elemItr)
11117         {
11118           SMDS_MeshElement* anElem = (SMDS_MeshElement*) *elemItr;
11119           SMDS_MeshFace* aFace = dynamic_cast<SMDS_MeshFace*> (anElem);
11120           if (!aFace)
11121             continue;
11122           // MESSAGE("aFace=" << aFace->GetID());
11123           bool isQuad = aFace->IsQuadratic();
11124           vector<const SMDS_MeshNode*> ln0, ln1, ln2, ln3, ln4;
11125
11126           // --- clone the nodes, create intermediate nodes for non medium nodes of a quad face
11127
11128           SMDS_ElemIteratorPtr nodeIt = aFace->nodesIterator();
11129           while (nodeIt->more())
11130             {
11131               const SMDS_MeshNode* node = static_cast<const SMDS_MeshNode*> (nodeIt->next());
11132               bool isMedium = isQuad && (aFace->IsMediumNode(node));
11133               if (isMedium)
11134                 ln2.push_back(node);
11135               else
11136                 ln0.push_back(node);
11137
11138               const SMDS_MeshNode* clone = 0;
11139               if (!clonedNodes.count(node))
11140                 {
11141                   clone = meshDS->AddNode(node->X(), node->Y(), node->Z());
11142                   clonedNodes[node] = clone;
11143                 }
11144               else
11145                 clone = clonedNodes[node];
11146
11147               if (isMedium)
11148                 ln3.push_back(clone);
11149               else
11150                 ln1.push_back(clone);
11151
11152               const SMDS_MeshNode* inter = 0;
11153               if (isQuad && (!isMedium))
11154                 {
11155                   if (!intermediateNodes.count(node))
11156                     {
11157                       inter = meshDS->AddNode(node->X(), node->Y(), node->Z());
11158                       intermediateNodes[node] = inter;
11159                     }
11160                   else
11161                     inter = intermediateNodes[node];
11162                   ln4.push_back(inter);
11163                 }
11164             }
11165
11166           // --- extrude the face
11167
11168           vector<const SMDS_MeshNode*> ln;
11169           SMDS_MeshVolume* vol = 0;
11170           vtkIdType aType = aFace->GetVtkType();
11171           switch (aType)
11172           {
11173             case VTK_TRIANGLE:
11174               vol = meshDS->AddVolume(ln0[2], ln0[1], ln0[0], ln1[2], ln1[1], ln1[0]);
11175               // MESSAGE("vol prism " << vol->GetID());
11176               ln.push_back(ln1[0]);
11177               ln.push_back(ln1[1]);
11178               ln.push_back(ln1[2]);
11179               break;
11180             case VTK_QUAD:
11181               vol = meshDS->AddVolume(ln0[3], ln0[2], ln0[1], ln0[0], ln1[3], ln1[2], ln1[1], ln1[0]);
11182               // MESSAGE("vol hexa " << vol->GetID());
11183               ln.push_back(ln1[0]);
11184               ln.push_back(ln1[1]);
11185               ln.push_back(ln1[2]);
11186               ln.push_back(ln1[3]);
11187               break;
11188             case VTK_QUADRATIC_TRIANGLE:
11189               vol = meshDS->AddVolume(ln1[0], ln1[1], ln1[2], ln0[0], ln0[1], ln0[2], ln3[0], ln3[1], ln3[2],
11190                                       ln2[0], ln2[1], ln2[2], ln4[0], ln4[1], ln4[2]);
11191               // MESSAGE("vol quad prism " << vol->GetID());
11192               ln.push_back(ln1[0]);
11193               ln.push_back(ln1[1]);
11194               ln.push_back(ln1[2]);
11195               ln.push_back(ln3[0]);
11196               ln.push_back(ln3[1]);
11197               ln.push_back(ln3[2]);
11198               break;
11199             case VTK_QUADRATIC_QUAD:
11200 //              vol = meshDS->AddVolume(ln0[0], ln0[1], ln0[2], ln0[3], ln1[0], ln1[1], ln1[2], ln1[3],
11201 //                                      ln2[0], ln2[1], ln2[2], ln2[3], ln3[0], ln3[1], ln3[2], ln3[3],
11202 //                                      ln4[0], ln4[1], ln4[2], ln4[3]);
11203               vol = meshDS->AddVolume(ln1[0], ln1[1], ln1[2], ln1[3], ln0[0], ln0[1], ln0[2], ln0[3],
11204                                       ln3[0], ln3[1], ln3[2], ln3[3], ln2[0], ln2[1], ln2[2], ln2[3],
11205                                       ln4[0], ln4[1], ln4[2], ln4[3]);
11206               // MESSAGE("vol quad hexa " << vol->GetID());
11207               ln.push_back(ln1[0]);
11208               ln.push_back(ln1[1]);
11209               ln.push_back(ln1[2]);
11210               ln.push_back(ln1[3]);
11211               ln.push_back(ln3[0]);
11212               ln.push_back(ln3[1]);
11213               ln.push_back(ln3[2]);
11214               ln.push_back(ln3[3]);
11215               break;
11216             case VTK_POLYGON:
11217               break;
11218             default:
11219               break;
11220           }
11221
11222           if (vol)
11223             {
11224               stringstream grpname;
11225               grpname << "jf_";
11226               grpname << idom;
11227               int idg;
11228               string namegrp = grpname.str();
11229               if (!mapOfJunctionGroups.count(namegrp))
11230                 mapOfJunctionGroups[namegrp] = this->myMesh->AddGroup(SMDSAbs_Volume, namegrp.c_str(), idg);
11231               SMESHDS_Group *sgrp = dynamic_cast<SMESHDS_Group*>(mapOfJunctionGroups[namegrp]->GetGroupDS());
11232               if (sgrp)
11233                 sgrp->Add(vol->GetID());
11234             }
11235
11236           // --- modify the face
11237
11238           aFace->ChangeNodes(&ln[0], ln.size());
11239         }
11240     }
11241   return true;
11242 }
11243
11244 //================================================================================
11245 /*!
11246  * \brief Generates skin mesh (containing 2D cells) from 3D mesh
11247  * The created 2D mesh elements based on nodes of free faces of boundary volumes
11248  * \return TRUE if operation has been completed successfully, FALSE otherwise
11249  */
11250 //================================================================================
11251
11252 bool SMESH_MeshEditor::Make2DMeshFrom3D()
11253 {
11254   // iterates on volume elements and detect all free faces on them
11255   SMESHDS_Mesh* aMesh = GetMeshDS();
11256   if (!aMesh)
11257     return false;
11258   //bool res = false;
11259   int nbFree = 0, nbExisted = 0, nbCreated = 0;
11260   SMDS_VolumeIteratorPtr vIt = aMesh->volumesIterator();
11261   while(vIt->more())
11262   {
11263     const SMDS_MeshVolume* volume = vIt->next();
11264     SMDS_VolumeTool vTool( volume, /*ignoreCentralNodes=*/false );
11265     vTool.SetExternalNormal();
11266     //const bool isPoly = volume->IsPoly();
11267     const int iQuad = volume->IsQuadratic();
11268     for ( int iface = 0, n = vTool.NbFaces(); iface < n; iface++ )
11269     {
11270       if (!vTool.IsFreeFace(iface))
11271         continue;
11272       nbFree++;
11273       vector<const SMDS_MeshNode *> nodes;
11274       int nbFaceNodes = vTool.NbFaceNodes(iface);
11275       const SMDS_MeshNode** faceNodes = vTool.GetFaceNodes(iface);
11276       int inode = 0;
11277       for ( ; inode < nbFaceNodes; inode += iQuad+1)
11278         nodes.push_back(faceNodes[inode]);
11279       if (iQuad) { // add medium nodes
11280         for ( inode = 1; inode < nbFaceNodes; inode += 2)
11281           nodes.push_back(faceNodes[inode]);
11282         if ( nbFaceNodes == 9 ) // bi-quadratic quad
11283           nodes.push_back(faceNodes[8]);
11284       }
11285       // add new face based on volume nodes
11286       if (aMesh->FindElement( nodes, SMDSAbs_Face, /*noMedium=*/false) ) {
11287         nbExisted++;
11288         continue; // face already exsist
11289       }
11290       AddElement(nodes, SMDSAbs_Face, ( !iQuad && nbFaceNodes/(iQuad+1) > 4 ));
11291       nbCreated++;
11292     }
11293   }
11294   return ( nbFree==(nbExisted+nbCreated) );
11295 }
11296
11297 namespace
11298 {
11299   inline const SMDS_MeshNode* getNodeWithSameID(SMESHDS_Mesh* mesh, const SMDS_MeshNode* node)
11300   {
11301     if ( const SMDS_MeshNode* n = mesh->FindNode( node->GetID() ))
11302       return n;
11303     return mesh->AddNodeWithID( node->X(),node->Y(),node->Z(), node->GetID() );
11304   }
11305 }
11306 //================================================================================
11307 /*!
11308  * \brief Creates missing boundary elements
11309  *  \param elements - elements whose boundary is to be checked
11310  *  \param dimension - defines type of boundary elements to create
11311  *  \param group - a group to store created boundary elements in
11312  *  \param targetMesh - a mesh to store created boundary elements in
11313  *  \param toCopyElements - if true, the checked elements will be copied into the targetMesh
11314  *  \param toCopyExistingBoundary - if true, not only new but also pre-existing
11315  *                                boundary elements will be copied into the targetMesh
11316  *  \param toAddExistingBondary - if true, not only new but also pre-existing
11317  *                                boundary elements will be added into the new group
11318  *  \param aroundElements - if true, elements will be created on boundary of given
11319  *                          elements else, on boundary of the whole mesh.
11320  * \return nb of added boundary elements
11321  */
11322 //================================================================================
11323
11324 int SMESH_MeshEditor::MakeBoundaryMesh(const TIDSortedElemSet& elements,
11325                                        Bnd_Dimension           dimension,
11326                                        SMESH_Group*            group/*=0*/,
11327                                        SMESH_Mesh*             targetMesh/*=0*/,
11328                                        bool                    toCopyElements/*=false*/,
11329                                        bool                    toCopyExistingBoundary/*=false*/,
11330                                        bool                    toAddExistingBondary/*= false*/,
11331                                        bool                    aroundElements/*= false*/)
11332 {
11333   SMDSAbs_ElementType missType = (dimension == BND_2DFROM3D) ? SMDSAbs_Face : SMDSAbs_Edge;
11334   SMDSAbs_ElementType elemType = (dimension == BND_1DFROM2D) ? SMDSAbs_Face : SMDSAbs_Volume;
11335   // hope that all elements are of the same type, do not check them all
11336   if ( !elements.empty() && (*elements.begin())->GetType() != elemType )
11337     throw SALOME_Exception(LOCALIZED("wrong element type"));
11338
11339   if ( !targetMesh )
11340     toCopyElements = toCopyExistingBoundary = false;
11341
11342   SMESH_MeshEditor tgtEditor( targetMesh ? targetMesh : myMesh );
11343   SMESHDS_Mesh* aMesh = GetMeshDS(), *tgtMeshDS = tgtEditor.GetMeshDS();
11344   int nbAddedBnd = 0;
11345
11346   // editor adding present bnd elements and optionally holding elements to add to the group
11347   SMESH_MeshEditor* presentEditor;
11348   SMESH_MeshEditor tgtEditor2( tgtEditor.GetMesh() );
11349   presentEditor = toAddExistingBondary ? &tgtEditor : &tgtEditor2;
11350
11351   SMESH_MesherHelper helper( *myMesh );
11352   const TopAbs_ShapeEnum missShapeType = ( missType==SMDSAbs_Face ? TopAbs_FACE : TopAbs_EDGE );
11353   SMDS_VolumeTool vTool;
11354   TIDSortedElemSet avoidSet;
11355   const TIDSortedElemSet emptySet, *elemSet = aroundElements ? &elements : &emptySet;
11356   int inode;
11357
11358   typedef vector<const SMDS_MeshNode*> TConnectivity;
11359
11360   SMDS_ElemIteratorPtr eIt;
11361   if (elements.empty())
11362     eIt = aMesh->elementsIterator(elemType);
11363   else
11364     eIt = SMDS_ElemIteratorPtr( new TSetIterator( elements.begin(), elements.end() ));
11365
11366   while (eIt->more())
11367   {
11368     const SMDS_MeshElement* elem = eIt->next();
11369     const int iQuad = elem->IsQuadratic();
11370
11371     // ------------------------------------------------------------------------------------
11372     // 1. For an elem, get present bnd elements and connectivities of missing bnd elements
11373     // ------------------------------------------------------------------------------------
11374     vector<const SMDS_MeshElement*> presentBndElems;
11375     vector<TConnectivity>           missingBndElems;
11376     TConnectivity nodes;
11377     if ( vTool.Set(elem, /*ignoreCentralNodes=*/true) ) // elem is a volume --------------
11378     {
11379       vTool.SetExternalNormal();
11380       const SMDS_MeshElement* otherVol = 0;
11381       for ( int iface = 0, n = vTool.NbFaces(); iface < n; iface++ )
11382       {
11383         if ( !vTool.IsFreeFace(iface, &otherVol) &&
11384              ( !aroundElements || elements.count( otherVol )))
11385           continue;
11386         const int nbFaceNodes = vTool.NbFaceNodes(iface);
11387         const SMDS_MeshNode** nn = vTool.GetFaceNodes(iface);
11388         if ( missType == SMDSAbs_Edge ) // boundary edges
11389         {
11390           nodes.resize( 2+iQuad );
11391           for ( int i = 0; i < nbFaceNodes; i += 1+iQuad)
11392           {
11393             for ( int j = 0; j < nodes.size(); ++j )
11394               nodes[j] =nn[i+j];
11395             if ( const SMDS_MeshElement* edge =
11396                  aMesh->FindElement(nodes,SMDSAbs_Edge,/*noMedium=*/false))
11397               presentBndElems.push_back( edge );
11398             else
11399               missingBndElems.push_back( nodes );
11400           }
11401         }
11402         else // boundary face
11403         {
11404           nodes.clear();
11405           for ( inode = 0; inode < nbFaceNodes; inode += 1+iQuad)
11406             nodes.push_back( nn[inode] );
11407           if (iQuad) // add medium nodes
11408             for ( inode = 1; inode < nbFaceNodes; inode += 2)
11409               nodes.push_back( nn[inode] );
11410           int iCenter = vTool.GetCenterNodeIndex(iface); // for HEX27
11411           if ( iCenter > 0 )
11412             nodes.push_back( vTool.GetNodes()[ iCenter ] );
11413
11414           if (const SMDS_MeshElement * f = aMesh->FindElement( nodes,
11415                                                                SMDSAbs_Face, /*noMedium=*/false ))
11416             presentBndElems.push_back( f );
11417           else
11418             missingBndElems.push_back( nodes );
11419
11420           if ( targetMesh != myMesh )
11421           {
11422             // add 1D elements on face boundary to be added to a new mesh
11423             const SMDS_MeshElement* edge;
11424             for ( inode = 0; inode < nbFaceNodes; inode += 1+iQuad)
11425             {
11426               if ( iQuad )
11427                 edge = aMesh->FindEdge( nn[inode], nn[inode+1], nn[inode+2]);
11428               else
11429                 edge = aMesh->FindEdge( nn[inode], nn[inode+1]);
11430               if ( edge && avoidSet.insert( edge ).second )
11431                 presentBndElems.push_back( edge );
11432             }
11433           }
11434         }
11435       }
11436     }
11437     else                     // elem is a face ------------------------------------------
11438     {
11439       avoidSet.clear(), avoidSet.insert( elem );
11440       int nbNodes = elem->NbCornerNodes();
11441       nodes.resize( 2 /*+ iQuad*/);
11442       for ( int i = 0; i < nbNodes; i++ )
11443       {
11444         nodes[0] = elem->GetNode(i);
11445         nodes[1] = elem->GetNode((i+1)%nbNodes);
11446         if ( FindFaceInSet( nodes[0], nodes[1], *elemSet, avoidSet))
11447           continue; // not free link
11448
11449         //if ( iQuad )
11450         //nodes[2] = elem->GetNode( i + nbNodes );
11451         if ( const SMDS_MeshElement* edge =
11452              aMesh->FindElement(nodes,SMDSAbs_Edge,/*noMedium=*/true))
11453           presentBndElems.push_back( edge );
11454         else
11455           missingBndElems.push_back( nodes );
11456       }
11457     }
11458
11459     // ---------------------------------
11460     // 2. Add missing boundary elements
11461     // ---------------------------------
11462     if ( targetMesh != myMesh )
11463       // instead of making a map of nodes in this mesh and targetMesh,
11464       // we create nodes with same IDs.
11465       for ( int i = 0; i < missingBndElems.size(); ++i )
11466       {
11467         TConnectivity& srcNodes = missingBndElems[i];
11468         TConnectivity  nodes( srcNodes.size() );
11469         for ( inode = 0; inode < nodes.size(); ++inode )
11470           nodes[inode] = getNodeWithSameID( tgtMeshDS, srcNodes[inode] );
11471         if ( aroundElements && tgtEditor.GetMeshDS()->FindElement( nodes,
11472                                                                    missType,
11473                                                                    /*noMedium=*/false))
11474           continue;
11475         tgtEditor.AddElement(nodes, missType, !iQuad && nodes.size()/(iQuad+1)>4);
11476         ++nbAddedBnd;
11477       }
11478     else
11479       for ( int i = 0; i < missingBndElems.size(); ++i )
11480       {
11481         TConnectivity& nodes = missingBndElems[i];
11482         if ( aroundElements && tgtEditor.GetMeshDS()->FindElement( nodes,
11483                                                                    missType,
11484                                                                    /*noMedium=*/false))
11485           continue;
11486         SMDS_MeshElement* elem = 
11487           tgtEditor.AddElement(nodes, missType, !iQuad && nodes.size()/(iQuad+1)>4);
11488         ++nbAddedBnd;
11489
11490         // try to set a new element to a shape
11491         if ( myMesh->HasShapeToMesh() )
11492         {
11493           bool ok = true;
11494           set< pair<TopAbs_ShapeEnum, int > > mediumShapes;
11495           const int nbN = nodes.size() / (iQuad+1 );
11496           for ( inode = 0; inode < nbN && ok; ++inode )
11497           {
11498             pair<int, TopAbs_ShapeEnum> i_stype =
11499               helper.GetMediumPos( nodes[inode], nodes[(inode+1)%nbN]);
11500             if (( ok = ( i_stype.first > 0 && i_stype.second >= TopAbs_FACE )))
11501               mediumShapes.insert( make_pair ( i_stype.second, i_stype.first ));
11502           }
11503           if ( ok && mediumShapes.size() > 1 )
11504           {
11505             set< pair<TopAbs_ShapeEnum, int > >::iterator stype_i = mediumShapes.begin();
11506             pair<TopAbs_ShapeEnum, int> stype_i_0 = *stype_i;
11507             for ( ++stype_i; stype_i != mediumShapes.end() && ok; ++stype_i )
11508             {
11509               if (( ok = ( stype_i->first != stype_i_0.first )))
11510                 ok = helper.IsSubShape( aMesh->IndexToShape( stype_i->second ),
11511                                         aMesh->IndexToShape( stype_i_0.second ));
11512             }
11513           }
11514           if ( ok && mediumShapes.begin()->first == missShapeType )
11515             aMesh->SetMeshElementOnShape( elem, mediumShapes.begin()->second );
11516         }
11517       }
11518
11519     // ----------------------------------
11520     // 3. Copy present boundary elements
11521     // ----------------------------------
11522     if ( toCopyExistingBoundary )
11523       for ( int i = 0 ; i < presentBndElems.size(); ++i )
11524       {
11525         const SMDS_MeshElement* e = presentBndElems[i];
11526         TConnectivity nodes( e->NbNodes() );
11527         for ( inode = 0; inode < nodes.size(); ++inode )
11528           nodes[inode] = getNodeWithSameID( tgtMeshDS, e->GetNode(inode) );
11529         presentEditor->AddElement(nodes, e->GetType(), e->IsPoly());
11530       }
11531     else // store present elements to add them to a group
11532       for ( int i = 0 ; i < presentBndElems.size(); ++i )
11533       {
11534         presentEditor->myLastCreatedElems.Append(presentBndElems[i]);
11535       }
11536       
11537   } // loop on given elements
11538
11539   // ---------------------------------------------
11540   // 4. Fill group with boundary elements
11541   // ---------------------------------------------
11542   if ( group )
11543   {
11544     if ( SMESHDS_Group* g = dynamic_cast<SMESHDS_Group*>( group->GetGroupDS() ))
11545       for ( int i = 0; i < tgtEditor.myLastCreatedElems.Size(); ++i )
11546         g->SMDSGroup().Add( tgtEditor.myLastCreatedElems( i+1 ));
11547   }
11548   tgtEditor.myLastCreatedElems.Clear();
11549   tgtEditor2.myLastCreatedElems.Clear();
11550
11551   // -----------------------
11552   // 5. Copy given elements
11553   // -----------------------
11554   if ( toCopyElements && targetMesh != myMesh )
11555   {
11556     if (elements.empty())
11557       eIt = aMesh->elementsIterator(elemType);
11558     else
11559       eIt = SMDS_ElemIteratorPtr( new TSetIterator( elements.begin(), elements.end() ));
11560     while (eIt->more())
11561     {
11562       const SMDS_MeshElement* elem = eIt->next();
11563       TConnectivity nodes( elem->NbNodes() );
11564       for ( inode = 0; inode < nodes.size(); ++inode )
11565         nodes[inode] = getNodeWithSameID( tgtMeshDS, elem->GetNode(inode) );
11566       tgtEditor.AddElement(nodes, elemType, elem->IsPoly());
11567
11568       tgtEditor.myLastCreatedElems.Clear();
11569     }
11570   }
11571   return nbAddedBnd;
11572 }