Salome HOME
0021270: EDF 1870 SMESH: ExtrusionAlongPathObjX + Merge nodes remove 3D elements
[modules/smesh.git] / src / SMESH / SMESH_MeshEditor.cxx
1 // Copyright (C) 2007-2011  CEA/DEN, EDF R&D, OPEN CASCADE
2 //
3 // Copyright (C) 2003-2007  OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN,
4 // CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS
5 //
6 // This library is free software; you can redistribute it and/or
7 // modify it under the terms of the GNU Lesser General Public
8 // License as published by the Free Software Foundation; either
9 // version 2.1 of the License.
10 //
11 // This library is distributed in the hope that it will be useful,
12 // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14 // Lesser General Public License for more details.
15 //
16 // You should have received a copy of the GNU Lesser General Public
17 // License along with this library; if not, write to the Free Software
18 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
19 //
20 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
21
22 // SMESH SMESH : idl implementation based on 'SMESH' unit's classes
23 // File      : SMESH_MeshEditor.cxx
24 // Created   : Mon Apr 12 16:10:22 2004
25 // Author    : Edward AGAPOV (eap)
26
27 #include "SMESH_MeshEditor.hxx"
28
29 #include "SMDS_FaceOfNodes.hxx"
30 #include "SMDS_VolumeTool.hxx"
31 #include "SMDS_EdgePosition.hxx"
32 #include "SMDS_FacePosition.hxx"
33 #include "SMDS_SpacePosition.hxx"
34 #include "SMDS_MeshGroup.hxx"
35 #include "SMDS_LinearEdge.hxx"
36 #include "SMDS_Downward.hxx"
37 #include "SMDS_SetIterator.hxx"
38
39 #include "SMESHDS_Group.hxx"
40 #include "SMESHDS_Mesh.hxx"
41
42 #include "SMESH_Algo.hxx"
43 #include "SMESH_ControlsDef.hxx"
44 #include "SMESH_Group.hxx"
45 #include "SMESH_MesherHelper.hxx"
46 #include "SMESH_OctreeNode.hxx"
47 #include "SMESH_subMesh.hxx"
48
49 #include <Basics_OCCTVersion.hxx>
50
51 #include "utilities.h"
52
53 #include <BRepAdaptor_Surface.hxx>
54 #include <BRepBuilderAPI_MakeEdge.hxx>
55 #include <BRepClass3d_SolidClassifier.hxx>
56 #include <BRep_Tool.hxx>
57 #include <ElCLib.hxx>
58 #include <Extrema_GenExtPS.hxx>
59 #include <Extrema_POnCurv.hxx>
60 #include <Extrema_POnSurf.hxx>
61 #include <GC_MakeSegment.hxx>
62 #include <Geom2d_Curve.hxx>
63 #include <GeomAPI_ExtremaCurveCurve.hxx>
64 #include <GeomAdaptor_Surface.hxx>
65 #include <Geom_Curve.hxx>
66 #include <Geom_Line.hxx>
67 #include <Geom_Surface.hxx>
68 #include <IntAna_IntConicQuad.hxx>
69 #include <IntAna_Quadric.hxx>
70 #include <Precision.hxx>
71 #include <TColStd_ListOfInteger.hxx>
72 #include <TopAbs_State.hxx>
73 #include <TopExp.hxx>
74 #include <TopExp_Explorer.hxx>
75 #include <TopTools_ListIteratorOfListOfShape.hxx>
76 #include <TopTools_ListOfShape.hxx>
77 #include <TopTools_SequenceOfShape.hxx>
78 #include <TopoDS.hxx>
79 #include <TopoDS_Face.hxx>
80 #include <gp.hxx>
81 #include <gp_Ax1.hxx>
82 #include <gp_Dir.hxx>
83 #include <gp_Lin.hxx>
84 #include <gp_Pln.hxx>
85 #include <gp_Trsf.hxx>
86 #include <gp_Vec.hxx>
87 #include <gp_XY.hxx>
88 #include <gp_XYZ.hxx>
89
90 #include <cmath>
91
92 #include <map>
93 #include <set>
94 #include <numeric>
95 #include <limits>
96 #include <algorithm>
97 #include <sstream>
98
99 #define cast2Node(elem) static_cast<const SMDS_MeshNode*>( elem )
100
101 using namespace std;
102 using namespace SMESH::Controls;
103
104 typedef map<const SMDS_MeshElement*, list<const SMDS_MeshNode*> >    TElemOfNodeListMap;
105 typedef map<const SMDS_MeshElement*, list<const SMDS_MeshElement*> > TElemOfElemListMap;
106
107 typedef SMDS_SetIterator< SMDS_pElement, TIDSortedElemSet::const_iterator> TSetIterator;
108
109 //=======================================================================
110 //function : SMESH_MeshEditor
111 //purpose  :
112 //=======================================================================
113
114 SMESH_MeshEditor::SMESH_MeshEditor( SMESH_Mesh* theMesh )
115   :myMesh( theMesh ) // theMesh may be NULL
116 {
117 }
118
119 //=======================================================================
120 /*!
121  * \brief Add element
122  */
123 //=======================================================================
124
125 SMDS_MeshElement*
126 SMESH_MeshEditor::AddElement(const vector<const SMDS_MeshNode*> & node,
127                              const SMDSAbs_ElementType            type,
128                              const bool                           isPoly,
129                              const int                            ID)
130 {
131   //MESSAGE("AddElement " <<node.size() << " " << type << " " << isPoly << " " << ID);
132   SMDS_MeshElement* e = 0;
133   int nbnode = node.size();
134   SMESHDS_Mesh* mesh = GetMeshDS();
135   switch ( type ) {
136   case SMDSAbs_Face:
137     if ( !isPoly ) {
138       if      (nbnode == 3) {
139         if ( ID >= 1 ) e = mesh->AddFaceWithID(node[0], node[1], node[2], ID);
140         else           e = mesh->AddFace      (node[0], node[1], node[2] );
141       }
142       else if (nbnode == 4) {
143         if ( ID >= 1 ) e = mesh->AddFaceWithID(node[0], node[1], node[2], node[3], ID);
144         else           e = mesh->AddFace      (node[0], node[1], node[2], node[3] );
145       }
146       else if (nbnode == 6) {
147         if ( ID >= 1 ) e = mesh->AddFaceWithID(node[0], node[1], node[2], node[3],
148                                                node[4], node[5], ID);
149         else           e = mesh->AddFace      (node[0], node[1], node[2], node[3],
150                                                node[4], node[5] );
151       }
152       else if (nbnode == 8) {
153         if ( ID >= 1 ) e = mesh->AddFaceWithID(node[0], node[1], node[2], node[3],
154                                                node[4], node[5], node[6], node[7], ID);
155         else           e = mesh->AddFace      (node[0], node[1], node[2], node[3],
156                                                node[4], node[5], node[6], node[7] );
157       }
158       else if (nbnode == 9) {
159         if ( ID >= 1 ) e = mesh->AddFaceWithID(node[0], node[1], node[2], node[3],
160                                                node[4], node[5], node[6], node[7], node[8], ID);
161         else           e = mesh->AddFace      (node[0], node[1], node[2], node[3],
162                                                node[4], node[5], node[6], node[7], node[8] );
163       }
164     } else {
165       if ( ID >= 1 ) e = mesh->AddPolygonalFaceWithID(node, ID);
166       else           e = mesh->AddPolygonalFace      (node    );
167     }
168     break;
169
170   case SMDSAbs_Volume:
171     if ( !isPoly ) {
172       if      (nbnode == 4) {
173         if ( ID >= 1 ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3], ID);
174         else           e = mesh->AddVolume      (node[0], node[1], node[2], node[3] );
175       }
176       else if (nbnode == 5) {
177         if ( ID >= 1 ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
178                                                  node[4], ID);
179         else           e = mesh->AddVolume      (node[0], node[1], node[2], node[3],
180                                                  node[4] );
181       }
182       else if (nbnode == 6) {
183         if ( ID >= 1 ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
184                                                  node[4], node[5], ID);
185         else           e = mesh->AddVolume      (node[0], node[1], node[2], node[3],
186                                                  node[4], node[5] );
187       }
188       else if (nbnode == 8) {
189         if ( ID >= 1 ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
190                                                  node[4], node[5], node[6], node[7], ID);
191         else           e = mesh->AddVolume      (node[0], node[1], node[2], node[3],
192                                                  node[4], node[5], node[6], node[7] );
193       }
194       else if (nbnode == 10) {
195         if ( ID >= 1 ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
196                                                  node[4], node[5], node[6], node[7],
197                                                  node[8], node[9], ID);
198         else           e = mesh->AddVolume      (node[0], node[1], node[2], node[3],
199                                                  node[4], node[5], node[6], node[7],
200                                                  node[8], node[9] );
201       }
202       else if (nbnode == 12) {
203         if ( ID >= 1 ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
204                                                  node[4], node[5], node[6], node[7],
205                                                  node[8], node[9], node[10], node[11], ID);
206         else           e = mesh->AddVolume      (node[0], node[1], node[2], node[3],
207                                                  node[4], node[5], node[6], node[7],
208                                                  node[8], node[9], node[10], node[11] );
209       }
210       else if (nbnode == 13) {
211         if ( ID >= 1 ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
212                                                  node[4], node[5], node[6], node[7],
213                                                  node[8], node[9], node[10],node[11],
214                                                  node[12],ID);
215         else           e = mesh->AddVolume      (node[0], node[1], node[2], node[3],
216                                                  node[4], node[5], node[6], node[7],
217                                                  node[8], node[9], node[10],node[11],
218                                                  node[12] );
219       }
220       else if (nbnode == 15) {
221         if ( ID >= 1 ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
222                                                  node[4], node[5], node[6], node[7],
223                                                  node[8], node[9], node[10],node[11],
224                                                  node[12],node[13],node[14],ID);
225         else           e = mesh->AddVolume      (node[0], node[1], node[2], node[3],
226                                                  node[4], node[5], node[6], node[7],
227                                                  node[8], node[9], node[10],node[11],
228                                                  node[12],node[13],node[14] );
229       }
230       else if (nbnode == 20) {
231         if ( ID >= 1 ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
232                                                  node[4], node[5], node[6], node[7],
233                                                  node[8], node[9], node[10],node[11],
234                                                  node[12],node[13],node[14],node[15],
235                                                  node[16],node[17],node[18],node[19],ID);
236         else           e = mesh->AddVolume      (node[0], node[1], node[2], node[3],
237                                                  node[4], node[5], node[6], node[7],
238                                                  node[8], node[9], node[10],node[11],
239                                                  node[12],node[13],node[14],node[15],
240                                                  node[16],node[17],node[18],node[19] );
241       }
242       else if (nbnode == 27) {
243         if ( ID >= 1 ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
244                                                  node[4], node[5], node[6], node[7],
245                                                  node[8], node[9], node[10],node[11],
246                                                  node[12],node[13],node[14],node[15],
247                                                  node[16],node[17],node[18],node[19],
248                                                  node[20],node[21],node[22],node[23],
249                                                  node[24],node[25],node[26], ID);
250         else           e = mesh->AddVolume      (node[0], node[1], node[2], node[3],
251                                                  node[4], node[5], node[6], node[7],
252                                                  node[8], node[9], node[10],node[11],
253                                                  node[12],node[13],node[14],node[15],
254                                                  node[16],node[17],node[18],node[19],
255                                                  node[20],node[21],node[22],node[23],
256                                                  node[24],node[25],node[26] );
257       }
258     }
259     break;
260
261   case SMDSAbs_Edge:
262     if ( nbnode == 2 ) {
263       if ( ID >= 1 ) e = mesh->AddEdgeWithID(node[0], node[1], ID);
264       else           e = mesh->AddEdge      (node[0], node[1] );
265     }
266     else if ( nbnode == 3 ) {
267       if ( ID >= 1 ) e = mesh->AddEdgeWithID(node[0], node[1], node[2], ID);
268       else           e = mesh->AddEdge      (node[0], node[1], node[2] );
269     }
270     break;
271
272   case SMDSAbs_0DElement:
273     if ( nbnode == 1 ) {
274       if ( ID >= 1 ) e = mesh->Add0DElementWithID(node[0], ID);
275       else           e = mesh->Add0DElement      (node[0] );
276     }
277     break;
278
279   case SMDSAbs_Node:
280     if ( ID >= 1 ) e = mesh->AddNodeWithID(node[0]->X(), node[0]->Y(), node[0]->Z(), ID);
281     else           e = mesh->AddNode      (node[0]->X(), node[0]->Y(), node[0]->Z());
282     break;
283
284   default:;
285   }
286   if ( e ) myLastCreatedElems.Append( e );
287   return e;
288 }
289
290 //=======================================================================
291 /*!
292  * \brief Add element
293  */
294 //=======================================================================
295
296 SMDS_MeshElement* SMESH_MeshEditor::AddElement(const vector<int> &       nodeIDs,
297                                                const SMDSAbs_ElementType type,
298                                                const bool                isPoly,
299                                                const int                 ID)
300 {
301   vector<const SMDS_MeshNode*> nodes;
302   nodes.reserve( nodeIDs.size() );
303   vector<int>::const_iterator id = nodeIDs.begin();
304   while ( id != nodeIDs.end() ) {
305     if ( const SMDS_MeshNode* node = GetMeshDS()->FindNode( *id++ ))
306       nodes.push_back( node );
307     else
308       return 0;
309   }
310   return AddElement( nodes, type, isPoly, ID );
311 }
312
313 //=======================================================================
314 //function : Remove
315 //purpose  : Remove a node or an element.
316 //           Modify a compute state of sub-meshes which become empty
317 //=======================================================================
318
319 int SMESH_MeshEditor::Remove (const list< int >& theIDs,
320                               const bool         isNodes )
321 {
322   myLastCreatedElems.Clear();
323   myLastCreatedNodes.Clear();
324
325   SMESHDS_Mesh* aMesh = GetMeshDS();
326   set< SMESH_subMesh *> smmap;
327
328   int removed = 0;
329   list<int>::const_iterator it = theIDs.begin();
330   for ( ; it != theIDs.end(); it++ ) {
331     const SMDS_MeshElement * elem;
332     if ( isNodes )
333       elem = aMesh->FindNode( *it );
334     else
335       elem = aMesh->FindElement( *it );
336     if ( !elem )
337       continue;
338
339     // Notify VERTEX sub-meshes about modification
340     if ( isNodes ) {
341       const SMDS_MeshNode* node = cast2Node( elem );
342       if ( node->GetPosition()->GetTypeOfPosition() == SMDS_TOP_VERTEX )
343         if ( int aShapeID = node->getshapeId() )
344           if ( SMESH_subMesh * sm = GetMesh()->GetSubMeshContaining( aShapeID ) )
345             smmap.insert( sm );
346     }
347     // Find sub-meshes to notify about modification
348     //     SMDS_ElemIteratorPtr nodeIt = elem->nodesIterator();
349     //     while ( nodeIt->more() ) {
350     //       const SMDS_MeshNode* node = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
351     //       const SMDS_PositionPtr& aPosition = node->GetPosition();
352     //       if ( aPosition.get() ) {
353     //         if ( int aShapeID = aPosition->GetShapeId() ) {
354     //           if ( SMESH_subMesh * sm = GetMesh()->GetSubMeshContaining( aShapeID ) )
355     //             smmap.insert( sm );
356     //         }
357     //       }
358     //     }
359
360     // Do remove
361     if ( isNodes )
362       aMesh->RemoveNode( static_cast< const SMDS_MeshNode* >( elem ));
363     else
364       aMesh->RemoveElement( elem );
365     removed++;
366   }
367
368   // Notify sub-meshes about modification
369   if ( !smmap.empty() ) {
370     set< SMESH_subMesh *>::iterator smIt;
371     for ( smIt = smmap.begin(); smIt != smmap.end(); smIt++ )
372       (*smIt)->ComputeStateEngine( SMESH_subMesh::MESH_ENTITY_REMOVED );
373   }
374
375   //   // Check if the whole mesh becomes empty
376   //   if ( SMESH_subMesh * sm = GetMesh()->GetSubMeshContaining( 1 ) )
377   //     sm->ComputeStateEngine( SMESH_subMesh::CHECK_COMPUTE_STATE );
378
379   return removed;
380 }
381
382 //=======================================================================
383 //function : FindShape
384 //purpose  : Return an index of the shape theElem is on
385 //           or zero if a shape not found
386 //=======================================================================
387
388 int SMESH_MeshEditor::FindShape (const SMDS_MeshElement * theElem)
389 {
390   myLastCreatedElems.Clear();
391   myLastCreatedNodes.Clear();
392
393   SMESHDS_Mesh * aMesh = GetMeshDS();
394   if ( aMesh->ShapeToMesh().IsNull() )
395     return 0;
396
397   int aShapeID = theElem->getshapeId();
398   if ( aShapeID < 1 )
399     return 0;
400
401   if ( SMESHDS_SubMesh * sm = aMesh->MeshElements( aShapeID ))
402     if ( sm->Contains( theElem ))
403       return aShapeID;
404
405   if ( theElem->GetType() == SMDSAbs_Node ) {
406     MESSAGE( ":( Error: invalid myShapeId of node " << theElem->GetID() );
407   }
408   else {
409     MESSAGE( ":( Error: invalid myShapeId of element " << theElem->GetID() );
410   }
411
412   TopoDS_Shape aShape; // the shape a node of theElem is on
413   if ( theElem->GetType() != SMDSAbs_Node )
414   {
415     SMDS_ElemIteratorPtr nodeIt = theElem->nodesIterator();
416     while ( nodeIt->more() ) {
417       const SMDS_MeshNode* node = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
418       if ((aShapeID = node->getshapeId()) > 0) {
419         if ( SMESHDS_SubMesh * sm = aMesh->MeshElements( aShapeID ) ) {
420           if ( sm->Contains( theElem ))
421             return aShapeID;
422           if ( aShape.IsNull() )
423             aShape = aMesh->IndexToShape( aShapeID );
424         }
425       }
426     }
427   }
428
429   // None of nodes is on a proper shape,
430   // find the shape among ancestors of aShape on which a node is
431   if ( !aShape.IsNull() ) {
432     TopTools_ListIteratorOfListOfShape ancIt( GetMesh()->GetAncestors( aShape ));
433     for ( ; ancIt.More(); ancIt.Next() ) {
434       SMESHDS_SubMesh * sm = aMesh->MeshElements( ancIt.Value() );
435       if ( sm && sm->Contains( theElem ))
436         return aMesh->ShapeToIndex( ancIt.Value() );
437     }
438   }
439   else
440   {
441     const map<int,SMESHDS_SubMesh*>& id2sm = GetMeshDS()->SubMeshes();
442     map<int,SMESHDS_SubMesh*>::const_iterator id_sm = id2sm.begin();
443     for ( ; id_sm != id2sm.end(); ++id_sm )
444       if ( id_sm->second->Contains( theElem ))
445         return id_sm->first;
446   }
447
448   //MESSAGE ("::FindShape() - SHAPE NOT FOUND")
449   return 0;
450 }
451
452 //=======================================================================
453 //function : IsMedium
454 //purpose  :
455 //=======================================================================
456
457 bool SMESH_MeshEditor::IsMedium(const SMDS_MeshNode*      node,
458                                 const SMDSAbs_ElementType typeToCheck)
459 {
460   bool isMedium = false;
461   SMDS_ElemIteratorPtr it = node->GetInverseElementIterator(typeToCheck);
462   while (it->more() && !isMedium ) {
463     const SMDS_MeshElement* elem = it->next();
464     isMedium = elem->IsMediumNode(node);
465   }
466   return isMedium;
467 }
468
469 //=======================================================================
470 //function : ShiftNodesQuadTria
471 //purpose  : auxilary
472 //           Shift nodes in the array corresponded to quadratic triangle
473 //           example: (0,1,2,3,4,5) -> (1,2,0,4,5,3)
474 //=======================================================================
475 static void ShiftNodesQuadTria(const SMDS_MeshNode* aNodes[])
476 {
477   const SMDS_MeshNode* nd1 = aNodes[0];
478   aNodes[0] = aNodes[1];
479   aNodes[1] = aNodes[2];
480   aNodes[2] = nd1;
481   const SMDS_MeshNode* nd2 = aNodes[3];
482   aNodes[3] = aNodes[4];
483   aNodes[4] = aNodes[5];
484   aNodes[5] = nd2;
485 }
486
487 //=======================================================================
488 //function : edgeConnectivity
489 //purpose  : auxilary 
490 //           return number of the edges connected with the theNode.
491 //           if theEdges has connections with the other type of the
492 //           elements, return -1 
493 //=======================================================================
494 static int nbEdgeConnectivity(const SMDS_MeshNode* theNode)
495 {
496   SMDS_ElemIteratorPtr elemIt = theNode->GetInverseElementIterator();
497   int nb=0;
498   while(elemIt->more()) {
499     elemIt->next();
500     nb++;
501   }
502   return nb;
503 }
504
505
506 //=======================================================================
507 //function : GetNodesFromTwoTria
508 //purpose  : auxilary
509 //           Shift nodes in the array corresponded to quadratic triangle
510 //           example: (0,1,2,3,4,5) -> (1,2,0,4,5,3)
511 //=======================================================================
512 static bool GetNodesFromTwoTria(const SMDS_MeshElement * theTria1,
513                                 const SMDS_MeshElement * theTria2,
514                                 const SMDS_MeshNode* N1[],
515                                 const SMDS_MeshNode* N2[])
516 {
517   SMDS_ElemIteratorPtr it = theTria1->nodesIterator();
518   int i=0;
519   while(i<6) {
520     N1[i] = static_cast<const SMDS_MeshNode*>( it->next() );
521     i++;
522   }
523   if(it->more()) return false;
524   it = theTria2->nodesIterator();
525   i=0;
526   while(i<6) {
527     N2[i] = static_cast<const SMDS_MeshNode*>( it->next() );
528     i++;
529   }
530   if(it->more()) return false;
531
532   int sames[3] = {-1,-1,-1};
533   int nbsames = 0;
534   int j;
535   for(i=0; i<3; i++) {
536     for(j=0; j<3; j++) {
537       if(N1[i]==N2[j]) {
538         sames[i] = j;
539         nbsames++;
540         break;
541       }
542     }
543   }
544   if(nbsames!=2) return false;
545   if(sames[0]>-1) {
546     ShiftNodesQuadTria(N1);
547     if(sames[1]>-1) {
548       ShiftNodesQuadTria(N1);
549     }
550   }
551   i = sames[0] + sames[1] + sames[2];
552   for(; i<2; i++) {
553     ShiftNodesQuadTria(N2);
554   }
555   // now we receive following N1 and N2 (using numeration as above image)
556   // tria1 : (1 2 4 5 9 7)  and  tria2 : (3 4 2 8 9 6)
557   // i.e. first nodes from both arrays determ new diagonal
558   return true;
559 }
560
561 //=======================================================================
562 //function : InverseDiag
563 //purpose  : Replace two neighbour triangles with ones built on the same 4 nodes
564 //           but having other common link.
565 //           Return False if args are improper
566 //=======================================================================
567
568 bool SMESH_MeshEditor::InverseDiag (const SMDS_MeshElement * theTria1,
569                                     const SMDS_MeshElement * theTria2 )
570 {
571   MESSAGE("InverseDiag");
572   myLastCreatedElems.Clear();
573   myLastCreatedNodes.Clear();
574
575   if (!theTria1 || !theTria2)
576     return false;
577
578   const SMDS_VtkFace* F1 = dynamic_cast<const SMDS_VtkFace*>( theTria1 );
579   if (!F1) return false;
580   const SMDS_VtkFace* F2 = dynamic_cast<const SMDS_VtkFace*>( theTria2 );
581   if (!F2) return false;
582   if ((theTria1->GetEntityType() == SMDSEntity_Triangle) &&
583       (theTria2->GetEntityType() == SMDSEntity_Triangle)) {
584
585     //  1 +--+ A  theTria1: ( 1 A B ) A->2 ( 1 2 B ) 1 +--+ A
586     //    | /|    theTria2: ( B A 2 ) B->1 ( 1 A 2 )   |\ |
587     //    |/ |                                         | \|
588     //  B +--+ 2                                     B +--+ 2
589
590     // put nodes in array and find out indices of the same ones
591     const SMDS_MeshNode* aNodes [6];
592     int sameInd [] = { 0, 0, 0, 0, 0, 0 };
593     int i = 0;
594     SMDS_ElemIteratorPtr it = theTria1->nodesIterator();
595     while ( it->more() ) {
596       aNodes[ i ] = static_cast<const SMDS_MeshNode*>( it->next() );
597
598       if ( i > 2 ) // theTria2
599         // find same node of theTria1
600         for ( int j = 0; j < 3; j++ )
601           if ( aNodes[ i ] == aNodes[ j ]) {
602             sameInd[ j ] = i;
603             sameInd[ i ] = j;
604             break;
605           }
606       // next
607       i++;
608       if ( i == 3 ) {
609         if ( it->more() )
610           return false; // theTria1 is not a triangle
611         it = theTria2->nodesIterator();
612       }
613       if ( i == 6 && it->more() )
614         return false; // theTria2 is not a triangle
615     }
616
617     // find indices of 1,2 and of A,B in theTria1
618     int iA = 0, iB = 0, i1 = 0, i2 = 0;
619     for ( i = 0; i < 6; i++ ) {
620       if ( sameInd [ i ] == 0 ) {
621         if ( i < 3 ) i1 = i;
622         else         i2 = i;
623       }
624       else if (i < 3) {
625         if ( iA ) iB = i;
626         else      iA = i;
627       }
628     }
629     // nodes 1 and 2 should not be the same
630     if ( aNodes[ i1 ] == aNodes[ i2 ] )
631       return false;
632
633     // theTria1: A->2
634     aNodes[ iA ] = aNodes[ i2 ];
635     // theTria2: B->1
636     aNodes[ sameInd[ iB ]] = aNodes[ i1 ];
637
638     GetMeshDS()->ChangeElementNodes( theTria1, aNodes, 3 );
639     GetMeshDS()->ChangeElementNodes( theTria2, &aNodes[ 3 ], 3 );
640
641     return true;
642
643   } // end if(F1 && F2)
644
645   // check case of quadratic faces
646   if (theTria1->GetEntityType() != SMDSEntity_Quad_Triangle)
647     return false;
648   if (theTria2->GetEntityType() != SMDSEntity_Quad_Triangle)
649     return false;
650
651   //       5
652   //  1 +--+--+ 2  theTria1: (1 2 4 5 9 7) or (2 4 1 9 7 5) or (4 1 2 7 5 9)
653   //    |    /|    theTria2: (2 3 4 6 8 9) or (3 4 2 8 9 6) or (4 2 3 9 6 8)
654   //    |   / |
655   //  7 +  +  + 6
656   //    | /9  |
657   //    |/    |
658   //  4 +--+--+ 3
659   //       8
660
661   const SMDS_MeshNode* N1 [6];
662   const SMDS_MeshNode* N2 [6];
663   if(!GetNodesFromTwoTria(theTria1,theTria2,N1,N2))
664     return false;
665   // now we receive following N1 and N2 (using numeration as above image)
666   // tria1 : (1 2 4 5 9 7)  and  tria2 : (3 4 2 8 9 6)
667   // i.e. first nodes from both arrays determ new diagonal
668
669   const SMDS_MeshNode* N1new [6];
670   const SMDS_MeshNode* N2new [6];
671   N1new[0] = N1[0];
672   N1new[1] = N2[0];
673   N1new[2] = N2[1];
674   N1new[3] = N1[4];
675   N1new[4] = N2[3];
676   N1new[5] = N1[5];
677   N2new[0] = N1[0];
678   N2new[1] = N1[1];
679   N2new[2] = N2[0];
680   N2new[3] = N1[3];
681   N2new[4] = N2[5];
682   N2new[5] = N1[4];
683   // replaces nodes in faces
684   GetMeshDS()->ChangeElementNodes( theTria1, N1new, 6 );
685   GetMeshDS()->ChangeElementNodes( theTria2, N2new, 6 );
686
687   return true;
688 }
689
690 //=======================================================================
691 //function : findTriangles
692 //purpose  : find triangles sharing theNode1-theNode2 link
693 //=======================================================================
694
695 static bool findTriangles(const SMDS_MeshNode *    theNode1,
696                           const SMDS_MeshNode *    theNode2,
697                           const SMDS_MeshElement*& theTria1,
698                           const SMDS_MeshElement*& theTria2)
699 {
700   if ( !theNode1 || !theNode2 ) return false;
701
702   theTria1 = theTria2 = 0;
703
704   set< const SMDS_MeshElement* > emap;
705   SMDS_ElemIteratorPtr it = theNode1->GetInverseElementIterator(SMDSAbs_Face);
706   while (it->more()) {
707     const SMDS_MeshElement* elem = it->next();
708     if ( elem->NbNodes() == 3 )
709       emap.insert( elem );
710   }
711   it = theNode2->GetInverseElementIterator(SMDSAbs_Face);
712   while (it->more()) {
713     const SMDS_MeshElement* elem = it->next();
714     if ( emap.find( elem ) != emap.end() ) {
715       if ( theTria1 ) {
716         // theTria1 must be element with minimum ID
717         if( theTria1->GetID() < elem->GetID() ) {
718           theTria2 = elem;
719         }
720         else {
721           theTria2 = theTria1;
722           theTria1 = elem;
723         }
724         break;
725       }
726       else {
727         theTria1 = elem;
728       }
729     }
730   }
731   return ( theTria1 && theTria2 );
732 }
733
734 //=======================================================================
735 //function : InverseDiag
736 //purpose  : Replace two neighbour triangles sharing theNode1-theNode2 link
737 //           with ones built on the same 4 nodes but having other common link.
738 //           Return false if proper faces not found
739 //=======================================================================
740
741 bool SMESH_MeshEditor::InverseDiag (const SMDS_MeshNode * theNode1,
742                                     const SMDS_MeshNode * theNode2)
743 {
744   myLastCreatedElems.Clear();
745   myLastCreatedNodes.Clear();
746
747   MESSAGE( "::InverseDiag()" );
748
749   const SMDS_MeshElement *tr1, *tr2;
750   if ( !findTriangles( theNode1, theNode2, tr1, tr2 ))
751     return false;
752
753   const SMDS_VtkFace* F1 = dynamic_cast<const SMDS_VtkFace*>( tr1 );
754   if (!F1) return false;
755   const SMDS_VtkFace* F2 = dynamic_cast<const SMDS_VtkFace*>( tr2 );
756   if (!F2) return false;
757   if ((tr1->GetEntityType() == SMDSEntity_Triangle) &&
758       (tr2->GetEntityType() == SMDSEntity_Triangle)) {
759
760     //  1 +--+ A  tr1: ( 1 A B ) A->2 ( 1 2 B ) 1 +--+ A
761     //    | /|    tr2: ( B A 2 ) B->1 ( 1 A 2 )   |\ |
762     //    |/ |                                    | \|
763     //  B +--+ 2                                B +--+ 2
764
765     // put nodes in array
766     // and find indices of 1,2 and of A in tr1 and of B in tr2
767     int i, iA1 = 0, i1 = 0;
768     const SMDS_MeshNode* aNodes1 [3];
769     SMDS_ElemIteratorPtr it;
770     for (i = 0, it = tr1->nodesIterator(); it->more(); i++ ) {
771       aNodes1[ i ] = static_cast<const SMDS_MeshNode*>( it->next() );
772       if ( aNodes1[ i ] == theNode1 )
773         iA1 = i; // node A in tr1
774       else if ( aNodes1[ i ] != theNode2 )
775         i1 = i;  // node 1
776     }
777     int iB2 = 0, i2 = 0;
778     const SMDS_MeshNode* aNodes2 [3];
779     for (i = 0, it = tr2->nodesIterator(); it->more(); i++ ) {
780       aNodes2[ i ] = static_cast<const SMDS_MeshNode*>( it->next() );
781       if ( aNodes2[ i ] == theNode2 )
782         iB2 = i; // node B in tr2
783       else if ( aNodes2[ i ] != theNode1 )
784         i2 = i;  // node 2
785     }
786
787     // nodes 1 and 2 should not be the same
788     if ( aNodes1[ i1 ] == aNodes2[ i2 ] )
789       return false;
790
791     // tr1: A->2
792     aNodes1[ iA1 ] = aNodes2[ i2 ];
793     // tr2: B->1
794     aNodes2[ iB2 ] = aNodes1[ i1 ];
795
796     GetMeshDS()->ChangeElementNodes( tr1, aNodes1, 3 );
797     GetMeshDS()->ChangeElementNodes( tr2, aNodes2, 3 );
798
799     return true;
800   }
801
802   // check case of quadratic faces
803   return InverseDiag(tr1,tr2);
804 }
805
806 //=======================================================================
807 //function : getQuadrangleNodes
808 //purpose  : fill theQuadNodes - nodes of a quadrangle resulting from
809 //           fusion of triangles tr1 and tr2 having shared link on
810 //           theNode1 and theNode2
811 //=======================================================================
812
813 bool getQuadrangleNodes(const SMDS_MeshNode *    theQuadNodes [],
814                         const SMDS_MeshNode *    theNode1,
815                         const SMDS_MeshNode *    theNode2,
816                         const SMDS_MeshElement * tr1,
817                         const SMDS_MeshElement * tr2 )
818 {
819   if( tr1->NbNodes() != tr2->NbNodes() )
820     return false;
821   // find the 4-th node to insert into tr1
822   const SMDS_MeshNode* n4 = 0;
823   SMDS_ElemIteratorPtr it = tr2->nodesIterator();
824   int i=0;
825   while ( !n4 && i<3 ) {
826     const SMDS_MeshNode * n = cast2Node( it->next() );
827     i++;
828     bool isDiag = ( n == theNode1 || n == theNode2 );
829     if ( !isDiag )
830       n4 = n;
831   }
832   // Make an array of nodes to be in a quadrangle
833   int iNode = 0, iFirstDiag = -1;
834   it = tr1->nodesIterator();
835   i=0;
836   while ( i<3 ) {
837     const SMDS_MeshNode * n = cast2Node( it->next() );
838     i++;
839     bool isDiag = ( n == theNode1 || n == theNode2 );
840     if ( isDiag ) {
841       if ( iFirstDiag < 0 )
842         iFirstDiag = iNode;
843       else if ( iNode - iFirstDiag == 1 )
844         theQuadNodes[ iNode++ ] = n4; // insert the 4-th node between diagonal nodes
845     }
846     else if ( n == n4 ) {
847       return false; // tr1 and tr2 should not have all the same nodes
848     }
849     theQuadNodes[ iNode++ ] = n;
850   }
851   if ( iNode == 3 ) // diagonal nodes have 0 and 2 indices
852     theQuadNodes[ iNode ] = n4;
853
854   return true;
855 }
856
857 //=======================================================================
858 //function : DeleteDiag
859 //purpose  : Replace two neighbour triangles sharing theNode1-theNode2 link
860 //           with a quadrangle built on the same 4 nodes.
861 //           Return false if proper faces not found
862 //=======================================================================
863
864 bool SMESH_MeshEditor::DeleteDiag (const SMDS_MeshNode * theNode1,
865                                    const SMDS_MeshNode * theNode2)
866 {
867   myLastCreatedElems.Clear();
868   myLastCreatedNodes.Clear();
869
870   MESSAGE( "::DeleteDiag()" );
871
872   const SMDS_MeshElement *tr1, *tr2;
873   if ( !findTriangles( theNode1, theNode2, tr1, tr2 ))
874     return false;
875
876   const SMDS_VtkFace* F1 = dynamic_cast<const SMDS_VtkFace*>( tr1 );
877   if (!F1) return false;
878   const SMDS_VtkFace* F2 = dynamic_cast<const SMDS_VtkFace*>( tr2 );
879   if (!F2) return false;
880   SMESHDS_Mesh * aMesh = GetMeshDS();
881
882   if ((tr1->GetEntityType() == SMDSEntity_Triangle) &&
883       (tr2->GetEntityType() == SMDSEntity_Triangle)) {
884
885     const SMDS_MeshNode* aNodes [ 4 ];
886     if ( ! getQuadrangleNodes( aNodes, theNode1, theNode2, tr1, tr2 ))
887       return false;
888
889     const SMDS_MeshElement* newElem = 0;
890     newElem = aMesh->AddFace( aNodes[0], aNodes[1], aNodes[2], aNodes[3] );
891     myLastCreatedElems.Append(newElem);
892     AddToSameGroups( newElem, tr1, aMesh );
893     int aShapeId = tr1->getshapeId();
894     if ( aShapeId )
895       {
896         aMesh->SetMeshElementOnShape( newElem, aShapeId );
897       }
898     aMesh->RemoveElement( tr1 );
899     aMesh->RemoveElement( tr2 );
900
901     return true;
902   }
903
904   // check case of quadratic faces
905   if (tr1->GetEntityType() != SMDSEntity_Quad_Triangle)
906     return false;
907   if (tr2->GetEntityType() != SMDSEntity_Quad_Triangle)
908     return false;
909
910   //       5
911   //  1 +--+--+ 2  tr1: (1 2 4 5 9 7) or (2 4 1 9 7 5) or (4 1 2 7 5 9)
912   //    |    /|    tr2: (2 3 4 6 8 9) or (3 4 2 8 9 6) or (4 2 3 9 6 8)
913   //    |   / |
914   //  7 +  +  + 6
915   //    | /9  |
916   //    |/    |
917   //  4 +--+--+ 3
918   //       8
919
920   const SMDS_MeshNode* N1 [6];
921   const SMDS_MeshNode* N2 [6];
922   if(!GetNodesFromTwoTria(tr1,tr2,N1,N2))
923     return false;
924   // now we receive following N1 and N2 (using numeration as above image)
925   // tria1 : (1 2 4 5 9 7)  and  tria2 : (3 4 2 8 9 6)
926   // i.e. first nodes from both arrays determ new diagonal
927
928   const SMDS_MeshNode* aNodes[8];
929   aNodes[0] = N1[0];
930   aNodes[1] = N1[1];
931   aNodes[2] = N2[0];
932   aNodes[3] = N2[1];
933   aNodes[4] = N1[3];
934   aNodes[5] = N2[5];
935   aNodes[6] = N2[3];
936   aNodes[7] = N1[5];
937
938   const SMDS_MeshElement* newElem = 0;
939   newElem = aMesh->AddFace( aNodes[0], aNodes[1], aNodes[2], aNodes[3],
940                             aNodes[4], aNodes[5], aNodes[6], aNodes[7]);
941   myLastCreatedElems.Append(newElem);
942   AddToSameGroups( newElem, tr1, aMesh );
943   int aShapeId = tr1->getshapeId();
944   if ( aShapeId )
945     {
946       aMesh->SetMeshElementOnShape( newElem, aShapeId );
947     }
948   aMesh->RemoveElement( tr1 );
949   aMesh->RemoveElement( tr2 );
950
951   // remove middle node (9)
952   GetMeshDS()->RemoveNode( N1[4] );
953
954   return true;
955 }
956
957 //=======================================================================
958 //function : Reorient
959 //purpose  : Reverse theElement orientation
960 //=======================================================================
961
962 bool SMESH_MeshEditor::Reorient (const SMDS_MeshElement * theElem)
963 {
964   MESSAGE("Reorient");
965   myLastCreatedElems.Clear();
966   myLastCreatedNodes.Clear();
967
968   if (!theElem)
969     return false;
970   SMDS_ElemIteratorPtr it = theElem->nodesIterator();
971   if ( !it || !it->more() )
972     return false;
973
974   switch ( theElem->GetType() ) {
975
976   case SMDSAbs_Edge:
977   case SMDSAbs_Face: {
978     if(!theElem->IsQuadratic()) {
979       int i = theElem->NbNodes();
980       vector<const SMDS_MeshNode*> aNodes( i );
981       while ( it->more() )
982         aNodes[ --i ]= static_cast<const SMDS_MeshNode*>( it->next() );
983       return GetMeshDS()->ChangeElementNodes( theElem, &aNodes[0], theElem->NbNodes() );
984     }
985     else {
986       // quadratic elements
987       if(theElem->GetType()==SMDSAbs_Edge) {
988         vector<const SMDS_MeshNode*> aNodes(3);
989         aNodes[1]= static_cast<const SMDS_MeshNode*>( it->next() );
990         aNodes[0]= static_cast<const SMDS_MeshNode*>( it->next() );
991         aNodes[2]= static_cast<const SMDS_MeshNode*>( it->next() );
992         return GetMeshDS()->ChangeElementNodes( theElem, &aNodes[0], 3 );
993       }
994       else {
995         int nbn = theElem->NbNodes();
996         vector<const SMDS_MeshNode*> aNodes(nbn);
997         aNodes[0]= static_cast<const SMDS_MeshNode*>( it->next() );
998         int i=1;
999         for(; i<nbn/2; i++) {
1000           aNodes[nbn/2-i]= static_cast<const SMDS_MeshNode*>( it->next() );
1001         }
1002         for(i=0; i<nbn/2; i++) {
1003           aNodes[nbn-i-1]= static_cast<const SMDS_MeshNode*>( it->next() );
1004         }
1005         return GetMeshDS()->ChangeElementNodes( theElem, &aNodes[0], nbn );
1006       }
1007     }
1008   }
1009   case SMDSAbs_Volume: {
1010     if (theElem->IsPoly()) {
1011       // TODO reorient vtk polyhedron
1012       MESSAGE("reorient vtk polyhedron ?");
1013       const SMDS_VtkVolume* aPolyedre =
1014         dynamic_cast<const SMDS_VtkVolume*>( theElem );
1015       if (!aPolyedre) {
1016         MESSAGE("Warning: bad volumic element");
1017         return false;
1018       }
1019
1020       int nbFaces = aPolyedre->NbFaces();
1021       vector<const SMDS_MeshNode *> poly_nodes;
1022       vector<int> quantities (nbFaces);
1023
1024       // reverse each face of the polyedre
1025       for (int iface = 1; iface <= nbFaces; iface++) {
1026         int inode, nbFaceNodes = aPolyedre->NbFaceNodes(iface);
1027         quantities[iface - 1] = nbFaceNodes;
1028
1029         for (inode = nbFaceNodes; inode >= 1; inode--) {
1030           const SMDS_MeshNode* curNode = aPolyedre->GetFaceNode(iface, inode);
1031           poly_nodes.push_back(curNode);
1032         }
1033       }
1034
1035       return GetMeshDS()->ChangePolyhedronNodes( theElem, poly_nodes, quantities );
1036
1037     }
1038     else {
1039       SMDS_VolumeTool vTool;
1040       if ( !vTool.Set( theElem ))
1041         return false;
1042       vTool.Inverse();
1043       MESSAGE("ChangeElementNodes reorient: check vTool.Inverse");
1044       return GetMeshDS()->ChangeElementNodes( theElem, vTool.GetNodes(), vTool.NbNodes() );
1045     }
1046   }
1047   default:;
1048   }
1049
1050   return false;
1051 }
1052
1053 //=======================================================================
1054 //function : getBadRate
1055 //purpose  :
1056 //=======================================================================
1057
1058 static double getBadRate (const SMDS_MeshElement*               theElem,
1059                           SMESH::Controls::NumericalFunctorPtr& theCrit)
1060 {
1061   SMESH::Controls::TSequenceOfXYZ P;
1062   if ( !theElem || !theCrit->GetPoints( theElem, P ))
1063     return 1e100;
1064   return theCrit->GetBadRate( theCrit->GetValue( P ), theElem->NbNodes() );
1065   //return theCrit->GetBadRate( theCrit->GetValue( theElem->GetID() ), theElem->NbNodes() );
1066 }
1067
1068 //=======================================================================
1069 //function : QuadToTri
1070 //purpose  : Cut quadrangles into triangles.
1071 //           theCrit is used to select a diagonal to cut
1072 //=======================================================================
1073
1074 bool SMESH_MeshEditor::QuadToTri (TIDSortedElemSet &                   theElems,
1075                                   SMESH::Controls::NumericalFunctorPtr theCrit)
1076 {
1077   myLastCreatedElems.Clear();
1078   myLastCreatedNodes.Clear();
1079
1080   MESSAGE( "::QuadToTri()" );
1081
1082   if ( !theCrit.get() )
1083     return false;
1084
1085   SMESHDS_Mesh * aMesh = GetMeshDS();
1086
1087   Handle(Geom_Surface) surface;
1088   SMESH_MesherHelper   helper( *GetMesh() );
1089
1090   TIDSortedElemSet::iterator itElem;
1091   for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
1092     const SMDS_MeshElement* elem = *itElem;
1093     if ( !elem || elem->GetType() != SMDSAbs_Face )
1094       continue;
1095     if ( elem->NbCornerNodes() != 4 )
1096       continue;
1097
1098     // retrieve element nodes
1099     vector< const SMDS_MeshNode* > aNodes( elem->begin_nodes(), elem->end_nodes() );
1100
1101     // compare two sets of possible triangles
1102     double aBadRate1, aBadRate2; // to what extent a set is bad
1103     SMDS_FaceOfNodes tr1 ( aNodes[0], aNodes[1], aNodes[2] );
1104     SMDS_FaceOfNodes tr2 ( aNodes[2], aNodes[3], aNodes[0] );
1105     aBadRate1 = getBadRate( &tr1, theCrit ) + getBadRate( &tr2, theCrit );
1106
1107     SMDS_FaceOfNodes tr3 ( aNodes[1], aNodes[2], aNodes[3] );
1108     SMDS_FaceOfNodes tr4 ( aNodes[3], aNodes[0], aNodes[1] );
1109     aBadRate2 = getBadRate( &tr3, theCrit ) + getBadRate( &tr4, theCrit );
1110
1111     int aShapeId = FindShape( elem );
1112     const SMDS_MeshElement* newElem1 = 0;
1113     const SMDS_MeshElement* newElem2 = 0;
1114
1115     if( !elem->IsQuadratic() ) {
1116
1117       // split liner quadrangle
1118
1119       if ( aBadRate1 <= aBadRate2 ) {
1120         // tr1 + tr2 is better
1121         newElem1 = aMesh->AddFace( aNodes[2], aNodes[3], aNodes[0] );
1122         newElem2 = aMesh->AddFace( aNodes[2], aNodes[0], aNodes[1] );
1123       }
1124       else {
1125         // tr3 + tr4 is better
1126         newElem1 = aMesh->AddFace( aNodes[3], aNodes[0], aNodes[1] );
1127         newElem2 = aMesh->AddFace( aNodes[3], aNodes[1], aNodes[2] );
1128       }
1129     }
1130     else {
1131
1132       // split quadratic quadrangle
1133
1134       // get surface elem is on
1135       if ( aShapeId != helper.GetSubShapeID() ) {
1136         surface.Nullify();
1137         TopoDS_Shape shape;
1138         if ( aShapeId > 0 )
1139           shape = aMesh->IndexToShape( aShapeId );
1140         if ( !shape.IsNull() && shape.ShapeType() == TopAbs_FACE ) {
1141           TopoDS_Face face = TopoDS::Face( shape );
1142           surface = BRep_Tool::Surface( face );
1143           if ( !surface.IsNull() )
1144             helper.SetSubShape( shape );
1145         }
1146       }
1147       // find middle point for (0,1,2,3)
1148       // and create a node in this point;
1149       const SMDS_MeshNode* newN = 0;
1150       if ( aNodes.size() == 9 )
1151       {
1152         // SMDSEntity_BiQuad_Quadrangle
1153         newN = aNodes.back();
1154       }
1155       else
1156       {
1157         gp_XYZ p( 0,0,0 );
1158         if ( surface.IsNull() )
1159         {
1160           for ( int i = 0; i < 4; i++ )
1161             p += gp_XYZ(aNodes[i]->X(), aNodes[i]->Y(), aNodes[i]->Z() );
1162           p /= 4;
1163         }
1164         else
1165         {
1166           const SMDS_MeshNode* inFaceNode = 0;
1167           if ( helper.GetNodeUVneedInFaceNode() )
1168             for ( size_t i = 0; i < aNodes.size() && !inFaceNode; ++i )
1169               if ( aNodes[ i ]->GetPosition()->GetTypeOfPosition() == SMDS_TOP_FACE )
1170                 inFaceNode = aNodes[ i ];
1171
1172           TopoDS_Face face = TopoDS::Face( helper.GetSubShape() );
1173           gp_XY uv( 0,0 );
1174           for ( int i = 0; i < 4; i++ )
1175             uv += helper.GetNodeUV( face, aNodes[i], inFaceNode );
1176           uv /= 4.;
1177           p = surface->Value( uv.X(), uv.Y() ).XYZ();
1178         }
1179         newN = aMesh->AddNode( p.X(), p.Y(), p.Z() );
1180         myLastCreatedNodes.Append(newN);
1181       }
1182       // create a new element
1183       if ( aBadRate1 <= aBadRate2 ) {
1184         newElem1 = aMesh->AddFace(aNodes[2], aNodes[3], aNodes[0],
1185                                   aNodes[6], aNodes[7], newN );
1186         newElem2 = aMesh->AddFace(aNodes[2], aNodes[0], aNodes[1],
1187                                   newN,      aNodes[4], aNodes[5] );
1188       }
1189       else {
1190         newElem1 = aMesh->AddFace(aNodes[3], aNodes[0], aNodes[1],
1191                                   aNodes[7], aNodes[4], newN );
1192         newElem2 = aMesh->AddFace(aNodes[3], aNodes[1], aNodes[2],
1193                                   newN,      aNodes[5], aNodes[6] );
1194       }
1195     } // quadratic case
1196
1197     // care of a new element
1198
1199     myLastCreatedElems.Append(newElem1);
1200     myLastCreatedElems.Append(newElem2);
1201     AddToSameGroups( newElem1, elem, aMesh );
1202     AddToSameGroups( newElem2, elem, aMesh );
1203
1204     // put a new triangle on the same shape
1205     if ( aShapeId )
1206       {
1207         aMesh->SetMeshElementOnShape( newElem1, aShapeId );
1208         aMesh->SetMeshElementOnShape( newElem2, aShapeId );
1209       }
1210     aMesh->RemoveElement( elem );
1211   }
1212   return true;
1213 }
1214
1215 //=======================================================================
1216 //function : BestSplit
1217 //purpose  : Find better diagonal for cutting.
1218 //=======================================================================
1219
1220 int SMESH_MeshEditor::BestSplit (const SMDS_MeshElement*              theQuad,
1221                                  SMESH::Controls::NumericalFunctorPtr theCrit)
1222 {
1223   myLastCreatedElems.Clear();
1224   myLastCreatedNodes.Clear();
1225
1226   if (!theCrit.get())
1227     return -1;
1228
1229   if (!theQuad || theQuad->GetType() != SMDSAbs_Face )
1230     return -1;
1231
1232   if( theQuad->NbNodes()==4 ||
1233       (theQuad->NbNodes()==8 && theQuad->IsQuadratic()) ) {
1234
1235     // retrieve element nodes
1236     const SMDS_MeshNode* aNodes [4];
1237     SMDS_ElemIteratorPtr itN = theQuad->nodesIterator();
1238     int i = 0;
1239     //while (itN->more())
1240     while (i<4) {
1241       aNodes[ i++ ] = static_cast<const SMDS_MeshNode*>( itN->next() );
1242     }
1243     // compare two sets of possible triangles
1244     double aBadRate1, aBadRate2; // to what extent a set is bad
1245     SMDS_FaceOfNodes tr1 ( aNodes[0], aNodes[1], aNodes[2] );
1246     SMDS_FaceOfNodes tr2 ( aNodes[2], aNodes[3], aNodes[0] );
1247     aBadRate1 = getBadRate( &tr1, theCrit ) + getBadRate( &tr2, theCrit );
1248
1249     SMDS_FaceOfNodes tr3 ( aNodes[1], aNodes[2], aNodes[3] );
1250     SMDS_FaceOfNodes tr4 ( aNodes[3], aNodes[0], aNodes[1] );
1251     aBadRate2 = getBadRate( &tr3, theCrit ) + getBadRate( &tr4, theCrit );
1252
1253     if (aBadRate1 <= aBadRate2) // tr1 + tr2 is better
1254       return 1; // diagonal 1-3
1255
1256     return 2; // diagonal 2-4
1257   }
1258   return -1;
1259 }
1260
1261 namespace
1262 {
1263   // Methods of splitting volumes into tetra
1264
1265   const int theHexTo5_1[5*4+1] =
1266     {
1267       0, 1, 2, 5,    0, 4, 5, 7,     0, 2, 3, 7,    2, 5, 6, 7,     0, 5, 2, 7,   -1
1268     };
1269   const int theHexTo5_2[5*4+1] =
1270     {
1271       1, 2, 3, 6,    1, 4, 5, 6,     0, 1, 3, 4,    3, 4, 6, 7,     1, 3, 4, 6,   -1
1272     };
1273   const int* theHexTo5[2] = { theHexTo5_1, theHexTo5_2 };
1274
1275   const int theHexTo6_1[6*4+1] =
1276     {
1277       1, 5, 6, 0,    0, 1, 2, 6,     0, 4, 5, 6,    0, 4, 6, 7,     0, 2, 3, 6,   0, 3, 7, 6,  -1
1278     };
1279   const int theHexTo6_2[6*4+1] =
1280     {
1281       2, 6, 7, 1,    1, 2, 3, 7,     1, 5, 6, 7,    1, 5, 7, 4,     1, 3, 0, 7,   1, 0, 4, 7,  -1
1282     };
1283   const int theHexTo6_3[6*4+1] =
1284     {
1285       3, 7, 4, 2,    2, 3, 0, 4,     2, 6, 7, 4,    2, 6, 4, 5,     2, 0, 1, 4,   2, 1, 5, 4,  -1
1286     };
1287   const int theHexTo6_4[6*4+1] =
1288     {
1289       0, 4, 5, 3,    3, 0, 1, 5,     3, 7, 4, 5,    3, 7, 5, 6,     3, 1, 2, 5,   3, 2, 6, 5,  -1
1290     };
1291   const int* theHexTo6[4] = { theHexTo6_1, theHexTo6_2, theHexTo6_3, theHexTo6_4 };
1292
1293   const int thePyraTo2_1[2*4+1] =
1294     {
1295       0, 1, 2, 4,    0, 2, 3, 4,   -1
1296     };
1297   const int thePyraTo2_2[2*4+1] =
1298     {
1299       1, 2, 3, 4,    1, 3, 0, 4,   -1
1300     };
1301   const int* thePyraTo2[2] = { thePyraTo2_1, thePyraTo2_2 };
1302
1303   const int thePentaTo3_1[3*4+1] =
1304     {
1305       0, 1, 2, 3,    1, 3, 4, 2,     2, 3, 4, 5,    -1
1306     };
1307   const int thePentaTo3_2[3*4+1] =
1308     {
1309       1, 2, 0, 4,    2, 4, 5, 0,     0, 4, 5, 3,    -1
1310     };
1311   const int thePentaTo3_3[3*4+1] =
1312     {
1313       2, 0, 1, 5,    0, 5, 3, 1,     1, 5, 3, 4,    -1
1314     };
1315   const int thePentaTo3_4[3*4+1] =
1316     {
1317       0, 1, 2, 3,    1, 3, 4, 5,     2, 3, 1, 5,    -1
1318     };
1319   const int thePentaTo3_5[3*4+1] =
1320     {
1321       1, 2, 0, 4,    2, 4, 5, 3,     0, 4, 2, 3,    -1
1322     };
1323   const int thePentaTo3_6[3*4+1] =
1324     {
1325       2, 0, 1, 5,    0, 5, 3, 4,     1, 5, 0, 4,    -1
1326     };
1327   const int* thePentaTo3[6] = { thePentaTo3_1, thePentaTo3_2, thePentaTo3_3,
1328                                 thePentaTo3_4, thePentaTo3_5, thePentaTo3_6 };
1329
1330   struct TTriangleFacet //!< stores indices of three nodes of tetra facet
1331   {
1332     int _n1, _n2, _n3;
1333     TTriangleFacet(int n1, int n2, int n3): _n1(n1), _n2(n2), _n3(n3) {}
1334     bool contains(int n) const { return ( n == _n1 || n == _n2 || n == _n3 ); }
1335     bool hasAdjacentTetra( const SMDS_MeshElement* elem ) const;
1336   };
1337   struct TSplitMethod
1338   {
1339     int        _nbTetra;
1340     const int* _connectivity; //!< foursomes of tetra connectivy finished by -1
1341     bool       _baryNode;     //!< additional node is to be created at cell barycenter
1342     bool       _ownConn;      //!< to delete _connectivity in destructor
1343     map<int, const SMDS_MeshNode*> _faceBaryNode; //!< map face index to node at BC of face
1344
1345     TSplitMethod( int nbTet=0, const int* conn=0, bool addNode=false)
1346       : _nbTetra(nbTet), _connectivity(conn), _baryNode(addNode), _ownConn(false) {}
1347     ~TSplitMethod() { if ( _ownConn ) delete [] _connectivity; _connectivity = 0; }
1348     bool hasFacet( const TTriangleFacet& facet ) const
1349     {
1350       const int* tetConn = _connectivity;
1351       for ( ; tetConn[0] >= 0; tetConn += 4 )
1352         if (( facet.contains( tetConn[0] ) +
1353               facet.contains( tetConn[1] ) +
1354               facet.contains( tetConn[2] ) +
1355               facet.contains( tetConn[3] )) == 3 )
1356           return true;
1357       return false;
1358     }
1359   };
1360
1361   //=======================================================================
1362   /*!
1363    * \brief return TSplitMethod for the given element
1364    */
1365   //=======================================================================
1366
1367   TSplitMethod getSplitMethod( SMDS_VolumeTool& vol, const int theMethodFlags)
1368   {
1369     const int iQ = vol.Element()->IsQuadratic() ? 2 : 1;
1370
1371     // at HEXA_TO_24 method, each face of volume is split into triangles each based on
1372     // an edge and a face barycenter; tertaherdons are based on triangles and
1373     // a volume barycenter
1374     const bool is24TetMode = ( theMethodFlags == SMESH_MeshEditor::HEXA_TO_24 );
1375
1376     // Find out how adjacent volumes are split
1377
1378     vector < list< TTriangleFacet > > triaSplitsByFace( vol.NbFaces() ); // splits of each side
1379     int hasAdjacentSplits = 0, maxTetConnSize = 0;
1380     for ( int iF = 0; iF < vol.NbFaces(); ++iF )
1381     {
1382       int nbNodes = vol.NbFaceNodes( iF ) / iQ;
1383       maxTetConnSize += 4 * ( nbNodes - (is24TetMode ? 0 : 2));
1384       if ( nbNodes < 4 ) continue;
1385
1386       list< TTriangleFacet >& triaSplits = triaSplitsByFace[ iF ];
1387       const int* nInd = vol.GetFaceNodesIndices( iF );
1388       if ( nbNodes == 4 )
1389       {
1390         TTriangleFacet t012( nInd[0*iQ], nInd[1*iQ], nInd[2*iQ] );
1391         TTriangleFacet t123( nInd[1*iQ], nInd[2*iQ], nInd[3*iQ] );
1392         if      ( t012.hasAdjacentTetra( vol.Element() )) triaSplits.push_back( t012 );
1393         else if ( t123.hasAdjacentTetra( vol.Element() )) triaSplits.push_back( t123 );
1394       }
1395       else
1396       {
1397         int iCom = 0; // common node of triangle faces to split into
1398         for ( int iVar = 0; iVar < nbNodes; ++iVar, ++iCom )
1399         {
1400           TTriangleFacet t012( nInd[ iQ * ( iCom             )],
1401                                nInd[ iQ * ( (iCom+1)%nbNodes )],
1402                                nInd[ iQ * ( (iCom+2)%nbNodes )]);
1403           TTriangleFacet t023( nInd[ iQ * ( iCom             )],
1404                                nInd[ iQ * ( (iCom+2)%nbNodes )],
1405                                nInd[ iQ * ( (iCom+3)%nbNodes )]);
1406           if ( t012.hasAdjacentTetra( vol.Element() ) && t023.hasAdjacentTetra( vol.Element() ))
1407           {
1408             triaSplits.push_back( t012 );
1409             triaSplits.push_back( t023 );
1410             break;
1411           }
1412         }
1413       }
1414       if ( !triaSplits.empty() )
1415         hasAdjacentSplits = true;
1416     }
1417
1418     // Among variants of split method select one compliant with adjacent volumes
1419
1420     TSplitMethod method;
1421     if ( !vol.Element()->IsPoly() && !is24TetMode )
1422     {
1423       int nbVariants = 2, nbTet = 0;
1424       const int** connVariants = 0;
1425       switch ( vol.Element()->GetEntityType() )
1426       {
1427       case SMDSEntity_Hexa:
1428       case SMDSEntity_Quad_Hexa:
1429       case SMDSEntity_TriQuad_Hexa:
1430         if ( theMethodFlags == SMESH_MeshEditor::HEXA_TO_5 )
1431           connVariants = theHexTo5, nbTet = 5;
1432         else
1433           connVariants = theHexTo6, nbTet = 6, nbVariants = 4;
1434         break;
1435       case SMDSEntity_Pyramid:
1436       case SMDSEntity_Quad_Pyramid:
1437         connVariants = thePyraTo2;  nbTet = 2;
1438         break;
1439       case SMDSEntity_Penta:
1440       case SMDSEntity_Quad_Penta:
1441         connVariants = thePentaTo3; nbTet = 3; nbVariants = 6;
1442         break;
1443       default:
1444         nbVariants = 0;
1445       }
1446       for ( int variant = 0; variant < nbVariants && method._nbTetra == 0; ++variant )
1447       {
1448         // check method compliancy with adjacent tetras,
1449         // all found splits must be among facets of tetras described by this method
1450         method = TSplitMethod( nbTet, connVariants[variant] );
1451         if ( hasAdjacentSplits && method._nbTetra > 0 )
1452         {
1453           bool facetCreated = true;
1454           for ( int iF = 0; facetCreated && iF < triaSplitsByFace.size(); ++iF )
1455           {
1456             list< TTriangleFacet >::const_iterator facet = triaSplitsByFace[iF].begin();
1457             for ( ; facetCreated && facet != triaSplitsByFace[iF].end(); ++facet )
1458               facetCreated = method.hasFacet( *facet );
1459           }
1460           if ( !facetCreated )
1461             method = TSplitMethod(0); // incompatible method
1462         }
1463       }
1464     }
1465     if ( method._nbTetra < 1 )
1466     {
1467       // No standard method is applicable, use a generic solution:
1468       // each facet of a volume is split into triangles and
1469       // each of triangles and a volume barycenter form a tetrahedron.
1470
1471       const bool isHex27 = ( vol.Element()->GetEntityType() == SMDSEntity_TriQuad_Hexa );
1472
1473       int* connectivity = new int[ maxTetConnSize + 1 ];
1474       method._connectivity = connectivity;
1475       method._ownConn = true;
1476       method._baryNode = !isHex27; // to create central node or not
1477
1478       int connSize = 0;
1479       int baryCenInd = vol.NbNodes() - int( isHex27 );
1480       for ( int iF = 0; iF < vol.NbFaces(); ++iF )
1481       {
1482         const int nbNodes = vol.NbFaceNodes( iF ) / iQ;
1483         const int*   nInd = vol.GetFaceNodesIndices( iF );
1484         // find common node of triangle facets of tetra to create
1485         int iCommon = 0; // index in linear numeration
1486         const list< TTriangleFacet >& triaSplits = triaSplitsByFace[ iF ];
1487         if ( !triaSplits.empty() )
1488         {
1489           // by found facets
1490           const TTriangleFacet* facet = &triaSplits.front();
1491           for ( ; iCommon < nbNodes-1 ; ++iCommon )
1492             if ( facet->contains( nInd[ iQ * iCommon ]) &&
1493                  facet->contains( nInd[ iQ * ((iCommon+2)%nbNodes) ]))
1494               break;
1495         }
1496         else if ( nbNodes > 3 && !is24TetMode )
1497         {
1498           // find the best method of splitting into triangles by aspect ratio
1499           SMESH::Controls::NumericalFunctorPtr aspectRatio( new SMESH::Controls::AspectRatio);
1500           map< double, int > badness2iCommon;
1501           const SMDS_MeshNode** nodes = vol.GetFaceNodes( iF );
1502           int nbVariants = ( nbNodes == 4 ? 2 : nbNodes );
1503           for ( int iVar = 0; iVar < nbVariants; ++iVar, ++iCommon )
1504           {
1505             double badness = 0;
1506             for ( int iLast = iCommon+2; iLast < iCommon+nbNodes; ++iLast )
1507             {
1508               SMDS_FaceOfNodes tria ( nodes[ iQ*( iCommon         )],
1509                                       nodes[ iQ*((iLast-1)%nbNodes)],
1510                                       nodes[ iQ*((iLast  )%nbNodes)]);
1511               badness += getBadRate( &tria, aspectRatio );
1512             }
1513             badness2iCommon.insert( make_pair( badness, iCommon ));
1514           }
1515           // use iCommon with lowest badness
1516           iCommon = badness2iCommon.begin()->second;
1517         }
1518         if ( iCommon >= nbNodes )
1519           iCommon = 0; // something wrong
1520
1521         // fill connectivity of tetrahedra based on a current face
1522         int nbTet = nbNodes - 2;
1523         if ( is24TetMode && nbNodes > 3 && triaSplits.empty())
1524         {
1525           int faceBaryCenInd;
1526           if ( isHex27 )
1527           {
1528             faceBaryCenInd = vol.GetCenterNodeIndex( iF );
1529             method._faceBaryNode[ iF ] = vol.GetNodes()[ faceBaryCenInd ];
1530           }
1531           else
1532           {
1533             method._faceBaryNode[ iF ] = 0;
1534             faceBaryCenInd = baryCenInd + method._faceBaryNode.size();
1535           }
1536           nbTet = nbNodes;
1537           for ( int i = 0; i < nbTet; ++i )
1538           {
1539             int i1 = i, i2 = (i+1) % nbNodes;
1540             if ( !vol.IsFaceExternal( iF )) swap( i1, i2 );
1541             connectivity[ connSize++ ] = nInd[ iQ * i1 ];
1542             connectivity[ connSize++ ] = nInd[ iQ * i2 ];
1543             connectivity[ connSize++ ] = faceBaryCenInd;
1544             connectivity[ connSize++ ] = baryCenInd;
1545           }
1546         }
1547         else
1548         {
1549           for ( int i = 0; i < nbTet; ++i )
1550           {
1551             int i1 = (iCommon+1+i) % nbNodes, i2 = (iCommon+2+i) % nbNodes;
1552             if ( !vol.IsFaceExternal( iF )) swap( i1, i2 );
1553             connectivity[ connSize++ ] = nInd[ iQ * iCommon ];
1554             connectivity[ connSize++ ] = nInd[ iQ * i1 ];
1555             connectivity[ connSize++ ] = nInd[ iQ * i2 ];
1556             connectivity[ connSize++ ] = baryCenInd;
1557           }
1558         }
1559         method._nbTetra += nbTet;
1560
1561       } // loop on volume faces
1562
1563       connectivity[ connSize++ ] = -1;
1564
1565     } // end of generic solution
1566
1567     return method;
1568   }
1569   //================================================================================
1570   /*!
1571    * \brief Check if there is a tetraherdon adjacent to the given element via this facet
1572    */
1573   //================================================================================
1574
1575   bool TTriangleFacet::hasAdjacentTetra( const SMDS_MeshElement* elem ) const
1576   {
1577     // find the tetrahedron including the three nodes of facet
1578     const SMDS_MeshNode* n1 = elem->GetNode(_n1);
1579     const SMDS_MeshNode* n2 = elem->GetNode(_n2);
1580     const SMDS_MeshNode* n3 = elem->GetNode(_n3);
1581     SMDS_ElemIteratorPtr volIt1 = n1->GetInverseElementIterator(SMDSAbs_Volume);
1582     while ( volIt1->more() )
1583     {
1584       const SMDS_MeshElement* v = volIt1->next();
1585       SMDSAbs_EntityType type = v->GetEntityType();
1586       if ( type != SMDSEntity_Tetra && type != SMDSEntity_Quad_Tetra )
1587         continue;
1588       if ( type == SMDSEntity_Quad_Tetra && v->GetNodeIndex( n1 ) > 3 )
1589         continue; // medium node not allowed
1590       const int ind2 = v->GetNodeIndex( n2 );
1591       if ( ind2 < 0 || 3 < ind2 )
1592         continue;
1593       const int ind3 = v->GetNodeIndex( n3 );
1594       if ( ind3 < 0 || 3 < ind3 )
1595         continue;
1596       return true;
1597     }
1598     return false;
1599   }
1600
1601   //=======================================================================
1602   /*!
1603    * \brief A key of a face of volume
1604    */
1605   //=======================================================================
1606
1607   struct TVolumeFaceKey: pair< pair< int, int>, pair< int, int> >
1608   {
1609     TVolumeFaceKey( SMDS_VolumeTool& vol, int iF )
1610     {
1611       TIDSortedNodeSet sortedNodes;
1612       const int iQ = vol.Element()->IsQuadratic() ? 2 : 1;
1613       int nbNodes = vol.NbFaceNodes( iF );
1614       const SMDS_MeshNode** fNodes = vol.GetFaceNodes( iF );
1615       for ( int i = 0; i < nbNodes; i += iQ )
1616         sortedNodes.insert( fNodes[i] );
1617       TIDSortedNodeSet::iterator n = sortedNodes.begin();
1618       first.first   = (*(n++))->GetID();
1619       first.second  = (*(n++))->GetID();
1620       second.first  = (*(n++))->GetID();
1621       second.second = ( sortedNodes.size() > 3 ) ? (*(n++))->GetID() : 0;
1622     }
1623   };
1624 } // namespace
1625
1626 //=======================================================================
1627 //function : SplitVolumesIntoTetra
1628 //purpose  : Split volume elements into tetrahedra.
1629 //=======================================================================
1630
1631 void SMESH_MeshEditor::SplitVolumesIntoTetra (const TIDSortedElemSet & theElems,
1632                                               const int                theMethodFlags)
1633 {
1634   // std-like iterator on coordinates of nodes of mesh element
1635   typedef SMDS_StdIterator< SMESH_TNodeXYZ, SMDS_ElemIteratorPtr > NXyzIterator;
1636   NXyzIterator xyzEnd;
1637
1638   SMDS_VolumeTool    volTool;
1639   SMESH_MesherHelper helper( *GetMesh());
1640
1641   SMESHDS_SubMesh* subMesh = 0;//GetMeshDS()->MeshElements(1);
1642   SMESHDS_SubMesh* fSubMesh = 0;//subMesh;
1643   
1644   SMESH_SequenceOfElemPtr newNodes, newElems;
1645
1646   // map face of volume to it's baricenrtic node
1647   map< TVolumeFaceKey, const SMDS_MeshNode* > volFace2BaryNode;
1648   double bc[3];
1649
1650   TIDSortedElemSet::const_iterator elem = theElems.begin();
1651   for ( ; elem != theElems.end(); ++elem )
1652   {
1653     if ( (*elem)->GetType() != SMDSAbs_Volume )
1654       continue;
1655     SMDSAbs_EntityType geomType = (*elem)->GetEntityType();
1656     if ( geomType == SMDSEntity_Tetra || geomType == SMDSEntity_Quad_Tetra )
1657       continue;
1658
1659     if ( !volTool.Set( *elem, /*ignoreCentralNodes=*/false )) continue; // strange...
1660
1661     TSplitMethod splitMethod = getSplitMethod( volTool, theMethodFlags );
1662     if ( splitMethod._nbTetra < 1 ) continue;
1663
1664     // find submesh to add new tetras to
1665     if ( !subMesh || !subMesh->Contains( *elem ))
1666     {
1667       int shapeID = FindShape( *elem );
1668       helper.SetSubShape( shapeID ); // helper will add tetras to the found submesh
1669       subMesh = GetMeshDS()->MeshElements( shapeID );
1670     }
1671     int iQ;
1672     if ( (*elem)->IsQuadratic() )
1673     {
1674       iQ = 2;
1675       // add quadratic links to the helper
1676       for ( int iF = 0; iF < volTool.NbFaces(); ++iF )
1677       {
1678         const SMDS_MeshNode** fNodes = volTool.GetFaceNodes( iF );
1679         int nbN = volTool.NbFaceNodes( iF ) - bool( volTool.GetCenterNodeIndex(iF) > 0 );
1680         for ( int iN = 0; iN < nbN; iN += iQ )
1681           helper.AddTLinkNode( fNodes[iN], fNodes[iN+2], fNodes[iN+1] );
1682       }
1683       helper.SetIsQuadratic( true );
1684     }
1685     else
1686     {
1687       iQ = 1;
1688       helper.SetIsQuadratic( false );
1689     }
1690     vector<const SMDS_MeshNode*> nodes( (*elem)->begin_nodes(), (*elem)->end_nodes() );
1691     helper.SetElementsOnShape( true );
1692     if ( splitMethod._baryNode )
1693     {
1694       // make a node at barycenter
1695       volTool.GetBaryCenter( bc[0], bc[1], bc[2] );
1696       SMDS_MeshNode* gcNode = helper.AddNode( bc[0], bc[1], bc[2] );
1697       nodes.push_back( gcNode );
1698       newNodes.Append( gcNode );
1699     }
1700     if ( !splitMethod._faceBaryNode.empty() )
1701     {
1702       // make or find baricentric nodes of faces
1703       map<int, const SMDS_MeshNode*>::iterator iF_n = splitMethod._faceBaryNode.begin();
1704       for ( ; iF_n != splitMethod._faceBaryNode.end(); ++iF_n )
1705       {
1706         map< TVolumeFaceKey, const SMDS_MeshNode* >::iterator f_n =
1707           volFace2BaryNode.insert
1708           ( make_pair( TVolumeFaceKey( volTool,iF_n->first ), iF_n->second )).first;
1709         if ( !f_n->second )
1710         {
1711           volTool.GetFaceBaryCenter( iF_n->first, bc[0], bc[1], bc[2] );
1712           newNodes.Append( f_n->second = helper.AddNode( bc[0], bc[1], bc[2] ));
1713         }
1714         nodes.push_back( iF_n->second = f_n->second );
1715       }
1716     }
1717
1718     // make tetras
1719     vector<const SMDS_MeshElement* > tetras( splitMethod._nbTetra ); // splits of a volume
1720     const int* tetConn = splitMethod._connectivity;
1721     for ( int i = 0; i < splitMethod._nbTetra; ++i, tetConn += 4 )
1722       newElems.Append( tetras[ i ] = helper.AddVolume( nodes[ tetConn[0] ],
1723                                                        nodes[ tetConn[1] ],
1724                                                        nodes[ tetConn[2] ],
1725                                                        nodes[ tetConn[3] ]));
1726
1727     ReplaceElemInGroups( *elem, tetras, GetMeshDS() );
1728
1729     // Split faces on sides of the split volume
1730
1731     const SMDS_MeshNode** volNodes = volTool.GetNodes();
1732     for ( int iF = 0; iF < volTool.NbFaces(); ++iF )
1733     {
1734       const int nbNodes = volTool.NbFaceNodes( iF ) / iQ;
1735       if ( nbNodes < 4 ) continue;
1736
1737       // find an existing face
1738       vector<const SMDS_MeshNode*> fNodes( volTool.GetFaceNodes( iF ),
1739                                            volTool.GetFaceNodes( iF ) + volTool.NbFaceNodes( iF ));
1740       while ( const SMDS_MeshElement* face = GetMeshDS()->FindElement( fNodes, SMDSAbs_Face,
1741                                                                        /*noMedium=*/false))
1742       {
1743         // make triangles
1744         helper.SetElementsOnShape( false );
1745         vector< const SMDS_MeshElement* > triangles;
1746
1747         // find submesh to add new triangles in
1748         if ( !fSubMesh || !fSubMesh->Contains( face ))
1749         {
1750           int shapeID = FindShape( face );
1751           fSubMesh = GetMeshDS()->MeshElements( shapeID );
1752         }
1753         map<int, const SMDS_MeshNode*>::iterator iF_n = splitMethod._faceBaryNode.find(iF);
1754         if ( iF_n != splitMethod._faceBaryNode.end() )
1755         {
1756           for ( int iN = 0; iN < nbNodes*iQ; iN += iQ )
1757           {
1758             const SMDS_MeshNode* n1 = fNodes[iN];
1759             const SMDS_MeshNode *n2 = fNodes[(iN+iQ)%(nbNodes*iQ)];
1760             const SMDS_MeshNode *n3 = iF_n->second;
1761             if ( !volTool.IsFaceExternal( iF ))
1762               swap( n2, n3 );
1763             triangles.push_back( helper.AddFace( n1,n2,n3 ));
1764
1765             if ( fSubMesh && n3->getshapeId() < 1 )
1766               fSubMesh->AddNode( n3 );
1767           }
1768         }
1769         else
1770         {
1771           // among possible triangles create ones discribed by split method
1772           const int* nInd = volTool.GetFaceNodesIndices( iF );
1773           int nbVariants = ( nbNodes == 4 ? 2 : nbNodes );
1774           int iCom = 0; // common node of triangle faces to split into
1775           list< TTriangleFacet > facets;
1776           for ( int iVar = 0; iVar < nbVariants; ++iVar, ++iCom )
1777           {
1778             TTriangleFacet t012( nInd[ iQ * ( iCom                )],
1779                                  nInd[ iQ * ( (iCom+1)%nbNodes )],
1780                                  nInd[ iQ * ( (iCom+2)%nbNodes )]);
1781             TTriangleFacet t023( nInd[ iQ * ( iCom                )],
1782                                  nInd[ iQ * ( (iCom+2)%nbNodes )],
1783                                  nInd[ iQ * ( (iCom+3)%nbNodes )]);
1784             if ( splitMethod.hasFacet( t012 ) && splitMethod.hasFacet( t023 ))
1785             {
1786               facets.push_back( t012 );
1787               facets.push_back( t023 );
1788               for ( int iLast = iCom+4; iLast < iCom+nbNodes; ++iLast )
1789                 facets.push_back( TTriangleFacet( nInd[ iQ * ( iCom             )],
1790                                                   nInd[ iQ * ((iLast-1)%nbNodes )],
1791                                                   nInd[ iQ * ((iLast  )%nbNodes )]));
1792               break;
1793             }
1794           }
1795           list< TTriangleFacet >::iterator facet = facets.begin();
1796           for ( ; facet != facets.end(); ++facet )
1797           {
1798             if ( !volTool.IsFaceExternal( iF ))
1799               swap( facet->_n2, facet->_n3 );
1800             triangles.push_back( helper.AddFace( volNodes[ facet->_n1 ],
1801                                                  volNodes[ facet->_n2 ],
1802                                                  volNodes[ facet->_n3 ]));
1803           }
1804         }
1805         for ( int i = 0; i < triangles.size(); ++i )
1806         {
1807           if ( !triangles[i] ) continue;
1808           if ( fSubMesh )
1809             fSubMesh->AddElement( triangles[i]);
1810           newElems.Append( triangles[i] );
1811         }
1812         ReplaceElemInGroups( face, triangles, GetMeshDS() );
1813         GetMeshDS()->RemoveFreeElement( face, fSubMesh, /*fromGroups=*/false );
1814       }
1815
1816     } // loop on volume faces to split them into triangles
1817
1818     GetMeshDS()->RemoveFreeElement( *elem, subMesh, /*fromGroups=*/false );
1819
1820     if ( geomType == SMDSEntity_TriQuad_Hexa )
1821     {
1822       // remove medium nodes that could become free
1823       for ( int i = 20; i < volTool.NbNodes(); ++i )
1824         if ( volNodes[i]->NbInverseElements() == 0 )
1825           GetMeshDS()->RemoveNode( volNodes[i] );
1826     }
1827   } // loop on volumes to split
1828
1829   myLastCreatedNodes = newNodes;
1830   myLastCreatedElems = newElems;
1831 }
1832
1833 //=======================================================================
1834 //function : AddToSameGroups
1835 //purpose  : add elemToAdd to the groups the elemInGroups belongs to
1836 //=======================================================================
1837
1838 void SMESH_MeshEditor::AddToSameGroups (const SMDS_MeshElement* elemToAdd,
1839                                         const SMDS_MeshElement* elemInGroups,
1840                                         SMESHDS_Mesh *          aMesh)
1841 {
1842   const set<SMESHDS_GroupBase*>& groups = aMesh->GetGroups();
1843   if (!groups.empty()) {
1844     set<SMESHDS_GroupBase*>::const_iterator grIt = groups.begin();
1845     for ( ; grIt != groups.end(); grIt++ ) {
1846       SMESHDS_Group* group = dynamic_cast<SMESHDS_Group*>( *grIt );
1847       if ( group && group->Contains( elemInGroups ))
1848         group->SMDSGroup().Add( elemToAdd );
1849     }
1850   }
1851 }
1852
1853
1854 //=======================================================================
1855 //function : RemoveElemFromGroups
1856 //purpose  : Remove removeelem to the groups the elemInGroups belongs to
1857 //=======================================================================
1858 void SMESH_MeshEditor::RemoveElemFromGroups (const SMDS_MeshElement* removeelem,
1859                                              SMESHDS_Mesh *          aMesh)
1860 {
1861   const set<SMESHDS_GroupBase*>& groups = aMesh->GetGroups();
1862   if (!groups.empty())
1863   {
1864     set<SMESHDS_GroupBase*>::const_iterator GrIt = groups.begin();
1865     for (; GrIt != groups.end(); GrIt++)
1866     {
1867       SMESHDS_Group* grp = dynamic_cast<SMESHDS_Group*>(*GrIt);
1868       if (!grp || grp->IsEmpty()) continue;
1869       grp->SMDSGroup().Remove(removeelem);
1870     }
1871   }
1872 }
1873
1874 //================================================================================
1875 /*!
1876  * \brief Replace elemToRm by elemToAdd in the all groups
1877  */
1878 //================================================================================
1879
1880 void SMESH_MeshEditor::ReplaceElemInGroups (const SMDS_MeshElement* elemToRm,
1881                                             const SMDS_MeshElement* elemToAdd,
1882                                             SMESHDS_Mesh *          aMesh)
1883 {
1884   const set<SMESHDS_GroupBase*>& groups = aMesh->GetGroups();
1885   if (!groups.empty()) {
1886     set<SMESHDS_GroupBase*>::const_iterator grIt = groups.begin();
1887     for ( ; grIt != groups.end(); grIt++ ) {
1888       SMESHDS_Group* group = dynamic_cast<SMESHDS_Group*>( *grIt );
1889       if ( group && group->SMDSGroup().Remove( elemToRm ) && elemToAdd )
1890         group->SMDSGroup().Add( elemToAdd );
1891     }
1892   }
1893 }
1894
1895 //================================================================================
1896 /*!
1897  * \brief Replace elemToRm by elemToAdd in the all groups
1898  */
1899 //================================================================================
1900
1901 void SMESH_MeshEditor::ReplaceElemInGroups (const SMDS_MeshElement*                elemToRm,
1902                                             const vector<const SMDS_MeshElement*>& elemToAdd,
1903                                             SMESHDS_Mesh *                         aMesh)
1904 {
1905   const set<SMESHDS_GroupBase*>& groups = aMesh->GetGroups();
1906   if (!groups.empty())
1907   {
1908     set<SMESHDS_GroupBase*>::const_iterator grIt = groups.begin();
1909     for ( ; grIt != groups.end(); grIt++ ) {
1910       SMESHDS_Group* group = dynamic_cast<SMESHDS_Group*>( *grIt );
1911       if ( group && group->SMDSGroup().Remove( elemToRm ) )
1912         for ( int i = 0; i < elemToAdd.size(); ++i )
1913           group->SMDSGroup().Add( elemToAdd[ i ] );
1914     }
1915   }
1916 }
1917
1918 //=======================================================================
1919 //function : QuadToTri
1920 //purpose  : Cut quadrangles into triangles.
1921 //           theCrit is used to select a diagonal to cut
1922 //=======================================================================
1923
1924 bool SMESH_MeshEditor::QuadToTri (TIDSortedElemSet & theElems,
1925                                   const bool         the13Diag)
1926 {
1927   myLastCreatedElems.Clear();
1928   myLastCreatedNodes.Clear();
1929
1930   MESSAGE( "::QuadToTri()" );
1931
1932   SMESHDS_Mesh * aMesh = GetMeshDS();
1933
1934   Handle(Geom_Surface) surface;
1935   SMESH_MesherHelper   helper( *GetMesh() );
1936
1937   TIDSortedElemSet::iterator itElem;
1938   for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
1939     const SMDS_MeshElement* elem = *itElem;
1940     if ( !elem || elem->GetType() != SMDSAbs_Face )
1941       continue;
1942     bool isquad = elem->NbNodes()==4 || elem->NbNodes()==8;
1943     if(!isquad) continue;
1944
1945     if(elem->NbNodes()==4) {
1946       // retrieve element nodes
1947       const SMDS_MeshNode* aNodes [4];
1948       SMDS_ElemIteratorPtr itN = elem->nodesIterator();
1949       int i = 0;
1950       while ( itN->more() )
1951         aNodes[ i++ ] = static_cast<const SMDS_MeshNode*>( itN->next() );
1952
1953       int aShapeId = FindShape( elem );
1954       const SMDS_MeshElement* newElem1 = 0;
1955       const SMDS_MeshElement* newElem2 = 0;
1956       if ( the13Diag ) {
1957         newElem1 = aMesh->AddFace( aNodes[2], aNodes[0], aNodes[1] );
1958         newElem2 = aMesh->AddFace( aNodes[2], aNodes[3], aNodes[0] );
1959       }
1960       else {
1961         newElem1 = aMesh->AddFace( aNodes[3], aNodes[0], aNodes[1] );
1962         newElem2 = aMesh->AddFace( aNodes[3], aNodes[1], aNodes[2] );
1963       }
1964       myLastCreatedElems.Append(newElem1);
1965       myLastCreatedElems.Append(newElem2);
1966       // put a new triangle on the same shape and add to the same groups
1967       if ( aShapeId )
1968         {
1969           aMesh->SetMeshElementOnShape( newElem1, aShapeId );
1970           aMesh->SetMeshElementOnShape( newElem2, aShapeId );
1971         }
1972       AddToSameGroups( newElem1, elem, aMesh );
1973       AddToSameGroups( newElem2, elem, aMesh );
1974       //aMesh->RemoveFreeElement(elem, aMesh->MeshElements(aShapeId), true);
1975       aMesh->RemoveElement( elem );
1976     }
1977
1978     // Quadratic quadrangle
1979
1980     if( elem->NbNodes()==8 && elem->IsQuadratic() ) {
1981
1982       // get surface elem is on
1983       int aShapeId = FindShape( elem );
1984       if ( aShapeId != helper.GetSubShapeID() ) {
1985         surface.Nullify();
1986         TopoDS_Shape shape;
1987         if ( aShapeId > 0 )
1988           shape = aMesh->IndexToShape( aShapeId );
1989         if ( !shape.IsNull() && shape.ShapeType() == TopAbs_FACE ) {
1990           TopoDS_Face face = TopoDS::Face( shape );
1991           surface = BRep_Tool::Surface( face );
1992           if ( !surface.IsNull() )
1993             helper.SetSubShape( shape );
1994         }
1995       }
1996
1997       const SMDS_MeshNode* aNodes [8];
1998       const SMDS_MeshNode* inFaceNode = 0;
1999       SMDS_ElemIteratorPtr itN = elem->nodesIterator();
2000       int i = 0;
2001       while ( itN->more() ) {
2002         aNodes[ i++ ] = static_cast<const SMDS_MeshNode*>( itN->next() );
2003         if ( !inFaceNode && helper.GetNodeUVneedInFaceNode() &&
2004              aNodes[ i-1 ]->GetPosition()->GetTypeOfPosition() == SMDS_TOP_FACE )
2005         {
2006           inFaceNode = aNodes[ i-1 ];
2007         }
2008       }
2009
2010       // find middle point for (0,1,2,3)
2011       // and create a node in this point;
2012       gp_XYZ p( 0,0,0 );
2013       if ( surface.IsNull() ) {
2014         for(i=0; i<4; i++)
2015           p += gp_XYZ(aNodes[i]->X(), aNodes[i]->Y(), aNodes[i]->Z() );
2016         p /= 4;
2017       }
2018       else {
2019         TopoDS_Face geomFace = TopoDS::Face( helper.GetSubShape() );
2020         gp_XY uv( 0,0 );
2021         for(i=0; i<4; i++)
2022           uv += helper.GetNodeUV( geomFace, aNodes[i], inFaceNode );
2023         uv /= 4.;
2024         p = surface->Value( uv.X(), uv.Y() ).XYZ();
2025       }
2026       const SMDS_MeshNode* newN = aMesh->AddNode( p.X(), p.Y(), p.Z() );
2027       myLastCreatedNodes.Append(newN);
2028
2029       // create a new element
2030       const SMDS_MeshElement* newElem1 = 0;
2031       const SMDS_MeshElement* newElem2 = 0;
2032       if ( the13Diag ) {
2033         newElem1 = aMesh->AddFace(aNodes[2], aNodes[3], aNodes[0],
2034                                   aNodes[6], aNodes[7], newN );
2035         newElem2 = aMesh->AddFace(aNodes[2], aNodes[0], aNodes[1],
2036                                   newN,      aNodes[4], aNodes[5] );
2037       }
2038       else {
2039         newElem1 = aMesh->AddFace(aNodes[3], aNodes[0], aNodes[1],
2040                                   aNodes[7], aNodes[4], newN );
2041         newElem2 = aMesh->AddFace(aNodes[3], aNodes[1], aNodes[2],
2042                                   newN,      aNodes[5], aNodes[6] );
2043       }
2044       myLastCreatedElems.Append(newElem1);
2045       myLastCreatedElems.Append(newElem2);
2046       // put a new triangle on the same shape and add to the same groups
2047       if ( aShapeId )
2048         {
2049           aMesh->SetMeshElementOnShape( newElem1, aShapeId );
2050           aMesh->SetMeshElementOnShape( newElem2, aShapeId );
2051         }
2052       AddToSameGroups( newElem1, elem, aMesh );
2053       AddToSameGroups( newElem2, elem, aMesh );
2054       aMesh->RemoveElement( elem );
2055     }
2056   }
2057
2058   return true;
2059 }
2060
2061 //=======================================================================
2062 //function : getAngle
2063 //purpose  :
2064 //=======================================================================
2065
2066 double getAngle(const SMDS_MeshElement * tr1,
2067                 const SMDS_MeshElement * tr2,
2068                 const SMDS_MeshNode *    n1,
2069                 const SMDS_MeshNode *    n2)
2070 {
2071   double angle = 2. * M_PI; // bad angle
2072
2073   // get normals
2074   SMESH::Controls::TSequenceOfXYZ P1, P2;
2075   if ( !SMESH::Controls::NumericalFunctor::GetPoints( tr1, P1 ) ||
2076        !SMESH::Controls::NumericalFunctor::GetPoints( tr2, P2 ))
2077     return angle;
2078   gp_Vec N1,N2;
2079   if(!tr1->IsQuadratic())
2080     N1 = gp_Vec( P1(2) - P1(1) ) ^ gp_Vec( P1(3) - P1(1) );
2081   else
2082     N1 = gp_Vec( P1(3) - P1(1) ) ^ gp_Vec( P1(5) - P1(1) );
2083   if ( N1.SquareMagnitude() <= gp::Resolution() )
2084     return angle;
2085   if(!tr2->IsQuadratic())
2086     N2 = gp_Vec( P2(2) - P2(1) ) ^ gp_Vec( P2(3) - P2(1) );
2087   else
2088     N2 = gp_Vec( P2(3) - P2(1) ) ^ gp_Vec( P2(5) - P2(1) );
2089   if ( N2.SquareMagnitude() <= gp::Resolution() )
2090     return angle;
2091
2092   // find the first diagonal node n1 in the triangles:
2093   // take in account a diagonal link orientation
2094   const SMDS_MeshElement *nFirst[2], *tr[] = { tr1, tr2 };
2095   for ( int t = 0; t < 2; t++ ) {
2096     SMDS_ElemIteratorPtr it = tr[ t ]->nodesIterator();
2097     int i = 0, iDiag = -1;
2098     while ( it->more()) {
2099       const SMDS_MeshElement *n = it->next();
2100       if ( n == n1 || n == n2 ) {
2101         if ( iDiag < 0)
2102           iDiag = i;
2103         else {
2104           if ( i - iDiag == 1 )
2105             nFirst[ t ] = ( n == n1 ? n2 : n1 );
2106           else
2107             nFirst[ t ] = n;
2108           break;
2109         }
2110       }
2111       i++;
2112     }
2113   }
2114   if ( nFirst[ 0 ] == nFirst[ 1 ] )
2115     N2.Reverse();
2116
2117   angle = N1.Angle( N2 );
2118   //SCRUTE( angle );
2119   return angle;
2120 }
2121
2122 // =================================================
2123 // class generating a unique ID for a pair of nodes
2124 // and able to return nodes by that ID
2125 // =================================================
2126 class LinkID_Gen {
2127 public:
2128
2129   LinkID_Gen( const SMESHDS_Mesh* theMesh )
2130     :myMesh( theMesh ), myMaxID( theMesh->MaxNodeID() + 1)
2131   {}
2132
2133   long GetLinkID (const SMDS_MeshNode * n1,
2134                   const SMDS_MeshNode * n2) const
2135   {
2136     return ( Min(n1->GetID(),n2->GetID()) * myMaxID + Max(n1->GetID(),n2->GetID()));
2137   }
2138
2139   bool GetNodes (const long             theLinkID,
2140                  const SMDS_MeshNode* & theNode1,
2141                  const SMDS_MeshNode* & theNode2) const
2142   {
2143     theNode1 = myMesh->FindNode( theLinkID / myMaxID );
2144     if ( !theNode1 ) return false;
2145     theNode2 = myMesh->FindNode( theLinkID % myMaxID );
2146     if ( !theNode2 ) return false;
2147     return true;
2148   }
2149
2150 private:
2151   LinkID_Gen();
2152   const SMESHDS_Mesh* myMesh;
2153   long                myMaxID;
2154 };
2155
2156
2157 //=======================================================================
2158 //function : TriToQuad
2159 //purpose  : Fuse neighbour triangles into quadrangles.
2160 //           theCrit is used to select a neighbour to fuse with.
2161 //           theMaxAngle is a max angle between element normals at which
2162 //           fusion is still performed.
2163 //=======================================================================
2164
2165 bool SMESH_MeshEditor::TriToQuad (TIDSortedElemSet &                   theElems,
2166                                   SMESH::Controls::NumericalFunctorPtr theCrit,
2167                                   const double                         theMaxAngle)
2168 {
2169   myLastCreatedElems.Clear();
2170   myLastCreatedNodes.Clear();
2171
2172   MESSAGE( "::TriToQuad()" );
2173
2174   if ( !theCrit.get() )
2175     return false;
2176
2177   SMESHDS_Mesh * aMesh = GetMeshDS();
2178
2179   // Prepare data for algo: build
2180   // 1. map of elements with their linkIDs
2181   // 2. map of linkIDs with their elements
2182
2183   map< SMESH_TLink, list< const SMDS_MeshElement* > > mapLi_listEl;
2184   map< SMESH_TLink, list< const SMDS_MeshElement* > >::iterator itLE;
2185   map< const SMDS_MeshElement*, set< SMESH_TLink > >  mapEl_setLi;
2186   map< const SMDS_MeshElement*, set< SMESH_TLink > >::iterator itEL;
2187
2188   TIDSortedElemSet::iterator itElem;
2189   for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
2190     const SMDS_MeshElement* elem = *itElem;
2191     if(!elem || elem->GetType() != SMDSAbs_Face ) continue;
2192     bool IsTria = elem->NbNodes()==3 || (elem->NbNodes()==6 && elem->IsQuadratic());
2193     if(!IsTria) continue;
2194
2195     // retrieve element nodes
2196     const SMDS_MeshNode* aNodes [4];
2197     SMDS_ElemIteratorPtr itN = elem->nodesIterator();
2198     int i = 0;
2199     while ( i<3 )
2200       aNodes[ i++ ] = cast2Node( itN->next() );
2201     aNodes[ 3 ] = aNodes[ 0 ];
2202
2203     // fill maps
2204     for ( i = 0; i < 3; i++ ) {
2205       SMESH_TLink link( aNodes[i], aNodes[i+1] );
2206       // check if elements sharing a link can be fused
2207       itLE = mapLi_listEl.find( link );
2208       if ( itLE != mapLi_listEl.end() ) {
2209         if ((*itLE).second.size() > 1 ) // consider only 2 elems adjacent by a link
2210           continue;
2211         const SMDS_MeshElement* elem2 = (*itLE).second.front();
2212         //if ( FindShape( elem ) != FindShape( elem2 ))
2213         //  continue; // do not fuse triangles laying on different shapes
2214         if ( getAngle( elem, elem2, aNodes[i], aNodes[i+1] ) > theMaxAngle )
2215           continue; // avoid making badly shaped quads
2216         (*itLE).second.push_back( elem );
2217       }
2218       else {
2219         mapLi_listEl[ link ].push_back( elem );
2220       }
2221       mapEl_setLi [ elem ].insert( link );
2222     }
2223   }
2224   // Clean the maps from the links shared by a sole element, ie
2225   // links to which only one element is bound in mapLi_listEl
2226
2227   for ( itLE = mapLi_listEl.begin(); itLE != mapLi_listEl.end(); itLE++ ) {
2228     int nbElems = (*itLE).second.size();
2229     if ( nbElems < 2  ) {
2230       const SMDS_MeshElement* elem = (*itLE).second.front();
2231       SMESH_TLink link = (*itLE).first;
2232       mapEl_setLi[ elem ].erase( link );
2233       if ( mapEl_setLi[ elem ].empty() )
2234         mapEl_setLi.erase( elem );
2235     }
2236   }
2237
2238   // Algo: fuse triangles into quadrangles
2239
2240   while ( ! mapEl_setLi.empty() ) {
2241     // Look for the start element:
2242     // the element having the least nb of shared links
2243     const SMDS_MeshElement* startElem = 0;
2244     int minNbLinks = 4;
2245     for ( itEL = mapEl_setLi.begin(); itEL != mapEl_setLi.end(); itEL++ ) {
2246       int nbLinks = (*itEL).second.size();
2247       if ( nbLinks < minNbLinks ) {
2248         startElem = (*itEL).first;
2249         minNbLinks = nbLinks;
2250         if ( minNbLinks == 1 )
2251           break;
2252       }
2253     }
2254
2255     // search elements to fuse starting from startElem or links of elements
2256     // fused earlyer - startLinks
2257     list< SMESH_TLink > startLinks;
2258     while ( startElem || !startLinks.empty() ) {
2259       while ( !startElem && !startLinks.empty() ) {
2260         // Get an element to start, by a link
2261         SMESH_TLink linkId = startLinks.front();
2262         startLinks.pop_front();
2263         itLE = mapLi_listEl.find( linkId );
2264         if ( itLE != mapLi_listEl.end() ) {
2265           list< const SMDS_MeshElement* > & listElem = (*itLE).second;
2266           list< const SMDS_MeshElement* >::iterator itE = listElem.begin();
2267           for ( ; itE != listElem.end() ; itE++ )
2268             if ( mapEl_setLi.find( (*itE) ) != mapEl_setLi.end() )
2269               startElem = (*itE);
2270           mapLi_listEl.erase( itLE );
2271         }
2272       }
2273
2274       if ( startElem ) {
2275         // Get candidates to be fused
2276         const SMDS_MeshElement *tr1 = startElem, *tr2 = 0, *tr3 = 0;
2277         const SMESH_TLink *link12, *link13;
2278         startElem = 0;
2279         ASSERT( mapEl_setLi.find( tr1 ) != mapEl_setLi.end() );
2280         set< SMESH_TLink >& setLi = mapEl_setLi[ tr1 ];
2281         ASSERT( !setLi.empty() );
2282         set< SMESH_TLink >::iterator itLi;
2283         for ( itLi = setLi.begin(); itLi != setLi.end(); itLi++ )
2284         {
2285           const SMESH_TLink & link = (*itLi);
2286           itLE = mapLi_listEl.find( link );
2287           if ( itLE == mapLi_listEl.end() )
2288             continue;
2289
2290           const SMDS_MeshElement* elem = (*itLE).second.front();
2291           if ( elem == tr1 )
2292             elem = (*itLE).second.back();
2293           mapLi_listEl.erase( itLE );
2294           if ( mapEl_setLi.find( elem ) == mapEl_setLi.end())
2295             continue;
2296           if ( tr2 ) {
2297             tr3 = elem;
2298             link13 = &link;
2299           }
2300           else {
2301             tr2 = elem;
2302             link12 = &link;
2303           }
2304
2305           // add other links of elem to list of links to re-start from
2306           set< SMESH_TLink >& links = mapEl_setLi[ elem ];
2307           set< SMESH_TLink >::iterator it;
2308           for ( it = links.begin(); it != links.end(); it++ ) {
2309             const SMESH_TLink& link2 = (*it);
2310             if ( link2 != link )
2311               startLinks.push_back( link2 );
2312           }
2313         }
2314
2315         // Get nodes of possible quadrangles
2316         const SMDS_MeshNode *n12 [4], *n13 [4];
2317         bool Ok12 = false, Ok13 = false;
2318         const SMDS_MeshNode *linkNode1, *linkNode2;
2319         if(tr2) {
2320           linkNode1 = link12->first;
2321           linkNode2 = link12->second;
2322           if ( tr2 && getQuadrangleNodes( n12, linkNode1, linkNode2, tr1, tr2 ))
2323             Ok12 = true;
2324         }
2325         if(tr3) {
2326           linkNode1 = link13->first;
2327           linkNode2 = link13->second;
2328           if ( tr3 && getQuadrangleNodes( n13, linkNode1, linkNode2, tr1, tr3 ))
2329             Ok13 = true;
2330         }
2331
2332         // Choose a pair to fuse
2333         if ( Ok12 && Ok13 ) {
2334           SMDS_FaceOfNodes quad12 ( n12[ 0 ], n12[ 1 ], n12[ 2 ], n12[ 3 ] );
2335           SMDS_FaceOfNodes quad13 ( n13[ 0 ], n13[ 1 ], n13[ 2 ], n13[ 3 ] );
2336           double aBadRate12 = getBadRate( &quad12, theCrit );
2337           double aBadRate13 = getBadRate( &quad13, theCrit );
2338           if (  aBadRate13 < aBadRate12 )
2339             Ok12 = false;
2340           else
2341             Ok13 = false;
2342         }
2343
2344         // Make quadrangles
2345         // and remove fused elems and removed links from the maps
2346         mapEl_setLi.erase( tr1 );
2347         if ( Ok12 ) {
2348           mapEl_setLi.erase( tr2 );
2349           mapLi_listEl.erase( *link12 );
2350           if(tr1->NbNodes()==3) {
2351             const SMDS_MeshElement* newElem = 0;
2352             newElem = aMesh->AddFace(n12[0], n12[1], n12[2], n12[3] );
2353             myLastCreatedElems.Append(newElem);
2354             AddToSameGroups( newElem, tr1, aMesh );
2355             int aShapeId = tr1->getshapeId();
2356             if ( aShapeId )
2357               {
2358                 aMesh->SetMeshElementOnShape( newElem, aShapeId );
2359               }
2360             aMesh->RemoveElement( tr1 );
2361             aMesh->RemoveElement( tr2 );
2362           }
2363           else {
2364             const SMDS_MeshNode* N1 [6];
2365             const SMDS_MeshNode* N2 [6];
2366             GetNodesFromTwoTria(tr1,tr2,N1,N2);
2367             // now we receive following N1 and N2 (using numeration as above image)
2368             // tria1 : (1 2 4 5 9 7)  and  tria2 : (3 4 2 8 9 6)
2369             // i.e. first nodes from both arrays determ new diagonal
2370             const SMDS_MeshNode* aNodes[8];
2371             aNodes[0] = N1[0];
2372             aNodes[1] = N1[1];
2373             aNodes[2] = N2[0];
2374             aNodes[3] = N2[1];
2375             aNodes[4] = N1[3];
2376             aNodes[5] = N2[5];
2377             aNodes[6] = N2[3];
2378             aNodes[7] = N1[5];
2379             const SMDS_MeshElement* newElem = 0;
2380             newElem = aMesh->AddFace(aNodes[0], aNodes[1], aNodes[2], aNodes[3],
2381                                      aNodes[4], aNodes[5], aNodes[6], aNodes[7]);
2382             myLastCreatedElems.Append(newElem);
2383             AddToSameGroups( newElem, tr1, aMesh );
2384             int aShapeId = tr1->getshapeId();
2385             if ( aShapeId )
2386               {
2387                 aMesh->SetMeshElementOnShape( newElem, aShapeId );
2388               }
2389             aMesh->RemoveElement( tr1 );
2390             aMesh->RemoveElement( tr2 );
2391             // remove middle node (9)
2392             GetMeshDS()->RemoveNode( N1[4] );
2393           }
2394         }
2395         else if ( Ok13 ) {
2396           mapEl_setLi.erase( tr3 );
2397           mapLi_listEl.erase( *link13 );
2398           if(tr1->NbNodes()==3) {
2399             const SMDS_MeshElement* newElem = 0;
2400             newElem = aMesh->AddFace(n13[0], n13[1], n13[2], n13[3] );
2401             myLastCreatedElems.Append(newElem);
2402             AddToSameGroups( newElem, tr1, aMesh );
2403             int aShapeId = tr1->getshapeId();
2404             if ( aShapeId )
2405               {
2406                 aMesh->SetMeshElementOnShape( newElem, aShapeId );
2407               }
2408             aMesh->RemoveElement( tr1 );
2409             aMesh->RemoveElement( tr3 );
2410           }
2411           else {
2412             const SMDS_MeshNode* N1 [6];
2413             const SMDS_MeshNode* N2 [6];
2414             GetNodesFromTwoTria(tr1,tr3,N1,N2);
2415             // now we receive following N1 and N2 (using numeration as above image)
2416             // tria1 : (1 2 4 5 9 7)  and  tria2 : (3 4 2 8 9 6)
2417             // i.e. first nodes from both arrays determ new diagonal
2418             const SMDS_MeshNode* aNodes[8];
2419             aNodes[0] = N1[0];
2420             aNodes[1] = N1[1];
2421             aNodes[2] = N2[0];
2422             aNodes[3] = N2[1];
2423             aNodes[4] = N1[3];
2424             aNodes[5] = N2[5];
2425             aNodes[6] = N2[3];
2426             aNodes[7] = N1[5];
2427             const SMDS_MeshElement* newElem = 0;
2428             newElem = aMesh->AddFace(aNodes[0], aNodes[1], aNodes[2], aNodes[3],
2429                                      aNodes[4], aNodes[5], aNodes[6], aNodes[7]);
2430             myLastCreatedElems.Append(newElem);
2431             AddToSameGroups( newElem, tr1, aMesh );
2432             int aShapeId = tr1->getshapeId();
2433             if ( aShapeId )
2434               {
2435                 aMesh->SetMeshElementOnShape( newElem, aShapeId );
2436               }
2437             aMesh->RemoveElement( tr1 );
2438             aMesh->RemoveElement( tr3 );
2439             // remove middle node (9)
2440             GetMeshDS()->RemoveNode( N1[4] );
2441           }
2442         }
2443
2444         // Next element to fuse: the rejected one
2445         if ( tr3 )
2446           startElem = Ok12 ? tr3 : tr2;
2447
2448       } // if ( startElem )
2449     } // while ( startElem || !startLinks.empty() )
2450   } // while ( ! mapEl_setLi.empty() )
2451
2452   return true;
2453 }
2454
2455
2456 /*#define DUMPSO(txt) \
2457 //  cout << txt << endl;
2458 //=============================================================================
2459 //
2460 //
2461 //
2462 //=============================================================================
2463 static void swap( int i1, int i2, int idNodes[], gp_Pnt P[] )
2464 {
2465 if ( i1 == i2 )
2466 return;
2467 int tmp = idNodes[ i1 ];
2468 idNodes[ i1 ] = idNodes[ i2 ];
2469 idNodes[ i2 ] = tmp;
2470 gp_Pnt Ptmp = P[ i1 ];
2471 P[ i1 ] = P[ i2 ];
2472 P[ i2 ] = Ptmp;
2473 DUMPSO( i1 << "(" << idNodes[ i2 ] << ") <-> " << i2 << "(" << idNodes[ i1 ] << ")");
2474 }
2475
2476 //=======================================================================
2477 //function : SortQuadNodes
2478 //purpose  : Set 4 nodes of a quadrangle face in a good order.
2479 //           Swap 1<->2 or 2<->3 nodes and correspondingly return
2480 //           1 or 2 else 0.
2481 //=======================================================================
2482
2483 int SMESH_MeshEditor::SortQuadNodes (const SMDS_Mesh * theMesh,
2484 int               idNodes[] )
2485 {
2486   gp_Pnt P[4];
2487   int i;
2488   for ( i = 0; i < 4; i++ ) {
2489     const SMDS_MeshNode *n = theMesh->FindNode( idNodes[i] );
2490     if ( !n ) return 0;
2491     P[ i ].SetCoord( n->X(), n->Y(), n->Z() );
2492   }
2493
2494   gp_Vec V1(P[0], P[1]);
2495   gp_Vec V2(P[0], P[2]);
2496   gp_Vec V3(P[0], P[3]);
2497
2498   gp_Vec Cross1 = V1 ^ V2;
2499   gp_Vec Cross2 = V2 ^ V3;
2500
2501   i = 0;
2502   if (Cross1.Dot(Cross2) < 0)
2503   {
2504     Cross1 = V2 ^ V1;
2505     Cross2 = V1 ^ V3;
2506
2507     if (Cross1.Dot(Cross2) < 0)
2508       i = 2;
2509     else
2510       i = 1;
2511     swap ( i, i + 1, idNodes, P );
2512
2513     //     for ( int ii = 0; ii < 4; ii++ ) {
2514     //       const SMDS_MeshNode *n = theMesh->FindNode( idNodes[ii] );
2515     //       DUMPSO( ii << "(" << idNodes[ii] <<") : "<<n->X()<<" "<<n->Y()<<" "<<n->Z());
2516     //     }
2517   }
2518   return i;
2519 }
2520
2521 //=======================================================================
2522 //function : SortHexaNodes
2523 //purpose  : Set 8 nodes of a hexahedron in a good order.
2524 //           Return success status
2525 //=======================================================================
2526
2527 bool SMESH_MeshEditor::SortHexaNodes (const SMDS_Mesh * theMesh,
2528                                       int               idNodes[] )
2529 {
2530   gp_Pnt P[8];
2531   int i;
2532   DUMPSO( "INPUT: ========================================");
2533   for ( i = 0; i < 8; i++ ) {
2534     const SMDS_MeshNode *n = theMesh->FindNode( idNodes[i] );
2535     if ( !n ) return false;
2536     P[ i ].SetCoord( n->X(), n->Y(), n->Z() );
2537     DUMPSO( i << "(" << idNodes[i] <<") : "<<n->X()<<" "<<n->Y()<<" "<<n->Z());
2538   }
2539   DUMPSO( "========================================");
2540
2541
2542   set<int> faceNodes;  // ids of bottom face nodes, to be found
2543   set<int> checkedId1; // ids of tried 2-nd nodes
2544   Standard_Real leastDist = DBL_MAX; // dist of the 4-th node from 123 plane
2545   const Standard_Real tol = 1.e-6;   // tolerance to find nodes in plane
2546   int iMin, iLoop1 = 0;
2547
2548   // Loop to try the 2-nd nodes
2549
2550   while ( leastDist > DBL_MIN && ++iLoop1 < 8 )
2551   {
2552     // Find not checked 2-nd node
2553     for ( i = 1; i < 8; i++ )
2554       if ( checkedId1.find( idNodes[i] ) == checkedId1.end() ) {
2555         int id1 = idNodes[i];
2556         swap ( 1, i, idNodes, P );
2557         checkedId1.insert ( id1 );
2558         break;
2559       }
2560
2561     // Find the 3-d node so that 1-2-3 triangle to be on a hexa face,
2562     // ie that all but meybe one (id3 which is on the same face) nodes
2563     // lay on the same side from the triangle plane.
2564
2565     bool manyInPlane = false; // more than 4 nodes lay in plane
2566     int iLoop2 = 0;
2567     while ( ++iLoop2 < 6 ) {
2568
2569       // get 1-2-3 plane coeffs
2570       Standard_Real A, B, C, D;
2571       gp_Vec N = gp_Vec (P[0], P[1]).Crossed( gp_Vec (P[0], P[2]) );
2572       if ( N.SquareMagnitude() > gp::Resolution() )
2573       {
2574         gp_Pln pln ( P[0], N );
2575         pln.Coefficients( A, B, C, D );
2576
2577         // find the node (iMin) closest to pln
2578         Standard_Real dist[ 8 ], minDist = DBL_MAX;
2579         set<int> idInPln;
2580         for ( i = 3; i < 8; i++ ) {
2581           dist[i] = A * P[i].X() + B * P[i].Y() + C * P[i].Z() + D;
2582           if ( fabs( dist[i] ) < minDist ) {
2583             minDist = fabs( dist[i] );
2584             iMin = i;
2585           }
2586           if ( fabs( dist[i] ) <= tol )
2587             idInPln.insert( idNodes[i] );
2588         }
2589
2590         // there should not be more than 4 nodes in bottom plane
2591         if ( idInPln.size() > 1 )
2592         {
2593           DUMPSO( "### idInPln.size() = " << idInPln.size());
2594           // idInPlane does not contain the first 3 nodes
2595           if ( manyInPlane || idInPln.size() == 5)
2596             return false; // all nodes in one plane
2597           manyInPlane = true;
2598
2599           // set the 1-st node to be not in plane
2600           for ( i = 3; i < 8; i++ ) {
2601             if ( idInPln.find( idNodes[ i ] ) == idInPln.end() ) {
2602               DUMPSO( "### Reset 0-th node");
2603               swap( 0, i, idNodes, P );
2604               break;
2605             }
2606           }
2607
2608           // reset to re-check second nodes
2609           leastDist = DBL_MAX;
2610           faceNodes.clear();
2611           checkedId1.clear();
2612           iLoop1 = 0;
2613           break; // from iLoop2;
2614         }
2615
2616         // check that the other 4 nodes are on the same side
2617         bool sameSide = true;
2618         bool isNeg = dist[ iMin == 3 ? 4 : 3 ] <= 0.;
2619         for ( i = 3; sameSide && i < 8; i++ ) {
2620           if ( i != iMin )
2621             sameSide = ( isNeg == dist[i] <= 0.);
2622         }
2623
2624         // keep best solution
2625         if ( sameSide && minDist < leastDist ) {
2626           leastDist = minDist;
2627           faceNodes.clear();
2628           faceNodes.insert( idNodes[ 1 ] );
2629           faceNodes.insert( idNodes[ 2 ] );
2630           faceNodes.insert( idNodes[ iMin ] );
2631           DUMPSO( "loop " << iLoop2 << " id2 " << idNodes[ 1 ] << " id3 " << idNodes[ 2 ]
2632                   << " leastDist = " << leastDist);
2633           if ( leastDist <= DBL_MIN )
2634             break;
2635         }
2636       }
2637
2638       // set next 3-d node to check
2639       int iNext = 2 + iLoop2;
2640       if ( iNext < 8 ) {
2641         DUMPSO( "Try 2-nd");
2642         swap ( 2, iNext, idNodes, P );
2643       }
2644     } // while ( iLoop2 < 6 )
2645   } // iLoop1
2646
2647   if ( faceNodes.empty() ) return false;
2648
2649   // Put the faceNodes in proper places
2650   for ( i = 4; i < 8; i++ ) {
2651     if ( faceNodes.find( idNodes[ i ] ) != faceNodes.end() ) {
2652       // find a place to put
2653       int iTo = 1;
2654       while ( faceNodes.find( idNodes[ iTo ] ) != faceNodes.end() )
2655         iTo++;
2656       DUMPSO( "Set faceNodes");
2657       swap ( iTo, i, idNodes, P );
2658     }
2659   }
2660
2661
2662   // Set nodes of the found bottom face in good order
2663   DUMPSO( " Found bottom face: ");
2664   i = SortQuadNodes( theMesh, idNodes );
2665   if ( i ) {
2666     gp_Pnt Ptmp = P[ i ];
2667     P[ i ] = P[ i+1 ];
2668     P[ i+1 ] = Ptmp;
2669   }
2670   //   else
2671   //     for ( int ii = 0; ii < 4; ii++ ) {
2672   //       const SMDS_MeshNode *n = theMesh->FindNode( idNodes[ii] );
2673   //       DUMPSO( ii << "(" << idNodes[ii] <<") : "<<n->X()<<" "<<n->Y()<<" "<<n->Z());
2674   //    }
2675
2676   // Gravity center of the top and bottom faces
2677   gp_Pnt aGCb = ( P[0].XYZ() + P[1].XYZ() + P[2].XYZ() + P[3].XYZ() ) / 4.;
2678   gp_Pnt aGCt = ( P[4].XYZ() + P[5].XYZ() + P[6].XYZ() + P[7].XYZ() ) / 4.;
2679
2680   // Get direction from the bottom to the top face
2681   gp_Vec upDir ( aGCb, aGCt );
2682   Standard_Real upDirSize = upDir.Magnitude();
2683   if ( upDirSize <= gp::Resolution() ) return false;
2684   upDir / upDirSize;
2685
2686   // Assure that the bottom face normal points up
2687   gp_Vec Nb = gp_Vec (P[0], P[1]).Crossed( gp_Vec (P[0], P[2]) );
2688   Nb += gp_Vec (P[0], P[2]).Crossed( gp_Vec (P[0], P[3]) );
2689   if ( Nb.Dot( upDir ) < 0 ) {
2690     DUMPSO( "Reverse bottom face");
2691     swap( 1, 3, idNodes, P );
2692   }
2693
2694   // Find 5-th node - the one closest to the 1-st among the last 4 nodes.
2695   Standard_Real minDist = DBL_MAX;
2696   for ( i = 4; i < 8; i++ ) {
2697     // projection of P[i] to the plane defined by P[0] and upDir
2698     gp_Pnt Pp = P[i].Translated( upDir * ( upDir.Dot( gp_Vec( P[i], P[0] ))));
2699     Standard_Real sqDist = P[0].SquareDistance( Pp );
2700     if ( sqDist < minDist ) {
2701       minDist = sqDist;
2702       iMin = i;
2703     }
2704   }
2705   DUMPSO( "Set 4-th");
2706   swap ( 4, iMin, idNodes, P );
2707
2708   // Set nodes of the top face in good order
2709   DUMPSO( "Sort top face");
2710   i = SortQuadNodes( theMesh, &idNodes[4] );
2711   if ( i ) {
2712     i += 4;
2713     gp_Pnt Ptmp = P[ i ];
2714     P[ i ] = P[ i+1 ];
2715     P[ i+1 ] = Ptmp;
2716   }
2717
2718   // Assure that direction of the top face normal is from the bottom face
2719   gp_Vec Nt = gp_Vec (P[4], P[5]).Crossed( gp_Vec (P[4], P[6]) );
2720   Nt += gp_Vec (P[4], P[6]).Crossed( gp_Vec (P[4], P[7]) );
2721   if ( Nt.Dot( upDir ) < 0 ) {
2722     DUMPSO( "Reverse top face");
2723     swap( 5, 7, idNodes, P );
2724   }
2725
2726   //   DUMPSO( "OUTPUT: ========================================");
2727   //   for ( i = 0; i < 8; i++ ) {
2728   //     float *p = ugrid->GetPoint(idNodes[i]);
2729   //     DUMPSO( i << "(" << idNodes[i] << ") : " << p[0] << " " << p[1] << " " << p[2]);
2730   //   }
2731
2732   return true;
2733 }*/
2734
2735 //================================================================================
2736 /*!
2737  * \brief Return nodes linked to the given one
2738  * \param theNode - the node
2739  * \param linkedNodes - the found nodes
2740  * \param type - the type of elements to check
2741  *
2742  * Medium nodes are ignored
2743  */
2744 //================================================================================
2745
2746 void SMESH_MeshEditor::GetLinkedNodes( const SMDS_MeshNode* theNode,
2747                                        TIDSortedElemSet &   linkedNodes,
2748                                        SMDSAbs_ElementType  type )
2749 {
2750   SMDS_ElemIteratorPtr elemIt = theNode->GetInverseElementIterator(type);
2751   while ( elemIt->more() )
2752   {
2753     const SMDS_MeshElement* elem = elemIt->next();
2754     if(elem->GetType() == SMDSAbs_0DElement)
2755       continue;
2756     
2757     SMDS_ElemIteratorPtr nodeIt = elem->nodesIterator();
2758     if ( elem->GetType() == SMDSAbs_Volume )
2759     {
2760       SMDS_VolumeTool vol( elem );
2761       while ( nodeIt->more() ) {
2762         const SMDS_MeshNode* n = cast2Node( nodeIt->next() );
2763         if ( theNode != n && vol.IsLinked( theNode, n ))
2764           linkedNodes.insert( n );
2765       }
2766     }
2767     else
2768     {
2769       for ( int i = 0; nodeIt->more(); ++i ) {
2770         const SMDS_MeshNode* n = cast2Node( nodeIt->next() );
2771         if ( n == theNode ) {
2772           int iBefore = i - 1;
2773           int iAfter  = i + 1;
2774           if ( elem->IsQuadratic() ) {
2775             int nb = elem->NbNodes() / 2;
2776             iAfter  = SMESH_MesherHelper::WrapIndex( iAfter, nb );
2777             iBefore = SMESH_MesherHelper::WrapIndex( iBefore, nb );
2778           }
2779           linkedNodes.insert( elem->GetNodeWrap( iAfter ));
2780           linkedNodes.insert( elem->GetNodeWrap( iBefore ));
2781         }
2782       }
2783     }
2784   }
2785 }
2786
2787 //=======================================================================
2788 //function : laplacianSmooth
2789 //purpose  : pulls theNode toward the center of surrounding nodes directly
2790 //           connected to that node along an element edge
2791 //=======================================================================
2792
2793 void laplacianSmooth(const SMDS_MeshNode*                 theNode,
2794                      const Handle(Geom_Surface)&          theSurface,
2795                      map< const SMDS_MeshNode*, gp_XY* >& theUVMap)
2796 {
2797   // find surrounding nodes
2798
2799   TIDSortedElemSet nodeSet;
2800   SMESH_MeshEditor::GetLinkedNodes( theNode, nodeSet, SMDSAbs_Face );
2801
2802   // compute new coodrs
2803
2804   double coord[] = { 0., 0., 0. };
2805   TIDSortedElemSet::iterator nodeSetIt = nodeSet.begin();
2806   for ( ; nodeSetIt != nodeSet.end(); nodeSetIt++ ) {
2807     const SMDS_MeshNode* node = cast2Node(*nodeSetIt);
2808     if ( theSurface.IsNull() ) { // smooth in 3D
2809       coord[0] += node->X();
2810       coord[1] += node->Y();
2811       coord[2] += node->Z();
2812     }
2813     else { // smooth in 2D
2814       ASSERT( theUVMap.find( node ) != theUVMap.end() );
2815       gp_XY* uv = theUVMap[ node ];
2816       coord[0] += uv->X();
2817       coord[1] += uv->Y();
2818     }
2819   }
2820   int nbNodes = nodeSet.size();
2821   if ( !nbNodes )
2822     return;
2823   coord[0] /= nbNodes;
2824   coord[1] /= nbNodes;
2825
2826   if ( !theSurface.IsNull() ) {
2827     ASSERT( theUVMap.find( theNode ) != theUVMap.end() );
2828     theUVMap[ theNode ]->SetCoord( coord[0], coord[1] );
2829     gp_Pnt p3d = theSurface->Value( coord[0], coord[1] );
2830     coord[0] = p3d.X();
2831     coord[1] = p3d.Y();
2832     coord[2] = p3d.Z();
2833   }
2834   else
2835     coord[2] /= nbNodes;
2836
2837   // move node
2838
2839   const_cast< SMDS_MeshNode* >( theNode )->setXYZ(coord[0],coord[1],coord[2]);
2840 }
2841
2842 //=======================================================================
2843 //function : centroidalSmooth
2844 //purpose  : pulls theNode toward the element-area-weighted centroid of the
2845 //           surrounding elements
2846 //=======================================================================
2847
2848 void centroidalSmooth(const SMDS_MeshNode*                 theNode,
2849                       const Handle(Geom_Surface)&          theSurface,
2850                       map< const SMDS_MeshNode*, gp_XY* >& theUVMap)
2851 {
2852   gp_XYZ aNewXYZ(0.,0.,0.);
2853   SMESH::Controls::Area anAreaFunc;
2854   double totalArea = 0.;
2855   int nbElems = 0;
2856
2857   // compute new XYZ
2858
2859   SMDS_ElemIteratorPtr elemIt = theNode->GetInverseElementIterator(SMDSAbs_Face);
2860   while ( elemIt->more() )
2861   {
2862     const SMDS_MeshElement* elem = elemIt->next();
2863     nbElems++;
2864
2865     gp_XYZ elemCenter(0.,0.,0.);
2866     SMESH::Controls::TSequenceOfXYZ aNodePoints;
2867     SMDS_ElemIteratorPtr itN = elem->nodesIterator();
2868     int nn = elem->NbNodes();
2869     if(elem->IsQuadratic()) nn = nn/2;
2870     int i=0;
2871     //while ( itN->more() ) {
2872     while ( i<nn ) {
2873       const SMDS_MeshNode* aNode = static_cast<const SMDS_MeshNode*>( itN->next() );
2874       i++;
2875       gp_XYZ aP( aNode->X(), aNode->Y(), aNode->Z() );
2876       aNodePoints.push_back( aP );
2877       if ( !theSurface.IsNull() ) { // smooth in 2D
2878         ASSERT( theUVMap.find( aNode ) != theUVMap.end() );
2879         gp_XY* uv = theUVMap[ aNode ];
2880         aP.SetCoord( uv->X(), uv->Y(), 0. );
2881       }
2882       elemCenter += aP;
2883     }
2884     double elemArea = anAreaFunc.GetValue( aNodePoints );
2885     totalArea += elemArea;
2886     elemCenter /= nn;
2887     aNewXYZ += elemCenter * elemArea;
2888   }
2889   aNewXYZ /= totalArea;
2890   if ( !theSurface.IsNull() ) {
2891     theUVMap[ theNode ]->SetCoord( aNewXYZ.X(), aNewXYZ.Y() );
2892     aNewXYZ = theSurface->Value( aNewXYZ.X(), aNewXYZ.Y() ).XYZ();
2893   }
2894
2895   // move node
2896
2897   const_cast< SMDS_MeshNode* >( theNode )->setXYZ(aNewXYZ.X(),aNewXYZ.Y(),aNewXYZ.Z());
2898 }
2899
2900 //=======================================================================
2901 //function : getClosestUV
2902 //purpose  : return UV of closest projection
2903 //=======================================================================
2904
2905 static bool getClosestUV (Extrema_GenExtPS& projector,
2906                           const gp_Pnt&     point,
2907                           gp_XY &           result)
2908 {
2909   projector.Perform( point );
2910   if ( projector.IsDone() ) {
2911     double u, v, minVal = DBL_MAX;
2912     for ( int i = projector.NbExt(); i > 0; i-- )
2913 #if OCC_VERSION_LARGE > 0x06040000 // Porting to OCCT6.5.1
2914       if ( projector.SquareDistance( i ) < minVal ) {
2915         minVal = projector.SquareDistance( i );
2916 #else
2917       if ( projector.Value( i ) < minVal ) {
2918         minVal = projector.Value( i );
2919 #endif
2920         projector.Point( i ).Parameter( u, v );
2921       }
2922     result.SetCoord( u, v );
2923     return true;
2924   }
2925   return false;
2926 }
2927
2928 //=======================================================================
2929 //function : Smooth
2930 //purpose  : Smooth theElements during theNbIterations or until a worst
2931 //           element has aspect ratio <= theTgtAspectRatio.
2932 //           Aspect Ratio varies in range [1.0, inf].
2933 //           If theElements is empty, the whole mesh is smoothed.
2934 //           theFixedNodes contains additionally fixed nodes. Nodes built
2935 //           on edges and boundary nodes are always fixed.
2936 //=======================================================================
2937
2938 void SMESH_MeshEditor::Smooth (TIDSortedElemSet &          theElems,
2939                                set<const SMDS_MeshNode*> & theFixedNodes,
2940                                const SmoothMethod          theSmoothMethod,
2941                                const int                   theNbIterations,
2942                                double                      theTgtAspectRatio,
2943                                const bool                  the2D)
2944 {
2945   myLastCreatedElems.Clear();
2946   myLastCreatedNodes.Clear();
2947
2948   MESSAGE((theSmoothMethod==LAPLACIAN ? "LAPLACIAN" : "CENTROIDAL") << "--::Smooth()");
2949
2950   if ( theTgtAspectRatio < 1.0 )
2951     theTgtAspectRatio = 1.0;
2952
2953   const double disttol = 1.e-16;
2954
2955   SMESH::Controls::AspectRatio aQualityFunc;
2956
2957   SMESHDS_Mesh* aMesh = GetMeshDS();
2958
2959   if ( theElems.empty() ) {
2960     // add all faces to theElems
2961     SMDS_FaceIteratorPtr fIt = aMesh->facesIterator();
2962     while ( fIt->more() ) {
2963       const SMDS_MeshElement* face = fIt->next();
2964       theElems.insert( face );
2965     }
2966   }
2967   // get all face ids theElems are on
2968   set< int > faceIdSet;
2969   TIDSortedElemSet::iterator itElem;
2970   if ( the2D )
2971     for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
2972       int fId = FindShape( *itElem );
2973       // check that corresponding submesh exists and a shape is face
2974       if (fId &&
2975           faceIdSet.find( fId ) == faceIdSet.end() &&
2976           aMesh->MeshElements( fId )) {
2977         TopoDS_Shape F = aMesh->IndexToShape( fId );
2978         if ( !F.IsNull() && F.ShapeType() == TopAbs_FACE )
2979           faceIdSet.insert( fId );
2980       }
2981     }
2982   faceIdSet.insert( 0 ); // to smooth elements that are not on any TopoDS_Face
2983
2984   // ===============================================
2985   // smooth elements on each TopoDS_Face separately
2986   // ===============================================
2987
2988   set< int >::reverse_iterator fId = faceIdSet.rbegin(); // treate 0 fId at the end
2989   for ( ; fId != faceIdSet.rend(); ++fId ) {
2990     // get face surface and submesh
2991     Handle(Geom_Surface) surface;
2992     SMESHDS_SubMesh* faceSubMesh = 0;
2993     TopoDS_Face face;
2994     double fToler2 = 0, f,l;
2995     double u1 = 0, u2 = 0, v1 = 0, v2 = 0;
2996     bool isUPeriodic = false, isVPeriodic = false;
2997     if ( *fId ) {
2998       face = TopoDS::Face( aMesh->IndexToShape( *fId ));
2999       surface = BRep_Tool::Surface( face );
3000       faceSubMesh = aMesh->MeshElements( *fId );
3001       fToler2 = BRep_Tool::Tolerance( face );
3002       fToler2 *= fToler2 * 10.;
3003       isUPeriodic = surface->IsUPeriodic();
3004       if ( isUPeriodic )
3005         surface->UPeriod();
3006       isVPeriodic = surface->IsVPeriodic();
3007       if ( isVPeriodic )
3008         surface->VPeriod();
3009       surface->Bounds( u1, u2, v1, v2 );
3010     }
3011     // ---------------------------------------------------------
3012     // for elements on a face, find movable and fixed nodes and
3013     // compute UV for them
3014     // ---------------------------------------------------------
3015     bool checkBoundaryNodes = false;
3016     bool isQuadratic = false;
3017     set<const SMDS_MeshNode*> setMovableNodes;
3018     map< const SMDS_MeshNode*, gp_XY* > uvMap, uvMap2;
3019     list< gp_XY > listUV; // uvs the 2 uvMaps refer to
3020     list< const SMDS_MeshElement* > elemsOnFace;
3021
3022     Extrema_GenExtPS projector;
3023     GeomAdaptor_Surface surfAdaptor;
3024     if ( !surface.IsNull() ) {
3025       surfAdaptor.Load( surface );
3026       projector.Initialize( surfAdaptor, 20,20, 1e-5,1e-5 );
3027     }
3028     int nbElemOnFace = 0;
3029     itElem = theElems.begin();
3030     // loop on not yet smoothed elements: look for elems on a face
3031     while ( itElem != theElems.end() ) {
3032       if ( faceSubMesh && nbElemOnFace == faceSubMesh->NbElements() )
3033         break; // all elements found
3034
3035       const SMDS_MeshElement* elem = *itElem;
3036       if ( !elem || elem->GetType() != SMDSAbs_Face || elem->NbNodes() < 3 ||
3037            ( faceSubMesh && !faceSubMesh->Contains( elem ))) {
3038         ++itElem;
3039         continue;
3040       }
3041       elemsOnFace.push_back( elem );
3042       theElems.erase( itElem++ );
3043       nbElemOnFace++;
3044
3045       if ( !isQuadratic )
3046         isQuadratic = elem->IsQuadratic();
3047
3048       // get movable nodes of elem
3049       const SMDS_MeshNode* node;
3050       SMDS_TypeOfPosition posType;
3051       SMDS_ElemIteratorPtr itN = elem->nodesIterator();
3052       int nn = 0, nbn =  elem->NbNodes();
3053       if(elem->IsQuadratic())
3054         nbn = nbn/2;
3055       while ( nn++ < nbn ) {
3056         node = static_cast<const SMDS_MeshNode*>( itN->next() );
3057         const SMDS_PositionPtr& pos = node->GetPosition();
3058         posType = pos ? pos->GetTypeOfPosition() : SMDS_TOP_3DSPACE;
3059         if (posType != SMDS_TOP_EDGE &&
3060             posType != SMDS_TOP_VERTEX &&
3061             theFixedNodes.find( node ) == theFixedNodes.end())
3062         {
3063           // check if all faces around the node are on faceSubMesh
3064           // because a node on edge may be bound to face
3065           SMDS_ElemIteratorPtr eIt = node->GetInverseElementIterator(SMDSAbs_Face);
3066           bool all = true;
3067           if ( faceSubMesh ) {
3068             while ( eIt->more() && all ) {
3069               const SMDS_MeshElement* e = eIt->next();
3070               all = faceSubMesh->Contains( e );
3071             }
3072           }
3073           if ( all )
3074             setMovableNodes.insert( node );
3075           else
3076             checkBoundaryNodes = true;
3077         }
3078         if ( posType == SMDS_TOP_3DSPACE )
3079           checkBoundaryNodes = true;
3080       }
3081
3082       if ( surface.IsNull() )
3083         continue;
3084
3085       // get nodes to check UV
3086       list< const SMDS_MeshNode* > uvCheckNodes;
3087       itN = elem->nodesIterator();
3088       nn = 0; nbn =  elem->NbNodes();
3089       if(elem->IsQuadratic())
3090         nbn = nbn/2;
3091       while ( nn++ < nbn ) {
3092         node = static_cast<const SMDS_MeshNode*>( itN->next() );
3093         if ( uvMap.find( node ) == uvMap.end() )
3094           uvCheckNodes.push_back( node );
3095         // add nodes of elems sharing node
3096         //         SMDS_ElemIteratorPtr eIt = node->GetInverseElementIterator(SMDSAbs_Face);
3097         //         while ( eIt->more() ) {
3098         //           const SMDS_MeshElement* e = eIt->next();
3099         //           if ( e != elem ) {
3100         //             SMDS_ElemIteratorPtr nIt = e->nodesIterator();
3101         //             while ( nIt->more() ) {
3102         //               const SMDS_MeshNode* n =
3103         //                 static_cast<const SMDS_MeshNode*>( nIt->next() );
3104         //               if ( uvMap.find( n ) == uvMap.end() )
3105         //                 uvCheckNodes.push_back( n );
3106         //             }
3107         //           }
3108         //         }
3109       }
3110       // check UV on face
3111       list< const SMDS_MeshNode* >::iterator n = uvCheckNodes.begin();
3112       for ( ; n != uvCheckNodes.end(); ++n ) {
3113         node = *n;
3114         gp_XY uv( 0, 0 );
3115         const SMDS_PositionPtr& pos = node->GetPosition();
3116         posType = pos ? pos->GetTypeOfPosition() : SMDS_TOP_3DSPACE;
3117         // get existing UV
3118         switch ( posType ) {
3119         case SMDS_TOP_FACE: {
3120           SMDS_FacePosition* fPos = ( SMDS_FacePosition* ) pos;
3121           uv.SetCoord( fPos->GetUParameter(), fPos->GetVParameter() );
3122           break;
3123         }
3124         case SMDS_TOP_EDGE: {
3125           TopoDS_Shape S = aMesh->IndexToShape( node->getshapeId() );
3126           Handle(Geom2d_Curve) pcurve;
3127           if ( !S.IsNull() && S.ShapeType() == TopAbs_EDGE )
3128             pcurve = BRep_Tool::CurveOnSurface( TopoDS::Edge( S ), face, f,l );
3129           if ( !pcurve.IsNull() ) {
3130             double u = (( SMDS_EdgePosition* ) pos )->GetUParameter();
3131             uv = pcurve->Value( u ).XY();
3132           }
3133           break;
3134         }
3135         case SMDS_TOP_VERTEX: {
3136           TopoDS_Shape S = aMesh->IndexToShape( node->getshapeId() );
3137           if ( !S.IsNull() && S.ShapeType() == TopAbs_VERTEX )
3138             uv = BRep_Tool::Parameters( TopoDS::Vertex( S ), face ).XY();
3139           break;
3140         }
3141         default:;
3142         }
3143         // check existing UV
3144         bool project = true;
3145         gp_Pnt pNode ( node->X(), node->Y(), node->Z() );
3146         double dist1 = DBL_MAX, dist2 = 0;
3147         if ( posType != SMDS_TOP_3DSPACE ) {
3148           dist1 = pNode.SquareDistance( surface->Value( uv.X(), uv.Y() ));
3149           project = dist1 > fToler2;
3150         }
3151         if ( project ) { // compute new UV
3152           gp_XY newUV;
3153           if ( !getClosestUV( projector, pNode, newUV )) {
3154             MESSAGE("Node Projection Failed " << node);
3155           }
3156           else {
3157             if ( isUPeriodic )
3158               newUV.SetX( ElCLib::InPeriod( newUV.X(), u1, u2 ));
3159             if ( isVPeriodic )
3160               newUV.SetY( ElCLib::InPeriod( newUV.Y(), v1, v2 ));
3161             // check new UV
3162             if ( posType != SMDS_TOP_3DSPACE )
3163               dist2 = pNode.SquareDistance( surface->Value( newUV.X(), newUV.Y() ));
3164             if ( dist2 < dist1 )
3165               uv = newUV;
3166           }
3167         }
3168         // store UV in the map
3169         listUV.push_back( uv );
3170         uvMap.insert( make_pair( node, &listUV.back() ));
3171       }
3172     } // loop on not yet smoothed elements
3173
3174     if ( !faceSubMesh || nbElemOnFace != faceSubMesh->NbElements() )
3175       checkBoundaryNodes = true;
3176
3177     // fix nodes on mesh boundary
3178
3179     if ( checkBoundaryNodes ) {
3180       map< SMESH_TLink, int > linkNbMap; // how many times a link encounters in elemsOnFace
3181       map< SMESH_TLink, int >::iterator link_nb;
3182       // put all elements links to linkNbMap
3183       list< const SMDS_MeshElement* >::iterator elemIt = elemsOnFace.begin();
3184       for ( ; elemIt != elemsOnFace.end(); ++elemIt ) {
3185         const SMDS_MeshElement* elem = (*elemIt);
3186         int nbn =  elem->NbCornerNodes();
3187         // loop on elem links: insert them in linkNbMap
3188         for ( int iN = 0; iN < nbn; ++iN ) {
3189           const SMDS_MeshNode* n1 = elem->GetNode( iN );
3190           const SMDS_MeshNode* n2 = elem->GetNode(( iN+1 ) % nbn);
3191           SMESH_TLink link( n1, n2 );
3192           link_nb = linkNbMap.insert( make_pair( link, 0 )).first;
3193           link_nb->second++;
3194         }
3195       }
3196       // remove nodes that are in links encountered only once from setMovableNodes
3197       for ( link_nb = linkNbMap.begin(); link_nb != linkNbMap.end(); ++link_nb ) {
3198         if ( link_nb->second == 1 ) {
3199           setMovableNodes.erase( link_nb->first.node1() );
3200           setMovableNodes.erase( link_nb->first.node2() );
3201         }
3202       }
3203     }
3204
3205     // -----------------------------------------------------
3206     // for nodes on seam edge, compute one more UV ( uvMap2 );
3207     // find movable nodes linked to nodes on seam and which
3208     // are to be smoothed using the second UV ( uvMap2 )
3209     // -----------------------------------------------------
3210
3211     set<const SMDS_MeshNode*> nodesNearSeam; // to smooth using uvMap2
3212     if ( !surface.IsNull() ) {
3213       TopExp_Explorer eExp( face, TopAbs_EDGE );
3214       for ( ; eExp.More(); eExp.Next() ) {
3215         TopoDS_Edge edge = TopoDS::Edge( eExp.Current() );
3216         if ( !BRep_Tool::IsClosed( edge, face ))
3217           continue;
3218         SMESHDS_SubMesh* sm = aMesh->MeshElements( edge );
3219         if ( !sm ) continue;
3220         // find out which parameter varies for a node on seam
3221         double f,l;
3222         gp_Pnt2d uv1, uv2;
3223         Handle(Geom2d_Curve) pcurve = BRep_Tool::CurveOnSurface( edge, face, f, l );
3224         if ( pcurve.IsNull() ) continue;
3225         uv1 = pcurve->Value( f );
3226         edge.Reverse();
3227         pcurve = BRep_Tool::CurveOnSurface( edge, face, f, l );
3228         if ( pcurve.IsNull() ) continue;
3229         uv2 = pcurve->Value( f );
3230         int iPar = Abs( uv1.X() - uv2.X() ) > Abs( uv1.Y() - uv2.Y() ) ? 1 : 2;
3231         // assure uv1 < uv2
3232         if ( uv1.Coord( iPar ) > uv2.Coord( iPar )) {
3233           gp_Pnt2d tmp = uv1; uv1 = uv2; uv2 = tmp;
3234         }
3235         // get nodes on seam and its vertices
3236         list< const SMDS_MeshNode* > seamNodes;
3237         SMDS_NodeIteratorPtr nSeamIt = sm->GetNodes();
3238         while ( nSeamIt->more() ) {
3239           const SMDS_MeshNode* node = nSeamIt->next();
3240           if ( !isQuadratic || !IsMedium( node ))
3241             seamNodes.push_back( node );
3242         }
3243         TopExp_Explorer vExp( edge, TopAbs_VERTEX );
3244         for ( ; vExp.More(); vExp.Next() ) {
3245           sm = aMesh->MeshElements( vExp.Current() );
3246           if ( sm ) {
3247             nSeamIt = sm->GetNodes();
3248             while ( nSeamIt->more() )
3249               seamNodes.push_back( nSeamIt->next() );
3250           }
3251         }
3252         // loop on nodes on seam
3253         list< const SMDS_MeshNode* >::iterator noSeIt = seamNodes.begin();
3254         for ( ; noSeIt != seamNodes.end(); ++noSeIt ) {
3255           const SMDS_MeshNode* nSeam = *noSeIt;
3256           map< const SMDS_MeshNode*, gp_XY* >::iterator n_uv = uvMap.find( nSeam );
3257           if ( n_uv == uvMap.end() )
3258             continue;
3259           // set the first UV
3260           n_uv->second->SetCoord( iPar, uv1.Coord( iPar ));
3261           // set the second UV
3262           listUV.push_back( *n_uv->second );
3263           listUV.back().SetCoord( iPar, uv2.Coord( iPar ));
3264           if ( uvMap2.empty() )
3265             uvMap2 = uvMap; // copy the uvMap contents
3266           uvMap2[ nSeam ] = &listUV.back();
3267
3268           // collect movable nodes linked to ones on seam in nodesNearSeam
3269           SMDS_ElemIteratorPtr eIt = nSeam->GetInverseElementIterator(SMDSAbs_Face);
3270           while ( eIt->more() ) {
3271             const SMDS_MeshElement* e = eIt->next();
3272             int nbUseMap1 = 0, nbUseMap2 = 0;
3273             SMDS_ElemIteratorPtr nIt = e->nodesIterator();
3274             int nn = 0, nbn =  e->NbNodes();
3275             if(e->IsQuadratic()) nbn = nbn/2;
3276             while ( nn++ < nbn )
3277             {
3278               const SMDS_MeshNode* n =
3279                 static_cast<const SMDS_MeshNode*>( nIt->next() );
3280               if (n == nSeam ||
3281                   setMovableNodes.find( n ) == setMovableNodes.end() )
3282                 continue;
3283               // add only nodes being closer to uv2 than to uv1
3284               gp_Pnt pMid (0.5 * ( n->X() + nSeam->X() ),
3285                            0.5 * ( n->Y() + nSeam->Y() ),
3286                            0.5 * ( n->Z() + nSeam->Z() ));
3287               gp_XY uv;
3288               getClosestUV( projector, pMid, uv );
3289               if ( uv.Coord( iPar ) > uvMap[ n ]->Coord( iPar ) ) {
3290                 nodesNearSeam.insert( n );
3291                 nbUseMap2++;
3292               }
3293               else
3294                 nbUseMap1++;
3295             }
3296             // for centroidalSmooth all element nodes must
3297             // be on one side of a seam
3298             if ( theSmoothMethod == CENTROIDAL && nbUseMap1 && nbUseMap2 ) {
3299               SMDS_ElemIteratorPtr nIt = e->nodesIterator();
3300               nn = 0;
3301               while ( nn++ < nbn ) {
3302                 const SMDS_MeshNode* n =
3303                   static_cast<const SMDS_MeshNode*>( nIt->next() );
3304                 setMovableNodes.erase( n );
3305               }
3306             }
3307           }
3308         } // loop on nodes on seam
3309       } // loop on edge of a face
3310     } // if ( !face.IsNull() )
3311
3312     if ( setMovableNodes.empty() ) {
3313       MESSAGE( "Face id : " << *fId << " - NO SMOOTHING: no nodes to move!!!");
3314       continue; // goto next face
3315     }
3316
3317     // -------------
3318     // SMOOTHING //
3319     // -------------
3320
3321     int it = -1;
3322     double maxRatio = -1., maxDisplacement = -1.;
3323     set<const SMDS_MeshNode*>::iterator nodeToMove;
3324     for ( it = 0; it < theNbIterations; it++ ) {
3325       maxDisplacement = 0.;
3326       nodeToMove = setMovableNodes.begin();
3327       for ( ; nodeToMove != setMovableNodes.end(); nodeToMove++ ) {
3328         const SMDS_MeshNode* node = (*nodeToMove);
3329         gp_XYZ aPrevPos ( node->X(), node->Y(), node->Z() );
3330
3331         // smooth
3332         bool map2 = ( nodesNearSeam.find( node ) != nodesNearSeam.end() );
3333         if ( theSmoothMethod == LAPLACIAN )
3334           laplacianSmooth( node, surface, map2 ? uvMap2 : uvMap );
3335         else
3336           centroidalSmooth( node, surface, map2 ? uvMap2 : uvMap );
3337
3338         // node displacement
3339         gp_XYZ aNewPos ( node->X(), node->Y(), node->Z() );
3340         Standard_Real aDispl = (aPrevPos - aNewPos).SquareModulus();
3341         if ( aDispl > maxDisplacement )
3342           maxDisplacement = aDispl;
3343       }
3344       // no node movement => exit
3345       //if ( maxDisplacement < 1.e-16 ) {
3346       if ( maxDisplacement < disttol ) {
3347         MESSAGE("-- no node movement --");
3348         break;
3349       }
3350
3351       // check elements quality
3352       maxRatio  = 0;
3353       list< const SMDS_MeshElement* >::iterator elemIt = elemsOnFace.begin();
3354       for ( ; elemIt != elemsOnFace.end(); ++elemIt ) {
3355         const SMDS_MeshElement* elem = (*elemIt);
3356         if ( !elem || elem->GetType() != SMDSAbs_Face )
3357           continue;
3358         SMESH::Controls::TSequenceOfXYZ aPoints;
3359         if ( aQualityFunc.GetPoints( elem, aPoints )) {
3360           double aValue = aQualityFunc.GetValue( aPoints );
3361           if ( aValue > maxRatio )
3362             maxRatio = aValue;
3363         }
3364       }
3365       if ( maxRatio <= theTgtAspectRatio ) {
3366         MESSAGE("-- quality achived --");
3367         break;
3368       }
3369       if (it+1 == theNbIterations) {
3370         MESSAGE("-- Iteration limit exceeded --");
3371       }
3372     } // smoothing iterations
3373
3374     MESSAGE(" Face id: " << *fId <<
3375             " Nb iterstions: " << it <<
3376             " Displacement: " << maxDisplacement <<
3377             " Aspect Ratio " << maxRatio);
3378
3379     // ---------------------------------------
3380     // new nodes positions are computed,
3381     // record movement in DS and set new UV
3382     // ---------------------------------------
3383     nodeToMove = setMovableNodes.begin();
3384     for ( ; nodeToMove != setMovableNodes.end(); nodeToMove++ ) {
3385       SMDS_MeshNode* node = const_cast< SMDS_MeshNode* > (*nodeToMove);
3386       aMesh->MoveNode( node, node->X(), node->Y(), node->Z() );
3387       map< const SMDS_MeshNode*, gp_XY* >::iterator node_uv = uvMap.find( node );
3388       if ( node_uv != uvMap.end() ) {
3389         gp_XY* uv = node_uv->second;
3390         node->SetPosition
3391           ( SMDS_PositionPtr( new SMDS_FacePosition( uv->X(), uv->Y() )));
3392       }
3393     }
3394
3395     // move medium nodes of quadratic elements
3396     if ( isQuadratic )
3397     {
3398       SMESH_MesherHelper helper( *GetMesh() );
3399       if ( !face.IsNull() )
3400         helper.SetSubShape( face );
3401       list< const SMDS_MeshElement* >::iterator elemIt = elemsOnFace.begin();
3402       for ( ; elemIt != elemsOnFace.end(); ++elemIt ) {
3403         const SMDS_VtkFace* QF =
3404           dynamic_cast<const SMDS_VtkFace*> (*elemIt);
3405         if(QF && QF->IsQuadratic()) {
3406           vector<const SMDS_MeshNode*> Ns;
3407           Ns.reserve(QF->NbNodes()+1);
3408           SMDS_ElemIteratorPtr anIter = QF->interlacedNodesElemIterator();
3409           while ( anIter->more() )
3410             Ns.push_back( cast2Node(anIter->next()) );
3411           Ns.push_back( Ns[0] );
3412           double x, y, z;
3413           for(int i=0; i<QF->NbNodes(); i=i+2) {
3414             if ( !surface.IsNull() ) {
3415               gp_XY uv1 = helper.GetNodeUV( face, Ns[i], Ns[i+2] );
3416               gp_XY uv2 = helper.GetNodeUV( face, Ns[i+2], Ns[i] );
3417               gp_XY uv = ( uv1 + uv2 ) / 2.;
3418               gp_Pnt xyz = surface->Value( uv.X(), uv.Y() );
3419               x = xyz.X(); y = xyz.Y(); z = xyz.Z();
3420             }
3421             else {
3422               x = (Ns[i]->X() + Ns[i+2]->X())/2;
3423               y = (Ns[i]->Y() + Ns[i+2]->Y())/2;
3424               z = (Ns[i]->Z() + Ns[i+2]->Z())/2;
3425             }
3426             if( fabs( Ns[i+1]->X() - x ) > disttol ||
3427                 fabs( Ns[i+1]->Y() - y ) > disttol ||
3428                 fabs( Ns[i+1]->Z() - z ) > disttol ) {
3429               // we have to move i+1 node
3430               aMesh->MoveNode( Ns[i+1], x, y, z );
3431             }
3432           }
3433         }
3434       }
3435     }
3436
3437   } // loop on face ids
3438
3439 }
3440
3441 //=======================================================================
3442 //function : isReverse
3443 //purpose  : Return true if normal of prevNodes is not co-directied with
3444 //           gp_Vec(prevNodes[iNotSame],nextNodes[iNotSame]).
3445 //           iNotSame is where prevNodes and nextNodes are different.
3446 //           If result is true then future volume orientation is OK
3447 //=======================================================================
3448
3449 static bool isReverse(const SMDS_MeshElement*             face,
3450                       const vector<const SMDS_MeshNode*>& prevNodes,
3451                       const vector<const SMDS_MeshNode*>& nextNodes,
3452                       const int                           iNotSame)
3453 {
3454
3455   SMESH_TNodeXYZ pP = prevNodes[ iNotSame ];
3456   SMESH_TNodeXYZ pN = nextNodes[ iNotSame ];
3457   gp_XYZ extrDir( pN - pP ), faceNorm;
3458   SMESH_Algo::FaceNormal( face, faceNorm, /*normalized=*/false );
3459
3460   return faceNorm * extrDir < 0.0;
3461 }
3462
3463 //=======================================================================
3464 /*!
3465  * \brief Create elements by sweeping an element
3466  * \param elem - element to sweep
3467  * \param newNodesItVec - nodes generated from each node of the element
3468  * \param newElems - generated elements
3469  * \param nbSteps - number of sweeping steps
3470  * \param srcElements - to append elem for each generated element
3471  */
3472 //=======================================================================
3473
3474 void SMESH_MeshEditor::sweepElement(const SMDS_MeshElement*               elem,
3475                                     const vector<TNodeOfNodeListMapItr> & newNodesItVec,
3476                                     list<const SMDS_MeshElement*>&        newElems,
3477                                     const int                             nbSteps,
3478                                     SMESH_SequenceOfElemPtr&              srcElements)
3479 {
3480   //MESSAGE("sweepElement " << nbSteps);
3481   SMESHDS_Mesh* aMesh = GetMeshDS();
3482
3483   const int           nbNodes = elem->NbNodes();          
3484   const int         nbCorners = elem->NbCornerNodes();
3485   SMDSAbs_EntityType baseType = elem->GetEntityType(); /* it can change in case of 
3486                                                           polyhedron creation !!! */
3487   // Loop on elem nodes:
3488   // find new nodes and detect same nodes indices
3489   vector < list< const SMDS_MeshNode* >::const_iterator > itNN( nbNodes );
3490   vector<const SMDS_MeshNode*> prevNod( nbNodes );
3491   vector<const SMDS_MeshNode*> nextNod( nbNodes );
3492   vector<const SMDS_MeshNode*> midlNod( nbNodes );
3493
3494   int iNode, nbSame = 0, nbDouble = 0, iNotSameNode = 0;
3495   vector<int> sames(nbNodes);
3496   vector<bool> isSingleNode(nbNodes);
3497
3498   for ( iNode = 0; iNode < nbNodes; iNode++ ) {
3499     TNodeOfNodeListMapItr                        nnIt = newNodesItVec[ iNode ];
3500     const SMDS_MeshNode*                         node = nnIt->first;
3501     const list< const SMDS_MeshNode* > & listNewNodes = nnIt->second;
3502     if ( listNewNodes.empty() )
3503       return;
3504
3505     itNN   [ iNode ] = listNewNodes.begin();
3506     prevNod[ iNode ] = node;
3507     nextNod[ iNode ] = listNewNodes.front();
3508
3509     isSingleNode[iNode] = (listNewNodes.size()==nbSteps); /* medium node of quadratic or
3510                                                              corner node of linear */
3511     if ( prevNod[ iNode ] != nextNod [ iNode ])
3512       nbDouble += !isSingleNode[iNode];
3513
3514     if( iNode < nbCorners ) { // check corners only
3515       if ( prevNod[ iNode ] == nextNod [ iNode ])
3516         sames[nbSame++] = iNode;
3517       else
3518         iNotSameNode = iNode;
3519     }
3520   }
3521
3522   if ( nbSame == nbNodes || nbSame > 2) {
3523     MESSAGE( " Too many same nodes of element " << elem->GetID() );
3524     return;
3525   }
3526
3527   if ( elem->GetType() == SMDSAbs_Face && !isReverse( elem, prevNod, nextNod, iNotSameNode ))
3528   {
3529     // fix nodes order to have bottom normal external
3530     if ( baseType == SMDSEntity_Polygon )
3531     {
3532       std::reverse( itNN.begin(), itNN.end() );
3533       std::reverse( prevNod.begin(), prevNod.end() );
3534       std::reverse( midlNod.begin(), midlNod.end() );
3535       std::reverse( nextNod.begin(), nextNod.end() );
3536       std::reverse( isSingleNode.begin(), isSingleNode.end() );
3537     }
3538     else
3539     {
3540       const vector<int>& ind = SMDS_MeshCell::reverseSmdsOrder( baseType );
3541       SMDS_MeshCell::applyInterlace( ind, itNN );
3542       SMDS_MeshCell::applyInterlace( ind, prevNod );
3543       SMDS_MeshCell::applyInterlace( ind, nextNod );
3544       SMDS_MeshCell::applyInterlace( ind, midlNod );
3545       SMDS_MeshCell::applyInterlace( ind, isSingleNode );
3546       if ( nbSame > 0 )
3547       {
3548         sames[nbSame] = iNotSameNode;
3549         for ( int j = 0; j <= nbSame; ++j )
3550           for ( size_t i = 0; i < ind.size(); ++i )
3551             if ( ind[i] == sames[j] )
3552             {
3553               sames[j] = i;
3554               break;
3555             }
3556         iNotSameNode = sames[nbSame];
3557       }
3558     }
3559   }
3560
3561   int iSameNode = 0, iBeforeSame = 0, iAfterSame = 0, iOpposSame = 0;
3562   if ( nbSame > 0 ) {
3563     iSameNode    = sames[ nbSame-1 ];
3564     iBeforeSame  = ( iSameNode + nbCorners - 1 ) % nbCorners;
3565     iAfterSame   = ( iSameNode + 1 ) % nbCorners;
3566     iOpposSame   = ( iSameNode - 2 < 0  ? iSameNode + 2 : iSameNode - 2 );
3567   }
3568
3569   // make new elements
3570   for (int iStep = 0; iStep < nbSteps; iStep++ )
3571   {
3572     // get next nodes
3573     for ( iNode = 0; iNode < nbNodes; iNode++ )
3574     {
3575       midlNod[ iNode ] = isSingleNode[iNode] ? 0 : *itNN[ iNode ]++;
3576       nextNod[ iNode ] = *itNN[ iNode ]++;
3577     }
3578
3579     SMDS_MeshElement* aNewElem = 0;
3580     /*if(!elem->IsPoly())*/ {
3581       switch ( baseType ) {
3582       case SMDSEntity_0D:
3583       case SMDSEntity_Node: { // sweep NODE
3584         if ( nbSame == 0 ) {
3585           if ( isSingleNode[0] )
3586             aNewElem = aMesh->AddEdge( prevNod[ 0 ], nextNod[ 0 ] );
3587           else
3588             aNewElem = aMesh->AddEdge( prevNod[ 0 ], nextNod[ 0 ], midlNod[ 0 ] );
3589         }
3590         else
3591           return;
3592         break;
3593       }
3594       case SMDSEntity_Edge: { // sweep EDGE
3595         if ( nbDouble == 0 )
3596         {
3597           if ( nbSame == 0 ) // ---> quadrangle
3598             aNewElem = aMesh->AddFace(prevNod[ 0 ], prevNod[ 1 ],
3599                                       nextNod[ 1 ], nextNod[ 0 ] );
3600           else               // ---> triangle
3601             aNewElem = aMesh->AddFace(prevNod[ 0 ], prevNod[ 1 ],
3602                                       nextNod[ iNotSameNode ] );
3603         }
3604         else                 // ---> polygon
3605         {
3606           vector<const SMDS_MeshNode*> poly_nodes;
3607           poly_nodes.push_back( prevNod[0] );
3608           poly_nodes.push_back( prevNod[1] );
3609           if ( prevNod[1] != nextNod[1] )
3610           {
3611             if ( midlNod[1]) poly_nodes.push_back( midlNod[1]);
3612             poly_nodes.push_back( nextNod[1] );
3613           }
3614           if ( prevNod[0] != nextNod[0] )
3615           {
3616             poly_nodes.push_back( nextNod[0] );
3617             if ( midlNod[0]) poly_nodes.push_back( midlNod[0]);
3618           }
3619           switch ( poly_nodes.size() ) {
3620           case 3:
3621             aNewElem = aMesh->AddFace( poly_nodes[ 0 ], poly_nodes[ 1 ], poly_nodes[ 2 ]);
3622             break;
3623           case 4:
3624             aNewElem = aMesh->AddFace( poly_nodes[ 0 ], poly_nodes[ 1 ],
3625                                        poly_nodes[ 2 ], poly_nodes[ 3 ]);
3626             break;
3627           default:
3628             aNewElem = aMesh->AddPolygonalFace (poly_nodes);
3629           }
3630         }
3631         break;
3632       }
3633       case SMDSEntity_Triangle: // TRIANGLE --->
3634         {
3635           if ( nbDouble > 0 ) break;
3636           if ( nbSame == 0 )       // ---> pentahedron
3637             aNewElem = aMesh->AddVolume (prevNod[ 0 ], prevNod[ 1 ], prevNod[ 2 ],
3638                                          nextNod[ 0 ], nextNod[ 1 ], nextNod[ 2 ] );
3639
3640           else if ( nbSame == 1 )  // ---> pyramid
3641             aNewElem = aMesh->AddVolume (prevNod[ iBeforeSame ], prevNod[ iAfterSame ],
3642                                          nextNod[ iAfterSame ],  nextNod[ iBeforeSame ],
3643                                          nextNod[ iSameNode ]);
3644
3645           else // 2 same nodes:       ---> tetrahedron
3646             aNewElem = aMesh->AddVolume (prevNod[ 0 ], prevNod[ 1 ], prevNod[ 2 ],
3647                                          nextNod[ iNotSameNode ]);
3648           break;
3649         }
3650       case SMDSEntity_Quad_Edge: // sweep quadratic EDGE --->
3651         {
3652           if ( nbSame == 2 )
3653             return;
3654           if ( nbDouble+nbSame == 2 )
3655           {
3656             if(nbSame==0) {      // ---> quadratic quadrangle
3657               aNewElem = aMesh->AddFace(prevNod[0], prevNod[1], nextNod[1], nextNod[0],
3658                                         prevNod[2], midlNod[1], nextNod[2], midlNod[0]);
3659             }
3660             else { //(nbSame==1) // ---> quadratic triangle
3661               if(sames[0]==2) {
3662                 return; // medium node on axis
3663               }
3664               else if(sames[0]==0)
3665                 aNewElem = aMesh->AddFace(prevNod[0], nextNod[1], prevNod[1],
3666                                           nextNod[2], midlNod[1], prevNod[2]);
3667               else // sames[0]==1
3668                 aNewElem = aMesh->AddFace(prevNod[0], nextNod[0], prevNod[1],
3669                                           midlNod[0], nextNod[2], prevNod[2]);
3670             }
3671           }
3672           else if ( nbDouble == 3 )
3673           {
3674             if ( nbSame == 0 ) {  // ---> bi-quadratic quadrangle
3675               aNewElem = aMesh->AddFace(prevNod[0], prevNod[1], nextNod[1], nextNod[0],
3676                                         prevNod[2], midlNod[1], nextNod[2], midlNod[0], midlNod[2]);
3677             }
3678           }
3679           else
3680             return;
3681           break;
3682         }
3683       case SMDSEntity_Quadrangle: { // sweep QUADRANGLE --->
3684         if ( nbDouble > 0 ) break;
3685
3686         if ( nbSame == 0 )       // ---> hexahedron
3687           aNewElem = aMesh->AddVolume (prevNod[ 0 ], prevNod[ 1 ], prevNod[ 2 ], prevNod[ 3 ],
3688                                        nextNod[ 0 ], nextNod[ 1 ], nextNod[ 2 ], nextNod[ 3 ]);
3689
3690         else if ( nbSame == 1 ) { // ---> pyramid + pentahedron
3691           aNewElem = aMesh->AddVolume (prevNod[ iBeforeSame ], prevNod[ iAfterSame ],
3692                                        nextNod[ iAfterSame ],  nextNod[ iBeforeSame ],
3693                                        nextNod[ iSameNode ]);
3694           newElems.push_back( aNewElem );
3695           aNewElem = aMesh->AddVolume (prevNod[ iAfterSame ],  prevNod[ iOpposSame ],
3696                                        prevNod[ iBeforeSame ], nextNod[ iAfterSame ],
3697                                        nextNod[ iOpposSame ],  nextNod[ iBeforeSame ] );
3698         }
3699         else if ( nbSame == 2 ) { // ---> pentahedron
3700           if ( prevNod[ iBeforeSame ] == nextNod[ iBeforeSame ] )
3701             // iBeforeSame is same too
3702             aNewElem = aMesh->AddVolume (prevNod[ iBeforeSame ], prevNod[ iOpposSame ],
3703                                          nextNod[ iOpposSame ],  prevNod[ iSameNode ],
3704                                          prevNod[ iAfterSame ],  nextNod[ iAfterSame ]);
3705           else
3706             // iAfterSame is same too
3707             aNewElem = aMesh->AddVolume (prevNod[ iSameNode ],   prevNod[ iBeforeSame ],
3708                                          nextNod[ iBeforeSame ], prevNod[ iAfterSame ],
3709                                          prevNod[ iOpposSame ],  nextNod[ iOpposSame ]);
3710         }
3711         break;
3712       }
3713       case SMDSEntity_Quad_Triangle: { // sweep Quadratic TRIANGLE --->
3714         if ( nbDouble+nbSame != 3 ) break;
3715         if(nbSame==0) {
3716           // --->  pentahedron with 15 nodes
3717           aNewElem = aMesh->AddVolume (prevNod[0], prevNod[1], prevNod[2],
3718                                        nextNod[0], nextNod[1], nextNod[2],
3719                                        prevNod[3], prevNod[4], prevNod[5],
3720                                        nextNod[3], nextNod[4], nextNod[5],
3721                                        midlNod[0], midlNod[1], midlNod[2]);
3722         }
3723         else if(nbSame==1) {
3724           // --->  2d order pyramid of 13 nodes
3725           int apex = iSameNode;
3726           int i0 = ( apex + 1 ) % nbCorners;
3727           int i1 = ( apex - 1 + nbCorners ) % nbCorners;
3728           int i0a = apex + 3;
3729           int i1a = i1 + 3;
3730           int i01 = i0 + 3;
3731           aNewElem = aMesh->AddVolume(prevNod[i1], prevNod[i0],
3732                                       nextNod[i0], nextNod[i1], prevNod[apex],
3733                                       prevNod[i01], midlNod[i0],
3734                                       nextNod[i01], midlNod[i1],
3735                                       prevNod[i1a], prevNod[i0a],
3736                                       nextNod[i0a], nextNod[i1a]);
3737         }
3738         else if(nbSame==2) {
3739           // --->  2d order tetrahedron of 10 nodes
3740           int n1 = iNotSameNode;
3741           int n2 = ( n1 + 1             ) % nbCorners;
3742           int n3 = ( n1 + nbCorners - 1 ) % nbCorners;
3743           int n12 = n1 + 3;
3744           int n23 = n2 + 3;
3745           int n31 = n3 + 3;
3746           aNewElem = aMesh->AddVolume (prevNod[n1], prevNod[n2], prevNod[n3], nextNod[n1],
3747                                        prevNod[n12], prevNod[n23], prevNod[n31],
3748                                        midlNod[n1], nextNod[n12], nextNod[n31]);
3749         }
3750         break;
3751       }
3752       case SMDSEntity_Quad_Quadrangle: { // sweep Quadratic QUADRANGLE --->
3753         if ( nbDouble != 4 ) break;
3754         if( nbSame == 0 ) {
3755           // --->  hexahedron with 20 nodes
3756           aNewElem = aMesh->AddVolume (prevNod[0], prevNod[1], prevNod[2], prevNod[3],
3757                                        nextNod[0], nextNod[1], nextNod[2], nextNod[3],
3758                                        prevNod[4], prevNod[5], prevNod[6], prevNod[7],
3759                                        nextNod[4], nextNod[5], nextNod[6], nextNod[7],
3760                                        midlNod[0], midlNod[1], midlNod[2], midlNod[3]);
3761         }
3762         else if(nbSame==1) {
3763           // ---> pyramid + pentahedron - can not be created since it is needed 
3764           // additional middle node at the center of face
3765           INFOS( " Sweep for face " << elem->GetID() << " can not be created" );
3766           return;
3767         }
3768         else if( nbSame == 2 ) {
3769           // --->  2d order Pentahedron with 15 nodes
3770           int n1,n2,n4,n5;
3771           if ( prevNod[ iBeforeSame ] == nextNod[ iBeforeSame ] ) {
3772             // iBeforeSame is same too
3773             n1 = iBeforeSame;
3774             n2 = iOpposSame;
3775             n4 = iSameNode;
3776             n5 = iAfterSame;
3777           }
3778           else {
3779             // iAfterSame is same too
3780             n1 = iSameNode;
3781             n2 = iBeforeSame;
3782             n4 = iAfterSame;
3783             n5 = iOpposSame;
3784           }
3785           int n12 = n2 + 4;
3786           int n45 = n4 + 4;
3787           int n14 = n1 + 4;
3788           int n25 = n5 + 4;
3789           aNewElem = aMesh->AddVolume (prevNod[n1], prevNod[n2], nextNod[n2],
3790                                        prevNod[n4], prevNod[n5], nextNod[n5],
3791                                        prevNod[n12], midlNod[n2], nextNod[n12],
3792                                        prevNod[n45], midlNod[n5], nextNod[n45],
3793                                        prevNod[n14], prevNod[n25], nextNod[n25]);
3794         }
3795         break;
3796       }
3797       case SMDSEntity_BiQuad_Quadrangle: { // sweep BiQuadratic QUADRANGLE --->
3798
3799         if( nbSame == 0 && nbDouble == 9 ) {
3800           // --->  tri-quadratic hexahedron with 27 nodes
3801           aNewElem = aMesh->AddVolume (prevNod[0], prevNod[1], prevNod[2], prevNod[3],
3802                                        nextNod[0], nextNod[1], nextNod[2], nextNod[3],
3803                                        prevNod[4], prevNod[5], prevNod[6], prevNod[7],
3804                                        nextNod[4], nextNod[5], nextNod[6], nextNod[7],
3805                                        midlNod[0], midlNod[1], midlNod[2], midlNod[3],
3806                                        prevNod[8], // bottom center
3807                                        midlNod[4], midlNod[5], midlNod[6], midlNod[7],
3808                                        nextNod[8], // top center
3809                                        midlNod[8]);// elem center
3810         }
3811         else
3812         {
3813           return;
3814         }
3815         break;
3816       }
3817       case SMDSEntity_Polygon: { // sweep POLYGON
3818
3819         if ( nbNodes == 6 && nbSame == 0 && nbDouble == 0 ) {
3820           // --->  hexagonal prism
3821           aNewElem = aMesh->AddVolume (prevNod[0], prevNod[1], prevNod[2],
3822                                        prevNod[3], prevNod[4], prevNod[5],
3823                                        nextNod[0], nextNod[1], nextNod[2],
3824                                        nextNod[3], nextNod[4], nextNod[5]);
3825         }
3826         break;
3827       }
3828       default:
3829         break;
3830       }
3831     }
3832
3833     if ( !aNewElem && elem->GetType() == SMDSAbs_Face ) // try to create a polyherdal prism
3834     {
3835       if ( baseType != SMDSEntity_Polygon )
3836       {
3837         const std::vector<int>& ind = SMDS_MeshCell::interlacedSmdsOrder(baseType);
3838         SMDS_MeshCell::applyInterlace( ind, prevNod );
3839         SMDS_MeshCell::applyInterlace( ind, nextNod );
3840         SMDS_MeshCell::applyInterlace( ind, midlNod );
3841         SMDS_MeshCell::applyInterlace( ind, itNN );
3842         SMDS_MeshCell::applyInterlace( ind, isSingleNode );
3843         baseType = SMDSEntity_Polygon; // WARNING: change baseType !!!!
3844       }
3845       vector<const SMDS_MeshNode*> polyedre_nodes (nbNodes*2 + 4*nbNodes);
3846       vector<int> quantities (nbNodes + 2);
3847       polyedre_nodes.clear();
3848       quantities.clear();
3849
3850       // bottom of prism
3851       for (int inode = 0; inode < nbNodes; inode++)
3852         polyedre_nodes.push_back( prevNod[inode] );
3853       quantities.push_back( nbNodes );
3854
3855       // top of prism
3856       polyedre_nodes.push_back( nextNod[0] );
3857       for (int inode = nbNodes; inode-1; --inode )
3858         polyedre_nodes.push_back( nextNod[inode-1] );
3859       quantities.push_back( nbNodes );
3860
3861       // side faces
3862       for (int iface = 0; iface < nbNodes; iface++)
3863       {
3864         const int prevNbNodes = polyedre_nodes.size();
3865         int inextface = (iface+1) % nbNodes;
3866         polyedre_nodes.push_back( prevNod[inextface] );
3867         polyedre_nodes.push_back( prevNod[iface] );
3868         if ( prevNod[iface] != nextNod[iface] )
3869         {
3870           if ( midlNod[ iface ]) polyedre_nodes.push_back( midlNod[ iface ]);
3871           polyedre_nodes.push_back( nextNod[iface] );
3872         }
3873         if ( prevNod[inextface] != nextNod[inextface] )
3874         {
3875           polyedre_nodes.push_back( nextNod[inextface] );
3876           if ( midlNod[ inextface ]) polyedre_nodes.push_back( midlNod[ inextface ]);
3877         }
3878         const int nbFaceNodes = polyedre_nodes.size() - prevNbNodes;
3879         if ( nbFaceNodes > 2 )
3880           quantities.push_back( nbFaceNodes );
3881         else // degenerated face
3882           polyedre_nodes.resize( prevNbNodes );
3883       }
3884       aNewElem = aMesh->AddPolyhedralVolume (polyedre_nodes, quantities);
3885     }
3886
3887     if ( aNewElem ) {
3888       newElems.push_back( aNewElem );
3889       myLastCreatedElems.Append(aNewElem);
3890       srcElements.Append( elem );
3891     }
3892
3893     // set new prev nodes
3894     for ( iNode = 0; iNode < nbNodes; iNode++ )
3895       prevNod[ iNode ] = nextNod[ iNode ];
3896
3897   } // for steps
3898 }
3899
3900 //=======================================================================
3901 /*!
3902  * \brief Create 1D and 2D elements around swept elements
3903  * \param mapNewNodes - source nodes and ones generated from them
3904  * \param newElemsMap - source elements and ones generated from them
3905  * \param elemNewNodesMap - nodes generated from each node of each element
3906  * \param elemSet - all swept elements
3907  * \param nbSteps - number of sweeping steps
3908  * \param srcElements - to append elem for each generated element
3909  */
3910 //=======================================================================
3911
3912 void SMESH_MeshEditor::makeWalls (TNodeOfNodeListMap &     mapNewNodes,
3913                                   TElemOfElemListMap &     newElemsMap,
3914                                   TElemOfVecOfNnlmiMap &   elemNewNodesMap,
3915                                   TIDSortedElemSet&        elemSet,
3916                                   const int                nbSteps,
3917                                   SMESH_SequenceOfElemPtr& srcElements)
3918 {
3919   ASSERT( newElemsMap.size() == elemNewNodesMap.size() );
3920   SMESHDS_Mesh* aMesh = GetMeshDS();
3921
3922   // Find nodes belonging to only one initial element - sweep them to get edges.
3923
3924   TNodeOfNodeListMapItr nList = mapNewNodes.begin();
3925   for ( ; nList != mapNewNodes.end(); nList++ )
3926   {
3927     const SMDS_MeshNode* node =
3928       static_cast<const SMDS_MeshNode*>( nList->first );
3929     SMDS_ElemIteratorPtr eIt = node->GetInverseElementIterator();
3930     int nbInitElems = 0;
3931     const SMDS_MeshElement* el = 0;
3932     SMDSAbs_ElementType highType = SMDSAbs_Edge; // count most complex elements only
3933     while ( eIt->more() && nbInitElems < 2 ) {
3934       el = eIt->next();
3935       SMDSAbs_ElementType type = el->GetType();
3936       if ( type == SMDSAbs_Volume || type < highType ) continue;
3937       if ( type > highType ) {
3938         nbInitElems = 0;
3939         highType = type;
3940       }
3941       nbInitElems += elemSet.count(el);
3942     }
3943     if ( nbInitElems < 2 ) {
3944       bool NotCreateEdge = el && el->IsMediumNode(node);
3945       if(!NotCreateEdge) {
3946         vector<TNodeOfNodeListMapItr> newNodesItVec( 1, nList );
3947         list<const SMDS_MeshElement*> newEdges;
3948         sweepElement( node, newNodesItVec, newEdges, nbSteps, srcElements );
3949       }
3950     }
3951   }
3952
3953   // Make a ceiling for each element ie an equal element of last new nodes.
3954   // Find free links of faces - make edges and sweep them into faces.
3955
3956   TElemOfElemListMap::iterator   itElem      = newElemsMap.begin();
3957   TElemOfVecOfNnlmiMap::iterator itElemNodes = elemNewNodesMap.begin();
3958   for ( ; itElem != newElemsMap.end(); itElem++, itElemNodes++ )
3959   {
3960     const SMDS_MeshElement* elem = itElem->first;
3961     vector<TNodeOfNodeListMapItr>& vecNewNodes = itElemNodes->second;
3962
3963     if(itElem->second.size()==0) continue;
3964
3965     const bool isQuadratic = elem->IsQuadratic();
3966
3967     if ( elem->GetType() == SMDSAbs_Edge ) {
3968       // create a ceiling edge
3969       if ( !isQuadratic ) {
3970         if ( !aMesh->FindEdge( vecNewNodes[ 0 ]->second.back(),
3971                                vecNewNodes[ 1 ]->second.back())) {
3972           myLastCreatedElems.Append(aMesh->AddEdge(vecNewNodes[ 0 ]->second.back(),
3973                                                    vecNewNodes[ 1 ]->second.back()));
3974           srcElements.Append( myLastCreatedElems.Last() );
3975         }
3976       }
3977       else {
3978         if ( !aMesh->FindEdge( vecNewNodes[ 0 ]->second.back(),
3979                                vecNewNodes[ 1 ]->second.back(),
3980                                vecNewNodes[ 2 ]->second.back())) {
3981           myLastCreatedElems.Append(aMesh->AddEdge(vecNewNodes[ 0 ]->second.back(),
3982                                                    vecNewNodes[ 1 ]->second.back(),
3983                                                    vecNewNodes[ 2 ]->second.back()));
3984           srcElements.Append( myLastCreatedElems.Last() );
3985         }
3986       }
3987     }
3988     if ( elem->GetType() != SMDSAbs_Face )
3989       continue;
3990
3991     bool hasFreeLinks = false;
3992
3993     TIDSortedElemSet avoidSet;
3994     avoidSet.insert( elem );
3995
3996     set<const SMDS_MeshNode*> aFaceLastNodes;
3997     int iNode, nbNodes = vecNewNodes.size();
3998     if ( !isQuadratic ) {
3999       // loop on the face nodes
4000       for ( iNode = 0; iNode < nbNodes; iNode++ ) {
4001         aFaceLastNodes.insert( vecNewNodes[ iNode ]->second.back() );
4002         // look for free links of the face
4003         int iNext = ( iNode + 1 == nbNodes ) ? 0 : iNode + 1;
4004         const SMDS_MeshNode* n1 = vecNewNodes[ iNode ]->first;
4005         const SMDS_MeshNode* n2 = vecNewNodes[ iNext ]->first;
4006         // check if a link is free
4007         if ( ! SMESH_MeshEditor::FindFaceInSet ( n1, n2, elemSet, avoidSet )) {
4008           hasFreeLinks = true;
4009           // make an edge and a ceiling for a new edge
4010           if ( !aMesh->FindEdge( n1, n2 )) {
4011             myLastCreatedElems.Append(aMesh->AddEdge( n1, n2 )); // free link edge
4012             srcElements.Append( myLastCreatedElems.Last() );
4013           }
4014           n1 = vecNewNodes[ iNode ]->second.back();
4015           n2 = vecNewNodes[ iNext ]->second.back();
4016           if ( !aMesh->FindEdge( n1, n2 )) {
4017             myLastCreatedElems.Append(aMesh->AddEdge( n1, n2 )); // ceiling edge
4018             srcElements.Append( myLastCreatedElems.Last() );
4019           }
4020         }
4021       }
4022     }
4023     else { // elem is quadratic face
4024       int nbn = nbNodes/2;
4025       for ( iNode = 0; iNode < nbn; iNode++ ) {
4026         aFaceLastNodes.insert( vecNewNodes[ iNode ]->second.back() );
4027         int iNext = ( iNode + 1 == nbn ) ? 0 : iNode + 1;
4028         const SMDS_MeshNode* n1 = vecNewNodes[ iNode ]->first;
4029         const SMDS_MeshNode* n2 = vecNewNodes[ iNext ]->first;
4030         const SMDS_MeshNode* n3 = vecNewNodes[ iNode+nbn ]->first;
4031         // check if a link is free
4032         if ( ! SMESH_MeshEditor::FindFaceInSet ( n1, n2, elemSet, avoidSet ) &&
4033              ! SMESH_MeshEditor::FindFaceInSet ( n1, n3, elemSet, avoidSet ) &&
4034              ! SMESH_MeshEditor::FindFaceInSet ( n3, n2, elemSet, avoidSet ) ) {
4035           hasFreeLinks = true;
4036           // make an edge and a ceiling for a new edge
4037           // find medium node
4038           if ( !aMesh->FindEdge( n1, n2, n3 )) {
4039             myLastCreatedElems.Append(aMesh->AddEdge( n1, n2, n3 )); // free link edge
4040             srcElements.Append( myLastCreatedElems.Last() );
4041           }
4042           n1 = vecNewNodes[ iNode ]->second.back();
4043           n2 = vecNewNodes[ iNext ]->second.back();
4044           n3 = vecNewNodes[ iNode+nbn ]->second.back();
4045           if ( !aMesh->FindEdge( n1, n2, n3 )) {
4046             myLastCreatedElems.Append(aMesh->AddEdge( n1, n2, n3 )); // ceiling edge
4047             srcElements.Append( myLastCreatedElems.Last() );
4048           }
4049         }
4050       }
4051       for ( iNode = nbn; iNode < nbNodes; iNode++ ) {
4052         aFaceLastNodes.insert( vecNewNodes[ iNode ]->second.back() );
4053       }
4054     }
4055
4056     // sweep free links into faces
4057
4058     if ( hasFreeLinks )  {
4059       list<const SMDS_MeshElement*> & newVolumes = itElem->second;
4060       int iVol, volNb, nbVolumesByStep = newVolumes.size() / nbSteps;
4061
4062       set<const SMDS_MeshNode*> initNodeSet, topNodeSet, faceNodeSet;
4063       for ( iNode = 0; iNode < nbNodes; iNode++ ) {
4064         initNodeSet.insert( vecNewNodes[ iNode ]->first );
4065         topNodeSet .insert( vecNewNodes[ iNode ]->second.back() );
4066       }
4067       for ( volNb = 0; volNb < nbVolumesByStep; volNb++ ) {
4068         list<const SMDS_MeshElement*>::iterator v = newVolumes.begin();
4069         std::advance( v, volNb );
4070         // find indices of free faces of a volume and their source edges
4071         list< int > freeInd;
4072         list< const SMDS_MeshElement* > srcEdges; // source edges of free faces
4073         SMDS_VolumeTool vTool( *v, /*ignoreCentralNodes=*/false );
4074         int iF, nbF = vTool.NbFaces();
4075         for ( iF = 0; iF < nbF; iF ++ ) {
4076           if (vTool.IsFreeFace( iF ) &&
4077               vTool.GetFaceNodes( iF, faceNodeSet ) &&
4078               initNodeSet != faceNodeSet) // except an initial face
4079           {
4080             if ( nbSteps == 1 && faceNodeSet == topNodeSet )
4081               continue;
4082             freeInd.push_back( iF );
4083             // find source edge of a free face iF
4084             vector<const SMDS_MeshNode*> commonNodes; // shared by the initial and free faces
4085             commonNodes.resize( initNodeSet.size(), NULL ); // avoid spoiling memory
4086             std::set_intersection( faceNodeSet.begin(), faceNodeSet.end(),
4087                                    initNodeSet.begin(), initNodeSet.end(),
4088                                    commonNodes.begin());
4089             if ( (*v)->IsQuadratic() )
4090               srcEdges.push_back(aMesh->FindEdge (commonNodes[0],commonNodes[1],commonNodes[2]));
4091             else
4092               srcEdges.push_back(aMesh->FindEdge (commonNodes[0],commonNodes[1]));
4093 #ifdef _DEBUG_
4094             if ( !srcEdges.back() )
4095             {
4096               cout << "SMESH_MeshEditor::makeWalls(), no source edge found for a free face #"
4097                    << iF << " of volume #" << vTool.ID() << endl;
4098             }
4099 #endif
4100           }
4101         }
4102         if ( freeInd.empty() )
4103           continue;
4104
4105         // create faces for all steps;
4106         // if such a face has been already created by sweep of edge,
4107         // assure that its orientation is OK
4108         for ( int iStep = 0; iStep < nbSteps; iStep++ ) {
4109           vTool.Set( *v, /*ignoreCentralNodes=*/false );
4110           vTool.SetExternalNormal();
4111           const int nextShift = vTool.IsForward() ? +1 : -1;
4112           list< int >::iterator ind = freeInd.begin();
4113           list< const SMDS_MeshElement* >::iterator srcEdge = srcEdges.begin();
4114           for ( ; ind != freeInd.end(); ++ind, ++srcEdge ) // loop on free faces
4115           {
4116             const SMDS_MeshNode** nodes = vTool.GetFaceNodes( *ind );
4117             int nbn = vTool.NbFaceNodes( *ind );
4118             const SMDS_MeshElement * f = 0;
4119             if ( nbn == 3 )              ///// triangle
4120             {
4121               f = aMesh->FindFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ]);
4122               if ( !f ||
4123                    nodes[ 1 ] != f->GetNodeWrap( f->GetNodeIndex( nodes[ 0 ]) + nextShift ))
4124               {
4125                 const SMDS_MeshNode* newOrder[3] = { nodes[ 1 - nextShift ],
4126                                                      nodes[ 1 ],
4127                                                      nodes[ 1 + nextShift ] };
4128                 if ( f )
4129                   aMesh->ChangeElementNodes( f, &newOrder[0], nbn );
4130                 else
4131                   myLastCreatedElems.Append(aMesh->AddFace( newOrder[ 0 ], newOrder[ 1 ],
4132                                                             newOrder[ 2 ] ));
4133               }
4134             }
4135             else if ( nbn == 4 )       ///// quadrangle
4136             {
4137               f = aMesh->FindFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ], nodes[ 3 ]);
4138               if ( !f ||
4139                    nodes[ 1 ] != f->GetNodeWrap( f->GetNodeIndex( nodes[ 0 ]) + nextShift ))
4140               {
4141                 const SMDS_MeshNode* newOrder[4] = { nodes[ 0 ], nodes[ 2-nextShift ],
4142                                                      nodes[ 2 ], nodes[ 2+nextShift ] };
4143                 if ( f )
4144                   aMesh->ChangeElementNodes( f, &newOrder[0], nbn );
4145                 else
4146                   myLastCreatedElems.Append(aMesh->AddFace( newOrder[ 0 ], newOrder[ 1 ],
4147                                                             newOrder[ 2 ], newOrder[ 3 ]));
4148               }
4149             }
4150             else if ( nbn == 6 && isQuadratic ) /////// quadratic triangle
4151             {
4152               f = aMesh->FindFace( nodes[0], nodes[2], nodes[4], nodes[1], nodes[3], nodes[5] );
4153               if ( !f ||
4154                    nodes[2] != f->GetNodeWrap( f->GetNodeIndex( nodes[0] ) + 2*nextShift ))
4155               {
4156                 const SMDS_MeshNode* newOrder[6] = { nodes[2 - 2*nextShift],
4157                                                      nodes[2],
4158                                                      nodes[2 + 2*nextShift],
4159                                                      nodes[3 - 2*nextShift],
4160                                                      nodes[3],
4161                                                      nodes[3 + 2*nextShift]};
4162                 if ( f )
4163                   aMesh->ChangeElementNodes( f, &newOrder[0], nbn );
4164                 else
4165                   myLastCreatedElems.Append(aMesh->AddFace( newOrder[ 0 ],
4166                                                             newOrder[ 1 ],
4167                                                             newOrder[ 2 ],
4168                                                             newOrder[ 3 ],
4169                                                             newOrder[ 4 ],
4170                                                             newOrder[ 5 ] ));
4171               }
4172             }
4173             else if ( nbn == 8 && isQuadratic ) /////// quadratic quadrangle
4174             {
4175               f = aMesh->FindFace( nodes[0], nodes[2], nodes[4], nodes[6],
4176                                    nodes[1], nodes[3], nodes[5], nodes[7] );
4177               if ( !f ||
4178                    nodes[ 2 ] != f->GetNodeWrap( f->GetNodeIndex( nodes[ 0 ] ) + 2*nextShift ))
4179               {
4180                 const SMDS_MeshNode* newOrder[8] = { nodes[0],
4181                                                      nodes[4 - 2*nextShift],
4182                                                      nodes[4],
4183                                                      nodes[4 + 2*nextShift],
4184                                                      nodes[1],
4185                                                      nodes[5 - 2*nextShift],
4186                                                      nodes[5],
4187                                                      nodes[5 + 2*nextShift] };
4188                 if ( f )
4189                   aMesh->ChangeElementNodes( f, &newOrder[0], nbn );
4190                 else
4191                   myLastCreatedElems.Append(aMesh->AddFace(newOrder[ 0 ], newOrder[ 1 ],
4192                                                            newOrder[ 2 ], newOrder[ 3 ],
4193                                                            newOrder[ 4 ], newOrder[ 5 ],
4194                                                            newOrder[ 6 ], newOrder[ 7 ]));
4195               }
4196             }
4197             else if ( nbn == 9 && isQuadratic ) /////// bi-quadratic quadrangle
4198             {
4199               f = aMesh->FindElement( vector<const SMDS_MeshNode*>( nodes, nodes+nbn ),
4200                                       SMDSAbs_Face, /*noMedium=*/false);
4201               if ( !f ||
4202                    nodes[ 2 ] != f->GetNodeWrap( f->GetNodeIndex( nodes[ 0 ] ) + 2*nextShift ))
4203               {
4204                 const SMDS_MeshNode* newOrder[9] = { nodes[0],
4205                                                      nodes[4 - 2*nextShift],
4206                                                      nodes[4],
4207                                                      nodes[4 + 2*nextShift],
4208                                                      nodes[1],
4209                                                      nodes[5 - 2*nextShift],
4210                                                      nodes[5],
4211                                                      nodes[5 + 2*nextShift],
4212                                                      nodes[8] };
4213                 if ( f )
4214                   aMesh->ChangeElementNodes( f, &newOrder[0], nbn );
4215                 else
4216                   myLastCreatedElems.Append(aMesh->AddFace(newOrder[ 0 ], newOrder[ 1 ],
4217                                                            newOrder[ 2 ], newOrder[ 3 ],
4218                                                            newOrder[ 4 ], newOrder[ 5 ],
4219                                                            newOrder[ 6 ], newOrder[ 7 ],
4220                                                            newOrder[ 8 ]));
4221               }
4222             }
4223             else  //////// polygon
4224             {
4225               vector<const SMDS_MeshNode*> polygon_nodes ( nodes, nodes+nbn );
4226               const SMDS_MeshFace * f = aMesh->FindFace( polygon_nodes );
4227               if ( !f ||
4228                    nodes[ 1 ] != f->GetNodeWrap( f->GetNodeIndex( nodes[ 0 ] ) + nextShift ))
4229               {
4230                 if ( !vTool.IsForward() )
4231                   std::reverse( polygon_nodes.begin(), polygon_nodes.end());
4232                 if ( f )
4233                   aMesh->ChangeElementNodes( f, &polygon_nodes[0], nbn );
4234                 else
4235                   AddElement(polygon_nodes, SMDSAbs_Face, polygon_nodes.size()>4);
4236               }
4237             }
4238
4239             while ( srcElements.Length() < myLastCreatedElems.Length() )
4240               srcElements.Append( *srcEdge );
4241
4242           }  // loop on free faces
4243
4244           // go to the next volume
4245           iVol = 0;
4246           while ( iVol++ < nbVolumesByStep ) v++;
4247
4248         } // loop on steps
4249       } // loop on volumes of one step
4250     } // sweep free links into faces
4251
4252     // Make a ceiling face with a normal external to a volume
4253
4254     SMDS_VolumeTool lastVol( itElem->second.back(), /*ignoreCentralNodes=*/false );
4255
4256     int iF = lastVol.GetFaceIndex( aFaceLastNodes );
4257     if ( iF >= 0 ) {
4258       lastVol.SetExternalNormal();
4259       const SMDS_MeshNode** nodes = lastVol.GetFaceNodes( iF );
4260       int nbn = lastVol.NbFaceNodes( iF );
4261       if ( nbn == 3 ) {
4262         if (!hasFreeLinks ||
4263             !aMesh->FindFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ]))
4264           myLastCreatedElems.Append(aMesh->AddFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ] ));
4265       }
4266       else if ( nbn == 4 )
4267       {
4268         if (!hasFreeLinks ||
4269             !aMesh->FindFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ], nodes[ 3 ]))
4270           myLastCreatedElems.Append(aMesh->AddFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ], nodes[ 3 ]));
4271       }
4272       else if ( nbn == 6 && isQuadratic )
4273       {
4274         if (!hasFreeLinks ||
4275             !aMesh->FindFace(nodes[0], nodes[2], nodes[4], nodes[1], nodes[3], nodes[5]) )
4276           myLastCreatedElems.Append(aMesh->AddFace(nodes[0], nodes[2], nodes[4],
4277                                                    nodes[1], nodes[3], nodes[5]));
4278       }
4279       else if ( nbn == 8 && isQuadratic )
4280       {
4281         if (!hasFreeLinks ||
4282             !aMesh->FindFace(nodes[0], nodes[2], nodes[4], nodes[6],
4283                              nodes[1], nodes[3], nodes[5], nodes[7]) )
4284           myLastCreatedElems.Append(aMesh->AddFace(nodes[0], nodes[2], nodes[4], nodes[6],
4285                                                    nodes[1], nodes[3], nodes[5], nodes[7]));
4286       }
4287       else if ( nbn == 9 && isQuadratic )
4288       {
4289         if (!hasFreeLinks ||
4290             !aMesh->FindElement(vector<const SMDS_MeshNode*>( nodes, nodes+nbn ),
4291                                 SMDSAbs_Face, /*noMedium=*/false) )
4292           myLastCreatedElems.Append(aMesh->AddFace(nodes[0], nodes[2], nodes[4], nodes[6],
4293                                                    nodes[1], nodes[3], nodes[5], nodes[7],
4294                                                    nodes[8]));
4295       }
4296       else {
4297         vector<const SMDS_MeshNode*> polygon_nodes ( nodes, nodes + nbn );
4298         if (!hasFreeLinks || !aMesh->FindFace(polygon_nodes))
4299           myLastCreatedElems.Append(aMesh->AddPolygonalFace(polygon_nodes));
4300       }
4301
4302       while ( srcElements.Length() < myLastCreatedElems.Length() )
4303         srcElements.Append( myLastCreatedElems.Last() );
4304     }
4305   } // loop on swept elements
4306 }
4307
4308 //=======================================================================
4309 //function : RotationSweep
4310 //purpose  :
4311 //=======================================================================
4312
4313 SMESH_MeshEditor::PGroupIDs
4314 SMESH_MeshEditor::RotationSweep(TIDSortedElemSet & theElems,
4315                                 const gp_Ax1&      theAxis,
4316                                 const double       theAngle,
4317                                 const int          theNbSteps,
4318                                 const double       theTol,
4319                                 const bool         theMakeGroups,
4320                                 const bool         theMakeWalls)
4321 {
4322   myLastCreatedElems.Clear();
4323   myLastCreatedNodes.Clear();
4324
4325   // source elements for each generated one
4326   SMESH_SequenceOfElemPtr srcElems, srcNodes;
4327
4328   MESSAGE( "RotationSweep()");
4329   gp_Trsf aTrsf;
4330   aTrsf.SetRotation( theAxis, theAngle );
4331   gp_Trsf aTrsf2;
4332   aTrsf2.SetRotation( theAxis, theAngle/2. );
4333
4334   gp_Lin aLine( theAxis );
4335   double aSqTol = theTol * theTol;
4336
4337   SMESHDS_Mesh* aMesh = GetMeshDS();
4338
4339   TNodeOfNodeListMap mapNewNodes;
4340   TElemOfVecOfNnlmiMap mapElemNewNodes;
4341   TElemOfElemListMap newElemsMap;
4342
4343   const bool isQuadraticMesh = bool( myMesh->NbEdges(ORDER_QUADRATIC) +
4344                                      myMesh->NbFaces(ORDER_QUADRATIC) +
4345                                      myMesh->NbVolumes(ORDER_QUADRATIC) );
4346   // loop on theElems
4347   TIDSortedElemSet::iterator itElem;
4348   for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
4349     const SMDS_MeshElement* elem = *itElem;
4350     if ( !elem || elem->GetType() == SMDSAbs_Volume )
4351       continue;
4352     vector<TNodeOfNodeListMapItr> & newNodesItVec = mapElemNewNodes[ elem ];
4353     newNodesItVec.reserve( elem->NbNodes() );
4354
4355     // loop on elem nodes
4356     SMDS_ElemIteratorPtr itN = elem->nodesIterator();
4357     while ( itN->more() )
4358     {
4359       // check if a node has been already sweeped
4360       const SMDS_MeshNode* node = cast2Node( itN->next() );
4361
4362       gp_XYZ aXYZ( node->X(), node->Y(), node->Z() );
4363       double coord[3];
4364       aXYZ.Coord( coord[0], coord[1], coord[2] );
4365       bool isOnAxis = ( aLine.SquareDistance( aXYZ ) <= aSqTol );
4366
4367       TNodeOfNodeListMapItr nIt =
4368         mapNewNodes.insert( make_pair( node, list<const SMDS_MeshNode*>() )).first;
4369       list<const SMDS_MeshNode*>& listNewNodes = nIt->second;
4370       if ( listNewNodes.empty() )
4371       {
4372         // check if we are to create medium nodes between corner ones
4373         bool needMediumNodes = false;
4374         if ( isQuadraticMesh )
4375         {
4376           SMDS_ElemIteratorPtr it = node->GetInverseElementIterator();
4377           while (it->more() && !needMediumNodes )
4378           {
4379             const SMDS_MeshElement* invElem = it->next();
4380             if ( invElem != elem && !theElems.count( invElem )) continue;
4381             needMediumNodes = ( invElem->IsQuadratic() && !invElem->IsMediumNode(node) );
4382             if ( !needMediumNodes && invElem->GetEntityType() == SMDSEntity_BiQuad_Quadrangle )
4383               needMediumNodes = true;
4384           }
4385         }
4386
4387         // make new nodes
4388         const SMDS_MeshNode * newNode = node;
4389         for ( int i = 0; i < theNbSteps; i++ ) {
4390           if ( !isOnAxis ) {
4391             if ( needMediumNodes )  // create a medium node
4392             {
4393               aTrsf2.Transforms( coord[0], coord[1], coord[2] );
4394               newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
4395               myLastCreatedNodes.Append(newNode);
4396               srcNodes.Append( node );
4397               listNewNodes.push_back( newNode );
4398               aTrsf2.Transforms( coord[0], coord[1], coord[2] );
4399             }
4400             else {
4401               aTrsf.Transforms( coord[0], coord[1], coord[2] );
4402             }
4403             // create a corner node
4404             newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
4405             myLastCreatedNodes.Append(newNode);
4406             srcNodes.Append( node );
4407             listNewNodes.push_back( newNode );
4408           }
4409           else {
4410             listNewNodes.push_back( newNode );
4411             // if ( needMediumNodes )
4412             //   listNewNodes.push_back( newNode );
4413           }
4414         }
4415       }
4416       newNodesItVec.push_back( nIt );
4417     }
4418     // make new elements
4419     sweepElement( elem, newNodesItVec, newElemsMap[elem], theNbSteps, srcElems );
4420   }
4421
4422   if ( theMakeWalls )
4423     makeWalls( mapNewNodes, newElemsMap, mapElemNewNodes, theElems, theNbSteps, srcElems );
4424
4425   PGroupIDs newGroupIDs;
4426   if ( theMakeGroups )
4427     newGroupIDs = generateGroups( srcNodes, srcElems, "rotated");
4428
4429   return newGroupIDs;
4430 }
4431
4432
4433 //=======================================================================
4434 //function : CreateNode
4435 //purpose  :
4436 //=======================================================================
4437 const SMDS_MeshNode* SMESH_MeshEditor::CreateNode(const double x,
4438                                                   const double y,
4439                                                   const double z,
4440                                                   const double tolnode,
4441                                                   SMESH_SequenceOfNode& aNodes)
4442 {
4443   // myLastCreatedElems.Clear();
4444   // myLastCreatedNodes.Clear();
4445
4446   gp_Pnt P1(x,y,z);
4447   SMESHDS_Mesh * aMesh = myMesh->GetMeshDS();
4448
4449   // try to search in sequence of existing nodes
4450   // if aNodes.Length()>0 we 'nave to use given sequence
4451   // else - use all nodes of mesh
4452   if(aNodes.Length()>0) {
4453     int i;
4454     for(i=1; i<=aNodes.Length(); i++) {
4455       gp_Pnt P2(aNodes.Value(i)->X(),aNodes.Value(i)->Y(),aNodes.Value(i)->Z());
4456       if(P1.Distance(P2)<tolnode)
4457         return aNodes.Value(i);
4458     }
4459   }
4460   else {
4461     SMDS_NodeIteratorPtr itn = aMesh->nodesIterator();
4462     while(itn->more()) {
4463       const SMDS_MeshNode* aN = static_cast<const SMDS_MeshNode*> (itn->next());
4464       gp_Pnt P2(aN->X(),aN->Y(),aN->Z());
4465       if(P1.Distance(P2)<tolnode)
4466         return aN;
4467     }
4468   }
4469
4470   // create new node and return it
4471   const SMDS_MeshNode* NewNode = aMesh->AddNode(x,y,z);
4472   //myLastCreatedNodes.Append(NewNode);
4473   return NewNode;
4474 }
4475
4476
4477 //=======================================================================
4478 //function : ExtrusionSweep
4479 //purpose  :
4480 //=======================================================================
4481
4482 SMESH_MeshEditor::PGroupIDs
4483 SMESH_MeshEditor::ExtrusionSweep (TIDSortedElemSet &  theElems,
4484                                   const gp_Vec&       theStep,
4485                                   const int           theNbSteps,
4486                                   TElemOfElemListMap& newElemsMap,
4487                                   const bool          theMakeGroups,
4488                                   const int           theFlags,
4489                                   const double        theTolerance)
4490 {
4491   ExtrusParam aParams;
4492   aParams.myDir = gp_Dir(theStep);
4493   aParams.myNodes.Clear();
4494   aParams.mySteps = new TColStd_HSequenceOfReal;
4495   int i;
4496   for(i=1; i<=theNbSteps; i++)
4497     aParams.mySteps->Append(theStep.Magnitude());
4498
4499   return
4500     ExtrusionSweep(theElems,aParams,newElemsMap,theMakeGroups,theFlags,theTolerance);
4501 }
4502
4503
4504 //=======================================================================
4505 //function : ExtrusionSweep
4506 //purpose  :
4507 //=======================================================================
4508
4509 SMESH_MeshEditor::PGroupIDs
4510 SMESH_MeshEditor::ExtrusionSweep (TIDSortedElemSet &  theElems,
4511                                   ExtrusParam&        theParams,
4512                                   TElemOfElemListMap& newElemsMap,
4513                                   const bool          theMakeGroups,
4514                                   const int           theFlags,
4515                                   const double        theTolerance)
4516 {
4517   myLastCreatedElems.Clear();
4518   myLastCreatedNodes.Clear();
4519
4520   // source elements for each generated one
4521   SMESH_SequenceOfElemPtr srcElems, srcNodes;
4522
4523   SMESHDS_Mesh* aMesh = GetMeshDS();
4524
4525   int nbsteps = theParams.mySteps->Length();
4526
4527   TNodeOfNodeListMap mapNewNodes;
4528   //TNodeOfNodeVecMap mapNewNodes;
4529   TElemOfVecOfNnlmiMap mapElemNewNodes;
4530   //TElemOfVecOfMapNodesMap mapElemNewNodes;
4531
4532   const bool isQuadraticMesh = bool( myMesh->NbEdges(ORDER_QUADRATIC) +
4533                                      myMesh->NbFaces(ORDER_QUADRATIC) +
4534                                      myMesh->NbVolumes(ORDER_QUADRATIC) );
4535   // loop on theElems
4536   TIDSortedElemSet::iterator itElem;
4537   for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
4538     // check element type
4539     const SMDS_MeshElement* elem = *itElem;
4540     if ( !elem  || elem->GetType() == SMDSAbs_Volume )
4541       continue;
4542
4543     vector<TNodeOfNodeListMapItr> & newNodesItVec = mapElemNewNodes[ elem ];
4544     newNodesItVec.reserve( elem->NbNodes() );
4545
4546     // loop on elem nodes
4547     SMDS_ElemIteratorPtr itN = elem->nodesIterator();
4548     while ( itN->more() )
4549     {
4550       // check if a node has been already sweeped
4551       const SMDS_MeshNode* node = cast2Node( itN->next() );
4552       TNodeOfNodeListMap::iterator nIt =
4553         mapNewNodes.insert( make_pair( node, list<const SMDS_MeshNode*>() )).first;
4554       list<const SMDS_MeshNode*>& listNewNodes = nIt->second;
4555       if ( listNewNodes.empty() )
4556       {
4557         // make new nodes
4558
4559         // check if we are to create medium nodes between corner ones
4560         bool needMediumNodes = false;
4561         if ( isQuadraticMesh )
4562         {
4563           SMDS_ElemIteratorPtr it = node->GetInverseElementIterator();
4564           while (it->more() && !needMediumNodes )
4565           {
4566             const SMDS_MeshElement* invElem = it->next();
4567             if ( invElem != elem && !theElems.count( invElem )) continue;
4568             needMediumNodes = ( invElem->IsQuadratic() && !invElem->IsMediumNode(node) );
4569             if ( !needMediumNodes && invElem->GetEntityType() == SMDSEntity_BiQuad_Quadrangle )
4570               needMediumNodes = true;
4571           }
4572         }
4573
4574         double coord[] = { node->X(), node->Y(), node->Z() };
4575         for ( int i = 0; i < nbsteps; i++ )
4576         {
4577           if ( needMediumNodes ) // create a medium node
4578           {
4579             double x = coord[0] + theParams.myDir.X()*theParams.mySteps->Value(i+1)/2.;
4580             double y = coord[1] + theParams.myDir.Y()*theParams.mySteps->Value(i+1)/2.;
4581             double z = coord[2] + theParams.myDir.Z()*theParams.mySteps->Value(i+1)/2.;
4582             if( theFlags & EXTRUSION_FLAG_SEW ) {
4583               const SMDS_MeshNode * newNode = CreateNode(x, y, z,
4584                                                          theTolerance, theParams.myNodes);
4585               listNewNodes.push_back( newNode );
4586             }
4587             else {
4588               const SMDS_MeshNode * newNode = aMesh->AddNode(x, y, z);
4589               myLastCreatedNodes.Append(newNode);
4590               srcNodes.Append( node );
4591               listNewNodes.push_back( newNode );
4592             }
4593           }
4594           // create a corner node
4595           coord[0] = coord[0] + theParams.myDir.X()*theParams.mySteps->Value(i+1);
4596           coord[1] = coord[1] + theParams.myDir.Y()*theParams.mySteps->Value(i+1);
4597           coord[2] = coord[2] + theParams.myDir.Z()*theParams.mySteps->Value(i+1);
4598           if( theFlags & EXTRUSION_FLAG_SEW ) {
4599             const SMDS_MeshNode * newNode = CreateNode(coord[0], coord[1], coord[2],
4600                                                        theTolerance, theParams.myNodes);
4601             listNewNodes.push_back( newNode );
4602           }
4603           else {
4604             const SMDS_MeshNode * newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
4605             myLastCreatedNodes.Append(newNode);
4606             srcNodes.Append( node );
4607             listNewNodes.push_back( newNode );
4608           }
4609         }
4610       }
4611       newNodesItVec.push_back( nIt );
4612     }
4613     // make new elements
4614     sweepElement( elem, newNodesItVec, newElemsMap[elem], nbsteps, srcElems );
4615   }
4616
4617   if( theFlags & EXTRUSION_FLAG_BOUNDARY ) {
4618     makeWalls( mapNewNodes, newElemsMap, mapElemNewNodes, theElems, nbsteps, srcElems );
4619   }
4620   PGroupIDs newGroupIDs;
4621   if ( theMakeGroups )
4622     newGroupIDs = generateGroups( srcNodes, srcElems, "extruded");
4623
4624   return newGroupIDs;
4625 }
4626
4627 //=======================================================================
4628 //function : ExtrusionAlongTrack
4629 //purpose  :
4630 //=======================================================================
4631 SMESH_MeshEditor::Extrusion_Error
4632 SMESH_MeshEditor::ExtrusionAlongTrack (TIDSortedElemSet &   theElements,
4633                                        SMESH_subMesh*       theTrack,
4634                                        const SMDS_MeshNode* theN1,
4635                                        const bool           theHasAngles,
4636                                        list<double>&        theAngles,
4637                                        const bool           theLinearVariation,
4638                                        const bool           theHasRefPoint,
4639                                        const gp_Pnt&        theRefPoint,
4640                                        const bool           theMakeGroups)
4641 {
4642   MESSAGE("ExtrusionAlongTrack");
4643   myLastCreatedElems.Clear();
4644   myLastCreatedNodes.Clear();
4645
4646   int aNbE;
4647   std::list<double> aPrms;
4648   TIDSortedElemSet::iterator itElem;
4649
4650   gp_XYZ aGC;
4651   TopoDS_Edge aTrackEdge;
4652   TopoDS_Vertex aV1, aV2;
4653
4654   SMDS_ElemIteratorPtr aItE;
4655   SMDS_NodeIteratorPtr aItN;
4656   SMDSAbs_ElementType aTypeE;
4657
4658   TNodeOfNodeListMap mapNewNodes;
4659
4660   // 1. Check data
4661   aNbE = theElements.size();
4662   // nothing to do
4663   if ( !aNbE )
4664     return EXTR_NO_ELEMENTS;
4665
4666   // 1.1 Track Pattern
4667   ASSERT( theTrack );
4668
4669   SMESHDS_SubMesh* pSubMeshDS = theTrack->GetSubMeshDS();
4670
4671   aItE = pSubMeshDS->GetElements();
4672   while ( aItE->more() ) {
4673     const SMDS_MeshElement* pE = aItE->next();
4674     aTypeE = pE->GetType();
4675     // Pattern must contain links only
4676     if ( aTypeE != SMDSAbs_Edge )
4677       return EXTR_PATH_NOT_EDGE;
4678   }
4679
4680   list<SMESH_MeshEditor_PathPoint> fullList;
4681
4682   const TopoDS_Shape& aS = theTrack->GetSubShape();
4683   // Sub shape for the Pattern must be an Edge or Wire
4684   if( aS.ShapeType() == TopAbs_EDGE ) {
4685     aTrackEdge = TopoDS::Edge( aS );
4686     // the Edge must not be degenerated
4687     if ( BRep_Tool::Degenerated( aTrackEdge ) )
4688       return EXTR_BAD_PATH_SHAPE;
4689     TopExp::Vertices( aTrackEdge, aV1, aV2 );
4690     aItN = theTrack->GetFather()->GetSubMesh( aV1 )->GetSubMeshDS()->GetNodes();
4691     const SMDS_MeshNode* aN1 = aItN->next();
4692     aItN = theTrack->GetFather()->GetSubMesh( aV2 )->GetSubMeshDS()->GetNodes();
4693     const SMDS_MeshNode* aN2 = aItN->next();
4694     // starting node must be aN1 or aN2
4695     if ( !( aN1 == theN1 || aN2 == theN1 ) )
4696       return EXTR_BAD_STARTING_NODE;
4697     aItN = pSubMeshDS->GetNodes();
4698     while ( aItN->more() ) {
4699       const SMDS_MeshNode* pNode = aItN->next();
4700       const SMDS_EdgePosition* pEPos =
4701         static_cast<const SMDS_EdgePosition*>( pNode->GetPosition() );
4702       double aT = pEPos->GetUParameter();
4703       aPrms.push_back( aT );
4704     }
4705     //Extrusion_Error err =
4706     MakeEdgePathPoints(aPrms, aTrackEdge, (aN1==theN1), fullList);
4707   } else if( aS.ShapeType() == TopAbs_WIRE ) {
4708     list< SMESH_subMesh* > LSM;
4709     TopTools_SequenceOfShape Edges;
4710     SMESH_subMeshIteratorPtr itSM = theTrack->getDependsOnIterator(false,true);
4711     while(itSM->more()) {
4712       SMESH_subMesh* SM = itSM->next();
4713       LSM.push_back(SM);
4714       const TopoDS_Shape& aS = SM->GetSubShape();
4715       Edges.Append(aS);
4716     }
4717     list< list<SMESH_MeshEditor_PathPoint> > LLPPs;
4718     int startNid = theN1->GetID();
4719     TColStd_MapOfInteger UsedNums;
4720     
4721     int NbEdges = Edges.Length();
4722     int i = 1;
4723     for(; i<=NbEdges; i++) {
4724       int k = 0;
4725       list< SMESH_subMesh* >::iterator itLSM = LSM.begin();
4726       for(; itLSM!=LSM.end(); itLSM++) {
4727         k++;
4728         if(UsedNums.Contains(k)) continue;
4729         aTrackEdge = TopoDS::Edge( Edges.Value(k) );
4730         SMESH_subMesh* locTrack = *itLSM;
4731         SMESHDS_SubMesh* locMeshDS = locTrack->GetSubMeshDS();
4732         TopExp::Vertices( aTrackEdge, aV1, aV2 );
4733         aItN = locTrack->GetFather()->GetSubMesh(aV1)->GetSubMeshDS()->GetNodes();
4734         const SMDS_MeshNode* aN1 = aItN->next();
4735         aItN = locTrack->GetFather()->GetSubMesh(aV2)->GetSubMeshDS()->GetNodes();
4736         const SMDS_MeshNode* aN2 = aItN->next();
4737         // starting node must be aN1 or aN2
4738         if ( !( aN1->GetID() == startNid || aN2->GetID() == startNid ) ) continue;
4739         // 2. Collect parameters on the track edge
4740         aPrms.clear();
4741         aItN = locMeshDS->GetNodes();
4742         while ( aItN->more() ) {
4743           const SMDS_MeshNode* pNode = aItN->next();
4744           const SMDS_EdgePosition* pEPos =
4745             static_cast<const SMDS_EdgePosition*>( pNode->GetPosition() );
4746           double aT = pEPos->GetUParameter();
4747           aPrms.push_back( aT );
4748         }
4749         list<SMESH_MeshEditor_PathPoint> LPP;
4750         //Extrusion_Error err =
4751         MakeEdgePathPoints(aPrms, aTrackEdge,(aN1->GetID()==startNid), LPP);
4752         LLPPs.push_back(LPP);
4753         UsedNums.Add(k);
4754         // update startN for search following egde
4755         if( aN1->GetID() == startNid ) startNid = aN2->GetID();
4756         else startNid = aN1->GetID();
4757         break;
4758       }
4759     }
4760     list< list<SMESH_MeshEditor_PathPoint> >::iterator itLLPP = LLPPs.begin();
4761     list<SMESH_MeshEditor_PathPoint> firstList = *itLLPP;
4762     list<SMESH_MeshEditor_PathPoint>::iterator itPP = firstList.begin();
4763     for(; itPP!=firstList.end(); itPP++) {
4764       fullList.push_back( *itPP );
4765     }
4766     SMESH_MeshEditor_PathPoint PP1 = fullList.back();
4767     fullList.pop_back();
4768     itLLPP++;
4769     for(; itLLPP!=LLPPs.end(); itLLPP++) {
4770       list<SMESH_MeshEditor_PathPoint> currList = *itLLPP;
4771       itPP = currList.begin();
4772       SMESH_MeshEditor_PathPoint PP2 = currList.front();
4773       gp_Dir D1 = PP1.Tangent();
4774       gp_Dir D2 = PP2.Tangent();
4775       gp_Dir Dnew( gp_Vec( (D1.X()+D2.X())/2, (D1.Y()+D2.Y())/2,
4776                            (D1.Z()+D2.Z())/2 ) );
4777       PP1.SetTangent(Dnew);
4778       fullList.push_back(PP1);
4779       itPP++;
4780       for(; itPP!=firstList.end(); itPP++) {
4781         fullList.push_back( *itPP );
4782       }
4783       PP1 = fullList.back();
4784       fullList.pop_back();
4785     }
4786     // if wire not closed
4787     fullList.push_back(PP1);
4788     // else ???
4789   }
4790   else {
4791     return EXTR_BAD_PATH_SHAPE;
4792   }
4793
4794   return MakeExtrElements(theElements, fullList, theHasAngles, theAngles, theLinearVariation,
4795                           theHasRefPoint, theRefPoint, theMakeGroups);
4796 }
4797
4798
4799 //=======================================================================
4800 //function : ExtrusionAlongTrack
4801 //purpose  :
4802 //=======================================================================
4803 SMESH_MeshEditor::Extrusion_Error
4804 SMESH_MeshEditor::ExtrusionAlongTrack (TIDSortedElemSet &   theElements,
4805                                        SMESH_Mesh*          theTrack,
4806                                        const SMDS_MeshNode* theN1,
4807                                        const bool           theHasAngles,
4808                                        list<double>&        theAngles,
4809                                        const bool           theLinearVariation,
4810                                        const bool           theHasRefPoint,
4811                                        const gp_Pnt&        theRefPoint,
4812                                        const bool           theMakeGroups)
4813 {
4814   myLastCreatedElems.Clear();
4815   myLastCreatedNodes.Clear();
4816
4817   int aNbE;
4818   std::list<double> aPrms;
4819   TIDSortedElemSet::iterator itElem;
4820
4821   gp_XYZ aGC;
4822   TopoDS_Edge aTrackEdge;
4823   TopoDS_Vertex aV1, aV2;
4824
4825   SMDS_ElemIteratorPtr aItE;
4826   SMDS_NodeIteratorPtr aItN;
4827   SMDSAbs_ElementType aTypeE;
4828
4829   TNodeOfNodeListMap mapNewNodes;
4830
4831   // 1. Check data
4832   aNbE = theElements.size();
4833   // nothing to do
4834   if ( !aNbE )
4835     return EXTR_NO_ELEMENTS;
4836
4837   // 1.1 Track Pattern
4838   ASSERT( theTrack );
4839
4840   SMESHDS_Mesh* pMeshDS = theTrack->GetMeshDS();
4841
4842   aItE = pMeshDS->elementsIterator();
4843   while ( aItE->more() ) {
4844     const SMDS_MeshElement* pE = aItE->next();
4845     aTypeE = pE->GetType();
4846     // Pattern must contain links only
4847     if ( aTypeE != SMDSAbs_Edge )
4848       return EXTR_PATH_NOT_EDGE;
4849   }
4850
4851   list<SMESH_MeshEditor_PathPoint> fullList;
4852
4853   const TopoDS_Shape& aS = theTrack->GetShapeToMesh();
4854
4855   if( aS == SMESH_Mesh::PseudoShape() ) {
4856     //Mesh without shape
4857     const SMDS_MeshNode* currentNode = NULL;
4858     const SMDS_MeshNode* prevNode = theN1;
4859     std::vector<const SMDS_MeshNode*> aNodesList;
4860     aNodesList.push_back(theN1);
4861     int nbEdges = 0, conn=0;
4862     const SMDS_MeshElement* prevElem = NULL;
4863     const SMDS_MeshElement* currentElem = NULL;
4864     int totalNbEdges = theTrack->NbEdges();
4865     SMDS_ElemIteratorPtr nIt;
4866     bool isClosed = false;
4867
4868     //check start node
4869     if( !theTrack->GetMeshDS()->Contains(theN1) ) {
4870       return EXTR_BAD_STARTING_NODE;
4871     }
4872     
4873     conn = nbEdgeConnectivity(theN1);
4874     if(conn > 2)
4875       return EXTR_PATH_NOT_EDGE;
4876
4877     aItE = theN1->GetInverseElementIterator();
4878     prevElem = aItE->next();
4879     currentElem = prevElem;
4880     //Get all nodes
4881     if(totalNbEdges == 1 ) {
4882       nIt = currentElem->nodesIterator();
4883       currentNode = static_cast<const SMDS_MeshNode*>(nIt->next());
4884       if(currentNode == prevNode)
4885         currentNode = static_cast<const SMDS_MeshNode*>(nIt->next());
4886       aNodesList.push_back(currentNode);
4887     } else { 
4888       nIt = currentElem->nodesIterator();
4889       while( nIt->more() ) {
4890         currentNode = static_cast<const SMDS_MeshNode*>(nIt->next());
4891         if(currentNode == prevNode)
4892           currentNode = static_cast<const SMDS_MeshNode*>(nIt->next());
4893         aNodesList.push_back(currentNode);
4894         
4895         //case of the closed mesh
4896         if(currentNode == theN1) {
4897           nbEdges++;
4898           isClosed = true;
4899           break;
4900         }
4901
4902         conn = nbEdgeConnectivity(currentNode);
4903         if(conn > 2) {
4904           return EXTR_PATH_NOT_EDGE;    
4905         }else if( conn == 1 && nbEdges > 0 ) {
4906           //End of the path
4907           nbEdges++;
4908           break;
4909         }else {
4910           prevNode = currentNode;
4911           aItE = currentNode->GetInverseElementIterator();
4912           currentElem = aItE->next();
4913           if( currentElem  == prevElem)
4914             currentElem = aItE->next();
4915           nIt = currentElem->nodesIterator();
4916           prevElem = currentElem;
4917           nbEdges++;
4918         }
4919       }
4920     } 
4921     
4922     if(nbEdges != totalNbEdges)
4923       return EXTR_PATH_NOT_EDGE;
4924
4925     TopTools_SequenceOfShape Edges;
4926     double x1,x2,y1,y2,z1,z2;
4927     list< list<SMESH_MeshEditor_PathPoint> > LLPPs;
4928     int startNid = theN1->GetID();
4929     for(int i = 1; i < aNodesList.size(); i++) {
4930       x1 = aNodesList[i-1]->X();x2 = aNodesList[i]->X();
4931       y1 = aNodesList[i-1]->Y();y2 = aNodesList[i]->Y();
4932       z1 = aNodesList[i-1]->Z();z2 = aNodesList[i]->Z();
4933       TopoDS_Edge e = BRepBuilderAPI_MakeEdge(gp_Pnt(x1,y1,z1),gp_Pnt(x2,y2,z2));  
4934       list<SMESH_MeshEditor_PathPoint> LPP;
4935       aPrms.clear();
4936       MakeEdgePathPoints(aPrms, e, (aNodesList[i-1]->GetID()==startNid), LPP);
4937       LLPPs.push_back(LPP);
4938       if( aNodesList[i-1]->GetID() == startNid ) startNid = aNodesList[i]->GetID();
4939       else startNid = aNodesList[i-1]->GetID();
4940
4941     }
4942
4943     list< list<SMESH_MeshEditor_PathPoint> >::iterator itLLPP = LLPPs.begin();
4944     list<SMESH_MeshEditor_PathPoint> firstList = *itLLPP;
4945     list<SMESH_MeshEditor_PathPoint>::iterator itPP = firstList.begin();
4946     for(; itPP!=firstList.end(); itPP++) {
4947       fullList.push_back( *itPP );
4948     }
4949
4950     SMESH_MeshEditor_PathPoint PP1 = fullList.back();
4951     SMESH_MeshEditor_PathPoint PP2;
4952     fullList.pop_back();
4953     itLLPP++;
4954     for(; itLLPP!=LLPPs.end(); itLLPP++) {
4955       list<SMESH_MeshEditor_PathPoint> currList = *itLLPP;
4956       itPP = currList.begin();
4957       PP2 = currList.front();
4958       gp_Dir D1 = PP1.Tangent();
4959       gp_Dir D2 = PP2.Tangent();
4960       gp_Dir Dnew( gp_Vec( (D1.X()+D2.X())/2, (D1.Y()+D2.Y())/2,
4961                            (D1.Z()+D2.Z())/2 ) );
4962       PP1.SetTangent(Dnew);
4963       fullList.push_back(PP1);
4964       itPP++;
4965       for(; itPP!=currList.end(); itPP++) {
4966         fullList.push_back( *itPP );
4967       }
4968       PP1 = fullList.back();
4969       fullList.pop_back();
4970     }
4971     fullList.push_back(PP1);
4972     
4973   } // Sub shape for the Pattern must be an Edge or Wire
4974   else if( aS.ShapeType() == TopAbs_EDGE ) {
4975     aTrackEdge = TopoDS::Edge( aS );
4976     // the Edge must not be degenerated
4977     if ( BRep_Tool::Degenerated( aTrackEdge ) )
4978       return EXTR_BAD_PATH_SHAPE;
4979     TopExp::Vertices( aTrackEdge, aV1, aV2 );
4980     aItN = theTrack->GetSubMesh( aV1 )->GetSubMeshDS()->GetNodes();
4981     const SMDS_MeshNode* aN1 = aItN->next();
4982     aItN = theTrack->GetSubMesh( aV2 )->GetSubMeshDS()->GetNodes();
4983     const SMDS_MeshNode* aN2 = aItN->next();
4984     // starting node must be aN1 or aN2
4985     if ( !( aN1 == theN1 || aN2 == theN1 ) )
4986       return EXTR_BAD_STARTING_NODE;
4987     aItN = pMeshDS->nodesIterator();
4988     while ( aItN->more() ) {
4989       const SMDS_MeshNode* pNode = aItN->next();
4990       if( pNode==aN1 || pNode==aN2 ) continue;
4991       const SMDS_EdgePosition* pEPos =
4992         static_cast<const SMDS_EdgePosition*>( pNode->GetPosition() );
4993       double aT = pEPos->GetUParameter();
4994       aPrms.push_back( aT );
4995     }
4996     //Extrusion_Error err =
4997     MakeEdgePathPoints(aPrms, aTrackEdge, (aN1==theN1), fullList);
4998   }
4999   else if( aS.ShapeType() == TopAbs_WIRE ) {
5000     list< SMESH_subMesh* > LSM;
5001     TopTools_SequenceOfShape Edges;
5002     TopExp_Explorer eExp(aS, TopAbs_EDGE);
5003     for(; eExp.More(); eExp.Next()) {
5004       TopoDS_Edge E = TopoDS::Edge( eExp.Current() );
5005       if( BRep_Tool::Degenerated(E) ) continue;
5006       SMESH_subMesh* SM = theTrack->GetSubMesh(E);
5007       if(SM) {
5008         LSM.push_back(SM);
5009         Edges.Append(E);
5010       }
5011     }
5012     list< list<SMESH_MeshEditor_PathPoint> > LLPPs;
5013     int startNid = theN1->GetID();
5014     TColStd_MapOfInteger UsedNums;
5015     int NbEdges = Edges.Length();
5016     int i = 1;
5017     for(; i<=NbEdges; i++) {
5018       int k = 0;
5019       list< SMESH_subMesh* >::iterator itLSM = LSM.begin();
5020       for(; itLSM!=LSM.end(); itLSM++) {
5021         k++;
5022         if(UsedNums.Contains(k)) continue;
5023         aTrackEdge = TopoDS::Edge( Edges.Value(k) );
5024         SMESH_subMesh* locTrack = *itLSM;
5025         SMESHDS_SubMesh* locMeshDS = locTrack->GetSubMeshDS();
5026         TopExp::Vertices( aTrackEdge, aV1, aV2 );
5027         aItN = locTrack->GetFather()->GetSubMesh(aV1)->GetSubMeshDS()->GetNodes();
5028         const SMDS_MeshNode* aN1 = aItN->next();
5029         aItN = locTrack->GetFather()->GetSubMesh(aV2)->GetSubMeshDS()->GetNodes();
5030         const SMDS_MeshNode* aN2 = aItN->next();
5031         // starting node must be aN1 or aN2
5032         if ( !( aN1->GetID() == startNid || aN2->GetID() == startNid ) ) continue;
5033         // 2. Collect parameters on the track edge
5034         aPrms.clear();
5035         aItN = locMeshDS->GetNodes();
5036         while ( aItN->more() ) {
5037           const SMDS_MeshNode* pNode = aItN->next();
5038           const SMDS_EdgePosition* pEPos =
5039             static_cast<const SMDS_EdgePosition*>( pNode->GetPosition() );
5040           double aT = pEPos->GetUParameter();
5041           aPrms.push_back( aT );
5042         }
5043         list<SMESH_MeshEditor_PathPoint> LPP;
5044         //Extrusion_Error err =
5045         MakeEdgePathPoints(aPrms, aTrackEdge,(aN1->GetID()==startNid), LPP);
5046         LLPPs.push_back(LPP);
5047         UsedNums.Add(k);
5048         // update startN for search following egde
5049         if( aN1->GetID() == startNid ) startNid = aN2->GetID();
5050         else startNid = aN1->GetID();
5051         break;
5052       }
5053     }
5054     list< list<SMESH_MeshEditor_PathPoint> >::iterator itLLPP = LLPPs.begin();
5055     list<SMESH_MeshEditor_PathPoint> firstList = *itLLPP;
5056     list<SMESH_MeshEditor_PathPoint>::iterator itPP = firstList.begin();
5057     for(; itPP!=firstList.end(); itPP++) {
5058       fullList.push_back( *itPP );
5059     }
5060     SMESH_MeshEditor_PathPoint PP1 = fullList.back();
5061     fullList.pop_back();
5062     itLLPP++;
5063     for(; itLLPP!=LLPPs.end(); itLLPP++) {
5064       list<SMESH_MeshEditor_PathPoint> currList = *itLLPP;
5065       itPP = currList.begin();
5066       SMESH_MeshEditor_PathPoint PP2 = currList.front();
5067       gp_Dir D1 = PP1.Tangent();
5068       gp_Dir D2 = PP2.Tangent();
5069       gp_Dir Dnew( gp_Vec( (D1.X()+D2.X())/2, (D1.Y()+D2.Y())/2,
5070                            (D1.Z()+D2.Z())/2 ) );
5071       PP1.SetTangent(Dnew);
5072       fullList.push_back(PP1);
5073       itPP++;
5074       for(; itPP!=currList.end(); itPP++) {
5075         fullList.push_back( *itPP );
5076       }
5077       PP1 = fullList.back();
5078       fullList.pop_back();
5079     }
5080     // if wire not closed
5081     fullList.push_back(PP1);
5082     // else ???
5083   }
5084   else {
5085     return EXTR_BAD_PATH_SHAPE;
5086   }
5087
5088   return MakeExtrElements(theElements, fullList, theHasAngles, theAngles, theLinearVariation,
5089                           theHasRefPoint, theRefPoint, theMakeGroups);
5090 }
5091
5092
5093 //=======================================================================
5094 //function : MakeEdgePathPoints
5095 //purpose  : auxilary for ExtrusionAlongTrack
5096 //=======================================================================
5097 SMESH_MeshEditor::Extrusion_Error
5098 SMESH_MeshEditor::MakeEdgePathPoints(std::list<double>& aPrms,
5099                                      const TopoDS_Edge& aTrackEdge,
5100                                      bool FirstIsStart,
5101                                      list<SMESH_MeshEditor_PathPoint>& LPP)
5102 {
5103   Standard_Real aTx1, aTx2, aL2, aTolVec, aTolVec2;
5104   aTolVec=1.e-7;
5105   aTolVec2=aTolVec*aTolVec;
5106   double aT1, aT2;
5107   TopoDS_Vertex aV1, aV2;
5108   TopExp::Vertices( aTrackEdge, aV1, aV2 );
5109   aT1=BRep_Tool::Parameter( aV1, aTrackEdge );
5110   aT2=BRep_Tool::Parameter( aV2, aTrackEdge );
5111   // 2. Collect parameters on the track edge
5112   aPrms.push_front( aT1 );
5113   aPrms.push_back( aT2 );
5114   // sort parameters
5115   aPrms.sort();
5116   if( FirstIsStart ) {
5117     if ( aT1 > aT2 ) {
5118       aPrms.reverse();
5119     }
5120   }
5121   else {
5122     if ( aT2 > aT1 ) {
5123       aPrms.reverse();
5124     }
5125   }
5126   // 3. Path Points
5127   SMESH_MeshEditor_PathPoint aPP;
5128   Handle(Geom_Curve) aC3D = BRep_Tool::Curve( aTrackEdge, aTx1, aTx2 );
5129   std::list<double>::iterator aItD = aPrms.begin();
5130   for(; aItD != aPrms.end(); ++aItD) {
5131     double aT = *aItD;
5132     gp_Pnt aP3D;
5133     gp_Vec aVec;
5134     aC3D->D1( aT, aP3D, aVec );
5135     aL2 = aVec.SquareMagnitude();
5136     if ( aL2 < aTolVec2 )
5137       return EXTR_CANT_GET_TANGENT;
5138     gp_Dir aTgt( aVec );
5139     aPP.SetPnt( aP3D );
5140     aPP.SetTangent( aTgt );
5141     aPP.SetParameter( aT );
5142     LPP.push_back(aPP);
5143   }
5144   return EXTR_OK;
5145 }
5146
5147
5148 //=======================================================================
5149 //function : MakeExtrElements
5150 //purpose  : auxilary for ExtrusionAlongTrack
5151 //=======================================================================
5152 SMESH_MeshEditor::Extrusion_Error
5153 SMESH_MeshEditor::MakeExtrElements(TIDSortedElemSet&  theElements,
5154                                    list<SMESH_MeshEditor_PathPoint>& fullList,
5155                                    const bool theHasAngles,
5156                                    list<double>& theAngles,
5157                                    const bool theLinearVariation,
5158                                    const bool theHasRefPoint,
5159                                    const gp_Pnt& theRefPoint,
5160                                    const bool theMakeGroups)
5161 {
5162   MESSAGE("MakeExtrElements");
5163   //cout<<"MakeExtrElements  fullList.size() = "<<fullList.size()<<endl;
5164   int aNbTP = fullList.size();
5165   vector<SMESH_MeshEditor_PathPoint> aPPs(aNbTP);
5166   // Angles
5167   if( theHasAngles && theAngles.size()>0 && theLinearVariation ) {
5168     LinearAngleVariation(aNbTP-1, theAngles);
5169   }
5170   vector<double> aAngles( aNbTP );
5171   int j = 0;
5172   for(; j<aNbTP; ++j) {
5173     aAngles[j] = 0.;
5174   }
5175   if ( theHasAngles ) {
5176     double anAngle;;
5177     std::list<double>::iterator aItD = theAngles.begin();
5178     for ( j=1; (aItD != theAngles.end()) && (j<aNbTP); ++aItD, ++j ) {
5179       anAngle = *aItD;
5180       aAngles[j] = anAngle;
5181     }
5182   }
5183   // fill vector of path points with angles
5184   //aPPs.resize(fullList.size());
5185   j = -1;
5186   list<SMESH_MeshEditor_PathPoint>::iterator itPP = fullList.begin();
5187   for(; itPP!=fullList.end(); itPP++) {
5188     j++;
5189     SMESH_MeshEditor_PathPoint PP = *itPP;
5190     PP.SetAngle(aAngles[j]);
5191     aPPs[j] = PP;
5192   }
5193
5194   TNodeOfNodeListMap mapNewNodes;
5195   TElemOfVecOfNnlmiMap mapElemNewNodes;
5196   TElemOfElemListMap newElemsMap;
5197   TIDSortedElemSet::iterator itElem;
5198   double aX, aY, aZ;
5199   int aNb;
5200   SMDSAbs_ElementType aTypeE;
5201   // source elements for each generated one
5202   SMESH_SequenceOfElemPtr srcElems, srcNodes;
5203
5204   // 3. Center of rotation aV0
5205   gp_Pnt aV0 = theRefPoint;
5206   gp_XYZ aGC;
5207   if ( !theHasRefPoint ) {
5208     aNb = 0;
5209     aGC.SetCoord( 0.,0.,0. );
5210
5211     itElem = theElements.begin();
5212     for ( ; itElem != theElements.end(); itElem++ ) {
5213       const SMDS_MeshElement* elem = *itElem;
5214
5215       SMDS_ElemIteratorPtr itN = elem->nodesIterator();
5216       while ( itN->more() ) {
5217         const SMDS_MeshNode* node = static_cast<const SMDS_MeshNode*>( itN->next() );
5218         aX = node->X();
5219         aY = node->Y();
5220         aZ = node->Z();
5221
5222         if ( mapNewNodes.find( node ) == mapNewNodes.end() ) {
5223           list<const SMDS_MeshNode*> aLNx;
5224           mapNewNodes[node] = aLNx;
5225           //
5226           gp_XYZ aXYZ( aX, aY, aZ );
5227           aGC += aXYZ;
5228           ++aNb;
5229         }
5230       }
5231     }
5232     aGC /= aNb;
5233     aV0.SetXYZ( aGC );
5234   } // if (!theHasRefPoint) {
5235   mapNewNodes.clear();
5236
5237   // 4. Processing the elements
5238   SMESHDS_Mesh* aMesh = GetMeshDS();
5239
5240   for ( itElem = theElements.begin(); itElem != theElements.end(); itElem++ ) {
5241     // check element type
5242     const SMDS_MeshElement* elem = *itElem;
5243     aTypeE = elem->GetType();
5244     if ( !elem || ( aTypeE != SMDSAbs_Face && aTypeE != SMDSAbs_Edge ) )
5245       continue;
5246
5247     vector<TNodeOfNodeListMapItr> & newNodesItVec = mapElemNewNodes[ elem ];
5248     newNodesItVec.reserve( elem->NbNodes() );
5249
5250     // loop on elem nodes
5251     int nodeIndex = -1;
5252     SMDS_ElemIteratorPtr itN = elem->nodesIterator();
5253     while ( itN->more() )
5254     {
5255       ++nodeIndex;
5256       // check if a node has been already processed
5257       const SMDS_MeshNode* node =
5258         static_cast<const SMDS_MeshNode*>( itN->next() );
5259       TNodeOfNodeListMap::iterator nIt = mapNewNodes.find( node );
5260       if ( nIt == mapNewNodes.end() ) {
5261         nIt = mapNewNodes.insert( make_pair( node, list<const SMDS_MeshNode*>() )).first;
5262         list<const SMDS_MeshNode*>& listNewNodes = nIt->second;
5263
5264         // make new nodes
5265         aX = node->X();  aY = node->Y(); aZ = node->Z();
5266
5267         Standard_Real aAngle1x, aAngleT1T0, aTolAng;
5268         gp_Pnt aP0x, aP1x, aPN0, aPN1, aV0x, aV1x;
5269         gp_Ax1 anAx1, anAxT1T0;
5270         gp_Dir aDT1x, aDT0x, aDT1T0;
5271
5272         aTolAng=1.e-4;
5273
5274         aV0x = aV0;
5275         aPN0.SetCoord(aX, aY, aZ);
5276
5277         const SMESH_MeshEditor_PathPoint& aPP0 = aPPs[0];
5278         aP0x = aPP0.Pnt();
5279         aDT0x= aPP0.Tangent();
5280         //cout<<"j = 0   PP: Pnt("<<aP0x.X()<<","<<aP0x.Y()<<","<<aP0x.Z()<<")"<<endl;
5281
5282         for ( j = 1; j < aNbTP; ++j ) {
5283           const SMESH_MeshEditor_PathPoint& aPP1 = aPPs[j];
5284           aP1x = aPP1.Pnt();
5285           aDT1x = aPP1.Tangent();
5286           aAngle1x = aPP1.Angle();
5287
5288           gp_Trsf aTrsf, aTrsfRot, aTrsfRotT1T0;
5289           // Translation
5290           gp_Vec aV01x( aP0x, aP1x );
5291           aTrsf.SetTranslation( aV01x );
5292
5293           // traslated point
5294           aV1x = aV0x.Transformed( aTrsf );
5295           aPN1 = aPN0.Transformed( aTrsf );
5296
5297           // rotation 1 [ T1,T0 ]
5298           aAngleT1T0=-aDT1x.Angle( aDT0x );
5299           if (fabs(aAngleT1T0) > aTolAng) {
5300             aDT1T0=aDT1x^aDT0x;
5301             anAxT1T0.SetLocation( aV1x );
5302             anAxT1T0.SetDirection( aDT1T0 );
5303             aTrsfRotT1T0.SetRotation( anAxT1T0, aAngleT1T0 );
5304
5305             aPN1 = aPN1.Transformed( aTrsfRotT1T0 );
5306           }
5307
5308           // rotation 2
5309           if ( theHasAngles ) {
5310             anAx1.SetLocation( aV1x );
5311             anAx1.SetDirection( aDT1x );
5312             aTrsfRot.SetRotation( anAx1, aAngle1x );
5313
5314             aPN1 = aPN1.Transformed( aTrsfRot );
5315           }
5316
5317           // make new node
5318           //MESSAGE("elem->IsQuadratic " << elem->IsQuadratic() << " " << elem->IsMediumNode(node));
5319           if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
5320             // create additional node
5321             double x = ( aPN1.X() + aPN0.X() )/2.;
5322             double y = ( aPN1.Y() + aPN0.Y() )/2.;
5323             double z = ( aPN1.Z() + aPN0.Z() )/2.;
5324             const SMDS_MeshNode* newNode = aMesh->AddNode(x,y,z);
5325             myLastCreatedNodes.Append(newNode);
5326             srcNodes.Append( node );
5327             listNewNodes.push_back( newNode );
5328           }
5329           aX = aPN1.X();
5330           aY = aPN1.Y();
5331           aZ = aPN1.Z();
5332           const SMDS_MeshNode* newNode = aMesh->AddNode( aX, aY, aZ );
5333           myLastCreatedNodes.Append(newNode);
5334           srcNodes.Append( node );
5335           listNewNodes.push_back( newNode );
5336
5337           aPN0 = aPN1;
5338           aP0x = aP1x;
5339           aV0x = aV1x;
5340           aDT0x = aDT1x;
5341         }
5342       }
5343
5344       else {
5345         // if current elem is quadratic and current node is not medium
5346         // we have to check - may be it is needed to insert additional nodes
5347         if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
5348           list< const SMDS_MeshNode* > & listNewNodes = nIt->second;
5349           if(listNewNodes.size()==aNbTP-1) {
5350             vector<const SMDS_MeshNode*> aNodes(2*(aNbTP-1));
5351             gp_XYZ P(node->X(), node->Y(), node->Z());
5352             list< const SMDS_MeshNode* >::iterator it = listNewNodes.begin();
5353             int i;
5354             for(i=0; i<aNbTP-1; i++) {
5355               const SMDS_MeshNode* N = *it;
5356               double x = ( N->X() + P.X() )/2.;
5357               double y = ( N->Y() + P.Y() )/2.;
5358               double z = ( N->Z() + P.Z() )/2.;
5359               const SMDS_MeshNode* newN = aMesh->AddNode(x,y,z);
5360               srcNodes.Append( node );
5361               myLastCreatedNodes.Append(newN);
5362               aNodes[2*i] = newN;
5363               aNodes[2*i+1] = N;
5364               P = gp_XYZ(N->X(),N->Y(),N->Z());
5365             }
5366             listNewNodes.clear();
5367             for(i=0; i<2*(aNbTP-1); i++) {
5368               listNewNodes.push_back(aNodes[i]);
5369             }
5370           }
5371         }
5372       }
5373
5374       newNodesItVec.push_back( nIt );
5375     }
5376     // make new elements
5377     //sweepElement( aMesh, elem, newNodesItVec, newElemsMap[elem],
5378     //              newNodesItVec[0]->second.size(), myLastCreatedElems );
5379     sweepElement( elem, newNodesItVec, newElemsMap[elem], aNbTP-1, srcElems );
5380   }
5381
5382   makeWalls( mapNewNodes, newElemsMap, mapElemNewNodes, theElements, aNbTP-1, srcElems );
5383
5384   if ( theMakeGroups )
5385     generateGroups( srcNodes, srcElems, "extruded");
5386
5387   return EXTR_OK;
5388 }
5389
5390
5391 //=======================================================================
5392 //function : LinearAngleVariation
5393 //purpose  : auxilary for ExtrusionAlongTrack
5394 //=======================================================================
5395 void SMESH_MeshEditor::LinearAngleVariation(const int nbSteps,
5396                                             list<double>& Angles)
5397 {
5398   int nbAngles = Angles.size();
5399   if( nbSteps > nbAngles ) {
5400     vector<double> theAngles(nbAngles);
5401     list<double>::iterator it = Angles.begin();
5402     int i = -1;
5403     for(; it!=Angles.end(); it++) {
5404       i++;
5405       theAngles[i] = (*it);
5406     }
5407     list<double> res;
5408     double rAn2St = double( nbAngles ) / double( nbSteps );
5409     double angPrev = 0, angle;
5410     for ( int iSt = 0; iSt < nbSteps; ++iSt ) {
5411       double angCur = rAn2St * ( iSt+1 );
5412       double angCurFloor  = floor( angCur );
5413       double angPrevFloor = floor( angPrev );
5414       if ( angPrevFloor == angCurFloor )
5415         angle = rAn2St * theAngles[ int( angCurFloor ) ];
5416       else {
5417         int iP = int( angPrevFloor );
5418         double angPrevCeil = ceil(angPrev);
5419         angle = ( angPrevCeil - angPrev ) * theAngles[ iP ];
5420
5421         int iC = int( angCurFloor );
5422         if ( iC < nbAngles )
5423           angle += ( angCur - angCurFloor ) * theAngles[ iC ];
5424
5425         iP = int( angPrevCeil );
5426         while ( iC-- > iP )
5427           angle += theAngles[ iC ];
5428       }
5429       res.push_back(angle);
5430       angPrev = angCur;
5431     }
5432     Angles.clear();
5433     it = res.begin();
5434     for(; it!=res.end(); it++)
5435       Angles.push_back( *it );
5436   }
5437 }
5438
5439
5440 //================================================================================
5441 /*!
5442  * \brief Move or copy theElements applying theTrsf to their nodes
5443  *  \param theElems - elements to transform, if theElems is empty then apply to all mesh nodes
5444  *  \param theTrsf - transformation to apply
5445  *  \param theCopy - if true, create translated copies of theElems
5446  *  \param theMakeGroups - if true and theCopy, create translated groups
5447  *  \param theTargetMesh - mesh to copy translated elements into
5448  *  \return SMESH_MeshEditor::PGroupIDs - list of ids of created groups
5449  */
5450 //================================================================================
5451
5452 SMESH_MeshEditor::PGroupIDs
5453 SMESH_MeshEditor::Transform (TIDSortedElemSet & theElems,
5454                              const gp_Trsf&     theTrsf,
5455                              const bool         theCopy,
5456                              const bool         theMakeGroups,
5457                              SMESH_Mesh*        theTargetMesh)
5458 {
5459   myLastCreatedElems.Clear();
5460   myLastCreatedNodes.Clear();
5461
5462   bool needReverse = false;
5463   string groupPostfix;
5464   switch ( theTrsf.Form() ) {
5465   case gp_PntMirror:
5466     MESSAGE("gp_PntMirror");
5467     needReverse = true;
5468     groupPostfix = "mirrored";
5469     break;
5470   case gp_Ax1Mirror:
5471     MESSAGE("gp_Ax1Mirror");
5472     groupPostfix = "mirrored";
5473     break;
5474   case gp_Ax2Mirror:
5475     MESSAGE("gp_Ax2Mirror");
5476     needReverse = true;
5477     groupPostfix = "mirrored";
5478     break;
5479   case gp_Rotation:
5480     MESSAGE("gp_Rotation");
5481     groupPostfix = "rotated";
5482     break;
5483   case gp_Translation:
5484     MESSAGE("gp_Translation");
5485     groupPostfix = "translated";
5486     break;
5487   case gp_Scale:
5488     MESSAGE("gp_Scale");
5489     groupPostfix = "scaled";
5490     break;
5491   case gp_CompoundTrsf: // different scale by axis
5492     MESSAGE("gp_CompoundTrsf");
5493     groupPostfix = "scaled";
5494     break;
5495   default:
5496     MESSAGE("default");
5497     needReverse = false;
5498     groupPostfix = "transformed";
5499   }
5500
5501   SMESH_MeshEditor targetMeshEditor( theTargetMesh );
5502   SMESHDS_Mesh* aTgtMesh = theTargetMesh ? theTargetMesh->GetMeshDS() : 0;
5503   SMESHDS_Mesh* aMesh    = GetMeshDS();
5504
5505
5506   // map old node to new one
5507   TNodeNodeMap nodeMap;
5508
5509   // elements sharing moved nodes; those of them which have all
5510   // nodes mirrored but are not in theElems are to be reversed
5511   TIDSortedElemSet inverseElemSet;
5512
5513   // source elements for each generated one
5514   SMESH_SequenceOfElemPtr srcElems, srcNodes;
5515
5516   // issue 021015: EDF 1578 SMESH: Free nodes are removed when translating a mesh
5517   TIDSortedElemSet orphanNode;
5518
5519   if ( theElems.empty() ) // transform the whole mesh
5520   {
5521     // add all elements
5522     SMDS_ElemIteratorPtr eIt = aMesh->elementsIterator();
5523     while ( eIt->more() ) theElems.insert( eIt->next() );
5524     // add orphan nodes
5525     SMDS_NodeIteratorPtr nIt = aMesh->nodesIterator();
5526     while ( nIt->more() )
5527     {
5528       const SMDS_MeshNode* node = nIt->next();
5529       if ( node->NbInverseElements() == 0)
5530         orphanNode.insert( node );
5531     }
5532   }
5533
5534   // loop on elements to transform nodes : first orphan nodes then elems
5535   TIDSortedElemSet::iterator itElem;
5536   TIDSortedElemSet *elements[] = {&orphanNode, &theElems };
5537   for (int i=0; i<2; i++)
5538   for ( itElem = elements[i]->begin(); itElem != elements[i]->end(); itElem++ ) {
5539     const SMDS_MeshElement* elem = *itElem;
5540     if ( !elem )
5541       continue;
5542
5543     // loop on elem nodes
5544     SMDS_ElemIteratorPtr itN = elem->nodesIterator();
5545     while ( itN->more() ) {
5546
5547       const SMDS_MeshNode* node = cast2Node( itN->next() );
5548       // check if a node has been already transformed
5549       pair<TNodeNodeMap::iterator,bool> n2n_isnew =
5550         nodeMap.insert( make_pair ( node, node ));
5551       if ( !n2n_isnew.second )
5552         continue;
5553
5554       double coord[3];
5555       coord[0] = node->X();
5556       coord[1] = node->Y();
5557       coord[2] = node->Z();
5558       theTrsf.Transforms( coord[0], coord[1], coord[2] );
5559       if ( theTargetMesh ) {
5560         const SMDS_MeshNode * newNode = aTgtMesh->AddNode( coord[0], coord[1], coord[2] );
5561         n2n_isnew.first->second = newNode;
5562         myLastCreatedNodes.Append(newNode);
5563         srcNodes.Append( node );
5564       }
5565       else if ( theCopy ) {
5566         const SMDS_MeshNode * newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
5567         n2n_isnew.first->second = newNode;
5568         myLastCreatedNodes.Append(newNode);
5569         srcNodes.Append( node );
5570       }
5571       else {
5572         aMesh->MoveNode( node, coord[0], coord[1], coord[2] );
5573         // node position on shape becomes invalid
5574         const_cast< SMDS_MeshNode* > ( node )->SetPosition
5575           ( SMDS_SpacePosition::originSpacePosition() );
5576       }
5577
5578       // keep inverse elements
5579       if ( !theCopy && !theTargetMesh && needReverse ) {
5580         SMDS_ElemIteratorPtr invElemIt = node->GetInverseElementIterator();
5581         while ( invElemIt->more() ) {
5582           const SMDS_MeshElement* iel = invElemIt->next();
5583           inverseElemSet.insert( iel );
5584         }
5585       }
5586     }
5587   }
5588
5589   // either create new elements or reverse mirrored ones
5590   if ( !theCopy && !needReverse && !theTargetMesh )
5591     return PGroupIDs();
5592
5593   TIDSortedElemSet::iterator invElemIt = inverseElemSet.begin();
5594   for ( ; invElemIt != inverseElemSet.end(); invElemIt++ )
5595     theElems.insert( *invElemIt );
5596
5597   // Replicate or reverse elements
5598
5599   std::vector<int> iForw;
5600   for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ )
5601   {
5602     const SMDS_MeshElement* elem = *itElem;
5603     if ( !elem || elem->GetType() == SMDSAbs_Node )
5604       continue;
5605
5606     int nbNodes = elem->NbNodes();
5607     int elemType = elem->GetType();
5608
5609     if (elem->IsPoly()) {
5610
5611       // polygon or polyhedral volume
5612       switch ( elemType ) {
5613       case SMDSAbs_Face:
5614         {
5615           vector<const SMDS_MeshNode*> poly_nodes (nbNodes);
5616           int iNode = 0;
5617           SMDS_ElemIteratorPtr itN = elem->nodesIterator();
5618           while (itN->more()) {
5619             const SMDS_MeshNode* node =
5620               static_cast<const SMDS_MeshNode*>(itN->next());
5621             TNodeNodeMap::iterator nodeMapIt = nodeMap.find(node);
5622             if (nodeMapIt == nodeMap.end())
5623               break; // not all nodes transformed
5624             if (needReverse) {
5625               // reverse mirrored faces and volumes
5626               poly_nodes[nbNodes - iNode - 1] = (*nodeMapIt).second;
5627             } else {
5628               poly_nodes[iNode] = (*nodeMapIt).second;
5629             }
5630             iNode++;
5631           }
5632           if ( iNode != nbNodes )
5633             continue; // not all nodes transformed
5634
5635           if ( theTargetMesh ) {
5636             myLastCreatedElems.Append(aTgtMesh->AddPolygonalFace(poly_nodes));
5637             srcElems.Append( elem );
5638           }
5639           else if ( theCopy ) {
5640             myLastCreatedElems.Append(aMesh->AddPolygonalFace(poly_nodes));
5641             srcElems.Append( elem );
5642           }
5643           else {
5644             aMesh->ChangePolygonNodes(elem, poly_nodes);
5645           }
5646         }
5647         break;
5648       case SMDSAbs_Volume:
5649         {
5650           const SMDS_VtkVolume* aPolyedre =
5651             dynamic_cast<const SMDS_VtkVolume*>( elem );
5652           if (!aPolyedre) {
5653             MESSAGE("Warning: bad volumic element");
5654             continue;
5655           }
5656
5657           vector<const SMDS_MeshNode*> poly_nodes; poly_nodes.reserve( nbNodes );
5658           vector<int> quantities;
5659
5660           bool allTransformed = true;
5661           int nbFaces = aPolyedre->NbFaces();
5662           for (int iface = 1; iface <= nbFaces && allTransformed; iface++) {
5663             int nbFaceNodes = aPolyedre->NbFaceNodes(iface);
5664             for (int inode = 1; inode <= nbFaceNodes && allTransformed; inode++) {
5665               const SMDS_MeshNode* node = aPolyedre->GetFaceNode(iface, inode);
5666               TNodeNodeMap::iterator nodeMapIt = nodeMap.find(node);
5667               if (nodeMapIt == nodeMap.end()) {
5668                 allTransformed = false; // not all nodes transformed
5669               } else {
5670                 poly_nodes.push_back((*nodeMapIt).second);
5671               }
5672               if ( needReverse && allTransformed )
5673                 std::reverse( poly_nodes.end() - nbFaceNodes, poly_nodes.end() );
5674             }
5675             quantities.push_back(nbFaceNodes);
5676           }
5677           if ( !allTransformed )
5678             continue; // not all nodes transformed
5679
5680           if ( theTargetMesh ) {
5681             myLastCreatedElems.Append(aTgtMesh->AddPolyhedralVolume(poly_nodes, quantities));
5682             srcElems.Append( elem );
5683           }
5684           else if ( theCopy ) {
5685             myLastCreatedElems.Append(aMesh->AddPolyhedralVolume(poly_nodes, quantities));
5686             srcElems.Append( elem );
5687           }
5688           else {
5689             aMesh->ChangePolyhedronNodes(elem, poly_nodes, quantities);
5690           }
5691         }
5692         break;
5693       default:;
5694       }
5695       continue;
5696
5697     } // elem->isPoly()
5698
5699     // Regular elements
5700
5701     while ( iForw.size() < nbNodes ) iForw.push_back( iForw.size() );
5702     const std::vector<int>& iRev = SMDS_MeshCell::reverseSmdsOrder( elem->GetEntityType() );
5703     const std::vector<int>& i = needReverse ? iRev : iForw;
5704
5705     // find transformed nodes
5706     vector<const SMDS_MeshNode*> nodes(nbNodes);
5707     int iNode = 0;
5708     SMDS_ElemIteratorPtr itN = elem->nodesIterator();
5709     while ( itN->more() ) {
5710       const SMDS_MeshNode* node =
5711         static_cast<const SMDS_MeshNode*>( itN->next() );
5712       TNodeNodeMap::iterator nodeMapIt = nodeMap.find( node );
5713       if ( nodeMapIt == nodeMap.end() )
5714         break; // not all nodes transformed
5715       nodes[ i [ iNode++ ]] = (*nodeMapIt).second;
5716     }
5717     if ( iNode != nbNodes )
5718       continue; // not all nodes transformed
5719
5720     if ( theTargetMesh ) {
5721       if ( SMDS_MeshElement* copy =
5722            targetMeshEditor.AddElement( nodes, elem->GetType(), elem->IsPoly() )) {
5723         myLastCreatedElems.Append( copy );
5724         srcElems.Append( elem );
5725       }
5726     }
5727     else if ( theCopy ) {
5728       if ( AddElement( nodes, elem->GetType(), elem->IsPoly() ))
5729         srcElems.Append( elem );
5730     }
5731     else {
5732       // reverse element as it was reversed by transformation
5733       if ( nbNodes > 2 )
5734         aMesh->ChangeElementNodes( elem, &nodes[0], nbNodes );
5735     }
5736
5737   } // loop on elements
5738
5739   PGroupIDs newGroupIDs;
5740
5741   if ( ( theMakeGroups && theCopy ) ||
5742        ( theMakeGroups && theTargetMesh ) )
5743     newGroupIDs = generateGroups( srcNodes, srcElems, groupPostfix, theTargetMesh );
5744
5745   return newGroupIDs;
5746 }
5747
5748 //=======================================================================
5749 /*!
5750  * \brief Create groups of elements made during transformation
5751  * \param nodeGens - nodes making corresponding myLastCreatedNodes
5752  * \param elemGens - elements making corresponding myLastCreatedElems
5753  * \param postfix - to append to names of new groups
5754  */
5755 //=======================================================================
5756
5757 SMESH_MeshEditor::PGroupIDs
5758 SMESH_MeshEditor::generateGroups(const SMESH_SequenceOfElemPtr& nodeGens,
5759                                  const SMESH_SequenceOfElemPtr& elemGens,
5760                                  const std::string&             postfix,
5761                                  SMESH_Mesh*                    targetMesh)
5762 {
5763   PGroupIDs newGroupIDs( new list<int> );
5764   SMESH_Mesh* mesh = targetMesh ? targetMesh : GetMesh();
5765
5766   // Sort existing groups by types and collect their names
5767
5768   // to store an old group and a generated new one
5769   typedef pair< SMESHDS_GroupBase*, SMDS_MeshGroup* > TOldNewGroup;
5770   vector< list< TOldNewGroup > > groupsByType( SMDSAbs_NbElementTypes );
5771   // group names
5772   set< string > groupNames;
5773   //
5774   SMDS_MeshGroup* nullNewGroup = (SMDS_MeshGroup*) 0;
5775   SMESH_Mesh::GroupIteratorPtr groupIt = GetMesh()->GetGroups();
5776   while ( groupIt->more() ) {
5777     SMESH_Group * group = groupIt->next();
5778     if ( !group ) continue;
5779     SMESHDS_GroupBase* groupDS = group->GetGroupDS();
5780     if ( !groupDS || groupDS->IsEmpty() ) continue;
5781     groupNames.insert( group->GetName() );
5782     groupDS->SetStoreName( group->GetName() );
5783     groupsByType[ groupDS->GetType() ].push_back( make_pair( groupDS, nullNewGroup ));
5784   }
5785
5786   // Groups creation
5787
5788   // loop on nodes and elements
5789   for ( int isNodes = 0; isNodes < 2; ++isNodes )
5790   {
5791     const SMESH_SequenceOfElemPtr& gens  = isNodes ? nodeGens : elemGens;
5792     const SMESH_SequenceOfElemPtr& elems = isNodes ? myLastCreatedNodes : myLastCreatedElems;
5793     if ( gens.Length() != elems.Length() )
5794       throw SALOME_Exception(LOCALIZED("invalid args"));
5795
5796     // loop on created elements
5797     for (int iElem = 1; iElem <= elems.Length(); ++iElem )
5798     {
5799       const SMDS_MeshElement* sourceElem = gens( iElem );
5800       if ( !sourceElem ) {
5801         MESSAGE("generateGroups(): NULL source element");
5802         continue;
5803       }
5804       list< TOldNewGroup > & groupsOldNew = groupsByType[ sourceElem->GetType() ];
5805       if ( groupsOldNew.empty() ) {
5806         while ( iElem < gens.Length() && gens( iElem+1 ) == sourceElem )
5807           ++iElem; // skip all elements made by sourceElem
5808         continue;
5809       }
5810       // collect all elements made by sourceElem
5811       list< const SMDS_MeshElement* > resultElems;
5812       if ( const SMDS_MeshElement* resElem = elems( iElem ))
5813         if ( resElem != sourceElem )
5814           resultElems.push_back( resElem );
5815       while ( iElem < gens.Length() && gens( iElem+1 ) == sourceElem )
5816         if ( const SMDS_MeshElement* resElem = elems( ++iElem ))
5817           if ( resElem != sourceElem )
5818             resultElems.push_back( resElem );
5819       // do not generate element groups from node ones
5820       if ( sourceElem->GetType() == SMDSAbs_Node &&
5821            elems( iElem )->GetType() != SMDSAbs_Node )
5822         continue;
5823
5824       // add resultElems to groups made by ones the sourceElem belongs to
5825       list< TOldNewGroup >::iterator gOldNew, gLast = groupsOldNew.end();
5826       for ( gOldNew = groupsOldNew.begin(); gOldNew != gLast; ++gOldNew )
5827       {
5828         SMESHDS_GroupBase* oldGroup = gOldNew->first;
5829         if ( oldGroup->Contains( sourceElem )) // sourceElem in oldGroup
5830         {
5831           SMDS_MeshGroup* & newGroup = gOldNew->second;
5832           if ( !newGroup )// create a new group
5833           {
5834             // make a name
5835             string name = oldGroup->GetStoreName();
5836             if ( !targetMesh ) {
5837               name += "_";
5838               name += postfix;
5839               int nb = 0;
5840               while ( !groupNames.insert( name ).second ) // name exists
5841               {
5842                 if ( nb == 0 ) {
5843                   name += "_1";
5844                 }
5845                 else {
5846                   TCollection_AsciiString nbStr(nb+1);
5847                   name.resize( name.rfind('_')+1 );
5848                   name += nbStr.ToCString();
5849                 }
5850                 ++nb;
5851               }
5852             }
5853             // make a group
5854             int id;
5855             SMESH_Group* group = mesh->AddGroup( resultElems.back()->GetType(),
5856                                                  name.c_str(), id );
5857             SMESHDS_Group* groupDS = static_cast<SMESHDS_Group*>(group->GetGroupDS());
5858             newGroup = & groupDS->SMDSGroup();
5859             newGroupIDs->push_back( id );
5860           }
5861
5862           // fill in a new group
5863           list< const SMDS_MeshElement* >::iterator resLast = resultElems.end(), resElemIt;
5864           for ( resElemIt = resultElems.begin(); resElemIt != resLast; ++resElemIt )
5865             newGroup->Add( *resElemIt );
5866         }
5867       }
5868     } // loop on created elements
5869   }// loop on nodes and elements
5870
5871   return newGroupIDs;
5872 }
5873
5874 //================================================================================
5875 /*!
5876  * \brief Return list of group of nodes close to each other within theTolerance
5877  *        Search among theNodes or in the whole mesh if theNodes is empty using
5878  *        an Octree algorithm
5879  */
5880 //================================================================================
5881
5882 void SMESH_MeshEditor::FindCoincidentNodes (TIDSortedNodeSet &   theNodes,
5883                                             const double         theTolerance,
5884                                             TListOfListOfNodes & theGroupsOfNodes)
5885 {
5886   myLastCreatedElems.Clear();
5887   myLastCreatedNodes.Clear();
5888
5889   if ( theNodes.empty() )
5890   { // get all nodes in the mesh
5891     SMDS_NodeIteratorPtr nIt = GetMeshDS()->nodesIterator(/*idInceasingOrder=*/true);
5892     while ( nIt->more() )
5893       theNodes.insert( theNodes.end(),nIt->next());
5894   }
5895
5896   SMESH_OctreeNode::FindCoincidentNodes ( theNodes, &theGroupsOfNodes, theTolerance);
5897 }
5898
5899
5900 //=======================================================================
5901 /*!
5902  * \brief Implementation of search for the node closest to point
5903  */
5904 //=======================================================================
5905
5906 struct SMESH_NodeSearcherImpl: public SMESH_NodeSearcher
5907 {
5908   //---------------------------------------------------------------------
5909   /*!
5910    * \brief Constructor
5911    */
5912   SMESH_NodeSearcherImpl( const SMESHDS_Mesh* theMesh )
5913   {
5914     myMesh = ( SMESHDS_Mesh* ) theMesh;
5915
5916     TIDSortedNodeSet nodes;
5917     if ( theMesh ) {
5918       SMDS_NodeIteratorPtr nIt = theMesh->nodesIterator(/*idInceasingOrder=*/true);
5919       while ( nIt->more() )
5920         nodes.insert( nodes.end(), nIt->next() );
5921     }
5922     myOctreeNode = new SMESH_OctreeNode(nodes) ;
5923
5924     // get max size of a leaf box
5925     SMESH_OctreeNode* tree = myOctreeNode;
5926     while ( !tree->isLeaf() )
5927     {
5928       SMESH_OctreeNodeIteratorPtr cIt = tree->GetChildrenIterator();
5929       if ( cIt->more() )
5930         tree = cIt->next();
5931     }
5932     myHalfLeafSize = tree->maxSize() / 2.;
5933   }
5934
5935   //---------------------------------------------------------------------
5936   /*!
5937    * \brief Move node and update myOctreeNode accordingly
5938    */
5939   void MoveNode( const SMDS_MeshNode* node, const gp_Pnt& toPnt )
5940   {
5941     myOctreeNode->UpdateByMoveNode( node, toPnt );
5942     myMesh->MoveNode( node, toPnt.X(), toPnt.Y(), toPnt.Z() );
5943   }
5944
5945   //---------------------------------------------------------------------
5946   /*!
5947    * \brief Do it's job
5948    */
5949   const SMDS_MeshNode* FindClosestTo( const gp_Pnt& thePnt )
5950   {
5951     map<double, const SMDS_MeshNode*> dist2Nodes;
5952     myOctreeNode->NodesAround( thePnt.Coord(), dist2Nodes, myHalfLeafSize );
5953     if ( !dist2Nodes.empty() )
5954       return dist2Nodes.begin()->second;
5955     list<const SMDS_MeshNode*> nodes;
5956     //myOctreeNode->NodesAround( &tgtNode, &nodes, myHalfLeafSize );
5957
5958     double minSqDist = DBL_MAX;
5959     if ( nodes.empty() )  // get all nodes of OctreeNode's closest to thePnt
5960     {
5961       // sort leafs by their distance from thePnt
5962       typedef map< double, SMESH_OctreeNode* > TDistTreeMap;
5963       TDistTreeMap treeMap;
5964       list< SMESH_OctreeNode* > treeList;
5965       list< SMESH_OctreeNode* >::iterator trIt;
5966       treeList.push_back( myOctreeNode );
5967
5968       gp_XYZ pointNode( thePnt.X(), thePnt.Y(), thePnt.Z() );
5969       bool pointInside = myOctreeNode->isInside( pointNode, myHalfLeafSize );
5970       for ( trIt = treeList.begin(); trIt != treeList.end(); ++trIt)
5971       {
5972         SMESH_OctreeNode* tree = *trIt;
5973         if ( !tree->isLeaf() ) // put children to the queue
5974         {
5975           if ( pointInside && !tree->isInside( pointNode, myHalfLeafSize )) continue;
5976           SMESH_OctreeNodeIteratorPtr cIt = tree->GetChildrenIterator();
5977           while ( cIt->more() )
5978             treeList.push_back( cIt->next() );
5979         }
5980         else if ( tree->NbNodes() ) // put a tree to the treeMap
5981         {
5982           const Bnd_B3d& box = tree->getBox();
5983           double sqDist = thePnt.SquareDistance( 0.5 * ( box.CornerMin() + box.CornerMax() ));
5984           pair<TDistTreeMap::iterator,bool> it_in = treeMap.insert( make_pair( sqDist, tree ));
5985           if ( !it_in.second ) // not unique distance to box center
5986             treeMap.insert( it_in.first, make_pair( sqDist + 1e-13*treeMap.size(), tree ));
5987         }
5988       }
5989       // find distance after which there is no sense to check tree's
5990       double sqLimit = DBL_MAX;
5991       TDistTreeMap::iterator sqDist_tree = treeMap.begin();
5992       if ( treeMap.size() > 5 ) {
5993         SMESH_OctreeNode* closestTree = sqDist_tree->second;
5994         const Bnd_B3d& box = closestTree->getBox();
5995         double limit = sqrt( sqDist_tree->first ) + sqrt ( box.SquareExtent() );
5996         sqLimit = limit * limit;
5997       }
5998       // get all nodes from trees
5999       for ( ; sqDist_tree != treeMap.end(); ++sqDist_tree) {
6000         if ( sqDist_tree->first > sqLimit )
6001           break;
6002         SMESH_OctreeNode* tree = sqDist_tree->second;
6003         tree->NodesAround( tree->GetNodeIterator()->next(), &nodes );
6004       }
6005     }
6006     // find closest among nodes
6007     minSqDist = DBL_MAX;
6008     const SMDS_MeshNode* closestNode = 0;
6009     list<const SMDS_MeshNode*>::iterator nIt = nodes.begin();
6010     for ( ; nIt != nodes.end(); ++nIt ) {
6011       double sqDist = thePnt.SquareDistance( SMESH_TNodeXYZ( *nIt ) );
6012       if ( minSqDist > sqDist ) {
6013         closestNode = *nIt;
6014         minSqDist = sqDist;
6015       }
6016     }
6017     return closestNode;
6018   }
6019
6020   //---------------------------------------------------------------------
6021   /*!
6022    * \brief Destructor
6023    */
6024   ~SMESH_NodeSearcherImpl() { delete myOctreeNode; }
6025
6026   //---------------------------------------------------------------------
6027   /*!
6028    * \brief Return the node tree
6029    */
6030   const SMESH_OctreeNode* getTree() const { return myOctreeNode; }
6031
6032 private:
6033   SMESH_OctreeNode* myOctreeNode;
6034   SMESHDS_Mesh*     myMesh;
6035   double            myHalfLeafSize; // max size of a leaf box
6036 };
6037
6038 //=======================================================================
6039 /*!
6040  * \brief Return SMESH_NodeSearcher
6041  */
6042 //=======================================================================
6043
6044 SMESH_NodeSearcher* SMESH_MeshEditor::GetNodeSearcher() 
6045 {
6046   return new SMESH_NodeSearcherImpl( GetMeshDS() );
6047 }
6048
6049 // ========================================================================
6050 namespace // Utils used in SMESH_ElementSearcherImpl::FindElementsByPoint()
6051 {
6052   const int MaxNbElemsInLeaf = 10; // maximal number of elements in a leaf of tree
6053   const int MaxLevel         = 7;  // maximal tree height -> nb terminal boxes: 8^7 = 2097152
6054   const double NodeRadius = 1e-9;  // to enlarge bnd box of element
6055
6056   //=======================================================================
6057   /*!
6058    * \brief Octal tree of bounding boxes of elements
6059    */
6060   //=======================================================================
6061
6062   class ElementBndBoxTree : public SMESH_Octree
6063   {
6064   public:
6065
6066     ElementBndBoxTree(const SMDS_Mesh& mesh, SMDSAbs_ElementType elemType, SMDS_ElemIteratorPtr theElemIt = SMDS_ElemIteratorPtr(), double tolerance = NodeRadius );
6067     void getElementsNearPoint( const gp_Pnt& point, TIDSortedElemSet& foundElems);
6068     void getElementsNearLine ( const gp_Ax1& line, TIDSortedElemSet& foundElems);
6069     ~ElementBndBoxTree();
6070
6071   protected:
6072     ElementBndBoxTree() {}
6073     SMESH_Octree* allocateOctreeChild() const { return new ElementBndBoxTree; }
6074     void buildChildrenData();
6075     Bnd_B3d* buildRootBox();
6076   private:
6077     //!< Bounding box of element
6078     struct ElementBox : public Bnd_B3d
6079     {
6080       const SMDS_MeshElement* _element;
6081       int                     _refCount; // an ElementBox can be included in several tree branches
6082       ElementBox(const SMDS_MeshElement* elem, double tolerance);
6083     };
6084     vector< ElementBox* > _elements;
6085   };
6086
6087   //================================================================================
6088   /*!
6089    * \brief ElementBndBoxTree creation
6090    */
6091   //================================================================================
6092
6093   ElementBndBoxTree::ElementBndBoxTree(const SMDS_Mesh& mesh, SMDSAbs_ElementType elemType, SMDS_ElemIteratorPtr theElemIt, double tolerance)
6094     :SMESH_Octree( new SMESH_Octree::Limit( MaxLevel, /*minSize=*/0. ))
6095   {
6096     int nbElems = mesh.GetMeshInfo().NbElements( elemType );
6097     _elements.reserve( nbElems );
6098
6099     SMDS_ElemIteratorPtr elemIt = theElemIt ? theElemIt : mesh.elementsIterator( elemType );
6100     while ( elemIt->more() )
6101       _elements.push_back( new ElementBox( elemIt->next(),tolerance  ));
6102
6103     if ( _elements.size() > MaxNbElemsInLeaf )
6104       compute();
6105     else
6106       myIsLeaf = true;
6107   }
6108
6109   //================================================================================
6110   /*!
6111    * \brief Destructor
6112    */
6113   //================================================================================
6114
6115   ElementBndBoxTree::~ElementBndBoxTree()
6116   {
6117     for ( int i = 0; i < _elements.size(); ++i )
6118       if ( --_elements[i]->_refCount <= 0 )
6119         delete _elements[i];
6120   }
6121
6122   //================================================================================
6123   /*!
6124    * \brief Return the maximal box
6125    */
6126   //================================================================================
6127
6128   Bnd_B3d* ElementBndBoxTree::buildRootBox()
6129   {
6130     Bnd_B3d* box = new Bnd_B3d;
6131     for ( int i = 0; i < _elements.size(); ++i )
6132       box->Add( *_elements[i] );
6133     return box;
6134   }
6135
6136   //================================================================================
6137   /*!
6138    * \brief Redistrubute element boxes among children
6139    */
6140   //================================================================================
6141
6142   void ElementBndBoxTree::buildChildrenData()
6143   {
6144     for ( int i = 0; i < _elements.size(); ++i )
6145     {
6146       for (int j = 0; j < 8; j++)
6147       {
6148         if ( !_elements[i]->IsOut( myChildren[j]->getBox() ))
6149         {
6150           _elements[i]->_refCount++;
6151           ((ElementBndBoxTree*)myChildren[j])->_elements.push_back( _elements[i]);
6152         }
6153       }
6154       _elements[i]->_refCount--;
6155     }
6156     _elements.clear();
6157
6158     for (int j = 0; j < 8; j++)
6159     {
6160       ElementBndBoxTree* child = static_cast<ElementBndBoxTree*>( myChildren[j]);
6161       if ( child->_elements.size() <= MaxNbElemsInLeaf )
6162         child->myIsLeaf = true;
6163
6164       if ( child->_elements.capacity() - child->_elements.size() > 1000 )
6165         child->_elements.resize( child->_elements.size() ); // compact
6166     }
6167   }
6168
6169   //================================================================================
6170   /*!
6171    * \brief Return elements which can include the point
6172    */
6173   //================================================================================
6174
6175   void ElementBndBoxTree::getElementsNearPoint( const gp_Pnt&     point,
6176                                                 TIDSortedElemSet& foundElems)
6177   {
6178     if ( level() && getBox().IsOut( point.XYZ() ))
6179       return;
6180
6181     if ( isLeaf() )
6182     {
6183       for ( int i = 0; i < _elements.size(); ++i )
6184         if ( !_elements[i]->IsOut( point.XYZ() ))
6185           foundElems.insert( _elements[i]->_element );
6186     }
6187     else
6188     {
6189       for (int i = 0; i < 8; i++)
6190         ((ElementBndBoxTree*) myChildren[i])->getElementsNearPoint( point, foundElems );
6191     }
6192   }
6193
6194   //================================================================================
6195   /*!
6196    * \brief Return elements which can be intersected by the line
6197    */
6198   //================================================================================
6199
6200   void ElementBndBoxTree::getElementsNearLine( const gp_Ax1&     line,
6201                                                TIDSortedElemSet& foundElems)
6202   {
6203     if ( level() && getBox().IsOut( line ))
6204       return;
6205
6206     if ( isLeaf() )
6207     {
6208       for ( int i = 0; i < _elements.size(); ++i )
6209         if ( !_elements[i]->IsOut( line ))
6210           foundElems.insert( _elements[i]->_element );
6211     }
6212     else
6213     {
6214       for (int i = 0; i < 8; i++)
6215         ((ElementBndBoxTree*) myChildren[i])->getElementsNearLine( line, foundElems );
6216     }
6217   }
6218
6219   //================================================================================
6220   /*!
6221    * \brief Construct the element box
6222    */
6223   //================================================================================
6224
6225   ElementBndBoxTree::ElementBox::ElementBox(const SMDS_MeshElement* elem, double tolerance)
6226   {
6227     _element  = elem;
6228     _refCount = 1;
6229     SMDS_ElemIteratorPtr nIt = elem->nodesIterator();
6230     while ( nIt->more() )
6231       Add( SMESH_TNodeXYZ( cast2Node( nIt->next() )));
6232     Enlarge( tolerance );
6233   }
6234
6235 } // namespace
6236
6237 //=======================================================================
6238 /*!
6239  * \brief Implementation of search for the elements by point and
6240  *        of classification of point in 2D mesh
6241  */
6242 //=======================================================================
6243
6244 struct SMESH_ElementSearcherImpl: public SMESH_ElementSearcher
6245 {
6246   SMESHDS_Mesh*                _mesh;
6247   SMDS_ElemIteratorPtr         _meshPartIt;
6248   ElementBndBoxTree*           _ebbTree;
6249   SMESH_NodeSearcherImpl*      _nodeSearcher;
6250   SMDSAbs_ElementType          _elementType;
6251   double                       _tolerance;
6252   bool                         _outerFacesFound;
6253   set<const SMDS_MeshElement*> _outerFaces; // empty means "no internal faces at all"
6254
6255   SMESH_ElementSearcherImpl( SMESHDS_Mesh& mesh, SMDS_ElemIteratorPtr elemIt=SMDS_ElemIteratorPtr())
6256     : _mesh(&mesh),_meshPartIt(elemIt),_ebbTree(0),_nodeSearcher(0),_tolerance(-1),_outerFacesFound(false) {}
6257   ~SMESH_ElementSearcherImpl()
6258   {
6259     if ( _ebbTree )      delete _ebbTree;      _ebbTree      = 0;
6260     if ( _nodeSearcher ) delete _nodeSearcher; _nodeSearcher = 0;
6261   }
6262   virtual int FindElementsByPoint(const gp_Pnt&                      point,
6263                                   SMDSAbs_ElementType                type,
6264                                   vector< const SMDS_MeshElement* >& foundElements);
6265   virtual TopAbs_State GetPointState(const gp_Pnt& point);
6266
6267   void GetElementsNearLine( const gp_Ax1&                      line,
6268                             SMDSAbs_ElementType                type,
6269                             vector< const SMDS_MeshElement* >& foundElems);
6270   double getTolerance();
6271   bool getIntersParamOnLine(const gp_Lin& line, const SMDS_MeshElement* face,
6272                             const double tolerance, double & param);
6273   void findOuterBoundary(const SMDS_MeshElement* anyOuterFace);
6274   bool isOuterBoundary(const SMDS_MeshElement* face) const
6275   {
6276     return _outerFaces.empty() || _outerFaces.count(face);
6277   }
6278   struct TInters //!< data of intersection of the line and the mesh face (used in GetPointState())
6279   {
6280     const SMDS_MeshElement* _face;
6281     gp_Vec                  _faceNorm;
6282     bool                    _coincides; //!< the line lays in face plane
6283     TInters(const SMDS_MeshElement* face, const gp_Vec& faceNorm, bool coinc=false)
6284       : _face(face), _faceNorm( faceNorm ), _coincides( coinc ) {}
6285   };
6286   struct TFaceLink //!< link and faces sharing it (used in findOuterBoundary())
6287   {
6288     SMESH_TLink      _link;
6289     TIDSortedElemSet _faces;
6290     TFaceLink( const SMDS_MeshNode* n1, const SMDS_MeshNode* n2, const SMDS_MeshElement* face)
6291       : _link( n1, n2 ), _faces( &face, &face + 1) {}
6292   };
6293 };
6294
6295 ostream& operator<< (ostream& out, const SMESH_ElementSearcherImpl::TInters& i)
6296 {
6297   return out << "TInters(face=" << ( i._face ? i._face->GetID() : 0)
6298              << ", _coincides="<<i._coincides << ")";
6299 }
6300
6301 //=======================================================================
6302 /*!
6303  * \brief define tolerance for search
6304  */
6305 //=======================================================================
6306
6307 double SMESH_ElementSearcherImpl::getTolerance()
6308 {
6309   if ( _tolerance < 0 )
6310   {
6311     const SMDS_MeshInfo& meshInfo = _mesh->GetMeshInfo();
6312
6313     _tolerance = 0;
6314     if ( _nodeSearcher && meshInfo.NbNodes() > 1 )
6315     {
6316       double boxSize = _nodeSearcher->getTree()->maxSize();
6317       _tolerance = 1e-8 * boxSize/* / meshInfo.NbNodes()*/;
6318     }
6319     else if ( _ebbTree && meshInfo.NbElements() > 0 )
6320     {
6321       double boxSize = _ebbTree->maxSize();
6322       _tolerance = 1e-8 * boxSize/* / meshInfo.NbElements()*/;
6323     }
6324     if ( _tolerance == 0 )
6325     {
6326       // define tolerance by size of a most complex element
6327       int complexType = SMDSAbs_Volume;
6328       while ( complexType > SMDSAbs_All &&
6329               meshInfo.NbElements( SMDSAbs_ElementType( complexType )) < 1 )
6330         --complexType;
6331       if ( complexType == SMDSAbs_All ) return 0; // empty mesh
6332       double elemSize;
6333       if ( complexType == int( SMDSAbs_Node ))
6334       {
6335         SMDS_NodeIteratorPtr nodeIt = _mesh->nodesIterator();
6336         elemSize = 1;
6337         if ( meshInfo.NbNodes() > 2 )
6338           elemSize = SMESH_TNodeXYZ( nodeIt->next() ).Distance( nodeIt->next() );
6339       }
6340       else
6341       {
6342         SMDS_ElemIteratorPtr elemIt =
6343             _mesh->elementsIterator( SMDSAbs_ElementType( complexType ));
6344         const SMDS_MeshElement* elem = elemIt->next();
6345         SMDS_ElemIteratorPtr nodeIt = elem->nodesIterator();
6346         SMESH_TNodeXYZ n1( cast2Node( nodeIt->next() ));
6347         elemSize = 0;
6348         while ( nodeIt->more() )
6349         {
6350           double dist = n1.Distance( cast2Node( nodeIt->next() ));
6351           elemSize = max( dist, elemSize );
6352         }
6353       }
6354       _tolerance = 1e-4 * elemSize;
6355     }
6356   }
6357   return _tolerance;
6358 }
6359
6360 //================================================================================
6361 /*!
6362  * \brief Find intersection of the line and an edge of face and return parameter on line
6363  */
6364 //================================================================================
6365
6366 bool SMESH_ElementSearcherImpl::getIntersParamOnLine(const gp_Lin&           line,
6367                                                      const SMDS_MeshElement* face,
6368                                                      const double            tol,
6369                                                      double &                param)
6370 {
6371   int nbInts = 0;
6372   param = 0;
6373
6374   GeomAPI_ExtremaCurveCurve anExtCC;
6375   Handle(Geom_Curve) lineCurve = new Geom_Line( line );
6376   
6377   int nbNodes = face->IsQuadratic() ? face->NbNodes()/2 : face->NbNodes();
6378   for ( int i = 0; i < nbNodes && nbInts < 2; ++i )
6379   {
6380     GC_MakeSegment edge( SMESH_TNodeXYZ( face->GetNode( i )),
6381                          SMESH_TNodeXYZ( face->GetNode( (i+1)%nbNodes) )); 
6382     anExtCC.Init( lineCurve, edge);
6383     if ( anExtCC.NbExtrema() > 0 && anExtCC.LowerDistance() <= tol)
6384     {
6385       Quantity_Parameter pl, pe;
6386       anExtCC.LowerDistanceParameters( pl, pe );
6387       param += pl;
6388       if ( ++nbInts == 2 )
6389         break;
6390     }
6391   }
6392   if ( nbInts > 0 ) param /= nbInts;
6393   return nbInts > 0;
6394 }
6395 //================================================================================
6396 /*!
6397  * \brief Find all faces belonging to the outer boundary of mesh
6398  */
6399 //================================================================================
6400
6401 void SMESH_ElementSearcherImpl::findOuterBoundary(const SMDS_MeshElement* outerFace)
6402 {
6403   if ( _outerFacesFound ) return;
6404
6405   // Collect all outer faces by passing from one outer face to another via their links
6406   // and BTW find out if there are internal faces at all.
6407
6408   // checked links and links where outer boundary meets internal one
6409   set< SMESH_TLink > visitedLinks, seamLinks;
6410
6411   // links to treat with already visited faces sharing them
6412   list < TFaceLink > startLinks;
6413
6414   // load startLinks with the first outerFace
6415   startLinks.push_back( TFaceLink( outerFace->GetNode(0), outerFace->GetNode(1), outerFace));
6416   _outerFaces.insert( outerFace );
6417
6418   TIDSortedElemSet emptySet;
6419   while ( !startLinks.empty() )
6420   {
6421     const SMESH_TLink& link  = startLinks.front()._link;
6422     TIDSortedElemSet&  faces = startLinks.front()._faces;
6423
6424     outerFace = *faces.begin();
6425     // find other faces sharing the link
6426     const SMDS_MeshElement* f;
6427     while (( f = SMESH_MeshEditor::FindFaceInSet(link.node1(), link.node2(), emptySet, faces )))
6428       faces.insert( f );
6429
6430     // select another outer face among the found 
6431     const SMDS_MeshElement* outerFace2 = 0;
6432     if ( faces.size() == 2 )
6433     {
6434       outerFace2 = (outerFace == *faces.begin() ? *faces.rbegin() : *faces.begin());
6435     }
6436     else if ( faces.size() > 2 )
6437     {
6438       seamLinks.insert( link );
6439
6440       // link direction within the outerFace
6441       gp_Vec n1n2( SMESH_TNodeXYZ( link.node1()),
6442                    SMESH_TNodeXYZ( link.node2()));
6443       int i1 = outerFace->GetNodeIndex( link.node1() );
6444       int i2 = outerFace->GetNodeIndex( link.node2() );
6445       bool rev = ( abs(i2-i1) == 1 ? i1 > i2 : i2 > i1 );
6446       if ( rev ) n1n2.Reverse();
6447       // outerFace normal
6448       gp_XYZ ofNorm, fNorm;
6449       if ( SMESH_Algo::FaceNormal( outerFace, ofNorm, /*normalized=*/false ))
6450       {
6451         // direction from the link inside outerFace
6452         gp_Vec dirInOF = gp_Vec( ofNorm ) ^ n1n2;
6453         // sort all other faces by angle with the dirInOF
6454         map< double, const SMDS_MeshElement* > angle2Face;
6455         set< const SMDS_MeshElement*, TIDCompare >::const_iterator face = faces.begin();
6456         for ( ; face != faces.end(); ++face )
6457         {
6458           if ( !SMESH_Algo::FaceNormal( *face, fNorm, /*normalized=*/false ))
6459             continue;
6460           gp_Vec dirInF = gp_Vec( fNorm ) ^ n1n2;
6461           double angle = dirInOF.AngleWithRef( dirInF, n1n2 );
6462           if ( angle < 0 ) angle += 2. * M_PI;
6463           angle2Face.insert( make_pair( angle, *face ));
6464         }
6465         if ( !angle2Face.empty() )
6466           outerFace2 = angle2Face.begin()->second;
6467       }
6468     }
6469     // store the found outer face and add its links to continue seaching from
6470     if ( outerFace2 )
6471     {
6472       _outerFaces.insert( outerFace );
6473       int nbNodes = outerFace2->NbNodes()/( outerFace2->IsQuadratic() ? 2 : 1 );
6474       for ( int i = 0; i < nbNodes; ++i )
6475       {
6476         SMESH_TLink link2( outerFace2->GetNode(i), outerFace2->GetNode((i+1)%nbNodes));
6477         if ( visitedLinks.insert( link2 ).second )
6478           startLinks.push_back( TFaceLink( link2.node1(), link2.node2(), outerFace2 ));
6479       }
6480     }
6481     startLinks.pop_front();
6482   }
6483   _outerFacesFound = true;
6484
6485   if ( !seamLinks.empty() )
6486   {
6487     // There are internal boundaries touching the outher one,
6488     // find all faces of internal boundaries in order to find
6489     // faces of boundaries of holes, if any.
6490     
6491   }
6492   else
6493   {
6494     _outerFaces.clear();
6495   }
6496 }
6497
6498 //=======================================================================
6499 /*!
6500  * \brief Find elements of given type where the given point is IN or ON.
6501  *        Returns nb of found elements and elements them-selves.
6502  *
6503  * 'ALL' type means elements of any type excluding nodes and 0D elements
6504  */
6505 //=======================================================================
6506
6507 int SMESH_ElementSearcherImpl::
6508 FindElementsByPoint(const gp_Pnt&                      point,
6509                     SMDSAbs_ElementType                type,
6510                     vector< const SMDS_MeshElement* >& foundElements)
6511 {
6512   foundElements.clear();
6513
6514   double tolerance = getTolerance();
6515
6516   // =================================================================================
6517   if ( type == SMDSAbs_Node || type == SMDSAbs_0DElement )
6518   {
6519     if ( !_nodeSearcher )
6520       _nodeSearcher = new SMESH_NodeSearcherImpl( _mesh );
6521
6522     const SMDS_MeshNode* closeNode = _nodeSearcher->FindClosestTo( point );
6523     if ( !closeNode ) return foundElements.size();
6524
6525     if ( point.Distance( SMESH_TNodeXYZ( closeNode )) > tolerance )
6526       return foundElements.size(); // to far from any node
6527
6528     if ( type == SMDSAbs_Node )
6529     {
6530       foundElements.push_back( closeNode );
6531     }
6532     else
6533     {
6534       SMDS_ElemIteratorPtr elemIt = closeNode->GetInverseElementIterator( SMDSAbs_0DElement );
6535       while ( elemIt->more() )
6536         foundElements.push_back( elemIt->next() );
6537     }
6538   }
6539   // =================================================================================
6540   else // elements more complex than 0D
6541   {
6542     if ( !_ebbTree || _elementType != type )
6543     {
6544       if ( _ebbTree ) delete _ebbTree;
6545       _ebbTree = new ElementBndBoxTree( *_mesh, _elementType = type, _meshPartIt, tolerance );
6546     }
6547     TIDSortedElemSet suspectElems;
6548     _ebbTree->getElementsNearPoint( point, suspectElems );
6549     TIDSortedElemSet::iterator elem = suspectElems.begin();
6550     for ( ; elem != suspectElems.end(); ++elem )
6551       if ( !SMESH_MeshEditor::isOut( *elem, point, tolerance ))
6552         foundElements.push_back( *elem );
6553   }
6554   return foundElements.size();
6555 }
6556
6557 //================================================================================
6558 /*!
6559  * \brief Classify the given point in the closed 2D mesh
6560  */
6561 //================================================================================
6562
6563 TopAbs_State SMESH_ElementSearcherImpl::GetPointState(const gp_Pnt& point)
6564 {
6565   double tolerance = getTolerance();
6566   if ( !_ebbTree || _elementType != SMDSAbs_Face )
6567   {
6568     if ( _ebbTree ) delete _ebbTree;
6569     _ebbTree = new ElementBndBoxTree( *_mesh, _elementType = SMDSAbs_Face, _meshPartIt );
6570   }
6571   // Algo: analyse transition of a line starting at the point through mesh boundary;
6572   // try three lines parallel to axis of the coordinate system and perform rough
6573   // analysis. If solution is not clear perform thorough analysis.
6574
6575   const int nbAxes = 3;
6576   gp_Dir axisDir[ nbAxes ] = { gp::DX(), gp::DY(), gp::DZ() };
6577   map< double, TInters >   paramOnLine2TInters[ nbAxes ];
6578   list< TInters > tangentInters[ nbAxes ]; // of faces whose plane includes the line
6579   multimap< int, int > nbInt2Axis; // to find the simplest case
6580   for ( int axis = 0; axis < nbAxes; ++axis )
6581   {
6582     gp_Ax1 lineAxis( point, axisDir[axis]);
6583     gp_Lin line    ( lineAxis );
6584
6585     TIDSortedElemSet suspectFaces; // faces possibly intersecting the line
6586     _ebbTree->getElementsNearLine( lineAxis, suspectFaces );
6587
6588     // Intersect faces with the line
6589
6590     map< double, TInters > & u2inters = paramOnLine2TInters[ axis ];
6591     TIDSortedElemSet::iterator face = suspectFaces.begin();
6592     for ( ; face != suspectFaces.end(); ++face )
6593     {
6594       // get face plane
6595       gp_XYZ fNorm;
6596       if ( !SMESH_Algo::FaceNormal( *face, fNorm, /*normalized=*/false)) continue;
6597       gp_Pln facePlane( SMESH_TNodeXYZ( (*face)->GetNode(0)), fNorm );
6598
6599       // perform intersection
6600       IntAna_IntConicQuad intersection( line, IntAna_Quadric( facePlane ));
6601       if ( !intersection.IsDone() )
6602         continue;
6603       if ( intersection.IsInQuadric() )
6604       {
6605         tangentInters[ axis ].push_back( TInters( *face, fNorm, true ));
6606       }
6607       else if ( ! intersection.IsParallel() && intersection.NbPoints() > 0 )
6608       {
6609         gp_Pnt intersectionPoint = intersection.Point(1);
6610         if ( !SMESH_MeshEditor::isOut( *face, intersectionPoint, tolerance ))
6611           u2inters.insert(make_pair( intersection.ParamOnConic(1), TInters( *face, fNorm )));
6612       }
6613     }
6614     // Analyse intersections roughly
6615
6616     int nbInter = u2inters.size();
6617     if ( nbInter == 0 )
6618       return TopAbs_OUT; 
6619
6620     double f = u2inters.begin()->first, l = u2inters.rbegin()->first;
6621     if ( nbInter == 1 ) // not closed mesh
6622       return fabs( f ) < tolerance ? TopAbs_ON : TopAbs_UNKNOWN;
6623
6624     if ( fabs( f ) < tolerance || fabs( l ) < tolerance )
6625       return TopAbs_ON;
6626
6627     if ( (f<0) == (l<0) )
6628       return TopAbs_OUT;
6629
6630     int nbIntBeforePoint = std::distance( u2inters.begin(), u2inters.lower_bound(0));
6631     int nbIntAfterPoint  = nbInter - nbIntBeforePoint;
6632     if ( nbIntBeforePoint == 1 || nbIntAfterPoint == 1 )
6633       return TopAbs_IN;
6634
6635     nbInt2Axis.insert( make_pair( min( nbIntBeforePoint, nbIntAfterPoint ), axis ));
6636
6637     if ( _outerFacesFound ) break; // pass to thorough analysis
6638
6639   } // three attempts - loop on CS axes
6640
6641   // Analyse intersections thoroughly.
6642   // We make two loops maximum, on the first one we only exclude touching intersections,
6643   // on the second, if situation is still unclear, we gather and use information on
6644   // position of faces (internal or outer). If faces position is already gathered,
6645   // we make the second loop right away.
6646
6647   for ( int hasPositionInfo = _outerFacesFound; hasPositionInfo < 2; ++hasPositionInfo )
6648   {
6649     multimap< int, int >::const_iterator nb_axis = nbInt2Axis.begin();
6650     for ( ; nb_axis != nbInt2Axis.end(); ++nb_axis )
6651     {
6652       int axis = nb_axis->second;
6653       map< double, TInters > & u2inters = paramOnLine2TInters[ axis ];
6654
6655       gp_Ax1 lineAxis( point, axisDir[axis]);
6656       gp_Lin line    ( lineAxis );
6657
6658       // add tangent intersections to u2inters
6659       double param;
6660       list< TInters >::const_iterator tgtInt = tangentInters[ axis ].begin();
6661       for ( ; tgtInt != tangentInters[ axis ].end(); ++tgtInt )
6662         if ( getIntersParamOnLine( line, tgtInt->_face, tolerance, param ))
6663           u2inters.insert(make_pair( param, *tgtInt ));
6664       tangentInters[ axis ].clear();
6665
6666       // Count intersections before and after the point excluding touching ones.
6667       // If hasPositionInfo we count intersections of outer boundary only
6668
6669       int nbIntBeforePoint = 0, nbIntAfterPoint = 0;
6670       double f = numeric_limits<double>::max(), l = -numeric_limits<double>::max();
6671       map< double, TInters >::iterator u_int1 = u2inters.begin(), u_int2 = u_int1;
6672       bool ok = ! u_int1->second._coincides;
6673       while ( ok && u_int1 != u2inters.end() )
6674       {
6675         double u = u_int1->first;
6676         bool touchingInt = false;
6677         if ( ++u_int2 != u2inters.end() )
6678         {
6679           // skip intersections at the same point (if the line passes through edge or node)
6680           int nbSamePnt = 0;
6681           while ( u_int2 != u2inters.end() && fabs( u_int2->first - u ) < tolerance )
6682           {
6683             ++nbSamePnt;
6684             ++u_int2;
6685           }
6686
6687           // skip tangent intersections
6688           int nbTgt = 0;
6689           const SMDS_MeshElement* prevFace = u_int1->second._face;
6690           while ( ok && u_int2->second._coincides )
6691           {
6692             if ( SMESH_Algo::GetCommonNodes(prevFace , u_int2->second._face).empty() )
6693               ok = false;
6694             else
6695             {
6696               nbTgt++;
6697               u_int2++;
6698               ok = ( u_int2 != u2inters.end() );
6699             }
6700           }
6701           if ( !ok ) break;
6702
6703           // skip intersections at the same point after tangent intersections
6704           if ( nbTgt > 0 )
6705           {
6706             double u2 = u_int2->first;
6707             ++u_int2;
6708             while ( u_int2 != u2inters.end() && fabs( u_int2->first - u2 ) < tolerance )
6709             {
6710               ++nbSamePnt;
6711               ++u_int2;
6712             }
6713           }
6714           // decide if we skipped a touching intersection
6715           if ( nbSamePnt + nbTgt > 0 )
6716           {
6717             double minDot = numeric_limits<double>::max(), maxDot = -numeric_limits<double>::max();
6718             map< double, TInters >::iterator u_int = u_int1;
6719             for ( ; u_int != u_int2; ++u_int )
6720             {
6721               if ( u_int->second._coincides ) continue;
6722               double dot = u_int->second._faceNorm * line.Direction();
6723               if ( dot > maxDot ) maxDot = dot;
6724               if ( dot < minDot ) minDot = dot;
6725             }
6726             touchingInt = ( minDot*maxDot < 0 );
6727           }
6728         }
6729         if ( !touchingInt )
6730         {
6731           if ( !hasPositionInfo || isOuterBoundary( u_int1->second._face ))
6732           {
6733             if ( u < 0 )
6734               ++nbIntBeforePoint;
6735             else
6736               ++nbIntAfterPoint;
6737           }
6738           if ( u < f ) f = u;
6739           if ( u > l ) l = u;
6740         }
6741
6742         u_int1 = u_int2; // to next intersection
6743
6744       } // loop on intersections with one line
6745
6746       if ( ok )
6747       {
6748         if ( fabs( f ) < tolerance || fabs( l ) < tolerance )
6749           return TopAbs_ON;
6750
6751         if ( nbIntBeforePoint == 0  || nbIntAfterPoint == 0)
6752           return TopAbs_OUT; 
6753
6754         if ( nbIntBeforePoint + nbIntAfterPoint == 1 ) // not closed mesh
6755           return fabs( f ) < tolerance ? TopAbs_ON : TopAbs_UNKNOWN;
6756
6757         if ( nbIntBeforePoint == 1 || nbIntAfterPoint == 1 )
6758           return TopAbs_IN;
6759
6760         if ( (f<0) == (l<0) )
6761           return TopAbs_OUT;
6762
6763         if ( hasPositionInfo )
6764           return nbIntBeforePoint % 2 ? TopAbs_IN : TopAbs_OUT;
6765       }
6766     } // loop on intersections of the tree lines - thorough analysis
6767
6768     if ( !hasPositionInfo )
6769     {
6770       // gather info on faces position - is face in the outer boundary or not
6771       map< double, TInters > & u2inters = paramOnLine2TInters[ 0 ];
6772       findOuterBoundary( u2inters.begin()->second._face );
6773     }
6774
6775   } // two attempts - with and w/o faces position info in the mesh
6776
6777   return TopAbs_UNKNOWN;
6778 }
6779
6780 //=======================================================================
6781 /*!
6782  * \brief Return elements possibly intersecting the line
6783  */
6784 //=======================================================================
6785
6786 void SMESH_ElementSearcherImpl::GetElementsNearLine( const gp_Ax1&                      line,
6787                                                      SMDSAbs_ElementType                type,
6788                                                      vector< const SMDS_MeshElement* >& foundElems)
6789 {
6790   if ( !_ebbTree || _elementType != type )
6791   {
6792     if ( _ebbTree ) delete _ebbTree;
6793     _ebbTree = new ElementBndBoxTree( *_mesh, _elementType = type, _meshPartIt );
6794   }
6795   TIDSortedElemSet suspectFaces; // elements possibly intersecting the line
6796   _ebbTree->getElementsNearLine( line, suspectFaces );
6797   foundElems.assign( suspectFaces.begin(), suspectFaces.end());
6798 }
6799
6800 //=======================================================================
6801 /*!
6802  * \brief Return SMESH_ElementSearcher
6803  */
6804 //=======================================================================
6805
6806 SMESH_ElementSearcher* SMESH_MeshEditor::GetElementSearcher()
6807 {
6808   return new SMESH_ElementSearcherImpl( *GetMeshDS() );
6809 }
6810
6811 //=======================================================================
6812 /*!
6813  * \brief Return SMESH_ElementSearcher acting on a sub-set of elements
6814  */
6815 //=======================================================================
6816
6817 SMESH_ElementSearcher* SMESH_MeshEditor::GetElementSearcher(SMDS_ElemIteratorPtr elemIt)
6818 {
6819   return new SMESH_ElementSearcherImpl( *GetMeshDS(), elemIt );
6820 }
6821
6822 //=======================================================================
6823 /*!
6824  * \brief Return true if the point is IN or ON of the element
6825  */
6826 //=======================================================================
6827
6828 bool SMESH_MeshEditor::isOut( const SMDS_MeshElement* element, const gp_Pnt& point, double tol )
6829 {
6830   if ( element->GetType() == SMDSAbs_Volume)
6831   {
6832     return SMDS_VolumeTool( element ).IsOut( point.X(), point.Y(), point.Z(), tol );
6833   }
6834
6835   // get ordered nodes
6836
6837   vector< gp_XYZ > xyz;
6838   vector<const SMDS_MeshNode*> nodeList;
6839
6840   SMDS_ElemIteratorPtr nodeIt = element->nodesIterator();
6841   if ( element->IsQuadratic() ) {
6842     if (const SMDS_VtkFace* f=dynamic_cast<const SMDS_VtkFace*>(element))
6843       nodeIt = f->interlacedNodesElemIterator();
6844     else if (const SMDS_VtkEdge*  e =dynamic_cast<const SMDS_VtkEdge*>(element))
6845       nodeIt = e->interlacedNodesElemIterator();
6846   }
6847   while ( nodeIt->more() )
6848     {
6849       const SMDS_MeshNode* node = cast2Node( nodeIt->next() );
6850       xyz.push_back( SMESH_TNodeXYZ(node) );
6851       nodeList.push_back(node);
6852     }
6853
6854   int i, nbNodes = element->NbNodes();
6855
6856   if ( element->GetType() == SMDSAbs_Face ) // --------------------------------------------------
6857   {
6858     // compute face normal
6859     gp_Vec faceNorm(0,0,0);
6860     xyz.push_back( xyz.front() );
6861     nodeList.push_back( nodeList.front() );
6862     for ( i = 0; i < nbNodes; ++i )
6863     {
6864       gp_Vec edge1( xyz[i+1], xyz[i]);
6865       gp_Vec edge2( xyz[i+1], xyz[(i+2)%nbNodes] );
6866       faceNorm += edge1 ^ edge2;
6867     }
6868     double normSize = faceNorm.Magnitude();
6869     if ( normSize <= tol )
6870     {
6871       // degenerated face: point is out if it is out of all face edges
6872       for ( i = 0; i < nbNodes; ++i )
6873       {
6874         SMDS_LinearEdge edge( nodeList[i], nodeList[i+1] );
6875         if ( !isOut( &edge, point, tol ))
6876           return false;
6877       }
6878       return true;
6879     }
6880     faceNorm /= normSize;
6881
6882     // check if the point lays on face plane
6883     gp_Vec n2p( xyz[0], point );
6884     if ( fabs( n2p * faceNorm ) > tol )
6885       return true; // not on face plane
6886
6887     // check if point is out of face boundary:
6888     // define it by closest transition of a ray point->infinity through face boundary
6889     // on the face plane.
6890     // First, find normal of a plane perpendicular to face plane, to be used as a cutting tool
6891     // to find intersections of the ray with the boundary.
6892     gp_Vec ray = n2p;
6893     gp_Vec plnNorm = ray ^ faceNorm;
6894     normSize = plnNorm.Magnitude();
6895     if ( normSize <= tol ) return false; // point coincides with the first node
6896     plnNorm /= normSize;
6897     // for each node of the face, compute its signed distance to the plane
6898     vector<double> dist( nbNodes + 1);
6899     for ( i = 0; i < nbNodes; ++i )
6900     {
6901       gp_Vec n2p( xyz[i], point );
6902       dist[i] = n2p * plnNorm;
6903     }
6904     dist.back() = dist.front();
6905     // find the closest intersection
6906     int    iClosest = -1;
6907     double rClosest, distClosest = 1e100;;
6908     gp_Pnt pClosest;
6909     for ( i = 0; i < nbNodes; ++i )
6910     {
6911       double r;
6912       if ( fabs( dist[i]) < tol )
6913         r = 0.;
6914       else if ( fabs( dist[i+1]) < tol )
6915         r = 1.;
6916       else if ( dist[i] * dist[i+1] < 0 )
6917         r = dist[i] / ( dist[i] - dist[i+1] );
6918       else
6919         continue; // no intersection
6920       gp_Pnt pInt = xyz[i] * (1.-r) + xyz[i+1] * r;
6921       gp_Vec p2int ( point, pInt);
6922       if ( p2int * ray > -tol ) // right half-space
6923       {
6924         double intDist = p2int.SquareMagnitude();
6925         if ( intDist < distClosest )
6926         {
6927           iClosest = i;
6928           rClosest = r;
6929           pClosest = pInt;
6930           distClosest = intDist;
6931         }
6932       }
6933     }
6934     if ( iClosest < 0 )
6935       return true; // no intesections - out
6936
6937     // analyse transition
6938     gp_Vec edge( xyz[iClosest], xyz[iClosest+1] );
6939     gp_Vec edgeNorm = -( edge ^ faceNorm ); // normal to intersected edge pointing out of face
6940     gp_Vec p2int ( point, pClosest );
6941     bool out = (edgeNorm * p2int) < -tol;
6942     if ( rClosest > 0. && rClosest < 1. ) // not node intersection
6943       return out;
6944
6945     // ray pass through a face node; analyze transition through an adjacent edge
6946     gp_Pnt p1 = xyz[ (rClosest == 0.) ? ((iClosest+nbNodes-1) % nbNodes) : (iClosest+1) ];
6947     gp_Pnt p2 = xyz[ (rClosest == 0.) ? iClosest : ((iClosest+2) % nbNodes) ];
6948     gp_Vec edgeAdjacent( p1, p2 );
6949     gp_Vec edgeNorm2 = -( edgeAdjacent ^ faceNorm );
6950     bool out2 = (edgeNorm2 * p2int) < -tol;
6951
6952     bool covexCorner = ( edgeNorm * edgeAdjacent * (rClosest==1. ? 1. : -1.)) < 0;
6953     return covexCorner ? (out || out2) : (out && out2);
6954   }
6955   if ( element->GetType() == SMDSAbs_Edge ) // --------------------------------------------------
6956   {
6957     // point is out of edge if it is NOT ON any straight part of edge
6958     // (we consider quadratic edge as being composed of two straight parts)
6959     for ( i = 1; i < nbNodes; ++i )
6960     {
6961       gp_Vec edge( xyz[i-1], xyz[i]);
6962       gp_Vec n1p ( xyz[i-1], point);
6963       double dist = ( edge ^ n1p ).Magnitude() / edge.Magnitude();
6964       if ( dist > tol )
6965         continue;
6966       gp_Vec n2p( xyz[i], point );
6967       if ( fabs( edge.Magnitude() - n1p.Magnitude() - n2p.Magnitude()) > tol )
6968         continue;
6969       return false; // point is ON this part
6970     }
6971     return true;
6972   }
6973   // Node or 0D element -------------------------------------------------------------------------
6974   {
6975     gp_Vec n2p ( xyz[0], point );
6976     return n2p.Magnitude() <= tol;
6977   }
6978   return true;
6979 }
6980
6981 //=======================================================================
6982 //function : SimplifyFace
6983 //purpose  :
6984 //=======================================================================
6985 int SMESH_MeshEditor::SimplifyFace (const vector<const SMDS_MeshNode *> faceNodes,
6986                                     vector<const SMDS_MeshNode *>&      poly_nodes,
6987                                     vector<int>&                        quantities) const
6988 {
6989   int nbNodes = faceNodes.size();
6990
6991   if (nbNodes < 3)
6992     return 0;
6993
6994   set<const SMDS_MeshNode*> nodeSet;
6995
6996   // get simple seq of nodes
6997   //const SMDS_MeshNode* simpleNodes[ nbNodes ];
6998   vector<const SMDS_MeshNode*> simpleNodes( nbNodes );
6999   int iSimple = 0, nbUnique = 0;
7000
7001   simpleNodes[iSimple++] = faceNodes[0];
7002   nbUnique++;
7003   for (int iCur = 1; iCur < nbNodes; iCur++) {
7004     if (faceNodes[iCur] != simpleNodes[iSimple - 1]) {
7005       simpleNodes[iSimple++] = faceNodes[iCur];
7006       if (nodeSet.insert( faceNodes[iCur] ).second)
7007         nbUnique++;
7008     }
7009   }
7010   int nbSimple = iSimple;
7011   if (simpleNodes[nbSimple - 1] == simpleNodes[0]) {
7012     nbSimple--;
7013     iSimple--;
7014   }
7015
7016   if (nbUnique < 3)
7017     return 0;
7018
7019   // separate loops
7020   int nbNew = 0;
7021   bool foundLoop = (nbSimple > nbUnique);
7022   while (foundLoop) {
7023     foundLoop = false;
7024     set<const SMDS_MeshNode*> loopSet;
7025     for (iSimple = 0; iSimple < nbSimple && !foundLoop; iSimple++) {
7026       const SMDS_MeshNode* n = simpleNodes[iSimple];
7027       if (!loopSet.insert( n ).second) {
7028         foundLoop = true;
7029
7030         // separate loop
7031         int iC = 0, curLast = iSimple;
7032         for (; iC < curLast; iC++) {
7033           if (simpleNodes[iC] == n) break;
7034         }
7035         int loopLen = curLast - iC;
7036         if (loopLen > 2) {
7037           // create sub-element
7038           nbNew++;
7039           quantities.push_back(loopLen);
7040           for (; iC < curLast; iC++) {
7041             poly_nodes.push_back(simpleNodes[iC]);
7042           }
7043         }
7044         // shift the rest nodes (place from the first loop position)
7045         for (iC = curLast + 1; iC < nbSimple; iC++) {
7046           simpleNodes[iC - loopLen] = simpleNodes[iC];
7047         }
7048         nbSimple -= loopLen;
7049         iSimple -= loopLen;
7050       }
7051     } // for (iSimple = 0; iSimple < nbSimple; iSimple++)
7052   } // while (foundLoop)
7053
7054   if (iSimple > 2) {
7055     nbNew++;
7056     quantities.push_back(iSimple);
7057     for (int i = 0; i < iSimple; i++)
7058       poly_nodes.push_back(simpleNodes[i]);
7059   }
7060
7061   return nbNew;
7062 }
7063
7064 //=======================================================================
7065 //function : MergeNodes
7066 //purpose  : In each group, the cdr of nodes are substituted by the first one
7067 //           in all elements.
7068 //=======================================================================
7069
7070 void SMESH_MeshEditor::MergeNodes (TListOfListOfNodes & theGroupsOfNodes)
7071 {
7072   MESSAGE("MergeNodes");
7073   myLastCreatedElems.Clear();
7074   myLastCreatedNodes.Clear();
7075
7076   SMESHDS_Mesh* aMesh = GetMeshDS();
7077
7078   TNodeNodeMap nodeNodeMap; // node to replace - new node
7079   set<const SMDS_MeshElement*> elems; // all elements with changed nodes
7080   list< int > rmElemIds, rmNodeIds;
7081
7082   // Fill nodeNodeMap and elems
7083
7084   TListOfListOfNodes::iterator grIt = theGroupsOfNodes.begin();
7085   for ( ; grIt != theGroupsOfNodes.end(); grIt++ ) {
7086     list<const SMDS_MeshNode*>& nodes = *grIt;
7087     list<const SMDS_MeshNode*>::iterator nIt = nodes.begin();
7088     const SMDS_MeshNode* nToKeep = *nIt;
7089     //MESSAGE("node to keep " << nToKeep->GetID());
7090     for ( ++nIt; nIt != nodes.end(); nIt++ ) {
7091       const SMDS_MeshNode* nToRemove = *nIt;
7092       nodeNodeMap.insert( TNodeNodeMap::value_type( nToRemove, nToKeep ));
7093       if ( nToRemove != nToKeep ) {
7094         //MESSAGE("  node to remove " << nToRemove->GetID());
7095         rmNodeIds.push_back( nToRemove->GetID() );
7096         AddToSameGroups( nToKeep, nToRemove, aMesh );
7097       }
7098
7099       SMDS_ElemIteratorPtr invElemIt = nToRemove->GetInverseElementIterator();
7100       while ( invElemIt->more() ) {
7101         const SMDS_MeshElement* elem = invElemIt->next();
7102         elems.insert(elem);
7103       }
7104     }
7105   }
7106   // Change element nodes or remove an element
7107
7108   set<const SMDS_MeshElement*>::iterator eIt = elems.begin();
7109   for ( ; eIt != elems.end(); eIt++ ) {
7110     const SMDS_MeshElement* elem = *eIt;
7111     //MESSAGE(" ---- inverse elem on node to remove " << elem->GetID());
7112     int nbNodes = elem->NbNodes();
7113     int aShapeId = FindShape( elem );
7114
7115     set<const SMDS_MeshNode*> nodeSet;
7116     vector< const SMDS_MeshNode*> curNodes( nbNodes ), uniqueNodes( nbNodes );
7117     int iUnique = 0, iCur = 0, nbRepl = 0;
7118     vector<int> iRepl( nbNodes );
7119
7120     // get new seq of nodes
7121     SMDS_ElemIteratorPtr itN = elem->nodesIterator();
7122     while ( itN->more() ) {
7123       const SMDS_MeshNode* n =
7124         static_cast<const SMDS_MeshNode*>( itN->next() );
7125
7126       TNodeNodeMap::iterator nnIt = nodeNodeMap.find( n );
7127       if ( nnIt != nodeNodeMap.end() ) { // n sticks
7128         n = (*nnIt).second;
7129         // BUG 0020185: begin
7130         {
7131           bool stopRecur = false;
7132           set<const SMDS_MeshNode*> nodesRecur;
7133           nodesRecur.insert(n);
7134           while (!stopRecur) {
7135             TNodeNodeMap::iterator nnIt_i = nodeNodeMap.find( n );
7136             if ( nnIt_i != nodeNodeMap.end() ) { // n sticks
7137               n = (*nnIt_i).second;
7138               if (!nodesRecur.insert(n).second) {
7139                 // error: recursive dependancy
7140                 stopRecur = true;
7141               }
7142             }
7143             else
7144               stopRecur = true;
7145           }
7146         }
7147         // BUG 0020185: end
7148       }
7149       curNodes[ iCur ] = n;
7150       bool isUnique = nodeSet.insert( n ).second;
7151       if ( isUnique )
7152         uniqueNodes[ iUnique++ ] = n;
7153       else
7154         iRepl[ nbRepl++ ] = iCur;
7155       iCur++;
7156     }
7157
7158     // Analyse element topology after replacement
7159
7160     bool isOk = true;
7161     int nbUniqueNodes = nodeSet.size();
7162     //MESSAGE("nbNodes nbUniqueNodes " << nbNodes << " " << nbUniqueNodes);
7163     if ( nbNodes != nbUniqueNodes ) { // some nodes stick
7164       // Polygons and Polyhedral volumes
7165       if (elem->IsPoly()) {
7166
7167         if (elem->GetType() == SMDSAbs_Face) {
7168           // Polygon
7169           vector<const SMDS_MeshNode *> face_nodes (nbNodes);
7170           int inode = 0;
7171           for (; inode < nbNodes; inode++) {
7172             face_nodes[inode] = curNodes[inode];
7173           }
7174
7175           vector<const SMDS_MeshNode *> polygons_nodes;
7176           vector<int> quantities;
7177           int nbNew = SimplifyFace(face_nodes, polygons_nodes, quantities);
7178           if (nbNew > 0) {
7179             inode = 0;
7180             for (int iface = 0; iface < nbNew; iface++) {
7181               int nbNodes = quantities[iface];
7182               vector<const SMDS_MeshNode *> poly_nodes (nbNodes);
7183               for (int ii = 0; ii < nbNodes; ii++, inode++) {
7184                 poly_nodes[ii] = polygons_nodes[inode];
7185               }
7186               SMDS_MeshElement* newElem = aMesh->AddPolygonalFace(poly_nodes);
7187               myLastCreatedElems.Append(newElem);
7188               if (aShapeId)
7189                 aMesh->SetMeshElementOnShape(newElem, aShapeId);
7190             }
7191
7192             MESSAGE("ChangeElementNodes MergeNodes Polygon");
7193             //aMesh->ChangeElementNodes(elem, &polygons_nodes[inode], quantities[nbNew - 1]);
7194             vector<const SMDS_MeshNode *> polynodes(polygons_nodes.begin()+inode,polygons_nodes.end());
7195             int quid =0;
7196             if (nbNew > 0) quid = nbNew - 1;
7197             vector<int> newquant(quantities.begin()+quid, quantities.end());
7198             const SMDS_MeshElement* newElem = 0;
7199             newElem = aMesh->AddPolyhedralVolume(polynodes, newquant);
7200             myLastCreatedElems.Append(newElem);
7201             if ( aShapeId && newElem )
7202               aMesh->SetMeshElementOnShape( newElem, aShapeId );
7203             rmElemIds.push_back(elem->GetID());
7204           }
7205           else {
7206             rmElemIds.push_back(elem->GetID());
7207           }
7208
7209         }
7210         else if (elem->GetType() == SMDSAbs_Volume) {
7211           // Polyhedral volume
7212           if (nbUniqueNodes < 4) {
7213             rmElemIds.push_back(elem->GetID());
7214           }
7215           else {
7216             // each face has to be analyzed in order to check volume validity
7217             const SMDS_VtkVolume* aPolyedre =
7218               dynamic_cast<const SMDS_VtkVolume*>( elem );
7219             if (aPolyedre) {
7220               int nbFaces = aPolyedre->NbFaces();
7221
7222               vector<const SMDS_MeshNode *> poly_nodes;
7223               vector<int> quantities;
7224
7225               for (int iface = 1; iface <= nbFaces; iface++) {
7226                 int nbFaceNodes = aPolyedre->NbFaceNodes(iface);
7227                 vector<const SMDS_MeshNode *> faceNodes (nbFaceNodes);
7228
7229                 for (int inode = 1; inode <= nbFaceNodes; inode++) {
7230                   const SMDS_MeshNode * faceNode = aPolyedre->GetFaceNode(iface, inode);
7231                   TNodeNodeMap::iterator nnIt = nodeNodeMap.find(faceNode);
7232                   if (nnIt != nodeNodeMap.end()) { // faceNode sticks
7233                     faceNode = (*nnIt).second;
7234                   }
7235                   faceNodes[inode - 1] = faceNode;
7236                 }
7237
7238                 SimplifyFace(faceNodes, poly_nodes, quantities);
7239               }
7240
7241               if (quantities.size() > 3) {
7242                 // to be done: remove coincident faces
7243               }
7244
7245               if (quantities.size() > 3)
7246                 {
7247                   MESSAGE("ChangeElementNodes MergeNodes Polyhedron");
7248                   //aMesh->ChangePolyhedronNodes(elem, poly_nodes, quantities);
7249                   const SMDS_MeshElement* newElem = 0;
7250                   newElem = aMesh->AddPolyhedralVolume(poly_nodes, quantities);
7251                   myLastCreatedElems.Append(newElem);
7252                   if ( aShapeId && newElem )
7253                     aMesh->SetMeshElementOnShape( newElem, aShapeId );
7254                   rmElemIds.push_back(elem->GetID());
7255                 }
7256             }
7257             else {
7258               rmElemIds.push_back(elem->GetID());
7259             }
7260           }
7261         }
7262         else {
7263         }
7264
7265         continue;
7266       } // poly element
7267
7268       // Regular elements
7269       // TODO not all the possible cases are solved. Find something more generic?
7270       switch ( nbNodes ) {
7271       case 2: ///////////////////////////////////// EDGE
7272         isOk = false; break;
7273       case 3: ///////////////////////////////////// TRIANGLE
7274         isOk = false; break;
7275       case 4:
7276         if ( elem->GetType() == SMDSAbs_Volume ) // TETRAHEDRON
7277           isOk = false;
7278         else { //////////////////////////////////// QUADRANGLE
7279           if ( nbUniqueNodes < 3 )
7280             isOk = false;
7281           else if ( nbRepl == 2 && iRepl[ 1 ] - iRepl[ 0 ] == 2 )
7282             isOk = false; // opposite nodes stick
7283           //MESSAGE("isOk " << isOk);
7284         }
7285         break;
7286       case 6: ///////////////////////////////////// PENTAHEDRON
7287         if ( nbUniqueNodes == 4 ) {
7288           // ---------------------------------> tetrahedron
7289           if (nbRepl == 3 &&
7290               iRepl[ 0 ] > 2 && iRepl[ 1 ] > 2 && iRepl[ 2 ] > 2 ) {
7291             // all top nodes stick: reverse a bottom
7292             uniqueNodes[ 0 ] = curNodes [ 1 ];
7293             uniqueNodes[ 1 ] = curNodes [ 0 ];
7294           }
7295           else if (nbRepl == 3 &&
7296                    iRepl[ 0 ] < 3 && iRepl[ 1 ] < 3 && iRepl[ 2 ] < 3 ) {
7297             // all bottom nodes stick: set a top before
7298             uniqueNodes[ 3 ] = uniqueNodes [ 0 ];
7299             uniqueNodes[ 0 ] = curNodes [ 3 ];
7300             uniqueNodes[ 1 ] = curNodes [ 4 ];
7301             uniqueNodes[ 2 ] = curNodes [ 5 ];
7302           }
7303           else if (nbRepl == 4 &&
7304                    iRepl[ 2 ] - iRepl [ 0 ] == 3 && iRepl[ 3 ] - iRepl [ 1 ] == 3 ) {
7305             // a lateral face turns into a line: reverse a bottom
7306             uniqueNodes[ 0 ] = curNodes [ 1 ];
7307             uniqueNodes[ 1 ] = curNodes [ 0 ];
7308           }
7309           else
7310             isOk = false;
7311         }
7312         else if ( nbUniqueNodes == 5 ) {
7313           // PENTAHEDRON --------------------> 2 tetrahedrons
7314           if ( nbRepl == 2 && iRepl[ 1 ] - iRepl [ 0 ] == 3 ) {
7315             // a bottom node sticks with a linked top one
7316             // 1.
7317             SMDS_MeshElement* newElem =
7318               aMesh->AddVolume(curNodes[ 3 ],
7319                                curNodes[ 4 ],
7320                                curNodes[ 5 ],
7321                                curNodes[ iRepl[ 0 ] == 2 ? 1 : 2 ]);
7322             myLastCreatedElems.Append(newElem);
7323             if ( aShapeId )
7324               aMesh->SetMeshElementOnShape( newElem, aShapeId );
7325             // 2. : reverse a bottom
7326             uniqueNodes[ 0 ] = curNodes [ 1 ];
7327             uniqueNodes[ 1 ] = curNodes [ 0 ];
7328             nbUniqueNodes = 4;
7329           }
7330           else
7331             isOk = false;
7332         }
7333         else
7334           isOk = false;
7335         break;
7336       case 8: {
7337         if(elem->IsQuadratic()) { // Quadratic quadrangle
7338           //   1    5    2
7339           //    +---+---+
7340           //    |       |
7341           //    |       |
7342           //   4+       +6
7343           //    |       |
7344           //    |       |
7345           //    +---+---+
7346           //   0    7    3
7347           isOk = false;
7348           if(nbRepl==2) {
7349             MESSAGE("nbRepl=2: " << iRepl[0] << " " << iRepl[1]);
7350           }
7351           if(nbRepl==3) {
7352             MESSAGE("nbRepl=3: " << iRepl[0] << " " << iRepl[1]  << " " << iRepl[2]);
7353             nbUniqueNodes = 6;
7354             if( iRepl[0]==0 && iRepl[1]==1 && iRepl[2]==4 ) {
7355               uniqueNodes[0] = curNodes[0];
7356               uniqueNodes[1] = curNodes[2];
7357               uniqueNodes[2] = curNodes[3];
7358               uniqueNodes[3] = curNodes[5];
7359               uniqueNodes[4] = curNodes[6];
7360               uniqueNodes[5] = curNodes[7];
7361               isOk = true;
7362             }
7363             if( iRepl[0]==0 && iRepl[1]==3 && iRepl[2]==7 ) {
7364               uniqueNodes[0] = curNodes[0];
7365               uniqueNodes[1] = curNodes[1];
7366               uniqueNodes[2] = curNodes[2];
7367               uniqueNodes[3] = curNodes[4];
7368               uniqueNodes[4] = curNodes[5];
7369               uniqueNodes[5] = curNodes[6];
7370               isOk = true;
7371             }
7372             if( iRepl[0]==0 && iRepl[1]==4 && iRepl[2]==7 ) {
7373               uniqueNodes[0] = curNodes[1];
7374               uniqueNodes[1] = curNodes[2];
7375               uniqueNodes[2] = curNodes[3];
7376               uniqueNodes[3] = curNodes[5];
7377               uniqueNodes[4] = curNodes[6];
7378               uniqueNodes[5] = curNodes[0];
7379               isOk = true;
7380             }
7381             if( iRepl[0]==1 && iRepl[1]==2 && iRepl[2]==5 ) {
7382               uniqueNodes[0] = curNodes[0];
7383               uniqueNodes[1] = curNodes[1];
7384               uniqueNodes[2] = curNodes[3];
7385               uniqueNodes[3] = curNodes[4];
7386               uniqueNodes[4] = curNodes[6];
7387               uniqueNodes[5] = curNodes[7];
7388               isOk = true;
7389             }
7390             if( iRepl[0]==1 && iRepl[1]==4 && iRepl[2]==5 ) {
7391               uniqueNodes[0] = curNodes[0];
7392               uniqueNodes[1] = curNodes[2];
7393               uniqueNodes[2] = curNodes[3];
7394               uniqueNodes[3] = curNodes[1];
7395               uniqueNodes[4] = curNodes[6];
7396               uniqueNodes[5] = curNodes[7];
7397               isOk = true;
7398             }
7399             if( iRepl[0]==2 && iRepl[1]==3 && iRepl[2]==6 ) {
7400               uniqueNodes[0] = curNodes[0];
7401               uniqueNodes[1] = curNodes[1];
7402               uniqueNodes[2] = curNodes[2];
7403               uniqueNodes[3] = curNodes[4];
7404               uniqueNodes[4] = curNodes[5];
7405               uniqueNodes[5] = curNodes[7];
7406               isOk = true;
7407             }
7408             if( iRepl[0]==2 && iRepl[1]==5 && iRepl[2]==6 ) {
7409               uniqueNodes[0] = curNodes[0];
7410               uniqueNodes[1] = curNodes[1];
7411               uniqueNodes[2] = curNodes[3];
7412               uniqueNodes[3] = curNodes[4];
7413               uniqueNodes[4] = curNodes[2];
7414               uniqueNodes[5] = curNodes[7];
7415               isOk = true;
7416             }
7417             if( iRepl[0]==3 && iRepl[1]==6 && iRepl[2]==7 ) {
7418               uniqueNodes[0] = curNodes[0];
7419               uniqueNodes[1] = curNodes[1];
7420               uniqueNodes[2] = curNodes[2];
7421               uniqueNodes[3] = curNodes[4];
7422               uniqueNodes[4] = curNodes[5];
7423               uniqueNodes[5] = curNodes[3];
7424               isOk = true;
7425             }
7426           }
7427           if(nbRepl==4) {
7428             MESSAGE("nbRepl=4: " << iRepl[0] << " " << iRepl[1]  << " " << iRepl[2] << " " << iRepl[3]);
7429           }
7430           if(nbRepl==5) {
7431             MESSAGE("nbRepl=5: " << iRepl[0] << " " << iRepl[1]  << " " << iRepl[2] << " " << iRepl[3] << " " << iRepl[4]);
7432           }
7433           break;
7434         }
7435         //////////////////////////////////// HEXAHEDRON
7436         isOk = false;
7437         SMDS_VolumeTool hexa (elem);
7438         hexa.SetExternalNormal();
7439         if ( nbUniqueNodes == 4 && nbRepl == 4 ) {
7440           //////////////////////// HEX ---> 1 tetrahedron
7441           for ( int iFace = 0; iFace < 6; iFace++ ) {
7442             const int *ind = hexa.GetFaceNodesIndices( iFace ); // indices of face nodes
7443             if (curNodes[ind[ 0 ]] == curNodes[ind[ 1 ]] &&
7444                 curNodes[ind[ 0 ]] == curNodes[ind[ 2 ]] &&
7445                 curNodes[ind[ 0 ]] == curNodes[ind[ 3 ]] ) {
7446               // one face turns into a point ...
7447               int iOppFace = hexa.GetOppFaceIndex( iFace );
7448               ind = hexa.GetFaceNodesIndices( iOppFace );
7449               int nbStick = 0;
7450               for ( iCur = 0; iCur < 4 && nbStick < 2; iCur++ ) {
7451                 if ( curNodes[ind[ iCur ]] == curNodes[ind[ iCur + 1 ]] )
7452                   nbStick++;
7453               }
7454               if ( nbStick == 1 ) {
7455                 // ... and the opposite one - into a triangle.
7456                 // set a top node
7457                 ind = hexa.GetFaceNodesIndices( iFace );
7458                 uniqueNodes[ 3 ] = curNodes[ind[ 0 ]];
7459                 isOk = true;
7460               }
7461               break;
7462             }
7463           }
7464         }
7465         else if ( nbUniqueNodes == 6 && nbRepl == 2 ) {
7466           //////////////////////// HEX ---> 1 prism
7467           int nbTria = 0, iTria[3];
7468           const int *ind; // indices of face nodes
7469           // look for triangular faces
7470           for ( int iFace = 0; iFace < 6 && nbTria < 3; iFace++ ) {
7471             ind = hexa.GetFaceNodesIndices( iFace );
7472             TIDSortedNodeSet faceNodes;
7473             for ( iCur = 0; iCur < 4; iCur++ )
7474               faceNodes.insert( curNodes[ind[iCur]] );
7475             if ( faceNodes.size() == 3 )
7476               iTria[ nbTria++ ] = iFace;
7477           }
7478           // check if triangles are opposite
7479           if ( nbTria == 2 && iTria[0] == hexa.GetOppFaceIndex( iTria[1] ))
7480           {
7481             isOk = true;
7482             // set nodes of the bottom triangle
7483             ind = hexa.GetFaceNodesIndices( iTria[ 0 ]);
7484             vector<int> indB;
7485             for ( iCur = 0; iCur < 4; iCur++ )
7486               if ( ind[iCur] != iRepl[0] && ind[iCur] != iRepl[1])
7487                 indB.push_back( ind[iCur] );
7488             if ( !hexa.IsForward() )
7489               std::swap( indB[0], indB[2] );
7490             for ( iCur = 0; iCur < 3; iCur++ )
7491               uniqueNodes[ iCur ] = curNodes[indB[iCur]];
7492             // set nodes of the top triangle
7493             const int *indT = hexa.GetFaceNodesIndices( iTria[ 1 ]);
7494             for ( iCur = 0; iCur < 3; ++iCur )
7495               for ( int j = 0; j < 4; ++j )
7496                 if ( hexa.IsLinked( indB[ iCur ], indT[ j ] ))
7497                 {
7498                   uniqueNodes[ iCur + 3 ] = curNodes[ indT[ j ]];
7499                   break;
7500                 }
7501           }
7502           break;
7503         }
7504         else if (nbUniqueNodes == 5 && nbRepl == 4 ) {
7505           //////////////////// HEXAHEDRON ---> 2 tetrahedrons
7506           for ( int iFace = 0; iFace < 6; iFace++ ) {
7507             const int *ind = hexa.GetFaceNodesIndices( iFace ); // indices of face nodes
7508             if (curNodes[ind[ 0 ]] == curNodes[ind[ 1 ]] &&
7509                 curNodes[ind[ 0 ]] == curNodes[ind[ 2 ]] &&
7510                 curNodes[ind[ 0 ]] == curNodes[ind[ 3 ]] ) {
7511               // one face turns into a point ...
7512               int iOppFace = hexa.GetOppFaceIndex( iFace );
7513               ind = hexa.GetFaceNodesIndices( iOppFace );
7514               int nbStick = 0;
7515               iUnique = 2;  // reverse a tetrahedron 1 bottom
7516               for ( iCur = 0; iCur < 4 && nbStick == 0; iCur++ ) {
7517                 if ( curNodes[ind[ iCur ]] == curNodes[ind[ iCur + 1 ]] )
7518                   nbStick++;
7519                 else if ( iUnique >= 0 )
7520                   uniqueNodes[ iUnique-- ] = curNodes[ind[ iCur ]];
7521               }
7522               if ( nbStick == 0 ) {
7523                 // ... and the opposite one is a quadrangle
7524                 // set a top node
7525                 const int* indTop = hexa.GetFaceNodesIndices( iFace );
7526                 uniqueNodes[ 3 ] = curNodes[indTop[ 0 ]];
7527                 nbUniqueNodes = 4;
7528                 // tetrahedron 2
7529                 SMDS_MeshElement* newElem =
7530                   aMesh->AddVolume(curNodes[ind[ 0 ]],
7531                                    curNodes[ind[ 3 ]],
7532                                    curNodes[ind[ 2 ]],
7533                                    curNodes[indTop[ 0 ]]);
7534                 myLastCreatedElems.Append(newElem);
7535                 if ( aShapeId )
7536                   aMesh->SetMeshElementOnShape( newElem, aShapeId );
7537                 isOk = true;
7538               }
7539               break;
7540             }
7541           }
7542         }
7543         else if ( nbUniqueNodes == 6 && nbRepl == 4 ) {
7544           ////////////////// HEXAHEDRON ---> 2 tetrahedrons or 1 prism
7545           // find indices of quad and tri faces
7546           int iQuadFace[ 6 ], iTriFace[ 6 ], nbQuad = 0, nbTri = 0, iFace;
7547           for ( iFace = 0; iFace < 6; iFace++ ) {
7548             const int *ind = hexa.GetFaceNodesIndices( iFace ); // indices of face nodes
7549             nodeSet.clear();
7550             for ( iCur = 0; iCur < 4; iCur++ )
7551               nodeSet.insert( curNodes[ind[ iCur ]] );
7552             nbUniqueNodes = nodeSet.size();
7553             if ( nbUniqueNodes == 3 )
7554               iTriFace[ nbTri++ ] = iFace;
7555             else if ( nbUniqueNodes == 4 )
7556               iQuadFace[ nbQuad++ ] = iFace;
7557           }
7558           if (nbQuad == 2 && nbTri == 4 &&
7559               hexa.GetOppFaceIndex( iQuadFace[ 0 ] ) == iQuadFace[ 1 ]) {
7560             // 2 opposite quadrangles stuck with a diagonal;
7561             // sample groups of merged indices: (0-4)(2-6)
7562             // --------------------------------------------> 2 tetrahedrons
7563             const int *ind1 = hexa.GetFaceNodesIndices( iQuadFace[ 0 ]); // indices of quad1 nodes
7564             const int *ind2 = hexa.GetFaceNodesIndices( iQuadFace[ 1 ]);
7565             int i0, i1d, i2, i3d, i0t, i2t; // d-daigonal, t-top
7566             if (curNodes[ind1[ 0 ]] == curNodes[ind2[ 0 ]] &&
7567                 curNodes[ind1[ 2 ]] == curNodes[ind2[ 2 ]]) {
7568               // stuck with 0-2 diagonal
7569               i0  = ind1[ 3 ];
7570               i1d = ind1[ 0 ];
7571               i2  = ind1[ 1 ];
7572               i3d = ind1[ 2 ];
7573               i0t = ind2[ 1 ];
7574               i2t = ind2[ 3 ];
7575             }
7576             else if (curNodes[ind1[ 1 ]] == curNodes[ind2[ 3 ]] &&
7577                      curNodes[ind1[ 3 ]] == curNodes[ind2[ 1 ]]) {
7578               // stuck with 1-3 diagonal
7579               i0  = ind1[ 0 ];
7580               i1d = ind1[ 1 ];
7581               i2  = ind1[ 2 ];
7582               i3d = ind1[ 3 ];
7583               i0t = ind2[ 0 ];
7584               i2t = ind2[ 1 ];
7585             }
7586             else {
7587               ASSERT(0);
7588             }
7589             // tetrahedron 1
7590             uniqueNodes[ 0 ] = curNodes [ i0 ];
7591             uniqueNodes[ 1 ] = curNodes [ i1d ];
7592             uniqueNodes[ 2 ] = curNodes [ i3d ];
7593             uniqueNodes[ 3 ] = curNodes [ i0t ];
7594             nbUniqueNodes = 4;
7595             // tetrahedron 2
7596             SMDS_MeshElement* newElem = aMesh->AddVolume(curNodes[ i1d ],
7597                                                          curNodes[ i2 ],
7598                                                          curNodes[ i3d ],
7599                                                          curNodes[ i2t ]);
7600             myLastCreatedElems.Append(newElem);
7601             if ( aShapeId )
7602               aMesh->SetMeshElementOnShape( newElem, aShapeId );
7603             isOk = true;
7604           }
7605           else if (( nbTri == 2 && nbQuad == 3 ) || // merged (0-4)(1-5)
7606                    ( nbTri == 4 && nbQuad == 2 )) { // merged (7-4)(1-5)
7607             // --------------------------------------------> prism
7608             // find 2 opposite triangles
7609             nbUniqueNodes = 6;
7610             for ( iFace = 0; iFace + 1 < nbTri; iFace++ ) {
7611               if ( hexa.GetOppFaceIndex( iTriFace[ iFace ] ) == iTriFace[ iFace + 1 ]) {
7612                 // find indices of kept and replaced nodes
7613                 // and fill unique nodes of 2 opposite triangles
7614                 const int *ind1 = hexa.GetFaceNodesIndices( iTriFace[ iFace ]);
7615                 const int *ind2 = hexa.GetFaceNodesIndices( iTriFace[ iFace + 1 ]);
7616                 const SMDS_MeshNode** hexanodes = hexa.GetNodes();
7617                 // fill unique nodes
7618                 iUnique = 0;
7619                 isOk = true;
7620                 for ( iCur = 0; iCur < 4 && isOk; iCur++ ) {
7621                   const SMDS_MeshNode* n     = curNodes[ind1[ iCur ]];
7622                   const SMDS_MeshNode* nInit = hexanodes[ind1[ iCur ]];
7623                   if ( n == nInit ) {
7624                     // iCur of a linked node of the opposite face (make normals co-directed):
7625                     int iCurOpp = ( iCur == 1 || iCur == 3 ) ? 4 - iCur : iCur;
7626                     // check that correspondent corners of triangles are linked
7627                     if ( !hexa.IsLinked( ind1[ iCur ], ind2[ iCurOpp ] ))
7628                       isOk = false;
7629                     else {
7630                       uniqueNodes[ iUnique ] = n;
7631                       uniqueNodes[ iUnique + 3 ] = curNodes[ind2[ iCurOpp ]];
7632                       iUnique++;
7633                     }
7634                   }
7635                 }
7636                 break;
7637               }
7638             }
7639           }
7640         } // if ( nbUniqueNodes == 6 && nbRepl == 4 )
7641         else
7642         {
7643           MESSAGE("MergeNodes() removes hexahedron "<< elem);
7644         }
7645         break;
7646       } // HEXAHEDRON
7647
7648       default:
7649         isOk = false;
7650       } // switch ( nbNodes )
7651
7652     } // if ( nbNodes != nbUniqueNodes ) // some nodes stick
7653
7654     if ( isOk ) { // the elem remains valid after sticking nodes
7655       if (elem->IsPoly() && elem->GetType() == SMDSAbs_Volume)
7656       {
7657         // Change nodes of polyedre
7658         const SMDS_VtkVolume* aPolyedre =
7659           dynamic_cast<const SMDS_VtkVolume*>( elem );
7660         if (aPolyedre) {
7661           int nbFaces = aPolyedre->NbFaces();
7662
7663           vector<const SMDS_MeshNode *> poly_nodes;
7664           vector<int> quantities (nbFaces);
7665
7666           for (int iface = 1; iface <= nbFaces; iface++) {
7667             int inode, nbFaceNodes = aPolyedre->NbFaceNodes(iface);
7668             quantities[iface - 1] = nbFaceNodes;
7669
7670             for (inode = 1; inode <= nbFaceNodes; inode++) {
7671               const SMDS_MeshNode* curNode = aPolyedre->GetFaceNode(iface, inode);
7672
7673               TNodeNodeMap::iterator nnIt = nodeNodeMap.find( curNode );
7674               if (nnIt != nodeNodeMap.end()) { // curNode sticks
7675                 curNode = (*nnIt).second;
7676               }
7677               poly_nodes.push_back(curNode);
7678             }
7679           }
7680           aMesh->ChangePolyhedronNodes( elem, poly_nodes, quantities );
7681         }
7682       }
7683       else // replace non-polyhedron elements
7684       {
7685         const SMDSAbs_ElementType etyp = elem->GetType();
7686         const int elemId               = elem->GetID();
7687         const bool isPoly              = (elem->GetEntityType() == SMDSEntity_Polygon);
7688         uniqueNodes.resize(nbUniqueNodes);
7689
7690         SMESHDS_SubMesh * sm = aShapeId > 0 ? aMesh->MeshElements(aShapeId) : 0;
7691
7692         aMesh->RemoveFreeElement(elem, sm, /*fromGroups=*/false);
7693         SMDS_MeshElement* newElem = this->AddElement(uniqueNodes, etyp, isPoly, elemId);
7694         if ( sm && newElem )
7695           sm->AddElement( newElem );
7696         if ( elem != newElem )
7697           ReplaceElemInGroups( elem, newElem, aMesh );
7698       }
7699     }
7700     else {
7701       // Remove invalid regular element or invalid polygon
7702       rmElemIds.push_back( elem->GetID() );
7703     }
7704
7705   } // loop on elements
7706
7707   // Remove bad elements, then equal nodes (order important)
7708
7709   Remove( rmElemIds, false );
7710   Remove( rmNodeIds, true );
7711
7712 }
7713
7714
7715 // ========================================================
7716 // class   : SortableElement
7717 // purpose : allow sorting elements basing on their nodes
7718 // ========================================================
7719 class SortableElement : public set <const SMDS_MeshElement*>
7720 {
7721 public:
7722
7723   SortableElement( const SMDS_MeshElement* theElem )
7724   {
7725     myElem = theElem;
7726     SMDS_ElemIteratorPtr nodeIt = theElem->nodesIterator();
7727     while ( nodeIt->more() )
7728       this->insert( nodeIt->next() );
7729   }
7730
7731   const SMDS_MeshElement* Get() const
7732   { return myElem; }
7733
7734   void Set(const SMDS_MeshElement* e) const
7735   { myElem = e; }
7736
7737
7738 private:
7739   mutable const SMDS_MeshElement* myElem;
7740 };
7741
7742 //=======================================================================
7743 //function : FindEqualElements
7744 //purpose  : Return list of group of elements built on the same nodes.
7745 //           Search among theElements or in the whole mesh if theElements is empty
7746 //=======================================================================
7747 void SMESH_MeshEditor::FindEqualElements(set<const SMDS_MeshElement*> & theElements,
7748                                          TListOfListOfElementsID &      theGroupsOfElementsID)
7749 {
7750   myLastCreatedElems.Clear();
7751   myLastCreatedNodes.Clear();
7752
7753   typedef set<const SMDS_MeshElement*> TElemsSet;
7754   typedef map< SortableElement, int > TMapOfNodeSet;
7755   typedef list<int> TGroupOfElems;
7756
7757   TElemsSet elems;
7758   if ( theElements.empty() )
7759   { // get all elements in the mesh
7760     SMDS_ElemIteratorPtr eIt = GetMeshDS()->elementsIterator();
7761     while ( eIt->more() )
7762       elems.insert( elems.end(), eIt->next());
7763   }
7764   else
7765     elems = theElements;
7766
7767   vector< TGroupOfElems > arrayOfGroups;
7768   TGroupOfElems groupOfElems;
7769   TMapOfNodeSet mapOfNodeSet;
7770
7771   TElemsSet::iterator elemIt = elems.begin();
7772   for ( int i = 0, j=0; elemIt != elems.end(); ++elemIt, ++j ) {
7773     const SMDS_MeshElement* curElem = *elemIt;
7774     SortableElement SE(curElem);
7775     int ind = -1;
7776     // check uniqueness
7777     pair< TMapOfNodeSet::iterator, bool> pp = mapOfNodeSet.insert(make_pair(SE, i));
7778     if( !(pp.second) ) {
7779       TMapOfNodeSet::iterator& itSE = pp.first;
7780       ind = (*itSE).second;
7781       arrayOfGroups[ind].push_back(curElem->GetID());
7782     }
7783     else {
7784       groupOfElems.clear();
7785       groupOfElems.push_back(curElem->GetID());
7786       arrayOfGroups.push_back(groupOfElems);
7787       i++;
7788     }
7789   }
7790
7791   vector< TGroupOfElems >::iterator groupIt = arrayOfGroups.begin();
7792   for ( ; groupIt != arrayOfGroups.end(); ++groupIt ) {
7793     groupOfElems = *groupIt;
7794     if ( groupOfElems.size() > 1 ) {
7795       groupOfElems.sort();
7796       theGroupsOfElementsID.push_back(groupOfElems);
7797     }
7798   }
7799 }
7800
7801 //=======================================================================
7802 //function : MergeElements
7803 //purpose  : In each given group, substitute all elements by the first one.
7804 //=======================================================================
7805
7806 void SMESH_MeshEditor::MergeElements(TListOfListOfElementsID & theGroupsOfElementsID)
7807 {
7808   myLastCreatedElems.Clear();
7809   myLastCreatedNodes.Clear();
7810
7811   typedef list<int> TListOfIDs;
7812   TListOfIDs rmElemIds; // IDs of elems to remove
7813
7814   SMESHDS_Mesh* aMesh = GetMeshDS();
7815
7816   TListOfListOfElementsID::iterator groupsIt = theGroupsOfElementsID.begin();
7817   while ( groupsIt != theGroupsOfElementsID.end() ) {
7818     TListOfIDs& aGroupOfElemID = *groupsIt;
7819     aGroupOfElemID.sort();
7820     int elemIDToKeep = aGroupOfElemID.front();
7821     const SMDS_MeshElement* elemToKeep = aMesh->FindElement(elemIDToKeep);
7822     aGroupOfElemID.pop_front();
7823     TListOfIDs::iterator idIt = aGroupOfElemID.begin();
7824     while ( idIt != aGroupOfElemID.end() ) {
7825       int elemIDToRemove = *idIt;
7826       const SMDS_MeshElement* elemToRemove = aMesh->FindElement(elemIDToRemove);
7827       // add the kept element in groups of removed one (PAL15188)
7828       AddToSameGroups( elemToKeep, elemToRemove, aMesh );
7829       rmElemIds.push_back( elemIDToRemove );
7830       ++idIt;
7831     }
7832     ++groupsIt;
7833   }
7834
7835   Remove( rmElemIds, false );
7836 }
7837
7838 //=======================================================================
7839 //function : MergeEqualElements
7840 //purpose  : Remove all but one of elements built on the same nodes.
7841 //=======================================================================
7842
7843 void SMESH_MeshEditor::MergeEqualElements()
7844 {
7845   set<const SMDS_MeshElement*> aMeshElements; /* empty input -
7846                                                  to merge equal elements in the whole mesh */
7847   TListOfListOfElementsID aGroupsOfElementsID;
7848   FindEqualElements(aMeshElements, aGroupsOfElementsID);
7849   MergeElements(aGroupsOfElementsID);
7850 }
7851
7852 //=======================================================================
7853 //function : FindFaceInSet
7854 //purpose  : Return a face having linked nodes n1 and n2 and which is
7855 //           - not in avoidSet,
7856 //           - in elemSet provided that !elemSet.empty()
7857 //           i1 and i2 optionally returns indices of n1 and n2
7858 //=======================================================================
7859
7860 const SMDS_MeshElement*
7861 SMESH_MeshEditor::FindFaceInSet(const SMDS_MeshNode*    n1,
7862                                 const SMDS_MeshNode*    n2,
7863                                 const TIDSortedElemSet& elemSet,
7864                                 const TIDSortedElemSet& avoidSet,
7865                                 int*                    n1ind,
7866                                 int*                    n2ind)
7867
7868 {
7869   int i1, i2;
7870   const SMDS_MeshElement* face = 0;
7871
7872   SMDS_ElemIteratorPtr invElemIt = n1->GetInverseElementIterator(SMDSAbs_Face);
7873   //MESSAGE("n1->GetInverseElementIterator(SMDSAbs_Face) " << invElemIt);
7874   while ( invElemIt->more() && !face ) // loop on inverse faces of n1
7875   {
7876     //MESSAGE("in while ( invElemIt->more() && !face )");
7877     const SMDS_MeshElement* elem = invElemIt->next();
7878     if (avoidSet.count( elem ))
7879       continue;
7880     if ( !elemSet.empty() && !elemSet.count( elem ))
7881       continue;
7882     // index of n1
7883     i1 = elem->GetNodeIndex( n1 );
7884     // find a n2 linked to n1
7885     int nbN = elem->IsQuadratic() ? elem->NbNodes()/2 : elem->NbNodes();
7886     for ( int di = -1; di < 2 && !face; di += 2 )
7887     {
7888       i2 = (i1+di+nbN) % nbN;
7889       if ( elem->GetNode( i2 ) == n2 )
7890         face = elem;
7891     }
7892     if ( !face && elem->IsQuadratic())
7893     {
7894       // analysis for quadratic elements using all nodes
7895       const SMDS_VtkFace* F =
7896         dynamic_cast<const SMDS_VtkFace*>(elem);
7897       if (!F) throw SALOME_Exception(LOCALIZED("not an SMDS_VtkFace"));
7898       // use special nodes iterator
7899       SMDS_ElemIteratorPtr anIter = F->interlacedNodesElemIterator();
7900       const SMDS_MeshNode* prevN = cast2Node( anIter->next() );
7901       for ( i1 = -1, i2 = 0; anIter->more() && !face; i1++, i2++ )
7902       {
7903         const SMDS_MeshNode* n = cast2Node( anIter->next() );
7904         if ( n1 == prevN && n2 == n )
7905         {
7906           face = elem;
7907         }
7908         else if ( n2 == prevN && n1 == n )
7909         {
7910           face = elem; swap( i1, i2 );
7911         }
7912         prevN = n;
7913       }
7914     }
7915   }
7916   if ( n1ind ) *n1ind = i1;
7917   if ( n2ind ) *n2ind = i2;
7918   return face;
7919 }
7920
7921 //=======================================================================
7922 //function : findAdjacentFace
7923 //purpose  :
7924 //=======================================================================
7925
7926 static const SMDS_MeshElement* findAdjacentFace(const SMDS_MeshNode* n1,
7927                                                 const SMDS_MeshNode* n2,
7928                                                 const SMDS_MeshElement* elem)
7929 {
7930   TIDSortedElemSet elemSet, avoidSet;
7931   if ( elem )
7932     avoidSet.insert ( elem );
7933   return SMESH_MeshEditor::FindFaceInSet( n1, n2, elemSet, avoidSet );
7934 }
7935
7936 //=======================================================================
7937 //function : FindFreeBorder
7938 //purpose  :
7939 //=======================================================================
7940
7941 #define ControlFreeBorder SMESH::Controls::FreeEdges::IsFreeEdge
7942
7943 bool SMESH_MeshEditor::FindFreeBorder (const SMDS_MeshNode*             theFirstNode,
7944                                        const SMDS_MeshNode*             theSecondNode,
7945                                        const SMDS_MeshNode*             theLastNode,
7946                                        list< const SMDS_MeshNode* > &   theNodes,
7947                                        list< const SMDS_MeshElement* >& theFaces)
7948 {
7949   if ( !theFirstNode || !theSecondNode )
7950     return false;
7951   // find border face between theFirstNode and theSecondNode
7952   const SMDS_MeshElement* curElem = findAdjacentFace( theFirstNode, theSecondNode, 0 );
7953   if ( !curElem )
7954     return false;
7955
7956   theFaces.push_back( curElem );
7957   theNodes.push_back( theFirstNode );
7958   theNodes.push_back( theSecondNode );
7959
7960   //vector<const SMDS_MeshNode*> nodes;
7961   const SMDS_MeshNode *nIgnore = theFirstNode, *nStart = theSecondNode;
7962   TIDSortedElemSet foundElems;
7963   bool needTheLast = ( theLastNode != 0 );
7964
7965   while ( nStart != theLastNode ) {
7966     if ( nStart == theFirstNode )
7967       return !needTheLast;
7968
7969     // find all free border faces sharing form nStart
7970
7971     list< const SMDS_MeshElement* > curElemList;
7972     list< const SMDS_MeshNode* > nStartList;
7973     SMDS_ElemIteratorPtr invElemIt = nStart->GetInverseElementIterator(SMDSAbs_Face);
7974     while ( invElemIt->more() ) {
7975       const SMDS_MeshElement* e = invElemIt->next();
7976       if ( e == curElem || foundElems.insert( e ).second ) {
7977         // get nodes
7978         int iNode = 0, nbNodes = e->NbNodes();
7979         //const SMDS_MeshNode* nodes[nbNodes+1];
7980         vector<const SMDS_MeshNode*> nodes(nbNodes+1);
7981
7982         if(e->IsQuadratic()) {
7983           const SMDS_VtkFace* F =
7984             dynamic_cast<const SMDS_VtkFace*>(e);
7985           if (!F) throw SALOME_Exception(LOCALIZED("not an SMDS_VtkFace"));
7986           // use special nodes iterator
7987           SMDS_ElemIteratorPtr anIter = F->interlacedNodesElemIterator();
7988           while( anIter->more() ) {
7989             nodes[ iNode++ ] = cast2Node(anIter->next());
7990           }
7991         }
7992         else {
7993           SMDS_ElemIteratorPtr nIt = e->nodesIterator();
7994           while ( nIt->more() )
7995             nodes[ iNode++ ] = static_cast<const SMDS_MeshNode*>( nIt->next() );
7996         }
7997         nodes[ iNode ] = nodes[ 0 ];
7998         // check 2 links
7999         for ( iNode = 0; iNode < nbNodes; iNode++ )
8000           if (((nodes[ iNode ] == nStart && nodes[ iNode + 1] != nIgnore ) ||
8001                (nodes[ iNode + 1] == nStart && nodes[ iNode ] != nIgnore )) &&
8002               ControlFreeBorder( &nodes[ iNode ], e->GetID() ))
8003           {
8004             nStartList.push_back( nodes[ iNode + ( nodes[ iNode ] == nStart ? 1 : 0 )]);
8005             curElemList.push_back( e );
8006           }
8007       }
8008     }
8009     // analyse the found
8010
8011     int nbNewBorders = curElemList.size();
8012     if ( nbNewBorders == 0 ) {
8013       // no free border furthermore
8014       return !needTheLast;
8015     }
8016     else if ( nbNewBorders == 1 ) {
8017       // one more element found
8018       nIgnore = nStart;
8019       nStart = nStartList.front();
8020       curElem = curElemList.front();
8021       theFaces.push_back( curElem );
8022       theNodes.push_back( nStart );
8023     }
8024     else {
8025       // several continuations found
8026       list< const SMDS_MeshElement* >::iterator curElemIt;
8027       list< const SMDS_MeshNode* >::iterator nStartIt;
8028       // check if one of them reached the last node
8029       if ( needTheLast ) {
8030         for (curElemIt = curElemList.begin(), nStartIt = nStartList.begin();
8031              curElemIt!= curElemList.end();
8032              curElemIt++, nStartIt++ )
8033           if ( *nStartIt == theLastNode ) {
8034             theFaces.push_back( *curElemIt );
8035             theNodes.push_back( *nStartIt );
8036             return true;
8037           }
8038       }
8039       // find the best free border by the continuations
8040       list<const SMDS_MeshNode*>    contNodes[ 2 ], *cNL;
8041       list<const SMDS_MeshElement*> contFaces[ 2 ], *cFL;
8042       for (curElemIt = curElemList.begin(), nStartIt = nStartList.begin();
8043            curElemIt!= curElemList.end();
8044            curElemIt++, nStartIt++ )
8045       {
8046         cNL = & contNodes[ contNodes[0].empty() ? 0 : 1 ];
8047         cFL = & contFaces[ contFaces[0].empty() ? 0 : 1 ];
8048         // find one more free border
8049         if ( ! FindFreeBorder( nStart, *nStartIt, theLastNode, *cNL, *cFL )) {
8050           cNL->clear();
8051           cFL->clear();
8052         }
8053         else if ( !contNodes[0].empty() && !contNodes[1].empty() ) {
8054           // choice: clear a worse one
8055           int iLongest = ( contNodes[0].size() < contNodes[1].size() ? 1 : 0 );
8056           int iWorse = ( needTheLast ? 1 - iLongest : iLongest );
8057           contNodes[ iWorse ].clear();
8058           contFaces[ iWorse ].clear();
8059         }
8060       }
8061       if ( contNodes[0].empty() && contNodes[1].empty() )
8062         return false;
8063
8064       // append the best free border
8065       cNL = & contNodes[ contNodes[0].empty() ? 1 : 0 ];
8066       cFL = & contFaces[ contFaces[0].empty() ? 1 : 0 ];
8067       theNodes.pop_back(); // remove nIgnore
8068       theNodes.pop_back(); // remove nStart
8069       theFaces.pop_back(); // remove curElem
8070       list< const SMDS_MeshNode* >::iterator nIt = cNL->begin();
8071       list< const SMDS_MeshElement* >::iterator fIt = cFL->begin();
8072       for ( ; nIt != cNL->end(); nIt++ ) theNodes.push_back( *nIt );
8073       for ( ; fIt != cFL->end(); fIt++ ) theFaces.push_back( *fIt );
8074       return true;
8075
8076     } // several continuations found
8077   } // while ( nStart != theLastNode )
8078
8079   return true;
8080 }
8081
8082 //=======================================================================
8083 //function : CheckFreeBorderNodes
8084 //purpose  : Return true if the tree nodes are on a free border
8085 //=======================================================================
8086
8087 bool SMESH_MeshEditor::CheckFreeBorderNodes(const SMDS_MeshNode* theNode1,
8088                                             const SMDS_MeshNode* theNode2,
8089                                             const SMDS_MeshNode* theNode3)
8090 {
8091   list< const SMDS_MeshNode* > nodes;
8092   list< const SMDS_MeshElement* > faces;
8093   return FindFreeBorder( theNode1, theNode2, theNode3, nodes, faces);
8094 }
8095
8096 //=======================================================================
8097 //function : SewFreeBorder
8098 //purpose  :
8099 //=======================================================================
8100
8101 SMESH_MeshEditor::Sew_Error
8102 SMESH_MeshEditor::SewFreeBorder (const SMDS_MeshNode* theBordFirstNode,
8103                                  const SMDS_MeshNode* theBordSecondNode,
8104                                  const SMDS_MeshNode* theBordLastNode,
8105                                  const SMDS_MeshNode* theSideFirstNode,
8106                                  const SMDS_MeshNode* theSideSecondNode,
8107                                  const SMDS_MeshNode* theSideThirdNode,
8108                                  const bool           theSideIsFreeBorder,
8109                                  const bool           toCreatePolygons,
8110                                  const bool           toCreatePolyedrs)
8111 {
8112   myLastCreatedElems.Clear();
8113   myLastCreatedNodes.Clear();
8114
8115   MESSAGE("::SewFreeBorder()");
8116   Sew_Error aResult = SEW_OK;
8117
8118   // ====================================
8119   //    find side nodes and elements
8120   // ====================================
8121
8122   list< const SMDS_MeshNode* > nSide[ 2 ];
8123   list< const SMDS_MeshElement* > eSide[ 2 ];
8124   list< const SMDS_MeshNode* >::iterator nIt[ 2 ];
8125   list< const SMDS_MeshElement* >::iterator eIt[ 2 ];
8126
8127   // Free border 1
8128   // --------------
8129   if (!FindFreeBorder(theBordFirstNode,theBordSecondNode,theBordLastNode,
8130                       nSide[0], eSide[0])) {
8131     MESSAGE(" Free Border 1 not found " );
8132     aResult = SEW_BORDER1_NOT_FOUND;
8133   }
8134   if (theSideIsFreeBorder) {
8135     // Free border 2
8136     // --------------
8137     if (!FindFreeBorder(theSideFirstNode, theSideSecondNode, theSideThirdNode,
8138                         nSide[1], eSide[1])) {
8139       MESSAGE(" Free Border 2 not found " );
8140       aResult = ( aResult != SEW_OK ? SEW_BOTH_BORDERS_NOT_FOUND : SEW_BORDER2_NOT_FOUND );
8141     }
8142   }
8143   if ( aResult != SEW_OK )
8144     return aResult;
8145
8146   if (!theSideIsFreeBorder) {
8147     // Side 2
8148     // --------------
8149
8150     // -------------------------------------------------------------------------
8151     // Algo:
8152     // 1. If nodes to merge are not coincident, move nodes of the free border
8153     //    from the coord sys defined by the direction from the first to last
8154     //    nodes of the border to the correspondent sys of the side 2
8155     // 2. On the side 2, find the links most co-directed with the correspondent
8156     //    links of the free border
8157     // -------------------------------------------------------------------------
8158
8159     // 1. Since sewing may break if there are volumes to split on the side 2,
8160     //    we wont move nodes but just compute new coordinates for them
8161     typedef map<const SMDS_MeshNode*, gp_XYZ> TNodeXYZMap;
8162     TNodeXYZMap nBordXYZ;
8163     list< const SMDS_MeshNode* >& bordNodes = nSide[ 0 ];
8164     list< const SMDS_MeshNode* >::iterator nBordIt;
8165
8166     gp_XYZ Pb1( theBordFirstNode->X(), theBordFirstNode->Y(), theBordFirstNode->Z() );
8167     gp_XYZ Pb2( theBordLastNode->X(), theBordLastNode->Y(), theBordLastNode->Z() );
8168     gp_XYZ Ps1( theSideFirstNode->X(), theSideFirstNode->Y(), theSideFirstNode->Z() );
8169     gp_XYZ Ps2( theSideSecondNode->X(), theSideSecondNode->Y(), theSideSecondNode->Z() );
8170     double tol2 = 1.e-8;
8171     gp_Vec Vbs1( Pb1 - Ps1 ),Vbs2( Pb2 - Ps2 );
8172     if ( Vbs1.SquareMagnitude() > tol2 || Vbs2.SquareMagnitude() > tol2 ) {
8173       // Need node movement.
8174
8175       // find X and Z axes to create trsf
8176       gp_Vec Zb( Pb1 - Pb2 ), Zs( Ps1 - Ps2 );
8177       gp_Vec X = Zs ^ Zb;
8178       if ( X.SquareMagnitude() <= gp::Resolution() * gp::Resolution() )
8179         // Zb || Zs
8180         X = gp_Ax2( gp::Origin(), Zb ).XDirection();
8181
8182       // coord systems
8183       gp_Ax3 toBordAx( Pb1, Zb, X );
8184       gp_Ax3 fromSideAx( Ps1, Zs, X );
8185       gp_Ax3 toGlobalAx( gp::Origin(), gp::DZ(), gp::DX() );
8186       // set trsf
8187       gp_Trsf toBordSys, fromSide2Sys;
8188       toBordSys.SetTransformation( toBordAx );
8189       fromSide2Sys.SetTransformation( fromSideAx, toGlobalAx );
8190       fromSide2Sys.SetScaleFactor( Zs.Magnitude() / Zb.Magnitude() );
8191
8192       // move
8193       for ( nBordIt = bordNodes.begin(); nBordIt != bordNodes.end(); nBordIt++ ) {
8194         const SMDS_MeshNode* n = *nBordIt;
8195         gp_XYZ xyz( n->X(),n->Y(),n->Z() );
8196         toBordSys.Transforms( xyz );
8197         fromSide2Sys.Transforms( xyz );
8198         nBordXYZ.insert( TNodeXYZMap::value_type( n, xyz ));
8199       }
8200     }
8201     else {
8202       // just insert nodes XYZ in the nBordXYZ map
8203       for ( nBordIt = bordNodes.begin(); nBordIt != bordNodes.end(); nBordIt++ ) {
8204         const SMDS_MeshNode* n = *nBordIt;
8205         nBordXYZ.insert( TNodeXYZMap::value_type( n, gp_XYZ( n->X(),n->Y(),n->Z() )));
8206       }
8207     }
8208
8209     // 2. On the side 2, find the links most co-directed with the correspondent
8210     //    links of the free border
8211
8212     list< const SMDS_MeshElement* >& sideElems = eSide[ 1 ];
8213     list< const SMDS_MeshNode* >& sideNodes = nSide[ 1 ];
8214     sideNodes.push_back( theSideFirstNode );
8215
8216     bool hasVolumes = false;
8217     LinkID_Gen aLinkID_Gen( GetMeshDS() );
8218     set<long> foundSideLinkIDs, checkedLinkIDs;
8219     SMDS_VolumeTool volume;
8220     //const SMDS_MeshNode* faceNodes[ 4 ];
8221
8222     const SMDS_MeshNode*    sideNode;
8223     const SMDS_MeshElement* sideElem;
8224     const SMDS_MeshNode* prevSideNode = theSideFirstNode;
8225     const SMDS_MeshNode* prevBordNode = theBordFirstNode;
8226     nBordIt = bordNodes.begin();
8227     nBordIt++;
8228     // border node position and border link direction to compare with
8229     gp_XYZ bordPos = nBordXYZ[ *nBordIt ];
8230     gp_XYZ bordDir = bordPos - nBordXYZ[ prevBordNode ];
8231     // choose next side node by link direction or by closeness to
8232     // the current border node:
8233     bool searchByDir = ( *nBordIt != theBordLastNode );
8234     do {
8235       // find the next node on the Side 2
8236       sideNode = 0;
8237       double maxDot = -DBL_MAX, minDist = DBL_MAX;
8238       long linkID;
8239       checkedLinkIDs.clear();
8240       gp_XYZ prevXYZ( prevSideNode->X(), prevSideNode->Y(), prevSideNode->Z() );
8241
8242       // loop on inverse elements of current node (prevSideNode) on the Side 2
8243       SMDS_ElemIteratorPtr invElemIt = prevSideNode->GetInverseElementIterator();
8244       while ( invElemIt->more() )
8245       {
8246         const SMDS_MeshElement* elem = invElemIt->next();
8247         // prepare data for a loop on links coming to prevSideNode, of a face or a volume
8248         int iPrevNode, iNode = 0, nbNodes = elem->NbNodes();
8249         vector< const SMDS_MeshNode* > faceNodes( nbNodes, (const SMDS_MeshNode*)0 );
8250         bool isVolume = volume.Set( elem );
8251         const SMDS_MeshNode** nodes = isVolume ? volume.GetNodes() : & faceNodes[0];
8252         if ( isVolume ) // --volume
8253           hasVolumes = true;
8254         else if ( elem->GetType()==SMDSAbs_Face ) { // --face
8255           // retrieve all face nodes and find iPrevNode - an index of the prevSideNode
8256           if(elem->IsQuadratic()) {
8257             const SMDS_VtkFace* F =
8258               dynamic_cast<const SMDS_VtkFace*>(elem);
8259             if (!F) throw SALOME_Exception(LOCALIZED("not an SMDS_VtkFace"));
8260             // use special nodes iterator
8261             SMDS_ElemIteratorPtr anIter = F->interlacedNodesElemIterator();
8262             while( anIter->more() ) {
8263               nodes[ iNode ] = cast2Node(anIter->next());
8264               if ( nodes[ iNode++ ] == prevSideNode )
8265                 iPrevNode = iNode - 1;
8266             }
8267           }
8268           else {
8269             SMDS_ElemIteratorPtr nIt = elem->nodesIterator();
8270             while ( nIt->more() ) {
8271               nodes[ iNode ] = cast2Node( nIt->next() );
8272               if ( nodes[ iNode++ ] == prevSideNode )
8273                 iPrevNode = iNode - 1;
8274             }
8275           }
8276           // there are 2 links to check
8277           nbNodes = 2;
8278         }
8279         else // --edge
8280           continue;
8281         // loop on links, to be precise, on the second node of links
8282         for ( iNode = 0; iNode < nbNodes; iNode++ ) {
8283           const SMDS_MeshNode* n = nodes[ iNode ];
8284           if ( isVolume ) {
8285             if ( !volume.IsLinked( n, prevSideNode ))
8286               continue;
8287           }
8288           else {
8289             if ( iNode ) // a node before prevSideNode
8290               n = nodes[ iPrevNode == 0 ? elem->NbNodes() - 1 : iPrevNode - 1 ];
8291             else         // a node after prevSideNode
8292               n = nodes[ iPrevNode + 1 == elem->NbNodes() ? 0 : iPrevNode + 1 ];
8293           }
8294           // check if this link was already used
8295           long iLink = aLinkID_Gen.GetLinkID( prevSideNode, n );
8296           bool isJustChecked = !checkedLinkIDs.insert( iLink ).second;
8297           if (!isJustChecked &&
8298               foundSideLinkIDs.find( iLink ) == foundSideLinkIDs.end() )
8299           {
8300             // test a link geometrically
8301             gp_XYZ nextXYZ ( n->X(), n->Y(), n->Z() );
8302             bool linkIsBetter = false;
8303             double dot = 0.0, dist = 0.0;
8304             if ( searchByDir ) { // choose most co-directed link
8305               dot = bordDir * ( nextXYZ - prevXYZ ).Normalized();
8306               linkIsBetter = ( dot > maxDot );
8307             }
8308             else { // choose link with the node closest to bordPos
8309               dist = ( nextXYZ - bordPos ).SquareModulus();
8310               linkIsBetter = ( dist < minDist );
8311             }
8312             if ( linkIsBetter ) {
8313               maxDot = dot;
8314               minDist = dist;
8315               linkID = iLink;
8316               sideNode = n;
8317               sideElem = elem;
8318             }
8319           }
8320         }
8321       } // loop on inverse elements of prevSideNode
8322
8323       if ( !sideNode ) {
8324         MESSAGE(" Cant find path by links of the Side 2 ");
8325         return SEW_BAD_SIDE_NODES;
8326       }
8327       sideNodes.push_back( sideNode );
8328       sideElems.push_back( sideElem );
8329       foundSideLinkIDs.insert ( linkID );
8330       prevSideNode = sideNode;
8331
8332       if ( *nBordIt == theBordLastNode )
8333         searchByDir = false;
8334       else {
8335         // find the next border link to compare with
8336         gp_XYZ sidePos( sideNode->X(), sideNode->Y(), sideNode->Z() );
8337         searchByDir = ( bordDir * ( sidePos - bordPos ) <= 0 );
8338         // move to next border node if sideNode is before forward border node (bordPos)
8339         while ( *nBordIt != theBordLastNode && !searchByDir ) {
8340           prevBordNode = *nBordIt;
8341           nBordIt++;
8342           bordPos = nBordXYZ[ *nBordIt ];
8343           bordDir = bordPos - nBordXYZ[ prevBordNode ];
8344           searchByDir = ( bordDir * ( sidePos - bordPos ) <= 0 );
8345         }
8346       }
8347     }
8348     while ( sideNode != theSideSecondNode );
8349
8350     if ( hasVolumes && sideNodes.size () != bordNodes.size() && !toCreatePolyedrs) {
8351       MESSAGE("VOLUME SPLITTING IS FORBIDDEN");
8352       return SEW_VOLUMES_TO_SPLIT; // volume splitting is forbidden
8353     }
8354   } // end nodes search on the side 2
8355
8356   // ============================
8357   // sew the border to the side 2
8358   // ============================
8359
8360   int nbNodes[]  = { nSide[0].size(), nSide[1].size() };
8361   int maxNbNodes = Max( nbNodes[0], nbNodes[1] );
8362
8363   TListOfListOfNodes nodeGroupsToMerge;
8364   if ( nbNodes[0] == nbNodes[1] ||
8365        ( theSideIsFreeBorder && !theSideThirdNode)) {
8366
8367     // all nodes are to be merged
8368
8369     for (nIt[0] = nSide[0].begin(), nIt[1] = nSide[1].begin();
8370          nIt[0] != nSide[0].end() && nIt[1] != nSide[1].end();
8371          nIt[0]++, nIt[1]++ )
8372     {
8373       nodeGroupsToMerge.push_back( list<const SMDS_MeshNode*>() );
8374       nodeGroupsToMerge.back().push_back( *nIt[1] ); // to keep
8375       nodeGroupsToMerge.back().push_back( *nIt[0] ); // to remove
8376     }
8377   }
8378   else {
8379
8380     // insert new nodes into the border and the side to get equal nb of segments
8381
8382     // get normalized parameters of nodes on the borders
8383     //double param[ 2 ][ maxNbNodes ];
8384     double* param[ 2 ];
8385     param[0] = new double [ maxNbNodes ];
8386     param[1] = new double [ maxNbNodes ];
8387     int iNode, iBord;
8388     for ( iBord = 0; iBord < 2; iBord++ ) { // loop on 2 borders
8389       list< const SMDS_MeshNode* >& nodes = nSide[ iBord ];
8390       list< const SMDS_MeshNode* >::iterator nIt = nodes.begin();
8391       const SMDS_MeshNode* nPrev = *nIt;
8392       double bordLength = 0;
8393       for ( iNode = 0; nIt != nodes.end(); nIt++, iNode++ ) { // loop on border nodes
8394         const SMDS_MeshNode* nCur = *nIt;
8395         gp_XYZ segment (nCur->X() - nPrev->X(),
8396                         nCur->Y() - nPrev->Y(),
8397                         nCur->Z() - nPrev->Z());
8398         double segmentLen = segment.Modulus();
8399         bordLength += segmentLen;
8400         param[ iBord ][ iNode ] = bordLength;
8401         nPrev = nCur;
8402       }
8403       // normalize within [0,1]
8404       for ( iNode = 0; iNode < nbNodes[ iBord ]; iNode++ ) {
8405         param[ iBord ][ iNode ] /= bordLength;
8406       }
8407     }
8408
8409     // loop on border segments
8410     const SMDS_MeshNode *nPrev[ 2 ] = { 0, 0 };
8411     int i[ 2 ] = { 0, 0 };
8412     nIt[0] = nSide[0].begin(); eIt[0] = eSide[0].begin();
8413     nIt[1] = nSide[1].begin(); eIt[1] = eSide[1].begin();
8414
8415     TElemOfNodeListMap insertMap;
8416     TElemOfNodeListMap::iterator insertMapIt;
8417     // insertMap is
8418     // key:   elem to insert nodes into
8419     // value: 2 nodes to insert between + nodes to be inserted
8420     do {
8421       bool next[ 2 ] = { false, false };
8422
8423       // find min adjacent segment length after sewing
8424       double nextParam = 10., prevParam = 0;
8425       for ( iBord = 0; iBord < 2; iBord++ ) { // loop on 2 borders
8426         if ( i[ iBord ] + 1 < nbNodes[ iBord ])
8427           nextParam = Min( nextParam, param[iBord][ i[iBord] + 1 ]);
8428         if ( i[ iBord ] > 0 )
8429           prevParam = Max( prevParam, param[iBord][ i[iBord] - 1 ]);
8430       }
8431       double minParam = Min( param[ 0 ][ i[0] ], param[ 1 ][ i[1] ]);
8432       double maxParam = Max( param[ 0 ][ i[0] ], param[ 1 ][ i[1] ]);
8433       double minSegLen = Min( nextParam - minParam, maxParam - prevParam );
8434
8435       // choose to insert or to merge nodes
8436       double du = param[ 1 ][ i[1] ] - param[ 0 ][ i[0] ];
8437       if ( Abs( du ) <= minSegLen * 0.2 ) {
8438         // merge
8439         // ------
8440         nodeGroupsToMerge.push_back( list<const SMDS_MeshNode*>() );
8441         const SMDS_MeshNode* n0 = *nIt[0];
8442         const SMDS_MeshNode* n1 = *nIt[1];
8443         nodeGroupsToMerge.back().push_back( n1 );
8444         nodeGroupsToMerge.back().push_back( n0 );
8445         // position of node of the border changes due to merge
8446         param[ 0 ][ i[0] ] += du;
8447         // move n1 for the sake of elem shape evaluation during insertion.
8448         // n1 will be removed by MergeNodes() anyway
8449         const_cast<SMDS_MeshNode*>( n0 )->setXYZ( n1->X(), n1->Y(), n1->Z() );
8450         next[0] = next[1] = true;
8451       }
8452       else {
8453         // insert
8454         // ------
8455         int intoBord = ( du < 0 ) ? 0 : 1;
8456         const SMDS_MeshElement* elem = *eIt[ intoBord ];
8457         const SMDS_MeshNode*    n1   = nPrev[ intoBord ];
8458         const SMDS_MeshNode*    n2   = *nIt[ intoBord ];
8459         const SMDS_MeshNode*    nIns = *nIt[ 1 - intoBord ];
8460         if ( intoBord == 1 ) {
8461           // move node of the border to be on a link of elem of the side
8462           gp_XYZ p1 (n1->X(), n1->Y(), n1->Z());
8463           gp_XYZ p2 (n2->X(), n2->Y(), n2->Z());
8464           double ratio = du / ( param[ 1 ][ i[1] ] - param[ 1 ][ i[1]-1 ]);
8465           gp_XYZ p = p2 * ( 1 - ratio ) + p1 * ratio;
8466           GetMeshDS()->MoveNode( nIns, p.X(), p.Y(), p.Z() );
8467         }
8468         insertMapIt = insertMap.find( elem );
8469         bool notFound = ( insertMapIt == insertMap.end() );
8470         bool otherLink = ( !notFound && (*insertMapIt).second.front() != n1 );
8471         if ( otherLink ) {
8472           // insert into another link of the same element:
8473           // 1. perform insertion into the other link of the elem
8474           list<const SMDS_MeshNode*> & nodeList = (*insertMapIt).second;
8475           const SMDS_MeshNode* n12 = nodeList.front(); nodeList.pop_front();
8476           const SMDS_MeshNode* n22 = nodeList.front(); nodeList.pop_front();
8477           InsertNodesIntoLink( elem, n12, n22, nodeList, toCreatePolygons );
8478           // 2. perform insertion into the link of adjacent faces
8479           while (true) {
8480             const SMDS_MeshElement* adjElem = findAdjacentFace( n12, n22, elem );
8481             if ( adjElem )
8482               InsertNodesIntoLink( adjElem, n12, n22, nodeList, toCreatePolygons );
8483             else
8484               break;
8485           }
8486           if (toCreatePolyedrs) {
8487             // perform insertion into the links of adjacent volumes
8488             UpdateVolumes(n12, n22, nodeList);
8489           }
8490           // 3. find an element appeared on n1 and n2 after the insertion
8491           insertMap.erase( elem );
8492           elem = findAdjacentFace( n1, n2, 0 );
8493         }
8494         if ( notFound || otherLink ) {
8495           // add element and nodes of the side into the insertMap
8496           insertMapIt = insertMap.insert
8497             ( TElemOfNodeListMap::value_type( elem, list<const SMDS_MeshNode*>() )).first;
8498           (*insertMapIt).second.push_back( n1 );
8499           (*insertMapIt).second.push_back( n2 );
8500         }
8501         // add node to be inserted into elem
8502         (*insertMapIt).second.push_back( nIns );
8503         next[ 1 - intoBord ] = true;
8504       }
8505
8506       // go to the next segment
8507       for ( iBord = 0; iBord < 2; iBord++ ) { // loop on 2 borders
8508         if ( next[ iBord ] ) {
8509           if ( i[ iBord ] != 0 && eIt[ iBord ] != eSide[ iBord ].end())
8510             eIt[ iBord ]++;
8511           nPrev[ iBord ] = *nIt[ iBord ];
8512           nIt[ iBord ]++; i[ iBord ]++;
8513         }
8514       }
8515     }
8516     while ( nIt[0] != nSide[0].end() && nIt[1] != nSide[1].end());
8517
8518     // perform insertion of nodes into elements
8519
8520     for (insertMapIt = insertMap.begin();
8521          insertMapIt != insertMap.end();
8522          insertMapIt++ )
8523     {
8524       const SMDS_MeshElement* elem = (*insertMapIt).first;
8525       list<const SMDS_MeshNode*> & nodeList = (*insertMapIt).second;
8526       const SMDS_MeshNode* n1 = nodeList.front(); nodeList.pop_front();
8527       const SMDS_MeshNode* n2 = nodeList.front(); nodeList.pop_front();
8528
8529       InsertNodesIntoLink( elem, n1, n2, nodeList, toCreatePolygons );
8530
8531       if ( !theSideIsFreeBorder ) {
8532         // look for and insert nodes into the faces adjacent to elem
8533         while (true) {
8534           const SMDS_MeshElement* adjElem = findAdjacentFace( n1, n2, elem );
8535           if ( adjElem )
8536             InsertNodesIntoLink( adjElem, n1, n2, nodeList, toCreatePolygons );
8537           else
8538             break;
8539         }
8540       }
8541       if (toCreatePolyedrs) {
8542         // perform insertion into the links of adjacent volumes
8543         UpdateVolumes(n1, n2, nodeList);
8544       }
8545     }
8546
8547     delete param[0];
8548     delete param[1];
8549   } // end: insert new nodes
8550
8551   MergeNodes ( nodeGroupsToMerge );
8552
8553   return aResult;
8554 }
8555
8556 //=======================================================================
8557 //function : InsertNodesIntoLink
8558 //purpose  : insert theNodesToInsert into theFace between theBetweenNode1
8559 //           and theBetweenNode2 and split theElement
8560 //=======================================================================
8561
8562 void SMESH_MeshEditor::InsertNodesIntoLink(const SMDS_MeshElement*     theFace,
8563                                            const SMDS_MeshNode*        theBetweenNode1,
8564                                            const SMDS_MeshNode*        theBetweenNode2,
8565                                            list<const SMDS_MeshNode*>& theNodesToInsert,
8566                                            const bool                  toCreatePoly)
8567 {
8568   if ( theFace->GetType() != SMDSAbs_Face ) return;
8569
8570   // find indices of 2 link nodes and of the rest nodes
8571   int iNode = 0, il1, il2, i3, i4;
8572   il1 = il2 = i3 = i4 = -1;
8573   //const SMDS_MeshNode* nodes[ theFace->NbNodes() ];
8574   vector<const SMDS_MeshNode*> nodes( theFace->NbNodes() );
8575
8576   if(theFace->IsQuadratic()) {
8577     const SMDS_VtkFace* F =
8578       dynamic_cast<const SMDS_VtkFace*>(theFace);
8579     if (!F) throw SALOME_Exception(LOCALIZED("not an SMDS_VtkFace"));
8580     // use special nodes iterator
8581     SMDS_ElemIteratorPtr anIter = F->interlacedNodesElemIterator();
8582     while( anIter->more() ) {
8583       const SMDS_MeshNode* n = cast2Node(anIter->next());
8584       if ( n == theBetweenNode1 )
8585         il1 = iNode;
8586       else if ( n == theBetweenNode2 )
8587         il2 = iNode;
8588       else if ( i3 < 0 )
8589         i3 = iNode;
8590       else
8591         i4 = iNode;
8592       nodes[ iNode++ ] = n;
8593     }
8594   }
8595   else {
8596     SMDS_ElemIteratorPtr nodeIt = theFace->nodesIterator();
8597     while ( nodeIt->more() ) {
8598       const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
8599       if ( n == theBetweenNode1 )
8600         il1 = iNode;
8601       else if ( n == theBetweenNode2 )
8602         il2 = iNode;
8603       else if ( i3 < 0 )
8604         i3 = iNode;
8605       else
8606         i4 = iNode;
8607       nodes[ iNode++ ] = n;
8608     }
8609   }
8610   if ( il1 < 0 || il2 < 0 || i3 < 0 )
8611     return ;
8612
8613   // arrange link nodes to go one after another regarding the face orientation
8614   bool reverse = ( Abs( il2 - il1 ) == 1 ? il2 < il1 : il1 < il2 );
8615   list<const SMDS_MeshNode *> aNodesToInsert = theNodesToInsert;
8616   if ( reverse ) {
8617     iNode = il1;
8618     il1 = il2;
8619     il2 = iNode;
8620     aNodesToInsert.reverse();
8621   }
8622   // check that not link nodes of a quadrangles are in good order
8623   int nbFaceNodes = theFace->NbNodes();
8624   if ( nbFaceNodes == 4 && i4 - i3 != 1 ) {
8625     iNode = i3;
8626     i3 = i4;
8627     i4 = iNode;
8628   }
8629
8630   if (toCreatePoly || theFace->IsPoly()) {
8631
8632     iNode = 0;
8633     vector<const SMDS_MeshNode *> poly_nodes (nbFaceNodes + aNodesToInsert.size());
8634
8635     // add nodes of face up to first node of link
8636     bool isFLN = false;
8637
8638     if(theFace->IsQuadratic()) {
8639       const SMDS_VtkFace* F =
8640         dynamic_cast<const SMDS_VtkFace*>(theFace);
8641       if (!F) throw SALOME_Exception(LOCALIZED("not an SMDS_VtkFace"));
8642       // use special nodes iterator
8643       SMDS_ElemIteratorPtr anIter = F->interlacedNodesElemIterator();
8644       while( anIter->more()  && !isFLN ) {
8645         const SMDS_MeshNode* n = cast2Node(anIter->next());
8646         poly_nodes[iNode++] = n;
8647         if (n == nodes[il1]) {
8648           isFLN = true;
8649         }
8650       }
8651       // add nodes to insert
8652       list<const SMDS_MeshNode*>::iterator nIt = aNodesToInsert.begin();
8653       for (; nIt != aNodesToInsert.end(); nIt++) {
8654         poly_nodes[iNode++] = *nIt;
8655       }
8656       // add nodes of face starting from last node of link
8657       while ( anIter->more() ) {
8658         poly_nodes[iNode++] = cast2Node(anIter->next());
8659       }
8660     }
8661     else {
8662       SMDS_ElemIteratorPtr nodeIt = theFace->nodesIterator();
8663       while ( nodeIt->more() && !isFLN ) {
8664         const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
8665         poly_nodes[iNode++] = n;
8666         if (n == nodes[il1]) {
8667           isFLN = true;
8668         }
8669       }
8670       // add nodes to insert
8671       list<const SMDS_MeshNode*>::iterator nIt = aNodesToInsert.begin();
8672       for (; nIt != aNodesToInsert.end(); nIt++) {
8673         poly_nodes[iNode++] = *nIt;
8674       }
8675       // add nodes of face starting from last node of link
8676       while ( nodeIt->more() ) {
8677         const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
8678         poly_nodes[iNode++] = n;
8679       }
8680     }
8681
8682     // edit or replace the face
8683     SMESHDS_Mesh *aMesh = GetMeshDS();
8684
8685     if (theFace->IsPoly()) {
8686       aMesh->ChangePolygonNodes(theFace, poly_nodes);
8687     }
8688     else {
8689       int aShapeId = FindShape( theFace );
8690
8691       SMDS_MeshElement* newElem = aMesh->AddPolygonalFace(poly_nodes);
8692       myLastCreatedElems.Append(newElem);
8693       if ( aShapeId && newElem )
8694         aMesh->SetMeshElementOnShape( newElem, aShapeId );
8695
8696       aMesh->RemoveElement(theFace);
8697     }
8698     return;
8699   }
8700
8701   SMESHDS_Mesh *aMesh = GetMeshDS();
8702   if( !theFace->IsQuadratic() ) {
8703
8704     // put aNodesToInsert between theBetweenNode1 and theBetweenNode2
8705     int nbLinkNodes = 2 + aNodesToInsert.size();
8706     //const SMDS_MeshNode* linkNodes[ nbLinkNodes ];
8707     vector<const SMDS_MeshNode*> linkNodes( nbLinkNodes );
8708     linkNodes[ 0 ] = nodes[ il1 ];
8709     linkNodes[ nbLinkNodes - 1 ] = nodes[ il2 ];
8710     list<const SMDS_MeshNode*>::iterator nIt = aNodesToInsert.begin();
8711     for ( iNode = 1; nIt != aNodesToInsert.end(); nIt++ ) {
8712       linkNodes[ iNode++ ] = *nIt;
8713     }
8714     // decide how to split a quadrangle: compare possible variants
8715     // and choose which of splits to be a quadrangle
8716     int i1, i2, iSplit, nbSplits = nbLinkNodes - 1, iBestQuad;
8717     if ( nbFaceNodes == 3 ) {
8718       iBestQuad = nbSplits;
8719       i4 = i3;
8720     }
8721     else if ( nbFaceNodes == 4 ) {
8722       SMESH::Controls::NumericalFunctorPtr aCrit( new SMESH::Controls::AspectRatio);
8723       double aBestRate = DBL_MAX;
8724       for ( int iQuad = 0; iQuad < nbSplits; iQuad++ ) {
8725         i1 = 0; i2 = 1;
8726         double aBadRate = 0;
8727         // evaluate elements quality
8728         for ( iSplit = 0; iSplit < nbSplits; iSplit++ ) {
8729           if ( iSplit == iQuad ) {
8730             SMDS_FaceOfNodes quad (linkNodes[ i1++ ],
8731                                    linkNodes[ i2++ ],
8732                                    nodes[ i3 ],
8733                                    nodes[ i4 ]);
8734             aBadRate += getBadRate( &quad, aCrit );
8735           }
8736           else {
8737             SMDS_FaceOfNodes tria (linkNodes[ i1++ ],
8738                                    linkNodes[ i2++ ],
8739                                    nodes[ iSplit < iQuad ? i4 : i3 ]);
8740             aBadRate += getBadRate( &tria, aCrit );
8741           }
8742         }
8743         // choice
8744         if ( aBadRate < aBestRate ) {
8745           iBestQuad = iQuad;
8746           aBestRate = aBadRate;
8747         }
8748       }
8749     }
8750
8751     // create new elements
8752     int aShapeId = FindShape( theFace );
8753
8754     i1 = 0; i2 = 1;
8755     for ( iSplit = 0; iSplit < nbSplits - 1; iSplit++ ) {
8756       SMDS_MeshElement* newElem = 0;
8757       if ( iSplit == iBestQuad )
8758         newElem = aMesh->AddFace (linkNodes[ i1++ ],
8759                                   linkNodes[ i2++ ],
8760                                   nodes[ i3 ],
8761                                   nodes[ i4 ]);
8762       else
8763         newElem = aMesh->AddFace (linkNodes[ i1++ ],
8764                                   linkNodes[ i2++ ],
8765                                   nodes[ iSplit < iBestQuad ? i4 : i3 ]);
8766       myLastCreatedElems.Append(newElem);
8767       if ( aShapeId && newElem )
8768         aMesh->SetMeshElementOnShape( newElem, aShapeId );
8769     }
8770
8771     // change nodes of theFace
8772     const SMDS_MeshNode* newNodes[ 4 ];
8773     newNodes[ 0 ] = linkNodes[ i1 ];
8774     newNodes[ 1 ] = linkNodes[ i2 ];
8775     newNodes[ 2 ] = nodes[ iSplit >= iBestQuad ? i3 : i4 ];
8776     newNodes[ 3 ] = nodes[ i4 ];
8777     //aMesh->ChangeElementNodes( theFace, newNodes, iSplit == iBestQuad ? 4 : 3 );
8778     const SMDS_MeshElement* newElem = 0;
8779     if (iSplit == iBestQuad)
8780       newElem = aMesh->AddFace( newNodes[0], newNodes[1], newNodes[2], newNodes[3] );
8781     else
8782       newElem = aMesh->AddFace( newNodes[0], newNodes[1], newNodes[2] );
8783     myLastCreatedElems.Append(newElem);
8784     if ( aShapeId && newElem )
8785       aMesh->SetMeshElementOnShape( newElem, aShapeId );
8786 } // end if(!theFace->IsQuadratic())
8787   else { // theFace is quadratic
8788     // we have to split theFace on simple triangles and one simple quadrangle
8789     int tmp = il1/2;
8790     int nbshift = tmp*2;
8791     // shift nodes in nodes[] by nbshift
8792     int i,j;
8793     for(i=0; i<nbshift; i++) {
8794       const SMDS_MeshNode* n = nodes[0];
8795       for(j=0; j<nbFaceNodes-1; j++) {
8796         nodes[j] = nodes[j+1];
8797       }
8798       nodes[nbFaceNodes-1] = n;
8799     }
8800     il1 = il1 - nbshift;
8801     // now have to insert nodes between n0 and n1 or n1 and n2 (see below)
8802     //   n0      n1     n2    n0      n1     n2
8803     //     +-----+-----+        +-----+-----+
8804     //      \         /         |           |
8805     //       \       /          |           |
8806     //      n5+     +n3       n7+           +n3
8807     //         \   /            |           |
8808     //          \ /             |           |
8809     //           +              +-----+-----+
8810     //           n4           n6      n5     n4
8811
8812     // create new elements
8813     int aShapeId = FindShape( theFace );
8814
8815     int n1,n2,n3;
8816     if(nbFaceNodes==6) { // quadratic triangle
8817       SMDS_MeshElement* newElem =
8818         aMesh->AddFace(nodes[3],nodes[4],nodes[5]);
8819       myLastCreatedElems.Append(newElem);
8820       if ( aShapeId && newElem )
8821         aMesh->SetMeshElementOnShape( newElem, aShapeId );
8822       if(theFace->IsMediumNode(nodes[il1])) {
8823         // create quadrangle
8824         newElem = aMesh->AddFace(nodes[0],nodes[1],nodes[3],nodes[5]);
8825         myLastCreatedElems.Append(newElem);
8826         if ( aShapeId && newElem )
8827           aMesh->SetMeshElementOnShape( newElem, aShapeId );
8828         n1 = 1;
8829         n2 = 2;
8830         n3 = 3;
8831       }
8832       else {
8833         // create quadrangle
8834         newElem = aMesh->AddFace(nodes[1],nodes[2],nodes[3],nodes[5]);
8835         myLastCreatedElems.Append(newElem);
8836         if ( aShapeId && newElem )
8837           aMesh->SetMeshElementOnShape( newElem, aShapeId );
8838         n1 = 0;
8839         n2 = 1;
8840         n3 = 5;
8841       }
8842     }
8843     else { // nbFaceNodes==8 - quadratic quadrangle
8844       SMDS_MeshElement* newElem =
8845         aMesh->AddFace(nodes[3],nodes[4],nodes[5]);
8846       myLastCreatedElems.Append(newElem);
8847       if ( aShapeId && newElem )
8848         aMesh->SetMeshElementOnShape( newElem, aShapeId );
8849       newElem = aMesh->AddFace(nodes[5],nodes[6],nodes[7]);
8850       myLastCreatedElems.Append(newElem);
8851       if ( aShapeId && newElem )
8852         aMesh->SetMeshElementOnShape( newElem, aShapeId );
8853       newElem = aMesh->AddFace(nodes[5],nodes[7],nodes[3]);
8854       myLastCreatedElems.Append(newElem);
8855       if ( aShapeId && newElem )
8856         aMesh->SetMeshElementOnShape( newElem, aShapeId );
8857       if(theFace->IsMediumNode(nodes[il1])) {
8858         // create quadrangle
8859         newElem = aMesh->AddFace(nodes[0],nodes[1],nodes[3],nodes[7]);
8860         myLastCreatedElems.Append(newElem);
8861         if ( aShapeId && newElem )
8862           aMesh->SetMeshElementOnShape( newElem, aShapeId );
8863         n1 = 1;
8864         n2 = 2;
8865         n3 = 3;
8866       }
8867       else {
8868         // create quadrangle
8869         newElem = aMesh->AddFace(nodes[1],nodes[2],nodes[3],nodes[7]);
8870         myLastCreatedElems.Append(newElem);
8871         if ( aShapeId && newElem )
8872           aMesh->SetMeshElementOnShape( newElem, aShapeId );
8873         n1 = 0;
8874         n2 = 1;
8875         n3 = 7;
8876       }
8877     }
8878     // create needed triangles using n1,n2,n3 and inserted nodes
8879     int nbn = 2 + aNodesToInsert.size();
8880     //const SMDS_MeshNode* aNodes[nbn];
8881     vector<const SMDS_MeshNode*> aNodes(nbn);
8882     aNodes[0] = nodes[n1];
8883     aNodes[nbn-1] = nodes[n2];
8884     list<const SMDS_MeshNode*>::iterator nIt = aNodesToInsert.begin();
8885     for ( iNode = 1; nIt != aNodesToInsert.end(); nIt++ ) {
8886       aNodes[iNode++] = *nIt;
8887     }
8888     for(i=1; i<nbn; i++) {
8889       SMDS_MeshElement* newElem =
8890         aMesh->AddFace(aNodes[i-1],aNodes[i],nodes[n3]);
8891       myLastCreatedElems.Append(newElem);
8892       if ( aShapeId && newElem )
8893         aMesh->SetMeshElementOnShape( newElem, aShapeId );
8894     }
8895   }
8896   // remove old face
8897   aMesh->RemoveElement(theFace);
8898 }
8899
8900 //=======================================================================
8901 //function : UpdateVolumes
8902 //purpose  :
8903 //=======================================================================
8904 void SMESH_MeshEditor::UpdateVolumes (const SMDS_MeshNode*        theBetweenNode1,
8905                                       const SMDS_MeshNode*        theBetweenNode2,
8906                                       list<const SMDS_MeshNode*>& theNodesToInsert)
8907 {
8908   myLastCreatedElems.Clear();
8909   myLastCreatedNodes.Clear();
8910
8911   SMDS_ElemIteratorPtr invElemIt = theBetweenNode1->GetInverseElementIterator(SMDSAbs_Volume);
8912   while (invElemIt->more()) { // loop on inverse elements of theBetweenNode1
8913     const SMDS_MeshElement* elem = invElemIt->next();
8914
8915     // check, if current volume has link theBetweenNode1 - theBetweenNode2
8916     SMDS_VolumeTool aVolume (elem);
8917     if (!aVolume.IsLinked(theBetweenNode1, theBetweenNode2))
8918       continue;
8919
8920     // insert new nodes in all faces of the volume, sharing link theBetweenNode1 - theBetweenNode2
8921     int iface, nbFaces = aVolume.NbFaces();
8922     vector<const SMDS_MeshNode *> poly_nodes;
8923     vector<int> quantities (nbFaces);
8924
8925     for (iface = 0; iface < nbFaces; iface++) {
8926       int nbFaceNodes = aVolume.NbFaceNodes(iface), nbInserted = 0;
8927       // faceNodes will contain (nbFaceNodes + 1) nodes, last = first
8928       const SMDS_MeshNode** faceNodes = aVolume.GetFaceNodes(iface);
8929
8930       for (int inode = 0; inode < nbFaceNodes; inode++) {
8931         poly_nodes.push_back(faceNodes[inode]);
8932
8933         if (nbInserted == 0) {
8934           if (faceNodes[inode] == theBetweenNode1) {
8935             if (faceNodes[inode + 1] == theBetweenNode2) {
8936               nbInserted = theNodesToInsert.size();
8937
8938               // add nodes to insert
8939               list<const SMDS_MeshNode*>::iterator nIt = theNodesToInsert.begin();
8940               for (; nIt != theNodesToInsert.end(); nIt++) {
8941                 poly_nodes.push_back(*nIt);
8942               }
8943             }
8944           }
8945           else if (faceNodes[inode] == theBetweenNode2) {
8946             if (faceNodes[inode + 1] == theBetweenNode1) {
8947               nbInserted = theNodesToInsert.size();
8948
8949               // add nodes to insert in reversed order
8950               list<const SMDS_MeshNode*>::iterator nIt = theNodesToInsert.end();
8951               nIt--;
8952               for (; nIt != theNodesToInsert.begin(); nIt--) {
8953                 poly_nodes.push_back(*nIt);
8954               }
8955               poly_nodes.push_back(*nIt);
8956             }
8957           }
8958           else {
8959           }
8960         }
8961       }
8962       quantities[iface] = nbFaceNodes + nbInserted;
8963     }
8964
8965     // Replace or update the volume
8966     SMESHDS_Mesh *aMesh = GetMeshDS();
8967
8968     if (elem->IsPoly()) {
8969       aMesh->ChangePolyhedronNodes(elem, poly_nodes, quantities);
8970
8971     }
8972     else {
8973       int aShapeId = FindShape( elem );
8974
8975       SMDS_MeshElement* newElem =
8976         aMesh->AddPolyhedralVolume(poly_nodes, quantities);
8977       myLastCreatedElems.Append(newElem);
8978       if (aShapeId && newElem)
8979         aMesh->SetMeshElementOnShape(newElem, aShapeId);
8980
8981       aMesh->RemoveElement(elem);
8982     }
8983   }
8984 }
8985
8986 namespace
8987 {
8988   //================================================================================
8989   /*!
8990    * \brief Transform any volume into data of SMDSEntity_Polyhedra
8991    */
8992   //================================================================================
8993
8994   void volumeToPolyhedron( const SMDS_MeshElement*         elem,
8995                            vector<const SMDS_MeshNode *> & nodes,
8996                            vector<int> &                   nbNodeInFaces )
8997   {
8998     nodes.clear();
8999     nbNodeInFaces.clear();
9000     SMDS_VolumeTool vTool ( elem );
9001     for ( int iF = 0; iF < vTool.NbFaces(); ++iF )
9002     {
9003       const SMDS_MeshNode** fNodes = vTool.GetFaceNodes( iF );
9004       nodes.insert( nodes.end(), fNodes, fNodes + vTool.NbFaceNodes( iF ));
9005       nbNodeInFaces.push_back( vTool.NbFaceNodes( iF ));
9006     }
9007   }
9008 }
9009
9010 //=======================================================================
9011 /*!
9012  * \brief Convert elements contained in a submesh to quadratic
9013  * \return int - nb of checked elements
9014  */
9015 //=======================================================================
9016
9017 int SMESH_MeshEditor::convertElemToQuadratic(SMESHDS_SubMesh *   theSm,
9018                                              SMESH_MesherHelper& theHelper,
9019                                              const bool          theForce3d)
9020 {
9021   int nbElem = 0;
9022   if( !theSm ) return nbElem;
9023
9024   vector<int> nbNodeInFaces;
9025   vector<const SMDS_MeshNode *> nodes;
9026   SMDS_ElemIteratorPtr ElemItr = theSm->GetElements();
9027   while(ElemItr->more())
9028   {
9029     nbElem++;
9030     const SMDS_MeshElement* elem = ElemItr->next();
9031     if( !elem || elem->IsQuadratic() ) continue;
9032
9033     // get elem data needed to re-create it
9034     //
9035     int id = elem->GetID();
9036     int nbNodes = elem->NbNodes();
9037     SMDSAbs_ElementType aType = elem->GetType();
9038     nodes.assign(elem->begin_nodes(), elem->end_nodes());
9039     if ( elem->GetEntityType() == SMDSEntity_Polyhedra )
9040       nbNodeInFaces = static_cast<const SMDS_VtkVolume* >( elem )->GetQuantities();
9041     else if ( elem->GetEntityType() == SMDSEntity_Hexagonal_Prism )
9042       volumeToPolyhedron( elem, nodes, nbNodeInFaces );
9043
9044     // remove a linear element
9045     GetMeshDS()->RemoveFreeElement(elem, theSm, /*fromGroups=*/false);
9046
9047     const SMDS_MeshElement* NewElem = 0;
9048
9049     switch( aType )
9050     {
9051     case SMDSAbs_Edge :
9052       {
9053         NewElem = theHelper.AddEdge(nodes[0], nodes[1], id, theForce3d);
9054         break;
9055       }
9056     case SMDSAbs_Face :
9057       {
9058         switch(nbNodes)
9059         {
9060         case 3:
9061           NewElem = theHelper.AddFace(nodes[0], nodes[1], nodes[2], id, theForce3d);
9062           break;
9063         case 4:
9064           NewElem = theHelper.AddFace(nodes[0], nodes[1], nodes[2], nodes[3], id, theForce3d);
9065           break;
9066         default:
9067           NewElem = theHelper.AddPolygonalFace(nodes, id, theForce3d);
9068           continue;
9069         }
9070         break;
9071       }
9072     case SMDSAbs_Volume :
9073       {
9074         switch( elem->GetEntityType() )
9075         {
9076         case SMDSEntity_Tetra:
9077           NewElem = theHelper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3], id, theForce3d);
9078           break;
9079         case SMDSEntity_Pyramid:
9080           NewElem = theHelper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3], nodes[4], id, theForce3d);
9081           break;
9082         case SMDSEntity_Penta:
9083           NewElem = theHelper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3], nodes[4], nodes[5], id, theForce3d);
9084           break;
9085         case SMDSEntity_Hexa:
9086           NewElem = theHelper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3],
9087                                         nodes[4], nodes[5], nodes[6], nodes[7], id, theForce3d);
9088           break;
9089         case SMDSEntity_Hexagonal_Prism:
9090         default:
9091           NewElem = theHelper.AddPolyhedralVolume(nodes, nbNodeInFaces, id, theForce3d);
9092         }
9093         break;
9094       }
9095     default :
9096       continue;
9097     }
9098     ReplaceElemInGroups( elem, NewElem, GetMeshDS());
9099     if( NewElem )
9100       theSm->AddElement( NewElem );
9101   }
9102 //  if (!GetMeshDS()->isCompacted())
9103 //    GetMeshDS()->compactMesh();
9104   return nbElem;
9105 }
9106
9107 //=======================================================================
9108 //function : ConvertToQuadratic
9109 //purpose  :
9110 //=======================================================================
9111
9112 void SMESH_MeshEditor::ConvertToQuadratic(const bool theForce3d)
9113 {
9114   SMESHDS_Mesh* meshDS = GetMeshDS();
9115
9116   SMESH_MesherHelper aHelper(*myMesh);
9117   aHelper.SetIsQuadratic( true );
9118
9119   int nbCheckedElems = 0;
9120   if ( myMesh->HasShapeToMesh() )
9121   {
9122     if ( SMESH_subMesh *aSubMesh = myMesh->GetSubMeshContaining(myMesh->GetShapeToMesh()))
9123     {
9124       SMESH_subMeshIteratorPtr smIt = aSubMesh->getDependsOnIterator(true,false);
9125       while ( smIt->more() ) {
9126         SMESH_subMesh* sm = smIt->next();
9127         if ( SMESHDS_SubMesh *smDS = sm->GetSubMeshDS() ) {
9128           aHelper.SetSubShape( sm->GetSubShape() );
9129           nbCheckedElems += convertElemToQuadratic(smDS, aHelper, theForce3d);
9130         }
9131       }
9132     }
9133   }
9134   int totalNbElems = meshDS->NbEdges() + meshDS->NbFaces() + meshDS->NbVolumes();
9135   if ( nbCheckedElems < totalNbElems ) // not all elements are in submeshes
9136   {
9137     SMESHDS_SubMesh *smDS = 0;
9138     SMDS_EdgeIteratorPtr aEdgeItr = meshDS->edgesIterator();
9139     while(aEdgeItr->more())
9140     {
9141       const SMDS_MeshEdge* edge = aEdgeItr->next();
9142       if(edge && !edge->IsQuadratic())
9143       {
9144         int id = edge->GetID();
9145         //MESSAGE("edge->GetID() " << id);
9146         const SMDS_MeshNode* n1 = edge->GetNode(0);
9147         const SMDS_MeshNode* n2 = edge->GetNode(1);
9148
9149         meshDS->RemoveFreeElement(edge, smDS, /*fromGroups=*/false);
9150
9151         const SMDS_MeshEdge* NewEdge = aHelper.AddEdge(n1, n2, id, theForce3d);
9152         ReplaceElemInGroups( edge, NewEdge, GetMeshDS());
9153       }
9154     }
9155     SMDS_FaceIteratorPtr aFaceItr = meshDS->facesIterator();
9156     while(aFaceItr->more())
9157     {
9158       const SMDS_MeshFace* face = aFaceItr->next();
9159       if(!face || face->IsQuadratic() ) continue;
9160
9161       const int id = face->GetID();
9162       const SMDSAbs_EntityType type = face->GetEntityType();
9163       vector<const SMDS_MeshNode *> nodes ( face->begin_nodes(), face->end_nodes());
9164
9165       meshDS->RemoveFreeElement(face, smDS, /*fromGroups=*/false);
9166
9167       SMDS_MeshFace * NewFace = 0;
9168       switch( type )
9169       {
9170       case SMDSEntity_Triangle:
9171         NewFace = aHelper.AddFace(nodes[0], nodes[1], nodes[2], id, theForce3d);
9172         break;
9173       case SMDSEntity_Quadrangle:
9174         NewFace = aHelper.AddFace(nodes[0], nodes[1], nodes[2], nodes[3], id, theForce3d);
9175         break;
9176       default:
9177         NewFace = aHelper.AddPolygonalFace(nodes, id, theForce3d);
9178       }
9179       ReplaceElemInGroups( face, NewFace, GetMeshDS());
9180     }
9181     vector<int> nbNodeInFaces;
9182     SMDS_VolumeIteratorPtr aVolumeItr = meshDS->volumesIterator();
9183     while(aVolumeItr->more())
9184     {
9185       const SMDS_MeshVolume* volume = aVolumeItr->next();
9186       if(!volume || volume->IsQuadratic() ) continue;
9187
9188       const int id = volume->GetID();
9189       const SMDSAbs_EntityType type = volume->GetEntityType();
9190       vector<const SMDS_MeshNode *> nodes (volume->begin_nodes(), volume->end_nodes());
9191       if ( type == SMDSEntity_Polyhedra )
9192         nbNodeInFaces = static_cast<const SMDS_VtkVolume* >(volume)->GetQuantities();
9193       else if ( type == SMDSEntity_Hexagonal_Prism )
9194         volumeToPolyhedron( volume, nodes, nbNodeInFaces );
9195
9196       meshDS->RemoveFreeElement(volume, smDS, /*fromGroups=*/false);
9197
9198       SMDS_MeshVolume * NewVolume = 0;
9199       switch ( type )
9200       {
9201       case SMDSEntity_Tetra:
9202         NewVolume = aHelper.AddVolume(nodes[0], nodes[1], nodes[2],
9203                                       nodes[3], id, theForce3d );
9204         break;
9205       case SMDSEntity_Hexa:
9206         NewVolume = aHelper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3],
9207                                       nodes[4], nodes[5], nodes[6], nodes[7], id, theForce3d);
9208         break;
9209       case SMDSEntity_Pyramid:
9210         NewVolume = aHelper.AddVolume(nodes[0], nodes[1], nodes[2],
9211                                       nodes[3], nodes[4], id, theForce3d);
9212         break;
9213       case SMDSEntity_Penta:
9214         NewVolume = aHelper.AddVolume(nodes[0], nodes[1], nodes[2],
9215                                       nodes[3], nodes[4], nodes[5], id, theForce3d);
9216         break;
9217       case SMDSEntity_Hexagonal_Prism:
9218       default:
9219         NewVolume = aHelper.AddPolyhedralVolume(nodes, nbNodeInFaces, id, theForce3d);
9220       }
9221       ReplaceElemInGroups(volume, NewVolume, meshDS);
9222     }
9223   }
9224
9225   if ( !theForce3d )
9226   { // setenv NO_FixQuadraticElements to know if FixQuadraticElements() is guilty of bad conversion
9227     aHelper.SetSubShape(0); // apply FixQuadraticElements() to the whole mesh
9228     aHelper.FixQuadraticElements();
9229   }
9230 }
9231
9232 //================================================================================
9233 /*!
9234  * \brief Makes given elements quadratic
9235  *  \param theForce3d - if true, the medium nodes will be placed in the middle of link
9236  *  \param theElements - elements to make quadratic 
9237  */
9238 //================================================================================
9239
9240 void SMESH_MeshEditor::ConvertToQuadratic(const bool        theForce3d,
9241                                           TIDSortedElemSet& theElements)
9242 {
9243   if ( theElements.empty() ) return;
9244
9245   // we believe that all theElements are of the same type
9246   SMDSAbs_ElementType elemType = (*theElements.begin())->GetType();
9247   
9248   // get all nodes shared by theElements
9249   TIDSortedNodeSet allNodes;
9250   TIDSortedElemSet::iterator eIt = theElements.begin();
9251   for ( ; eIt != theElements.end(); ++eIt )
9252     allNodes.insert( (*eIt)->begin_nodes(), (*eIt)->end_nodes() );
9253
9254   // complete theElements with elements of lower dim whose all nodes are in allNodes
9255
9256   TIDSortedElemSet quadAdjacentElems    [ SMDSAbs_NbElementTypes ]; // quadratic adjacent elements
9257   TIDSortedElemSet checkedAdjacentElems [ SMDSAbs_NbElementTypes ];
9258   TIDSortedNodeSet::iterator nIt = allNodes.begin();
9259   for ( ; nIt != allNodes.end(); ++nIt )
9260   {
9261     const SMDS_MeshNode* n = *nIt;
9262     SMDS_ElemIteratorPtr invIt = n->GetInverseElementIterator();
9263     while ( invIt->more() )
9264     {
9265       const SMDS_MeshElement* e = invIt->next();
9266       if ( e->IsQuadratic() )
9267       {
9268         quadAdjacentElems[ e->GetType() ].insert( e );
9269         continue;
9270       }
9271       if ( e->GetType() >= elemType )
9272       {
9273         continue; // same type of more complex linear element
9274       }
9275
9276       if ( !checkedAdjacentElems[ e->GetType() ].insert( e ).second )
9277         continue; // e is already checked
9278
9279       // check nodes
9280       bool allIn = true;
9281       SMDS_ElemIteratorPtr nodeIt = e->nodesIterator();
9282       while ( nodeIt->more() && allIn )
9283         allIn = allNodes.count( cast2Node( nodeIt->next() ));
9284       if ( allIn )
9285         theElements.insert(e );
9286     }
9287   }
9288
9289   SMESH_MesherHelper helper(*myMesh);
9290   helper.SetIsQuadratic( true );
9291
9292   // add links of quadratic adjacent elements to the helper
9293
9294   if ( !quadAdjacentElems[SMDSAbs_Edge].empty() )
9295     for ( eIt  = quadAdjacentElems[SMDSAbs_Edge].begin();
9296           eIt != quadAdjacentElems[SMDSAbs_Edge].end(); ++eIt )
9297     {
9298       helper.AddTLinks( static_cast< const SMDS_MeshEdge*> (*eIt) );
9299     }
9300   if ( !quadAdjacentElems[SMDSAbs_Face].empty() )
9301     for ( eIt  = quadAdjacentElems[SMDSAbs_Face].begin();
9302           eIt != quadAdjacentElems[SMDSAbs_Face].end(); ++eIt )
9303     {
9304       helper.AddTLinks( static_cast< const SMDS_MeshFace*> (*eIt) );
9305     }
9306   if ( !quadAdjacentElems[SMDSAbs_Volume].empty() )
9307     for ( eIt  = quadAdjacentElems[SMDSAbs_Volume].begin();
9308           eIt != quadAdjacentElems[SMDSAbs_Volume].end(); ++eIt )
9309     {
9310       helper.AddTLinks( static_cast< const SMDS_MeshVolume*> (*eIt) );
9311     }
9312
9313   // make quadratic elements instead of linear ones
9314
9315   SMESHDS_Mesh* meshDS = GetMeshDS();
9316   SMESHDS_SubMesh* smDS = 0;
9317   for ( eIt = theElements.begin(); eIt != theElements.end(); ++eIt )
9318   {
9319     const SMDS_MeshElement* elem = *eIt;
9320     if( elem->IsQuadratic() || elem->NbNodes() < 2 || elem->IsPoly() )
9321       continue;
9322
9323     int id = elem->GetID();
9324     SMDSAbs_ElementType type = elem->GetType();
9325     vector<const SMDS_MeshNode *> nodes ( elem->begin_nodes(), elem->end_nodes());
9326
9327     if ( !smDS || !smDS->Contains( elem ))
9328       smDS = meshDS->MeshElements( elem->getshapeId() );
9329     meshDS->RemoveFreeElement(elem, smDS, /*fromGroups=*/false);
9330
9331     SMDS_MeshElement * newElem = 0;
9332     switch( nodes.size() )
9333     {
9334     case 4: // cases for most multiple element types go first (for optimization)
9335       if ( type == SMDSAbs_Volume )
9336         newElem = helper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3], id, theForce3d);
9337       else
9338         newElem = helper.AddFace  (nodes[0], nodes[1], nodes[2], nodes[3], id, theForce3d);
9339       break;
9340     case 8:
9341       newElem = helper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3],
9342                                  nodes[4], nodes[5], nodes[6], nodes[7], id, theForce3d);
9343       break;
9344     case 3:
9345       newElem = helper.AddFace  (nodes[0], nodes[1], nodes[2], id, theForce3d);
9346       break;
9347     case 2:
9348       newElem = helper.AddEdge(nodes[0], nodes[1], id, theForce3d);
9349       break;
9350     case 5:
9351       newElem = helper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3],
9352                                  nodes[4], id, theForce3d);
9353       break;
9354     case 6:
9355       newElem = helper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3],
9356                                  nodes[4], nodes[5], id, theForce3d);
9357       break;
9358     default:;
9359     }
9360     ReplaceElemInGroups( elem, newElem, meshDS);
9361     if( newElem && smDS )
9362       smDS->AddElement( newElem );
9363   }
9364
9365   if ( !theForce3d  && !getenv("NO_FixQuadraticElements"))
9366   { // setenv NO_FixQuadraticElements to know if FixQuadraticElements() is guilty of bad conversion
9367     helper.SetSubShape(0); // apply FixQuadraticElements() to the whole mesh
9368     helper.FixQuadraticElements();
9369   }
9370 }
9371
9372 //=======================================================================
9373 /*!
9374  * \brief Convert quadratic elements to linear ones and remove quadratic nodes
9375  * \return int - nb of checked elements
9376  */
9377 //=======================================================================
9378
9379 int SMESH_MeshEditor::removeQuadElem(SMESHDS_SubMesh *    theSm,
9380                                      SMDS_ElemIteratorPtr theItr,
9381                                      const int            theShapeID)
9382 {
9383   int nbElem = 0;
9384   SMESHDS_Mesh* meshDS = GetMeshDS();
9385
9386   while( theItr->more() )
9387   {
9388     const SMDS_MeshElement* elem = theItr->next();
9389     nbElem++;
9390     if( elem && elem->IsQuadratic())
9391     {
9392       int id                    = elem->GetID();
9393       int nbCornerNodes         = elem->NbCornerNodes();
9394       SMDSAbs_ElementType aType = elem->GetType();
9395
9396       vector<const SMDS_MeshNode *> nodes( elem->begin_nodes(), elem->end_nodes() );
9397
9398       //remove a quadratic element
9399       if ( !theSm || !theSm->Contains( elem ))
9400         theSm = meshDS->MeshElements( elem->getshapeId() );
9401       meshDS->RemoveFreeElement( elem, theSm, /*fromGroups=*/false );
9402
9403       // remove medium nodes
9404       for ( unsigned i = nbCornerNodes; i < nodes.size(); ++i )
9405         if ( nodes[i]->NbInverseElements() == 0 )
9406           meshDS->RemoveFreeNode( nodes[i], theSm );
9407
9408       // add a linear element
9409       nodes.resize( nbCornerNodes );
9410       SMDS_MeshElement * newElem = AddElement( nodes, aType, false, id );
9411       ReplaceElemInGroups(elem, newElem, meshDS);
9412       if( theSm && newElem )
9413         theSm->AddElement( newElem );
9414     }
9415   }
9416   return nbElem;
9417 }
9418
9419 //=======================================================================
9420 //function : ConvertFromQuadratic
9421 //purpose  :
9422 //=======================================================================
9423
9424 bool SMESH_MeshEditor::ConvertFromQuadratic()
9425 {
9426   int nbCheckedElems = 0;
9427   if ( myMesh->HasShapeToMesh() )
9428   {
9429     if ( SMESH_subMesh *aSubMesh = myMesh->GetSubMeshContaining(myMesh->GetShapeToMesh()))
9430     {
9431       SMESH_subMeshIteratorPtr smIt = aSubMesh->getDependsOnIterator(true,false);
9432       while ( smIt->more() ) {
9433         SMESH_subMesh* sm = smIt->next();
9434         if ( SMESHDS_SubMesh *smDS = sm->GetSubMeshDS() )
9435           nbCheckedElems += removeQuadElem( smDS, smDS->GetElements(), sm->GetId() );
9436       }
9437     }
9438   }
9439
9440   int totalNbElems =
9441     GetMeshDS()->NbEdges() + GetMeshDS()->NbFaces() + GetMeshDS()->NbVolumes();
9442   if ( nbCheckedElems < totalNbElems ) // not all elements are in submeshes
9443   {
9444     SMESHDS_SubMesh *aSM = 0;
9445     removeQuadElem( aSM, GetMeshDS()->elementsIterator(), 0 );
9446   }
9447
9448   return true;
9449 }
9450
9451 namespace
9452 {
9453   //================================================================================
9454   /*!
9455    * \brief Return true if all medium nodes of the element are in the node set
9456    */
9457   //================================================================================
9458
9459   bool allMediumNodesIn(const SMDS_MeshElement* elem, TIDSortedNodeSet& nodeSet )
9460   {
9461     for ( int i = elem->NbCornerNodes(); i < elem->NbNodes(); ++i )
9462       if ( !nodeSet.count( elem->GetNode(i) ))
9463         return false;
9464     return true;
9465   }
9466 }
9467
9468 //================================================================================
9469 /*!
9470  * \brief Makes given elements linear
9471  */
9472 //================================================================================
9473
9474 void SMESH_MeshEditor::ConvertFromQuadratic(TIDSortedElemSet& theElements)
9475 {
9476   if ( theElements.empty() ) return;
9477
9478   // collect IDs of medium nodes of theElements; some of these nodes will be removed
9479   set<int> mediumNodeIDs;
9480   TIDSortedElemSet::iterator eIt = theElements.begin();
9481   for ( ; eIt != theElements.end(); ++eIt )
9482   {
9483     const SMDS_MeshElement* e = *eIt;
9484     for ( int i = e->NbCornerNodes(); i < e->NbNodes(); ++i )
9485       mediumNodeIDs.insert( e->GetNode(i)->GetID() );
9486   }
9487
9488   // replace given elements by linear ones
9489   typedef SMDS_SetIterator<const SMDS_MeshElement*, TIDSortedElemSet::iterator> TSetIterator;
9490   SMDS_ElemIteratorPtr elemIt( new TSetIterator( theElements.begin(), theElements.end() ));
9491   removeQuadElem( /*theSm=*/0, elemIt, /*theShapeID=*/0 );
9492
9493   // we need to convert remaining elements whose all medium nodes are in mediumNodeIDs
9494   // except those elements sharing medium nodes of quadratic element whose medium nodes
9495   // are not all in mediumNodeIDs
9496
9497   // get remaining medium nodes
9498   TIDSortedNodeSet mediumNodes;
9499   set<int>::iterator nIdsIt = mediumNodeIDs.begin();
9500   for ( ; nIdsIt != mediumNodeIDs.end(); ++nIdsIt )
9501     if ( const SMDS_MeshNode* n = GetMeshDS()->FindNode( *nIdsIt ))
9502       mediumNodes.insert( mediumNodes.end(), n );
9503
9504   // find more quadratic elements to convert
9505   TIDSortedElemSet moreElemsToConvert;
9506   TIDSortedNodeSet::iterator nIt = mediumNodes.begin();
9507   for ( ; nIt != mediumNodes.end(); ++nIt )
9508   {
9509     SMDS_ElemIteratorPtr invIt = (*nIt)->GetInverseElementIterator();
9510     while ( invIt->more() )
9511     {
9512       const SMDS_MeshElement* e = invIt->next();
9513       if ( e->IsQuadratic() && allMediumNodesIn( e, mediumNodes ))
9514       {
9515         // find a more complex element including e and
9516         // whose medium nodes are not in mediumNodes
9517         bool complexFound = false;
9518         for ( int type = e->GetType() + 1; type < SMDSAbs_0DElement; ++type )
9519         {
9520           SMDS_ElemIteratorPtr invIt2 =
9521             (*nIt)->GetInverseElementIterator( SMDSAbs_ElementType( type ));
9522           while ( invIt2->more() )
9523           {
9524             const SMDS_MeshElement* eComplex = invIt2->next();
9525             if ( eComplex->IsQuadratic() && !allMediumNodesIn( eComplex, mediumNodes))
9526             {
9527               int nbCommonNodes = SMESH_Algo::GetCommonNodes( e, eComplex ).size();
9528               if ( nbCommonNodes == e->NbNodes())
9529               {
9530                 complexFound = true;
9531                 type = SMDSAbs_NbElementTypes; // to quit from the outer loop
9532                 break;
9533               }
9534             }
9535           }
9536         }
9537         if ( !complexFound )
9538           moreElemsToConvert.insert( e );
9539       }
9540     }
9541   }
9542   elemIt = SMDS_ElemIteratorPtr
9543     (new TSetIterator( moreElemsToConvert.begin(), moreElemsToConvert.end() ));
9544   removeQuadElem( /*theSm=*/0, elemIt, /*theShapeID=*/0 );
9545 }
9546
9547 //=======================================================================
9548 //function : SewSideElements
9549 //purpose  :
9550 //=======================================================================
9551
9552 SMESH_MeshEditor::Sew_Error
9553 SMESH_MeshEditor::SewSideElements (TIDSortedElemSet&    theSide1,
9554                                    TIDSortedElemSet&    theSide2,
9555                                    const SMDS_MeshNode* theFirstNode1,
9556                                    const SMDS_MeshNode* theFirstNode2,
9557                                    const SMDS_MeshNode* theSecondNode1,
9558                                    const SMDS_MeshNode* theSecondNode2)
9559 {
9560   myLastCreatedElems.Clear();
9561   myLastCreatedNodes.Clear();
9562
9563   MESSAGE ("::::SewSideElements()");
9564   if ( theSide1.size() != theSide2.size() )
9565     return SEW_DIFF_NB_OF_ELEMENTS;
9566
9567   Sew_Error aResult = SEW_OK;
9568   // Algo:
9569   // 1. Build set of faces representing each side
9570   // 2. Find which nodes of the side 1 to merge with ones on the side 2
9571   // 3. Replace nodes in elements of the side 1 and remove replaced nodes
9572
9573   // =======================================================================
9574   // 1. Build set of faces representing each side:
9575   // =======================================================================
9576   // a. build set of nodes belonging to faces
9577   // b. complete set of faces: find missing faces whose nodes are in set of nodes
9578   // c. create temporary faces representing side of volumes if correspondent
9579   //    face does not exist
9580
9581   SMESHDS_Mesh* aMesh = GetMeshDS();
9582   // TODO algoritm not OK with vtkUnstructuredGrid: 2 meshes can't share nodes
9583   //SMDS_Mesh aTmpFacesMesh; // try to use the same mesh
9584   set<const SMDS_MeshElement*> faceSet1, faceSet2;
9585   set<const SMDS_MeshElement*> volSet1,  volSet2;
9586   set<const SMDS_MeshNode*>    nodeSet1, nodeSet2;
9587   set<const SMDS_MeshElement*> * faceSetPtr[] = { &faceSet1, &faceSet2 };
9588   set<const SMDS_MeshElement*>  * volSetPtr[] = { &volSet1,  &volSet2  };
9589   set<const SMDS_MeshNode*>    * nodeSetPtr[] = { &nodeSet1, &nodeSet2 };
9590   TIDSortedElemSet * elemSetPtr[] = { &theSide1, &theSide2 };
9591   int iSide, iFace, iNode;
9592
9593   list<const SMDS_MeshElement* > tempFaceList;
9594   for ( iSide = 0; iSide < 2; iSide++ ) {
9595     set<const SMDS_MeshNode*>    * nodeSet = nodeSetPtr[ iSide ];
9596     TIDSortedElemSet * elemSet = elemSetPtr[ iSide ];
9597     set<const SMDS_MeshElement*> * faceSet = faceSetPtr[ iSide ];
9598     set<const SMDS_MeshElement*> * volSet  = volSetPtr [ iSide ];
9599     set<const SMDS_MeshElement*>::iterator vIt;
9600     TIDSortedElemSet::iterator eIt;
9601     set<const SMDS_MeshNode*>::iterator    nIt;
9602
9603     // check that given nodes belong to given elements
9604     const SMDS_MeshNode* n1 = ( iSide == 0 ) ? theFirstNode1 : theFirstNode2;
9605     const SMDS_MeshNode* n2 = ( iSide == 0 ) ? theSecondNode1 : theSecondNode2;
9606     int firstIndex = -1, secondIndex = -1;
9607     for (eIt = elemSet->begin(); eIt != elemSet->end(); eIt++ ) {
9608       const SMDS_MeshElement* elem = *eIt;
9609       if ( firstIndex  < 0 ) firstIndex  = elem->GetNodeIndex( n1 );
9610       if ( secondIndex < 0 ) secondIndex = elem->GetNodeIndex( n2 );
9611       if ( firstIndex > -1 && secondIndex > -1 ) break;
9612     }
9613     if ( firstIndex < 0 || secondIndex < 0 ) {
9614       // we can simply return until temporary faces created
9615       return (iSide == 0 ) ? SEW_BAD_SIDE1_NODES : SEW_BAD_SIDE2_NODES;
9616     }
9617
9618     // -----------------------------------------------------------
9619     // 1a. Collect nodes of existing faces
9620     //     and build set of face nodes in order to detect missing
9621     //     faces corresponding to sides of volumes
9622     // -----------------------------------------------------------
9623
9624     set< set <const SMDS_MeshNode*> > setOfFaceNodeSet;
9625
9626     // loop on the given element of a side
9627     for (eIt = elemSet->begin(); eIt != elemSet->end(); eIt++ ) {
9628       //const SMDS_MeshElement* elem = *eIt;
9629       const SMDS_MeshElement* elem = *eIt;
9630       if ( elem->GetType() == SMDSAbs_Face ) {
9631         faceSet->insert( elem );
9632         set <const SMDS_MeshNode*> faceNodeSet;
9633         SMDS_ElemIteratorPtr nodeIt = elem->nodesIterator();
9634         while ( nodeIt->more() ) {
9635           const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
9636           nodeSet->insert( n );
9637           faceNodeSet.insert( n );
9638         }
9639         setOfFaceNodeSet.insert( faceNodeSet );
9640       }
9641       else if ( elem->GetType() == SMDSAbs_Volume )
9642         volSet->insert( elem );
9643     }
9644     // ------------------------------------------------------------------------------
9645     // 1b. Complete set of faces: find missing faces whose nodes are in set of nodes
9646     // ------------------------------------------------------------------------------
9647
9648     for ( nIt = nodeSet->begin(); nIt != nodeSet->end(); nIt++ ) { // loop on nodes of iSide
9649       SMDS_ElemIteratorPtr fIt = (*nIt)->GetInverseElementIterator(SMDSAbs_Face);
9650       while ( fIt->more() ) { // loop on faces sharing a node
9651         const SMDS_MeshElement* f = fIt->next();
9652         if ( faceSet->find( f ) == faceSet->end() ) {
9653           // check if all nodes are in nodeSet and
9654           // complete setOfFaceNodeSet if they are
9655           set <const SMDS_MeshNode*> faceNodeSet;
9656           SMDS_ElemIteratorPtr nodeIt = f->nodesIterator();
9657           bool allInSet = true;
9658           while ( nodeIt->more() && allInSet ) { // loop on nodes of a face
9659             const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
9660             if ( nodeSet->find( n ) == nodeSet->end() )
9661               allInSet = false;
9662             else
9663               faceNodeSet.insert( n );
9664           }
9665           if ( allInSet ) {
9666             faceSet->insert( f );
9667             setOfFaceNodeSet.insert( faceNodeSet );
9668           }
9669         }
9670       }
9671     }
9672
9673     // -------------------------------------------------------------------------
9674     // 1c. Create temporary faces representing sides of volumes if correspondent
9675     //     face does not exist
9676     // -------------------------------------------------------------------------
9677
9678     if ( !volSet->empty() ) {
9679       //int nodeSetSize = nodeSet->size();
9680
9681       // loop on given volumes
9682       for ( vIt = volSet->begin(); vIt != volSet->end(); vIt++ ) {
9683         SMDS_VolumeTool vol (*vIt);
9684         // loop on volume faces: find free faces
9685         // --------------------------------------
9686         list<const SMDS_MeshElement* > freeFaceList;
9687         for ( iFace = 0; iFace < vol.NbFaces(); iFace++ ) {
9688           if ( !vol.IsFreeFace( iFace ))
9689             continue;
9690           // check if there is already a face with same nodes in a face set
9691           const SMDS_MeshElement* aFreeFace = 0;
9692           const SMDS_MeshNode** fNodes = vol.GetFaceNodes( iFace );
9693           int nbNodes = vol.NbFaceNodes( iFace );
9694           set <const SMDS_MeshNode*> faceNodeSet;
9695           vol.GetFaceNodes( iFace, faceNodeSet );
9696           bool isNewFace = setOfFaceNodeSet.insert( faceNodeSet ).second;
9697           if ( isNewFace ) {
9698             // no such a face is given but it still can exist, check it
9699             if ( nbNodes == 3 ) {
9700               aFreeFace = aMesh->FindFace( fNodes[0],fNodes[1],fNodes[2] );
9701             }
9702             else if ( nbNodes == 4 ) {
9703               aFreeFace = aMesh->FindFace( fNodes[0],fNodes[1],fNodes[2],fNodes[3] );
9704             }
9705             else {
9706               vector<const SMDS_MeshNode *> poly_nodes ( fNodes, & fNodes[nbNodes]);
9707               aFreeFace = aMesh->FindFace(poly_nodes);
9708             }
9709           }
9710           if ( !aFreeFace ) {
9711             // create a temporary face
9712             if ( nbNodes == 3 ) {
9713               //aFreeFace = aTmpFacesMesh.AddFace( fNodes[0],fNodes[1],fNodes[2] );
9714               aFreeFace = aMesh->AddFace( fNodes[0],fNodes[1],fNodes[2] );
9715             }
9716             else if ( nbNodes == 4 ) {
9717               //aFreeFace = aTmpFacesMesh.AddFace( fNodes[0],fNodes[1],fNodes[2],fNodes[3] );
9718               aFreeFace = aMesh->AddFace( fNodes[0],fNodes[1],fNodes[2],fNodes[3] );
9719             }
9720             else {
9721               vector<const SMDS_MeshNode *> poly_nodes ( fNodes, & fNodes[nbNodes]);
9722               //aFreeFace = aTmpFacesMesh.AddPolygonalFace(poly_nodes);
9723               aFreeFace = aMesh->AddPolygonalFace(poly_nodes);
9724             }
9725           }
9726           if ( aFreeFace ) {
9727             freeFaceList.push_back( aFreeFace );
9728             tempFaceList.push_back( aFreeFace );
9729           }
9730
9731         } // loop on faces of a volume
9732
9733         // choose one of several free faces
9734         // --------------------------------------
9735         if ( freeFaceList.size() > 1 ) {
9736           // choose a face having max nb of nodes shared by other elems of a side
9737           int maxNbNodes = -1/*, nbExcludedFaces = 0*/;
9738           list<const SMDS_MeshElement* >::iterator fIt = freeFaceList.begin();
9739           while ( fIt != freeFaceList.end() ) { // loop on free faces
9740             int nbSharedNodes = 0;
9741             SMDS_ElemIteratorPtr nodeIt = (*fIt)->nodesIterator();
9742             while ( nodeIt->more() ) { // loop on free face nodes
9743               const SMDS_MeshNode* n =
9744                 static_cast<const SMDS_MeshNode*>( nodeIt->next() );
9745               SMDS_ElemIteratorPtr invElemIt = n->GetInverseElementIterator();
9746               while ( invElemIt->more() ) {
9747                 const SMDS_MeshElement* e = invElemIt->next();
9748                 if ( faceSet->find( e ) != faceSet->end() )
9749                   nbSharedNodes++;
9750                 if ( elemSet->find( e ) != elemSet->end() )
9751                   nbSharedNodes++;
9752               }
9753             }
9754             if ( nbSharedNodes >= maxNbNodes ) {
9755               maxNbNodes = nbSharedNodes;
9756               fIt++;
9757             }
9758             else
9759               freeFaceList.erase( fIt++ ); // here fIt++ occurs before erase
9760           }
9761           if ( freeFaceList.size() > 1 )
9762           {
9763             // could not choose one face, use another way
9764             // choose a face most close to the bary center of the opposite side
9765             gp_XYZ aBC( 0., 0., 0. );
9766             set <const SMDS_MeshNode*> addedNodes;
9767             TIDSortedElemSet * elemSet2 = elemSetPtr[ 1 - iSide ];
9768             eIt = elemSet2->begin();
9769             for ( eIt = elemSet2->begin(); eIt != elemSet2->end(); eIt++ ) {
9770               SMDS_ElemIteratorPtr nodeIt = (*eIt)->nodesIterator();
9771               while ( nodeIt->more() ) { // loop on free face nodes
9772                 const SMDS_MeshNode* n =
9773                   static_cast<const SMDS_MeshNode*>( nodeIt->next() );
9774                 if ( addedNodes.insert( n ).second )
9775                   aBC += gp_XYZ( n->X(),n->Y(),n->Z() );
9776               }
9777             }
9778             aBC /= addedNodes.size();
9779             double minDist = DBL_MAX;
9780             fIt = freeFaceList.begin();
9781             while ( fIt != freeFaceList.end() ) { // loop on free faces
9782               double dist = 0;
9783               SMDS_ElemIteratorPtr nodeIt = (*fIt)->nodesIterator();
9784               while ( nodeIt->more() ) { // loop on free face nodes
9785                 const SMDS_MeshNode* n =
9786                   static_cast<const SMDS_MeshNode*>( nodeIt->next() );
9787                 gp_XYZ p( n->X(),n->Y(),n->Z() );
9788                 dist += ( aBC - p ).SquareModulus();
9789               }
9790               if ( dist < minDist ) {
9791                 minDist = dist;
9792                 freeFaceList.erase( freeFaceList.begin(), fIt++ );
9793               }
9794               else
9795                 fIt = freeFaceList.erase( fIt++ );
9796             }
9797           }
9798         } // choose one of several free faces of a volume
9799
9800         if ( freeFaceList.size() == 1 ) {
9801           const SMDS_MeshElement* aFreeFace = freeFaceList.front();
9802           faceSet->insert( aFreeFace );
9803           // complete a node set with nodes of a found free face
9804           //           for ( iNode = 0; iNode < ; iNode++ )
9805           //             nodeSet->insert( fNodes[ iNode ] );
9806         }
9807
9808       } // loop on volumes of a side
9809
9810       //       // complete a set of faces if new nodes in a nodeSet appeared
9811       //       // ----------------------------------------------------------
9812       //       if ( nodeSetSize != nodeSet->size() ) {
9813       //         for ( ; nIt != nodeSet->end(); nIt++ ) { // loop on nodes of iSide
9814       //           SMDS_ElemIteratorPtr fIt = (*nIt)->GetInverseElementIterator(SMDSAbs_Face);
9815       //           while ( fIt->more() ) { // loop on faces sharing a node
9816       //             const SMDS_MeshElement* f = fIt->next();
9817       //             if ( faceSet->find( f ) == faceSet->end() ) {
9818       //               // check if all nodes are in nodeSet and
9819       //               // complete setOfFaceNodeSet if they are
9820       //               set <const SMDS_MeshNode*> faceNodeSet;
9821       //               SMDS_ElemIteratorPtr nodeIt = f->nodesIterator();
9822       //               bool allInSet = true;
9823       //               while ( nodeIt->more() && allInSet ) { // loop on nodes of a face
9824       //                 const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
9825       //                 if ( nodeSet->find( n ) == nodeSet->end() )
9826       //                   allInSet = false;
9827       //                 else
9828       //                   faceNodeSet.insert( n );
9829       //               }
9830       //               if ( allInSet ) {
9831       //                 faceSet->insert( f );
9832       //                 setOfFaceNodeSet.insert( faceNodeSet );
9833       //               }
9834       //             }
9835       //           }
9836       //         }
9837       //       }
9838     } // Create temporary faces, if there are volumes given
9839   } // loop on sides
9840
9841   if ( faceSet1.size() != faceSet2.size() ) {
9842     // delete temporary faces: they are in reverseElements of actual nodes
9843 //    SMDS_FaceIteratorPtr tmpFaceIt = aTmpFacesMesh.facesIterator();
9844 //    while ( tmpFaceIt->more() )
9845 //      aTmpFacesMesh.RemoveElement( tmpFaceIt->next() );
9846 //    list<const SMDS_MeshElement* >::iterator tmpFaceIt = tempFaceList.begin();
9847 //    for (; tmpFaceIt !=tempFaceList.end(); ++tmpFaceIt)
9848 //      aMesh->RemoveElement(*tmpFaceIt);
9849     MESSAGE("Diff nb of faces");
9850     return SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
9851   }
9852
9853   // ============================================================
9854   // 2. Find nodes to merge:
9855   //              bind a node to remove to a node to put instead
9856   // ============================================================
9857
9858   TNodeNodeMap nReplaceMap; // bind a node to remove to a node to put instead
9859   if ( theFirstNode1 != theFirstNode2 )
9860     nReplaceMap.insert( TNodeNodeMap::value_type( theFirstNode1, theFirstNode2 ));
9861   if ( theSecondNode1 != theSecondNode2 )
9862     nReplaceMap.insert( TNodeNodeMap::value_type( theSecondNode1, theSecondNode2 ));
9863
9864   LinkID_Gen aLinkID_Gen( GetMeshDS() );
9865   set< long > linkIdSet; // links to process
9866   linkIdSet.insert( aLinkID_Gen.GetLinkID( theFirstNode1, theSecondNode1 ));
9867
9868   typedef pair< const SMDS_MeshNode*, const SMDS_MeshNode* > NLink;
9869   list< NLink > linkList[2];
9870   linkList[0].push_back( NLink( theFirstNode1, theSecondNode1 ));
9871   linkList[1].push_back( NLink( theFirstNode2, theSecondNode2 ));
9872   // loop on links in linkList; find faces by links and append links
9873   // of the found faces to linkList
9874   list< NLink >::iterator linkIt[] = { linkList[0].begin(), linkList[1].begin() } ;
9875   for ( ; linkIt[0] != linkList[0].end(); linkIt[0]++, linkIt[1]++ ) {
9876     NLink link[] = { *linkIt[0], *linkIt[1] };
9877     long linkID = aLinkID_Gen.GetLinkID( link[0].first, link[0].second );
9878     if ( linkIdSet.find( linkID ) == linkIdSet.end() )
9879       continue;
9880
9881     // by links, find faces in the face sets,
9882     // and find indices of link nodes in the found faces;
9883     // in a face set, there is only one or no face sharing a link
9884     // ---------------------------------------------------------------
9885
9886     const SMDS_MeshElement* face[] = { 0, 0 };
9887     //const SMDS_MeshNode* faceNodes[ 2 ][ 5 ];
9888     vector<const SMDS_MeshNode*> fnodes1(9);
9889     vector<const SMDS_MeshNode*> fnodes2(9);
9890     //const SMDS_MeshNode* notLinkNodes[ 2 ][ 2 ] = {{ 0, 0 },{ 0, 0 }} ;
9891     vector<const SMDS_MeshNode*> notLinkNodes1(6);
9892     vector<const SMDS_MeshNode*> notLinkNodes2(6);
9893     int iLinkNode[2][2];
9894     for ( iSide = 0; iSide < 2; iSide++ ) { // loop on 2 sides
9895       const SMDS_MeshNode* n1 = link[iSide].first;
9896       const SMDS_MeshNode* n2 = link[iSide].second;
9897       set<const SMDS_MeshElement*> * faceSet = faceSetPtr[ iSide ];
9898       set< const SMDS_MeshElement* > fMap;
9899       for ( int i = 0; i < 2; i++ ) { // loop on 2 nodes of a link
9900         const SMDS_MeshNode* n = i ? n1 : n2; // a node of a link
9901         SMDS_ElemIteratorPtr fIt = n->GetInverseElementIterator(SMDSAbs_Face);
9902         while ( fIt->more() ) { // loop on faces sharing a node
9903           const SMDS_MeshElement* f = fIt->next();
9904           if (faceSet->find( f ) != faceSet->end() && // f is in face set
9905               ! fMap.insert( f ).second ) // f encounters twice
9906           {
9907             if ( face[ iSide ] ) {
9908               MESSAGE( "2 faces per link " );
9909               aResult = iSide ? SEW_BAD_SIDE2_NODES : SEW_BAD_SIDE1_NODES;
9910               break;
9911             }
9912             face[ iSide ] = f;
9913             faceSet->erase( f );
9914             // get face nodes and find ones of a link
9915             iNode = 0;
9916             int nbl = -1;
9917             if(f->IsPoly()) {
9918               if(iSide==0) {
9919                 fnodes1.resize(f->NbNodes()+1);
9920                 notLinkNodes1.resize(f->NbNodes()-2);
9921               }
9922               else {
9923                 fnodes2.resize(f->NbNodes()+1);
9924                 notLinkNodes2.resize(f->NbNodes()-2);
9925               }
9926             }
9927             if(!f->IsQuadratic()) {
9928               SMDS_ElemIteratorPtr nIt = f->nodesIterator();
9929               while ( nIt->more() ) {
9930                 const SMDS_MeshNode* n =
9931                   static_cast<const SMDS_MeshNode*>( nIt->next() );
9932                 if ( n == n1 ) {
9933                   iLinkNode[ iSide ][ 0 ] = iNode;
9934                 }
9935                 else if ( n == n2 ) {
9936                   iLinkNode[ iSide ][ 1 ] = iNode;
9937                 }
9938                 //else if ( notLinkNodes[ iSide ][ 0 ] )
9939                 //  notLinkNodes[ iSide ][ 1 ] = n;
9940                 //else
9941                 //  notLinkNodes[ iSide ][ 0 ] = n;
9942                 else {
9943                   nbl++;
9944                   if(iSide==0)
9945                     notLinkNodes1[nbl] = n;
9946                   //notLinkNodes1.push_back(n);
9947                   else
9948                     notLinkNodes2[nbl] = n;
9949                   //notLinkNodes2.push_back(n);
9950                 }
9951                 //faceNodes[ iSide ][ iNode++ ] = n;
9952                 if(iSide==0) {
9953                   fnodes1[iNode++] = n;
9954                 }
9955                 else {
9956                   fnodes2[iNode++] = n;
9957                 }
9958               }
9959             }
9960             else { // f->IsQuadratic()
9961               const SMDS_VtkFace* F =
9962                 dynamic_cast<const SMDS_VtkFace*>(f);
9963               if (!F) throw SALOME_Exception(LOCALIZED("not an SMDS_VtkFace"));
9964               // use special nodes iterator
9965               SMDS_ElemIteratorPtr anIter = F->interlacedNodesElemIterator();
9966               while ( anIter->more() ) {
9967                 const SMDS_MeshNode* n =
9968                   static_cast<const SMDS_MeshNode*>( anIter->next() );
9969                 if ( n == n1 ) {
9970                   iLinkNode[ iSide ][ 0 ] = iNode;
9971                 }
9972                 else if ( n == n2 ) {
9973                   iLinkNode[ iSide ][ 1 ] = iNode;
9974                 }
9975                 else {
9976                   nbl++;
9977                   if(iSide==0) {
9978                     notLinkNodes1[nbl] = n;
9979                   }
9980                   else {
9981                     notLinkNodes2[nbl] = n;
9982                   }
9983                 }
9984                 if(iSide==0) {
9985                   fnodes1[iNode++] = n;
9986                 }
9987                 else {
9988                   fnodes2[iNode++] = n;
9989                 }
9990               }
9991             }
9992             //faceNodes[ iSide ][ iNode ] = faceNodes[ iSide ][ 0 ];
9993             if(iSide==0) {
9994               fnodes1[iNode] = fnodes1[0];
9995             }
9996             else {
9997               fnodes2[iNode] = fnodes1[0];
9998             }
9999           }
10000         }
10001       }
10002     }
10003
10004     // check similarity of elements of the sides
10005     if (aResult == SEW_OK && (( face[0] && !face[1] ) || ( !face[0] && face[1] ))) {
10006       MESSAGE("Correspondent face not found on side " << ( face[0] ? 1 : 0 ));
10007       if ( nReplaceMap.size() == 2 ) { // faces on input nodes not found
10008         aResult = ( face[0] ? SEW_BAD_SIDE2_NODES : SEW_BAD_SIDE1_NODES );
10009       }
10010       else {
10011         aResult = SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
10012       }
10013       break; // do not return because it s necessary to remove tmp faces
10014     }
10015
10016     // set nodes to merge
10017     // -------------------
10018
10019     if ( face[0] && face[1] )  {
10020       int nbNodes = face[0]->NbNodes();
10021       if ( nbNodes != face[1]->NbNodes() ) {
10022         MESSAGE("Diff nb of face nodes");
10023         aResult = SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
10024         break; // do not return because it s necessary to remove tmp faces
10025       }
10026       bool reverse[] = { false, false }; // order of notLinkNodes of quadrangle
10027       if ( nbNodes == 3 ) {
10028         //nReplaceMap.insert( TNodeNodeMap::value_type
10029         //                   ( notLinkNodes[0][0], notLinkNodes[1][0] ));
10030         nReplaceMap.insert( TNodeNodeMap::value_type
10031                             ( notLinkNodes1[0], notLinkNodes2[0] ));
10032       }
10033       else {
10034         for ( iSide = 0; iSide < 2; iSide++ ) { // loop on 2 sides
10035           // analyse link orientation in faces
10036           int i1 = iLinkNode[ iSide ][ 0 ];
10037           int i2 = iLinkNode[ iSide ][ 1 ];
10038           reverse[ iSide ] = Abs( i1 - i2 ) == 1 ? i1 > i2 : i2 > i1;
10039           // if notLinkNodes are the first and the last ones, then
10040           // their order does not correspond to the link orientation
10041           if (( i1 == 1 && i2 == 2 ) ||
10042               ( i1 == 2 && i2 == 1 ))
10043             reverse[ iSide ] = !reverse[ iSide ];
10044         }
10045         if ( reverse[0] == reverse[1] ) {
10046           //nReplaceMap.insert( TNodeNodeMap::value_type
10047           //                   ( notLinkNodes[0][0], notLinkNodes[1][0] ));
10048           //nReplaceMap.insert( TNodeNodeMap::value_type
10049           //                   ( notLinkNodes[0][1], notLinkNodes[1][1] ));
10050           for(int nn=0; nn<nbNodes-2; nn++) {
10051             nReplaceMap.insert( TNodeNodeMap::value_type
10052                                 ( notLinkNodes1[nn], notLinkNodes2[nn] ));
10053           }
10054         }
10055         else {
10056           //nReplaceMap.insert( TNodeNodeMap::value_type
10057           //                   ( notLinkNodes[0][0], notLinkNodes[1][1] ));
10058           //nReplaceMap.insert( TNodeNodeMap::value_type
10059           //                   ( notLinkNodes[0][1], notLinkNodes[1][0] ));
10060           for(int nn=0; nn<nbNodes-2; nn++) {
10061             nReplaceMap.insert( TNodeNodeMap::value_type
10062                                 ( notLinkNodes1[nn], notLinkNodes2[nbNodes-3-nn] ));
10063           }
10064         }
10065       }
10066
10067       // add other links of the faces to linkList
10068       // -----------------------------------------
10069
10070       //const SMDS_MeshNode** nodes = faceNodes[ 0 ];
10071       for ( iNode = 0; iNode < nbNodes; iNode++ )  {
10072         //linkID = aLinkID_Gen.GetLinkID( nodes[iNode], nodes[iNode+1] );
10073         linkID = aLinkID_Gen.GetLinkID( fnodes1[iNode], fnodes1[iNode+1] );
10074         pair< set<long>::iterator, bool > iter_isnew = linkIdSet.insert( linkID );
10075         if ( !iter_isnew.second ) { // already in a set: no need to process
10076           linkIdSet.erase( iter_isnew.first );
10077         }
10078         else // new in set == encountered for the first time: add
10079         {
10080           //const SMDS_MeshNode* n1 = nodes[ iNode ];
10081           //const SMDS_MeshNode* n2 = nodes[ iNode + 1];
10082           const SMDS_MeshNode* n1 = fnodes1[ iNode ];
10083           const SMDS_MeshNode* n2 = fnodes1[ iNode + 1];
10084           linkList[0].push_back ( NLink( n1, n2 ));
10085           linkList[1].push_back ( NLink( nReplaceMap[n1], nReplaceMap[n2] ));
10086         }
10087       }
10088     } // 2 faces found
10089   } // loop on link lists
10090
10091   if ( aResult == SEW_OK &&
10092        ( linkIt[0] != linkList[0].end() ||
10093          !faceSetPtr[0]->empty() || !faceSetPtr[1]->empty() )) {
10094     MESSAGE( (linkIt[0] != linkList[0].end()) <<" "<< (faceSetPtr[0]->empty()) <<
10095              " " << (faceSetPtr[1]->empty()));
10096     aResult = SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
10097   }
10098
10099   // ====================================================================
10100   // 3. Replace nodes in elements of the side 1 and remove replaced nodes
10101   // ====================================================================
10102
10103   // delete temporary faces: they are in reverseElements of actual nodes
10104 //  SMDS_FaceIteratorPtr tmpFaceIt = aTmpFacesMesh.facesIterator();
10105 //  while ( tmpFaceIt->more() )
10106 //    aTmpFacesMesh.RemoveElement( tmpFaceIt->next() );
10107 //  list<const SMDS_MeshElement* >::iterator tmpFaceIt = tempFaceList.begin();
10108 //  for (; tmpFaceIt !=tempFaceList.end(); ++tmpFaceIt)
10109 //    aMesh->RemoveElement(*tmpFaceIt);
10110
10111   if ( aResult != SEW_OK)
10112     return aResult;
10113
10114   list< int > nodeIDsToRemove/*, elemIDsToRemove*/;
10115   // loop on nodes replacement map
10116   TNodeNodeMap::iterator nReplaceMapIt = nReplaceMap.begin(), nnIt;
10117   for ( ; nReplaceMapIt != nReplaceMap.end(); nReplaceMapIt++ )
10118     if ( (*nReplaceMapIt).first != (*nReplaceMapIt).second ) {
10119       const SMDS_MeshNode* nToRemove = (*nReplaceMapIt).first;
10120       nodeIDsToRemove.push_back( nToRemove->GetID() );
10121       // loop on elements sharing nToRemove
10122       SMDS_ElemIteratorPtr invElemIt = nToRemove->GetInverseElementIterator();
10123       while ( invElemIt->more() ) {
10124         const SMDS_MeshElement* e = invElemIt->next();
10125         // get a new suite of nodes: make replacement
10126         int nbReplaced = 0, i = 0, nbNodes = e->NbNodes();
10127         vector< const SMDS_MeshNode*> nodes( nbNodes );
10128         SMDS_ElemIteratorPtr nIt = e->nodesIterator();
10129         while ( nIt->more() ) {
10130           const SMDS_MeshNode* n =
10131             static_cast<const SMDS_MeshNode*>( nIt->next() );
10132           nnIt = nReplaceMap.find( n );
10133           if ( nnIt != nReplaceMap.end() ) {
10134             nbReplaced++;
10135             n = (*nnIt).second;
10136           }
10137           nodes[ i++ ] = n;
10138         }
10139         //       if ( nbReplaced == nbNodes && e->GetType() == SMDSAbs_Face )
10140         //         elemIDsToRemove.push_back( e->GetID() );
10141         //       else
10142         if ( nbReplaced )
10143           {
10144             SMDSAbs_ElementType etyp = e->GetType();
10145             SMDS_MeshElement* newElem = this->AddElement(nodes, etyp, false);
10146             if (newElem)
10147               {
10148                 myLastCreatedElems.Append(newElem);
10149                 AddToSameGroups(newElem, e, aMesh);
10150                 int aShapeId = e->getshapeId();
10151                 if ( aShapeId )
10152                   {
10153                     aMesh->SetMeshElementOnShape( newElem, aShapeId );
10154                   }
10155               }
10156             aMesh->RemoveElement(e);
10157           }
10158       }
10159     }
10160
10161   Remove( nodeIDsToRemove, true );
10162
10163   return aResult;
10164 }
10165
10166 //================================================================================
10167 /*!
10168  * \brief Find corresponding nodes in two sets of faces
10169  * \param theSide1 - first face set
10170  * \param theSide2 - second first face
10171  * \param theFirstNode1 - a boundary node of set 1
10172  * \param theFirstNode2 - a node of set 2 corresponding to theFirstNode1
10173  * \param theSecondNode1 - a boundary node of set 1 linked with theFirstNode1
10174  * \param theSecondNode2 - a node of set 2 corresponding to theSecondNode1
10175  * \param nReplaceMap - output map of corresponding nodes
10176  * \return bool  - is a success or not
10177  */
10178 //================================================================================
10179
10180 #ifdef _DEBUG_
10181 //#define DEBUG_MATCHING_NODES
10182 #endif
10183
10184 SMESH_MeshEditor::Sew_Error
10185 SMESH_MeshEditor::FindMatchingNodes(set<const SMDS_MeshElement*>& theSide1,
10186                                     set<const SMDS_MeshElement*>& theSide2,
10187                                     const SMDS_MeshNode*          theFirstNode1,
10188                                     const SMDS_MeshNode*          theFirstNode2,
10189                                     const SMDS_MeshNode*          theSecondNode1,
10190                                     const SMDS_MeshNode*          theSecondNode2,
10191                                     TNodeNodeMap &                nReplaceMap)
10192 {
10193   set<const SMDS_MeshElement*> * faceSetPtr[] = { &theSide1, &theSide2 };
10194
10195   nReplaceMap.clear();
10196   if ( theFirstNode1 != theFirstNode2 )
10197     nReplaceMap.insert( make_pair( theFirstNode1, theFirstNode2 ));
10198   if ( theSecondNode1 != theSecondNode2 )
10199     nReplaceMap.insert( make_pair( theSecondNode1, theSecondNode2 ));
10200
10201   set< SMESH_TLink > linkSet; // set of nodes where order of nodes is ignored
10202   linkSet.insert( SMESH_TLink( theFirstNode1, theSecondNode1 ));
10203
10204   list< NLink > linkList[2];
10205   linkList[0].push_back( NLink( theFirstNode1, theSecondNode1 ));
10206   linkList[1].push_back( NLink( theFirstNode2, theSecondNode2 ));
10207
10208   // loop on links in linkList; find faces by links and append links
10209   // of the found faces to linkList
10210   list< NLink >::iterator linkIt[] = { linkList[0].begin(), linkList[1].begin() } ;
10211   for ( ; linkIt[0] != linkList[0].end(); linkIt[0]++, linkIt[1]++ ) {
10212     NLink link[] = { *linkIt[0], *linkIt[1] };
10213     if ( linkSet.find( link[0] ) == linkSet.end() )
10214       continue;
10215
10216     // by links, find faces in the face sets,
10217     // and find indices of link nodes in the found faces;
10218     // in a face set, there is only one or no face sharing a link
10219     // ---------------------------------------------------------------
10220
10221     const SMDS_MeshElement* face[] = { 0, 0 };
10222     list<const SMDS_MeshNode*> notLinkNodes[2];
10223     //bool reverse[] = { false, false }; // order of notLinkNodes
10224     int nbNodes[2];
10225     for ( int iSide = 0; iSide < 2; iSide++ ) // loop on 2 sides
10226     {
10227       const SMDS_MeshNode* n1 = link[iSide].first;
10228       const SMDS_MeshNode* n2 = link[iSide].second;
10229       set<const SMDS_MeshElement*> * faceSet = faceSetPtr[ iSide ];
10230       set< const SMDS_MeshElement* > facesOfNode1;
10231       for ( int iNode = 0; iNode < 2; iNode++ ) // loop on 2 nodes of a link
10232       {
10233         // during a loop of the first node, we find all faces around n1,
10234         // during a loop of the second node, we find one face sharing both n1 and n2
10235         const SMDS_MeshNode* n = iNode ? n1 : n2; // a node of a link
10236         SMDS_ElemIteratorPtr fIt = n->GetInverseElementIterator(SMDSAbs_Face);
10237         while ( fIt->more() ) { // loop on faces sharing a node
10238           const SMDS_MeshElement* f = fIt->next();
10239           if (faceSet->find( f ) != faceSet->end() && // f is in face set
10240               ! facesOfNode1.insert( f ).second ) // f encounters twice
10241           {
10242             if ( face[ iSide ] ) {
10243               MESSAGE( "2 faces per link " );
10244               return ( iSide ? SEW_BAD_SIDE2_NODES : SEW_BAD_SIDE1_NODES );
10245             }
10246             face[ iSide ] = f;
10247             faceSet->erase( f );
10248
10249             // get not link nodes
10250             int nbN = f->NbNodes();
10251             if ( f->IsQuadratic() )
10252               nbN /= 2;
10253             nbNodes[ iSide ] = nbN;
10254             list< const SMDS_MeshNode* > & nodes = notLinkNodes[ iSide ];
10255             int i1 = f->GetNodeIndex( n1 );
10256             int i2 = f->GetNodeIndex( n2 );
10257             int iEnd = nbN, iBeg = -1, iDelta = 1;
10258             bool reverse = ( Abs( i1 - i2 ) == 1 ? i1 > i2 : i2 > i1 );
10259             if ( reverse ) {
10260               std::swap( iEnd, iBeg ); iDelta = -1;
10261             }
10262             int i = i2;
10263             while ( true ) {
10264               i += iDelta;
10265               if ( i == iEnd ) i = iBeg + iDelta;
10266               if ( i == i1 ) break;
10267               nodes.push_back ( f->GetNode( i ) );
10268             }
10269           }
10270         }
10271       }
10272     }
10273     // check similarity of elements of the sides
10274     if (( face[0] && !face[1] ) || ( !face[0] && face[1] )) {
10275       MESSAGE("Correspondent face not found on side " << ( face[0] ? 1 : 0 ));
10276       if ( nReplaceMap.size() == 2 ) { // faces on input nodes not found
10277         return ( face[0] ? SEW_BAD_SIDE2_NODES : SEW_BAD_SIDE1_NODES );
10278       }
10279       else {
10280         return SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
10281       }
10282     }
10283
10284     // set nodes to merge
10285     // -------------------
10286
10287     if ( face[0] && face[1] )  {
10288       if ( nbNodes[0] != nbNodes[1] ) {
10289         MESSAGE("Diff nb of face nodes");
10290         return SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
10291       }
10292 #ifdef DEBUG_MATCHING_NODES
10293       MESSAGE ( " Link 1: " << link[0].first->GetID() <<" "<< link[0].second->GetID()
10294                 << " F 1: " << face[0] << "| Link 2: " << link[1].first->GetID() <<" "
10295                 << link[1].second->GetID() << " F 2: " << face[1] << " | Bind: " ) ;
10296 #endif
10297       int nbN = nbNodes[0];
10298       {
10299         list<const SMDS_MeshNode*>::iterator n1 = notLinkNodes[0].begin();
10300         list<const SMDS_MeshNode*>::iterator n2 = notLinkNodes[1].begin();
10301         for ( int i = 0 ; i < nbN - 2; ++i ) {
10302 #ifdef DEBUG_MATCHING_NODES
10303           MESSAGE ( (*n1)->GetID() << " to " << (*n2)->GetID() );
10304 #endif
10305           nReplaceMap.insert( make_pair( *(n1++), *(n2++) ));
10306         }
10307       }
10308
10309       // add other links of the face 1 to linkList
10310       // -----------------------------------------
10311
10312       const SMDS_MeshElement* f0 = face[0];
10313       const SMDS_MeshNode* n1 = f0->GetNode( nbN - 1 );
10314       for ( int i = 0; i < nbN; i++ )
10315       {
10316         const SMDS_MeshNode* n2 = f0->GetNode( i );
10317         pair< set< SMESH_TLink >::iterator, bool > iter_isnew =
10318           linkSet.insert( SMESH_TLink( n1, n2 ));
10319         if ( !iter_isnew.second ) { // already in a set: no need to process
10320           linkSet.erase( iter_isnew.first );
10321         }
10322         else // new in set == encountered for the first time: add
10323         {
10324 #ifdef DEBUG_MATCHING_NODES
10325           MESSAGE ( "Add link 1: " << n1->GetID() << " " << n2->GetID() << " "
10326                     << " | link 2: " << nReplaceMap[n1]->GetID() << " " << nReplaceMap[n2]->GetID() << " " );
10327 #endif
10328           linkList[0].push_back ( NLink( n1, n2 ));
10329           linkList[1].push_back ( NLink( nReplaceMap[n1], nReplaceMap[n2] ));
10330         }
10331         n1 = n2;
10332       }
10333     } // 2 faces found
10334   } // loop on link lists
10335
10336   return SEW_OK;
10337 }
10338
10339 //================================================================================
10340 /*!
10341   \brief Creates a hole in a mesh by doubling the nodes of some particular elements
10342   \param theElems - the list of elements (edges or faces) to be replicated
10343   The nodes for duplication could be found from these elements
10344   \param theNodesNot - list of nodes to NOT replicate
10345   \param theAffectedElems - the list of elements (cells and edges) to which the 
10346   replicated nodes should be associated to.
10347   \return TRUE if operation has been completed successfully, FALSE otherwise
10348 */
10349 //================================================================================
10350
10351 bool SMESH_MeshEditor::DoubleNodes( const TIDSortedElemSet& theElems,
10352                                     const TIDSortedElemSet& theNodesNot,
10353                                     const TIDSortedElemSet& theAffectedElems )
10354 {
10355   myLastCreatedElems.Clear();
10356   myLastCreatedNodes.Clear();
10357
10358   if ( theElems.size() == 0 )
10359     return false;
10360
10361   SMESHDS_Mesh* aMeshDS = GetMeshDS();
10362   if ( !aMeshDS )
10363     return false;
10364
10365   bool res = false;
10366   std::map< const SMDS_MeshNode*, const SMDS_MeshNode* > anOldNodeToNewNode;
10367   // duplicate elements and nodes
10368   res = doubleNodes( aMeshDS, theElems, theNodesNot, anOldNodeToNewNode, true );
10369   // replce nodes by duplications
10370   res = doubleNodes( aMeshDS, theAffectedElems, theNodesNot, anOldNodeToNewNode, false );
10371   return res;
10372 }
10373
10374 //================================================================================
10375 /*!
10376   \brief Creates a hole in a mesh by doubling the nodes of some particular elements
10377   \param theMeshDS - mesh instance
10378   \param theElems - the elements replicated or modified (nodes should be changed)
10379   \param theNodesNot - nodes to NOT replicate
10380   \param theNodeNodeMap - relation of old node to new created node
10381   \param theIsDoubleElem - flag os to replicate element or modify
10382   \return TRUE if operation has been completed successfully, FALSE otherwise
10383 */
10384 //================================================================================
10385
10386 bool SMESH_MeshEditor::doubleNodes( SMESHDS_Mesh*     theMeshDS,
10387                                     const TIDSortedElemSet& theElems,
10388                                     const TIDSortedElemSet& theNodesNot,
10389                                     std::map< const SMDS_MeshNode*,
10390                                     const SMDS_MeshNode* >& theNodeNodeMap,
10391                                     const bool theIsDoubleElem )
10392 {
10393   MESSAGE("doubleNodes");
10394   // iterate on through element and duplicate them (by nodes duplication)
10395   bool res = false;
10396   TIDSortedElemSet::const_iterator elemItr = theElems.begin();
10397   for ( ;  elemItr != theElems.end(); ++elemItr )
10398   {
10399     const SMDS_MeshElement* anElem = *elemItr;
10400     if (!anElem)
10401       continue;
10402
10403     bool isDuplicate = false;
10404     // duplicate nodes to duplicate element
10405     std::vector<const SMDS_MeshNode*> newNodes( anElem->NbNodes() );
10406     SMDS_ElemIteratorPtr anIter = anElem->nodesIterator();
10407     int ind = 0;
10408     while ( anIter->more() ) 
10409     { 
10410
10411       SMDS_MeshNode* aCurrNode = (SMDS_MeshNode*)anIter->next();
10412       SMDS_MeshNode* aNewNode = aCurrNode;
10413       if ( theNodeNodeMap.find( aCurrNode ) != theNodeNodeMap.end() )
10414         aNewNode = (SMDS_MeshNode*)theNodeNodeMap[ aCurrNode ];
10415       else if ( theIsDoubleElem && theNodesNot.find( aCurrNode ) == theNodesNot.end() )
10416       {
10417         // duplicate node
10418         aNewNode = theMeshDS->AddNode( aCurrNode->X(), aCurrNode->Y(), aCurrNode->Z() );
10419         theNodeNodeMap[ aCurrNode ] = aNewNode;
10420         myLastCreatedNodes.Append( aNewNode );
10421       }
10422       isDuplicate |= (aCurrNode != aNewNode);
10423       newNodes[ ind++ ] = aNewNode;
10424     }
10425     if ( !isDuplicate )
10426       continue;
10427
10428     if ( theIsDoubleElem )
10429       AddElement(newNodes, anElem->GetType(), anElem->IsPoly());
10430     else
10431       {
10432       MESSAGE("ChangeElementNodes");
10433       theMeshDS->ChangeElementNodes( anElem, &newNodes[ 0 ], anElem->NbNodes() );
10434       }
10435     res = true;
10436   }
10437   return res;
10438 }
10439
10440 //================================================================================
10441 /*!
10442   \brief Creates a hole in a mesh by doubling the nodes of some particular elements
10443   \param theNodes - identifiers of nodes to be doubled
10444   \param theModifiedElems - identifiers of elements to be updated by the new (doubled) 
10445          nodes. If list of element identifiers is empty then nodes are doubled but 
10446          they not assigned to elements
10447   \return TRUE if operation has been completed successfully, FALSE otherwise
10448 */
10449 //================================================================================
10450
10451 bool SMESH_MeshEditor::DoubleNodes( const std::list< int >& theListOfNodes, 
10452                                     const std::list< int >& theListOfModifiedElems )
10453 {
10454   MESSAGE("DoubleNodes");
10455   myLastCreatedElems.Clear();
10456   myLastCreatedNodes.Clear();
10457
10458   if ( theListOfNodes.size() == 0 )
10459     return false;
10460
10461   SMESHDS_Mesh* aMeshDS = GetMeshDS();
10462   if ( !aMeshDS )
10463     return false;
10464
10465   // iterate through nodes and duplicate them
10466
10467   std::map< const SMDS_MeshNode*, const SMDS_MeshNode* > anOldNodeToNewNode;
10468
10469   std::list< int >::const_iterator aNodeIter;
10470   for ( aNodeIter = theListOfNodes.begin(); aNodeIter != theListOfNodes.end(); ++aNodeIter )
10471   {
10472     int aCurr = *aNodeIter;
10473     SMDS_MeshNode* aNode = (SMDS_MeshNode*)aMeshDS->FindNode( aCurr );
10474     if ( !aNode )
10475       continue;
10476
10477     // duplicate node
10478
10479     const SMDS_MeshNode* aNewNode = aMeshDS->AddNode( aNode->X(), aNode->Y(), aNode->Z() );
10480     if ( aNewNode )
10481     {
10482       anOldNodeToNewNode[ aNode ] = aNewNode;
10483       myLastCreatedNodes.Append( aNewNode );
10484     }
10485   }
10486
10487   // Create map of new nodes for modified elements
10488
10489   std::map< SMDS_MeshElement*, vector<const SMDS_MeshNode*> > anElemToNodes;
10490
10491   std::list< int >::const_iterator anElemIter;
10492   for ( anElemIter = theListOfModifiedElems.begin(); 
10493         anElemIter != theListOfModifiedElems.end(); ++anElemIter )
10494   {
10495     int aCurr = *anElemIter;
10496     SMDS_MeshElement* anElem = (SMDS_MeshElement*)aMeshDS->FindElement( aCurr );
10497     if ( !anElem )
10498       continue;
10499
10500     vector<const SMDS_MeshNode*> aNodeArr( anElem->NbNodes() );
10501
10502     SMDS_ElemIteratorPtr anIter = anElem->nodesIterator();
10503     int ind = 0;
10504     while ( anIter->more() ) 
10505     { 
10506       SMDS_MeshNode* aCurrNode = (SMDS_MeshNode*)anIter->next();
10507       if ( aCurr && anOldNodeToNewNode.find( aCurrNode ) != anOldNodeToNewNode.end() )
10508       {
10509         const SMDS_MeshNode* aNewNode = anOldNodeToNewNode[ aCurrNode ];
10510         aNodeArr[ ind++ ] = aNewNode;
10511       }
10512       else
10513         aNodeArr[ ind++ ] = aCurrNode;
10514     }
10515     anElemToNodes[ anElem ] = aNodeArr;
10516   }
10517
10518   // Change nodes of elements  
10519
10520   std::map< SMDS_MeshElement*, vector<const SMDS_MeshNode*> >::iterator
10521     anElemToNodesIter = anElemToNodes.begin();
10522   for ( ; anElemToNodesIter != anElemToNodes.end(); ++anElemToNodesIter )
10523   {
10524     const SMDS_MeshElement* anElem = anElemToNodesIter->first;
10525     vector<const SMDS_MeshNode*> aNodeArr = anElemToNodesIter->second;
10526     if ( anElem )
10527       {
10528       MESSAGE("ChangeElementNodes");
10529       aMeshDS->ChangeElementNodes( anElem, &aNodeArr[ 0 ], anElem->NbNodes() );
10530       }
10531   }
10532
10533   return true;
10534 }
10535
10536 namespace {
10537
10538   //================================================================================
10539   /*!
10540   \brief Check if element located inside shape
10541   \return TRUE if IN or ON shape, FALSE otherwise
10542   */
10543   //================================================================================
10544
10545   template<class Classifier>
10546   bool isInside(const SMDS_MeshElement* theElem,
10547                 Classifier&             theClassifier,
10548                 const double            theTol)
10549   {
10550     gp_XYZ centerXYZ (0, 0, 0);
10551     SMDS_ElemIteratorPtr aNodeItr = theElem->nodesIterator();
10552     while (aNodeItr->more())
10553       centerXYZ += SMESH_TNodeXYZ(cast2Node( aNodeItr->next()));
10554
10555     gp_Pnt aPnt = centerXYZ / theElem->NbNodes();
10556     theClassifier.Perform(aPnt, theTol);
10557     TopAbs_State aState = theClassifier.State();
10558     return (aState == TopAbs_IN || aState == TopAbs_ON );
10559   }
10560
10561   //================================================================================
10562   /*!
10563    * \brief Classifier of the 3D point on the TopoDS_Face
10564    *        with interaface suitable for isInside()
10565    */
10566   //================================================================================
10567
10568   struct _FaceClassifier
10569   {
10570     Extrema_ExtPS       _extremum;
10571     BRepAdaptor_Surface _surface;
10572     TopAbs_State        _state;
10573
10574     _FaceClassifier(const TopoDS_Face& face):_extremum(),_surface(face),_state(TopAbs_OUT)
10575     {
10576       _extremum.Initialize( _surface,
10577                             _surface.FirstUParameter(), _surface.LastUParameter(),
10578                             _surface.FirstVParameter(), _surface.LastVParameter(),
10579                             _surface.Tolerance(), _surface.Tolerance() );
10580     }
10581     void Perform(const gp_Pnt& aPnt, double theTol)
10582     {
10583       _state = TopAbs_OUT;
10584       _extremum.Perform(aPnt);
10585       if ( _extremum.IsDone() )
10586         for ( int iSol = 1; iSol <= _extremum.NbExt() && _state == TopAbs_OUT; ++iSol)
10587 #if OCC_VERSION_LARGE > 0x06040000 // Porting to OCCT6.5.1
10588           _state = ( _extremum.SquareDistance(iSol) <= theTol ? TopAbs_IN : TopAbs_OUT );
10589 #else
10590           _state = ( _extremum.Value(iSol) <= theTol ? TopAbs_IN : TopAbs_OUT );
10591 #endif
10592     }
10593     TopAbs_State State() const
10594     {
10595       return _state;
10596     }
10597   };
10598 }
10599
10600 //================================================================================
10601 /*!
10602   \brief Creates a hole in a mesh by doubling the nodes of some particular elements
10603   \param theElems - group of of elements (edges or faces) to be replicated
10604   \param theNodesNot - group of nodes not to replicate
10605   \param theShape - shape to detect affected elements (element which geometric center
10606   located on or inside shape).
10607   The replicated nodes should be associated to affected elements.
10608   \return TRUE if operation has been completed successfully, FALSE otherwise
10609 */
10610 //================================================================================
10611
10612 bool SMESH_MeshEditor::DoubleNodesInRegion( const TIDSortedElemSet& theElems,
10613                                             const TIDSortedElemSet& theNodesNot,
10614                                             const TopoDS_Shape&     theShape )
10615 {
10616   if ( theShape.IsNull() )
10617     return false;
10618
10619   const double aTol = Precision::Confusion();
10620   auto_ptr< BRepClass3d_SolidClassifier> bsc3d;
10621   auto_ptr<_FaceClassifier>              aFaceClassifier;
10622   if ( theShape.ShapeType() == TopAbs_SOLID )
10623   {
10624     bsc3d.reset( new BRepClass3d_SolidClassifier(theShape));;
10625     bsc3d->PerformInfinitePoint(aTol);
10626   }
10627   else if (theShape.ShapeType() == TopAbs_FACE )
10628   {
10629     aFaceClassifier.reset( new _FaceClassifier(TopoDS::Face(theShape)));
10630   }
10631
10632   // iterates on indicated elements and get elements by back references from their nodes
10633   TIDSortedElemSet anAffected;
10634   TIDSortedElemSet::const_iterator elemItr = theElems.begin();
10635   for ( ;  elemItr != theElems.end(); ++elemItr )
10636   {
10637     SMDS_MeshElement* anElem = (SMDS_MeshElement*)*elemItr;
10638     if (!anElem)
10639       continue;
10640
10641     SMDS_ElemIteratorPtr nodeItr = anElem->nodesIterator();
10642     while ( nodeItr->more() )
10643     {
10644       const SMDS_MeshNode* aNode = cast2Node(nodeItr->next());
10645       if ( !aNode || theNodesNot.find(aNode) != theNodesNot.end() )
10646         continue;
10647       SMDS_ElemIteratorPtr backElemItr = aNode->GetInverseElementIterator();
10648       while ( backElemItr->more() )
10649       {
10650         const SMDS_MeshElement* curElem = backElemItr->next();
10651         if ( curElem && theElems.find(curElem) == theElems.end() &&
10652              ( bsc3d.get() ?
10653                isInside( curElem, *bsc3d, aTol ) :
10654                isInside( curElem, *aFaceClassifier, aTol )))
10655           anAffected.insert( curElem );
10656       }
10657     }
10658   }
10659   return DoubleNodes( theElems, theNodesNot, anAffected );
10660 }
10661
10662 /*!
10663  *  \brief compute an oriented angle between two planes defined by four points.
10664  *  The vector (p0,p1) defines the intersection of the 2 planes (p0,p1,g1) and (p0,p1,g2)
10665  *  @param p0 base of the rotation axe
10666  *  @param p1 extremity of the rotation axe
10667  *  @param g1 belongs to the first plane
10668  *  @param g2 belongs to the second plane
10669  */
10670 double SMESH_MeshEditor::OrientedAngle(const gp_Pnt& p0, const gp_Pnt& p1, const gp_Pnt& g1, const gp_Pnt& g2)
10671 {
10672 //  MESSAGE("    p0: " << p0.X() << " " << p0.Y() << " " << p0.Z());
10673 //  MESSAGE("    p1: " << p1.X() << " " << p1.Y() << " " << p1.Z());
10674 //  MESSAGE("    g1: " << g1.X() << " " << g1.Y() << " " << g1.Z());
10675 //  MESSAGE("    g2: " << g2.X() << " " << g2.Y() << " " << g2.Z());
10676   gp_Vec vref(p0, p1);
10677   gp_Vec v1(p0, g1);
10678   gp_Vec v2(p0, g2);
10679   gp_Vec n1 = vref.Crossed(v1);
10680   gp_Vec n2 = vref.Crossed(v2);
10681   return n2.AngleWithRef(n1, vref);
10682 }
10683
10684 /*!
10685  * \brief Double nodes on shared faces between groups of volumes and create flat elements on demand.
10686  * The list of groups must describe a partition of the mesh volumes.
10687  * The nodes of the internal faces at the boundaries of the groups are doubled.
10688  * In option, the internal faces are replaced by flat elements.
10689  * Triangles are transformed in prisms, and quadrangles in hexahedrons.
10690  * The flat elements are stored in groups of volumes.
10691  * @param theElems - list of groups of volumes, where a group of volume is a set of
10692  * SMDS_MeshElements sorted by Id.
10693  * @param createJointElems - if TRUE, create the elements
10694  * @return TRUE if operation has been completed successfully, FALSE otherwise
10695  */
10696 bool SMESH_MeshEditor::DoubleNodesOnGroupBoundaries( const std::vector<TIDSortedElemSet>& theElems,
10697                                                      bool createJointElems)
10698 {
10699   MESSAGE("----------------------------------------------");
10700   MESSAGE("SMESH_MeshEditor::doubleNodesOnGroupBoundaries");
10701   MESSAGE("----------------------------------------------");
10702
10703   SMESHDS_Mesh *meshDS = this->myMesh->GetMeshDS();
10704   meshDS->BuildDownWardConnectivity(true);
10705   CHRONO(50);
10706   SMDS_UnstructuredGrid *grid = meshDS->getGrid();
10707
10708   // --- build the list of faces shared by 2 domains (group of elements), with their domain and volume indexes
10709   //     build the list of cells with only a node or an edge on the border, with their domain and volume indexes
10710   //     build the list of nodes shared by 2 or more domains, with their domain indexes
10711
10712   std::map<DownIdType, std::map<int,int>, DownIdCompare> faceDomains; // face --> (id domain --> id volume)
10713   std::map<int,int>celldom; // cell vtkId --> domain
10714   std::map<DownIdType, std::map<int,int>, DownIdCompare> cellDomains;  // oldNode --> (id domain --> id cell)
10715   std::map<int, std::map<int,int> > nodeDomains; // oldId -->  (domainId --> newId)
10716   faceDomains.clear();
10717   celldom.clear();
10718   cellDomains.clear();
10719   nodeDomains.clear();
10720   std::map<int,int> emptyMap;
10721   std::set<int> emptySet;
10722   emptyMap.clear();
10723
10724   for (int idom = 0; idom < theElems.size(); idom++)
10725     {
10726
10727       // --- build a map (face to duplicate --> volume to modify)
10728       //     with all the faces shared by 2 domains (group of elements)
10729       //     and corresponding volume of this domain, for each shared face.
10730       //     a volume has a face shared by 2 domains if it has a neighbor which is not in is domain.
10731
10732       const TIDSortedElemSet& domain = theElems[idom];
10733       TIDSortedElemSet::const_iterator elemItr = domain.begin();
10734       for (; elemItr != domain.end(); ++elemItr)
10735         {
10736           SMDS_MeshElement* anElem = (SMDS_MeshElement*) *elemItr;
10737           if (!anElem)
10738             continue;
10739           int vtkId = anElem->getVtkId();
10740           int neighborsVtkIds[NBMAXNEIGHBORS];
10741           int downIds[NBMAXNEIGHBORS];
10742           unsigned char downTypes[NBMAXNEIGHBORS];
10743           int nbNeighbors = grid->GetNeighbors(neighborsVtkIds, downIds, downTypes, vtkId);
10744           for (int n = 0; n < nbNeighbors; n++)
10745             {
10746               int smdsId = meshDS->fromVtkToSmds(neighborsVtkIds[n]);
10747               const SMDS_MeshElement* elem = meshDS->FindElement(smdsId);
10748               if (! domain.count(elem)) // neighbor is in another domain : face is shared
10749                 {
10750                   DownIdType face(downIds[n], downTypes[n]);
10751                   if (!faceDomains.count(face))
10752                     faceDomains[face] = emptyMap; // create an empty entry for face
10753                   if (!faceDomains[face].count(idom))
10754                     {
10755                       faceDomains[face][idom] = vtkId; // volume associated to face in this domain
10756                       celldom[vtkId] = idom;
10757                     }
10758                 }
10759             }
10760         }
10761     }
10762
10763   //MESSAGE("Number of shared faces " << faceDomains.size());
10764   std::map<DownIdType, std::map<int, int>, DownIdCompare>::iterator itface;
10765
10766   // --- explore the shared faces domain by domain,
10767   //     explore the nodes of the face and see if they belong to a cell in the domain,
10768   //     which has only a node or an edge on the border (not a shared face)
10769
10770   for (int idomain = 0; idomain < theElems.size(); idomain++)
10771     {
10772       const TIDSortedElemSet& domain = theElems[idomain];
10773       itface = faceDomains.begin();
10774       for (; itface != faceDomains.end(); ++itface)
10775         {
10776           std::map<int, int> domvol = itface->second;
10777           if (!domvol.count(idomain))
10778             continue;
10779           DownIdType face = itface->first;
10780           //MESSAGE(" --- face " << face.cellId);
10781           std::set<int> oldNodes;
10782           oldNodes.clear();
10783           grid->GetNodeIds(oldNodes, face.cellId, face.cellType);
10784           std::set<int>::iterator itn = oldNodes.begin();
10785           for (; itn != oldNodes.end(); ++itn)
10786             {
10787               int oldId = *itn;
10788               //MESSAGE("     node " << oldId);
10789               std::set<int> cells;
10790               cells.clear();
10791               vtkCellLinks::Link l = grid->GetCellLinks()->GetLink(oldId);
10792               for (int i=0; i<l.ncells; i++)
10793                 {
10794                   int vtkId = l.cells[i];
10795                   const SMDS_MeshElement* anElem = GetMeshDS()->FindElement(GetMeshDS()->fromVtkToSmds(vtkId));
10796                   if (!domain.count(anElem))
10797                     continue;
10798                   int vtkType = grid->GetCellType(vtkId);
10799                   int downId = grid->CellIdToDownId(vtkId);
10800                   if (downId < 0)
10801                     {
10802                       MESSAGE("doubleNodesOnGroupBoundaries: internal algorithm problem");
10803                       continue; // not OK at this stage of the algorithm:
10804                                 //no cells created after BuildDownWardConnectivity
10805                     }
10806                   DownIdType aCell(downId, vtkType);
10807                   if (celldom.count(vtkId))
10808                     continue;
10809                   cellDomains[aCell][idomain] = vtkId;
10810                   celldom[vtkId] = idomain;
10811                 }
10812             }
10813         }
10814     }
10815
10816   // --- explore the shared faces domain by domain, to duplicate the nodes in a coherent way
10817   //     for each shared face, get the nodes
10818   //     for each node, for each domain of the face, create a clone of the node
10819
10820   // --- edges at the intersection of 3 or 4 domains, with the order of domains to build
10821   //     junction elements of type prism or hexa. the key is the pair of nodesId (lower first)
10822   //     the value is the ordered domain ids. (more than 4 domains not taken into account)
10823
10824   std::map<std::vector<int>, std::vector<int> > edgesMultiDomains; // nodes of edge --> ordered domains
10825   std::map<int, std::vector<int> > mutipleNodes; // nodes muti domains with domain order
10826
10827   for (int idomain = 0; idomain < theElems.size(); idomain++)
10828     {
10829       itface = faceDomains.begin();
10830       for (; itface != faceDomains.end(); ++itface)
10831         {
10832           std::map<int, int> domvol = itface->second;
10833           if (!domvol.count(idomain))
10834             continue;
10835           DownIdType face = itface->first;
10836           //MESSAGE(" --- face " << face.cellId);
10837           std::set<int> oldNodes;
10838           oldNodes.clear();
10839           grid->GetNodeIds(oldNodes, face.cellId, face.cellType);
10840           bool isMultipleDetected = false;
10841           std::set<int>::iterator itn = oldNodes.begin();
10842           for (; itn != oldNodes.end(); ++itn)
10843             {
10844               int oldId = *itn;
10845               //MESSAGE("     node " << oldId);
10846               if (!nodeDomains.count(oldId))
10847                 nodeDomains[oldId] = emptyMap; // create an empty entry for node
10848               if (nodeDomains[oldId].empty())
10849                 nodeDomains[oldId][idomain] = oldId; // keep the old node in the first domain
10850               std::map<int, int>::iterator itdom = domvol.begin();
10851               for (; itdom != domvol.end(); ++itdom)
10852                 {
10853                   int idom = itdom->first;
10854                   //MESSAGE("         domain " << idom);
10855                   if (!nodeDomains[oldId].count(idom)) // --- node to clone
10856                     {
10857                       if (nodeDomains[oldId].size() >= 2) // a multiple node
10858                         {
10859                           vector<int> orderedDoms;
10860                           //MESSAGE("multiple node " << oldId);
10861                           isMultipleDetected =true;
10862                           if (mutipleNodes.count(oldId))
10863                             orderedDoms = mutipleNodes[oldId];
10864                           else
10865                             {
10866                               map<int,int>::iterator it = nodeDomains[oldId].begin();
10867                               for (; it != nodeDomains[oldId].end(); ++it)
10868                                 orderedDoms.push_back(it->first);
10869                             }
10870                           orderedDoms.push_back(idom); // TODO order ==> push_front or back
10871                           //stringstream txt;
10872                           //for (int i=0; i<orderedDoms.size(); i++)
10873                           //  txt << orderedDoms[i] << " ";
10874                           //MESSAGE("orderedDoms " << txt.str());
10875                           mutipleNodes[oldId] = orderedDoms;
10876                         }
10877                       double *coords = grid->GetPoint(oldId);
10878                       SMDS_MeshNode *newNode = meshDS->AddNode(coords[0], coords[1], coords[2]);
10879                       int newId = newNode->getVtkId();
10880                       nodeDomains[oldId][idom] = newId; // cloned node for other domains
10881                       //MESSAGE("   newNode " << newId << " oldNode " << oldId << " size=" <<nodeDomains[oldId].size());
10882                     }
10883                   if (nodeDomains[oldId].size() >= 3)
10884                     {
10885                       //MESSAGE("confirm multiple node " << oldId);
10886                       isMultipleDetected =true;
10887                     }
10888                 }
10889             }
10890           if (isMultipleDetected) // check if an edge of the face is shared between 3 or more domains
10891             {
10892               //MESSAGE("multiple Nodes detected on a shared face");
10893               int downId = itface->first.cellId;
10894               unsigned char cellType = itface->first.cellType;
10895               int nbEdges = grid->getDownArray(cellType)->getNumberOfDownCells(downId);
10896               const int *downEdgeIds = grid->getDownArray(cellType)->getDownCells(downId);
10897               const unsigned char* edgeType = grid->getDownArray(cellType)->getDownTypes(downId);
10898               for (int ie =0; ie < nbEdges; ie++)
10899                 {
10900                   int nodes[3];
10901                   int nbNodes = grid->getDownArray(edgeType[ie])->getNodes(downEdgeIds[ie], nodes);
10902                   if (mutipleNodes.count(nodes[0]) && mutipleNodes.count(nodes[nbNodes-1]))
10903                     {
10904                       vector<int> vn0 = mutipleNodes[nodes[0]];
10905                       vector<int> vn1 = mutipleNodes[nodes[nbNodes - 1]];
10906                       sort( vn0.begin(), vn0.end() );
10907                       sort( vn1.begin(), vn1.end() );
10908                       if (vn0 == vn1)
10909                         {
10910                           //MESSAGE(" detect edgesMultiDomains " << nodes[0] << " " << nodes[nbNodes - 1]);
10911                           double *coords = grid->GetPoint(nodes[0]);
10912                           gp_Pnt p0(coords[0], coords[1], coords[2]);
10913                           coords = grid->GetPoint(nodes[nbNodes - 1]);
10914                           gp_Pnt p1(coords[0], coords[1], coords[2]);
10915                           gp_Pnt gref;
10916                           int vtkVolIds[1000];  // an edge can belong to a lot of volumes
10917                           map<int, SMDS_VtkVolume*> domvol; // domain --> a volume with the edge
10918                           map<int, double> angleDom; // oriented angles between planes defined by edge and volume centers
10919                           int nbvol = grid->GetParentVolumes(vtkVolIds, downEdgeIds[ie], edgeType[ie]);
10920                           for (int id=0; id < vn0.size(); id++)
10921                             {
10922                               int idom = vn0[id];
10923                               for (int ivol=0; ivol<nbvol; ivol++)
10924                                 {
10925                                   int smdsId = meshDS->fromVtkToSmds(vtkVolIds[ivol]);
10926                                   SMDS_MeshElement* elem = (SMDS_MeshElement*)meshDS->FindElement(smdsId);
10927                                   if (theElems[idom].count(elem))
10928                                     {
10929                                       SMDS_VtkVolume* svol = dynamic_cast<SMDS_VtkVolume*>(elem);
10930                                       domvol[idom] = svol;
10931                                       //MESSAGE("  domain " << idom << " volume " << elem->GetID());
10932                                       double values[3];
10933                                       vtkIdType npts = 0;
10934                                       vtkIdType* pts = 0;
10935                                       grid->GetCellPoints(vtkVolIds[ivol], npts, pts);
10936                                       SMDS_VtkVolume::gravityCenter(grid, pts, npts, values);
10937                                       if (id ==0)
10938                                         {
10939                                           gref.SetXYZ(gp_XYZ(values[0], values[1], values[2]));
10940                                           angleDom[idom] = 0;
10941                                         }
10942                                       else
10943                                         {
10944                                           gp_Pnt g(values[0], values[1], values[2]);
10945                                           angleDom[idom] = OrientedAngle(p0, p1, gref, g); // -pi<angle<+pi
10946                                           //MESSAGE("  angle=" << angleDom[idom]);
10947                                         }
10948                                       break;
10949                                     }
10950                                 }
10951                             }
10952                           map<double, int> sortedDom; // sort domains by angle
10953                           for (map<int, double>::iterator ia = angleDom.begin(); ia != angleDom.end(); ++ia)
10954                             sortedDom[ia->second] = ia->first;
10955                           vector<int> vnodes;
10956                           vector<int> vdom;
10957                           for (map<double, int>::iterator ib = sortedDom.begin(); ib != sortedDom.end(); ++ib)
10958                             {
10959                               vdom.push_back(ib->second);
10960                               //MESSAGE("  ordered domain " << ib->second << "  angle " << ib->first);
10961                             }
10962                           for (int ino = 0; ino < nbNodes; ino++)
10963                             vnodes.push_back(nodes[ino]);
10964                           edgesMultiDomains[vnodes] = vdom; // nodes vector --> ordered domains
10965                         }
10966                     }
10967                 }
10968             }
10969         }
10970     }
10971
10972   // --- iterate on shared faces (volumes to modify, face to extrude)
10973   //     get node id's of the face (id SMDS = id VTK)
10974   //     create flat element with old and new nodes if requested
10975
10976   // --- new quad nodes on flat quad elements: oldId --> ((domain1 X domain2) --> newId)
10977   //     (domain1 X domain2) = domain1 + MAXINT*domain2
10978
10979   std::map<int, std::map<long,int> > nodeQuadDomains;
10980   std::map<std::string, SMESH_Group*> mapOfJunctionGroups;
10981
10982   if (createJointElems)
10983     {
10984       itface = faceDomains.begin();
10985       for (; itface != faceDomains.end(); ++itface)
10986         {
10987           DownIdType face = itface->first;
10988           std::set<int> oldNodes;
10989           std::set<int>::iterator itn;
10990           oldNodes.clear();
10991           grid->GetNodeIds(oldNodes, face.cellId, face.cellType);
10992
10993           std::map<int, int> domvol = itface->second;
10994           std::map<int, int>::iterator itdom = domvol.begin();
10995           int dom1 = itdom->first;
10996           int vtkVolId = itdom->second;
10997           itdom++;
10998           int dom2 = itdom->first;
10999           SMDS_MeshVolume *vol = grid->extrudeVolumeFromFace(vtkVolId, dom1, dom2, oldNodes, nodeDomains,
11000                                                              nodeQuadDomains);
11001           stringstream grpname;
11002           grpname << "j_";
11003           if (dom1 < dom2)
11004             grpname << dom1 << "_" << dom2;
11005           else
11006             grpname << dom2 << "_" << dom1;
11007           int idg;
11008           string namegrp = grpname.str();
11009           if (!mapOfJunctionGroups.count(namegrp))
11010             mapOfJunctionGroups[namegrp] = this->myMesh->AddGroup(SMDSAbs_Volume, namegrp.c_str(), idg);
11011           SMESHDS_Group *sgrp = dynamic_cast<SMESHDS_Group*>(mapOfJunctionGroups[namegrp]->GetGroupDS());
11012           if (sgrp)
11013             sgrp->Add(vol->GetID());
11014         }
11015     }
11016
11017   // --- create volumes on multiple domain intersection if requested
11018   //     iterate on edgesMultiDomains
11019
11020   if (createJointElems)
11021     {
11022       std::map<std::vector<int>, std::vector<int> >::iterator ite = edgesMultiDomains.begin();
11023       for (; ite != edgesMultiDomains.end(); ++ite)
11024         {
11025           vector<int> nodes = ite->first;
11026           vector<int> orderDom = ite->second;
11027           vector<vtkIdType> orderedNodes;
11028           if (nodes.size() == 2)
11029             {
11030               //MESSAGE(" use edgesMultiDomains " << nodes[0] << " " << nodes[1]);
11031               for (int ino=0; ino < nodes.size(); ino++)
11032                 if (orderDom.size() == 3)
11033                   for (int idom = 0; idom <orderDom.size(); idom++)
11034                     orderedNodes.push_back( nodeDomains[nodes[ino]][orderDom[idom]] );
11035                 else
11036                   for (int idom = orderDom.size()-1; idom >=0; idom--)
11037                     orderedNodes.push_back( nodeDomains[nodes[ino]][orderDom[idom]] );
11038               SMDS_MeshVolume* vol = this->GetMeshDS()->AddVolumeFromVtkIds(orderedNodes);
11039
11040               stringstream grpname;
11041               grpname << "mj_";
11042               grpname << 0 << "_" << 0;
11043               int idg;
11044               string namegrp = grpname.str();
11045               if (!mapOfJunctionGroups.count(namegrp))
11046                 mapOfJunctionGroups[namegrp] = this->myMesh->AddGroup(SMDSAbs_Volume, namegrp.c_str(), idg);
11047               SMESHDS_Group *sgrp = dynamic_cast<SMESHDS_Group*>(mapOfJunctionGroups[namegrp]->GetGroupDS());
11048               if (sgrp)
11049                 sgrp->Add(vol->GetID());
11050             }
11051           else
11052             {
11053               //MESSAGE("Quadratic multiple joints not implemented");
11054               // TODO quadratic nodes
11055             }
11056         }
11057     }
11058
11059   // --- list the explicit faces and edges of the mesh that need to be modified,
11060   //     i.e. faces and edges built with one or more duplicated nodes.
11061   //     associate these faces or edges to their corresponding domain.
11062   //     only the first domain found is kept when a face or edge is shared
11063
11064   std::map<DownIdType, std::map<int,int>, DownIdCompare> faceOrEdgeDom; // cellToModify --> (id domain --> id cell)
11065   std::map<int,int> feDom; // vtk id of cell to modify --> id domain
11066   faceOrEdgeDom.clear();
11067   feDom.clear();
11068
11069   for (int idomain = 0; idomain < theElems.size(); idomain++)
11070     {
11071       std::map<int, std::map<int, int> >::const_iterator itnod = nodeDomains.begin();
11072       for (; itnod != nodeDomains.end(); ++itnod)
11073         {
11074           int oldId = itnod->first;
11075           //MESSAGE("     node " << oldId);
11076           vtkCellLinks::Link l = grid->GetCellLinks()->GetLink(oldId);
11077           for (int i = 0; i < l.ncells; i++)
11078             {
11079               int vtkId = l.cells[i];
11080               int vtkType = grid->GetCellType(vtkId);
11081               int downId = grid->CellIdToDownId(vtkId);
11082               if (downId < 0)
11083                 continue; // new cells: not to be modified
11084               DownIdType aCell(downId, vtkType);
11085               int volParents[1000];
11086               int nbvol = grid->GetParentVolumes(volParents, vtkId);
11087               for (int j = 0; j < nbvol; j++)
11088                 if (celldom.count(volParents[j]) && (celldom[volParents[j]] == idomain))
11089                   if (!feDom.count(vtkId))
11090                     {
11091                       feDom[vtkId] = idomain;
11092                       faceOrEdgeDom[aCell] = emptyMap;
11093                       faceOrEdgeDom[aCell][idomain] = vtkId; // affect face or edge to the first domain only
11094                       //MESSAGE("affect cell " << this->GetMeshDS()->fromVtkToSmds(vtkId) << " domain " << idomain
11095                       //        << " type " << vtkType << " downId " << downId);
11096                     }
11097             }
11098         }
11099     }
11100
11101   // --- iterate on shared faces (volumes to modify, face to extrude)
11102   //     get node id's of the face
11103   //     replace old nodes by new nodes in volumes, and update inverse connectivity
11104
11105   std::map<DownIdType, std::map<int,int>, DownIdCompare>* maps[3] = {&faceDomains, &cellDomains, &faceOrEdgeDom};
11106   for (int m=0; m<3; m++)
11107     {
11108       std::map<DownIdType, std::map<int,int>, DownIdCompare>* amap = maps[m];
11109       itface = (*amap).begin();
11110       for (; itface != (*amap).end(); ++itface)
11111         {
11112           DownIdType face = itface->first;
11113           std::set<int> oldNodes;
11114           std::set<int>::iterator itn;
11115           oldNodes.clear();
11116           grid->GetNodeIds(oldNodes, face.cellId, face.cellType);
11117           //MESSAGE("examine cell, downId " << face.cellId << " type " << int(face.cellType));
11118           std::map<int, int> localClonedNodeIds;
11119
11120           std::map<int, int> domvol = itface->second;
11121           std::map<int, int>::iterator itdom = domvol.begin();
11122           for (; itdom != domvol.end(); ++itdom)
11123             {
11124               int idom = itdom->first;
11125               int vtkVolId = itdom->second;
11126               //MESSAGE("modify nodes of cell " << this->GetMeshDS()->fromVtkToSmds(vtkVolId) << " domain " << idom);
11127               localClonedNodeIds.clear();
11128               for (itn = oldNodes.begin(); itn != oldNodes.end(); ++itn)
11129                 {
11130                   int oldId = *itn;
11131                   if (nodeDomains[oldId].count(idom))
11132                     {
11133                       localClonedNodeIds[oldId] = nodeDomains[oldId][idom];
11134                       //MESSAGE("     node " << oldId << " --> " << localClonedNodeIds[oldId]);
11135                     }
11136                 }
11137               meshDS->ModifyCellNodes(vtkVolId, localClonedNodeIds);
11138             }
11139         }
11140     }
11141
11142   meshDS->CleanDownWardConnectivity(); // Mesh has been modified, downward connectivity is no more usable, free memory
11143   grid->BuildLinks();
11144
11145   CHRONOSTOP(50);
11146   counters::stats();
11147   return true;
11148 }
11149
11150 /*!
11151  * \brief Double nodes on some external faces and create flat elements.
11152  * Flat elements are mainly used by some types of mechanic calculations.
11153  *
11154  * Each group of the list must be constituted of faces.
11155  * Triangles are transformed in prisms, and quadrangles in hexahedrons.
11156  * @param theElems - list of groups of faces, where a group of faces is a set of
11157  * SMDS_MeshElements sorted by Id.
11158  * @return TRUE if operation has been completed successfully, FALSE otherwise
11159  */
11160 bool SMESH_MeshEditor::CreateFlatElementsOnFacesGroups(const std::vector<TIDSortedElemSet>& theElems)
11161 {
11162   MESSAGE("-------------------------------------------------");
11163   MESSAGE("SMESH_MeshEditor::CreateFlatElementsOnFacesGroups");
11164   MESSAGE("-------------------------------------------------");
11165
11166   SMESHDS_Mesh *meshDS = this->myMesh->GetMeshDS();
11167
11168   // --- For each group of faces
11169   //     duplicate the nodes, create a flat element based on the face
11170   //     replace the nodes of the faces by their clones
11171
11172   std::map<const SMDS_MeshNode*, const SMDS_MeshNode*> clonedNodes;
11173   std::map<const SMDS_MeshNode*, const SMDS_MeshNode*> intermediateNodes;
11174   clonedNodes.clear();
11175   intermediateNodes.clear();
11176   std::map<std::string, SMESH_Group*> mapOfJunctionGroups;
11177   mapOfJunctionGroups.clear();
11178
11179   for (int idom = 0; idom < theElems.size(); idom++)
11180     {
11181       const TIDSortedElemSet& domain = theElems[idom];
11182       TIDSortedElemSet::const_iterator elemItr = domain.begin();
11183       for (; elemItr != domain.end(); ++elemItr)
11184         {
11185           SMDS_MeshElement* anElem = (SMDS_MeshElement*) *elemItr;
11186           SMDS_MeshFace* aFace = dynamic_cast<SMDS_MeshFace*> (anElem);
11187           if (!aFace)
11188             continue;
11189           // MESSAGE("aFace=" << aFace->GetID());
11190           bool isQuad = aFace->IsQuadratic();
11191           vector<const SMDS_MeshNode*> ln0, ln1, ln2, ln3, ln4;
11192
11193           // --- clone the nodes, create intermediate nodes for non medium nodes of a quad face
11194
11195           SMDS_ElemIteratorPtr nodeIt = aFace->nodesIterator();
11196           while (nodeIt->more())
11197             {
11198               const SMDS_MeshNode* node = static_cast<const SMDS_MeshNode*> (nodeIt->next());
11199               bool isMedium = isQuad && (aFace->IsMediumNode(node));
11200               if (isMedium)
11201                 ln2.push_back(node);
11202               else
11203                 ln0.push_back(node);
11204
11205               const SMDS_MeshNode* clone = 0;
11206               if (!clonedNodes.count(node))
11207                 {
11208                   clone = meshDS->AddNode(node->X(), node->Y(), node->Z());
11209                   clonedNodes[node] = clone;
11210                 }
11211               else
11212                 clone = clonedNodes[node];
11213
11214               if (isMedium)
11215                 ln3.push_back(clone);
11216               else
11217                 ln1.push_back(clone);
11218
11219               const SMDS_MeshNode* inter = 0;
11220               if (isQuad && (!isMedium))
11221                 {
11222                   if (!intermediateNodes.count(node))
11223                     {
11224                       inter = meshDS->AddNode(node->X(), node->Y(), node->Z());
11225                       intermediateNodes[node] = inter;
11226                     }
11227                   else
11228                     inter = intermediateNodes[node];
11229                   ln4.push_back(inter);
11230                 }
11231             }
11232
11233           // --- extrude the face
11234
11235           vector<const SMDS_MeshNode*> ln;
11236           SMDS_MeshVolume* vol = 0;
11237           vtkIdType aType = aFace->GetVtkType();
11238           switch (aType)
11239           {
11240             case VTK_TRIANGLE:
11241               vol = meshDS->AddVolume(ln0[2], ln0[1], ln0[0], ln1[2], ln1[1], ln1[0]);
11242               // MESSAGE("vol prism " << vol->GetID());
11243               ln.push_back(ln1[0]);
11244               ln.push_back(ln1[1]);
11245               ln.push_back(ln1[2]);
11246               break;
11247             case VTK_QUAD:
11248               vol = meshDS->AddVolume(ln0[3], ln0[2], ln0[1], ln0[0], ln1[3], ln1[2], ln1[1], ln1[0]);
11249               // MESSAGE("vol hexa " << vol->GetID());
11250               ln.push_back(ln1[0]);
11251               ln.push_back(ln1[1]);
11252               ln.push_back(ln1[2]);
11253               ln.push_back(ln1[3]);
11254               break;
11255             case VTK_QUADRATIC_TRIANGLE:
11256               vol = meshDS->AddVolume(ln1[0], ln1[1], ln1[2], ln0[0], ln0[1], ln0[2], ln3[0], ln3[1], ln3[2],
11257                                       ln2[0], ln2[1], ln2[2], ln4[0], ln4[1], ln4[2]);
11258               // MESSAGE("vol quad prism " << vol->GetID());
11259               ln.push_back(ln1[0]);
11260               ln.push_back(ln1[1]);
11261               ln.push_back(ln1[2]);
11262               ln.push_back(ln3[0]);
11263               ln.push_back(ln3[1]);
11264               ln.push_back(ln3[2]);
11265               break;
11266             case VTK_QUADRATIC_QUAD:
11267 //              vol = meshDS->AddVolume(ln0[0], ln0[1], ln0[2], ln0[3], ln1[0], ln1[1], ln1[2], ln1[3],
11268 //                                      ln2[0], ln2[1], ln2[2], ln2[3], ln3[0], ln3[1], ln3[2], ln3[3],
11269 //                                      ln4[0], ln4[1], ln4[2], ln4[3]);
11270               vol = meshDS->AddVolume(ln1[0], ln1[1], ln1[2], ln1[3], ln0[0], ln0[1], ln0[2], ln0[3],
11271                                       ln3[0], ln3[1], ln3[2], ln3[3], ln2[0], ln2[1], ln2[2], ln2[3],
11272                                       ln4[0], ln4[1], ln4[2], ln4[3]);
11273               // MESSAGE("vol quad hexa " << vol->GetID());
11274               ln.push_back(ln1[0]);
11275               ln.push_back(ln1[1]);
11276               ln.push_back(ln1[2]);
11277               ln.push_back(ln1[3]);
11278               ln.push_back(ln3[0]);
11279               ln.push_back(ln3[1]);
11280               ln.push_back(ln3[2]);
11281               ln.push_back(ln3[3]);
11282               break;
11283             case VTK_POLYGON:
11284               break;
11285             default:
11286               break;
11287           }
11288
11289           if (vol)
11290             {
11291               stringstream grpname;
11292               grpname << "jf_";
11293               grpname << idom;
11294               int idg;
11295               string namegrp = grpname.str();
11296               if (!mapOfJunctionGroups.count(namegrp))
11297                 mapOfJunctionGroups[namegrp] = this->myMesh->AddGroup(SMDSAbs_Volume, namegrp.c_str(), idg);
11298               SMESHDS_Group *sgrp = dynamic_cast<SMESHDS_Group*>(mapOfJunctionGroups[namegrp]->GetGroupDS());
11299               if (sgrp)
11300                 sgrp->Add(vol->GetID());
11301             }
11302
11303           // --- modify the face
11304
11305           aFace->ChangeNodes(&ln[0], ln.size());
11306         }
11307     }
11308   return true;
11309 }
11310
11311 //================================================================================
11312 /*!
11313  * \brief Generates skin mesh (containing 2D cells) from 3D mesh
11314  * The created 2D mesh elements based on nodes of free faces of boundary volumes
11315  * \return TRUE if operation has been completed successfully, FALSE otherwise
11316  */
11317 //================================================================================
11318
11319 bool SMESH_MeshEditor::Make2DMeshFrom3D()
11320 {
11321   // iterates on volume elements and detect all free faces on them
11322   SMESHDS_Mesh* aMesh = GetMeshDS();
11323   if (!aMesh)
11324     return false;
11325   //bool res = false;
11326   int nbFree = 0, nbExisted = 0, nbCreated = 0;
11327   SMDS_VolumeIteratorPtr vIt = aMesh->volumesIterator();
11328   while(vIt->more())
11329   {
11330     const SMDS_MeshVolume* volume = vIt->next();
11331     SMDS_VolumeTool vTool( volume, /*ignoreCentralNodes=*/false );
11332     vTool.SetExternalNormal();
11333     //const bool isPoly = volume->IsPoly();
11334     const int iQuad = volume->IsQuadratic();
11335     for ( int iface = 0, n = vTool.NbFaces(); iface < n; iface++ )
11336     {
11337       if (!vTool.IsFreeFace(iface))
11338         continue;
11339       nbFree++;
11340       vector<const SMDS_MeshNode *> nodes;
11341       int nbFaceNodes = vTool.NbFaceNodes(iface);
11342       const SMDS_MeshNode** faceNodes = vTool.GetFaceNodes(iface);
11343       int inode = 0;
11344       for ( ; inode < nbFaceNodes; inode += iQuad+1)
11345         nodes.push_back(faceNodes[inode]);
11346       if (iQuad) { // add medium nodes
11347         for ( inode = 1; inode < nbFaceNodes; inode += 2)
11348           nodes.push_back(faceNodes[inode]);
11349         if ( nbFaceNodes == 9 ) // bi-quadratic quad
11350           nodes.push_back(faceNodes[8]);
11351       }
11352       // add new face based on volume nodes
11353       if (aMesh->FindElement( nodes, SMDSAbs_Face, /*noMedium=*/false) ) {
11354         nbExisted++;
11355         continue; // face already exsist
11356       }
11357       AddElement(nodes, SMDSAbs_Face, ( !iQuad && nbFaceNodes/(iQuad+1) > 4 ));
11358       nbCreated++;
11359     }
11360   }
11361   return ( nbFree==(nbExisted+nbCreated) );
11362 }
11363
11364 namespace
11365 {
11366   inline const SMDS_MeshNode* getNodeWithSameID(SMESHDS_Mesh* mesh, const SMDS_MeshNode* node)
11367   {
11368     if ( const SMDS_MeshNode* n = mesh->FindNode( node->GetID() ))
11369       return n;
11370     return mesh->AddNodeWithID( node->X(),node->Y(),node->Z(), node->GetID() );
11371   }
11372 }
11373 //================================================================================
11374 /*!
11375  * \brief Creates missing boundary elements
11376  *  \param elements - elements whose boundary is to be checked
11377  *  \param dimension - defines type of boundary elements to create
11378  *  \param group - a group to store created boundary elements in
11379  *  \param targetMesh - a mesh to store created boundary elements in
11380  *  \param toCopyElements - if true, the checked elements will be copied into the targetMesh
11381  *  \param toCopyExistingBoundary - if true, not only new but also pre-existing
11382  *                                boundary elements will be copied into the targetMesh
11383  *  \param toAddExistingBondary - if true, not only new but also pre-existing
11384  *                                boundary elements will be added into the new group
11385  *  \param aroundElements - if true, elements will be created on boundary of given
11386  *                          elements else, on boundary of the whole mesh.
11387  * \return nb of added boundary elements
11388  */
11389 //================================================================================
11390
11391 int SMESH_MeshEditor::MakeBoundaryMesh(const TIDSortedElemSet& elements,
11392                                        Bnd_Dimension           dimension,
11393                                        SMESH_Group*            group/*=0*/,
11394                                        SMESH_Mesh*             targetMesh/*=0*/,
11395                                        bool                    toCopyElements/*=false*/,
11396                                        bool                    toCopyExistingBoundary/*=false*/,
11397                                        bool                    toAddExistingBondary/*= false*/,
11398                                        bool                    aroundElements/*= false*/)
11399 {
11400   SMDSAbs_ElementType missType = (dimension == BND_2DFROM3D) ? SMDSAbs_Face : SMDSAbs_Edge;
11401   SMDSAbs_ElementType elemType = (dimension == BND_1DFROM2D) ? SMDSAbs_Face : SMDSAbs_Volume;
11402   // hope that all elements are of the same type, do not check them all
11403   if ( !elements.empty() && (*elements.begin())->GetType() != elemType )
11404     throw SALOME_Exception(LOCALIZED("wrong element type"));
11405
11406   if ( !targetMesh )
11407     toCopyElements = toCopyExistingBoundary = false;
11408
11409   SMESH_MeshEditor tgtEditor( targetMesh ? targetMesh : myMesh );
11410   SMESHDS_Mesh* aMesh = GetMeshDS(), *tgtMeshDS = tgtEditor.GetMeshDS();
11411   int nbAddedBnd = 0;
11412
11413   // editor adding present bnd elements and optionally holding elements to add to the group
11414   SMESH_MeshEditor* presentEditor;
11415   SMESH_MeshEditor tgtEditor2( tgtEditor.GetMesh() );
11416   presentEditor = toAddExistingBondary ? &tgtEditor : &tgtEditor2;
11417
11418   SMDS_VolumeTool vTool;
11419   TIDSortedElemSet avoidSet;
11420   const TIDSortedElemSet emptySet, *elemSet = aroundElements ? &elements : &emptySet;
11421   int inode;
11422
11423   typedef vector<const SMDS_MeshNode*> TConnectivity;
11424
11425   SMDS_ElemIteratorPtr eIt;
11426   if (elements.empty())
11427     eIt = aMesh->elementsIterator(elemType);
11428   else
11429     eIt = SMDS_ElemIteratorPtr( new TSetIterator( elements.begin(), elements.end() ));
11430
11431   while (eIt->more())
11432   {
11433     const SMDS_MeshElement* elem = eIt->next();
11434     const int iQuad = elem->IsQuadratic();
11435
11436     // ------------------------------------------------------------------------------------
11437     // 1. For an elem, get present bnd elements and connectivities of missing bnd elements
11438     // ------------------------------------------------------------------------------------
11439     vector<const SMDS_MeshElement*> presentBndElems;
11440     vector<TConnectivity>           missingBndElems;
11441     TConnectivity nodes;
11442     if ( vTool.Set(elem, /*ignoreCentralNodes=*/true) ) // elem is a volume --------------
11443     {
11444       vTool.SetExternalNormal();
11445       const SMDS_MeshElement* otherVol = 0;
11446       for ( int iface = 0, n = vTool.NbFaces(); iface < n; iface++ )
11447       {
11448         if ( !vTool.IsFreeFace(iface, &otherVol) &&
11449              ( !aroundElements || elements.count( otherVol )))
11450           continue;
11451         const int nbFaceNodes = vTool.NbFaceNodes(iface);
11452         const SMDS_MeshNode** nn = vTool.GetFaceNodes(iface);
11453         if ( missType == SMDSAbs_Edge ) // boundary edges
11454         {
11455           nodes.resize( 2+iQuad );
11456           for ( int i = 0; i < nbFaceNodes; i += 1+iQuad)
11457           {
11458             for ( int j = 0; j < nodes.size(); ++j )
11459               nodes[j] =nn[i+j];
11460             if ( const SMDS_MeshElement* edge =
11461                  aMesh->FindElement(nodes,SMDSAbs_Edge,/*noMedium=*/false))
11462               presentBndElems.push_back( edge );
11463             else
11464               missingBndElems.push_back( nodes );
11465           }
11466         }
11467         else // boundary face
11468         {
11469           nodes.clear();
11470           for ( inode = 0; inode < nbFaceNodes; inode += 1+iQuad)
11471             nodes.push_back( nn[inode] );
11472           if (iQuad) // add medium nodes
11473             for ( inode = 1; inode < nbFaceNodes; inode += 2)
11474               nodes.push_back( nn[inode] );
11475           int iCenter = vTool.GetCenterNodeIndex(iface); // for HEX27
11476           if ( iCenter > 0 )
11477             nodes.push_back( vTool.GetNodes()[ iCenter ] );
11478
11479           if (const SMDS_MeshElement * f = aMesh->FindElement( nodes,
11480                                                                SMDSAbs_Face, /*noMedium=*/false ))
11481             presentBndElems.push_back( f );
11482           else
11483             missingBndElems.push_back( nodes );
11484
11485           if ( targetMesh != myMesh )
11486           {
11487             // add 1D elements on face boundary to be added to a new mesh
11488             const SMDS_MeshElement* edge;
11489             for ( inode = 0; inode < nbFaceNodes; inode += 1+iQuad)
11490             {
11491               if ( iQuad )
11492                 edge = aMesh->FindEdge( nn[inode], nn[inode+1], nn[inode+2]);
11493               else
11494                 edge = aMesh->FindEdge( nn[inode], nn[inode+1]);
11495               if ( edge && avoidSet.insert( edge ).second )
11496                 presentBndElems.push_back( edge );
11497             }
11498           }
11499         }
11500       }
11501     }
11502     else                     // elem is a face ------------------------------------------
11503     {
11504       avoidSet.clear(), avoidSet.insert( elem );
11505       int nbNodes = elem->NbCornerNodes();
11506       nodes.resize( 2 /*+ iQuad*/);
11507       for ( int i = 0; i < nbNodes; i++ )
11508       {
11509         nodes[0] = elem->GetNode(i);
11510         nodes[1] = elem->GetNode((i+1)%nbNodes);
11511         if ( FindFaceInSet( nodes[0], nodes[1], *elemSet, avoidSet))
11512           continue; // not free link
11513
11514         //if ( iQuad )
11515         //nodes[2] = elem->GetNode( i + nbNodes );
11516         if ( const SMDS_MeshElement* edge =
11517              aMesh->FindElement(nodes,SMDSAbs_Edge,/*noMedium=*/true))
11518           presentBndElems.push_back( edge );
11519         else
11520           missingBndElems.push_back( nodes );
11521       }
11522     }
11523
11524     // ---------------------------------
11525     // 2. Add missing boundary elements
11526     // ---------------------------------
11527     if ( targetMesh != myMesh )
11528       // instead of making a map of nodes in this mesh and targetMesh,
11529       // we create nodes with same IDs.
11530       for ( int i = 0; i < missingBndElems.size(); ++i )
11531       {
11532         TConnectivity& srcNodes = missingBndElems[i];
11533         TConnectivity  nodes( srcNodes.size() );
11534         for ( inode = 0; inode < nodes.size(); ++inode )
11535           nodes[inode] = getNodeWithSameID( tgtMeshDS, srcNodes[inode] );
11536         if ( aroundElements && tgtEditor.GetMeshDS()->FindElement( nodes,
11537                                                                    missType,
11538                                                                    /*noMedium=*/false))
11539           continue;
11540         tgtEditor.AddElement(nodes, missType, !iQuad && nodes.size()/(iQuad+1)>4);
11541         ++nbAddedBnd;
11542       }
11543     else
11544       for ( int i = 0; i < missingBndElems.size(); ++i )
11545       {
11546         TConnectivity& nodes = missingBndElems[i];
11547         if ( aroundElements && tgtEditor.GetMeshDS()->FindElement( nodes,
11548                                                                    missType,
11549                                                                    /*noMedium=*/false))
11550           continue;
11551         tgtEditor.AddElement(nodes, missType, !iQuad && nodes.size()/(iQuad+1)>4);
11552         ++nbAddedBnd;
11553       }
11554
11555     // ----------------------------------
11556     // 3. Copy present boundary elements
11557     // ----------------------------------
11558     if ( toCopyExistingBoundary )
11559       for ( int i = 0 ; i < presentBndElems.size(); ++i )
11560       {
11561         const SMDS_MeshElement* e = presentBndElems[i];
11562         TConnectivity nodes( e->NbNodes() );
11563         for ( inode = 0; inode < nodes.size(); ++inode )
11564           nodes[inode] = getNodeWithSameID( tgtMeshDS, e->GetNode(inode) );
11565         presentEditor->AddElement(nodes, e->GetType(), e->IsPoly());
11566       }
11567     else // store present elements to add them to a group
11568       for ( int i = 0 ; i < presentBndElems.size(); ++i )
11569       {
11570         presentEditor->myLastCreatedElems.Append(presentBndElems[i]);
11571       }
11572       
11573   } // loop on given elements
11574
11575   // ---------------------------------------------
11576   // 4. Fill group with boundary elements
11577   // ---------------------------------------------
11578   if ( group )
11579   {
11580     if ( SMESHDS_Group* g = dynamic_cast<SMESHDS_Group*>( group->GetGroupDS() ))
11581       for ( int i = 0; i < tgtEditor.myLastCreatedElems.Size(); ++i )
11582         g->SMDSGroup().Add( tgtEditor.myLastCreatedElems( i+1 ));
11583   }
11584   tgtEditor.myLastCreatedElems.Clear();
11585   tgtEditor2.myLastCreatedElems.Clear();
11586
11587   // -----------------------
11588   // 5. Copy given elements
11589   // -----------------------
11590   if ( toCopyElements && targetMesh != myMesh )
11591   {
11592     if (elements.empty())
11593       eIt = aMesh->elementsIterator(elemType);
11594     else
11595       eIt = SMDS_ElemIteratorPtr( new TSetIterator( elements.begin(), elements.end() ));
11596     while (eIt->more())
11597     {
11598       const SMDS_MeshElement* elem = eIt->next();
11599       TConnectivity nodes( elem->NbNodes() );
11600       for ( inode = 0; inode < nodes.size(); ++inode )
11601         nodes[inode] = getNodeWithSameID( tgtMeshDS, elem->GetNode(inode) );
11602       tgtEditor.AddElement(nodes, elemType, elem->IsPoly());
11603
11604       tgtEditor.myLastCreatedElems.Clear();
11605     }
11606   }
11607   return nbAddedBnd;
11608 }