Salome HOME
0021457: [CEA] import check_mesh stability
[modules/smesh.git] / src / SMESH / SMESH_MeshEditor.cxx
1 // Copyright (C) 2007-2011  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 // SMESH SMESH : idl implementation based on 'SMESH' unit's classes
23 // File      : SMESH_MeshEditor.cxx
24 // Created   : Mon Apr 12 16:10:22 2004
25 // Author    : Edward AGAPOV (eap)
26
27 #include "SMESH_MeshEditor.hxx"
28
29 #include "SMDS_FaceOfNodes.hxx"
30 #include "SMDS_VolumeTool.hxx"
31 #include "SMDS_EdgePosition.hxx"
32 #include "SMDS_FacePosition.hxx"
33 #include "SMDS_SpacePosition.hxx"
34 #include "SMDS_MeshGroup.hxx"
35 #include "SMDS_LinearEdge.hxx"
36 #include "SMDS_Downward.hxx"
37 #include "SMDS_SetIterator.hxx"
38
39 #include "SMESHDS_Group.hxx"
40 #include "SMESHDS_Mesh.hxx"
41
42 #include "SMESH_Algo.hxx"
43 #include "SMESH_ControlsDef.hxx"
44 #include "SMESH_Group.hxx"
45 #include "SMESH_MesherHelper.hxx"
46 #include "SMESH_OctreeNode.hxx"
47 #include "SMESH_subMesh.hxx"
48
49 #include <Basics_OCCTVersion.hxx>
50
51 #include "utilities.h"
52
53 #include <BRepAdaptor_Surface.hxx>
54 #include <BRepBuilderAPI_MakeEdge.hxx>
55 #include <BRepClass3d_SolidClassifier.hxx>
56 #include <BRep_Tool.hxx>
57 #include <ElCLib.hxx>
58 #include <Extrema_GenExtPS.hxx>
59 #include <Extrema_POnCurv.hxx>
60 #include <Extrema_POnSurf.hxx>
61 #include <GC_MakeSegment.hxx>
62 #include <Geom2d_Curve.hxx>
63 #include <GeomAPI_ExtremaCurveCurve.hxx>
64 #include <GeomAdaptor_Surface.hxx>
65 #include <Geom_Curve.hxx>
66 #include <Geom_Line.hxx>
67 #include <Geom_Surface.hxx>
68 #include <IntAna_IntConicQuad.hxx>
69 #include <IntAna_Quadric.hxx>
70 #include <Precision.hxx>
71 #include <TColStd_ListOfInteger.hxx>
72 #include <TopAbs_State.hxx>
73 #include <TopExp.hxx>
74 #include <TopExp_Explorer.hxx>
75 #include <TopTools_ListIteratorOfListOfShape.hxx>
76 #include <TopTools_ListOfShape.hxx>
77 #include <TopTools_SequenceOfShape.hxx>
78 #include <TopoDS.hxx>
79 #include <TopoDS_Face.hxx>
80 #include <gp.hxx>
81 #include <gp_Ax1.hxx>
82 #include <gp_Dir.hxx>
83 #include <gp_Lin.hxx>
84 #include <gp_Pln.hxx>
85 #include <gp_Trsf.hxx>
86 #include <gp_Vec.hxx>
87 #include <gp_XY.hxx>
88 #include <gp_XYZ.hxx>
89
90 #include <cmath>
91
92 #include <map>
93 #include <set>
94 #include <numeric>
95 #include <limits>
96 #include <algorithm>
97 #include <sstream>
98
99 #define cast2Node(elem) static_cast<const SMDS_MeshNode*>( elem )
100
101 using namespace std;
102 using namespace SMESH::Controls;
103
104 typedef map<const SMDS_MeshElement*, list<const SMDS_MeshNode*> >    TElemOfNodeListMap;
105 typedef map<const SMDS_MeshElement*, list<const SMDS_MeshElement*> > TElemOfElemListMap;
106
107 typedef SMDS_SetIterator< SMDS_pElement, TIDSortedElemSet::const_iterator> TSetIterator;
108
109 //=======================================================================
110 //function : SMESH_MeshEditor
111 //purpose  :
112 //=======================================================================
113
114 SMESH_MeshEditor::SMESH_MeshEditor( SMESH_Mesh* theMesh )
115   :myMesh( theMesh ) // theMesh may be NULL
116 {
117 }
118
119 //=======================================================================
120 /*!
121  * \brief Add element
122  */
123 //=======================================================================
124
125 SMDS_MeshElement*
126 SMESH_MeshEditor::AddElement(const vector<const SMDS_MeshNode*> & node,
127                              const SMDSAbs_ElementType            type,
128                              const bool                           isPoly,
129                              const int                            ID)
130 {
131   //MESSAGE("AddElement " <<node.size() << " " << type << " " << isPoly << " " << ID);
132   SMDS_MeshElement* e = 0;
133   int nbnode = node.size();
134   SMESHDS_Mesh* mesh = GetMeshDS();
135   switch ( type ) {
136   case SMDSAbs_Face:
137     if ( !isPoly ) {
138       if      (nbnode == 3) {
139         if ( ID >= 1 ) e = mesh->AddFaceWithID(node[0], node[1], node[2], ID);
140         else           e = mesh->AddFace      (node[0], node[1], node[2] );
141       }
142       else if (nbnode == 4) {
143         if ( ID >= 1 ) e = mesh->AddFaceWithID(node[0], node[1], node[2], node[3], ID);
144         else           e = mesh->AddFace      (node[0], node[1], node[2], node[3] );
145       }
146       else if (nbnode == 6) {
147         if ( ID >= 1 ) e = mesh->AddFaceWithID(node[0], node[1], node[2], node[3],
148                                                node[4], node[5], ID);
149         else           e = mesh->AddFace      (node[0], node[1], node[2], node[3],
150                                                node[4], node[5] );
151       }
152       else if (nbnode == 8) {
153         if ( ID >= 1 ) e = mesh->AddFaceWithID(node[0], node[1], node[2], node[3],
154                                                node[4], node[5], node[6], node[7], ID);
155         else           e = mesh->AddFace      (node[0], node[1], node[2], node[3],
156                                                node[4], node[5], node[6], node[7] );
157       }
158       else if (nbnode == 9) {
159         if ( ID >= 1 ) e = mesh->AddFaceWithID(node[0], node[1], node[2], node[3],
160                                                node[4], node[5], node[6], node[7], node[8], ID);
161         else           e = mesh->AddFace      (node[0], node[1], node[2], node[3],
162                                                node[4], node[5], node[6], node[7], node[8] );
163       }
164     } else {
165       if ( ID >= 1 ) e = mesh->AddPolygonalFaceWithID(node, ID);
166       else           e = mesh->AddPolygonalFace      (node    );
167     }
168     break;
169
170   case SMDSAbs_Volume:
171     if ( !isPoly ) {
172       if      (nbnode == 4) {
173         if ( ID >= 1 ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3], ID);
174         else           e = mesh->AddVolume      (node[0], node[1], node[2], node[3] );
175       }
176       else if (nbnode == 5) {
177         if ( ID >= 1 ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
178                                                  node[4], ID);
179         else           e = mesh->AddVolume      (node[0], node[1], node[2], node[3],
180                                                  node[4] );
181       }
182       else if (nbnode == 6) {
183         if ( ID >= 1 ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
184                                                  node[4], node[5], ID);
185         else           e = mesh->AddVolume      (node[0], node[1], node[2], node[3],
186                                                  node[4], node[5] );
187       }
188       else if (nbnode == 8) {
189         if ( ID >= 1 ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
190                                                  node[4], node[5], node[6], node[7], ID);
191         else           e = mesh->AddVolume      (node[0], node[1], node[2], node[3],
192                                                  node[4], node[5], node[6], node[7] );
193       }
194       else if (nbnode == 10) {
195         if ( ID >= 1 ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
196                                                  node[4], node[5], node[6], node[7],
197                                                  node[8], node[9], ID);
198         else           e = mesh->AddVolume      (node[0], node[1], node[2], node[3],
199                                                  node[4], node[5], node[6], node[7],
200                                                  node[8], node[9] );
201       }
202       else if (nbnode == 12) {
203         if ( ID >= 1 ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
204                                                  node[4], node[5], node[6], node[7],
205                                                  node[8], node[9], node[10], node[11], ID);
206         else           e = mesh->AddVolume      (node[0], node[1], node[2], node[3],
207                                                  node[4], node[5], node[6], node[7],
208                                                  node[8], node[9], node[10], node[11] );
209       }
210       else if (nbnode == 13) {
211         if ( ID >= 1 ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
212                                                  node[4], node[5], node[6], node[7],
213                                                  node[8], node[9], node[10],node[11],
214                                                  node[12],ID);
215         else           e = mesh->AddVolume      (node[0], node[1], node[2], node[3],
216                                                  node[4], node[5], node[6], node[7],
217                                                  node[8], node[9], node[10],node[11],
218                                                  node[12] );
219       }
220       else if (nbnode == 15) {
221         if ( ID >= 1 ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
222                                                  node[4], node[5], node[6], node[7],
223                                                  node[8], node[9], node[10],node[11],
224                                                  node[12],node[13],node[14],ID);
225         else           e = mesh->AddVolume      (node[0], node[1], node[2], node[3],
226                                                  node[4], node[5], node[6], node[7],
227                                                  node[8], node[9], node[10],node[11],
228                                                  node[12],node[13],node[14] );
229       }
230       else if (nbnode == 20) {
231         if ( ID >= 1 ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
232                                                  node[4], node[5], node[6], node[7],
233                                                  node[8], node[9], node[10],node[11],
234                                                  node[12],node[13],node[14],node[15],
235                                                  node[16],node[17],node[18],node[19],ID);
236         else           e = mesh->AddVolume      (node[0], node[1], node[2], node[3],
237                                                  node[4], node[5], node[6], node[7],
238                                                  node[8], node[9], node[10],node[11],
239                                                  node[12],node[13],node[14],node[15],
240                                                  node[16],node[17],node[18],node[19] );
241       }
242       else if (nbnode == 27) {
243         if ( ID >= 1 ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
244                                                  node[4], node[5], node[6], node[7],
245                                                  node[8], node[9], node[10],node[11],
246                                                  node[12],node[13],node[14],node[15],
247                                                  node[16],node[17],node[18],node[19],
248                                                  node[20],node[21],node[22],node[23],
249                                                  node[24],node[25],node[26], ID);
250         else           e = mesh->AddVolume      (node[0], node[1], node[2], node[3],
251                                                  node[4], node[5], node[6], node[7],
252                                                  node[8], node[9], node[10],node[11],
253                                                  node[12],node[13],node[14],node[15],
254                                                  node[16],node[17],node[18],node[19],
255                                                  node[20],node[21],node[22],node[23],
256                                                  node[24],node[25],node[26] );
257       }
258     }
259     break;
260
261   case SMDSAbs_Edge:
262     if ( nbnode == 2 ) {
263       if ( ID >= 1 ) e = mesh->AddEdgeWithID(node[0], node[1], ID);
264       else           e = mesh->AddEdge      (node[0], node[1] );
265     }
266     else if ( nbnode == 3 ) {
267       if ( ID >= 1 ) e = mesh->AddEdgeWithID(node[0], node[1], node[2], ID);
268       else           e = mesh->AddEdge      (node[0], node[1], node[2] );
269     }
270     break;
271
272   case SMDSAbs_0DElement:
273     if ( nbnode == 1 ) {
274       if ( ID >= 1 ) e = mesh->Add0DElementWithID(node[0], ID);
275       else           e = mesh->Add0DElement      (node[0] );
276     }
277     break;
278
279   case SMDSAbs_Node:
280     if ( ID >= 1 ) e = mesh->AddNodeWithID(node[0]->X(), node[0]->Y(), node[0]->Z(), ID);
281     else           e = mesh->AddNode      (node[0]->X(), node[0]->Y(), node[0]->Z());
282     break;
283
284   default:;
285   }
286   if ( e ) myLastCreatedElems.Append( e );
287   return e;
288 }
289
290 //=======================================================================
291 /*!
292  * \brief Add element
293  */
294 //=======================================================================
295
296 SMDS_MeshElement* SMESH_MeshEditor::AddElement(const vector<int> &       nodeIDs,
297                                                const SMDSAbs_ElementType type,
298                                                const bool                isPoly,
299                                                const int                 ID)
300 {
301   vector<const SMDS_MeshNode*> nodes;
302   nodes.reserve( nodeIDs.size() );
303   vector<int>::const_iterator id = nodeIDs.begin();
304   while ( id != nodeIDs.end() ) {
305     if ( const SMDS_MeshNode* node = GetMeshDS()->FindNode( *id++ ))
306       nodes.push_back( node );
307     else
308       return 0;
309   }
310   return AddElement( nodes, type, isPoly, ID );
311 }
312
313 //=======================================================================
314 //function : Remove
315 //purpose  : Remove a node or an element.
316 //           Modify a compute state of sub-meshes which become empty
317 //=======================================================================
318
319 int SMESH_MeshEditor::Remove (const list< int >& theIDs,
320                               const bool         isNodes )
321 {
322   myLastCreatedElems.Clear();
323   myLastCreatedNodes.Clear();
324
325   SMESHDS_Mesh* aMesh = GetMeshDS();
326   set< SMESH_subMesh *> smmap;
327
328   int removed = 0;
329   list<int>::const_iterator it = theIDs.begin();
330   for ( ; it != theIDs.end(); it++ ) {
331     const SMDS_MeshElement * elem;
332     if ( isNodes )
333       elem = aMesh->FindNode( *it );
334     else
335       elem = aMesh->FindElement( *it );
336     if ( !elem )
337       continue;
338
339     // Notify VERTEX sub-meshes about modification
340     if ( isNodes ) {
341       const SMDS_MeshNode* node = cast2Node( elem );
342       if ( node->GetPosition()->GetTypeOfPosition() == SMDS_TOP_VERTEX )
343         if ( int aShapeID = node->getshapeId() )
344           if ( SMESH_subMesh * sm = GetMesh()->GetSubMeshContaining( aShapeID ) )
345             smmap.insert( sm );
346     }
347     // Find sub-meshes to notify about modification
348     //     SMDS_ElemIteratorPtr nodeIt = elem->nodesIterator();
349     //     while ( nodeIt->more() ) {
350     //       const SMDS_MeshNode* node = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
351     //       const SMDS_PositionPtr& aPosition = node->GetPosition();
352     //       if ( aPosition.get() ) {
353     //         if ( int aShapeID = aPosition->GetShapeId() ) {
354     //           if ( SMESH_subMesh * sm = GetMesh()->GetSubMeshContaining( aShapeID ) )
355     //             smmap.insert( sm );
356     //         }
357     //       }
358     //     }
359
360     // Do remove
361     if ( isNodes )
362       aMesh->RemoveNode( static_cast< const SMDS_MeshNode* >( elem ));
363     else
364       aMesh->RemoveElement( elem );
365     removed++;
366   }
367
368   // Notify sub-meshes about modification
369   if ( !smmap.empty() ) {
370     set< SMESH_subMesh *>::iterator smIt;
371     for ( smIt = smmap.begin(); smIt != smmap.end(); smIt++ )
372       (*smIt)->ComputeStateEngine( SMESH_subMesh::MESH_ENTITY_REMOVED );
373   }
374
375   //   // Check if the whole mesh becomes empty
376   //   if ( SMESH_subMesh * sm = GetMesh()->GetSubMeshContaining( 1 ) )
377   //     sm->ComputeStateEngine( SMESH_subMesh::CHECK_COMPUTE_STATE );
378
379   return removed;
380 }
381
382 //=======================================================================
383 //function : FindShape
384 //purpose  : Return an index of the shape theElem is on
385 //           or zero if a shape not found
386 //=======================================================================
387
388 int SMESH_MeshEditor::FindShape (const SMDS_MeshElement * theElem)
389 {
390   myLastCreatedElems.Clear();
391   myLastCreatedNodes.Clear();
392
393   SMESHDS_Mesh * aMesh = GetMeshDS();
394   if ( aMesh->ShapeToMesh().IsNull() )
395     return 0;
396
397   int aShapeID = theElem->getshapeId();
398   if ( aShapeID < 1 )
399     return 0;
400
401   if ( SMESHDS_SubMesh * sm = aMesh->MeshElements( aShapeID ))
402     if ( sm->Contains( theElem ))
403       return aShapeID;
404
405   if ( theElem->GetType() == SMDSAbs_Node ) {
406     MESSAGE( ":( Error: invalid myShapeId of node " << theElem->GetID() );
407   }
408   else {
409     MESSAGE( ":( Error: invalid myShapeId of element " << theElem->GetID() );
410   }
411
412   TopoDS_Shape aShape; // the shape a node of theElem is on
413   if ( theElem->GetType() != SMDSAbs_Node )
414   {
415     SMDS_ElemIteratorPtr nodeIt = theElem->nodesIterator();
416     while ( nodeIt->more() ) {
417       const SMDS_MeshNode* node = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
418       if ((aShapeID = node->getshapeId()) > 0) {
419         if ( SMESHDS_SubMesh * sm = aMesh->MeshElements( aShapeID ) ) {
420           if ( sm->Contains( theElem ))
421             return aShapeID;
422           if ( aShape.IsNull() )
423             aShape = aMesh->IndexToShape( aShapeID );
424         }
425       }
426     }
427   }
428
429   // None of nodes is on a proper shape,
430   // find the shape among ancestors of aShape on which a node is
431   if ( !aShape.IsNull() ) {
432     TopTools_ListIteratorOfListOfShape ancIt( GetMesh()->GetAncestors( aShape ));
433     for ( ; ancIt.More(); ancIt.Next() ) {
434       SMESHDS_SubMesh * sm = aMesh->MeshElements( ancIt.Value() );
435       if ( sm && sm->Contains( theElem ))
436         return aMesh->ShapeToIndex( ancIt.Value() );
437     }
438   }
439   else
440   {
441     const map<int,SMESHDS_SubMesh*>& id2sm = GetMeshDS()->SubMeshes();
442     map<int,SMESHDS_SubMesh*>::const_iterator id_sm = id2sm.begin();
443     for ( ; id_sm != id2sm.end(); ++id_sm )
444       if ( id_sm->second->Contains( theElem ))
445         return id_sm->first;
446   }
447
448   //MESSAGE ("::FindShape() - SHAPE NOT FOUND")
449   return 0;
450 }
451
452 //=======================================================================
453 //function : IsMedium
454 //purpose  :
455 //=======================================================================
456
457 bool SMESH_MeshEditor::IsMedium(const SMDS_MeshNode*      node,
458                                 const SMDSAbs_ElementType typeToCheck)
459 {
460   bool isMedium = false;
461   SMDS_ElemIteratorPtr it = node->GetInverseElementIterator(typeToCheck);
462   while (it->more() && !isMedium ) {
463     const SMDS_MeshElement* elem = it->next();
464     isMedium = elem->IsMediumNode(node);
465   }
466   return isMedium;
467 }
468
469 //=======================================================================
470 //function : ShiftNodesQuadTria
471 //purpose  : auxilary
472 //           Shift nodes in the array corresponded to quadratic triangle
473 //           example: (0,1,2,3,4,5) -> (1,2,0,4,5,3)
474 //=======================================================================
475 static void ShiftNodesQuadTria(const SMDS_MeshNode* aNodes[])
476 {
477   const SMDS_MeshNode* nd1 = aNodes[0];
478   aNodes[0] = aNodes[1];
479   aNodes[1] = aNodes[2];
480   aNodes[2] = nd1;
481   const SMDS_MeshNode* nd2 = aNodes[3];
482   aNodes[3] = aNodes[4];
483   aNodes[4] = aNodes[5];
484   aNodes[5] = nd2;
485 }
486
487 //=======================================================================
488 //function : edgeConnectivity
489 //purpose  : auxilary 
490 //           return number of the edges connected with the theNode.
491 //           if theEdges has connections with the other type of the
492 //           elements, return -1 
493 //=======================================================================
494 static int nbEdgeConnectivity(const SMDS_MeshNode* theNode)
495 {
496   SMDS_ElemIteratorPtr elemIt = theNode->GetInverseElementIterator();
497   int nb=0;
498   while(elemIt->more()) {
499     elemIt->next();
500     nb++;
501   }
502   return nb;
503 }
504
505
506 //=======================================================================
507 //function : GetNodesFromTwoTria
508 //purpose  : auxilary
509 //           Shift nodes in the array corresponded to quadratic triangle
510 //           example: (0,1,2,3,4,5) -> (1,2,0,4,5,3)
511 //=======================================================================
512 static bool GetNodesFromTwoTria(const SMDS_MeshElement * theTria1,
513                                 const SMDS_MeshElement * theTria2,
514                                 const SMDS_MeshNode* N1[],
515                                 const SMDS_MeshNode* N2[])
516 {
517   SMDS_ElemIteratorPtr it = theTria1->nodesIterator();
518   int i=0;
519   while(i<6) {
520     N1[i] = static_cast<const SMDS_MeshNode*>( it->next() );
521     i++;
522   }
523   if(it->more()) return false;
524   it = theTria2->nodesIterator();
525   i=0;
526   while(i<6) {
527     N2[i] = static_cast<const SMDS_MeshNode*>( it->next() );
528     i++;
529   }
530   if(it->more()) return false;
531
532   int sames[3] = {-1,-1,-1};
533   int nbsames = 0;
534   int j;
535   for(i=0; i<3; i++) {
536     for(j=0; j<3; j++) {
537       if(N1[i]==N2[j]) {
538         sames[i] = j;
539         nbsames++;
540         break;
541       }
542     }
543   }
544   if(nbsames!=2) return false;
545   if(sames[0]>-1) {
546     ShiftNodesQuadTria(N1);
547     if(sames[1]>-1) {
548       ShiftNodesQuadTria(N1);
549     }
550   }
551   i = sames[0] + sames[1] + sames[2];
552   for(; i<2; i++) {
553     ShiftNodesQuadTria(N2);
554   }
555   // now we receive following N1 and N2 (using numeration as above image)
556   // tria1 : (1 2 4 5 9 7)  and  tria2 : (3 4 2 8 9 6)
557   // i.e. first nodes from both arrays determ new diagonal
558   return true;
559 }
560
561 //=======================================================================
562 //function : InverseDiag
563 //purpose  : Replace two neighbour triangles with ones built on the same 4 nodes
564 //           but having other common link.
565 //           Return False if args are improper
566 //=======================================================================
567
568 bool SMESH_MeshEditor::InverseDiag (const SMDS_MeshElement * theTria1,
569                                     const SMDS_MeshElement * theTria2 )
570 {
571   MESSAGE("InverseDiag");
572   myLastCreatedElems.Clear();
573   myLastCreatedNodes.Clear();
574
575   if (!theTria1 || !theTria2)
576     return false;
577
578   const SMDS_VtkFace* F1 = dynamic_cast<const SMDS_VtkFace*>( theTria1 );
579   if (!F1) return false;
580   const SMDS_VtkFace* F2 = dynamic_cast<const SMDS_VtkFace*>( theTria2 );
581   if (!F2) return false;
582   if ((theTria1->GetEntityType() == SMDSEntity_Triangle) &&
583       (theTria2->GetEntityType() == SMDSEntity_Triangle)) {
584
585     //  1 +--+ A  theTria1: ( 1 A B ) A->2 ( 1 2 B ) 1 +--+ A
586     //    | /|    theTria2: ( B A 2 ) B->1 ( 1 A 2 )   |\ |
587     //    |/ |                                         | \|
588     //  B +--+ 2                                     B +--+ 2
589
590     // put nodes in array and find out indices of the same ones
591     const SMDS_MeshNode* aNodes [6];
592     int sameInd [] = { 0, 0, 0, 0, 0, 0 };
593     int i = 0;
594     SMDS_ElemIteratorPtr it = theTria1->nodesIterator();
595     while ( it->more() ) {
596       aNodes[ i ] = static_cast<const SMDS_MeshNode*>( it->next() );
597
598       if ( i > 2 ) // theTria2
599         // find same node of theTria1
600         for ( int j = 0; j < 3; j++ )
601           if ( aNodes[ i ] == aNodes[ j ]) {
602             sameInd[ j ] = i;
603             sameInd[ i ] = j;
604             break;
605           }
606       // next
607       i++;
608       if ( i == 3 ) {
609         if ( it->more() )
610           return false; // theTria1 is not a triangle
611         it = theTria2->nodesIterator();
612       }
613       if ( i == 6 && it->more() )
614         return false; // theTria2 is not a triangle
615     }
616
617     // find indices of 1,2 and of A,B in theTria1
618     int iA = 0, iB = 0, i1 = 0, i2 = 0;
619     for ( i = 0; i < 6; i++ ) {
620       if ( sameInd [ i ] == 0 ) {
621         if ( i < 3 ) i1 = i;
622         else         i2 = i;
623       }
624       else if (i < 3) {
625         if ( iA ) iB = i;
626         else      iA = i;
627       }
628     }
629     // nodes 1 and 2 should not be the same
630     if ( aNodes[ i1 ] == aNodes[ i2 ] )
631       return false;
632
633     // theTria1: A->2
634     aNodes[ iA ] = aNodes[ i2 ];
635     // theTria2: B->1
636     aNodes[ sameInd[ iB ]] = aNodes[ i1 ];
637
638     GetMeshDS()->ChangeElementNodes( theTria1, aNodes, 3 );
639     GetMeshDS()->ChangeElementNodes( theTria2, &aNodes[ 3 ], 3 );
640
641     return true;
642
643   } // end if(F1 && F2)
644
645   // check case of quadratic faces
646   if (theTria1->GetEntityType() != SMDSEntity_Quad_Triangle)
647     return false;
648   if (theTria2->GetEntityType() != SMDSEntity_Quad_Triangle)
649     return false;
650
651   //       5
652   //  1 +--+--+ 2  theTria1: (1 2 4 5 9 7) or (2 4 1 9 7 5) or (4 1 2 7 5 9)
653   //    |    /|    theTria2: (2 3 4 6 8 9) or (3 4 2 8 9 6) or (4 2 3 9 6 8)
654   //    |   / |
655   //  7 +  +  + 6
656   //    | /9  |
657   //    |/    |
658   //  4 +--+--+ 3
659   //       8
660
661   const SMDS_MeshNode* N1 [6];
662   const SMDS_MeshNode* N2 [6];
663   if(!GetNodesFromTwoTria(theTria1,theTria2,N1,N2))
664     return false;
665   // now we receive following N1 and N2 (using numeration as above image)
666   // tria1 : (1 2 4 5 9 7)  and  tria2 : (3 4 2 8 9 6)
667   // i.e. first nodes from both arrays determ new diagonal
668
669   const SMDS_MeshNode* N1new [6];
670   const SMDS_MeshNode* N2new [6];
671   N1new[0] = N1[0];
672   N1new[1] = N2[0];
673   N1new[2] = N2[1];
674   N1new[3] = N1[4];
675   N1new[4] = N2[3];
676   N1new[5] = N1[5];
677   N2new[0] = N1[0];
678   N2new[1] = N1[1];
679   N2new[2] = N2[0];
680   N2new[3] = N1[3];
681   N2new[4] = N2[5];
682   N2new[5] = N1[4];
683   // replaces nodes in faces
684   GetMeshDS()->ChangeElementNodes( theTria1, N1new, 6 );
685   GetMeshDS()->ChangeElementNodes( theTria2, N2new, 6 );
686
687   return true;
688 }
689
690 //=======================================================================
691 //function : findTriangles
692 //purpose  : find triangles sharing theNode1-theNode2 link
693 //=======================================================================
694
695 static bool findTriangles(const SMDS_MeshNode *    theNode1,
696                           const SMDS_MeshNode *    theNode2,
697                           const SMDS_MeshElement*& theTria1,
698                           const SMDS_MeshElement*& theTria2)
699 {
700   if ( !theNode1 || !theNode2 ) return false;
701
702   theTria1 = theTria2 = 0;
703
704   set< const SMDS_MeshElement* > emap;
705   SMDS_ElemIteratorPtr it = theNode1->GetInverseElementIterator(SMDSAbs_Face);
706   while (it->more()) {
707     const SMDS_MeshElement* elem = it->next();
708     if ( elem->NbNodes() == 3 )
709       emap.insert( elem );
710   }
711   it = theNode2->GetInverseElementIterator(SMDSAbs_Face);
712   while (it->more()) {
713     const SMDS_MeshElement* elem = it->next();
714     if ( emap.find( elem ) != emap.end() ) {
715       if ( theTria1 ) {
716         // theTria1 must be element with minimum ID
717         if( theTria1->GetID() < elem->GetID() ) {
718           theTria2 = elem;
719         }
720         else {
721           theTria2 = theTria1;
722           theTria1 = elem;
723         }
724         break;
725       }
726       else {
727         theTria1 = elem;
728       }
729     }
730   }
731   return ( theTria1 && theTria2 );
732 }
733
734 //=======================================================================
735 //function : InverseDiag
736 //purpose  : Replace two neighbour triangles sharing theNode1-theNode2 link
737 //           with ones built on the same 4 nodes but having other common link.
738 //           Return false if proper faces not found
739 //=======================================================================
740
741 bool SMESH_MeshEditor::InverseDiag (const SMDS_MeshNode * theNode1,
742                                     const SMDS_MeshNode * theNode2)
743 {
744   myLastCreatedElems.Clear();
745   myLastCreatedNodes.Clear();
746
747   MESSAGE( "::InverseDiag()" );
748
749   const SMDS_MeshElement *tr1, *tr2;
750   if ( !findTriangles( theNode1, theNode2, tr1, tr2 ))
751     return false;
752
753   const SMDS_VtkFace* F1 = dynamic_cast<const SMDS_VtkFace*>( tr1 );
754   if (!F1) return false;
755   const SMDS_VtkFace* F2 = dynamic_cast<const SMDS_VtkFace*>( tr2 );
756   if (!F2) return false;
757   if ((tr1->GetEntityType() == SMDSEntity_Triangle) &&
758       (tr2->GetEntityType() == SMDSEntity_Triangle)) {
759
760     //  1 +--+ A  tr1: ( 1 A B ) A->2 ( 1 2 B ) 1 +--+ A
761     //    | /|    tr2: ( B A 2 ) B->1 ( 1 A 2 )   |\ |
762     //    |/ |                                    | \|
763     //  B +--+ 2                                B +--+ 2
764
765     // put nodes in array
766     // and find indices of 1,2 and of A in tr1 and of B in tr2
767     int i, iA1 = 0, i1 = 0;
768     const SMDS_MeshNode* aNodes1 [3];
769     SMDS_ElemIteratorPtr it;
770     for (i = 0, it = tr1->nodesIterator(); it->more(); i++ ) {
771       aNodes1[ i ] = static_cast<const SMDS_MeshNode*>( it->next() );
772       if ( aNodes1[ i ] == theNode1 )
773         iA1 = i; // node A in tr1
774       else if ( aNodes1[ i ] != theNode2 )
775         i1 = i;  // node 1
776     }
777     int iB2 = 0, i2 = 0;
778     const SMDS_MeshNode* aNodes2 [3];
779     for (i = 0, it = tr2->nodesIterator(); it->more(); i++ ) {
780       aNodes2[ i ] = static_cast<const SMDS_MeshNode*>( it->next() );
781       if ( aNodes2[ i ] == theNode2 )
782         iB2 = i; // node B in tr2
783       else if ( aNodes2[ i ] != theNode1 )
784         i2 = i;  // node 2
785     }
786
787     // nodes 1 and 2 should not be the same
788     if ( aNodes1[ i1 ] == aNodes2[ i2 ] )
789       return false;
790
791     // tr1: A->2
792     aNodes1[ iA1 ] = aNodes2[ i2 ];
793     // tr2: B->1
794     aNodes2[ iB2 ] = aNodes1[ i1 ];
795
796     GetMeshDS()->ChangeElementNodes( tr1, aNodes1, 3 );
797     GetMeshDS()->ChangeElementNodes( tr2, aNodes2, 3 );
798
799     return true;
800   }
801
802   // check case of quadratic faces
803   return InverseDiag(tr1,tr2);
804 }
805
806 //=======================================================================
807 //function : getQuadrangleNodes
808 //purpose  : fill theQuadNodes - nodes of a quadrangle resulting from
809 //           fusion of triangles tr1 and tr2 having shared link on
810 //           theNode1 and theNode2
811 //=======================================================================
812
813 bool getQuadrangleNodes(const SMDS_MeshNode *    theQuadNodes [],
814                         const SMDS_MeshNode *    theNode1,
815                         const SMDS_MeshNode *    theNode2,
816                         const SMDS_MeshElement * tr1,
817                         const SMDS_MeshElement * tr2 )
818 {
819   if( tr1->NbNodes() != tr2->NbNodes() )
820     return false;
821   // find the 4-th node to insert into tr1
822   const SMDS_MeshNode* n4 = 0;
823   SMDS_ElemIteratorPtr it = tr2->nodesIterator();
824   int i=0;
825   while ( !n4 && i<3 ) {
826     const SMDS_MeshNode * n = cast2Node( it->next() );
827     i++;
828     bool isDiag = ( n == theNode1 || n == theNode2 );
829     if ( !isDiag )
830       n4 = n;
831   }
832   // Make an array of nodes to be in a quadrangle
833   int iNode = 0, iFirstDiag = -1;
834   it = tr1->nodesIterator();
835   i=0;
836   while ( i<3 ) {
837     const SMDS_MeshNode * n = cast2Node( it->next() );
838     i++;
839     bool isDiag = ( n == theNode1 || n == theNode2 );
840     if ( isDiag ) {
841       if ( iFirstDiag < 0 )
842         iFirstDiag = iNode;
843       else if ( iNode - iFirstDiag == 1 )
844         theQuadNodes[ iNode++ ] = n4; // insert the 4-th node between diagonal nodes
845     }
846     else if ( n == n4 ) {
847       return false; // tr1 and tr2 should not have all the same nodes
848     }
849     theQuadNodes[ iNode++ ] = n;
850   }
851   if ( iNode == 3 ) // diagonal nodes have 0 and 2 indices
852     theQuadNodes[ iNode ] = n4;
853
854   return true;
855 }
856
857 //=======================================================================
858 //function : DeleteDiag
859 //purpose  : Replace two neighbour triangles sharing theNode1-theNode2 link
860 //           with a quadrangle built on the same 4 nodes.
861 //           Return false if proper faces not found
862 //=======================================================================
863
864 bool SMESH_MeshEditor::DeleteDiag (const SMDS_MeshNode * theNode1,
865                                    const SMDS_MeshNode * theNode2)
866 {
867   myLastCreatedElems.Clear();
868   myLastCreatedNodes.Clear();
869
870   MESSAGE( "::DeleteDiag()" );
871
872   const SMDS_MeshElement *tr1, *tr2;
873   if ( !findTriangles( theNode1, theNode2, tr1, tr2 ))
874     return false;
875
876   const SMDS_VtkFace* F1 = dynamic_cast<const SMDS_VtkFace*>( tr1 );
877   if (!F1) return false;
878   const SMDS_VtkFace* F2 = dynamic_cast<const SMDS_VtkFace*>( tr2 );
879   if (!F2) return false;
880   SMESHDS_Mesh * aMesh = GetMeshDS();
881
882   if ((tr1->GetEntityType() == SMDSEntity_Triangle) &&
883       (tr2->GetEntityType() == SMDSEntity_Triangle)) {
884
885     const SMDS_MeshNode* aNodes [ 4 ];
886     if ( ! getQuadrangleNodes( aNodes, theNode1, theNode2, tr1, tr2 ))
887       return false;
888
889     const SMDS_MeshElement* newElem = 0;
890     newElem = aMesh->AddFace( aNodes[0], aNodes[1], aNodes[2], aNodes[3] );
891     myLastCreatedElems.Append(newElem);
892     AddToSameGroups( newElem, tr1, aMesh );
893     int aShapeId = tr1->getshapeId();
894     if ( aShapeId )
895       {
896         aMesh->SetMeshElementOnShape( newElem, aShapeId );
897       }
898     aMesh->RemoveElement( tr1 );
899     aMesh->RemoveElement( tr2 );
900
901     return true;
902   }
903
904   // check case of quadratic faces
905   if (tr1->GetEntityType() != SMDSEntity_Quad_Triangle)
906     return false;
907   if (tr2->GetEntityType() != SMDSEntity_Quad_Triangle)
908     return false;
909
910   //       5
911   //  1 +--+--+ 2  tr1: (1 2 4 5 9 7) or (2 4 1 9 7 5) or (4 1 2 7 5 9)
912   //    |    /|    tr2: (2 3 4 6 8 9) or (3 4 2 8 9 6) or (4 2 3 9 6 8)
913   //    |   / |
914   //  7 +  +  + 6
915   //    | /9  |
916   //    |/    |
917   //  4 +--+--+ 3
918   //       8
919
920   const SMDS_MeshNode* N1 [6];
921   const SMDS_MeshNode* N2 [6];
922   if(!GetNodesFromTwoTria(tr1,tr2,N1,N2))
923     return false;
924   // now we receive following N1 and N2 (using numeration as above image)
925   // tria1 : (1 2 4 5 9 7)  and  tria2 : (3 4 2 8 9 6)
926   // i.e. first nodes from both arrays determ new diagonal
927
928   const SMDS_MeshNode* aNodes[8];
929   aNodes[0] = N1[0];
930   aNodes[1] = N1[1];
931   aNodes[2] = N2[0];
932   aNodes[3] = N2[1];
933   aNodes[4] = N1[3];
934   aNodes[5] = N2[5];
935   aNodes[6] = N2[3];
936   aNodes[7] = N1[5];
937
938   const SMDS_MeshElement* newElem = 0;
939   newElem = aMesh->AddFace( aNodes[0], aNodes[1], aNodes[2], aNodes[3],
940                             aNodes[4], aNodes[5], aNodes[6], aNodes[7]);
941   myLastCreatedElems.Append(newElem);
942   AddToSameGroups( newElem, tr1, aMesh );
943   int aShapeId = tr1->getshapeId();
944   if ( aShapeId )
945     {
946       aMesh->SetMeshElementOnShape( newElem, aShapeId );
947     }
948   aMesh->RemoveElement( tr1 );
949   aMesh->RemoveElement( tr2 );
950
951   // remove middle node (9)
952   GetMeshDS()->RemoveNode( N1[4] );
953
954   return true;
955 }
956
957 //=======================================================================
958 //function : Reorient
959 //purpose  : Reverse theElement orientation
960 //=======================================================================
961
962 bool SMESH_MeshEditor::Reorient (const SMDS_MeshElement * theElem)
963 {
964   MESSAGE("Reorient");
965   myLastCreatedElems.Clear();
966   myLastCreatedNodes.Clear();
967
968   if (!theElem)
969     return false;
970   SMDS_ElemIteratorPtr it = theElem->nodesIterator();
971   if ( !it || !it->more() )
972     return false;
973
974   switch ( theElem->GetType() ) {
975
976   case SMDSAbs_Edge:
977   case SMDSAbs_Face: {
978     if(!theElem->IsQuadratic()) {
979       int i = theElem->NbNodes();
980       vector<const SMDS_MeshNode*> aNodes( i );
981       while ( it->more() )
982         aNodes[ --i ]= static_cast<const SMDS_MeshNode*>( it->next() );
983       return GetMeshDS()->ChangeElementNodes( theElem, &aNodes[0], theElem->NbNodes() );
984     }
985     else {
986       // quadratic elements
987       if(theElem->GetType()==SMDSAbs_Edge) {
988         vector<const SMDS_MeshNode*> aNodes(3);
989         aNodes[1]= static_cast<const SMDS_MeshNode*>( it->next() );
990         aNodes[0]= static_cast<const SMDS_MeshNode*>( it->next() );
991         aNodes[2]= static_cast<const SMDS_MeshNode*>( it->next() );
992         return GetMeshDS()->ChangeElementNodes( theElem, &aNodes[0], 3 );
993       }
994       else {
995         int nbn = theElem->NbNodes();
996         vector<const SMDS_MeshNode*> aNodes(nbn);
997         aNodes[0]= static_cast<const SMDS_MeshNode*>( it->next() );
998         int i=1;
999         for(; i<nbn/2; i++) {
1000           aNodes[nbn/2-i]= static_cast<const SMDS_MeshNode*>( it->next() );
1001         }
1002         for(i=0; i<nbn/2; i++) {
1003           aNodes[nbn-i-1]= static_cast<const SMDS_MeshNode*>( it->next() );
1004         }
1005         return GetMeshDS()->ChangeElementNodes( theElem, &aNodes[0], nbn );
1006       }
1007     }
1008   }
1009   case SMDSAbs_Volume: {
1010     if (theElem->IsPoly()) {
1011       // TODO reorient vtk polyhedron
1012       MESSAGE("reorient vtk polyhedron ?");
1013       const SMDS_VtkVolume* aPolyedre =
1014         dynamic_cast<const SMDS_VtkVolume*>( theElem );
1015       if (!aPolyedre) {
1016         MESSAGE("Warning: bad volumic element");
1017         return false;
1018       }
1019
1020       int nbFaces = aPolyedre->NbFaces();
1021       vector<const SMDS_MeshNode *> poly_nodes;
1022       vector<int> quantities (nbFaces);
1023
1024       // reverse each face of the polyedre
1025       for (int iface = 1; iface <= nbFaces; iface++) {
1026         int inode, nbFaceNodes = aPolyedre->NbFaceNodes(iface);
1027         quantities[iface - 1] = nbFaceNodes;
1028
1029         for (inode = nbFaceNodes; inode >= 1; inode--) {
1030           const SMDS_MeshNode* curNode = aPolyedre->GetFaceNode(iface, inode);
1031           poly_nodes.push_back(curNode);
1032         }
1033       }
1034
1035       return GetMeshDS()->ChangePolyhedronNodes( theElem, poly_nodes, quantities );
1036
1037     }
1038     else {
1039       SMDS_VolumeTool vTool;
1040       if ( !vTool.Set( theElem ))
1041         return false;
1042       vTool.Inverse();
1043       MESSAGE("ChangeElementNodes reorient: check vTool.Inverse");
1044       return GetMeshDS()->ChangeElementNodes( theElem, vTool.GetNodes(), vTool.NbNodes() );
1045     }
1046   }
1047   default:;
1048   }
1049
1050   return false;
1051 }
1052
1053 //=======================================================================
1054 //function : getBadRate
1055 //purpose  :
1056 //=======================================================================
1057
1058 static double getBadRate (const SMDS_MeshElement*               theElem,
1059                           SMESH::Controls::NumericalFunctorPtr& theCrit)
1060 {
1061   SMESH::Controls::TSequenceOfXYZ P;
1062   if ( !theElem || !theCrit->GetPoints( theElem, P ))
1063     return 1e100;
1064   return theCrit->GetBadRate( theCrit->GetValue( P ), theElem->NbNodes() );
1065   //return theCrit->GetBadRate( theCrit->GetValue( theElem->GetID() ), theElem->NbNodes() );
1066 }
1067
1068 //=======================================================================
1069 //function : QuadToTri
1070 //purpose  : Cut quadrangles into triangles.
1071 //           theCrit is used to select a diagonal to cut
1072 //=======================================================================
1073
1074 bool SMESH_MeshEditor::QuadToTri (TIDSortedElemSet &                   theElems,
1075                                   SMESH::Controls::NumericalFunctorPtr theCrit)
1076 {
1077   myLastCreatedElems.Clear();
1078   myLastCreatedNodes.Clear();
1079
1080   MESSAGE( "::QuadToTri()" );
1081
1082   if ( !theCrit.get() )
1083     return false;
1084
1085   SMESHDS_Mesh * aMesh = GetMeshDS();
1086
1087   Handle(Geom_Surface) surface;
1088   SMESH_MesherHelper   helper( *GetMesh() );
1089
1090   TIDSortedElemSet::iterator itElem;
1091   for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
1092     const SMDS_MeshElement* elem = *itElem;
1093     if ( !elem || elem->GetType() != SMDSAbs_Face )
1094       continue;
1095     if ( elem->NbCornerNodes() != 4 )
1096       continue;
1097
1098     // retrieve element nodes
1099     vector< const SMDS_MeshNode* > aNodes( elem->begin_nodes(), elem->end_nodes() );
1100
1101     // compare two sets of possible triangles
1102     double aBadRate1, aBadRate2; // to what extent a set is bad
1103     SMDS_FaceOfNodes tr1 ( aNodes[0], aNodes[1], aNodes[2] );
1104     SMDS_FaceOfNodes tr2 ( aNodes[2], aNodes[3], aNodes[0] );
1105     aBadRate1 = getBadRate( &tr1, theCrit ) + getBadRate( &tr2, theCrit );
1106
1107     SMDS_FaceOfNodes tr3 ( aNodes[1], aNodes[2], aNodes[3] );
1108     SMDS_FaceOfNodes tr4 ( aNodes[3], aNodes[0], aNodes[1] );
1109     aBadRate2 = getBadRate( &tr3, theCrit ) + getBadRate( &tr4, theCrit );
1110
1111     int aShapeId = FindShape( elem );
1112     const SMDS_MeshElement* newElem1 = 0;
1113     const SMDS_MeshElement* newElem2 = 0;
1114
1115     if( !elem->IsQuadratic() ) {
1116
1117       // split liner quadrangle
1118
1119       if ( aBadRate1 <= aBadRate2 ) {
1120         // tr1 + tr2 is better
1121         newElem1 = aMesh->AddFace( aNodes[2], aNodes[3], aNodes[0] );
1122         newElem2 = aMesh->AddFace( aNodes[2], aNodes[0], aNodes[1] );
1123       }
1124       else {
1125         // tr3 + tr4 is better
1126         newElem1 = aMesh->AddFace( aNodes[3], aNodes[0], aNodes[1] );
1127         newElem2 = aMesh->AddFace( aNodes[3], aNodes[1], aNodes[2] );
1128       }
1129     }
1130     else {
1131
1132       // split quadratic quadrangle
1133
1134       // get surface elem is on
1135       if ( aShapeId != helper.GetSubShapeID() ) {
1136         surface.Nullify();
1137         TopoDS_Shape shape;
1138         if ( aShapeId > 0 )
1139           shape = aMesh->IndexToShape( aShapeId );
1140         if ( !shape.IsNull() && shape.ShapeType() == TopAbs_FACE ) {
1141           TopoDS_Face face = TopoDS::Face( shape );
1142           surface = BRep_Tool::Surface( face );
1143           if ( !surface.IsNull() )
1144             helper.SetSubShape( shape );
1145         }
1146       }
1147       // find middle point for (0,1,2,3)
1148       // and create a node in this point;
1149       const SMDS_MeshNode* newN = 0;
1150       if ( aNodes.size() == 9 )
1151       {
1152         // SMDSEntity_BiQuad_Quadrangle
1153         newN = aNodes.back();
1154       }
1155       else
1156       {
1157         gp_XYZ p( 0,0,0 );
1158         if ( surface.IsNull() )
1159         {
1160           for ( int i = 0; i < 4; i++ )
1161             p += gp_XYZ(aNodes[i]->X(), aNodes[i]->Y(), aNodes[i]->Z() );
1162           p /= 4;
1163         }
1164         else
1165         {
1166           const SMDS_MeshNode* inFaceNode = 0;
1167           if ( helper.GetNodeUVneedInFaceNode() )
1168             for ( size_t i = 0; i < aNodes.size() && !inFaceNode; ++i )
1169               if ( aNodes[ i ]->GetPosition()->GetTypeOfPosition() == SMDS_TOP_FACE )
1170                 inFaceNode = aNodes[ i ];
1171
1172           TopoDS_Face face = TopoDS::Face( helper.GetSubShape() );
1173           gp_XY uv( 0,0 );
1174           for ( int i = 0; i < 4; i++ )
1175             uv += helper.GetNodeUV( face, aNodes[i], inFaceNode );
1176           uv /= 4.;
1177           p = surface->Value( uv.X(), uv.Y() ).XYZ();
1178         }
1179         newN = aMesh->AddNode( p.X(), p.Y(), p.Z() );
1180         myLastCreatedNodes.Append(newN);
1181       }
1182       // create a new element
1183       if ( aBadRate1 <= aBadRate2 ) {
1184         newElem1 = aMesh->AddFace(aNodes[2], aNodes[3], aNodes[0],
1185                                   aNodes[6], aNodes[7], newN );
1186         newElem2 = aMesh->AddFace(aNodes[2], aNodes[0], aNodes[1],
1187                                   newN,      aNodes[4], aNodes[5] );
1188       }
1189       else {
1190         newElem1 = aMesh->AddFace(aNodes[3], aNodes[0], aNodes[1],
1191                                   aNodes[7], aNodes[4], newN );
1192         newElem2 = aMesh->AddFace(aNodes[3], aNodes[1], aNodes[2],
1193                                   newN,      aNodes[5], aNodes[6] );
1194       }
1195     } // quadratic case
1196
1197     // care of a new element
1198
1199     myLastCreatedElems.Append(newElem1);
1200     myLastCreatedElems.Append(newElem2);
1201     AddToSameGroups( newElem1, elem, aMesh );
1202     AddToSameGroups( newElem2, elem, aMesh );
1203
1204     // put a new triangle on the same shape
1205     if ( aShapeId )
1206       {
1207         aMesh->SetMeshElementOnShape( newElem1, aShapeId );
1208         aMesh->SetMeshElementOnShape( newElem2, aShapeId );
1209       }
1210     aMesh->RemoveElement( elem );
1211   }
1212   return true;
1213 }
1214
1215 //=======================================================================
1216 //function : BestSplit
1217 //purpose  : Find better diagonal for cutting.
1218 //=======================================================================
1219
1220 int SMESH_MeshEditor::BestSplit (const SMDS_MeshElement*              theQuad,
1221                                  SMESH::Controls::NumericalFunctorPtr theCrit)
1222 {
1223   myLastCreatedElems.Clear();
1224   myLastCreatedNodes.Clear();
1225
1226   if (!theCrit.get())
1227     return -1;
1228
1229   if (!theQuad || theQuad->GetType() != SMDSAbs_Face )
1230     return -1;
1231
1232   if( theQuad->NbNodes()==4 ||
1233       (theQuad->NbNodes()==8 && theQuad->IsQuadratic()) ) {
1234
1235     // retrieve element nodes
1236     const SMDS_MeshNode* aNodes [4];
1237     SMDS_ElemIteratorPtr itN = theQuad->nodesIterator();
1238     int i = 0;
1239     //while (itN->more())
1240     while (i<4) {
1241       aNodes[ i++ ] = static_cast<const SMDS_MeshNode*>( itN->next() );
1242     }
1243     // compare two sets of possible triangles
1244     double aBadRate1, aBadRate2; // to what extent a set is bad
1245     SMDS_FaceOfNodes tr1 ( aNodes[0], aNodes[1], aNodes[2] );
1246     SMDS_FaceOfNodes tr2 ( aNodes[2], aNodes[3], aNodes[0] );
1247     aBadRate1 = getBadRate( &tr1, theCrit ) + getBadRate( &tr2, theCrit );
1248
1249     SMDS_FaceOfNodes tr3 ( aNodes[1], aNodes[2], aNodes[3] );
1250     SMDS_FaceOfNodes tr4 ( aNodes[3], aNodes[0], aNodes[1] );
1251     aBadRate2 = getBadRate( &tr3, theCrit ) + getBadRate( &tr4, theCrit );
1252
1253     if (aBadRate1 <= aBadRate2) // tr1 + tr2 is better
1254       return 1; // diagonal 1-3
1255
1256     return 2; // diagonal 2-4
1257   }
1258   return -1;
1259 }
1260
1261 namespace
1262 {
1263   // Methods of splitting volumes into tetra
1264
1265   const int theHexTo5_1[5*4+1] =
1266     {
1267       0, 1, 2, 5,    0, 4, 5, 7,     0, 2, 3, 7,    2, 5, 6, 7,     0, 5, 2, 7,   -1
1268     };
1269   const int theHexTo5_2[5*4+1] =
1270     {
1271       1, 2, 3, 6,    1, 4, 5, 6,     0, 1, 3, 4,    3, 4, 6, 7,     1, 3, 4, 6,   -1
1272     };
1273   const int* theHexTo5[2] = { theHexTo5_1, theHexTo5_2 };
1274
1275   const int theHexTo6_1[6*4+1] =
1276     {
1277       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
1278     };
1279   const int theHexTo6_2[6*4+1] =
1280     {
1281       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
1282     };
1283   const int theHexTo6_3[6*4+1] =
1284     {
1285       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
1286     };
1287   const int theHexTo6_4[6*4+1] =
1288     {
1289       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
1290     };
1291   const int* theHexTo6[4] = { theHexTo6_1, theHexTo6_2, theHexTo6_3, theHexTo6_4 };
1292
1293   const int thePyraTo2_1[2*4+1] =
1294     {
1295       0, 1, 2, 4,    0, 2, 3, 4,   -1
1296     };
1297   const int thePyraTo2_2[2*4+1] =
1298     {
1299       1, 2, 3, 4,    1, 3, 0, 4,   -1
1300     };
1301   const int* thePyraTo2[2] = { thePyraTo2_1, thePyraTo2_2 };
1302
1303   const int thePentaTo3_1[3*4+1] =
1304     {
1305       0, 1, 2, 3,    1, 3, 4, 2,     2, 3, 4, 5,    -1
1306     };
1307   const int thePentaTo3_2[3*4+1] =
1308     {
1309       1, 2, 0, 4,    2, 4, 5, 0,     0, 4, 5, 3,    -1
1310     };
1311   const int thePentaTo3_3[3*4+1] =
1312     {
1313       2, 0, 1, 5,    0, 5, 3, 1,     1, 5, 3, 4,    -1
1314     };
1315   const int thePentaTo3_4[3*4+1] =
1316     {
1317       0, 1, 2, 3,    1, 3, 4, 5,     2, 3, 1, 5,    -1
1318     };
1319   const int thePentaTo3_5[3*4+1] =
1320     {
1321       1, 2, 0, 4,    2, 4, 5, 3,     0, 4, 2, 3,    -1
1322     };
1323   const int thePentaTo3_6[3*4+1] =
1324     {
1325       2, 0, 1, 5,    0, 5, 3, 4,     1, 5, 0, 4,    -1
1326     };
1327   const int* thePentaTo3[6] = { thePentaTo3_1, thePentaTo3_2, thePentaTo3_3,
1328                                 thePentaTo3_4, thePentaTo3_5, thePentaTo3_6 };
1329
1330   struct TTriangleFacet //!< stores indices of three nodes of tetra facet
1331   {
1332     int _n1, _n2, _n3;
1333     TTriangleFacet(int n1, int n2, int n3): _n1(n1), _n2(n2), _n3(n3) {}
1334     bool contains(int n) const { return ( n == _n1 || n == _n2 || n == _n3 ); }
1335     bool hasAdjacentTetra( const SMDS_MeshElement* elem ) const;
1336   };
1337   struct TSplitMethod
1338   {
1339     int        _nbTetra;
1340     const int* _connectivity; //!< foursomes of tetra connectivy finished by -1
1341     bool       _baryNode;     //!< additional node is to be created at cell barycenter
1342     bool       _ownConn;      //!< to delete _connectivity in destructor
1343     map<int, const SMDS_MeshNode*> _faceBaryNode; //!< map face index to node at BC of face
1344
1345     TSplitMethod( int nbTet=0, const int* conn=0, bool addNode=false)
1346       : _nbTetra(nbTet), _connectivity(conn), _baryNode(addNode), _ownConn(false) {}
1347     ~TSplitMethod() { if ( _ownConn ) delete [] _connectivity; _connectivity = 0; }
1348     bool hasFacet( const TTriangleFacet& facet ) const
1349     {
1350       const int* tetConn = _connectivity;
1351       for ( ; tetConn[0] >= 0; tetConn += 4 )
1352         if (( facet.contains( tetConn[0] ) +
1353               facet.contains( tetConn[1] ) +
1354               facet.contains( tetConn[2] ) +
1355               facet.contains( tetConn[3] )) == 3 )
1356           return true;
1357       return false;
1358     }
1359   };
1360
1361   //=======================================================================
1362   /*!
1363    * \brief return TSplitMethod for the given element
1364    */
1365   //=======================================================================
1366
1367   TSplitMethod getSplitMethod( SMDS_VolumeTool& vol, const int theMethodFlags)
1368   {
1369     const int iQ = vol.Element()->IsQuadratic() ? 2 : 1;
1370
1371     // at HEXA_TO_24 method, each face of volume is split into triangles each based on
1372     // an edge and a face barycenter; tertaherdons are based on triangles and
1373     // a volume barycenter
1374     const bool is24TetMode = ( theMethodFlags == SMESH_MeshEditor::HEXA_TO_24 );
1375
1376     // Find out how adjacent volumes are split
1377
1378     vector < list< TTriangleFacet > > triaSplitsByFace( vol.NbFaces() ); // splits of each side
1379     int hasAdjacentSplits = 0, maxTetConnSize = 0;
1380     for ( int iF = 0; iF < vol.NbFaces(); ++iF )
1381     {
1382       int nbNodes = vol.NbFaceNodes( iF ) / iQ;
1383       maxTetConnSize += 4 * ( nbNodes - (is24TetMode ? 0 : 2));
1384       if ( nbNodes < 4 ) continue;
1385
1386       list< TTriangleFacet >& triaSplits = triaSplitsByFace[ iF ];
1387       const int* nInd = vol.GetFaceNodesIndices( iF );
1388       if ( nbNodes == 4 )
1389       {
1390         TTriangleFacet t012( nInd[0*iQ], nInd[1*iQ], nInd[2*iQ] );
1391         TTriangleFacet t123( nInd[1*iQ], nInd[2*iQ], nInd[3*iQ] );
1392         if      ( t012.hasAdjacentTetra( vol.Element() )) triaSplits.push_back( t012 );
1393         else if ( t123.hasAdjacentTetra( vol.Element() )) triaSplits.push_back( t123 );
1394       }
1395       else
1396       {
1397         int iCom = 0; // common node of triangle faces to split into
1398         for ( int iVar = 0; iVar < nbNodes; ++iVar, ++iCom )
1399         {
1400           TTriangleFacet t012( nInd[ iQ * ( iCom             )],
1401                                nInd[ iQ * ( (iCom+1)%nbNodes )],
1402                                nInd[ iQ * ( (iCom+2)%nbNodes )]);
1403           TTriangleFacet t023( nInd[ iQ * ( iCom             )],
1404                                nInd[ iQ * ( (iCom+2)%nbNodes )],
1405                                nInd[ iQ * ( (iCom+3)%nbNodes )]);
1406           if ( t012.hasAdjacentTetra( vol.Element() ) && t023.hasAdjacentTetra( vol.Element() ))
1407           {
1408             triaSplits.push_back( t012 );
1409             triaSplits.push_back( t023 );
1410             break;
1411           }
1412         }
1413       }
1414       if ( !triaSplits.empty() )
1415         hasAdjacentSplits = true;
1416     }
1417
1418     // Among variants of split method select one compliant with adjacent volumes
1419
1420     TSplitMethod method;
1421     if ( !vol.Element()->IsPoly() && !is24TetMode )
1422     {
1423       int nbVariants = 2, nbTet = 0;
1424       const int** connVariants = 0;
1425       switch ( vol.Element()->GetEntityType() )
1426       {
1427       case SMDSEntity_Hexa:
1428       case SMDSEntity_Quad_Hexa:
1429       case SMDSEntity_TriQuad_Hexa:
1430         if ( theMethodFlags == SMESH_MeshEditor::HEXA_TO_5 )
1431           connVariants = theHexTo5, nbTet = 5;
1432         else
1433           connVariants = theHexTo6, nbTet = 6, nbVariants = 4;
1434         break;
1435       case SMDSEntity_Pyramid:
1436       case SMDSEntity_Quad_Pyramid:
1437         connVariants = thePyraTo2;  nbTet = 2;
1438         break;
1439       case SMDSEntity_Penta:
1440       case SMDSEntity_Quad_Penta:
1441         connVariants = thePentaTo3; nbTet = 3; nbVariants = 6;
1442         break;
1443       default:
1444         nbVariants = 0;
1445       }
1446       for ( int variant = 0; variant < nbVariants && method._nbTetra == 0; ++variant )
1447       {
1448         // check method compliancy with adjacent tetras,
1449         // all found splits must be among facets of tetras described by this method
1450         method = TSplitMethod( nbTet, connVariants[variant] );
1451         if ( hasAdjacentSplits && method._nbTetra > 0 )
1452         {
1453           bool facetCreated = true;
1454           for ( int iF = 0; facetCreated && iF < triaSplitsByFace.size(); ++iF )
1455           {
1456             list< TTriangleFacet >::const_iterator facet = triaSplitsByFace[iF].begin();
1457             for ( ; facetCreated && facet != triaSplitsByFace[iF].end(); ++facet )
1458               facetCreated = method.hasFacet( *facet );
1459           }
1460           if ( !facetCreated )
1461             method = TSplitMethod(0); // incompatible method
1462         }
1463       }
1464     }
1465     if ( method._nbTetra < 1 )
1466     {
1467       // No standard method is applicable, use a generic solution:
1468       // each facet of a volume is split into triangles and
1469       // each of triangles and a volume barycenter form a tetrahedron.
1470
1471       const bool isHex27 = ( vol.Element()->GetEntityType() == SMDSEntity_TriQuad_Hexa );
1472
1473       int* connectivity = new int[ maxTetConnSize + 1 ];
1474       method._connectivity = connectivity;
1475       method._ownConn = true;
1476       method._baryNode = !isHex27; // to create central node or not
1477
1478       int connSize = 0;
1479       int baryCenInd = vol.NbNodes() - int( isHex27 );
1480       for ( int iF = 0; iF < vol.NbFaces(); ++iF )
1481       {
1482         const int nbNodes = vol.NbFaceNodes( iF ) / iQ;
1483         const int*   nInd = vol.GetFaceNodesIndices( iF );
1484         // find common node of triangle facets of tetra to create
1485         int iCommon = 0; // index in linear numeration
1486         const list< TTriangleFacet >& triaSplits = triaSplitsByFace[ iF ];
1487         if ( !triaSplits.empty() )
1488         {
1489           // by found facets
1490           const TTriangleFacet* facet = &triaSplits.front();
1491           for ( ; iCommon < nbNodes-1 ; ++iCommon )
1492             if ( facet->contains( nInd[ iQ * iCommon ]) &&
1493                  facet->contains( nInd[ iQ * ((iCommon+2)%nbNodes) ]))
1494               break;
1495         }
1496         else if ( nbNodes > 3 && !is24TetMode )
1497         {
1498           // find the best method of splitting into triangles by aspect ratio
1499           SMESH::Controls::NumericalFunctorPtr aspectRatio( new SMESH::Controls::AspectRatio);
1500           map< double, int > badness2iCommon;
1501           const SMDS_MeshNode** nodes = vol.GetFaceNodes( iF );
1502           int nbVariants = ( nbNodes == 4 ? 2 : nbNodes );
1503           for ( int iVar = 0; iVar < nbVariants; ++iVar, ++iCommon )
1504           {
1505             double badness = 0;
1506             for ( int iLast = iCommon+2; iLast < iCommon+nbNodes; ++iLast )
1507             {
1508               SMDS_FaceOfNodes tria ( nodes[ iQ*( iCommon         )],
1509                                       nodes[ iQ*((iLast-1)%nbNodes)],
1510                                       nodes[ iQ*((iLast  )%nbNodes)]);
1511               badness += getBadRate( &tria, aspectRatio );
1512             }
1513             badness2iCommon.insert( make_pair( badness, iCommon ));
1514           }
1515           // use iCommon with lowest badness
1516           iCommon = badness2iCommon.begin()->second;
1517         }
1518         if ( iCommon >= nbNodes )
1519           iCommon = 0; // something wrong
1520
1521         // fill connectivity of tetrahedra based on a current face
1522         int nbTet = nbNodes - 2;
1523         if ( is24TetMode && nbNodes > 3 && triaSplits.empty())
1524         {
1525           int faceBaryCenInd;
1526           if ( isHex27 )
1527           {
1528             faceBaryCenInd = vol.GetCenterNodeIndex( iF );
1529             method._faceBaryNode[ iF ] = vol.GetNodes()[ faceBaryCenInd ];
1530           }
1531           else
1532           {
1533             method._faceBaryNode[ iF ] = 0;
1534             faceBaryCenInd = baryCenInd + method._faceBaryNode.size();
1535           }
1536           nbTet = nbNodes;
1537           for ( int i = 0; i < nbTet; ++i )
1538           {
1539             int i1 = i, i2 = (i+1) % nbNodes;
1540             if ( !vol.IsFaceExternal( iF )) swap( i1, i2 );
1541             connectivity[ connSize++ ] = nInd[ iQ * i1 ];
1542             connectivity[ connSize++ ] = nInd[ iQ * i2 ];
1543             connectivity[ connSize++ ] = faceBaryCenInd;
1544             connectivity[ connSize++ ] = baryCenInd;
1545           }
1546         }
1547         else
1548         {
1549           for ( int i = 0; i < nbTet; ++i )
1550           {
1551             int i1 = (iCommon+1+i) % nbNodes, i2 = (iCommon+2+i) % nbNodes;
1552             if ( !vol.IsFaceExternal( iF )) swap( i1, i2 );
1553             connectivity[ connSize++ ] = nInd[ iQ * iCommon ];
1554             connectivity[ connSize++ ] = nInd[ iQ * i1 ];
1555             connectivity[ connSize++ ] = nInd[ iQ * i2 ];
1556             connectivity[ connSize++ ] = baryCenInd;
1557           }
1558         }
1559         method._nbTetra += nbTet;
1560
1561       } // loop on volume faces
1562
1563       connectivity[ connSize++ ] = -1;
1564
1565     } // end of generic solution
1566
1567     return method;
1568   }
1569   //================================================================================
1570   /*!
1571    * \brief Check if there is a tetraherdon adjacent to the given element via this facet
1572    */
1573   //================================================================================
1574
1575   bool TTriangleFacet::hasAdjacentTetra( const SMDS_MeshElement* elem ) const
1576   {
1577     // find the tetrahedron including the three nodes of facet
1578     const SMDS_MeshNode* n1 = elem->GetNode(_n1);
1579     const SMDS_MeshNode* n2 = elem->GetNode(_n2);
1580     const SMDS_MeshNode* n3 = elem->GetNode(_n3);
1581     SMDS_ElemIteratorPtr volIt1 = n1->GetInverseElementIterator(SMDSAbs_Volume);
1582     while ( volIt1->more() )
1583     {
1584       const SMDS_MeshElement* v = volIt1->next();
1585       SMDSAbs_EntityType type = v->GetEntityType();
1586       if ( type != SMDSEntity_Tetra && type != SMDSEntity_Quad_Tetra )
1587         continue;
1588       if ( type == SMDSEntity_Quad_Tetra && v->GetNodeIndex( n1 ) > 3 )
1589         continue; // medium node not allowed
1590       const int ind2 = v->GetNodeIndex( n2 );
1591       if ( ind2 < 0 || 3 < ind2 )
1592         continue;
1593       const int ind3 = v->GetNodeIndex( n3 );
1594       if ( ind3 < 0 || 3 < ind3 )
1595         continue;
1596       return true;
1597     }
1598     return false;
1599   }
1600
1601   //=======================================================================
1602   /*!
1603    * \brief A key of a face of volume
1604    */
1605   //=======================================================================
1606
1607   struct TVolumeFaceKey: pair< pair< int, int>, pair< int, int> >
1608   {
1609     TVolumeFaceKey( SMDS_VolumeTool& vol, int iF )
1610     {
1611       TIDSortedNodeSet sortedNodes;
1612       const int iQ = vol.Element()->IsQuadratic() ? 2 : 1;
1613       int nbNodes = vol.NbFaceNodes( iF );
1614       const SMDS_MeshNode** fNodes = vol.GetFaceNodes( iF );
1615       for ( int i = 0; i < nbNodes; i += iQ )
1616         sortedNodes.insert( fNodes[i] );
1617       TIDSortedNodeSet::iterator n = sortedNodes.begin();
1618       first.first   = (*(n++))->GetID();
1619       first.second  = (*(n++))->GetID();
1620       second.first  = (*(n++))->GetID();
1621       second.second = ( sortedNodes.size() > 3 ) ? (*(n++))->GetID() : 0;
1622     }
1623   };
1624 } // namespace
1625
1626 //=======================================================================
1627 //function : SplitVolumesIntoTetra
1628 //purpose  : Split volume elements into tetrahedra.
1629 //=======================================================================
1630
1631 void SMESH_MeshEditor::SplitVolumesIntoTetra (const TIDSortedElemSet & theElems,
1632                                               const int                theMethodFlags)
1633 {
1634   // std-like iterator on coordinates of nodes of mesh element
1635   typedef SMDS_StdIterator< SMESH_TNodeXYZ, SMDS_ElemIteratorPtr > NXyzIterator;
1636   NXyzIterator xyzEnd;
1637
1638   SMDS_VolumeTool    volTool;
1639   SMESH_MesherHelper helper( *GetMesh());
1640
1641   SMESHDS_SubMesh* subMesh = 0;//GetMeshDS()->MeshElements(1);
1642   SMESHDS_SubMesh* fSubMesh = 0;//subMesh;
1643   
1644   SMESH_SequenceOfElemPtr newNodes, newElems;
1645
1646   // map face of volume to it's baricenrtic node
1647   map< TVolumeFaceKey, const SMDS_MeshNode* > volFace2BaryNode;
1648   double bc[3];
1649
1650   TIDSortedElemSet::const_iterator elem = theElems.begin();
1651   for ( ; elem != theElems.end(); ++elem )
1652   {
1653     if ( (*elem)->GetType() != SMDSAbs_Volume )
1654       continue;
1655     SMDSAbs_EntityType geomType = (*elem)->GetEntityType();
1656     if ( geomType == SMDSEntity_Tetra || geomType == SMDSEntity_Quad_Tetra )
1657       continue;
1658
1659     if ( !volTool.Set( *elem, /*ignoreCentralNodes=*/false )) continue; // strange...
1660
1661     TSplitMethod splitMethod = getSplitMethod( volTool, theMethodFlags );
1662     if ( splitMethod._nbTetra < 1 ) continue;
1663
1664     // find submesh to add new tetras to
1665     if ( !subMesh || !subMesh->Contains( *elem ))
1666     {
1667       int shapeID = FindShape( *elem );
1668       helper.SetSubShape( shapeID ); // helper will add tetras to the found submesh
1669       subMesh = GetMeshDS()->MeshElements( shapeID );
1670     }
1671     int iQ;
1672     if ( (*elem)->IsQuadratic() )
1673     {
1674       iQ = 2;
1675       // add quadratic links to the helper
1676       for ( int iF = 0; iF < volTool.NbFaces(); ++iF )
1677       {
1678         const SMDS_MeshNode** fNodes = volTool.GetFaceNodes( iF );
1679         int nbN = volTool.NbFaceNodes( iF ) - bool( volTool.GetCenterNodeIndex(iF) > 0 );
1680         for ( int iN = 0; iN < nbN; iN += iQ )
1681           helper.AddTLinkNode( fNodes[iN], fNodes[iN+2], fNodes[iN+1] );
1682       }
1683       helper.SetIsQuadratic( true );
1684     }
1685     else
1686     {
1687       iQ = 1;
1688       helper.SetIsQuadratic( false );
1689     }
1690     vector<const SMDS_MeshNode*> nodes( (*elem)->begin_nodes(), (*elem)->end_nodes() );
1691     helper.SetElementsOnShape( true );
1692     if ( splitMethod._baryNode )
1693     {
1694       // make a node at barycenter
1695       volTool.GetBaryCenter( bc[0], bc[1], bc[2] );
1696       SMDS_MeshNode* gcNode = helper.AddNode( bc[0], bc[1], bc[2] );
1697       nodes.push_back( gcNode );
1698       newNodes.Append( gcNode );
1699     }
1700     if ( !splitMethod._faceBaryNode.empty() )
1701     {
1702       // make or find baricentric nodes of faces
1703       map<int, const SMDS_MeshNode*>::iterator iF_n = splitMethod._faceBaryNode.begin();
1704       for ( ; iF_n != splitMethod._faceBaryNode.end(); ++iF_n )
1705       {
1706         map< TVolumeFaceKey, const SMDS_MeshNode* >::iterator f_n =
1707           volFace2BaryNode.insert
1708           ( make_pair( TVolumeFaceKey( volTool,iF_n->first ), iF_n->second )).first;
1709         if ( !f_n->second )
1710         {
1711           volTool.GetFaceBaryCenter( iF_n->first, bc[0], bc[1], bc[2] );
1712           newNodes.Append( f_n->second = helper.AddNode( bc[0], bc[1], bc[2] ));
1713         }
1714         nodes.push_back( iF_n->second = f_n->second );
1715       }
1716     }
1717
1718     // make tetras
1719     vector<const SMDS_MeshElement* > tetras( splitMethod._nbTetra ); // splits of a volume
1720     const int* tetConn = splitMethod._connectivity;
1721     for ( int i = 0; i < splitMethod._nbTetra; ++i, tetConn += 4 )
1722       newElems.Append( tetras[ i ] = helper.AddVolume( nodes[ tetConn[0] ],
1723                                                        nodes[ tetConn[1] ],
1724                                                        nodes[ tetConn[2] ],
1725                                                        nodes[ tetConn[3] ]));
1726
1727     ReplaceElemInGroups( *elem, tetras, GetMeshDS() );
1728
1729     // Split faces on sides of the split volume
1730
1731     const SMDS_MeshNode** volNodes = volTool.GetNodes();
1732     for ( int iF = 0; iF < volTool.NbFaces(); ++iF )
1733     {
1734       const int nbNodes = volTool.NbFaceNodes( iF ) / iQ;
1735       if ( nbNodes < 4 ) continue;
1736
1737       // find an existing face
1738       vector<const SMDS_MeshNode*> fNodes( volTool.GetFaceNodes( iF ),
1739                                            volTool.GetFaceNodes( iF ) + volTool.NbFaceNodes( iF ));
1740       while ( const SMDS_MeshElement* face = GetMeshDS()->FindElement( fNodes, SMDSAbs_Face,
1741                                                                        /*noMedium=*/false))
1742       {
1743         // make triangles
1744         helper.SetElementsOnShape( false );
1745         vector< const SMDS_MeshElement* > triangles;
1746
1747         // find submesh to add new triangles in
1748         if ( !fSubMesh || !fSubMesh->Contains( face ))
1749         {
1750           int shapeID = FindShape( face );
1751           fSubMesh = GetMeshDS()->MeshElements( shapeID );
1752         }
1753         map<int, const SMDS_MeshNode*>::iterator iF_n = splitMethod._faceBaryNode.find(iF);
1754         if ( iF_n != splitMethod._faceBaryNode.end() )
1755         {
1756           for ( int iN = 0; iN < nbNodes*iQ; iN += iQ )
1757           {
1758             const SMDS_MeshNode* n1 = fNodes[iN];
1759             const SMDS_MeshNode *n2 = fNodes[(iN+iQ)%(nbNodes*iQ)];
1760             const SMDS_MeshNode *n3 = iF_n->second;
1761             if ( !volTool.IsFaceExternal( iF ))
1762               swap( n2, n3 );
1763             triangles.push_back( helper.AddFace( n1,n2,n3 ));
1764
1765             if ( fSubMesh && n3->getshapeId() < 1 )
1766               fSubMesh->AddNode( n3 );
1767           }
1768         }
1769         else
1770         {
1771           // among possible triangles create ones discribed by split method
1772           const int* nInd = volTool.GetFaceNodesIndices( iF );
1773           int nbVariants = ( nbNodes == 4 ? 2 : nbNodes );
1774           int iCom = 0; // common node of triangle faces to split into
1775           list< TTriangleFacet > facets;
1776           for ( int iVar = 0; iVar < nbVariants; ++iVar, ++iCom )
1777           {
1778             TTriangleFacet t012( nInd[ iQ * ( iCom                )],
1779                                  nInd[ iQ * ( (iCom+1)%nbNodes )],
1780                                  nInd[ iQ * ( (iCom+2)%nbNodes )]);
1781             TTriangleFacet t023( nInd[ iQ * ( iCom                )],
1782                                  nInd[ iQ * ( (iCom+2)%nbNodes )],
1783                                  nInd[ iQ * ( (iCom+3)%nbNodes )]);
1784             if ( splitMethod.hasFacet( t012 ) && splitMethod.hasFacet( t023 ))
1785             {
1786               facets.push_back( t012 );
1787               facets.push_back( t023 );
1788               for ( int iLast = iCom+4; iLast < iCom+nbNodes; ++iLast )
1789                 facets.push_back( TTriangleFacet( nInd[ iQ * ( iCom             )],
1790                                                   nInd[ iQ * ((iLast-1)%nbNodes )],
1791                                                   nInd[ iQ * ((iLast  )%nbNodes )]));
1792               break;
1793             }
1794           }
1795           list< TTriangleFacet >::iterator facet = facets.begin();
1796           for ( ; facet != facets.end(); ++facet )
1797           {
1798             if ( !volTool.IsFaceExternal( iF ))
1799               swap( facet->_n2, facet->_n3 );
1800             triangles.push_back( helper.AddFace( volNodes[ facet->_n1 ],
1801                                                  volNodes[ facet->_n2 ],
1802                                                  volNodes[ facet->_n3 ]));
1803           }
1804         }
1805         for ( int i = 0; i < triangles.size(); ++i )
1806         {
1807           if ( !triangles[i] ) continue;
1808           if ( fSubMesh )
1809             fSubMesh->AddElement( triangles[i]);
1810           newElems.Append( triangles[i] );
1811         }
1812         ReplaceElemInGroups( face, triangles, GetMeshDS() );
1813         GetMeshDS()->RemoveFreeElement( face, fSubMesh, /*fromGroups=*/false );
1814       }
1815
1816     } // loop on volume faces to split them into triangles
1817
1818     GetMeshDS()->RemoveFreeElement( *elem, subMesh, /*fromGroups=*/false );
1819
1820     if ( geomType == SMDSEntity_TriQuad_Hexa )
1821     {
1822       // remove medium nodes that could become free
1823       for ( int i = 20; i < volTool.NbNodes(); ++i )
1824         if ( volNodes[i]->NbInverseElements() == 0 )
1825           GetMeshDS()->RemoveNode( volNodes[i] );
1826     }
1827   } // loop on volumes to split
1828
1829   myLastCreatedNodes = newNodes;
1830   myLastCreatedElems = newElems;
1831 }
1832
1833 //=======================================================================
1834 //function : AddToSameGroups
1835 //purpose  : add elemToAdd to the groups the elemInGroups belongs to
1836 //=======================================================================
1837
1838 void SMESH_MeshEditor::AddToSameGroups (const SMDS_MeshElement* elemToAdd,
1839                                         const SMDS_MeshElement* elemInGroups,
1840                                         SMESHDS_Mesh *          aMesh)
1841 {
1842   const set<SMESHDS_GroupBase*>& groups = aMesh->GetGroups();
1843   if (!groups.empty()) {
1844     set<SMESHDS_GroupBase*>::const_iterator grIt = groups.begin();
1845     for ( ; grIt != groups.end(); grIt++ ) {
1846       SMESHDS_Group* group = dynamic_cast<SMESHDS_Group*>( *grIt );
1847       if ( group && group->Contains( elemInGroups ))
1848         group->SMDSGroup().Add( elemToAdd );
1849     }
1850   }
1851 }
1852
1853
1854 //=======================================================================
1855 //function : RemoveElemFromGroups
1856 //purpose  : Remove removeelem to the groups the elemInGroups belongs to
1857 //=======================================================================
1858 void SMESH_MeshEditor::RemoveElemFromGroups (const SMDS_MeshElement* removeelem,
1859                                              SMESHDS_Mesh *          aMesh)
1860 {
1861   const set<SMESHDS_GroupBase*>& groups = aMesh->GetGroups();
1862   if (!groups.empty())
1863   {
1864     set<SMESHDS_GroupBase*>::const_iterator GrIt = groups.begin();
1865     for (; GrIt != groups.end(); GrIt++)
1866     {
1867       SMESHDS_Group* grp = dynamic_cast<SMESHDS_Group*>(*GrIt);
1868       if (!grp || grp->IsEmpty()) continue;
1869       grp->SMDSGroup().Remove(removeelem);
1870     }
1871   }
1872 }
1873
1874 //================================================================================
1875 /*!
1876  * \brief Replace elemToRm by elemToAdd in the all groups
1877  */
1878 //================================================================================
1879
1880 void SMESH_MeshEditor::ReplaceElemInGroups (const SMDS_MeshElement* elemToRm,
1881                                             const SMDS_MeshElement* elemToAdd,
1882                                             SMESHDS_Mesh *          aMesh)
1883 {
1884   const set<SMESHDS_GroupBase*>& groups = aMesh->GetGroups();
1885   if (!groups.empty()) {
1886     set<SMESHDS_GroupBase*>::const_iterator grIt = groups.begin();
1887     for ( ; grIt != groups.end(); grIt++ ) {
1888       SMESHDS_Group* group = dynamic_cast<SMESHDS_Group*>( *grIt );
1889       if ( group && group->SMDSGroup().Remove( elemToRm ) && elemToAdd )
1890         group->SMDSGroup().Add( elemToAdd );
1891     }
1892   }
1893 }
1894
1895 //================================================================================
1896 /*!
1897  * \brief Replace elemToRm by elemToAdd in the all groups
1898  */
1899 //================================================================================
1900
1901 void SMESH_MeshEditor::ReplaceElemInGroups (const SMDS_MeshElement*                elemToRm,
1902                                             const vector<const SMDS_MeshElement*>& elemToAdd,
1903                                             SMESHDS_Mesh *                         aMesh)
1904 {
1905   const set<SMESHDS_GroupBase*>& groups = aMesh->GetGroups();
1906   if (!groups.empty())
1907   {
1908     set<SMESHDS_GroupBase*>::const_iterator grIt = groups.begin();
1909     for ( ; grIt != groups.end(); grIt++ ) {
1910       SMESHDS_Group* group = dynamic_cast<SMESHDS_Group*>( *grIt );
1911       if ( group && group->SMDSGroup().Remove( elemToRm ) )
1912         for ( int i = 0; i < elemToAdd.size(); ++i )
1913           group->SMDSGroup().Add( elemToAdd[ i ] );
1914     }
1915   }
1916 }
1917
1918 //=======================================================================
1919 //function : QuadToTri
1920 //purpose  : Cut quadrangles into triangles.
1921 //           theCrit is used to select a diagonal to cut
1922 //=======================================================================
1923
1924 bool SMESH_MeshEditor::QuadToTri (TIDSortedElemSet & theElems,
1925                                   const bool         the13Diag)
1926 {
1927   myLastCreatedElems.Clear();
1928   myLastCreatedNodes.Clear();
1929
1930   MESSAGE( "::QuadToTri()" );
1931
1932   SMESHDS_Mesh * aMesh = GetMeshDS();
1933
1934   Handle(Geom_Surface) surface;
1935   SMESH_MesherHelper   helper( *GetMesh() );
1936
1937   TIDSortedElemSet::iterator itElem;
1938   for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
1939     const SMDS_MeshElement* elem = *itElem;
1940     if ( !elem || elem->GetType() != SMDSAbs_Face )
1941       continue;
1942     bool isquad = elem->NbNodes()==4 || elem->NbNodes()==8;
1943     if(!isquad) continue;
1944
1945     if(elem->NbNodes()==4) {
1946       // retrieve element nodes
1947       const SMDS_MeshNode* aNodes [4];
1948       SMDS_ElemIteratorPtr itN = elem->nodesIterator();
1949       int i = 0;
1950       while ( itN->more() )
1951         aNodes[ i++ ] = static_cast<const SMDS_MeshNode*>( itN->next() );
1952
1953       int aShapeId = FindShape( elem );
1954       const SMDS_MeshElement* newElem1 = 0;
1955       const SMDS_MeshElement* newElem2 = 0;
1956       if ( the13Diag ) {
1957         newElem1 = aMesh->AddFace( aNodes[2], aNodes[0], aNodes[1] );
1958         newElem2 = aMesh->AddFace( aNodes[2], aNodes[3], aNodes[0] );
1959       }
1960       else {
1961         newElem1 = aMesh->AddFace( aNodes[3], aNodes[0], aNodes[1] );
1962         newElem2 = aMesh->AddFace( aNodes[3], aNodes[1], aNodes[2] );
1963       }
1964       myLastCreatedElems.Append(newElem1);
1965       myLastCreatedElems.Append(newElem2);
1966       // put a new triangle on the same shape and add to the same groups
1967       if ( aShapeId )
1968         {
1969           aMesh->SetMeshElementOnShape( newElem1, aShapeId );
1970           aMesh->SetMeshElementOnShape( newElem2, aShapeId );
1971         }
1972       AddToSameGroups( newElem1, elem, aMesh );
1973       AddToSameGroups( newElem2, elem, aMesh );
1974       //aMesh->RemoveFreeElement(elem, aMesh->MeshElements(aShapeId), true);
1975       aMesh->RemoveElement( elem );
1976     }
1977
1978     // Quadratic quadrangle
1979
1980     if( elem->NbNodes()==8 && elem->IsQuadratic() ) {
1981
1982       // get surface elem is on
1983       int aShapeId = FindShape( elem );
1984       if ( aShapeId != helper.GetSubShapeID() ) {
1985         surface.Nullify();
1986         TopoDS_Shape shape;
1987         if ( aShapeId > 0 )
1988           shape = aMesh->IndexToShape( aShapeId );
1989         if ( !shape.IsNull() && shape.ShapeType() == TopAbs_FACE ) {
1990           TopoDS_Face face = TopoDS::Face( shape );
1991           surface = BRep_Tool::Surface( face );
1992           if ( !surface.IsNull() )
1993             helper.SetSubShape( shape );
1994         }
1995       }
1996
1997       const SMDS_MeshNode* aNodes [8];
1998       const SMDS_MeshNode* inFaceNode = 0;
1999       SMDS_ElemIteratorPtr itN = elem->nodesIterator();
2000       int i = 0;
2001       while ( itN->more() ) {
2002         aNodes[ i++ ] = static_cast<const SMDS_MeshNode*>( itN->next() );
2003         if ( !inFaceNode && helper.GetNodeUVneedInFaceNode() &&
2004              aNodes[ i-1 ]->GetPosition()->GetTypeOfPosition() == SMDS_TOP_FACE )
2005         {
2006           inFaceNode = aNodes[ i-1 ];
2007         }
2008       }
2009
2010       // find middle point for (0,1,2,3)
2011       // and create a node in this point;
2012       gp_XYZ p( 0,0,0 );
2013       if ( surface.IsNull() ) {
2014         for(i=0; i<4; i++)
2015           p += gp_XYZ(aNodes[i]->X(), aNodes[i]->Y(), aNodes[i]->Z() );
2016         p /= 4;
2017       }
2018       else {
2019         TopoDS_Face geomFace = TopoDS::Face( helper.GetSubShape() );
2020         gp_XY uv( 0,0 );
2021         for(i=0; i<4; i++)
2022           uv += helper.GetNodeUV( geomFace, aNodes[i], inFaceNode );
2023         uv /= 4.;
2024         p = surface->Value( uv.X(), uv.Y() ).XYZ();
2025       }
2026       const SMDS_MeshNode* newN = aMesh->AddNode( p.X(), p.Y(), p.Z() );
2027       myLastCreatedNodes.Append(newN);
2028
2029       // create a new element
2030       const SMDS_MeshElement* newElem1 = 0;
2031       const SMDS_MeshElement* newElem2 = 0;
2032       if ( the13Diag ) {
2033         newElem1 = aMesh->AddFace(aNodes[2], aNodes[3], aNodes[0],
2034                                   aNodes[6], aNodes[7], newN );
2035         newElem2 = aMesh->AddFace(aNodes[2], aNodes[0], aNodes[1],
2036                                   newN,      aNodes[4], aNodes[5] );
2037       }
2038       else {
2039         newElem1 = aMesh->AddFace(aNodes[3], aNodes[0], aNodes[1],
2040                                   aNodes[7], aNodes[4], newN );
2041         newElem2 = aMesh->AddFace(aNodes[3], aNodes[1], aNodes[2],
2042                                   newN,      aNodes[5], aNodes[6] );
2043       }
2044       myLastCreatedElems.Append(newElem1);
2045       myLastCreatedElems.Append(newElem2);
2046       // put a new triangle on the same shape and add to the same groups
2047       if ( aShapeId )
2048         {
2049           aMesh->SetMeshElementOnShape( newElem1, aShapeId );
2050           aMesh->SetMeshElementOnShape( newElem2, aShapeId );
2051         }
2052       AddToSameGroups( newElem1, elem, aMesh );
2053       AddToSameGroups( newElem2, elem, aMesh );
2054       aMesh->RemoveElement( elem );
2055     }
2056   }
2057
2058   return true;
2059 }
2060
2061 //=======================================================================
2062 //function : getAngle
2063 //purpose  :
2064 //=======================================================================
2065
2066 double getAngle(const SMDS_MeshElement * tr1,
2067                 const SMDS_MeshElement * tr2,
2068                 const SMDS_MeshNode *    n1,
2069                 const SMDS_MeshNode *    n2)
2070 {
2071   double angle = 2. * M_PI; // bad angle
2072
2073   // get normals
2074   SMESH::Controls::TSequenceOfXYZ P1, P2;
2075   if ( !SMESH::Controls::NumericalFunctor::GetPoints( tr1, P1 ) ||
2076        !SMESH::Controls::NumericalFunctor::GetPoints( tr2, P2 ))
2077     return angle;
2078   gp_Vec N1,N2;
2079   if(!tr1->IsQuadratic())
2080     N1 = gp_Vec( P1(2) - P1(1) ) ^ gp_Vec( P1(3) - P1(1) );
2081   else
2082     N1 = gp_Vec( P1(3) - P1(1) ) ^ gp_Vec( P1(5) - P1(1) );
2083   if ( N1.SquareMagnitude() <= gp::Resolution() )
2084     return angle;
2085   if(!tr2->IsQuadratic())
2086     N2 = gp_Vec( P2(2) - P2(1) ) ^ gp_Vec( P2(3) - P2(1) );
2087   else
2088     N2 = gp_Vec( P2(3) - P2(1) ) ^ gp_Vec( P2(5) - P2(1) );
2089   if ( N2.SquareMagnitude() <= gp::Resolution() )
2090     return angle;
2091
2092   // find the first diagonal node n1 in the triangles:
2093   // take in account a diagonal link orientation
2094   const SMDS_MeshElement *nFirst[2], *tr[] = { tr1, tr2 };
2095   for ( int t = 0; t < 2; t++ ) {
2096     SMDS_ElemIteratorPtr it = tr[ t ]->nodesIterator();
2097     int i = 0, iDiag = -1;
2098     while ( it->more()) {
2099       const SMDS_MeshElement *n = it->next();
2100       if ( n == n1 || n == n2 ) {
2101         if ( iDiag < 0)
2102           iDiag = i;
2103         else {
2104           if ( i - iDiag == 1 )
2105             nFirst[ t ] = ( n == n1 ? n2 : n1 );
2106           else
2107             nFirst[ t ] = n;
2108           break;
2109         }
2110       }
2111       i++;
2112     }
2113   }
2114   if ( nFirst[ 0 ] == nFirst[ 1 ] )
2115     N2.Reverse();
2116
2117   angle = N1.Angle( N2 );
2118   //SCRUTE( angle );
2119   return angle;
2120 }
2121
2122 // =================================================
2123 // class generating a unique ID for a pair of nodes
2124 // and able to return nodes by that ID
2125 // =================================================
2126 class LinkID_Gen {
2127 public:
2128
2129   LinkID_Gen( const SMESHDS_Mesh* theMesh )
2130     :myMesh( theMesh ), myMaxID( theMesh->MaxNodeID() + 1)
2131   {}
2132
2133   long GetLinkID (const SMDS_MeshNode * n1,
2134                   const SMDS_MeshNode * n2) const
2135   {
2136     return ( Min(n1->GetID(),n2->GetID()) * myMaxID + Max(n1->GetID(),n2->GetID()));
2137   }
2138
2139   bool GetNodes (const long             theLinkID,
2140                  const SMDS_MeshNode* & theNode1,
2141                  const SMDS_MeshNode* & theNode2) const
2142   {
2143     theNode1 = myMesh->FindNode( theLinkID / myMaxID );
2144     if ( !theNode1 ) return false;
2145     theNode2 = myMesh->FindNode( theLinkID % myMaxID );
2146     if ( !theNode2 ) return false;
2147     return true;
2148   }
2149
2150 private:
2151   LinkID_Gen();
2152   const SMESHDS_Mesh* myMesh;
2153   long                myMaxID;
2154 };
2155
2156
2157 //=======================================================================
2158 //function : TriToQuad
2159 //purpose  : Fuse neighbour triangles into quadrangles.
2160 //           theCrit is used to select a neighbour to fuse with.
2161 //           theMaxAngle is a max angle between element normals at which
2162 //           fusion is still performed.
2163 //=======================================================================
2164
2165 bool SMESH_MeshEditor::TriToQuad (TIDSortedElemSet &                   theElems,
2166                                   SMESH::Controls::NumericalFunctorPtr theCrit,
2167                                   const double                         theMaxAngle)
2168 {
2169   myLastCreatedElems.Clear();
2170   myLastCreatedNodes.Clear();
2171
2172   MESSAGE( "::TriToQuad()" );
2173
2174   if ( !theCrit.get() )
2175     return false;
2176
2177   SMESHDS_Mesh * aMesh = GetMeshDS();
2178
2179   // Prepare data for algo: build
2180   // 1. map of elements with their linkIDs
2181   // 2. map of linkIDs with their elements
2182
2183   map< SMESH_TLink, list< const SMDS_MeshElement* > > mapLi_listEl;
2184   map< SMESH_TLink, list< const SMDS_MeshElement* > >::iterator itLE;
2185   map< const SMDS_MeshElement*, set< SMESH_TLink > >  mapEl_setLi;
2186   map< const SMDS_MeshElement*, set< SMESH_TLink > >::iterator itEL;
2187
2188   TIDSortedElemSet::iterator itElem;
2189   for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
2190     const SMDS_MeshElement* elem = *itElem;
2191     if(!elem || elem->GetType() != SMDSAbs_Face ) continue;
2192     bool IsTria = elem->NbNodes()==3 || (elem->NbNodes()==6 && elem->IsQuadratic());
2193     if(!IsTria) continue;
2194
2195     // retrieve element nodes
2196     const SMDS_MeshNode* aNodes [4];
2197     SMDS_ElemIteratorPtr itN = elem->nodesIterator();
2198     int i = 0;
2199     while ( i<3 )
2200       aNodes[ i++ ] = cast2Node( itN->next() );
2201     aNodes[ 3 ] = aNodes[ 0 ];
2202
2203     // fill maps
2204     for ( i = 0; i < 3; i++ ) {
2205       SMESH_TLink link( aNodes[i], aNodes[i+1] );
2206       // check if elements sharing a link can be fused
2207       itLE = mapLi_listEl.find( link );
2208       if ( itLE != mapLi_listEl.end() ) {
2209         if ((*itLE).second.size() > 1 ) // consider only 2 elems adjacent by a link
2210           continue;
2211         const SMDS_MeshElement* elem2 = (*itLE).second.front();
2212         //if ( FindShape( elem ) != FindShape( elem2 ))
2213         //  continue; // do not fuse triangles laying on different shapes
2214         if ( getAngle( elem, elem2, aNodes[i], aNodes[i+1] ) > theMaxAngle )
2215           continue; // avoid making badly shaped quads
2216         (*itLE).second.push_back( elem );
2217       }
2218       else {
2219         mapLi_listEl[ link ].push_back( elem );
2220       }
2221       mapEl_setLi [ elem ].insert( link );
2222     }
2223   }
2224   // Clean the maps from the links shared by a sole element, ie
2225   // links to which only one element is bound in mapLi_listEl
2226
2227   for ( itLE = mapLi_listEl.begin(); itLE != mapLi_listEl.end(); itLE++ ) {
2228     int nbElems = (*itLE).second.size();
2229     if ( nbElems < 2  ) {
2230       const SMDS_MeshElement* elem = (*itLE).second.front();
2231       SMESH_TLink link = (*itLE).first;
2232       mapEl_setLi[ elem ].erase( link );
2233       if ( mapEl_setLi[ elem ].empty() )
2234         mapEl_setLi.erase( elem );
2235     }
2236   }
2237
2238   // Algo: fuse triangles into quadrangles
2239
2240   while ( ! mapEl_setLi.empty() ) {
2241     // Look for the start element:
2242     // the element having the least nb of shared links
2243     const SMDS_MeshElement* startElem = 0;
2244     int minNbLinks = 4;
2245     for ( itEL = mapEl_setLi.begin(); itEL != mapEl_setLi.end(); itEL++ ) {
2246       int nbLinks = (*itEL).second.size();
2247       if ( nbLinks < minNbLinks ) {
2248         startElem = (*itEL).first;
2249         minNbLinks = nbLinks;
2250         if ( minNbLinks == 1 )
2251           break;
2252       }
2253     }
2254
2255     // search elements to fuse starting from startElem or links of elements
2256     // fused earlyer - startLinks
2257     list< SMESH_TLink > startLinks;
2258     while ( startElem || !startLinks.empty() ) {
2259       while ( !startElem && !startLinks.empty() ) {
2260         // Get an element to start, by a link
2261         SMESH_TLink linkId = startLinks.front();
2262         startLinks.pop_front();
2263         itLE = mapLi_listEl.find( linkId );
2264         if ( itLE != mapLi_listEl.end() ) {
2265           list< const SMDS_MeshElement* > & listElem = (*itLE).second;
2266           list< const SMDS_MeshElement* >::iterator itE = listElem.begin();
2267           for ( ; itE != listElem.end() ; itE++ )
2268             if ( mapEl_setLi.find( (*itE) ) != mapEl_setLi.end() )
2269               startElem = (*itE);
2270           mapLi_listEl.erase( itLE );
2271         }
2272       }
2273
2274       if ( startElem ) {
2275         // Get candidates to be fused
2276         const SMDS_MeshElement *tr1 = startElem, *tr2 = 0, *tr3 = 0;
2277         const SMESH_TLink *link12, *link13;
2278         startElem = 0;
2279         ASSERT( mapEl_setLi.find( tr1 ) != mapEl_setLi.end() );
2280         set< SMESH_TLink >& setLi = mapEl_setLi[ tr1 ];
2281         ASSERT( !setLi.empty() );
2282         set< SMESH_TLink >::iterator itLi;
2283         for ( itLi = setLi.begin(); itLi != setLi.end(); itLi++ )
2284         {
2285           const SMESH_TLink & link = (*itLi);
2286           itLE = mapLi_listEl.find( link );
2287           if ( itLE == mapLi_listEl.end() )
2288             continue;
2289
2290           const SMDS_MeshElement* elem = (*itLE).second.front();
2291           if ( elem == tr1 )
2292             elem = (*itLE).second.back();
2293           mapLi_listEl.erase( itLE );
2294           if ( mapEl_setLi.find( elem ) == mapEl_setLi.end())
2295             continue;
2296           if ( tr2 ) {
2297             tr3 = elem;
2298             link13 = &link;
2299           }
2300           else {
2301             tr2 = elem;
2302             link12 = &link;
2303           }
2304
2305           // add other links of elem to list of links to re-start from
2306           set< SMESH_TLink >& links = mapEl_setLi[ elem ];
2307           set< SMESH_TLink >::iterator it;
2308           for ( it = links.begin(); it != links.end(); it++ ) {
2309             const SMESH_TLink& link2 = (*it);
2310             if ( link2 != link )
2311               startLinks.push_back( link2 );
2312           }
2313         }
2314
2315         // Get nodes of possible quadrangles
2316         const SMDS_MeshNode *n12 [4], *n13 [4];
2317         bool Ok12 = false, Ok13 = false;
2318         const SMDS_MeshNode *linkNode1, *linkNode2;
2319         if(tr2) {
2320           linkNode1 = link12->first;
2321           linkNode2 = link12->second;
2322           if ( tr2 && getQuadrangleNodes( n12, linkNode1, linkNode2, tr1, tr2 ))
2323             Ok12 = true;
2324         }
2325         if(tr3) {
2326           linkNode1 = link13->first;
2327           linkNode2 = link13->second;
2328           if ( tr3 && getQuadrangleNodes( n13, linkNode1, linkNode2, tr1, tr3 ))
2329             Ok13 = true;
2330         }
2331
2332         // Choose a pair to fuse
2333         if ( Ok12 && Ok13 ) {
2334           SMDS_FaceOfNodes quad12 ( n12[ 0 ], n12[ 1 ], n12[ 2 ], n12[ 3 ] );
2335           SMDS_FaceOfNodes quad13 ( n13[ 0 ], n13[ 1 ], n13[ 2 ], n13[ 3 ] );
2336           double aBadRate12 = getBadRate( &quad12, theCrit );
2337           double aBadRate13 = getBadRate( &quad13, theCrit );
2338           if (  aBadRate13 < aBadRate12 )
2339             Ok12 = false;
2340           else
2341             Ok13 = false;
2342         }
2343
2344         // Make quadrangles
2345         // and remove fused elems and removed links from the maps
2346         mapEl_setLi.erase( tr1 );
2347         if ( Ok12 ) {
2348           mapEl_setLi.erase( tr2 );
2349           mapLi_listEl.erase( *link12 );
2350           if(tr1->NbNodes()==3) {
2351             const SMDS_MeshElement* newElem = 0;
2352             newElem = aMesh->AddFace(n12[0], n12[1], n12[2], n12[3] );
2353             myLastCreatedElems.Append(newElem);
2354             AddToSameGroups( newElem, tr1, aMesh );
2355             int aShapeId = tr1->getshapeId();
2356             if ( aShapeId )
2357               {
2358                 aMesh->SetMeshElementOnShape( newElem, aShapeId );
2359               }
2360             aMesh->RemoveElement( tr1 );
2361             aMesh->RemoveElement( tr2 );
2362           }
2363           else {
2364             const SMDS_MeshNode* N1 [6];
2365             const SMDS_MeshNode* N2 [6];
2366             GetNodesFromTwoTria(tr1,tr2,N1,N2);
2367             // now we receive following N1 and N2 (using numeration as above image)
2368             // tria1 : (1 2 4 5 9 7)  and  tria2 : (3 4 2 8 9 6)
2369             // i.e. first nodes from both arrays determ new diagonal
2370             const SMDS_MeshNode* aNodes[8];
2371             aNodes[0] = N1[0];
2372             aNodes[1] = N1[1];
2373             aNodes[2] = N2[0];
2374             aNodes[3] = N2[1];
2375             aNodes[4] = N1[3];
2376             aNodes[5] = N2[5];
2377             aNodes[6] = N2[3];
2378             aNodes[7] = N1[5];
2379             const SMDS_MeshElement* newElem = 0;
2380             newElem = aMesh->AddFace(aNodes[0], aNodes[1], aNodes[2], aNodes[3],
2381                                      aNodes[4], aNodes[5], aNodes[6], aNodes[7]);
2382             myLastCreatedElems.Append(newElem);
2383             AddToSameGroups( newElem, tr1, aMesh );
2384             int aShapeId = tr1->getshapeId();
2385             if ( aShapeId )
2386               {
2387                 aMesh->SetMeshElementOnShape( newElem, aShapeId );
2388               }
2389             aMesh->RemoveElement( tr1 );
2390             aMesh->RemoveElement( tr2 );
2391             // remove middle node (9)
2392             GetMeshDS()->RemoveNode( N1[4] );
2393           }
2394         }
2395         else if ( Ok13 ) {
2396           mapEl_setLi.erase( tr3 );
2397           mapLi_listEl.erase( *link13 );
2398           if(tr1->NbNodes()==3) {
2399             const SMDS_MeshElement* newElem = 0;
2400             newElem = aMesh->AddFace(n13[0], n13[1], n13[2], n13[3] );
2401             myLastCreatedElems.Append(newElem);
2402             AddToSameGroups( newElem, tr1, aMesh );
2403             int aShapeId = tr1->getshapeId();
2404             if ( aShapeId )
2405               {
2406                 aMesh->SetMeshElementOnShape( newElem, aShapeId );
2407               }
2408             aMesh->RemoveElement( tr1 );
2409             aMesh->RemoveElement( tr3 );
2410           }
2411           else {
2412             const SMDS_MeshNode* N1 [6];
2413             const SMDS_MeshNode* N2 [6];
2414             GetNodesFromTwoTria(tr1,tr3,N1,N2);
2415             // now we receive following N1 and N2 (using numeration as above image)
2416             // tria1 : (1 2 4 5 9 7)  and  tria2 : (3 4 2 8 9 6)
2417             // i.e. first nodes from both arrays determ new diagonal
2418             const SMDS_MeshNode* aNodes[8];
2419             aNodes[0] = N1[0];
2420             aNodes[1] = N1[1];
2421             aNodes[2] = N2[0];
2422             aNodes[3] = N2[1];
2423             aNodes[4] = N1[3];
2424             aNodes[5] = N2[5];
2425             aNodes[6] = N2[3];
2426             aNodes[7] = N1[5];
2427             const SMDS_MeshElement* newElem = 0;
2428             newElem = aMesh->AddFace(aNodes[0], aNodes[1], aNodes[2], aNodes[3],
2429                                      aNodes[4], aNodes[5], aNodes[6], aNodes[7]);
2430             myLastCreatedElems.Append(newElem);
2431             AddToSameGroups( newElem, tr1, aMesh );
2432             int aShapeId = tr1->getshapeId();
2433             if ( aShapeId )
2434               {
2435                 aMesh->SetMeshElementOnShape( newElem, aShapeId );
2436               }
2437             aMesh->RemoveElement( tr1 );
2438             aMesh->RemoveElement( tr3 );
2439             // remove middle node (9)
2440             GetMeshDS()->RemoveNode( N1[4] );
2441           }
2442         }
2443
2444         // Next element to fuse: the rejected one
2445         if ( tr3 )
2446           startElem = Ok12 ? tr3 : tr2;
2447
2448       } // if ( startElem )
2449     } // while ( startElem || !startLinks.empty() )
2450   } // while ( ! mapEl_setLi.empty() )
2451
2452   return true;
2453 }
2454
2455
2456 /*#define DUMPSO(txt) \
2457 //  cout << txt << endl;
2458 //=============================================================================
2459 //
2460 //
2461 //
2462 //=============================================================================
2463 static void swap( int i1, int i2, int idNodes[], gp_Pnt P[] )
2464 {
2465 if ( i1 == i2 )
2466 return;
2467 int tmp = idNodes[ i1 ];
2468 idNodes[ i1 ] = idNodes[ i2 ];
2469 idNodes[ i2 ] = tmp;
2470 gp_Pnt Ptmp = P[ i1 ];
2471 P[ i1 ] = P[ i2 ];
2472 P[ i2 ] = Ptmp;
2473 DUMPSO( i1 << "(" << idNodes[ i2 ] << ") <-> " << i2 << "(" << idNodes[ i1 ] << ")");
2474 }
2475
2476 //=======================================================================
2477 //function : SortQuadNodes
2478 //purpose  : Set 4 nodes of a quadrangle face in a good order.
2479 //           Swap 1<->2 or 2<->3 nodes and correspondingly return
2480 //           1 or 2 else 0.
2481 //=======================================================================
2482
2483 int SMESH_MeshEditor::SortQuadNodes (const SMDS_Mesh * theMesh,
2484 int               idNodes[] )
2485 {
2486   gp_Pnt P[4];
2487   int i;
2488   for ( i = 0; i < 4; i++ ) {
2489     const SMDS_MeshNode *n = theMesh->FindNode( idNodes[i] );
2490     if ( !n ) return 0;
2491     P[ i ].SetCoord( n->X(), n->Y(), n->Z() );
2492   }
2493
2494   gp_Vec V1(P[0], P[1]);
2495   gp_Vec V2(P[0], P[2]);
2496   gp_Vec V3(P[0], P[3]);
2497
2498   gp_Vec Cross1 = V1 ^ V2;
2499   gp_Vec Cross2 = V2 ^ V3;
2500
2501   i = 0;
2502   if (Cross1.Dot(Cross2) < 0)
2503   {
2504     Cross1 = V2 ^ V1;
2505     Cross2 = V1 ^ V3;
2506
2507     if (Cross1.Dot(Cross2) < 0)
2508       i = 2;
2509     else
2510       i = 1;
2511     swap ( i, i + 1, idNodes, P );
2512
2513     //     for ( int ii = 0; ii < 4; ii++ ) {
2514     //       const SMDS_MeshNode *n = theMesh->FindNode( idNodes[ii] );
2515     //       DUMPSO( ii << "(" << idNodes[ii] <<") : "<<n->X()<<" "<<n->Y()<<" "<<n->Z());
2516     //     }
2517   }
2518   return i;
2519 }
2520
2521 //=======================================================================
2522 //function : SortHexaNodes
2523 //purpose  : Set 8 nodes of a hexahedron in a good order.
2524 //           Return success status
2525 //=======================================================================
2526
2527 bool SMESH_MeshEditor::SortHexaNodes (const SMDS_Mesh * theMesh,
2528                                       int               idNodes[] )
2529 {
2530   gp_Pnt P[8];
2531   int i;
2532   DUMPSO( "INPUT: ========================================");
2533   for ( i = 0; i < 8; i++ ) {
2534     const SMDS_MeshNode *n = theMesh->FindNode( idNodes[i] );
2535     if ( !n ) return false;
2536     P[ i ].SetCoord( n->X(), n->Y(), n->Z() );
2537     DUMPSO( i << "(" << idNodes[i] <<") : "<<n->X()<<" "<<n->Y()<<" "<<n->Z());
2538   }
2539   DUMPSO( "========================================");
2540
2541
2542   set<int> faceNodes;  // ids of bottom face nodes, to be found
2543   set<int> checkedId1; // ids of tried 2-nd nodes
2544   Standard_Real leastDist = DBL_MAX; // dist of the 4-th node from 123 plane
2545   const Standard_Real tol = 1.e-6;   // tolerance to find nodes in plane
2546   int iMin, iLoop1 = 0;
2547
2548   // Loop to try the 2-nd nodes
2549
2550   while ( leastDist > DBL_MIN && ++iLoop1 < 8 )
2551   {
2552     // Find not checked 2-nd node
2553     for ( i = 1; i < 8; i++ )
2554       if ( checkedId1.find( idNodes[i] ) == checkedId1.end() ) {
2555         int id1 = idNodes[i];
2556         swap ( 1, i, idNodes, P );
2557         checkedId1.insert ( id1 );
2558         break;
2559       }
2560
2561     // Find the 3-d node so that 1-2-3 triangle to be on a hexa face,
2562     // ie that all but meybe one (id3 which is on the same face) nodes
2563     // lay on the same side from the triangle plane.
2564
2565     bool manyInPlane = false; // more than 4 nodes lay in plane
2566     int iLoop2 = 0;
2567     while ( ++iLoop2 < 6 ) {
2568
2569       // get 1-2-3 plane coeffs
2570       Standard_Real A, B, C, D;
2571       gp_Vec N = gp_Vec (P[0], P[1]).Crossed( gp_Vec (P[0], P[2]) );
2572       if ( N.SquareMagnitude() > gp::Resolution() )
2573       {
2574         gp_Pln pln ( P[0], N );
2575         pln.Coefficients( A, B, C, D );
2576
2577         // find the node (iMin) closest to pln
2578         Standard_Real dist[ 8 ], minDist = DBL_MAX;
2579         set<int> idInPln;
2580         for ( i = 3; i < 8; i++ ) {
2581           dist[i] = A * P[i].X() + B * P[i].Y() + C * P[i].Z() + D;
2582           if ( fabs( dist[i] ) < minDist ) {
2583             minDist = fabs( dist[i] );
2584             iMin = i;
2585           }
2586           if ( fabs( dist[i] ) <= tol )
2587             idInPln.insert( idNodes[i] );
2588         }
2589
2590         // there should not be more than 4 nodes in bottom plane
2591         if ( idInPln.size() > 1 )
2592         {
2593           DUMPSO( "### idInPln.size() = " << idInPln.size());
2594           // idInPlane does not contain the first 3 nodes
2595           if ( manyInPlane || idInPln.size() == 5)
2596             return false; // all nodes in one plane
2597           manyInPlane = true;
2598
2599           // set the 1-st node to be not in plane
2600           for ( i = 3; i < 8; i++ ) {
2601             if ( idInPln.find( idNodes[ i ] ) == idInPln.end() ) {
2602               DUMPSO( "### Reset 0-th node");
2603               swap( 0, i, idNodes, P );
2604               break;
2605             }
2606           }
2607
2608           // reset to re-check second nodes
2609           leastDist = DBL_MAX;
2610           faceNodes.clear();
2611           checkedId1.clear();
2612           iLoop1 = 0;
2613           break; // from iLoop2;
2614         }
2615
2616         // check that the other 4 nodes are on the same side
2617         bool sameSide = true;
2618         bool isNeg = dist[ iMin == 3 ? 4 : 3 ] <= 0.;
2619         for ( i = 3; sameSide && i < 8; i++ ) {
2620           if ( i != iMin )
2621             sameSide = ( isNeg == dist[i] <= 0.);
2622         }
2623
2624         // keep best solution
2625         if ( sameSide && minDist < leastDist ) {
2626           leastDist = minDist;
2627           faceNodes.clear();
2628           faceNodes.insert( idNodes[ 1 ] );
2629           faceNodes.insert( idNodes[ 2 ] );
2630           faceNodes.insert( idNodes[ iMin ] );
2631           DUMPSO( "loop " << iLoop2 << " id2 " << idNodes[ 1 ] << " id3 " << idNodes[ 2 ]
2632                   << " leastDist = " << leastDist);
2633           if ( leastDist <= DBL_MIN )
2634             break;
2635         }
2636       }
2637
2638       // set next 3-d node to check
2639       int iNext = 2 + iLoop2;
2640       if ( iNext < 8 ) {
2641         DUMPSO( "Try 2-nd");
2642         swap ( 2, iNext, idNodes, P );
2643       }
2644     } // while ( iLoop2 < 6 )
2645   } // iLoop1
2646
2647   if ( faceNodes.empty() ) return false;
2648
2649   // Put the faceNodes in proper places
2650   for ( i = 4; i < 8; i++ ) {
2651     if ( faceNodes.find( idNodes[ i ] ) != faceNodes.end() ) {
2652       // find a place to put
2653       int iTo = 1;
2654       while ( faceNodes.find( idNodes[ iTo ] ) != faceNodes.end() )
2655         iTo++;
2656       DUMPSO( "Set faceNodes");
2657       swap ( iTo, i, idNodes, P );
2658     }
2659   }
2660
2661
2662   // Set nodes of the found bottom face in good order
2663   DUMPSO( " Found bottom face: ");
2664   i = SortQuadNodes( theMesh, idNodes );
2665   if ( i ) {
2666     gp_Pnt Ptmp = P[ i ];
2667     P[ i ] = P[ i+1 ];
2668     P[ i+1 ] = Ptmp;
2669   }
2670   //   else
2671   //     for ( int ii = 0; ii < 4; ii++ ) {
2672   //       const SMDS_MeshNode *n = theMesh->FindNode( idNodes[ii] );
2673   //       DUMPSO( ii << "(" << idNodes[ii] <<") : "<<n->X()<<" "<<n->Y()<<" "<<n->Z());
2674   //    }
2675
2676   // Gravity center of the top and bottom faces
2677   gp_Pnt aGCb = ( P[0].XYZ() + P[1].XYZ() + P[2].XYZ() + P[3].XYZ() ) / 4.;
2678   gp_Pnt aGCt = ( P[4].XYZ() + P[5].XYZ() + P[6].XYZ() + P[7].XYZ() ) / 4.;
2679
2680   // Get direction from the bottom to the top face
2681   gp_Vec upDir ( aGCb, aGCt );
2682   Standard_Real upDirSize = upDir.Magnitude();
2683   if ( upDirSize <= gp::Resolution() ) return false;
2684   upDir / upDirSize;
2685
2686   // Assure that the bottom face normal points up
2687   gp_Vec Nb = gp_Vec (P[0], P[1]).Crossed( gp_Vec (P[0], P[2]) );
2688   Nb += gp_Vec (P[0], P[2]).Crossed( gp_Vec (P[0], P[3]) );
2689   if ( Nb.Dot( upDir ) < 0 ) {
2690     DUMPSO( "Reverse bottom face");
2691     swap( 1, 3, idNodes, P );
2692   }
2693
2694   // Find 5-th node - the one closest to the 1-st among the last 4 nodes.
2695   Standard_Real minDist = DBL_MAX;
2696   for ( i = 4; i < 8; i++ ) {
2697     // projection of P[i] to the plane defined by P[0] and upDir
2698     gp_Pnt Pp = P[i].Translated( upDir * ( upDir.Dot( gp_Vec( P[i], P[0] ))));
2699     Standard_Real sqDist = P[0].SquareDistance( Pp );
2700     if ( sqDist < minDist ) {
2701       minDist = sqDist;
2702       iMin = i;
2703     }
2704   }
2705   DUMPSO( "Set 4-th");
2706   swap ( 4, iMin, idNodes, P );
2707
2708   // Set nodes of the top face in good order
2709   DUMPSO( "Sort top face");
2710   i = SortQuadNodes( theMesh, &idNodes[4] );
2711   if ( i ) {
2712     i += 4;
2713     gp_Pnt Ptmp = P[ i ];
2714     P[ i ] = P[ i+1 ];
2715     P[ i+1 ] = Ptmp;
2716   }
2717
2718   // Assure that direction of the top face normal is from the bottom face
2719   gp_Vec Nt = gp_Vec (P[4], P[5]).Crossed( gp_Vec (P[4], P[6]) );
2720   Nt += gp_Vec (P[4], P[6]).Crossed( gp_Vec (P[4], P[7]) );
2721   if ( Nt.Dot( upDir ) < 0 ) {
2722     DUMPSO( "Reverse top face");
2723     swap( 5, 7, idNodes, P );
2724   }
2725
2726   //   DUMPSO( "OUTPUT: ========================================");
2727   //   for ( i = 0; i < 8; i++ ) {
2728   //     float *p = ugrid->GetPoint(idNodes[i]);
2729   //     DUMPSO( i << "(" << idNodes[i] << ") : " << p[0] << " " << p[1] << " " << p[2]);
2730   //   }
2731
2732   return true;
2733 }*/
2734
2735 //================================================================================
2736 /*!
2737  * \brief Return nodes linked to the given one
2738  * \param theNode - the node
2739  * \param linkedNodes - the found nodes
2740  * \param type - the type of elements to check
2741  *
2742  * Medium nodes are ignored
2743  */
2744 //================================================================================
2745
2746 void SMESH_MeshEditor::GetLinkedNodes( const SMDS_MeshNode* theNode,
2747                                        TIDSortedElemSet &   linkedNodes,
2748                                        SMDSAbs_ElementType  type )
2749 {
2750   SMDS_ElemIteratorPtr elemIt = theNode->GetInverseElementIterator(type);
2751   while ( elemIt->more() )
2752   {
2753     const SMDS_MeshElement* elem = elemIt->next();
2754     if(elem->GetType() == SMDSAbs_0DElement)
2755       continue;
2756     
2757     SMDS_ElemIteratorPtr nodeIt = elem->nodesIterator();
2758     if ( elem->GetType() == SMDSAbs_Volume )
2759     {
2760       SMDS_VolumeTool vol( elem );
2761       while ( nodeIt->more() ) {
2762         const SMDS_MeshNode* n = cast2Node( nodeIt->next() );
2763         if ( theNode != n && vol.IsLinked( theNode, n ))
2764           linkedNodes.insert( n );
2765       }
2766     }
2767     else
2768     {
2769       for ( int i = 0; nodeIt->more(); ++i ) {
2770         const SMDS_MeshNode* n = cast2Node( nodeIt->next() );
2771         if ( n == theNode ) {
2772           int iBefore = i - 1;
2773           int iAfter  = i + 1;
2774           if ( elem->IsQuadratic() ) {
2775             int nb = elem->NbNodes() / 2;
2776             iAfter  = SMESH_MesherHelper::WrapIndex( iAfter, nb );
2777             iBefore = SMESH_MesherHelper::WrapIndex( iBefore, nb );
2778           }
2779           linkedNodes.insert( elem->GetNodeWrap( iAfter ));
2780           linkedNodes.insert( elem->GetNodeWrap( iBefore ));
2781         }
2782       }
2783     }
2784   }
2785 }
2786
2787 //=======================================================================
2788 //function : laplacianSmooth
2789 //purpose  : pulls theNode toward the center of surrounding nodes directly
2790 //           connected to that node along an element edge
2791 //=======================================================================
2792
2793 void laplacianSmooth(const SMDS_MeshNode*                 theNode,
2794                      const Handle(Geom_Surface)&          theSurface,
2795                      map< const SMDS_MeshNode*, gp_XY* >& theUVMap)
2796 {
2797   // find surrounding nodes
2798
2799   TIDSortedElemSet nodeSet;
2800   SMESH_MeshEditor::GetLinkedNodes( theNode, nodeSet, SMDSAbs_Face );
2801
2802   // compute new coodrs
2803
2804   double coord[] = { 0., 0., 0. };
2805   TIDSortedElemSet::iterator nodeSetIt = nodeSet.begin();
2806   for ( ; nodeSetIt != nodeSet.end(); nodeSetIt++ ) {
2807     const SMDS_MeshNode* node = cast2Node(*nodeSetIt);
2808     if ( theSurface.IsNull() ) { // smooth in 3D
2809       coord[0] += node->X();
2810       coord[1] += node->Y();
2811       coord[2] += node->Z();
2812     }
2813     else { // smooth in 2D
2814       ASSERT( theUVMap.find( node ) != theUVMap.end() );
2815       gp_XY* uv = theUVMap[ node ];
2816       coord[0] += uv->X();
2817       coord[1] += uv->Y();
2818     }
2819   }
2820   int nbNodes = nodeSet.size();
2821   if ( !nbNodes )
2822     return;
2823   coord[0] /= nbNodes;
2824   coord[1] /= nbNodes;
2825
2826   if ( !theSurface.IsNull() ) {
2827     ASSERT( theUVMap.find( theNode ) != theUVMap.end() );
2828     theUVMap[ theNode ]->SetCoord( coord[0], coord[1] );
2829     gp_Pnt p3d = theSurface->Value( coord[0], coord[1] );
2830     coord[0] = p3d.X();
2831     coord[1] = p3d.Y();
2832     coord[2] = p3d.Z();
2833   }
2834   else
2835     coord[2] /= nbNodes;
2836
2837   // move node
2838
2839   const_cast< SMDS_MeshNode* >( theNode )->setXYZ(coord[0],coord[1],coord[2]);
2840 }
2841
2842 //=======================================================================
2843 //function : centroidalSmooth
2844 //purpose  : pulls theNode toward the element-area-weighted centroid of the
2845 //           surrounding elements
2846 //=======================================================================
2847
2848 void centroidalSmooth(const SMDS_MeshNode*                 theNode,
2849                       const Handle(Geom_Surface)&          theSurface,
2850                       map< const SMDS_MeshNode*, gp_XY* >& theUVMap)
2851 {
2852   gp_XYZ aNewXYZ(0.,0.,0.);
2853   SMESH::Controls::Area anAreaFunc;
2854   double totalArea = 0.;
2855   int nbElems = 0;
2856
2857   // compute new XYZ
2858
2859   SMDS_ElemIteratorPtr elemIt = theNode->GetInverseElementIterator(SMDSAbs_Face);
2860   while ( elemIt->more() )
2861   {
2862     const SMDS_MeshElement* elem = elemIt->next();
2863     nbElems++;
2864
2865     gp_XYZ elemCenter(0.,0.,0.);
2866     SMESH::Controls::TSequenceOfXYZ aNodePoints;
2867     SMDS_ElemIteratorPtr itN = elem->nodesIterator();
2868     int nn = elem->NbNodes();
2869     if(elem->IsQuadratic()) nn = nn/2;
2870     int i=0;
2871     //while ( itN->more() ) {
2872     while ( i<nn ) {
2873       const SMDS_MeshNode* aNode = static_cast<const SMDS_MeshNode*>( itN->next() );
2874       i++;
2875       gp_XYZ aP( aNode->X(), aNode->Y(), aNode->Z() );
2876       aNodePoints.push_back( aP );
2877       if ( !theSurface.IsNull() ) { // smooth in 2D
2878         ASSERT( theUVMap.find( aNode ) != theUVMap.end() );
2879         gp_XY* uv = theUVMap[ aNode ];
2880         aP.SetCoord( uv->X(), uv->Y(), 0. );
2881       }
2882       elemCenter += aP;
2883     }
2884     double elemArea = anAreaFunc.GetValue( aNodePoints );
2885     totalArea += elemArea;
2886     elemCenter /= nn;
2887     aNewXYZ += elemCenter * elemArea;
2888   }
2889   aNewXYZ /= totalArea;
2890   if ( !theSurface.IsNull() ) {
2891     theUVMap[ theNode ]->SetCoord( aNewXYZ.X(), aNewXYZ.Y() );
2892     aNewXYZ = theSurface->Value( aNewXYZ.X(), aNewXYZ.Y() ).XYZ();
2893   }
2894
2895   // move node
2896
2897   const_cast< SMDS_MeshNode* >( theNode )->setXYZ(aNewXYZ.X(),aNewXYZ.Y(),aNewXYZ.Z());
2898 }
2899
2900 //=======================================================================
2901 //function : getClosestUV
2902 //purpose  : return UV of closest projection
2903 //=======================================================================
2904
2905 static bool getClosestUV (Extrema_GenExtPS& projector,
2906                           const gp_Pnt&     point,
2907                           gp_XY &           result)
2908 {
2909   projector.Perform( point );
2910   if ( projector.IsDone() ) {
2911     double u, v, minVal = DBL_MAX;
2912     for ( int i = projector.NbExt(); i > 0; i-- )
2913 #if OCC_VERSION_LARGE > 0x06040000 // Porting to OCCT6.5.1
2914       if ( projector.SquareDistance( i ) < minVal ) {
2915         minVal = projector.SquareDistance( i );
2916 #else
2917       if ( projector.Value( i ) < minVal ) {
2918         minVal = projector.Value( i );
2919 #endif
2920         projector.Point( i ).Parameter( u, v );
2921       }
2922     result.SetCoord( u, v );
2923     return true;
2924   }
2925   return false;
2926 }
2927
2928 //=======================================================================
2929 //function : Smooth
2930 //purpose  : Smooth theElements during theNbIterations or until a worst
2931 //           element has aspect ratio <= theTgtAspectRatio.
2932 //           Aspect Ratio varies in range [1.0, inf].
2933 //           If theElements is empty, the whole mesh is smoothed.
2934 //           theFixedNodes contains additionally fixed nodes. Nodes built
2935 //           on edges and boundary nodes are always fixed.
2936 //=======================================================================
2937
2938 void SMESH_MeshEditor::Smooth (TIDSortedElemSet &          theElems,
2939                                set<const SMDS_MeshNode*> & theFixedNodes,
2940                                const SmoothMethod          theSmoothMethod,
2941                                const int                   theNbIterations,
2942                                double                      theTgtAspectRatio,
2943                                const bool                  the2D)
2944 {
2945   myLastCreatedElems.Clear();
2946   myLastCreatedNodes.Clear();
2947
2948   MESSAGE((theSmoothMethod==LAPLACIAN ? "LAPLACIAN" : "CENTROIDAL") << "--::Smooth()");
2949
2950   if ( theTgtAspectRatio < 1.0 )
2951     theTgtAspectRatio = 1.0;
2952
2953   const double disttol = 1.e-16;
2954
2955   SMESH::Controls::AspectRatio aQualityFunc;
2956
2957   SMESHDS_Mesh* aMesh = GetMeshDS();
2958
2959   if ( theElems.empty() ) {
2960     // add all faces to theElems
2961     SMDS_FaceIteratorPtr fIt = aMesh->facesIterator();
2962     while ( fIt->more() ) {
2963       const SMDS_MeshElement* face = fIt->next();
2964       theElems.insert( face );
2965     }
2966   }
2967   // get all face ids theElems are on
2968   set< int > faceIdSet;
2969   TIDSortedElemSet::iterator itElem;
2970   if ( the2D )
2971     for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
2972       int fId = FindShape( *itElem );
2973       // check that corresponding submesh exists and a shape is face
2974       if (fId &&
2975           faceIdSet.find( fId ) == faceIdSet.end() &&
2976           aMesh->MeshElements( fId )) {
2977         TopoDS_Shape F = aMesh->IndexToShape( fId );
2978         if ( !F.IsNull() && F.ShapeType() == TopAbs_FACE )
2979           faceIdSet.insert( fId );
2980       }
2981     }
2982   faceIdSet.insert( 0 ); // to smooth elements that are not on any TopoDS_Face
2983
2984   // ===============================================
2985   // smooth elements on each TopoDS_Face separately
2986   // ===============================================
2987
2988   set< int >::reverse_iterator fId = faceIdSet.rbegin(); // treate 0 fId at the end
2989   for ( ; fId != faceIdSet.rend(); ++fId ) {
2990     // get face surface and submesh
2991     Handle(Geom_Surface) surface;
2992     SMESHDS_SubMesh* faceSubMesh = 0;
2993     TopoDS_Face face;
2994     double fToler2 = 0, f,l;
2995     double u1 = 0, u2 = 0, v1 = 0, v2 = 0;
2996     bool isUPeriodic = false, isVPeriodic = false;
2997     if ( *fId ) {
2998       face = TopoDS::Face( aMesh->IndexToShape( *fId ));
2999       surface = BRep_Tool::Surface( face );
3000       faceSubMesh = aMesh->MeshElements( *fId );
3001       fToler2 = BRep_Tool::Tolerance( face );
3002       fToler2 *= fToler2 * 10.;
3003       isUPeriodic = surface->IsUPeriodic();
3004       if ( isUPeriodic )
3005         surface->UPeriod();
3006       isVPeriodic = surface->IsVPeriodic();
3007       if ( isVPeriodic )
3008         surface->VPeriod();
3009       surface->Bounds( u1, u2, v1, v2 );
3010     }
3011     // ---------------------------------------------------------
3012     // for elements on a face, find movable and fixed nodes and
3013     // compute UV for them
3014     // ---------------------------------------------------------
3015     bool checkBoundaryNodes = false;
3016     bool isQuadratic = false;
3017     set<const SMDS_MeshNode*> setMovableNodes;
3018     map< const SMDS_MeshNode*, gp_XY* > uvMap, uvMap2;
3019     list< gp_XY > listUV; // uvs the 2 uvMaps refer to
3020     list< const SMDS_MeshElement* > elemsOnFace;
3021
3022     Extrema_GenExtPS projector;
3023     GeomAdaptor_Surface surfAdaptor;
3024     if ( !surface.IsNull() ) {
3025       surfAdaptor.Load( surface );
3026       projector.Initialize( surfAdaptor, 20,20, 1e-5,1e-5 );
3027     }
3028     int nbElemOnFace = 0;
3029     itElem = theElems.begin();
3030     // loop on not yet smoothed elements: look for elems on a face
3031     while ( itElem != theElems.end() ) {
3032       if ( faceSubMesh && nbElemOnFace == faceSubMesh->NbElements() )
3033         break; // all elements found
3034
3035       const SMDS_MeshElement* elem = *itElem;
3036       if ( !elem || elem->GetType() != SMDSAbs_Face || elem->NbNodes() < 3 ||
3037            ( faceSubMesh && !faceSubMesh->Contains( elem ))) {
3038         ++itElem;
3039         continue;
3040       }
3041       elemsOnFace.push_back( elem );
3042       theElems.erase( itElem++ );
3043       nbElemOnFace++;
3044
3045       if ( !isQuadratic )
3046         isQuadratic = elem->IsQuadratic();
3047
3048       // get movable nodes of elem
3049       const SMDS_MeshNode* node;
3050       SMDS_TypeOfPosition posType;
3051       SMDS_ElemIteratorPtr itN = elem->nodesIterator();
3052       int nn = 0, nbn =  elem->NbNodes();
3053       if(elem->IsQuadratic())
3054         nbn = nbn/2;
3055       while ( nn++ < nbn ) {
3056         node = static_cast<const SMDS_MeshNode*>( itN->next() );
3057         const SMDS_PositionPtr& pos = node->GetPosition();
3058         posType = pos ? pos->GetTypeOfPosition() : SMDS_TOP_3DSPACE;
3059         if (posType != SMDS_TOP_EDGE &&
3060             posType != SMDS_TOP_VERTEX &&
3061             theFixedNodes.find( node ) == theFixedNodes.end())
3062         {
3063           // check if all faces around the node are on faceSubMesh
3064           // because a node on edge may be bound to face
3065           SMDS_ElemIteratorPtr eIt = node->GetInverseElementIterator(SMDSAbs_Face);
3066           bool all = true;
3067           if ( faceSubMesh ) {
3068             while ( eIt->more() && all ) {
3069               const SMDS_MeshElement* e = eIt->next();
3070               all = faceSubMesh->Contains( e );
3071             }
3072           }
3073           if ( all )
3074             setMovableNodes.insert( node );
3075           else
3076             checkBoundaryNodes = true;
3077         }
3078         if ( posType == SMDS_TOP_3DSPACE )
3079           checkBoundaryNodes = true;
3080       }
3081
3082       if ( surface.IsNull() )
3083         continue;
3084
3085       // get nodes to check UV
3086       list< const SMDS_MeshNode* > uvCheckNodes;
3087       itN = elem->nodesIterator();
3088       nn = 0; nbn =  elem->NbNodes();
3089       if(elem->IsQuadratic())
3090         nbn = nbn/2;
3091       while ( nn++ < nbn ) {
3092         node = static_cast<const SMDS_MeshNode*>( itN->next() );
3093         if ( uvMap.find( node ) == uvMap.end() )
3094           uvCheckNodes.push_back( node );
3095         // add nodes of elems sharing node
3096         //         SMDS_ElemIteratorPtr eIt = node->GetInverseElementIterator(SMDSAbs_Face);
3097         //         while ( eIt->more() ) {
3098         //           const SMDS_MeshElement* e = eIt->next();
3099         //           if ( e != elem ) {
3100         //             SMDS_ElemIteratorPtr nIt = e->nodesIterator();
3101         //             while ( nIt->more() ) {
3102         //               const SMDS_MeshNode* n =
3103         //                 static_cast<const SMDS_MeshNode*>( nIt->next() );
3104         //               if ( uvMap.find( n ) == uvMap.end() )
3105         //                 uvCheckNodes.push_back( n );
3106         //             }
3107         //           }
3108         //         }
3109       }
3110       // check UV on face
3111       list< const SMDS_MeshNode* >::iterator n = uvCheckNodes.begin();
3112       for ( ; n != uvCheckNodes.end(); ++n ) {
3113         node = *n;
3114         gp_XY uv( 0, 0 );
3115         const SMDS_PositionPtr& pos = node->GetPosition();
3116         posType = pos ? pos->GetTypeOfPosition() : SMDS_TOP_3DSPACE;
3117         // get existing UV
3118         switch ( posType ) {
3119         case SMDS_TOP_FACE: {
3120           SMDS_FacePosition* fPos = ( SMDS_FacePosition* ) pos;
3121           uv.SetCoord( fPos->GetUParameter(), fPos->GetVParameter() );
3122           break;
3123         }
3124         case SMDS_TOP_EDGE: {
3125           TopoDS_Shape S = aMesh->IndexToShape( node->getshapeId() );
3126           Handle(Geom2d_Curve) pcurve;
3127           if ( !S.IsNull() && S.ShapeType() == TopAbs_EDGE )
3128             pcurve = BRep_Tool::CurveOnSurface( TopoDS::Edge( S ), face, f,l );
3129           if ( !pcurve.IsNull() ) {
3130             double u = (( SMDS_EdgePosition* ) pos )->GetUParameter();
3131             uv = pcurve->Value( u ).XY();
3132           }
3133           break;
3134         }
3135         case SMDS_TOP_VERTEX: {
3136           TopoDS_Shape S = aMesh->IndexToShape( node->getshapeId() );
3137           if ( !S.IsNull() && S.ShapeType() == TopAbs_VERTEX )
3138             uv = BRep_Tool::Parameters( TopoDS::Vertex( S ), face ).XY();
3139           break;
3140         }
3141         default:;
3142         }
3143         // check existing UV
3144         bool project = true;
3145         gp_Pnt pNode ( node->X(), node->Y(), node->Z() );
3146         double dist1 = DBL_MAX, dist2 = 0;
3147         if ( posType != SMDS_TOP_3DSPACE ) {
3148           dist1 = pNode.SquareDistance( surface->Value( uv.X(), uv.Y() ));
3149           project = dist1 > fToler2;
3150         }
3151         if ( project ) { // compute new UV
3152           gp_XY newUV;
3153           if ( !getClosestUV( projector, pNode, newUV )) {
3154             MESSAGE("Node Projection Failed " << node);
3155           }
3156           else {
3157             if ( isUPeriodic )
3158               newUV.SetX( ElCLib::InPeriod( newUV.X(), u1, u2 ));
3159             if ( isVPeriodic )
3160               newUV.SetY( ElCLib::InPeriod( newUV.Y(), v1, v2 ));
3161             // check new UV
3162             if ( posType != SMDS_TOP_3DSPACE )
3163               dist2 = pNode.SquareDistance( surface->Value( newUV.X(), newUV.Y() ));
3164             if ( dist2 < dist1 )
3165               uv = newUV;
3166           }
3167         }
3168         // store UV in the map
3169         listUV.push_back( uv );
3170         uvMap.insert( make_pair( node, &listUV.back() ));
3171       }
3172     } // loop on not yet smoothed elements
3173
3174     if ( !faceSubMesh || nbElemOnFace != faceSubMesh->NbElements() )
3175       checkBoundaryNodes = true;
3176
3177     // fix nodes on mesh boundary
3178
3179     if ( checkBoundaryNodes ) {
3180       map< SMESH_TLink, int > linkNbMap; // how many times a link encounters in elemsOnFace
3181       map< SMESH_TLink, int >::iterator link_nb;
3182       // put all elements links to linkNbMap
3183       list< const SMDS_MeshElement* >::iterator elemIt = elemsOnFace.begin();
3184       for ( ; elemIt != elemsOnFace.end(); ++elemIt ) {
3185         const SMDS_MeshElement* elem = (*elemIt);
3186         int nbn =  elem->NbCornerNodes();
3187         // loop on elem links: insert them in linkNbMap
3188         for ( int iN = 0; iN < nbn; ++iN ) {
3189           const SMDS_MeshNode* n1 = elem->GetNode( iN );
3190           const SMDS_MeshNode* n2 = elem->GetNode(( iN+1 ) % nbn);
3191           SMESH_TLink link( n1, n2 );
3192           link_nb = linkNbMap.insert( make_pair( link, 0 )).first;
3193           link_nb->second++;
3194         }
3195       }
3196       // remove nodes that are in links encountered only once from setMovableNodes
3197       for ( link_nb = linkNbMap.begin(); link_nb != linkNbMap.end(); ++link_nb ) {
3198         if ( link_nb->second == 1 ) {
3199           setMovableNodes.erase( link_nb->first.node1() );
3200           setMovableNodes.erase( link_nb->first.node2() );
3201         }
3202       }
3203     }
3204
3205     // -----------------------------------------------------
3206     // for nodes on seam edge, compute one more UV ( uvMap2 );
3207     // find movable nodes linked to nodes on seam and which
3208     // are to be smoothed using the second UV ( uvMap2 )
3209     // -----------------------------------------------------
3210
3211     set<const SMDS_MeshNode*> nodesNearSeam; // to smooth using uvMap2
3212     if ( !surface.IsNull() ) {
3213       TopExp_Explorer eExp( face, TopAbs_EDGE );
3214       for ( ; eExp.More(); eExp.Next() ) {
3215         TopoDS_Edge edge = TopoDS::Edge( eExp.Current() );
3216         if ( !BRep_Tool::IsClosed( edge, face ))
3217           continue;
3218         SMESHDS_SubMesh* sm = aMesh->MeshElements( edge );
3219         if ( !sm ) continue;
3220         // find out which parameter varies for a node on seam
3221         double f,l;
3222         gp_Pnt2d uv1, uv2;
3223         Handle(Geom2d_Curve) pcurve = BRep_Tool::CurveOnSurface( edge, face, f, l );
3224         if ( pcurve.IsNull() ) continue;
3225         uv1 = pcurve->Value( f );
3226         edge.Reverse();
3227         pcurve = BRep_Tool::CurveOnSurface( edge, face, f, l );
3228         if ( pcurve.IsNull() ) continue;
3229         uv2 = pcurve->Value( f );
3230         int iPar = Abs( uv1.X() - uv2.X() ) > Abs( uv1.Y() - uv2.Y() ) ? 1 : 2;
3231         // assure uv1 < uv2
3232         if ( uv1.Coord( iPar ) > uv2.Coord( iPar )) {
3233           gp_Pnt2d tmp = uv1; uv1 = uv2; uv2 = tmp;
3234         }
3235         // get nodes on seam and its vertices
3236         list< const SMDS_MeshNode* > seamNodes;
3237         SMDS_NodeIteratorPtr nSeamIt = sm->GetNodes();
3238         while ( nSeamIt->more() ) {
3239           const SMDS_MeshNode* node = nSeamIt->next();
3240           if ( !isQuadratic || !IsMedium( node ))
3241             seamNodes.push_back( node );
3242         }
3243         TopExp_Explorer vExp( edge, TopAbs_VERTEX );
3244         for ( ; vExp.More(); vExp.Next() ) {
3245           sm = aMesh->MeshElements( vExp.Current() );
3246           if ( sm ) {
3247             nSeamIt = sm->GetNodes();
3248             while ( nSeamIt->more() )
3249               seamNodes.push_back( nSeamIt->next() );
3250           }
3251         }
3252         // loop on nodes on seam
3253         list< const SMDS_MeshNode* >::iterator noSeIt = seamNodes.begin();
3254         for ( ; noSeIt != seamNodes.end(); ++noSeIt ) {
3255           const SMDS_MeshNode* nSeam = *noSeIt;
3256           map< const SMDS_MeshNode*, gp_XY* >::iterator n_uv = uvMap.find( nSeam );
3257           if ( n_uv == uvMap.end() )
3258             continue;
3259           // set the first UV
3260           n_uv->second->SetCoord( iPar, uv1.Coord( iPar ));
3261           // set the second UV
3262           listUV.push_back( *n_uv->second );
3263           listUV.back().SetCoord( iPar, uv2.Coord( iPar ));
3264           if ( uvMap2.empty() )
3265             uvMap2 = uvMap; // copy the uvMap contents
3266           uvMap2[ nSeam ] = &listUV.back();
3267
3268           // collect movable nodes linked to ones on seam in nodesNearSeam
3269           SMDS_ElemIteratorPtr eIt = nSeam->GetInverseElementIterator(SMDSAbs_Face);
3270           while ( eIt->more() ) {
3271             const SMDS_MeshElement* e = eIt->next();
3272             int nbUseMap1 = 0, nbUseMap2 = 0;
3273             SMDS_ElemIteratorPtr nIt = e->nodesIterator();
3274             int nn = 0, nbn =  e->NbNodes();
3275             if(e->IsQuadratic()) nbn = nbn/2;
3276             while ( nn++ < nbn )
3277             {
3278               const SMDS_MeshNode* n =
3279                 static_cast<const SMDS_MeshNode*>( nIt->next() );
3280               if (n == nSeam ||
3281                   setMovableNodes.find( n ) == setMovableNodes.end() )
3282                 continue;
3283               // add only nodes being closer to uv2 than to uv1
3284               gp_Pnt pMid (0.5 * ( n->X() + nSeam->X() ),
3285                            0.5 * ( n->Y() + nSeam->Y() ),
3286                            0.5 * ( n->Z() + nSeam->Z() ));
3287               gp_XY uv;
3288               getClosestUV( projector, pMid, uv );
3289               if ( uv.Coord( iPar ) > uvMap[ n ]->Coord( iPar ) ) {
3290                 nodesNearSeam.insert( n );
3291                 nbUseMap2++;
3292               }
3293               else
3294                 nbUseMap1++;
3295             }
3296             // for centroidalSmooth all element nodes must
3297             // be on one side of a seam
3298             if ( theSmoothMethod == CENTROIDAL && nbUseMap1 && nbUseMap2 ) {
3299               SMDS_ElemIteratorPtr nIt = e->nodesIterator();
3300               nn = 0;
3301               while ( nn++ < nbn ) {
3302                 const SMDS_MeshNode* n =
3303                   static_cast<const SMDS_MeshNode*>( nIt->next() );
3304                 setMovableNodes.erase( n );
3305               }
3306             }
3307           }
3308         } // loop on nodes on seam
3309       } // loop on edge of a face
3310     } // if ( !face.IsNull() )
3311
3312     if ( setMovableNodes.empty() ) {
3313       MESSAGE( "Face id : " << *fId << " - NO SMOOTHING: no nodes to move!!!");
3314       continue; // goto next face
3315     }
3316
3317     // -------------
3318     // SMOOTHING //
3319     // -------------
3320
3321     int it = -1;
3322     double maxRatio = -1., maxDisplacement = -1.;
3323     set<const SMDS_MeshNode*>::iterator nodeToMove;
3324     for ( it = 0; it < theNbIterations; it++ ) {
3325       maxDisplacement = 0.;
3326       nodeToMove = setMovableNodes.begin();
3327       for ( ; nodeToMove != setMovableNodes.end(); nodeToMove++ ) {
3328         const SMDS_MeshNode* node = (*nodeToMove);
3329         gp_XYZ aPrevPos ( node->X(), node->Y(), node->Z() );
3330
3331         // smooth
3332         bool map2 = ( nodesNearSeam.find( node ) != nodesNearSeam.end() );
3333         if ( theSmoothMethod == LAPLACIAN )
3334           laplacianSmooth( node, surface, map2 ? uvMap2 : uvMap );
3335         else
3336           centroidalSmooth( node, surface, map2 ? uvMap2 : uvMap );
3337
3338         // node displacement
3339         gp_XYZ aNewPos ( node->X(), node->Y(), node->Z() );
3340         Standard_Real aDispl = (aPrevPos - aNewPos).SquareModulus();
3341         if ( aDispl > maxDisplacement )
3342           maxDisplacement = aDispl;
3343       }
3344       // no node movement => exit
3345       //if ( maxDisplacement < 1.e-16 ) {
3346       if ( maxDisplacement < disttol ) {
3347         MESSAGE("-- no node movement --");
3348         break;
3349       }
3350
3351       // check elements quality
3352       maxRatio  = 0;
3353       list< const SMDS_MeshElement* >::iterator elemIt = elemsOnFace.begin();
3354       for ( ; elemIt != elemsOnFace.end(); ++elemIt ) {
3355         const SMDS_MeshElement* elem = (*elemIt);
3356         if ( !elem || elem->GetType() != SMDSAbs_Face )
3357           continue;
3358         SMESH::Controls::TSequenceOfXYZ aPoints;
3359         if ( aQualityFunc.GetPoints( elem, aPoints )) {
3360           double aValue = aQualityFunc.GetValue( aPoints );
3361           if ( aValue > maxRatio )
3362             maxRatio = aValue;
3363         }
3364       }
3365       if ( maxRatio <= theTgtAspectRatio ) {
3366         MESSAGE("-- quality achived --");
3367         break;
3368       }
3369       if (it+1 == theNbIterations) {
3370         MESSAGE("-- Iteration limit exceeded --");
3371       }
3372     } // smoothing iterations
3373
3374     MESSAGE(" Face id: " << *fId <<
3375             " Nb iterstions: " << it <<
3376             " Displacement: " << maxDisplacement <<
3377             " Aspect Ratio " << maxRatio);
3378
3379     // ---------------------------------------
3380     // new nodes positions are computed,
3381     // record movement in DS and set new UV
3382     // ---------------------------------------
3383     nodeToMove = setMovableNodes.begin();
3384     for ( ; nodeToMove != setMovableNodes.end(); nodeToMove++ ) {
3385       SMDS_MeshNode* node = const_cast< SMDS_MeshNode* > (*nodeToMove);
3386       aMesh->MoveNode( node, node->X(), node->Y(), node->Z() );
3387       map< const SMDS_MeshNode*, gp_XY* >::iterator node_uv = uvMap.find( node );
3388       if ( node_uv != uvMap.end() ) {
3389         gp_XY* uv = node_uv->second;
3390         node->SetPosition
3391           ( SMDS_PositionPtr( new SMDS_FacePosition( uv->X(), uv->Y() )));
3392       }
3393     }
3394
3395     // move medium nodes of quadratic elements
3396     if ( isQuadratic )
3397     {
3398       SMESH_MesherHelper helper( *GetMesh() );
3399       if ( !face.IsNull() )
3400         helper.SetSubShape( face );
3401       list< const SMDS_MeshElement* >::iterator elemIt = elemsOnFace.begin();
3402       for ( ; elemIt != elemsOnFace.end(); ++elemIt ) {
3403         const SMDS_VtkFace* QF =
3404           dynamic_cast<const SMDS_VtkFace*> (*elemIt);
3405         if(QF && QF->IsQuadratic()) {
3406           vector<const SMDS_MeshNode*> Ns;
3407           Ns.reserve(QF->NbNodes()+1);
3408           SMDS_ElemIteratorPtr anIter = QF->interlacedNodesElemIterator();
3409           while ( anIter->more() )
3410             Ns.push_back( cast2Node(anIter->next()) );
3411           Ns.push_back( Ns[0] );
3412           double x, y, z;
3413           for(int i=0; i<QF->NbNodes(); i=i+2) {
3414             if ( !surface.IsNull() ) {
3415               gp_XY uv1 = helper.GetNodeUV( face, Ns[i], Ns[i+2] );
3416               gp_XY uv2 = helper.GetNodeUV( face, Ns[i+2], Ns[i] );
3417               gp_XY uv = ( uv1 + uv2 ) / 2.;
3418               gp_Pnt xyz = surface->Value( uv.X(), uv.Y() );
3419               x = xyz.X(); y = xyz.Y(); z = xyz.Z();
3420             }
3421             else {
3422               x = (Ns[i]->X() + Ns[i+2]->X())/2;
3423               y = (Ns[i]->Y() + Ns[i+2]->Y())/2;
3424               z = (Ns[i]->Z() + Ns[i+2]->Z())/2;
3425             }
3426             if( fabs( Ns[i+1]->X() - x ) > disttol ||
3427                 fabs( Ns[i+1]->Y() - y ) > disttol ||
3428                 fabs( Ns[i+1]->Z() - z ) > disttol ) {
3429               // we have to move i+1 node
3430               aMesh->MoveNode( Ns[i+1], x, y, z );
3431             }
3432           }
3433         }
3434       }
3435     }
3436
3437   } // loop on face ids
3438
3439 }
3440
3441 //=======================================================================
3442 //function : isReverse
3443 //purpose  : Return true if normal of prevNodes is not co-directied with
3444 //           gp_Vec(prevNodes[iNotSame],nextNodes[iNotSame]).
3445 //           iNotSame is where prevNodes and nextNodes are different.
3446 //           If result is true then future volume orientation is OK
3447 //=======================================================================
3448
3449 static bool isReverse(const SMDS_MeshElement*             face,
3450                       const vector<const SMDS_MeshNode*>& prevNodes,
3451                       const vector<const SMDS_MeshNode*>& nextNodes,
3452                       const int                           iNotSame)
3453 {
3454
3455   SMESH_TNodeXYZ pP = prevNodes[ iNotSame ];
3456   SMESH_TNodeXYZ pN = nextNodes[ iNotSame ];
3457   gp_XYZ extrDir( pN - pP ), faceNorm;
3458   SMESH_Algo::FaceNormal( face, faceNorm, /*normalized=*/false );
3459
3460   return faceNorm * extrDir < 0.0;
3461 }
3462
3463 //=======================================================================
3464 /*!
3465  * \brief Create elements by sweeping an element
3466  * \param elem - element to sweep
3467  * \param newNodesItVec - nodes generated from each node of the element
3468  * \param newElems - generated elements
3469  * \param nbSteps - number of sweeping steps
3470  * \param srcElements - to append elem for each generated element
3471  */
3472 //=======================================================================
3473
3474 void SMESH_MeshEditor::sweepElement(const SMDS_MeshElement*               elem,
3475                                     const vector<TNodeOfNodeListMapItr> & newNodesItVec,
3476                                     list<const SMDS_MeshElement*>&        newElems,
3477                                     const int                             nbSteps,
3478                                     SMESH_SequenceOfElemPtr&              srcElements)
3479 {
3480   //MESSAGE("sweepElement " << nbSteps);
3481   SMESHDS_Mesh* aMesh = GetMeshDS();
3482
3483   const int           nbNodes = elem->NbNodes();          
3484   const int         nbCorners = elem->NbCornerNodes();
3485   SMDSAbs_EntityType baseType = elem->GetEntityType(); /* it can change in case of 
3486                                                           polyhedron creation !!! */
3487   // Loop on elem nodes:
3488   // find new nodes and detect same nodes indices
3489   vector < list< const SMDS_MeshNode* >::const_iterator > itNN( nbNodes );
3490   vector<const SMDS_MeshNode*> prevNod( nbNodes );
3491   vector<const SMDS_MeshNode*> nextNod( nbNodes );
3492   vector<const SMDS_MeshNode*> midlNod( nbNodes );
3493
3494   int iNode, nbSame = 0, nbDouble = 0, iNotSameNode = 0;
3495   vector<int> sames(nbNodes);
3496   vector<bool> isSingleNode(nbNodes);
3497
3498   for ( iNode = 0; iNode < nbNodes; iNode++ ) {
3499     TNodeOfNodeListMapItr                        nnIt = newNodesItVec[ iNode ];
3500     const SMDS_MeshNode*                         node = nnIt->first;
3501     const list< const SMDS_MeshNode* > & listNewNodes = nnIt->second;
3502     if ( listNewNodes.empty() )
3503       return;
3504
3505     itNN   [ iNode ] = listNewNodes.begin();
3506     prevNod[ iNode ] = node;
3507     nextNod[ iNode ] = listNewNodes.front();
3508
3509     isSingleNode[iNode] = (listNewNodes.size()==nbSteps); /* medium node of quadratic or
3510                                                              corner node of linear */
3511     if ( prevNod[ iNode ] != nextNod [ iNode ])
3512       nbDouble += !isSingleNode[iNode];
3513
3514     if( iNode < nbCorners ) { // check corners only
3515       if ( prevNod[ iNode ] == nextNod [ iNode ])
3516         sames[nbSame++] = iNode;
3517       else
3518         iNotSameNode = iNode;
3519     }
3520   }
3521
3522   if ( nbSame == nbNodes || nbSame > 2) {
3523     MESSAGE( " Too many same nodes of element " << elem->GetID() );
3524     return;
3525   }
3526
3527   if ( elem->GetType() == SMDSAbs_Face && !isReverse( elem, prevNod, nextNod, iNotSameNode ))
3528   {
3529     // fix nodes order to have bottom normal external
3530     if ( baseType == SMDSEntity_Polygon )
3531     {
3532       std::reverse( itNN.begin(), itNN.end() );
3533       std::reverse( prevNod.begin(), prevNod.end() );
3534       std::reverse( midlNod.begin(), midlNod.end() );
3535       std::reverse( nextNod.begin(), nextNod.end() );
3536       std::reverse( isSingleNode.begin(), isSingleNode.end() );
3537     }
3538     else
3539     {
3540       const vector<int>& ind = SMDS_MeshCell::reverseSmdsOrder( baseType );
3541       SMDS_MeshCell::applyInterlace( ind, itNN );
3542       SMDS_MeshCell::applyInterlace( ind, prevNod );
3543       SMDS_MeshCell::applyInterlace( ind, nextNod );
3544       SMDS_MeshCell::applyInterlace( ind, midlNod );
3545       SMDS_MeshCell::applyInterlace( ind, isSingleNode );
3546       if ( nbSame > 0 )
3547       {
3548         sames[nbSame] = iNotSameNode;
3549         for ( int j = 0; j <= nbSame; ++j )
3550           for ( size_t i = 0; i < ind.size(); ++i )
3551             if ( ind[i] == sames[j] )
3552             {
3553               sames[j] = i;
3554               break;
3555             }
3556         iNotSameNode = sames[nbSame];
3557       }
3558     }
3559   }
3560
3561   int iSameNode = 0, iBeforeSame = 0, iAfterSame = 0, iOpposSame = 0;
3562   if ( nbSame > 0 ) {
3563     iSameNode    = sames[ nbSame-1 ];
3564     iBeforeSame  = ( iSameNode + nbCorners - 1 ) % nbCorners;
3565     iAfterSame   = ( iSameNode + 1 ) % nbCorners;
3566     iOpposSame   = ( iSameNode - 2 < 0  ? iSameNode + 2 : iSameNode - 2 );
3567   }
3568
3569   // make new elements
3570   for (int iStep = 0; iStep < nbSteps; iStep++ )
3571   {
3572     // get next nodes
3573     for ( iNode = 0; iNode < nbNodes; iNode++ )
3574     {
3575       midlNod[ iNode ] = isSingleNode[iNode] ? 0 : *itNN[ iNode ]++;
3576       nextNod[ iNode ] = *itNN[ iNode ]++;
3577     }
3578
3579     SMDS_MeshElement* aNewElem = 0;
3580     /*if(!elem->IsPoly())*/ {
3581       switch ( baseType ) {
3582       case SMDSEntity_0D:
3583       case SMDSEntity_Node: { // sweep NODE
3584         if ( nbSame == 0 ) {
3585           if ( isSingleNode[0] )
3586             aNewElem = aMesh->AddEdge( prevNod[ 0 ], nextNod[ 0 ] );
3587           else
3588             aNewElem = aMesh->AddEdge( prevNod[ 0 ], nextNod[ 0 ], midlNod[ 0 ] );
3589         }
3590         else
3591           return;
3592         break;
3593       }
3594       case SMDSEntity_Edge: { // sweep EDGE
3595         if ( nbDouble == 0 )
3596         {
3597           if ( nbSame == 0 ) // ---> quadrangle
3598             aNewElem = aMesh->AddFace(prevNod[ 0 ], prevNod[ 1 ],
3599                                       nextNod[ 1 ], nextNod[ 0 ] );
3600           else               // ---> triangle
3601             aNewElem = aMesh->AddFace(prevNod[ 0 ], prevNod[ 1 ],
3602                                       nextNod[ iNotSameNode ] );
3603         }
3604         else                 // ---> polygon
3605         {
3606           vector<const SMDS_MeshNode*> poly_nodes;
3607           poly_nodes.push_back( prevNod[0] );
3608           poly_nodes.push_back( prevNod[1] );
3609           if ( prevNod[1] != nextNod[1] )
3610           {
3611             if ( midlNod[1]) poly_nodes.push_back( midlNod[1]);
3612             poly_nodes.push_back( nextNod[1] );
3613           }
3614           if ( prevNod[0] != nextNod[0] )
3615           {
3616             poly_nodes.push_back( nextNod[0] );
3617             if ( midlNod[0]) poly_nodes.push_back( midlNod[0]);
3618           }
3619           switch ( poly_nodes.size() ) {
3620           case 3:
3621             aNewElem = aMesh->AddFace( poly_nodes[ 0 ], poly_nodes[ 1 ], poly_nodes[ 2 ]);
3622             break;
3623           case 4:
3624             aNewElem = aMesh->AddFace( poly_nodes[ 0 ], poly_nodes[ 1 ],
3625                                        poly_nodes[ 2 ], poly_nodes[ 3 ]);
3626             break;
3627           default:
3628             aNewElem = aMesh->AddPolygonalFace (poly_nodes);
3629           }
3630         }
3631         break;
3632       }
3633       case SMDSEntity_Triangle: // TRIANGLE --->
3634         {
3635           if ( nbDouble > 0 ) break;
3636           if ( nbSame == 0 )       // ---> pentahedron
3637             aNewElem = aMesh->AddVolume (prevNod[ 0 ], prevNod[ 1 ], prevNod[ 2 ],
3638                                          nextNod[ 0 ], nextNod[ 1 ], nextNod[ 2 ] );
3639
3640           else if ( nbSame == 1 )  // ---> pyramid
3641             aNewElem = aMesh->AddVolume (prevNod[ iBeforeSame ], prevNod[ iAfterSame ],
3642                                          nextNod[ iAfterSame ],  nextNod[ iBeforeSame ],
3643                                          nextNod[ iSameNode ]);
3644
3645           else // 2 same nodes:       ---> tetrahedron
3646             aNewElem = aMesh->AddVolume (prevNod[ 0 ], prevNod[ 1 ], prevNod[ 2 ],
3647                                          nextNod[ iNotSameNode ]);
3648           break;
3649         }
3650       case SMDSEntity_Quad_Edge: // sweep quadratic EDGE --->
3651         {
3652           if ( nbSame == 2 )
3653             return;
3654           if ( nbDouble+nbSame == 2 )
3655           {
3656             if(nbSame==0) {      // ---> quadratic quadrangle
3657               aNewElem = aMesh->AddFace(prevNod[0], prevNod[1], nextNod[1], nextNod[0],
3658                                         prevNod[2], midlNod[1], nextNod[2], midlNod[0]);
3659             }
3660             else { //(nbSame==1) // ---> quadratic triangle
3661               if(sames[0]==2) {
3662                 return; // medium node on axis
3663               }
3664               else if(sames[0]==0)
3665                 aNewElem = aMesh->AddFace(prevNod[0], nextNod[1], prevNod[1],
3666                                           nextNod[2], midlNod[1], prevNod[2]);
3667               else // sames[0]==1
3668                 aNewElem = aMesh->AddFace(prevNod[0], nextNod[0], prevNod[1],
3669                                           midlNod[0], nextNod[2], prevNod[2]);
3670             }
3671           }
3672           else if ( nbDouble == 3 )
3673           {
3674             if ( nbSame == 0 ) {  // ---> bi-quadratic quadrangle
3675               aNewElem = aMesh->AddFace(prevNod[0], prevNod[1], nextNod[1], nextNod[0],
3676                                         prevNod[2], midlNod[1], nextNod[2], midlNod[0], midlNod[2]);
3677             }
3678           }
3679           else
3680             return;
3681           break;
3682         }
3683       case SMDSEntity_Quadrangle: { // sweep QUADRANGLE --->
3684         if ( nbDouble > 0 ) break;
3685
3686         if ( nbSame == 0 )       // ---> hexahedron
3687           aNewElem = aMesh->AddVolume (prevNod[ 0 ], prevNod[ 1 ], prevNod[ 2 ], prevNod[ 3 ],
3688                                        nextNod[ 0 ], nextNod[ 1 ], nextNod[ 2 ], nextNod[ 3 ]);
3689
3690         else if ( nbSame == 1 ) { // ---> pyramid + pentahedron
3691           aNewElem = aMesh->AddVolume (prevNod[ iBeforeSame ], prevNod[ iAfterSame ],
3692                                        nextNod[ iAfterSame ],  nextNod[ iBeforeSame ],
3693                                        nextNod[ iSameNode ]);
3694           newElems.push_back( aNewElem );
3695           aNewElem = aMesh->AddVolume (prevNod[ iAfterSame ],  prevNod[ iOpposSame ],
3696                                        prevNod[ iBeforeSame ], nextNod[ iAfterSame ],
3697                                        nextNod[ iOpposSame ],  nextNod[ iBeforeSame ] );
3698         }
3699         else if ( nbSame == 2 ) { // ---> pentahedron
3700           if ( prevNod[ iBeforeSame ] == nextNod[ iBeforeSame ] )
3701             // iBeforeSame is same too
3702             aNewElem = aMesh->AddVolume (prevNod[ iBeforeSame ], prevNod[ iOpposSame ],
3703                                          nextNod[ iOpposSame ],  prevNod[ iSameNode ],
3704                                          prevNod[ iAfterSame ],  nextNod[ iAfterSame ]);
3705           else
3706             // iAfterSame is same too
3707             aNewElem = aMesh->AddVolume (prevNod[ iSameNode ],   prevNod[ iBeforeSame ],
3708                                          nextNod[ iBeforeSame ], prevNod[ iAfterSame ],
3709                                          prevNod[ iOpposSame ],  nextNod[ iOpposSame ]);
3710         }
3711         break;
3712       }
3713       case SMDSEntity_Quad_Triangle: { // sweep Quadratic TRIANGLE --->
3714         if ( nbDouble+nbSame != 3 ) break;
3715         if(nbSame==0) {
3716           // --->  pentahedron with 15 nodes
3717           aNewElem = aMesh->AddVolume (prevNod[0], prevNod[1], prevNod[2],
3718                                        nextNod[0], nextNod[1], nextNod[2],
3719                                        prevNod[3], prevNod[4], prevNod[5],
3720                                        nextNod[3], nextNod[4], nextNod[5],
3721                                        midlNod[0], midlNod[1], midlNod[2]);
3722         }
3723         else if(nbSame==1) {
3724           // --->  2d order pyramid of 13 nodes
3725           int apex = iSameNode;
3726           int i0 = ( apex + 1 ) % nbCorners;
3727           int i1 = ( apex - 1 + nbCorners ) % nbCorners;
3728           int i0a = apex + 3;
3729           int i1a = i1 + 3;
3730           int i01 = i0 + 3;
3731           aNewElem = aMesh->AddVolume(prevNod[i1], prevNod[i0],
3732                                       nextNod[i0], nextNod[i1], prevNod[apex],
3733                                       prevNod[i01], midlNod[i0],
3734                                       nextNod[i01], midlNod[i1],
3735                                       prevNod[i1a], prevNod[i0a],
3736                                       nextNod[i0a], nextNod[i1a]);
3737         }
3738         else if(nbSame==2) {
3739           // --->  2d order tetrahedron of 10 nodes
3740           int n1 = iNotSameNode;
3741           int n2 = ( n1 + 1             ) % nbCorners;
3742           int n3 = ( n1 + nbCorners - 1 ) % nbCorners;
3743           int n12 = n1 + 3;
3744           int n23 = n2 + 3;
3745           int n31 = n3 + 3;
3746           aNewElem = aMesh->AddVolume (prevNod[n1], prevNod[n2], prevNod[n3], nextNod[n1],
3747                                        prevNod[n12], prevNod[n23], prevNod[n31],
3748                                        midlNod[n1], nextNod[n12], nextNod[n31]);
3749         }
3750         break;
3751       }
3752       case SMDSEntity_Quad_Quadrangle: { // sweep Quadratic QUADRANGLE --->
3753         if ( nbDouble != 4 ) break;
3754         if( nbSame == 0 ) {
3755           // --->  hexahedron with 20 nodes
3756           aNewElem = aMesh->AddVolume (prevNod[0], prevNod[1], prevNod[2], prevNod[3],
3757                                        nextNod[0], nextNod[1], nextNod[2], nextNod[3],
3758                                        prevNod[4], prevNod[5], prevNod[6], prevNod[7],
3759                                        nextNod[4], nextNod[5], nextNod[6], nextNod[7],
3760                                        midlNod[0], midlNod[1], midlNod[2], midlNod[3]);
3761         }
3762         else if(nbSame==1) {
3763           // ---> pyramid + pentahedron - can not be created since it is needed 
3764           // additional middle node at the center of face
3765           INFOS( " Sweep for face " << elem->GetID() << " can not be created" );
3766           return;
3767         }
3768         else if( nbSame == 2 ) {
3769           // --->  2d order Pentahedron with 15 nodes
3770           int n1,n2,n4,n5;
3771           if ( prevNod[ iBeforeSame ] == nextNod[ iBeforeSame ] ) {
3772             // iBeforeSame is same too
3773             n1 = iBeforeSame;
3774             n2 = iOpposSame;
3775             n4 = iSameNode;
3776             n5 = iAfterSame;
3777           }
3778           else {
3779             // iAfterSame is same too
3780             n1 = iSameNode;
3781             n2 = iBeforeSame;
3782             n4 = iAfterSame;
3783             n5 = iOpposSame;
3784           }
3785           int n12 = n2 + 4;
3786           int n45 = n4 + 4;
3787           int n14 = n1 + 4;
3788           int n25 = n5 + 4;
3789           aNewElem = aMesh->AddVolume (prevNod[n1], prevNod[n2], nextNod[n2],
3790                                        prevNod[n4], prevNod[n5], nextNod[n5],
3791                                        prevNod[n12], midlNod[n2], nextNod[n12],
3792                                        prevNod[n45], midlNod[n5], nextNod[n45],
3793                                        prevNod[n14], prevNod[n25], nextNod[n25]);
3794         }
3795         break;
3796       }
3797       case SMDSEntity_BiQuad_Quadrangle: { // sweep BiQuadratic QUADRANGLE --->
3798
3799         if( nbSame == 0 && nbDouble == 9 ) {
3800           // --->  tri-quadratic hexahedron with 27 nodes
3801           aNewElem = aMesh->AddVolume (prevNod[0], prevNod[1], prevNod[2], prevNod[3],
3802                                        nextNod[0], nextNod[1], nextNod[2], nextNod[3],
3803                                        prevNod[4], prevNod[5], prevNod[6], prevNod[7],
3804                                        nextNod[4], nextNod[5], nextNod[6], nextNod[7],
3805                                        midlNod[0], midlNod[1], midlNod[2], midlNod[3],
3806                                        prevNod[8], // bottom center
3807                                        midlNod[4], midlNod[5], midlNod[6], midlNod[7],
3808                                        nextNod[8], // top center
3809                                        midlNod[8]);// elem center
3810         }
3811         else
3812         {
3813           return;
3814         }
3815         break;
3816       }
3817       case SMDSEntity_Polygon: { // sweep POLYGON
3818
3819         if ( nbNodes == 6 && nbSame == 0 && nbDouble == 0 ) {
3820           // --->  hexagonal prism
3821           aNewElem = aMesh->AddVolume (prevNod[0], prevNod[1], prevNod[2],
3822                                        prevNod[3], prevNod[4], prevNod[5],
3823                                        nextNod[0], nextNod[1], nextNod[2],
3824                                        nextNod[3], nextNod[4], nextNod[5]);
3825         }
3826         break;
3827       }
3828       default:
3829         break;
3830       }
3831     }
3832
3833     if ( !aNewElem && elem->GetType() == SMDSAbs_Face ) // try to create a polyherdal prism
3834     {
3835       if ( baseType != SMDSEntity_Polygon )
3836       {
3837         const std::vector<int>& ind = SMDS_MeshCell::interlacedSmdsOrder(baseType);
3838         SMDS_MeshCell::applyInterlace( ind, prevNod );
3839         SMDS_MeshCell::applyInterlace( ind, nextNod );
3840         SMDS_MeshCell::applyInterlace( ind, midlNod );
3841         SMDS_MeshCell::applyInterlace( ind, itNN );
3842         SMDS_MeshCell::applyInterlace( ind, isSingleNode );
3843         baseType = SMDSEntity_Polygon; // WARNING: change baseType !!!!
3844       }
3845       vector<const SMDS_MeshNode*> polyedre_nodes (nbNodes*2 + 4*nbNodes);
3846       vector<int> quantities (nbNodes + 2);
3847       polyedre_nodes.clear();
3848       quantities.clear();
3849
3850       // bottom of prism
3851       for (int inode = 0; inode < nbNodes; inode++)
3852         polyedre_nodes.push_back( prevNod[inode] );
3853       quantities.push_back( nbNodes );
3854
3855       // top of prism
3856       polyedre_nodes.push_back( nextNod[0] );
3857       for (int inode = nbNodes; inode-1; --inode )
3858         polyedre_nodes.push_back( nextNod[inode-1] );
3859       quantities.push_back( nbNodes );
3860
3861       // side faces
3862       for (int iface = 0; iface < nbNodes; iface++)
3863       {
3864         const int prevNbNodes = polyedre_nodes.size();
3865         int inextface = (iface+1) % nbNodes;
3866         polyedre_nodes.push_back( prevNod[inextface] );
3867         polyedre_nodes.push_back( prevNod[iface] );
3868         if ( prevNod[iface] != nextNod[iface] )
3869         {
3870           if ( midlNod[ iface ]) polyedre_nodes.push_back( midlNod[ iface ]);
3871           polyedre_nodes.push_back( nextNod[iface] );
3872         }
3873         if ( prevNod[inextface] != nextNod[inextface] )
3874         {
3875           polyedre_nodes.push_back( nextNod[inextface] );
3876           if ( midlNod[ inextface ]) polyedre_nodes.push_back( midlNod[ inextface ]);
3877         }
3878         const int nbFaceNodes = polyedre_nodes.size() - prevNbNodes;
3879         if ( nbFaceNodes > 2 )
3880           quantities.push_back( nbFaceNodes );
3881         else // degenerated face
3882           polyedre_nodes.resize( prevNbNodes );
3883       }
3884       aNewElem = aMesh->AddPolyhedralVolume (polyedre_nodes, quantities);
3885     }
3886
3887     if ( aNewElem ) {
3888       newElems.push_back( aNewElem );
3889       myLastCreatedElems.Append(aNewElem);
3890       srcElements.Append( elem );
3891     }
3892
3893     // set new prev nodes
3894     for ( iNode = 0; iNode < nbNodes; iNode++ )
3895       prevNod[ iNode ] = nextNod[ iNode ];
3896
3897   } // for steps
3898 }
3899
3900 //=======================================================================
3901 /*!
3902  * \brief Create 1D and 2D elements around swept elements
3903  * \param mapNewNodes - source nodes and ones generated from them
3904  * \param newElemsMap - source elements and ones generated from them
3905  * \param elemNewNodesMap - nodes generated from each node of each element
3906  * \param elemSet - all swept elements
3907  * \param nbSteps - number of sweeping steps
3908  * \param srcElements - to append elem for each generated element
3909  */
3910 //=======================================================================
3911
3912 void SMESH_MeshEditor::makeWalls (TNodeOfNodeListMap &     mapNewNodes,
3913                                   TElemOfElemListMap &     newElemsMap,
3914                                   TElemOfVecOfNnlmiMap &   elemNewNodesMap,
3915                                   TIDSortedElemSet&        elemSet,
3916                                   const int                nbSteps,
3917                                   SMESH_SequenceOfElemPtr& srcElements)
3918 {
3919   ASSERT( newElemsMap.size() == elemNewNodesMap.size() );
3920   SMESHDS_Mesh* aMesh = GetMeshDS();
3921
3922   // Find nodes belonging to only one initial element - sweep them to get edges.
3923
3924   TNodeOfNodeListMapItr nList = mapNewNodes.begin();
3925   for ( ; nList != mapNewNodes.end(); nList++ )
3926   {
3927     const SMDS_MeshNode* node =
3928       static_cast<const SMDS_MeshNode*>( nList->first );
3929     SMDS_ElemIteratorPtr eIt = node->GetInverseElementIterator();
3930     int nbInitElems = 0;
3931     const SMDS_MeshElement* el = 0;
3932     SMDSAbs_ElementType highType = SMDSAbs_Edge; // count most complex elements only
3933     while ( eIt->more() && nbInitElems < 2 ) {
3934       el = eIt->next();
3935       SMDSAbs_ElementType type = el->GetType();
3936       if ( type == SMDSAbs_Volume || type < highType ) continue;
3937       if ( type > highType ) {
3938         nbInitElems = 0;
3939         highType = type;
3940       }
3941       nbInitElems += elemSet.count(el);
3942     }
3943     if ( nbInitElems < 2 ) {
3944       bool NotCreateEdge = el && el->IsMediumNode(node);
3945       if(!NotCreateEdge) {
3946         vector<TNodeOfNodeListMapItr> newNodesItVec( 1, nList );
3947         list<const SMDS_MeshElement*> newEdges;
3948         sweepElement( node, newNodesItVec, newEdges, nbSteps, srcElements );
3949       }
3950     }
3951   }
3952
3953   // Make a ceiling for each element ie an equal element of last new nodes.
3954   // Find free links of faces - make edges and sweep them into faces.
3955
3956   TElemOfElemListMap::iterator   itElem      = newElemsMap.begin();
3957   TElemOfVecOfNnlmiMap::iterator itElemNodes = elemNewNodesMap.begin();
3958   for ( ; itElem != newElemsMap.end(); itElem++, itElemNodes++ )
3959   {
3960     const SMDS_MeshElement* elem = itElem->first;
3961     vector<TNodeOfNodeListMapItr>& vecNewNodes = itElemNodes->second;
3962
3963     if(itElem->second.size()==0) continue;
3964
3965     const bool isQuadratic = elem->IsQuadratic();
3966
3967     if ( elem->GetType() == SMDSAbs_Edge ) {
3968       // create a ceiling edge
3969       if ( !isQuadratic ) {
3970         if ( !aMesh->FindEdge( vecNewNodes[ 0 ]->second.back(),
3971                                vecNewNodes[ 1 ]->second.back())) {
3972           myLastCreatedElems.Append(aMesh->AddEdge(vecNewNodes[ 0 ]->second.back(),
3973                                                    vecNewNodes[ 1 ]->second.back()));
3974           srcElements.Append( myLastCreatedElems.Last() );
3975         }
3976       }
3977       else {
3978         if ( !aMesh->FindEdge( vecNewNodes[ 0 ]->second.back(),
3979                                vecNewNodes[ 1 ]->second.back(),
3980                                vecNewNodes[ 2 ]->second.back())) {
3981           myLastCreatedElems.Append(aMesh->AddEdge(vecNewNodes[ 0 ]->second.back(),
3982                                                    vecNewNodes[ 1 ]->second.back(),
3983                                                    vecNewNodes[ 2 ]->second.back()));
3984           srcElements.Append( myLastCreatedElems.Last() );
3985         }
3986       }
3987     }
3988     if ( elem->GetType() != SMDSAbs_Face )
3989       continue;
3990
3991     bool hasFreeLinks = false;
3992
3993     TIDSortedElemSet avoidSet;
3994     avoidSet.insert( elem );
3995
3996     set<const SMDS_MeshNode*> aFaceLastNodes;
3997     int iNode, nbNodes = vecNewNodes.size();
3998     if ( !isQuadratic ) {
3999       // loop on the face nodes
4000       for ( iNode = 0; iNode < nbNodes; iNode++ ) {
4001         aFaceLastNodes.insert( vecNewNodes[ iNode ]->second.back() );
4002         // look for free links of the face
4003         int iNext = ( iNode + 1 == nbNodes ) ? 0 : iNode + 1;
4004         const SMDS_MeshNode* n1 = vecNewNodes[ iNode ]->first;
4005         const SMDS_MeshNode* n2 = vecNewNodes[ iNext ]->first;
4006         // check if a link is free
4007         if ( ! SMESH_MeshEditor::FindFaceInSet ( n1, n2, elemSet, avoidSet )) {
4008           hasFreeLinks = true;
4009           // make an edge and a ceiling for a new edge
4010           if ( !aMesh->FindEdge( n1, n2 )) {
4011             myLastCreatedElems.Append(aMesh->AddEdge( n1, n2 )); // free link edge
4012             srcElements.Append( myLastCreatedElems.Last() );
4013           }
4014           n1 = vecNewNodes[ iNode ]->second.back();
4015           n2 = vecNewNodes[ iNext ]->second.back();
4016           if ( !aMesh->FindEdge( n1, n2 )) {
4017             myLastCreatedElems.Append(aMesh->AddEdge( n1, n2 )); // ceiling edge
4018             srcElements.Append( myLastCreatedElems.Last() );
4019           }
4020         }
4021       }
4022     }
4023     else { // elem is quadratic face
4024       int nbn = nbNodes/2;
4025       for ( iNode = 0; iNode < nbn; iNode++ ) {
4026         aFaceLastNodes.insert( vecNewNodes[ iNode ]->second.back() );
4027         int iNext = ( iNode + 1 == nbn ) ? 0 : iNode + 1;
4028         const SMDS_MeshNode* n1 = vecNewNodes[ iNode ]->first;
4029         const SMDS_MeshNode* n2 = vecNewNodes[ iNext ]->first;
4030         const SMDS_MeshNode* n3 = vecNewNodes[ iNode+nbn ]->first;
4031         // check if a link is free
4032         if ( ! SMESH_MeshEditor::FindFaceInSet ( n1, n2, elemSet, avoidSet ) &&
4033              ! SMESH_MeshEditor::FindFaceInSet ( n1, n3, elemSet, avoidSet ) &&
4034              ! SMESH_MeshEditor::FindFaceInSet ( n3, n2, elemSet, avoidSet ) ) {
4035           hasFreeLinks = true;
4036           // make an edge and a ceiling for a new edge
4037           // find medium node
4038           if ( !aMesh->FindEdge( n1, n2, n3 )) {
4039             myLastCreatedElems.Append(aMesh->AddEdge( n1, n2, n3 )); // free link edge
4040             srcElements.Append( myLastCreatedElems.Last() );
4041           }
4042           n1 = vecNewNodes[ iNode ]->second.back();
4043           n2 = vecNewNodes[ iNext ]->second.back();
4044           n3 = vecNewNodes[ iNode+nbn ]->second.back();
4045           if ( !aMesh->FindEdge( n1, n2, n3 )) {
4046             myLastCreatedElems.Append(aMesh->AddEdge( n1, n2, n3 )); // ceiling edge
4047             srcElements.Append( myLastCreatedElems.Last() );
4048           }
4049         }
4050       }
4051       for ( iNode = nbn; iNode < nbNodes; iNode++ ) {
4052         aFaceLastNodes.insert( vecNewNodes[ iNode ]->second.back() );
4053       }
4054     }
4055
4056     // sweep free links into faces
4057
4058     if ( hasFreeLinks )  {
4059       list<const SMDS_MeshElement*> & newVolumes = itElem->second;
4060       int iVol, volNb, nbVolumesByStep = newVolumes.size() / nbSteps;
4061
4062       set<const SMDS_MeshNode*> initNodeSet, topNodeSet, faceNodeSet;
4063       for ( iNode = 0; iNode < nbNodes; iNode++ ) {
4064         initNodeSet.insert( vecNewNodes[ iNode ]->first );
4065         topNodeSet .insert( vecNewNodes[ iNode ]->second.back() );
4066       }
4067       for ( volNb = 0; volNb < nbVolumesByStep; volNb++ ) {
4068         list<const SMDS_MeshElement*>::iterator v = newVolumes.begin();
4069         std::advance( v, volNb );
4070         // find indices of free faces of a volume and their source edges
4071         list< int > freeInd;
4072         list< const SMDS_MeshElement* > srcEdges; // source edges of free faces
4073         SMDS_VolumeTool vTool( *v, /*ignoreCentralNodes=*/false );
4074         int iF, nbF = vTool.NbFaces();
4075         for ( iF = 0; iF < nbF; iF ++ ) {
4076           if (vTool.IsFreeFace( iF ) &&
4077               vTool.GetFaceNodes( iF, faceNodeSet ) &&
4078               initNodeSet != faceNodeSet) // except an initial face
4079           {
4080             if ( nbSteps == 1 && faceNodeSet == topNodeSet )
4081               continue;
4082             freeInd.push_back( iF );
4083             // find source edge of a free face iF
4084             vector<const SMDS_MeshNode*> commonNodes; // shared by the initial and free faces
4085             commonNodes.resize( initNodeSet.size(), NULL ); // avoid spoiling memory
4086             std::set_intersection( faceNodeSet.begin(), faceNodeSet.end(),
4087                                    initNodeSet.begin(), initNodeSet.end(),
4088                                    commonNodes.begin());
4089             if ( (*v)->IsQuadratic() )
4090               srcEdges.push_back(aMesh->FindEdge (commonNodes[0],commonNodes[1],commonNodes[2]));
4091             else
4092               srcEdges.push_back(aMesh->FindEdge (commonNodes[0],commonNodes[1]));
4093 #ifdef _DEBUG_
4094             if ( !srcEdges.back() )
4095             {
4096               cout << "SMESH_MeshEditor::makeWalls(), no source edge found for a free face #"
4097                    << iF << " of volume #" << vTool.ID() << endl;
4098             }
4099 #endif
4100           }
4101         }
4102         if ( freeInd.empty() )
4103           continue;
4104
4105         // create faces for all steps;
4106         // if such a face has been already created by sweep of edge,
4107         // assure that its orientation is OK
4108         for ( int iStep = 0; iStep < nbSteps; iStep++ ) {
4109           vTool.Set( *v, /*ignoreCentralNodes=*/false );
4110           vTool.SetExternalNormal();
4111           const int nextShift = vTool.IsForward() ? +1 : -1;
4112           list< int >::iterator ind = freeInd.begin();
4113           list< const SMDS_MeshElement* >::iterator srcEdge = srcEdges.begin();
4114           for ( ; ind != freeInd.end(); ++ind, ++srcEdge ) // loop on free faces
4115           {
4116             const SMDS_MeshNode** nodes = vTool.GetFaceNodes( *ind );
4117             int nbn = vTool.NbFaceNodes( *ind );
4118             const SMDS_MeshElement * f = 0;
4119             if ( nbn == 3 )              ///// triangle
4120             {
4121               f = aMesh->FindFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ]);
4122               if ( !f ||
4123                    nodes[ 1 ] != f->GetNodeWrap( f->GetNodeIndex( nodes[ 0 ]) + nextShift ))
4124               {
4125                 const SMDS_MeshNode* newOrder[3] = { nodes[ 1 - nextShift ],
4126                                                      nodes[ 1 ],
4127                                                      nodes[ 1 + nextShift ] };
4128                 if ( f )
4129                   aMesh->ChangeElementNodes( f, &newOrder[0], nbn );
4130                 else
4131                   myLastCreatedElems.Append(aMesh->AddFace( newOrder[ 0 ], newOrder[ 1 ],
4132                                                             newOrder[ 2 ] ));
4133               }
4134             }
4135             else if ( nbn == 4 )       ///// quadrangle
4136             {
4137               f = aMesh->FindFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ], nodes[ 3 ]);
4138               if ( !f ||
4139                    nodes[ 1 ] != f->GetNodeWrap( f->GetNodeIndex( nodes[ 0 ]) + nextShift ))
4140               {
4141                 const SMDS_MeshNode* newOrder[4] = { nodes[ 0 ], nodes[ 2-nextShift ],
4142                                                      nodes[ 2 ], nodes[ 2+nextShift ] };
4143                 if ( f )
4144                   aMesh->ChangeElementNodes( f, &newOrder[0], nbn );
4145                 else
4146                   myLastCreatedElems.Append(aMesh->AddFace( newOrder[ 0 ], newOrder[ 1 ],
4147                                                             newOrder[ 2 ], newOrder[ 3 ]));
4148               }
4149             }
4150             else if ( nbn == 6 && isQuadratic ) /////// quadratic triangle
4151             {
4152               f = aMesh->FindFace( nodes[0], nodes[2], nodes[4], nodes[1], nodes[3], nodes[5] );
4153               if ( !f ||
4154                    nodes[2] != f->GetNodeWrap( f->GetNodeIndex( nodes[0] ) + 2*nextShift ))
4155               {
4156                 const SMDS_MeshNode* newOrder[6] = { nodes[2 - 2*nextShift],
4157                                                      nodes[2],
4158                                                      nodes[2 + 2*nextShift],
4159                                                      nodes[3 - 2*nextShift],
4160                                                      nodes[3],
4161                                                      nodes[3 + 2*nextShift]};
4162                 if ( f )
4163                   aMesh->ChangeElementNodes( f, &newOrder[0], nbn );
4164                 else
4165                   myLastCreatedElems.Append(aMesh->AddFace( newOrder[ 0 ],
4166                                                             newOrder[ 1 ],
4167                                                             newOrder[ 2 ],
4168                                                             newOrder[ 3 ],
4169                                                             newOrder[ 4 ],
4170                                                             newOrder[ 5 ] ));
4171               }
4172             }
4173             else if ( nbn == 8 && isQuadratic ) /////// quadratic quadrangle
4174             {
4175               f = aMesh->FindFace( nodes[0], nodes[2], nodes[4], nodes[6],
4176                                    nodes[1], nodes[3], nodes[5], nodes[7] );
4177               if ( !f ||
4178                    nodes[ 2 ] != f->GetNodeWrap( f->GetNodeIndex( nodes[ 0 ] ) + 2*nextShift ))
4179               {
4180                 const SMDS_MeshNode* newOrder[8] = { nodes[0],
4181                                                      nodes[4 - 2*nextShift],
4182                                                      nodes[4],
4183                                                      nodes[4 + 2*nextShift],
4184                                                      nodes[1],
4185                                                      nodes[5 - 2*nextShift],
4186                                                      nodes[5],
4187                                                      nodes[5 + 2*nextShift] };
4188                 if ( f )
4189                   aMesh->ChangeElementNodes( f, &newOrder[0], nbn );
4190                 else
4191                   myLastCreatedElems.Append(aMesh->AddFace(newOrder[ 0 ], newOrder[ 1 ],
4192                                                            newOrder[ 2 ], newOrder[ 3 ],
4193                                                            newOrder[ 4 ], newOrder[ 5 ],
4194                                                            newOrder[ 6 ], newOrder[ 7 ]));
4195               }
4196             }
4197             else if ( nbn == 9 && isQuadratic ) /////// bi-quadratic quadrangle
4198             {
4199               f = aMesh->FindElement( vector<const SMDS_MeshNode*>( nodes, nodes+nbn ),
4200                                       SMDSAbs_Face, /*noMedium=*/false);
4201               if ( !f ||
4202                    nodes[ 2 ] != f->GetNodeWrap( f->GetNodeIndex( nodes[ 0 ] ) + 2*nextShift ))
4203               {
4204                 const SMDS_MeshNode* newOrder[9] = { nodes[0],
4205                                                      nodes[4 - 2*nextShift],
4206                                                      nodes[4],
4207                                                      nodes[4 + 2*nextShift],
4208                                                      nodes[1],
4209                                                      nodes[5 - 2*nextShift],
4210                                                      nodes[5],
4211                                                      nodes[5 + 2*nextShift],
4212                                                      nodes[8] };
4213                 if ( f )
4214                   aMesh->ChangeElementNodes( f, &newOrder[0], nbn );
4215                 else
4216                   myLastCreatedElems.Append(aMesh->AddFace(newOrder[ 0 ], newOrder[ 1 ],
4217                                                            newOrder[ 2 ], newOrder[ 3 ],
4218                                                            newOrder[ 4 ], newOrder[ 5 ],
4219                                                            newOrder[ 6 ], newOrder[ 7 ],
4220                                                            newOrder[ 8 ]));
4221               }
4222             }
4223             else  //////// polygon
4224             {
4225               vector<const SMDS_MeshNode*> polygon_nodes ( nodes, nodes+nbn );
4226               const SMDS_MeshFace * f = aMesh->FindFace( polygon_nodes );
4227               if ( !f ||
4228                    nodes[ 1 ] != f->GetNodeWrap( f->GetNodeIndex( nodes[ 0 ] ) + nextShift ))
4229               {
4230                 if ( !vTool.IsForward() )
4231                   std::reverse( polygon_nodes.begin(), polygon_nodes.end());
4232                 if ( f )
4233                   aMesh->ChangeElementNodes( f, &polygon_nodes[0], nbn );
4234                 else
4235                   AddElement(polygon_nodes, SMDSAbs_Face, polygon_nodes.size()>4);
4236               }
4237             }
4238
4239             while ( srcElements.Length() < myLastCreatedElems.Length() )
4240               srcElements.Append( *srcEdge );
4241
4242           }  // loop on free faces
4243
4244           // go to the next volume
4245           iVol = 0;
4246           while ( iVol++ < nbVolumesByStep ) v++;
4247
4248         } // loop on steps
4249       } // loop on volumes of one step
4250     } // sweep free links into faces
4251
4252     // Make a ceiling face with a normal external to a volume
4253
4254     SMDS_VolumeTool lastVol( itElem->second.back(), /*ignoreCentralNodes=*/false );
4255
4256     int iF = lastVol.GetFaceIndex( aFaceLastNodes );
4257     if ( iF >= 0 ) {
4258       lastVol.SetExternalNormal();
4259       const SMDS_MeshNode** nodes = lastVol.GetFaceNodes( iF );
4260       int nbn = lastVol.NbFaceNodes( iF );
4261       if ( nbn == 3 ) {
4262         if (!hasFreeLinks ||
4263             !aMesh->FindFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ]))
4264           myLastCreatedElems.Append(aMesh->AddFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ] ));
4265       }
4266       else if ( nbn == 4 )
4267       {
4268         if (!hasFreeLinks ||
4269             !aMesh->FindFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ], nodes[ 3 ]))
4270           myLastCreatedElems.Append(aMesh->AddFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ], nodes[ 3 ]));
4271       }
4272       else if ( nbn == 6 && isQuadratic )
4273       {
4274         if (!hasFreeLinks ||
4275             !aMesh->FindFace(nodes[0], nodes[2], nodes[4], nodes[1], nodes[3], nodes[5]) )
4276           myLastCreatedElems.Append(aMesh->AddFace(nodes[0], nodes[2], nodes[4],
4277                                                    nodes[1], nodes[3], nodes[5]));
4278       }
4279       else if ( nbn == 8 && isQuadratic )
4280       {
4281         if (!hasFreeLinks ||
4282             !aMesh->FindFace(nodes[0], nodes[2], nodes[4], nodes[6],
4283                              nodes[1], nodes[3], nodes[5], nodes[7]) )
4284           myLastCreatedElems.Append(aMesh->AddFace(nodes[0], nodes[2], nodes[4], nodes[6],
4285                                                    nodes[1], nodes[3], nodes[5], nodes[7]));
4286       }
4287       else if ( nbn == 9 && isQuadratic )
4288       {
4289         if (!hasFreeLinks ||
4290             !aMesh->FindElement(vector<const SMDS_MeshNode*>( nodes, nodes+nbn ),
4291                                 SMDSAbs_Face, /*noMedium=*/false) )
4292           myLastCreatedElems.Append(aMesh->AddFace(nodes[0], nodes[2], nodes[4], nodes[6],
4293                                                    nodes[1], nodes[3], nodes[5], nodes[7],
4294                                                    nodes[8]));
4295       }
4296       else {
4297         vector<const SMDS_MeshNode*> polygon_nodes ( nodes, nodes + nbn );
4298         if (!hasFreeLinks || !aMesh->FindFace(polygon_nodes))
4299           myLastCreatedElems.Append(aMesh->AddPolygonalFace(polygon_nodes));
4300       }
4301
4302       while ( srcElements.Length() < myLastCreatedElems.Length() )
4303         srcElements.Append( myLastCreatedElems.Last() );
4304     }
4305   } // loop on swept elements
4306 }
4307
4308 //=======================================================================
4309 //function : RotationSweep
4310 //purpose  :
4311 //=======================================================================
4312
4313 SMESH_MeshEditor::PGroupIDs
4314 SMESH_MeshEditor::RotationSweep(TIDSortedElemSet & theElems,
4315                                 const gp_Ax1&      theAxis,
4316                                 const double       theAngle,
4317                                 const int          theNbSteps,
4318                                 const double       theTol,
4319                                 const bool         theMakeGroups,
4320                                 const bool         theMakeWalls)
4321 {
4322   myLastCreatedElems.Clear();
4323   myLastCreatedNodes.Clear();
4324
4325   // source elements for each generated one
4326   SMESH_SequenceOfElemPtr srcElems, srcNodes;
4327
4328   MESSAGE( "RotationSweep()");
4329   gp_Trsf aTrsf;
4330   aTrsf.SetRotation( theAxis, theAngle );
4331   gp_Trsf aTrsf2;
4332   aTrsf2.SetRotation( theAxis, theAngle/2. );
4333
4334   gp_Lin aLine( theAxis );
4335   double aSqTol = theTol * theTol;
4336
4337   SMESHDS_Mesh* aMesh = GetMeshDS();
4338
4339   TNodeOfNodeListMap mapNewNodes;
4340   TElemOfVecOfNnlmiMap mapElemNewNodes;
4341   TElemOfElemListMap newElemsMap;
4342
4343   const bool isQuadraticMesh = bool( myMesh->NbEdges(ORDER_QUADRATIC) +
4344                                      myMesh->NbFaces(ORDER_QUADRATIC) +
4345                                      myMesh->NbVolumes(ORDER_QUADRATIC) );
4346   // loop on theElems
4347   TIDSortedElemSet::iterator itElem;
4348   for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
4349     const SMDS_MeshElement* elem = *itElem;
4350     if ( !elem || elem->GetType() == SMDSAbs_Volume )
4351       continue;
4352     vector<TNodeOfNodeListMapItr> & newNodesItVec = mapElemNewNodes[ elem ];
4353     newNodesItVec.reserve( elem->NbNodes() );
4354
4355     // loop on elem nodes
4356     SMDS_ElemIteratorPtr itN = elem->nodesIterator();
4357     while ( itN->more() )
4358     {
4359       // check if a node has been already sweeped
4360       const SMDS_MeshNode* node = cast2Node( itN->next() );
4361
4362       gp_XYZ aXYZ( node->X(), node->Y(), node->Z() );
4363       double coord[3];
4364       aXYZ.Coord( coord[0], coord[1], coord[2] );
4365       bool isOnAxis = ( aLine.SquareDistance( aXYZ ) <= aSqTol );
4366
4367       TNodeOfNodeListMapItr nIt =
4368         mapNewNodes.insert( make_pair( node, list<const SMDS_MeshNode*>() )).first;
4369       list<const SMDS_MeshNode*>& listNewNodes = nIt->second;
4370       if ( listNewNodes.empty() )
4371       {
4372         // check if we are to create medium nodes between corner ones
4373         bool needMediumNodes = false;
4374         if ( isQuadraticMesh )
4375         {
4376           SMDS_ElemIteratorPtr it = node->GetInverseElementIterator();
4377           while (it->more() && !needMediumNodes )
4378           {
4379             const SMDS_MeshElement* invElem = it->next();
4380             if ( invElem != elem && !theElems.count( invElem )) continue;
4381             needMediumNodes = ( invElem->IsQuadratic() && !invElem->IsMediumNode(node) );
4382             if ( !needMediumNodes && invElem->GetEntityType() == SMDSEntity_BiQuad_Quadrangle )
4383               needMediumNodes = true;
4384           }
4385         }
4386
4387         // make new nodes
4388         const SMDS_MeshNode * newNode = node;
4389         for ( int i = 0; i < theNbSteps; i++ ) {
4390           if ( !isOnAxis ) {
4391             if ( needMediumNodes )  // create a medium node
4392             {
4393               aTrsf2.Transforms( coord[0], coord[1], coord[2] );
4394               newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
4395               myLastCreatedNodes.Append(newNode);
4396               srcNodes.Append( node );
4397               listNewNodes.push_back( newNode );
4398               aTrsf2.Transforms( coord[0], coord[1], coord[2] );
4399             }
4400             else {
4401               aTrsf.Transforms( coord[0], coord[1], coord[2] );
4402             }
4403             // create a corner node
4404             newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
4405             myLastCreatedNodes.Append(newNode);
4406             srcNodes.Append( node );
4407             listNewNodes.push_back( newNode );
4408           }
4409           else {
4410             listNewNodes.push_back( newNode );
4411             // if ( needMediumNodes )
4412             //   listNewNodes.push_back( newNode );
4413           }
4414         }
4415       }
4416       newNodesItVec.push_back( nIt );
4417     }
4418     // make new elements
4419     sweepElement( elem, newNodesItVec, newElemsMap[elem], theNbSteps, srcElems );
4420   }
4421
4422   if ( theMakeWalls )
4423     makeWalls( mapNewNodes, newElemsMap, mapElemNewNodes, theElems, theNbSteps, srcElems );
4424
4425   PGroupIDs newGroupIDs;
4426   if ( theMakeGroups )
4427     newGroupIDs = generateGroups( srcNodes, srcElems, "rotated");
4428
4429   return newGroupIDs;
4430 }
4431
4432
4433 //=======================================================================
4434 //function : CreateNode
4435 //purpose  :
4436 //=======================================================================
4437 const SMDS_MeshNode* SMESH_MeshEditor::CreateNode(const double x,
4438                                                   const double y,
4439                                                   const double z,
4440                                                   const double tolnode,
4441                                                   SMESH_SequenceOfNode& aNodes)
4442 {
4443   // myLastCreatedElems.Clear();
4444   // myLastCreatedNodes.Clear();
4445
4446   gp_Pnt P1(x,y,z);
4447   SMESHDS_Mesh * aMesh = myMesh->GetMeshDS();
4448
4449   // try to search in sequence of existing nodes
4450   // if aNodes.Length()>0 we 'nave to use given sequence
4451   // else - use all nodes of mesh
4452   if(aNodes.Length()>0) {
4453     int i;
4454     for(i=1; i<=aNodes.Length(); i++) {
4455       gp_Pnt P2(aNodes.Value(i)->X(),aNodes.Value(i)->Y(),aNodes.Value(i)->Z());
4456       if(P1.Distance(P2)<tolnode)
4457         return aNodes.Value(i);
4458     }
4459   }
4460   else {
4461     SMDS_NodeIteratorPtr itn = aMesh->nodesIterator();
4462     while(itn->more()) {
4463       const SMDS_MeshNode* aN = static_cast<const SMDS_MeshNode*> (itn->next());
4464       gp_Pnt P2(aN->X(),aN->Y(),aN->Z());
4465       if(P1.Distance(P2)<tolnode)
4466         return aN;
4467     }
4468   }
4469
4470   // create new node and return it
4471   const SMDS_MeshNode* NewNode = aMesh->AddNode(x,y,z);
4472   //myLastCreatedNodes.Append(NewNode);
4473   return NewNode;
4474 }
4475
4476
4477 //=======================================================================
4478 //function : ExtrusionSweep
4479 //purpose  :
4480 //=======================================================================
4481
4482 SMESH_MeshEditor::PGroupIDs
4483 SMESH_MeshEditor::ExtrusionSweep (TIDSortedElemSet &  theElems,
4484                                   const gp_Vec&       theStep,
4485                                   const int           theNbSteps,
4486                                   TElemOfElemListMap& newElemsMap,
4487                                   const bool          theMakeGroups,
4488                                   const int           theFlags,
4489                                   const double        theTolerance)
4490 {
4491   ExtrusParam aParams;
4492   aParams.myDir = gp_Dir(theStep);
4493   aParams.myNodes.Clear();
4494   aParams.mySteps = new TColStd_HSequenceOfReal;
4495   int i;
4496   for(i=1; i<=theNbSteps; i++)
4497     aParams.mySteps->Append(theStep.Magnitude());
4498
4499   return
4500     ExtrusionSweep(theElems,aParams,newElemsMap,theMakeGroups,theFlags,theTolerance);
4501 }
4502
4503
4504 //=======================================================================
4505 //function : ExtrusionSweep
4506 //purpose  :
4507 //=======================================================================
4508
4509 SMESH_MeshEditor::PGroupIDs
4510 SMESH_MeshEditor::ExtrusionSweep (TIDSortedElemSet &  theElems,
4511                                   ExtrusParam&        theParams,
4512                                   TElemOfElemListMap& newElemsMap,
4513                                   const bool          theMakeGroups,
4514                                   const int           theFlags,
4515                                   const double        theTolerance)
4516 {
4517   myLastCreatedElems.Clear();
4518   myLastCreatedNodes.Clear();
4519
4520   // source elements for each generated one
4521   SMESH_SequenceOfElemPtr srcElems, srcNodes;
4522
4523   SMESHDS_Mesh* aMesh = GetMeshDS();
4524
4525   int nbsteps = theParams.mySteps->Length();
4526
4527   TNodeOfNodeListMap mapNewNodes;
4528   //TNodeOfNodeVecMap mapNewNodes;
4529   TElemOfVecOfNnlmiMap mapElemNewNodes;
4530   //TElemOfVecOfMapNodesMap mapElemNewNodes;
4531
4532   const bool isQuadraticMesh = bool( myMesh->NbEdges(ORDER_QUADRATIC) +
4533                                      myMesh->NbFaces(ORDER_QUADRATIC) +
4534                                      myMesh->NbVolumes(ORDER_QUADRATIC) );
4535   // loop on theElems
4536   TIDSortedElemSet::iterator itElem;
4537   for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
4538     // check element type
4539     const SMDS_MeshElement* elem = *itElem;
4540     if ( !elem  || elem->GetType() == SMDSAbs_Volume )
4541       continue;
4542
4543     vector<TNodeOfNodeListMapItr> & newNodesItVec = mapElemNewNodes[ elem ];
4544     newNodesItVec.reserve( elem->NbNodes() );
4545
4546     // loop on elem nodes
4547     SMDS_ElemIteratorPtr itN = elem->nodesIterator();
4548     while ( itN->more() )
4549     {
4550       // check if a node has been already sweeped
4551       const SMDS_MeshNode* node = cast2Node( itN->next() );
4552       TNodeOfNodeListMap::iterator nIt =
4553         mapNewNodes.insert( make_pair( node, list<const SMDS_MeshNode*>() )).first;
4554       list<const SMDS_MeshNode*>& listNewNodes = nIt->second;
4555       if ( listNewNodes.empty() )
4556       {
4557         // make new nodes
4558
4559         // check if we are to create medium nodes between corner ones
4560         bool needMediumNodes = false;
4561         if ( isQuadraticMesh )
4562         {
4563           SMDS_ElemIteratorPtr it = node->GetInverseElementIterator();
4564           while (it->more() && !needMediumNodes )
4565           {
4566             const SMDS_MeshElement* invElem = it->next();
4567             if ( invElem != elem && !theElems.count( invElem )) continue;
4568             needMediumNodes = ( invElem->IsQuadratic() && !invElem->IsMediumNode(node) );
4569             if ( !needMediumNodes && invElem->GetEntityType() == SMDSEntity_BiQuad_Quadrangle )
4570               needMediumNodes = true;
4571           }
4572         }
4573
4574         double coord[] = { node->X(), node->Y(), node->Z() };
4575         for ( int i = 0; i < nbsteps; i++ )
4576         {
4577           if ( needMediumNodes ) // create a medium node
4578           {
4579             double x = coord[0] + theParams.myDir.X()*theParams.mySteps->Value(i+1)/2.;
4580             double y = coord[1] + theParams.myDir.Y()*theParams.mySteps->Value(i+1)/2.;
4581             double z = coord[2] + theParams.myDir.Z()*theParams.mySteps->Value(i+1)/2.;
4582             if( theFlags & EXTRUSION_FLAG_SEW ) {
4583               const SMDS_MeshNode * newNode = CreateNode(x, y, z,
4584                                                          theTolerance, theParams.myNodes);
4585               listNewNodes.push_back( newNode );
4586             }
4587             else {
4588               const SMDS_MeshNode * newNode = aMesh->AddNode(x, y, z);
4589               myLastCreatedNodes.Append(newNode);
4590               srcNodes.Append( node );
4591               listNewNodes.push_back( newNode );
4592             }
4593           }
4594           // create a corner node
4595           coord[0] = coord[0] + theParams.myDir.X()*theParams.mySteps->Value(i+1);
4596           coord[1] = coord[1] + theParams.myDir.Y()*theParams.mySteps->Value(i+1);
4597           coord[2] = coord[2] + theParams.myDir.Z()*theParams.mySteps->Value(i+1);
4598           if( theFlags & EXTRUSION_FLAG_SEW ) {
4599             const SMDS_MeshNode * newNode = CreateNode(coord[0], coord[1], coord[2],
4600                                                        theTolerance, theParams.myNodes);
4601             listNewNodes.push_back( newNode );
4602           }
4603           else {
4604             const SMDS_MeshNode * newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
4605             myLastCreatedNodes.Append(newNode);
4606             srcNodes.Append( node );
4607             listNewNodes.push_back( newNode );
4608           }
4609         }
4610       }
4611       newNodesItVec.push_back( nIt );
4612     }
4613     // make new elements
4614     sweepElement( elem, newNodesItVec, newElemsMap[elem], nbsteps, srcElems );
4615   }
4616
4617   if( theFlags & EXTRUSION_FLAG_BOUNDARY ) {
4618     makeWalls( mapNewNodes, newElemsMap, mapElemNewNodes, theElems, nbsteps, srcElems );
4619   }
4620   PGroupIDs newGroupIDs;
4621   if ( theMakeGroups )
4622     newGroupIDs = generateGroups( srcNodes, srcElems, "extruded");
4623
4624   return newGroupIDs;
4625 }
4626
4627 //=======================================================================
4628 //function : ExtrusionAlongTrack
4629 //purpose  :
4630 //=======================================================================
4631 SMESH_MeshEditor::Extrusion_Error
4632 SMESH_MeshEditor::ExtrusionAlongTrack (TIDSortedElemSet &   theElements,
4633                                        SMESH_subMesh*       theTrack,
4634                                        const SMDS_MeshNode* theN1,
4635                                        const bool           theHasAngles,
4636                                        list<double>&        theAngles,
4637                                        const bool           theLinearVariation,
4638                                        const bool           theHasRefPoint,
4639                                        const gp_Pnt&        theRefPoint,
4640                                        const bool           theMakeGroups)
4641 {
4642   MESSAGE("ExtrusionAlongTrack");
4643   myLastCreatedElems.Clear();
4644   myLastCreatedNodes.Clear();
4645
4646   int aNbE;
4647   std::list<double> aPrms;
4648   TIDSortedElemSet::iterator itElem;
4649
4650   gp_XYZ aGC;
4651   TopoDS_Edge aTrackEdge;
4652   TopoDS_Vertex aV1, aV2;
4653
4654   SMDS_ElemIteratorPtr aItE;
4655   SMDS_NodeIteratorPtr aItN;
4656   SMDSAbs_ElementType aTypeE;
4657
4658   TNodeOfNodeListMap mapNewNodes;
4659
4660   // 1. Check data
4661   aNbE = theElements.size();
4662   // nothing to do
4663   if ( !aNbE )
4664     return EXTR_NO_ELEMENTS;
4665
4666   // 1.1 Track Pattern
4667   ASSERT( theTrack );
4668
4669   SMESHDS_SubMesh* pSubMeshDS = theTrack->GetSubMeshDS();
4670
4671   aItE = pSubMeshDS->GetElements();
4672   while ( aItE->more() ) {
4673     const SMDS_MeshElement* pE = aItE->next();
4674     aTypeE = pE->GetType();
4675     // Pattern must contain links only
4676     if ( aTypeE != SMDSAbs_Edge )
4677       return EXTR_PATH_NOT_EDGE;
4678   }
4679
4680   list<SMESH_MeshEditor_PathPoint> fullList;
4681
4682   const TopoDS_Shape& aS = theTrack->GetSubShape();
4683   // Sub shape for the Pattern must be an Edge or Wire
4684   if( aS.ShapeType() == TopAbs_EDGE ) {
4685     aTrackEdge = TopoDS::Edge( aS );
4686     // the Edge must not be degenerated
4687     if ( BRep_Tool::Degenerated( aTrackEdge ) )
4688       return EXTR_BAD_PATH_SHAPE;
4689     TopExp::Vertices( aTrackEdge, aV1, aV2 );
4690     aItN = theTrack->GetFather()->GetSubMesh( aV1 )->GetSubMeshDS()->GetNodes();
4691     const SMDS_MeshNode* aN1 = aItN->next();
4692     aItN = theTrack->GetFather()->GetSubMesh( aV2 )->GetSubMeshDS()->GetNodes();
4693     const SMDS_MeshNode* aN2 = aItN->next();
4694     // starting node must be aN1 or aN2
4695     if ( !( aN1 == theN1 || aN2 == theN1 ) )
4696       return EXTR_BAD_STARTING_NODE;
4697     aItN = pSubMeshDS->GetNodes();
4698     while ( aItN->more() ) {
4699       const SMDS_MeshNode* pNode = aItN->next();
4700       const SMDS_EdgePosition* pEPos =
4701         static_cast<const SMDS_EdgePosition*>( pNode->GetPosition() );
4702       double aT = pEPos->GetUParameter();
4703       aPrms.push_back( aT );
4704     }
4705     //Extrusion_Error err =
4706     MakeEdgePathPoints(aPrms, aTrackEdge, (aN1==theN1), fullList);
4707   } else if( aS.ShapeType() == TopAbs_WIRE ) {
4708     list< SMESH_subMesh* > LSM;
4709     TopTools_SequenceOfShape Edges;
4710     SMESH_subMeshIteratorPtr itSM = theTrack->getDependsOnIterator(false,true);
4711     while(itSM->more()) {
4712       SMESH_subMesh* SM = itSM->next();
4713       LSM.push_back(SM);
4714       const TopoDS_Shape& aS = SM->GetSubShape();
4715       Edges.Append(aS);
4716     }
4717     list< list<SMESH_MeshEditor_PathPoint> > LLPPs;
4718     int startNid = theN1->GetID();
4719     TColStd_MapOfInteger UsedNums;
4720     
4721     int NbEdges = Edges.Length();
4722     int i = 1;
4723     for(; i<=NbEdges; i++) {
4724       int k = 0;
4725       list< SMESH_subMesh* >::iterator itLSM = LSM.begin();
4726       for(; itLSM!=LSM.end(); itLSM++) {
4727         k++;
4728         if(UsedNums.Contains(k)) continue;
4729         aTrackEdge = TopoDS::Edge( Edges.Value(k) );
4730         SMESH_subMesh* locTrack = *itLSM;
4731         SMESHDS_SubMesh* locMeshDS = locTrack->GetSubMeshDS();
4732         TopExp::Vertices( aTrackEdge, aV1, aV2 );
4733         aItN = locTrack->GetFather()->GetSubMesh(aV1)->GetSubMeshDS()->GetNodes();
4734         const SMDS_MeshNode* aN1 = aItN->next();
4735         aItN = locTrack->GetFather()->GetSubMesh(aV2)->GetSubMeshDS()->GetNodes();
4736         const SMDS_MeshNode* aN2 = aItN->next();
4737         // starting node must be aN1 or aN2
4738         if ( !( aN1->GetID() == startNid || aN2->GetID() == startNid ) ) continue;
4739         // 2. Collect parameters on the track edge
4740         aPrms.clear();
4741         aItN = locMeshDS->GetNodes();
4742         while ( aItN->more() ) {
4743           const SMDS_MeshNode* pNode = aItN->next();
4744           const SMDS_EdgePosition* pEPos =
4745             static_cast<const SMDS_EdgePosition*>( pNode->GetPosition() );
4746           double aT = pEPos->GetUParameter();
4747           aPrms.push_back( aT );
4748         }
4749         list<SMESH_MeshEditor_PathPoint> LPP;
4750         //Extrusion_Error err =
4751         MakeEdgePathPoints(aPrms, aTrackEdge,(aN1->GetID()==startNid), LPP);
4752         LLPPs.push_back(LPP);
4753         UsedNums.Add(k);
4754         // update startN for search following egde
4755         if( aN1->GetID() == startNid ) startNid = aN2->GetID();
4756         else startNid = aN1->GetID();
4757         break;
4758       }
4759     }
4760     list< list<SMESH_MeshEditor_PathPoint> >::iterator itLLPP = LLPPs.begin();
4761     list<SMESH_MeshEditor_PathPoint> firstList = *itLLPP;
4762     list<SMESH_MeshEditor_PathPoint>::iterator itPP = firstList.begin();
4763     for(; itPP!=firstList.end(); itPP++) {
4764       fullList.push_back( *itPP );
4765     }
4766     SMESH_MeshEditor_PathPoint PP1 = fullList.back();
4767     fullList.pop_back();
4768     itLLPP++;
4769     for(; itLLPP!=LLPPs.end(); itLLPP++) {
4770       list<SMESH_MeshEditor_PathPoint> currList = *itLLPP;
4771       itPP = currList.begin();
4772       SMESH_MeshEditor_PathPoint PP2 = currList.front();
4773       gp_Dir D1 = PP1.Tangent();
4774       gp_Dir D2 = PP2.Tangent();
4775       gp_Dir Dnew( gp_Vec( (D1.X()+D2.X())/2, (D1.Y()+D2.Y())/2,
4776                            (D1.Z()+D2.Z())/2 ) );
4777       PP1.SetTangent(Dnew);
4778       fullList.push_back(PP1);
4779       itPP++;
4780       for(; itPP!=firstList.end(); itPP++) {
4781         fullList.push_back( *itPP );
4782       }
4783       PP1 = fullList.back();
4784       fullList.pop_back();
4785     }
4786     // if wire not closed
4787     fullList.push_back(PP1);
4788     // else ???
4789   }
4790   else {
4791     return EXTR_BAD_PATH_SHAPE;
4792   }
4793
4794   return MakeExtrElements(theElements, fullList, theHasAngles, theAngles, theLinearVariation,
4795                           theHasRefPoint, theRefPoint, theMakeGroups);
4796 }
4797
4798
4799 //=======================================================================
4800 //function : ExtrusionAlongTrack
4801 //purpose  :
4802 //=======================================================================
4803 SMESH_MeshEditor::Extrusion_Error
4804 SMESH_MeshEditor::ExtrusionAlongTrack (TIDSortedElemSet &   theElements,
4805                                        SMESH_Mesh*          theTrack,
4806                                        const SMDS_MeshNode* theN1,
4807                                        const bool           theHasAngles,
4808                                        list<double>&        theAngles,
4809                                        const bool           theLinearVariation,
4810                                        const bool           theHasRefPoint,
4811                                        const gp_Pnt&        theRefPoint,
4812                                        const bool           theMakeGroups)
4813 {
4814   myLastCreatedElems.Clear();
4815   myLastCreatedNodes.Clear();
4816
4817   int aNbE;
4818   std::list<double> aPrms;
4819   TIDSortedElemSet::iterator itElem;
4820
4821   gp_XYZ aGC;
4822   TopoDS_Edge aTrackEdge;
4823   TopoDS_Vertex aV1, aV2;
4824
4825   SMDS_ElemIteratorPtr aItE;
4826   SMDS_NodeIteratorPtr aItN;
4827   SMDSAbs_ElementType aTypeE;
4828
4829   TNodeOfNodeListMap mapNewNodes;
4830
4831   // 1. Check data
4832   aNbE = theElements.size();
4833   // nothing to do
4834   if ( !aNbE )
4835     return EXTR_NO_ELEMENTS;
4836
4837   // 1.1 Track Pattern
4838   ASSERT( theTrack );
4839
4840   SMESHDS_Mesh* pMeshDS = theTrack->GetMeshDS();
4841
4842   aItE = pMeshDS->elementsIterator();
4843   while ( aItE->more() ) {
4844     const SMDS_MeshElement* pE = aItE->next();
4845     aTypeE = pE->GetType();
4846     // Pattern must contain links only
4847     if ( aTypeE != SMDSAbs_Edge )
4848       return EXTR_PATH_NOT_EDGE;
4849   }
4850
4851   list<SMESH_MeshEditor_PathPoint> fullList;
4852
4853   const TopoDS_Shape& aS = theTrack->GetShapeToMesh();
4854
4855   if( aS == SMESH_Mesh::PseudoShape() ) {
4856     //Mesh without shape
4857     const SMDS_MeshNode* currentNode = NULL;
4858     const SMDS_MeshNode* prevNode = theN1;
4859     std::vector<const SMDS_MeshNode*> aNodesList;
4860     aNodesList.push_back(theN1);
4861     int nbEdges = 0, conn=0;
4862     const SMDS_MeshElement* prevElem = NULL;
4863     const SMDS_MeshElement* currentElem = NULL;
4864     int totalNbEdges = theTrack->NbEdges();
4865     SMDS_ElemIteratorPtr nIt;
4866     bool isClosed = false;
4867
4868     //check start node
4869     if( !theTrack->GetMeshDS()->Contains(theN1) ) {
4870       return EXTR_BAD_STARTING_NODE;
4871     }
4872     
4873     conn = nbEdgeConnectivity(theN1);
4874     if(conn > 2)
4875       return EXTR_PATH_NOT_EDGE;
4876
4877     aItE = theN1->GetInverseElementIterator();
4878     prevElem = aItE->next();
4879     currentElem = prevElem;
4880     //Get all nodes
4881     if(totalNbEdges == 1 ) {
4882       nIt = currentElem->nodesIterator();
4883       currentNode = static_cast<const SMDS_MeshNode*>(nIt->next());
4884       if(currentNode == prevNode)
4885         currentNode = static_cast<const SMDS_MeshNode*>(nIt->next());
4886       aNodesList.push_back(currentNode);
4887     } else { 
4888       nIt = currentElem->nodesIterator();
4889       while( nIt->more() ) {
4890         currentNode = static_cast<const SMDS_MeshNode*>(nIt->next());
4891         if(currentNode == prevNode)
4892           currentNode = static_cast<const SMDS_MeshNode*>(nIt->next());
4893         aNodesList.push_back(currentNode);
4894         
4895         //case of the closed mesh
4896         if(currentNode == theN1) {
4897           nbEdges++;
4898           isClosed = true;
4899           break;
4900         }
4901
4902         conn = nbEdgeConnectivity(currentNode);
4903         if(conn > 2) {
4904           return EXTR_PATH_NOT_EDGE;    
4905         }else if( conn == 1 && nbEdges > 0 ) {
4906           //End of the path
4907           nbEdges++;
4908           break;
4909         }else {
4910           prevNode = currentNode;
4911           aItE = currentNode->GetInverseElementIterator();
4912           currentElem = aItE->next();
4913           if( currentElem  == prevElem)
4914             currentElem = aItE->next();
4915           nIt = currentElem->nodesIterator();
4916           prevElem = currentElem;
4917           nbEdges++;
4918         }
4919       }
4920     } 
4921     
4922     if(nbEdges != totalNbEdges)
4923       return EXTR_PATH_NOT_EDGE;
4924
4925     TopTools_SequenceOfShape Edges;
4926     double x1,x2,y1,y2,z1,z2;
4927     list< list<SMESH_MeshEditor_PathPoint> > LLPPs;
4928     int startNid = theN1->GetID();
4929     for(int i = 1; i < aNodesList.size(); i++) {
4930       x1 = aNodesList[i-1]->X();x2 = aNodesList[i]->X();
4931       y1 = aNodesList[i-1]->Y();y2 = aNodesList[i]->Y();
4932       z1 = aNodesList[i-1]->Z();z2 = aNodesList[i]->Z();
4933       TopoDS_Edge e = BRepBuilderAPI_MakeEdge(gp_Pnt(x1,y1,z1),gp_Pnt(x2,y2,z2));  
4934       list<SMESH_MeshEditor_PathPoint> LPP;
4935       aPrms.clear();
4936       MakeEdgePathPoints(aPrms, e, (aNodesList[i-1]->GetID()==startNid), LPP);
4937       LLPPs.push_back(LPP);
4938       if( aNodesList[i-1]->GetID() == startNid ) startNid = aNodesList[i]->GetID();
4939       else startNid = aNodesList[i-1]->GetID();
4940
4941     }
4942
4943     list< list<SMESH_MeshEditor_PathPoint> >::iterator itLLPP = LLPPs.begin();
4944     list<SMESH_MeshEditor_PathPoint> firstList = *itLLPP;
4945     list<SMESH_MeshEditor_PathPoint>::iterator itPP = firstList.begin();
4946     for(; itPP!=firstList.end(); itPP++) {
4947       fullList.push_back( *itPP );
4948     }
4949
4950     SMESH_MeshEditor_PathPoint PP1 = fullList.back();
4951     SMESH_MeshEditor_PathPoint PP2;
4952     fullList.pop_back();
4953     itLLPP++;
4954     for(; itLLPP!=LLPPs.end(); itLLPP++) {
4955       list<SMESH_MeshEditor_PathPoint> currList = *itLLPP;
4956       itPP = currList.begin();
4957       PP2 = currList.front();
4958       gp_Dir D1 = PP1.Tangent();
4959       gp_Dir D2 = PP2.Tangent();
4960       gp_Dir Dnew( gp_Vec( (D1.X()+D2.X())/2, (D1.Y()+D2.Y())/2,
4961                            (D1.Z()+D2.Z())/2 ) );
4962       PP1.SetTangent(Dnew);
4963       fullList.push_back(PP1);
4964       itPP++;
4965       for(; itPP!=currList.end(); itPP++) {
4966         fullList.push_back( *itPP );
4967       }
4968       PP1 = fullList.back();
4969       fullList.pop_back();
4970     }
4971     fullList.push_back(PP1);
4972     
4973   } // Sub shape for the Pattern must be an Edge or Wire
4974   else if( aS.ShapeType() == TopAbs_EDGE ) {
4975     aTrackEdge = TopoDS::Edge( aS );
4976     // the Edge must not be degenerated
4977     if ( BRep_Tool::Degenerated( aTrackEdge ) )
4978       return EXTR_BAD_PATH_SHAPE;
4979     TopExp::Vertices( aTrackEdge, aV1, aV2 );
4980     aItN = theTrack->GetSubMesh( aV1 )->GetSubMeshDS()->GetNodes();
4981     const SMDS_MeshNode* aN1 = aItN->next();
4982     aItN = theTrack->GetSubMesh( aV2 )->GetSubMeshDS()->GetNodes();
4983     const SMDS_MeshNode* aN2 = aItN->next();
4984     // starting node must be aN1 or aN2
4985     if ( !( aN1 == theN1 || aN2 == theN1 ) )
4986       return EXTR_BAD_STARTING_NODE;
4987     aItN = pMeshDS->nodesIterator();
4988     while ( aItN->more() ) {
4989       const SMDS_MeshNode* pNode = aItN->next();
4990       if( pNode==aN1 || pNode==aN2 ) continue;
4991       const SMDS_EdgePosition* pEPos =
4992         static_cast<const SMDS_EdgePosition*>( pNode->GetPosition() );
4993       double aT = pEPos->GetUParameter();
4994       aPrms.push_back( aT );
4995     }
4996     //Extrusion_Error err =
4997     MakeEdgePathPoints(aPrms, aTrackEdge, (aN1==theN1), fullList);
4998   }
4999   else if( aS.ShapeType() == TopAbs_WIRE ) {
5000     list< SMESH_subMesh* > LSM;
5001     TopTools_SequenceOfShape Edges;
5002     TopExp_Explorer eExp(aS, TopAbs_EDGE);
5003     for(; eExp.More(); eExp.Next()) {
5004       TopoDS_Edge E = TopoDS::Edge( eExp.Current() );
5005       if( BRep_Tool::Degenerated(E) ) continue;
5006       SMESH_subMesh* SM = theTrack->GetSubMesh(E);
5007       if(SM) {
5008         LSM.push_back(SM);
5009         Edges.Append(E);
5010       }
5011     }
5012     list< list<SMESH_MeshEditor_PathPoint> > LLPPs;
5013     int startNid = theN1->GetID();
5014     TColStd_MapOfInteger UsedNums;
5015     int NbEdges = Edges.Length();
5016     int i = 1;
5017     for(; i<=NbEdges; i++) {
5018       int k = 0;
5019       list< SMESH_subMesh* >::iterator itLSM = LSM.begin();
5020       for(; itLSM!=LSM.end(); itLSM++) {
5021         k++;
5022         if(UsedNums.Contains(k)) continue;
5023         aTrackEdge = TopoDS::Edge( Edges.Value(k) );
5024         SMESH_subMesh* locTrack = *itLSM;
5025         SMESHDS_SubMesh* locMeshDS = locTrack->GetSubMeshDS();
5026         TopExp::Vertices( aTrackEdge, aV1, aV2 );
5027         aItN = locTrack->GetFather()->GetSubMesh(aV1)->GetSubMeshDS()->GetNodes();
5028         const SMDS_MeshNode* aN1 = aItN->next();
5029         aItN = locTrack->GetFather()->GetSubMesh(aV2)->GetSubMeshDS()->GetNodes();
5030         const SMDS_MeshNode* aN2 = aItN->next();
5031         // starting node must be aN1 or aN2
5032         if ( !( aN1->GetID() == startNid || aN2->GetID() == startNid ) ) continue;
5033         // 2. Collect parameters on the track edge
5034         aPrms.clear();
5035         aItN = locMeshDS->GetNodes();
5036         while ( aItN->more() ) {
5037           const SMDS_MeshNode* pNode = aItN->next();
5038           const SMDS_EdgePosition* pEPos =
5039             static_cast<const SMDS_EdgePosition*>( pNode->GetPosition() );
5040           double aT = pEPos->GetUParameter();
5041           aPrms.push_back( aT );
5042         }
5043         list<SMESH_MeshEditor_PathPoint> LPP;
5044         //Extrusion_Error err =
5045         MakeEdgePathPoints(aPrms, aTrackEdge,(aN1->GetID()==startNid), LPP);
5046         LLPPs.push_back(LPP);
5047         UsedNums.Add(k);
5048         // update startN for search following egde
5049         if( aN1->GetID() == startNid ) startNid = aN2->GetID();
5050         else startNid = aN1->GetID();
5051         break;
5052       }
5053     }
5054     list< list<SMESH_MeshEditor_PathPoint> >::iterator itLLPP = LLPPs.begin();
5055     list<SMESH_MeshEditor_PathPoint> firstList = *itLLPP;
5056     list<SMESH_MeshEditor_PathPoint>::iterator itPP = firstList.begin();
5057     for(; itPP!=firstList.end(); itPP++) {
5058       fullList.push_back( *itPP );
5059     }
5060     SMESH_MeshEditor_PathPoint PP1 = fullList.back();
5061     fullList.pop_back();
5062     itLLPP++;
5063     for(; itLLPP!=LLPPs.end(); itLLPP++) {
5064       list<SMESH_MeshEditor_PathPoint> currList = *itLLPP;
5065       itPP = currList.begin();
5066       SMESH_MeshEditor_PathPoint PP2 = currList.front();
5067       gp_Dir D1 = PP1.Tangent();
5068       gp_Dir D2 = PP2.Tangent();
5069       gp_Dir Dnew( gp_Vec( (D1.X()+D2.X())/2, (D1.Y()+D2.Y())/2,
5070                            (D1.Z()+D2.Z())/2 ) );
5071       PP1.SetTangent(Dnew);
5072       fullList.push_back(PP1);
5073       itPP++;
5074       for(; itPP!=currList.end(); itPP++) {
5075         fullList.push_back( *itPP );
5076       }
5077       PP1 = fullList.back();
5078       fullList.pop_back();
5079     }
5080     // if wire not closed
5081     fullList.push_back(PP1);
5082     // else ???
5083   }
5084   else {
5085     return EXTR_BAD_PATH_SHAPE;
5086   }
5087
5088   return MakeExtrElements(theElements, fullList, theHasAngles, theAngles, theLinearVariation,
5089                           theHasRefPoint, theRefPoint, theMakeGroups);
5090 }
5091
5092
5093 //=======================================================================
5094 //function : MakeEdgePathPoints
5095 //purpose  : auxilary for ExtrusionAlongTrack
5096 //=======================================================================
5097 SMESH_MeshEditor::Extrusion_Error
5098 SMESH_MeshEditor::MakeEdgePathPoints(std::list<double>& aPrms,
5099                                      const TopoDS_Edge& aTrackEdge,
5100                                      bool FirstIsStart,
5101                                      list<SMESH_MeshEditor_PathPoint>& LPP)
5102 {
5103   Standard_Real aTx1, aTx2, aL2, aTolVec, aTolVec2;
5104   aTolVec=1.e-7;
5105   aTolVec2=aTolVec*aTolVec;
5106   double aT1, aT2;
5107   TopoDS_Vertex aV1, aV2;
5108   TopExp::Vertices( aTrackEdge, aV1, aV2 );
5109   aT1=BRep_Tool::Parameter( aV1, aTrackEdge );
5110   aT2=BRep_Tool::Parameter( aV2, aTrackEdge );
5111   // 2. Collect parameters on the track edge
5112   aPrms.push_front( aT1 );
5113   aPrms.push_back( aT2 );
5114   // sort parameters
5115   aPrms.sort();
5116   if( FirstIsStart ) {
5117     if ( aT1 > aT2 ) {
5118       aPrms.reverse();
5119     }
5120   }
5121   else {
5122     if ( aT2 > aT1 ) {
5123       aPrms.reverse();
5124     }
5125   }
5126   // 3. Path Points
5127   SMESH_MeshEditor_PathPoint aPP;
5128   Handle(Geom_Curve) aC3D = BRep_Tool::Curve( aTrackEdge, aTx1, aTx2 );
5129   std::list<double>::iterator aItD = aPrms.begin();
5130   for(; aItD != aPrms.end(); ++aItD) {
5131     double aT = *aItD;
5132     gp_Pnt aP3D;
5133     gp_Vec aVec;
5134     aC3D->D1( aT, aP3D, aVec );
5135     aL2 = aVec.SquareMagnitude();
5136     if ( aL2 < aTolVec2 )
5137       return EXTR_CANT_GET_TANGENT;
5138     gp_Dir aTgt( aVec );
5139     aPP.SetPnt( aP3D );
5140     aPP.SetTangent( aTgt );
5141     aPP.SetParameter( aT );
5142     LPP.push_back(aPP);
5143   }
5144   return EXTR_OK;
5145 }
5146
5147
5148 //=======================================================================
5149 //function : MakeExtrElements
5150 //purpose  : auxilary for ExtrusionAlongTrack
5151 //=======================================================================
5152 SMESH_MeshEditor::Extrusion_Error
5153 SMESH_MeshEditor::MakeExtrElements(TIDSortedElemSet&  theElements,
5154                                    list<SMESH_MeshEditor_PathPoint>& fullList,
5155                                    const bool theHasAngles,
5156                                    list<double>& theAngles,
5157                                    const bool theLinearVariation,
5158                                    const bool theHasRefPoint,
5159                                    const gp_Pnt& theRefPoint,
5160                                    const bool theMakeGroups)
5161 {
5162   MESSAGE("MakeExtrElements");
5163   //cout<<"MakeExtrElements  fullList.size() = "<<fullList.size()<<endl;
5164   int aNbTP = fullList.size();
5165   vector<SMESH_MeshEditor_PathPoint> aPPs(aNbTP);
5166   // Angles
5167   if( theHasAngles && theAngles.size()>0 && theLinearVariation ) {
5168     LinearAngleVariation(aNbTP-1, theAngles);
5169   }
5170   vector<double> aAngles( aNbTP );
5171   int j = 0;
5172   for(; j<aNbTP; ++j) {
5173     aAngles[j] = 0.;
5174   }
5175   if ( theHasAngles ) {
5176     double anAngle;;
5177     std::list<double>::iterator aItD = theAngles.begin();
5178     for ( j=1; (aItD != theAngles.end()) && (j<aNbTP); ++aItD, ++j ) {
5179       anAngle = *aItD;
5180       aAngles[j] = anAngle;
5181     }
5182   }
5183   // fill vector of path points with angles
5184   //aPPs.resize(fullList.size());
5185   j = -1;
5186   list<SMESH_MeshEditor_PathPoint>::iterator itPP = fullList.begin();
5187   for(; itPP!=fullList.end(); itPP++) {
5188     j++;
5189     SMESH_MeshEditor_PathPoint PP = *itPP;
5190     PP.SetAngle(aAngles[j]);
5191     aPPs[j] = PP;
5192   }
5193
5194   TNodeOfNodeListMap mapNewNodes;
5195   TElemOfVecOfNnlmiMap mapElemNewNodes;
5196   TElemOfElemListMap newElemsMap;
5197   TIDSortedElemSet::iterator itElem;
5198   double aX, aY, aZ;
5199   int aNb;
5200   SMDSAbs_ElementType aTypeE;
5201   // source elements for each generated one
5202   SMESH_SequenceOfElemPtr srcElems, srcNodes;
5203
5204   // 3. Center of rotation aV0
5205   gp_Pnt aV0 = theRefPoint;
5206   gp_XYZ aGC;
5207   if ( !theHasRefPoint ) {
5208     aNb = 0;
5209     aGC.SetCoord( 0.,0.,0. );
5210
5211     itElem = theElements.begin();
5212     for ( ; itElem != theElements.end(); itElem++ ) {
5213       const SMDS_MeshElement* elem = *itElem;
5214
5215       SMDS_ElemIteratorPtr itN = elem->nodesIterator();
5216       while ( itN->more() ) {
5217         const SMDS_MeshNode* node = static_cast<const SMDS_MeshNode*>( itN->next() );
5218         aX = node->X();
5219         aY = node->Y();
5220         aZ = node->Z();
5221
5222         if ( mapNewNodes.find( node ) == mapNewNodes.end() ) {
5223           list<const SMDS_MeshNode*> aLNx;
5224           mapNewNodes[node] = aLNx;
5225           //
5226           gp_XYZ aXYZ( aX, aY, aZ );
5227           aGC += aXYZ;
5228           ++aNb;
5229         }
5230       }
5231     }
5232     aGC /= aNb;
5233     aV0.SetXYZ( aGC );
5234   } // if (!theHasRefPoint) {
5235   mapNewNodes.clear();
5236
5237   // 4. Processing the elements
5238   SMESHDS_Mesh* aMesh = GetMeshDS();
5239
5240   for ( itElem = theElements.begin(); itElem != theElements.end(); itElem++ ) {
5241     // check element type
5242     const SMDS_MeshElement* elem = *itElem;
5243     aTypeE = elem->GetType();
5244     if ( !elem || ( aTypeE != SMDSAbs_Face && aTypeE != SMDSAbs_Edge ) )
5245       continue;
5246
5247     vector<TNodeOfNodeListMapItr> & newNodesItVec = mapElemNewNodes[ elem ];
5248     newNodesItVec.reserve( elem->NbNodes() );
5249
5250     // loop on elem nodes
5251     int nodeIndex = -1;
5252     SMDS_ElemIteratorPtr itN = elem->nodesIterator();
5253     while ( itN->more() )
5254     {
5255       ++nodeIndex;
5256       // check if a node has been already processed
5257       const SMDS_MeshNode* node =
5258         static_cast<const SMDS_MeshNode*>( itN->next() );
5259       TNodeOfNodeListMap::iterator nIt = mapNewNodes.find( node );
5260       if ( nIt == mapNewNodes.end() ) {
5261         nIt = mapNewNodes.insert( make_pair( node, list<const SMDS_MeshNode*>() )).first;
5262         list<const SMDS_MeshNode*>& listNewNodes = nIt->second;
5263
5264         // make new nodes
5265         aX = node->X();  aY = node->Y(); aZ = node->Z();
5266
5267         Standard_Real aAngle1x, aAngleT1T0, aTolAng;
5268         gp_Pnt aP0x, aP1x, aPN0, aPN1, aV0x, aV1x;
5269         gp_Ax1 anAx1, anAxT1T0;
5270         gp_Dir aDT1x, aDT0x, aDT1T0;
5271
5272         aTolAng=1.e-4;
5273
5274         aV0x = aV0;
5275         aPN0.SetCoord(aX, aY, aZ);
5276
5277         const SMESH_MeshEditor_PathPoint& aPP0 = aPPs[0];
5278         aP0x = aPP0.Pnt();
5279         aDT0x= aPP0.Tangent();
5280         //cout<<"j = 0   PP: Pnt("<<aP0x.X()<<","<<aP0x.Y()<<","<<aP0x.Z()<<")"<<endl;
5281
5282         for ( j = 1; j < aNbTP; ++j ) {
5283           const SMESH_MeshEditor_PathPoint& aPP1 = aPPs[j];
5284           aP1x = aPP1.Pnt();
5285           aDT1x = aPP1.Tangent();
5286           aAngle1x = aPP1.Angle();
5287
5288           gp_Trsf aTrsf, aTrsfRot, aTrsfRotT1T0;
5289           // Translation
5290           gp_Vec aV01x( aP0x, aP1x );
5291           aTrsf.SetTranslation( aV01x );
5292
5293           // traslated point
5294           aV1x = aV0x.Transformed( aTrsf );
5295           aPN1 = aPN0.Transformed( aTrsf );
5296
5297           // rotation 1 [ T1,T0 ]
5298           aAngleT1T0=-aDT1x.Angle( aDT0x );
5299           if (fabs(aAngleT1T0) > aTolAng) {
5300             aDT1T0=aDT1x^aDT0x;
5301             anAxT1T0.SetLocation( aV1x );
5302             anAxT1T0.SetDirection( aDT1T0 );
5303             aTrsfRotT1T0.SetRotation( anAxT1T0, aAngleT1T0 );
5304
5305             aPN1 = aPN1.Transformed( aTrsfRotT1T0 );
5306           }
5307
5308           // rotation 2
5309           if ( theHasAngles ) {
5310             anAx1.SetLocation( aV1x );
5311             anAx1.SetDirection( aDT1x );
5312             aTrsfRot.SetRotation( anAx1, aAngle1x );
5313
5314             aPN1 = aPN1.Transformed( aTrsfRot );
5315           }
5316
5317           // make new node
5318           //MESSAGE("elem->IsQuadratic " << elem->IsQuadratic() << " " << elem->IsMediumNode(node));
5319           if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
5320             // create additional node
5321             double x = ( aPN1.X() + aPN0.X() )/2.;
5322             double y = ( aPN1.Y() + aPN0.Y() )/2.;
5323             double z = ( aPN1.Z() + aPN0.Z() )/2.;
5324             const SMDS_MeshNode* newNode = aMesh->AddNode(x,y,z);
5325             myLastCreatedNodes.Append(newNode);
5326             srcNodes.Append( node );
5327             listNewNodes.push_back( newNode );
5328           }
5329           aX = aPN1.X();
5330           aY = aPN1.Y();
5331           aZ = aPN1.Z();
5332           const SMDS_MeshNode* newNode = aMesh->AddNode( aX, aY, aZ );
5333           myLastCreatedNodes.Append(newNode);
5334           srcNodes.Append( node );
5335           listNewNodes.push_back( newNode );
5336
5337           aPN0 = aPN1;
5338           aP0x = aP1x;
5339           aV0x = aV1x;
5340           aDT0x = aDT1x;
5341         }
5342       }
5343
5344       else {
5345         // if current elem is quadratic and current node is not medium
5346         // we have to check - may be it is needed to insert additional nodes
5347         if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
5348           list< const SMDS_MeshNode* > & listNewNodes = nIt->second;
5349           if(listNewNodes.size()==aNbTP-1) {
5350             vector<const SMDS_MeshNode*> aNodes(2*(aNbTP-1));
5351             gp_XYZ P(node->X(), node->Y(), node->Z());
5352             list< const SMDS_MeshNode* >::iterator it = listNewNodes.begin();
5353             int i;
5354             for(i=0; i<aNbTP-1; i++) {
5355               const SMDS_MeshNode* N = *it;
5356               double x = ( N->X() + P.X() )/2.;
5357               double y = ( N->Y() + P.Y() )/2.;
5358               double z = ( N->Z() + P.Z() )/2.;
5359               const SMDS_MeshNode* newN = aMesh->AddNode(x,y,z);
5360               srcNodes.Append( node );
5361               myLastCreatedNodes.Append(newN);
5362               aNodes[2*i] = newN;
5363               aNodes[2*i+1] = N;
5364               P = gp_XYZ(N->X(),N->Y(),N->Z());
5365             }
5366             listNewNodes.clear();
5367             for(i=0; i<2*(aNbTP-1); i++) {
5368               listNewNodes.push_back(aNodes[i]);
5369             }
5370           }
5371         }
5372       }
5373
5374       newNodesItVec.push_back( nIt );
5375     }
5376     // make new elements
5377     //sweepElement( aMesh, elem, newNodesItVec, newElemsMap[elem],
5378     //              newNodesItVec[0]->second.size(), myLastCreatedElems );
5379     sweepElement( elem, newNodesItVec, newElemsMap[elem], aNbTP-1, srcElems );
5380   }
5381
5382   makeWalls( mapNewNodes, newElemsMap, mapElemNewNodes, theElements, aNbTP-1, srcElems );
5383
5384   if ( theMakeGroups )
5385     generateGroups( srcNodes, srcElems, "extruded");
5386
5387   return EXTR_OK;
5388 }
5389
5390
5391 //=======================================================================
5392 //function : LinearAngleVariation
5393 //purpose  : auxilary for ExtrusionAlongTrack
5394 //=======================================================================
5395 void SMESH_MeshEditor::LinearAngleVariation(const int nbSteps,
5396                                             list<double>& Angles)
5397 {
5398   int nbAngles = Angles.size();
5399   if( nbSteps > nbAngles ) {
5400     vector<double> theAngles(nbAngles);
5401     list<double>::iterator it = Angles.begin();
5402     int i = -1;
5403     for(; it!=Angles.end(); it++) {
5404       i++;
5405       theAngles[i] = (*it);
5406     }
5407     list<double> res;
5408     double rAn2St = double( nbAngles ) / double( nbSteps );
5409     double angPrev = 0, angle;
5410     for ( int iSt = 0; iSt < nbSteps; ++iSt ) {
5411       double angCur = rAn2St * ( iSt+1 );
5412       double angCurFloor  = floor( angCur );
5413       double angPrevFloor = floor( angPrev );
5414       if ( angPrevFloor == angCurFloor )
5415         angle = rAn2St * theAngles[ int( angCurFloor ) ];
5416       else {
5417         int iP = int( angPrevFloor );
5418         double angPrevCeil = ceil(angPrev);
5419         angle = ( angPrevCeil - angPrev ) * theAngles[ iP ];
5420
5421         int iC = int( angCurFloor );
5422         if ( iC < nbAngles )
5423           angle += ( angCur - angCurFloor ) * theAngles[ iC ];
5424
5425         iP = int( angPrevCeil );
5426         while ( iC-- > iP )
5427           angle += theAngles[ iC ];
5428       }
5429       res.push_back(angle);
5430       angPrev = angCur;
5431     }
5432     Angles.clear();
5433     it = res.begin();
5434     for(; it!=res.end(); it++)
5435       Angles.push_back( *it );
5436   }
5437 }
5438
5439
5440 //================================================================================
5441 /*!
5442  * \brief Move or copy theElements applying theTrsf to their nodes
5443  *  \param theElems - elements to transform, if theElems is empty then apply to all mesh nodes
5444  *  \param theTrsf - transformation to apply
5445  *  \param theCopy - if true, create translated copies of theElems
5446  *  \param theMakeGroups - if true and theCopy, create translated groups
5447  *  \param theTargetMesh - mesh to copy translated elements into
5448  *  \return SMESH_MeshEditor::PGroupIDs - list of ids of created groups
5449  */
5450 //================================================================================
5451
5452 SMESH_MeshEditor::PGroupIDs
5453 SMESH_MeshEditor::Transform (TIDSortedElemSet & theElems,
5454                              const gp_Trsf&     theTrsf,
5455                              const bool         theCopy,
5456                              const bool         theMakeGroups,
5457                              SMESH_Mesh*        theTargetMesh)
5458 {
5459   myLastCreatedElems.Clear();
5460   myLastCreatedNodes.Clear();
5461
5462   bool needReverse = false;
5463   string groupPostfix;
5464   switch ( theTrsf.Form() ) {
5465   case gp_PntMirror:
5466     MESSAGE("gp_PntMirror");
5467     needReverse = true;
5468     groupPostfix = "mirrored";
5469     break;
5470   case gp_Ax1Mirror:
5471     MESSAGE("gp_Ax1Mirror");
5472     groupPostfix = "mirrored";
5473     break;
5474   case gp_Ax2Mirror:
5475     MESSAGE("gp_Ax2Mirror");
5476     needReverse = true;
5477     groupPostfix = "mirrored";
5478     break;
5479   case gp_Rotation:
5480     MESSAGE("gp_Rotation");
5481     groupPostfix = "rotated";
5482     break;
5483   case gp_Translation:
5484     MESSAGE("gp_Translation");
5485     groupPostfix = "translated";
5486     break;
5487   case gp_Scale:
5488     MESSAGE("gp_Scale");
5489     groupPostfix = "scaled";
5490     break;
5491   case gp_CompoundTrsf: // different scale by axis
5492     MESSAGE("gp_CompoundTrsf");
5493     groupPostfix = "scaled";
5494     break;
5495   default:
5496     MESSAGE("default");
5497     needReverse = false;
5498     groupPostfix = "transformed";
5499   }
5500
5501   SMESH_MeshEditor targetMeshEditor( theTargetMesh );
5502   SMESHDS_Mesh* aTgtMesh = theTargetMesh ? theTargetMesh->GetMeshDS() : 0;
5503   SMESHDS_Mesh* aMesh    = GetMeshDS();
5504
5505
5506   // map old node to new one
5507   TNodeNodeMap nodeMap;
5508
5509   // elements sharing moved nodes; those of them which have all
5510   // nodes mirrored but are not in theElems are to be reversed
5511   TIDSortedElemSet inverseElemSet;
5512
5513   // source elements for each generated one
5514   SMESH_SequenceOfElemPtr srcElems, srcNodes;
5515
5516   // issue 021015: EDF 1578 SMESH: Free nodes are removed when translating a mesh
5517   TIDSortedElemSet orphanNode;
5518
5519   if ( theElems.empty() ) // transform the whole mesh
5520   {
5521     // add all elements
5522     SMDS_ElemIteratorPtr eIt = aMesh->elementsIterator();
5523     while ( eIt->more() ) theElems.insert( eIt->next() );
5524     // add orphan nodes
5525     SMDS_NodeIteratorPtr nIt = aMesh->nodesIterator();
5526     while ( nIt->more() )
5527     {
5528       const SMDS_MeshNode* node = nIt->next();
5529       if ( node->NbInverseElements() == 0)
5530         orphanNode.insert( node );
5531     }
5532   }
5533
5534   // loop on elements to transform nodes : first orphan nodes then elems
5535   TIDSortedElemSet::iterator itElem;
5536   TIDSortedElemSet *elements[] = {&orphanNode, &theElems };
5537   for (int i=0; i<2; i++)
5538   for ( itElem = elements[i]->begin(); itElem != elements[i]->end(); itElem++ ) {
5539     const SMDS_MeshElement* elem = *itElem;
5540     if ( !elem )
5541       continue;
5542
5543     // loop on elem nodes
5544     SMDS_ElemIteratorPtr itN = elem->nodesIterator();
5545     while ( itN->more() ) {
5546
5547       const SMDS_MeshNode* node = cast2Node( itN->next() );
5548       // check if a node has been already transformed
5549       pair<TNodeNodeMap::iterator,bool> n2n_isnew =
5550         nodeMap.insert( make_pair ( node, node ));
5551       if ( !n2n_isnew.second )
5552         continue;
5553
5554       double coord[3];
5555       coord[0] = node->X();
5556       coord[1] = node->Y();
5557       coord[2] = node->Z();
5558       theTrsf.Transforms( coord[0], coord[1], coord[2] );
5559       if ( theTargetMesh ) {
5560         const SMDS_MeshNode * newNode = aTgtMesh->AddNode( coord[0], coord[1], coord[2] );
5561         n2n_isnew.first->second = newNode;
5562         myLastCreatedNodes.Append(newNode);
5563         srcNodes.Append( node );
5564       }
5565       else if ( theCopy ) {
5566         const SMDS_MeshNode * newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
5567         n2n_isnew.first->second = newNode;
5568         myLastCreatedNodes.Append(newNode);
5569         srcNodes.Append( node );
5570       }
5571       else {
5572         aMesh->MoveNode( node, coord[0], coord[1], coord[2] );
5573         // node position on shape becomes invalid
5574         const_cast< SMDS_MeshNode* > ( node )->SetPosition
5575           ( SMDS_SpacePosition::originSpacePosition() );
5576       }
5577
5578       // keep inverse elements
5579       if ( !theCopy && !theTargetMesh && needReverse ) {
5580         SMDS_ElemIteratorPtr invElemIt = node->GetInverseElementIterator();
5581         while ( invElemIt->more() ) {
5582           const SMDS_MeshElement* iel = invElemIt->next();
5583           inverseElemSet.insert( iel );
5584         }
5585       }
5586     }
5587   }
5588
5589   // either create new elements or reverse mirrored ones
5590   if ( !theCopy && !needReverse && !theTargetMesh )
5591     return PGroupIDs();
5592
5593   TIDSortedElemSet::iterator invElemIt = inverseElemSet.begin();
5594   for ( ; invElemIt != inverseElemSet.end(); invElemIt++ )
5595     theElems.insert( *invElemIt );
5596
5597   // Replicate or reverse elements
5598
5599   std::vector<int> iForw;
5600   for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ )
5601   {
5602     const SMDS_MeshElement* elem = *itElem;
5603     if ( !elem || elem->GetType() == SMDSAbs_Node )
5604       continue;
5605
5606     int nbNodes = elem->NbNodes();
5607     int elemType = elem->GetType();
5608
5609     if (elem->IsPoly()) {
5610
5611       // polygon or polyhedral volume
5612       switch ( elemType ) {
5613       case SMDSAbs_Face:
5614         {
5615           vector<const SMDS_MeshNode*> poly_nodes (nbNodes);
5616           int iNode = 0;
5617           SMDS_ElemIteratorPtr itN = elem->nodesIterator();
5618           while (itN->more()) {
5619             const SMDS_MeshNode* node =
5620               static_cast<const SMDS_MeshNode*>(itN->next());
5621             TNodeNodeMap::iterator nodeMapIt = nodeMap.find(node);
5622             if (nodeMapIt == nodeMap.end())
5623               break; // not all nodes transformed
5624             if (needReverse) {
5625               // reverse mirrored faces and volumes
5626               poly_nodes[nbNodes - iNode - 1] = (*nodeMapIt).second;
5627             } else {
5628               poly_nodes[iNode] = (*nodeMapIt).second;
5629             }
5630             iNode++;
5631           }
5632           if ( iNode != nbNodes )
5633             continue; // not all nodes transformed
5634
5635           if ( theTargetMesh ) {
5636             myLastCreatedElems.Append(aTgtMesh->AddPolygonalFace(poly_nodes));
5637             srcElems.Append( elem );
5638           }
5639           else if ( theCopy ) {
5640             myLastCreatedElems.Append(aMesh->AddPolygonalFace(poly_nodes));
5641             srcElems.Append( elem );
5642           }
5643           else {
5644             aMesh->ChangePolygonNodes(elem, poly_nodes);
5645           }
5646         }
5647         break;
5648       case SMDSAbs_Volume:
5649         {
5650           const SMDS_VtkVolume* aPolyedre =
5651             dynamic_cast<const SMDS_VtkVolume*>( elem );
5652           if (!aPolyedre) {
5653             MESSAGE("Warning: bad volumic element");
5654             continue;
5655           }
5656
5657           vector<const SMDS_MeshNode*> poly_nodes; poly_nodes.reserve( nbNodes );
5658           vector<int> quantities;
5659
5660           bool allTransformed = true;
5661           int nbFaces = aPolyedre->NbFaces();
5662           for (int iface = 1; iface <= nbFaces && allTransformed; iface++) {
5663             int nbFaceNodes = aPolyedre->NbFaceNodes(iface);
5664             for (int inode = 1; inode <= nbFaceNodes && allTransformed; inode++) {
5665               const SMDS_MeshNode* node = aPolyedre->GetFaceNode(iface, inode);
5666               TNodeNodeMap::iterator nodeMapIt = nodeMap.find(node);
5667               if (nodeMapIt == nodeMap.end()) {
5668                 allTransformed = false; // not all nodes transformed
5669               } else {
5670                 poly_nodes.push_back((*nodeMapIt).second);
5671               }
5672               if ( needReverse && allTransformed )
5673                 std::reverse( poly_nodes.end() - nbFaceNodes, poly_nodes.end() );
5674             }
5675             quantities.push_back(nbFaceNodes);
5676           }
5677           if ( !allTransformed )
5678             continue; // not all nodes transformed
5679
5680           if ( theTargetMesh ) {
5681             myLastCreatedElems.Append(aTgtMesh->AddPolyhedralVolume(poly_nodes, quantities));
5682             srcElems.Append( elem );
5683           }
5684           else if ( theCopy ) {
5685             myLastCreatedElems.Append(aMesh->AddPolyhedralVolume(poly_nodes, quantities));
5686             srcElems.Append( elem );
5687           }
5688           else {
5689             aMesh->ChangePolyhedronNodes(elem, poly_nodes, quantities);
5690           }
5691         }
5692         break;
5693       default:;
5694       }
5695       continue;
5696
5697     } // elem->isPoly()
5698
5699     // Regular elements
5700
5701     while ( iForw.size() < nbNodes ) iForw.push_back( iForw.size() );
5702     const std::vector<int>& iRev = SMDS_MeshCell::reverseSmdsOrder( elem->GetEntityType() );
5703     const std::vector<int>& i = needReverse ? iRev : iForw;
5704
5705     // find transformed nodes
5706     vector<const SMDS_MeshNode*> nodes(nbNodes);
5707     int iNode = 0;
5708     SMDS_ElemIteratorPtr itN = elem->nodesIterator();
5709     while ( itN->more() ) {
5710       const SMDS_MeshNode* node =
5711         static_cast<const SMDS_MeshNode*>( itN->next() );
5712       TNodeNodeMap::iterator nodeMapIt = nodeMap.find( node );
5713       if ( nodeMapIt == nodeMap.end() )
5714         break; // not all nodes transformed
5715       nodes[ i [ iNode++ ]] = (*nodeMapIt).second;
5716     }
5717     if ( iNode != nbNodes )
5718       continue; // not all nodes transformed
5719
5720     if ( theTargetMesh ) {
5721       if ( SMDS_MeshElement* copy =
5722            targetMeshEditor.AddElement( nodes, elem->GetType(), elem->IsPoly() )) {
5723         myLastCreatedElems.Append( copy );
5724         srcElems.Append( elem );
5725       }
5726     }
5727     else if ( theCopy ) {
5728       if ( AddElement( nodes, elem->GetType(), elem->IsPoly() ))
5729         srcElems.Append( elem );
5730     }
5731     else {
5732       // reverse element as it was reversed by transformation
5733       if ( nbNodes > 2 )
5734         aMesh->ChangeElementNodes( elem, &nodes[0], nbNodes );
5735     }
5736
5737   } // loop on elements
5738
5739   PGroupIDs newGroupIDs;
5740
5741   if ( ( theMakeGroups && theCopy ) ||
5742        ( theMakeGroups && theTargetMesh ) )
5743     newGroupIDs = generateGroups( srcNodes, srcElems, groupPostfix, theTargetMesh );
5744
5745   return newGroupIDs;
5746 }
5747
5748 //=======================================================================
5749 /*!
5750  * \brief Create groups of elements made during transformation
5751  * \param nodeGens - nodes making corresponding myLastCreatedNodes
5752  * \param elemGens - elements making corresponding myLastCreatedElems
5753  * \param postfix - to append to names of new groups
5754  */
5755 //=======================================================================
5756
5757 SMESH_MeshEditor::PGroupIDs
5758 SMESH_MeshEditor::generateGroups(const SMESH_SequenceOfElemPtr& nodeGens,
5759                                  const SMESH_SequenceOfElemPtr& elemGens,
5760                                  const std::string&             postfix,
5761                                  SMESH_Mesh*                    targetMesh)
5762 {
5763   PGroupIDs newGroupIDs( new list<int> );
5764   SMESH_Mesh* mesh = targetMesh ? targetMesh : GetMesh();
5765
5766   // Sort existing groups by types and collect their names
5767
5768   // to store an old group and a generated new one
5769   typedef pair< SMESHDS_GroupBase*, SMDS_MeshGroup* > TOldNewGroup;
5770   vector< list< TOldNewGroup > > groupsByType( SMDSAbs_NbElementTypes );
5771   // group names
5772   set< string > groupNames;
5773   //
5774   SMDS_MeshGroup* nullNewGroup = (SMDS_MeshGroup*) 0;
5775   SMESH_Mesh::GroupIteratorPtr groupIt = GetMesh()->GetGroups();
5776   while ( groupIt->more() ) {
5777     SMESH_Group * group = groupIt->next();
5778     if ( !group ) continue;
5779     SMESHDS_GroupBase* groupDS = group->GetGroupDS();
5780     if ( !groupDS || groupDS->IsEmpty() ) continue;
5781     groupNames.insert( group->GetName() );
5782     groupDS->SetStoreName( group->GetName() );
5783     groupsByType[ groupDS->GetType() ].push_back( make_pair( groupDS, nullNewGroup ));
5784   }
5785
5786   // Groups creation
5787
5788   // loop on nodes and elements
5789   for ( int isNodes = 0; isNodes < 2; ++isNodes )
5790   {
5791     const SMESH_SequenceOfElemPtr& gens  = isNodes ? nodeGens : elemGens;
5792     const SMESH_SequenceOfElemPtr& elems = isNodes ? myLastCreatedNodes : myLastCreatedElems;
5793     if ( gens.Length() != elems.Length() )
5794       throw SALOME_Exception(LOCALIZED("invalid args"));
5795
5796     // loop on created elements
5797     for (int iElem = 1; iElem <= elems.Length(); ++iElem )
5798     {
5799       const SMDS_MeshElement* sourceElem = gens( iElem );
5800       if ( !sourceElem ) {
5801         MESSAGE("generateGroups(): NULL source element");
5802         continue;
5803       }
5804       list< TOldNewGroup > & groupsOldNew = groupsByType[ sourceElem->GetType() ];
5805       if ( groupsOldNew.empty() ) {
5806         while ( iElem < gens.Length() && gens( iElem+1 ) == sourceElem )
5807           ++iElem; // skip all elements made by sourceElem
5808         continue;
5809       }
5810       // collect all elements made by sourceElem
5811       list< const SMDS_MeshElement* > resultElems;
5812       if ( const SMDS_MeshElement* resElem = elems( iElem ))
5813         if ( resElem != sourceElem )
5814           resultElems.push_back( resElem );
5815       while ( iElem < gens.Length() && gens( iElem+1 ) == sourceElem )
5816         if ( const SMDS_MeshElement* resElem = elems( ++iElem ))
5817           if ( resElem != sourceElem )
5818             resultElems.push_back( resElem );
5819       // do not generate element groups from node ones
5820       if ( sourceElem->GetType() == SMDSAbs_Node &&
5821            elems( iElem )->GetType() != SMDSAbs_Node )
5822         continue;
5823
5824       // add resultElems to groups made by ones the sourceElem belongs to
5825       list< TOldNewGroup >::iterator gOldNew, gLast = groupsOldNew.end();
5826       for ( gOldNew = groupsOldNew.begin(); gOldNew != gLast; ++gOldNew )
5827       {
5828         SMESHDS_GroupBase* oldGroup = gOldNew->first;
5829         if ( oldGroup->Contains( sourceElem )) // sourceElem in oldGroup
5830         {
5831           SMDS_MeshGroup* & newGroup = gOldNew->second;
5832           if ( !newGroup )// create a new group
5833           {
5834             // make a name
5835             string name = oldGroup->GetStoreName();
5836             if ( !targetMesh ) {
5837               name += "_";
5838               name += postfix;
5839               int nb = 0;
5840               while ( !groupNames.insert( name ).second ) // name exists
5841               {
5842                 if ( nb == 0 ) {
5843                   name += "_1";
5844                 }
5845                 else {
5846                   TCollection_AsciiString nbStr(nb+1);
5847                   name.resize( name.rfind('_')+1 );
5848                   name += nbStr.ToCString();
5849                 }
5850                 ++nb;
5851               }
5852             }
5853             // make a group
5854             int id;
5855             SMESH_Group* group = mesh->AddGroup( resultElems.back()->GetType(),
5856                                                  name.c_str(), id );
5857             SMESHDS_Group* groupDS = static_cast<SMESHDS_Group*>(group->GetGroupDS());
5858             newGroup = & groupDS->SMDSGroup();
5859             newGroupIDs->push_back( id );
5860           }
5861
5862           // fill in a new group
5863           list< const SMDS_MeshElement* >::iterator resLast = resultElems.end(), resElemIt;
5864           for ( resElemIt = resultElems.begin(); resElemIt != resLast; ++resElemIt )
5865             newGroup->Add( *resElemIt );
5866         }
5867       }
5868     } // loop on created elements
5869   }// loop on nodes and elements
5870
5871   return newGroupIDs;
5872 }
5873
5874 //================================================================================
5875 /*!
5876  * \brief Return list of group of nodes close to each other within theTolerance
5877  *        Search among theNodes or in the whole mesh if theNodes is empty using
5878  *        an Octree algorithm
5879  */
5880 //================================================================================
5881
5882 void SMESH_MeshEditor::FindCoincidentNodes (TIDSortedNodeSet &   theNodes,
5883                                             const double         theTolerance,
5884                                             TListOfListOfNodes & theGroupsOfNodes)
5885 {
5886   myLastCreatedElems.Clear();
5887   myLastCreatedNodes.Clear();
5888
5889   if ( theNodes.empty() )
5890   { // get all nodes in the mesh
5891     SMDS_NodeIteratorPtr nIt = GetMeshDS()->nodesIterator(/*idInceasingOrder=*/true);
5892     while ( nIt->more() )
5893       theNodes.insert( theNodes.end(),nIt->next());
5894   }
5895
5896   SMESH_OctreeNode::FindCoincidentNodes ( theNodes, &theGroupsOfNodes, theTolerance);
5897 }
5898
5899
5900 //=======================================================================
5901 /*!
5902  * \brief Implementation of search for the node closest to point
5903  */
5904 //=======================================================================
5905
5906 struct SMESH_NodeSearcherImpl: public SMESH_NodeSearcher
5907 {
5908   //---------------------------------------------------------------------
5909   /*!
5910    * \brief Constructor
5911    */
5912   SMESH_NodeSearcherImpl( const SMESHDS_Mesh* theMesh )
5913   {
5914     myMesh = ( SMESHDS_Mesh* ) theMesh;
5915
5916     TIDSortedNodeSet nodes;
5917     if ( theMesh ) {
5918       SMDS_NodeIteratorPtr nIt = theMesh->nodesIterator(/*idInceasingOrder=*/true);
5919       while ( nIt->more() )
5920         nodes.insert( nodes.end(), nIt->next() );
5921     }
5922     myOctreeNode = new SMESH_OctreeNode(nodes) ;
5923
5924     // get max size of a leaf box
5925     SMESH_OctreeNode* tree = myOctreeNode;
5926     while ( !tree->isLeaf() )
5927     {
5928       SMESH_OctreeNodeIteratorPtr cIt = tree->GetChildrenIterator();
5929       if ( cIt->more() )
5930         tree = cIt->next();
5931     }
5932     myHalfLeafSize = tree->maxSize() / 2.;
5933   }
5934
5935   //---------------------------------------------------------------------
5936   /*!
5937    * \brief Move node and update myOctreeNode accordingly
5938    */
5939   void MoveNode( const SMDS_MeshNode* node, const gp_Pnt& toPnt )
5940   {
5941     myOctreeNode->UpdateByMoveNode( node, toPnt );
5942     myMesh->MoveNode( node, toPnt.X(), toPnt.Y(), toPnt.Z() );
5943   }
5944
5945   //---------------------------------------------------------------------
5946   /*!
5947    * \brief Do it's job
5948    */
5949   const SMDS_MeshNode* FindClosestTo( const gp_Pnt& thePnt )
5950   {
5951     map<double, const SMDS_MeshNode*> dist2Nodes;
5952     myOctreeNode->NodesAround( thePnt.Coord(), dist2Nodes, myHalfLeafSize );
5953     if ( !dist2Nodes.empty() )
5954       return dist2Nodes.begin()->second;
5955     list<const SMDS_MeshNode*> nodes;
5956     //myOctreeNode->NodesAround( &tgtNode, &nodes, myHalfLeafSize );
5957
5958     double minSqDist = DBL_MAX;
5959     if ( nodes.empty() )  // get all nodes of OctreeNode's closest to thePnt
5960     {
5961       // sort leafs by their distance from thePnt
5962       typedef map< double, SMESH_OctreeNode* > TDistTreeMap;
5963       TDistTreeMap treeMap;
5964       list< SMESH_OctreeNode* > treeList;
5965       list< SMESH_OctreeNode* >::iterator trIt;
5966       treeList.push_back( myOctreeNode );
5967
5968       gp_XYZ pointNode( thePnt.X(), thePnt.Y(), thePnt.Z() );
5969       bool pointInside = myOctreeNode->isInside( pointNode, myHalfLeafSize );
5970       for ( trIt = treeList.begin(); trIt != treeList.end(); ++trIt)
5971       {
5972         SMESH_OctreeNode* tree = *trIt;
5973         if ( !tree->isLeaf() ) // put children to the queue
5974         {
5975           if ( pointInside && !tree->isInside( pointNode, myHalfLeafSize )) continue;
5976           SMESH_OctreeNodeIteratorPtr cIt = tree->GetChildrenIterator();
5977           while ( cIt->more() )
5978             treeList.push_back( cIt->next() );
5979         }
5980         else if ( tree->NbNodes() ) // put a tree to the treeMap
5981         {
5982           const Bnd_B3d& box = tree->getBox();
5983           double sqDist = thePnt.SquareDistance( 0.5 * ( box.CornerMin() + box.CornerMax() ));
5984           pair<TDistTreeMap::iterator,bool> it_in = treeMap.insert( make_pair( sqDist, tree ));
5985           if ( !it_in.second ) // not unique distance to box center
5986             treeMap.insert( it_in.first, make_pair( sqDist + 1e-13*treeMap.size(), tree ));
5987         }
5988       }
5989       // find distance after which there is no sense to check tree's
5990       double sqLimit = DBL_MAX;
5991       TDistTreeMap::iterator sqDist_tree = treeMap.begin();
5992       if ( treeMap.size() > 5 ) {
5993         SMESH_OctreeNode* closestTree = sqDist_tree->second;
5994         const Bnd_B3d& box = closestTree->getBox();
5995         double limit = sqrt( sqDist_tree->first ) + sqrt ( box.SquareExtent() );
5996         sqLimit = limit * limit;
5997       }
5998       // get all nodes from trees
5999       for ( ; sqDist_tree != treeMap.end(); ++sqDist_tree) {
6000         if ( sqDist_tree->first > sqLimit )
6001           break;
6002         SMESH_OctreeNode* tree = sqDist_tree->second;
6003         tree->NodesAround( tree->GetNodeIterator()->next(), &nodes );
6004       }
6005     }
6006     // find closest among nodes
6007     minSqDist = DBL_MAX;
6008     const SMDS_MeshNode* closestNode = 0;
6009     list<const SMDS_MeshNode*>::iterator nIt = nodes.begin();
6010     for ( ; nIt != nodes.end(); ++nIt ) {
6011       double sqDist = thePnt.SquareDistance( SMESH_TNodeXYZ( *nIt ) );
6012       if ( minSqDist > sqDist ) {
6013         closestNode = *nIt;
6014         minSqDist = sqDist;
6015       }
6016     }
6017     return closestNode;
6018   }
6019
6020   //---------------------------------------------------------------------
6021   /*!
6022    * \brief Destructor
6023    */
6024   ~SMESH_NodeSearcherImpl() { delete myOctreeNode; }
6025
6026   //---------------------------------------------------------------------
6027   /*!
6028    * \brief Return the node tree
6029    */
6030   const SMESH_OctreeNode* getTree() const { return myOctreeNode; }
6031
6032 private:
6033   SMESH_OctreeNode* myOctreeNode;
6034   SMESHDS_Mesh*     myMesh;
6035   double            myHalfLeafSize; // max size of a leaf box
6036 };
6037
6038 //=======================================================================
6039 /*!
6040  * \brief Return SMESH_NodeSearcher
6041  */
6042 //=======================================================================
6043
6044 SMESH_NodeSearcher* SMESH_MeshEditor::GetNodeSearcher() 
6045 {
6046   return new SMESH_NodeSearcherImpl( GetMeshDS() );
6047 }
6048
6049 // ========================================================================
6050 namespace // Utils used in SMESH_ElementSearcherImpl::FindElementsByPoint()
6051 {
6052   const int MaxNbElemsInLeaf = 10; // maximal number of elements in a leaf of tree
6053   const int MaxLevel         = 7;  // maximal tree height -> nb terminal boxes: 8^7 = 2097152
6054   const double NodeRadius = 1e-9;  // to enlarge bnd box of element
6055
6056   //=======================================================================
6057   /*!
6058    * \brief Octal tree of bounding boxes of elements
6059    */
6060   //=======================================================================
6061
6062   class ElementBndBoxTree : public SMESH_Octree
6063   {
6064   public:
6065
6066     ElementBndBoxTree(const SMDS_Mesh& mesh, SMDSAbs_ElementType elemType, SMDS_ElemIteratorPtr theElemIt = SMDS_ElemIteratorPtr(), double tolerance = NodeRadius );
6067     void getElementsNearPoint( const gp_Pnt& point, TIDSortedElemSet& foundElems);
6068     void getElementsNearLine ( const gp_Ax1& line, TIDSortedElemSet& foundElems);
6069     ~ElementBndBoxTree();
6070
6071   protected:
6072     ElementBndBoxTree() {}
6073     SMESH_Octree* allocateOctreeChild() const { return new ElementBndBoxTree; }
6074     void buildChildrenData();
6075     Bnd_B3d* buildRootBox();
6076   private:
6077     //!< Bounding box of element
6078     struct ElementBox : public Bnd_B3d
6079     {
6080       const SMDS_MeshElement* _element;
6081       int                     _refCount; // an ElementBox can be included in several tree branches
6082       ElementBox(const SMDS_MeshElement* elem, double tolerance);
6083     };
6084     vector< ElementBox* > _elements;
6085   };
6086
6087   //================================================================================
6088   /*!
6089    * \brief ElementBndBoxTree creation
6090    */
6091   //================================================================================
6092
6093   ElementBndBoxTree::ElementBndBoxTree(const SMDS_Mesh& mesh, SMDSAbs_ElementType elemType, SMDS_ElemIteratorPtr theElemIt, double tolerance)
6094     :SMESH_Octree( new SMESH_Octree::Limit( MaxLevel, /*minSize=*/0. ))
6095   {
6096     int nbElems = mesh.GetMeshInfo().NbElements( elemType );
6097     _elements.reserve( nbElems );
6098
6099     SMDS_ElemIteratorPtr elemIt = theElemIt ? theElemIt : mesh.elementsIterator( elemType );
6100     while ( elemIt->more() )
6101       _elements.push_back( new ElementBox( elemIt->next(),tolerance  ));
6102
6103     if ( _elements.size() > MaxNbElemsInLeaf )
6104       compute();
6105     else
6106       myIsLeaf = true;
6107   }
6108
6109   //================================================================================
6110   /*!
6111    * \brief Destructor
6112    */
6113   //================================================================================
6114
6115   ElementBndBoxTree::~ElementBndBoxTree()
6116   {
6117     for ( int i = 0; i < _elements.size(); ++i )
6118       if ( --_elements[i]->_refCount <= 0 )
6119         delete _elements[i];
6120   }
6121
6122   //================================================================================
6123   /*!
6124    * \brief Return the maximal box
6125    */
6126   //================================================================================
6127
6128   Bnd_B3d* ElementBndBoxTree::buildRootBox()
6129   {
6130     Bnd_B3d* box = new Bnd_B3d;
6131     for ( int i = 0; i < _elements.size(); ++i )
6132       box->Add( *_elements[i] );
6133     return box;
6134   }
6135
6136   //================================================================================
6137   /*!
6138    * \brief Redistrubute element boxes among children
6139    */
6140   //================================================================================
6141
6142   void ElementBndBoxTree::buildChildrenData()
6143   {
6144     for ( int i = 0; i < _elements.size(); ++i )
6145     {
6146       for (int j = 0; j < 8; j++)
6147       {
6148         if ( !_elements[i]->IsOut( myChildren[j]->getBox() ))
6149         {
6150           _elements[i]->_refCount++;
6151           ((ElementBndBoxTree*)myChildren[j])->_elements.push_back( _elements[i]);
6152         }
6153       }
6154       _elements[i]->_refCount--;
6155     }
6156     _elements.clear();
6157
6158     for (int j = 0; j < 8; j++)
6159     {
6160       ElementBndBoxTree* child = static_cast<ElementBndBoxTree*>( myChildren[j]);
6161       if ( child->_elements.size() <= MaxNbElemsInLeaf )
6162         child->myIsLeaf = true;
6163
6164       if ( child->_elements.capacity() - child->_elements.size() > 1000 )
6165         child->_elements.resize( child->_elements.size() ); // compact
6166     }
6167   }
6168
6169   //================================================================================
6170   /*!
6171    * \brief Return elements which can include the point
6172    */
6173   //================================================================================
6174
6175   void ElementBndBoxTree::getElementsNearPoint( const gp_Pnt&     point,
6176                                                 TIDSortedElemSet& foundElems)
6177   {
6178     if ( level() && getBox().IsOut( point.XYZ() ))
6179       return;
6180
6181     if ( isLeaf() )
6182     {
6183       for ( int i = 0; i < _elements.size(); ++i )
6184         if ( !_elements[i]->IsOut( point.XYZ() ))
6185           foundElems.insert( _elements[i]->_element );
6186     }
6187     else
6188     {
6189       for (int i = 0; i < 8; i++)
6190         ((ElementBndBoxTree*) myChildren[i])->getElementsNearPoint( point, foundElems );
6191     }
6192   }
6193
6194   //================================================================================
6195   /*!
6196    * \brief Return elements which can be intersected by the line
6197    */
6198   //================================================================================
6199
6200   void ElementBndBoxTree::getElementsNearLine( const gp_Ax1&     line,
6201                                                TIDSortedElemSet& foundElems)
6202   {
6203     if ( level() && getBox().IsOut( line ))
6204       return;
6205
6206     if ( isLeaf() )
6207     {
6208       for ( int i = 0; i < _elements.size(); ++i )
6209         if ( !_elements[i]->IsOut( line ))
6210           foundElems.insert( _elements[i]->_element );
6211     }
6212     else
6213     {
6214       for (int i = 0; i < 8; i++)
6215         ((ElementBndBoxTree*) myChildren[i])->getElementsNearLine( line, foundElems );
6216     }
6217   }
6218
6219   //================================================================================
6220   /*!
6221    * \brief Construct the element box
6222    */
6223   //================================================================================
6224
6225   ElementBndBoxTree::ElementBox::ElementBox(const SMDS_MeshElement* elem, double tolerance)
6226   {
6227     _element  = elem;
6228     _refCount = 1;
6229     SMDS_ElemIteratorPtr nIt = elem->nodesIterator();
6230     while ( nIt->more() )
6231       Add( SMESH_TNodeXYZ( cast2Node( nIt->next() )));
6232     Enlarge( tolerance );
6233   }
6234
6235 } // namespace
6236
6237 //=======================================================================
6238 /*!
6239  * \brief Implementation of search for the elements by point and
6240  *        of classification of point in 2D mesh
6241  */
6242 //=======================================================================
6243
6244 struct SMESH_ElementSearcherImpl: public SMESH_ElementSearcher
6245 {
6246   SMESHDS_Mesh*                _mesh;
6247   SMDS_ElemIteratorPtr         _meshPartIt;
6248   ElementBndBoxTree*           _ebbTree;
6249   SMESH_NodeSearcherImpl*      _nodeSearcher;
6250   SMDSAbs_ElementType          _elementType;
6251   double                       _tolerance;
6252   bool                         _outerFacesFound;
6253   set<const SMDS_MeshElement*> _outerFaces; // empty means "no internal faces at all"
6254
6255   SMESH_ElementSearcherImpl( SMESHDS_Mesh& mesh, SMDS_ElemIteratorPtr elemIt=SMDS_ElemIteratorPtr())
6256     : _mesh(&mesh),_meshPartIt(elemIt),_ebbTree(0),_nodeSearcher(0),_tolerance(-1),_outerFacesFound(false) {}
6257   ~SMESH_ElementSearcherImpl()
6258   {
6259     if ( _ebbTree )      delete _ebbTree;      _ebbTree      = 0;
6260     if ( _nodeSearcher ) delete _nodeSearcher; _nodeSearcher = 0;
6261   }
6262   virtual int FindElementsByPoint(const gp_Pnt&                      point,
6263                                   SMDSAbs_ElementType                type,
6264                                   vector< const SMDS_MeshElement* >& foundElements);
6265   virtual TopAbs_State GetPointState(const gp_Pnt& point);
6266
6267   void GetElementsNearLine( const gp_Ax1&                      line,
6268                             SMDSAbs_ElementType                type,
6269                             vector< const SMDS_MeshElement* >& foundElems);
6270   double getTolerance();
6271   bool getIntersParamOnLine(const gp_Lin& line, const SMDS_MeshElement* face,
6272                             const double tolerance, double & param);
6273   void findOuterBoundary(const SMDS_MeshElement* anyOuterFace);
6274   bool isOuterBoundary(const SMDS_MeshElement* face) const
6275   {
6276     return _outerFaces.empty() || _outerFaces.count(face);
6277   }
6278   struct TInters //!< data of intersection of the line and the mesh face (used in GetPointState())
6279   {
6280     const SMDS_MeshElement* _face;
6281     gp_Vec                  _faceNorm;
6282     bool                    _coincides; //!< the line lays in face plane
6283     TInters(const SMDS_MeshElement* face, const gp_Vec& faceNorm, bool coinc=false)
6284       : _face(face), _faceNorm( faceNorm ), _coincides( coinc ) {}
6285   };
6286   struct TFaceLink //!< link and faces sharing it (used in findOuterBoundary())
6287   {
6288     SMESH_TLink      _link;
6289     TIDSortedElemSet _faces;
6290     TFaceLink( const SMDS_MeshNode* n1, const SMDS_MeshNode* n2, const SMDS_MeshElement* face)
6291       : _link( n1, n2 ), _faces( &face, &face + 1) {}
6292   };
6293 };
6294
6295 ostream& operator<< (ostream& out, const SMESH_ElementSearcherImpl::TInters& i)
6296 {
6297   return out << "TInters(face=" << ( i._face ? i._face->GetID() : 0)
6298              << ", _coincides="<<i._coincides << ")";
6299 }
6300
6301 //=======================================================================
6302 /*!
6303  * \brief define tolerance for search
6304  */
6305 //=======================================================================
6306
6307 double SMESH_ElementSearcherImpl::getTolerance()
6308 {
6309   if ( _tolerance < 0 )
6310   {
6311     const SMDS_MeshInfo& meshInfo = _mesh->GetMeshInfo();
6312
6313     _tolerance = 0;
6314     if ( _nodeSearcher && meshInfo.NbNodes() > 1 )
6315     {
6316       double boxSize = _nodeSearcher->getTree()->maxSize();
6317       _tolerance = 1e-8 * boxSize/* / meshInfo.NbNodes()*/;
6318     }
6319     else if ( _ebbTree && meshInfo.NbElements() > 0 )
6320     {
6321       double boxSize = _ebbTree->maxSize();
6322       _tolerance = 1e-8 * boxSize/* / meshInfo.NbElements()*/;
6323     }
6324     if ( _tolerance == 0 )
6325     {
6326       // define tolerance by size of a most complex element
6327       int complexType = SMDSAbs_Volume;
6328       while ( complexType > SMDSAbs_All &&
6329               meshInfo.NbElements( SMDSAbs_ElementType( complexType )) < 1 )
6330         --complexType;
6331       if ( complexType == SMDSAbs_All ) return 0; // empty mesh
6332       double elemSize;
6333       if ( complexType == int( SMDSAbs_Node ))
6334       {
6335         SMDS_NodeIteratorPtr nodeIt = _mesh->nodesIterator();
6336         elemSize = 1;
6337         if ( meshInfo.NbNodes() > 2 )
6338           elemSize = SMESH_TNodeXYZ( nodeIt->next() ).Distance( nodeIt->next() );
6339       }
6340       else
6341       {
6342         SMDS_ElemIteratorPtr elemIt =
6343             _mesh->elementsIterator( SMDSAbs_ElementType( complexType ));
6344         const SMDS_MeshElement* elem = elemIt->next();
6345         SMDS_ElemIteratorPtr nodeIt = elem->nodesIterator();
6346         SMESH_TNodeXYZ n1( cast2Node( nodeIt->next() ));
6347         elemSize = 0;
6348         while ( nodeIt->more() )
6349         {
6350           double dist = n1.Distance( cast2Node( nodeIt->next() ));
6351           elemSize = max( dist, elemSize );
6352         }
6353       }
6354       _tolerance = 1e-4 * elemSize;
6355     }
6356   }
6357   return _tolerance;
6358 }
6359
6360 //================================================================================
6361 /*!
6362  * \brief Find intersection of the line and an edge of face and return parameter on line
6363  */
6364 //================================================================================
6365
6366 bool SMESH_ElementSearcherImpl::getIntersParamOnLine(const gp_Lin&           line,
6367                                                      const SMDS_MeshElement* face,
6368                                                      const double            tol,
6369                                                      double &                param)
6370 {
6371   int nbInts = 0;
6372   param = 0;
6373
6374   GeomAPI_ExtremaCurveCurve anExtCC;
6375   Handle(Geom_Curve) lineCurve = new Geom_Line( line );
6376   
6377   int nbNodes = face->IsQuadratic() ? face->NbNodes()/2 : face->NbNodes();
6378   for ( int i = 0; i < nbNodes && nbInts < 2; ++i )
6379   {
6380     GC_MakeSegment edge( SMESH_TNodeXYZ( face->GetNode( i )),
6381                          SMESH_TNodeXYZ( face->GetNode( (i+1)%nbNodes) )); 
6382     anExtCC.Init( lineCurve, edge);
6383     if ( anExtCC.NbExtrema() > 0 && anExtCC.LowerDistance() <= tol)
6384     {
6385       Quantity_Parameter pl, pe;
6386       anExtCC.LowerDistanceParameters( pl, pe );
6387       param += pl;
6388       if ( ++nbInts == 2 )
6389         break;
6390     }
6391   }
6392   if ( nbInts > 0 ) param /= nbInts;
6393   return nbInts > 0;
6394 }
6395 //================================================================================
6396 /*!
6397  * \brief Find all faces belonging to the outer boundary of mesh
6398  */
6399 //================================================================================
6400
6401 void SMESH_ElementSearcherImpl::findOuterBoundary(const SMDS_MeshElement* outerFace)
6402 {
6403   if ( _outerFacesFound ) return;
6404
6405   // Collect all outer faces by passing from one outer face to another via their links
6406   // and BTW find out if there are internal faces at all.
6407
6408   // checked links and links where outer boundary meets internal one
6409   set< SMESH_TLink > visitedLinks, seamLinks;
6410
6411   // links to treat with already visited faces sharing them
6412   list < TFaceLink > startLinks;
6413
6414   // load startLinks with the first outerFace
6415   startLinks.push_back( TFaceLink( outerFace->GetNode(0), outerFace->GetNode(1), outerFace));
6416   _outerFaces.insert( outerFace );
6417
6418   TIDSortedElemSet emptySet;
6419   while ( !startLinks.empty() )
6420   {
6421     const SMESH_TLink& link  = startLinks.front()._link;
6422     TIDSortedElemSet&  faces = startLinks.front()._faces;
6423
6424     outerFace = *faces.begin();
6425     // find other faces sharing the link
6426     const SMDS_MeshElement* f;
6427     while (( f = SMESH_MeshEditor::FindFaceInSet(link.node1(), link.node2(), emptySet, faces )))
6428       faces.insert( f );
6429
6430     // select another outer face among the found 
6431     const SMDS_MeshElement* outerFace2 = 0;
6432     if ( faces.size() == 2 )
6433     {
6434       outerFace2 = (outerFace == *faces.begin() ? *faces.rbegin() : *faces.begin());
6435     }
6436     else if ( faces.size() > 2 )
6437     {
6438       seamLinks.insert( link );
6439
6440       // link direction within the outerFace
6441       gp_Vec n1n2( SMESH_TNodeXYZ( link.node1()),
6442                    SMESH_TNodeXYZ( link.node2()));
6443       int i1 = outerFace->GetNodeIndex( link.node1() );
6444       int i2 = outerFace->GetNodeIndex( link.node2() );
6445       bool rev = ( abs(i2-i1) == 1 ? i1 > i2 : i2 > i1 );
6446       if ( rev ) n1n2.Reverse();
6447       // outerFace normal
6448       gp_XYZ ofNorm, fNorm;
6449       if ( SMESH_Algo::FaceNormal( outerFace, ofNorm, /*normalized=*/false ))
6450       {
6451         // direction from the link inside outerFace
6452         gp_Vec dirInOF = gp_Vec( ofNorm ) ^ n1n2;
6453         // sort all other faces by angle with the dirInOF
6454         map< double, const SMDS_MeshElement* > angle2Face;
6455         set< const SMDS_MeshElement*, TIDCompare >::const_iterator face = faces.begin();
6456         for ( ; face != faces.end(); ++face )
6457         {
6458           if ( !SMESH_Algo::FaceNormal( *face, fNorm, /*normalized=*/false ))
6459             continue;
6460           gp_Vec dirInF = gp_Vec( fNorm ) ^ n1n2;
6461           double angle = dirInOF.AngleWithRef( dirInF, n1n2 );
6462           if ( angle < 0 ) angle += 2. * M_PI;
6463           angle2Face.insert( make_pair( angle, *face ));
6464         }
6465         if ( !angle2Face.empty() )
6466           outerFace2 = angle2Face.begin()->second;
6467       }
6468     }
6469     // store the found outer face and add its links to continue seaching from
6470     if ( outerFace2 )
6471     {
6472       _outerFaces.insert( outerFace );
6473       int nbNodes = outerFace2->NbNodes()/( outerFace2->IsQuadratic() ? 2 : 1 );
6474       for ( int i = 0; i < nbNodes; ++i )
6475       {
6476         SMESH_TLink link2( outerFace2->GetNode(i), outerFace2->GetNode((i+1)%nbNodes));
6477         if ( visitedLinks.insert( link2 ).second )
6478           startLinks.push_back( TFaceLink( link2.node1(), link2.node2(), outerFace2 ));
6479       }
6480     }
6481     startLinks.pop_front();
6482   }
6483   _outerFacesFound = true;
6484
6485   if ( !seamLinks.empty() )
6486   {
6487     // There are internal boundaries touching the outher one,
6488     // find all faces of internal boundaries in order to find
6489     // faces of boundaries of holes, if any.
6490     
6491   }
6492   else
6493   {
6494     _outerFaces.clear();
6495   }
6496 }
6497
6498 //=======================================================================
6499 /*!
6500  * \brief Find elements of given type where the given point is IN or ON.
6501  *        Returns nb of found elements and elements them-selves.
6502  *
6503  * 'ALL' type means elements of any type excluding nodes and 0D elements
6504  */
6505 //=======================================================================
6506
6507 int SMESH_ElementSearcherImpl::
6508 FindElementsByPoint(const gp_Pnt&                      point,
6509                     SMDSAbs_ElementType                type,
6510                     vector< const SMDS_MeshElement* >& foundElements)
6511 {
6512   foundElements.clear();
6513
6514   double tolerance = getTolerance();
6515
6516   // =================================================================================
6517   if ( type == SMDSAbs_Node || type == SMDSAbs_0DElement )
6518   {
6519     if ( !_nodeSearcher )
6520       _nodeSearcher = new SMESH_NodeSearcherImpl( _mesh );
6521
6522     const SMDS_MeshNode* closeNode = _nodeSearcher->FindClosestTo( point );
6523     if ( !closeNode ) return foundElements.size();
6524
6525     if ( point.Distance( SMESH_TNodeXYZ( closeNode )) > tolerance )
6526       return foundElements.size(); // to far from any node
6527
6528     if ( type == SMDSAbs_Node )
6529     {
6530       foundElements.push_back( closeNode );
6531     }
6532     else
6533     {
6534       SMDS_ElemIteratorPtr elemIt = closeNode->GetInverseElementIterator( SMDSAbs_0DElement );
6535       while ( elemIt->more() )
6536         foundElements.push_back( elemIt->next() );
6537     }
6538   }
6539   // =================================================================================
6540   else // elements more complex than 0D
6541   {
6542     if ( !_ebbTree || _elementType != type )
6543     {
6544       if ( _ebbTree ) delete _ebbTree;
6545       _ebbTree = new ElementBndBoxTree( *_mesh, _elementType = type, _meshPartIt, tolerance );
6546     }
6547     TIDSortedElemSet suspectElems;
6548     _ebbTree->getElementsNearPoint( point, suspectElems );
6549     TIDSortedElemSet::iterator elem = suspectElems.begin();
6550     for ( ; elem != suspectElems.end(); ++elem )
6551       if ( !SMESH_MeshEditor::isOut( *elem, point, tolerance ))
6552         foundElements.push_back( *elem );
6553   }
6554   return foundElements.size();
6555 }
6556
6557 //================================================================================
6558 /*!
6559  * \brief Classify the given point in the closed 2D mesh
6560  */
6561 //================================================================================
6562
6563 TopAbs_State SMESH_ElementSearcherImpl::GetPointState(const gp_Pnt& point)
6564 {
6565   double tolerance = getTolerance();
6566   if ( !_ebbTree || _elementType != SMDSAbs_Face )
6567   {
6568     if ( _ebbTree ) delete _ebbTree;
6569     _ebbTree = new ElementBndBoxTree( *_mesh, _elementType = SMDSAbs_Face, _meshPartIt );
6570   }
6571   // Algo: analyse transition of a line starting at the point through mesh boundary;
6572   // try three lines parallel to axis of the coordinate system and perform rough
6573   // analysis. If solution is not clear perform thorough analysis.
6574
6575   const int nbAxes = 3;
6576   gp_Dir axisDir[ nbAxes ] = { gp::DX(), gp::DY(), gp::DZ() };
6577   map< double, TInters >   paramOnLine2TInters[ nbAxes ];
6578   list< TInters > tangentInters[ nbAxes ]; // of faces whose plane includes the line
6579   multimap< int, int > nbInt2Axis; // to find the simplest case
6580   for ( int axis = 0; axis < nbAxes; ++axis )
6581   {
6582     gp_Ax1 lineAxis( point, axisDir[axis]);
6583     gp_Lin line    ( lineAxis );
6584
6585     TIDSortedElemSet suspectFaces; // faces possibly intersecting the line
6586     _ebbTree->getElementsNearLine( lineAxis, suspectFaces );
6587
6588     // Intersect faces with the line
6589
6590     map< double, TInters > & u2inters = paramOnLine2TInters[ axis ];
6591     TIDSortedElemSet::iterator face = suspectFaces.begin();
6592     for ( ; face != suspectFaces.end(); ++face )
6593     {
6594       // get face plane
6595       gp_XYZ fNorm;
6596       if ( !SMESH_Algo::FaceNormal( *face, fNorm, /*normalized=*/false)) continue;
6597       gp_Pln facePlane( SMESH_TNodeXYZ( (*face)->GetNode(0)), fNorm );
6598
6599       // perform intersection
6600       IntAna_IntConicQuad intersection( line, IntAna_Quadric( facePlane ));
6601       if ( !intersection.IsDone() )
6602         continue;
6603       if ( intersection.IsInQuadric() )
6604       {
6605         tangentInters[ axis ].push_back( TInters( *face, fNorm, true ));
6606       }
6607       else if ( ! intersection.IsParallel() && intersection.NbPoints() > 0 )
6608       {
6609         gp_Pnt intersectionPoint = intersection.Point(1);
6610         if ( !SMESH_MeshEditor::isOut( *face, intersectionPoint, tolerance ))
6611           u2inters.insert(make_pair( intersection.ParamOnConic(1), TInters( *face, fNorm )));
6612       }
6613     }
6614     // Analyse intersections roughly
6615
6616     int nbInter = u2inters.size();
6617     if ( nbInter == 0 )
6618       return TopAbs_OUT; 
6619
6620     double f = u2inters.begin()->first, l = u2inters.rbegin()->first;
6621     if ( nbInter == 1 ) // not closed mesh
6622       return fabs( f ) < tolerance ? TopAbs_ON : TopAbs_UNKNOWN;
6623
6624     if ( fabs( f ) < tolerance || fabs( l ) < tolerance )
6625       return TopAbs_ON;
6626
6627     if ( (f<0) == (l<0) )
6628       return TopAbs_OUT;
6629
6630     int nbIntBeforePoint = std::distance( u2inters.begin(), u2inters.lower_bound(0));
6631     int nbIntAfterPoint  = nbInter - nbIntBeforePoint;
6632     if ( nbIntBeforePoint == 1 || nbIntAfterPoint == 1 )
6633       return TopAbs_IN;
6634
6635     nbInt2Axis.insert( make_pair( min( nbIntBeforePoint, nbIntAfterPoint ), axis ));
6636
6637     if ( _outerFacesFound ) break; // pass to thorough analysis
6638
6639   } // three attempts - loop on CS axes
6640
6641   // Analyse intersections thoroughly.
6642   // We make two loops maximum, on the first one we only exclude touching intersections,
6643   // on the second, if situation is still unclear, we gather and use information on
6644   // position of faces (internal or outer). If faces position is already gathered,
6645   // we make the second loop right away.
6646
6647   for ( int hasPositionInfo = _outerFacesFound; hasPositionInfo < 2; ++hasPositionInfo )
6648   {
6649     multimap< int, int >::const_iterator nb_axis = nbInt2Axis.begin();
6650     for ( ; nb_axis != nbInt2Axis.end(); ++nb_axis )
6651     {
6652       int axis = nb_axis->second;
6653       map< double, TInters > & u2inters = paramOnLine2TInters[ axis ];
6654
6655       gp_Ax1 lineAxis( point, axisDir[axis]);
6656       gp_Lin line    ( lineAxis );
6657
6658       // add tangent intersections to u2inters
6659       double param;
6660       list< TInters >::const_iterator tgtInt = tangentInters[ axis ].begin();
6661       for ( ; tgtInt != tangentInters[ axis ].end(); ++tgtInt )
6662         if ( getIntersParamOnLine( line, tgtInt->_face, tolerance, param ))
6663           u2inters.insert(make_pair( param, *tgtInt ));
6664       tangentInters[ axis ].clear();
6665
6666       // Count intersections before and after the point excluding touching ones.
6667       // If hasPositionInfo we count intersections of outer boundary only
6668
6669       int nbIntBeforePoint = 0, nbIntAfterPoint = 0;
6670       double f = numeric_limits<double>::max(), l = -numeric_limits<double>::max();
6671       map< double, TInters >::iterator u_int1 = u2inters.begin(), u_int2 = u_int1;
6672       bool ok = ! u_int1->second._coincides;
6673       while ( ok && u_int1 != u2inters.end() )
6674       {
6675         double u = u_int1->first;
6676         bool touchingInt = false;
6677         if ( ++u_int2 != u2inters.end() )
6678         {
6679           // skip intersections at the same point (if the line passes through edge or node)
6680           int nbSamePnt = 0;
6681           while ( u_int2 != u2inters.end() && fabs( u_int2->first - u ) < tolerance )
6682           {
6683             ++nbSamePnt;
6684             ++u_int2;
6685           }
6686
6687           // skip tangent intersections
6688           int nbTgt = 0;
6689           const SMDS_MeshElement* prevFace = u_int1->second._face;
6690           while ( ok && u_int2->second._coincides )
6691           {
6692             if ( SMESH_Algo::GetCommonNodes(prevFace , u_int2->second._face).empty() )
6693               ok = false;
6694             else
6695             {
6696               nbTgt++;
6697               u_int2++;
6698               ok = ( u_int2 != u2inters.end() );
6699             }
6700           }
6701           if ( !ok ) break;
6702
6703           // skip intersections at the same point after tangent intersections
6704           if ( nbTgt > 0 )
6705           {
6706             double u2 = u_int2->first;
6707             ++u_int2;
6708             while ( u_int2 != u2inters.end() && fabs( u_int2->first - u2 ) < tolerance )
6709             {
6710               ++nbSamePnt;
6711               ++u_int2;
6712             }
6713           }
6714           // decide if we skipped a touching intersection
6715           if ( nbSamePnt + nbTgt > 0 )
6716           {
6717             double minDot = numeric_limits<double>::max(), maxDot = -numeric_limits<double>::max();
6718             map< double, TInters >::iterator u_int = u_int1;
6719             for ( ; u_int != u_int2; ++u_int )
6720             {
6721               if ( u_int->second._coincides ) continue;
6722               double dot = u_int->second._faceNorm * line.Direction();
6723               if ( dot > maxDot ) maxDot = dot;
6724               if ( dot < minDot ) minDot = dot;
6725             }
6726             touchingInt = ( minDot*maxDot < 0 );
6727           }
6728         }
6729         if ( !touchingInt )
6730         {
6731           if ( !hasPositionInfo || isOuterBoundary( u_int1->second._face ))
6732           {
6733             if ( u < 0 )
6734               ++nbIntBeforePoint;
6735             else
6736               ++nbIntAfterPoint;
6737           }
6738           if ( u < f ) f = u;
6739           if ( u > l ) l = u;
6740         }
6741
6742         u_int1 = u_int2; // to next intersection
6743
6744       } // loop on intersections with one line
6745
6746       if ( ok )
6747       {
6748         if ( fabs( f ) < tolerance || fabs( l ) < tolerance )
6749           return TopAbs_ON;
6750
6751         if ( nbIntBeforePoint == 0  || nbIntAfterPoint == 0)
6752           return TopAbs_OUT; 
6753
6754         if ( nbIntBeforePoint + nbIntAfterPoint == 1 ) // not closed mesh
6755           return fabs( f ) < tolerance ? TopAbs_ON : TopAbs_UNKNOWN;
6756
6757         if ( nbIntBeforePoint == 1 || nbIntAfterPoint == 1 )
6758           return TopAbs_IN;
6759
6760         if ( (f<0) == (l<0) )
6761           return TopAbs_OUT;
6762
6763         if ( hasPositionInfo )
6764           return nbIntBeforePoint % 2 ? TopAbs_IN : TopAbs_OUT;
6765       }
6766     } // loop on intersections of the tree lines - thorough analysis
6767
6768     if ( !hasPositionInfo )
6769     {
6770       // gather info on faces position - is face in the outer boundary or not
6771       map< double, TInters > & u2inters = paramOnLine2TInters[ 0 ];
6772       findOuterBoundary( u2inters.begin()->second._face );
6773     }
6774
6775   } // two attempts - with and w/o faces position info in the mesh
6776
6777   return TopAbs_UNKNOWN;
6778 }
6779
6780 //=======================================================================
6781 /*!
6782  * \brief Return elements possibly intersecting the line
6783  */
6784 //=======================================================================
6785
6786 void SMESH_ElementSearcherImpl::GetElementsNearLine( const gp_Ax1&                      line,
6787                                                      SMDSAbs_ElementType                type,
6788                                                      vector< const SMDS_MeshElement* >& foundElems)
6789 {
6790   if ( !_ebbTree || _elementType != type )
6791   {
6792     if ( _ebbTree ) delete _ebbTree;
6793     _ebbTree = new ElementBndBoxTree( *_mesh, _elementType = type, _meshPartIt );
6794   }
6795   TIDSortedElemSet suspectFaces; // elements possibly intersecting the line
6796   _ebbTree->getElementsNearLine( line, suspectFaces );
6797   foundElems.assign( suspectFaces.begin(), suspectFaces.end());
6798 }
6799
6800 //=======================================================================
6801 /*!
6802  * \brief Return SMESH_ElementSearcher
6803  */
6804 //=======================================================================
6805
6806 SMESH_ElementSearcher* SMESH_MeshEditor::GetElementSearcher()
6807 {
6808   return new SMESH_ElementSearcherImpl( *GetMeshDS() );
6809 }
6810
6811 //=======================================================================
6812 /*!
6813  * \brief Return SMESH_ElementSearcher acting on a sub-set of elements
6814  */
6815 //=======================================================================
6816
6817 SMESH_ElementSearcher* SMESH_MeshEditor::GetElementSearcher(SMDS_ElemIteratorPtr elemIt)
6818 {
6819   return new SMESH_ElementSearcherImpl( *GetMeshDS(), elemIt );
6820 }
6821
6822 //=======================================================================
6823 /*!
6824  * \brief Return true if the point is IN or ON of the element
6825  */
6826 //=======================================================================
6827
6828 bool SMESH_MeshEditor::isOut( const SMDS_MeshElement* element, const gp_Pnt& point, double tol )
6829 {
6830   if ( element->GetType() == SMDSAbs_Volume)
6831   {
6832     return SMDS_VolumeTool( element ).IsOut( point.X(), point.Y(), point.Z(), tol );
6833   }
6834
6835   // get ordered nodes
6836
6837   vector< gp_XYZ > xyz;
6838   vector<const SMDS_MeshNode*> nodeList;
6839
6840   SMDS_ElemIteratorPtr nodeIt = element->nodesIterator();
6841   if ( element->IsQuadratic() ) {
6842     if (const SMDS_VtkFace* f=dynamic_cast<const SMDS_VtkFace*>(element))
6843       nodeIt = f->interlacedNodesElemIterator();
6844     else if (const SMDS_VtkEdge*  e =dynamic_cast<const SMDS_VtkEdge*>(element))
6845       nodeIt = e->interlacedNodesElemIterator();
6846   }
6847   while ( nodeIt->more() )
6848     {
6849       const SMDS_MeshNode* node = cast2Node( nodeIt->next() );
6850       xyz.push_back( SMESH_TNodeXYZ(node) );
6851       nodeList.push_back(node);
6852     }
6853
6854   int i, nbNodes = element->NbNodes();
6855
6856   if ( element->GetType() == SMDSAbs_Face ) // --------------------------------------------------
6857   {
6858     // compute face normal
6859     gp_Vec faceNorm(0,0,0);
6860     xyz.push_back( xyz.front() );
6861     nodeList.push_back( nodeList.front() );
6862     for ( i = 0; i < nbNodes; ++i )
6863     {
6864       gp_Vec edge1( xyz[i+1], xyz[i]);
6865       gp_Vec edge2( xyz[i+1], xyz[(i+2)%nbNodes] );
6866       faceNorm += edge1 ^ edge2;
6867     }
6868     double normSize = faceNorm.Magnitude();
6869     if ( normSize <= tol )
6870     {
6871       // degenerated face: point is out if it is out of all face edges
6872       for ( i = 0; i < nbNodes; ++i )
6873       {
6874         SMDS_LinearEdge edge( nodeList[i], nodeList[i+1] );
6875         if ( !isOut( &edge, point, tol ))
6876           return false;
6877       }
6878       return true;
6879     }
6880     faceNorm /= normSize;
6881
6882     // check if the point lays on face plane
6883     gp_Vec n2p( xyz[0], point );
6884     if ( fabs( n2p * faceNorm ) > tol )
6885       return true; // not on face plane
6886
6887     // check if point is out of face boundary:
6888     // define it by closest transition of a ray point->infinity through face boundary
6889     // on the face plane.
6890     // First, find normal of a plane perpendicular to face plane, to be used as a cutting tool
6891     // to find intersections of the ray with the boundary.
6892     gp_Vec ray = n2p;
6893     gp_Vec plnNorm = ray ^ faceNorm;
6894     normSize = plnNorm.Magnitude();
6895     if ( normSize <= tol ) return false; // point coincides with the first node
6896     plnNorm /= normSize;
6897     // for each node of the face, compute its signed distance to the plane
6898     vector<double> dist( nbNodes + 1);
6899     for ( i = 0; i < nbNodes; ++i )
6900     {
6901       gp_Vec n2p( xyz[i], point );
6902       dist[i] = n2p * plnNorm;
6903     }
6904     dist.back() = dist.front();
6905     // find the closest intersection
6906     int    iClosest = -1;
6907     double rClosest, distClosest = 1e100;;
6908     gp_Pnt pClosest;
6909     for ( i = 0; i < nbNodes; ++i )
6910     {
6911       double r;
6912       if ( fabs( dist[i]) < tol )
6913         r = 0.;
6914       else if ( fabs( dist[i+1]) < tol )
6915         r = 1.;
6916       else if ( dist[i] * dist[i+1] < 0 )
6917         r = dist[i] / ( dist[i] - dist[i+1] );
6918       else
6919         continue; // no intersection
6920       gp_Pnt pInt = xyz[i] * (1.-r) + xyz[i+1] * r;
6921       gp_Vec p2int ( point, pInt);
6922       if ( p2int * ray > -tol ) // right half-space
6923       {
6924         double intDist = p2int.SquareMagnitude();
6925         if ( intDist < distClosest )
6926         {
6927           iClosest = i;
6928           rClosest = r;
6929           pClosest = pInt;
6930           distClosest = intDist;
6931         }
6932       }
6933     }
6934     if ( iClosest < 0 )
6935       return true; // no intesections - out
6936
6937     // analyse transition
6938     gp_Vec edge( xyz[iClosest], xyz[iClosest+1] );
6939     gp_Vec edgeNorm = -( edge ^ faceNorm ); // normal to intersected edge pointing out of face
6940     gp_Vec p2int ( point, pClosest );
6941     bool out = (edgeNorm * p2int) < -tol;
6942     if ( rClosest > 0. && rClosest < 1. ) // not node intersection
6943       return out;
6944
6945     // ray pass through a face node; analyze transition through an adjacent edge
6946     gp_Pnt p1 = xyz[ (rClosest == 0.) ? ((iClosest+nbNodes-1) % nbNodes) : (iClosest+1) ];
6947     gp_Pnt p2 = xyz[ (rClosest == 0.) ? iClosest : ((iClosest+2) % nbNodes) ];
6948     gp_Vec edgeAdjacent( p1, p2 );
6949     gp_Vec edgeNorm2 = -( edgeAdjacent ^ faceNorm );
6950     bool out2 = (edgeNorm2 * p2int) < -tol;
6951
6952     bool covexCorner = ( edgeNorm * edgeAdjacent * (rClosest==1. ? 1. : -1.)) < 0;
6953     return covexCorner ? (out || out2) : (out && out2);
6954   }
6955   if ( element->GetType() == SMDSAbs_Edge ) // --------------------------------------------------
6956   {
6957     // point is out of edge if it is NOT ON any straight part of edge
6958     // (we consider quadratic edge as being composed of two straight parts)
6959     for ( i = 1; i < nbNodes; ++i )
6960     {
6961       gp_Vec edge( xyz[i-1], xyz[i]);
6962       gp_Vec n1p ( xyz[i-1], point);
6963       double dist = ( edge ^ n1p ).Magnitude() / edge.Magnitude();
6964       if ( dist > tol )
6965         continue;
6966       gp_Vec n2p( xyz[i], point );
6967       if ( fabs( edge.Magnitude() - n1p.Magnitude() - n2p.Magnitude()) > tol )
6968         continue;
6969       return false; // point is ON this part
6970     }
6971     return true;
6972   }
6973   // Node or 0D element -------------------------------------------------------------------------
6974   {
6975     gp_Vec n2p ( xyz[0], point );
6976     return n2p.Magnitude() <= tol;
6977   }
6978   return true;
6979 }
6980
6981 //=======================================================================
6982 //function : SimplifyFace
6983 //purpose  :
6984 //=======================================================================
6985 int SMESH_MeshEditor::SimplifyFace (const vector<const SMDS_MeshNode *> faceNodes,
6986                                     vector<const SMDS_MeshNode *>&      poly_nodes,
6987                                     vector<int>&                        quantities) const
6988 {
6989   int nbNodes = faceNodes.size();
6990
6991   if (nbNodes < 3)
6992     return 0;
6993
6994   set<const SMDS_MeshNode*> nodeSet;
6995
6996   // get simple seq of nodes
6997   //const SMDS_MeshNode* simpleNodes[ nbNodes ];
6998   vector<const SMDS_MeshNode*> simpleNodes( nbNodes );
6999   int iSimple = 0, nbUnique = 0;
7000
7001   simpleNodes[iSimple++] = faceNodes[0];
7002   nbUnique++;
7003   for (int iCur = 1; iCur < nbNodes; iCur++) {
7004     if (faceNodes[iCur] != simpleNodes[iSimple - 1]) {
7005       simpleNodes[iSimple++] = faceNodes[iCur];
7006       if (nodeSet.insert( faceNodes[iCur] ).second)
7007         nbUnique++;
7008     }
7009   }
7010   int nbSimple = iSimple;
7011   if (simpleNodes[nbSimple - 1] == simpleNodes[0]) {
7012     nbSimple--;
7013     iSimple--;
7014   }
7015
7016   if (nbUnique < 3)
7017     return 0;
7018
7019   // separate loops
7020   int nbNew = 0;
7021   bool foundLoop = (nbSimple > nbUnique);
7022   while (foundLoop) {
7023     foundLoop = false;
7024     set<const SMDS_MeshNode*> loopSet;
7025     for (iSimple = 0; iSimple < nbSimple && !foundLoop; iSimple++) {
7026       const SMDS_MeshNode* n = simpleNodes[iSimple];
7027       if (!loopSet.insert( n ).second) {
7028         foundLoop = true;
7029
7030         // separate loop
7031         int iC = 0, curLast = iSimple;
7032         for (; iC < curLast; iC++) {
7033           if (simpleNodes[iC] == n) break;
7034         }
7035         int loopLen = curLast - iC;
7036         if (loopLen > 2) {
7037           // create sub-element
7038           nbNew++;
7039           quantities.push_back(loopLen);
7040           for (; iC < curLast; iC++) {
7041             poly_nodes.push_back(simpleNodes[iC]);
7042           }
7043         }
7044         // shift the rest nodes (place from the first loop position)
7045         for (iC = curLast + 1; iC < nbSimple; iC++) {
7046           simpleNodes[iC - loopLen] = simpleNodes[iC];
7047         }
7048         nbSimple -= loopLen;
7049         iSimple -= loopLen;
7050       }
7051     } // for (iSimple = 0; iSimple < nbSimple; iSimple++)
7052   } // while (foundLoop)
7053
7054   if (iSimple > 2) {
7055     nbNew++;
7056     quantities.push_back(iSimple);
7057     for (int i = 0; i < iSimple; i++)
7058       poly_nodes.push_back(simpleNodes[i]);
7059   }
7060
7061   return nbNew;
7062 }
7063
7064 //=======================================================================
7065 //function : MergeNodes
7066 //purpose  : In each group, the cdr of nodes are substituted by the first one
7067 //           in all elements.
7068 //=======================================================================
7069
7070 void SMESH_MeshEditor::MergeNodes (TListOfListOfNodes & theGroupsOfNodes)
7071 {
7072   MESSAGE("MergeNodes");
7073   myLastCreatedElems.Clear();
7074   myLastCreatedNodes.Clear();
7075
7076   SMESHDS_Mesh* aMesh = GetMeshDS();
7077
7078   TNodeNodeMap nodeNodeMap; // node to replace - new node
7079   set<const SMDS_MeshElement*> elems; // all elements with changed nodes
7080   list< int > rmElemIds, rmNodeIds;
7081
7082   // Fill nodeNodeMap and elems
7083
7084   TListOfListOfNodes::iterator grIt = theGroupsOfNodes.begin();
7085   for ( ; grIt != theGroupsOfNodes.end(); grIt++ ) {
7086     list<const SMDS_MeshNode*>& nodes = *grIt;
7087     list<const SMDS_MeshNode*>::iterator nIt = nodes.begin();
7088     const SMDS_MeshNode* nToKeep = *nIt;
7089     //MESSAGE("node to keep " << nToKeep->GetID());
7090     for ( ++nIt; nIt != nodes.end(); nIt++ ) {
7091       const SMDS_MeshNode* nToRemove = *nIt;
7092       nodeNodeMap.insert( TNodeNodeMap::value_type( nToRemove, nToKeep ));
7093       if ( nToRemove != nToKeep ) {
7094         //MESSAGE("  node to remove " << nToRemove->GetID());
7095         rmNodeIds.push_back( nToRemove->GetID() );
7096         AddToSameGroups( nToKeep, nToRemove, aMesh );
7097       }
7098
7099       SMDS_ElemIteratorPtr invElemIt = nToRemove->GetInverseElementIterator();
7100       while ( invElemIt->more() ) {
7101         const SMDS_MeshElement* elem = invElemIt->next();
7102         elems.insert(elem);
7103       }
7104     }
7105   }
7106   // Change element nodes or remove an element
7107
7108   set<const SMDS_MeshElement*>::iterator eIt = elems.begin();
7109   for ( ; eIt != elems.end(); eIt++ ) {
7110     const SMDS_MeshElement* elem = *eIt;
7111     //MESSAGE(" ---- inverse elem on node to remove " << elem->GetID());
7112     int nbNodes = elem->NbNodes();
7113     int aShapeId = FindShape( elem );
7114
7115     set<const SMDS_MeshNode*> nodeSet;
7116     vector< const SMDS_MeshNode*> curNodes( nbNodes ), uniqueNodes( nbNodes );
7117     int iUnique = 0, iCur = 0, nbRepl = 0;
7118     vector<int> iRepl( nbNodes );
7119
7120     // get new seq of nodes
7121     SMDS_ElemIteratorPtr itN = elem->nodesIterator();
7122     while ( itN->more() ) {
7123       const SMDS_MeshNode* n =
7124         static_cast<const SMDS_MeshNode*>( itN->next() );
7125
7126       TNodeNodeMap::iterator nnIt = nodeNodeMap.find( n );
7127       if ( nnIt != nodeNodeMap.end() ) { // n sticks
7128         n = (*nnIt).second;
7129         // BUG 0020185: begin
7130         {
7131           bool stopRecur = false;
7132           set<const SMDS_MeshNode*> nodesRecur;
7133           nodesRecur.insert(n);
7134           while (!stopRecur) {
7135             TNodeNodeMap::iterator nnIt_i = nodeNodeMap.find( n );
7136             if ( nnIt_i != nodeNodeMap.end() ) { // n sticks
7137               n = (*nnIt_i).second;
7138               if (!nodesRecur.insert(n).second) {
7139                 // error: recursive dependancy
7140                 stopRecur = true;
7141               }
7142             }
7143             else
7144               stopRecur = true;
7145           }
7146         }
7147         // BUG 0020185: end
7148         iRepl[ nbRepl++ ] = iCur;
7149       }
7150       curNodes[ iCur ] = n;
7151       bool isUnique = nodeSet.insert( n ).second;
7152       if ( isUnique ) {
7153         uniqueNodes[ iUnique++ ] = n;
7154         if ( nbRepl && iRepl[ nbRepl-1 ] == iCur )
7155           --nbRepl; // n do not stick to a node of the elem
7156       }
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     int id = elem->GetID();
9038     int nbNodes = elem->NbNodes();
9039     SMDSAbs_ElementType aType = elem->GetType();
9040     nodes.assign(elem->begin_nodes(), elem->end_nodes());
9041     if ( elem->GetEntityType() == SMDSEntity_Polyhedra )
9042       nbNodeInFaces = static_cast<const SMDS_VtkVolume* >( elem )->GetQuantities();
9043     else if ( elem->GetEntityType() == SMDSEntity_Hexagonal_Prism )
9044       volumeToPolyhedron( elem, nodes, nbNodeInFaces );
9045
9046     // remove a linear element
9047     GetMeshDS()->RemoveFreeElement(elem, theSm, /*fromGroups=*/false);
9048
9049     const SMDS_MeshElement* NewElem = 0;
9050
9051     switch( aType )
9052     {
9053     case SMDSAbs_Edge :
9054       {
9055         NewElem = theHelper.AddEdge(nodes[0], nodes[1], id, theForce3d);
9056         break;
9057       }
9058     case SMDSAbs_Face :
9059       {
9060         switch(nbNodes)
9061         {
9062         case 3:
9063           NewElem = theHelper.AddFace(nodes[0], nodes[1], nodes[2], id, theForce3d);
9064           break;
9065         case 4:
9066           NewElem = theHelper.AddFace(nodes[0], nodes[1], nodes[2], nodes[3], id, theForce3d);
9067           break;
9068         default:
9069           NewElem = theHelper.AddPolygonalFace(nodes, id, theForce3d);
9070           continue;
9071         }
9072         break;
9073       }
9074     case SMDSAbs_Volume :
9075       {
9076         switch( elem->GetEntityType() )
9077         {
9078         case SMDSEntity_Tetra:
9079           NewElem = theHelper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3], id, theForce3d);
9080           break;
9081         case SMDSEntity_Pyramid:
9082           NewElem = theHelper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3], nodes[4], id, theForce3d);
9083           break;
9084         case SMDSEntity_Penta:
9085           NewElem = theHelper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3], nodes[4], nodes[5], id, theForce3d);
9086           break;
9087         case SMDSEntity_Hexa:
9088           NewElem = theHelper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3],
9089                                         nodes[4], nodes[5], nodes[6], nodes[7], id, theForce3d);
9090           break;
9091         case SMDSEntity_Hexagonal_Prism:
9092         default:
9093           NewElem = theHelper.AddPolyhedralVolume(nodes, nbNodeInFaces, id, theForce3d);
9094         }
9095         break;
9096       }
9097     default :
9098       continue;
9099     }
9100     ReplaceElemInGroups( elem, NewElem, GetMeshDS());
9101     if( NewElem )
9102       theSm->AddElement( NewElem );
9103   }
9104 //  if (!GetMeshDS()->isCompacted())
9105 //    GetMeshDS()->compactMesh();
9106   return nbElem;
9107 }
9108
9109 //=======================================================================
9110 //function : ConvertToQuadratic
9111 //purpose  :
9112 //=======================================================================
9113
9114 void SMESH_MeshEditor::ConvertToQuadratic(const bool theForce3d)
9115 {
9116   SMESHDS_Mesh* meshDS = GetMeshDS();
9117
9118   SMESH_MesherHelper aHelper(*myMesh);
9119   aHelper.SetIsQuadratic( true );
9120
9121   int nbCheckedElems = 0;
9122   if ( myMesh->HasShapeToMesh() )
9123   {
9124     if ( SMESH_subMesh *aSubMesh = myMesh->GetSubMeshContaining(myMesh->GetShapeToMesh()))
9125     {
9126       SMESH_subMeshIteratorPtr smIt = aSubMesh->getDependsOnIterator(true,false);
9127       while ( smIt->more() ) {
9128         SMESH_subMesh* sm = smIt->next();
9129         if ( SMESHDS_SubMesh *smDS = sm->GetSubMeshDS() ) {
9130           aHelper.SetSubShape( sm->GetSubShape() );
9131           nbCheckedElems += convertElemToQuadratic(smDS, aHelper, theForce3d);
9132         }
9133       }
9134     }
9135   }
9136   int totalNbElems = meshDS->NbEdges() + meshDS->NbFaces() + meshDS->NbVolumes();
9137   if ( nbCheckedElems < totalNbElems ) // not all elements are in submeshes
9138   {
9139     SMESHDS_SubMesh *smDS = 0;
9140     SMDS_EdgeIteratorPtr aEdgeItr = meshDS->edgesIterator();
9141     while(aEdgeItr->more())
9142     {
9143       const SMDS_MeshEdge* edge = aEdgeItr->next();
9144       if(edge && !edge->IsQuadratic())
9145       {
9146         int id = edge->GetID();
9147         //MESSAGE("edge->GetID() " << id);
9148         const SMDS_MeshNode* n1 = edge->GetNode(0);
9149         const SMDS_MeshNode* n2 = edge->GetNode(1);
9150
9151         meshDS->RemoveFreeElement(edge, smDS, /*fromGroups=*/false);
9152
9153         const SMDS_MeshEdge* NewEdge = aHelper.AddEdge(n1, n2, id, theForce3d);
9154         ReplaceElemInGroups( edge, NewEdge, GetMeshDS());
9155       }
9156     }
9157     SMDS_FaceIteratorPtr aFaceItr = meshDS->facesIterator();
9158     while(aFaceItr->more())
9159     {
9160       const SMDS_MeshFace* face = aFaceItr->next();
9161       if(!face || face->IsQuadratic() ) continue;
9162
9163       const int id = face->GetID();
9164       const SMDSAbs_EntityType type = face->GetEntityType();
9165       vector<const SMDS_MeshNode *> nodes ( face->begin_nodes(), face->end_nodes());
9166
9167       meshDS->RemoveFreeElement(face, smDS, /*fromGroups=*/false);
9168
9169       SMDS_MeshFace * NewFace = 0;
9170       switch( type )
9171       {
9172       case SMDSEntity_Triangle:
9173         NewFace = aHelper.AddFace(nodes[0], nodes[1], nodes[2], id, theForce3d);
9174         break;
9175       case SMDSEntity_Quadrangle:
9176         NewFace = aHelper.AddFace(nodes[0], nodes[1], nodes[2], nodes[3], id, theForce3d);
9177         break;
9178       default:
9179         NewFace = aHelper.AddPolygonalFace(nodes, id, theForce3d);
9180       }
9181       ReplaceElemInGroups( face, NewFace, GetMeshDS());
9182     }
9183     vector<int> nbNodeInFaces;
9184     SMDS_VolumeIteratorPtr aVolumeItr = meshDS->volumesIterator();
9185     while(aVolumeItr->more())
9186     {
9187       const SMDS_MeshVolume* volume = aVolumeItr->next();
9188       if(!volume || volume->IsQuadratic() ) continue;
9189
9190       const int id = volume->GetID();
9191       const SMDSAbs_EntityType type = volume->GetEntityType();
9192       vector<const SMDS_MeshNode *> nodes (volume->begin_nodes(), volume->end_nodes());
9193       if ( type == SMDSEntity_Polyhedra )
9194         nbNodeInFaces = static_cast<const SMDS_VtkVolume* >(volume)->GetQuantities();
9195       else if ( type == SMDSEntity_Hexagonal_Prism )
9196         volumeToPolyhedron( volume, nodes, nbNodeInFaces );
9197
9198       meshDS->RemoveFreeElement(volume, smDS, /*fromGroups=*/false);
9199
9200       SMDS_MeshVolume * NewVolume = 0;
9201       switch ( type )
9202       {
9203       case SMDSEntity_Tetra:
9204         NewVolume = aHelper.AddVolume(nodes[0], nodes[1], nodes[2],
9205                                       nodes[3], id, theForce3d );
9206         break;
9207       case SMDSEntity_Hexa:
9208         NewVolume = aHelper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3],
9209                                       nodes[4], nodes[5], nodes[6], nodes[7], id, theForce3d);
9210         break;
9211       case SMDSEntity_Pyramid:
9212         NewVolume = aHelper.AddVolume(nodes[0], nodes[1], nodes[2],
9213                                       nodes[3], nodes[4], id, theForce3d);
9214         break;
9215       case SMDSEntity_Penta:
9216         NewVolume = aHelper.AddVolume(nodes[0], nodes[1], nodes[2],
9217                                       nodes[3], nodes[4], nodes[5], id, theForce3d);
9218         break;
9219       case SMDSEntity_Hexagonal_Prism:
9220       default:
9221         NewVolume = aHelper.AddPolyhedralVolume(nodes, nbNodeInFaces, id, theForce3d);
9222       }
9223       ReplaceElemInGroups(volume, NewVolume, meshDS);
9224     }
9225   }
9226
9227   if ( !theForce3d )
9228   { // setenv NO_FixQuadraticElements to know if FixQuadraticElements() is guilty of bad conversion
9229     aHelper.SetSubShape(0); // apply FixQuadraticElements() to the whole mesh
9230     aHelper.FixQuadraticElements();
9231   }
9232 }
9233
9234 //================================================================================
9235 /*!
9236  * \brief Makes given elements quadratic
9237  *  \param theForce3d - if true, the medium nodes will be placed in the middle of link
9238  *  \param theElements - elements to make quadratic 
9239  */
9240 //================================================================================
9241
9242 void SMESH_MeshEditor::ConvertToQuadratic(const bool        theForce3d,
9243                                           TIDSortedElemSet& theElements)
9244 {
9245   if ( theElements.empty() ) return;
9246
9247   // we believe that all theElements are of the same type
9248   SMDSAbs_ElementType elemType = (*theElements.begin())->GetType();
9249   
9250   // get all nodes shared by theElements
9251   TIDSortedNodeSet allNodes;
9252   TIDSortedElemSet::iterator eIt = theElements.begin();
9253   for ( ; eIt != theElements.end(); ++eIt )
9254     allNodes.insert( (*eIt)->begin_nodes(), (*eIt)->end_nodes() );
9255
9256   // complete theElements with elements of lower dim whose all nodes are in allNodes
9257
9258   TIDSortedElemSet quadAdjacentElems    [ SMDSAbs_NbElementTypes ]; // quadratic adjacent elements
9259   TIDSortedElemSet checkedAdjacentElems [ SMDSAbs_NbElementTypes ];
9260   TIDSortedNodeSet::iterator nIt = allNodes.begin();
9261   for ( ; nIt != allNodes.end(); ++nIt )
9262   {
9263     const SMDS_MeshNode* n = *nIt;
9264     SMDS_ElemIteratorPtr invIt = n->GetInverseElementIterator();
9265     while ( invIt->more() )
9266     {
9267       const SMDS_MeshElement* e = invIt->next();
9268       if ( e->IsQuadratic() )
9269       {
9270         quadAdjacentElems[ e->GetType() ].insert( e );
9271         continue;
9272       }
9273       if ( e->GetType() >= elemType )
9274       {
9275         continue; // same type of more complex linear element
9276       }
9277
9278       if ( !checkedAdjacentElems[ e->GetType() ].insert( e ).second )
9279         continue; // e is already checked
9280
9281       // check nodes
9282       bool allIn = true;
9283       SMDS_ElemIteratorPtr nodeIt = e->nodesIterator();
9284       while ( nodeIt->more() && allIn )
9285         allIn = allNodes.count( cast2Node( nodeIt->next() ));
9286       if ( allIn )
9287         theElements.insert(e );
9288     }
9289   }
9290
9291   SMESH_MesherHelper helper(*myMesh);
9292   helper.SetIsQuadratic( true );
9293
9294   // add links of quadratic adjacent elements to the helper
9295
9296   if ( !quadAdjacentElems[SMDSAbs_Edge].empty() )
9297     for ( eIt  = quadAdjacentElems[SMDSAbs_Edge].begin();
9298           eIt != quadAdjacentElems[SMDSAbs_Edge].end(); ++eIt )
9299     {
9300       helper.AddTLinks( static_cast< const SMDS_MeshEdge*> (*eIt) );
9301     }
9302   if ( !quadAdjacentElems[SMDSAbs_Face].empty() )
9303     for ( eIt  = quadAdjacentElems[SMDSAbs_Face].begin();
9304           eIt != quadAdjacentElems[SMDSAbs_Face].end(); ++eIt )
9305     {
9306       helper.AddTLinks( static_cast< const SMDS_MeshFace*> (*eIt) );
9307     }
9308   if ( !quadAdjacentElems[SMDSAbs_Volume].empty() )
9309     for ( eIt  = quadAdjacentElems[SMDSAbs_Volume].begin();
9310           eIt != quadAdjacentElems[SMDSAbs_Volume].end(); ++eIt )
9311     {
9312       helper.AddTLinks( static_cast< const SMDS_MeshVolume*> (*eIt) );
9313     }
9314
9315   // make quadratic elements instead of linear ones
9316
9317   SMESHDS_Mesh* meshDS = GetMeshDS();
9318   SMESHDS_SubMesh* smDS = 0;
9319   for ( eIt = theElements.begin(); eIt != theElements.end(); ++eIt )
9320   {
9321     const SMDS_MeshElement* elem = *eIt;
9322     if( elem->IsQuadratic() || elem->NbNodes() < 2 || elem->IsPoly() )
9323       continue;
9324
9325     int id = elem->GetID();
9326     SMDSAbs_ElementType type = elem->GetType();
9327     vector<const SMDS_MeshNode *> nodes ( elem->begin_nodes(), elem->end_nodes());
9328
9329     if ( !smDS || !smDS->Contains( elem ))
9330       smDS = meshDS->MeshElements( elem->getshapeId() );
9331     meshDS->RemoveFreeElement(elem, smDS, /*fromGroups=*/false);
9332
9333     SMDS_MeshElement * newElem = 0;
9334     switch( nodes.size() )
9335     {
9336     case 4: // cases for most multiple element types go first (for optimization)
9337       if ( type == SMDSAbs_Volume )
9338         newElem = helper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3], id, theForce3d);
9339       else
9340         newElem = helper.AddFace  (nodes[0], nodes[1], nodes[2], nodes[3], id, theForce3d);
9341       break;
9342     case 8:
9343       newElem = helper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3],
9344                                  nodes[4], nodes[5], nodes[6], nodes[7], id, theForce3d);
9345       break;
9346     case 3:
9347       newElem = helper.AddFace  (nodes[0], nodes[1], nodes[2], id, theForce3d);
9348       break;
9349     case 2:
9350       newElem = helper.AddEdge(nodes[0], nodes[1], id, theForce3d);
9351       break;
9352     case 5:
9353       newElem = helper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3],
9354                                  nodes[4], id, theForce3d);
9355       break;
9356     case 6:
9357       newElem = helper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3],
9358                                  nodes[4], nodes[5], id, theForce3d);
9359       break;
9360     default:;
9361     }
9362     ReplaceElemInGroups( elem, newElem, meshDS);
9363     if( newElem && smDS )
9364       smDS->AddElement( newElem );
9365   }
9366
9367   if ( !theForce3d  && !getenv("NO_FixQuadraticElements"))
9368   { // setenv NO_FixQuadraticElements to know if FixQuadraticElements() is guilty of bad conversion
9369     helper.SetSubShape(0); // apply FixQuadraticElements() to the whole mesh
9370     helper.FixQuadraticElements();
9371   }
9372 }
9373
9374 //=======================================================================
9375 /*!
9376  * \brief Convert quadratic elements to linear ones and remove quadratic nodes
9377  * \return int - nb of checked elements
9378  */
9379 //=======================================================================
9380
9381 int SMESH_MeshEditor::removeQuadElem(SMESHDS_SubMesh *    theSm,
9382                                      SMDS_ElemIteratorPtr theItr,
9383                                      const int            theShapeID)
9384 {
9385   int nbElem = 0;
9386   SMESHDS_Mesh* meshDS = GetMeshDS();
9387
9388   while( theItr->more() )
9389   {
9390     const SMDS_MeshElement* elem = theItr->next();
9391     nbElem++;
9392     if( elem && elem->IsQuadratic())
9393     {
9394       int id                    = elem->GetID();
9395       int nbCornerNodes         = elem->NbCornerNodes();
9396       SMDSAbs_ElementType aType = elem->GetType();
9397
9398       vector<const SMDS_MeshNode *> nodes( elem->begin_nodes(), elem->end_nodes() );
9399
9400       //remove a quadratic element
9401       if ( !theSm || !theSm->Contains( elem ))
9402         theSm = meshDS->MeshElements( elem->getshapeId() );
9403       meshDS->RemoveFreeElement( elem, theSm, /*fromGroups=*/false );
9404
9405       // remove medium nodes
9406       for ( unsigned i = nbCornerNodes; i < nodes.size(); ++i )
9407         if ( nodes[i]->NbInverseElements() == 0 )
9408           meshDS->RemoveFreeNode( nodes[i], theSm );
9409
9410       // add a linear element
9411       nodes.resize( nbCornerNodes );
9412       SMDS_MeshElement * newElem = AddElement( nodes, aType, false, id );
9413       ReplaceElemInGroups(elem, newElem, meshDS);
9414       if( theSm && newElem )
9415         theSm->AddElement( newElem );
9416     }
9417   }
9418   return nbElem;
9419 }
9420
9421 //=======================================================================
9422 //function : ConvertFromQuadratic
9423 //purpose  :
9424 //=======================================================================
9425
9426 bool SMESH_MeshEditor::ConvertFromQuadratic()
9427 {
9428   int nbCheckedElems = 0;
9429   if ( myMesh->HasShapeToMesh() )
9430   {
9431     if ( SMESH_subMesh *aSubMesh = myMesh->GetSubMeshContaining(myMesh->GetShapeToMesh()))
9432     {
9433       SMESH_subMeshIteratorPtr smIt = aSubMesh->getDependsOnIterator(true,false);
9434       while ( smIt->more() ) {
9435         SMESH_subMesh* sm = smIt->next();
9436         if ( SMESHDS_SubMesh *smDS = sm->GetSubMeshDS() )
9437           nbCheckedElems += removeQuadElem( smDS, smDS->GetElements(), sm->GetId() );
9438       }
9439     }
9440   }
9441
9442   int totalNbElems =
9443     GetMeshDS()->NbEdges() + GetMeshDS()->NbFaces() + GetMeshDS()->NbVolumes();
9444   if ( nbCheckedElems < totalNbElems ) // not all elements are in submeshes
9445   {
9446     SMESHDS_SubMesh *aSM = 0;
9447     removeQuadElem( aSM, GetMeshDS()->elementsIterator(), 0 );
9448   }
9449
9450   return true;
9451 }
9452
9453 namespace
9454 {
9455   //================================================================================
9456   /*!
9457    * \brief Return true if all medium nodes of the element are in the node set
9458    */
9459   //================================================================================
9460
9461   bool allMediumNodesIn(const SMDS_MeshElement* elem, TIDSortedNodeSet& nodeSet )
9462   {
9463     for ( int i = elem->NbCornerNodes(); i < elem->NbNodes(); ++i )
9464       if ( !nodeSet.count( elem->GetNode(i) ))
9465         return false;
9466     return true;
9467   }
9468 }
9469
9470 //================================================================================
9471 /*!
9472  * \brief Makes given elements linear
9473  */
9474 //================================================================================
9475
9476 void SMESH_MeshEditor::ConvertFromQuadratic(TIDSortedElemSet& theElements)
9477 {
9478   if ( theElements.empty() ) return;
9479
9480   // collect IDs of medium nodes of theElements; some of these nodes will be removed
9481   set<int> mediumNodeIDs;
9482   TIDSortedElemSet::iterator eIt = theElements.begin();
9483   for ( ; eIt != theElements.end(); ++eIt )
9484   {
9485     const SMDS_MeshElement* e = *eIt;
9486     for ( int i = e->NbCornerNodes(); i < e->NbNodes(); ++i )
9487       mediumNodeIDs.insert( e->GetNode(i)->GetID() );
9488   }
9489
9490   // replace given elements by linear ones
9491   typedef SMDS_SetIterator<const SMDS_MeshElement*, TIDSortedElemSet::iterator> TSetIterator;
9492   SMDS_ElemIteratorPtr elemIt( new TSetIterator( theElements.begin(), theElements.end() ));
9493   removeQuadElem( /*theSm=*/0, elemIt, /*theShapeID=*/0 );
9494
9495   // we need to convert remaining elements whose all medium nodes are in mediumNodeIDs
9496   // except those elements sharing medium nodes of quadratic element whose medium nodes
9497   // are not all in mediumNodeIDs
9498
9499   // get remaining medium nodes
9500   TIDSortedNodeSet mediumNodes;
9501   set<int>::iterator nIdsIt = mediumNodeIDs.begin();
9502   for ( ; nIdsIt != mediumNodeIDs.end(); ++nIdsIt )
9503     if ( const SMDS_MeshNode* n = GetMeshDS()->FindNode( *nIdsIt ))
9504       mediumNodes.insert( mediumNodes.end(), n );
9505
9506   // find more quadratic elements to convert
9507   TIDSortedElemSet moreElemsToConvert;
9508   TIDSortedNodeSet::iterator nIt = mediumNodes.begin();
9509   for ( ; nIt != mediumNodes.end(); ++nIt )
9510   {
9511     SMDS_ElemIteratorPtr invIt = (*nIt)->GetInverseElementIterator();
9512     while ( invIt->more() )
9513     {
9514       const SMDS_MeshElement* e = invIt->next();
9515       if ( e->IsQuadratic() && allMediumNodesIn( e, mediumNodes ))
9516       {
9517         // find a more complex element including e and
9518         // whose medium nodes are not in mediumNodes
9519         bool complexFound = false;
9520         for ( int type = e->GetType() + 1; type < SMDSAbs_0DElement; ++type )
9521         {
9522           SMDS_ElemIteratorPtr invIt2 =
9523             (*nIt)->GetInverseElementIterator( SMDSAbs_ElementType( type ));
9524           while ( invIt2->more() )
9525           {
9526             const SMDS_MeshElement* eComplex = invIt2->next();
9527             if ( eComplex->IsQuadratic() && !allMediumNodesIn( eComplex, mediumNodes))
9528             {
9529               int nbCommonNodes = SMESH_Algo::GetCommonNodes( e, eComplex ).size();
9530               if ( nbCommonNodes == e->NbNodes())
9531               {
9532                 complexFound = true;
9533                 type = SMDSAbs_NbElementTypes; // to quit from the outer loop
9534                 break;
9535               }
9536             }
9537           }
9538         }
9539         if ( !complexFound )
9540           moreElemsToConvert.insert( e );
9541       }
9542     }
9543   }
9544   elemIt = SMDS_ElemIteratorPtr
9545     (new TSetIterator( moreElemsToConvert.begin(), moreElemsToConvert.end() ));
9546   removeQuadElem( /*theSm=*/0, elemIt, /*theShapeID=*/0 );
9547 }
9548
9549 //=======================================================================
9550 //function : SewSideElements
9551 //purpose  :
9552 //=======================================================================
9553
9554 SMESH_MeshEditor::Sew_Error
9555 SMESH_MeshEditor::SewSideElements (TIDSortedElemSet&    theSide1,
9556                                    TIDSortedElemSet&    theSide2,
9557                                    const SMDS_MeshNode* theFirstNode1,
9558                                    const SMDS_MeshNode* theFirstNode2,
9559                                    const SMDS_MeshNode* theSecondNode1,
9560                                    const SMDS_MeshNode* theSecondNode2)
9561 {
9562   myLastCreatedElems.Clear();
9563   myLastCreatedNodes.Clear();
9564
9565   MESSAGE ("::::SewSideElements()");
9566   if ( theSide1.size() != theSide2.size() )
9567     return SEW_DIFF_NB_OF_ELEMENTS;
9568
9569   Sew_Error aResult = SEW_OK;
9570   // Algo:
9571   // 1. Build set of faces representing each side
9572   // 2. Find which nodes of the side 1 to merge with ones on the side 2
9573   // 3. Replace nodes in elements of the side 1 and remove replaced nodes
9574
9575   // =======================================================================
9576   // 1. Build set of faces representing each side:
9577   // =======================================================================
9578   // a. build set of nodes belonging to faces
9579   // b. complete set of faces: find missing faces whose nodes are in set of nodes
9580   // c. create temporary faces representing side of volumes if correspondent
9581   //    face does not exist
9582
9583   SMESHDS_Mesh* aMesh = GetMeshDS();
9584   // TODO algoritm not OK with vtkUnstructuredGrid: 2 meshes can't share nodes
9585   //SMDS_Mesh aTmpFacesMesh; // try to use the same mesh
9586   set<const SMDS_MeshElement*> faceSet1, faceSet2;
9587   set<const SMDS_MeshElement*> volSet1,  volSet2;
9588   set<const SMDS_MeshNode*>    nodeSet1, nodeSet2;
9589   set<const SMDS_MeshElement*> * faceSetPtr[] = { &faceSet1, &faceSet2 };
9590   set<const SMDS_MeshElement*>  * volSetPtr[] = { &volSet1,  &volSet2  };
9591   set<const SMDS_MeshNode*>    * nodeSetPtr[] = { &nodeSet1, &nodeSet2 };
9592   TIDSortedElemSet * elemSetPtr[] = { &theSide1, &theSide2 };
9593   int iSide, iFace, iNode;
9594
9595   list<const SMDS_MeshElement* > tempFaceList;
9596   for ( iSide = 0; iSide < 2; iSide++ ) {
9597     set<const SMDS_MeshNode*>    * nodeSet = nodeSetPtr[ iSide ];
9598     TIDSortedElemSet * elemSet = elemSetPtr[ iSide ];
9599     set<const SMDS_MeshElement*> * faceSet = faceSetPtr[ iSide ];
9600     set<const SMDS_MeshElement*> * volSet  = volSetPtr [ iSide ];
9601     set<const SMDS_MeshElement*>::iterator vIt;
9602     TIDSortedElemSet::iterator eIt;
9603     set<const SMDS_MeshNode*>::iterator    nIt;
9604
9605     // check that given nodes belong to given elements
9606     const SMDS_MeshNode* n1 = ( iSide == 0 ) ? theFirstNode1 : theFirstNode2;
9607     const SMDS_MeshNode* n2 = ( iSide == 0 ) ? theSecondNode1 : theSecondNode2;
9608     int firstIndex = -1, secondIndex = -1;
9609     for (eIt = elemSet->begin(); eIt != elemSet->end(); eIt++ ) {
9610       const SMDS_MeshElement* elem = *eIt;
9611       if ( firstIndex  < 0 ) firstIndex  = elem->GetNodeIndex( n1 );
9612       if ( secondIndex < 0 ) secondIndex = elem->GetNodeIndex( n2 );
9613       if ( firstIndex > -1 && secondIndex > -1 ) break;
9614     }
9615     if ( firstIndex < 0 || secondIndex < 0 ) {
9616       // we can simply return until temporary faces created
9617       return (iSide == 0 ) ? SEW_BAD_SIDE1_NODES : SEW_BAD_SIDE2_NODES;
9618     }
9619
9620     // -----------------------------------------------------------
9621     // 1a. Collect nodes of existing faces
9622     //     and build set of face nodes in order to detect missing
9623     //     faces corresponding to sides of volumes
9624     // -----------------------------------------------------------
9625
9626     set< set <const SMDS_MeshNode*> > setOfFaceNodeSet;
9627
9628     // loop on the given element of a side
9629     for (eIt = elemSet->begin(); eIt != elemSet->end(); eIt++ ) {
9630       //const SMDS_MeshElement* elem = *eIt;
9631       const SMDS_MeshElement* elem = *eIt;
9632       if ( elem->GetType() == SMDSAbs_Face ) {
9633         faceSet->insert( elem );
9634         set <const SMDS_MeshNode*> faceNodeSet;
9635         SMDS_ElemIteratorPtr nodeIt = elem->nodesIterator();
9636         while ( nodeIt->more() ) {
9637           const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
9638           nodeSet->insert( n );
9639           faceNodeSet.insert( n );
9640         }
9641         setOfFaceNodeSet.insert( faceNodeSet );
9642       }
9643       else if ( elem->GetType() == SMDSAbs_Volume )
9644         volSet->insert( elem );
9645     }
9646     // ------------------------------------------------------------------------------
9647     // 1b. Complete set of faces: find missing faces whose nodes are in set of nodes
9648     // ------------------------------------------------------------------------------
9649
9650     for ( nIt = nodeSet->begin(); nIt != nodeSet->end(); nIt++ ) { // loop on nodes of iSide
9651       SMDS_ElemIteratorPtr fIt = (*nIt)->GetInverseElementIterator(SMDSAbs_Face);
9652       while ( fIt->more() ) { // loop on faces sharing a node
9653         const SMDS_MeshElement* f = fIt->next();
9654         if ( faceSet->find( f ) == faceSet->end() ) {
9655           // check if all nodes are in nodeSet and
9656           // complete setOfFaceNodeSet if they are
9657           set <const SMDS_MeshNode*> faceNodeSet;
9658           SMDS_ElemIteratorPtr nodeIt = f->nodesIterator();
9659           bool allInSet = true;
9660           while ( nodeIt->more() && allInSet ) { // loop on nodes of a face
9661             const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
9662             if ( nodeSet->find( n ) == nodeSet->end() )
9663               allInSet = false;
9664             else
9665               faceNodeSet.insert( n );
9666           }
9667           if ( allInSet ) {
9668             faceSet->insert( f );
9669             setOfFaceNodeSet.insert( faceNodeSet );
9670           }
9671         }
9672       }
9673     }
9674
9675     // -------------------------------------------------------------------------
9676     // 1c. Create temporary faces representing sides of volumes if correspondent
9677     //     face does not exist
9678     // -------------------------------------------------------------------------
9679
9680     if ( !volSet->empty() ) {
9681       //int nodeSetSize = nodeSet->size();
9682
9683       // loop on given volumes
9684       for ( vIt = volSet->begin(); vIt != volSet->end(); vIt++ ) {
9685         SMDS_VolumeTool vol (*vIt);
9686         // loop on volume faces: find free faces
9687         // --------------------------------------
9688         list<const SMDS_MeshElement* > freeFaceList;
9689         for ( iFace = 0; iFace < vol.NbFaces(); iFace++ ) {
9690           if ( !vol.IsFreeFace( iFace ))
9691             continue;
9692           // check if there is already a face with same nodes in a face set
9693           const SMDS_MeshElement* aFreeFace = 0;
9694           const SMDS_MeshNode** fNodes = vol.GetFaceNodes( iFace );
9695           int nbNodes = vol.NbFaceNodes( iFace );
9696           set <const SMDS_MeshNode*> faceNodeSet;
9697           vol.GetFaceNodes( iFace, faceNodeSet );
9698           bool isNewFace = setOfFaceNodeSet.insert( faceNodeSet ).second;
9699           if ( isNewFace ) {
9700             // no such a face is given but it still can exist, check it
9701             if ( nbNodes == 3 ) {
9702               aFreeFace = aMesh->FindFace( fNodes[0],fNodes[1],fNodes[2] );
9703             }
9704             else if ( nbNodes == 4 ) {
9705               aFreeFace = aMesh->FindFace( fNodes[0],fNodes[1],fNodes[2],fNodes[3] );
9706             }
9707             else {
9708               vector<const SMDS_MeshNode *> poly_nodes ( fNodes, & fNodes[nbNodes]);
9709               aFreeFace = aMesh->FindFace(poly_nodes);
9710             }
9711           }
9712           if ( !aFreeFace ) {
9713             // create a temporary face
9714             if ( nbNodes == 3 ) {
9715               //aFreeFace = aTmpFacesMesh.AddFace( fNodes[0],fNodes[1],fNodes[2] );
9716               aFreeFace = aMesh->AddFace( fNodes[0],fNodes[1],fNodes[2] );
9717             }
9718             else if ( nbNodes == 4 ) {
9719               //aFreeFace = aTmpFacesMesh.AddFace( fNodes[0],fNodes[1],fNodes[2],fNodes[3] );
9720               aFreeFace = aMesh->AddFace( fNodes[0],fNodes[1],fNodes[2],fNodes[3] );
9721             }
9722             else {
9723               vector<const SMDS_MeshNode *> poly_nodes ( fNodes, & fNodes[nbNodes]);
9724               //aFreeFace = aTmpFacesMesh.AddPolygonalFace(poly_nodes);
9725               aFreeFace = aMesh->AddPolygonalFace(poly_nodes);
9726             }
9727           }
9728           if ( aFreeFace ) {
9729             freeFaceList.push_back( aFreeFace );
9730             tempFaceList.push_back( aFreeFace );
9731           }
9732
9733         } // loop on faces of a volume
9734
9735         // choose one of several free faces
9736         // --------------------------------------
9737         if ( freeFaceList.size() > 1 ) {
9738           // choose a face having max nb of nodes shared by other elems of a side
9739           int maxNbNodes = -1/*, nbExcludedFaces = 0*/;
9740           list<const SMDS_MeshElement* >::iterator fIt = freeFaceList.begin();
9741           while ( fIt != freeFaceList.end() ) { // loop on free faces
9742             int nbSharedNodes = 0;
9743             SMDS_ElemIteratorPtr nodeIt = (*fIt)->nodesIterator();
9744             while ( nodeIt->more() ) { // loop on free face nodes
9745               const SMDS_MeshNode* n =
9746                 static_cast<const SMDS_MeshNode*>( nodeIt->next() );
9747               SMDS_ElemIteratorPtr invElemIt = n->GetInverseElementIterator();
9748               while ( invElemIt->more() ) {
9749                 const SMDS_MeshElement* e = invElemIt->next();
9750                 if ( faceSet->find( e ) != faceSet->end() )
9751                   nbSharedNodes++;
9752                 if ( elemSet->find( e ) != elemSet->end() )
9753                   nbSharedNodes++;
9754               }
9755             }
9756             if ( nbSharedNodes >= maxNbNodes ) {
9757               maxNbNodes = nbSharedNodes;
9758               fIt++;
9759             }
9760             else
9761               freeFaceList.erase( fIt++ ); // here fIt++ occurs before erase
9762           }
9763           if ( freeFaceList.size() > 1 )
9764           {
9765             // could not choose one face, use another way
9766             // choose a face most close to the bary center of the opposite side
9767             gp_XYZ aBC( 0., 0., 0. );
9768             set <const SMDS_MeshNode*> addedNodes;
9769             TIDSortedElemSet * elemSet2 = elemSetPtr[ 1 - iSide ];
9770             eIt = elemSet2->begin();
9771             for ( eIt = elemSet2->begin(); eIt != elemSet2->end(); eIt++ ) {
9772               SMDS_ElemIteratorPtr nodeIt = (*eIt)->nodesIterator();
9773               while ( nodeIt->more() ) { // loop on free face nodes
9774                 const SMDS_MeshNode* n =
9775                   static_cast<const SMDS_MeshNode*>( nodeIt->next() );
9776                 if ( addedNodes.insert( n ).second )
9777                   aBC += gp_XYZ( n->X(),n->Y(),n->Z() );
9778               }
9779             }
9780             aBC /= addedNodes.size();
9781             double minDist = DBL_MAX;
9782             fIt = freeFaceList.begin();
9783             while ( fIt != freeFaceList.end() ) { // loop on free faces
9784               double dist = 0;
9785               SMDS_ElemIteratorPtr nodeIt = (*fIt)->nodesIterator();
9786               while ( nodeIt->more() ) { // loop on free face nodes
9787                 const SMDS_MeshNode* n =
9788                   static_cast<const SMDS_MeshNode*>( nodeIt->next() );
9789                 gp_XYZ p( n->X(),n->Y(),n->Z() );
9790                 dist += ( aBC - p ).SquareModulus();
9791               }
9792               if ( dist < minDist ) {
9793                 minDist = dist;
9794                 freeFaceList.erase( freeFaceList.begin(), fIt++ );
9795               }
9796               else
9797                 fIt = freeFaceList.erase( fIt++ );
9798             }
9799           }
9800         } // choose one of several free faces of a volume
9801
9802         if ( freeFaceList.size() == 1 ) {
9803           const SMDS_MeshElement* aFreeFace = freeFaceList.front();
9804           faceSet->insert( aFreeFace );
9805           // complete a node set with nodes of a found free face
9806           //           for ( iNode = 0; iNode < ; iNode++ )
9807           //             nodeSet->insert( fNodes[ iNode ] );
9808         }
9809
9810       } // loop on volumes of a side
9811
9812       //       // complete a set of faces if new nodes in a nodeSet appeared
9813       //       // ----------------------------------------------------------
9814       //       if ( nodeSetSize != nodeSet->size() ) {
9815       //         for ( ; nIt != nodeSet->end(); nIt++ ) { // loop on nodes of iSide
9816       //           SMDS_ElemIteratorPtr fIt = (*nIt)->GetInverseElementIterator(SMDSAbs_Face);
9817       //           while ( fIt->more() ) { // loop on faces sharing a node
9818       //             const SMDS_MeshElement* f = fIt->next();
9819       //             if ( faceSet->find( f ) == faceSet->end() ) {
9820       //               // check if all nodes are in nodeSet and
9821       //               // complete setOfFaceNodeSet if they are
9822       //               set <const SMDS_MeshNode*> faceNodeSet;
9823       //               SMDS_ElemIteratorPtr nodeIt = f->nodesIterator();
9824       //               bool allInSet = true;
9825       //               while ( nodeIt->more() && allInSet ) { // loop on nodes of a face
9826       //                 const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
9827       //                 if ( nodeSet->find( n ) == nodeSet->end() )
9828       //                   allInSet = false;
9829       //                 else
9830       //                   faceNodeSet.insert( n );
9831       //               }
9832       //               if ( allInSet ) {
9833       //                 faceSet->insert( f );
9834       //                 setOfFaceNodeSet.insert( faceNodeSet );
9835       //               }
9836       //             }
9837       //           }
9838       //         }
9839       //       }
9840     } // Create temporary faces, if there are volumes given
9841   } // loop on sides
9842
9843   if ( faceSet1.size() != faceSet2.size() ) {
9844     // delete temporary faces: they are in reverseElements of actual nodes
9845 //    SMDS_FaceIteratorPtr tmpFaceIt = aTmpFacesMesh.facesIterator();
9846 //    while ( tmpFaceIt->more() )
9847 //      aTmpFacesMesh.RemoveElement( tmpFaceIt->next() );
9848 //    list<const SMDS_MeshElement* >::iterator tmpFaceIt = tempFaceList.begin();
9849 //    for (; tmpFaceIt !=tempFaceList.end(); ++tmpFaceIt)
9850 //      aMesh->RemoveElement(*tmpFaceIt);
9851     MESSAGE("Diff nb of faces");
9852     return SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
9853   }
9854
9855   // ============================================================
9856   // 2. Find nodes to merge:
9857   //              bind a node to remove to a node to put instead
9858   // ============================================================
9859
9860   TNodeNodeMap nReplaceMap; // bind a node to remove to a node to put instead
9861   if ( theFirstNode1 != theFirstNode2 )
9862     nReplaceMap.insert( TNodeNodeMap::value_type( theFirstNode1, theFirstNode2 ));
9863   if ( theSecondNode1 != theSecondNode2 )
9864     nReplaceMap.insert( TNodeNodeMap::value_type( theSecondNode1, theSecondNode2 ));
9865
9866   LinkID_Gen aLinkID_Gen( GetMeshDS() );
9867   set< long > linkIdSet; // links to process
9868   linkIdSet.insert( aLinkID_Gen.GetLinkID( theFirstNode1, theSecondNode1 ));
9869
9870   typedef pair< const SMDS_MeshNode*, const SMDS_MeshNode* > NLink;
9871   list< NLink > linkList[2];
9872   linkList[0].push_back( NLink( theFirstNode1, theSecondNode1 ));
9873   linkList[1].push_back( NLink( theFirstNode2, theSecondNode2 ));
9874   // loop on links in linkList; find faces by links and append links
9875   // of the found faces to linkList
9876   list< NLink >::iterator linkIt[] = { linkList[0].begin(), linkList[1].begin() } ;
9877   for ( ; linkIt[0] != linkList[0].end(); linkIt[0]++, linkIt[1]++ ) {
9878     NLink link[] = { *linkIt[0], *linkIt[1] };
9879     long linkID = aLinkID_Gen.GetLinkID( link[0].first, link[0].second );
9880     if ( linkIdSet.find( linkID ) == linkIdSet.end() )
9881       continue;
9882
9883     // by links, find faces in the face sets,
9884     // and find indices of link nodes in the found faces;
9885     // in a face set, there is only one or no face sharing a link
9886     // ---------------------------------------------------------------
9887
9888     const SMDS_MeshElement* face[] = { 0, 0 };
9889     //const SMDS_MeshNode* faceNodes[ 2 ][ 5 ];
9890     vector<const SMDS_MeshNode*> fnodes1(9);
9891     vector<const SMDS_MeshNode*> fnodes2(9);
9892     //const SMDS_MeshNode* notLinkNodes[ 2 ][ 2 ] = {{ 0, 0 },{ 0, 0 }} ;
9893     vector<const SMDS_MeshNode*> notLinkNodes1(6);
9894     vector<const SMDS_MeshNode*> notLinkNodes2(6);
9895     int iLinkNode[2][2];
9896     for ( iSide = 0; iSide < 2; iSide++ ) { // loop on 2 sides
9897       const SMDS_MeshNode* n1 = link[iSide].first;
9898       const SMDS_MeshNode* n2 = link[iSide].second;
9899       set<const SMDS_MeshElement*> * faceSet = faceSetPtr[ iSide ];
9900       set< const SMDS_MeshElement* > fMap;
9901       for ( int i = 0; i < 2; i++ ) { // loop on 2 nodes of a link
9902         const SMDS_MeshNode* n = i ? n1 : n2; // a node of a link
9903         SMDS_ElemIteratorPtr fIt = n->GetInverseElementIterator(SMDSAbs_Face);
9904         while ( fIt->more() ) { // loop on faces sharing a node
9905           const SMDS_MeshElement* f = fIt->next();
9906           if (faceSet->find( f ) != faceSet->end() && // f is in face set
9907               ! fMap.insert( f ).second ) // f encounters twice
9908           {
9909             if ( face[ iSide ] ) {
9910               MESSAGE( "2 faces per link " );
9911               aResult = iSide ? SEW_BAD_SIDE2_NODES : SEW_BAD_SIDE1_NODES;
9912               break;
9913             }
9914             face[ iSide ] = f;
9915             faceSet->erase( f );
9916             // get face nodes and find ones of a link
9917             iNode = 0;
9918             int nbl = -1;
9919             if(f->IsPoly()) {
9920               if(iSide==0) {
9921                 fnodes1.resize(f->NbNodes()+1);
9922                 notLinkNodes1.resize(f->NbNodes()-2);
9923               }
9924               else {
9925                 fnodes2.resize(f->NbNodes()+1);
9926                 notLinkNodes2.resize(f->NbNodes()-2);
9927               }
9928             }
9929             if(!f->IsQuadratic()) {
9930               SMDS_ElemIteratorPtr nIt = f->nodesIterator();
9931               while ( nIt->more() ) {
9932                 const SMDS_MeshNode* n =
9933                   static_cast<const SMDS_MeshNode*>( nIt->next() );
9934                 if ( n == n1 ) {
9935                   iLinkNode[ iSide ][ 0 ] = iNode;
9936                 }
9937                 else if ( n == n2 ) {
9938                   iLinkNode[ iSide ][ 1 ] = iNode;
9939                 }
9940                 //else if ( notLinkNodes[ iSide ][ 0 ] )
9941                 //  notLinkNodes[ iSide ][ 1 ] = n;
9942                 //else
9943                 //  notLinkNodes[ iSide ][ 0 ] = n;
9944                 else {
9945                   nbl++;
9946                   if(iSide==0)
9947                     notLinkNodes1[nbl] = n;
9948                   //notLinkNodes1.push_back(n);
9949                   else
9950                     notLinkNodes2[nbl] = n;
9951                   //notLinkNodes2.push_back(n);
9952                 }
9953                 //faceNodes[ iSide ][ iNode++ ] = n;
9954                 if(iSide==0) {
9955                   fnodes1[iNode++] = n;
9956                 }
9957                 else {
9958                   fnodes2[iNode++] = n;
9959                 }
9960               }
9961             }
9962             else { // f->IsQuadratic()
9963               const SMDS_VtkFace* F =
9964                 dynamic_cast<const SMDS_VtkFace*>(f);
9965               if (!F) throw SALOME_Exception(LOCALIZED("not an SMDS_VtkFace"));
9966               // use special nodes iterator
9967               SMDS_ElemIteratorPtr anIter = F->interlacedNodesElemIterator();
9968               while ( anIter->more() ) {
9969                 const SMDS_MeshNode* n =
9970                   static_cast<const SMDS_MeshNode*>( anIter->next() );
9971                 if ( n == n1 ) {
9972                   iLinkNode[ iSide ][ 0 ] = iNode;
9973                 }
9974                 else if ( n == n2 ) {
9975                   iLinkNode[ iSide ][ 1 ] = iNode;
9976                 }
9977                 else {
9978                   nbl++;
9979                   if(iSide==0) {
9980                     notLinkNodes1[nbl] = n;
9981                   }
9982                   else {
9983                     notLinkNodes2[nbl] = n;
9984                   }
9985                 }
9986                 if(iSide==0) {
9987                   fnodes1[iNode++] = n;
9988                 }
9989                 else {
9990                   fnodes2[iNode++] = n;
9991                 }
9992               }
9993             }
9994             //faceNodes[ iSide ][ iNode ] = faceNodes[ iSide ][ 0 ];
9995             if(iSide==0) {
9996               fnodes1[iNode] = fnodes1[0];
9997             }
9998             else {
9999               fnodes2[iNode] = fnodes1[0];
10000             }
10001           }
10002         }
10003       }
10004     }
10005
10006     // check similarity of elements of the sides
10007     if (aResult == SEW_OK && (( face[0] && !face[1] ) || ( !face[0] && face[1] ))) {
10008       MESSAGE("Correspondent face not found on side " << ( face[0] ? 1 : 0 ));
10009       if ( nReplaceMap.size() == 2 ) { // faces on input nodes not found
10010         aResult = ( face[0] ? SEW_BAD_SIDE2_NODES : SEW_BAD_SIDE1_NODES );
10011       }
10012       else {
10013         aResult = SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
10014       }
10015       break; // do not return because it s necessary to remove tmp faces
10016     }
10017
10018     // set nodes to merge
10019     // -------------------
10020
10021     if ( face[0] && face[1] )  {
10022       int nbNodes = face[0]->NbNodes();
10023       if ( nbNodes != face[1]->NbNodes() ) {
10024         MESSAGE("Diff nb of face nodes");
10025         aResult = SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
10026         break; // do not return because it s necessary to remove tmp faces
10027       }
10028       bool reverse[] = { false, false }; // order of notLinkNodes of quadrangle
10029       if ( nbNodes == 3 ) {
10030         //nReplaceMap.insert( TNodeNodeMap::value_type
10031         //                   ( notLinkNodes[0][0], notLinkNodes[1][0] ));
10032         nReplaceMap.insert( TNodeNodeMap::value_type
10033                             ( notLinkNodes1[0], notLinkNodes2[0] ));
10034       }
10035       else {
10036         for ( iSide = 0; iSide < 2; iSide++ ) { // loop on 2 sides
10037           // analyse link orientation in faces
10038           int i1 = iLinkNode[ iSide ][ 0 ];
10039           int i2 = iLinkNode[ iSide ][ 1 ];
10040           reverse[ iSide ] = Abs( i1 - i2 ) == 1 ? i1 > i2 : i2 > i1;
10041           // if notLinkNodes are the first and the last ones, then
10042           // their order does not correspond to the link orientation
10043           if (( i1 == 1 && i2 == 2 ) ||
10044               ( i1 == 2 && i2 == 1 ))
10045             reverse[ iSide ] = !reverse[ iSide ];
10046         }
10047         if ( reverse[0] == reverse[1] ) {
10048           //nReplaceMap.insert( TNodeNodeMap::value_type
10049           //                   ( notLinkNodes[0][0], notLinkNodes[1][0] ));
10050           //nReplaceMap.insert( TNodeNodeMap::value_type
10051           //                   ( notLinkNodes[0][1], notLinkNodes[1][1] ));
10052           for(int nn=0; nn<nbNodes-2; nn++) {
10053             nReplaceMap.insert( TNodeNodeMap::value_type
10054                                 ( notLinkNodes1[nn], notLinkNodes2[nn] ));
10055           }
10056         }
10057         else {
10058           //nReplaceMap.insert( TNodeNodeMap::value_type
10059           //                   ( notLinkNodes[0][0], notLinkNodes[1][1] ));
10060           //nReplaceMap.insert( TNodeNodeMap::value_type
10061           //                   ( notLinkNodes[0][1], notLinkNodes[1][0] ));
10062           for(int nn=0; nn<nbNodes-2; nn++) {
10063             nReplaceMap.insert( TNodeNodeMap::value_type
10064                                 ( notLinkNodes1[nn], notLinkNodes2[nbNodes-3-nn] ));
10065           }
10066         }
10067       }
10068
10069       // add other links of the faces to linkList
10070       // -----------------------------------------
10071
10072       //const SMDS_MeshNode** nodes = faceNodes[ 0 ];
10073       for ( iNode = 0; iNode < nbNodes; iNode++ )  {
10074         //linkID = aLinkID_Gen.GetLinkID( nodes[iNode], nodes[iNode+1] );
10075         linkID = aLinkID_Gen.GetLinkID( fnodes1[iNode], fnodes1[iNode+1] );
10076         pair< set<long>::iterator, bool > iter_isnew = linkIdSet.insert( linkID );
10077         if ( !iter_isnew.second ) { // already in a set: no need to process
10078           linkIdSet.erase( iter_isnew.first );
10079         }
10080         else // new in set == encountered for the first time: add
10081         {
10082           //const SMDS_MeshNode* n1 = nodes[ iNode ];
10083           //const SMDS_MeshNode* n2 = nodes[ iNode + 1];
10084           const SMDS_MeshNode* n1 = fnodes1[ iNode ];
10085           const SMDS_MeshNode* n2 = fnodes1[ iNode + 1];
10086           linkList[0].push_back ( NLink( n1, n2 ));
10087           linkList[1].push_back ( NLink( nReplaceMap[n1], nReplaceMap[n2] ));
10088         }
10089       }
10090     } // 2 faces found
10091   } // loop on link lists
10092
10093   if ( aResult == SEW_OK &&
10094        ( linkIt[0] != linkList[0].end() ||
10095          !faceSetPtr[0]->empty() || !faceSetPtr[1]->empty() )) {
10096     MESSAGE( (linkIt[0] != linkList[0].end()) <<" "<< (faceSetPtr[0]->empty()) <<
10097              " " << (faceSetPtr[1]->empty()));
10098     aResult = SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
10099   }
10100
10101   // ====================================================================
10102   // 3. Replace nodes in elements of the side 1 and remove replaced nodes
10103   // ====================================================================
10104
10105   // delete temporary faces: they are in reverseElements of actual nodes
10106 //  SMDS_FaceIteratorPtr tmpFaceIt = aTmpFacesMesh.facesIterator();
10107 //  while ( tmpFaceIt->more() )
10108 //    aTmpFacesMesh.RemoveElement( tmpFaceIt->next() );
10109 //  list<const SMDS_MeshElement* >::iterator tmpFaceIt = tempFaceList.begin();
10110 //  for (; tmpFaceIt !=tempFaceList.end(); ++tmpFaceIt)
10111 //    aMesh->RemoveElement(*tmpFaceIt);
10112
10113   if ( aResult != SEW_OK)
10114     return aResult;
10115
10116   list< int > nodeIDsToRemove/*, elemIDsToRemove*/;
10117   // loop on nodes replacement map
10118   TNodeNodeMap::iterator nReplaceMapIt = nReplaceMap.begin(), nnIt;
10119   for ( ; nReplaceMapIt != nReplaceMap.end(); nReplaceMapIt++ )
10120     if ( (*nReplaceMapIt).first != (*nReplaceMapIt).second ) {
10121       const SMDS_MeshNode* nToRemove = (*nReplaceMapIt).first;
10122       nodeIDsToRemove.push_back( nToRemove->GetID() );
10123       // loop on elements sharing nToRemove
10124       SMDS_ElemIteratorPtr invElemIt = nToRemove->GetInverseElementIterator();
10125       while ( invElemIt->more() ) {
10126         const SMDS_MeshElement* e = invElemIt->next();
10127         // get a new suite of nodes: make replacement
10128         int nbReplaced = 0, i = 0, nbNodes = e->NbNodes();
10129         vector< const SMDS_MeshNode*> nodes( nbNodes );
10130         SMDS_ElemIteratorPtr nIt = e->nodesIterator();
10131         while ( nIt->more() ) {
10132           const SMDS_MeshNode* n =
10133             static_cast<const SMDS_MeshNode*>( nIt->next() );
10134           nnIt = nReplaceMap.find( n );
10135           if ( nnIt != nReplaceMap.end() ) {
10136             nbReplaced++;
10137             n = (*nnIt).second;
10138           }
10139           nodes[ i++ ] = n;
10140         }
10141         //       if ( nbReplaced == nbNodes && e->GetType() == SMDSAbs_Face )
10142         //         elemIDsToRemove.push_back( e->GetID() );
10143         //       else
10144         if ( nbReplaced )
10145           {
10146             SMDSAbs_ElementType etyp = e->GetType();
10147             SMDS_MeshElement* newElem = this->AddElement(nodes, etyp, false);
10148             if (newElem)
10149               {
10150                 myLastCreatedElems.Append(newElem);
10151                 AddToSameGroups(newElem, e, aMesh);
10152                 int aShapeId = e->getshapeId();
10153                 if ( aShapeId )
10154                   {
10155                     aMesh->SetMeshElementOnShape( newElem, aShapeId );
10156                   }
10157               }
10158             aMesh->RemoveElement(e);
10159           }
10160       }
10161     }
10162
10163   Remove( nodeIDsToRemove, true );
10164
10165   return aResult;
10166 }
10167
10168 //================================================================================
10169 /*!
10170  * \brief Find corresponding nodes in two sets of faces
10171  * \param theSide1 - first face set
10172  * \param theSide2 - second first face
10173  * \param theFirstNode1 - a boundary node of set 1
10174  * \param theFirstNode2 - a node of set 2 corresponding to theFirstNode1
10175  * \param theSecondNode1 - a boundary node of set 1 linked with theFirstNode1
10176  * \param theSecondNode2 - a node of set 2 corresponding to theSecondNode1
10177  * \param nReplaceMap - output map of corresponding nodes
10178  * \return bool  - is a success or not
10179  */
10180 //================================================================================
10181
10182 #ifdef _DEBUG_
10183 //#define DEBUG_MATCHING_NODES
10184 #endif
10185
10186 SMESH_MeshEditor::Sew_Error
10187 SMESH_MeshEditor::FindMatchingNodes(set<const SMDS_MeshElement*>& theSide1,
10188                                     set<const SMDS_MeshElement*>& theSide2,
10189                                     const SMDS_MeshNode*          theFirstNode1,
10190                                     const SMDS_MeshNode*          theFirstNode2,
10191                                     const SMDS_MeshNode*          theSecondNode1,
10192                                     const SMDS_MeshNode*          theSecondNode2,
10193                                     TNodeNodeMap &                nReplaceMap)
10194 {
10195   set<const SMDS_MeshElement*> * faceSetPtr[] = { &theSide1, &theSide2 };
10196
10197   nReplaceMap.clear();
10198   if ( theFirstNode1 != theFirstNode2 )
10199     nReplaceMap.insert( make_pair( theFirstNode1, theFirstNode2 ));
10200   if ( theSecondNode1 != theSecondNode2 )
10201     nReplaceMap.insert( make_pair( theSecondNode1, theSecondNode2 ));
10202
10203   set< SMESH_TLink > linkSet; // set of nodes where order of nodes is ignored
10204   linkSet.insert( SMESH_TLink( theFirstNode1, theSecondNode1 ));
10205
10206   list< NLink > linkList[2];
10207   linkList[0].push_back( NLink( theFirstNode1, theSecondNode1 ));
10208   linkList[1].push_back( NLink( theFirstNode2, theSecondNode2 ));
10209
10210   // loop on links in linkList; find faces by links and append links
10211   // of the found faces to linkList
10212   list< NLink >::iterator linkIt[] = { linkList[0].begin(), linkList[1].begin() } ;
10213   for ( ; linkIt[0] != linkList[0].end(); linkIt[0]++, linkIt[1]++ ) {
10214     NLink link[] = { *linkIt[0], *linkIt[1] };
10215     if ( linkSet.find( link[0] ) == linkSet.end() )
10216       continue;
10217
10218     // by links, find faces in the face sets,
10219     // and find indices of link nodes in the found faces;
10220     // in a face set, there is only one or no face sharing a link
10221     // ---------------------------------------------------------------
10222
10223     const SMDS_MeshElement* face[] = { 0, 0 };
10224     list<const SMDS_MeshNode*> notLinkNodes[2];
10225     //bool reverse[] = { false, false }; // order of notLinkNodes
10226     int nbNodes[2];
10227     for ( int iSide = 0; iSide < 2; iSide++ ) // loop on 2 sides
10228     {
10229       const SMDS_MeshNode* n1 = link[iSide].first;
10230       const SMDS_MeshNode* n2 = link[iSide].second;
10231       set<const SMDS_MeshElement*> * faceSet = faceSetPtr[ iSide ];
10232       set< const SMDS_MeshElement* > facesOfNode1;
10233       for ( int iNode = 0; iNode < 2; iNode++ ) // loop on 2 nodes of a link
10234       {
10235         // during a loop of the first node, we find all faces around n1,
10236         // during a loop of the second node, we find one face sharing both n1 and n2
10237         const SMDS_MeshNode* n = iNode ? n1 : n2; // a node of a link
10238         SMDS_ElemIteratorPtr fIt = n->GetInverseElementIterator(SMDSAbs_Face);
10239         while ( fIt->more() ) { // loop on faces sharing a node
10240           const SMDS_MeshElement* f = fIt->next();
10241           if (faceSet->find( f ) != faceSet->end() && // f is in face set
10242               ! facesOfNode1.insert( f ).second ) // f encounters twice
10243           {
10244             if ( face[ iSide ] ) {
10245               MESSAGE( "2 faces per link " );
10246               return ( iSide ? SEW_BAD_SIDE2_NODES : SEW_BAD_SIDE1_NODES );
10247             }
10248             face[ iSide ] = f;
10249             faceSet->erase( f );
10250
10251             // get not link nodes
10252             int nbN = f->NbNodes();
10253             if ( f->IsQuadratic() )
10254               nbN /= 2;
10255             nbNodes[ iSide ] = nbN;
10256             list< const SMDS_MeshNode* > & nodes = notLinkNodes[ iSide ];
10257             int i1 = f->GetNodeIndex( n1 );
10258             int i2 = f->GetNodeIndex( n2 );
10259             int iEnd = nbN, iBeg = -1, iDelta = 1;
10260             bool reverse = ( Abs( i1 - i2 ) == 1 ? i1 > i2 : i2 > i1 );
10261             if ( reverse ) {
10262               std::swap( iEnd, iBeg ); iDelta = -1;
10263             }
10264             int i = i2;
10265             while ( true ) {
10266               i += iDelta;
10267               if ( i == iEnd ) i = iBeg + iDelta;
10268               if ( i == i1 ) break;
10269               nodes.push_back ( f->GetNode( i ) );
10270             }
10271           }
10272         }
10273       }
10274     }
10275     // check similarity of elements of the sides
10276     if (( face[0] && !face[1] ) || ( !face[0] && face[1] )) {
10277       MESSAGE("Correspondent face not found on side " << ( face[0] ? 1 : 0 ));
10278       if ( nReplaceMap.size() == 2 ) { // faces on input nodes not found
10279         return ( face[0] ? SEW_BAD_SIDE2_NODES : SEW_BAD_SIDE1_NODES );
10280       }
10281       else {
10282         return SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
10283       }
10284     }
10285
10286     // set nodes to merge
10287     // -------------------
10288
10289     if ( face[0] && face[1] )  {
10290       if ( nbNodes[0] != nbNodes[1] ) {
10291         MESSAGE("Diff nb of face nodes");
10292         return SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
10293       }
10294 #ifdef DEBUG_MATCHING_NODES
10295       MESSAGE ( " Link 1: " << link[0].first->GetID() <<" "<< link[0].second->GetID()
10296                 << " F 1: " << face[0] << "| Link 2: " << link[1].first->GetID() <<" "
10297                 << link[1].second->GetID() << " F 2: " << face[1] << " | Bind: " ) ;
10298 #endif
10299       int nbN = nbNodes[0];
10300       {
10301         list<const SMDS_MeshNode*>::iterator n1 = notLinkNodes[0].begin();
10302         list<const SMDS_MeshNode*>::iterator n2 = notLinkNodes[1].begin();
10303         for ( int i = 0 ; i < nbN - 2; ++i ) {
10304 #ifdef DEBUG_MATCHING_NODES
10305           MESSAGE ( (*n1)->GetID() << " to " << (*n2)->GetID() );
10306 #endif
10307           nReplaceMap.insert( make_pair( *(n1++), *(n2++) ));
10308         }
10309       }
10310
10311       // add other links of the face 1 to linkList
10312       // -----------------------------------------
10313
10314       const SMDS_MeshElement* f0 = face[0];
10315       const SMDS_MeshNode* n1 = f0->GetNode( nbN - 1 );
10316       for ( int i = 0; i < nbN; i++ )
10317       {
10318         const SMDS_MeshNode* n2 = f0->GetNode( i );
10319         pair< set< SMESH_TLink >::iterator, bool > iter_isnew =
10320           linkSet.insert( SMESH_TLink( n1, n2 ));
10321         if ( !iter_isnew.second ) { // already in a set: no need to process
10322           linkSet.erase( iter_isnew.first );
10323         }
10324         else // new in set == encountered for the first time: add
10325         {
10326 #ifdef DEBUG_MATCHING_NODES
10327           MESSAGE ( "Add link 1: " << n1->GetID() << " " << n2->GetID() << " "
10328                     << " | link 2: " << nReplaceMap[n1]->GetID() << " " << nReplaceMap[n2]->GetID() << " " );
10329 #endif
10330           linkList[0].push_back ( NLink( n1, n2 ));
10331           linkList[1].push_back ( NLink( nReplaceMap[n1], nReplaceMap[n2] ));
10332         }
10333         n1 = n2;
10334       }
10335     } // 2 faces found
10336   } // loop on link lists
10337
10338   return SEW_OK;
10339 }
10340
10341 //================================================================================
10342 /*!
10343   \brief Creates a hole in a mesh by doubling the nodes of some particular elements
10344   \param theElems - the list of elements (edges or faces) to be replicated
10345   The nodes for duplication could be found from these elements
10346   \param theNodesNot - list of nodes to NOT replicate
10347   \param theAffectedElems - the list of elements (cells and edges) to which the 
10348   replicated nodes should be associated to.
10349   \return TRUE if operation has been completed successfully, FALSE otherwise
10350 */
10351 //================================================================================
10352
10353 bool SMESH_MeshEditor::DoubleNodes( const TIDSortedElemSet& theElems,
10354                                     const TIDSortedElemSet& theNodesNot,
10355                                     const TIDSortedElemSet& theAffectedElems )
10356 {
10357   myLastCreatedElems.Clear();
10358   myLastCreatedNodes.Clear();
10359
10360   if ( theElems.size() == 0 )
10361     return false;
10362
10363   SMESHDS_Mesh* aMeshDS = GetMeshDS();
10364   if ( !aMeshDS )
10365     return false;
10366
10367   bool res = false;
10368   std::map< const SMDS_MeshNode*, const SMDS_MeshNode* > anOldNodeToNewNode;
10369   // duplicate elements and nodes
10370   res = doubleNodes( aMeshDS, theElems, theNodesNot, anOldNodeToNewNode, true );
10371   // replce nodes by duplications
10372   res = doubleNodes( aMeshDS, theAffectedElems, theNodesNot, anOldNodeToNewNode, false );
10373   return res;
10374 }
10375
10376 //================================================================================
10377 /*!
10378   \brief Creates a hole in a mesh by doubling the nodes of some particular elements
10379   \param theMeshDS - mesh instance
10380   \param theElems - the elements replicated or modified (nodes should be changed)
10381   \param theNodesNot - nodes to NOT replicate
10382   \param theNodeNodeMap - relation of old node to new created node
10383   \param theIsDoubleElem - flag os to replicate element or modify
10384   \return TRUE if operation has been completed successfully, FALSE otherwise
10385 */
10386 //================================================================================
10387
10388 bool SMESH_MeshEditor::doubleNodes( SMESHDS_Mesh*     theMeshDS,
10389                                     const TIDSortedElemSet& theElems,
10390                                     const TIDSortedElemSet& theNodesNot,
10391                                     std::map< const SMDS_MeshNode*,
10392                                     const SMDS_MeshNode* >& theNodeNodeMap,
10393                                     const bool theIsDoubleElem )
10394 {
10395   MESSAGE("doubleNodes");
10396   // iterate on through element and duplicate them (by nodes duplication)
10397   bool res = false;
10398   TIDSortedElemSet::const_iterator elemItr = theElems.begin();
10399   for ( ;  elemItr != theElems.end(); ++elemItr )
10400   {
10401     const SMDS_MeshElement* anElem = *elemItr;
10402     if (!anElem)
10403       continue;
10404
10405     bool isDuplicate = false;
10406     // duplicate nodes to duplicate element
10407     std::vector<const SMDS_MeshNode*> newNodes( anElem->NbNodes() );
10408     SMDS_ElemIteratorPtr anIter = anElem->nodesIterator();
10409     int ind = 0;
10410     while ( anIter->more() ) 
10411     { 
10412
10413       SMDS_MeshNode* aCurrNode = (SMDS_MeshNode*)anIter->next();
10414       SMDS_MeshNode* aNewNode = aCurrNode;
10415       if ( theNodeNodeMap.find( aCurrNode ) != theNodeNodeMap.end() )
10416         aNewNode = (SMDS_MeshNode*)theNodeNodeMap[ aCurrNode ];
10417       else if ( theIsDoubleElem && theNodesNot.find( aCurrNode ) == theNodesNot.end() )
10418       {
10419         // duplicate node
10420         aNewNode = theMeshDS->AddNode( aCurrNode->X(), aCurrNode->Y(), aCurrNode->Z() );
10421         theNodeNodeMap[ aCurrNode ] = aNewNode;
10422         myLastCreatedNodes.Append( aNewNode );
10423       }
10424       isDuplicate |= (aCurrNode != aNewNode);
10425       newNodes[ ind++ ] = aNewNode;
10426     }
10427     if ( !isDuplicate )
10428       continue;
10429
10430     if ( theIsDoubleElem )
10431       AddElement(newNodes, anElem->GetType(), anElem->IsPoly());
10432     else
10433       {
10434       MESSAGE("ChangeElementNodes");
10435       theMeshDS->ChangeElementNodes( anElem, &newNodes[ 0 ], anElem->NbNodes() );
10436       }
10437     res = true;
10438   }
10439   return res;
10440 }
10441
10442 //================================================================================
10443 /*!
10444   \brief Creates a hole in a mesh by doubling the nodes of some particular elements
10445   \param theNodes - identifiers of nodes to be doubled
10446   \param theModifiedElems - identifiers of elements to be updated by the new (doubled) 
10447          nodes. If list of element identifiers is empty then nodes are doubled but 
10448          they not assigned to elements
10449   \return TRUE if operation has been completed successfully, FALSE otherwise
10450 */
10451 //================================================================================
10452
10453 bool SMESH_MeshEditor::DoubleNodes( const std::list< int >& theListOfNodes, 
10454                                     const std::list< int >& theListOfModifiedElems )
10455 {
10456   MESSAGE("DoubleNodes");
10457   myLastCreatedElems.Clear();
10458   myLastCreatedNodes.Clear();
10459
10460   if ( theListOfNodes.size() == 0 )
10461     return false;
10462
10463   SMESHDS_Mesh* aMeshDS = GetMeshDS();
10464   if ( !aMeshDS )
10465     return false;
10466
10467   // iterate through nodes and duplicate them
10468
10469   std::map< const SMDS_MeshNode*, const SMDS_MeshNode* > anOldNodeToNewNode;
10470
10471   std::list< int >::const_iterator aNodeIter;
10472   for ( aNodeIter = theListOfNodes.begin(); aNodeIter != theListOfNodes.end(); ++aNodeIter )
10473   {
10474     int aCurr = *aNodeIter;
10475     SMDS_MeshNode* aNode = (SMDS_MeshNode*)aMeshDS->FindNode( aCurr );
10476     if ( !aNode )
10477       continue;
10478
10479     // duplicate node
10480
10481     const SMDS_MeshNode* aNewNode = aMeshDS->AddNode( aNode->X(), aNode->Y(), aNode->Z() );
10482     if ( aNewNode )
10483     {
10484       anOldNodeToNewNode[ aNode ] = aNewNode;
10485       myLastCreatedNodes.Append( aNewNode );
10486     }
10487   }
10488
10489   // Create map of new nodes for modified elements
10490
10491   std::map< SMDS_MeshElement*, vector<const SMDS_MeshNode*> > anElemToNodes;
10492
10493   std::list< int >::const_iterator anElemIter;
10494   for ( anElemIter = theListOfModifiedElems.begin(); 
10495         anElemIter != theListOfModifiedElems.end(); ++anElemIter )
10496   {
10497     int aCurr = *anElemIter;
10498     SMDS_MeshElement* anElem = (SMDS_MeshElement*)aMeshDS->FindElement( aCurr );
10499     if ( !anElem )
10500       continue;
10501
10502     vector<const SMDS_MeshNode*> aNodeArr( anElem->NbNodes() );
10503
10504     SMDS_ElemIteratorPtr anIter = anElem->nodesIterator();
10505     int ind = 0;
10506     while ( anIter->more() ) 
10507     { 
10508       SMDS_MeshNode* aCurrNode = (SMDS_MeshNode*)anIter->next();
10509       if ( aCurr && anOldNodeToNewNode.find( aCurrNode ) != anOldNodeToNewNode.end() )
10510       {
10511         const SMDS_MeshNode* aNewNode = anOldNodeToNewNode[ aCurrNode ];
10512         aNodeArr[ ind++ ] = aNewNode;
10513       }
10514       else
10515         aNodeArr[ ind++ ] = aCurrNode;
10516     }
10517     anElemToNodes[ anElem ] = aNodeArr;
10518   }
10519
10520   // Change nodes of elements  
10521
10522   std::map< SMDS_MeshElement*, vector<const SMDS_MeshNode*> >::iterator
10523     anElemToNodesIter = anElemToNodes.begin();
10524   for ( ; anElemToNodesIter != anElemToNodes.end(); ++anElemToNodesIter )
10525   {
10526     const SMDS_MeshElement* anElem = anElemToNodesIter->first;
10527     vector<const SMDS_MeshNode*> aNodeArr = anElemToNodesIter->second;
10528     if ( anElem )
10529       {
10530       MESSAGE("ChangeElementNodes");
10531       aMeshDS->ChangeElementNodes( anElem, &aNodeArr[ 0 ], anElem->NbNodes() );
10532       }
10533   }
10534
10535   return true;
10536 }
10537
10538 namespace {
10539
10540   //================================================================================
10541   /*!
10542   \brief Check if element located inside shape
10543   \return TRUE if IN or ON shape, FALSE otherwise
10544   */
10545   //================================================================================
10546
10547   template<class Classifier>
10548   bool isInside(const SMDS_MeshElement* theElem,
10549                 Classifier&             theClassifier,
10550                 const double            theTol)
10551   {
10552     gp_XYZ centerXYZ (0, 0, 0);
10553     SMDS_ElemIteratorPtr aNodeItr = theElem->nodesIterator();
10554     while (aNodeItr->more())
10555       centerXYZ += SMESH_TNodeXYZ(cast2Node( aNodeItr->next()));
10556
10557     gp_Pnt aPnt = centerXYZ / theElem->NbNodes();
10558     theClassifier.Perform(aPnt, theTol);
10559     TopAbs_State aState = theClassifier.State();
10560     return (aState == TopAbs_IN || aState == TopAbs_ON );
10561   }
10562
10563   //================================================================================
10564   /*!
10565    * \brief Classifier of the 3D point on the TopoDS_Face
10566    *        with interaface suitable for isInside()
10567    */
10568   //================================================================================
10569
10570   struct _FaceClassifier
10571   {
10572     Extrema_ExtPS       _extremum;
10573     BRepAdaptor_Surface _surface;
10574     TopAbs_State        _state;
10575
10576     _FaceClassifier(const TopoDS_Face& face):_extremum(),_surface(face),_state(TopAbs_OUT)
10577     {
10578       _extremum.Initialize( _surface,
10579                             _surface.FirstUParameter(), _surface.LastUParameter(),
10580                             _surface.FirstVParameter(), _surface.LastVParameter(),
10581                             _surface.Tolerance(), _surface.Tolerance() );
10582     }
10583     void Perform(const gp_Pnt& aPnt, double theTol)
10584     {
10585       _state = TopAbs_OUT;
10586       _extremum.Perform(aPnt);
10587       if ( _extremum.IsDone() )
10588         for ( int iSol = 1; iSol <= _extremum.NbExt() && _state == TopAbs_OUT; ++iSol)
10589 #if OCC_VERSION_LARGE > 0x06040000 // Porting to OCCT6.5.1
10590           _state = ( _extremum.SquareDistance(iSol) <= theTol ? TopAbs_IN : TopAbs_OUT );
10591 #else
10592           _state = ( _extremum.Value(iSol) <= theTol ? TopAbs_IN : TopAbs_OUT );
10593 #endif
10594     }
10595     TopAbs_State State() const
10596     {
10597       return _state;
10598     }
10599   };
10600 }
10601
10602 //================================================================================
10603 /*!
10604   \brief Creates a hole in a mesh by doubling the nodes of some particular elements
10605   \param theElems - group of of elements (edges or faces) to be replicated
10606   \param theNodesNot - group of nodes not to replicate
10607   \param theShape - shape to detect affected elements (element which geometric center
10608   located on or inside shape).
10609   The replicated nodes should be associated to affected elements.
10610   \return TRUE if operation has been completed successfully, FALSE otherwise
10611 */
10612 //================================================================================
10613
10614 bool SMESH_MeshEditor::DoubleNodesInRegion( const TIDSortedElemSet& theElems,
10615                                             const TIDSortedElemSet& theNodesNot,
10616                                             const TopoDS_Shape&     theShape )
10617 {
10618   if ( theShape.IsNull() )
10619     return false;
10620
10621   const double aTol = Precision::Confusion();
10622   auto_ptr< BRepClass3d_SolidClassifier> bsc3d;
10623   auto_ptr<_FaceClassifier>              aFaceClassifier;
10624   if ( theShape.ShapeType() == TopAbs_SOLID )
10625   {
10626     bsc3d.reset( new BRepClass3d_SolidClassifier(theShape));;
10627     bsc3d->PerformInfinitePoint(aTol);
10628   }
10629   else if (theShape.ShapeType() == TopAbs_FACE )
10630   {
10631     aFaceClassifier.reset( new _FaceClassifier(TopoDS::Face(theShape)));
10632   }
10633
10634   // iterates on indicated elements and get elements by back references from their nodes
10635   TIDSortedElemSet anAffected;
10636   TIDSortedElemSet::const_iterator elemItr = theElems.begin();
10637   for ( ;  elemItr != theElems.end(); ++elemItr )
10638   {
10639     SMDS_MeshElement* anElem = (SMDS_MeshElement*)*elemItr;
10640     if (!anElem)
10641       continue;
10642
10643     SMDS_ElemIteratorPtr nodeItr = anElem->nodesIterator();
10644     while ( nodeItr->more() )
10645     {
10646       const SMDS_MeshNode* aNode = cast2Node(nodeItr->next());
10647       if ( !aNode || theNodesNot.find(aNode) != theNodesNot.end() )
10648         continue;
10649       SMDS_ElemIteratorPtr backElemItr = aNode->GetInverseElementIterator();
10650       while ( backElemItr->more() )
10651       {
10652         const SMDS_MeshElement* curElem = backElemItr->next();
10653         if ( curElem && theElems.find(curElem) == theElems.end() &&
10654              ( bsc3d.get() ?
10655                isInside( curElem, *bsc3d, aTol ) :
10656                isInside( curElem, *aFaceClassifier, aTol )))
10657           anAffected.insert( curElem );
10658       }
10659     }
10660   }
10661   return DoubleNodes( theElems, theNodesNot, anAffected );
10662 }
10663
10664 /*!
10665  *  \brief compute an oriented angle between two planes defined by four points.
10666  *  The vector (p0,p1) defines the intersection of the 2 planes (p0,p1,g1) and (p0,p1,g2)
10667  *  @param p0 base of the rotation axe
10668  *  @param p1 extremity of the rotation axe
10669  *  @param g1 belongs to the first plane
10670  *  @param g2 belongs to the second plane
10671  */
10672 double SMESH_MeshEditor::OrientedAngle(const gp_Pnt& p0, const gp_Pnt& p1, const gp_Pnt& g1, const gp_Pnt& g2)
10673 {
10674 //  MESSAGE("    p0: " << p0.X() << " " << p0.Y() << " " << p0.Z());
10675 //  MESSAGE("    p1: " << p1.X() << " " << p1.Y() << " " << p1.Z());
10676 //  MESSAGE("    g1: " << g1.X() << " " << g1.Y() << " " << g1.Z());
10677 //  MESSAGE("    g2: " << g2.X() << " " << g2.Y() << " " << g2.Z());
10678   gp_Vec vref(p0, p1);
10679   gp_Vec v1(p0, g1);
10680   gp_Vec v2(p0, g2);
10681   gp_Vec n1 = vref.Crossed(v1);
10682   gp_Vec n2 = vref.Crossed(v2);
10683   return n2.AngleWithRef(n1, vref);
10684 }
10685
10686 /*!
10687  * \brief Double nodes on shared faces between groups of volumes and create flat elements on demand.
10688  * The list of groups must describe a partition of the mesh volumes.
10689  * The nodes of the internal faces at the boundaries of the groups are doubled.
10690  * In option, the internal faces are replaced by flat elements.
10691  * Triangles are transformed in prisms, and quadrangles in hexahedrons.
10692  * The flat elements are stored in groups of volumes.
10693  * @param theElems - list of groups of volumes, where a group of volume is a set of
10694  * SMDS_MeshElements sorted by Id.
10695  * @param createJointElems - if TRUE, create the elements
10696  * @return TRUE if operation has been completed successfully, FALSE otherwise
10697  */
10698 bool SMESH_MeshEditor::DoubleNodesOnGroupBoundaries( const std::vector<TIDSortedElemSet>& theElems,
10699                                                      bool createJointElems)
10700 {
10701   MESSAGE("----------------------------------------------");
10702   MESSAGE("SMESH_MeshEditor::doubleNodesOnGroupBoundaries");
10703   MESSAGE("----------------------------------------------");
10704
10705   SMESHDS_Mesh *meshDS = this->myMesh->GetMeshDS();
10706   meshDS->BuildDownWardConnectivity(true);
10707   CHRONO(50);
10708   SMDS_UnstructuredGrid *grid = meshDS->getGrid();
10709
10710   // --- build the list of faces shared by 2 domains (group of elements), with their domain and volume indexes
10711   //     build the list of cells with only a node or an edge on the border, with their domain and volume indexes
10712   //     build the list of nodes shared by 2 or more domains, with their domain indexes
10713
10714   std::map<DownIdType, std::map<int,int>, DownIdCompare> faceDomains; // face --> (id domain --> id volume)
10715   std::map<int,int>celldom; // cell vtkId --> domain
10716   std::map<DownIdType, std::map<int,int>, DownIdCompare> cellDomains;  // oldNode --> (id domain --> id cell)
10717   std::map<int, std::map<int,int> > nodeDomains; // oldId -->  (domainId --> newId)
10718   faceDomains.clear();
10719   celldom.clear();
10720   cellDomains.clear();
10721   nodeDomains.clear();
10722   std::map<int,int> emptyMap;
10723   std::set<int> emptySet;
10724   emptyMap.clear();
10725
10726   for (int idom = 0; idom < theElems.size(); idom++)
10727     {
10728
10729       // --- build a map (face to duplicate --> volume to modify)
10730       //     with all the faces shared by 2 domains (group of elements)
10731       //     and corresponding volume of this domain, for each shared face.
10732       //     a volume has a face shared by 2 domains if it has a neighbor which is not in is domain.
10733
10734       const TIDSortedElemSet& domain = theElems[idom];
10735       TIDSortedElemSet::const_iterator elemItr = domain.begin();
10736       for (; elemItr != domain.end(); ++elemItr)
10737         {
10738           SMDS_MeshElement* anElem = (SMDS_MeshElement*) *elemItr;
10739           if (!anElem)
10740             continue;
10741           int vtkId = anElem->getVtkId();
10742           int neighborsVtkIds[NBMAXNEIGHBORS];
10743           int downIds[NBMAXNEIGHBORS];
10744           unsigned char downTypes[NBMAXNEIGHBORS];
10745           int nbNeighbors = grid->GetNeighbors(neighborsVtkIds, downIds, downTypes, vtkId);
10746           for (int n = 0; n < nbNeighbors; n++)
10747             {
10748               int smdsId = meshDS->fromVtkToSmds(neighborsVtkIds[n]);
10749               const SMDS_MeshElement* elem = meshDS->FindElement(smdsId);
10750               if (! domain.count(elem)) // neighbor is in another domain : face is shared
10751                 {
10752                   DownIdType face(downIds[n], downTypes[n]);
10753                   if (!faceDomains.count(face))
10754                     faceDomains[face] = emptyMap; // create an empty entry for face
10755                   if (!faceDomains[face].count(idom))
10756                     {
10757                       faceDomains[face][idom] = vtkId; // volume associated to face in this domain
10758                       celldom[vtkId] = idom;
10759                     }
10760                 }
10761             }
10762         }
10763     }
10764
10765   //MESSAGE("Number of shared faces " << faceDomains.size());
10766   std::map<DownIdType, std::map<int, int>, DownIdCompare>::iterator itface;
10767
10768   // --- explore the shared faces domain by domain,
10769   //     explore the nodes of the face and see if they belong to a cell in the domain,
10770   //     which has only a node or an edge on the border (not a shared face)
10771
10772   for (int idomain = 0; idomain < theElems.size(); idomain++)
10773     {
10774       const TIDSortedElemSet& domain = theElems[idomain];
10775       itface = faceDomains.begin();
10776       for (; itface != faceDomains.end(); ++itface)
10777         {
10778           std::map<int, int> domvol = itface->second;
10779           if (!domvol.count(idomain))
10780             continue;
10781           DownIdType face = itface->first;
10782           //MESSAGE(" --- face " << face.cellId);
10783           std::set<int> oldNodes;
10784           oldNodes.clear();
10785           grid->GetNodeIds(oldNodes, face.cellId, face.cellType);
10786           std::set<int>::iterator itn = oldNodes.begin();
10787           for (; itn != oldNodes.end(); ++itn)
10788             {
10789               int oldId = *itn;
10790               //MESSAGE("     node " << oldId);
10791               std::set<int> cells;
10792               cells.clear();
10793               vtkCellLinks::Link l = grid->GetCellLinks()->GetLink(oldId);
10794               for (int i=0; i<l.ncells; i++)
10795                 {
10796                   int vtkId = l.cells[i];
10797                   const SMDS_MeshElement* anElem = GetMeshDS()->FindElement(GetMeshDS()->fromVtkToSmds(vtkId));
10798                   if (!domain.count(anElem))
10799                     continue;
10800                   int vtkType = grid->GetCellType(vtkId);
10801                   int downId = grid->CellIdToDownId(vtkId);
10802                   if (downId < 0)
10803                     {
10804                       MESSAGE("doubleNodesOnGroupBoundaries: internal algorithm problem");
10805                       continue; // not OK at this stage of the algorithm:
10806                                 //no cells created after BuildDownWardConnectivity
10807                     }
10808                   DownIdType aCell(downId, vtkType);
10809                   if (celldom.count(vtkId))
10810                     continue;
10811                   cellDomains[aCell][idomain] = vtkId;
10812                   celldom[vtkId] = idomain;
10813                 }
10814             }
10815         }
10816     }
10817
10818   // --- explore the shared faces domain by domain, to duplicate the nodes in a coherent way
10819   //     for each shared face, get the nodes
10820   //     for each node, for each domain of the face, create a clone of the node
10821
10822   // --- edges at the intersection of 3 or 4 domains, with the order of domains to build
10823   //     junction elements of type prism or hexa. the key is the pair of nodesId (lower first)
10824   //     the value is the ordered domain ids. (more than 4 domains not taken into account)
10825
10826   std::map<std::vector<int>, std::vector<int> > edgesMultiDomains; // nodes of edge --> ordered domains
10827   std::map<int, std::vector<int> > mutipleNodes; // nodes muti domains with domain order
10828
10829   for (int idomain = 0; idomain < theElems.size(); idomain++)
10830     {
10831       itface = faceDomains.begin();
10832       for (; itface != faceDomains.end(); ++itface)
10833         {
10834           std::map<int, int> domvol = itface->second;
10835           if (!domvol.count(idomain))
10836             continue;
10837           DownIdType face = itface->first;
10838           //MESSAGE(" --- face " << face.cellId);
10839           std::set<int> oldNodes;
10840           oldNodes.clear();
10841           grid->GetNodeIds(oldNodes, face.cellId, face.cellType);
10842           bool isMultipleDetected = false;
10843           std::set<int>::iterator itn = oldNodes.begin();
10844           for (; itn != oldNodes.end(); ++itn)
10845             {
10846               int oldId = *itn;
10847               //MESSAGE("     node " << oldId);
10848               if (!nodeDomains.count(oldId))
10849                 nodeDomains[oldId] = emptyMap; // create an empty entry for node
10850               if (nodeDomains[oldId].empty())
10851                 nodeDomains[oldId][idomain] = oldId; // keep the old node in the first domain
10852               std::map<int, int>::iterator itdom = domvol.begin();
10853               for (; itdom != domvol.end(); ++itdom)
10854                 {
10855                   int idom = itdom->first;
10856                   //MESSAGE("         domain " << idom);
10857                   if (!nodeDomains[oldId].count(idom)) // --- node to clone
10858                     {
10859                       if (nodeDomains[oldId].size() >= 2) // a multiple node
10860                         {
10861                           vector<int> orderedDoms;
10862                           //MESSAGE("multiple node " << oldId);
10863                           isMultipleDetected =true;
10864                           if (mutipleNodes.count(oldId))
10865                             orderedDoms = mutipleNodes[oldId];
10866                           else
10867                             {
10868                               map<int,int>::iterator it = nodeDomains[oldId].begin();
10869                               for (; it != nodeDomains[oldId].end(); ++it)
10870                                 orderedDoms.push_back(it->first);
10871                             }
10872                           orderedDoms.push_back(idom); // TODO order ==> push_front or back
10873                           //stringstream txt;
10874                           //for (int i=0; i<orderedDoms.size(); i++)
10875                           //  txt << orderedDoms[i] << " ";
10876                           //MESSAGE("orderedDoms " << txt.str());
10877                           mutipleNodes[oldId] = orderedDoms;
10878                         }
10879                       double *coords = grid->GetPoint(oldId);
10880                       SMDS_MeshNode *newNode = meshDS->AddNode(coords[0], coords[1], coords[2]);
10881                       int newId = newNode->getVtkId();
10882                       nodeDomains[oldId][idom] = newId; // cloned node for other domains
10883                       //MESSAGE("   newNode " << newId << " oldNode " << oldId << " size=" <<nodeDomains[oldId].size());
10884                     }
10885                   if (nodeDomains[oldId].size() >= 3)
10886                     {
10887                       //MESSAGE("confirm multiple node " << oldId);
10888                       isMultipleDetected =true;
10889                     }
10890                 }
10891             }
10892           if (isMultipleDetected) // check if an edge of the face is shared between 3 or more domains
10893             {
10894               //MESSAGE("multiple Nodes detected on a shared face");
10895               int downId = itface->first.cellId;
10896               unsigned char cellType = itface->first.cellType;
10897               int nbEdges = grid->getDownArray(cellType)->getNumberOfDownCells(downId);
10898               const int *downEdgeIds = grid->getDownArray(cellType)->getDownCells(downId);
10899               const unsigned char* edgeType = grid->getDownArray(cellType)->getDownTypes(downId);
10900               for (int ie =0; ie < nbEdges; ie++)
10901                 {
10902                   int nodes[3];
10903                   int nbNodes = grid->getDownArray(edgeType[ie])->getNodes(downEdgeIds[ie], nodes);
10904                   if (mutipleNodes.count(nodes[0]) && mutipleNodes.count(nodes[nbNodes-1]))
10905                     {
10906                       vector<int> vn0 = mutipleNodes[nodes[0]];
10907                       vector<int> vn1 = mutipleNodes[nodes[nbNodes - 1]];
10908                       sort( vn0.begin(), vn0.end() );
10909                       sort( vn1.begin(), vn1.end() );
10910                       if (vn0 == vn1)
10911                         {
10912                           //MESSAGE(" detect edgesMultiDomains " << nodes[0] << " " << nodes[nbNodes - 1]);
10913                           double *coords = grid->GetPoint(nodes[0]);
10914                           gp_Pnt p0(coords[0], coords[1], coords[2]);
10915                           coords = grid->GetPoint(nodes[nbNodes - 1]);
10916                           gp_Pnt p1(coords[0], coords[1], coords[2]);
10917                           gp_Pnt gref;
10918                           int vtkVolIds[1000];  // an edge can belong to a lot of volumes
10919                           map<int, SMDS_VtkVolume*> domvol; // domain --> a volume with the edge
10920                           map<int, double> angleDom; // oriented angles between planes defined by edge and volume centers
10921                           int nbvol = grid->GetParentVolumes(vtkVolIds, downEdgeIds[ie], edgeType[ie]);
10922                           for (int id=0; id < vn0.size(); id++)
10923                             {
10924                               int idom = vn0[id];
10925                               for (int ivol=0; ivol<nbvol; ivol++)
10926                                 {
10927                                   int smdsId = meshDS->fromVtkToSmds(vtkVolIds[ivol]);
10928                                   SMDS_MeshElement* elem = (SMDS_MeshElement*)meshDS->FindElement(smdsId);
10929                                   if (theElems[idom].count(elem))
10930                                     {
10931                                       SMDS_VtkVolume* svol = dynamic_cast<SMDS_VtkVolume*>(elem);
10932                                       domvol[idom] = svol;
10933                                       //MESSAGE("  domain " << idom << " volume " << elem->GetID());
10934                                       double values[3];
10935                                       vtkIdType npts = 0;
10936                                       vtkIdType* pts = 0;
10937                                       grid->GetCellPoints(vtkVolIds[ivol], npts, pts);
10938                                       SMDS_VtkVolume::gravityCenter(grid, pts, npts, values);
10939                                       if (id ==0)
10940                                         {
10941                                           gref.SetXYZ(gp_XYZ(values[0], values[1], values[2]));
10942                                           angleDom[idom] = 0;
10943                                         }
10944                                       else
10945                                         {
10946                                           gp_Pnt g(values[0], values[1], values[2]);
10947                                           angleDom[idom] = OrientedAngle(p0, p1, gref, g); // -pi<angle<+pi
10948                                           //MESSAGE("  angle=" << angleDom[idom]);
10949                                         }
10950                                       break;
10951                                     }
10952                                 }
10953                             }
10954                           map<double, int> sortedDom; // sort domains by angle
10955                           for (map<int, double>::iterator ia = angleDom.begin(); ia != angleDom.end(); ++ia)
10956                             sortedDom[ia->second] = ia->first;
10957                           vector<int> vnodes;
10958                           vector<int> vdom;
10959                           for (map<double, int>::iterator ib = sortedDom.begin(); ib != sortedDom.end(); ++ib)
10960                             {
10961                               vdom.push_back(ib->second);
10962                               //MESSAGE("  ordered domain " << ib->second << "  angle " << ib->first);
10963                             }
10964                           for (int ino = 0; ino < nbNodes; ino++)
10965                             vnodes.push_back(nodes[ino]);
10966                           edgesMultiDomains[vnodes] = vdom; // nodes vector --> ordered domains
10967                         }
10968                     }
10969                 }
10970             }
10971         }
10972     }
10973
10974   // --- iterate on shared faces (volumes to modify, face to extrude)
10975   //     get node id's of the face (id SMDS = id VTK)
10976   //     create flat element with old and new nodes if requested
10977
10978   // --- new quad nodes on flat quad elements: oldId --> ((domain1 X domain2) --> newId)
10979   //     (domain1 X domain2) = domain1 + MAXINT*domain2
10980
10981   std::map<int, std::map<long,int> > nodeQuadDomains;
10982   std::map<std::string, SMESH_Group*> mapOfJunctionGroups;
10983
10984   if (createJointElems)
10985     {
10986       itface = faceDomains.begin();
10987       for (; itface != faceDomains.end(); ++itface)
10988         {
10989           DownIdType face = itface->first;
10990           std::set<int> oldNodes;
10991           std::set<int>::iterator itn;
10992           oldNodes.clear();
10993           grid->GetNodeIds(oldNodes, face.cellId, face.cellType);
10994
10995           std::map<int, int> domvol = itface->second;
10996           std::map<int, int>::iterator itdom = domvol.begin();
10997           int dom1 = itdom->first;
10998           int vtkVolId = itdom->second;
10999           itdom++;
11000           int dom2 = itdom->first;
11001           SMDS_MeshVolume *vol = grid->extrudeVolumeFromFace(vtkVolId, dom1, dom2, oldNodes, nodeDomains,
11002                                                              nodeQuadDomains);
11003           stringstream grpname;
11004           grpname << "j_";
11005           if (dom1 < dom2)
11006             grpname << dom1 << "_" << dom2;
11007           else
11008             grpname << dom2 << "_" << dom1;
11009           int idg;
11010           string namegrp = grpname.str();
11011           if (!mapOfJunctionGroups.count(namegrp))
11012             mapOfJunctionGroups[namegrp] = this->myMesh->AddGroup(SMDSAbs_Volume, namegrp.c_str(), idg);
11013           SMESHDS_Group *sgrp = dynamic_cast<SMESHDS_Group*>(mapOfJunctionGroups[namegrp]->GetGroupDS());
11014           if (sgrp)
11015             sgrp->Add(vol->GetID());
11016         }
11017     }
11018
11019   // --- create volumes on multiple domain intersection if requested
11020   //     iterate on edgesMultiDomains
11021
11022   if (createJointElems)
11023     {
11024       std::map<std::vector<int>, std::vector<int> >::iterator ite = edgesMultiDomains.begin();
11025       for (; ite != edgesMultiDomains.end(); ++ite)
11026         {
11027           vector<int> nodes = ite->first;
11028           vector<int> orderDom = ite->second;
11029           vector<vtkIdType> orderedNodes;
11030           if (nodes.size() == 2)
11031             {
11032               //MESSAGE(" use edgesMultiDomains " << nodes[0] << " " << nodes[1]);
11033               for (int ino=0; ino < nodes.size(); ino++)
11034                 if (orderDom.size() == 3)
11035                   for (int idom = 0; idom <orderDom.size(); idom++)
11036                     orderedNodes.push_back( nodeDomains[nodes[ino]][orderDom[idom]] );
11037                 else
11038                   for (int idom = orderDom.size()-1; idom >=0; idom--)
11039                     orderedNodes.push_back( nodeDomains[nodes[ino]][orderDom[idom]] );
11040               SMDS_MeshVolume* vol = this->GetMeshDS()->AddVolumeFromVtkIds(orderedNodes);
11041
11042               stringstream grpname;
11043               grpname << "mj_";
11044               grpname << 0 << "_" << 0;
11045               int idg;
11046               string namegrp = grpname.str();
11047               if (!mapOfJunctionGroups.count(namegrp))
11048                 mapOfJunctionGroups[namegrp] = this->myMesh->AddGroup(SMDSAbs_Volume, namegrp.c_str(), idg);
11049               SMESHDS_Group *sgrp = dynamic_cast<SMESHDS_Group*>(mapOfJunctionGroups[namegrp]->GetGroupDS());
11050               if (sgrp)
11051                 sgrp->Add(vol->GetID());
11052             }
11053           else
11054             {
11055               //MESSAGE("Quadratic multiple joints not implemented");
11056               // TODO quadratic nodes
11057             }
11058         }
11059     }
11060
11061   // --- list the explicit faces and edges of the mesh that need to be modified,
11062   //     i.e. faces and edges built with one or more duplicated nodes.
11063   //     associate these faces or edges to their corresponding domain.
11064   //     only the first domain found is kept when a face or edge is shared
11065
11066   std::map<DownIdType, std::map<int,int>, DownIdCompare> faceOrEdgeDom; // cellToModify --> (id domain --> id cell)
11067   std::map<int,int> feDom; // vtk id of cell to modify --> id domain
11068   faceOrEdgeDom.clear();
11069   feDom.clear();
11070
11071   for (int idomain = 0; idomain < theElems.size(); idomain++)
11072     {
11073       std::map<int, std::map<int, int> >::const_iterator itnod = nodeDomains.begin();
11074       for (; itnod != nodeDomains.end(); ++itnod)
11075         {
11076           int oldId = itnod->first;
11077           //MESSAGE("     node " << oldId);
11078           vtkCellLinks::Link l = grid->GetCellLinks()->GetLink(oldId);
11079           for (int i = 0; i < l.ncells; i++)
11080             {
11081               int vtkId = l.cells[i];
11082               int vtkType = grid->GetCellType(vtkId);
11083               int downId = grid->CellIdToDownId(vtkId);
11084               if (downId < 0)
11085                 continue; // new cells: not to be modified
11086               DownIdType aCell(downId, vtkType);
11087               int volParents[1000];
11088               int nbvol = grid->GetParentVolumes(volParents, vtkId);
11089               for (int j = 0; j < nbvol; j++)
11090                 if (celldom.count(volParents[j]) && (celldom[volParents[j]] == idomain))
11091                   if (!feDom.count(vtkId))
11092                     {
11093                       feDom[vtkId] = idomain;
11094                       faceOrEdgeDom[aCell] = emptyMap;
11095                       faceOrEdgeDom[aCell][idomain] = vtkId; // affect face or edge to the first domain only
11096                       //MESSAGE("affect cell " << this->GetMeshDS()->fromVtkToSmds(vtkId) << " domain " << idomain
11097                       //        << " type " << vtkType << " downId " << downId);
11098                     }
11099             }
11100         }
11101     }
11102
11103   // --- iterate on shared faces (volumes to modify, face to extrude)
11104   //     get node id's of the face
11105   //     replace old nodes by new nodes in volumes, and update inverse connectivity
11106
11107   std::map<DownIdType, std::map<int,int>, DownIdCompare>* maps[3] = {&faceDomains, &cellDomains, &faceOrEdgeDom};
11108   for (int m=0; m<3; m++)
11109     {
11110       std::map<DownIdType, std::map<int,int>, DownIdCompare>* amap = maps[m];
11111       itface = (*amap).begin();
11112       for (; itface != (*amap).end(); ++itface)
11113         {
11114           DownIdType face = itface->first;
11115           std::set<int> oldNodes;
11116           std::set<int>::iterator itn;
11117           oldNodes.clear();
11118           grid->GetNodeIds(oldNodes, face.cellId, face.cellType);
11119           //MESSAGE("examine cell, downId " << face.cellId << " type " << int(face.cellType));
11120           std::map<int, int> localClonedNodeIds;
11121
11122           std::map<int, int> domvol = itface->second;
11123           std::map<int, int>::iterator itdom = domvol.begin();
11124           for (; itdom != domvol.end(); ++itdom)
11125             {
11126               int idom = itdom->first;
11127               int vtkVolId = itdom->second;
11128               //MESSAGE("modify nodes of cell " << this->GetMeshDS()->fromVtkToSmds(vtkVolId) << " domain " << idom);
11129               localClonedNodeIds.clear();
11130               for (itn = oldNodes.begin(); itn != oldNodes.end(); ++itn)
11131                 {
11132                   int oldId = *itn;
11133                   if (nodeDomains[oldId].count(idom))
11134                     {
11135                       localClonedNodeIds[oldId] = nodeDomains[oldId][idom];
11136                       //MESSAGE("     node " << oldId << " --> " << localClonedNodeIds[oldId]);
11137                     }
11138                 }
11139               meshDS->ModifyCellNodes(vtkVolId, localClonedNodeIds);
11140             }
11141         }
11142     }
11143
11144   meshDS->CleanDownWardConnectivity(); // Mesh has been modified, downward connectivity is no more usable, free memory
11145   grid->BuildLinks();
11146
11147   CHRONOSTOP(50);
11148   counters::stats();
11149   return true;
11150 }
11151
11152 /*!
11153  * \brief Double nodes on some external faces and create flat elements.
11154  * Flat elements are mainly used by some types of mechanic calculations.
11155  *
11156  * Each group of the list must be constituted of faces.
11157  * Triangles are transformed in prisms, and quadrangles in hexahedrons.
11158  * @param theElems - list of groups of faces, where a group of faces is a set of
11159  * SMDS_MeshElements sorted by Id.
11160  * @return TRUE if operation has been completed successfully, FALSE otherwise
11161  */
11162 bool SMESH_MeshEditor::CreateFlatElementsOnFacesGroups(const std::vector<TIDSortedElemSet>& theElems)
11163 {
11164   MESSAGE("-------------------------------------------------");
11165   MESSAGE("SMESH_MeshEditor::CreateFlatElementsOnFacesGroups");
11166   MESSAGE("-------------------------------------------------");
11167
11168   SMESHDS_Mesh *meshDS = this->myMesh->GetMeshDS();
11169
11170   // --- For each group of faces
11171   //     duplicate the nodes, create a flat element based on the face
11172   //     replace the nodes of the faces by their clones
11173
11174   std::map<const SMDS_MeshNode*, const SMDS_MeshNode*> clonedNodes;
11175   std::map<const SMDS_MeshNode*, const SMDS_MeshNode*> intermediateNodes;
11176   clonedNodes.clear();
11177   intermediateNodes.clear();
11178   std::map<std::string, SMESH_Group*> mapOfJunctionGroups;
11179   mapOfJunctionGroups.clear();
11180
11181   for (int idom = 0; idom < theElems.size(); idom++)
11182     {
11183       const TIDSortedElemSet& domain = theElems[idom];
11184       TIDSortedElemSet::const_iterator elemItr = domain.begin();
11185       for (; elemItr != domain.end(); ++elemItr)
11186         {
11187           SMDS_MeshElement* anElem = (SMDS_MeshElement*) *elemItr;
11188           SMDS_MeshFace* aFace = dynamic_cast<SMDS_MeshFace*> (anElem);
11189           if (!aFace)
11190             continue;
11191           // MESSAGE("aFace=" << aFace->GetID());
11192           bool isQuad = aFace->IsQuadratic();
11193           vector<const SMDS_MeshNode*> ln0, ln1, ln2, ln3, ln4;
11194
11195           // --- clone the nodes, create intermediate nodes for non medium nodes of a quad face
11196
11197           SMDS_ElemIteratorPtr nodeIt = aFace->nodesIterator();
11198           while (nodeIt->more())
11199             {
11200               const SMDS_MeshNode* node = static_cast<const SMDS_MeshNode*> (nodeIt->next());
11201               bool isMedium = isQuad && (aFace->IsMediumNode(node));
11202               if (isMedium)
11203                 ln2.push_back(node);
11204               else
11205                 ln0.push_back(node);
11206
11207               const SMDS_MeshNode* clone = 0;
11208               if (!clonedNodes.count(node))
11209                 {
11210                   clone = meshDS->AddNode(node->X(), node->Y(), node->Z());
11211                   clonedNodes[node] = clone;
11212                 }
11213               else
11214                 clone = clonedNodes[node];
11215
11216               if (isMedium)
11217                 ln3.push_back(clone);
11218               else
11219                 ln1.push_back(clone);
11220
11221               const SMDS_MeshNode* inter = 0;
11222               if (isQuad && (!isMedium))
11223                 {
11224                   if (!intermediateNodes.count(node))
11225                     {
11226                       inter = meshDS->AddNode(node->X(), node->Y(), node->Z());
11227                       intermediateNodes[node] = inter;
11228                     }
11229                   else
11230                     inter = intermediateNodes[node];
11231                   ln4.push_back(inter);
11232                 }
11233             }
11234
11235           // --- extrude the face
11236
11237           vector<const SMDS_MeshNode*> ln;
11238           SMDS_MeshVolume* vol = 0;
11239           vtkIdType aType = aFace->GetVtkType();
11240           switch (aType)
11241           {
11242             case VTK_TRIANGLE:
11243               vol = meshDS->AddVolume(ln0[2], ln0[1], ln0[0], ln1[2], ln1[1], ln1[0]);
11244               // MESSAGE("vol prism " << vol->GetID());
11245               ln.push_back(ln1[0]);
11246               ln.push_back(ln1[1]);
11247               ln.push_back(ln1[2]);
11248               break;
11249             case VTK_QUAD:
11250               vol = meshDS->AddVolume(ln0[3], ln0[2], ln0[1], ln0[0], ln1[3], ln1[2], ln1[1], ln1[0]);
11251               // MESSAGE("vol hexa " << vol->GetID());
11252               ln.push_back(ln1[0]);
11253               ln.push_back(ln1[1]);
11254               ln.push_back(ln1[2]);
11255               ln.push_back(ln1[3]);
11256               break;
11257             case VTK_QUADRATIC_TRIANGLE:
11258               vol = meshDS->AddVolume(ln1[0], ln1[1], ln1[2], ln0[0], ln0[1], ln0[2], ln3[0], ln3[1], ln3[2],
11259                                       ln2[0], ln2[1], ln2[2], ln4[0], ln4[1], ln4[2]);
11260               // MESSAGE("vol quad prism " << vol->GetID());
11261               ln.push_back(ln1[0]);
11262               ln.push_back(ln1[1]);
11263               ln.push_back(ln1[2]);
11264               ln.push_back(ln3[0]);
11265               ln.push_back(ln3[1]);
11266               ln.push_back(ln3[2]);
11267               break;
11268             case VTK_QUADRATIC_QUAD:
11269 //              vol = meshDS->AddVolume(ln0[0], ln0[1], ln0[2], ln0[3], ln1[0], ln1[1], ln1[2], ln1[3],
11270 //                                      ln2[0], ln2[1], ln2[2], ln2[3], ln3[0], ln3[1], ln3[2], ln3[3],
11271 //                                      ln4[0], ln4[1], ln4[2], ln4[3]);
11272               vol = meshDS->AddVolume(ln1[0], ln1[1], ln1[2], ln1[3], ln0[0], ln0[1], ln0[2], ln0[3],
11273                                       ln3[0], ln3[1], ln3[2], ln3[3], ln2[0], ln2[1], ln2[2], ln2[3],
11274                                       ln4[0], ln4[1], ln4[2], ln4[3]);
11275               // MESSAGE("vol quad hexa " << vol->GetID());
11276               ln.push_back(ln1[0]);
11277               ln.push_back(ln1[1]);
11278               ln.push_back(ln1[2]);
11279               ln.push_back(ln1[3]);
11280               ln.push_back(ln3[0]);
11281               ln.push_back(ln3[1]);
11282               ln.push_back(ln3[2]);
11283               ln.push_back(ln3[3]);
11284               break;
11285             case VTK_POLYGON:
11286               break;
11287             default:
11288               break;
11289           }
11290
11291           if (vol)
11292             {
11293               stringstream grpname;
11294               grpname << "jf_";
11295               grpname << idom;
11296               int idg;
11297               string namegrp = grpname.str();
11298               if (!mapOfJunctionGroups.count(namegrp))
11299                 mapOfJunctionGroups[namegrp] = this->myMesh->AddGroup(SMDSAbs_Volume, namegrp.c_str(), idg);
11300               SMESHDS_Group *sgrp = dynamic_cast<SMESHDS_Group*>(mapOfJunctionGroups[namegrp]->GetGroupDS());
11301               if (sgrp)
11302                 sgrp->Add(vol->GetID());
11303             }
11304
11305           // --- modify the face
11306
11307           aFace->ChangeNodes(&ln[0], ln.size());
11308         }
11309     }
11310   return true;
11311 }
11312
11313 //================================================================================
11314 /*!
11315  * \brief Generates skin mesh (containing 2D cells) from 3D mesh
11316  * The created 2D mesh elements based on nodes of free faces of boundary volumes
11317  * \return TRUE if operation has been completed successfully, FALSE otherwise
11318  */
11319 //================================================================================
11320
11321 bool SMESH_MeshEditor::Make2DMeshFrom3D()
11322 {
11323   // iterates on volume elements and detect all free faces on them
11324   SMESHDS_Mesh* aMesh = GetMeshDS();
11325   if (!aMesh)
11326     return false;
11327   //bool res = false;
11328   int nbFree = 0, nbExisted = 0, nbCreated = 0;
11329   SMDS_VolumeIteratorPtr vIt = aMesh->volumesIterator();
11330   while(vIt->more())
11331   {
11332     const SMDS_MeshVolume* volume = vIt->next();
11333     SMDS_VolumeTool vTool( volume, /*ignoreCentralNodes=*/false );
11334     vTool.SetExternalNormal();
11335     //const bool isPoly = volume->IsPoly();
11336     const int iQuad = volume->IsQuadratic();
11337     for ( int iface = 0, n = vTool.NbFaces(); iface < n; iface++ )
11338     {
11339       if (!vTool.IsFreeFace(iface))
11340         continue;
11341       nbFree++;
11342       vector<const SMDS_MeshNode *> nodes;
11343       int nbFaceNodes = vTool.NbFaceNodes(iface);
11344       const SMDS_MeshNode** faceNodes = vTool.GetFaceNodes(iface);
11345       int inode = 0;
11346       for ( ; inode < nbFaceNodes; inode += iQuad+1)
11347         nodes.push_back(faceNodes[inode]);
11348       if (iQuad) { // add medium nodes
11349         for ( inode = 1; inode < nbFaceNodes; inode += 2)
11350           nodes.push_back(faceNodes[inode]);
11351         if ( nbFaceNodes == 9 ) // bi-quadratic quad
11352           nodes.push_back(faceNodes[8]);
11353       }
11354       // add new face based on volume nodes
11355       if (aMesh->FindElement( nodes, SMDSAbs_Face, /*noMedium=*/false) ) {
11356         nbExisted++;
11357         continue; // face already exsist
11358       }
11359       AddElement(nodes, SMDSAbs_Face, ( !iQuad && nbFaceNodes/(iQuad+1) > 4 ));
11360       nbCreated++;
11361     }
11362   }
11363   return ( nbFree==(nbExisted+nbCreated) );
11364 }
11365
11366 namespace
11367 {
11368   inline const SMDS_MeshNode* getNodeWithSameID(SMESHDS_Mesh* mesh, const SMDS_MeshNode* node)
11369   {
11370     if ( const SMDS_MeshNode* n = mesh->FindNode( node->GetID() ))
11371       return n;
11372     return mesh->AddNodeWithID( node->X(),node->Y(),node->Z(), node->GetID() );
11373   }
11374 }
11375 //================================================================================
11376 /*!
11377  * \brief Creates missing boundary elements
11378  *  \param elements - elements whose boundary is to be checked
11379  *  \param dimension - defines type of boundary elements to create
11380  *  \param group - a group to store created boundary elements in
11381  *  \param targetMesh - a mesh to store created boundary elements in
11382  *  \param toCopyElements - if true, the checked elements will be copied into the targetMesh
11383  *  \param toCopyExistingBoundary - if true, not only new but also pre-existing
11384  *                                boundary elements will be copied into the targetMesh
11385  *  \param toAddExistingBondary - if true, not only new but also pre-existing
11386  *                                boundary elements will be added into the new group
11387  *  \param aroundElements - if true, elements will be created on boundary of given
11388  *                          elements else, on boundary of the whole mesh.
11389  * \return nb of added boundary elements
11390  */
11391 //================================================================================
11392
11393 int SMESH_MeshEditor::MakeBoundaryMesh(const TIDSortedElemSet& elements,
11394                                        Bnd_Dimension           dimension,
11395                                        SMESH_Group*            group/*=0*/,
11396                                        SMESH_Mesh*             targetMesh/*=0*/,
11397                                        bool                    toCopyElements/*=false*/,
11398                                        bool                    toCopyExistingBoundary/*=false*/,
11399                                        bool                    toAddExistingBondary/*= false*/,
11400                                        bool                    aroundElements/*= false*/)
11401 {
11402   SMDSAbs_ElementType missType = (dimension == BND_2DFROM3D) ? SMDSAbs_Face : SMDSAbs_Edge;
11403   SMDSAbs_ElementType elemType = (dimension == BND_1DFROM2D) ? SMDSAbs_Face : SMDSAbs_Volume;
11404   // hope that all elements are of the same type, do not check them all
11405   if ( !elements.empty() && (*elements.begin())->GetType() != elemType )
11406     throw SALOME_Exception(LOCALIZED("wrong element type"));
11407
11408   if ( !targetMesh )
11409     toCopyElements = toCopyExistingBoundary = false;
11410
11411   SMESH_MeshEditor tgtEditor( targetMesh ? targetMesh : myMesh );
11412   SMESHDS_Mesh* aMesh = GetMeshDS(), *tgtMeshDS = tgtEditor.GetMeshDS();
11413   int nbAddedBnd = 0;
11414
11415   // editor adding present bnd elements and optionally holding elements to add to the group
11416   SMESH_MeshEditor* presentEditor;
11417   SMESH_MeshEditor tgtEditor2( tgtEditor.GetMesh() );
11418   presentEditor = toAddExistingBondary ? &tgtEditor : &tgtEditor2;
11419
11420   SMDS_VolumeTool vTool;
11421   TIDSortedElemSet avoidSet;
11422   const TIDSortedElemSet emptySet, *elemSet = aroundElements ? &elements : &emptySet;
11423   int inode;
11424
11425   typedef vector<const SMDS_MeshNode*> TConnectivity;
11426
11427   SMDS_ElemIteratorPtr eIt;
11428   if (elements.empty())
11429     eIt = aMesh->elementsIterator(elemType);
11430   else
11431     eIt = SMDS_ElemIteratorPtr( new TSetIterator( elements.begin(), elements.end() ));
11432
11433   while (eIt->more())
11434   {
11435     const SMDS_MeshElement* elem = eIt->next();
11436     const int iQuad = elem->IsQuadratic();
11437
11438     // ------------------------------------------------------------------------------------
11439     // 1. For an elem, get present bnd elements and connectivities of missing bnd elements
11440     // ------------------------------------------------------------------------------------
11441     vector<const SMDS_MeshElement*> presentBndElems;
11442     vector<TConnectivity>           missingBndElems;
11443     TConnectivity nodes;
11444     if ( vTool.Set(elem, /*ignoreCentralNodes=*/true) ) // elem is a volume --------------
11445     {
11446       vTool.SetExternalNormal();
11447       const SMDS_MeshElement* otherVol = 0;
11448       for ( int iface = 0, n = vTool.NbFaces(); iface < n; iface++ )
11449       {
11450         if ( !vTool.IsFreeFace(iface, &otherVol) &&
11451              ( !aroundElements || elements.count( otherVol )))
11452           continue;
11453         const int nbFaceNodes = vTool.NbFaceNodes(iface);
11454         const SMDS_MeshNode** nn = vTool.GetFaceNodes(iface);
11455         if ( missType == SMDSAbs_Edge ) // boundary edges
11456         {
11457           nodes.resize( 2+iQuad );
11458           for ( int i = 0; i < nbFaceNodes; i += 1+iQuad)
11459           {
11460             for ( int j = 0; j < nodes.size(); ++j )
11461               nodes[j] =nn[i+j];
11462             if ( const SMDS_MeshElement* edge =
11463                  aMesh->FindElement(nodes,SMDSAbs_Edge,/*noMedium=*/false))
11464               presentBndElems.push_back( edge );
11465             else
11466               missingBndElems.push_back( nodes );
11467           }
11468         }
11469         else // boundary face
11470         {
11471           nodes.clear();
11472           for ( inode = 0; inode < nbFaceNodes; inode += 1+iQuad)
11473             nodes.push_back( nn[inode] );
11474           if (iQuad) // add medium nodes
11475             for ( inode = 1; inode < nbFaceNodes; inode += 2)
11476               nodes.push_back( nn[inode] );
11477           int iCenter = vTool.GetCenterNodeIndex(iface); // for HEX27
11478           if ( iCenter > 0 )
11479             nodes.push_back( vTool.GetNodes()[ iCenter ] );
11480
11481           if (const SMDS_MeshElement * f = aMesh->FindElement( nodes,
11482                                                                SMDSAbs_Face, /*noMedium=*/false ))
11483             presentBndElems.push_back( f );
11484           else
11485             missingBndElems.push_back( nodes );
11486
11487           if ( targetMesh != myMesh )
11488           {
11489             // add 1D elements on face boundary to be added to a new mesh
11490             const SMDS_MeshElement* edge;
11491             for ( inode = 0; inode < nbFaceNodes; inode += 1+iQuad)
11492             {
11493               if ( iQuad )
11494                 edge = aMesh->FindEdge( nn[inode], nn[inode+1], nn[inode+2]);
11495               else
11496                 edge = aMesh->FindEdge( nn[inode], nn[inode+1]);
11497               if ( edge && avoidSet.insert( edge ).second )
11498                 presentBndElems.push_back( edge );
11499             }
11500           }
11501         }
11502       }
11503     }
11504     else                     // elem is a face ------------------------------------------
11505     {
11506       avoidSet.clear(), avoidSet.insert( elem );
11507       int nbNodes = elem->NbCornerNodes();
11508       nodes.resize( 2 /*+ iQuad*/);
11509       for ( int i = 0; i < nbNodes; i++ )
11510       {
11511         nodes[0] = elem->GetNode(i);
11512         nodes[1] = elem->GetNode((i+1)%nbNodes);
11513         if ( FindFaceInSet( nodes[0], nodes[1], *elemSet, avoidSet))
11514           continue; // not free link
11515
11516         //if ( iQuad )
11517         //nodes[2] = elem->GetNode( i + nbNodes );
11518         if ( const SMDS_MeshElement* edge =
11519              aMesh->FindElement(nodes,SMDSAbs_Edge,/*noMedium=*/true))
11520           presentBndElems.push_back( edge );
11521         else
11522           missingBndElems.push_back( nodes );
11523       }
11524     }
11525
11526     // ---------------------------------
11527     // 2. Add missing boundary elements
11528     // ---------------------------------
11529     if ( targetMesh != myMesh )
11530       // instead of making a map of nodes in this mesh and targetMesh,
11531       // we create nodes with same IDs.
11532       for ( int i = 0; i < missingBndElems.size(); ++i )
11533       {
11534         TConnectivity& srcNodes = missingBndElems[i];
11535         TConnectivity  nodes( srcNodes.size() );
11536         for ( inode = 0; inode < nodes.size(); ++inode )
11537           nodes[inode] = getNodeWithSameID( tgtMeshDS, srcNodes[inode] );
11538         if ( aroundElements && tgtEditor.GetMeshDS()->FindElement( nodes,
11539                                                                    missType,
11540                                                                    /*noMedium=*/false))
11541           continue;
11542         tgtEditor.AddElement(nodes, missType, !iQuad && nodes.size()/(iQuad+1)>4);
11543         ++nbAddedBnd;
11544       }
11545     else
11546       for ( int i = 0; i < missingBndElems.size(); ++i )
11547       {
11548         TConnectivity& nodes = missingBndElems[i];
11549         if ( aroundElements && tgtEditor.GetMeshDS()->FindElement( nodes,
11550                                                                    missType,
11551                                                                    /*noMedium=*/false))
11552           continue;
11553         tgtEditor.AddElement(nodes, missType, !iQuad && nodes.size()/(iQuad+1)>4);
11554         ++nbAddedBnd;
11555       }
11556
11557     // ----------------------------------
11558     // 3. Copy present boundary elements
11559     // ----------------------------------
11560     if ( toCopyExistingBoundary )
11561       for ( int i = 0 ; i < presentBndElems.size(); ++i )
11562       {
11563         const SMDS_MeshElement* e = presentBndElems[i];
11564         TConnectivity nodes( e->NbNodes() );
11565         for ( inode = 0; inode < nodes.size(); ++inode )
11566           nodes[inode] = getNodeWithSameID( tgtMeshDS, e->GetNode(inode) );
11567         presentEditor->AddElement(nodes, e->GetType(), e->IsPoly());
11568       }
11569     else // store present elements to add them to a group
11570       for ( int i = 0 ; i < presentBndElems.size(); ++i )
11571       {
11572         presentEditor->myLastCreatedElems.Append(presentBndElems[i]);
11573       }
11574       
11575   } // loop on given elements
11576
11577   // ---------------------------------------------
11578   // 4. Fill group with boundary elements
11579   // ---------------------------------------------
11580   if ( group )
11581   {
11582     if ( SMESHDS_Group* g = dynamic_cast<SMESHDS_Group*>( group->GetGroupDS() ))
11583       for ( int i = 0; i < tgtEditor.myLastCreatedElems.Size(); ++i )
11584         g->SMDSGroup().Add( tgtEditor.myLastCreatedElems( i+1 ));
11585   }
11586   tgtEditor.myLastCreatedElems.Clear();
11587   tgtEditor2.myLastCreatedElems.Clear();
11588
11589   // -----------------------
11590   // 5. Copy given elements
11591   // -----------------------
11592   if ( toCopyElements && targetMesh != myMesh )
11593   {
11594     if (elements.empty())
11595       eIt = aMesh->elementsIterator(elemType);
11596     else
11597       eIt = SMDS_ElemIteratorPtr( new TSetIterator( elements.begin(), elements.end() ));
11598     while (eIt->more())
11599     {
11600       const SMDS_MeshElement* elem = eIt->next();
11601       TConnectivity nodes( elem->NbNodes() );
11602       for ( inode = 0; inode < nodes.size(); ++inode )
11603         nodes[inode] = getNodeWithSameID( tgtMeshDS, elem->GetNode(inode) );
11604       tgtEditor.AddElement(nodes, elemType, elem->IsPoly());
11605
11606       tgtEditor.myLastCreatedElems.Clear();
11607     }
11608   }
11609   return nbAddedBnd;
11610 }