Salome HOME
Porting to OCCT development version: Standard_PI -> M_PI
[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 #define CHRONODEF
28 #include "SMESH_MeshEditor.hxx"
29
30 #include "SMDS_FaceOfNodes.hxx"
31 #include "SMDS_VolumeTool.hxx"
32 #include "SMDS_EdgePosition.hxx"
33 #include "SMDS_PolyhedralVolumeOfNodes.hxx"
34 #include "SMDS_FacePosition.hxx"
35 #include "SMDS_SpacePosition.hxx"
36 //#include "SMDS_QuadraticFaceOfNodes.hxx"
37 #include "SMDS_MeshGroup.hxx"
38 #include "SMDS_LinearEdge.hxx"
39 #include "SMDS_Downward.hxx"
40 #include "SMDS_SetIterator.hxx"
41
42 #include "SMESHDS_Group.hxx"
43 #include "SMESHDS_Mesh.hxx"
44
45 #include "SMESH_Algo.hxx"
46 #include "SMESH_ControlsDef.hxx"
47 #include "SMESH_Group.hxx"
48 #include "SMESH_MesherHelper.hxx"
49 #include "SMESH_OctreeNode.hxx"
50 #include "SMESH_subMesh.hxx"
51
52 #include <Basics_OCCTVersion.hxx>
53
54 #include "utilities.h"
55
56 #include <BRepAdaptor_Surface.hxx>
57 #include <BRepBuilderAPI_MakeEdge.hxx>
58 #include <BRepClass3d_SolidClassifier.hxx>
59 #include <BRep_Tool.hxx>
60 #include <ElCLib.hxx>
61 #include <Extrema_GenExtPS.hxx>
62 #include <Extrema_POnCurv.hxx>
63 #include <Extrema_POnSurf.hxx>
64 #include <GC_MakeSegment.hxx>
65 #include <Geom2d_Curve.hxx>
66 #include <GeomAPI_ExtremaCurveCurve.hxx>
67 #include <GeomAdaptor_Surface.hxx>
68 #include <Geom_Curve.hxx>
69 #include <Geom_Line.hxx>
70 #include <Geom_Surface.hxx>
71 #include <IntAna_IntConicQuad.hxx>
72 #include <IntAna_Quadric.hxx>
73 #include <Precision.hxx>
74 #include <TColStd_ListOfInteger.hxx>
75 #include <TopAbs_State.hxx>
76 #include <TopExp.hxx>
77 #include <TopExp_Explorer.hxx>
78 #include <TopTools_ListIteratorOfListOfShape.hxx>
79 #include <TopTools_ListOfShape.hxx>
80 #include <TopTools_SequenceOfShape.hxx>
81 #include <TopoDS.hxx>
82 #include <TopoDS_Face.hxx>
83 #include <gp.hxx>
84 #include <gp_Ax1.hxx>
85 #include <gp_Dir.hxx>
86 #include <gp_Lin.hxx>
87 #include <gp_Pln.hxx>
88 #include <gp_Trsf.hxx>
89 #include <gp_Vec.hxx>
90 #include <gp_XY.hxx>
91 #include <gp_XYZ.hxx>
92
93 #include <cmath>
94
95 #include <map>
96 #include <set>
97 #include <numeric>
98 #include <limits>
99 #include <algorithm>
100 #include <sstream>
101
102 #define cast2Node(elem) static_cast<const SMDS_MeshNode*>( elem )
103
104 using namespace std;
105 using namespace SMESH::Controls;
106
107 typedef map<const SMDS_MeshElement*, list<const SMDS_MeshNode*> >    TElemOfNodeListMap;
108 typedef map<const SMDS_MeshElement*, list<const SMDS_MeshElement*> > TElemOfElemListMap;
109
110 typedef SMDS_SetIterator< SMDS_pElement, TIDSortedElemSet::const_iterator> TSetIterator;
111
112 //=======================================================================
113 //function : SMESH_MeshEditor
114 //purpose  :
115 //=======================================================================
116
117 SMESH_MeshEditor::SMESH_MeshEditor( SMESH_Mesh* theMesh )
118   :myMesh( theMesh ) // theMesh may be NULL
119 {
120 }
121
122 //=======================================================================
123 /*!
124  * \brief Add element
125  */
126 //=======================================================================
127
128 SMDS_MeshElement*
129 SMESH_MeshEditor::AddElement(const vector<const SMDS_MeshNode*> & node,
130                              const SMDSAbs_ElementType            type,
131                              const bool                           isPoly,
132                              const int                            ID)
133 {
134   //MESSAGE("AddElement " <<node.size() << " " << type << " " << isPoly << " " << ID);
135   SMDS_MeshElement* e = 0;
136   int nbnode = node.size();
137   SMESHDS_Mesh* mesh = GetMeshDS();
138   switch ( type ) {
139   case SMDSAbs_Face:
140     if ( !isPoly ) {
141       if      (nbnode == 3) {
142         if ( ID >= 1 ) e = mesh->AddFaceWithID(node[0], node[1], node[2], ID);
143         else           e = mesh->AddFace      (node[0], node[1], node[2] );
144       }
145       else if (nbnode == 4) {
146         if ( ID >= 1 ) e = mesh->AddFaceWithID(node[0], node[1], node[2], node[3], ID);
147         else           e = mesh->AddFace      (node[0], node[1], node[2], node[3] );
148       }
149       else if (nbnode == 6) {
150         if ( ID >= 1 ) e = mesh->AddFaceWithID(node[0], node[1], node[2], node[3],
151                                                node[4], node[5], ID);
152         else           e = mesh->AddFace      (node[0], node[1], node[2], node[3],
153                                                node[4], node[5] );
154       }
155       else if (nbnode == 8) {
156         if ( ID >= 1 ) e = mesh->AddFaceWithID(node[0], node[1], node[2], node[3],
157                                                node[4], node[5], node[6], node[7], ID);
158         else           e = mesh->AddFace      (node[0], node[1], node[2], node[3],
159                                                node[4], node[5], node[6], node[7] );
160       }
161       else if (nbnode == 9) {
162         if ( ID >= 1 ) e = mesh->AddFaceWithID(node[0], node[1], node[2], node[3],
163                                                node[4], node[5], node[6], node[7], node[8], ID);
164         else           e = mesh->AddFace      (node[0], node[1], node[2], node[3],
165                                                node[4], node[5], node[6], node[7], node[8] );
166       }
167     } else {
168       if ( ID >= 1 ) e = mesh->AddPolygonalFaceWithID(node, ID);
169       else           e = mesh->AddPolygonalFace      (node    );
170     }
171     break;
172
173   case SMDSAbs_Volume:
174     if ( !isPoly ) {
175       if      (nbnode == 4) {
176         if ( ID >= 1 ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3], ID);
177         else           e = mesh->AddVolume      (node[0], node[1], node[2], node[3] );
178       }
179       else if (nbnode == 5) {
180         if ( ID >= 1 ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
181                                                  node[4], ID);
182         else           e = mesh->AddVolume      (node[0], node[1], node[2], node[3],
183                                                  node[4] );
184       }
185       else if (nbnode == 6) {
186         if ( ID >= 1 ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
187                                                  node[4], node[5], ID);
188         else           e = mesh->AddVolume      (node[0], node[1], node[2], node[3],
189                                                  node[4], node[5] );
190       }
191       else if (nbnode == 8) {
192         if ( ID >= 1 ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
193                                                  node[4], node[5], node[6], node[7], ID);
194         else           e = mesh->AddVolume      (node[0], node[1], node[2], node[3],
195                                                  node[4], node[5], node[6], node[7] );
196       }
197       else if (nbnode == 10) {
198         if ( ID >= 1 ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
199                                                  node[4], node[5], node[6], node[7],
200                                                  node[8], node[9], ID);
201         else           e = mesh->AddVolume      (node[0], node[1], node[2], node[3],
202                                                  node[4], node[5], node[6], node[7],
203                                                  node[8], node[9] );
204       }
205       else if (nbnode == 12) {
206         if ( ID >= 1 ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
207                                                  node[4], node[5], node[6], node[7],
208                                                  node[8], node[9], node[10], node[11], ID);
209         else           e = mesh->AddVolume      (node[0], node[1], node[2], node[3],
210                                                  node[4], node[5], node[6], node[7],
211                                                  node[8], node[9], node[10], node[11] );
212       }
213       else if (nbnode == 13) {
214         if ( ID >= 1 ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
215                                                  node[4], node[5], node[6], node[7],
216                                                  node[8], node[9], node[10],node[11],
217                                                  node[12],ID);
218         else           e = mesh->AddVolume      (node[0], node[1], node[2], node[3],
219                                                  node[4], node[5], node[6], node[7],
220                                                  node[8], node[9], node[10],node[11],
221                                                  node[12] );
222       }
223       else if (nbnode == 15) {
224         if ( ID >= 1 ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
225                                                  node[4], node[5], node[6], node[7],
226                                                  node[8], node[9], node[10],node[11],
227                                                  node[12],node[13],node[14],ID);
228         else           e = mesh->AddVolume      (node[0], node[1], node[2], node[3],
229                                                  node[4], node[5], node[6], node[7],
230                                                  node[8], node[9], node[10],node[11],
231                                                  node[12],node[13],node[14] );
232       }
233       else if (nbnode == 20) {
234         if ( ID >= 1 ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
235                                                  node[4], node[5], node[6], node[7],
236                                                  node[8], node[9], node[10],node[11],
237                                                  node[12],node[13],node[14],node[15],
238                                                  node[16],node[17],node[18],node[19],ID);
239         else           e = mesh->AddVolume      (node[0], node[1], node[2], node[3],
240                                                  node[4], node[5], node[6], node[7],
241                                                  node[8], node[9], node[10],node[11],
242                                                  node[12],node[13],node[14],node[15],
243                                                  node[16],node[17],node[18],node[19] );
244       }
245       else if (nbnode == 27) {
246         if ( ID >= 1 ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
247                                                  node[4], node[5], node[6], node[7],
248                                                  node[8], node[9], node[10],node[11],
249                                                  node[12],node[13],node[14],node[15],
250                                                  node[16],node[17],node[18],node[19],
251                                                  node[20],node[21],node[22],node[23],
252                                                  node[24],node[25],node[26], ID);
253         else           e = mesh->AddVolume      (node[0], node[1], node[2], node[3],
254                                                  node[4], node[5], node[6], node[7],
255                                                  node[8], node[9], node[10],node[11],
256                                                  node[12],node[13],node[14],node[15],
257                                                  node[16],node[17],node[18],node[19],
258                                                  node[20],node[21],node[22],node[23],
259                                                  node[24],node[25],node[26] );
260       }
261     }
262     break;
263
264   case SMDSAbs_Edge:
265     if ( nbnode == 2 ) {
266       if ( ID >= 1 ) e = mesh->AddEdgeWithID(node[0], node[1], ID);
267       else           e = mesh->AddEdge      (node[0], node[1] );
268     }
269     else if ( nbnode == 3 ) {
270       if ( ID >= 1 ) e = mesh->AddEdgeWithID(node[0], node[1], node[2], ID);
271       else           e = mesh->AddEdge      (node[0], node[1], node[2] );
272     }
273     break;
274
275   case SMDSAbs_0DElement:
276     if ( nbnode == 1 ) {
277       if ( ID >= 1 ) e = mesh->Add0DElementWithID(node[0], ID);
278       else           e = mesh->Add0DElement      (node[0] );
279     }
280     break;
281
282   case SMDSAbs_Node:
283     if ( ID >= 1 ) e = mesh->AddNodeWithID(node[0]->X(), node[0]->Y(), node[0]->Z(), ID);
284     else           e = mesh->AddNode      (node[0]->X(), node[0]->Y(), node[0]->Z());
285     break;
286
287   default:;
288   }
289   if ( e ) myLastCreatedElems.Append( e );
290   return e;
291 }
292
293 //=======================================================================
294 /*!
295  * \brief Add element
296  */
297 //=======================================================================
298
299 SMDS_MeshElement* SMESH_MeshEditor::AddElement(const vector<int> &       nodeIDs,
300                                                const SMDSAbs_ElementType type,
301                                                const bool                isPoly,
302                                                const int                 ID)
303 {
304   vector<const SMDS_MeshNode*> nodes;
305   nodes.reserve( nodeIDs.size() );
306   vector<int>::const_iterator id = nodeIDs.begin();
307   while ( id != nodeIDs.end() ) {
308     if ( const SMDS_MeshNode* node = GetMeshDS()->FindNode( *id++ ))
309       nodes.push_back( node );
310     else
311       return 0;
312   }
313   return AddElement( nodes, type, isPoly, ID );
314 }
315
316 //=======================================================================
317 //function : Remove
318 //purpose  : Remove a node or an element.
319 //           Modify a compute state of sub-meshes which become empty
320 //=======================================================================
321
322 int SMESH_MeshEditor::Remove (const list< int >& theIDs,
323                               const bool         isNodes )
324 {
325   myLastCreatedElems.Clear();
326   myLastCreatedNodes.Clear();
327
328   SMESHDS_Mesh* aMesh = GetMeshDS();
329   set< SMESH_subMesh *> smmap;
330
331   int removed = 0;
332   list<int>::const_iterator it = theIDs.begin();
333   for ( ; it != theIDs.end(); it++ ) {
334     const SMDS_MeshElement * elem;
335     if ( isNodes )
336       elem = aMesh->FindNode( *it );
337     else
338       elem = aMesh->FindElement( *it );
339     if ( !elem )
340       continue;
341
342     // Notify VERTEX sub-meshes about modification
343     if ( isNodes ) {
344       const SMDS_MeshNode* node = cast2Node( elem );
345       if ( node->GetPosition()->GetTypeOfPosition() == SMDS_TOP_VERTEX )
346         if ( int aShapeID = node->getshapeId() )
347           if ( SMESH_subMesh * sm = GetMesh()->GetSubMeshContaining( aShapeID ) )
348             smmap.insert( sm );
349     }
350     // Find sub-meshes to notify about modification
351     //     SMDS_ElemIteratorPtr nodeIt = elem->nodesIterator();
352     //     while ( nodeIt->more() ) {
353     //       const SMDS_MeshNode* node = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
354     //       const SMDS_PositionPtr& aPosition = node->GetPosition();
355     //       if ( aPosition.get() ) {
356     //         if ( int aShapeID = aPosition->GetShapeId() ) {
357     //           if ( SMESH_subMesh * sm = GetMesh()->GetSubMeshContaining( aShapeID ) )
358     //             smmap.insert( sm );
359     //         }
360     //       }
361     //     }
362
363     // Do remove
364     if ( isNodes )
365       aMesh->RemoveNode( static_cast< const SMDS_MeshNode* >( elem ));
366     else
367       aMesh->RemoveElement( elem );
368     removed++;
369   }
370
371   // Notify sub-meshes about modification
372   if ( !smmap.empty() ) {
373     set< SMESH_subMesh *>::iterator smIt;
374     for ( smIt = smmap.begin(); smIt != smmap.end(); smIt++ )
375       (*smIt)->ComputeStateEngine( SMESH_subMesh::MESH_ENTITY_REMOVED );
376   }
377
378   //   // Check if the whole mesh becomes empty
379   //   if ( SMESH_subMesh * sm = GetMesh()->GetSubMeshContaining( 1 ) )
380   //     sm->ComputeStateEngine( SMESH_subMesh::CHECK_COMPUTE_STATE );
381
382   return removed;
383 }
384
385 //=======================================================================
386 //function : FindShape
387 //purpose  : Return an index of the shape theElem is on
388 //           or zero if a shape not found
389 //=======================================================================
390
391 int SMESH_MeshEditor::FindShape (const SMDS_MeshElement * theElem)
392 {
393   myLastCreatedElems.Clear();
394   myLastCreatedNodes.Clear();
395
396   SMESHDS_Mesh * aMesh = GetMeshDS();
397   if ( aMesh->ShapeToMesh().IsNull() )
398     return 0;
399
400   int aShapeID = theElem->getshapeId();
401   if ( aShapeID < 1 )
402     return 0;
403
404   if ( SMESHDS_SubMesh * sm = aMesh->MeshElements( aShapeID ))
405     if ( sm->Contains( theElem ))
406       return aShapeID;
407
408   if ( theElem->GetType() == SMDSAbs_Node ) {
409     MESSAGE( ":( Error: invalid myShapeId of node " << theElem->GetID() );
410   }
411   else {
412     MESSAGE( ":( Error: invalid myShapeId of element " << theElem->GetID() );
413   }
414
415   TopoDS_Shape aShape; // the shape a node of theElem is on
416   if ( theElem->GetType() != SMDSAbs_Node )
417   {
418     SMDS_ElemIteratorPtr nodeIt = theElem->nodesIterator();
419     while ( nodeIt->more() ) {
420       const SMDS_MeshNode* node = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
421       if ((aShapeID = node->getshapeId()) > 0) {
422         if ( SMESHDS_SubMesh * sm = aMesh->MeshElements( aShapeID ) ) {
423           if ( sm->Contains( theElem ))
424             return aShapeID;
425           if ( aShape.IsNull() )
426             aShape = aMesh->IndexToShape( aShapeID );
427         }
428       }
429     }
430   }
431
432   // None of nodes is on a proper shape,
433   // find the shape among ancestors of aShape on which a node is
434   if ( !aShape.IsNull() ) {
435     TopTools_ListIteratorOfListOfShape ancIt( GetMesh()->GetAncestors( aShape ));
436     for ( ; ancIt.More(); ancIt.Next() ) {
437       SMESHDS_SubMesh * sm = aMesh->MeshElements( ancIt.Value() );
438       if ( sm && sm->Contains( theElem ))
439         return aMesh->ShapeToIndex( ancIt.Value() );
440     }
441   }
442   else
443   {
444     const map<int,SMESHDS_SubMesh*>& id2sm = GetMeshDS()->SubMeshes();
445     map<int,SMESHDS_SubMesh*>::const_iterator id_sm = id2sm.begin();
446     for ( ; id_sm != id2sm.end(); ++id_sm )
447       if ( id_sm->second->Contains( theElem ))
448         return id_sm->first;
449   }
450
451   //MESSAGE ("::FindShape() - SHAPE NOT FOUND")
452   return 0;
453 }
454
455 //=======================================================================
456 //function : IsMedium
457 //purpose  :
458 //=======================================================================
459
460 bool SMESH_MeshEditor::IsMedium(const SMDS_MeshNode*      node,
461                                 const SMDSAbs_ElementType typeToCheck)
462 {
463   bool isMedium = false;
464   SMDS_ElemIteratorPtr it = node->GetInverseElementIterator(typeToCheck);
465   while (it->more() && !isMedium ) {
466     const SMDS_MeshElement* elem = it->next();
467     isMedium = elem->IsMediumNode(node);
468   }
469   return isMedium;
470 }
471
472 //=======================================================================
473 //function : ShiftNodesQuadTria
474 //purpose  : auxilary
475 //           Shift nodes in the array corresponded to quadratic triangle
476 //           example: (0,1,2,3,4,5) -> (1,2,0,4,5,3)
477 //=======================================================================
478 static void ShiftNodesQuadTria(const SMDS_MeshNode* aNodes[])
479 {
480   const SMDS_MeshNode* nd1 = aNodes[0];
481   aNodes[0] = aNodes[1];
482   aNodes[1] = aNodes[2];
483   aNodes[2] = nd1;
484   const SMDS_MeshNode* nd2 = aNodes[3];
485   aNodes[3] = aNodes[4];
486   aNodes[4] = aNodes[5];
487   aNodes[5] = nd2;
488 }
489
490 //=======================================================================
491 //function : edgeConnectivity
492 //purpose  : auxilary 
493 //           return number of the edges connected with the theNode.
494 //           if theEdges has connections with the other type of the
495 //           elements, return -1 
496 //=======================================================================
497 static int nbEdgeConnectivity(const SMDS_MeshNode* theNode)
498 {
499   SMDS_ElemIteratorPtr elemIt = theNode->GetInverseElementIterator();
500   int nb=0;
501   while(elemIt->more()) {
502     elemIt->next();
503     nb++;
504   }
505   return nb;
506 }
507
508
509 //=======================================================================
510 //function : GetNodesFromTwoTria
511 //purpose  : auxilary
512 //           Shift nodes in the array corresponded to quadratic triangle
513 //           example: (0,1,2,3,4,5) -> (1,2,0,4,5,3)
514 //=======================================================================
515 static bool GetNodesFromTwoTria(const SMDS_MeshElement * theTria1,
516                                 const SMDS_MeshElement * theTria2,
517                                 const SMDS_MeshNode* N1[],
518                                 const SMDS_MeshNode* N2[])
519 {
520   SMDS_ElemIteratorPtr it = theTria1->nodesIterator();
521   int i=0;
522   while(i<6) {
523     N1[i] = static_cast<const SMDS_MeshNode*>( it->next() );
524     i++;
525   }
526   if(it->more()) return false;
527   it = theTria2->nodesIterator();
528   i=0;
529   while(i<6) {
530     N2[i] = static_cast<const SMDS_MeshNode*>( it->next() );
531     i++;
532   }
533   if(it->more()) return false;
534
535   int sames[3] = {-1,-1,-1};
536   int nbsames = 0;
537   int j;
538   for(i=0; i<3; i++) {
539     for(j=0; j<3; j++) {
540       if(N1[i]==N2[j]) {
541         sames[i] = j;
542         nbsames++;
543         break;
544       }
545     }
546   }
547   if(nbsames!=2) return false;
548   if(sames[0]>-1) {
549     ShiftNodesQuadTria(N1);
550     if(sames[1]>-1) {
551       ShiftNodesQuadTria(N1);
552     }
553   }
554   i = sames[0] + sames[1] + sames[2];
555   for(; i<2; i++) {
556     ShiftNodesQuadTria(N2);
557   }
558   // now we receive following N1 and N2 (using numeration as above image)
559   // tria1 : (1 2 4 5 9 7)  and  tria2 : (3 4 2 8 9 6)
560   // i.e. first nodes from both arrays determ new diagonal
561   return true;
562 }
563
564 //=======================================================================
565 //function : InverseDiag
566 //purpose  : Replace two neighbour triangles with ones built on the same 4 nodes
567 //           but having other common link.
568 //           Return False if args are improper
569 //=======================================================================
570
571 bool SMESH_MeshEditor::InverseDiag (const SMDS_MeshElement * theTria1,
572                                     const SMDS_MeshElement * theTria2 )
573 {
574   MESSAGE("InverseDiag");
575   myLastCreatedElems.Clear();
576   myLastCreatedNodes.Clear();
577
578   if (!theTria1 || !theTria2)
579     return false;
580
581   const SMDS_VtkFace* F1 = dynamic_cast<const SMDS_VtkFace*>( theTria1 );
582   if (!F1) return false;
583   const SMDS_VtkFace* F2 = dynamic_cast<const SMDS_VtkFace*>( theTria2 );
584   if (!F2) return false;
585   if ((theTria1->GetEntityType() == SMDSEntity_Triangle) &&
586       (theTria2->GetEntityType() == SMDSEntity_Triangle)) {
587
588     //  1 +--+ A  theTria1: ( 1 A B ) A->2 ( 1 2 B ) 1 +--+ A
589     //    | /|    theTria2: ( B A 2 ) B->1 ( 1 A 2 )   |\ |
590     //    |/ |                                         | \|
591     //  B +--+ 2                                     B +--+ 2
592
593     // put nodes in array and find out indices of the same ones
594     const SMDS_MeshNode* aNodes [6];
595     int sameInd [] = { 0, 0, 0, 0, 0, 0 };
596     int i = 0;
597     SMDS_ElemIteratorPtr it = theTria1->nodesIterator();
598     while ( it->more() ) {
599       aNodes[ i ] = static_cast<const SMDS_MeshNode*>( it->next() );
600
601       if ( i > 2 ) // theTria2
602         // find same node of theTria1
603         for ( int j = 0; j < 3; j++ )
604           if ( aNodes[ i ] == aNodes[ j ]) {
605             sameInd[ j ] = i;
606             sameInd[ i ] = j;
607             break;
608           }
609       // next
610       i++;
611       if ( i == 3 ) {
612         if ( it->more() )
613           return false; // theTria1 is not a triangle
614         it = theTria2->nodesIterator();
615       }
616       if ( i == 6 && it->more() )
617         return false; // theTria2 is not a triangle
618     }
619
620     // find indices of 1,2 and of A,B in theTria1
621     int iA = 0, iB = 0, i1 = 0, i2 = 0;
622     for ( i = 0; i < 6; i++ ) {
623       if ( sameInd [ i ] == 0 ) {
624         if ( i < 3 ) i1 = i;
625         else         i2 = i;
626       }
627       else if (i < 3) {
628         if ( iA ) iB = i;
629         else      iA = i;
630       }
631     }
632     // nodes 1 and 2 should not be the same
633     if ( aNodes[ i1 ] == aNodes[ i2 ] )
634       return false;
635
636     // theTria1: A->2
637     aNodes[ iA ] = aNodes[ i2 ];
638     // theTria2: B->1
639     aNodes[ sameInd[ iB ]] = aNodes[ i1 ];
640
641     GetMeshDS()->ChangeElementNodes( theTria1, aNodes, 3 );
642     GetMeshDS()->ChangeElementNodes( theTria2, &aNodes[ 3 ], 3 );
643
644     return true;
645
646   } // end if(F1 && F2)
647
648   // check case of quadratic faces
649   if (theTria1->GetEntityType() != SMDSEntity_Quad_Triangle)
650     return false;
651   if (theTria2->GetEntityType() != SMDSEntity_Quad_Triangle)
652     return false;
653
654   //       5
655   //  1 +--+--+ 2  theTria1: (1 2 4 5 9 7) or (2 4 1 9 7 5) or (4 1 2 7 5 9)
656   //    |    /|    theTria2: (2 3 4 6 8 9) or (3 4 2 8 9 6) or (4 2 3 9 6 8)
657   //    |   / |
658   //  7 +  +  + 6
659   //    | /9  |
660   //    |/    |
661   //  4 +--+--+ 3
662   //       8
663
664   const SMDS_MeshNode* N1 [6];
665   const SMDS_MeshNode* N2 [6];
666   if(!GetNodesFromTwoTria(theTria1,theTria2,N1,N2))
667     return false;
668   // now we receive following N1 and N2 (using numeration as above image)
669   // tria1 : (1 2 4 5 9 7)  and  tria2 : (3 4 2 8 9 6)
670   // i.e. first nodes from both arrays determ new diagonal
671
672   const SMDS_MeshNode* N1new [6];
673   const SMDS_MeshNode* N2new [6];
674   N1new[0] = N1[0];
675   N1new[1] = N2[0];
676   N1new[2] = N2[1];
677   N1new[3] = N1[4];
678   N1new[4] = N2[3];
679   N1new[5] = N1[5];
680   N2new[0] = N1[0];
681   N2new[1] = N1[1];
682   N2new[2] = N2[0];
683   N2new[3] = N1[3];
684   N2new[4] = N2[5];
685   N2new[5] = N1[4];
686   // replaces nodes in faces
687   GetMeshDS()->ChangeElementNodes( theTria1, N1new, 6 );
688   GetMeshDS()->ChangeElementNodes( theTria2, N2new, 6 );
689
690   return true;
691 }
692
693 //=======================================================================
694 //function : findTriangles
695 //purpose  : find triangles sharing theNode1-theNode2 link
696 //=======================================================================
697
698 static bool findTriangles(const SMDS_MeshNode *    theNode1,
699                           const SMDS_MeshNode *    theNode2,
700                           const SMDS_MeshElement*& theTria1,
701                           const SMDS_MeshElement*& theTria2)
702 {
703   if ( !theNode1 || !theNode2 ) return false;
704
705   theTria1 = theTria2 = 0;
706
707   set< const SMDS_MeshElement* > emap;
708   SMDS_ElemIteratorPtr it = theNode1->GetInverseElementIterator(SMDSAbs_Face);
709   while (it->more()) {
710     const SMDS_MeshElement* elem = it->next();
711     if ( elem->NbNodes() == 3 )
712       emap.insert( elem );
713   }
714   it = theNode2->GetInverseElementIterator(SMDSAbs_Face);
715   while (it->more()) {
716     const SMDS_MeshElement* elem = it->next();
717     if ( emap.find( elem ) != emap.end() ) {
718       if ( theTria1 ) {
719         // theTria1 must be element with minimum ID
720         if( theTria1->GetID() < elem->GetID() ) {
721           theTria2 = elem;
722         }
723         else {
724           theTria2 = theTria1;
725           theTria1 = elem;
726         }
727         break;
728       }
729       else {
730         theTria1 = elem;
731       }
732     }
733   }
734   return ( theTria1 && theTria2 );
735 }
736
737 //=======================================================================
738 //function : InverseDiag
739 //purpose  : Replace two neighbour triangles sharing theNode1-theNode2 link
740 //           with ones built on the same 4 nodes but having other common link.
741 //           Return false if proper faces not found
742 //=======================================================================
743
744 bool SMESH_MeshEditor::InverseDiag (const SMDS_MeshNode * theNode1,
745                                     const SMDS_MeshNode * theNode2)
746 {
747   myLastCreatedElems.Clear();
748   myLastCreatedNodes.Clear();
749
750   MESSAGE( "::InverseDiag()" );
751
752   const SMDS_MeshElement *tr1, *tr2;
753   if ( !findTriangles( theNode1, theNode2, tr1, tr2 ))
754     return false;
755
756   const SMDS_VtkFace* F1 = dynamic_cast<const SMDS_VtkFace*>( tr1 );
757   if (!F1) return false;
758   const SMDS_VtkFace* F2 = dynamic_cast<const SMDS_VtkFace*>( tr2 );
759   if (!F2) return false;
760   if ((tr1->GetEntityType() == SMDSEntity_Triangle) &&
761       (tr2->GetEntityType() == SMDSEntity_Triangle)) {
762
763     //  1 +--+ A  tr1: ( 1 A B ) A->2 ( 1 2 B ) 1 +--+ A
764     //    | /|    tr2: ( B A 2 ) B->1 ( 1 A 2 )   |\ |
765     //    |/ |                                    | \|
766     //  B +--+ 2                                B +--+ 2
767
768     // put nodes in array
769     // and find indices of 1,2 and of A in tr1 and of B in tr2
770     int i, iA1 = 0, i1 = 0;
771     const SMDS_MeshNode* aNodes1 [3];
772     SMDS_ElemIteratorPtr it;
773     for (i = 0, it = tr1->nodesIterator(); it->more(); i++ ) {
774       aNodes1[ i ] = static_cast<const SMDS_MeshNode*>( it->next() );
775       if ( aNodes1[ i ] == theNode1 )
776         iA1 = i; // node A in tr1
777       else if ( aNodes1[ i ] != theNode2 )
778         i1 = i;  // node 1
779     }
780     int iB2 = 0, i2 = 0;
781     const SMDS_MeshNode* aNodes2 [3];
782     for (i = 0, it = tr2->nodesIterator(); it->more(); i++ ) {
783       aNodes2[ i ] = static_cast<const SMDS_MeshNode*>( it->next() );
784       if ( aNodes2[ i ] == theNode2 )
785         iB2 = i; // node B in tr2
786       else if ( aNodes2[ i ] != theNode1 )
787         i2 = i;  // node 2
788     }
789
790     // nodes 1 and 2 should not be the same
791     if ( aNodes1[ i1 ] == aNodes2[ i2 ] )
792       return false;
793
794     // tr1: A->2
795     aNodes1[ iA1 ] = aNodes2[ i2 ];
796     // tr2: B->1
797     aNodes2[ iB2 ] = aNodes1[ i1 ];
798
799     GetMeshDS()->ChangeElementNodes( tr1, aNodes1, 3 );
800     GetMeshDS()->ChangeElementNodes( tr2, aNodes2, 3 );
801
802     return true;
803   }
804
805   // check case of quadratic faces
806   return InverseDiag(tr1,tr2);
807 }
808
809 //=======================================================================
810 //function : getQuadrangleNodes
811 //purpose  : fill theQuadNodes - nodes of a quadrangle resulting from
812 //           fusion of triangles tr1 and tr2 having shared link on
813 //           theNode1 and theNode2
814 //=======================================================================
815
816 bool getQuadrangleNodes(const SMDS_MeshNode *    theQuadNodes [],
817                         const SMDS_MeshNode *    theNode1,
818                         const SMDS_MeshNode *    theNode2,
819                         const SMDS_MeshElement * tr1,
820                         const SMDS_MeshElement * tr2 )
821 {
822   if( tr1->NbNodes() != tr2->NbNodes() )
823     return false;
824   // find the 4-th node to insert into tr1
825   const SMDS_MeshNode* n4 = 0;
826   SMDS_ElemIteratorPtr it = tr2->nodesIterator();
827   int i=0;
828   while ( !n4 && i<3 ) {
829     const SMDS_MeshNode * n = cast2Node( it->next() );
830     i++;
831     bool isDiag = ( n == theNode1 || n == theNode2 );
832     if ( !isDiag )
833       n4 = n;
834   }
835   // Make an array of nodes to be in a quadrangle
836   int iNode = 0, iFirstDiag = -1;
837   it = tr1->nodesIterator();
838   i=0;
839   while ( i<3 ) {
840     const SMDS_MeshNode * n = cast2Node( it->next() );
841     i++;
842     bool isDiag = ( n == theNode1 || n == theNode2 );
843     if ( isDiag ) {
844       if ( iFirstDiag < 0 )
845         iFirstDiag = iNode;
846       else if ( iNode - iFirstDiag == 1 )
847         theQuadNodes[ iNode++ ] = n4; // insert the 4-th node between diagonal nodes
848     }
849     else if ( n == n4 ) {
850       return false; // tr1 and tr2 should not have all the same nodes
851     }
852     theQuadNodes[ iNode++ ] = n;
853   }
854   if ( iNode == 3 ) // diagonal nodes have 0 and 2 indices
855     theQuadNodes[ iNode ] = n4;
856
857   return true;
858 }
859
860 //=======================================================================
861 //function : DeleteDiag
862 //purpose  : Replace two neighbour triangles sharing theNode1-theNode2 link
863 //           with a quadrangle built on the same 4 nodes.
864 //           Return false if proper faces not found
865 //=======================================================================
866
867 bool SMESH_MeshEditor::DeleteDiag (const SMDS_MeshNode * theNode1,
868                                    const SMDS_MeshNode * theNode2)
869 {
870   myLastCreatedElems.Clear();
871   myLastCreatedNodes.Clear();
872
873   MESSAGE( "::DeleteDiag()" );
874
875   const SMDS_MeshElement *tr1, *tr2;
876   if ( !findTriangles( theNode1, theNode2, tr1, tr2 ))
877     return false;
878
879   const SMDS_VtkFace* F1 = dynamic_cast<const SMDS_VtkFace*>( tr1 );
880   if (!F1) return false;
881   const SMDS_VtkFace* F2 = dynamic_cast<const SMDS_VtkFace*>( tr2 );
882   if (!F2) return false;
883   SMESHDS_Mesh * aMesh = GetMeshDS();
884
885   if ((tr1->GetEntityType() == SMDSEntity_Triangle) &&
886       (tr2->GetEntityType() == SMDSEntity_Triangle)) {
887
888     const SMDS_MeshNode* aNodes [ 4 ];
889     if ( ! getQuadrangleNodes( aNodes, theNode1, theNode2, tr1, tr2 ))
890       return false;
891
892     const SMDS_MeshElement* newElem = 0;
893     newElem = aMesh->AddFace( aNodes[0], aNodes[1], aNodes[2], aNodes[3] );
894     myLastCreatedElems.Append(newElem);
895     AddToSameGroups( newElem, tr1, aMesh );
896     int aShapeId = tr1->getshapeId();
897     if ( aShapeId )
898       {
899         aMesh->SetMeshElementOnShape( newElem, aShapeId );
900       }
901     aMesh->RemoveElement( tr1 );
902     aMesh->RemoveElement( tr2 );
903
904     return true;
905   }
906
907   // check case of quadratic faces
908   if (tr1->GetEntityType() != SMDSEntity_Quad_Triangle)
909     return false;
910   if (tr2->GetEntityType() != SMDSEntity_Quad_Triangle)
911     return false;
912
913   //       5
914   //  1 +--+--+ 2  tr1: (1 2 4 5 9 7) or (2 4 1 9 7 5) or (4 1 2 7 5 9)
915   //    |    /|    tr2: (2 3 4 6 8 9) or (3 4 2 8 9 6) or (4 2 3 9 6 8)
916   //    |   / |
917   //  7 +  +  + 6
918   //    | /9  |
919   //    |/    |
920   //  4 +--+--+ 3
921   //       8
922
923   const SMDS_MeshNode* N1 [6];
924   const SMDS_MeshNode* N2 [6];
925   if(!GetNodesFromTwoTria(tr1,tr2,N1,N2))
926     return false;
927   // now we receive following N1 and N2 (using numeration as above image)
928   // tria1 : (1 2 4 5 9 7)  and  tria2 : (3 4 2 8 9 6)
929   // i.e. first nodes from both arrays determ new diagonal
930
931   const SMDS_MeshNode* aNodes[8];
932   aNodes[0] = N1[0];
933   aNodes[1] = N1[1];
934   aNodes[2] = N2[0];
935   aNodes[3] = N2[1];
936   aNodes[4] = N1[3];
937   aNodes[5] = N2[5];
938   aNodes[6] = N2[3];
939   aNodes[7] = N1[5];
940
941   const SMDS_MeshElement* newElem = 0;
942   newElem = aMesh->AddFace( aNodes[0], aNodes[1], aNodes[2], aNodes[3],
943                             aNodes[4], aNodes[5], aNodes[6], aNodes[7]);
944   myLastCreatedElems.Append(newElem);
945   AddToSameGroups( newElem, tr1, aMesh );
946   int aShapeId = tr1->getshapeId();
947   if ( aShapeId )
948     {
949       aMesh->SetMeshElementOnShape( newElem, aShapeId );
950     }
951   aMesh->RemoveElement( tr1 );
952   aMesh->RemoveElement( tr2 );
953
954   // remove middle node (9)
955   GetMeshDS()->RemoveNode( N1[4] );
956
957   return true;
958 }
959
960 //=======================================================================
961 //function : Reorient
962 //purpose  : Reverse theElement orientation
963 //=======================================================================
964
965 bool SMESH_MeshEditor::Reorient (const SMDS_MeshElement * theElem)
966 {
967   MESSAGE("Reorient");
968   myLastCreatedElems.Clear();
969   myLastCreatedNodes.Clear();
970
971   if (!theElem)
972     return false;
973   SMDS_ElemIteratorPtr it = theElem->nodesIterator();
974   if ( !it || !it->more() )
975     return false;
976
977   switch ( theElem->GetType() ) {
978
979   case SMDSAbs_Edge:
980   case SMDSAbs_Face: {
981     if(!theElem->IsQuadratic()) {
982       int i = theElem->NbNodes();
983       vector<const SMDS_MeshNode*> aNodes( i );
984       while ( it->more() )
985         aNodes[ --i ]= static_cast<const SMDS_MeshNode*>( it->next() );
986       return GetMeshDS()->ChangeElementNodes( theElem, &aNodes[0], theElem->NbNodes() );
987     }
988     else {
989       // quadratic elements
990       if(theElem->GetType()==SMDSAbs_Edge) {
991         vector<const SMDS_MeshNode*> aNodes(3);
992         aNodes[1]= static_cast<const SMDS_MeshNode*>( it->next() );
993         aNodes[0]= static_cast<const SMDS_MeshNode*>( it->next() );
994         aNodes[2]= static_cast<const SMDS_MeshNode*>( it->next() );
995         return GetMeshDS()->ChangeElementNodes( theElem, &aNodes[0], 3 );
996       }
997       else {
998         int nbn = theElem->NbNodes();
999         vector<const SMDS_MeshNode*> aNodes(nbn);
1000         aNodes[0]= static_cast<const SMDS_MeshNode*>( it->next() );
1001         int i=1;
1002         for(; i<nbn/2; i++) {
1003           aNodes[nbn/2-i]= static_cast<const SMDS_MeshNode*>( it->next() );
1004         }
1005         for(i=0; i<nbn/2; i++) {
1006           aNodes[nbn-i-1]= static_cast<const SMDS_MeshNode*>( it->next() );
1007         }
1008         return GetMeshDS()->ChangeElementNodes( theElem, &aNodes[0], nbn );
1009       }
1010     }
1011   }
1012   case SMDSAbs_Volume: {
1013     if (theElem->IsPoly()) {
1014       // TODO reorient vtk polyhedron
1015       MESSAGE("reorient vtk polyhedron ?");
1016       const SMDS_VtkVolume* aPolyedre =
1017         dynamic_cast<const SMDS_VtkVolume*>( theElem );
1018       if (!aPolyedre) {
1019         MESSAGE("Warning: bad volumic element");
1020         return false;
1021       }
1022
1023       int nbFaces = aPolyedre->NbFaces();
1024       vector<const SMDS_MeshNode *> poly_nodes;
1025       vector<int> quantities (nbFaces);
1026
1027       // reverse each face of the polyedre
1028       for (int iface = 1; iface <= nbFaces; iface++) {
1029         int inode, nbFaceNodes = aPolyedre->NbFaceNodes(iface);
1030         quantities[iface - 1] = nbFaceNodes;
1031
1032         for (inode = nbFaceNodes; inode >= 1; inode--) {
1033           const SMDS_MeshNode* curNode = aPolyedre->GetFaceNode(iface, inode);
1034           poly_nodes.push_back(curNode);
1035         }
1036       }
1037
1038       return GetMeshDS()->ChangePolyhedronNodes( theElem, poly_nodes, quantities );
1039
1040     }
1041     else {
1042       SMDS_VolumeTool vTool;
1043       if ( !vTool.Set( theElem ))
1044         return false;
1045       vTool.Inverse();
1046       MESSAGE("ChangeElementNodes reorient: check vTool.Inverse");
1047       return GetMeshDS()->ChangeElementNodes( theElem, vTool.GetNodes(), vTool.NbNodes() );
1048     }
1049   }
1050   default:;
1051   }
1052
1053   return false;
1054 }
1055
1056 //=======================================================================
1057 //function : getBadRate
1058 //purpose  :
1059 //=======================================================================
1060
1061 static double getBadRate (const SMDS_MeshElement*               theElem,
1062                           SMESH::Controls::NumericalFunctorPtr& theCrit)
1063 {
1064   SMESH::Controls::TSequenceOfXYZ P;
1065   if ( !theElem || !theCrit->GetPoints( theElem, P ))
1066     return 1e100;
1067   return theCrit->GetBadRate( theCrit->GetValue( P ), theElem->NbNodes() );
1068   //return theCrit->GetBadRate( theCrit->GetValue( theElem->GetID() ), theElem->NbNodes() );
1069 }
1070
1071 //=======================================================================
1072 //function : QuadToTri
1073 //purpose  : Cut quadrangles into triangles.
1074 //           theCrit is used to select a diagonal to cut
1075 //=======================================================================
1076
1077 bool SMESH_MeshEditor::QuadToTri (TIDSortedElemSet &                   theElems,
1078                                   SMESH::Controls::NumericalFunctorPtr theCrit)
1079 {
1080   myLastCreatedElems.Clear();
1081   myLastCreatedNodes.Clear();
1082
1083   MESSAGE( "::QuadToTri()" );
1084
1085   if ( !theCrit.get() )
1086     return false;
1087
1088   SMESHDS_Mesh * aMesh = GetMeshDS();
1089
1090   Handle(Geom_Surface) surface;
1091   SMESH_MesherHelper   helper( *GetMesh() );
1092
1093   TIDSortedElemSet::iterator itElem;
1094   for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
1095     const SMDS_MeshElement* elem = *itElem;
1096     if ( !elem || elem->GetType() != SMDSAbs_Face )
1097       continue;
1098     if ( elem->NbCornerNodes() != 4 )
1099       continue;
1100
1101     // retrieve element nodes
1102     vector< const SMDS_MeshNode* > aNodes( elem->begin_nodes(), elem->end_nodes() );
1103
1104     // compare two sets of possible triangles
1105     double aBadRate1, aBadRate2; // to what extent a set is bad
1106     SMDS_FaceOfNodes tr1 ( aNodes[0], aNodes[1], aNodes[2] );
1107     SMDS_FaceOfNodes tr2 ( aNodes[2], aNodes[3], aNodes[0] );
1108     aBadRate1 = getBadRate( &tr1, theCrit ) + getBadRate( &tr2, theCrit );
1109
1110     SMDS_FaceOfNodes tr3 ( aNodes[1], aNodes[2], aNodes[3] );
1111     SMDS_FaceOfNodes tr4 ( aNodes[3], aNodes[0], aNodes[1] );
1112     aBadRate2 = getBadRate( &tr3, theCrit ) + getBadRate( &tr4, theCrit );
1113
1114     int aShapeId = FindShape( elem );
1115     const SMDS_MeshElement* newElem1 = 0;
1116     const SMDS_MeshElement* newElem2 = 0;
1117
1118     if( !elem->IsQuadratic() ) {
1119
1120       // split liner quadrangle
1121
1122       if ( aBadRate1 <= aBadRate2 ) {
1123         // tr1 + tr2 is better
1124         newElem1 = aMesh->AddFace( aNodes[2], aNodes[3], aNodes[0] );
1125         newElem2 = aMesh->AddFace( aNodes[2], aNodes[0], aNodes[1] );
1126       }
1127       else {
1128         // tr3 + tr4 is better
1129         newElem1 = aMesh->AddFace( aNodes[3], aNodes[0], aNodes[1] );
1130         newElem2 = aMesh->AddFace( aNodes[3], aNodes[1], aNodes[2] );
1131       }
1132     }
1133     else {
1134
1135       // split quadratic quadrangle
1136
1137       // get surface elem is on
1138       if ( aShapeId != helper.GetSubShapeID() ) {
1139         surface.Nullify();
1140         TopoDS_Shape shape;
1141         if ( aShapeId > 0 )
1142           shape = aMesh->IndexToShape( aShapeId );
1143         if ( !shape.IsNull() && shape.ShapeType() == TopAbs_FACE ) {
1144           TopoDS_Face face = TopoDS::Face( shape );
1145           surface = BRep_Tool::Surface( face );
1146           if ( !surface.IsNull() )
1147             helper.SetSubShape( shape );
1148         }
1149       }
1150       // find middle point for (0,1,2,3)
1151       // and create a node in this point;
1152       const SMDS_MeshNode* newN = 0;
1153       if ( aNodes.size() == 9 )
1154       {
1155         // SMDSEntity_BiQuad_Quadrangle
1156         newN = aNodes.back();
1157       }
1158       else
1159       {
1160         gp_XYZ p( 0,0,0 );
1161         if ( surface.IsNull() )
1162         {
1163           for ( int i = 0; i < 4; i++ )
1164             p += gp_XYZ(aNodes[i]->X(), aNodes[i]->Y(), aNodes[i]->Z() );
1165           p /= 4;
1166         }
1167         else
1168         {
1169           const SMDS_MeshNode* inFaceNode = 0;
1170           if ( helper.GetNodeUVneedInFaceNode() )
1171             for ( size_t i = 0; i < aNodes.size() && !inFaceNode; ++i )
1172               if ( aNodes[ i ]->GetPosition()->GetTypeOfPosition() == SMDS_TOP_FACE )
1173                 inFaceNode = aNodes[ i ];
1174
1175           TopoDS_Face face = TopoDS::Face( helper.GetSubShape() );
1176           gp_XY uv( 0,0 );
1177           for ( int i = 0; i < 4; i++ )
1178             uv += helper.GetNodeUV( face, aNodes[i], inFaceNode );
1179           uv /= 4.;
1180           p = surface->Value( uv.X(), uv.Y() ).XYZ();
1181         }
1182         newN = aMesh->AddNode( p.X(), p.Y(), p.Z() );
1183         myLastCreatedNodes.Append(newN);
1184       }
1185       // create a new element
1186       if ( aBadRate1 <= aBadRate2 ) {
1187         newElem1 = aMesh->AddFace(aNodes[2], aNodes[3], aNodes[0],
1188                                   aNodes[6], aNodes[7], newN );
1189         newElem2 = aMesh->AddFace(aNodes[2], aNodes[0], aNodes[1],
1190                                   newN,      aNodes[4], aNodes[5] );
1191       }
1192       else {
1193         newElem1 = aMesh->AddFace(aNodes[3], aNodes[0], aNodes[1],
1194                                   aNodes[7], aNodes[4], newN );
1195         newElem2 = aMesh->AddFace(aNodes[3], aNodes[1], aNodes[2],
1196                                   newN,      aNodes[5], aNodes[6] );
1197       }
1198     } // quadratic case
1199
1200     // care of a new element
1201
1202     myLastCreatedElems.Append(newElem1);
1203     myLastCreatedElems.Append(newElem2);
1204     AddToSameGroups( newElem1, elem, aMesh );
1205     AddToSameGroups( newElem2, elem, aMesh );
1206
1207     // put a new triangle on the same shape
1208     if ( aShapeId )
1209       {
1210         aMesh->SetMeshElementOnShape( newElem1, aShapeId );
1211         aMesh->SetMeshElementOnShape( newElem2, aShapeId );
1212       }
1213     aMesh->RemoveElement( elem );
1214   }
1215   return true;
1216 }
1217
1218 //=======================================================================
1219 //function : BestSplit
1220 //purpose  : Find better diagonal for cutting.
1221 //=======================================================================
1222
1223 int SMESH_MeshEditor::BestSplit (const SMDS_MeshElement*              theQuad,
1224                                  SMESH::Controls::NumericalFunctorPtr theCrit)
1225 {
1226   myLastCreatedElems.Clear();
1227   myLastCreatedNodes.Clear();
1228
1229   if (!theCrit.get())
1230     return -1;
1231
1232   if (!theQuad || theQuad->GetType() != SMDSAbs_Face )
1233     return -1;
1234
1235   if( theQuad->NbNodes()==4 ||
1236       (theQuad->NbNodes()==8 && theQuad->IsQuadratic()) ) {
1237
1238     // retrieve element nodes
1239     const SMDS_MeshNode* aNodes [4];
1240     SMDS_ElemIteratorPtr itN = theQuad->nodesIterator();
1241     int i = 0;
1242     //while (itN->more())
1243     while (i<4) {
1244       aNodes[ i++ ] = static_cast<const SMDS_MeshNode*>( itN->next() );
1245     }
1246     // compare two sets of possible triangles
1247     double aBadRate1, aBadRate2; // to what extent a set is bad
1248     SMDS_FaceOfNodes tr1 ( aNodes[0], aNodes[1], aNodes[2] );
1249     SMDS_FaceOfNodes tr2 ( aNodes[2], aNodes[3], aNodes[0] );
1250     aBadRate1 = getBadRate( &tr1, theCrit ) + getBadRate( &tr2, theCrit );
1251
1252     SMDS_FaceOfNodes tr3 ( aNodes[1], aNodes[2], aNodes[3] );
1253     SMDS_FaceOfNodes tr4 ( aNodes[3], aNodes[0], aNodes[1] );
1254     aBadRate2 = getBadRate( &tr3, theCrit ) + getBadRate( &tr4, theCrit );
1255
1256     if (aBadRate1 <= aBadRate2) // tr1 + tr2 is better
1257       return 1; // diagonal 1-3
1258
1259     return 2; // diagonal 2-4
1260   }
1261   return -1;
1262 }
1263
1264 namespace
1265 {
1266   // Methods of splitting volumes into tetra
1267
1268   const int theHexTo5_1[5*4+1] =
1269     {
1270       0, 1, 2, 5,    0, 4, 5, 7,     0, 2, 3, 7,    2, 5, 6, 7,     0, 5, 2, 7,   -1
1271     };
1272   const int theHexTo5_2[5*4+1] =
1273     {
1274       1, 2, 3, 6,    1, 4, 5, 6,     0, 1, 3, 4,    3, 4, 6, 7,     1, 3, 4, 6,   -1
1275     };
1276   const int* theHexTo5[2] = { theHexTo5_1, theHexTo5_2 };
1277
1278   const int theHexTo6_1[6*4+1] =
1279     {
1280       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
1281     };
1282   const int theHexTo6_2[6*4+1] =
1283     {
1284       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
1285     };
1286   const int theHexTo6_3[6*4+1] =
1287     {
1288       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
1289     };
1290   const int theHexTo6_4[6*4+1] =
1291     {
1292       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
1293     };
1294   const int* theHexTo6[4] = { theHexTo6_1, theHexTo6_2, theHexTo6_3, theHexTo6_4 };
1295
1296   const int thePyraTo2_1[2*4+1] =
1297     {
1298       0, 1, 2, 4,    0, 2, 3, 4,   -1
1299     };
1300   const int thePyraTo2_2[2*4+1] =
1301     {
1302       1, 2, 3, 4,    1, 3, 0, 4,   -1
1303     };
1304   const int* thePyraTo2[2] = { thePyraTo2_1, thePyraTo2_2 };
1305
1306   const int thePentaTo3_1[3*4+1] =
1307     {
1308       0, 1, 2, 3,    1, 3, 4, 2,     2, 3, 4, 5,    -1
1309     };
1310   const int thePentaTo3_2[3*4+1] =
1311     {
1312       1, 2, 0, 4,    2, 4, 5, 0,     0, 4, 5, 3,    -1
1313     };
1314   const int thePentaTo3_3[3*4+1] =
1315     {
1316       2, 0, 1, 5,    0, 5, 3, 1,     1, 5, 3, 4,    -1
1317     };
1318   const int thePentaTo3_4[3*4+1] =
1319     {
1320       0, 1, 2, 3,    1, 3, 4, 5,     2, 3, 1, 5,    -1
1321     };
1322   const int thePentaTo3_5[3*4+1] =
1323     {
1324       1, 2, 0, 4,    2, 4, 5, 3,     0, 4, 2, 3,    -1
1325     };
1326   const int thePentaTo3_6[3*4+1] =
1327     {
1328       2, 0, 1, 5,    0, 5, 3, 4,     1, 5, 0, 4,    -1
1329     };
1330   const int* thePentaTo3[6] = { thePentaTo3_1, thePentaTo3_2, thePentaTo3_3,
1331                                 thePentaTo3_4, thePentaTo3_5, thePentaTo3_6 };
1332
1333   struct TTriangleFacet //!< stores indices of three nodes of tetra facet
1334   {
1335     int _n1, _n2, _n3;
1336     TTriangleFacet(int n1, int n2, int n3): _n1(n1), _n2(n2), _n3(n3) {}
1337     bool contains(int n) const { return ( n == _n1 || n == _n2 || n == _n3 ); }
1338     bool hasAdjacentTetra( const SMDS_MeshElement* elem ) const;
1339   };
1340   struct TSplitMethod
1341   {
1342     int        _nbTetra;
1343     const int* _connectivity; //!< foursomes of tetra connectivy finished by -1
1344     bool       _baryNode;     //!< additional node is to be created at cell barycenter
1345     bool       _ownConn;      //!< to delete _connectivity in destructor
1346     map<int, const SMDS_MeshNode*> _faceBaryNode; //!< map face index to node at BC of face
1347
1348     TSplitMethod( int nbTet=0, const int* conn=0, bool addNode=false)
1349       : _nbTetra(nbTet), _connectivity(conn), _baryNode(addNode), _ownConn(false) {}
1350     ~TSplitMethod() { if ( _ownConn ) delete [] _connectivity; _connectivity = 0; }
1351     bool hasFacet( const TTriangleFacet& facet ) const
1352     {
1353       const int* tetConn = _connectivity;
1354       for ( ; tetConn[0] >= 0; tetConn += 4 )
1355         if (( facet.contains( tetConn[0] ) +
1356               facet.contains( tetConn[1] ) +
1357               facet.contains( tetConn[2] ) +
1358               facet.contains( tetConn[3] )) == 3 )
1359           return true;
1360       return false;
1361     }
1362   };
1363
1364   //=======================================================================
1365   /*!
1366    * \brief return TSplitMethod for the given element
1367    */
1368   //=======================================================================
1369
1370   TSplitMethod getSplitMethod( SMDS_VolumeTool& vol, const int theMethodFlags)
1371   {
1372     const int iQ = vol.Element()->IsQuadratic() ? 2 : 1;
1373
1374     // at HEXA_TO_24 method, each face of volume is split into triangles each based on
1375     // an edge and a face barycenter; tertaherdons are based on triangles and
1376     // a volume barycenter
1377     const bool is24TetMode = ( theMethodFlags == SMESH_MeshEditor::HEXA_TO_24 );
1378
1379     // Find out how adjacent volumes are split
1380
1381     vector < list< TTriangleFacet > > triaSplitsByFace( vol.NbFaces() ); // splits of each side
1382     int hasAdjacentSplits = 0, maxTetConnSize = 0;
1383     for ( int iF = 0; iF < vol.NbFaces(); ++iF )
1384     {
1385       int nbNodes = vol.NbFaceNodes( iF ) / iQ;
1386       maxTetConnSize += 4 * ( nbNodes - (is24TetMode ? 0 : 2));
1387       if ( nbNodes < 4 ) continue;
1388
1389       list< TTriangleFacet >& triaSplits = triaSplitsByFace[ iF ];
1390       const int* nInd = vol.GetFaceNodesIndices( iF );
1391       if ( nbNodes == 4 )
1392       {
1393         TTriangleFacet t012( nInd[0*iQ], nInd[1*iQ], nInd[2*iQ] );
1394         TTriangleFacet t123( nInd[1*iQ], nInd[2*iQ], nInd[3*iQ] );
1395         if      ( t012.hasAdjacentTetra( vol.Element() )) triaSplits.push_back( t012 );
1396         else if ( t123.hasAdjacentTetra( vol.Element() )) triaSplits.push_back( t123 );
1397       }
1398       else
1399       {
1400         int iCom = 0; // common node of triangle faces to split into
1401         for ( int iVar = 0; iVar < nbNodes; ++iVar, ++iCom )
1402         {
1403           TTriangleFacet t012( nInd[ iQ * ( iCom             )],
1404                                nInd[ iQ * ( (iCom+1)%nbNodes )],
1405                                nInd[ iQ * ( (iCom+2)%nbNodes )]);
1406           TTriangleFacet t023( nInd[ iQ * ( iCom             )],
1407                                nInd[ iQ * ( (iCom+2)%nbNodes )],
1408                                nInd[ iQ * ( (iCom+3)%nbNodes )]);
1409           if ( t012.hasAdjacentTetra( vol.Element() ) && t023.hasAdjacentTetra( vol.Element() ))
1410           {
1411             triaSplits.push_back( t012 );
1412             triaSplits.push_back( t023 );
1413             break;
1414           }
1415         }
1416       }
1417       if ( !triaSplits.empty() )
1418         hasAdjacentSplits = true;
1419     }
1420
1421     // Among variants of split method select one compliant with adjacent volumes
1422
1423     TSplitMethod method;
1424     if ( !vol.Element()->IsPoly() && !is24TetMode )
1425     {
1426       int nbVariants = 2, nbTet = 0;
1427       const int** connVariants = 0;
1428       switch ( vol.Element()->GetEntityType() )
1429       {
1430       case SMDSEntity_Hexa:
1431       case SMDSEntity_Quad_Hexa:
1432       case SMDSEntity_TriQuad_Hexa:
1433         if ( theMethodFlags == SMESH_MeshEditor::HEXA_TO_5 )
1434           connVariants = theHexTo5, nbTet = 5;
1435         else
1436           connVariants = theHexTo6, nbTet = 6, nbVariants = 4;
1437         break;
1438       case SMDSEntity_Pyramid:
1439       case SMDSEntity_Quad_Pyramid:
1440         connVariants = thePyraTo2;  nbTet = 2;
1441         break;
1442       case SMDSEntity_Penta:
1443       case SMDSEntity_Quad_Penta:
1444         connVariants = thePentaTo3; nbTet = 3; nbVariants = 6;
1445         break;
1446       default:
1447         nbVariants = 0;
1448       }
1449       for ( int variant = 0; variant < nbVariants && method._nbTetra == 0; ++variant )
1450       {
1451         // check method compliancy with adjacent tetras,
1452         // all found splits must be among facets of tetras described by this method
1453         method = TSplitMethod( nbTet, connVariants[variant] );
1454         if ( hasAdjacentSplits && method._nbTetra > 0 )
1455         {
1456           bool facetCreated = true;
1457           for ( int iF = 0; facetCreated && iF < triaSplitsByFace.size(); ++iF )
1458           {
1459             list< TTriangleFacet >::const_iterator facet = triaSplitsByFace[iF].begin();
1460             for ( ; facetCreated && facet != triaSplitsByFace[iF].end(); ++facet )
1461               facetCreated = method.hasFacet( *facet );
1462           }
1463           if ( !facetCreated )
1464             method = TSplitMethod(0); // incompatible method
1465         }
1466       }
1467     }
1468     if ( method._nbTetra < 1 )
1469     {
1470       // No standard method is applicable, use a generic solution:
1471       // each facet of a volume is split into triangles and
1472       // each of triangles and a volume barycenter form a tetrahedron.
1473
1474       const bool isHex27 = ( vol.Element()->GetEntityType() == SMDSEntity_TriQuad_Hexa );
1475
1476       int* connectivity = new int[ maxTetConnSize + 1 ];
1477       method._connectivity = connectivity;
1478       method._ownConn = true;
1479       method._baryNode = !isHex27; // to create central node or not
1480
1481       int connSize = 0;
1482       int baryCenInd = vol.NbNodes() - int( isHex27 );
1483       for ( int iF = 0; iF < vol.NbFaces(); ++iF )
1484       {
1485         const int nbNodes = vol.NbFaceNodes( iF ) / iQ;
1486         const int*   nInd = vol.GetFaceNodesIndices( iF );
1487         // find common node of triangle facets of tetra to create
1488         int iCommon = 0; // index in linear numeration
1489         const list< TTriangleFacet >& triaSplits = triaSplitsByFace[ iF ];
1490         if ( !triaSplits.empty() )
1491         {
1492           // by found facets
1493           const TTriangleFacet* facet = &triaSplits.front();
1494           for ( ; iCommon < nbNodes-1 ; ++iCommon )
1495             if ( facet->contains( nInd[ iQ * iCommon ]) &&
1496                  facet->contains( nInd[ iQ * ((iCommon+2)%nbNodes) ]))
1497               break;
1498         }
1499         else if ( nbNodes > 3 && !is24TetMode )
1500         {
1501           // find the best method of splitting into triangles by aspect ratio
1502           SMESH::Controls::NumericalFunctorPtr aspectRatio( new SMESH::Controls::AspectRatio);
1503           map< double, int > badness2iCommon;
1504           const SMDS_MeshNode** nodes = vol.GetFaceNodes( iF );
1505           int nbVariants = ( nbNodes == 4 ? 2 : nbNodes );
1506           for ( int iVar = 0; iVar < nbVariants; ++iVar, ++iCommon )
1507           {
1508             double badness = 0;
1509             for ( int iLast = iCommon+2; iLast < iCommon+nbNodes; ++iLast )
1510             {
1511               SMDS_FaceOfNodes tria ( nodes[ iQ*( iCommon         )],
1512                                       nodes[ iQ*((iLast-1)%nbNodes)],
1513                                       nodes[ iQ*((iLast  )%nbNodes)]);
1514               badness += getBadRate( &tria, aspectRatio );
1515             }
1516             badness2iCommon.insert( make_pair( badness, iCommon ));
1517           }
1518           // use iCommon with lowest badness
1519           iCommon = badness2iCommon.begin()->second;
1520         }
1521         if ( iCommon >= nbNodes )
1522           iCommon = 0; // something wrong
1523
1524         // fill connectivity of tetrahedra based on a current face
1525         int nbTet = nbNodes - 2;
1526         if ( is24TetMode && nbNodes > 3 && triaSplits.empty())
1527         {
1528           int faceBaryCenInd;
1529           if ( isHex27 )
1530           {
1531             faceBaryCenInd = vol.GetCenterNodeIndex( iF );
1532             method._faceBaryNode[ iF ] = vol.GetNodes()[ faceBaryCenInd ];
1533           }
1534           else
1535           {
1536             method._faceBaryNode[ iF ] = 0;
1537             faceBaryCenInd = baryCenInd + method._faceBaryNode.size();
1538           }
1539           nbTet = nbNodes;
1540           for ( int i = 0; i < nbTet; ++i )
1541           {
1542             int i1 = i, i2 = (i+1) % nbNodes;
1543             if ( !vol.IsFaceExternal( iF )) swap( i1, i2 );
1544             connectivity[ connSize++ ] = nInd[ iQ * i1 ];
1545             connectivity[ connSize++ ] = nInd[ iQ * i2 ];
1546             connectivity[ connSize++ ] = faceBaryCenInd;
1547             connectivity[ connSize++ ] = baryCenInd;
1548           }
1549         }
1550         else
1551         {
1552           for ( int i = 0; i < nbTet; ++i )
1553           {
1554             int i1 = (iCommon+1+i) % nbNodes, i2 = (iCommon+2+i) % nbNodes;
1555             if ( !vol.IsFaceExternal( iF )) swap( i1, i2 );
1556             connectivity[ connSize++ ] = nInd[ iQ * iCommon ];
1557             connectivity[ connSize++ ] = nInd[ iQ * i1 ];
1558             connectivity[ connSize++ ] = nInd[ iQ * i2 ];
1559             connectivity[ connSize++ ] = baryCenInd;
1560           }
1561         }
1562         method._nbTetra += nbTet;
1563
1564       } // loop on volume faces
1565
1566       connectivity[ connSize++ ] = -1;
1567
1568     } // end of generic solution
1569
1570     return method;
1571   }
1572   //================================================================================
1573   /*!
1574    * \brief Check if there is a tetraherdon adjacent to the given element via this facet
1575    */
1576   //================================================================================
1577
1578   bool TTriangleFacet::hasAdjacentTetra( const SMDS_MeshElement* elem ) const
1579   {
1580     // find the tetrahedron including the three nodes of facet
1581     const SMDS_MeshNode* n1 = elem->GetNode(_n1);
1582     const SMDS_MeshNode* n2 = elem->GetNode(_n2);
1583     const SMDS_MeshNode* n3 = elem->GetNode(_n3);
1584     SMDS_ElemIteratorPtr volIt1 = n1->GetInverseElementIterator(SMDSAbs_Volume);
1585     while ( volIt1->more() )
1586     {
1587       const SMDS_MeshElement* v = volIt1->next();
1588       SMDSAbs_EntityType type = v->GetEntityType();
1589       if ( type != SMDSEntity_Tetra && type != SMDSEntity_Quad_Tetra )
1590         continue;
1591       if ( type == SMDSEntity_Quad_Tetra && v->GetNodeIndex( n1 ) > 3 )
1592         continue; // medium node not allowed
1593       const int ind2 = v->GetNodeIndex( n2 );
1594       if ( ind2 < 0 || 3 < ind2 )
1595         continue;
1596       const int ind3 = v->GetNodeIndex( n3 );
1597       if ( ind3 < 0 || 3 < ind3 )
1598         continue;
1599       return true;
1600     }
1601     return false;
1602   }
1603
1604   //=======================================================================
1605   /*!
1606    * \brief A key of a face of volume
1607    */
1608   //=======================================================================
1609
1610   struct TVolumeFaceKey: pair< pair< int, int>, pair< int, int> >
1611   {
1612     TVolumeFaceKey( SMDS_VolumeTool& vol, int iF )
1613     {
1614       TIDSortedNodeSet sortedNodes;
1615       const int iQ = vol.Element()->IsQuadratic() ? 2 : 1;
1616       int nbNodes = vol.NbFaceNodes( iF );
1617       const SMDS_MeshNode** fNodes = vol.GetFaceNodes( iF );
1618       for ( int i = 0; i < nbNodes; i += iQ )
1619         sortedNodes.insert( fNodes[i] );
1620       TIDSortedNodeSet::iterator n = sortedNodes.begin();
1621       first.first   = (*(n++))->GetID();
1622       first.second  = (*(n++))->GetID();
1623       second.first  = (*(n++))->GetID();
1624       second.second = ( sortedNodes.size() > 3 ) ? (*(n++))->GetID() : 0;
1625     }
1626   };
1627 } // namespace
1628
1629 //=======================================================================
1630 //function : SplitVolumesIntoTetra
1631 //purpose  : Split volume elements into tetrahedra.
1632 //=======================================================================
1633
1634 void SMESH_MeshEditor::SplitVolumesIntoTetra (const TIDSortedElemSet & theElems,
1635                                               const int                theMethodFlags)
1636 {
1637   // std-like iterator on coordinates of nodes of mesh element
1638   typedef SMDS_StdIterator< SMESH_TNodeXYZ, SMDS_ElemIteratorPtr > NXyzIterator;
1639   NXyzIterator xyzEnd;
1640
1641   SMDS_VolumeTool    volTool;
1642   SMESH_MesherHelper helper( *GetMesh());
1643
1644   SMESHDS_SubMesh* subMesh = 0;//GetMeshDS()->MeshElements(1);
1645   SMESHDS_SubMesh* fSubMesh = 0;//subMesh;
1646   
1647   SMESH_SequenceOfElemPtr newNodes, newElems;
1648
1649   // map face of volume to it's baricenrtic node
1650   map< TVolumeFaceKey, const SMDS_MeshNode* > volFace2BaryNode;
1651   double bc[3];
1652
1653   TIDSortedElemSet::const_iterator elem = theElems.begin();
1654   for ( ; elem != theElems.end(); ++elem )
1655   {
1656     if ( (*elem)->GetType() != SMDSAbs_Volume )
1657       continue;
1658     SMDSAbs_EntityType geomType = (*elem)->GetEntityType();
1659     if ( geomType == SMDSEntity_Tetra || geomType == SMDSEntity_Quad_Tetra )
1660       continue;
1661
1662     if ( !volTool.Set( *elem, /*ignoreCentralNodes=*/false )) continue; // strange...
1663
1664     TSplitMethod splitMethod = getSplitMethod( volTool, theMethodFlags );
1665     if ( splitMethod._nbTetra < 1 ) continue;
1666
1667     // find submesh to add new tetras to
1668     if ( !subMesh || !subMesh->Contains( *elem ))
1669     {
1670       int shapeID = FindShape( *elem );
1671       helper.SetSubShape( shapeID ); // helper will add tetras to the found submesh
1672       subMesh = GetMeshDS()->MeshElements( shapeID );
1673     }
1674     int iQ;
1675     if ( (*elem)->IsQuadratic() )
1676     {
1677       iQ = 2;
1678       // add quadratic links to the helper
1679       for ( int iF = 0; iF < volTool.NbFaces(); ++iF )
1680       {
1681         const SMDS_MeshNode** fNodes = volTool.GetFaceNodes( iF );
1682         int nbN = volTool.NbFaceNodes( iF ) - bool( volTool.GetCenterNodeIndex(iF) > 0 );
1683         for ( int iN = 0; iN < nbN; iN += iQ )
1684           helper.AddTLinkNode( fNodes[iN], fNodes[iN+2], fNodes[iN+1] );
1685       }
1686       helper.SetIsQuadratic( true );
1687     }
1688     else
1689     {
1690       iQ = 1;
1691       helper.SetIsQuadratic( false );
1692     }
1693     vector<const SMDS_MeshNode*> nodes( (*elem)->begin_nodes(), (*elem)->end_nodes() );
1694     helper.SetElementsOnShape( true );
1695     if ( splitMethod._baryNode )
1696     {
1697       // make a node at barycenter
1698       volTool.GetBaryCenter( bc[0], bc[1], bc[2] );
1699       SMDS_MeshNode* gcNode = helper.AddNode( bc[0], bc[1], bc[2] );
1700       nodes.push_back( gcNode );
1701       newNodes.Append( gcNode );
1702     }
1703     if ( !splitMethod._faceBaryNode.empty() )
1704     {
1705       // make or find baricentric nodes of faces
1706       map<int, const SMDS_MeshNode*>::iterator iF_n = splitMethod._faceBaryNode.begin();
1707       for ( ; iF_n != splitMethod._faceBaryNode.end(); ++iF_n )
1708       {
1709         map< TVolumeFaceKey, const SMDS_MeshNode* >::iterator f_n =
1710           volFace2BaryNode.insert
1711           ( make_pair( TVolumeFaceKey( volTool,iF_n->first ), iF_n->second )).first;
1712         if ( !f_n->second )
1713         {
1714           volTool.GetFaceBaryCenter( iF_n->first, bc[0], bc[1], bc[2] );
1715           newNodes.Append( f_n->second = helper.AddNode( bc[0], bc[1], bc[2] ));
1716         }
1717         nodes.push_back( iF_n->second = f_n->second );
1718       }
1719     }
1720
1721     // make tetras
1722     vector<const SMDS_MeshElement* > tetras( splitMethod._nbTetra ); // splits of a volume
1723     const int* tetConn = splitMethod._connectivity;
1724     for ( int i = 0; i < splitMethod._nbTetra; ++i, tetConn += 4 )
1725       newElems.Append( tetras[ i ] = helper.AddVolume( nodes[ tetConn[0] ],
1726                                                        nodes[ tetConn[1] ],
1727                                                        nodes[ tetConn[2] ],
1728                                                        nodes[ tetConn[3] ]));
1729
1730     ReplaceElemInGroups( *elem, tetras, GetMeshDS() );
1731
1732     // Split faces on sides of the split volume
1733
1734     const SMDS_MeshNode** volNodes = volTool.GetNodes();
1735     for ( int iF = 0; iF < volTool.NbFaces(); ++iF )
1736     {
1737       const int nbNodes = volTool.NbFaceNodes( iF ) / iQ;
1738       if ( nbNodes < 4 ) continue;
1739
1740       // find an existing face
1741       vector<const SMDS_MeshNode*> fNodes( volTool.GetFaceNodes( iF ),
1742                                            volTool.GetFaceNodes( iF ) + volTool.NbFaceNodes( iF ));
1743       while ( const SMDS_MeshElement* face = GetMeshDS()->FindElement( fNodes, SMDSAbs_Face,
1744                                                                        /*noMedium=*/false))
1745       {
1746         // make triangles
1747         helper.SetElementsOnShape( false );
1748         vector< const SMDS_MeshElement* > triangles;
1749
1750         // find submesh to add new triangles in
1751         if ( !fSubMesh || !fSubMesh->Contains( face ))
1752         {
1753           int shapeID = FindShape( face );
1754           fSubMesh = GetMeshDS()->MeshElements( shapeID );
1755         }
1756         map<int, const SMDS_MeshNode*>::iterator iF_n = splitMethod._faceBaryNode.find(iF);
1757         if ( iF_n != splitMethod._faceBaryNode.end() )
1758         {
1759           for ( int iN = 0; iN < nbNodes*iQ; iN += iQ )
1760           {
1761             const SMDS_MeshNode* n1 = fNodes[iN];
1762             const SMDS_MeshNode *n2 = fNodes[(iN+iQ)%(nbNodes*iQ)];
1763             const SMDS_MeshNode *n3 = iF_n->second;
1764             if ( !volTool.IsFaceExternal( iF ))
1765               swap( n2, n3 );
1766             triangles.push_back( helper.AddFace( n1,n2,n3 ));
1767
1768             if ( fSubMesh && n3->getshapeId() < 1 )
1769               fSubMesh->AddNode( n3 );
1770           }
1771         }
1772         else
1773         {
1774           // among possible triangles create ones discribed by split method
1775           const int* nInd = volTool.GetFaceNodesIndices( iF );
1776           int nbVariants = ( nbNodes == 4 ? 2 : nbNodes );
1777           int iCom = 0; // common node of triangle faces to split into
1778           list< TTriangleFacet > facets;
1779           for ( int iVar = 0; iVar < nbVariants; ++iVar, ++iCom )
1780           {
1781             TTriangleFacet t012( nInd[ iQ * ( iCom                )],
1782                                  nInd[ iQ * ( (iCom+1)%nbNodes )],
1783                                  nInd[ iQ * ( (iCom+2)%nbNodes )]);
1784             TTriangleFacet t023( nInd[ iQ * ( iCom                )],
1785                                  nInd[ iQ * ( (iCom+2)%nbNodes )],
1786                                  nInd[ iQ * ( (iCom+3)%nbNodes )]);
1787             if ( splitMethod.hasFacet( t012 ) && splitMethod.hasFacet( t023 ))
1788             {
1789               facets.push_back( t012 );
1790               facets.push_back( t023 );
1791               for ( int iLast = iCom+4; iLast < iCom+nbNodes; ++iLast )
1792                 facets.push_back( TTriangleFacet( nInd[ iQ * ( iCom             )],
1793                                                   nInd[ iQ * ((iLast-1)%nbNodes )],
1794                                                   nInd[ iQ * ((iLast  )%nbNodes )]));
1795               break;
1796             }
1797           }
1798           list< TTriangleFacet >::iterator facet = facets.begin();
1799           for ( ; facet != facets.end(); ++facet )
1800           {
1801             if ( !volTool.IsFaceExternal( iF ))
1802               swap( facet->_n2, facet->_n3 );
1803             triangles.push_back( helper.AddFace( volNodes[ facet->_n1 ],
1804                                                  volNodes[ facet->_n2 ],
1805                                                  volNodes[ facet->_n3 ]));
1806           }
1807         }
1808         for ( int i = 0; i < triangles.size(); ++i )
1809         {
1810           if ( !triangles[i] ) continue;
1811           if ( fSubMesh )
1812             fSubMesh->AddElement( triangles[i]);
1813           newElems.Append( triangles[i] );
1814         }
1815         ReplaceElemInGroups( face, triangles, GetMeshDS() );
1816         GetMeshDS()->RemoveFreeElement( face, fSubMesh, /*fromGroups=*/false );
1817       }
1818
1819     } // loop on volume faces to split them into triangles
1820
1821     GetMeshDS()->RemoveFreeElement( *elem, subMesh, /*fromGroups=*/false );
1822
1823     if ( geomType == SMDSEntity_TriQuad_Hexa )
1824     {
1825       // remove medium nodes that could become free
1826       for ( int i = 20; i < volTool.NbNodes(); ++i )
1827         if ( volNodes[i]->NbInverseElements() == 0 )
1828           GetMeshDS()->RemoveNode( volNodes[i] );
1829     }
1830   } // loop on volumes to split
1831
1832   myLastCreatedNodes = newNodes;
1833   myLastCreatedElems = newElems;
1834 }
1835
1836 //=======================================================================
1837 //function : AddToSameGroups
1838 //purpose  : add elemToAdd to the groups the elemInGroups belongs to
1839 //=======================================================================
1840
1841 void SMESH_MeshEditor::AddToSameGroups (const SMDS_MeshElement* elemToAdd,
1842                                         const SMDS_MeshElement* elemInGroups,
1843                                         SMESHDS_Mesh *          aMesh)
1844 {
1845   const set<SMESHDS_GroupBase*>& groups = aMesh->GetGroups();
1846   if (!groups.empty()) {
1847     set<SMESHDS_GroupBase*>::const_iterator grIt = groups.begin();
1848     for ( ; grIt != groups.end(); grIt++ ) {
1849       SMESHDS_Group* group = dynamic_cast<SMESHDS_Group*>( *grIt );
1850       if ( group && group->Contains( elemInGroups ))
1851         group->SMDSGroup().Add( elemToAdd );
1852     }
1853   }
1854 }
1855
1856
1857 //=======================================================================
1858 //function : RemoveElemFromGroups
1859 //purpose  : Remove removeelem to the groups the elemInGroups belongs to
1860 //=======================================================================
1861 void SMESH_MeshEditor::RemoveElemFromGroups (const SMDS_MeshElement* removeelem,
1862                                              SMESHDS_Mesh *          aMesh)
1863 {
1864   const set<SMESHDS_GroupBase*>& groups = aMesh->GetGroups();
1865   if (!groups.empty())
1866   {
1867     set<SMESHDS_GroupBase*>::const_iterator GrIt = groups.begin();
1868     for (; GrIt != groups.end(); GrIt++)
1869     {
1870       SMESHDS_Group* grp = dynamic_cast<SMESHDS_Group*>(*GrIt);
1871       if (!grp || grp->IsEmpty()) continue;
1872       grp->SMDSGroup().Remove(removeelem);
1873     }
1874   }
1875 }
1876
1877 //================================================================================
1878 /*!
1879  * \brief Replace elemToRm by elemToAdd in the all groups
1880  */
1881 //================================================================================
1882
1883 void SMESH_MeshEditor::ReplaceElemInGroups (const SMDS_MeshElement* elemToRm,
1884                                             const SMDS_MeshElement* elemToAdd,
1885                                             SMESHDS_Mesh *          aMesh)
1886 {
1887   const set<SMESHDS_GroupBase*>& groups = aMesh->GetGroups();
1888   if (!groups.empty()) {
1889     set<SMESHDS_GroupBase*>::const_iterator grIt = groups.begin();
1890     for ( ; grIt != groups.end(); grIt++ ) {
1891       SMESHDS_Group* group = dynamic_cast<SMESHDS_Group*>( *grIt );
1892       if ( group && group->SMDSGroup().Remove( elemToRm ) && elemToAdd )
1893         group->SMDSGroup().Add( elemToAdd );
1894     }
1895   }
1896 }
1897
1898 //================================================================================
1899 /*!
1900  * \brief Replace elemToRm by elemToAdd in the all groups
1901  */
1902 //================================================================================
1903
1904 void SMESH_MeshEditor::ReplaceElemInGroups (const SMDS_MeshElement*                elemToRm,
1905                                             const vector<const SMDS_MeshElement*>& elemToAdd,
1906                                             SMESHDS_Mesh *                         aMesh)
1907 {
1908   const set<SMESHDS_GroupBase*>& groups = aMesh->GetGroups();
1909   if (!groups.empty())
1910   {
1911     set<SMESHDS_GroupBase*>::const_iterator grIt = groups.begin();
1912     for ( ; grIt != groups.end(); grIt++ ) {
1913       SMESHDS_Group* group = dynamic_cast<SMESHDS_Group*>( *grIt );
1914       if ( group && group->SMDSGroup().Remove( elemToRm ) )
1915         for ( int i = 0; i < elemToAdd.size(); ++i )
1916           group->SMDSGroup().Add( elemToAdd[ i ] );
1917     }
1918   }
1919 }
1920
1921 //=======================================================================
1922 //function : QuadToTri
1923 //purpose  : Cut quadrangles into triangles.
1924 //           theCrit is used to select a diagonal to cut
1925 //=======================================================================
1926
1927 bool SMESH_MeshEditor::QuadToTri (TIDSortedElemSet & theElems,
1928                                   const bool         the13Diag)
1929 {
1930   myLastCreatedElems.Clear();
1931   myLastCreatedNodes.Clear();
1932
1933   MESSAGE( "::QuadToTri()" );
1934
1935   SMESHDS_Mesh * aMesh = GetMeshDS();
1936
1937   Handle(Geom_Surface) surface;
1938   SMESH_MesherHelper   helper( *GetMesh() );
1939
1940   TIDSortedElemSet::iterator itElem;
1941   for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
1942     const SMDS_MeshElement* elem = *itElem;
1943     if ( !elem || elem->GetType() != SMDSAbs_Face )
1944       continue;
1945     bool isquad = elem->NbNodes()==4 || elem->NbNodes()==8;
1946     if(!isquad) continue;
1947
1948     if(elem->NbNodes()==4) {
1949       // retrieve element nodes
1950       const SMDS_MeshNode* aNodes [4];
1951       SMDS_ElemIteratorPtr itN = elem->nodesIterator();
1952       int i = 0;
1953       while ( itN->more() )
1954         aNodes[ i++ ] = static_cast<const SMDS_MeshNode*>( itN->next() );
1955
1956       int aShapeId = FindShape( elem );
1957       const SMDS_MeshElement* newElem1 = 0;
1958       const SMDS_MeshElement* newElem2 = 0;
1959       if ( the13Diag ) {
1960         newElem1 = aMesh->AddFace( aNodes[2], aNodes[0], aNodes[1] );
1961         newElem2 = aMesh->AddFace( aNodes[2], aNodes[3], aNodes[0] );
1962       }
1963       else {
1964         newElem1 = aMesh->AddFace( aNodes[3], aNodes[0], aNodes[1] );
1965         newElem2 = aMesh->AddFace( aNodes[3], aNodes[1], aNodes[2] );
1966       }
1967       myLastCreatedElems.Append(newElem1);
1968       myLastCreatedElems.Append(newElem2);
1969       // put a new triangle on the same shape and add to the same groups
1970       if ( aShapeId )
1971         {
1972           aMesh->SetMeshElementOnShape( newElem1, aShapeId );
1973           aMesh->SetMeshElementOnShape( newElem2, aShapeId );
1974         }
1975       AddToSameGroups( newElem1, elem, aMesh );
1976       AddToSameGroups( newElem2, elem, aMesh );
1977       //aMesh->RemoveFreeElement(elem, aMesh->MeshElements(aShapeId), true);
1978       aMesh->RemoveElement( elem );
1979     }
1980
1981     // Quadratic quadrangle
1982
1983     if( elem->NbNodes()==8 && elem->IsQuadratic() ) {
1984
1985       // get surface elem is on
1986       int aShapeId = FindShape( elem );
1987       if ( aShapeId != helper.GetSubShapeID() ) {
1988         surface.Nullify();
1989         TopoDS_Shape shape;
1990         if ( aShapeId > 0 )
1991           shape = aMesh->IndexToShape( aShapeId );
1992         if ( !shape.IsNull() && shape.ShapeType() == TopAbs_FACE ) {
1993           TopoDS_Face face = TopoDS::Face( shape );
1994           surface = BRep_Tool::Surface( face );
1995           if ( !surface.IsNull() )
1996             helper.SetSubShape( shape );
1997         }
1998       }
1999
2000       const SMDS_MeshNode* aNodes [8];
2001       const SMDS_MeshNode* inFaceNode = 0;
2002       SMDS_ElemIteratorPtr itN = elem->nodesIterator();
2003       int i = 0;
2004       while ( itN->more() ) {
2005         aNodes[ i++ ] = static_cast<const SMDS_MeshNode*>( itN->next() );
2006         if ( !inFaceNode && helper.GetNodeUVneedInFaceNode() &&
2007              aNodes[ i-1 ]->GetPosition()->GetTypeOfPosition() == SMDS_TOP_FACE )
2008         {
2009           inFaceNode = aNodes[ i-1 ];
2010         }
2011       }
2012
2013       // find middle point for (0,1,2,3)
2014       // and create a node in this point;
2015       gp_XYZ p( 0,0,0 );
2016       if ( surface.IsNull() ) {
2017         for(i=0; i<4; i++)
2018           p += gp_XYZ(aNodes[i]->X(), aNodes[i]->Y(), aNodes[i]->Z() );
2019         p /= 4;
2020       }
2021       else {
2022         TopoDS_Face geomFace = TopoDS::Face( helper.GetSubShape() );
2023         gp_XY uv( 0,0 );
2024         for(i=0; i<4; i++)
2025           uv += helper.GetNodeUV( geomFace, aNodes[i], inFaceNode );
2026         uv /= 4.;
2027         p = surface->Value( uv.X(), uv.Y() ).XYZ();
2028       }
2029       const SMDS_MeshNode* newN = aMesh->AddNode( p.X(), p.Y(), p.Z() );
2030       myLastCreatedNodes.Append(newN);
2031
2032       // create a new element
2033       const SMDS_MeshElement* newElem1 = 0;
2034       const SMDS_MeshElement* newElem2 = 0;
2035       if ( the13Diag ) {
2036         newElem1 = aMesh->AddFace(aNodes[2], aNodes[3], aNodes[0],
2037                                   aNodes[6], aNodes[7], newN );
2038         newElem2 = aMesh->AddFace(aNodes[2], aNodes[0], aNodes[1],
2039                                   newN,      aNodes[4], aNodes[5] );
2040       }
2041       else {
2042         newElem1 = aMesh->AddFace(aNodes[3], aNodes[0], aNodes[1],
2043                                   aNodes[7], aNodes[4], newN );
2044         newElem2 = aMesh->AddFace(aNodes[3], aNodes[1], aNodes[2],
2045                                   newN,      aNodes[5], aNodes[6] );
2046       }
2047       myLastCreatedElems.Append(newElem1);
2048       myLastCreatedElems.Append(newElem2);
2049       // put a new triangle on the same shape and add to the same groups
2050       if ( aShapeId )
2051         {
2052           aMesh->SetMeshElementOnShape( newElem1, aShapeId );
2053           aMesh->SetMeshElementOnShape( newElem2, aShapeId );
2054         }
2055       AddToSameGroups( newElem1, elem, aMesh );
2056       AddToSameGroups( newElem2, elem, aMesh );
2057       aMesh->RemoveElement( elem );
2058     }
2059   }
2060
2061   return true;
2062 }
2063
2064 //=======================================================================
2065 //function : getAngle
2066 //purpose  :
2067 //=======================================================================
2068
2069 double getAngle(const SMDS_MeshElement * tr1,
2070                 const SMDS_MeshElement * tr2,
2071                 const SMDS_MeshNode *    n1,
2072                 const SMDS_MeshNode *    n2)
2073 {
2074   double angle = 2. * M_PI; // bad angle
2075
2076   // get normals
2077   SMESH::Controls::TSequenceOfXYZ P1, P2;
2078   if ( !SMESH::Controls::NumericalFunctor::GetPoints( tr1, P1 ) ||
2079        !SMESH::Controls::NumericalFunctor::GetPoints( tr2, P2 ))
2080     return angle;
2081   gp_Vec N1,N2;
2082   if(!tr1->IsQuadratic())
2083     N1 = gp_Vec( P1(2) - P1(1) ) ^ gp_Vec( P1(3) - P1(1) );
2084   else
2085     N1 = gp_Vec( P1(3) - P1(1) ) ^ gp_Vec( P1(5) - P1(1) );
2086   if ( N1.SquareMagnitude() <= gp::Resolution() )
2087     return angle;
2088   if(!tr2->IsQuadratic())
2089     N2 = gp_Vec( P2(2) - P2(1) ) ^ gp_Vec( P2(3) - P2(1) );
2090   else
2091     N2 = gp_Vec( P2(3) - P2(1) ) ^ gp_Vec( P2(5) - P2(1) );
2092   if ( N2.SquareMagnitude() <= gp::Resolution() )
2093     return angle;
2094
2095   // find the first diagonal node n1 in the triangles:
2096   // take in account a diagonal link orientation
2097   const SMDS_MeshElement *nFirst[2], *tr[] = { tr1, tr2 };
2098   for ( int t = 0; t < 2; t++ ) {
2099     SMDS_ElemIteratorPtr it = tr[ t ]->nodesIterator();
2100     int i = 0, iDiag = -1;
2101     while ( it->more()) {
2102       const SMDS_MeshElement *n = it->next();
2103       if ( n == n1 || n == n2 ) {
2104         if ( iDiag < 0)
2105           iDiag = i;
2106         else {
2107           if ( i - iDiag == 1 )
2108             nFirst[ t ] = ( n == n1 ? n2 : n1 );
2109           else
2110             nFirst[ t ] = n;
2111           break;
2112         }
2113       }
2114       i++;
2115     }
2116   }
2117   if ( nFirst[ 0 ] == nFirst[ 1 ] )
2118     N2.Reverse();
2119
2120   angle = N1.Angle( N2 );
2121   //SCRUTE( angle );
2122   return angle;
2123 }
2124
2125 // =================================================
2126 // class generating a unique ID for a pair of nodes
2127 // and able to return nodes by that ID
2128 // =================================================
2129 class LinkID_Gen {
2130 public:
2131
2132   LinkID_Gen( const SMESHDS_Mesh* theMesh )
2133     :myMesh( theMesh ), myMaxID( theMesh->MaxNodeID() + 1)
2134   {}
2135
2136   long GetLinkID (const SMDS_MeshNode * n1,
2137                   const SMDS_MeshNode * n2) const
2138   {
2139     return ( Min(n1->GetID(),n2->GetID()) * myMaxID + Max(n1->GetID(),n2->GetID()));
2140   }
2141
2142   bool GetNodes (const long             theLinkID,
2143                  const SMDS_MeshNode* & theNode1,
2144                  const SMDS_MeshNode* & theNode2) const
2145   {
2146     theNode1 = myMesh->FindNode( theLinkID / myMaxID );
2147     if ( !theNode1 ) return false;
2148     theNode2 = myMesh->FindNode( theLinkID % myMaxID );
2149     if ( !theNode2 ) return false;
2150     return true;
2151   }
2152
2153 private:
2154   LinkID_Gen();
2155   const SMESHDS_Mesh* myMesh;
2156   long                myMaxID;
2157 };
2158
2159
2160 //=======================================================================
2161 //function : TriToQuad
2162 //purpose  : Fuse neighbour triangles into quadrangles.
2163 //           theCrit is used to select a neighbour to fuse with.
2164 //           theMaxAngle is a max angle between element normals at which
2165 //           fusion is still performed.
2166 //=======================================================================
2167
2168 bool SMESH_MeshEditor::TriToQuad (TIDSortedElemSet &                   theElems,
2169                                   SMESH::Controls::NumericalFunctorPtr theCrit,
2170                                   const double                         theMaxAngle)
2171 {
2172   myLastCreatedElems.Clear();
2173   myLastCreatedNodes.Clear();
2174
2175   MESSAGE( "::TriToQuad()" );
2176
2177   if ( !theCrit.get() )
2178     return false;
2179
2180   SMESHDS_Mesh * aMesh = GetMeshDS();
2181
2182   // Prepare data for algo: build
2183   // 1. map of elements with their linkIDs
2184   // 2. map of linkIDs with their elements
2185
2186   map< SMESH_TLink, list< const SMDS_MeshElement* > > mapLi_listEl;
2187   map< SMESH_TLink, list< const SMDS_MeshElement* > >::iterator itLE;
2188   map< const SMDS_MeshElement*, set< SMESH_TLink > >  mapEl_setLi;
2189   map< const SMDS_MeshElement*, set< SMESH_TLink > >::iterator itEL;
2190
2191   TIDSortedElemSet::iterator itElem;
2192   for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
2193     const SMDS_MeshElement* elem = *itElem;
2194     if(!elem || elem->GetType() != SMDSAbs_Face ) continue;
2195     bool IsTria = elem->NbNodes()==3 || (elem->NbNodes()==6 && elem->IsQuadratic());
2196     if(!IsTria) continue;
2197
2198     // retrieve element nodes
2199     const SMDS_MeshNode* aNodes [4];
2200     SMDS_ElemIteratorPtr itN = elem->nodesIterator();
2201     int i = 0;
2202     while ( i<3 )
2203       aNodes[ i++ ] = cast2Node( itN->next() );
2204     aNodes[ 3 ] = aNodes[ 0 ];
2205
2206     // fill maps
2207     for ( i = 0; i < 3; i++ ) {
2208       SMESH_TLink link( aNodes[i], aNodes[i+1] );
2209       // check if elements sharing a link can be fused
2210       itLE = mapLi_listEl.find( link );
2211       if ( itLE != mapLi_listEl.end() ) {
2212         if ((*itLE).second.size() > 1 ) // consider only 2 elems adjacent by a link
2213           continue;
2214         const SMDS_MeshElement* elem2 = (*itLE).second.front();
2215         //if ( FindShape( elem ) != FindShape( elem2 ))
2216         //  continue; // do not fuse triangles laying on different shapes
2217         if ( getAngle( elem, elem2, aNodes[i], aNodes[i+1] ) > theMaxAngle )
2218           continue; // avoid making badly shaped quads
2219         (*itLE).second.push_back( elem );
2220       }
2221       else {
2222         mapLi_listEl[ link ].push_back( elem );
2223       }
2224       mapEl_setLi [ elem ].insert( link );
2225     }
2226   }
2227   // Clean the maps from the links shared by a sole element, ie
2228   // links to which only one element is bound in mapLi_listEl
2229
2230   for ( itLE = mapLi_listEl.begin(); itLE != mapLi_listEl.end(); itLE++ ) {
2231     int nbElems = (*itLE).second.size();
2232     if ( nbElems < 2  ) {
2233       const SMDS_MeshElement* elem = (*itLE).second.front();
2234       SMESH_TLink link = (*itLE).first;
2235       mapEl_setLi[ elem ].erase( link );
2236       if ( mapEl_setLi[ elem ].empty() )
2237         mapEl_setLi.erase( elem );
2238     }
2239   }
2240
2241   // Algo: fuse triangles into quadrangles
2242
2243   while ( ! mapEl_setLi.empty() ) {
2244     // Look for the start element:
2245     // the element having the least nb of shared links
2246     const SMDS_MeshElement* startElem = 0;
2247     int minNbLinks = 4;
2248     for ( itEL = mapEl_setLi.begin(); itEL != mapEl_setLi.end(); itEL++ ) {
2249       int nbLinks = (*itEL).second.size();
2250       if ( nbLinks < minNbLinks ) {
2251         startElem = (*itEL).first;
2252         minNbLinks = nbLinks;
2253         if ( minNbLinks == 1 )
2254           break;
2255       }
2256     }
2257
2258     // search elements to fuse starting from startElem or links of elements
2259     // fused earlyer - startLinks
2260     list< SMESH_TLink > startLinks;
2261     while ( startElem || !startLinks.empty() ) {
2262       while ( !startElem && !startLinks.empty() ) {
2263         // Get an element to start, by a link
2264         SMESH_TLink linkId = startLinks.front();
2265         startLinks.pop_front();
2266         itLE = mapLi_listEl.find( linkId );
2267         if ( itLE != mapLi_listEl.end() ) {
2268           list< const SMDS_MeshElement* > & listElem = (*itLE).second;
2269           list< const SMDS_MeshElement* >::iterator itE = listElem.begin();
2270           for ( ; itE != listElem.end() ; itE++ )
2271             if ( mapEl_setLi.find( (*itE) ) != mapEl_setLi.end() )
2272               startElem = (*itE);
2273           mapLi_listEl.erase( itLE );
2274         }
2275       }
2276
2277       if ( startElem ) {
2278         // Get candidates to be fused
2279         const SMDS_MeshElement *tr1 = startElem, *tr2 = 0, *tr3 = 0;
2280         const SMESH_TLink *link12, *link13;
2281         startElem = 0;
2282         ASSERT( mapEl_setLi.find( tr1 ) != mapEl_setLi.end() );
2283         set< SMESH_TLink >& setLi = mapEl_setLi[ tr1 ];
2284         ASSERT( !setLi.empty() );
2285         set< SMESH_TLink >::iterator itLi;
2286         for ( itLi = setLi.begin(); itLi != setLi.end(); itLi++ )
2287         {
2288           const SMESH_TLink & link = (*itLi);
2289           itLE = mapLi_listEl.find( link );
2290           if ( itLE == mapLi_listEl.end() )
2291             continue;
2292
2293           const SMDS_MeshElement* elem = (*itLE).second.front();
2294           if ( elem == tr1 )
2295             elem = (*itLE).second.back();
2296           mapLi_listEl.erase( itLE );
2297           if ( mapEl_setLi.find( elem ) == mapEl_setLi.end())
2298             continue;
2299           if ( tr2 ) {
2300             tr3 = elem;
2301             link13 = &link;
2302           }
2303           else {
2304             tr2 = elem;
2305             link12 = &link;
2306           }
2307
2308           // add other links of elem to list of links to re-start from
2309           set< SMESH_TLink >& links = mapEl_setLi[ elem ];
2310           set< SMESH_TLink >::iterator it;
2311           for ( it = links.begin(); it != links.end(); it++ ) {
2312             const SMESH_TLink& link2 = (*it);
2313             if ( link2 != link )
2314               startLinks.push_back( link2 );
2315           }
2316         }
2317
2318         // Get nodes of possible quadrangles
2319         const SMDS_MeshNode *n12 [4], *n13 [4];
2320         bool Ok12 = false, Ok13 = false;
2321         const SMDS_MeshNode *linkNode1, *linkNode2;
2322         if(tr2) {
2323           linkNode1 = link12->first;
2324           linkNode2 = link12->second;
2325           if ( tr2 && getQuadrangleNodes( n12, linkNode1, linkNode2, tr1, tr2 ))
2326             Ok12 = true;
2327         }
2328         if(tr3) {
2329           linkNode1 = link13->first;
2330           linkNode2 = link13->second;
2331           if ( tr3 && getQuadrangleNodes( n13, linkNode1, linkNode2, tr1, tr3 ))
2332             Ok13 = true;
2333         }
2334
2335         // Choose a pair to fuse
2336         if ( Ok12 && Ok13 ) {
2337           SMDS_FaceOfNodes quad12 ( n12[ 0 ], n12[ 1 ], n12[ 2 ], n12[ 3 ] );
2338           SMDS_FaceOfNodes quad13 ( n13[ 0 ], n13[ 1 ], n13[ 2 ], n13[ 3 ] );
2339           double aBadRate12 = getBadRate( &quad12, theCrit );
2340           double aBadRate13 = getBadRate( &quad13, theCrit );
2341           if (  aBadRate13 < aBadRate12 )
2342             Ok12 = false;
2343           else
2344             Ok13 = false;
2345         }
2346
2347         // Make quadrangles
2348         // and remove fused elems and removed links from the maps
2349         mapEl_setLi.erase( tr1 );
2350         if ( Ok12 ) {
2351           mapEl_setLi.erase( tr2 );
2352           mapLi_listEl.erase( *link12 );
2353           if(tr1->NbNodes()==3) {
2354             const SMDS_MeshElement* newElem = 0;
2355             newElem = aMesh->AddFace(n12[0], n12[1], n12[2], n12[3] );
2356             myLastCreatedElems.Append(newElem);
2357             AddToSameGroups( newElem, tr1, aMesh );
2358             int aShapeId = tr1->getshapeId();
2359             if ( aShapeId )
2360               {
2361                 aMesh->SetMeshElementOnShape( newElem, aShapeId );
2362               }
2363             aMesh->RemoveElement( tr1 );
2364             aMesh->RemoveElement( tr2 );
2365           }
2366           else {
2367             const SMDS_MeshNode* N1 [6];
2368             const SMDS_MeshNode* N2 [6];
2369             GetNodesFromTwoTria(tr1,tr2,N1,N2);
2370             // now we receive following N1 and N2 (using numeration as above image)
2371             // tria1 : (1 2 4 5 9 7)  and  tria2 : (3 4 2 8 9 6)
2372             // i.e. first nodes from both arrays determ new diagonal
2373             const SMDS_MeshNode* aNodes[8];
2374             aNodes[0] = N1[0];
2375             aNodes[1] = N1[1];
2376             aNodes[2] = N2[0];
2377             aNodes[3] = N2[1];
2378             aNodes[4] = N1[3];
2379             aNodes[5] = N2[5];
2380             aNodes[6] = N2[3];
2381             aNodes[7] = N1[5];
2382             const SMDS_MeshElement* newElem = 0;
2383             newElem = aMesh->AddFace(aNodes[0], aNodes[1], aNodes[2], aNodes[3],
2384                                      aNodes[4], aNodes[5], aNodes[6], aNodes[7]);
2385             myLastCreatedElems.Append(newElem);
2386             AddToSameGroups( newElem, tr1, aMesh );
2387             int aShapeId = tr1->getshapeId();
2388             if ( aShapeId )
2389               {
2390                 aMesh->SetMeshElementOnShape( newElem, aShapeId );
2391               }
2392             aMesh->RemoveElement( tr1 );
2393             aMesh->RemoveElement( tr2 );
2394             // remove middle node (9)
2395             GetMeshDS()->RemoveNode( N1[4] );
2396           }
2397         }
2398         else if ( Ok13 ) {
2399           mapEl_setLi.erase( tr3 );
2400           mapLi_listEl.erase( *link13 );
2401           if(tr1->NbNodes()==3) {
2402             const SMDS_MeshElement* newElem = 0;
2403             newElem = aMesh->AddFace(n13[0], n13[1], n13[2], n13[3] );
2404             myLastCreatedElems.Append(newElem);
2405             AddToSameGroups( newElem, tr1, aMesh );
2406             int aShapeId = tr1->getshapeId();
2407             if ( aShapeId )
2408               {
2409                 aMesh->SetMeshElementOnShape( newElem, aShapeId );
2410               }
2411             aMesh->RemoveElement( tr1 );
2412             aMesh->RemoveElement( tr3 );
2413           }
2414           else {
2415             const SMDS_MeshNode* N1 [6];
2416             const SMDS_MeshNode* N2 [6];
2417             GetNodesFromTwoTria(tr1,tr3,N1,N2);
2418             // now we receive following N1 and N2 (using numeration as above image)
2419             // tria1 : (1 2 4 5 9 7)  and  tria2 : (3 4 2 8 9 6)
2420             // i.e. first nodes from both arrays determ new diagonal
2421             const SMDS_MeshNode* aNodes[8];
2422             aNodes[0] = N1[0];
2423             aNodes[1] = N1[1];
2424             aNodes[2] = N2[0];
2425             aNodes[3] = N2[1];
2426             aNodes[4] = N1[3];
2427             aNodes[5] = N2[5];
2428             aNodes[6] = N2[3];
2429             aNodes[7] = N1[5];
2430             const SMDS_MeshElement* newElem = 0;
2431             newElem = aMesh->AddFace(aNodes[0], aNodes[1], aNodes[2], aNodes[3],
2432                                      aNodes[4], aNodes[5], aNodes[6], aNodes[7]);
2433             myLastCreatedElems.Append(newElem);
2434             AddToSameGroups( newElem, tr1, aMesh );
2435             int aShapeId = tr1->getshapeId();
2436             if ( aShapeId )
2437               {
2438                 aMesh->SetMeshElementOnShape( newElem, aShapeId );
2439               }
2440             aMesh->RemoveElement( tr1 );
2441             aMesh->RemoveElement( tr3 );
2442             // remove middle node (9)
2443             GetMeshDS()->RemoveNode( N1[4] );
2444           }
2445         }
2446
2447         // Next element to fuse: the rejected one
2448         if ( tr3 )
2449           startElem = Ok12 ? tr3 : tr2;
2450
2451       } // if ( startElem )
2452     } // while ( startElem || !startLinks.empty() )
2453   } // while ( ! mapEl_setLi.empty() )
2454
2455   return true;
2456 }
2457
2458
2459 /*#define DUMPSO(txt) \
2460 //  cout << txt << endl;
2461 //=============================================================================
2462 //
2463 //
2464 //
2465 //=============================================================================
2466 static void swap( int i1, int i2, int idNodes[], gp_Pnt P[] )
2467 {
2468 if ( i1 == i2 )
2469 return;
2470 int tmp = idNodes[ i1 ];
2471 idNodes[ i1 ] = idNodes[ i2 ];
2472 idNodes[ i2 ] = tmp;
2473 gp_Pnt Ptmp = P[ i1 ];
2474 P[ i1 ] = P[ i2 ];
2475 P[ i2 ] = Ptmp;
2476 DUMPSO( i1 << "(" << idNodes[ i2 ] << ") <-> " << i2 << "(" << idNodes[ i1 ] << ")");
2477 }
2478
2479 //=======================================================================
2480 //function : SortQuadNodes
2481 //purpose  : Set 4 nodes of a quadrangle face in a good order.
2482 //           Swap 1<->2 or 2<->3 nodes and correspondingly return
2483 //           1 or 2 else 0.
2484 //=======================================================================
2485
2486 int SMESH_MeshEditor::SortQuadNodes (const SMDS_Mesh * theMesh,
2487 int               idNodes[] )
2488 {
2489   gp_Pnt P[4];
2490   int i;
2491   for ( i = 0; i < 4; i++ ) {
2492     const SMDS_MeshNode *n = theMesh->FindNode( idNodes[i] );
2493     if ( !n ) return 0;
2494     P[ i ].SetCoord( n->X(), n->Y(), n->Z() );
2495   }
2496
2497   gp_Vec V1(P[0], P[1]);
2498   gp_Vec V2(P[0], P[2]);
2499   gp_Vec V3(P[0], P[3]);
2500
2501   gp_Vec Cross1 = V1 ^ V2;
2502   gp_Vec Cross2 = V2 ^ V3;
2503
2504   i = 0;
2505   if (Cross1.Dot(Cross2) < 0)
2506   {
2507     Cross1 = V2 ^ V1;
2508     Cross2 = V1 ^ V3;
2509
2510     if (Cross1.Dot(Cross2) < 0)
2511       i = 2;
2512     else
2513       i = 1;
2514     swap ( i, i + 1, idNodes, P );
2515
2516     //     for ( int ii = 0; ii < 4; ii++ ) {
2517     //       const SMDS_MeshNode *n = theMesh->FindNode( idNodes[ii] );
2518     //       DUMPSO( ii << "(" << idNodes[ii] <<") : "<<n->X()<<" "<<n->Y()<<" "<<n->Z());
2519     //     }
2520   }
2521   return i;
2522 }
2523
2524 //=======================================================================
2525 //function : SortHexaNodes
2526 //purpose  : Set 8 nodes of a hexahedron in a good order.
2527 //           Return success status
2528 //=======================================================================
2529
2530 bool SMESH_MeshEditor::SortHexaNodes (const SMDS_Mesh * theMesh,
2531                                       int               idNodes[] )
2532 {
2533   gp_Pnt P[8];
2534   int i;
2535   DUMPSO( "INPUT: ========================================");
2536   for ( i = 0; i < 8; i++ ) {
2537     const SMDS_MeshNode *n = theMesh->FindNode( idNodes[i] );
2538     if ( !n ) return false;
2539     P[ i ].SetCoord( n->X(), n->Y(), n->Z() );
2540     DUMPSO( i << "(" << idNodes[i] <<") : "<<n->X()<<" "<<n->Y()<<" "<<n->Z());
2541   }
2542   DUMPSO( "========================================");
2543
2544
2545   set<int> faceNodes;  // ids of bottom face nodes, to be found
2546   set<int> checkedId1; // ids of tried 2-nd nodes
2547   Standard_Real leastDist = DBL_MAX; // dist of the 4-th node from 123 plane
2548   const Standard_Real tol = 1.e-6;   // tolerance to find nodes in plane
2549   int iMin, iLoop1 = 0;
2550
2551   // Loop to try the 2-nd nodes
2552
2553   while ( leastDist > DBL_MIN && ++iLoop1 < 8 )
2554   {
2555     // Find not checked 2-nd node
2556     for ( i = 1; i < 8; i++ )
2557       if ( checkedId1.find( idNodes[i] ) == checkedId1.end() ) {
2558         int id1 = idNodes[i];
2559         swap ( 1, i, idNodes, P );
2560         checkedId1.insert ( id1 );
2561         break;
2562       }
2563
2564     // Find the 3-d node so that 1-2-3 triangle to be on a hexa face,
2565     // ie that all but meybe one (id3 which is on the same face) nodes
2566     // lay on the same side from the triangle plane.
2567
2568     bool manyInPlane = false; // more than 4 nodes lay in plane
2569     int iLoop2 = 0;
2570     while ( ++iLoop2 < 6 ) {
2571
2572       // get 1-2-3 plane coeffs
2573       Standard_Real A, B, C, D;
2574       gp_Vec N = gp_Vec (P[0], P[1]).Crossed( gp_Vec (P[0], P[2]) );
2575       if ( N.SquareMagnitude() > gp::Resolution() )
2576       {
2577         gp_Pln pln ( P[0], N );
2578         pln.Coefficients( A, B, C, D );
2579
2580         // find the node (iMin) closest to pln
2581         Standard_Real dist[ 8 ], minDist = DBL_MAX;
2582         set<int> idInPln;
2583         for ( i = 3; i < 8; i++ ) {
2584           dist[i] = A * P[i].X() + B * P[i].Y() + C * P[i].Z() + D;
2585           if ( fabs( dist[i] ) < minDist ) {
2586             minDist = fabs( dist[i] );
2587             iMin = i;
2588           }
2589           if ( fabs( dist[i] ) <= tol )
2590             idInPln.insert( idNodes[i] );
2591         }
2592
2593         // there should not be more than 4 nodes in bottom plane
2594         if ( idInPln.size() > 1 )
2595         {
2596           DUMPSO( "### idInPln.size() = " << idInPln.size());
2597           // idInPlane does not contain the first 3 nodes
2598           if ( manyInPlane || idInPln.size() == 5)
2599             return false; // all nodes in one plane
2600           manyInPlane = true;
2601
2602           // set the 1-st node to be not in plane
2603           for ( i = 3; i < 8; i++ ) {
2604             if ( idInPln.find( idNodes[ i ] ) == idInPln.end() ) {
2605               DUMPSO( "### Reset 0-th node");
2606               swap( 0, i, idNodes, P );
2607               break;
2608             }
2609           }
2610
2611           // reset to re-check second nodes
2612           leastDist = DBL_MAX;
2613           faceNodes.clear();
2614           checkedId1.clear();
2615           iLoop1 = 0;
2616           break; // from iLoop2;
2617         }
2618
2619         // check that the other 4 nodes are on the same side
2620         bool sameSide = true;
2621         bool isNeg = dist[ iMin == 3 ? 4 : 3 ] <= 0.;
2622         for ( i = 3; sameSide && i < 8; i++ ) {
2623           if ( i != iMin )
2624             sameSide = ( isNeg == dist[i] <= 0.);
2625         }
2626
2627         // keep best solution
2628         if ( sameSide && minDist < leastDist ) {
2629           leastDist = minDist;
2630           faceNodes.clear();
2631           faceNodes.insert( idNodes[ 1 ] );
2632           faceNodes.insert( idNodes[ 2 ] );
2633           faceNodes.insert( idNodes[ iMin ] );
2634           DUMPSO( "loop " << iLoop2 << " id2 " << idNodes[ 1 ] << " id3 " << idNodes[ 2 ]
2635                   << " leastDist = " << leastDist);
2636           if ( leastDist <= DBL_MIN )
2637             break;
2638         }
2639       }
2640
2641       // set next 3-d node to check
2642       int iNext = 2 + iLoop2;
2643       if ( iNext < 8 ) {
2644         DUMPSO( "Try 2-nd");
2645         swap ( 2, iNext, idNodes, P );
2646       }
2647     } // while ( iLoop2 < 6 )
2648   } // iLoop1
2649
2650   if ( faceNodes.empty() ) return false;
2651
2652   // Put the faceNodes in proper places
2653   for ( i = 4; i < 8; i++ ) {
2654     if ( faceNodes.find( idNodes[ i ] ) != faceNodes.end() ) {
2655       // find a place to put
2656       int iTo = 1;
2657       while ( faceNodes.find( idNodes[ iTo ] ) != faceNodes.end() )
2658         iTo++;
2659       DUMPSO( "Set faceNodes");
2660       swap ( iTo, i, idNodes, P );
2661     }
2662   }
2663
2664
2665   // Set nodes of the found bottom face in good order
2666   DUMPSO( " Found bottom face: ");
2667   i = SortQuadNodes( theMesh, idNodes );
2668   if ( i ) {
2669     gp_Pnt Ptmp = P[ i ];
2670     P[ i ] = P[ i+1 ];
2671     P[ i+1 ] = Ptmp;
2672   }
2673   //   else
2674   //     for ( int ii = 0; ii < 4; ii++ ) {
2675   //       const SMDS_MeshNode *n = theMesh->FindNode( idNodes[ii] );
2676   //       DUMPSO( ii << "(" << idNodes[ii] <<") : "<<n->X()<<" "<<n->Y()<<" "<<n->Z());
2677   //    }
2678
2679   // Gravity center of the top and bottom faces
2680   gp_Pnt aGCb = ( P[0].XYZ() + P[1].XYZ() + P[2].XYZ() + P[3].XYZ() ) / 4.;
2681   gp_Pnt aGCt = ( P[4].XYZ() + P[5].XYZ() + P[6].XYZ() + P[7].XYZ() ) / 4.;
2682
2683   // Get direction from the bottom to the top face
2684   gp_Vec upDir ( aGCb, aGCt );
2685   Standard_Real upDirSize = upDir.Magnitude();
2686   if ( upDirSize <= gp::Resolution() ) return false;
2687   upDir / upDirSize;
2688
2689   // Assure that the bottom face normal points up
2690   gp_Vec Nb = gp_Vec (P[0], P[1]).Crossed( gp_Vec (P[0], P[2]) );
2691   Nb += gp_Vec (P[0], P[2]).Crossed( gp_Vec (P[0], P[3]) );
2692   if ( Nb.Dot( upDir ) < 0 ) {
2693     DUMPSO( "Reverse bottom face");
2694     swap( 1, 3, idNodes, P );
2695   }
2696
2697   // Find 5-th node - the one closest to the 1-st among the last 4 nodes.
2698   Standard_Real minDist = DBL_MAX;
2699   for ( i = 4; i < 8; i++ ) {
2700     // projection of P[i] to the plane defined by P[0] and upDir
2701     gp_Pnt Pp = P[i].Translated( upDir * ( upDir.Dot( gp_Vec( P[i], P[0] ))));
2702     Standard_Real sqDist = P[0].SquareDistance( Pp );
2703     if ( sqDist < minDist ) {
2704       minDist = sqDist;
2705       iMin = i;
2706     }
2707   }
2708   DUMPSO( "Set 4-th");
2709   swap ( 4, iMin, idNodes, P );
2710
2711   // Set nodes of the top face in good order
2712   DUMPSO( "Sort top face");
2713   i = SortQuadNodes( theMesh, &idNodes[4] );
2714   if ( i ) {
2715     i += 4;
2716     gp_Pnt Ptmp = P[ i ];
2717     P[ i ] = P[ i+1 ];
2718     P[ i+1 ] = Ptmp;
2719   }
2720
2721   // Assure that direction of the top face normal is from the bottom face
2722   gp_Vec Nt = gp_Vec (P[4], P[5]).Crossed( gp_Vec (P[4], P[6]) );
2723   Nt += gp_Vec (P[4], P[6]).Crossed( gp_Vec (P[4], P[7]) );
2724   if ( Nt.Dot( upDir ) < 0 ) {
2725     DUMPSO( "Reverse top face");
2726     swap( 5, 7, idNodes, P );
2727   }
2728
2729   //   DUMPSO( "OUTPUT: ========================================");
2730   //   for ( i = 0; i < 8; i++ ) {
2731   //     float *p = ugrid->GetPoint(idNodes[i]);
2732   //     DUMPSO( i << "(" << idNodes[i] << ") : " << p[0] << " " << p[1] << " " << p[2]);
2733   //   }
2734
2735   return true;
2736 }*/
2737
2738 //================================================================================
2739 /*!
2740  * \brief Return nodes linked to the given one
2741  * \param theNode - the node
2742  * \param linkedNodes - the found nodes
2743  * \param type - the type of elements to check
2744  *
2745  * Medium nodes are ignored
2746  */
2747 //================================================================================
2748
2749 void SMESH_MeshEditor::GetLinkedNodes( const SMDS_MeshNode* theNode,
2750                                        TIDSortedElemSet &   linkedNodes,
2751                                        SMDSAbs_ElementType  type )
2752 {
2753   SMDS_ElemIteratorPtr elemIt = theNode->GetInverseElementIterator(type);
2754   while ( elemIt->more() )
2755   {
2756     const SMDS_MeshElement* elem = elemIt->next();
2757     if(elem->GetType() == SMDSAbs_0DElement)
2758       continue;
2759     
2760     SMDS_ElemIteratorPtr nodeIt = elem->nodesIterator();
2761     if ( elem->GetType() == SMDSAbs_Volume )
2762     {
2763       SMDS_VolumeTool vol( elem );
2764       while ( nodeIt->more() ) {
2765         const SMDS_MeshNode* n = cast2Node( nodeIt->next() );
2766         if ( theNode != n && vol.IsLinked( theNode, n ))
2767           linkedNodes.insert( n );
2768       }
2769     }
2770     else
2771     {
2772       for ( int i = 0; nodeIt->more(); ++i ) {
2773         const SMDS_MeshNode* n = cast2Node( nodeIt->next() );
2774         if ( n == theNode ) {
2775           int iBefore = i - 1;
2776           int iAfter  = i + 1;
2777           if ( elem->IsQuadratic() ) {
2778             int nb = elem->NbNodes() / 2;
2779             iAfter  = SMESH_MesherHelper::WrapIndex( iAfter, nb );
2780             iBefore = SMESH_MesherHelper::WrapIndex( iBefore, nb );
2781           }
2782           linkedNodes.insert( elem->GetNodeWrap( iAfter ));
2783           linkedNodes.insert( elem->GetNodeWrap( iBefore ));
2784         }
2785       }
2786     }
2787   }
2788 }
2789
2790 //=======================================================================
2791 //function : laplacianSmooth
2792 //purpose  : pulls theNode toward the center of surrounding nodes directly
2793 //           connected to that node along an element edge
2794 //=======================================================================
2795
2796 void laplacianSmooth(const SMDS_MeshNode*                 theNode,
2797                      const Handle(Geom_Surface)&          theSurface,
2798                      map< const SMDS_MeshNode*, gp_XY* >& theUVMap)
2799 {
2800   // find surrounding nodes
2801
2802   TIDSortedElemSet nodeSet;
2803   SMESH_MeshEditor::GetLinkedNodes( theNode, nodeSet, SMDSAbs_Face );
2804
2805   // compute new coodrs
2806
2807   double coord[] = { 0., 0., 0. };
2808   TIDSortedElemSet::iterator nodeSetIt = nodeSet.begin();
2809   for ( ; nodeSetIt != nodeSet.end(); nodeSetIt++ ) {
2810     const SMDS_MeshNode* node = cast2Node(*nodeSetIt);
2811     if ( theSurface.IsNull() ) { // smooth in 3D
2812       coord[0] += node->X();
2813       coord[1] += node->Y();
2814       coord[2] += node->Z();
2815     }
2816     else { // smooth in 2D
2817       ASSERT( theUVMap.find( node ) != theUVMap.end() );
2818       gp_XY* uv = theUVMap[ node ];
2819       coord[0] += uv->X();
2820       coord[1] += uv->Y();
2821     }
2822   }
2823   int nbNodes = nodeSet.size();
2824   if ( !nbNodes )
2825     return;
2826   coord[0] /= nbNodes;
2827   coord[1] /= nbNodes;
2828
2829   if ( !theSurface.IsNull() ) {
2830     ASSERT( theUVMap.find( theNode ) != theUVMap.end() );
2831     theUVMap[ theNode ]->SetCoord( coord[0], coord[1] );
2832     gp_Pnt p3d = theSurface->Value( coord[0], coord[1] );
2833     coord[0] = p3d.X();
2834     coord[1] = p3d.Y();
2835     coord[2] = p3d.Z();
2836   }
2837   else
2838     coord[2] /= nbNodes;
2839
2840   // move node
2841
2842   const_cast< SMDS_MeshNode* >( theNode )->setXYZ(coord[0],coord[1],coord[2]);
2843 }
2844
2845 //=======================================================================
2846 //function : centroidalSmooth
2847 //purpose  : pulls theNode toward the element-area-weighted centroid of the
2848 //           surrounding elements
2849 //=======================================================================
2850
2851 void centroidalSmooth(const SMDS_MeshNode*                 theNode,
2852                       const Handle(Geom_Surface)&          theSurface,
2853                       map< const SMDS_MeshNode*, gp_XY* >& theUVMap)
2854 {
2855   gp_XYZ aNewXYZ(0.,0.,0.);
2856   SMESH::Controls::Area anAreaFunc;
2857   double totalArea = 0.;
2858   int nbElems = 0;
2859
2860   // compute new XYZ
2861
2862   SMDS_ElemIteratorPtr elemIt = theNode->GetInverseElementIterator(SMDSAbs_Face);
2863   while ( elemIt->more() )
2864   {
2865     const SMDS_MeshElement* elem = elemIt->next();
2866     nbElems++;
2867
2868     gp_XYZ elemCenter(0.,0.,0.);
2869     SMESH::Controls::TSequenceOfXYZ aNodePoints;
2870     SMDS_ElemIteratorPtr itN = elem->nodesIterator();
2871     int nn = elem->NbNodes();
2872     if(elem->IsQuadratic()) nn = nn/2;
2873     int i=0;
2874     //while ( itN->more() ) {
2875     while ( i<nn ) {
2876       const SMDS_MeshNode* aNode = static_cast<const SMDS_MeshNode*>( itN->next() );
2877       i++;
2878       gp_XYZ aP( aNode->X(), aNode->Y(), aNode->Z() );
2879       aNodePoints.push_back( aP );
2880       if ( !theSurface.IsNull() ) { // smooth in 2D
2881         ASSERT( theUVMap.find( aNode ) != theUVMap.end() );
2882         gp_XY* uv = theUVMap[ aNode ];
2883         aP.SetCoord( uv->X(), uv->Y(), 0. );
2884       }
2885       elemCenter += aP;
2886     }
2887     double elemArea = anAreaFunc.GetValue( aNodePoints );
2888     totalArea += elemArea;
2889     elemCenter /= nn;
2890     aNewXYZ += elemCenter * elemArea;
2891   }
2892   aNewXYZ /= totalArea;
2893   if ( !theSurface.IsNull() ) {
2894     theUVMap[ theNode ]->SetCoord( aNewXYZ.X(), aNewXYZ.Y() );
2895     aNewXYZ = theSurface->Value( aNewXYZ.X(), aNewXYZ.Y() ).XYZ();
2896   }
2897
2898   // move node
2899
2900   const_cast< SMDS_MeshNode* >( theNode )->setXYZ(aNewXYZ.X(),aNewXYZ.Y(),aNewXYZ.Z());
2901 }
2902
2903 //=======================================================================
2904 //function : getClosestUV
2905 //purpose  : return UV of closest projection
2906 //=======================================================================
2907
2908 static bool getClosestUV (Extrema_GenExtPS& projector,
2909                           const gp_Pnt&     point,
2910                           gp_XY &           result)
2911 {
2912   projector.Perform( point );
2913   if ( projector.IsDone() ) {
2914     double u, v, minVal = DBL_MAX;
2915     for ( int i = projector.NbExt(); i > 0; i-- )
2916 #if OCC_VERSION_LARGE > 0x06040000 // Porting to OCCT6.5.1
2917       if ( projector.SquareDistance( i ) < minVal ) {
2918         minVal = projector.SquareDistance( i );
2919 #else
2920       if ( projector.Value( i ) < minVal ) {
2921         minVal = projector.Value( i );
2922 #endif
2923         projector.Point( i ).Parameter( u, v );
2924       }
2925     result.SetCoord( u, v );
2926     return true;
2927   }
2928   return false;
2929 }
2930
2931 //=======================================================================
2932 //function : Smooth
2933 //purpose  : Smooth theElements during theNbIterations or until a worst
2934 //           element has aspect ratio <= theTgtAspectRatio.
2935 //           Aspect Ratio varies in range [1.0, inf].
2936 //           If theElements is empty, the whole mesh is smoothed.
2937 //           theFixedNodes contains additionally fixed nodes. Nodes built
2938 //           on edges and boundary nodes are always fixed.
2939 //=======================================================================
2940
2941 void SMESH_MeshEditor::Smooth (TIDSortedElemSet &          theElems,
2942                                set<const SMDS_MeshNode*> & theFixedNodes,
2943                                const SmoothMethod          theSmoothMethod,
2944                                const int                   theNbIterations,
2945                                double                      theTgtAspectRatio,
2946                                const bool                  the2D)
2947 {
2948   myLastCreatedElems.Clear();
2949   myLastCreatedNodes.Clear();
2950
2951   MESSAGE((theSmoothMethod==LAPLACIAN ? "LAPLACIAN" : "CENTROIDAL") << "--::Smooth()");
2952
2953   if ( theTgtAspectRatio < 1.0 )
2954     theTgtAspectRatio = 1.0;
2955
2956   const double disttol = 1.e-16;
2957
2958   SMESH::Controls::AspectRatio aQualityFunc;
2959
2960   SMESHDS_Mesh* aMesh = GetMeshDS();
2961
2962   if ( theElems.empty() ) {
2963     // add all faces to theElems
2964     SMDS_FaceIteratorPtr fIt = aMesh->facesIterator();
2965     while ( fIt->more() ) {
2966       const SMDS_MeshElement* face = fIt->next();
2967       theElems.insert( face );
2968     }
2969   }
2970   // get all face ids theElems are on
2971   set< int > faceIdSet;
2972   TIDSortedElemSet::iterator itElem;
2973   if ( the2D )
2974     for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
2975       int fId = FindShape( *itElem );
2976       // check that corresponding submesh exists and a shape is face
2977       if (fId &&
2978           faceIdSet.find( fId ) == faceIdSet.end() &&
2979           aMesh->MeshElements( fId )) {
2980         TopoDS_Shape F = aMesh->IndexToShape( fId );
2981         if ( !F.IsNull() && F.ShapeType() == TopAbs_FACE )
2982           faceIdSet.insert( fId );
2983       }
2984     }
2985   faceIdSet.insert( 0 ); // to smooth elements that are not on any TopoDS_Face
2986
2987   // ===============================================
2988   // smooth elements on each TopoDS_Face separately
2989   // ===============================================
2990
2991   set< int >::reverse_iterator fId = faceIdSet.rbegin(); // treate 0 fId at the end
2992   for ( ; fId != faceIdSet.rend(); ++fId ) {
2993     // get face surface and submesh
2994     Handle(Geom_Surface) surface;
2995     SMESHDS_SubMesh* faceSubMesh = 0;
2996     TopoDS_Face face;
2997     double fToler2 = 0, f,l;
2998     double u1 = 0, u2 = 0, v1 = 0, v2 = 0;
2999     bool isUPeriodic = false, isVPeriodic = false;
3000     if ( *fId ) {
3001       face = TopoDS::Face( aMesh->IndexToShape( *fId ));
3002       surface = BRep_Tool::Surface( face );
3003       faceSubMesh = aMesh->MeshElements( *fId );
3004       fToler2 = BRep_Tool::Tolerance( face );
3005       fToler2 *= fToler2 * 10.;
3006       isUPeriodic = surface->IsUPeriodic();
3007       if ( isUPeriodic )
3008         surface->UPeriod();
3009       isVPeriodic = surface->IsVPeriodic();
3010       if ( isVPeriodic )
3011         surface->VPeriod();
3012       surface->Bounds( u1, u2, v1, v2 );
3013     }
3014     // ---------------------------------------------------------
3015     // for elements on a face, find movable and fixed nodes and
3016     // compute UV for them
3017     // ---------------------------------------------------------
3018     bool checkBoundaryNodes = false;
3019     bool isQuadratic = false;
3020     set<const SMDS_MeshNode*> setMovableNodes;
3021     map< const SMDS_MeshNode*, gp_XY* > uvMap, uvMap2;
3022     list< gp_XY > listUV; // uvs the 2 uvMaps refer to
3023     list< const SMDS_MeshElement* > elemsOnFace;
3024
3025     Extrema_GenExtPS projector;
3026     GeomAdaptor_Surface surfAdaptor;
3027     if ( !surface.IsNull() ) {
3028       surfAdaptor.Load( surface );
3029       projector.Initialize( surfAdaptor, 20,20, 1e-5,1e-5 );
3030     }
3031     int nbElemOnFace = 0;
3032     itElem = theElems.begin();
3033     // loop on not yet smoothed elements: look for elems on a face
3034     while ( itElem != theElems.end() ) {
3035       if ( faceSubMesh && nbElemOnFace == faceSubMesh->NbElements() )
3036         break; // all elements found
3037
3038       const SMDS_MeshElement* elem = *itElem;
3039       if ( !elem || elem->GetType() != SMDSAbs_Face || elem->NbNodes() < 3 ||
3040            ( faceSubMesh && !faceSubMesh->Contains( elem ))) {
3041         ++itElem;
3042         continue;
3043       }
3044       elemsOnFace.push_back( elem );
3045       theElems.erase( itElem++ );
3046       nbElemOnFace++;
3047
3048       if ( !isQuadratic )
3049         isQuadratic = elem->IsQuadratic();
3050
3051       // get movable nodes of elem
3052       const SMDS_MeshNode* node;
3053       SMDS_TypeOfPosition posType;
3054       SMDS_ElemIteratorPtr itN = elem->nodesIterator();
3055       int nn = 0, nbn =  elem->NbNodes();
3056       if(elem->IsQuadratic())
3057         nbn = nbn/2;
3058       while ( nn++ < nbn ) {
3059         node = static_cast<const SMDS_MeshNode*>( itN->next() );
3060         const SMDS_PositionPtr& pos = node->GetPosition();
3061         posType = pos ? pos->GetTypeOfPosition() : SMDS_TOP_3DSPACE;
3062         if (posType != SMDS_TOP_EDGE &&
3063             posType != SMDS_TOP_VERTEX &&
3064             theFixedNodes.find( node ) == theFixedNodes.end())
3065         {
3066           // check if all faces around the node are on faceSubMesh
3067           // because a node on edge may be bound to face
3068           SMDS_ElemIteratorPtr eIt = node->GetInverseElementIterator(SMDSAbs_Face);
3069           bool all = true;
3070           if ( faceSubMesh ) {
3071             while ( eIt->more() && all ) {
3072               const SMDS_MeshElement* e = eIt->next();
3073               all = faceSubMesh->Contains( e );
3074             }
3075           }
3076           if ( all )
3077             setMovableNodes.insert( node );
3078           else
3079             checkBoundaryNodes = true;
3080         }
3081         if ( posType == SMDS_TOP_3DSPACE )
3082           checkBoundaryNodes = true;
3083       }
3084
3085       if ( surface.IsNull() )
3086         continue;
3087
3088       // get nodes to check UV
3089       list< const SMDS_MeshNode* > uvCheckNodes;
3090       itN = elem->nodesIterator();
3091       nn = 0; nbn =  elem->NbNodes();
3092       if(elem->IsQuadratic())
3093         nbn = nbn/2;
3094       while ( nn++ < nbn ) {
3095         node = static_cast<const SMDS_MeshNode*>( itN->next() );
3096         if ( uvMap.find( node ) == uvMap.end() )
3097           uvCheckNodes.push_back( node );
3098         // add nodes of elems sharing node
3099         //         SMDS_ElemIteratorPtr eIt = node->GetInverseElementIterator(SMDSAbs_Face);
3100         //         while ( eIt->more() ) {
3101         //           const SMDS_MeshElement* e = eIt->next();
3102         //           if ( e != elem ) {
3103         //             SMDS_ElemIteratorPtr nIt = e->nodesIterator();
3104         //             while ( nIt->more() ) {
3105         //               const SMDS_MeshNode* n =
3106         //                 static_cast<const SMDS_MeshNode*>( nIt->next() );
3107         //               if ( uvMap.find( n ) == uvMap.end() )
3108         //                 uvCheckNodes.push_back( n );
3109         //             }
3110         //           }
3111         //         }
3112       }
3113       // check UV on face
3114       list< const SMDS_MeshNode* >::iterator n = uvCheckNodes.begin();
3115       for ( ; n != uvCheckNodes.end(); ++n ) {
3116         node = *n;
3117         gp_XY uv( 0, 0 );
3118         const SMDS_PositionPtr& pos = node->GetPosition();
3119         posType = pos ? pos->GetTypeOfPosition() : SMDS_TOP_3DSPACE;
3120         // get existing UV
3121         switch ( posType ) {
3122         case SMDS_TOP_FACE: {
3123           SMDS_FacePosition* fPos = ( SMDS_FacePosition* ) pos;
3124           uv.SetCoord( fPos->GetUParameter(), fPos->GetVParameter() );
3125           break;
3126         }
3127         case SMDS_TOP_EDGE: {
3128           TopoDS_Shape S = aMesh->IndexToShape( node->getshapeId() );
3129           Handle(Geom2d_Curve) pcurve;
3130           if ( !S.IsNull() && S.ShapeType() == TopAbs_EDGE )
3131             pcurve = BRep_Tool::CurveOnSurface( TopoDS::Edge( S ), face, f,l );
3132           if ( !pcurve.IsNull() ) {
3133             double u = (( SMDS_EdgePosition* ) pos )->GetUParameter();
3134             uv = pcurve->Value( u ).XY();
3135           }
3136           break;
3137         }
3138         case SMDS_TOP_VERTEX: {
3139           TopoDS_Shape S = aMesh->IndexToShape( node->getshapeId() );
3140           if ( !S.IsNull() && S.ShapeType() == TopAbs_VERTEX )
3141             uv = BRep_Tool::Parameters( TopoDS::Vertex( S ), face ).XY();
3142           break;
3143         }
3144         default:;
3145         }
3146         // check existing UV
3147         bool project = true;
3148         gp_Pnt pNode ( node->X(), node->Y(), node->Z() );
3149         double dist1 = DBL_MAX, dist2 = 0;
3150         if ( posType != SMDS_TOP_3DSPACE ) {
3151           dist1 = pNode.SquareDistance( surface->Value( uv.X(), uv.Y() ));
3152           project = dist1 > fToler2;
3153         }
3154         if ( project ) { // compute new UV
3155           gp_XY newUV;
3156           if ( !getClosestUV( projector, pNode, newUV )) {
3157             MESSAGE("Node Projection Failed " << node);
3158           }
3159           else {
3160             if ( isUPeriodic )
3161               newUV.SetX( ElCLib::InPeriod( newUV.X(), u1, u2 ));
3162             if ( isVPeriodic )
3163               newUV.SetY( ElCLib::InPeriod( newUV.Y(), v1, v2 ));
3164             // check new UV
3165             if ( posType != SMDS_TOP_3DSPACE )
3166               dist2 = pNode.SquareDistance( surface->Value( newUV.X(), newUV.Y() ));
3167             if ( dist2 < dist1 )
3168               uv = newUV;
3169           }
3170         }
3171         // store UV in the map
3172         listUV.push_back( uv );
3173         uvMap.insert( make_pair( node, &listUV.back() ));
3174       }
3175     } // loop on not yet smoothed elements
3176
3177     if ( !faceSubMesh || nbElemOnFace != faceSubMesh->NbElements() )
3178       checkBoundaryNodes = true;
3179
3180     // fix nodes on mesh boundary
3181
3182     if ( checkBoundaryNodes ) {
3183       map< SMESH_TLink, int > linkNbMap; // how many times a link encounters in elemsOnFace
3184       map< SMESH_TLink, int >::iterator link_nb;
3185       // put all elements links to linkNbMap
3186       list< const SMDS_MeshElement* >::iterator elemIt = elemsOnFace.begin();
3187       for ( ; elemIt != elemsOnFace.end(); ++elemIt ) {
3188         const SMDS_MeshElement* elem = (*elemIt);
3189         int nbn =  elem->NbCornerNodes();
3190         // loop on elem links: insert them in linkNbMap
3191         for ( int iN = 0; iN < nbn; ++iN ) {
3192           const SMDS_MeshNode* n1 = elem->GetNode( iN );
3193           const SMDS_MeshNode* n2 = elem->GetNode(( iN+1 ) % nbn);
3194           SMESH_TLink link( n1, n2 );
3195           link_nb = linkNbMap.insert( make_pair( link, 0 )).first;
3196           link_nb->second++;
3197         }
3198       }
3199       // remove nodes that are in links encountered only once from setMovableNodes
3200       for ( link_nb = linkNbMap.begin(); link_nb != linkNbMap.end(); ++link_nb ) {
3201         if ( link_nb->second == 1 ) {
3202           setMovableNodes.erase( link_nb->first.node1() );
3203           setMovableNodes.erase( link_nb->first.node2() );
3204         }
3205       }
3206     }
3207
3208     // -----------------------------------------------------
3209     // for nodes on seam edge, compute one more UV ( uvMap2 );
3210     // find movable nodes linked to nodes on seam and which
3211     // are to be smoothed using the second UV ( uvMap2 )
3212     // -----------------------------------------------------
3213
3214     set<const SMDS_MeshNode*> nodesNearSeam; // to smooth using uvMap2
3215     if ( !surface.IsNull() ) {
3216       TopExp_Explorer eExp( face, TopAbs_EDGE );
3217       for ( ; eExp.More(); eExp.Next() ) {
3218         TopoDS_Edge edge = TopoDS::Edge( eExp.Current() );
3219         if ( !BRep_Tool::IsClosed( edge, face ))
3220           continue;
3221         SMESHDS_SubMesh* sm = aMesh->MeshElements( edge );
3222         if ( !sm ) continue;
3223         // find out which parameter varies for a node on seam
3224         double f,l;
3225         gp_Pnt2d uv1, uv2;
3226         Handle(Geom2d_Curve) pcurve = BRep_Tool::CurveOnSurface( edge, face, f, l );
3227         if ( pcurve.IsNull() ) continue;
3228         uv1 = pcurve->Value( f );
3229         edge.Reverse();
3230         pcurve = BRep_Tool::CurveOnSurface( edge, face, f, l );
3231         if ( pcurve.IsNull() ) continue;
3232         uv2 = pcurve->Value( f );
3233         int iPar = Abs( uv1.X() - uv2.X() ) > Abs( uv1.Y() - uv2.Y() ) ? 1 : 2;
3234         // assure uv1 < uv2
3235         if ( uv1.Coord( iPar ) > uv2.Coord( iPar )) {
3236           gp_Pnt2d tmp = uv1; uv1 = uv2; uv2 = tmp;
3237         }
3238         // get nodes on seam and its vertices
3239         list< const SMDS_MeshNode* > seamNodes;
3240         SMDS_NodeIteratorPtr nSeamIt = sm->GetNodes();
3241         while ( nSeamIt->more() ) {
3242           const SMDS_MeshNode* node = nSeamIt->next();
3243           if ( !isQuadratic || !IsMedium( node ))
3244             seamNodes.push_back( node );
3245         }
3246         TopExp_Explorer vExp( edge, TopAbs_VERTEX );
3247         for ( ; vExp.More(); vExp.Next() ) {
3248           sm = aMesh->MeshElements( vExp.Current() );
3249           if ( sm ) {
3250             nSeamIt = sm->GetNodes();
3251             while ( nSeamIt->more() )
3252               seamNodes.push_back( nSeamIt->next() );
3253           }
3254         }
3255         // loop on nodes on seam
3256         list< const SMDS_MeshNode* >::iterator noSeIt = seamNodes.begin();
3257         for ( ; noSeIt != seamNodes.end(); ++noSeIt ) {
3258           const SMDS_MeshNode* nSeam = *noSeIt;
3259           map< const SMDS_MeshNode*, gp_XY* >::iterator n_uv = uvMap.find( nSeam );
3260           if ( n_uv == uvMap.end() )
3261             continue;
3262           // set the first UV
3263           n_uv->second->SetCoord( iPar, uv1.Coord( iPar ));
3264           // set the second UV
3265           listUV.push_back( *n_uv->second );
3266           listUV.back().SetCoord( iPar, uv2.Coord( iPar ));
3267           if ( uvMap2.empty() )
3268             uvMap2 = uvMap; // copy the uvMap contents
3269           uvMap2[ nSeam ] = &listUV.back();
3270
3271           // collect movable nodes linked to ones on seam in nodesNearSeam
3272           SMDS_ElemIteratorPtr eIt = nSeam->GetInverseElementIterator(SMDSAbs_Face);
3273           while ( eIt->more() ) {
3274             const SMDS_MeshElement* e = eIt->next();
3275             int nbUseMap1 = 0, nbUseMap2 = 0;
3276             SMDS_ElemIteratorPtr nIt = e->nodesIterator();
3277             int nn = 0, nbn =  e->NbNodes();
3278             if(e->IsQuadratic()) nbn = nbn/2;
3279             while ( nn++ < nbn )
3280             {
3281               const SMDS_MeshNode* n =
3282                 static_cast<const SMDS_MeshNode*>( nIt->next() );
3283               if (n == nSeam ||
3284                   setMovableNodes.find( n ) == setMovableNodes.end() )
3285                 continue;
3286               // add only nodes being closer to uv2 than to uv1
3287               gp_Pnt pMid (0.5 * ( n->X() + nSeam->X() ),
3288                            0.5 * ( n->Y() + nSeam->Y() ),
3289                            0.5 * ( n->Z() + nSeam->Z() ));
3290               gp_XY uv;
3291               getClosestUV( projector, pMid, uv );
3292               if ( uv.Coord( iPar ) > uvMap[ n ]->Coord( iPar ) ) {
3293                 nodesNearSeam.insert( n );
3294                 nbUseMap2++;
3295               }
3296               else
3297                 nbUseMap1++;
3298             }
3299             // for centroidalSmooth all element nodes must
3300             // be on one side of a seam
3301             if ( theSmoothMethod == CENTROIDAL && nbUseMap1 && nbUseMap2 ) {
3302               SMDS_ElemIteratorPtr nIt = e->nodesIterator();
3303               nn = 0;
3304               while ( nn++ < nbn ) {
3305                 const SMDS_MeshNode* n =
3306                   static_cast<const SMDS_MeshNode*>( nIt->next() );
3307                 setMovableNodes.erase( n );
3308               }
3309             }
3310           }
3311         } // loop on nodes on seam
3312       } // loop on edge of a face
3313     } // if ( !face.IsNull() )
3314
3315     if ( setMovableNodes.empty() ) {
3316       MESSAGE( "Face id : " << *fId << " - NO SMOOTHING: no nodes to move!!!");
3317       continue; // goto next face
3318     }
3319
3320     // -------------
3321     // SMOOTHING //
3322     // -------------
3323
3324     int it = -1;
3325     double maxRatio = -1., maxDisplacement = -1.;
3326     set<const SMDS_MeshNode*>::iterator nodeToMove;
3327     for ( it = 0; it < theNbIterations; it++ ) {
3328       maxDisplacement = 0.;
3329       nodeToMove = setMovableNodes.begin();
3330       for ( ; nodeToMove != setMovableNodes.end(); nodeToMove++ ) {
3331         const SMDS_MeshNode* node = (*nodeToMove);
3332         gp_XYZ aPrevPos ( node->X(), node->Y(), node->Z() );
3333
3334         // smooth
3335         bool map2 = ( nodesNearSeam.find( node ) != nodesNearSeam.end() );
3336         if ( theSmoothMethod == LAPLACIAN )
3337           laplacianSmooth( node, surface, map2 ? uvMap2 : uvMap );
3338         else
3339           centroidalSmooth( node, surface, map2 ? uvMap2 : uvMap );
3340
3341         // node displacement
3342         gp_XYZ aNewPos ( node->X(), node->Y(), node->Z() );
3343         Standard_Real aDispl = (aPrevPos - aNewPos).SquareModulus();
3344         if ( aDispl > maxDisplacement )
3345           maxDisplacement = aDispl;
3346       }
3347       // no node movement => exit
3348       //if ( maxDisplacement < 1.e-16 ) {
3349       if ( maxDisplacement < disttol ) {
3350         MESSAGE("-- no node movement --");
3351         break;
3352       }
3353
3354       // check elements quality
3355       maxRatio  = 0;
3356       list< const SMDS_MeshElement* >::iterator elemIt = elemsOnFace.begin();
3357       for ( ; elemIt != elemsOnFace.end(); ++elemIt ) {
3358         const SMDS_MeshElement* elem = (*elemIt);
3359         if ( !elem || elem->GetType() != SMDSAbs_Face )
3360           continue;
3361         SMESH::Controls::TSequenceOfXYZ aPoints;
3362         if ( aQualityFunc.GetPoints( elem, aPoints )) {
3363           double aValue = aQualityFunc.GetValue( aPoints );
3364           if ( aValue > maxRatio )
3365             maxRatio = aValue;
3366         }
3367       }
3368       if ( maxRatio <= theTgtAspectRatio ) {
3369         MESSAGE("-- quality achived --");
3370         break;
3371       }
3372       if (it+1 == theNbIterations) {
3373         MESSAGE("-- Iteration limit exceeded --");
3374       }
3375     } // smoothing iterations
3376
3377     MESSAGE(" Face id: " << *fId <<
3378             " Nb iterstions: " << it <<
3379             " Displacement: " << maxDisplacement <<
3380             " Aspect Ratio " << maxRatio);
3381
3382     // ---------------------------------------
3383     // new nodes positions are computed,
3384     // record movement in DS and set new UV
3385     // ---------------------------------------
3386     nodeToMove = setMovableNodes.begin();
3387     for ( ; nodeToMove != setMovableNodes.end(); nodeToMove++ ) {
3388       SMDS_MeshNode* node = const_cast< SMDS_MeshNode* > (*nodeToMove);
3389       aMesh->MoveNode( node, node->X(), node->Y(), node->Z() );
3390       map< const SMDS_MeshNode*, gp_XY* >::iterator node_uv = uvMap.find( node );
3391       if ( node_uv != uvMap.end() ) {
3392         gp_XY* uv = node_uv->second;
3393         node->SetPosition
3394           ( SMDS_PositionPtr( new SMDS_FacePosition( uv->X(), uv->Y() )));
3395       }
3396     }
3397
3398     // move medium nodes of quadratic elements
3399     if ( isQuadratic )
3400     {
3401       SMESH_MesherHelper helper( *GetMesh() );
3402       if ( !face.IsNull() )
3403         helper.SetSubShape( face );
3404       list< const SMDS_MeshElement* >::iterator elemIt = elemsOnFace.begin();
3405       for ( ; elemIt != elemsOnFace.end(); ++elemIt ) {
3406         const SMDS_VtkFace* QF =
3407           dynamic_cast<const SMDS_VtkFace*> (*elemIt);
3408         if(QF && QF->IsQuadratic()) {
3409           vector<const SMDS_MeshNode*> Ns;
3410           Ns.reserve(QF->NbNodes()+1);
3411           SMDS_ElemIteratorPtr anIter = QF->interlacedNodesElemIterator();
3412           while ( anIter->more() )
3413             Ns.push_back( cast2Node(anIter->next()) );
3414           Ns.push_back( Ns[0] );
3415           double x, y, z;
3416           for(int i=0; i<QF->NbNodes(); i=i+2) {
3417             if ( !surface.IsNull() ) {
3418               gp_XY uv1 = helper.GetNodeUV( face, Ns[i], Ns[i+2] );
3419               gp_XY uv2 = helper.GetNodeUV( face, Ns[i+2], Ns[i] );
3420               gp_XY uv = ( uv1 + uv2 ) / 2.;
3421               gp_Pnt xyz = surface->Value( uv.X(), uv.Y() );
3422               x = xyz.X(); y = xyz.Y(); z = xyz.Z();
3423             }
3424             else {
3425               x = (Ns[i]->X() + Ns[i+2]->X())/2;
3426               y = (Ns[i]->Y() + Ns[i+2]->Y())/2;
3427               z = (Ns[i]->Z() + Ns[i+2]->Z())/2;
3428             }
3429             if( fabs( Ns[i+1]->X() - x ) > disttol ||
3430                 fabs( Ns[i+1]->Y() - y ) > disttol ||
3431                 fabs( Ns[i+1]->Z() - z ) > disttol ) {
3432               // we have to move i+1 node
3433               aMesh->MoveNode( Ns[i+1], x, y, z );
3434             }
3435           }
3436         }
3437       }
3438     }
3439
3440   } // loop on face ids
3441
3442 }
3443
3444 //=======================================================================
3445 //function : isReverse
3446 //purpose  : Return true if normal of prevNodes is not co-directied with
3447 //           gp_Vec(prevNodes[iNotSame],nextNodes[iNotSame]).
3448 //           iNotSame is where prevNodes and nextNodes are different.
3449 //           If result is true then future volume orientation is OK
3450 //=======================================================================
3451
3452 static bool isReverse(const SMDS_MeshElement*             face,
3453                       const vector<const SMDS_MeshNode*>& prevNodes,
3454                       const vector<const SMDS_MeshNode*>& nextNodes,
3455                       const int                           iNotSame)
3456 {
3457
3458   SMESH_TNodeXYZ pP = prevNodes[ iNotSame ];
3459   SMESH_TNodeXYZ pN = nextNodes[ iNotSame ];
3460   gp_XYZ extrDir( pN - pP ), faceNorm;
3461   SMESH_Algo::FaceNormal( face, faceNorm, /*normalized=*/false );
3462
3463   return faceNorm * extrDir < 0.0;
3464 }
3465
3466 //=======================================================================
3467 /*!
3468  * \brief Create elements by sweeping an element
3469  * \param elem - element to sweep
3470  * \param newNodesItVec - nodes generated from each node of the element
3471  * \param newElems - generated elements
3472  * \param nbSteps - number of sweeping steps
3473  * \param srcElements - to append elem for each generated element
3474  */
3475 //=======================================================================
3476
3477 void SMESH_MeshEditor::sweepElement(const SMDS_MeshElement*               elem,
3478                                     const vector<TNodeOfNodeListMapItr> & newNodesItVec,
3479                                     list<const SMDS_MeshElement*>&        newElems,
3480                                     const int                             nbSteps,
3481                                     SMESH_SequenceOfElemPtr&              srcElements)
3482 {
3483   //MESSAGE("sweepElement " << nbSteps);
3484   SMESHDS_Mesh* aMesh = GetMeshDS();
3485
3486   const int           nbNodes = elem->NbNodes();          
3487   const int         nbCorners = elem->NbCornerNodes();
3488   SMDSAbs_EntityType baseType = elem->GetEntityType(); /* it can change in case of 
3489                                                           polyhedron creation !!! */
3490   // Loop on elem nodes:
3491   // find new nodes and detect same nodes indices
3492   vector < list< const SMDS_MeshNode* >::const_iterator > itNN( nbNodes );
3493   vector<const SMDS_MeshNode*> prevNod( nbNodes );
3494   vector<const SMDS_MeshNode*> nextNod( nbNodes );
3495   vector<const SMDS_MeshNode*> midlNod( nbNodes );
3496
3497   int iNode, nbSame = 0, nbDouble = 0, iNotSameNode = 0;
3498   vector<int> sames(nbNodes);
3499   vector<bool> isSingleNode(nbNodes);
3500
3501   for ( iNode = 0; iNode < nbNodes; iNode++ ) {
3502     TNodeOfNodeListMapItr                        nnIt = newNodesItVec[ iNode ];
3503     const SMDS_MeshNode*                         node = nnIt->first;
3504     const list< const SMDS_MeshNode* > & listNewNodes = nnIt->second;
3505     if ( listNewNodes.empty() )
3506       return;
3507
3508     itNN   [ iNode ] = listNewNodes.begin();
3509     prevNod[ iNode ] = node;
3510     nextNod[ iNode ] = listNewNodes.front();
3511
3512     isSingleNode[iNode] = (listNewNodes.size()==nbSteps); /* medium node of quadratic or
3513                                                              corner node of linear */
3514     if ( prevNod[ iNode ] != nextNod [ iNode ])
3515       nbDouble += !isSingleNode[iNode];
3516
3517     if( iNode < nbCorners ) { // check corners only
3518       if ( prevNod[ iNode ] == nextNod [ iNode ])
3519         sames[nbSame++] = iNode;
3520       else
3521         iNotSameNode = iNode;
3522     }
3523   }
3524
3525   if ( nbSame == nbNodes || nbSame > 2) {
3526     MESSAGE( " Too many same nodes of element " << elem->GetID() );
3527     return;
3528   }
3529
3530   if ( elem->GetType() == SMDSAbs_Face && !isReverse( elem, prevNod, nextNod, iNotSameNode ))
3531   {
3532     // fix nodes order to have bottom normal external
3533     if ( baseType == SMDSEntity_Polygon )
3534     {
3535       std::reverse( itNN.begin(), itNN.end() );
3536       std::reverse( prevNod.begin(), prevNod.end() );
3537       std::reverse( midlNod.begin(), midlNod.end() );
3538       std::reverse( nextNod.begin(), nextNod.end() );
3539       std::reverse( isSingleNode.begin(), isSingleNode.end() );
3540     }
3541     else
3542     {
3543       const vector<int>& ind = SMDS_MeshCell::reverseSmdsOrder( baseType );
3544       SMDS_MeshCell::applyInterlace( ind, itNN );
3545       SMDS_MeshCell::applyInterlace( ind, prevNod );
3546       SMDS_MeshCell::applyInterlace( ind, nextNod );
3547       SMDS_MeshCell::applyInterlace( ind, midlNod );
3548       SMDS_MeshCell::applyInterlace( ind, isSingleNode );
3549       if ( nbSame > 0 )
3550       {
3551         sames[nbSame] = iNotSameNode;
3552         for ( int j = 0; j <= nbSame; ++j )
3553           for ( size_t i = 0; i < ind.size(); ++i )
3554             if ( ind[i] == sames[j] )
3555             {
3556               sames[j] = i;
3557               break;
3558             }
3559         iNotSameNode = sames[nbSame];
3560       }
3561     }
3562   }
3563
3564   int iSameNode = 0, iBeforeSame = 0, iAfterSame = 0, iOpposSame = 0;
3565   if ( nbSame > 0 ) {
3566     iSameNode    = sames[ nbSame-1 ];
3567     iBeforeSame  = ( iSameNode + nbCorners - 1 ) % nbCorners;
3568     iAfterSame   = ( iSameNode + 1 ) % nbCorners;
3569     iOpposSame   = ( iSameNode - 2 < 0  ? iSameNode + 2 : iSameNode - 2 );
3570   }
3571
3572   // make new elements
3573   for (int iStep = 0; iStep < nbSteps; iStep++ )
3574   {
3575     // get next nodes
3576     for ( iNode = 0; iNode < nbNodes; iNode++ )
3577     {
3578       midlNod[ iNode ] = isSingleNode[iNode] ? 0 : *itNN[ iNode ]++;
3579       nextNod[ iNode ] = *itNN[ iNode ]++;
3580     }
3581
3582     SMDS_MeshElement* aNewElem = 0;
3583     /*if(!elem->IsPoly())*/ {
3584       switch ( baseType ) {
3585       case SMDSEntity_0D:
3586       case SMDSEntity_Node: { // sweep NODE
3587         if ( nbSame == 0 ) {
3588           if ( isSingleNode[0] )
3589             aNewElem = aMesh->AddEdge( prevNod[ 0 ], nextNod[ 0 ] );
3590           else
3591             aNewElem = aMesh->AddEdge( prevNod[ 0 ], nextNod[ 0 ], midlNod[ 0 ] );
3592         }
3593         else
3594           return;
3595         break;
3596       }
3597       case SMDSEntity_Edge: { // sweep EDGE
3598         if ( nbDouble == 0 )
3599         {
3600           if ( nbSame == 0 ) // ---> quadrangle
3601             aNewElem = aMesh->AddFace(prevNod[ 0 ], prevNod[ 1 ],
3602                                       nextNod[ 1 ], nextNod[ 0 ] );
3603           else               // ---> triangle
3604             aNewElem = aMesh->AddFace(prevNod[ 0 ], prevNod[ 1 ],
3605                                       nextNod[ iNotSameNode ] );
3606         }
3607         else                 // ---> polygon
3608         {
3609           vector<const SMDS_MeshNode*> poly_nodes;
3610           poly_nodes.push_back( prevNod[0] );
3611           poly_nodes.push_back( prevNod[1] );
3612           if ( prevNod[1] != nextNod[1] )
3613           {
3614             if ( midlNod[1]) poly_nodes.push_back( midlNod[1]);
3615             poly_nodes.push_back( nextNod[1] );
3616           }
3617           if ( prevNod[0] != nextNod[0] )
3618           {
3619             poly_nodes.push_back( nextNod[0] );
3620             if ( midlNod[0]) poly_nodes.push_back( midlNod[0]);
3621           }
3622           switch ( poly_nodes.size() ) {
3623           case 3:
3624             aNewElem = aMesh->AddFace( poly_nodes[ 0 ], poly_nodes[ 1 ], poly_nodes[ 2 ]);
3625             break;
3626           case 4:
3627             aNewElem = aMesh->AddFace( poly_nodes[ 0 ], poly_nodes[ 1 ],
3628                                        poly_nodes[ 2 ], poly_nodes[ 3 ]);
3629             break;
3630           default:
3631             aNewElem = aMesh->AddPolygonalFace (poly_nodes);
3632           }
3633         }
3634         break;
3635       }
3636       case SMDSEntity_Triangle: // TRIANGLE --->
3637         {
3638           if ( nbDouble > 0 ) break;
3639           if ( nbSame == 0 )       // ---> pentahedron
3640             aNewElem = aMesh->AddVolume (prevNod[ 0 ], prevNod[ 1 ], prevNod[ 2 ],
3641                                          nextNod[ 0 ], nextNod[ 1 ], nextNod[ 2 ] );
3642
3643           else if ( nbSame == 1 )  // ---> pyramid
3644             aNewElem = aMesh->AddVolume (prevNod[ iBeforeSame ], prevNod[ iAfterSame ],
3645                                          nextNod[ iAfterSame ],  nextNod[ iBeforeSame ],
3646                                          nextNod[ iSameNode ]);
3647
3648           else // 2 same nodes:       ---> tetrahedron
3649             aNewElem = aMesh->AddVolume (prevNod[ 0 ], prevNod[ 1 ], prevNod[ 2 ],
3650                                          nextNod[ iNotSameNode ]);
3651           break;
3652         }
3653       case SMDSEntity_Quad_Edge: // sweep quadratic EDGE --->
3654         {
3655           if ( nbSame == 2 )
3656             return;
3657           if ( nbDouble+nbSame == 2 )
3658           {
3659             if(nbSame==0) {      // ---> quadratic quadrangle
3660               aNewElem = aMesh->AddFace(prevNod[0], prevNod[1], nextNod[1], nextNod[0],
3661                                         prevNod[2], midlNod[1], nextNod[2], midlNod[0]);
3662             }
3663             else { //(nbSame==1) // ---> quadratic triangle
3664               if(sames[0]==2) {
3665                 return; // medium node on axis
3666               }
3667               else if(sames[0]==0)
3668                 aNewElem = aMesh->AddFace(prevNod[0], nextNod[1], prevNod[1],
3669                                           nextNod[2], midlNod[1], prevNod[2]);
3670               else // sames[0]==1
3671                 aNewElem = aMesh->AddFace(prevNod[0], nextNod[0], prevNod[1],
3672                                           midlNod[0], nextNod[2], prevNod[2]);
3673             }
3674           }
3675           else if ( nbDouble == 3 )
3676           {
3677             if ( nbSame == 0 ) {  // ---> bi-quadratic quadrangle
3678               aNewElem = aMesh->AddFace(prevNod[0], prevNod[1], nextNod[1], nextNod[0],
3679                                         prevNod[2], midlNod[1], nextNod[2], midlNod[0], midlNod[2]);
3680             }
3681           }
3682           else
3683             return;
3684           break;
3685         }
3686       case SMDSEntity_Quadrangle: { // sweep QUADRANGLE --->
3687         if ( nbDouble > 0 ) break;
3688
3689         if ( nbSame == 0 )       // ---> hexahedron
3690           aNewElem = aMesh->AddVolume (prevNod[ 0 ], prevNod[ 1 ], prevNod[ 2 ], prevNod[ 3 ],
3691                                        nextNod[ 0 ], nextNod[ 1 ], nextNod[ 2 ], nextNod[ 3 ]);
3692
3693         else if ( nbSame == 1 ) { // ---> pyramid + pentahedron
3694           aNewElem = aMesh->AddVolume (prevNod[ iBeforeSame ], prevNod[ iAfterSame ],
3695                                        nextNod[ iAfterSame ],  nextNod[ iBeforeSame ],
3696                                        nextNod[ iSameNode ]);
3697           newElems.push_back( aNewElem );
3698           aNewElem = aMesh->AddVolume (prevNod[ iAfterSame ],  prevNod[ iOpposSame ],
3699                                        prevNod[ iBeforeSame ], nextNod[ iAfterSame ],
3700                                        nextNod[ iOpposSame ],  nextNod[ iBeforeSame ] );
3701         }
3702         else if ( nbSame == 2 ) { // ---> pentahedron
3703           if ( prevNod[ iBeforeSame ] == nextNod[ iBeforeSame ] )
3704             // iBeforeSame is same too
3705             aNewElem = aMesh->AddVolume (prevNod[ iBeforeSame ], prevNod[ iOpposSame ],
3706                                          nextNod[ iOpposSame ],  prevNod[ iSameNode ],
3707                                          prevNod[ iAfterSame ],  nextNod[ iAfterSame ]);
3708           else
3709             // iAfterSame is same too
3710             aNewElem = aMesh->AddVolume (prevNod[ iSameNode ],   prevNod[ iBeforeSame ],
3711                                          nextNod[ iBeforeSame ], prevNod[ iAfterSame ],
3712                                          prevNod[ iOpposSame ],  nextNod[ iOpposSame ]);
3713         }
3714         break;
3715       }
3716       case SMDSEntity_Quad_Triangle: { // sweep Quadratic TRIANGLE --->
3717         if ( nbDouble+nbSame != 3 ) break;
3718         if(nbSame==0) {
3719           // --->  pentahedron with 15 nodes
3720           aNewElem = aMesh->AddVolume (prevNod[0], prevNod[1], prevNod[2],
3721                                        nextNod[0], nextNod[1], nextNod[2],
3722                                        prevNod[3], prevNod[4], prevNod[5],
3723                                        nextNod[3], nextNod[4], nextNod[5],
3724                                        midlNod[0], midlNod[1], midlNod[2]);
3725         }
3726         else if(nbSame==1) {
3727           // --->  2d order pyramid of 13 nodes
3728           int apex = iSameNode;
3729           int i0 = ( apex + 1 ) % nbCorners;
3730           int i1 = ( apex - 1 + nbCorners ) % nbCorners;
3731           int i0a = apex + 3;
3732           int i1a = i1 + 3;
3733           int i01 = i0 + 3;
3734           aNewElem = aMesh->AddVolume(prevNod[i1], prevNod[i0],
3735                                       nextNod[i0], nextNod[i1], prevNod[apex],
3736                                       prevNod[i01], midlNod[i0],
3737                                       nextNod[i01], midlNod[i1],
3738                                       prevNod[i1a], prevNod[i0a],
3739                                       nextNod[i0a], nextNod[i1a]);
3740         }
3741         else if(nbSame==2) {
3742           // --->  2d order tetrahedron of 10 nodes
3743           int n1 = iNotSameNode;
3744           int n2 = ( n1 + 1             ) % nbCorners;
3745           int n3 = ( n1 + nbCorners - 1 ) % nbCorners;
3746           int n12 = n1 + 3;
3747           int n23 = n2 + 3;
3748           int n31 = n3 + 3;
3749           aNewElem = aMesh->AddVolume (prevNod[n1], prevNod[n2], prevNod[n3], nextNod[n1],
3750                                        prevNod[n12], prevNod[n23], prevNod[n31],
3751                                        midlNod[n1], nextNod[n12], nextNod[n31]);
3752         }
3753         break;
3754       }
3755       case SMDSEntity_Quad_Quadrangle: { // sweep Quadratic QUADRANGLE --->
3756         if ( nbDouble != 4 ) break;
3757         if( nbSame == 0 ) {
3758           // --->  hexahedron with 20 nodes
3759           aNewElem = aMesh->AddVolume (prevNod[0], prevNod[1], prevNod[2], prevNod[3],
3760                                        nextNod[0], nextNod[1], nextNod[2], nextNod[3],
3761                                        prevNod[4], prevNod[5], prevNod[6], prevNod[7],
3762                                        nextNod[4], nextNod[5], nextNod[6], nextNod[7],
3763                                        midlNod[0], midlNod[1], midlNod[2], midlNod[3]);
3764         }
3765         else if(nbSame==1) {
3766           // ---> pyramid + pentahedron - can not be created since it is needed 
3767           // additional middle node at the center of face
3768           INFOS( " Sweep for face " << elem->GetID() << " can not be created" );
3769           return;
3770         }
3771         else if( nbSame == 2 ) {
3772           // --->  2d order Pentahedron with 15 nodes
3773           int n1,n2,n4,n5;
3774           if ( prevNod[ iBeforeSame ] == nextNod[ iBeforeSame ] ) {
3775             // iBeforeSame is same too
3776             n1 = iBeforeSame;
3777             n2 = iOpposSame;
3778             n4 = iSameNode;
3779             n5 = iAfterSame;
3780           }
3781           else {
3782             // iAfterSame is same too
3783             n1 = iSameNode;
3784             n2 = iBeforeSame;
3785             n4 = iAfterSame;
3786             n5 = iOpposSame;
3787           }
3788           int n12 = n2 + 4;
3789           int n45 = n4 + 4;
3790           int n14 = n1 + 4;
3791           int n25 = n5 + 4;
3792           aNewElem = aMesh->AddVolume (prevNod[n1], prevNod[n2], nextNod[n2],
3793                                        prevNod[n4], prevNod[n5], nextNod[n5],
3794                                        prevNod[n12], midlNod[n2], nextNod[n12],
3795                                        prevNod[n45], midlNod[n5], nextNod[n45],
3796                                        prevNod[n14], prevNod[n25], nextNod[n25]);
3797         }
3798         break;
3799       }
3800       case SMDSEntity_BiQuad_Quadrangle: { // sweep BiQuadratic QUADRANGLE --->
3801
3802         if( nbSame == 0 && nbDouble == 9 ) {
3803           // --->  tri-quadratic hexahedron with 27 nodes
3804           aNewElem = aMesh->AddVolume (prevNod[0], prevNod[1], prevNod[2], prevNod[3],
3805                                        nextNod[0], nextNod[1], nextNod[2], nextNod[3],
3806                                        prevNod[4], prevNod[5], prevNod[6], prevNod[7],
3807                                        nextNod[4], nextNod[5], nextNod[6], nextNod[7],
3808                                        midlNod[0], midlNod[1], midlNod[2], midlNod[3],
3809                                        prevNod[8], // bottom center
3810                                        midlNod[4], midlNod[5], midlNod[6], midlNod[7],
3811                                        nextNod[8], // top center
3812                                        midlNod[8]);// elem center
3813         }
3814         else
3815         {
3816           return;
3817         }
3818         break;
3819       }
3820       case SMDSEntity_Polygon: { // sweep POLYGON
3821
3822         if ( nbNodes == 6 && nbSame == 0 && nbDouble == 0 ) {
3823           // --->  hexagonal prism
3824           aNewElem = aMesh->AddVolume (prevNod[0], prevNod[1], prevNod[2],
3825                                        prevNod[3], prevNod[4], prevNod[5],
3826                                        nextNod[0], nextNod[1], nextNod[2],
3827                                        nextNod[3], nextNod[4], nextNod[5]);
3828         }
3829         break;
3830       }
3831       default:
3832         break;
3833       }
3834     }
3835
3836     if ( !aNewElem && elem->GetType() == SMDSAbs_Face ) // try to create a polyherdal prism
3837     {
3838       if ( baseType != SMDSEntity_Polygon )
3839       {
3840         const std::vector<int>& ind = SMDS_MeshCell::interlacedSmdsOrder(baseType);
3841         SMDS_MeshCell::applyInterlace( ind, prevNod );
3842         SMDS_MeshCell::applyInterlace( ind, nextNod );
3843         SMDS_MeshCell::applyInterlace( ind, midlNod );
3844         SMDS_MeshCell::applyInterlace( ind, itNN );
3845         SMDS_MeshCell::applyInterlace( ind, isSingleNode );
3846         baseType = SMDSEntity_Polygon; // WARNING: change baseType !!!!
3847       }
3848       vector<const SMDS_MeshNode*> polyedre_nodes (nbNodes*2 + 4*nbNodes);
3849       vector<int> quantities (nbNodes + 2);
3850       polyedre_nodes.clear();
3851       quantities.clear();
3852
3853       // bottom of prism
3854       for (int inode = 0; inode < nbNodes; inode++)
3855         polyedre_nodes.push_back( prevNod[inode] );
3856       quantities.push_back( nbNodes );
3857
3858       // top of prism
3859       polyedre_nodes.push_back( nextNod[0] );
3860       for (int inode = nbNodes; inode-1; --inode )
3861         polyedre_nodes.push_back( nextNod[inode-1] );
3862       quantities.push_back( nbNodes );
3863
3864       // side faces
3865       for (int iface = 0; iface < nbNodes; iface++)
3866       {
3867         const int prevNbNodes = polyedre_nodes.size();
3868         int inextface = (iface+1) % nbNodes;
3869         polyedre_nodes.push_back( prevNod[inextface] );
3870         polyedre_nodes.push_back( prevNod[iface] );
3871         if ( prevNod[iface] != nextNod[iface] )
3872         {
3873           if ( midlNod[ iface ]) polyedre_nodes.push_back( midlNod[ iface ]);
3874           polyedre_nodes.push_back( nextNod[iface] );
3875         }
3876         if ( prevNod[inextface] != nextNod[inextface] )
3877         {
3878           polyedre_nodes.push_back( nextNod[inextface] );
3879           if ( midlNod[ inextface ]) polyedre_nodes.push_back( midlNod[ inextface ]);
3880         }
3881         const int nbFaceNodes = polyedre_nodes.size() - prevNbNodes;
3882         if ( nbFaceNodes > 2 )
3883           quantities.push_back( nbFaceNodes );
3884         else // degenerated face
3885           polyedre_nodes.resize( prevNbNodes );
3886       }
3887       aNewElem = aMesh->AddPolyhedralVolume (polyedre_nodes, quantities);
3888     }
3889
3890     if ( aNewElem ) {
3891       newElems.push_back( aNewElem );
3892       myLastCreatedElems.Append(aNewElem);
3893       srcElements.Append( elem );
3894     }
3895
3896     // set new prev nodes
3897     for ( iNode = 0; iNode < nbNodes; iNode++ )
3898       prevNod[ iNode ] = nextNod[ iNode ];
3899
3900   } // for steps
3901 }
3902
3903 //=======================================================================
3904 /*!
3905  * \brief Create 1D and 2D elements around swept elements
3906  * \param mapNewNodes - source nodes and ones generated from them
3907  * \param newElemsMap - source elements and ones generated from them
3908  * \param elemNewNodesMap - nodes generated from each node of each element
3909  * \param elemSet - all swept elements
3910  * \param nbSteps - number of sweeping steps
3911  * \param srcElements - to append elem for each generated element
3912  */
3913 //=======================================================================
3914
3915 void SMESH_MeshEditor::makeWalls (TNodeOfNodeListMap &     mapNewNodes,
3916                                   TElemOfElemListMap &     newElemsMap,
3917                                   TElemOfVecOfNnlmiMap &   elemNewNodesMap,
3918                                   TIDSortedElemSet&        elemSet,
3919                                   const int                nbSteps,
3920                                   SMESH_SequenceOfElemPtr& srcElements)
3921 {
3922   ASSERT( newElemsMap.size() == elemNewNodesMap.size() );
3923   SMESHDS_Mesh* aMesh = GetMeshDS();
3924
3925   // Find nodes belonging to only one initial element - sweep them to get edges.
3926
3927   TNodeOfNodeListMapItr nList = mapNewNodes.begin();
3928   for ( ; nList != mapNewNodes.end(); nList++ )
3929   {
3930     const SMDS_MeshNode* node =
3931       static_cast<const SMDS_MeshNode*>( nList->first );
3932     SMDS_ElemIteratorPtr eIt = node->GetInverseElementIterator();
3933     int nbInitElems = 0;
3934     const SMDS_MeshElement* el = 0;
3935     SMDSAbs_ElementType highType = SMDSAbs_Edge; // count most complex elements only
3936     while ( eIt->more() && nbInitElems < 2 ) {
3937       el = eIt->next();
3938       SMDSAbs_ElementType type = el->GetType();
3939       if ( type == SMDSAbs_Volume || type < highType ) continue;
3940       if ( type > highType ) {
3941         nbInitElems = 0;
3942         highType = type;
3943       }
3944       nbInitElems += elemSet.count(el);
3945     }
3946     if ( nbInitElems < 2 ) {
3947       bool NotCreateEdge = el && el->IsMediumNode(node);
3948       if(!NotCreateEdge) {
3949         vector<TNodeOfNodeListMapItr> newNodesItVec( 1, nList );
3950         list<const SMDS_MeshElement*> newEdges;
3951         sweepElement( node, newNodesItVec, newEdges, nbSteps, srcElements );
3952       }
3953     }
3954   }
3955
3956   // Make a ceiling for each element ie an equal element of last new nodes.
3957   // Find free links of faces - make edges and sweep them into faces.
3958
3959   TElemOfElemListMap::iterator   itElem      = newElemsMap.begin();
3960   TElemOfVecOfNnlmiMap::iterator itElemNodes = elemNewNodesMap.begin();
3961   for ( ; itElem != newElemsMap.end(); itElem++, itElemNodes++ )
3962   {
3963     const SMDS_MeshElement* elem = itElem->first;
3964     vector<TNodeOfNodeListMapItr>& vecNewNodes = itElemNodes->second;
3965
3966     if(itElem->second.size()==0) continue;
3967
3968     const bool isQuadratic = elem->IsQuadratic();
3969
3970     if ( elem->GetType() == SMDSAbs_Edge ) {
3971       // create a ceiling edge
3972       if ( !isQuadratic ) {
3973         if ( !aMesh->FindEdge( vecNewNodes[ 0 ]->second.back(),
3974                                vecNewNodes[ 1 ]->second.back())) {
3975           myLastCreatedElems.Append(aMesh->AddEdge(vecNewNodes[ 0 ]->second.back(),
3976                                                    vecNewNodes[ 1 ]->second.back()));
3977           srcElements.Append( myLastCreatedElems.Last() );
3978         }
3979       }
3980       else {
3981         if ( !aMesh->FindEdge( vecNewNodes[ 0 ]->second.back(),
3982                                vecNewNodes[ 1 ]->second.back(),
3983                                vecNewNodes[ 2 ]->second.back())) {
3984           myLastCreatedElems.Append(aMesh->AddEdge(vecNewNodes[ 0 ]->second.back(),
3985                                                    vecNewNodes[ 1 ]->second.back(),
3986                                                    vecNewNodes[ 2 ]->second.back()));
3987           srcElements.Append( myLastCreatedElems.Last() );
3988         }
3989       }
3990     }
3991     if ( elem->GetType() != SMDSAbs_Face )
3992       continue;
3993
3994     bool hasFreeLinks = false;
3995
3996     TIDSortedElemSet avoidSet;
3997     avoidSet.insert( elem );
3998
3999     set<const SMDS_MeshNode*> aFaceLastNodes;
4000     int iNode, nbNodes = vecNewNodes.size();
4001     if ( !isQuadratic ) {
4002       // loop on the face nodes
4003       for ( iNode = 0; iNode < nbNodes; iNode++ ) {
4004         aFaceLastNodes.insert( vecNewNodes[ iNode ]->second.back() );
4005         // look for free links of the face
4006         int iNext = ( iNode + 1 == nbNodes ) ? 0 : iNode + 1;
4007         const SMDS_MeshNode* n1 = vecNewNodes[ iNode ]->first;
4008         const SMDS_MeshNode* n2 = vecNewNodes[ iNext ]->first;
4009         // check if a link is free
4010         if ( ! SMESH_MeshEditor::FindFaceInSet ( n1, n2, elemSet, avoidSet )) {
4011           hasFreeLinks = true;
4012           // make an edge and a ceiling for a new edge
4013           if ( !aMesh->FindEdge( n1, n2 )) {
4014             myLastCreatedElems.Append(aMesh->AddEdge( n1, n2 )); // free link edge
4015             srcElements.Append( myLastCreatedElems.Last() );
4016           }
4017           n1 = vecNewNodes[ iNode ]->second.back();
4018           n2 = vecNewNodes[ iNext ]->second.back();
4019           if ( !aMesh->FindEdge( n1, n2 )) {
4020             myLastCreatedElems.Append(aMesh->AddEdge( n1, n2 )); // ceiling edge
4021             srcElements.Append( myLastCreatedElems.Last() );
4022           }
4023         }
4024       }
4025     }
4026     else { // elem is quadratic face
4027       int nbn = nbNodes/2;
4028       for ( iNode = 0; iNode < nbn; iNode++ ) {
4029         aFaceLastNodes.insert( vecNewNodes[ iNode ]->second.back() );
4030         int iNext = ( iNode + 1 == nbn ) ? 0 : iNode + 1;
4031         const SMDS_MeshNode* n1 = vecNewNodes[ iNode ]->first;
4032         const SMDS_MeshNode* n2 = vecNewNodes[ iNext ]->first;
4033         const SMDS_MeshNode* n3 = vecNewNodes[ iNode+nbn ]->first;
4034         // check if a link is free
4035         if ( ! SMESH_MeshEditor::FindFaceInSet ( n1, n2, elemSet, avoidSet ) &&
4036              ! SMESH_MeshEditor::FindFaceInSet ( n1, n3, elemSet, avoidSet ) &&
4037              ! SMESH_MeshEditor::FindFaceInSet ( n3, n2, elemSet, avoidSet ) ) {
4038           hasFreeLinks = true;
4039           // make an edge and a ceiling for a new edge
4040           // find medium node
4041           if ( !aMesh->FindEdge( n1, n2, n3 )) {
4042             myLastCreatedElems.Append(aMesh->AddEdge( n1, n2, n3 )); // free link edge
4043             srcElements.Append( myLastCreatedElems.Last() );
4044           }
4045           n1 = vecNewNodes[ iNode ]->second.back();
4046           n2 = vecNewNodes[ iNext ]->second.back();
4047           n3 = vecNewNodes[ iNode+nbn ]->second.back();
4048           if ( !aMesh->FindEdge( n1, n2, n3 )) {
4049             myLastCreatedElems.Append(aMesh->AddEdge( n1, n2, n3 )); // ceiling edge
4050             srcElements.Append( myLastCreatedElems.Last() );
4051           }
4052         }
4053       }
4054       for ( iNode = nbn; iNode < nbNodes; iNode++ ) {
4055         aFaceLastNodes.insert( vecNewNodes[ iNode ]->second.back() );
4056       }
4057     }
4058
4059     // sweep free links into faces
4060
4061     if ( hasFreeLinks )  {
4062       list<const SMDS_MeshElement*> & newVolumes = itElem->second;
4063       int iVol, volNb, nbVolumesByStep = newVolumes.size() / nbSteps;
4064
4065       set<const SMDS_MeshNode*> initNodeSet, topNodeSet, faceNodeSet;
4066       for ( iNode = 0; iNode < nbNodes; iNode++ ) {
4067         initNodeSet.insert( vecNewNodes[ iNode ]->first );
4068         topNodeSet .insert( vecNewNodes[ iNode ]->second.back() );
4069       }
4070       for ( volNb = 0; volNb < nbVolumesByStep; volNb++ ) {
4071         list<const SMDS_MeshElement*>::iterator v = newVolumes.begin();
4072         std::advance( v, volNb );
4073         // find indices of free faces of a volume and their source edges
4074         list< int > freeInd;
4075         list< const SMDS_MeshElement* > srcEdges; // source edges of free faces
4076         SMDS_VolumeTool vTool( *v, /*ignoreCentralNodes=*/false );
4077         int iF, nbF = vTool.NbFaces();
4078         for ( iF = 0; iF < nbF; iF ++ ) {
4079           if (vTool.IsFreeFace( iF ) &&
4080               vTool.GetFaceNodes( iF, faceNodeSet ) &&
4081               initNodeSet != faceNodeSet) // except an initial face
4082           {
4083             if ( nbSteps == 1 && faceNodeSet == topNodeSet )
4084               continue;
4085             freeInd.push_back( iF );
4086             // find source edge of a free face iF
4087             vector<const SMDS_MeshNode*> commonNodes; // shared by the initial and free faces
4088             commonNodes.resize( initNodeSet.size(), NULL ); // avoid spoiling memory
4089             std::set_intersection( faceNodeSet.begin(), faceNodeSet.end(),
4090                                    initNodeSet.begin(), initNodeSet.end(),
4091                                    commonNodes.begin());
4092             if ( (*v)->IsQuadratic() )
4093               srcEdges.push_back(aMesh->FindEdge (commonNodes[0],commonNodes[1],commonNodes[2]));
4094             else
4095               srcEdges.push_back(aMesh->FindEdge (commonNodes[0],commonNodes[1]));
4096 #ifdef _DEBUG_
4097             if ( !srcEdges.back() )
4098             {
4099               cout << "SMESH_MeshEditor::makeWalls(), no source edge found for a free face #"
4100                    << iF << " of volume #" << vTool.ID() << endl;
4101             }
4102 #endif
4103           }
4104         }
4105         if ( freeInd.empty() )
4106           continue;
4107
4108         // create faces for all steps;
4109         // if such a face has been already created by sweep of edge,
4110         // assure that its orientation is OK
4111         for ( int iStep = 0; iStep < nbSteps; iStep++ ) {
4112           vTool.Set( *v, /*ignoreCentralNodes=*/false );
4113           vTool.SetExternalNormal();
4114           const int nextShift = vTool.IsForward() ? +1 : -1;
4115           list< int >::iterator ind = freeInd.begin();
4116           list< const SMDS_MeshElement* >::iterator srcEdge = srcEdges.begin();
4117           for ( ; ind != freeInd.end(); ++ind, ++srcEdge ) // loop on free faces
4118           {
4119             const SMDS_MeshNode** nodes = vTool.GetFaceNodes( *ind );
4120             int nbn = vTool.NbFaceNodes( *ind );
4121             const SMDS_MeshElement * f = 0;
4122             if ( nbn == 3 )              ///// triangle
4123             {
4124               f = aMesh->FindFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ]);
4125               if ( !f ||
4126                    nodes[ 1 ] != f->GetNodeWrap( f->GetNodeIndex( nodes[ 0 ]) + nextShift ))
4127               {
4128                 const SMDS_MeshNode* newOrder[3] = { nodes[ 1 - nextShift ],
4129                                                      nodes[ 1 ],
4130                                                      nodes[ 1 + nextShift ] };
4131                 if ( f )
4132                   aMesh->ChangeElementNodes( f, &newOrder[0], nbn );
4133                 else
4134                   myLastCreatedElems.Append(aMesh->AddFace( newOrder[ 0 ], newOrder[ 1 ],
4135                                                             newOrder[ 2 ] ));
4136               }
4137             }
4138             else if ( nbn == 4 )       ///// quadrangle
4139             {
4140               f = aMesh->FindFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ], nodes[ 3 ]);
4141               if ( !f ||
4142                    nodes[ 1 ] != f->GetNodeWrap( f->GetNodeIndex( nodes[ 0 ]) + nextShift ))
4143               {
4144                 const SMDS_MeshNode* newOrder[4] = { nodes[ 0 ], nodes[ 2-nextShift ],
4145                                                      nodes[ 2 ], nodes[ 2+nextShift ] };
4146                 if ( f )
4147                   aMesh->ChangeElementNodes( f, &newOrder[0], nbn );
4148                 else
4149                   myLastCreatedElems.Append(aMesh->AddFace( newOrder[ 0 ], newOrder[ 1 ],
4150                                                             newOrder[ 2 ], newOrder[ 3 ]));
4151               }
4152             }
4153             else if ( nbn == 6 && isQuadratic ) /////// quadratic triangle
4154             {
4155               f = aMesh->FindFace( nodes[0], nodes[2], nodes[4], nodes[1], nodes[3], nodes[5] );
4156               if ( !f ||
4157                    nodes[2] != f->GetNodeWrap( f->GetNodeIndex( nodes[0] ) + 2*nextShift ))
4158               {
4159                 const SMDS_MeshNode* newOrder[6] = { nodes[2 - 2*nextShift],
4160                                                      nodes[2],
4161                                                      nodes[2 + 2*nextShift],
4162                                                      nodes[3 - 2*nextShift],
4163                                                      nodes[3],
4164                                                      nodes[3 + 2*nextShift]};
4165                 if ( f )
4166                   aMesh->ChangeElementNodes( f, &newOrder[0], nbn );
4167                 else
4168                   myLastCreatedElems.Append(aMesh->AddFace( newOrder[ 0 ],
4169                                                             newOrder[ 1 ],
4170                                                             newOrder[ 2 ],
4171                                                             newOrder[ 3 ],
4172                                                             newOrder[ 4 ],
4173                                                             newOrder[ 5 ] ));
4174               }
4175             }
4176             else if ( nbn == 8 && isQuadratic ) /////// quadratic quadrangle
4177             {
4178               f = aMesh->FindFace( nodes[0], nodes[2], nodes[4], nodes[6],
4179                                    nodes[1], nodes[3], nodes[5], nodes[7] );
4180               if ( !f ||
4181                    nodes[ 2 ] != f->GetNodeWrap( f->GetNodeIndex( nodes[ 0 ] ) + 2*nextShift ))
4182               {
4183                 const SMDS_MeshNode* newOrder[8] = { nodes[0],
4184                                                      nodes[4 - 2*nextShift],
4185                                                      nodes[4],
4186                                                      nodes[4 + 2*nextShift],
4187                                                      nodes[1],
4188                                                      nodes[5 - 2*nextShift],
4189                                                      nodes[5],
4190                                                      nodes[5 + 2*nextShift] };
4191                 if ( f )
4192                   aMesh->ChangeElementNodes( f, &newOrder[0], nbn );
4193                 else
4194                   myLastCreatedElems.Append(aMesh->AddFace(newOrder[ 0 ], newOrder[ 1 ],
4195                                                            newOrder[ 2 ], newOrder[ 3 ],
4196                                                            newOrder[ 4 ], newOrder[ 5 ],
4197                                                            newOrder[ 6 ], newOrder[ 7 ]));
4198               }
4199             }
4200             else if ( nbn == 9 && isQuadratic ) /////// bi-quadratic quadrangle
4201             {
4202               f = aMesh->FindElement( vector<const SMDS_MeshNode*>( nodes, nodes+nbn ),
4203                                       SMDSAbs_Face, /*noMedium=*/false);
4204               if ( !f ||
4205                    nodes[ 2 ] != f->GetNodeWrap( f->GetNodeIndex( nodes[ 0 ] ) + 2*nextShift ))
4206               {
4207                 const SMDS_MeshNode* newOrder[9] = { nodes[0],
4208                                                      nodes[4 - 2*nextShift],
4209                                                      nodes[4],
4210                                                      nodes[4 + 2*nextShift],
4211                                                      nodes[1],
4212                                                      nodes[5 - 2*nextShift],
4213                                                      nodes[5],
4214                                                      nodes[5 + 2*nextShift],
4215                                                      nodes[8] };
4216                 if ( f )
4217                   aMesh->ChangeElementNodes( f, &newOrder[0], nbn );
4218                 else
4219                   myLastCreatedElems.Append(aMesh->AddFace(newOrder[ 0 ], newOrder[ 1 ],
4220                                                            newOrder[ 2 ], newOrder[ 3 ],
4221                                                            newOrder[ 4 ], newOrder[ 5 ],
4222                                                            newOrder[ 6 ], newOrder[ 7 ],
4223                                                            newOrder[ 8 ]));
4224               }
4225             }
4226             else  //////// polygon
4227             {
4228               vector<const SMDS_MeshNode*> polygon_nodes ( nodes, nodes+nbn );
4229               const SMDS_MeshFace * f = aMesh->FindFace( polygon_nodes );
4230               if ( !f ||
4231                    nodes[ 1 ] != f->GetNodeWrap( f->GetNodeIndex( nodes[ 0 ] ) + nextShift ))
4232               {
4233                 if ( !vTool.IsForward() )
4234                   std::reverse( polygon_nodes.begin(), polygon_nodes.end());
4235                 if ( f )
4236                   aMesh->ChangeElementNodes( f, &polygon_nodes[0], nbn );
4237                 else
4238                   AddElement(polygon_nodes, SMDSAbs_Face, polygon_nodes.size()>4);
4239               }
4240             }
4241
4242             while ( srcElements.Length() < myLastCreatedElems.Length() )
4243               srcElements.Append( *srcEdge );
4244
4245           }  // loop on free faces
4246
4247           // go to the next volume
4248           iVol = 0;
4249           while ( iVol++ < nbVolumesByStep ) v++;
4250
4251         } // loop on steps
4252       } // loop on volumes of one step
4253     } // sweep free links into faces
4254
4255     // Make a ceiling face with a normal external to a volume
4256
4257     SMDS_VolumeTool lastVol( itElem->second.back(), /*ignoreCentralNodes=*/false );
4258
4259     int iF = lastVol.GetFaceIndex( aFaceLastNodes );
4260     if ( iF >= 0 ) {
4261       lastVol.SetExternalNormal();
4262       const SMDS_MeshNode** nodes = lastVol.GetFaceNodes( iF );
4263       int nbn = lastVol.NbFaceNodes( iF );
4264       if ( nbn == 3 ) {
4265         if (!hasFreeLinks ||
4266             !aMesh->FindFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ]))
4267           myLastCreatedElems.Append(aMesh->AddFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ] ));
4268       }
4269       else if ( nbn == 4 )
4270       {
4271         if (!hasFreeLinks ||
4272             !aMesh->FindFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ], nodes[ 3 ]))
4273           myLastCreatedElems.Append(aMesh->AddFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ], nodes[ 3 ]));
4274       }
4275       else if ( nbn == 6 && isQuadratic )
4276       {
4277         if (!hasFreeLinks ||
4278             !aMesh->FindFace(nodes[0], nodes[2], nodes[4], nodes[1], nodes[3], nodes[5]) )
4279           myLastCreatedElems.Append(aMesh->AddFace(nodes[0], nodes[2], nodes[4],
4280                                                    nodes[1], nodes[3], nodes[5]));
4281       }
4282       else if ( nbn == 8 && isQuadratic )
4283       {
4284         if (!hasFreeLinks ||
4285             !aMesh->FindFace(nodes[0], nodes[2], nodes[4], nodes[6],
4286                              nodes[1], nodes[3], nodes[5], nodes[7]) )
4287           myLastCreatedElems.Append(aMesh->AddFace(nodes[0], nodes[2], nodes[4], nodes[6],
4288                                                    nodes[1], nodes[3], nodes[5], nodes[7]));
4289       }
4290       else if ( nbn == 9 && isQuadratic )
4291       {
4292         if (!hasFreeLinks ||
4293             !aMesh->FindElement(vector<const SMDS_MeshNode*>( nodes, nodes+nbn ),
4294                                 SMDSAbs_Face, /*noMedium=*/false) )
4295           myLastCreatedElems.Append(aMesh->AddFace(nodes[0], nodes[2], nodes[4], nodes[6],
4296                                                    nodes[1], nodes[3], nodes[5], nodes[7],
4297                                                    nodes[8]));
4298       }
4299       else {
4300         vector<const SMDS_MeshNode*> polygon_nodes ( nodes, nodes + nbn );
4301         if (!hasFreeLinks || !aMesh->FindFace(polygon_nodes))
4302           myLastCreatedElems.Append(aMesh->AddPolygonalFace(polygon_nodes));
4303       }
4304
4305       while ( srcElements.Length() < myLastCreatedElems.Length() )
4306         srcElements.Append( myLastCreatedElems.Last() );
4307     }
4308   } // loop on swept elements
4309 }
4310
4311 //=======================================================================
4312 //function : RotationSweep
4313 //purpose  :
4314 //=======================================================================
4315
4316 SMESH_MeshEditor::PGroupIDs
4317 SMESH_MeshEditor::RotationSweep(TIDSortedElemSet & theElems,
4318                                 const gp_Ax1&      theAxis,
4319                                 const double       theAngle,
4320                                 const int          theNbSteps,
4321                                 const double       theTol,
4322                                 const bool         theMakeGroups,
4323                                 const bool         theMakeWalls)
4324 {
4325   myLastCreatedElems.Clear();
4326   myLastCreatedNodes.Clear();
4327
4328   // source elements for each generated one
4329   SMESH_SequenceOfElemPtr srcElems, srcNodes;
4330
4331   MESSAGE( "RotationSweep()");
4332   gp_Trsf aTrsf;
4333   aTrsf.SetRotation( theAxis, theAngle );
4334   gp_Trsf aTrsf2;
4335   aTrsf2.SetRotation( theAxis, theAngle/2. );
4336
4337   gp_Lin aLine( theAxis );
4338   double aSqTol = theTol * theTol;
4339
4340   SMESHDS_Mesh* aMesh = GetMeshDS();
4341
4342   TNodeOfNodeListMap mapNewNodes;
4343   TElemOfVecOfNnlmiMap mapElemNewNodes;
4344   TElemOfElemListMap newElemsMap;
4345
4346   const bool isQuadraticMesh = bool( myMesh->NbEdges(ORDER_QUADRATIC) +
4347                                      myMesh->NbFaces(ORDER_QUADRATIC) +
4348                                      myMesh->NbVolumes(ORDER_QUADRATIC) );
4349   // loop on theElems
4350   TIDSortedElemSet::iterator itElem;
4351   for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
4352     const SMDS_MeshElement* elem = *itElem;
4353     if ( !elem || elem->GetType() == SMDSAbs_Volume )
4354       continue;
4355     vector<TNodeOfNodeListMapItr> & newNodesItVec = mapElemNewNodes[ elem ];
4356     newNodesItVec.reserve( elem->NbNodes() );
4357
4358     // loop on elem nodes
4359     SMDS_ElemIteratorPtr itN = elem->nodesIterator();
4360     while ( itN->more() )
4361     {
4362       // check if a node has been already sweeped
4363       const SMDS_MeshNode* node = cast2Node( itN->next() );
4364
4365       gp_XYZ aXYZ( node->X(), node->Y(), node->Z() );
4366       double coord[3];
4367       aXYZ.Coord( coord[0], coord[1], coord[2] );
4368       bool isOnAxis = ( aLine.SquareDistance( aXYZ ) <= aSqTol );
4369
4370       TNodeOfNodeListMapItr nIt =
4371         mapNewNodes.insert( make_pair( node, list<const SMDS_MeshNode*>() )).first;
4372       list<const SMDS_MeshNode*>& listNewNodes = nIt->second;
4373       if ( listNewNodes.empty() )
4374       {
4375         // check if we are to create medium nodes between corner ones
4376         bool needMediumNodes = false;
4377         if ( isQuadraticMesh )
4378         {
4379           SMDS_ElemIteratorPtr it = node->GetInverseElementIterator();
4380           while (it->more() && !needMediumNodes )
4381           {
4382             const SMDS_MeshElement* invElem = it->next();
4383             if ( invElem != elem && !theElems.count( invElem )) continue;
4384             needMediumNodes = ( invElem->IsQuadratic() && !invElem->IsMediumNode(node) );
4385             if ( !needMediumNodes && invElem->GetEntityType() == SMDSEntity_BiQuad_Quadrangle )
4386               needMediumNodes = true;
4387           }
4388         }
4389
4390         // make new nodes
4391         const SMDS_MeshNode * newNode = node;
4392         for ( int i = 0; i < theNbSteps; i++ ) {
4393           if ( !isOnAxis ) {
4394             if ( needMediumNodes )  // create a medium node
4395             {
4396               aTrsf2.Transforms( coord[0], coord[1], coord[2] );
4397               newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
4398               myLastCreatedNodes.Append(newNode);
4399               srcNodes.Append( node );
4400               listNewNodes.push_back( newNode );
4401               aTrsf2.Transforms( coord[0], coord[1], coord[2] );
4402             }
4403             else {
4404               aTrsf.Transforms( coord[0], coord[1], coord[2] );
4405             }
4406             // create a corner node
4407             newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
4408             myLastCreatedNodes.Append(newNode);
4409             srcNodes.Append( node );
4410             listNewNodes.push_back( newNode );
4411           }
4412           else {
4413             listNewNodes.push_back( newNode );
4414             // if ( needMediumNodes )
4415             //   listNewNodes.push_back( newNode );
4416           }
4417         }
4418       }
4419       newNodesItVec.push_back( nIt );
4420     }
4421     // make new elements
4422     sweepElement( elem, newNodesItVec, newElemsMap[elem], theNbSteps, srcElems );
4423   }
4424
4425   if ( theMakeWalls )
4426     makeWalls( mapNewNodes, newElemsMap, mapElemNewNodes, theElems, theNbSteps, srcElems );
4427
4428   PGroupIDs newGroupIDs;
4429   if ( theMakeGroups )
4430     newGroupIDs = generateGroups( srcNodes, srcElems, "rotated");
4431
4432   return newGroupIDs;
4433 }
4434
4435
4436 //=======================================================================
4437 //function : CreateNode
4438 //purpose  :
4439 //=======================================================================
4440 const SMDS_MeshNode* SMESH_MeshEditor::CreateNode(const double x,
4441                                                   const double y,
4442                                                   const double z,
4443                                                   const double tolnode,
4444                                                   SMESH_SequenceOfNode& aNodes)
4445 {
4446   // myLastCreatedElems.Clear();
4447   // myLastCreatedNodes.Clear();
4448
4449   gp_Pnt P1(x,y,z);
4450   SMESHDS_Mesh * aMesh = myMesh->GetMeshDS();
4451
4452   // try to search in sequence of existing nodes
4453   // if aNodes.Length()>0 we 'nave to use given sequence
4454   // else - use all nodes of mesh
4455   if(aNodes.Length()>0) {
4456     int i;
4457     for(i=1; i<=aNodes.Length(); i++) {
4458       gp_Pnt P2(aNodes.Value(i)->X(),aNodes.Value(i)->Y(),aNodes.Value(i)->Z());
4459       if(P1.Distance(P2)<tolnode)
4460         return aNodes.Value(i);
4461     }
4462   }
4463   else {
4464     SMDS_NodeIteratorPtr itn = aMesh->nodesIterator();
4465     while(itn->more()) {
4466       const SMDS_MeshNode* aN = static_cast<const SMDS_MeshNode*> (itn->next());
4467       gp_Pnt P2(aN->X(),aN->Y(),aN->Z());
4468       if(P1.Distance(P2)<tolnode)
4469         return aN;
4470     }
4471   }
4472
4473   // create new node and return it
4474   const SMDS_MeshNode* NewNode = aMesh->AddNode(x,y,z);
4475   //myLastCreatedNodes.Append(NewNode);
4476   return NewNode;
4477 }
4478
4479
4480 //=======================================================================
4481 //function : ExtrusionSweep
4482 //purpose  :
4483 //=======================================================================
4484
4485 SMESH_MeshEditor::PGroupIDs
4486 SMESH_MeshEditor::ExtrusionSweep (TIDSortedElemSet &  theElems,
4487                                   const gp_Vec&       theStep,
4488                                   const int           theNbSteps,
4489                                   TElemOfElemListMap& newElemsMap,
4490                                   const bool          theMakeGroups,
4491                                   const int           theFlags,
4492                                   const double        theTolerance)
4493 {
4494   ExtrusParam aParams;
4495   aParams.myDir = gp_Dir(theStep);
4496   aParams.myNodes.Clear();
4497   aParams.mySteps = new TColStd_HSequenceOfReal;
4498   int i;
4499   for(i=1; i<=theNbSteps; i++)
4500     aParams.mySteps->Append(theStep.Magnitude());
4501
4502   return
4503     ExtrusionSweep(theElems,aParams,newElemsMap,theMakeGroups,theFlags,theTolerance);
4504 }
4505
4506
4507 //=======================================================================
4508 //function : ExtrusionSweep
4509 //purpose  :
4510 //=======================================================================
4511
4512 SMESH_MeshEditor::PGroupIDs
4513 SMESH_MeshEditor::ExtrusionSweep (TIDSortedElemSet &  theElems,
4514                                   ExtrusParam&        theParams,
4515                                   TElemOfElemListMap& newElemsMap,
4516                                   const bool          theMakeGroups,
4517                                   const int           theFlags,
4518                                   const double        theTolerance)
4519 {
4520   myLastCreatedElems.Clear();
4521   myLastCreatedNodes.Clear();
4522
4523   // source elements for each generated one
4524   SMESH_SequenceOfElemPtr srcElems, srcNodes;
4525
4526   SMESHDS_Mesh* aMesh = GetMeshDS();
4527
4528   int nbsteps = theParams.mySteps->Length();
4529
4530   TNodeOfNodeListMap mapNewNodes;
4531   //TNodeOfNodeVecMap mapNewNodes;
4532   TElemOfVecOfNnlmiMap mapElemNewNodes;
4533   //TElemOfVecOfMapNodesMap mapElemNewNodes;
4534
4535   const bool isQuadraticMesh = bool( myMesh->NbEdges(ORDER_QUADRATIC) +
4536                                      myMesh->NbFaces(ORDER_QUADRATIC) +
4537                                      myMesh->NbVolumes(ORDER_QUADRATIC) );
4538   // loop on theElems
4539   TIDSortedElemSet::iterator itElem;
4540   for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
4541     // check element type
4542     const SMDS_MeshElement* elem = *itElem;
4543     if ( !elem  || elem->GetType() == SMDSAbs_Volume )
4544       continue;
4545
4546     vector<TNodeOfNodeListMapItr> & newNodesItVec = mapElemNewNodes[ elem ];
4547     newNodesItVec.reserve( elem->NbNodes() );
4548
4549     // loop on elem nodes
4550     SMDS_ElemIteratorPtr itN = elem->nodesIterator();
4551     while ( itN->more() )
4552     {
4553       // check if a node has been already sweeped
4554       const SMDS_MeshNode* node = cast2Node( itN->next() );
4555       TNodeOfNodeListMap::iterator nIt =
4556         mapNewNodes.insert( make_pair( node, list<const SMDS_MeshNode*>() )).first;
4557       list<const SMDS_MeshNode*>& listNewNodes = nIt->second;
4558       if ( listNewNodes.empty() )
4559       {
4560         // make new nodes
4561
4562         // check if we are to create medium nodes between corner ones
4563         bool needMediumNodes = false;
4564         if ( isQuadraticMesh )
4565         {
4566           SMDS_ElemIteratorPtr it = node->GetInverseElementIterator();
4567           while (it->more() && !needMediumNodes )
4568           {
4569             const SMDS_MeshElement* invElem = it->next();
4570             if ( invElem != elem && !theElems.count( invElem )) continue;
4571             needMediumNodes = ( invElem->IsQuadratic() && !invElem->IsMediumNode(node) );
4572             if ( !needMediumNodes && invElem->GetEntityType() == SMDSEntity_BiQuad_Quadrangle )
4573               needMediumNodes = true;
4574           }
4575         }
4576
4577         double coord[] = { node->X(), node->Y(), node->Z() };
4578         for ( int i = 0; i < nbsteps; i++ )
4579         {
4580           if ( needMediumNodes ) // create a medium node
4581           {
4582             double x = coord[0] + theParams.myDir.X()*theParams.mySteps->Value(i+1)/2.;
4583             double y = coord[1] + theParams.myDir.Y()*theParams.mySteps->Value(i+1)/2.;
4584             double z = coord[2] + theParams.myDir.Z()*theParams.mySteps->Value(i+1)/2.;
4585             if( theFlags & EXTRUSION_FLAG_SEW ) {
4586               const SMDS_MeshNode * newNode = CreateNode(x, y, z,
4587                                                          theTolerance, theParams.myNodes);
4588               listNewNodes.push_back( newNode );
4589             }
4590             else {
4591               const SMDS_MeshNode * newNode = aMesh->AddNode(x, y, z);
4592               myLastCreatedNodes.Append(newNode);
4593               srcNodes.Append( node );
4594               listNewNodes.push_back( newNode );
4595             }
4596           }
4597           // create a corner node
4598           coord[0] = coord[0] + theParams.myDir.X()*theParams.mySteps->Value(i+1);
4599           coord[1] = coord[1] + theParams.myDir.Y()*theParams.mySteps->Value(i+1);
4600           coord[2] = coord[2] + theParams.myDir.Z()*theParams.mySteps->Value(i+1);
4601           if( theFlags & EXTRUSION_FLAG_SEW ) {
4602             const SMDS_MeshNode * newNode = CreateNode(coord[0], coord[1], coord[2],
4603                                                        theTolerance, theParams.myNodes);
4604             listNewNodes.push_back( newNode );
4605           }
4606           else {
4607             const SMDS_MeshNode * newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
4608             myLastCreatedNodes.Append(newNode);
4609             srcNodes.Append( node );
4610             listNewNodes.push_back( newNode );
4611           }
4612         }
4613       }
4614       newNodesItVec.push_back( nIt );
4615     }
4616     // make new elements
4617     sweepElement( elem, newNodesItVec, newElemsMap[elem], nbsteps, srcElems );
4618   }
4619
4620   if( theFlags & EXTRUSION_FLAG_BOUNDARY ) {
4621     makeWalls( mapNewNodes, newElemsMap, mapElemNewNodes, theElems, nbsteps, srcElems );
4622   }
4623   PGroupIDs newGroupIDs;
4624   if ( theMakeGroups )
4625     newGroupIDs = generateGroups( srcNodes, srcElems, "extruded");
4626
4627   return newGroupIDs;
4628 }
4629
4630 //=======================================================================
4631 //function : ExtrusionAlongTrack
4632 //purpose  :
4633 //=======================================================================
4634 SMESH_MeshEditor::Extrusion_Error
4635 SMESH_MeshEditor::ExtrusionAlongTrack (TIDSortedElemSet &   theElements,
4636                                        SMESH_subMesh*       theTrack,
4637                                        const SMDS_MeshNode* theN1,
4638                                        const bool           theHasAngles,
4639                                        list<double>&        theAngles,
4640                                        const bool           theLinearVariation,
4641                                        const bool           theHasRefPoint,
4642                                        const gp_Pnt&        theRefPoint,
4643                                        const bool           theMakeGroups)
4644 {
4645   MESSAGE("ExtrusionAlongTrack");
4646   myLastCreatedElems.Clear();
4647   myLastCreatedNodes.Clear();
4648
4649   int aNbE;
4650   std::list<double> aPrms;
4651   TIDSortedElemSet::iterator itElem;
4652
4653   gp_XYZ aGC;
4654   TopoDS_Edge aTrackEdge;
4655   TopoDS_Vertex aV1, aV2;
4656
4657   SMDS_ElemIteratorPtr aItE;
4658   SMDS_NodeIteratorPtr aItN;
4659   SMDSAbs_ElementType aTypeE;
4660
4661   TNodeOfNodeListMap mapNewNodes;
4662
4663   // 1. Check data
4664   aNbE = theElements.size();
4665   // nothing to do
4666   if ( !aNbE )
4667     return EXTR_NO_ELEMENTS;
4668
4669   // 1.1 Track Pattern
4670   ASSERT( theTrack );
4671
4672   SMESHDS_SubMesh* pSubMeshDS = theTrack->GetSubMeshDS();
4673
4674   aItE = pSubMeshDS->GetElements();
4675   while ( aItE->more() ) {
4676     const SMDS_MeshElement* pE = aItE->next();
4677     aTypeE = pE->GetType();
4678     // Pattern must contain links only
4679     if ( aTypeE != SMDSAbs_Edge )
4680       return EXTR_PATH_NOT_EDGE;
4681   }
4682
4683   list<SMESH_MeshEditor_PathPoint> fullList;
4684
4685   const TopoDS_Shape& aS = theTrack->GetSubShape();
4686   // Sub shape for the Pattern must be an Edge or Wire
4687   if( aS.ShapeType() == TopAbs_EDGE ) {
4688     aTrackEdge = TopoDS::Edge( aS );
4689     // the Edge must not be degenerated
4690     if ( BRep_Tool::Degenerated( aTrackEdge ) )
4691       return EXTR_BAD_PATH_SHAPE;
4692     TopExp::Vertices( aTrackEdge, aV1, aV2 );
4693     aItN = theTrack->GetFather()->GetSubMesh( aV1 )->GetSubMeshDS()->GetNodes();
4694     const SMDS_MeshNode* aN1 = aItN->next();
4695     aItN = theTrack->GetFather()->GetSubMesh( aV2 )->GetSubMeshDS()->GetNodes();
4696     const SMDS_MeshNode* aN2 = aItN->next();
4697     // starting node must be aN1 or aN2
4698     if ( !( aN1 == theN1 || aN2 == theN1 ) )
4699       return EXTR_BAD_STARTING_NODE;
4700     aItN = pSubMeshDS->GetNodes();
4701     while ( aItN->more() ) {
4702       const SMDS_MeshNode* pNode = aItN->next();
4703       const SMDS_EdgePosition* pEPos =
4704         static_cast<const SMDS_EdgePosition*>( pNode->GetPosition() );
4705       double aT = pEPos->GetUParameter();
4706       aPrms.push_back( aT );
4707     }
4708     //Extrusion_Error err =
4709     MakeEdgePathPoints(aPrms, aTrackEdge, (aN1==theN1), fullList);
4710   } else if( aS.ShapeType() == TopAbs_WIRE ) {
4711     list< SMESH_subMesh* > LSM;
4712     TopTools_SequenceOfShape Edges;
4713     SMESH_subMeshIteratorPtr itSM = theTrack->getDependsOnIterator(false,true);
4714     while(itSM->more()) {
4715       SMESH_subMesh* SM = itSM->next();
4716       LSM.push_back(SM);
4717       const TopoDS_Shape& aS = SM->GetSubShape();
4718       Edges.Append(aS);
4719     }
4720     list< list<SMESH_MeshEditor_PathPoint> > LLPPs;
4721     int startNid = theN1->GetID();
4722     TColStd_MapOfInteger UsedNums;
4723     
4724     int NbEdges = Edges.Length();
4725     int i = 1;
4726     for(; i<=NbEdges; i++) {
4727       int k = 0;
4728       list< SMESH_subMesh* >::iterator itLSM = LSM.begin();
4729       for(; itLSM!=LSM.end(); itLSM++) {
4730         k++;
4731         if(UsedNums.Contains(k)) continue;
4732         aTrackEdge = TopoDS::Edge( Edges.Value(k) );
4733         SMESH_subMesh* locTrack = *itLSM;
4734         SMESHDS_SubMesh* locMeshDS = locTrack->GetSubMeshDS();
4735         TopExp::Vertices( aTrackEdge, aV1, aV2 );
4736         aItN = locTrack->GetFather()->GetSubMesh(aV1)->GetSubMeshDS()->GetNodes();
4737         const SMDS_MeshNode* aN1 = aItN->next();
4738         aItN = locTrack->GetFather()->GetSubMesh(aV2)->GetSubMeshDS()->GetNodes();
4739         const SMDS_MeshNode* aN2 = aItN->next();
4740         // starting node must be aN1 or aN2
4741         if ( !( aN1->GetID() == startNid || aN2->GetID() == startNid ) ) continue;
4742         // 2. Collect parameters on the track edge
4743         aPrms.clear();
4744         aItN = locMeshDS->GetNodes();
4745         while ( aItN->more() ) {
4746           const SMDS_MeshNode* pNode = aItN->next();
4747           const SMDS_EdgePosition* pEPos =
4748             static_cast<const SMDS_EdgePosition*>( pNode->GetPosition() );
4749           double aT = pEPos->GetUParameter();
4750           aPrms.push_back( aT );
4751         }
4752         list<SMESH_MeshEditor_PathPoint> LPP;
4753         //Extrusion_Error err =
4754         MakeEdgePathPoints(aPrms, aTrackEdge,(aN1->GetID()==startNid), LPP);
4755         LLPPs.push_back(LPP);
4756         UsedNums.Add(k);
4757         // update startN for search following egde
4758         if( aN1->GetID() == startNid ) startNid = aN2->GetID();
4759         else startNid = aN1->GetID();
4760         break;
4761       }
4762     }
4763     list< list<SMESH_MeshEditor_PathPoint> >::iterator itLLPP = LLPPs.begin();
4764     list<SMESH_MeshEditor_PathPoint> firstList = *itLLPP;
4765     list<SMESH_MeshEditor_PathPoint>::iterator itPP = firstList.begin();
4766     for(; itPP!=firstList.end(); itPP++) {
4767       fullList.push_back( *itPP );
4768     }
4769     SMESH_MeshEditor_PathPoint PP1 = fullList.back();
4770     fullList.pop_back();
4771     itLLPP++;
4772     for(; itLLPP!=LLPPs.end(); itLLPP++) {
4773       list<SMESH_MeshEditor_PathPoint> currList = *itLLPP;
4774       itPP = currList.begin();
4775       SMESH_MeshEditor_PathPoint PP2 = currList.front();
4776       gp_Dir D1 = PP1.Tangent();
4777       gp_Dir D2 = PP2.Tangent();
4778       gp_Dir Dnew( gp_Vec( (D1.X()+D2.X())/2, (D1.Y()+D2.Y())/2,
4779                            (D1.Z()+D2.Z())/2 ) );
4780       PP1.SetTangent(Dnew);
4781       fullList.push_back(PP1);
4782       itPP++;
4783       for(; itPP!=firstList.end(); itPP++) {
4784         fullList.push_back( *itPP );
4785       }
4786       PP1 = fullList.back();
4787       fullList.pop_back();
4788     }
4789     // if wire not closed
4790     fullList.push_back(PP1);
4791     // else ???
4792   }
4793   else {
4794     return EXTR_BAD_PATH_SHAPE;
4795   }
4796
4797   return MakeExtrElements(theElements, fullList, theHasAngles, theAngles, theLinearVariation,
4798                           theHasRefPoint, theRefPoint, theMakeGroups);
4799 }
4800
4801
4802 //=======================================================================
4803 //function : ExtrusionAlongTrack
4804 //purpose  :
4805 //=======================================================================
4806 SMESH_MeshEditor::Extrusion_Error
4807 SMESH_MeshEditor::ExtrusionAlongTrack (TIDSortedElemSet &   theElements,
4808                                        SMESH_Mesh*          theTrack,
4809                                        const SMDS_MeshNode* theN1,
4810                                        const bool           theHasAngles,
4811                                        list<double>&        theAngles,
4812                                        const bool           theLinearVariation,
4813                                        const bool           theHasRefPoint,
4814                                        const gp_Pnt&        theRefPoint,
4815                                        const bool           theMakeGroups)
4816 {
4817   myLastCreatedElems.Clear();
4818   myLastCreatedNodes.Clear();
4819
4820   int aNbE;
4821   std::list<double> aPrms;
4822   TIDSortedElemSet::iterator itElem;
4823
4824   gp_XYZ aGC;
4825   TopoDS_Edge aTrackEdge;
4826   TopoDS_Vertex aV1, aV2;
4827
4828   SMDS_ElemIteratorPtr aItE;
4829   SMDS_NodeIteratorPtr aItN;
4830   SMDSAbs_ElementType aTypeE;
4831
4832   TNodeOfNodeListMap mapNewNodes;
4833
4834   // 1. Check data
4835   aNbE = theElements.size();
4836   // nothing to do
4837   if ( !aNbE )
4838     return EXTR_NO_ELEMENTS;
4839
4840   // 1.1 Track Pattern
4841   ASSERT( theTrack );
4842
4843   SMESHDS_Mesh* pMeshDS = theTrack->GetMeshDS();
4844
4845   aItE = pMeshDS->elementsIterator();
4846   while ( aItE->more() ) {
4847     const SMDS_MeshElement* pE = aItE->next();
4848     aTypeE = pE->GetType();
4849     // Pattern must contain links only
4850     if ( aTypeE != SMDSAbs_Edge )
4851       return EXTR_PATH_NOT_EDGE;
4852   }
4853
4854   list<SMESH_MeshEditor_PathPoint> fullList;
4855
4856   const TopoDS_Shape& aS = theTrack->GetShapeToMesh();
4857
4858   if( aS == SMESH_Mesh::PseudoShape() ) {
4859     //Mesh without shape
4860     const SMDS_MeshNode* currentNode = NULL;
4861     const SMDS_MeshNode* prevNode = theN1;
4862     std::vector<const SMDS_MeshNode*> aNodesList;
4863     aNodesList.push_back(theN1);
4864     int nbEdges = 0, conn=0;
4865     const SMDS_MeshElement* prevElem = NULL;
4866     const SMDS_MeshElement* currentElem = NULL;
4867     int totalNbEdges = theTrack->NbEdges();
4868     SMDS_ElemIteratorPtr nIt;
4869     bool isClosed = false;
4870
4871     //check start node
4872     if( !theTrack->GetMeshDS()->Contains(theN1) ) {
4873       return EXTR_BAD_STARTING_NODE;
4874     }
4875     
4876     conn = nbEdgeConnectivity(theN1);
4877     if(conn > 2)
4878       return EXTR_PATH_NOT_EDGE;
4879
4880     aItE = theN1->GetInverseElementIterator();
4881     prevElem = aItE->next();
4882     currentElem = prevElem;
4883     //Get all nodes
4884     if(totalNbEdges == 1 ) {
4885       nIt = currentElem->nodesIterator();
4886       currentNode = static_cast<const SMDS_MeshNode*>(nIt->next());
4887       if(currentNode == prevNode)
4888         currentNode = static_cast<const SMDS_MeshNode*>(nIt->next());
4889       aNodesList.push_back(currentNode);
4890     } else { 
4891       nIt = currentElem->nodesIterator();
4892       while( nIt->more() ) {
4893         currentNode = static_cast<const SMDS_MeshNode*>(nIt->next());
4894         if(currentNode == prevNode)
4895           currentNode = static_cast<const SMDS_MeshNode*>(nIt->next());
4896         aNodesList.push_back(currentNode);
4897         
4898         //case of the closed mesh
4899         if(currentNode == theN1) {
4900           nbEdges++;
4901           isClosed = true;
4902           break;
4903         }
4904
4905         conn = nbEdgeConnectivity(currentNode);
4906         if(conn > 2) {
4907           return EXTR_PATH_NOT_EDGE;    
4908         }else if( conn == 1 && nbEdges > 0 ) {
4909           //End of the path
4910           nbEdges++;
4911           break;
4912         }else {
4913           prevNode = currentNode;
4914           aItE = currentNode->GetInverseElementIterator();
4915           currentElem = aItE->next();
4916           if( currentElem  == prevElem)
4917             currentElem = aItE->next();
4918           nIt = currentElem->nodesIterator();
4919           prevElem = currentElem;
4920           nbEdges++;
4921         }
4922       }
4923     } 
4924     
4925     if(nbEdges != totalNbEdges)
4926       return EXTR_PATH_NOT_EDGE;
4927
4928     TopTools_SequenceOfShape Edges;
4929     double x1,x2,y1,y2,z1,z2;
4930     list< list<SMESH_MeshEditor_PathPoint> > LLPPs;
4931     int startNid = theN1->GetID();
4932     for(int i = 1; i < aNodesList.size(); i++) {
4933       x1 = aNodesList[i-1]->X();x2 = aNodesList[i]->X();
4934       y1 = aNodesList[i-1]->Y();y2 = aNodesList[i]->Y();
4935       z1 = aNodesList[i-1]->Z();z2 = aNodesList[i]->Z();
4936       TopoDS_Edge e = BRepBuilderAPI_MakeEdge(gp_Pnt(x1,y1,z1),gp_Pnt(x2,y2,z2));  
4937       list<SMESH_MeshEditor_PathPoint> LPP;
4938       aPrms.clear();
4939       MakeEdgePathPoints(aPrms, e, (aNodesList[i-1]->GetID()==startNid), LPP);
4940       LLPPs.push_back(LPP);
4941       if( aNodesList[i-1]->GetID() == startNid ) startNid = aNodesList[i]->GetID();
4942       else startNid = aNodesList[i-1]->GetID();
4943
4944     }
4945
4946     list< list<SMESH_MeshEditor_PathPoint> >::iterator itLLPP = LLPPs.begin();
4947     list<SMESH_MeshEditor_PathPoint> firstList = *itLLPP;
4948     list<SMESH_MeshEditor_PathPoint>::iterator itPP = firstList.begin();
4949     for(; itPP!=firstList.end(); itPP++) {
4950       fullList.push_back( *itPP );
4951     }
4952
4953     SMESH_MeshEditor_PathPoint PP1 = fullList.back();
4954     SMESH_MeshEditor_PathPoint PP2;
4955     fullList.pop_back();
4956     itLLPP++;
4957     for(; itLLPP!=LLPPs.end(); itLLPP++) {
4958       list<SMESH_MeshEditor_PathPoint> currList = *itLLPP;
4959       itPP = currList.begin();
4960       PP2 = currList.front();
4961       gp_Dir D1 = PP1.Tangent();
4962       gp_Dir D2 = PP2.Tangent();
4963       gp_Dir Dnew( gp_Vec( (D1.X()+D2.X())/2, (D1.Y()+D2.Y())/2,
4964                            (D1.Z()+D2.Z())/2 ) );
4965       PP1.SetTangent(Dnew);
4966       fullList.push_back(PP1);
4967       itPP++;
4968       for(; itPP!=currList.end(); itPP++) {
4969         fullList.push_back( *itPP );
4970       }
4971       PP1 = fullList.back();
4972       fullList.pop_back();
4973     }
4974     fullList.push_back(PP1);
4975     
4976   } // Sub shape for the Pattern must be an Edge or Wire
4977   else if( aS.ShapeType() == TopAbs_EDGE ) {
4978     aTrackEdge = TopoDS::Edge( aS );
4979     // the Edge must not be degenerated
4980     if ( BRep_Tool::Degenerated( aTrackEdge ) )
4981       return EXTR_BAD_PATH_SHAPE;
4982     TopExp::Vertices( aTrackEdge, aV1, aV2 );
4983     aItN = theTrack->GetSubMesh( aV1 )->GetSubMeshDS()->GetNodes();
4984     const SMDS_MeshNode* aN1 = aItN->next();
4985     aItN = theTrack->GetSubMesh( aV2 )->GetSubMeshDS()->GetNodes();
4986     const SMDS_MeshNode* aN2 = aItN->next();
4987     // starting node must be aN1 or aN2
4988     if ( !( aN1 == theN1 || aN2 == theN1 ) )
4989       return EXTR_BAD_STARTING_NODE;
4990     aItN = pMeshDS->nodesIterator();
4991     while ( aItN->more() ) {
4992       const SMDS_MeshNode* pNode = aItN->next();
4993       if( pNode==aN1 || pNode==aN2 ) continue;
4994       const SMDS_EdgePosition* pEPos =
4995         static_cast<const SMDS_EdgePosition*>( pNode->GetPosition() );
4996       double aT = pEPos->GetUParameter();
4997       aPrms.push_back( aT );
4998     }
4999     //Extrusion_Error err =
5000     MakeEdgePathPoints(aPrms, aTrackEdge, (aN1==theN1), fullList);
5001   }
5002   else if( aS.ShapeType() == TopAbs_WIRE ) {
5003     list< SMESH_subMesh* > LSM;
5004     TopTools_SequenceOfShape Edges;
5005     TopExp_Explorer eExp(aS, TopAbs_EDGE);
5006     for(; eExp.More(); eExp.Next()) {
5007       TopoDS_Edge E = TopoDS::Edge( eExp.Current() );
5008       if( BRep_Tool::Degenerated(E) ) continue;
5009       SMESH_subMesh* SM = theTrack->GetSubMesh(E);
5010       if(SM) {
5011         LSM.push_back(SM);
5012         Edges.Append(E);
5013       }
5014     }
5015     list< list<SMESH_MeshEditor_PathPoint> > LLPPs;
5016     int startNid = theN1->GetID();
5017     TColStd_MapOfInteger UsedNums;
5018     int NbEdges = Edges.Length();
5019     int i = 1;
5020     for(; i<=NbEdges; i++) {
5021       int k = 0;
5022       list< SMESH_subMesh* >::iterator itLSM = LSM.begin();
5023       for(; itLSM!=LSM.end(); itLSM++) {
5024         k++;
5025         if(UsedNums.Contains(k)) continue;
5026         aTrackEdge = TopoDS::Edge( Edges.Value(k) );
5027         SMESH_subMesh* locTrack = *itLSM;
5028         SMESHDS_SubMesh* locMeshDS = locTrack->GetSubMeshDS();
5029         TopExp::Vertices( aTrackEdge, aV1, aV2 );
5030         aItN = locTrack->GetFather()->GetSubMesh(aV1)->GetSubMeshDS()->GetNodes();
5031         const SMDS_MeshNode* aN1 = aItN->next();
5032         aItN = locTrack->GetFather()->GetSubMesh(aV2)->GetSubMeshDS()->GetNodes();
5033         const SMDS_MeshNode* aN2 = aItN->next();
5034         // starting node must be aN1 or aN2
5035         if ( !( aN1->GetID() == startNid || aN2->GetID() == startNid ) ) continue;
5036         // 2. Collect parameters on the track edge
5037         aPrms.clear();
5038         aItN = locMeshDS->GetNodes();
5039         while ( aItN->more() ) {
5040           const SMDS_MeshNode* pNode = aItN->next();
5041           const SMDS_EdgePosition* pEPos =
5042             static_cast<const SMDS_EdgePosition*>( pNode->GetPosition() );
5043           double aT = pEPos->GetUParameter();
5044           aPrms.push_back( aT );
5045         }
5046         list<SMESH_MeshEditor_PathPoint> LPP;
5047         //Extrusion_Error err =
5048         MakeEdgePathPoints(aPrms, aTrackEdge,(aN1->GetID()==startNid), LPP);
5049         LLPPs.push_back(LPP);
5050         UsedNums.Add(k);
5051         // update startN for search following egde
5052         if( aN1->GetID() == startNid ) startNid = aN2->GetID();
5053         else startNid = aN1->GetID();
5054         break;
5055       }
5056     }
5057     list< list<SMESH_MeshEditor_PathPoint> >::iterator itLLPP = LLPPs.begin();
5058     list<SMESH_MeshEditor_PathPoint> firstList = *itLLPP;
5059     list<SMESH_MeshEditor_PathPoint>::iterator itPP = firstList.begin();
5060     for(; itPP!=firstList.end(); itPP++) {
5061       fullList.push_back( *itPP );
5062     }
5063     SMESH_MeshEditor_PathPoint PP1 = fullList.back();
5064     fullList.pop_back();
5065     itLLPP++;
5066     for(; itLLPP!=LLPPs.end(); itLLPP++) {
5067       list<SMESH_MeshEditor_PathPoint> currList = *itLLPP;
5068       itPP = currList.begin();
5069       SMESH_MeshEditor_PathPoint PP2 = currList.front();
5070       gp_Dir D1 = PP1.Tangent();
5071       gp_Dir D2 = PP2.Tangent();
5072       gp_Dir Dnew( gp_Vec( (D1.X()+D2.X())/2, (D1.Y()+D2.Y())/2,
5073                            (D1.Z()+D2.Z())/2 ) );
5074       PP1.SetTangent(Dnew);
5075       fullList.push_back(PP1);
5076       itPP++;
5077       for(; itPP!=currList.end(); itPP++) {
5078         fullList.push_back( *itPP );
5079       }
5080       PP1 = fullList.back();
5081       fullList.pop_back();
5082     }
5083     // if wire not closed
5084     fullList.push_back(PP1);
5085     // else ???
5086   }
5087   else {
5088     return EXTR_BAD_PATH_SHAPE;
5089   }
5090
5091   return MakeExtrElements(theElements, fullList, theHasAngles, theAngles, theLinearVariation,
5092                           theHasRefPoint, theRefPoint, theMakeGroups);
5093 }
5094
5095
5096 //=======================================================================
5097 //function : MakeEdgePathPoints
5098 //purpose  : auxilary for ExtrusionAlongTrack
5099 //=======================================================================
5100 SMESH_MeshEditor::Extrusion_Error
5101 SMESH_MeshEditor::MakeEdgePathPoints(std::list<double>& aPrms,
5102                                      const TopoDS_Edge& aTrackEdge,
5103                                      bool FirstIsStart,
5104                                      list<SMESH_MeshEditor_PathPoint>& LPP)
5105 {
5106   Standard_Real aTx1, aTx2, aL2, aTolVec, aTolVec2;
5107   aTolVec=1.e-7;
5108   aTolVec2=aTolVec*aTolVec;
5109   double aT1, aT2;
5110   TopoDS_Vertex aV1, aV2;
5111   TopExp::Vertices( aTrackEdge, aV1, aV2 );
5112   aT1=BRep_Tool::Parameter( aV1, aTrackEdge );
5113   aT2=BRep_Tool::Parameter( aV2, aTrackEdge );
5114   // 2. Collect parameters on the track edge
5115   aPrms.push_front( aT1 );
5116   aPrms.push_back( aT2 );
5117   // sort parameters
5118   aPrms.sort();
5119   if( FirstIsStart ) {
5120     if ( aT1 > aT2 ) {
5121       aPrms.reverse();
5122     }
5123   }
5124   else {
5125     if ( aT2 > aT1 ) {
5126       aPrms.reverse();
5127     }
5128   }
5129   // 3. Path Points
5130   SMESH_MeshEditor_PathPoint aPP;
5131   Handle(Geom_Curve) aC3D = BRep_Tool::Curve( aTrackEdge, aTx1, aTx2 );
5132   std::list<double>::iterator aItD = aPrms.begin();
5133   for(; aItD != aPrms.end(); ++aItD) {
5134     double aT = *aItD;
5135     gp_Pnt aP3D;
5136     gp_Vec aVec;
5137     aC3D->D1( aT, aP3D, aVec );
5138     aL2 = aVec.SquareMagnitude();
5139     if ( aL2 < aTolVec2 )
5140       return EXTR_CANT_GET_TANGENT;
5141     gp_Dir aTgt( aVec );
5142     aPP.SetPnt( aP3D );
5143     aPP.SetTangent( aTgt );
5144     aPP.SetParameter( aT );
5145     LPP.push_back(aPP);
5146   }
5147   return EXTR_OK;
5148 }
5149
5150
5151 //=======================================================================
5152 //function : MakeExtrElements
5153 //purpose  : auxilary for ExtrusionAlongTrack
5154 //=======================================================================
5155 SMESH_MeshEditor::Extrusion_Error
5156 SMESH_MeshEditor::MakeExtrElements(TIDSortedElemSet&  theElements,
5157                                    list<SMESH_MeshEditor_PathPoint>& fullList,
5158                                    const bool theHasAngles,
5159                                    list<double>& theAngles,
5160                                    const bool theLinearVariation,
5161                                    const bool theHasRefPoint,
5162                                    const gp_Pnt& theRefPoint,
5163                                    const bool theMakeGroups)
5164 {
5165   MESSAGE("MakeExtrElements");
5166   //cout<<"MakeExtrElements  fullList.size() = "<<fullList.size()<<endl;
5167   int aNbTP = fullList.size();
5168   vector<SMESH_MeshEditor_PathPoint> aPPs(aNbTP);
5169   // Angles
5170   if( theHasAngles && theAngles.size()>0 && theLinearVariation ) {
5171     LinearAngleVariation(aNbTP-1, theAngles);
5172   }
5173   vector<double> aAngles( aNbTP );
5174   int j = 0;
5175   for(; j<aNbTP; ++j) {
5176     aAngles[j] = 0.;
5177   }
5178   if ( theHasAngles ) {
5179     double anAngle;;
5180     std::list<double>::iterator aItD = theAngles.begin();
5181     for ( j=1; (aItD != theAngles.end()) && (j<aNbTP); ++aItD, ++j ) {
5182       anAngle = *aItD;
5183       aAngles[j] = anAngle;
5184     }
5185   }
5186   // fill vector of path points with angles
5187   //aPPs.resize(fullList.size());
5188   j = -1;
5189   list<SMESH_MeshEditor_PathPoint>::iterator itPP = fullList.begin();
5190   for(; itPP!=fullList.end(); itPP++) {
5191     j++;
5192     SMESH_MeshEditor_PathPoint PP = *itPP;
5193     PP.SetAngle(aAngles[j]);
5194     aPPs[j] = PP;
5195   }
5196
5197   TNodeOfNodeListMap mapNewNodes;
5198   TElemOfVecOfNnlmiMap mapElemNewNodes;
5199   TElemOfElemListMap newElemsMap;
5200   TIDSortedElemSet::iterator itElem;
5201   double aX, aY, aZ;
5202   int aNb;
5203   SMDSAbs_ElementType aTypeE;
5204   // source elements for each generated one
5205   SMESH_SequenceOfElemPtr srcElems, srcNodes;
5206
5207   // 3. Center of rotation aV0
5208   gp_Pnt aV0 = theRefPoint;
5209   gp_XYZ aGC;
5210   if ( !theHasRefPoint ) {
5211     aNb = 0;
5212     aGC.SetCoord( 0.,0.,0. );
5213
5214     itElem = theElements.begin();
5215     for ( ; itElem != theElements.end(); itElem++ ) {
5216       const SMDS_MeshElement* elem = *itElem;
5217
5218       SMDS_ElemIteratorPtr itN = elem->nodesIterator();
5219       while ( itN->more() ) {
5220         const SMDS_MeshNode* node = static_cast<const SMDS_MeshNode*>( itN->next() );
5221         aX = node->X();
5222         aY = node->Y();
5223         aZ = node->Z();
5224
5225         if ( mapNewNodes.find( node ) == mapNewNodes.end() ) {
5226           list<const SMDS_MeshNode*> aLNx;
5227           mapNewNodes[node] = aLNx;
5228           //
5229           gp_XYZ aXYZ( aX, aY, aZ );
5230           aGC += aXYZ;
5231           ++aNb;
5232         }
5233       }
5234     }
5235     aGC /= aNb;
5236     aV0.SetXYZ( aGC );
5237   } // if (!theHasRefPoint) {
5238   mapNewNodes.clear();
5239
5240   // 4. Processing the elements
5241   SMESHDS_Mesh* aMesh = GetMeshDS();
5242
5243   for ( itElem = theElements.begin(); itElem != theElements.end(); itElem++ ) {
5244     // check element type
5245     const SMDS_MeshElement* elem = *itElem;
5246     aTypeE = elem->GetType();
5247     if ( !elem || ( aTypeE != SMDSAbs_Face && aTypeE != SMDSAbs_Edge ) )
5248       continue;
5249
5250     vector<TNodeOfNodeListMapItr> & newNodesItVec = mapElemNewNodes[ elem ];
5251     newNodesItVec.reserve( elem->NbNodes() );
5252
5253     // loop on elem nodes
5254     int nodeIndex = -1;
5255     SMDS_ElemIteratorPtr itN = elem->nodesIterator();
5256     while ( itN->more() )
5257     {
5258       ++nodeIndex;
5259       // check if a node has been already processed
5260       const SMDS_MeshNode* node =
5261         static_cast<const SMDS_MeshNode*>( itN->next() );
5262       TNodeOfNodeListMap::iterator nIt = mapNewNodes.find( node );
5263       if ( nIt == mapNewNodes.end() ) {
5264         nIt = mapNewNodes.insert( make_pair( node, list<const SMDS_MeshNode*>() )).first;
5265         list<const SMDS_MeshNode*>& listNewNodes = nIt->second;
5266
5267         // make new nodes
5268         aX = node->X();  aY = node->Y(); aZ = node->Z();
5269
5270         Standard_Real aAngle1x, aAngleT1T0, aTolAng;
5271         gp_Pnt aP0x, aP1x, aPN0, aPN1, aV0x, aV1x;
5272         gp_Ax1 anAx1, anAxT1T0;
5273         gp_Dir aDT1x, aDT0x, aDT1T0;
5274
5275         aTolAng=1.e-4;
5276
5277         aV0x = aV0;
5278         aPN0.SetCoord(aX, aY, aZ);
5279
5280         const SMESH_MeshEditor_PathPoint& aPP0 = aPPs[0];
5281         aP0x = aPP0.Pnt();
5282         aDT0x= aPP0.Tangent();
5283         //cout<<"j = 0   PP: Pnt("<<aP0x.X()<<","<<aP0x.Y()<<","<<aP0x.Z()<<")"<<endl;
5284
5285         for ( j = 1; j < aNbTP; ++j ) {
5286           const SMESH_MeshEditor_PathPoint& aPP1 = aPPs[j];
5287           aP1x = aPP1.Pnt();
5288           aDT1x = aPP1.Tangent();
5289           aAngle1x = aPP1.Angle();
5290
5291           gp_Trsf aTrsf, aTrsfRot, aTrsfRotT1T0;
5292           // Translation
5293           gp_Vec aV01x( aP0x, aP1x );
5294           aTrsf.SetTranslation( aV01x );
5295
5296           // traslated point
5297           aV1x = aV0x.Transformed( aTrsf );
5298           aPN1 = aPN0.Transformed( aTrsf );
5299
5300           // rotation 1 [ T1,T0 ]
5301           aAngleT1T0=-aDT1x.Angle( aDT0x );
5302           if (fabs(aAngleT1T0) > aTolAng) {
5303             aDT1T0=aDT1x^aDT0x;
5304             anAxT1T0.SetLocation( aV1x );
5305             anAxT1T0.SetDirection( aDT1T0 );
5306             aTrsfRotT1T0.SetRotation( anAxT1T0, aAngleT1T0 );
5307
5308             aPN1 = aPN1.Transformed( aTrsfRotT1T0 );
5309           }
5310
5311           // rotation 2
5312           if ( theHasAngles ) {
5313             anAx1.SetLocation( aV1x );
5314             anAx1.SetDirection( aDT1x );
5315             aTrsfRot.SetRotation( anAx1, aAngle1x );
5316
5317             aPN1 = aPN1.Transformed( aTrsfRot );
5318           }
5319
5320           // make new node
5321           //MESSAGE("elem->IsQuadratic " << elem->IsQuadratic() << " " << elem->IsMediumNode(node));
5322           if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
5323             // create additional node
5324             double x = ( aPN1.X() + aPN0.X() )/2.;
5325             double y = ( aPN1.Y() + aPN0.Y() )/2.;
5326             double z = ( aPN1.Z() + aPN0.Z() )/2.;
5327             const SMDS_MeshNode* newNode = aMesh->AddNode(x,y,z);
5328             myLastCreatedNodes.Append(newNode);
5329             srcNodes.Append( node );
5330             listNewNodes.push_back( newNode );
5331           }
5332           aX = aPN1.X();
5333           aY = aPN1.Y();
5334           aZ = aPN1.Z();
5335           const SMDS_MeshNode* newNode = aMesh->AddNode( aX, aY, aZ );
5336           myLastCreatedNodes.Append(newNode);
5337           srcNodes.Append( node );
5338           listNewNodes.push_back( newNode );
5339
5340           aPN0 = aPN1;
5341           aP0x = aP1x;
5342           aV0x = aV1x;
5343           aDT0x = aDT1x;
5344         }
5345       }
5346
5347       else {
5348         // if current elem is quadratic and current node is not medium
5349         // we have to check - may be it is needed to insert additional nodes
5350         if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
5351           list< const SMDS_MeshNode* > & listNewNodes = nIt->second;
5352           if(listNewNodes.size()==aNbTP-1) {
5353             vector<const SMDS_MeshNode*> aNodes(2*(aNbTP-1));
5354             gp_XYZ P(node->X(), node->Y(), node->Z());
5355             list< const SMDS_MeshNode* >::iterator it = listNewNodes.begin();
5356             int i;
5357             for(i=0; i<aNbTP-1; i++) {
5358               const SMDS_MeshNode* N = *it;
5359               double x = ( N->X() + P.X() )/2.;
5360               double y = ( N->Y() + P.Y() )/2.;
5361               double z = ( N->Z() + P.Z() )/2.;
5362               const SMDS_MeshNode* newN = aMesh->AddNode(x,y,z);
5363               srcNodes.Append( node );
5364               myLastCreatedNodes.Append(newN);
5365               aNodes[2*i] = newN;
5366               aNodes[2*i+1] = N;
5367               P = gp_XYZ(N->X(),N->Y(),N->Z());
5368             }
5369             listNewNodes.clear();
5370             for(i=0; i<2*(aNbTP-1); i++) {
5371               listNewNodes.push_back(aNodes[i]);
5372             }
5373           }
5374         }
5375       }
5376
5377       newNodesItVec.push_back( nIt );
5378     }
5379     // make new elements
5380     //sweepElement( aMesh, elem, newNodesItVec, newElemsMap[elem],
5381     //              newNodesItVec[0]->second.size(), myLastCreatedElems );
5382     sweepElement( elem, newNodesItVec, newElemsMap[elem], aNbTP-1, srcElems );
5383   }
5384
5385   makeWalls( mapNewNodes, newElemsMap, mapElemNewNodes, theElements, aNbTP-1, srcElems );
5386
5387   if ( theMakeGroups )
5388     generateGroups( srcNodes, srcElems, "extruded");
5389
5390   return EXTR_OK;
5391 }
5392
5393
5394 //=======================================================================
5395 //function : LinearAngleVariation
5396 //purpose  : auxilary for ExtrusionAlongTrack
5397 //=======================================================================
5398 void SMESH_MeshEditor::LinearAngleVariation(const int nbSteps,
5399                                             list<double>& Angles)
5400 {
5401   int nbAngles = Angles.size();
5402   if( nbSteps > nbAngles ) {
5403     vector<double> theAngles(nbAngles);
5404     list<double>::iterator it = Angles.begin();
5405     int i = -1;
5406     for(; it!=Angles.end(); it++) {
5407       i++;
5408       theAngles[i] = (*it);
5409     }
5410     list<double> res;
5411     double rAn2St = double( nbAngles ) / double( nbSteps );
5412     double angPrev = 0, angle;
5413     for ( int iSt = 0; iSt < nbSteps; ++iSt ) {
5414       double angCur = rAn2St * ( iSt+1 );
5415       double angCurFloor  = floor( angCur );
5416       double angPrevFloor = floor( angPrev );
5417       if ( angPrevFloor == angCurFloor )
5418         angle = rAn2St * theAngles[ int( angCurFloor ) ];
5419       else {
5420         int iP = int( angPrevFloor );
5421         double angPrevCeil = ceil(angPrev);
5422         angle = ( angPrevCeil - angPrev ) * theAngles[ iP ];
5423
5424         int iC = int( angCurFloor );
5425         if ( iC < nbAngles )
5426           angle += ( angCur - angCurFloor ) * theAngles[ iC ];
5427
5428         iP = int( angPrevCeil );
5429         while ( iC-- > iP )
5430           angle += theAngles[ iC ];
5431       }
5432       res.push_back(angle);
5433       angPrev = angCur;
5434     }
5435     Angles.clear();
5436     it = res.begin();
5437     for(; it!=res.end(); it++)
5438       Angles.push_back( *it );
5439   }
5440 }
5441
5442
5443 //================================================================================
5444 /*!
5445  * \brief Move or copy theElements applying theTrsf to their nodes
5446  *  \param theElems - elements to transform, if theElems is empty then apply to all mesh nodes
5447  *  \param theTrsf - transformation to apply
5448  *  \param theCopy - if true, create translated copies of theElems
5449  *  \param theMakeGroups - if true and theCopy, create translated groups
5450  *  \param theTargetMesh - mesh to copy translated elements into
5451  *  \return SMESH_MeshEditor::PGroupIDs - list of ids of created groups
5452  */
5453 //================================================================================
5454
5455 SMESH_MeshEditor::PGroupIDs
5456 SMESH_MeshEditor::Transform (TIDSortedElemSet & theElems,
5457                              const gp_Trsf&     theTrsf,
5458                              const bool         theCopy,
5459                              const bool         theMakeGroups,
5460                              SMESH_Mesh*        theTargetMesh)
5461 {
5462   myLastCreatedElems.Clear();
5463   myLastCreatedNodes.Clear();
5464
5465   bool needReverse = false;
5466   string groupPostfix;
5467   switch ( theTrsf.Form() ) {
5468   case gp_PntMirror:
5469     MESSAGE("gp_PntMirror");
5470     needReverse = true;
5471     groupPostfix = "mirrored";
5472     break;
5473   case gp_Ax1Mirror:
5474     MESSAGE("gp_Ax1Mirror");
5475     groupPostfix = "mirrored";
5476     break;
5477   case gp_Ax2Mirror:
5478     MESSAGE("gp_Ax2Mirror");
5479     needReverse = true;
5480     groupPostfix = "mirrored";
5481     break;
5482   case gp_Rotation:
5483     MESSAGE("gp_Rotation");
5484     groupPostfix = "rotated";
5485     break;
5486   case gp_Translation:
5487     MESSAGE("gp_Translation");
5488     groupPostfix = "translated";
5489     break;
5490   case gp_Scale:
5491     MESSAGE("gp_Scale");
5492     groupPostfix = "scaled";
5493     break;
5494   case gp_CompoundTrsf: // different scale by axis
5495     MESSAGE("gp_CompoundTrsf");
5496     groupPostfix = "scaled";
5497     break;
5498   default:
5499     MESSAGE("default");
5500     needReverse = false;
5501     groupPostfix = "transformed";
5502   }
5503
5504   SMESH_MeshEditor targetMeshEditor( theTargetMesh );
5505   SMESHDS_Mesh* aTgtMesh = theTargetMesh ? theTargetMesh->GetMeshDS() : 0;
5506   SMESHDS_Mesh* aMesh    = GetMeshDS();
5507
5508
5509   // map old node to new one
5510   TNodeNodeMap nodeMap;
5511
5512   // elements sharing moved nodes; those of them which have all
5513   // nodes mirrored but are not in theElems are to be reversed
5514   TIDSortedElemSet inverseElemSet;
5515
5516   // source elements for each generated one
5517   SMESH_SequenceOfElemPtr srcElems, srcNodes;
5518
5519   // issue 021015: EDF 1578 SMESH: Free nodes are removed when translating a mesh
5520   TIDSortedElemSet orphanNode;
5521
5522   if ( theElems.empty() ) // transform the whole mesh
5523   {
5524     // add all elements
5525     SMDS_ElemIteratorPtr eIt = aMesh->elementsIterator();
5526     while ( eIt->more() ) theElems.insert( eIt->next() );
5527     // add orphan nodes
5528     SMDS_NodeIteratorPtr nIt = aMesh->nodesIterator();
5529     while ( nIt->more() )
5530     {
5531       const SMDS_MeshNode* node = nIt->next();
5532       if ( node->NbInverseElements() == 0)
5533         orphanNode.insert( node );
5534     }
5535   }
5536
5537   // loop on elements to transform nodes : first orphan nodes then elems
5538   TIDSortedElemSet::iterator itElem;
5539   TIDSortedElemSet *elements[] = {&orphanNode, &theElems };
5540   for (int i=0; i<2; i++)
5541   for ( itElem = elements[i]->begin(); itElem != elements[i]->end(); itElem++ ) {
5542     const SMDS_MeshElement* elem = *itElem;
5543     if ( !elem )
5544       continue;
5545
5546     // loop on elem nodes
5547     SMDS_ElemIteratorPtr itN = elem->nodesIterator();
5548     while ( itN->more() ) {
5549
5550       const SMDS_MeshNode* node = cast2Node( itN->next() );
5551       // check if a node has been already transformed
5552       pair<TNodeNodeMap::iterator,bool> n2n_isnew =
5553         nodeMap.insert( make_pair ( node, node ));
5554       if ( !n2n_isnew.second )
5555         continue;
5556
5557       double coord[3];
5558       coord[0] = node->X();
5559       coord[1] = node->Y();
5560       coord[2] = node->Z();
5561       theTrsf.Transforms( coord[0], coord[1], coord[2] );
5562       if ( theTargetMesh ) {
5563         const SMDS_MeshNode * newNode = aTgtMesh->AddNode( coord[0], coord[1], coord[2] );
5564         n2n_isnew.first->second = newNode;
5565         myLastCreatedNodes.Append(newNode);
5566         srcNodes.Append( node );
5567       }
5568       else if ( theCopy ) {
5569         const SMDS_MeshNode * newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
5570         n2n_isnew.first->second = newNode;
5571         myLastCreatedNodes.Append(newNode);
5572         srcNodes.Append( node );
5573       }
5574       else {
5575         aMesh->MoveNode( node, coord[0], coord[1], coord[2] );
5576         // node position on shape becomes invalid
5577         const_cast< SMDS_MeshNode* > ( node )->SetPosition
5578           ( SMDS_SpacePosition::originSpacePosition() );
5579       }
5580
5581       // keep inverse elements
5582       if ( !theCopy && !theTargetMesh && needReverse ) {
5583         SMDS_ElemIteratorPtr invElemIt = node->GetInverseElementIterator();
5584         while ( invElemIt->more() ) {
5585           const SMDS_MeshElement* iel = invElemIt->next();
5586           inverseElemSet.insert( iel );
5587         }
5588       }
5589     }
5590   }
5591
5592   // either create new elements or reverse mirrored ones
5593   if ( !theCopy && !needReverse && !theTargetMesh )
5594     return PGroupIDs();
5595
5596   TIDSortedElemSet::iterator invElemIt = inverseElemSet.begin();
5597   for ( ; invElemIt != inverseElemSet.end(); invElemIt++ )
5598     theElems.insert( *invElemIt );
5599
5600   // Replicate or reverse elements
5601
5602   for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ )
5603   {
5604     const SMDS_MeshElement* elem = *itElem;
5605     if ( !elem || elem->GetType() == SMDSAbs_Node )
5606       continue;
5607
5608     int nbNodes = elem->NbNodes();
5609     int elemType = elem->GetType();
5610
5611     if (elem->IsPoly()) {
5612
5613       // polygon or polyhedral volume
5614       switch ( elemType ) {
5615       case SMDSAbs_Face:
5616         {
5617           vector<const SMDS_MeshNode*> poly_nodes (nbNodes);
5618           int iNode = 0;
5619           SMDS_ElemIteratorPtr itN = elem->nodesIterator();
5620           while (itN->more()) {
5621             const SMDS_MeshNode* node =
5622               static_cast<const SMDS_MeshNode*>(itN->next());
5623             TNodeNodeMap::iterator nodeMapIt = nodeMap.find(node);
5624             if (nodeMapIt == nodeMap.end())
5625               break; // not all nodes transformed
5626             if (needReverse) {
5627               // reverse mirrored faces and volumes
5628               poly_nodes[nbNodes - iNode - 1] = (*nodeMapIt).second;
5629             } else {
5630               poly_nodes[iNode] = (*nodeMapIt).second;
5631             }
5632             iNode++;
5633           }
5634           if ( iNode != nbNodes )
5635             continue; // not all nodes transformed
5636
5637           if ( theTargetMesh ) {
5638             myLastCreatedElems.Append(aTgtMesh->AddPolygonalFace(poly_nodes));
5639             srcElems.Append( elem );
5640           }
5641           else if ( theCopy ) {
5642             myLastCreatedElems.Append(aMesh->AddPolygonalFace(poly_nodes));
5643             srcElems.Append( elem );
5644           }
5645           else {
5646             aMesh->ChangePolygonNodes(elem, poly_nodes);
5647           }
5648         }
5649         break;
5650       case SMDSAbs_Volume:
5651         {
5652           const SMDS_VtkVolume* aPolyedre =
5653             dynamic_cast<const SMDS_VtkVolume*>( elem );
5654           if (!aPolyedre) {
5655             MESSAGE("Warning: bad volumic element");
5656             continue;
5657           }
5658
5659           vector<const SMDS_MeshNode*> poly_nodes; poly_nodes.reserve( nbNodes );
5660           vector<int> quantities;
5661
5662           bool allTransformed = true;
5663           int nbFaces = aPolyedre->NbFaces();
5664           for (int iface = 1; iface <= nbFaces && allTransformed; iface++) {
5665             int nbFaceNodes = aPolyedre->NbFaceNodes(iface);
5666             for (int inode = 1; inode <= nbFaceNodes && allTransformed; inode++) {
5667               const SMDS_MeshNode* node = aPolyedre->GetFaceNode(iface, inode);
5668               TNodeNodeMap::iterator nodeMapIt = nodeMap.find(node);
5669               if (nodeMapIt == nodeMap.end()) {
5670                 allTransformed = false; // not all nodes transformed
5671               } else {
5672                 poly_nodes.push_back((*nodeMapIt).second);
5673               }
5674               if ( needReverse && allTransformed )
5675                 std::reverse( poly_nodes.end() - nbFaceNodes, poly_nodes.end() );
5676             }
5677             quantities.push_back(nbFaceNodes);
5678           }
5679           if ( !allTransformed )
5680             continue; // not all nodes transformed
5681
5682           if ( theTargetMesh ) {
5683             myLastCreatedElems.Append(aTgtMesh->AddPolyhedralVolume(poly_nodes, quantities));
5684             srcElems.Append( elem );
5685           }
5686           else if ( theCopy ) {
5687             myLastCreatedElems.Append(aMesh->AddPolyhedralVolume(poly_nodes, quantities));
5688             srcElems.Append( elem );
5689           }
5690           else {
5691             aMesh->ChangePolyhedronNodes(elem, poly_nodes, quantities);
5692           }
5693         }
5694         break;
5695       default:;
5696       }
5697       continue;
5698
5699     } // elem->isPoly()
5700
5701     // Regular elements
5702
5703     const std::vector<int>& i = SMDS_MeshCell::reverseSmdsOrder( elem->GetEntityType() );
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 }