Salome HOME
Update copyright
[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
23 //  SMESH SMESH : idl implementation based on 'SMESH' unit's classes
24 // File      : SMESH_MeshEditor.cxx
25 // Created   : Mon Apr 12 16:10:22 2004
26 // Author    : Edward AGAPOV (eap)
27 //
28 #define CHRONODEF
29 #include "SMESH_MeshEditor.hxx"
30
31 #include "SMDS_FaceOfNodes.hxx"
32 #include "SMDS_VolumeTool.hxx"
33 #include "SMDS_EdgePosition.hxx"
34 #include "SMDS_PolyhedralVolumeOfNodes.hxx"
35 #include "SMDS_FacePosition.hxx"
36 #include "SMDS_SpacePosition.hxx"
37 //#include "SMDS_QuadraticFaceOfNodes.hxx"
38 #include "SMDS_MeshGroup.hxx"
39 #include "SMDS_LinearEdge.hxx"
40 #include "SMDS_Downward.hxx"
41 #include "SMDS_SetIterator.hxx"
42
43 #include "SMESHDS_Group.hxx"
44 #include "SMESHDS_Mesh.hxx"
45
46 #include "SMESH_Algo.hxx"
47 #include "SMESH_ControlsDef.hxx"
48 #include "SMESH_Group.hxx"
49 #include "SMESH_MesherHelper.hxx"
50 #include "SMESH_OctreeNode.hxx"
51 #include "SMESH_subMesh.hxx"
52
53 #include "utilities.h"
54
55 #include <BRepAdaptor_Surface.hxx>
56 #include <BRepClass3d_SolidClassifier.hxx>
57 #include <BRep_Tool.hxx>
58 #include <ElCLib.hxx>
59 #include <Extrema_GenExtPS.hxx>
60 #include <Extrema_POnCurv.hxx>
61 #include <Extrema_POnSurf.hxx>
62 #include <GC_MakeSegment.hxx>
63 #include <Geom2d_Curve.hxx>
64 #include <GeomAPI_ExtremaCurveCurve.hxx>
65 #include <GeomAdaptor_Surface.hxx>
66 #include <Geom_Curve.hxx>
67 #include <Geom_Line.hxx>
68 #include <Geom_Surface.hxx>
69 #include <IntAna_IntConicQuad.hxx>
70 #include <IntAna_Quadric.hxx>
71 #include <Precision.hxx>
72 #include <TColStd_ListOfInteger.hxx>
73 #include <TopAbs_State.hxx>
74 #include <TopExp.hxx>
75 #include <TopExp_Explorer.hxx>
76 #include <TopTools_ListIteratorOfListOfShape.hxx>
77 #include <TopTools_ListOfShape.hxx>
78 #include <TopTools_SequenceOfShape.hxx>
79 #include <TopoDS.hxx>
80 #include <TopoDS_Face.hxx>
81 #include <gp.hxx>
82 #include <gp_Ax1.hxx>
83 #include <gp_Dir.hxx>
84 #include <gp_Lin.hxx>
85 #include <gp_Pln.hxx>
86 #include <gp_Trsf.hxx>
87 #include <gp_Vec.hxx>
88 #include <gp_XY.hxx>
89 #include <gp_XYZ.hxx>
90
91 #include <math.h>
92
93 #include <map>
94 #include <set>
95 #include <numeric>
96 #include <limits>
97 #include <algorithm>
98 #include <sstream>
99
100 #define cast2Node(elem) static_cast<const SMDS_MeshNode*>( elem )
101
102 using namespace std;
103 using namespace SMESH::Controls;
104
105 typedef map<const SMDS_MeshElement*, list<const SMDS_MeshNode*> >    TElemOfNodeListMap;
106 typedef map<const SMDS_MeshElement*, list<const SMDS_MeshElement*> > TElemOfElemListMap;
107
108 typedef SMDS_SetIterator< SMDS_pElement, TIDSortedElemSet::const_iterator> TSetIterator;
109
110 //=======================================================================
111 //function : SMESH_MeshEditor
112 //purpose  :
113 //=======================================================================
114
115 SMESH_MeshEditor::SMESH_MeshEditor( SMESH_Mesh* theMesh )
116   :myMesh( theMesh ) // theMesh may be NULL
117 {
118 }
119
120 //=======================================================================
121 /*!
122  * \brief Add element
123  */
124 //=======================================================================
125
126 SMDS_MeshElement*
127 SMESH_MeshEditor::AddElement(const vector<const SMDS_MeshNode*> & node,
128                              const SMDSAbs_ElementType            type,
129                              const bool                           isPoly,
130                              const int                            ID)
131 {
132   //MESSAGE("AddElement " <<node.size() << " " << type << " " << isPoly << " " << ID);
133   SMDS_MeshElement* e = 0;
134   int nbnode = node.size();
135   SMESHDS_Mesh* mesh = GetMeshDS();
136   switch ( type ) {
137   case SMDSAbs_Face:
138     if ( !isPoly ) {
139       if      (nbnode == 3) {
140         if ( ID >= 1 ) e = mesh->AddFaceWithID(node[0], node[1], node[2], ID);
141         else           e = mesh->AddFace      (node[0], node[1], node[2] );
142       }
143       else if (nbnode == 4) {
144         if ( ID >= 1 ) e = mesh->AddFaceWithID(node[0], node[1], node[2], node[3], ID);
145         else           e = mesh->AddFace      (node[0], node[1], node[2], node[3] );
146       }
147       else if (nbnode == 6) {
148         if ( ID >= 1 ) e = mesh->AddFaceWithID(node[0], node[1], node[2], node[3],
149                                                node[4], node[5], ID);
150         else           e = mesh->AddFace      (node[0], node[1], node[2], node[3],
151                                                node[4], node[5] );
152       }
153       else if (nbnode == 8) {
154         if ( ID >= 1 ) e = mesh->AddFaceWithID(node[0], node[1], node[2], node[3],
155                                                node[4], node[5], node[6], node[7], ID);
156         else           e = mesh->AddFace      (node[0], node[1], node[2], node[3],
157                                                node[4], node[5], node[6], node[7] );
158       }
159     } else {
160       if ( ID >= 1 ) e = mesh->AddPolygonalFaceWithID(node, ID);
161       else           e = mesh->AddPolygonalFace      (node    );
162     }
163     break;
164
165   case SMDSAbs_Volume:
166     if ( !isPoly ) {
167       if      (nbnode == 4) {
168         if ( ID >= 1 ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3], ID);
169         else           e = mesh->AddVolume      (node[0], node[1], node[2], node[3] );
170       }
171       else if (nbnode == 5) {
172         if ( ID >= 1 ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
173                                                  node[4], ID);
174         else           e = mesh->AddVolume      (node[0], node[1], node[2], node[3],
175                                                  node[4] );
176       }
177       else if (nbnode == 6) {
178         if ( ID >= 1 ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
179                                                  node[4], node[5], ID);
180         else           e = mesh->AddVolume      (node[0], node[1], node[2], node[3],
181                                                  node[4], node[5] );
182       }
183       else if (nbnode == 8) {
184         if ( ID >= 1 ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
185                                                  node[4], node[5], node[6], node[7], ID);
186         else           e = mesh->AddVolume      (node[0], node[1], node[2], node[3],
187                                                  node[4], node[5], node[6], node[7] );
188       }
189       else if (nbnode == 10) {
190         if ( ID >= 1 ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
191                                                  node[4], node[5], node[6], node[7],
192                                                  node[8], node[9], ID);
193         else           e = mesh->AddVolume      (node[0], node[1], node[2], node[3],
194                                                  node[4], node[5], node[6], node[7],
195                                                  node[8], node[9] );
196       }
197       else if (nbnode == 13) {
198         if ( ID >= 1 ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
199                                                  node[4], node[5], node[6], node[7],
200                                                  node[8], node[9], node[10],node[11],
201                                                  node[12],ID);
202         else           e = mesh->AddVolume      (node[0], node[1], node[2], node[3],
203                                                  node[4], node[5], node[6], node[7],
204                                                  node[8], node[9], node[10],node[11],
205                                                  node[12] );
206       }
207       else if (nbnode == 15) {
208         if ( ID >= 1 ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
209                                                  node[4], node[5], node[6], node[7],
210                                                  node[8], node[9], node[10],node[11],
211                                                  node[12],node[13],node[14],ID);
212         else           e = mesh->AddVolume      (node[0], node[1], node[2], node[3],
213                                                  node[4], node[5], node[6], node[7],
214                                                  node[8], node[9], node[10],node[11],
215                                                  node[12],node[13],node[14] );
216       }
217       else if (nbnode == 20) {
218         if ( ID >= 1 ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
219                                                  node[4], node[5], node[6], node[7],
220                                                  node[8], node[9], node[10],node[11],
221                                                  node[12],node[13],node[14],node[15],
222                                                  node[16],node[17],node[18],node[19],ID);
223         else           e = mesh->AddVolume      (node[0], node[1], node[2], node[3],
224                                                  node[4], node[5], node[6], node[7],
225                                                  node[8], node[9], node[10],node[11],
226                                                  node[12],node[13],node[14],node[15],
227                                                  node[16],node[17],node[18],node[19] );
228       }
229     }
230     break;
231
232   case SMDSAbs_Edge:
233     if ( nbnode == 2 ) {
234       if ( ID >= 1 ) e = mesh->AddEdgeWithID(node[0], node[1], ID);
235       else           e = mesh->AddEdge      (node[0], node[1] );
236     }
237     else if ( nbnode == 3 ) {
238       if ( ID >= 1 ) e = mesh->AddEdgeWithID(node[0], node[1], node[2], ID);
239       else           e = mesh->AddEdge      (node[0], node[1], node[2] );
240     }
241     break;
242
243   case SMDSAbs_0DElement:
244     if ( nbnode == 1 ) {
245       if ( ID >= 1 ) e = mesh->Add0DElementWithID(node[0], ID);
246       else           e = mesh->Add0DElement      (node[0] );
247     }
248     break;
249
250   case SMDSAbs_Node:
251     if ( ID >= 1 ) e = mesh->AddNodeWithID(node[0]->X(), node[0]->Y(), node[0]->Z(), ID);
252     else           e = mesh->AddNode      (node[0]->X(), node[0]->Y(), node[0]->Z());
253     break;
254
255   default:;
256   }
257   if ( e ) myLastCreatedElems.Append( e );
258   return e;
259 }
260
261 //=======================================================================
262 /*!
263  * \brief Add element
264  */
265 //=======================================================================
266
267 SMDS_MeshElement* SMESH_MeshEditor::AddElement(const vector<int> &       nodeIDs,
268                                                const SMDSAbs_ElementType type,
269                                                const bool                isPoly,
270                                                const int                 ID)
271 {
272   vector<const SMDS_MeshNode*> nodes;
273   nodes.reserve( nodeIDs.size() );
274   vector<int>::const_iterator id = nodeIDs.begin();
275   while ( id != nodeIDs.end() ) {
276     if ( const SMDS_MeshNode* node = GetMeshDS()->FindNode( *id++ ))
277       nodes.push_back( node );
278     else
279       return 0;
280   }
281   return AddElement( nodes, type, isPoly, ID );
282 }
283
284 //=======================================================================
285 //function : Remove
286 //purpose  : Remove a node or an element.
287 //           Modify a compute state of sub-meshes which become empty
288 //=======================================================================
289
290 int SMESH_MeshEditor::Remove (const list< int >& theIDs,
291                               const bool         isNodes )
292 {
293   myLastCreatedElems.Clear();
294   myLastCreatedNodes.Clear();
295
296   SMESHDS_Mesh* aMesh = GetMeshDS();
297   set< SMESH_subMesh *> smmap;
298
299   int removed = 0;
300   list<int>::const_iterator it = theIDs.begin();
301   for ( ; it != theIDs.end(); it++ ) {
302     const SMDS_MeshElement * elem;
303     if ( isNodes )
304       elem = aMesh->FindNode( *it );
305     else
306       elem = aMesh->FindElement( *it );
307     if ( !elem )
308       continue;
309
310     // Notify VERTEX sub-meshes about modification
311     if ( isNodes ) {
312       const SMDS_MeshNode* node = cast2Node( elem );
313       if ( node->GetPosition()->GetTypeOfPosition() == SMDS_TOP_VERTEX )
314         if ( int aShapeID = node->getshapeId() )
315           if ( SMESH_subMesh * sm = GetMesh()->GetSubMeshContaining( aShapeID ) )
316             smmap.insert( sm );
317     }
318     // Find sub-meshes to notify about modification
319     //     SMDS_ElemIteratorPtr nodeIt = elem->nodesIterator();
320     //     while ( nodeIt->more() ) {
321     //       const SMDS_MeshNode* node = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
322     //       const SMDS_PositionPtr& aPosition = node->GetPosition();
323     //       if ( aPosition.get() ) {
324     //         if ( int aShapeID = aPosition->GetShapeId() ) {
325     //           if ( SMESH_subMesh * sm = GetMesh()->GetSubMeshContaining( aShapeID ) )
326     //             smmap.insert( sm );
327     //         }
328     //       }
329     //     }
330
331     // Do remove
332     if ( isNodes )
333       aMesh->RemoveNode( static_cast< const SMDS_MeshNode* >( elem ));
334     else
335       aMesh->RemoveElement( elem );
336     removed++;
337   }
338
339   // Notify sub-meshes about modification
340   if ( !smmap.empty() ) {
341     set< SMESH_subMesh *>::iterator smIt;
342     for ( smIt = smmap.begin(); smIt != smmap.end(); smIt++ )
343       (*smIt)->ComputeStateEngine( SMESH_subMesh::MESH_ENTITY_REMOVED );
344   }
345
346   //   // Check if the whole mesh becomes empty
347   //   if ( SMESH_subMesh * sm = GetMesh()->GetSubMeshContaining( 1 ) )
348   //     sm->ComputeStateEngine( SMESH_subMesh::CHECK_COMPUTE_STATE );
349
350   return removed;
351 }
352
353 //=======================================================================
354 //function : FindShape
355 //purpose  : Return an index of the shape theElem is on
356 //           or zero if a shape not found
357 //=======================================================================
358
359 int SMESH_MeshEditor::FindShape (const SMDS_MeshElement * theElem)
360 {
361   myLastCreatedElems.Clear();
362   myLastCreatedNodes.Clear();
363
364   SMESHDS_Mesh * aMesh = GetMeshDS();
365   if ( aMesh->ShapeToMesh().IsNull() )
366     return 0;
367
368   int aShapeID = theElem->getshapeId();
369   if ( aShapeID < 1 )
370     return 0;
371
372   if ( SMESHDS_SubMesh * sm = aMesh->MeshElements( aShapeID ))
373     if ( sm->Contains( theElem ))
374       return aShapeID;
375
376   if ( theElem->GetType() == SMDSAbs_Node ) {
377     MESSAGE( ":( Error: invalid myShapeId of node " << theElem->GetID() );
378   }
379   else {
380     MESSAGE( ":( Error: invalid myShapeId of element " << theElem->GetID() );
381   }
382
383   TopoDS_Shape aShape; // the shape a node of theElem is on
384   if ( theElem->GetType() != SMDSAbs_Node )
385   {
386     SMDS_ElemIteratorPtr nodeIt = theElem->nodesIterator();
387     while ( nodeIt->more() ) {
388       const SMDS_MeshNode* node = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
389       if ((aShapeID = node->getshapeId()) > 0) {
390         if ( SMESHDS_SubMesh * sm = aMesh->MeshElements( aShapeID ) ) {
391           if ( sm->Contains( theElem ))
392             return aShapeID;
393           if ( aShape.IsNull() )
394             aShape = aMesh->IndexToShape( aShapeID );
395         }
396       }
397     }
398   }
399
400   // None of nodes is on a proper shape,
401   // find the shape among ancestors of aShape on which a node is
402   if ( !aShape.IsNull() ) {
403     TopTools_ListIteratorOfListOfShape ancIt( GetMesh()->GetAncestors( aShape ));
404     for ( ; ancIt.More(); ancIt.Next() ) {
405       SMESHDS_SubMesh * sm = aMesh->MeshElements( ancIt.Value() );
406       if ( sm && sm->Contains( theElem ))
407         return aMesh->ShapeToIndex( ancIt.Value() );
408     }
409   }
410   else
411   {
412     const map<int,SMESHDS_SubMesh*>& id2sm = GetMeshDS()->SubMeshes();
413     map<int,SMESHDS_SubMesh*>::const_iterator id_sm = id2sm.begin();
414     for ( ; id_sm != id2sm.end(); ++id_sm )
415       if ( id_sm->second->Contains( theElem ))
416         return id_sm->first;
417   }
418
419   //MESSAGE ("::FindShape() - SHAPE NOT FOUND")
420   return 0;
421 }
422
423 //=======================================================================
424 //function : IsMedium
425 //purpose  :
426 //=======================================================================
427
428 bool SMESH_MeshEditor::IsMedium(const SMDS_MeshNode*      node,
429                                 const SMDSAbs_ElementType typeToCheck)
430 {
431   bool isMedium = false;
432   SMDS_ElemIteratorPtr it = node->GetInverseElementIterator(typeToCheck);
433   while (it->more() && !isMedium ) {
434     const SMDS_MeshElement* elem = it->next();
435     isMedium = elem->IsMediumNode(node);
436   }
437   return isMedium;
438 }
439
440 //=======================================================================
441 //function : ShiftNodesQuadTria
442 //purpose  : auxilary
443 //           Shift nodes in the array corresponded to quadratic triangle
444 //           example: (0,1,2,3,4,5) -> (1,2,0,4,5,3)
445 //=======================================================================
446 static void ShiftNodesQuadTria(const SMDS_MeshNode* aNodes[])
447 {
448   const SMDS_MeshNode* nd1 = aNodes[0];
449   aNodes[0] = aNodes[1];
450   aNodes[1] = aNodes[2];
451   aNodes[2] = nd1;
452   const SMDS_MeshNode* nd2 = aNodes[3];
453   aNodes[3] = aNodes[4];
454   aNodes[4] = aNodes[5];
455   aNodes[5] = nd2;
456 }
457
458 //=======================================================================
459 //function : GetNodesFromTwoTria
460 //purpose  : auxilary
461 //           Shift nodes in the array corresponded to quadratic triangle
462 //           example: (0,1,2,3,4,5) -> (1,2,0,4,5,3)
463 //=======================================================================
464 static bool GetNodesFromTwoTria(const SMDS_MeshElement * theTria1,
465                                 const SMDS_MeshElement * theTria2,
466                                 const SMDS_MeshNode* N1[],
467                                 const SMDS_MeshNode* N2[])
468 {
469   SMDS_ElemIteratorPtr it = theTria1->nodesIterator();
470   int i=0;
471   while(i<6) {
472     N1[i] = static_cast<const SMDS_MeshNode*>( it->next() );
473     i++;
474   }
475   if(it->more()) return false;
476   it = theTria2->nodesIterator();
477   i=0;
478   while(i<6) {
479     N2[i] = static_cast<const SMDS_MeshNode*>( it->next() );
480     i++;
481   }
482   if(it->more()) return false;
483
484   int sames[3] = {-1,-1,-1};
485   int nbsames = 0;
486   int j;
487   for(i=0; i<3; i++) {
488     for(j=0; j<3; j++) {
489       if(N1[i]==N2[j]) {
490         sames[i] = j;
491         nbsames++;
492         break;
493       }
494     }
495   }
496   if(nbsames!=2) return false;
497   if(sames[0]>-1) {
498     ShiftNodesQuadTria(N1);
499     if(sames[1]>-1) {
500       ShiftNodesQuadTria(N1);
501     }
502   }
503   i = sames[0] + sames[1] + sames[2];
504   for(; i<2; i++) {
505     ShiftNodesQuadTria(N2);
506   }
507   // now we receive following N1 and N2 (using numeration as above image)
508   // tria1 : (1 2 4 5 9 7)  and  tria2 : (3 4 2 8 9 6)
509   // i.e. first nodes from both arrays determ new diagonal
510   return true;
511 }
512
513 //=======================================================================
514 //function : InverseDiag
515 //purpose  : Replace two neighbour triangles with ones built on the same 4 nodes
516 //           but having other common link.
517 //           Return False if args are improper
518 //=======================================================================
519
520 bool SMESH_MeshEditor::InverseDiag (const SMDS_MeshElement * theTria1,
521                                     const SMDS_MeshElement * theTria2 )
522 {
523   MESSAGE("InverseDiag");
524   myLastCreatedElems.Clear();
525   myLastCreatedNodes.Clear();
526
527   if (!theTria1 || !theTria2)
528     return false;
529
530   const SMDS_VtkFace* F1 = dynamic_cast<const SMDS_VtkFace*>( theTria1 );
531   if (!F1) return false;
532   const SMDS_VtkFace* F2 = dynamic_cast<const SMDS_VtkFace*>( theTria2 );
533   if (!F2) return false;
534   if ((theTria1->GetEntityType() == SMDSEntity_Triangle) &&
535       (theTria2->GetEntityType() == SMDSEntity_Triangle)) {
536
537     //  1 +--+ A  theTria1: ( 1 A B ) A->2 ( 1 2 B ) 1 +--+ A
538     //    | /|    theTria2: ( B A 2 ) B->1 ( 1 A 2 )   |\ |
539     //    |/ |                                         | \|
540     //  B +--+ 2                                     B +--+ 2
541
542     // put nodes in array and find out indices of the same ones
543     const SMDS_MeshNode* aNodes [6];
544     int sameInd [] = { 0, 0, 0, 0, 0, 0 };
545     int i = 0;
546     SMDS_ElemIteratorPtr it = theTria1->nodesIterator();
547     while ( it->more() ) {
548       aNodes[ i ] = static_cast<const SMDS_MeshNode*>( it->next() );
549
550       if ( i > 2 ) // theTria2
551         // find same node of theTria1
552         for ( int j = 0; j < 3; j++ )
553           if ( aNodes[ i ] == aNodes[ j ]) {
554             sameInd[ j ] = i;
555             sameInd[ i ] = j;
556             break;
557           }
558       // next
559       i++;
560       if ( i == 3 ) {
561         if ( it->more() )
562           return false; // theTria1 is not a triangle
563         it = theTria2->nodesIterator();
564       }
565       if ( i == 6 && it->more() )
566         return false; // theTria2 is not a triangle
567     }
568
569     // find indices of 1,2 and of A,B in theTria1
570     int iA = 0, iB = 0, i1 = 0, i2 = 0;
571     for ( i = 0; i < 6; i++ ) {
572       if ( sameInd [ i ] == 0 ) {
573         if ( i < 3 ) i1 = i;
574         else         i2 = i;
575       }
576       else if (i < 3) {
577         if ( iA ) iB = i;
578         else      iA = i;
579       }
580     }
581     // nodes 1 and 2 should not be the same
582     if ( aNodes[ i1 ] == aNodes[ i2 ] )
583       return false;
584
585     // theTria1: A->2
586     aNodes[ iA ] = aNodes[ i2 ];
587     // theTria2: B->1
588     aNodes[ sameInd[ iB ]] = aNodes[ i1 ];
589
590     GetMeshDS()->ChangeElementNodes( theTria1, aNodes, 3 );
591     GetMeshDS()->ChangeElementNodes( theTria2, &aNodes[ 3 ], 3 );
592
593     return true;
594
595   } // end if(F1 && F2)
596
597   // check case of quadratic faces
598   if (theTria1->GetEntityType() != SMDSEntity_Quad_Triangle)
599     return false;
600   if (theTria2->GetEntityType() != SMDSEntity_Quad_Triangle)
601     return false;
602
603   //       5
604   //  1 +--+--+ 2  theTria1: (1 2 4 5 9 7) or (2 4 1 9 7 5) or (4 1 2 7 5 9)
605   //    |    /|    theTria2: (2 3 4 6 8 9) or (3 4 2 8 9 6) or (4 2 3 9 6 8)
606   //    |   / |
607   //  7 +  +  + 6
608   //    | /9  |
609   //    |/    |
610   //  4 +--+--+ 3
611   //       8
612
613   const SMDS_MeshNode* N1 [6];
614   const SMDS_MeshNode* N2 [6];
615   if(!GetNodesFromTwoTria(theTria1,theTria2,N1,N2))
616     return false;
617   // now we receive following N1 and N2 (using numeration as above image)
618   // tria1 : (1 2 4 5 9 7)  and  tria2 : (3 4 2 8 9 6)
619   // i.e. first nodes from both arrays determ new diagonal
620
621   const SMDS_MeshNode* N1new [6];
622   const SMDS_MeshNode* N2new [6];
623   N1new[0] = N1[0];
624   N1new[1] = N2[0];
625   N1new[2] = N2[1];
626   N1new[3] = N1[4];
627   N1new[4] = N2[3];
628   N1new[5] = N1[5];
629   N2new[0] = N1[0];
630   N2new[1] = N1[1];
631   N2new[2] = N2[0];
632   N2new[3] = N1[3];
633   N2new[4] = N2[5];
634   N2new[5] = N1[4];
635   // replaces nodes in faces
636   GetMeshDS()->ChangeElementNodes( theTria1, N1new, 6 );
637   GetMeshDS()->ChangeElementNodes( theTria2, N2new, 6 );
638
639   return true;
640 }
641
642 //=======================================================================
643 //function : findTriangles
644 //purpose  : find triangles sharing theNode1-theNode2 link
645 //=======================================================================
646
647 static bool findTriangles(const SMDS_MeshNode *    theNode1,
648                           const SMDS_MeshNode *    theNode2,
649                           const SMDS_MeshElement*& theTria1,
650                           const SMDS_MeshElement*& theTria2)
651 {
652   if ( !theNode1 || !theNode2 ) return false;
653
654   theTria1 = theTria2 = 0;
655
656   set< const SMDS_MeshElement* > emap;
657   SMDS_ElemIteratorPtr it = theNode1->GetInverseElementIterator(SMDSAbs_Face);
658   while (it->more()) {
659     const SMDS_MeshElement* elem = it->next();
660     if ( elem->NbNodes() == 3 )
661       emap.insert( elem );
662   }
663   it = theNode2->GetInverseElementIterator(SMDSAbs_Face);
664   while (it->more()) {
665     const SMDS_MeshElement* elem = it->next();
666     if ( emap.find( elem ) != emap.end() ) {
667       if ( theTria1 ) {
668         // theTria1 must be element with minimum ID
669         if( theTria1->GetID() < elem->GetID() ) {
670           theTria2 = elem;
671         }
672         else {
673           theTria2 = theTria1;
674           theTria1 = elem;
675         }
676         break;
677       }
678       else {
679         theTria1 = elem;
680       }
681     }
682   }
683   return ( theTria1 && theTria2 );
684 }
685
686 //=======================================================================
687 //function : InverseDiag
688 //purpose  : Replace two neighbour triangles sharing theNode1-theNode2 link
689 //           with ones built on the same 4 nodes but having other common link.
690 //           Return false if proper faces not found
691 //=======================================================================
692
693 bool SMESH_MeshEditor::InverseDiag (const SMDS_MeshNode * theNode1,
694                                     const SMDS_MeshNode * theNode2)
695 {
696   myLastCreatedElems.Clear();
697   myLastCreatedNodes.Clear();
698
699   MESSAGE( "::InverseDiag()" );
700
701   const SMDS_MeshElement *tr1, *tr2;
702   if ( !findTriangles( theNode1, theNode2, tr1, tr2 ))
703     return false;
704
705   const SMDS_VtkFace* F1 = dynamic_cast<const SMDS_VtkFace*>( tr1 );
706   if (!F1) return false;
707   const SMDS_VtkFace* F2 = dynamic_cast<const SMDS_VtkFace*>( tr2 );
708   if (!F2) return false;
709   if ((tr1->GetEntityType() == SMDSEntity_Triangle) &&
710       (tr2->GetEntityType() == SMDSEntity_Triangle)) {
711
712     //  1 +--+ A  tr1: ( 1 A B ) A->2 ( 1 2 B ) 1 +--+ A
713     //    | /|    tr2: ( B A 2 ) B->1 ( 1 A 2 )   |\ |
714     //    |/ |                                    | \|
715     //  B +--+ 2                                B +--+ 2
716
717     // put nodes in array
718     // and find indices of 1,2 and of A in tr1 and of B in tr2
719     int i, iA1 = 0, i1 = 0;
720     const SMDS_MeshNode* aNodes1 [3];
721     SMDS_ElemIteratorPtr it;
722     for (i = 0, it = tr1->nodesIterator(); it->more(); i++ ) {
723       aNodes1[ i ] = static_cast<const SMDS_MeshNode*>( it->next() );
724       if ( aNodes1[ i ] == theNode1 )
725         iA1 = i; // node A in tr1
726       else if ( aNodes1[ i ] != theNode2 )
727         i1 = i;  // node 1
728     }
729     int iB2 = 0, i2 = 0;
730     const SMDS_MeshNode* aNodes2 [3];
731     for (i = 0, it = tr2->nodesIterator(); it->more(); i++ ) {
732       aNodes2[ i ] = static_cast<const SMDS_MeshNode*>( it->next() );
733       if ( aNodes2[ i ] == theNode2 )
734         iB2 = i; // node B in tr2
735       else if ( aNodes2[ i ] != theNode1 )
736         i2 = i;  // node 2
737     }
738
739     // nodes 1 and 2 should not be the same
740     if ( aNodes1[ i1 ] == aNodes2[ i2 ] )
741       return false;
742
743     // tr1: A->2
744     aNodes1[ iA1 ] = aNodes2[ i2 ];
745     // tr2: B->1
746     aNodes2[ iB2 ] = aNodes1[ i1 ];
747
748     GetMeshDS()->ChangeElementNodes( tr1, aNodes1, 3 );
749     GetMeshDS()->ChangeElementNodes( tr2, aNodes2, 3 );
750
751     return true;
752   }
753
754   // check case of quadratic faces
755   return InverseDiag(tr1,tr2);
756 }
757
758 //=======================================================================
759 //function : getQuadrangleNodes
760 //purpose  : fill theQuadNodes - nodes of a quadrangle resulting from
761 //           fusion of triangles tr1 and tr2 having shared link on
762 //           theNode1 and theNode2
763 //=======================================================================
764
765 bool getQuadrangleNodes(const SMDS_MeshNode *    theQuadNodes [],
766                         const SMDS_MeshNode *    theNode1,
767                         const SMDS_MeshNode *    theNode2,
768                         const SMDS_MeshElement * tr1,
769                         const SMDS_MeshElement * tr2 )
770 {
771   if( tr1->NbNodes() != tr2->NbNodes() )
772     return false;
773   // find the 4-th node to insert into tr1
774   const SMDS_MeshNode* n4 = 0;
775   SMDS_ElemIteratorPtr it = tr2->nodesIterator();
776   int i=0;
777   while ( !n4 && i<3 ) {
778     const SMDS_MeshNode * n = cast2Node( it->next() );
779     i++;
780     bool isDiag = ( n == theNode1 || n == theNode2 );
781     if ( !isDiag )
782       n4 = n;
783   }
784   // Make an array of nodes to be in a quadrangle
785   int iNode = 0, iFirstDiag = -1;
786   it = tr1->nodesIterator();
787   i=0;
788   while ( i<3 ) {
789     const SMDS_MeshNode * n = cast2Node( it->next() );
790     i++;
791     bool isDiag = ( n == theNode1 || n == theNode2 );
792     if ( isDiag ) {
793       if ( iFirstDiag < 0 )
794         iFirstDiag = iNode;
795       else if ( iNode - iFirstDiag == 1 )
796         theQuadNodes[ iNode++ ] = n4; // insert the 4-th node between diagonal nodes
797     }
798     else if ( n == n4 ) {
799       return false; // tr1 and tr2 should not have all the same nodes
800     }
801     theQuadNodes[ iNode++ ] = n;
802   }
803   if ( iNode == 3 ) // diagonal nodes have 0 and 2 indices
804     theQuadNodes[ iNode ] = n4;
805
806   return true;
807 }
808
809 //=======================================================================
810 //function : DeleteDiag
811 //purpose  : Replace two neighbour triangles sharing theNode1-theNode2 link
812 //           with a quadrangle built on the same 4 nodes.
813 //           Return false if proper faces not found
814 //=======================================================================
815
816 bool SMESH_MeshEditor::DeleteDiag (const SMDS_MeshNode * theNode1,
817                                    const SMDS_MeshNode * theNode2)
818 {
819   myLastCreatedElems.Clear();
820   myLastCreatedNodes.Clear();
821
822   MESSAGE( "::DeleteDiag()" );
823
824   const SMDS_MeshElement *tr1, *tr2;
825   if ( !findTriangles( theNode1, theNode2, tr1, tr2 ))
826     return false;
827
828   const SMDS_VtkFace* F1 = dynamic_cast<const SMDS_VtkFace*>( tr1 );
829   if (!F1) return false;
830   const SMDS_VtkFace* F2 = dynamic_cast<const SMDS_VtkFace*>( tr2 );
831   if (!F2) return false;
832   SMESHDS_Mesh * aMesh = GetMeshDS();
833
834   if ((tr1->GetEntityType() == SMDSEntity_Triangle) &&
835       (tr2->GetEntityType() == SMDSEntity_Triangle)) {
836
837     const SMDS_MeshNode* aNodes [ 4 ];
838     if ( ! getQuadrangleNodes( aNodes, theNode1, theNode2, tr1, tr2 ))
839       return false;
840
841     const SMDS_MeshElement* newElem = 0;
842     newElem = aMesh->AddFace( aNodes[0], aNodes[1], aNodes[2], aNodes[3] );
843     myLastCreatedElems.Append(newElem);
844     AddToSameGroups( newElem, tr1, aMesh );
845     int aShapeId = tr1->getshapeId();
846     if ( aShapeId )
847       {
848         aMesh->SetMeshElementOnShape( newElem, aShapeId );
849       }
850     aMesh->RemoveElement( tr1 );
851     aMesh->RemoveElement( tr2 );
852
853     return true;
854   }
855
856   // check case of quadratic faces
857   if (tr1->GetEntityType() != SMDSEntity_Quad_Triangle)
858     return false;
859   if (tr2->GetEntityType() != SMDSEntity_Quad_Triangle)
860     return false;
861
862   //       5
863   //  1 +--+--+ 2  tr1: (1 2 4 5 9 7) or (2 4 1 9 7 5) or (4 1 2 7 5 9)
864   //    |    /|    tr2: (2 3 4 6 8 9) or (3 4 2 8 9 6) or (4 2 3 9 6 8)
865   //    |   / |
866   //  7 +  +  + 6
867   //    | /9  |
868   //    |/    |
869   //  4 +--+--+ 3
870   //       8
871
872   const SMDS_MeshNode* N1 [6];
873   const SMDS_MeshNode* N2 [6];
874   if(!GetNodesFromTwoTria(tr1,tr2,N1,N2))
875     return false;
876   // now we receive following N1 and N2 (using numeration as above image)
877   // tria1 : (1 2 4 5 9 7)  and  tria2 : (3 4 2 8 9 6)
878   // i.e. first nodes from both arrays determ new diagonal
879
880   const SMDS_MeshNode* aNodes[8];
881   aNodes[0] = N1[0];
882   aNodes[1] = N1[1];
883   aNodes[2] = N2[0];
884   aNodes[3] = N2[1];
885   aNodes[4] = N1[3];
886   aNodes[5] = N2[5];
887   aNodes[6] = N2[3];
888   aNodes[7] = N1[5];
889
890   const SMDS_MeshElement* newElem = 0;
891   newElem = aMesh->AddFace( aNodes[0], aNodes[1], aNodes[2], aNodes[3],
892                             aNodes[4], aNodes[5], aNodes[6], aNodes[7]);
893   myLastCreatedElems.Append(newElem);
894   AddToSameGroups( newElem, tr1, aMesh );
895   int aShapeId = tr1->getshapeId();
896   if ( aShapeId )
897     {
898       aMesh->SetMeshElementOnShape( newElem, aShapeId );
899     }
900   aMesh->RemoveElement( tr1 );
901   aMesh->RemoveElement( tr2 );
902
903   // remove middle node (9)
904   GetMeshDS()->RemoveNode( N1[4] );
905
906   return true;
907 }
908
909 //=======================================================================
910 //function : Reorient
911 //purpose  : Reverse theElement orientation
912 //=======================================================================
913
914 bool SMESH_MeshEditor::Reorient (const SMDS_MeshElement * theElem)
915 {
916   MESSAGE("Reorient");
917   myLastCreatedElems.Clear();
918   myLastCreatedNodes.Clear();
919
920   if (!theElem)
921     return false;
922   SMDS_ElemIteratorPtr it = theElem->nodesIterator();
923   if ( !it || !it->more() )
924     return false;
925
926   switch ( theElem->GetType() ) {
927
928   case SMDSAbs_Edge:
929   case SMDSAbs_Face: {
930     if(!theElem->IsQuadratic()) {
931       int i = theElem->NbNodes();
932       vector<const SMDS_MeshNode*> aNodes( i );
933       while ( it->more() )
934         aNodes[ --i ]= static_cast<const SMDS_MeshNode*>( it->next() );
935       return GetMeshDS()->ChangeElementNodes( theElem, &aNodes[0], theElem->NbNodes() );
936     }
937     else {
938       // quadratic elements
939       if(theElem->GetType()==SMDSAbs_Edge) {
940         vector<const SMDS_MeshNode*> aNodes(3);
941         aNodes[1]= static_cast<const SMDS_MeshNode*>( it->next() );
942         aNodes[0]= static_cast<const SMDS_MeshNode*>( it->next() );
943         aNodes[2]= static_cast<const SMDS_MeshNode*>( it->next() );
944         return GetMeshDS()->ChangeElementNodes( theElem, &aNodes[0], 3 );
945       }
946       else {
947         int nbn = theElem->NbNodes();
948         vector<const SMDS_MeshNode*> aNodes(nbn);
949         aNodes[0]= static_cast<const SMDS_MeshNode*>( it->next() );
950         int i=1;
951         for(; i<nbn/2; i++) {
952           aNodes[nbn/2-i]= static_cast<const SMDS_MeshNode*>( it->next() );
953         }
954         for(i=0; i<nbn/2; i++) {
955           aNodes[nbn-i-1]= static_cast<const SMDS_MeshNode*>( it->next() );
956         }
957         return GetMeshDS()->ChangeElementNodes( theElem, &aNodes[0], nbn );
958       }
959     }
960   }
961   case SMDSAbs_Volume: {
962     if (theElem->IsPoly()) {
963       // TODO reorient vtk polyhedron
964       MESSAGE("reorient vtk polyhedron ?");
965       const SMDS_VtkVolume* aPolyedre =
966         dynamic_cast<const SMDS_VtkVolume*>( theElem );
967       if (!aPolyedre) {
968         MESSAGE("Warning: bad volumic element");
969         return false;
970       }
971
972       int nbFaces = aPolyedre->NbFaces();
973       vector<const SMDS_MeshNode *> poly_nodes;
974       vector<int> quantities (nbFaces);
975
976       // reverse each face of the polyedre
977       for (int iface = 1; iface <= nbFaces; iface++) {
978         int inode, nbFaceNodes = aPolyedre->NbFaceNodes(iface);
979         quantities[iface - 1] = nbFaceNodes;
980
981         for (inode = nbFaceNodes; inode >= 1; inode--) {
982           const SMDS_MeshNode* curNode = aPolyedre->GetFaceNode(iface, inode);
983           poly_nodes.push_back(curNode);
984         }
985       }
986
987       return GetMeshDS()->ChangePolyhedronNodes( theElem, poly_nodes, quantities );
988
989     }
990     else {
991       SMDS_VolumeTool vTool;
992       if ( !vTool.Set( theElem ))
993         return false;
994       vTool.Inverse();
995       MESSAGE("ChangeElementNodes reorient: check vTool.Inverse");
996       return GetMeshDS()->ChangeElementNodes( theElem, vTool.GetNodes(), vTool.NbNodes() );
997     }
998   }
999   default:;
1000   }
1001
1002   return false;
1003 }
1004
1005 //=======================================================================
1006 //function : getBadRate
1007 //purpose  :
1008 //=======================================================================
1009
1010 static double getBadRate (const SMDS_MeshElement*               theElem,
1011                           SMESH::Controls::NumericalFunctorPtr& theCrit)
1012 {
1013   SMESH::Controls::TSequenceOfXYZ P;
1014   if ( !theElem || !theCrit->GetPoints( theElem, P ))
1015     return 1e100;
1016   return theCrit->GetBadRate( theCrit->GetValue( P ), theElem->NbNodes() );
1017   //return theCrit->GetBadRate( theCrit->GetValue( theElem->GetID() ), theElem->NbNodes() );
1018 }
1019
1020 //=======================================================================
1021 //function : QuadToTri
1022 //purpose  : Cut quadrangles into triangles.
1023 //           theCrit is used to select a diagonal to cut
1024 //=======================================================================
1025
1026 bool SMESH_MeshEditor::QuadToTri (TIDSortedElemSet &                   theElems,
1027                                   SMESH::Controls::NumericalFunctorPtr theCrit)
1028 {
1029   myLastCreatedElems.Clear();
1030   myLastCreatedNodes.Clear();
1031
1032   MESSAGE( "::QuadToTri()" );
1033
1034   if ( !theCrit.get() )
1035     return false;
1036
1037   SMESHDS_Mesh * aMesh = GetMeshDS();
1038
1039   Handle(Geom_Surface) surface;
1040   SMESH_MesherHelper   helper( *GetMesh() );
1041
1042   TIDSortedElemSet::iterator itElem;
1043   for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
1044     const SMDS_MeshElement* elem = *itElem;
1045     if ( !elem || elem->GetType() != SMDSAbs_Face )
1046       continue;
1047     if ( elem->NbNodes() != ( elem->IsQuadratic() ? 8 : 4 ))
1048       continue;
1049
1050     // retrieve element nodes
1051     const SMDS_MeshNode* aNodes [8];
1052     SMDS_ElemIteratorPtr itN = elem->nodesIterator();
1053     int i = 0;
1054     while ( itN->more() )
1055       aNodes[ i++ ] = static_cast<const SMDS_MeshNode*>( itN->next() );
1056
1057     // compare two sets of possible triangles
1058     double aBadRate1, aBadRate2; // to what extent a set is bad
1059     SMDS_FaceOfNodes tr1 ( aNodes[0], aNodes[1], aNodes[2] );
1060     SMDS_FaceOfNodes tr2 ( aNodes[2], aNodes[3], aNodes[0] );
1061     aBadRate1 = getBadRate( &tr1, theCrit ) + getBadRate( &tr2, theCrit );
1062
1063     SMDS_FaceOfNodes tr3 ( aNodes[1], aNodes[2], aNodes[3] );
1064     SMDS_FaceOfNodes tr4 ( aNodes[3], aNodes[0], aNodes[1] );
1065     aBadRate2 = getBadRate( &tr3, theCrit ) + getBadRate( &tr4, theCrit );
1066
1067     int aShapeId = FindShape( elem );
1068     const SMDS_MeshElement* newElem1 = 0;
1069     const SMDS_MeshElement* newElem2 = 0;
1070
1071     if( !elem->IsQuadratic() ) {
1072
1073       // split liner quadrangle
1074       if ( aBadRate1 <= aBadRate2 ) {
1075         // tr1 + tr2 is better
1076         newElem1 = aMesh->AddFace( aNodes[2], aNodes[3], aNodes[0] );
1077         newElem2 = aMesh->AddFace( aNodes[2], aNodes[0], aNodes[1] );
1078       }
1079       else {
1080         // tr3 + tr4 is better
1081         newElem1 = aMesh->AddFace( aNodes[3], aNodes[0], aNodes[1] );
1082         newElem2 = aMesh->AddFace( aNodes[3], aNodes[1], aNodes[2] );
1083       }
1084     }
1085     else {
1086
1087       // split quadratic quadrangle
1088
1089       // get surface elem is on
1090       if ( aShapeId != helper.GetSubShapeID() ) {
1091         surface.Nullify();
1092         TopoDS_Shape shape;
1093         if ( aShapeId > 0 )
1094           shape = aMesh->IndexToShape( aShapeId );
1095         if ( !shape.IsNull() && shape.ShapeType() == TopAbs_FACE ) {
1096           TopoDS_Face face = TopoDS::Face( shape );
1097           surface = BRep_Tool::Surface( face );
1098           if ( !surface.IsNull() )
1099             helper.SetSubShape( shape );
1100         }
1101       }
1102       // get elem nodes
1103       const SMDS_MeshNode* aNodes [8];
1104       const SMDS_MeshNode* inFaceNode = 0;
1105       SMDS_ElemIteratorPtr itN = elem->nodesIterator();
1106       int i = 0;
1107       while ( itN->more() ) {
1108         aNodes[ i++ ] = static_cast<const SMDS_MeshNode*>( itN->next() );
1109         if ( !inFaceNode && helper.GetNodeUVneedInFaceNode() &&
1110              aNodes[ i-1 ]->GetPosition()->GetTypeOfPosition() == SMDS_TOP_FACE )
1111         {
1112           inFaceNode = aNodes[ i-1 ];
1113         }
1114       }
1115       // find middle point for (0,1,2,3)
1116       // and create a node in this point;
1117       gp_XYZ p( 0,0,0 );
1118       if ( surface.IsNull() ) {
1119         for(i=0; i<4; i++)
1120           p += gp_XYZ(aNodes[i]->X(), aNodes[i]->Y(), aNodes[i]->Z() );
1121         p /= 4;
1122       }
1123       else {
1124         TopoDS_Face face = TopoDS::Face( helper.GetSubShape() );
1125         gp_XY uv( 0,0 );
1126         for(i=0; i<4; i++)
1127           uv += helper.GetNodeUV( face, aNodes[i], inFaceNode );
1128         uv /= 4.;
1129         p = surface->Value( uv.X(), uv.Y() ).XYZ();
1130       }
1131       const SMDS_MeshNode* newN = aMesh->AddNode( p.X(), p.Y(), p.Z() );
1132       myLastCreatedNodes.Append(newN);
1133
1134       // create a new element
1135       if ( aBadRate1 <= aBadRate2 ) {
1136         newElem1 = aMesh->AddFace(aNodes[2], aNodes[3], aNodes[0],
1137                                   aNodes[6], aNodes[7], newN );
1138         newElem2 = aMesh->AddFace(aNodes[2], aNodes[0], aNodes[1],
1139                                   newN,      aNodes[4], aNodes[5] );
1140       }
1141       else {
1142         newElem1 = aMesh->AddFace(aNodes[3], aNodes[0], aNodes[1],
1143                                   aNodes[7], aNodes[4], newN );
1144         newElem2 = aMesh->AddFace(aNodes[3], aNodes[1], aNodes[2],
1145                                   newN,      aNodes[5], aNodes[6] );
1146       }
1147     } // quadratic case
1148
1149     // care of a new element
1150
1151     myLastCreatedElems.Append(newElem1);
1152     myLastCreatedElems.Append(newElem2);
1153     AddToSameGroups( newElem1, elem, aMesh );
1154     AddToSameGroups( newElem2, elem, aMesh );
1155
1156     // put a new triangle on the same shape
1157     if ( aShapeId )
1158       {
1159         aMesh->SetMeshElementOnShape( newElem1, aShapeId );
1160         aMesh->SetMeshElementOnShape( newElem2, aShapeId );
1161       }
1162     aMesh->RemoveElement( elem );
1163   }
1164   return true;
1165 }
1166
1167 //=======================================================================
1168 //function : BestSplit
1169 //purpose  : Find better diagonal for cutting.
1170 //=======================================================================
1171
1172 int SMESH_MeshEditor::BestSplit (const SMDS_MeshElement*              theQuad,
1173                                  SMESH::Controls::NumericalFunctorPtr theCrit)
1174 {
1175   myLastCreatedElems.Clear();
1176   myLastCreatedNodes.Clear();
1177
1178   if (!theCrit.get())
1179     return -1;
1180
1181   if (!theQuad || theQuad->GetType() != SMDSAbs_Face )
1182     return -1;
1183
1184   if( theQuad->NbNodes()==4 ||
1185       (theQuad->NbNodes()==8 && theQuad->IsQuadratic()) ) {
1186
1187     // retrieve element nodes
1188     const SMDS_MeshNode* aNodes [4];
1189     SMDS_ElemIteratorPtr itN = theQuad->nodesIterator();
1190     int i = 0;
1191     //while (itN->more())
1192     while (i<4) {
1193       aNodes[ i++ ] = static_cast<const SMDS_MeshNode*>( itN->next() );
1194     }
1195     // compare two sets of possible triangles
1196     double aBadRate1, aBadRate2; // to what extent a set is bad
1197     SMDS_FaceOfNodes tr1 ( aNodes[0], aNodes[1], aNodes[2] );
1198     SMDS_FaceOfNodes tr2 ( aNodes[2], aNodes[3], aNodes[0] );
1199     aBadRate1 = getBadRate( &tr1, theCrit ) + getBadRate( &tr2, theCrit );
1200
1201     SMDS_FaceOfNodes tr3 ( aNodes[1], aNodes[2], aNodes[3] );
1202     SMDS_FaceOfNodes tr4 ( aNodes[3], aNodes[0], aNodes[1] );
1203     aBadRate2 = getBadRate( &tr3, theCrit ) + getBadRate( &tr4, theCrit );
1204
1205     if (aBadRate1 <= aBadRate2) // tr1 + tr2 is better
1206       return 1; // diagonal 1-3
1207
1208     return 2; // diagonal 2-4
1209   }
1210   return -1;
1211 }
1212
1213 namespace
1214 {
1215   // Methods of splitting volumes into tetra
1216
1217   const int theHexTo5_1[5*4+1] =
1218     {
1219       0, 1, 2, 5,    0, 4, 5, 7,     0, 2, 3, 7,    2, 5, 6, 7,     0, 5, 2, 7,   -1
1220     };
1221   const int theHexTo5_2[5*4+1] =
1222     {
1223       1, 2, 3, 6,    1, 4, 5, 6,     0, 1, 3, 4,    3, 4, 6, 7,     1, 3, 4, 6,   -1
1224     };
1225   const int* theHexTo5[2] = { theHexTo5_1, theHexTo5_2 };
1226
1227   const int theHexTo6_1[6*4+1] =
1228     {
1229       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
1230     };
1231   const int theHexTo6_2[6*4+1] =
1232     {
1233       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
1234     };
1235   const int theHexTo6_3[6*4+1] =
1236     {
1237       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
1238     };
1239   const int theHexTo6_4[6*4+1] =
1240     {
1241       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
1242     };
1243   const int* theHexTo6[4] = { theHexTo6_1, theHexTo6_2, theHexTo6_3, theHexTo6_4 };
1244
1245   const int thePyraTo2_1[2*4+1] =
1246     {
1247       0, 1, 2, 4,    0, 2, 3, 4,   -1
1248     };
1249   const int thePyraTo2_2[2*4+1] =
1250     {
1251       1, 2, 3, 4,    1, 3, 0, 4,   -1
1252     };
1253   const int* thePyraTo2[2] = { thePyraTo2_1, thePyraTo2_2 };
1254
1255   const int thePentaTo3_1[3*4+1] =
1256     {
1257       0, 1, 2, 3,    1, 3, 4, 2,     2, 3, 4, 5,    -1
1258     };
1259   const int thePentaTo3_2[3*4+1] =
1260     {
1261       1, 2, 0, 4,    2, 4, 5, 0,     0, 4, 5, 3,    -1
1262     };
1263   const int thePentaTo3_3[3*4+1] =
1264     {
1265       2, 0, 1, 5,    0, 5, 3, 1,     1, 5, 3, 4,    -1
1266     };
1267   const int thePentaTo3_4[3*4+1] =
1268     {
1269       0, 1, 2, 3,    1, 3, 4, 5,     2, 3, 1, 5,    -1
1270     };
1271   const int thePentaTo3_5[3*4+1] =
1272     {
1273       1, 2, 0, 4,    2, 4, 5, 3,     0, 4, 2, 3,    -1
1274     };
1275   const int thePentaTo3_6[3*4+1] =
1276     {
1277       2, 0, 1, 5,    0, 5, 3, 4,     1, 5, 0, 4,    -1
1278     };
1279   const int* thePentaTo3[6] = { thePentaTo3_1, thePentaTo3_2, thePentaTo3_3,
1280                                 thePentaTo3_4, thePentaTo3_5, thePentaTo3_6 };
1281
1282   struct TTriangleFacet //!< stores indices of three nodes of tetra facet
1283   {
1284     int _n1, _n2, _n3;
1285     TTriangleFacet(int n1, int n2, int n3): _n1(n1), _n2(n2), _n3(n3) {}
1286     bool contains(int n) const { return ( n == _n1 || n == _n2 || n == _n3 ); }
1287     bool hasAdjacentTetra( const SMDS_MeshElement* elem ) const;
1288   };
1289   struct TSplitMethod
1290   {
1291     int        _nbTetra;
1292     const int* _connectivity; //!< foursomes of tetra connectivy finished by -1
1293     bool       _baryNode;     //!< additional node is to be created at cell barycenter
1294     bool       _ownConn;      //!< to delete _connectivity in destructor
1295     map<int, const SMDS_MeshNode*> _faceBaryNode; //!< map face index to node at BC of face
1296
1297     TSplitMethod( int nbTet=0, const int* conn=0, bool addNode=false)
1298       : _nbTetra(nbTet), _connectivity(conn), _baryNode(addNode), _ownConn(false) {}
1299     ~TSplitMethod() { if ( _ownConn ) delete [] _connectivity; _connectivity = 0; }
1300     bool hasFacet( const TTriangleFacet& facet ) const
1301     {
1302       const int* tetConn = _connectivity;
1303       for ( ; tetConn[0] >= 0; tetConn += 4 )
1304         if (( facet.contains( tetConn[0] ) +
1305               facet.contains( tetConn[1] ) +
1306               facet.contains( tetConn[2] ) +
1307               facet.contains( tetConn[3] )) == 3 )
1308           return true;
1309       return false;
1310     }
1311   };
1312
1313   //=======================================================================
1314   /*!
1315    * \brief return TSplitMethod for the given element
1316    */
1317   //=======================================================================
1318
1319   TSplitMethod getSplitMethod( SMDS_VolumeTool& vol, const int theMethodFlags)
1320   {
1321     const int iQ = vol.Element()->IsQuadratic() ? 2 : 1;
1322
1323     // at HEXA_TO_24 method, each face of volume is split into triangles each based on
1324     // an edge and a face barycenter; tertaherdons are based on triangles and
1325     // a volume barycenter
1326     const bool is24TetMode = ( theMethodFlags == SMESH_MeshEditor::HEXA_TO_24 );
1327
1328     // Find out how adjacent volumes are split
1329
1330     vector < list< TTriangleFacet > > triaSplitsByFace( vol.NbFaces() ); // splits of each side
1331     int hasAdjacentSplits = 0, maxTetConnSize = 0;
1332     for ( int iF = 0; iF < vol.NbFaces(); ++iF )
1333     {
1334       int nbNodes = vol.NbFaceNodes( iF ) / iQ;
1335       maxTetConnSize += 4 * ( nbNodes - (is24TetMode ? 0 : 2));
1336       if ( nbNodes < 4 ) continue;
1337
1338       list< TTriangleFacet >& triaSplits = triaSplitsByFace[ iF ];
1339       const int* nInd = vol.GetFaceNodesIndices( iF );
1340       if ( nbNodes == 4 )
1341       {
1342         TTriangleFacet t012( nInd[0*iQ], nInd[1*iQ], nInd[2*iQ] );
1343         TTriangleFacet t123( nInd[1*iQ], nInd[2*iQ], nInd[3*iQ] );
1344         if      ( t012.hasAdjacentTetra( vol.Element() )) triaSplits.push_back( t012 );
1345         else if ( t123.hasAdjacentTetra( vol.Element() )) triaSplits.push_back( t123 );
1346       }
1347       else
1348       {
1349         int iCom = 0; // common node of triangle faces to split into
1350         for ( int iVar = 0; iVar < nbNodes; ++iVar, ++iCom )
1351         {
1352           TTriangleFacet t012( nInd[ iQ * ( iCom             )],
1353                                nInd[ iQ * ( (iCom+1)%nbNodes )],
1354                                nInd[ iQ * ( (iCom+2)%nbNodes )]);
1355           TTriangleFacet t023( nInd[ iQ * ( iCom             )],
1356                                nInd[ iQ * ( (iCom+2)%nbNodes )],
1357                                nInd[ iQ * ( (iCom+3)%nbNodes )]);
1358           if ( t012.hasAdjacentTetra( vol.Element() ) && t023.hasAdjacentTetra( vol.Element() ))
1359           {
1360             triaSplits.push_back( t012 );
1361             triaSplits.push_back( t023 );
1362             break;
1363           }
1364         }
1365       }
1366       if ( !triaSplits.empty() )
1367         hasAdjacentSplits = true;
1368     }
1369
1370     // Among variants of split method select one compliant with adjacent volumes
1371
1372     TSplitMethod method;
1373     if ( !vol.Element()->IsPoly() && !is24TetMode )
1374     {
1375       int nbVariants = 2, nbTet = 0;
1376       const int** connVariants = 0;
1377       switch ( vol.Element()->GetEntityType() )
1378       {
1379       case SMDSEntity_Hexa:
1380       case SMDSEntity_Quad_Hexa:
1381         if ( theMethodFlags == SMESH_MeshEditor::HEXA_TO_5 )
1382           connVariants = theHexTo5, nbTet = 5;
1383         else
1384           connVariants = theHexTo6, nbTet = 6, nbVariants = 4;
1385         break;
1386       case SMDSEntity_Pyramid:
1387       case SMDSEntity_Quad_Pyramid:
1388         connVariants = thePyraTo2;  nbTet = 2;
1389         break;
1390       case SMDSEntity_Penta:
1391       case SMDSEntity_Quad_Penta:
1392         connVariants = thePentaTo3; nbTet = 3; nbVariants = 6;
1393         break;
1394       default:
1395         nbVariants = 0;
1396       }
1397       for ( int variant = 0; variant < nbVariants && method._nbTetra == 0; ++variant )
1398       {
1399         // check method compliancy with adjacent tetras,
1400         // all found splits must be among facets of tetras described by this method
1401         method = TSplitMethod( nbTet, connVariants[variant] );
1402         if ( hasAdjacentSplits && method._nbTetra > 0 )
1403         {
1404           bool facetCreated = true;
1405           for ( int iF = 0; facetCreated && iF < triaSplitsByFace.size(); ++iF )
1406           {
1407             list< TTriangleFacet >::const_iterator facet = triaSplitsByFace[iF].begin();
1408             for ( ; facetCreated && facet != triaSplitsByFace[iF].end(); ++facet )
1409               facetCreated = method.hasFacet( *facet );
1410           }
1411           if ( !facetCreated )
1412             method = TSplitMethod(0); // incompatible method
1413         }
1414       }
1415     }
1416     if ( method._nbTetra < 1 )
1417     {
1418       // No standard method is applicable, use a generic solution:
1419       // each facet of a volume is split into triangles and
1420       // each of triangles and a volume barycenter form a tetrahedron.
1421
1422       int* connectivity = new int[ maxTetConnSize + 1 ];
1423       method._connectivity = connectivity;
1424       method._ownConn = true;
1425       method._baryNode = true;
1426
1427       int connSize = 0;
1428       int baryCenInd = vol.NbNodes();
1429       for ( int iF = 0; iF < vol.NbFaces(); ++iF )
1430       {
1431         const int nbNodes = vol.NbFaceNodes( iF ) / iQ;
1432         const int*   nInd = vol.GetFaceNodesIndices( iF );
1433         // find common node of triangle facets of tetra to create
1434         int iCommon = 0; // index in linear numeration
1435         const list< TTriangleFacet >& triaSplits = triaSplitsByFace[ iF ];
1436         if ( !triaSplits.empty() )
1437         {
1438           // by found facets
1439           const TTriangleFacet* facet = &triaSplits.front();
1440           for ( ; iCommon < nbNodes-1 ; ++iCommon )
1441             if ( facet->contains( nInd[ iQ * iCommon ]) &&
1442                  facet->contains( nInd[ iQ * ((iCommon+2)%nbNodes) ]))
1443               break;
1444         }
1445         else if ( nbNodes > 3 && !is24TetMode )
1446         {
1447           // find the best method of splitting into triangles by aspect ratio
1448           SMESH::Controls::NumericalFunctorPtr aspectRatio( new SMESH::Controls::AspectRatio);
1449           map< double, int > badness2iCommon;
1450           const SMDS_MeshNode** nodes = vol.GetFaceNodes( iF );
1451           int nbVariants = ( nbNodes == 4 ? 2 : nbNodes );
1452           for ( int iVar = 0; iVar < nbVariants; ++iVar, ++iCommon )
1453             for ( int iLast = iCommon+2; iLast < iCommon+nbNodes; ++iLast )
1454             {
1455               SMDS_FaceOfNodes tria ( nodes[ iQ*( iCommon         )],
1456                                       nodes[ iQ*((iLast-1)%nbNodes)],
1457                                       nodes[ iQ*((iLast  )%nbNodes)]);
1458               double badness = getBadRate( &tria, aspectRatio );
1459               badness2iCommon.insert( make_pair( badness, iCommon ));
1460             }
1461           // use iCommon with lowest badness
1462           iCommon = badness2iCommon.begin()->second;
1463         }
1464         if ( iCommon >= nbNodes )
1465           iCommon = 0; // something wrong
1466
1467         // fill connectivity of tetrahedra based on a current face
1468         int nbTet = nbNodes - 2;
1469         if ( is24TetMode && nbNodes > 3 && triaSplits.empty())
1470         {
1471           method._faceBaryNode.insert( make_pair( iF, (const SMDS_MeshNode*)0 ));
1472           int faceBaryCenInd = baryCenInd + method._faceBaryNode.size();
1473           nbTet = nbNodes;
1474           for ( int i = 0; i < nbTet; ++i )
1475           {
1476             int i1 = i, i2 = (i+1) % nbNodes;
1477             if ( !vol.IsFaceExternal( iF )) swap( i1, i2 );
1478             connectivity[ connSize++ ] = nInd[ iQ * i1 ];
1479             connectivity[ connSize++ ] = nInd[ iQ * i2 ];
1480             connectivity[ connSize++ ] = faceBaryCenInd;
1481             connectivity[ connSize++ ] = baryCenInd;
1482           }
1483         }
1484         else
1485         {
1486           for ( int i = 0; i < nbTet; ++i )
1487           {
1488             int i1 = (iCommon+1+i) % nbNodes, i2 = (iCommon+2+i) % nbNodes;
1489             if ( !vol.IsFaceExternal( iF )) swap( i1, i2 );
1490             connectivity[ connSize++ ] = nInd[ iQ * iCommon ];
1491             connectivity[ connSize++ ] = nInd[ iQ * i1 ];
1492             connectivity[ connSize++ ] = nInd[ iQ * i2 ];
1493             connectivity[ connSize++ ] = baryCenInd;
1494           }
1495         }
1496         method._nbTetra += nbTet;
1497       }
1498       connectivity[ connSize++ ] = -1;
1499     }
1500     return method;
1501   }
1502   //================================================================================
1503   /*!
1504    * \brief Check if there is a tetraherdon adjacent to the given element via this facet
1505    */
1506   //================================================================================
1507
1508   bool TTriangleFacet::hasAdjacentTetra( const SMDS_MeshElement* elem ) const
1509   {
1510     // find the tetrahedron including the three nodes of facet
1511     const SMDS_MeshNode* n1 = elem->GetNode(_n1);
1512     const SMDS_MeshNode* n2 = elem->GetNode(_n2);
1513     const SMDS_MeshNode* n3 = elem->GetNode(_n3);
1514     SMDS_ElemIteratorPtr volIt1 = n1->GetInverseElementIterator(SMDSAbs_Volume);
1515     while ( volIt1->more() )
1516     {
1517       const SMDS_MeshElement* v = volIt1->next();
1518       if ( v->GetEntityType() != ( v->IsQuadratic() ? SMDSEntity_Quad_Tetra : SMDSEntity_Tetra ))
1519         continue;
1520       SMDS_ElemIteratorPtr volIt2 = n2->GetInverseElementIterator(SMDSAbs_Volume);
1521       while ( volIt2->more() )
1522         if ( v != volIt2->next() )
1523           continue;
1524       SMDS_ElemIteratorPtr volIt3 = n3->GetInverseElementIterator(SMDSAbs_Volume);
1525       while ( volIt3->more() )
1526         if ( v == volIt3->next() )
1527           return true;
1528     }
1529     return false;
1530   }
1531
1532   //=======================================================================
1533   /*!
1534    * \brief A key of a face of volume
1535    */
1536   //=======================================================================
1537
1538   struct TVolumeFaceKey: pair< int, pair< int, int> >
1539   {
1540     TVolumeFaceKey( SMDS_VolumeTool& vol, int iF )
1541     {
1542       TIDSortedNodeSet sortedNodes;
1543       const int iQ = vol.Element()->IsQuadratic() ? 2 : 1;
1544       int nbNodes = vol.NbFaceNodes( iF );
1545       const SMDS_MeshNode** fNodes = vol.GetFaceNodes( iF );
1546       for ( int i = 0; i < nbNodes; i += iQ )
1547         sortedNodes.insert( fNodes[i] );
1548       TIDSortedNodeSet::iterator n = sortedNodes.begin();
1549       first = (*(n++))->GetID();
1550       second.first = (*(n++))->GetID();
1551       second.second = (*(n++))->GetID();
1552     }
1553   };
1554 } // namespace
1555
1556 //=======================================================================
1557 //function : SplitVolumesIntoTetra
1558 //purpose  : Split volumic elements into tetrahedra.
1559 //=======================================================================
1560
1561 void SMESH_MeshEditor::SplitVolumesIntoTetra (const TIDSortedElemSet & theElems,
1562                                               const int                theMethodFlags)
1563 {
1564   // std-like iterator on coordinates of nodes of mesh element
1565   typedef SMDS_StdIterator< SMESH_TNodeXYZ, SMDS_ElemIteratorPtr > NXyzIterator;
1566   NXyzIterator xyzEnd;
1567
1568   SMDS_VolumeTool    volTool;
1569   SMESH_MesherHelper helper( *GetMesh());
1570
1571   SMESHDS_SubMesh* subMesh = 0;//GetMeshDS()->MeshElements(1);
1572   SMESHDS_SubMesh* fSubMesh = 0;//subMesh;
1573   
1574   SMESH_SequenceOfElemPtr newNodes, newElems;
1575
1576   // map face of volume to it's baricenrtic node
1577   map< TVolumeFaceKey, const SMDS_MeshNode* > volFace2BaryNode;
1578   double bc[3];
1579
1580   TIDSortedElemSet::const_iterator elem = theElems.begin();
1581   for ( ; elem != theElems.end(); ++elem )
1582   {
1583     SMDSAbs_EntityType geomType = (*elem)->GetEntityType();
1584     if ( geomType <= SMDSEntity_Quad_Tetra )
1585       continue; // tetra or face or ...
1586
1587     if ( !volTool.Set( *elem )) continue; // not volume? strange...
1588
1589     TSplitMethod splitMethod = getSplitMethod( volTool, theMethodFlags );
1590     if ( splitMethod._nbTetra < 1 ) continue;
1591
1592     // find submesh to add new tetras to
1593     if ( !subMesh || !subMesh->Contains( *elem ))
1594     {
1595       int shapeID = FindShape( *elem );
1596       helper.SetSubShape( shapeID ); // helper will add tetras to the found submesh
1597       subMesh = GetMeshDS()->MeshElements( shapeID );
1598     }
1599     int iQ;
1600     if ( (*elem)->IsQuadratic() )
1601     {
1602       iQ = 2;
1603       // add quadratic links to the helper
1604       for ( int iF = 0; iF < volTool.NbFaces(); ++iF )
1605       {
1606         const SMDS_MeshNode** fNodes = volTool.GetFaceNodes( iF );
1607         for ( int iN = 0; iN < volTool.NbFaceNodes( iF ); iN += iQ )
1608           helper.AddTLinkNode( fNodes[iF], fNodes[iF+2], fNodes[iF+1] );
1609       }
1610       helper.SetIsQuadratic( true );
1611     }
1612     else
1613     {
1614       iQ = 1;
1615       helper.SetIsQuadratic( false );
1616     }
1617     vector<const SMDS_MeshNode*> nodes( (*elem)->begin_nodes(), (*elem)->end_nodes() );
1618     if ( splitMethod._baryNode )
1619     {
1620       // make a node at barycenter
1621       volTool.GetBaryCenter( bc[0], bc[1], bc[2] );
1622       SMDS_MeshNode* gcNode = helper.AddNode( bc[0], bc[1], bc[2] );
1623       nodes.push_back( gcNode );
1624       newNodes.Append( gcNode );
1625     }
1626     if ( !splitMethod._faceBaryNode.empty() )
1627     {
1628       // make or find baricentric nodes of faces
1629       map<int, const SMDS_MeshNode*>::iterator iF_n = splitMethod._faceBaryNode.begin();
1630       for ( ; iF_n != splitMethod._faceBaryNode.end(); ++iF_n )
1631       {
1632         map< TVolumeFaceKey, const SMDS_MeshNode* >::iterator f_n =
1633           volFace2BaryNode.insert
1634           ( make_pair( TVolumeFaceKey( volTool,iF_n->first ), (const SMDS_MeshNode*)0) ).first;
1635         if ( !f_n->second )
1636         {
1637           volTool.GetFaceBaryCenter( iF_n->first, bc[0], bc[1], bc[2] );
1638           newNodes.Append( f_n->second = helper.AddNode( bc[0], bc[1], bc[2] ));
1639         }
1640         nodes.push_back( iF_n->second = f_n->second );
1641       }
1642     }
1643
1644     // make tetras
1645     helper.SetElementsOnShape( true );
1646     vector<const SMDS_MeshElement* > tetras( splitMethod._nbTetra ); // splits of a volume
1647     const int* tetConn = splitMethod._connectivity;
1648     for ( int i = 0; i < splitMethod._nbTetra; ++i, tetConn += 4 )
1649       newElems.Append( tetras[ i ] = helper.AddVolume( nodes[ tetConn[0] ],
1650                                                        nodes[ tetConn[1] ],
1651                                                        nodes[ tetConn[2] ],
1652                                                        nodes[ tetConn[3] ]));
1653
1654     ReplaceElemInGroups( *elem, tetras, GetMeshDS() );
1655
1656     // Split faces on sides of the split volume
1657
1658     const SMDS_MeshNode** volNodes = volTool.GetNodes();
1659     for ( int iF = 0; iF < volTool.NbFaces(); ++iF )
1660     {
1661       const int nbNodes = volTool.NbFaceNodes( iF ) / iQ;
1662       if ( nbNodes < 4 ) continue;
1663
1664       // find an existing face
1665       vector<const SMDS_MeshNode*> fNodes( volTool.GetFaceNodes( iF ),
1666                                            volTool.GetFaceNodes( iF ) + nbNodes*iQ );
1667       while ( const SMDS_MeshElement* face = GetMeshDS()->FindFace( fNodes ))
1668       {
1669         // make triangles
1670         helper.SetElementsOnShape( false );
1671         vector< const SMDS_MeshElement* > triangles;
1672
1673         map<int, const SMDS_MeshNode*>::iterator iF_n = splitMethod._faceBaryNode.find(iF);
1674         if ( iF_n != splitMethod._faceBaryNode.end() )
1675         {
1676           for ( int iN = 0; iN < nbNodes*iQ; iN += iQ )
1677           {
1678             const SMDS_MeshNode* n1 = fNodes[iN];
1679             const SMDS_MeshNode *n2 = fNodes[(iN+iQ)%nbNodes*iQ];
1680             const SMDS_MeshNode *n3 = iF_n->second;
1681             if ( !volTool.IsFaceExternal( iF ))
1682               swap( n2, n3 );
1683             triangles.push_back( helper.AddFace( n1,n2,n3 ));
1684           }
1685         }
1686         else
1687         {
1688           // among possible triangles create ones discribed by split method
1689           const int* nInd = volTool.GetFaceNodesIndices( iF );
1690           int nbVariants = ( nbNodes == 4 ? 2 : nbNodes );
1691           int iCom = 0; // common node of triangle faces to split into
1692           list< TTriangleFacet > facets;
1693           for ( int iVar = 0; iVar < nbVariants; ++iVar, ++iCom )
1694           {
1695             TTriangleFacet t012( nInd[ iQ * ( iCom                )],
1696                                  nInd[ iQ * ( (iCom+1)%nbNodes )],
1697                                  nInd[ iQ * ( (iCom+2)%nbNodes )]);
1698             TTriangleFacet t023( nInd[ iQ * ( iCom                )],
1699                                  nInd[ iQ * ( (iCom+2)%nbNodes )],
1700                                  nInd[ iQ * ( (iCom+3)%nbNodes )]);
1701             if ( splitMethod.hasFacet( t012 ) && splitMethod.hasFacet( t023 ))
1702             {
1703               facets.push_back( t012 );
1704               facets.push_back( t023 );
1705               for ( int iLast = iCom+4; iLast < iCom+nbNodes; ++iLast )
1706                 facets.push_back( TTriangleFacet( nInd[ iQ * ( iCom             )],
1707                                                   nInd[ iQ * ((iLast-1)%nbNodes )],
1708                                                   nInd[ iQ * ((iLast  )%nbNodes )]));
1709               break;
1710             }
1711           }
1712           list< TTriangleFacet >::iterator facet = facets.begin();
1713           for ( ; facet != facets.end(); ++facet )
1714           {
1715             if ( !volTool.IsFaceExternal( iF ))
1716               swap( facet->_n2, facet->_n3 );
1717             triangles.push_back( helper.AddFace( volNodes[ facet->_n1 ],
1718                                                  volNodes[ facet->_n2 ],
1719                                                  volNodes[ facet->_n3 ]));
1720           }
1721         }
1722         // find submesh to add new triangles in
1723         if ( !fSubMesh || !fSubMesh->Contains( face ))
1724         {
1725           int shapeID = FindShape( face );
1726           fSubMesh = GetMeshDS()->MeshElements( shapeID );
1727         }
1728         for ( int i = 0; i < triangles.size(); ++i )
1729         {
1730           if ( !triangles[i] ) continue;
1731           if ( fSubMesh )
1732             fSubMesh->AddElement( triangles[i]);
1733           newElems.Append( triangles[i] );
1734         }
1735         ReplaceElemInGroups( face, triangles, GetMeshDS() );
1736         GetMeshDS()->RemoveFreeElement( face, fSubMesh, /*fromGroups=*/false );
1737       }
1738
1739     } // loop on volume faces to split them into triangles
1740
1741     GetMeshDS()->RemoveFreeElement( *elem, subMesh, /*fromGroups=*/false );
1742
1743   } // loop on volumes to split
1744
1745   myLastCreatedNodes = newNodes;
1746   myLastCreatedElems = newElems;
1747 }
1748
1749 //=======================================================================
1750 //function : AddToSameGroups
1751 //purpose  : add elemToAdd to the groups the elemInGroups belongs to
1752 //=======================================================================
1753
1754 void SMESH_MeshEditor::AddToSameGroups (const SMDS_MeshElement* elemToAdd,
1755                                         const SMDS_MeshElement* elemInGroups,
1756                                         SMESHDS_Mesh *          aMesh)
1757 {
1758   const set<SMESHDS_GroupBase*>& groups = aMesh->GetGroups();
1759   if (!groups.empty()) {
1760     set<SMESHDS_GroupBase*>::const_iterator grIt = groups.begin();
1761     for ( ; grIt != groups.end(); grIt++ ) {
1762       SMESHDS_Group* group = dynamic_cast<SMESHDS_Group*>( *grIt );
1763       if ( group && group->Contains( elemInGroups ))
1764         group->SMDSGroup().Add( elemToAdd );
1765     }
1766   }
1767 }
1768
1769
1770 //=======================================================================
1771 //function : RemoveElemFromGroups
1772 //purpose  : Remove removeelem to the groups the elemInGroups belongs to
1773 //=======================================================================
1774 void SMESH_MeshEditor::RemoveElemFromGroups (const SMDS_MeshElement* removeelem,
1775                                              SMESHDS_Mesh *          aMesh)
1776 {
1777   const set<SMESHDS_GroupBase*>& groups = aMesh->GetGroups();
1778   if (!groups.empty())
1779   {
1780     set<SMESHDS_GroupBase*>::const_iterator GrIt = groups.begin();
1781     for (; GrIt != groups.end(); GrIt++)
1782     {
1783       SMESHDS_Group* grp = dynamic_cast<SMESHDS_Group*>(*GrIt);
1784       if (!grp || grp->IsEmpty()) continue;
1785       grp->SMDSGroup().Remove(removeelem);
1786     }
1787   }
1788 }
1789
1790 //================================================================================
1791 /*!
1792  * \brief Replace elemToRm by elemToAdd in the all groups
1793  */
1794 //================================================================================
1795
1796 void SMESH_MeshEditor::ReplaceElemInGroups (const SMDS_MeshElement* elemToRm,
1797                                             const SMDS_MeshElement* elemToAdd,
1798                                             SMESHDS_Mesh *          aMesh)
1799 {
1800   const set<SMESHDS_GroupBase*>& groups = aMesh->GetGroups();
1801   if (!groups.empty()) {
1802     set<SMESHDS_GroupBase*>::const_iterator grIt = groups.begin();
1803     for ( ; grIt != groups.end(); grIt++ ) {
1804       SMESHDS_Group* group = dynamic_cast<SMESHDS_Group*>( *grIt );
1805       if ( group && group->SMDSGroup().Remove( elemToRm ) && elemToAdd )
1806         group->SMDSGroup().Add( elemToAdd );
1807     }
1808   }
1809 }
1810
1811 //================================================================================
1812 /*!
1813  * \brief Replace elemToRm by elemToAdd in the all groups
1814  */
1815 //================================================================================
1816
1817 void SMESH_MeshEditor::ReplaceElemInGroups (const SMDS_MeshElement*                elemToRm,
1818                                             const vector<const SMDS_MeshElement*>& elemToAdd,
1819                                             SMESHDS_Mesh *                         aMesh)
1820 {
1821   const set<SMESHDS_GroupBase*>& groups = aMesh->GetGroups();
1822   if (!groups.empty())
1823   {
1824     set<SMESHDS_GroupBase*>::const_iterator grIt = groups.begin();
1825     for ( ; grIt != groups.end(); grIt++ ) {
1826       SMESHDS_Group* group = dynamic_cast<SMESHDS_Group*>( *grIt );
1827       if ( group && group->SMDSGroup().Remove( elemToRm ) )
1828         for ( int i = 0; i < elemToAdd.size(); ++i )
1829           group->SMDSGroup().Add( elemToAdd[ i ] );
1830     }
1831   }
1832 }
1833
1834 //=======================================================================
1835 //function : QuadToTri
1836 //purpose  : Cut quadrangles into triangles.
1837 //           theCrit is used to select a diagonal to cut
1838 //=======================================================================
1839
1840 bool SMESH_MeshEditor::QuadToTri (TIDSortedElemSet & theElems,
1841                                   const bool         the13Diag)
1842 {
1843   myLastCreatedElems.Clear();
1844   myLastCreatedNodes.Clear();
1845
1846   MESSAGE( "::QuadToTri()" );
1847
1848   SMESHDS_Mesh * aMesh = GetMeshDS();
1849
1850   Handle(Geom_Surface) surface;
1851   SMESH_MesherHelper   helper( *GetMesh() );
1852
1853   TIDSortedElemSet::iterator itElem;
1854   for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
1855     const SMDS_MeshElement* elem = *itElem;
1856     if ( !elem || elem->GetType() != SMDSAbs_Face )
1857       continue;
1858     bool isquad = elem->NbNodes()==4 || elem->NbNodes()==8;
1859     if(!isquad) continue;
1860
1861     if(elem->NbNodes()==4) {
1862       // retrieve element nodes
1863       const SMDS_MeshNode* aNodes [4];
1864       SMDS_ElemIteratorPtr itN = elem->nodesIterator();
1865       int i = 0;
1866       while ( itN->more() )
1867         aNodes[ i++ ] = static_cast<const SMDS_MeshNode*>( itN->next() );
1868
1869       int aShapeId = FindShape( elem );
1870       const SMDS_MeshElement* newElem1 = 0;
1871       const SMDS_MeshElement* newElem2 = 0;
1872       if ( the13Diag ) {
1873         newElem1 = aMesh->AddFace( aNodes[2], aNodes[0], aNodes[1] );
1874         newElem2 = aMesh->AddFace( aNodes[2], aNodes[3], aNodes[0] );
1875       }
1876       else {
1877         newElem1 = aMesh->AddFace( aNodes[3], aNodes[0], aNodes[1] );
1878         newElem2 = aMesh->AddFace( aNodes[3], aNodes[1], aNodes[2] );
1879       }
1880       myLastCreatedElems.Append(newElem1);
1881       myLastCreatedElems.Append(newElem2);
1882       // put a new triangle on the same shape and add to the same groups
1883       if ( aShapeId )
1884         {
1885           aMesh->SetMeshElementOnShape( newElem1, aShapeId );
1886           aMesh->SetMeshElementOnShape( newElem2, aShapeId );
1887         }
1888       AddToSameGroups( newElem1, elem, aMesh );
1889       AddToSameGroups( newElem2, elem, aMesh );
1890       //aMesh->RemoveFreeElement(elem, aMesh->MeshElements(aShapeId), true);
1891       aMesh->RemoveElement( elem );
1892     }
1893
1894     // Quadratic quadrangle
1895
1896     if( elem->NbNodes()==8 && elem->IsQuadratic() ) {
1897
1898       // get surface elem is on
1899       int aShapeId = FindShape( elem );
1900       if ( aShapeId != helper.GetSubShapeID() ) {
1901         surface.Nullify();
1902         TopoDS_Shape shape;
1903         if ( aShapeId > 0 )
1904           shape = aMesh->IndexToShape( aShapeId );
1905         if ( !shape.IsNull() && shape.ShapeType() == TopAbs_FACE ) {
1906           TopoDS_Face face = TopoDS::Face( shape );
1907           surface = BRep_Tool::Surface( face );
1908           if ( !surface.IsNull() )
1909             helper.SetSubShape( shape );
1910         }
1911       }
1912
1913       const SMDS_MeshNode* aNodes [8];
1914       const SMDS_MeshNode* inFaceNode = 0;
1915       SMDS_ElemIteratorPtr itN = elem->nodesIterator();
1916       int i = 0;
1917       while ( itN->more() ) {
1918         aNodes[ i++ ] = static_cast<const SMDS_MeshNode*>( itN->next() );
1919         if ( !inFaceNode && helper.GetNodeUVneedInFaceNode() &&
1920              aNodes[ i-1 ]->GetPosition()->GetTypeOfPosition() == SMDS_TOP_FACE )
1921         {
1922           inFaceNode = aNodes[ i-1 ];
1923         }
1924       }
1925
1926       // find middle point for (0,1,2,3)
1927       // and create a node in this point;
1928       gp_XYZ p( 0,0,0 );
1929       if ( surface.IsNull() ) {
1930         for(i=0; i<4; i++)
1931           p += gp_XYZ(aNodes[i]->X(), aNodes[i]->Y(), aNodes[i]->Z() );
1932         p /= 4;
1933       }
1934       else {
1935         TopoDS_Face geomFace = TopoDS::Face( helper.GetSubShape() );
1936         gp_XY uv( 0,0 );
1937         for(i=0; i<4; i++)
1938           uv += helper.GetNodeUV( geomFace, aNodes[i], inFaceNode );
1939         uv /= 4.;
1940         p = surface->Value( uv.X(), uv.Y() ).XYZ();
1941       }
1942       const SMDS_MeshNode* newN = aMesh->AddNode( p.X(), p.Y(), p.Z() );
1943       myLastCreatedNodes.Append(newN);
1944
1945       // create a new element
1946       const SMDS_MeshElement* newElem1 = 0;
1947       const SMDS_MeshElement* newElem2 = 0;
1948       if ( the13Diag ) {
1949         newElem1 = aMesh->AddFace(aNodes[2], aNodes[3], aNodes[0],
1950                                   aNodes[6], aNodes[7], newN );
1951         newElem2 = aMesh->AddFace(aNodes[2], aNodes[0], aNodes[1],
1952                                   newN,      aNodes[4], aNodes[5] );
1953       }
1954       else {
1955         newElem1 = aMesh->AddFace(aNodes[3], aNodes[0], aNodes[1],
1956                                   aNodes[7], aNodes[4], newN );
1957         newElem2 = aMesh->AddFace(aNodes[3], aNodes[1], aNodes[2],
1958                                   newN,      aNodes[5], aNodes[6] );
1959       }
1960       myLastCreatedElems.Append(newElem1);
1961       myLastCreatedElems.Append(newElem2);
1962       // put a new triangle on the same shape and add to the same groups
1963       if ( aShapeId )
1964         {
1965           aMesh->SetMeshElementOnShape( newElem1, aShapeId );
1966           aMesh->SetMeshElementOnShape( newElem2, aShapeId );
1967         }
1968       AddToSameGroups( newElem1, elem, aMesh );
1969       AddToSameGroups( newElem2, elem, aMesh );
1970       aMesh->RemoveElement( elem );
1971     }
1972   }
1973
1974   return true;
1975 }
1976
1977 //=======================================================================
1978 //function : getAngle
1979 //purpose  :
1980 //=======================================================================
1981
1982 double getAngle(const SMDS_MeshElement * tr1,
1983                 const SMDS_MeshElement * tr2,
1984                 const SMDS_MeshNode *    n1,
1985                 const SMDS_MeshNode *    n2)
1986 {
1987   double angle = 2*PI; // bad angle
1988
1989   // get normals
1990   SMESH::Controls::TSequenceOfXYZ P1, P2;
1991   if ( !SMESH::Controls::NumericalFunctor::GetPoints( tr1, P1 ) ||
1992        !SMESH::Controls::NumericalFunctor::GetPoints( tr2, P2 ))
1993     return angle;
1994   gp_Vec N1,N2;
1995   if(!tr1->IsQuadratic())
1996     N1 = gp_Vec( P1(2) - P1(1) ) ^ gp_Vec( P1(3) - P1(1) );
1997   else
1998     N1 = gp_Vec( P1(3) - P1(1) ) ^ gp_Vec( P1(5) - P1(1) );
1999   if ( N1.SquareMagnitude() <= gp::Resolution() )
2000     return angle;
2001   if(!tr2->IsQuadratic())
2002     N2 = gp_Vec( P2(2) - P2(1) ) ^ gp_Vec( P2(3) - P2(1) );
2003   else
2004     N2 = gp_Vec( P2(3) - P2(1) ) ^ gp_Vec( P2(5) - P2(1) );
2005   if ( N2.SquareMagnitude() <= gp::Resolution() )
2006     return angle;
2007
2008   // find the first diagonal node n1 in the triangles:
2009   // take in account a diagonal link orientation
2010   const SMDS_MeshElement *nFirst[2], *tr[] = { tr1, tr2 };
2011   for ( int t = 0; t < 2; t++ ) {
2012     SMDS_ElemIteratorPtr it = tr[ t ]->nodesIterator();
2013     int i = 0, iDiag = -1;
2014     while ( it->more()) {
2015       const SMDS_MeshElement *n = it->next();
2016       if ( n == n1 || n == n2 ) {
2017         if ( iDiag < 0)
2018           iDiag = i;
2019         else {
2020           if ( i - iDiag == 1 )
2021             nFirst[ t ] = ( n == n1 ? n2 : n1 );
2022           else
2023             nFirst[ t ] = n;
2024           break;
2025         }
2026       }
2027       i++;
2028     }
2029   }
2030   if ( nFirst[ 0 ] == nFirst[ 1 ] )
2031     N2.Reverse();
2032
2033   angle = N1.Angle( N2 );
2034   //SCRUTE( angle );
2035   return angle;
2036 }
2037
2038 // =================================================
2039 // class generating a unique ID for a pair of nodes
2040 // and able to return nodes by that ID
2041 // =================================================
2042 class LinkID_Gen {
2043 public:
2044
2045   LinkID_Gen( const SMESHDS_Mesh* theMesh )
2046     :myMesh( theMesh ), myMaxID( theMesh->MaxNodeID() + 1)
2047   {}
2048
2049   long GetLinkID (const SMDS_MeshNode * n1,
2050                   const SMDS_MeshNode * n2) const
2051   {
2052     return ( Min(n1->GetID(),n2->GetID()) * myMaxID + Max(n1->GetID(),n2->GetID()));
2053   }
2054
2055   bool GetNodes (const long             theLinkID,
2056                  const SMDS_MeshNode* & theNode1,
2057                  const SMDS_MeshNode* & theNode2) const
2058   {
2059     theNode1 = myMesh->FindNode( theLinkID / myMaxID );
2060     if ( !theNode1 ) return false;
2061     theNode2 = myMesh->FindNode( theLinkID % myMaxID );
2062     if ( !theNode2 ) return false;
2063     return true;
2064   }
2065
2066 private:
2067   LinkID_Gen();
2068   const SMESHDS_Mesh* myMesh;
2069   long                myMaxID;
2070 };
2071
2072
2073 //=======================================================================
2074 //function : TriToQuad
2075 //purpose  : Fuse neighbour triangles into quadrangles.
2076 //           theCrit is used to select a neighbour to fuse with.
2077 //           theMaxAngle is a max angle between element normals at which
2078 //           fusion is still performed.
2079 //=======================================================================
2080
2081 bool SMESH_MeshEditor::TriToQuad (TIDSortedElemSet &                   theElems,
2082                                   SMESH::Controls::NumericalFunctorPtr theCrit,
2083                                   const double                         theMaxAngle)
2084 {
2085   myLastCreatedElems.Clear();
2086   myLastCreatedNodes.Clear();
2087
2088   MESSAGE( "::TriToQuad()" );
2089
2090   if ( !theCrit.get() )
2091     return false;
2092
2093   SMESHDS_Mesh * aMesh = GetMeshDS();
2094
2095   // Prepare data for algo: build
2096   // 1. map of elements with their linkIDs
2097   // 2. map of linkIDs with their elements
2098
2099   map< SMESH_TLink, list< const SMDS_MeshElement* > > mapLi_listEl;
2100   map< SMESH_TLink, list< const SMDS_MeshElement* > >::iterator itLE;
2101   map< const SMDS_MeshElement*, set< SMESH_TLink > >  mapEl_setLi;
2102   map< const SMDS_MeshElement*, set< SMESH_TLink > >::iterator itEL;
2103
2104   TIDSortedElemSet::iterator itElem;
2105   for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
2106     const SMDS_MeshElement* elem = *itElem;
2107     if(!elem || elem->GetType() != SMDSAbs_Face ) continue;
2108     bool IsTria = elem->NbNodes()==3 || (elem->NbNodes()==6 && elem->IsQuadratic());
2109     if(!IsTria) continue;
2110
2111     // retrieve element nodes
2112     const SMDS_MeshNode* aNodes [4];
2113     SMDS_ElemIteratorPtr itN = elem->nodesIterator();
2114     int i = 0;
2115     while ( i<3 )
2116       aNodes[ i++ ] = cast2Node( itN->next() );
2117     aNodes[ 3 ] = aNodes[ 0 ];
2118
2119     // fill maps
2120     for ( i = 0; i < 3; i++ ) {
2121       SMESH_TLink link( aNodes[i], aNodes[i+1] );
2122       // check if elements sharing a link can be fused
2123       itLE = mapLi_listEl.find( link );
2124       if ( itLE != mapLi_listEl.end() ) {
2125         if ((*itLE).second.size() > 1 ) // consider only 2 elems adjacent by a link
2126           continue;
2127         const SMDS_MeshElement* elem2 = (*itLE).second.front();
2128         //if ( FindShape( elem ) != FindShape( elem2 ))
2129         //  continue; // do not fuse triangles laying on different shapes
2130         if ( getAngle( elem, elem2, aNodes[i], aNodes[i+1] ) > theMaxAngle )
2131           continue; // avoid making badly shaped quads
2132         (*itLE).second.push_back( elem );
2133       }
2134       else {
2135         mapLi_listEl[ link ].push_back( elem );
2136       }
2137       mapEl_setLi [ elem ].insert( link );
2138     }
2139   }
2140   // Clean the maps from the links shared by a sole element, ie
2141   // links to which only one element is bound in mapLi_listEl
2142
2143   for ( itLE = mapLi_listEl.begin(); itLE != mapLi_listEl.end(); itLE++ ) {
2144     int nbElems = (*itLE).second.size();
2145     if ( nbElems < 2  ) {
2146       const SMDS_MeshElement* elem = (*itLE).second.front();
2147       SMESH_TLink link = (*itLE).first;
2148       mapEl_setLi[ elem ].erase( link );
2149       if ( mapEl_setLi[ elem ].empty() )
2150         mapEl_setLi.erase( elem );
2151     }
2152   }
2153
2154   // Algo: fuse triangles into quadrangles
2155
2156   while ( ! mapEl_setLi.empty() ) {
2157     // Look for the start element:
2158     // the element having the least nb of shared links
2159     const SMDS_MeshElement* startElem = 0;
2160     int minNbLinks = 4;
2161     for ( itEL = mapEl_setLi.begin(); itEL != mapEl_setLi.end(); itEL++ ) {
2162       int nbLinks = (*itEL).second.size();
2163       if ( nbLinks < minNbLinks ) {
2164         startElem = (*itEL).first;
2165         minNbLinks = nbLinks;
2166         if ( minNbLinks == 1 )
2167           break;
2168       }
2169     }
2170
2171     // search elements to fuse starting from startElem or links of elements
2172     // fused earlyer - startLinks
2173     list< SMESH_TLink > startLinks;
2174     while ( startElem || !startLinks.empty() ) {
2175       while ( !startElem && !startLinks.empty() ) {
2176         // Get an element to start, by a link
2177         SMESH_TLink linkId = startLinks.front();
2178         startLinks.pop_front();
2179         itLE = mapLi_listEl.find( linkId );
2180         if ( itLE != mapLi_listEl.end() ) {
2181           list< const SMDS_MeshElement* > & listElem = (*itLE).second;
2182           list< const SMDS_MeshElement* >::iterator itE = listElem.begin();
2183           for ( ; itE != listElem.end() ; itE++ )
2184             if ( mapEl_setLi.find( (*itE) ) != mapEl_setLi.end() )
2185               startElem = (*itE);
2186           mapLi_listEl.erase( itLE );
2187         }
2188       }
2189
2190       if ( startElem ) {
2191         // Get candidates to be fused
2192         const SMDS_MeshElement *tr1 = startElem, *tr2 = 0, *tr3 = 0;
2193         const SMESH_TLink *link12, *link13;
2194         startElem = 0;
2195         ASSERT( mapEl_setLi.find( tr1 ) != mapEl_setLi.end() );
2196         set< SMESH_TLink >& setLi = mapEl_setLi[ tr1 ];
2197         ASSERT( !setLi.empty() );
2198         set< SMESH_TLink >::iterator itLi;
2199         for ( itLi = setLi.begin(); itLi != setLi.end(); itLi++ )
2200         {
2201           const SMESH_TLink & link = (*itLi);
2202           itLE = mapLi_listEl.find( link );
2203           if ( itLE == mapLi_listEl.end() )
2204             continue;
2205
2206           const SMDS_MeshElement* elem = (*itLE).second.front();
2207           if ( elem == tr1 )
2208             elem = (*itLE).second.back();
2209           mapLi_listEl.erase( itLE );
2210           if ( mapEl_setLi.find( elem ) == mapEl_setLi.end())
2211             continue;
2212           if ( tr2 ) {
2213             tr3 = elem;
2214             link13 = &link;
2215           }
2216           else {
2217             tr2 = elem;
2218             link12 = &link;
2219           }
2220
2221           // add other links of elem to list of links to re-start from
2222           set< SMESH_TLink >& links = mapEl_setLi[ elem ];
2223           set< SMESH_TLink >::iterator it;
2224           for ( it = links.begin(); it != links.end(); it++ ) {
2225             const SMESH_TLink& link2 = (*it);
2226             if ( link2 != link )
2227               startLinks.push_back( link2 );
2228           }
2229         }
2230
2231         // Get nodes of possible quadrangles
2232         const SMDS_MeshNode *n12 [4], *n13 [4];
2233         bool Ok12 = false, Ok13 = false;
2234         const SMDS_MeshNode *linkNode1, *linkNode2;
2235         if(tr2) {
2236           linkNode1 = link12->first;
2237           linkNode2 = link12->second;
2238           if ( tr2 && getQuadrangleNodes( n12, linkNode1, linkNode2, tr1, tr2 ))
2239             Ok12 = true;
2240         }
2241         if(tr3) {
2242           linkNode1 = link13->first;
2243           linkNode2 = link13->second;
2244           if ( tr3 && getQuadrangleNodes( n13, linkNode1, linkNode2, tr1, tr3 ))
2245             Ok13 = true;
2246         }
2247
2248         // Choose a pair to fuse
2249         if ( Ok12 && Ok13 ) {
2250           SMDS_FaceOfNodes quad12 ( n12[ 0 ], n12[ 1 ], n12[ 2 ], n12[ 3 ] );
2251           SMDS_FaceOfNodes quad13 ( n13[ 0 ], n13[ 1 ], n13[ 2 ], n13[ 3 ] );
2252           double aBadRate12 = getBadRate( &quad12, theCrit );
2253           double aBadRate13 = getBadRate( &quad13, theCrit );
2254           if (  aBadRate13 < aBadRate12 )
2255             Ok12 = false;
2256           else
2257             Ok13 = false;
2258         }
2259
2260         // Make quadrangles
2261         // and remove fused elems and removed links from the maps
2262         mapEl_setLi.erase( tr1 );
2263         if ( Ok12 ) {
2264           mapEl_setLi.erase( tr2 );
2265           mapLi_listEl.erase( *link12 );
2266           if(tr1->NbNodes()==3) {
2267             const SMDS_MeshElement* newElem = 0;
2268             newElem = aMesh->AddFace(n12[0], n12[1], n12[2], n12[3] );
2269             myLastCreatedElems.Append(newElem);
2270             AddToSameGroups( newElem, tr1, aMesh );
2271             int aShapeId = tr1->getshapeId();
2272             if ( aShapeId )
2273               {
2274                 aMesh->SetMeshElementOnShape( newElem, aShapeId );
2275               }
2276             aMesh->RemoveElement( tr1 );
2277             aMesh->RemoveElement( tr2 );
2278           }
2279           else {
2280             const SMDS_MeshNode* N1 [6];
2281             const SMDS_MeshNode* N2 [6];
2282             GetNodesFromTwoTria(tr1,tr2,N1,N2);
2283             // now we receive following N1 and N2 (using numeration as above image)
2284             // tria1 : (1 2 4 5 9 7)  and  tria2 : (3 4 2 8 9 6)
2285             // i.e. first nodes from both arrays determ new diagonal
2286             const SMDS_MeshNode* aNodes[8];
2287             aNodes[0] = N1[0];
2288             aNodes[1] = N1[1];
2289             aNodes[2] = N2[0];
2290             aNodes[3] = N2[1];
2291             aNodes[4] = N1[3];
2292             aNodes[5] = N2[5];
2293             aNodes[6] = N2[3];
2294             aNodes[7] = N1[5];
2295             const SMDS_MeshElement* newElem = 0;
2296             newElem = aMesh->AddFace(aNodes[0], aNodes[1], aNodes[2], aNodes[3],
2297                                      aNodes[4], aNodes[5], aNodes[6], aNodes[7]);
2298             myLastCreatedElems.Append(newElem);
2299             AddToSameGroups( newElem, tr1, aMesh );
2300             int aShapeId = tr1->getshapeId();
2301             if ( aShapeId )
2302               {
2303                 aMesh->SetMeshElementOnShape( newElem, aShapeId );
2304               }
2305             aMesh->RemoveElement( tr1 );
2306             aMesh->RemoveElement( tr2 );
2307             // remove middle node (9)
2308             GetMeshDS()->RemoveNode( N1[4] );
2309           }
2310         }
2311         else if ( Ok13 ) {
2312           mapEl_setLi.erase( tr3 );
2313           mapLi_listEl.erase( *link13 );
2314           if(tr1->NbNodes()==3) {
2315             const SMDS_MeshElement* newElem = 0;
2316             newElem = aMesh->AddFace(n13[0], n13[1], n13[2], n13[3] );
2317             myLastCreatedElems.Append(newElem);
2318             AddToSameGroups( newElem, tr1, aMesh );
2319             int aShapeId = tr1->getshapeId();
2320             if ( aShapeId )
2321               {
2322                 aMesh->SetMeshElementOnShape( newElem, aShapeId );
2323               }
2324             aMesh->RemoveElement( tr1 );
2325             aMesh->RemoveElement( tr3 );
2326           }
2327           else {
2328             const SMDS_MeshNode* N1 [6];
2329             const SMDS_MeshNode* N2 [6];
2330             GetNodesFromTwoTria(tr1,tr3,N1,N2);
2331             // now we receive following N1 and N2 (using numeration as above image)
2332             // tria1 : (1 2 4 5 9 7)  and  tria2 : (3 4 2 8 9 6)
2333             // i.e. first nodes from both arrays determ new diagonal
2334             const SMDS_MeshNode* aNodes[8];
2335             aNodes[0] = N1[0];
2336             aNodes[1] = N1[1];
2337             aNodes[2] = N2[0];
2338             aNodes[3] = N2[1];
2339             aNodes[4] = N1[3];
2340             aNodes[5] = N2[5];
2341             aNodes[6] = N2[3];
2342             aNodes[7] = N1[5];
2343             const SMDS_MeshElement* newElem = 0;
2344             newElem = aMesh->AddFace(aNodes[0], aNodes[1], aNodes[2], aNodes[3],
2345                                      aNodes[4], aNodes[5], aNodes[6], aNodes[7]);
2346             myLastCreatedElems.Append(newElem);
2347             AddToSameGroups( newElem, tr1, aMesh );
2348             int aShapeId = tr1->getshapeId();
2349             if ( aShapeId )
2350               {
2351                 aMesh->SetMeshElementOnShape( newElem, aShapeId );
2352               }
2353             aMesh->RemoveElement( tr1 );
2354             aMesh->RemoveElement( tr3 );
2355             // remove middle node (9)
2356             GetMeshDS()->RemoveNode( N1[4] );
2357           }
2358         }
2359
2360         // Next element to fuse: the rejected one
2361         if ( tr3 )
2362           startElem = Ok12 ? tr3 : tr2;
2363
2364       } // if ( startElem )
2365     } // while ( startElem || !startLinks.empty() )
2366   } // while ( ! mapEl_setLi.empty() )
2367
2368   return true;
2369 }
2370
2371
2372 /*#define DUMPSO(txt) \
2373 //  cout << txt << endl;
2374 //=============================================================================
2375 //
2376 //
2377 //
2378 //=============================================================================
2379 static void swap( int i1, int i2, int idNodes[], gp_Pnt P[] )
2380 {
2381 if ( i1 == i2 )
2382 return;
2383 int tmp = idNodes[ i1 ];
2384 idNodes[ i1 ] = idNodes[ i2 ];
2385 idNodes[ i2 ] = tmp;
2386 gp_Pnt Ptmp = P[ i1 ];
2387 P[ i1 ] = P[ i2 ];
2388 P[ i2 ] = Ptmp;
2389 DUMPSO( i1 << "(" << idNodes[ i2 ] << ") <-> " << i2 << "(" << idNodes[ i1 ] << ")");
2390 }
2391
2392 //=======================================================================
2393 //function : SortQuadNodes
2394 //purpose  : Set 4 nodes of a quadrangle face in a good order.
2395 //           Swap 1<->2 or 2<->3 nodes and correspondingly return
2396 //           1 or 2 else 0.
2397 //=======================================================================
2398
2399 int SMESH_MeshEditor::SortQuadNodes (const SMDS_Mesh * theMesh,
2400 int               idNodes[] )
2401 {
2402   gp_Pnt P[4];
2403   int i;
2404   for ( i = 0; i < 4; i++ ) {
2405     const SMDS_MeshNode *n = theMesh->FindNode( idNodes[i] );
2406     if ( !n ) return 0;
2407     P[ i ].SetCoord( n->X(), n->Y(), n->Z() );
2408   }
2409
2410   gp_Vec V1(P[0], P[1]);
2411   gp_Vec V2(P[0], P[2]);
2412   gp_Vec V3(P[0], P[3]);
2413
2414   gp_Vec Cross1 = V1 ^ V2;
2415   gp_Vec Cross2 = V2 ^ V3;
2416
2417   i = 0;
2418   if (Cross1.Dot(Cross2) < 0)
2419   {
2420     Cross1 = V2 ^ V1;
2421     Cross2 = V1 ^ V3;
2422
2423     if (Cross1.Dot(Cross2) < 0)
2424       i = 2;
2425     else
2426       i = 1;
2427     swap ( i, i + 1, idNodes, P );
2428
2429     //     for ( int ii = 0; ii < 4; ii++ ) {
2430     //       const SMDS_MeshNode *n = theMesh->FindNode( idNodes[ii] );
2431     //       DUMPSO( ii << "(" << idNodes[ii] <<") : "<<n->X()<<" "<<n->Y()<<" "<<n->Z());
2432     //     }
2433   }
2434   return i;
2435 }
2436
2437 //=======================================================================
2438 //function : SortHexaNodes
2439 //purpose  : Set 8 nodes of a hexahedron in a good order.
2440 //           Return success status
2441 //=======================================================================
2442
2443 bool SMESH_MeshEditor::SortHexaNodes (const SMDS_Mesh * theMesh,
2444                                       int               idNodes[] )
2445 {
2446   gp_Pnt P[8];
2447   int i;
2448   DUMPSO( "INPUT: ========================================");
2449   for ( i = 0; i < 8; i++ ) {
2450     const SMDS_MeshNode *n = theMesh->FindNode( idNodes[i] );
2451     if ( !n ) return false;
2452     P[ i ].SetCoord( n->X(), n->Y(), n->Z() );
2453     DUMPSO( i << "(" << idNodes[i] <<") : "<<n->X()<<" "<<n->Y()<<" "<<n->Z());
2454   }
2455   DUMPSO( "========================================");
2456
2457
2458   set<int> faceNodes;  // ids of bottom face nodes, to be found
2459   set<int> checkedId1; // ids of tried 2-nd nodes
2460   Standard_Real leastDist = DBL_MAX; // dist of the 4-th node from 123 plane
2461   const Standard_Real tol = 1.e-6;   // tolerance to find nodes in plane
2462   int iMin, iLoop1 = 0;
2463
2464   // Loop to try the 2-nd nodes
2465
2466   while ( leastDist > DBL_MIN && ++iLoop1 < 8 )
2467   {
2468     // Find not checked 2-nd node
2469     for ( i = 1; i < 8; i++ )
2470       if ( checkedId1.find( idNodes[i] ) == checkedId1.end() ) {
2471         int id1 = idNodes[i];
2472         swap ( 1, i, idNodes, P );
2473         checkedId1.insert ( id1 );
2474         break;
2475       }
2476
2477     // Find the 3-d node so that 1-2-3 triangle to be on a hexa face,
2478     // ie that all but meybe one (id3 which is on the same face) nodes
2479     // lay on the same side from the triangle plane.
2480
2481     bool manyInPlane = false; // more than 4 nodes lay in plane
2482     int iLoop2 = 0;
2483     while ( ++iLoop2 < 6 ) {
2484
2485       // get 1-2-3 plane coeffs
2486       Standard_Real A, B, C, D;
2487       gp_Vec N = gp_Vec (P[0], P[1]).Crossed( gp_Vec (P[0], P[2]) );
2488       if ( N.SquareMagnitude() > gp::Resolution() )
2489       {
2490         gp_Pln pln ( P[0], N );
2491         pln.Coefficients( A, B, C, D );
2492
2493         // find the node (iMin) closest to pln
2494         Standard_Real dist[ 8 ], minDist = DBL_MAX;
2495         set<int> idInPln;
2496         for ( i = 3; i < 8; i++ ) {
2497           dist[i] = A * P[i].X() + B * P[i].Y() + C * P[i].Z() + D;
2498           if ( fabs( dist[i] ) < minDist ) {
2499             minDist = fabs( dist[i] );
2500             iMin = i;
2501           }
2502           if ( fabs( dist[i] ) <= tol )
2503             idInPln.insert( idNodes[i] );
2504         }
2505
2506         // there should not be more than 4 nodes in bottom plane
2507         if ( idInPln.size() > 1 )
2508         {
2509           DUMPSO( "### idInPln.size() = " << idInPln.size());
2510           // idInPlane does not contain the first 3 nodes
2511           if ( manyInPlane || idInPln.size() == 5)
2512             return false; // all nodes in one plane
2513           manyInPlane = true;
2514
2515           // set the 1-st node to be not in plane
2516           for ( i = 3; i < 8; i++ ) {
2517             if ( idInPln.find( idNodes[ i ] ) == idInPln.end() ) {
2518               DUMPSO( "### Reset 0-th node");
2519               swap( 0, i, idNodes, P );
2520               break;
2521             }
2522           }
2523
2524           // reset to re-check second nodes
2525           leastDist = DBL_MAX;
2526           faceNodes.clear();
2527           checkedId1.clear();
2528           iLoop1 = 0;
2529           break; // from iLoop2;
2530         }
2531
2532         // check that the other 4 nodes are on the same side
2533         bool sameSide = true;
2534         bool isNeg = dist[ iMin == 3 ? 4 : 3 ] <= 0.;
2535         for ( i = 3; sameSide && i < 8; i++ ) {
2536           if ( i != iMin )
2537             sameSide = ( isNeg == dist[i] <= 0.);
2538         }
2539
2540         // keep best solution
2541         if ( sameSide && minDist < leastDist ) {
2542           leastDist = minDist;
2543           faceNodes.clear();
2544           faceNodes.insert( idNodes[ 1 ] );
2545           faceNodes.insert( idNodes[ 2 ] );
2546           faceNodes.insert( idNodes[ iMin ] );
2547           DUMPSO( "loop " << iLoop2 << " id2 " << idNodes[ 1 ] << " id3 " << idNodes[ 2 ]
2548                   << " leastDist = " << leastDist);
2549           if ( leastDist <= DBL_MIN )
2550             break;
2551         }
2552       }
2553
2554       // set next 3-d node to check
2555       int iNext = 2 + iLoop2;
2556       if ( iNext < 8 ) {
2557         DUMPSO( "Try 2-nd");
2558         swap ( 2, iNext, idNodes, P );
2559       }
2560     } // while ( iLoop2 < 6 )
2561   } // iLoop1
2562
2563   if ( faceNodes.empty() ) return false;
2564
2565   // Put the faceNodes in proper places
2566   for ( i = 4; i < 8; i++ ) {
2567     if ( faceNodes.find( idNodes[ i ] ) != faceNodes.end() ) {
2568       // find a place to put
2569       int iTo = 1;
2570       while ( faceNodes.find( idNodes[ iTo ] ) != faceNodes.end() )
2571         iTo++;
2572       DUMPSO( "Set faceNodes");
2573       swap ( iTo, i, idNodes, P );
2574     }
2575   }
2576
2577
2578   // Set nodes of the found bottom face in good order
2579   DUMPSO( " Found bottom face: ");
2580   i = SortQuadNodes( theMesh, idNodes );
2581   if ( i ) {
2582     gp_Pnt Ptmp = P[ i ];
2583     P[ i ] = P[ i+1 ];
2584     P[ i+1 ] = Ptmp;
2585   }
2586   //   else
2587   //     for ( int ii = 0; ii < 4; ii++ ) {
2588   //       const SMDS_MeshNode *n = theMesh->FindNode( idNodes[ii] );
2589   //       DUMPSO( ii << "(" << idNodes[ii] <<") : "<<n->X()<<" "<<n->Y()<<" "<<n->Z());
2590   //    }
2591
2592   // Gravity center of the top and bottom faces
2593   gp_Pnt aGCb = ( P[0].XYZ() + P[1].XYZ() + P[2].XYZ() + P[3].XYZ() ) / 4.;
2594   gp_Pnt aGCt = ( P[4].XYZ() + P[5].XYZ() + P[6].XYZ() + P[7].XYZ() ) / 4.;
2595
2596   // Get direction from the bottom to the top face
2597   gp_Vec upDir ( aGCb, aGCt );
2598   Standard_Real upDirSize = upDir.Magnitude();
2599   if ( upDirSize <= gp::Resolution() ) return false;
2600   upDir / upDirSize;
2601
2602   // Assure that the bottom face normal points up
2603   gp_Vec Nb = gp_Vec (P[0], P[1]).Crossed( gp_Vec (P[0], P[2]) );
2604   Nb += gp_Vec (P[0], P[2]).Crossed( gp_Vec (P[0], P[3]) );
2605   if ( Nb.Dot( upDir ) < 0 ) {
2606     DUMPSO( "Reverse bottom face");
2607     swap( 1, 3, idNodes, P );
2608   }
2609
2610   // Find 5-th node - the one closest to the 1-st among the last 4 nodes.
2611   Standard_Real minDist = DBL_MAX;
2612   for ( i = 4; i < 8; i++ ) {
2613     // projection of P[i] to the plane defined by P[0] and upDir
2614     gp_Pnt Pp = P[i].Translated( upDir * ( upDir.Dot( gp_Vec( P[i], P[0] ))));
2615     Standard_Real sqDist = P[0].SquareDistance( Pp );
2616     if ( sqDist < minDist ) {
2617       minDist = sqDist;
2618       iMin = i;
2619     }
2620   }
2621   DUMPSO( "Set 4-th");
2622   swap ( 4, iMin, idNodes, P );
2623
2624   // Set nodes of the top face in good order
2625   DUMPSO( "Sort top face");
2626   i = SortQuadNodes( theMesh, &idNodes[4] );
2627   if ( i ) {
2628     i += 4;
2629     gp_Pnt Ptmp = P[ i ];
2630     P[ i ] = P[ i+1 ];
2631     P[ i+1 ] = Ptmp;
2632   }
2633
2634   // Assure that direction of the top face normal is from the bottom face
2635   gp_Vec Nt = gp_Vec (P[4], P[5]).Crossed( gp_Vec (P[4], P[6]) );
2636   Nt += gp_Vec (P[4], P[6]).Crossed( gp_Vec (P[4], P[7]) );
2637   if ( Nt.Dot( upDir ) < 0 ) {
2638     DUMPSO( "Reverse top face");
2639     swap( 5, 7, idNodes, P );
2640   }
2641
2642   //   DUMPSO( "OUTPUT: ========================================");
2643   //   for ( i = 0; i < 8; i++ ) {
2644   //     float *p = ugrid->GetPoint(idNodes[i]);
2645   //     DUMPSO( i << "(" << idNodes[i] << ") : " << p[0] << " " << p[1] << " " << p[2]);
2646   //   }
2647
2648   return true;
2649 }*/
2650
2651 //================================================================================
2652 /*!
2653  * \brief Return nodes linked to the given one
2654  * \param theNode - the node
2655  * \param linkedNodes - the found nodes
2656  * \param type - the type of elements to check
2657  *
2658  * Medium nodes are ignored
2659  */
2660 //================================================================================
2661
2662 void SMESH_MeshEditor::GetLinkedNodes( const SMDS_MeshNode* theNode,
2663                                        TIDSortedElemSet &   linkedNodes,
2664                                        SMDSAbs_ElementType  type )
2665 {
2666   SMDS_ElemIteratorPtr elemIt = theNode->GetInverseElementIterator(type);
2667   while ( elemIt->more() )
2668   {
2669     const SMDS_MeshElement* elem = elemIt->next();
2670     if(elem->GetType() == SMDSAbs_0DElement)
2671       continue;
2672     
2673     SMDS_ElemIteratorPtr nodeIt = elem->nodesIterator();
2674     if ( elem->GetType() == SMDSAbs_Volume )
2675     {
2676       SMDS_VolumeTool vol( elem );
2677       while ( nodeIt->more() ) {
2678         const SMDS_MeshNode* n = cast2Node( nodeIt->next() );
2679         if ( theNode != n && vol.IsLinked( theNode, n ))
2680           linkedNodes.insert( n );
2681       }
2682     }
2683     else
2684     {
2685       for ( int i = 0; nodeIt->more(); ++i ) {
2686         const SMDS_MeshNode* n = cast2Node( nodeIt->next() );
2687         if ( n == theNode ) {
2688           int iBefore = i - 1;
2689           int iAfter  = i + 1;
2690           if ( elem->IsQuadratic() ) {
2691             int nb = elem->NbNodes() / 2;
2692             iAfter  = SMESH_MesherHelper::WrapIndex( iAfter, nb );
2693             iBefore = SMESH_MesherHelper::WrapIndex( iBefore, nb );
2694           }
2695           linkedNodes.insert( elem->GetNodeWrap( iAfter ));
2696           linkedNodes.insert( elem->GetNodeWrap( iBefore ));
2697         }
2698       }
2699     }
2700   }
2701 }
2702
2703 //=======================================================================
2704 //function : laplacianSmooth
2705 //purpose  : pulls theNode toward the center of surrounding nodes directly
2706 //           connected to that node along an element edge
2707 //=======================================================================
2708
2709 void laplacianSmooth(const SMDS_MeshNode*                 theNode,
2710                      const Handle(Geom_Surface)&          theSurface,
2711                      map< const SMDS_MeshNode*, gp_XY* >& theUVMap)
2712 {
2713   // find surrounding nodes
2714
2715   TIDSortedElemSet nodeSet;
2716   SMESH_MeshEditor::GetLinkedNodes( theNode, nodeSet, SMDSAbs_Face );
2717
2718   // compute new coodrs
2719
2720   double coord[] = { 0., 0., 0. };
2721   TIDSortedElemSet::iterator nodeSetIt = nodeSet.begin();
2722   for ( ; nodeSetIt != nodeSet.end(); nodeSetIt++ ) {
2723     const SMDS_MeshNode* node = cast2Node(*nodeSetIt);
2724     if ( theSurface.IsNull() ) { // smooth in 3D
2725       coord[0] += node->X();
2726       coord[1] += node->Y();
2727       coord[2] += node->Z();
2728     }
2729     else { // smooth in 2D
2730       ASSERT( theUVMap.find( node ) != theUVMap.end() );
2731       gp_XY* uv = theUVMap[ node ];
2732       coord[0] += uv->X();
2733       coord[1] += uv->Y();
2734     }
2735   }
2736   int nbNodes = nodeSet.size();
2737   if ( !nbNodes )
2738     return;
2739   coord[0] /= nbNodes;
2740   coord[1] /= nbNodes;
2741
2742   if ( !theSurface.IsNull() ) {
2743     ASSERT( theUVMap.find( theNode ) != theUVMap.end() );
2744     theUVMap[ theNode ]->SetCoord( coord[0], coord[1] );
2745     gp_Pnt p3d = theSurface->Value( coord[0], coord[1] );
2746     coord[0] = p3d.X();
2747     coord[1] = p3d.Y();
2748     coord[2] = p3d.Z();
2749   }
2750   else
2751     coord[2] /= nbNodes;
2752
2753   // move node
2754
2755   const_cast< SMDS_MeshNode* >( theNode )->setXYZ(coord[0],coord[1],coord[2]);
2756 }
2757
2758 //=======================================================================
2759 //function : centroidalSmooth
2760 //purpose  : pulls theNode toward the element-area-weighted centroid of the
2761 //           surrounding elements
2762 //=======================================================================
2763
2764 void centroidalSmooth(const SMDS_MeshNode*                 theNode,
2765                       const Handle(Geom_Surface)&          theSurface,
2766                       map< const SMDS_MeshNode*, gp_XY* >& theUVMap)
2767 {
2768   gp_XYZ aNewXYZ(0.,0.,0.);
2769   SMESH::Controls::Area anAreaFunc;
2770   double totalArea = 0.;
2771   int nbElems = 0;
2772
2773   // compute new XYZ
2774
2775   SMDS_ElemIteratorPtr elemIt = theNode->GetInverseElementIterator(SMDSAbs_Face);
2776   while ( elemIt->more() )
2777   {
2778     const SMDS_MeshElement* elem = elemIt->next();
2779     nbElems++;
2780
2781     gp_XYZ elemCenter(0.,0.,0.);
2782     SMESH::Controls::TSequenceOfXYZ aNodePoints;
2783     SMDS_ElemIteratorPtr itN = elem->nodesIterator();
2784     int nn = elem->NbNodes();
2785     if(elem->IsQuadratic()) nn = nn/2;
2786     int i=0;
2787     //while ( itN->more() ) {
2788     while ( i<nn ) {
2789       const SMDS_MeshNode* aNode = static_cast<const SMDS_MeshNode*>( itN->next() );
2790       i++;
2791       gp_XYZ aP( aNode->X(), aNode->Y(), aNode->Z() );
2792       aNodePoints.push_back( aP );
2793       if ( !theSurface.IsNull() ) { // smooth in 2D
2794         ASSERT( theUVMap.find( aNode ) != theUVMap.end() );
2795         gp_XY* uv = theUVMap[ aNode ];
2796         aP.SetCoord( uv->X(), uv->Y(), 0. );
2797       }
2798       elemCenter += aP;
2799     }
2800     double elemArea = anAreaFunc.GetValue( aNodePoints );
2801     totalArea += elemArea;
2802     elemCenter /= nn;
2803     aNewXYZ += elemCenter * elemArea;
2804   }
2805   aNewXYZ /= totalArea;
2806   if ( !theSurface.IsNull() ) {
2807     theUVMap[ theNode ]->SetCoord( aNewXYZ.X(), aNewXYZ.Y() );
2808     aNewXYZ = theSurface->Value( aNewXYZ.X(), aNewXYZ.Y() ).XYZ();
2809   }
2810
2811   // move node
2812
2813   const_cast< SMDS_MeshNode* >( theNode )->setXYZ(aNewXYZ.X(),aNewXYZ.Y(),aNewXYZ.Z());
2814 }
2815
2816 //=======================================================================
2817 //function : getClosestUV
2818 //purpose  : return UV of closest projection
2819 //=======================================================================
2820
2821 static bool getClosestUV (Extrema_GenExtPS& projector,
2822                           const gp_Pnt&     point,
2823                           gp_XY &           result)
2824 {
2825   projector.Perform( point );
2826   if ( projector.IsDone() ) {
2827     double u, v, minVal = DBL_MAX;
2828     for ( int i = projector.NbExt(); i > 0; i-- )
2829       if ( projector.Value( i ) < minVal ) {
2830         minVal = projector.Value( i );
2831         projector.Point( i ).Parameter( u, v );
2832       }
2833     result.SetCoord( u, v );
2834     return true;
2835   }
2836   return false;
2837 }
2838
2839 //=======================================================================
2840 //function : Smooth
2841 //purpose  : Smooth theElements during theNbIterations or until a worst
2842 //           element has aspect ratio <= theTgtAspectRatio.
2843 //           Aspect Ratio varies in range [1.0, inf].
2844 //           If theElements is empty, the whole mesh is smoothed.
2845 //           theFixedNodes contains additionally fixed nodes. Nodes built
2846 //           on edges and boundary nodes are always fixed.
2847 //=======================================================================
2848
2849 void SMESH_MeshEditor::Smooth (TIDSortedElemSet &          theElems,
2850                                set<const SMDS_MeshNode*> & theFixedNodes,
2851                                const SmoothMethod          theSmoothMethod,
2852                                const int                   theNbIterations,
2853                                double                      theTgtAspectRatio,
2854                                const bool                  the2D)
2855 {
2856   myLastCreatedElems.Clear();
2857   myLastCreatedNodes.Clear();
2858
2859   MESSAGE((theSmoothMethod==LAPLACIAN ? "LAPLACIAN" : "CENTROIDAL") << "--::Smooth()");
2860
2861   if ( theTgtAspectRatio < 1.0 )
2862     theTgtAspectRatio = 1.0;
2863
2864   const double disttol = 1.e-16;
2865
2866   SMESH::Controls::AspectRatio aQualityFunc;
2867
2868   SMESHDS_Mesh* aMesh = GetMeshDS();
2869
2870   if ( theElems.empty() ) {
2871     // add all faces to theElems
2872     SMDS_FaceIteratorPtr fIt = aMesh->facesIterator();
2873     while ( fIt->more() ) {
2874       const SMDS_MeshElement* face = fIt->next();
2875       theElems.insert( face );
2876     }
2877   }
2878   // get all face ids theElems are on
2879   set< int > faceIdSet;
2880   TIDSortedElemSet::iterator itElem;
2881   if ( the2D )
2882     for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
2883       int fId = FindShape( *itElem );
2884       // check that corresponding submesh exists and a shape is face
2885       if (fId &&
2886           faceIdSet.find( fId ) == faceIdSet.end() &&
2887           aMesh->MeshElements( fId )) {
2888         TopoDS_Shape F = aMesh->IndexToShape( fId );
2889         if ( !F.IsNull() && F.ShapeType() == TopAbs_FACE )
2890           faceIdSet.insert( fId );
2891       }
2892     }
2893   faceIdSet.insert( 0 ); // to smooth elements that are not on any TopoDS_Face
2894
2895   // ===============================================
2896   // smooth elements on each TopoDS_Face separately
2897   // ===============================================
2898
2899   set< int >::reverse_iterator fId = faceIdSet.rbegin(); // treate 0 fId at the end
2900   for ( ; fId != faceIdSet.rend(); ++fId ) {
2901     // get face surface and submesh
2902     Handle(Geom_Surface) surface;
2903     SMESHDS_SubMesh* faceSubMesh = 0;
2904     TopoDS_Face face;
2905     double fToler2 = 0, f,l;
2906     double u1 = 0, u2 = 0, v1 = 0, v2 = 0;
2907     bool isUPeriodic = false, isVPeriodic = false;
2908     if ( *fId ) {
2909       face = TopoDS::Face( aMesh->IndexToShape( *fId ));
2910       surface = BRep_Tool::Surface( face );
2911       faceSubMesh = aMesh->MeshElements( *fId );
2912       fToler2 = BRep_Tool::Tolerance( face );
2913       fToler2 *= fToler2 * 10.;
2914       isUPeriodic = surface->IsUPeriodic();
2915       if ( isUPeriodic )
2916         surface->UPeriod();
2917       isVPeriodic = surface->IsVPeriodic();
2918       if ( isVPeriodic )
2919         surface->VPeriod();
2920       surface->Bounds( u1, u2, v1, v2 );
2921     }
2922     // ---------------------------------------------------------
2923     // for elements on a face, find movable and fixed nodes and
2924     // compute UV for them
2925     // ---------------------------------------------------------
2926     bool checkBoundaryNodes = false;
2927     bool isQuadratic = false;
2928     set<const SMDS_MeshNode*> setMovableNodes;
2929     map< const SMDS_MeshNode*, gp_XY* > uvMap, uvMap2;
2930     list< gp_XY > listUV; // uvs the 2 uvMaps refer to
2931     list< const SMDS_MeshElement* > elemsOnFace;
2932
2933     Extrema_GenExtPS projector;
2934     GeomAdaptor_Surface surfAdaptor;
2935     if ( !surface.IsNull() ) {
2936       surfAdaptor.Load( surface );
2937       projector.Initialize( surfAdaptor, 20,20, 1e-5,1e-5 );
2938     }
2939     int nbElemOnFace = 0;
2940     itElem = theElems.begin();
2941     // loop on not yet smoothed elements: look for elems on a face
2942     while ( itElem != theElems.end() ) {
2943       if ( faceSubMesh && nbElemOnFace == faceSubMesh->NbElements() )
2944         break; // all elements found
2945
2946       const SMDS_MeshElement* elem = *itElem;
2947       if ( !elem || elem->GetType() != SMDSAbs_Face || elem->NbNodes() < 3 ||
2948            ( faceSubMesh && !faceSubMesh->Contains( elem ))) {
2949         ++itElem;
2950         continue;
2951       }
2952       elemsOnFace.push_back( elem );
2953       theElems.erase( itElem++ );
2954       nbElemOnFace++;
2955
2956       if ( !isQuadratic )
2957         isQuadratic = elem->IsQuadratic();
2958
2959       // get movable nodes of elem
2960       const SMDS_MeshNode* node;
2961       SMDS_TypeOfPosition posType;
2962       SMDS_ElemIteratorPtr itN = elem->nodesIterator();
2963       int nn = 0, nbn =  elem->NbNodes();
2964       if(elem->IsQuadratic())
2965         nbn = nbn/2;
2966       while ( nn++ < nbn ) {
2967         node = static_cast<const SMDS_MeshNode*>( itN->next() );
2968         const SMDS_PositionPtr& pos = node->GetPosition();
2969         posType = pos ? pos->GetTypeOfPosition() : SMDS_TOP_3DSPACE;
2970         if (posType != SMDS_TOP_EDGE &&
2971             posType != SMDS_TOP_VERTEX &&
2972             theFixedNodes.find( node ) == theFixedNodes.end())
2973         {
2974           // check if all faces around the node are on faceSubMesh
2975           // because a node on edge may be bound to face
2976           SMDS_ElemIteratorPtr eIt = node->GetInverseElementIterator(SMDSAbs_Face);
2977           bool all = true;
2978           if ( faceSubMesh ) {
2979             while ( eIt->more() && all ) {
2980               const SMDS_MeshElement* e = eIt->next();
2981               all = faceSubMesh->Contains( e );
2982             }
2983           }
2984           if ( all )
2985             setMovableNodes.insert( node );
2986           else
2987             checkBoundaryNodes = true;
2988         }
2989         if ( posType == SMDS_TOP_3DSPACE )
2990           checkBoundaryNodes = true;
2991       }
2992
2993       if ( surface.IsNull() )
2994         continue;
2995
2996       // get nodes to check UV
2997       list< const SMDS_MeshNode* > uvCheckNodes;
2998       itN = elem->nodesIterator();
2999       nn = 0; nbn =  elem->NbNodes();
3000       if(elem->IsQuadratic())
3001         nbn = nbn/2;
3002       while ( nn++ < nbn ) {
3003         node = static_cast<const SMDS_MeshNode*>( itN->next() );
3004         if ( uvMap.find( node ) == uvMap.end() )
3005           uvCheckNodes.push_back( node );
3006         // add nodes of elems sharing node
3007         //         SMDS_ElemIteratorPtr eIt = node->GetInverseElementIterator(SMDSAbs_Face);
3008         //         while ( eIt->more() ) {
3009         //           const SMDS_MeshElement* e = eIt->next();
3010         //           if ( e != elem ) {
3011         //             SMDS_ElemIteratorPtr nIt = e->nodesIterator();
3012         //             while ( nIt->more() ) {
3013         //               const SMDS_MeshNode* n =
3014         //                 static_cast<const SMDS_MeshNode*>( nIt->next() );
3015         //               if ( uvMap.find( n ) == uvMap.end() )
3016         //                 uvCheckNodes.push_back( n );
3017         //             }
3018         //           }
3019         //         }
3020       }
3021       // check UV on face
3022       list< const SMDS_MeshNode* >::iterator n = uvCheckNodes.begin();
3023       for ( ; n != uvCheckNodes.end(); ++n ) {
3024         node = *n;
3025         gp_XY uv( 0, 0 );
3026         const SMDS_PositionPtr& pos = node->GetPosition();
3027         posType = pos ? pos->GetTypeOfPosition() : SMDS_TOP_3DSPACE;
3028         // get existing UV
3029         switch ( posType ) {
3030         case SMDS_TOP_FACE: {
3031           SMDS_FacePosition* fPos = ( SMDS_FacePosition* ) pos;
3032           uv.SetCoord( fPos->GetUParameter(), fPos->GetVParameter() );
3033           break;
3034         }
3035         case SMDS_TOP_EDGE: {
3036           TopoDS_Shape S = aMesh->IndexToShape( node->getshapeId() );
3037           Handle(Geom2d_Curve) pcurve;
3038           if ( !S.IsNull() && S.ShapeType() == TopAbs_EDGE )
3039             pcurve = BRep_Tool::CurveOnSurface( TopoDS::Edge( S ), face, f,l );
3040           if ( !pcurve.IsNull() ) {
3041             double u = (( SMDS_EdgePosition* ) pos )->GetUParameter();
3042             uv = pcurve->Value( u ).XY();
3043           }
3044           break;
3045         }
3046         case SMDS_TOP_VERTEX: {
3047           TopoDS_Shape S = aMesh->IndexToShape( node->getshapeId() );
3048           if ( !S.IsNull() && S.ShapeType() == TopAbs_VERTEX )
3049             uv = BRep_Tool::Parameters( TopoDS::Vertex( S ), face ).XY();
3050           break;
3051         }
3052         default:;
3053         }
3054         // check existing UV
3055         bool project = true;
3056         gp_Pnt pNode ( node->X(), node->Y(), node->Z() );
3057         double dist1 = DBL_MAX, dist2 = 0;
3058         if ( posType != SMDS_TOP_3DSPACE ) {
3059           dist1 = pNode.SquareDistance( surface->Value( uv.X(), uv.Y() ));
3060           project = dist1 > fToler2;
3061         }
3062         if ( project ) { // compute new UV
3063           gp_XY newUV;
3064           if ( !getClosestUV( projector, pNode, newUV )) {
3065             MESSAGE("Node Projection Failed " << node);
3066           }
3067           else {
3068             if ( isUPeriodic )
3069               newUV.SetX( ElCLib::InPeriod( newUV.X(), u1, u2 ));
3070             if ( isVPeriodic )
3071               newUV.SetY( ElCLib::InPeriod( newUV.Y(), v1, v2 ));
3072             // check new UV
3073             if ( posType != SMDS_TOP_3DSPACE )
3074               dist2 = pNode.SquareDistance( surface->Value( newUV.X(), newUV.Y() ));
3075             if ( dist2 < dist1 )
3076               uv = newUV;
3077           }
3078         }
3079         // store UV in the map
3080         listUV.push_back( uv );
3081         uvMap.insert( make_pair( node, &listUV.back() ));
3082       }
3083     } // loop on not yet smoothed elements
3084
3085     if ( !faceSubMesh || nbElemOnFace != faceSubMesh->NbElements() )
3086       checkBoundaryNodes = true;
3087
3088     // fix nodes on mesh boundary
3089
3090     if ( checkBoundaryNodes ) {
3091       map< NLink, int > linkNbMap; // how many times a link encounters in elemsOnFace
3092       map< NLink, int >::iterator link_nb;
3093       // put all elements links to linkNbMap
3094       list< const SMDS_MeshElement* >::iterator elemIt = elemsOnFace.begin();
3095       for ( ; elemIt != elemsOnFace.end(); ++elemIt ) {
3096         const SMDS_MeshElement* elem = (*elemIt);
3097         int nbn =  elem->NbNodes();
3098         if(elem->IsQuadratic())
3099           nbn = nbn/2;
3100         // loop on elem links: insert them in linkNbMap
3101         const SMDS_MeshNode* curNode, *prevNode = elem->GetNodeWrap( nbn );
3102         for ( int iN = 0; iN < nbn; ++iN ) {
3103           curNode = elem->GetNode( iN );
3104           NLink link;
3105           if ( curNode < prevNode ) link = make_pair( curNode , prevNode );
3106           else                      link = make_pair( prevNode , curNode );
3107           prevNode = curNode;
3108           link_nb = linkNbMap.find( link );
3109           if ( link_nb == linkNbMap.end() )
3110             linkNbMap.insert( make_pair ( link, 1 ));
3111           else
3112             link_nb->second++;
3113         }
3114       }
3115       // remove nodes that are in links encountered only once from setMovableNodes
3116       for ( link_nb = linkNbMap.begin(); link_nb != linkNbMap.end(); ++link_nb ) {
3117         if ( link_nb->second == 1 ) {
3118           setMovableNodes.erase( link_nb->first.first );
3119           setMovableNodes.erase( link_nb->first.second );
3120         }
3121       }
3122     }
3123
3124     // -----------------------------------------------------
3125     // for nodes on seam edge, compute one more UV ( uvMap2 );
3126     // find movable nodes linked to nodes on seam and which
3127     // are to be smoothed using the second UV ( uvMap2 )
3128     // -----------------------------------------------------
3129
3130     set<const SMDS_MeshNode*> nodesNearSeam; // to smooth using uvMap2
3131     if ( !surface.IsNull() ) {
3132       TopExp_Explorer eExp( face, TopAbs_EDGE );
3133       for ( ; eExp.More(); eExp.Next() ) {
3134         TopoDS_Edge edge = TopoDS::Edge( eExp.Current() );
3135         if ( !BRep_Tool::IsClosed( edge, face ))
3136           continue;
3137         SMESHDS_SubMesh* sm = aMesh->MeshElements( edge );
3138         if ( !sm ) continue;
3139         // find out which parameter varies for a node on seam
3140         double f,l;
3141         gp_Pnt2d uv1, uv2;
3142         Handle(Geom2d_Curve) pcurve = BRep_Tool::CurveOnSurface( edge, face, f, l );
3143         if ( pcurve.IsNull() ) continue;
3144         uv1 = pcurve->Value( f );
3145         edge.Reverse();
3146         pcurve = BRep_Tool::CurveOnSurface( edge, face, f, l );
3147         if ( pcurve.IsNull() ) continue;
3148         uv2 = pcurve->Value( f );
3149         int iPar = Abs( uv1.X() - uv2.X() ) > Abs( uv1.Y() - uv2.Y() ) ? 1 : 2;
3150         // assure uv1 < uv2
3151         if ( uv1.Coord( iPar ) > uv2.Coord( iPar )) {
3152           gp_Pnt2d tmp = uv1; uv1 = uv2; uv2 = tmp;
3153         }
3154         // get nodes on seam and its vertices
3155         list< const SMDS_MeshNode* > seamNodes;
3156         SMDS_NodeIteratorPtr nSeamIt = sm->GetNodes();
3157         while ( nSeamIt->more() ) {
3158           const SMDS_MeshNode* node = nSeamIt->next();
3159           if ( !isQuadratic || !IsMedium( node ))
3160             seamNodes.push_back( node );
3161         }
3162         TopExp_Explorer vExp( edge, TopAbs_VERTEX );
3163         for ( ; vExp.More(); vExp.Next() ) {
3164           sm = aMesh->MeshElements( vExp.Current() );
3165           if ( sm ) {
3166             nSeamIt = sm->GetNodes();
3167             while ( nSeamIt->more() )
3168               seamNodes.push_back( nSeamIt->next() );
3169           }
3170         }
3171         // loop on nodes on seam
3172         list< const SMDS_MeshNode* >::iterator noSeIt = seamNodes.begin();
3173         for ( ; noSeIt != seamNodes.end(); ++noSeIt ) {
3174           const SMDS_MeshNode* nSeam = *noSeIt;
3175           map< const SMDS_MeshNode*, gp_XY* >::iterator n_uv = uvMap.find( nSeam );
3176           if ( n_uv == uvMap.end() )
3177             continue;
3178           // set the first UV
3179           n_uv->second->SetCoord( iPar, uv1.Coord( iPar ));
3180           // set the second UV
3181           listUV.push_back( *n_uv->second );
3182           listUV.back().SetCoord( iPar, uv2.Coord( iPar ));
3183           if ( uvMap2.empty() )
3184             uvMap2 = uvMap; // copy the uvMap contents
3185           uvMap2[ nSeam ] = &listUV.back();
3186
3187           // collect movable nodes linked to ones on seam in nodesNearSeam
3188           SMDS_ElemIteratorPtr eIt = nSeam->GetInverseElementIterator(SMDSAbs_Face);
3189           while ( eIt->more() ) {
3190             const SMDS_MeshElement* e = eIt->next();
3191             int nbUseMap1 = 0, nbUseMap2 = 0;
3192             SMDS_ElemIteratorPtr nIt = e->nodesIterator();
3193             int nn = 0, nbn =  e->NbNodes();
3194             if(e->IsQuadratic()) nbn = nbn/2;
3195             while ( nn++ < nbn )
3196             {
3197               const SMDS_MeshNode* n =
3198                 static_cast<const SMDS_MeshNode*>( nIt->next() );
3199               if (n == nSeam ||
3200                   setMovableNodes.find( n ) == setMovableNodes.end() )
3201                 continue;
3202               // add only nodes being closer to uv2 than to uv1
3203               gp_Pnt pMid (0.5 * ( n->X() + nSeam->X() ),
3204                            0.5 * ( n->Y() + nSeam->Y() ),
3205                            0.5 * ( n->Z() + nSeam->Z() ));
3206               gp_XY uv;
3207               getClosestUV( projector, pMid, uv );
3208               if ( uv.Coord( iPar ) > uvMap[ n ]->Coord( iPar ) ) {
3209                 nodesNearSeam.insert( n );
3210                 nbUseMap2++;
3211               }
3212               else
3213                 nbUseMap1++;
3214             }
3215             // for centroidalSmooth all element nodes must
3216             // be on one side of a seam
3217             if ( theSmoothMethod == CENTROIDAL && nbUseMap1 && nbUseMap2 ) {
3218               SMDS_ElemIteratorPtr nIt = e->nodesIterator();
3219               nn = 0;
3220               while ( nn++ < nbn ) {
3221                 const SMDS_MeshNode* n =
3222                   static_cast<const SMDS_MeshNode*>( nIt->next() );
3223                 setMovableNodes.erase( n );
3224               }
3225             }
3226           }
3227         } // loop on nodes on seam
3228       } // loop on edge of a face
3229     } // if ( !face.IsNull() )
3230
3231     if ( setMovableNodes.empty() ) {
3232       MESSAGE( "Face id : " << *fId << " - NO SMOOTHING: no nodes to move!!!");
3233       continue; // goto next face
3234     }
3235
3236     // -------------
3237     // SMOOTHING //
3238     // -------------
3239
3240     int it = -1;
3241     double maxRatio = -1., maxDisplacement = -1.;
3242     set<const SMDS_MeshNode*>::iterator nodeToMove;
3243     for ( it = 0; it < theNbIterations; it++ ) {
3244       maxDisplacement = 0.;
3245       nodeToMove = setMovableNodes.begin();
3246       for ( ; nodeToMove != setMovableNodes.end(); nodeToMove++ ) {
3247         const SMDS_MeshNode* node = (*nodeToMove);
3248         gp_XYZ aPrevPos ( node->X(), node->Y(), node->Z() );
3249
3250         // smooth
3251         bool map2 = ( nodesNearSeam.find( node ) != nodesNearSeam.end() );
3252         if ( theSmoothMethod == LAPLACIAN )
3253           laplacianSmooth( node, surface, map2 ? uvMap2 : uvMap );
3254         else
3255           centroidalSmooth( node, surface, map2 ? uvMap2 : uvMap );
3256
3257         // node displacement
3258         gp_XYZ aNewPos ( node->X(), node->Y(), node->Z() );
3259         Standard_Real aDispl = (aPrevPos - aNewPos).SquareModulus();
3260         if ( aDispl > maxDisplacement )
3261           maxDisplacement = aDispl;
3262       }
3263       // no node movement => exit
3264       //if ( maxDisplacement < 1.e-16 ) {
3265       if ( maxDisplacement < disttol ) {
3266         MESSAGE("-- no node movement --");
3267         break;
3268       }
3269
3270       // check elements quality
3271       maxRatio  = 0;
3272       list< const SMDS_MeshElement* >::iterator elemIt = elemsOnFace.begin();
3273       for ( ; elemIt != elemsOnFace.end(); ++elemIt ) {
3274         const SMDS_MeshElement* elem = (*elemIt);
3275         if ( !elem || elem->GetType() != SMDSAbs_Face )
3276           continue;
3277         SMESH::Controls::TSequenceOfXYZ aPoints;
3278         if ( aQualityFunc.GetPoints( elem, aPoints )) {
3279           double aValue = aQualityFunc.GetValue( aPoints );
3280           if ( aValue > maxRatio )
3281             maxRatio = aValue;
3282         }
3283       }
3284       if ( maxRatio <= theTgtAspectRatio ) {
3285         MESSAGE("-- quality achived --");
3286         break;
3287       }
3288       if (it+1 == theNbIterations) {
3289         MESSAGE("-- Iteration limit exceeded --");
3290       }
3291     } // smoothing iterations
3292
3293     MESSAGE(" Face id: " << *fId <<
3294             " Nb iterstions: " << it <<
3295             " Displacement: " << maxDisplacement <<
3296             " Aspect Ratio " << maxRatio);
3297
3298     // ---------------------------------------
3299     // new nodes positions are computed,
3300     // record movement in DS and set new UV
3301     // ---------------------------------------
3302     nodeToMove = setMovableNodes.begin();
3303     for ( ; nodeToMove != setMovableNodes.end(); nodeToMove++ ) {
3304       SMDS_MeshNode* node = const_cast< SMDS_MeshNode* > (*nodeToMove);
3305       aMesh->MoveNode( node, node->X(), node->Y(), node->Z() );
3306       map< const SMDS_MeshNode*, gp_XY* >::iterator node_uv = uvMap.find( node );
3307       if ( node_uv != uvMap.end() ) {
3308         gp_XY* uv = node_uv->second;
3309         node->SetPosition
3310           ( SMDS_PositionPtr( new SMDS_FacePosition( uv->X(), uv->Y() )));
3311       }
3312     }
3313
3314     // move medium nodes of quadratic elements
3315     if ( isQuadratic )
3316     {
3317       SMESH_MesherHelper helper( *GetMesh() );
3318       if ( !face.IsNull() )
3319         helper.SetSubShape( face );
3320       list< const SMDS_MeshElement* >::iterator elemIt = elemsOnFace.begin();
3321       for ( ; elemIt != elemsOnFace.end(); ++elemIt ) {
3322         const SMDS_VtkFace* QF =
3323           dynamic_cast<const SMDS_VtkFace*> (*elemIt);
3324         if(QF && QF->IsQuadratic()) {
3325           vector<const SMDS_MeshNode*> Ns;
3326           Ns.reserve(QF->NbNodes()+1);
3327           SMDS_ElemIteratorPtr anIter = QF->interlacedNodesElemIterator();
3328           while ( anIter->more() )
3329             Ns.push_back( cast2Node(anIter->next()) );
3330           Ns.push_back( Ns[0] );
3331           double x, y, z;
3332           for(int i=0; i<QF->NbNodes(); i=i+2) {
3333             if ( !surface.IsNull() ) {
3334               gp_XY uv1 = helper.GetNodeUV( face, Ns[i], Ns[i+2] );
3335               gp_XY uv2 = helper.GetNodeUV( face, Ns[i+2], Ns[i] );
3336               gp_XY uv = ( uv1 + uv2 ) / 2.;
3337               gp_Pnt xyz = surface->Value( uv.X(), uv.Y() );
3338               x = xyz.X(); y = xyz.Y(); z = xyz.Z();
3339             }
3340             else {
3341               x = (Ns[i]->X() + Ns[i+2]->X())/2;
3342               y = (Ns[i]->Y() + Ns[i+2]->Y())/2;
3343               z = (Ns[i]->Z() + Ns[i+2]->Z())/2;
3344             }
3345             if( fabs( Ns[i+1]->X() - x ) > disttol ||
3346                 fabs( Ns[i+1]->Y() - y ) > disttol ||
3347                 fabs( Ns[i+1]->Z() - z ) > disttol ) {
3348               // we have to move i+1 node
3349               aMesh->MoveNode( Ns[i+1], x, y, z );
3350             }
3351           }
3352         }
3353       }
3354     }
3355
3356   } // loop on face ids
3357
3358 }
3359
3360 //=======================================================================
3361 //function : isReverse
3362 //purpose  : Return true if normal of prevNodes is not co-directied with
3363 //           gp_Vec(prevNodes[iNotSame],nextNodes[iNotSame]).
3364 //           iNotSame is where prevNodes and nextNodes are different
3365 //=======================================================================
3366
3367 static bool isReverse(vector<const SMDS_MeshNode*> prevNodes,
3368                       vector<const SMDS_MeshNode*> nextNodes,
3369                       const int            nbNodes,
3370                       const int            iNotSame)
3371 {
3372   int iBeforeNotSame = ( iNotSame == 0 ? nbNodes - 1 : iNotSame - 1 );
3373   int iAfterNotSame  = ( iNotSame + 1 == nbNodes ? 0 : iNotSame + 1 );
3374
3375   const SMDS_MeshNode* nB = prevNodes[ iBeforeNotSame ];
3376   const SMDS_MeshNode* nA = prevNodes[ iAfterNotSame ];
3377   const SMDS_MeshNode* nP = prevNodes[ iNotSame ];
3378   const SMDS_MeshNode* nN = nextNodes[ iNotSame ];
3379
3380   gp_Pnt pB ( nB->X(), nB->Y(), nB->Z() );
3381   gp_Pnt pA ( nA->X(), nA->Y(), nA->Z() );
3382   gp_Pnt pP ( nP->X(), nP->Y(), nP->Z() );
3383   gp_Pnt pN ( nN->X(), nN->Y(), nN->Z() );
3384
3385   gp_Vec vB ( pP, pB ), vA ( pP, pA ), vN ( pP, pN );
3386
3387   return (vA ^ vB) * vN < 0.0;
3388 }
3389
3390 //=======================================================================
3391 /*!
3392  * \brief Create elements by sweeping an element
3393  * \param elem - element to sweep
3394  * \param newNodesItVec - nodes generated from each node of the element
3395  * \param newElems - generated elements
3396  * \param nbSteps - number of sweeping steps
3397  * \param srcElements - to append elem for each generated element
3398  */
3399 //=======================================================================
3400
3401 void SMESH_MeshEditor::sweepElement(const SMDS_MeshElement*               elem,
3402                                     const vector<TNodeOfNodeListMapItr> & newNodesItVec,
3403                                     list<const SMDS_MeshElement*>&        newElems,
3404                                     const int                             nbSteps,
3405                                     SMESH_SequenceOfElemPtr&              srcElements)
3406 {
3407   //MESSAGE("sweepElement " << nbSteps);
3408   SMESHDS_Mesh* aMesh = GetMeshDS();
3409
3410   // Loop on elem nodes:
3411   // find new nodes and detect same nodes indices
3412   int nbNodes = elem->NbNodes();
3413   vector < list< const SMDS_MeshNode* >::const_iterator > itNN( nbNodes );
3414   vector<const SMDS_MeshNode*> prevNod( nbNodes );
3415   vector<const SMDS_MeshNode*> nextNod( nbNodes );
3416   vector<const SMDS_MeshNode*> midlNod( nbNodes );
3417
3418   int iNode, nbSame = 0, iNotSameNode = 0, iSameNode = 0;
3419   vector<int> sames(nbNodes);
3420   vector<bool> issimple(nbNodes);
3421
3422   for ( iNode = 0; iNode < nbNodes; iNode++ ) {
3423     TNodeOfNodeListMapItr nnIt = newNodesItVec[ iNode ];
3424     const SMDS_MeshNode*                 node         = nnIt->first;
3425     const list< const SMDS_MeshNode* > & listNewNodes = nnIt->second;
3426     if ( listNewNodes.empty() ) {
3427       return;
3428     }
3429
3430     issimple[iNode] = (listNewNodes.size()==nbSteps); // is node medium
3431
3432     itNN[ iNode ] = listNewNodes.begin();
3433     prevNod[ iNode ] = node;
3434     nextNod[ iNode ] = listNewNodes.front();
3435     if( !elem->IsQuadratic() || !issimple[iNode] ) {
3436       if ( prevNod[ iNode ] != nextNod [ iNode ])
3437         iNotSameNode = iNode;
3438       else {
3439         iSameNode = iNode;
3440         //nbSame++;
3441         sames[nbSame++] = iNode;
3442       }
3443     }
3444   }
3445
3446   //cerr<<"  nbSame = "<<nbSame<<endl;
3447   if ( nbSame == nbNodes || nbSame > 2) {
3448     MESSAGE( " Too many same nodes of element " << elem->GetID() );
3449     //INFOS( " Too many same nodes of element " << elem->GetID() );
3450     return;
3451   }
3452
3453   //  if( elem->IsQuadratic() && nbSame>0 ) {
3454   //    MESSAGE( "Can not rotate quadratic element " << elem->GetID() );
3455   //    return;
3456   //  }
3457
3458   int iBeforeSame = 0, iAfterSame = 0, iOpposSame = 0;
3459   int nbBaseNodes = ( elem->IsQuadratic() ? nbNodes/2 : nbNodes );
3460   if ( nbSame > 0 ) {
3461     iBeforeSame = ( iSameNode == 0 ? nbBaseNodes - 1 : iSameNode - 1 );
3462     iAfterSame  = ( iSameNode + 1 == nbBaseNodes ? 0 : iSameNode + 1 );
3463     iOpposSame  = ( iSameNode - 2 < 0  ? iSameNode + 2 : iSameNode - 2 );
3464   }
3465
3466   //if(nbNodes==8)
3467   //cout<<" prevNod[0]="<< prevNod[0]<<" prevNod[1]="<< prevNod[1]
3468   //    <<" prevNod[2]="<< prevNod[2]<<" prevNod[3]="<< prevNod[4]
3469   //    <<" prevNod[4]="<< prevNod[4]<<" prevNod[5]="<< prevNod[5]
3470   //    <<" prevNod[6]="<< prevNod[6]<<" prevNod[7]="<< prevNod[7]<<endl;
3471
3472   // check element orientation
3473   int i0 = 0, i2 = 2;
3474   if ( nbNodes > 2 && !isReverse( prevNod, nextNod, nbNodes, iNotSameNode )) {
3475     //MESSAGE("Reversed elem " << elem );
3476     i0 = 2;
3477     i2 = 0;
3478     if ( nbSame > 0 )
3479       std::swap( iBeforeSame, iAfterSame );
3480   }
3481
3482   // make new elements
3483   const SMDS_MeshElement* lastElem = elem;
3484   for (int iStep = 0; iStep < nbSteps; iStep++ ) {
3485     // get next nodes
3486     for ( iNode = 0; iNode < nbNodes; iNode++ ) {
3487       if(issimple[iNode]) {
3488         nextNod[ iNode ] = *itNN[ iNode ];
3489         itNN[ iNode ]++;
3490       }
3491       else {
3492         if( elem->GetType()==SMDSAbs_Node ) {
3493           // we have to use two nodes
3494           midlNod[ iNode ] = *itNN[ iNode ];
3495           itNN[ iNode ]++;
3496           nextNod[ iNode ] = *itNN[ iNode ];
3497           itNN[ iNode ]++;
3498         }
3499         else if(!elem->IsQuadratic() || lastElem->IsMediumNode(prevNod[iNode]) ) {
3500           // we have to use each second node
3501           //itNN[ iNode ]++;
3502           nextNod[ iNode ] = *itNN[ iNode ];
3503           itNN[ iNode ]++;
3504         }
3505         else {
3506           // we have to use two nodes
3507           midlNod[ iNode ] = *itNN[ iNode ];
3508           itNN[ iNode ]++;
3509           nextNod[ iNode ] = *itNN[ iNode ];
3510           itNN[ iNode ]++;
3511         }
3512       }
3513     }
3514     SMDS_MeshElement* aNewElem = 0;
3515     if(!elem->IsPoly()) {
3516       switch ( nbNodes ) {
3517       case 0:
3518         return;
3519       case 1: { // NODE
3520         if ( nbSame == 0 ) {
3521           if(issimple[0])
3522             aNewElem = aMesh->AddEdge( prevNod[ 0 ], nextNod[ 0 ] );
3523           else
3524             aNewElem = aMesh->AddEdge( prevNod[ 0 ], nextNod[ 0 ], midlNod[ 0 ] );
3525         }
3526         break;
3527       }
3528       case 2: { // EDGE
3529         if ( nbSame == 0 )
3530           aNewElem = aMesh->AddFace(prevNod[ 0 ], prevNod[ 1 ],
3531                                     nextNod[ 1 ], nextNod[ 0 ] );
3532         else
3533           aNewElem = aMesh->AddFace(prevNod[ 0 ], prevNod[ 1 ],
3534                                     nextNod[ iNotSameNode ] );
3535         break;
3536       }
3537
3538       case 3: { // TRIANGLE or quadratic edge
3539         if(elem->GetType() == SMDSAbs_Face) { // TRIANGLE
3540
3541           if ( nbSame == 0 )       // --- pentahedron
3542             aNewElem = aMesh->AddVolume (prevNod[ i0 ], prevNod[ 1 ], prevNod[ i2 ],
3543                                          nextNod[ i0 ], nextNod[ 1 ], nextNod[ i2 ] );
3544
3545           else if ( nbSame == 1 )  // --- pyramid
3546             aNewElem = aMesh->AddVolume (prevNod[ iBeforeSame ],  prevNod[ iAfterSame ],
3547                                          nextNod[ iAfterSame ], nextNod[ iBeforeSame ],
3548                                          nextNod[ iSameNode ]);
3549
3550           else // 2 same nodes:      --- tetrahedron
3551             aNewElem = aMesh->AddVolume (prevNod[ i0 ], prevNod[ 1 ], prevNod[ i2 ],
3552                                          nextNod[ iNotSameNode ]);
3553         }
3554         else { // quadratic edge
3555           if(nbSame==0) {     // quadratic quadrangle
3556             aNewElem = aMesh->AddFace(prevNod[0], nextNod[0], nextNod[1], prevNod[1],
3557                                       midlNod[0], nextNod[2], midlNod[1], prevNod[2]);
3558           }
3559           else if(nbSame==1) { // quadratic triangle
3560             if(sames[0]==2) {
3561               return; // medium node on axis
3562             }
3563             else if(sames[0]==0) {
3564               aNewElem = aMesh->AddFace(prevNod[0], nextNod[1], prevNod[1],
3565                                         nextNod[2], midlNod[1], prevNod[2]);
3566             }
3567             else { // sames[0]==1
3568               aNewElem = aMesh->AddFace(prevNod[0], nextNod[0], prevNod[1],
3569                                         midlNod[0], nextNod[2], prevNod[2]);
3570             }
3571           }
3572           else {
3573             return;
3574           }
3575         }
3576         break;
3577       }
3578       case 4: { // QUADRANGLE
3579
3580         if ( nbSame == 0 )       // --- hexahedron
3581           aNewElem = aMesh->AddVolume (prevNod[ i0 ], prevNod[ 1 ], prevNod[ i2 ], prevNod[ 3 ],
3582                                        nextNod[ i0 ], nextNod[ 1 ], nextNod[ i2 ], nextNod[ 3 ]);
3583
3584         else if ( nbSame == 1 ) { // --- pyramid + pentahedron
3585           aNewElem = aMesh->AddVolume (prevNod[ iBeforeSame ],  prevNod[ iAfterSame ],
3586                                        nextNod[ iAfterSame ], nextNod[ iBeforeSame ],
3587                                        nextNod[ iSameNode ]);
3588           newElems.push_back( aNewElem );
3589           aNewElem = aMesh->AddVolume (prevNod[ iAfterSame ], prevNod[ iOpposSame ],
3590                                        prevNod[ iBeforeSame ],  nextNod[ iAfterSame ],
3591                                        nextNod[ iOpposSame ],  nextNod[ iBeforeSame ] );
3592         }
3593         else if ( nbSame == 2 ) { // pentahedron
3594           if ( prevNod[ iBeforeSame ] == nextNod[ iBeforeSame ] )
3595             // iBeforeSame is same too
3596             aNewElem = aMesh->AddVolume (prevNod[ iBeforeSame ], prevNod[ iOpposSame ],
3597                                          nextNod[ iOpposSame ], prevNod[ iSameNode ],
3598                                          prevNod[ iAfterSame ],  nextNod[ iAfterSame ]);
3599           else
3600             // iAfterSame is same too
3601             aNewElem = aMesh->AddVolume (prevNod[ iSameNode ], prevNod[ iBeforeSame ],
3602                                          nextNod[ iBeforeSame ], prevNod[ iAfterSame ],
3603                                          prevNod[ iOpposSame ],  nextNod[ iOpposSame ]);
3604         }
3605         break;
3606       }
3607       case 6: { // quadratic triangle
3608         // create pentahedron with 15 nodes
3609         if(nbSame==0) {
3610           if(i0>0) { // reversed case
3611             aNewElem = aMesh->AddVolume (prevNod[0], prevNod[2], prevNod[1],
3612                                          nextNod[0], nextNod[2], nextNod[1],
3613                                          prevNod[5], prevNod[4], prevNod[3],
3614                                          nextNod[5], nextNod[4], nextNod[3],
3615                                          midlNod[0], midlNod[2], midlNod[1]);
3616           }
3617           else { // not reversed case
3618             aNewElem = aMesh->AddVolume (prevNod[0], prevNod[1], prevNod[2],
3619                                          nextNod[0], nextNod[1], nextNod[2],
3620                                          prevNod[3], prevNod[4], prevNod[5],
3621                                          nextNod[3], nextNod[4], nextNod[5],
3622                                          midlNod[0], midlNod[1], midlNod[2]);
3623           }
3624         }
3625         else if(nbSame==1) {
3626           // 2d order pyramid of 13 nodes
3627           //SMDS_MeshVolume* AddVolumeWithID(int n1, int n2, int n3, int n4, int n5,
3628           //                                 int n12,int n23,int n34,int n41,
3629           //                                 int n15,int n25,int n35,int n45, int ID);
3630           int n5 = iSameNode;
3631           int n1,n4,n41,n15,n45;
3632           if(i0>0) { // reversed case
3633             n1 = ( n5 + 1 == nbBaseNodes ? 0 : n5 + 1 );
3634             n4 = ( n5 == 0 ? nbBaseNodes - 1 : n5 - 1 );
3635             n41 = n1 + 3;
3636             n15 = n5 + 3;
3637             n45 = n4 + 3;
3638           }
3639           else {
3640             n1 = ( n5 == 0 ? nbBaseNodes - 1 : n5 - 1 );
3641             n4 = ( n5 + 1 == nbBaseNodes ? 0 : n5 + 1 );
3642             n41 = n4 + 3;
3643             n15 = n1 + 3;
3644             n45 = n5 + 3;
3645           }
3646           aNewElem = aMesh->AddVolume(prevNod[n1], nextNod[n1],
3647                                       nextNod[n4], prevNod[n4], prevNod[n5],
3648                                       midlNod[n1], nextNod[n41],
3649                                       midlNod[n4], prevNod[n41],
3650                                       prevNod[n15], nextNod[n15],
3651                                       nextNod[n45], prevNod[n45]);
3652         }
3653         else if(nbSame==2) {
3654           // 2d order tetrahedron of 10 nodes
3655           //SMDS_MeshVolume* AddVolumeWithID(int n1, int n2, int n3, int n4,
3656           //                                 int n12,int n23,int n31,
3657           //                                 int n14,int n24,int n34, int ID);
3658           int n1 = iNotSameNode;
3659           int n2,n3,n12,n23,n31;
3660           if(i0>0) { // reversed case
3661             n2 = ( n1 == 0 ? nbBaseNodes - 1 : n1 - 1 );
3662             n3 = ( n1 + 1 == nbBaseNodes ? 0 : n1 + 1 );
3663             n12 = n2 + 3;
3664             n23 = n3 + 3;
3665             n31 = n1 + 3;
3666           }
3667           else {
3668             n2 = ( n1 + 1 == nbBaseNodes ? 0 : n1 + 1 );
3669             n3 = ( n1 == 0 ? nbBaseNodes - 1 : n1 - 1 );
3670             n12 = n1 + 3;
3671             n23 = n2 + 3;
3672             n31 = n3 + 3;
3673           }
3674           aNewElem = aMesh->AddVolume (prevNod[n1], prevNod[n2], prevNod[n3], nextNod[n1],
3675                                        prevNod[n12], prevNod[n23], prevNod[n31],
3676                                        midlNod[n1], nextNod[n12], nextNod[n31]);
3677         }
3678         break;
3679       }
3680       case 8: { // quadratic quadrangle
3681         if(nbSame==0) {
3682           // create hexahedron with 20 nodes
3683           if(i0>0) { // reversed case
3684             aNewElem = aMesh->AddVolume (prevNod[0], prevNod[3], prevNod[2], prevNod[1],
3685                                          nextNod[0], nextNod[3], nextNod[2], nextNod[1],
3686                                          prevNod[7], prevNod[6], prevNod[5], prevNod[4],
3687                                          nextNod[7], nextNod[6], nextNod[5], nextNod[4],
3688                                          midlNod[0], midlNod[3], midlNod[2], midlNod[1]);
3689           }
3690           else { // not reversed case
3691             aNewElem = aMesh->AddVolume (prevNod[0], prevNod[1], prevNod[2], prevNod[3],
3692                                          nextNod[0], nextNod[1], nextNod[2], nextNod[3],
3693                                          prevNod[4], prevNod[5], prevNod[6], prevNod[7],
3694                                          nextNod[4], nextNod[5], nextNod[6], nextNod[7],
3695                                          midlNod[0], midlNod[1], midlNod[2], midlNod[3]);
3696           }
3697         }
3698         else if(nbSame==1) { 
3699           // --- pyramid + pentahedron - can not be created since it is needed 
3700           // additional middle node ot the center of face
3701           INFOS( " Sweep for face " << elem->GetID() << " can not be created" );
3702           return;
3703         }
3704         else if(nbSame==2) {
3705           // 2d order Pentahedron with 15 nodes
3706           //SMDS_MeshVolume* AddVolumeWithID(int n1, int n2, int n3, int n4, int n5, int n6,
3707           //                                 int n12,int n23,int n31,int n45,int n56,int n64,
3708           //                                 int n14,int n25,int n36, int ID);
3709           int n1,n2,n4,n5;
3710           if ( prevNod[ iBeforeSame ] == nextNod[ iBeforeSame ] ) {
3711             // iBeforeSame is same too
3712             n1 = iBeforeSame;
3713             n2 = iOpposSame;
3714             n4 = iSameNode;
3715             n5 = iAfterSame;
3716           }
3717           else {
3718             // iAfterSame is same too
3719             n1 = iSameNode;
3720             n2 = iBeforeSame;
3721             n4 = iAfterSame;
3722             n5 = iOpposSame;
3723           }
3724           int n12,n45,n14,n25;
3725           if(i0>0) { //reversed case
3726             n12 = n1 + 4;
3727             n45 = n5 + 4;
3728             n14 = n4 + 4;
3729             n25 = n2 + 4;
3730           }
3731           else {
3732             n12 = n2 + 4;
3733             n45 = n4 + 4;
3734             n14 = n1 + 4;
3735             n25 = n5 + 4;
3736           }
3737           aNewElem = aMesh->AddVolume (prevNod[n1], prevNod[n2], nextNod[n2],
3738                                        prevNod[n4], prevNod[n5], nextNod[n5],
3739                                        prevNod[n12], midlNod[n2], nextNod[n12],
3740                                        prevNod[n45], midlNod[n5], nextNod[n45],
3741                                        prevNod[n14], prevNod[n25], nextNod[n25]);
3742         }
3743         break;
3744       }
3745       default: {
3746         // realized for extrusion only
3747         //vector<const SMDS_MeshNode*> polyedre_nodes (nbNodes*2 + 4*nbNodes);
3748         //vector<int> quantities (nbNodes + 2);
3749
3750         //quantities[0] = nbNodes; // bottom of prism
3751         //for (int inode = 0; inode < nbNodes; inode++) {
3752         //  polyedre_nodes[inode] = prevNod[inode];
3753         //}
3754
3755         //quantities[1] = nbNodes; // top of prism
3756         //for (int inode = 0; inode < nbNodes; inode++) {
3757         //  polyedre_nodes[nbNodes + inode] = nextNod[inode];
3758         //}
3759
3760         //for (int iface = 0; iface < nbNodes; iface++) {
3761         //  quantities[iface + 2] = 4;
3762         //  int inextface = (iface == nbNodes - 1) ? 0 : iface + 1;
3763         //  polyedre_nodes[2*nbNodes + 4*iface + 0] = prevNod[iface];
3764         //  polyedre_nodes[2*nbNodes + 4*iface + 1] = prevNod[inextface];
3765         //  polyedre_nodes[2*nbNodes + 4*iface + 2] = nextNod[inextface];
3766         //  polyedre_nodes[2*nbNodes + 4*iface + 3] = nextNod[iface];
3767         //}
3768         //aNewElem = aMesh->AddPolyhedralVolume (polyedre_nodes, quantities);
3769         break;
3770       }
3771       }
3772     }
3773
3774     if(!aNewElem) {
3775       // realized for extrusion only
3776       vector<const SMDS_MeshNode*> polyedre_nodes (nbNodes*2 + 4*nbNodes);
3777       vector<int> quantities (nbNodes + 2);
3778
3779       quantities[0] = nbNodes; // bottom of prism
3780       for (int inode = 0; inode < nbNodes; inode++) {
3781         polyedre_nodes[inode] = prevNod[inode];
3782       }
3783
3784       quantities[1] = nbNodes; // top of prism
3785       for (int inode = 0; inode < nbNodes; inode++) {
3786         polyedre_nodes[nbNodes + inode] = nextNod[inode];
3787       }
3788
3789       for (int iface = 0; iface < nbNodes; iface++) {
3790         quantities[iface + 2] = 4;
3791         int inextface = (iface == nbNodes - 1) ? 0 : iface + 1;
3792         polyedre_nodes[2*nbNodes + 4*iface + 0] = prevNod[iface];
3793         polyedre_nodes[2*nbNodes + 4*iface + 1] = prevNod[inextface];
3794         polyedre_nodes[2*nbNodes + 4*iface + 2] = nextNod[inextface];
3795         polyedre_nodes[2*nbNodes + 4*iface + 3] = nextNod[iface];
3796       }
3797       aNewElem = aMesh->AddPolyhedralVolume (polyedre_nodes, quantities);
3798     }
3799
3800     if ( aNewElem ) {
3801       newElems.push_back( aNewElem );
3802       myLastCreatedElems.Append(aNewElem);
3803       srcElements.Append( elem );
3804       lastElem = aNewElem;
3805     }
3806
3807     // set new prev nodes
3808     for ( iNode = 0; iNode < nbNodes; iNode++ )
3809       prevNod[ iNode ] = nextNod[ iNode ];
3810
3811   } // for steps
3812 }
3813
3814 //=======================================================================
3815 /*!
3816  * \brief Create 1D and 2D elements around swept elements
3817  * \param mapNewNodes - source nodes and ones generated from them
3818  * \param newElemsMap - source elements and ones generated from them
3819  * \param elemNewNodesMap - nodes generated from each node of each element
3820  * \param elemSet - all swept elements
3821  * \param nbSteps - number of sweeping steps
3822  * \param srcElements - to append elem for each generated element
3823  */
3824 //=======================================================================
3825
3826 void SMESH_MeshEditor::makeWalls (TNodeOfNodeListMap &     mapNewNodes,
3827                                   TElemOfElemListMap &     newElemsMap,
3828                                   TElemOfVecOfNnlmiMap &   elemNewNodesMap,
3829                                   TIDSortedElemSet&        elemSet,
3830                                   const int                nbSteps,
3831                                   SMESH_SequenceOfElemPtr& srcElements)
3832 {
3833   MESSAGE("makeWalls");
3834   ASSERT( newElemsMap.size() == elemNewNodesMap.size() );
3835   SMESHDS_Mesh* aMesh = GetMeshDS();
3836
3837   // Find nodes belonging to only one initial element - sweep them to get edges.
3838
3839   TNodeOfNodeListMapItr nList = mapNewNodes.begin();
3840   for ( ; nList != mapNewNodes.end(); nList++ ) {
3841     const SMDS_MeshNode* node =
3842       static_cast<const SMDS_MeshNode*>( nList->first );
3843     SMDS_ElemIteratorPtr eIt = node->GetInverseElementIterator();
3844     int nbInitElems = 0;
3845     const SMDS_MeshElement* el = 0;
3846     SMDSAbs_ElementType highType = SMDSAbs_Edge; // count most complex elements only
3847     while ( eIt->more() && nbInitElems < 2 ) {
3848       el = eIt->next();
3849       SMDSAbs_ElementType type = el->GetType();
3850       if ( type == SMDSAbs_Volume || type < highType ) continue;
3851       if ( type > highType ) {
3852         nbInitElems = 0;
3853         highType = type;
3854       }
3855       if ( elemSet.find(el) != elemSet.end() )
3856         nbInitElems++;
3857     }
3858     if ( nbInitElems < 2 ) {
3859       bool NotCreateEdge = el && el->IsQuadratic() && el->IsMediumNode(node);
3860       if(!NotCreateEdge) {
3861         vector<TNodeOfNodeListMapItr> newNodesItVec( 1, nList );
3862         list<const SMDS_MeshElement*> newEdges;
3863         sweepElement( node, newNodesItVec, newEdges, nbSteps, srcElements );
3864       }
3865     }
3866   }
3867
3868   // Make a ceiling for each element ie an equal element of last new nodes.
3869   // Find free links of faces - make edges and sweep them into faces.
3870
3871   TElemOfElemListMap::iterator   itElem      = newElemsMap.begin();
3872   TElemOfVecOfNnlmiMap::iterator itElemNodes = elemNewNodesMap.begin();
3873   for ( ; itElem != newElemsMap.end(); itElem++, itElemNodes++ ) {
3874     const SMDS_MeshElement* elem = itElem->first;
3875     vector<TNodeOfNodeListMapItr>& vecNewNodes = itElemNodes->second;
3876
3877     if(itElem->second.size()==0) continue;
3878
3879     if ( elem->GetType() == SMDSAbs_Edge ) {
3880       // create a ceiling edge
3881       if (!elem->IsQuadratic()) {
3882         if ( !aMesh->FindEdge( vecNewNodes[ 0 ]->second.back(),
3883                                vecNewNodes[ 1 ]->second.back())) {
3884           myLastCreatedElems.Append(aMesh->AddEdge(vecNewNodes[ 0 ]->second.back(),
3885                                                    vecNewNodes[ 1 ]->second.back()));
3886           srcElements.Append( myLastCreatedElems.Last() );
3887         }
3888       }
3889       else {
3890         if ( !aMesh->FindEdge( vecNewNodes[ 0 ]->second.back(),
3891                                vecNewNodes[ 1 ]->second.back(),
3892                                vecNewNodes[ 2 ]->second.back())) {
3893           myLastCreatedElems.Append(aMesh->AddEdge(vecNewNodes[ 0 ]->second.back(),
3894                                                    vecNewNodes[ 1 ]->second.back(),
3895                                                    vecNewNodes[ 2 ]->second.back()));
3896           srcElements.Append( myLastCreatedElems.Last() );
3897         }
3898       }
3899     }
3900     if ( elem->GetType() != SMDSAbs_Face )
3901       continue;
3902
3903     bool hasFreeLinks = false;
3904
3905     TIDSortedElemSet avoidSet;
3906     avoidSet.insert( elem );
3907
3908     set<const SMDS_MeshNode*> aFaceLastNodes;
3909     int iNode, nbNodes = vecNewNodes.size();
3910     if(!elem->IsQuadratic()) {
3911       // loop on the face nodes
3912       for ( iNode = 0; iNode < nbNodes; iNode++ ) {
3913         aFaceLastNodes.insert( vecNewNodes[ iNode ]->second.back() );
3914         // look for free links of the face
3915         int iNext = ( iNode + 1 == nbNodes ) ? 0 : iNode + 1;
3916         const SMDS_MeshNode* n1 = vecNewNodes[ iNode ]->first;
3917         const SMDS_MeshNode* n2 = vecNewNodes[ iNext ]->first;
3918         // check if a link is free
3919         if ( ! SMESH_MeshEditor::FindFaceInSet ( n1, n2, elemSet, avoidSet )) {
3920           hasFreeLinks = true;
3921           // make an edge and a ceiling for a new edge
3922           if ( !aMesh->FindEdge( n1, n2 )) {
3923             myLastCreatedElems.Append(aMesh->AddEdge( n1, n2 )); // free link edge
3924             srcElements.Append( myLastCreatedElems.Last() );
3925           }
3926           n1 = vecNewNodes[ iNode ]->second.back();
3927           n2 = vecNewNodes[ iNext ]->second.back();
3928           if ( !aMesh->FindEdge( n1, n2 )) {
3929             myLastCreatedElems.Append(aMesh->AddEdge( n1, n2 )); // ceiling edge
3930             srcElements.Append( myLastCreatedElems.Last() );
3931           }
3932         }
3933       }
3934     }
3935     else { // elem is quadratic face
3936       int nbn = nbNodes/2;
3937       for ( iNode = 0; iNode < nbn; iNode++ ) {
3938         aFaceLastNodes.insert( vecNewNodes[ iNode ]->second.back() );
3939         int iNext = ( iNode + 1 == nbn ) ? 0 : iNode + 1;
3940         const SMDS_MeshNode* n1 = vecNewNodes[ iNode ]->first;
3941         const SMDS_MeshNode* n2 = vecNewNodes[ iNext ]->first;
3942         // check if a link is free
3943         if ( ! SMESH_MeshEditor::FindFaceInSet ( n1, n2, elemSet, avoidSet )) {
3944           hasFreeLinks = true;
3945           // make an edge and a ceiling for a new edge
3946           // find medium node
3947           const SMDS_MeshNode* n3 = vecNewNodes[ iNode+nbn ]->first;
3948           if ( !aMesh->FindEdge( n1, n2, n3 )) {
3949             myLastCreatedElems.Append(aMesh->AddEdge( n1, n2, n3 )); // free link edge
3950             srcElements.Append( myLastCreatedElems.Last() );
3951           }
3952           n1 = vecNewNodes[ iNode ]->second.back();
3953           n2 = vecNewNodes[ iNext ]->second.back();
3954           n3 = vecNewNodes[ iNode+nbn ]->second.back();
3955           if ( !aMesh->FindEdge( n1, n2, n3 )) {
3956             myLastCreatedElems.Append(aMesh->AddEdge( n1, n2, n3 )); // ceiling edge
3957             srcElements.Append( myLastCreatedElems.Last() );
3958           }
3959         }
3960       }
3961       for ( iNode = nbn; iNode < 2*nbn; iNode++ ) {
3962         aFaceLastNodes.insert( vecNewNodes[ iNode ]->second.back() );
3963       }
3964     }
3965
3966     // sweep free links into faces
3967
3968     if ( hasFreeLinks )  {
3969       list<const SMDS_MeshElement*> & newVolumes = itElem->second;
3970       int iVol, volNb, nbVolumesByStep = newVolumes.size() / nbSteps;
3971
3972       set<const SMDS_MeshNode*> initNodeSet, topNodeSet, faceNodeSet;
3973       for ( iNode = 0; iNode < nbNodes; iNode++ ) {
3974         initNodeSet.insert( vecNewNodes[ iNode ]->first );
3975         topNodeSet .insert( vecNewNodes[ iNode ]->second.back() );
3976       }
3977       for ( volNb = 0; volNb < nbVolumesByStep; volNb++ ) {
3978         list<const SMDS_MeshElement*>::iterator v = newVolumes.begin();
3979         iVol = 0;
3980         while ( iVol++ < volNb ) v++;
3981         // find indices of free faces of a volume and their source edges
3982         list< int > freeInd;
3983         list< const SMDS_MeshElement* > srcEdges; // source edges of free faces
3984         SMDS_VolumeTool vTool( *v );
3985         int iF, nbF = vTool.NbFaces();
3986         for ( iF = 0; iF < nbF; iF ++ ) {
3987           if (vTool.IsFreeFace( iF ) &&
3988               vTool.GetFaceNodes( iF, faceNodeSet ) &&
3989               initNodeSet != faceNodeSet) // except an initial face
3990           {
3991             if ( nbSteps == 1 && faceNodeSet == topNodeSet )
3992               continue;
3993             freeInd.push_back( iF );
3994             // find source edge of a free face iF
3995             vector<const SMDS_MeshNode*> commonNodes; // shared by the initial and free faces
3996             commonNodes.resize( initNodeSet.size(), NULL ); // avoid spoiling memory
3997             std::set_intersection( faceNodeSet.begin(), faceNodeSet.end(),
3998                                    initNodeSet.begin(), initNodeSet.end(),
3999                                    commonNodes.begin());
4000             if ( (*v)->IsQuadratic() )
4001               srcEdges.push_back(aMesh->FindEdge (commonNodes[0],commonNodes[1],commonNodes[2]));
4002             else
4003               srcEdges.push_back(aMesh->FindEdge (commonNodes[0],commonNodes[1]));
4004 #ifdef _DEBUG_
4005             if ( !srcEdges.back() )
4006             {
4007               cout << "SMESH_MeshEditor::makeWalls(), no source edge found for a free face #"
4008                    << iF << " of volume #" << vTool.ID() << endl;
4009             }
4010 #endif
4011           }
4012         }
4013         if ( freeInd.empty() )
4014           continue;
4015
4016         // create faces for all steps;
4017         // if such a face has been already created by sweep of edge,
4018         // assure that its orientation is OK
4019         for ( int iStep = 0; iStep < nbSteps; iStep++ )  {
4020           vTool.Set( *v );
4021           vTool.SetExternalNormal();
4022           list< int >::iterator ind = freeInd.begin();
4023           list< const SMDS_MeshElement* >::iterator srcEdge = srcEdges.begin();
4024           for ( ; ind != freeInd.end(); ++ind, ++srcEdge ) // loop on free faces
4025           {
4026             const SMDS_MeshNode** nodes = vTool.GetFaceNodes( *ind );
4027             int nbn = vTool.NbFaceNodes( *ind );
4028             switch ( nbn ) {
4029             case 3: { ///// triangle
4030               const SMDS_MeshFace * f = aMesh->FindFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ]);
4031               if ( !f )
4032                 myLastCreatedElems.Append(aMesh->AddFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ] ));
4033               else if ( nodes[ 1 ] != f->GetNodeWrap( f->GetNodeIndex( nodes[ 0 ] ) + 1 ))
4034                 {
4035                   myLastCreatedElems.Append(aMesh->AddFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ] ));
4036                   aMesh->RemoveElement(f);
4037                 }
4038               break;
4039             }
4040             case 4: { ///// quadrangle
4041               const SMDS_MeshFace * f = aMesh->FindFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ], nodes[ 3 ]);
4042               if ( !f )
4043                 myLastCreatedElems.Append(aMesh->AddFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ], nodes[ 3 ] ));
4044               else if ( nodes[ 1 ] != f->GetNodeWrap( f->GetNodeIndex( nodes[ 0 ] ) + 1 ))
4045                 {
4046                   myLastCreatedElems.Append(aMesh->AddFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ], nodes[ 3 ] ));
4047                   aMesh->RemoveElement(f);
4048                 }
4049               break;
4050             }
4051             default:
4052               if( (*v)->IsQuadratic() ) {
4053                 if(nbn==6) { /////// quadratic triangle
4054                   const SMDS_MeshFace * f = aMesh->FindFace( nodes[0], nodes[2], nodes[4],
4055                                                              nodes[1], nodes[3], nodes[5] );
4056                   if ( !f ) {
4057                     myLastCreatedElems.Append(aMesh->AddFace(nodes[0], nodes[2], nodes[4],
4058                                                              nodes[1], nodes[3], nodes[5]));
4059                   }
4060                   else if ( nodes[ 2 ] != f->GetNodeWrap( f->GetNodeIndex( nodes[ 0 ] ) + 1 )) {
4061                     const SMDS_MeshNode** tmpnodes = new const SMDS_MeshNode*[6];
4062                     tmpnodes[0] = nodes[0];
4063                     tmpnodes[1] = nodes[2];
4064                     tmpnodes[2] = nodes[4];
4065                     tmpnodes[3] = nodes[1];
4066                     tmpnodes[4] = nodes[3];
4067                     tmpnodes[5] = nodes[5];
4068                     myLastCreatedElems.Append(aMesh->AddFace(nodes[0], nodes[2], nodes[4],
4069                                                              nodes[1], nodes[3], nodes[5]));
4070                     aMesh->RemoveElement(f);
4071                   }
4072                 }
4073                 else {       /////// quadratic quadrangle
4074                   const SMDS_MeshFace * f = aMesh->FindFace( nodes[0], nodes[2], nodes[4], nodes[6],
4075                                                              nodes[1], nodes[3], nodes[5], nodes[7] );
4076                   if ( !f ) {
4077                     myLastCreatedElems.Append(aMesh->AddFace(nodes[0], nodes[2], nodes[4], nodes[6],
4078                                                              nodes[1], nodes[3], nodes[5], nodes[7]));
4079                   }
4080                   else if ( nodes[ 2 ] != f->GetNodeWrap( f->GetNodeIndex( nodes[ 0 ] ) + 1 )) {
4081                     const SMDS_MeshNode** tmpnodes = new const SMDS_MeshNode*[8];
4082                     tmpnodes[0] = nodes[0];
4083                     tmpnodes[1] = nodes[2];
4084                     tmpnodes[2] = nodes[4];
4085                     tmpnodes[3] = nodes[6];
4086                     tmpnodes[4] = nodes[1];
4087                     tmpnodes[5] = nodes[3];
4088                     tmpnodes[6] = nodes[5];
4089                     tmpnodes[7] = nodes[7];
4090                     myLastCreatedElems.Append(aMesh->AddFace(nodes[0], nodes[2], nodes[4], nodes[6],
4091                                                              nodes[1], nodes[3], nodes[5], nodes[7]));
4092                     aMesh->RemoveElement(f);
4093                   }
4094                 }
4095               }
4096               else { //////// polygon
4097                 vector<const SMDS_MeshNode*> polygon_nodes ( nodes, &nodes[nbn] );
4098                 const SMDS_MeshFace * f = aMesh->FindFace( polygon_nodes );
4099                 if ( !f )
4100                   myLastCreatedElems.Append(aMesh->AddPolygonalFace(polygon_nodes));
4101                 else if ( nodes[ 1 ] != f->GetNodeWrap( f->GetNodeIndex( nodes[ 0 ] ) + 1 ))
4102                   {
4103                   // TODO problem ChangeElementNodes : not the same number of nodes, not the same type
4104                   MESSAGE("ChangeElementNodes");
4105                   aMesh->ChangeElementNodes( f, nodes, nbn );
4106                   }
4107               }
4108             }
4109             while ( srcElements.Length() < myLastCreatedElems.Length() )
4110               srcElements.Append( *srcEdge );
4111
4112           }  // loop on free faces
4113
4114           // go to the next volume
4115           iVol = 0;
4116           while ( iVol++ < nbVolumesByStep ) v++;
4117         }
4118       }
4119     } // sweep free links into faces
4120
4121     // Make a ceiling face with a normal external to a volume
4122
4123     SMDS_VolumeTool lastVol( itElem->second.back() );
4124
4125     int iF = lastVol.GetFaceIndex( aFaceLastNodes );
4126     if ( iF >= 0 ) {
4127       lastVol.SetExternalNormal();
4128       const SMDS_MeshNode** nodes = lastVol.GetFaceNodes( iF );
4129       int nbn = lastVol.NbFaceNodes( iF );
4130       switch ( nbn ) {
4131       case 3:
4132         if (!hasFreeLinks ||
4133             !aMesh->FindFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ]))
4134           myLastCreatedElems.Append(aMesh->AddFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ] ));
4135         break;
4136       case 4:
4137         if (!hasFreeLinks ||
4138             !aMesh->FindFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ], nodes[ 3 ]))
4139           myLastCreatedElems.Append(aMesh->AddFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ], nodes[ 3 ] ));
4140         break;
4141       default:
4142         if(itElem->second.back()->IsQuadratic()) {
4143           if(nbn==6) {
4144             if (!hasFreeLinks ||
4145                 !aMesh->FindFace(nodes[0], nodes[2], nodes[4],
4146                                  nodes[1], nodes[3], nodes[5]) ) {
4147               myLastCreatedElems.Append(aMesh->AddFace(nodes[0], nodes[2], nodes[4],
4148                                                        nodes[1], nodes[3], nodes[5]));
4149             }
4150           }
4151           else { // nbn==8
4152             if (!hasFreeLinks ||
4153                 !aMesh->FindFace(nodes[0], nodes[2], nodes[4], nodes[6],
4154                                  nodes[1], nodes[3], nodes[5], nodes[7]) )
4155               myLastCreatedElems.Append(aMesh->AddFace(nodes[0], nodes[2], nodes[4], nodes[6],
4156                                                        nodes[1], nodes[3], nodes[5], nodes[7]));
4157           }
4158         }
4159         else {
4160           vector<const SMDS_MeshNode*> polygon_nodes ( nodes, &nodes[nbn] );
4161           if (!hasFreeLinks || !aMesh->FindFace(polygon_nodes))
4162             myLastCreatedElems.Append(aMesh->AddPolygonalFace(polygon_nodes));
4163         }
4164       } // switch
4165
4166       while ( srcElements.Length() < myLastCreatedElems.Length() )
4167         srcElements.Append( myLastCreatedElems.Last() );
4168     }
4169   } // loop on swept elements
4170 }
4171
4172 //=======================================================================
4173 //function : RotationSweep
4174 //purpose  :
4175 //=======================================================================
4176
4177 SMESH_MeshEditor::PGroupIDs
4178 SMESH_MeshEditor::RotationSweep(TIDSortedElemSet & theElems,
4179                                 const gp_Ax1&      theAxis,
4180                                 const double       theAngle,
4181                                 const int          theNbSteps,
4182                                 const double       theTol,
4183                                 const bool         theMakeGroups,
4184                                 const bool         theMakeWalls)
4185 {
4186   myLastCreatedElems.Clear();
4187   myLastCreatedNodes.Clear();
4188
4189   // source elements for each generated one
4190   SMESH_SequenceOfElemPtr srcElems, srcNodes;
4191
4192   MESSAGE( "RotationSweep()");
4193   gp_Trsf aTrsf;
4194   aTrsf.SetRotation( theAxis, theAngle );
4195   gp_Trsf aTrsf2;
4196   aTrsf2.SetRotation( theAxis, theAngle/2. );
4197
4198   gp_Lin aLine( theAxis );
4199   double aSqTol = theTol * theTol;
4200
4201   SMESHDS_Mesh* aMesh = GetMeshDS();
4202
4203   TNodeOfNodeListMap mapNewNodes;
4204   TElemOfVecOfNnlmiMap mapElemNewNodes;
4205   TElemOfElemListMap newElemsMap;
4206
4207   // loop on theElems
4208   TIDSortedElemSet::iterator itElem;
4209   for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
4210     const SMDS_MeshElement* elem = *itElem;
4211     if ( !elem || elem->GetType() == SMDSAbs_Volume )
4212       continue;
4213     vector<TNodeOfNodeListMapItr> & newNodesItVec = mapElemNewNodes[ elem ];
4214     newNodesItVec.reserve( elem->NbNodes() );
4215
4216     // loop on elem nodes
4217     SMDS_ElemIteratorPtr itN = elem->nodesIterator();
4218     while ( itN->more() ) {
4219       // check if a node has been already sweeped
4220       const SMDS_MeshNode* node = cast2Node( itN->next() );
4221
4222       gp_XYZ aXYZ( node->X(), node->Y(), node->Z() );
4223       double coord[3];
4224       aXYZ.Coord( coord[0], coord[1], coord[2] );
4225       bool isOnAxis = ( aLine.SquareDistance( aXYZ ) <= aSqTol );
4226
4227       TNodeOfNodeListMapItr nIt = mapNewNodes.find( node );
4228       if ( nIt == mapNewNodes.end() ) {
4229         nIt = mapNewNodes.insert( make_pair( node, list<const SMDS_MeshNode*>() )).first;
4230         list<const SMDS_MeshNode*>& listNewNodes = nIt->second;
4231
4232         // make new nodes
4233         //gp_XYZ aXYZ( node->X(), node->Y(), node->Z() );
4234         //double coord[3];
4235         //aXYZ.Coord( coord[0], coord[1], coord[2] );
4236         //bool isOnAxis = ( aLine.SquareDistance( aXYZ ) <= aSqTol );
4237         const SMDS_MeshNode * newNode = node;
4238         for ( int i = 0; i < theNbSteps; i++ ) {
4239           if ( !isOnAxis ) {
4240             if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
4241               // create two nodes
4242               aTrsf2.Transforms( coord[0], coord[1], coord[2] );
4243               //aTrsf.Transforms( coord[0], coord[1], coord[2] );
4244               newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
4245               myLastCreatedNodes.Append(newNode);
4246               srcNodes.Append( node );
4247               listNewNodes.push_back( newNode );
4248               aTrsf2.Transforms( coord[0], coord[1], coord[2] );
4249               //aTrsf.Transforms( coord[0], coord[1], coord[2] );
4250             }
4251             else {
4252               aTrsf.Transforms( coord[0], coord[1], coord[2] );
4253             }
4254             newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
4255             myLastCreatedNodes.Append(newNode);
4256             srcNodes.Append( node );
4257             listNewNodes.push_back( newNode );
4258           }
4259           else {
4260             listNewNodes.push_back( newNode );
4261             if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
4262               listNewNodes.push_back( newNode );
4263             }
4264           }
4265         }
4266       }
4267       /*
4268         else {
4269         // if current elem is quadratic and current node is not medium
4270         // we have to check - may be it is needed to insert additional nodes
4271         if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
4272         list< const SMDS_MeshNode* > & listNewNodes = nIt->second;
4273         if(listNewNodes.size()==theNbSteps) {
4274         listNewNodes.clear();
4275         // make new nodes
4276         //gp_XYZ aXYZ( node->X(), node->Y(), node->Z() );
4277         //double coord[3];
4278         //aXYZ.Coord( coord[0], coord[1], coord[2] );
4279         const SMDS_MeshNode * newNode = node;
4280         if ( !isOnAxis ) {
4281         for(int i = 0; i<theNbSteps; i++) {
4282         aTrsf2.Transforms( coord[0], coord[1], coord[2] );
4283         newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
4284         cout<<"    3 AddNode:  "<<newNode;
4285         myLastCreatedNodes.Append(newNode);
4286         listNewNodes.push_back( newNode );
4287         srcNodes.Append( node );
4288         aTrsf2.Transforms( coord[0], coord[1], coord[2] );
4289         newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
4290         cout<<"    4 AddNode:  "<<newNode;
4291         myLastCreatedNodes.Append(newNode);
4292         srcNodes.Append( node );
4293         listNewNodes.push_back( newNode );
4294         }
4295         }
4296         else {
4297         listNewNodes.push_back( newNode );
4298         }
4299         }
4300         }
4301         }
4302       */
4303       newNodesItVec.push_back( nIt );
4304     }
4305     // make new elements
4306     sweepElement( elem, newNodesItVec, newElemsMap[elem], theNbSteps, srcElems );
4307   }
4308
4309   if ( theMakeWalls )
4310     makeWalls( mapNewNodes, newElemsMap, mapElemNewNodes, theElems, theNbSteps, srcElems );
4311
4312   PGroupIDs newGroupIDs;
4313   if ( theMakeGroups )
4314     newGroupIDs = generateGroups( srcNodes, srcElems, "rotated");
4315
4316   return newGroupIDs;
4317 }
4318
4319
4320 //=======================================================================
4321 //function : CreateNode
4322 //purpose  :
4323 //=======================================================================
4324 const SMDS_MeshNode* SMESH_MeshEditor::CreateNode(const double x,
4325                                                   const double y,
4326                                                   const double z,
4327                                                   const double tolnode,
4328                                                   SMESH_SequenceOfNode& aNodes)
4329 {
4330   myLastCreatedElems.Clear();
4331   myLastCreatedNodes.Clear();
4332
4333   gp_Pnt P1(x,y,z);
4334   SMESHDS_Mesh * aMesh = myMesh->GetMeshDS();
4335
4336   // try to search in sequence of existing nodes
4337   // if aNodes.Length()>0 we 'nave to use given sequence
4338   // else - use all nodes of mesh
4339   if(aNodes.Length()>0) {
4340     int i;
4341     for(i=1; i<=aNodes.Length(); i++) {
4342       gp_Pnt P2(aNodes.Value(i)->X(),aNodes.Value(i)->Y(),aNodes.Value(i)->Z());
4343       if(P1.Distance(P2)<tolnode)
4344         return aNodes.Value(i);
4345     }
4346   }
4347   else {
4348     SMDS_NodeIteratorPtr itn = aMesh->nodesIterator();
4349     while(itn->more()) {
4350       const SMDS_MeshNode* aN = static_cast<const SMDS_MeshNode*> (itn->next());
4351       gp_Pnt P2(aN->X(),aN->Y(),aN->Z());
4352       if(P1.Distance(P2)<tolnode)
4353         return aN;
4354     }
4355   }
4356
4357   // create new node and return it
4358   const SMDS_MeshNode* NewNode = aMesh->AddNode(x,y,z);
4359   myLastCreatedNodes.Append(NewNode);
4360   return NewNode;
4361 }
4362
4363
4364 //=======================================================================
4365 //function : ExtrusionSweep
4366 //purpose  :
4367 //=======================================================================
4368
4369 SMESH_MeshEditor::PGroupIDs
4370 SMESH_MeshEditor::ExtrusionSweep (TIDSortedElemSet &  theElems,
4371                                   const gp_Vec&       theStep,
4372                                   const int           theNbSteps,
4373                                   TElemOfElemListMap& newElemsMap,
4374                                   const bool          theMakeGroups,
4375                                   const int           theFlags,
4376                                   const double        theTolerance)
4377 {
4378   ExtrusParam aParams;
4379   aParams.myDir = gp_Dir(theStep);
4380   aParams.myNodes.Clear();
4381   aParams.mySteps = new TColStd_HSequenceOfReal;
4382   int i;
4383   for(i=1; i<=theNbSteps; i++)
4384     aParams.mySteps->Append(theStep.Magnitude());
4385
4386   return
4387     ExtrusionSweep(theElems,aParams,newElemsMap,theMakeGroups,theFlags,theTolerance);
4388 }
4389
4390
4391 //=======================================================================
4392 //function : ExtrusionSweep
4393 //purpose  :
4394 //=======================================================================
4395
4396 SMESH_MeshEditor::PGroupIDs
4397 SMESH_MeshEditor::ExtrusionSweep (TIDSortedElemSet &  theElems,
4398                                   ExtrusParam&        theParams,
4399                                   TElemOfElemListMap& newElemsMap,
4400                                   const bool          theMakeGroups,
4401                                   const int           theFlags,
4402                                   const double        theTolerance)
4403 {
4404   MESSAGE("ExtrusionSweep " << theMakeGroups << " " << theFlags << " " << theTolerance);
4405   myLastCreatedElems.Clear();
4406   myLastCreatedNodes.Clear();
4407
4408   // source elements for each generated one
4409   SMESH_SequenceOfElemPtr srcElems, srcNodes;
4410
4411   SMESHDS_Mesh* aMesh = GetMeshDS();
4412
4413   int nbsteps = theParams.mySteps->Length();
4414
4415   TNodeOfNodeListMap mapNewNodes;
4416   //TNodeOfNodeVecMap mapNewNodes;
4417   TElemOfVecOfNnlmiMap mapElemNewNodes;
4418   //TElemOfVecOfMapNodesMap mapElemNewNodes;
4419
4420   // loop on theElems
4421   TIDSortedElemSet::iterator itElem;
4422   for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
4423     // check element type
4424     const SMDS_MeshElement* elem = *itElem;
4425     if ( !elem  || elem->GetType() == SMDSAbs_Volume )
4426       continue;
4427
4428     vector<TNodeOfNodeListMapItr> & newNodesItVec = mapElemNewNodes[ elem ];
4429     //vector<TNodeOfNodeVecMapItr> & newNodesItVec = mapElemNewNodes[ elem ];
4430     newNodesItVec.reserve( elem->NbNodes() );
4431
4432     // loop on elem nodes
4433     SMDS_ElemIteratorPtr itN = elem->nodesIterator();
4434     while ( itN->more() )
4435     {
4436       // check if a node has been already sweeped
4437       const SMDS_MeshNode* node = cast2Node( itN->next() );
4438       TNodeOfNodeListMap::iterator nIt = mapNewNodes.find( node );
4439       //TNodeOfNodeVecMap::iterator nIt = mapNewNodes.find( node );
4440       if ( nIt == mapNewNodes.end() ) {
4441         nIt = mapNewNodes.insert( make_pair( node, list<const SMDS_MeshNode*>() )).first;
4442         //nIt = mapNewNodes.insert( make_pair( node, vector<const SMDS_MeshNode*>() )).first;
4443         list<const SMDS_MeshNode*>& listNewNodes = nIt->second;
4444         //vector<const SMDS_MeshNode*>& vecNewNodes = nIt->second;
4445         //vecNewNodes.reserve(nbsteps);
4446
4447         // make new nodes
4448         double coord[] = { node->X(), node->Y(), node->Z() };
4449         //int nbsteps = theParams.mySteps->Length();
4450         for ( int i = 0; i < nbsteps; i++ ) {
4451           if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
4452             // create additional node
4453             double x = coord[0] + theParams.myDir.X()*theParams.mySteps->Value(i+1)/2.;
4454             double y = coord[1] + theParams.myDir.Y()*theParams.mySteps->Value(i+1)/2.;
4455             double z = coord[2] + theParams.myDir.Z()*theParams.mySteps->Value(i+1)/2.;
4456             if( theFlags & EXTRUSION_FLAG_SEW ) {
4457               const SMDS_MeshNode * newNode = CreateNode(x, y, z,
4458                                                          theTolerance, theParams.myNodes);
4459               listNewNodes.push_back( newNode );
4460             }
4461             else {
4462               const SMDS_MeshNode * newNode = aMesh->AddNode(x, y, z);
4463               myLastCreatedNodes.Append(newNode);
4464               srcNodes.Append( node );
4465               listNewNodes.push_back( newNode );
4466             }
4467           }
4468           //aTrsf.Transforms( coord[0], coord[1], coord[2] );
4469           coord[0] = coord[0] + theParams.myDir.X()*theParams.mySteps->Value(i+1);
4470           coord[1] = coord[1] + theParams.myDir.Y()*theParams.mySteps->Value(i+1);
4471           coord[2] = coord[2] + theParams.myDir.Z()*theParams.mySteps->Value(i+1);
4472           if( theFlags & EXTRUSION_FLAG_SEW ) {
4473             const SMDS_MeshNode * newNode = CreateNode(coord[0], coord[1], coord[2],
4474                                                        theTolerance, theParams.myNodes);
4475             listNewNodes.push_back( newNode );
4476             //vecNewNodes[i]=newNode;
4477           }
4478           else {
4479             const SMDS_MeshNode * newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
4480             myLastCreatedNodes.Append(newNode);
4481             srcNodes.Append( node );
4482             listNewNodes.push_back( newNode );
4483             //vecNewNodes[i]=newNode;
4484           }
4485         }
4486       }
4487       else {
4488         // if current elem is quadratic and current node is not medium
4489         // we have to check - may be it is needed to insert additional nodes
4490         if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
4491           list< const SMDS_MeshNode* > & listNewNodes = nIt->second;
4492           if(listNewNodes.size()==nbsteps) {
4493             listNewNodes.clear();
4494             double coord[] = { node->X(), node->Y(), node->Z() };
4495             for ( int i = 0; i < nbsteps; i++ ) {
4496               double x = coord[0] + theParams.myDir.X()*theParams.mySteps->Value(i+1);
4497               double y = coord[1] + theParams.myDir.Y()*theParams.mySteps->Value(i+1);
4498               double z = coord[2] + theParams.myDir.Z()*theParams.mySteps->Value(i+1);
4499               if( theFlags & EXTRUSION_FLAG_SEW ) {
4500                 const SMDS_MeshNode * newNode = CreateNode(x, y, z,
4501                                                            theTolerance, theParams.myNodes);
4502                 listNewNodes.push_back( newNode );
4503               }
4504               else {
4505                 const SMDS_MeshNode * newNode = aMesh->AddNode(x, y, z);
4506                 myLastCreatedNodes.Append(newNode);
4507                 srcNodes.Append( node );
4508                 listNewNodes.push_back( newNode );
4509               }
4510               coord[0] = coord[0] + theParams.myDir.X()*theParams.mySteps->Value(i+1);
4511               coord[1] = coord[1] + theParams.myDir.Y()*theParams.mySteps->Value(i+1);
4512               coord[2] = coord[2] + theParams.myDir.Z()*theParams.mySteps->Value(i+1);
4513               if( theFlags & EXTRUSION_FLAG_SEW ) {
4514                 const SMDS_MeshNode * newNode = CreateNode(coord[0], coord[1], coord[2],
4515                                                            theTolerance, theParams.myNodes);
4516                 listNewNodes.push_back( newNode );
4517               }
4518               else {
4519                 const SMDS_MeshNode * newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
4520                 myLastCreatedNodes.Append(newNode);
4521                 srcNodes.Append( node );
4522                 listNewNodes.push_back( newNode );
4523               }
4524             }
4525           }
4526         }
4527       }
4528       newNodesItVec.push_back( nIt );
4529     }
4530     // make new elements
4531     sweepElement( elem, newNodesItVec, newElemsMap[elem], nbsteps, srcElems );
4532   }
4533
4534   if( theFlags & EXTRUSION_FLAG_BOUNDARY ) {
4535     makeWalls( mapNewNodes, newElemsMap, mapElemNewNodes, theElems, nbsteps, srcElems );
4536   }
4537   PGroupIDs newGroupIDs;
4538   if ( theMakeGroups )
4539     newGroupIDs = generateGroups( srcNodes, srcElems, "extruded");
4540
4541   return newGroupIDs;
4542 }
4543
4544 /*
4545 //=======================================================================
4546 //class    : SMESH_MeshEditor_PathPoint
4547 //purpose  : auxiliary class
4548 //=======================================================================
4549 class SMESH_MeshEditor_PathPoint {
4550 public:
4551 SMESH_MeshEditor_PathPoint() {
4552 myPnt.SetCoord(99., 99., 99.);
4553 myTgt.SetCoord(1.,0.,0.);
4554 myAngle=0.;
4555 myPrm=0.;
4556 }
4557 void SetPnt(const gp_Pnt& aP3D){
4558 myPnt=aP3D;
4559 }
4560 void SetTangent(const gp_Dir& aTgt){
4561 myTgt=aTgt;
4562 }
4563 void SetAngle(const double& aBeta){
4564 myAngle=aBeta;
4565 }
4566 void SetParameter(const double& aPrm){
4567 myPrm=aPrm;
4568 }
4569 const gp_Pnt& Pnt()const{
4570 return myPnt;
4571 }
4572 const gp_Dir& Tangent()const{
4573 return myTgt;
4574 }
4575 double Angle()const{
4576 return myAngle;
4577 }
4578 double Parameter()const{
4579 return myPrm;
4580 }
4581
4582 protected:
4583 gp_Pnt myPnt;
4584 gp_Dir myTgt;
4585 double myAngle;
4586 double myPrm;
4587 };
4588 */
4589
4590 //=======================================================================
4591 //function : ExtrusionAlongTrack
4592 //purpose  :
4593 //=======================================================================
4594 SMESH_MeshEditor::Extrusion_Error
4595 SMESH_MeshEditor::ExtrusionAlongTrack (TIDSortedElemSet &   theElements,
4596                                        SMESH_subMesh*       theTrack,
4597                                        const SMDS_MeshNode* theN1,
4598                                        const bool           theHasAngles,
4599                                        list<double>&        theAngles,
4600                                        const bool           theLinearVariation,
4601                                        const bool           theHasRefPoint,
4602                                        const gp_Pnt&        theRefPoint,
4603                                        const bool           theMakeGroups)
4604 {
4605   MESSAGE("ExtrusionAlongTrack");
4606   myLastCreatedElems.Clear();
4607   myLastCreatedNodes.Clear();
4608
4609   int aNbE;
4610   std::list<double> aPrms;
4611   TIDSortedElemSet::iterator itElem;
4612
4613   gp_XYZ aGC;
4614   TopoDS_Edge aTrackEdge;
4615   TopoDS_Vertex aV1, aV2;
4616
4617   SMDS_ElemIteratorPtr aItE;
4618   SMDS_NodeIteratorPtr aItN;
4619   SMDSAbs_ElementType aTypeE;
4620
4621   TNodeOfNodeListMap mapNewNodes;
4622
4623   // 1. Check data
4624   aNbE = theElements.size();
4625   // nothing to do
4626   if ( !aNbE )
4627     return EXTR_NO_ELEMENTS;
4628
4629   // 1.1 Track Pattern
4630   ASSERT( theTrack );
4631
4632   SMESHDS_SubMesh* pSubMeshDS = theTrack->GetSubMeshDS();
4633
4634   aItE = pSubMeshDS->GetElements();
4635   while ( aItE->more() ) {
4636     const SMDS_MeshElement* pE = aItE->next();
4637     aTypeE = pE->GetType();
4638     // Pattern must contain links only
4639     if ( aTypeE != SMDSAbs_Edge )
4640       return EXTR_PATH_NOT_EDGE;
4641   }
4642
4643   list<SMESH_MeshEditor_PathPoint> fullList;
4644
4645   const TopoDS_Shape& aS = theTrack->GetSubShape();
4646   // Sub shape for the Pattern must be an Edge or Wire
4647   if( aS.ShapeType() == TopAbs_EDGE ) {
4648     aTrackEdge = TopoDS::Edge( aS );
4649     // the Edge must not be degenerated
4650     if ( BRep_Tool::Degenerated( aTrackEdge ) )
4651       return EXTR_BAD_PATH_SHAPE;
4652     TopExp::Vertices( aTrackEdge, aV1, aV2 );
4653     aItN = theTrack->GetFather()->GetSubMesh( aV1 )->GetSubMeshDS()->GetNodes();
4654     const SMDS_MeshNode* aN1 = aItN->next();
4655     aItN = theTrack->GetFather()->GetSubMesh( aV2 )->GetSubMeshDS()->GetNodes();
4656     const SMDS_MeshNode* aN2 = aItN->next();
4657     // starting node must be aN1 or aN2
4658     if ( !( aN1 == theN1 || aN2 == theN1 ) )
4659       return EXTR_BAD_STARTING_NODE;
4660     aItN = pSubMeshDS->GetNodes();
4661     while ( aItN->more() ) {
4662       const SMDS_MeshNode* pNode = aItN->next();
4663       const SMDS_EdgePosition* pEPos =
4664         static_cast<const SMDS_EdgePosition*>( pNode->GetPosition() );
4665       double aT = pEPos->GetUParameter();
4666       aPrms.push_back( aT );
4667     }
4668     //Extrusion_Error err =
4669     MakeEdgePathPoints(aPrms, aTrackEdge, (aN1==theN1), fullList);
4670   }
4671   else if( aS.ShapeType() == TopAbs_WIRE ) {
4672     list< SMESH_subMesh* > LSM;
4673     TopTools_SequenceOfShape Edges;
4674     SMESH_subMeshIteratorPtr itSM = theTrack->getDependsOnIterator(false,true);
4675     while(itSM->more()) {
4676       SMESH_subMesh* SM = itSM->next();
4677       LSM.push_back(SM);
4678       const TopoDS_Shape& aS = SM->GetSubShape();
4679       Edges.Append(aS);
4680     }
4681     list< list<SMESH_MeshEditor_PathPoint> > LLPPs;
4682     int startNid = theN1->GetID();
4683     TColStd_MapOfInteger UsedNums;
4684     int NbEdges = Edges.Length();
4685     int i = 1;
4686     for(; i<=NbEdges; i++) {
4687       int k = 0;
4688       list< SMESH_subMesh* >::iterator itLSM = LSM.begin();
4689       for(; itLSM!=LSM.end(); itLSM++) {
4690         k++;
4691         if(UsedNums.Contains(k)) continue;
4692         aTrackEdge = TopoDS::Edge( Edges.Value(k) );
4693         SMESH_subMesh* locTrack = *itLSM;
4694         SMESHDS_SubMesh* locMeshDS = locTrack->GetSubMeshDS();
4695         TopExp::Vertices( aTrackEdge, aV1, aV2 );
4696         aItN = locTrack->GetFather()->GetSubMesh(aV1)->GetSubMeshDS()->GetNodes();
4697         const SMDS_MeshNode* aN1 = aItN->next();
4698         aItN = locTrack->GetFather()->GetSubMesh(aV2)->GetSubMeshDS()->GetNodes();
4699         const SMDS_MeshNode* aN2 = aItN->next();
4700         // starting node must be aN1 or aN2
4701         if ( !( aN1->GetID() == startNid || aN2->GetID() == startNid ) ) continue;
4702         // 2. Collect parameters on the track edge
4703         aPrms.clear();
4704         aItN = locMeshDS->GetNodes();
4705         while ( aItN->more() ) {
4706           const SMDS_MeshNode* pNode = aItN->next();
4707           const SMDS_EdgePosition* pEPos =
4708             static_cast<const SMDS_EdgePosition*>( pNode->GetPosition() );
4709           double aT = pEPos->GetUParameter();
4710           aPrms.push_back( aT );
4711         }
4712         list<SMESH_MeshEditor_PathPoint> LPP;
4713         //Extrusion_Error err =
4714         MakeEdgePathPoints(aPrms, aTrackEdge,(aN1->GetID()==startNid), LPP);
4715         LLPPs.push_back(LPP);
4716         UsedNums.Add(k);
4717         // update startN for search following egde
4718         if( aN1->GetID() == startNid ) startNid = aN2->GetID();
4719         else startNid = aN1->GetID();
4720         break;
4721       }
4722     }
4723     list< list<SMESH_MeshEditor_PathPoint> >::iterator itLLPP = LLPPs.begin();
4724     list<SMESH_MeshEditor_PathPoint> firstList = *itLLPP;
4725     list<SMESH_MeshEditor_PathPoint>::iterator itPP = firstList.begin();
4726     for(; itPP!=firstList.end(); itPP++) {
4727       fullList.push_back( *itPP );
4728     }
4729     SMESH_MeshEditor_PathPoint PP1 = fullList.back();
4730     fullList.pop_back();
4731     itLLPP++;
4732     for(; itLLPP!=LLPPs.end(); itLLPP++) {
4733       list<SMESH_MeshEditor_PathPoint> currList = *itLLPP;
4734       itPP = currList.begin();
4735       SMESH_MeshEditor_PathPoint PP2 = currList.front();
4736       gp_Dir D1 = PP1.Tangent();
4737       gp_Dir D2 = PP2.Tangent();
4738       gp_Dir Dnew( gp_Vec( (D1.X()+D2.X())/2, (D1.Y()+D2.Y())/2,
4739                            (D1.Z()+D2.Z())/2 ) );
4740       PP1.SetTangent(Dnew);
4741       fullList.push_back(PP1);
4742       itPP++;
4743       for(; itPP!=firstList.end(); itPP++) {
4744         fullList.push_back( *itPP );
4745       }
4746       PP1 = fullList.back();
4747       fullList.pop_back();
4748     }
4749     // if wire not closed
4750     fullList.push_back(PP1);
4751     // else ???
4752   }
4753   else {
4754     return EXTR_BAD_PATH_SHAPE;
4755   }
4756
4757   return MakeExtrElements(theElements, fullList, theHasAngles, theAngles, theLinearVariation,
4758                           theHasRefPoint, theRefPoint, theMakeGroups);
4759 }
4760
4761
4762 //=======================================================================
4763 //function : ExtrusionAlongTrack
4764 //purpose  :
4765 //=======================================================================
4766 SMESH_MeshEditor::Extrusion_Error
4767 SMESH_MeshEditor::ExtrusionAlongTrack (TIDSortedElemSet &   theElements,
4768                                        SMESH_Mesh*          theTrack,
4769                                        const SMDS_MeshNode* theN1,
4770                                        const bool           theHasAngles,
4771                                        list<double>&        theAngles,
4772                                        const bool           theLinearVariation,
4773                                        const bool           theHasRefPoint,
4774                                        const gp_Pnt&        theRefPoint,
4775                                        const bool           theMakeGroups)
4776 {
4777   myLastCreatedElems.Clear();
4778   myLastCreatedNodes.Clear();
4779
4780   int aNbE;
4781   std::list<double> aPrms;
4782   TIDSortedElemSet::iterator itElem;
4783
4784   gp_XYZ aGC;
4785   TopoDS_Edge aTrackEdge;
4786   TopoDS_Vertex aV1, aV2;
4787
4788   SMDS_ElemIteratorPtr aItE;
4789   SMDS_NodeIteratorPtr aItN;
4790   SMDSAbs_ElementType aTypeE;
4791
4792   TNodeOfNodeListMap mapNewNodes;
4793
4794   // 1. Check data
4795   aNbE = theElements.size();
4796   // nothing to do
4797   if ( !aNbE )
4798     return EXTR_NO_ELEMENTS;
4799
4800   // 1.1 Track Pattern
4801   ASSERT( theTrack );
4802
4803   SMESHDS_Mesh* pMeshDS = theTrack->GetMeshDS();
4804
4805   aItE = pMeshDS->elementsIterator();
4806   while ( aItE->more() ) {
4807     const SMDS_MeshElement* pE = aItE->next();
4808     aTypeE = pE->GetType();
4809     // Pattern must contain links only
4810     if ( aTypeE != SMDSAbs_Edge )
4811       return EXTR_PATH_NOT_EDGE;
4812   }
4813
4814   list<SMESH_MeshEditor_PathPoint> fullList;
4815
4816   const TopoDS_Shape& aS = theTrack->GetShapeToMesh();
4817   // Sub shape for the Pattern must be an Edge or Wire
4818   if( aS.ShapeType() == TopAbs_EDGE ) {
4819     aTrackEdge = TopoDS::Edge( aS );
4820     // the Edge must not be degenerated
4821     if ( BRep_Tool::Degenerated( aTrackEdge ) )
4822       return EXTR_BAD_PATH_SHAPE;
4823     TopExp::Vertices( aTrackEdge, aV1, aV2 );
4824     aItN = theTrack->GetSubMesh( aV1 )->GetSubMeshDS()->GetNodes();
4825     const SMDS_MeshNode* aN1 = aItN->next();
4826     aItN = theTrack->GetSubMesh( aV2 )->GetSubMeshDS()->GetNodes();
4827     const SMDS_MeshNode* aN2 = aItN->next();
4828     // starting node must be aN1 or aN2
4829     if ( !( aN1 == theN1 || aN2 == theN1 ) )
4830       return EXTR_BAD_STARTING_NODE;
4831     aItN = pMeshDS->nodesIterator();
4832     while ( aItN->more() ) {
4833       const SMDS_MeshNode* pNode = aItN->next();
4834       if( pNode==aN1 || pNode==aN2 ) continue;
4835       const SMDS_EdgePosition* pEPos =
4836         static_cast<const SMDS_EdgePosition*>( pNode->GetPosition() );
4837       double aT = pEPos->GetUParameter();
4838       aPrms.push_back( aT );
4839     }
4840     //Extrusion_Error err =
4841     MakeEdgePathPoints(aPrms, aTrackEdge, (aN1==theN1), fullList);
4842   }
4843   else if( aS.ShapeType() == TopAbs_WIRE ) {
4844     list< SMESH_subMesh* > LSM;
4845     TopTools_SequenceOfShape Edges;
4846     TopExp_Explorer eExp(aS, TopAbs_EDGE);
4847     for(; eExp.More(); eExp.Next()) {
4848       TopoDS_Edge E = TopoDS::Edge( eExp.Current() );
4849       if( BRep_Tool::Degenerated(E) ) continue;
4850       SMESH_subMesh* SM = theTrack->GetSubMesh(E);
4851       if(SM) {
4852         LSM.push_back(SM);
4853         Edges.Append(E);
4854       }
4855     }
4856     list< list<SMESH_MeshEditor_PathPoint> > LLPPs;
4857     int startNid = theN1->GetID();
4858     TColStd_MapOfInteger UsedNums;
4859     int NbEdges = Edges.Length();
4860     int i = 1;
4861     for(; i<=NbEdges; i++) {
4862       int k = 0;
4863       list< SMESH_subMesh* >::iterator itLSM = LSM.begin();
4864       for(; itLSM!=LSM.end(); itLSM++) {
4865         k++;
4866         if(UsedNums.Contains(k)) continue;
4867         aTrackEdge = TopoDS::Edge( Edges.Value(k) );
4868         SMESH_subMesh* locTrack = *itLSM;
4869         SMESHDS_SubMesh* locMeshDS = locTrack->GetSubMeshDS();
4870         TopExp::Vertices( aTrackEdge, aV1, aV2 );
4871         aItN = locTrack->GetFather()->GetSubMesh(aV1)->GetSubMeshDS()->GetNodes();
4872         const SMDS_MeshNode* aN1 = aItN->next();
4873         aItN = locTrack->GetFather()->GetSubMesh(aV2)->GetSubMeshDS()->GetNodes();
4874         const SMDS_MeshNode* aN2 = aItN->next();
4875         // starting node must be aN1 or aN2
4876         if ( !( aN1->GetID() == startNid || aN2->GetID() == startNid ) ) continue;
4877         // 2. Collect parameters on the track edge
4878         aPrms.clear();
4879         aItN = locMeshDS->GetNodes();
4880         while ( aItN->more() ) {
4881           const SMDS_MeshNode* pNode = aItN->next();
4882           const SMDS_EdgePosition* pEPos =
4883             static_cast<const SMDS_EdgePosition*>( pNode->GetPosition() );
4884           double aT = pEPos->GetUParameter();
4885           aPrms.push_back( aT );
4886         }
4887         list<SMESH_MeshEditor_PathPoint> LPP;
4888         //Extrusion_Error err =
4889         MakeEdgePathPoints(aPrms, aTrackEdge,(aN1->GetID()==startNid), LPP);
4890         LLPPs.push_back(LPP);
4891         UsedNums.Add(k);
4892         // update startN for search following egde
4893         if( aN1->GetID() == startNid ) startNid = aN2->GetID();
4894         else startNid = aN1->GetID();
4895         break;
4896       }
4897     }
4898     list< list<SMESH_MeshEditor_PathPoint> >::iterator itLLPP = LLPPs.begin();
4899     list<SMESH_MeshEditor_PathPoint> firstList = *itLLPP;
4900     list<SMESH_MeshEditor_PathPoint>::iterator itPP = firstList.begin();
4901     for(; itPP!=firstList.end(); itPP++) {
4902       fullList.push_back( *itPP );
4903     }
4904     SMESH_MeshEditor_PathPoint PP1 = fullList.back();
4905     fullList.pop_back();
4906     itLLPP++;
4907     for(; itLLPP!=LLPPs.end(); itLLPP++) {
4908       list<SMESH_MeshEditor_PathPoint> currList = *itLLPP;
4909       itPP = currList.begin();
4910       SMESH_MeshEditor_PathPoint PP2 = currList.front();
4911       gp_Dir D1 = PP1.Tangent();
4912       gp_Dir D2 = PP2.Tangent();
4913       gp_Dir Dnew( gp_Vec( (D1.X()+D2.X())/2, (D1.Y()+D2.Y())/2,
4914                            (D1.Z()+D2.Z())/2 ) );
4915       PP1.SetTangent(Dnew);
4916       fullList.push_back(PP1);
4917       itPP++;
4918       for(; itPP!=currList.end(); itPP++) {
4919         fullList.push_back( *itPP );
4920       }
4921       PP1 = fullList.back();
4922       fullList.pop_back();
4923     }
4924     // if wire not closed
4925     fullList.push_back(PP1);
4926     // else ???
4927   }
4928   else {
4929     return EXTR_BAD_PATH_SHAPE;
4930   }
4931
4932   return MakeExtrElements(theElements, fullList, theHasAngles, theAngles, theLinearVariation,
4933                           theHasRefPoint, theRefPoint, theMakeGroups);
4934 }
4935
4936
4937 //=======================================================================
4938 //function : MakeEdgePathPoints
4939 //purpose  : auxilary for ExtrusionAlongTrack
4940 //=======================================================================
4941 SMESH_MeshEditor::Extrusion_Error
4942 SMESH_MeshEditor::MakeEdgePathPoints(std::list<double>& aPrms,
4943                                      const TopoDS_Edge& aTrackEdge,
4944                                      bool FirstIsStart,
4945                                      list<SMESH_MeshEditor_PathPoint>& LPP)
4946 {
4947   Standard_Real aTx1, aTx2, aL2, aTolVec, aTolVec2;
4948   aTolVec=1.e-7;
4949   aTolVec2=aTolVec*aTolVec;
4950   double aT1, aT2;
4951   TopoDS_Vertex aV1, aV2;
4952   TopExp::Vertices( aTrackEdge, aV1, aV2 );
4953   aT1=BRep_Tool::Parameter( aV1, aTrackEdge );
4954   aT2=BRep_Tool::Parameter( aV2, aTrackEdge );
4955   // 2. Collect parameters on the track edge
4956   aPrms.push_front( aT1 );
4957   aPrms.push_back( aT2 );
4958   // sort parameters
4959   aPrms.sort();
4960   if( FirstIsStart ) {
4961     if ( aT1 > aT2 ) {
4962       aPrms.reverse();
4963     }
4964   }
4965   else {
4966     if ( aT2 > aT1 ) {
4967       aPrms.reverse();
4968     }
4969   }
4970   // 3. Path Points
4971   SMESH_MeshEditor_PathPoint aPP;
4972   Handle(Geom_Curve) aC3D = BRep_Tool::Curve( aTrackEdge, aTx1, aTx2 );
4973   std::list<double>::iterator aItD = aPrms.begin();
4974   for(; aItD != aPrms.end(); ++aItD) {
4975     double aT = *aItD;
4976     gp_Pnt aP3D;
4977     gp_Vec aVec;
4978     aC3D->D1( aT, aP3D, aVec );
4979     aL2 = aVec.SquareMagnitude();
4980     if ( aL2 < aTolVec2 )
4981       return EXTR_CANT_GET_TANGENT;
4982     gp_Dir aTgt( aVec );
4983     aPP.SetPnt( aP3D );
4984     aPP.SetTangent( aTgt );
4985     aPP.SetParameter( aT );
4986     LPP.push_back(aPP);
4987   }
4988   return EXTR_OK;
4989 }
4990
4991
4992 //=======================================================================
4993 //function : MakeExtrElements
4994 //purpose  : auxilary for ExtrusionAlongTrack
4995 //=======================================================================
4996 SMESH_MeshEditor::Extrusion_Error
4997 SMESH_MeshEditor::MakeExtrElements(TIDSortedElemSet&  theElements,
4998                                    list<SMESH_MeshEditor_PathPoint>& fullList,
4999                                    const bool theHasAngles,
5000                                    list<double>& theAngles,
5001                                    const bool theLinearVariation,
5002                                    const bool theHasRefPoint,
5003                                    const gp_Pnt& theRefPoint,
5004                                    const bool theMakeGroups)
5005 {
5006   MESSAGE("MakeExtrElements");
5007   //cout<<"MakeExtrElements  fullList.size() = "<<fullList.size()<<endl;
5008   int aNbTP = fullList.size();
5009   vector<SMESH_MeshEditor_PathPoint> aPPs(aNbTP);
5010   // Angles
5011   if( theHasAngles && theAngles.size()>0 && theLinearVariation ) {
5012     LinearAngleVariation(aNbTP-1, theAngles);
5013   }
5014   vector<double> aAngles( aNbTP );
5015   int j = 0;
5016   for(; j<aNbTP; ++j) {
5017     aAngles[j] = 0.;
5018   }
5019   if ( theHasAngles ) {
5020     double anAngle;;
5021     std::list<double>::iterator aItD = theAngles.begin();
5022     for ( j=1; (aItD != theAngles.end()) && (j<aNbTP); ++aItD, ++j ) {
5023       anAngle = *aItD;
5024       aAngles[j] = anAngle;
5025     }
5026   }
5027   // fill vector of path points with angles
5028   //aPPs.resize(fullList.size());
5029   j = -1;
5030   list<SMESH_MeshEditor_PathPoint>::iterator itPP = fullList.begin();
5031   for(; itPP!=fullList.end(); itPP++) {
5032     j++;
5033     SMESH_MeshEditor_PathPoint PP = *itPP;
5034     PP.SetAngle(aAngles[j]);
5035     aPPs[j] = PP;
5036   }
5037
5038   TNodeOfNodeListMap mapNewNodes;
5039   TElemOfVecOfNnlmiMap mapElemNewNodes;
5040   TElemOfElemListMap newElemsMap;
5041   TIDSortedElemSet::iterator itElem;
5042   double aX, aY, aZ;
5043   int aNb;
5044   SMDSAbs_ElementType aTypeE;
5045   // source elements for each generated one
5046   SMESH_SequenceOfElemPtr srcElems, srcNodes;
5047
5048   // 3. Center of rotation aV0
5049   gp_Pnt aV0 = theRefPoint;
5050   gp_XYZ aGC;
5051   if ( !theHasRefPoint ) {
5052     aNb = 0;
5053     aGC.SetCoord( 0.,0.,0. );
5054
5055     itElem = theElements.begin();
5056     for ( ; itElem != theElements.end(); itElem++ ) {
5057       const SMDS_MeshElement* elem = *itElem;
5058
5059       SMDS_ElemIteratorPtr itN = elem->nodesIterator();
5060       while ( itN->more() ) {
5061         const SMDS_MeshNode* node = static_cast<const SMDS_MeshNode*>( itN->next() );
5062         aX = node->X();
5063         aY = node->Y();
5064         aZ = node->Z();
5065
5066         if ( mapNewNodes.find( node ) == mapNewNodes.end() ) {
5067           list<const SMDS_MeshNode*> aLNx;
5068           mapNewNodes[node] = aLNx;
5069           //
5070           gp_XYZ aXYZ( aX, aY, aZ );
5071           aGC += aXYZ;
5072           ++aNb;
5073         }
5074       }
5075     }
5076     aGC /= aNb;
5077     aV0.SetXYZ( aGC );
5078   } // if (!theHasRefPoint) {
5079   mapNewNodes.clear();
5080
5081   // 4. Processing the elements
5082   SMESHDS_Mesh* aMesh = GetMeshDS();
5083
5084   for ( itElem = theElements.begin(); itElem != theElements.end(); itElem++ ) {
5085     // check element type
5086     const SMDS_MeshElement* elem = *itElem;
5087     aTypeE = elem->GetType();
5088     if ( !elem || ( aTypeE != SMDSAbs_Face && aTypeE != SMDSAbs_Edge ) )
5089       continue;
5090
5091     vector<TNodeOfNodeListMapItr> & newNodesItVec = mapElemNewNodes[ elem ];
5092     newNodesItVec.reserve( elem->NbNodes() );
5093
5094     // loop on elem nodes
5095     int nodeIndex = -1;
5096     SMDS_ElemIteratorPtr itN = elem->nodesIterator();
5097     while ( itN->more() )
5098     {
5099       ++nodeIndex;
5100       // check if a node has been already processed
5101       const SMDS_MeshNode* node =
5102         static_cast<const SMDS_MeshNode*>( itN->next() );
5103       TNodeOfNodeListMap::iterator nIt = mapNewNodes.find( node );
5104       if ( nIt == mapNewNodes.end() ) {
5105         nIt = mapNewNodes.insert( make_pair( node, list<const SMDS_MeshNode*>() )).first;
5106         list<const SMDS_MeshNode*>& listNewNodes = nIt->second;
5107
5108         // make new nodes
5109         aX = node->X();  aY = node->Y(); aZ = node->Z();
5110
5111         Standard_Real aAngle1x, aAngleT1T0, aTolAng;
5112         gp_Pnt aP0x, aP1x, aPN0, aPN1, aV0x, aV1x;
5113         gp_Ax1 anAx1, anAxT1T0;
5114         gp_Dir aDT1x, aDT0x, aDT1T0;
5115
5116         aTolAng=1.e-4;
5117
5118         aV0x = aV0;
5119         aPN0.SetCoord(aX, aY, aZ);
5120
5121         const SMESH_MeshEditor_PathPoint& aPP0 = aPPs[0];
5122         aP0x = aPP0.Pnt();
5123         aDT0x= aPP0.Tangent();
5124         //cout<<"j = 0   PP: Pnt("<<aP0x.X()<<","<<aP0x.Y()<<","<<aP0x.Z()<<")"<<endl;
5125
5126         for ( j = 1; j < aNbTP; ++j ) {
5127           const SMESH_MeshEditor_PathPoint& aPP1 = aPPs[j];
5128           aP1x = aPP1.Pnt();
5129           aDT1x = aPP1.Tangent();
5130           aAngle1x = aPP1.Angle();
5131
5132           gp_Trsf aTrsf, aTrsfRot, aTrsfRotT1T0;
5133           // Translation
5134           gp_Vec aV01x( aP0x, aP1x );
5135           aTrsf.SetTranslation( aV01x );
5136
5137           // traslated point
5138           aV1x = aV0x.Transformed( aTrsf );
5139           aPN1 = aPN0.Transformed( aTrsf );
5140
5141           // rotation 1 [ T1,T0 ]
5142           aAngleT1T0=-aDT1x.Angle( aDT0x );
5143           if (fabs(aAngleT1T0) > aTolAng) {
5144             aDT1T0=aDT1x^aDT0x;
5145             anAxT1T0.SetLocation( aV1x );
5146             anAxT1T0.SetDirection( aDT1T0 );
5147             aTrsfRotT1T0.SetRotation( anAxT1T0, aAngleT1T0 );
5148
5149             aPN1 = aPN1.Transformed( aTrsfRotT1T0 );
5150           }
5151
5152           // rotation 2
5153           if ( theHasAngles ) {
5154             anAx1.SetLocation( aV1x );
5155             anAx1.SetDirection( aDT1x );
5156             aTrsfRot.SetRotation( anAx1, aAngle1x );
5157
5158             aPN1 = aPN1.Transformed( aTrsfRot );
5159           }
5160
5161           // make new node
5162           //MESSAGE("elem->IsQuadratic " << elem->IsQuadratic() << " " << elem->IsMediumNode(node));
5163           if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
5164             // create additional node
5165             double x = ( aPN1.X() + aPN0.X() )/2.;
5166             double y = ( aPN1.Y() + aPN0.Y() )/2.;
5167             double z = ( aPN1.Z() + aPN0.Z() )/2.;
5168             const SMDS_MeshNode* newNode = aMesh->AddNode(x,y,z);
5169             myLastCreatedNodes.Append(newNode);
5170             srcNodes.Append( node );
5171             listNewNodes.push_back( newNode );
5172           }
5173           aX = aPN1.X();
5174           aY = aPN1.Y();
5175           aZ = aPN1.Z();
5176           const SMDS_MeshNode* newNode = aMesh->AddNode( aX, aY, aZ );
5177           myLastCreatedNodes.Append(newNode);
5178           srcNodes.Append( node );
5179           listNewNodes.push_back( newNode );
5180
5181           aPN0 = aPN1;
5182           aP0x = aP1x;
5183           aV0x = aV1x;
5184           aDT0x = aDT1x;
5185         }
5186       }
5187
5188       else {
5189         // if current elem is quadratic and current node is not medium
5190         // we have to check - may be it is needed to insert additional nodes
5191         if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
5192           list< const SMDS_MeshNode* > & listNewNodes = nIt->second;
5193           if(listNewNodes.size()==aNbTP-1) {
5194             vector<const SMDS_MeshNode*> aNodes(2*(aNbTP-1));
5195             gp_XYZ P(node->X(), node->Y(), node->Z());
5196             list< const SMDS_MeshNode* >::iterator it = listNewNodes.begin();
5197             int i;
5198             for(i=0; i<aNbTP-1; i++) {
5199               const SMDS_MeshNode* N = *it;
5200               double x = ( N->X() + P.X() )/2.;
5201               double y = ( N->Y() + P.Y() )/2.;
5202               double z = ( N->Z() + P.Z() )/2.;
5203               const SMDS_MeshNode* newN = aMesh->AddNode(x,y,z);
5204               srcNodes.Append( node );
5205               myLastCreatedNodes.Append(newN);
5206               aNodes[2*i] = newN;
5207               aNodes[2*i+1] = N;
5208               P = gp_XYZ(N->X(),N->Y(),N->Z());
5209             }
5210             listNewNodes.clear();
5211             for(i=0; i<2*(aNbTP-1); i++) {
5212               listNewNodes.push_back(aNodes[i]);
5213             }
5214           }
5215         }
5216       }
5217
5218       newNodesItVec.push_back( nIt );
5219     }
5220     // make new elements
5221     //sweepElement( aMesh, elem, newNodesItVec, newElemsMap[elem],
5222     //              newNodesItVec[0]->second.size(), myLastCreatedElems );
5223     sweepElement( elem, newNodesItVec, newElemsMap[elem], aNbTP-1, srcElems );
5224   }
5225
5226   makeWalls( mapNewNodes, newElemsMap, mapElemNewNodes, theElements, aNbTP-1, srcElems );
5227
5228   if ( theMakeGroups )
5229     generateGroups( srcNodes, srcElems, "extruded");
5230
5231   return EXTR_OK;
5232 }
5233
5234
5235 //=======================================================================
5236 //function : LinearAngleVariation
5237 //purpose  : auxilary for ExtrusionAlongTrack
5238 //=======================================================================
5239 void SMESH_MeshEditor::LinearAngleVariation(const int nbSteps,
5240                                             list<double>& Angles)
5241 {
5242   int nbAngles = Angles.size();
5243   if( nbSteps > nbAngles ) {
5244     vector<double> theAngles(nbAngles);
5245     list<double>::iterator it = Angles.begin();
5246     int i = -1;
5247     for(; it!=Angles.end(); it++) {
5248       i++;
5249       theAngles[i] = (*it);
5250     }
5251     list<double> res;
5252     double rAn2St = double( nbAngles ) / double( nbSteps );
5253     double angPrev = 0, angle;
5254     for ( int iSt = 0; iSt < nbSteps; ++iSt ) {
5255       double angCur = rAn2St * ( iSt+1 );
5256       double angCurFloor  = floor( angCur );
5257       double angPrevFloor = floor( angPrev );
5258       if ( angPrevFloor == angCurFloor )
5259         angle = rAn2St * theAngles[ int( angCurFloor ) ];
5260       else {
5261         int iP = int( angPrevFloor );
5262         double angPrevCeil = ceil(angPrev);
5263         angle = ( angPrevCeil - angPrev ) * theAngles[ iP ];
5264
5265         int iC = int( angCurFloor );
5266         if ( iC < nbAngles )
5267           angle += ( angCur - angCurFloor ) * theAngles[ iC ];
5268
5269         iP = int( angPrevCeil );
5270         while ( iC-- > iP )
5271           angle += theAngles[ iC ];
5272       }
5273       res.push_back(angle);
5274       angPrev = angCur;
5275     }
5276     Angles.clear();
5277     it = res.begin();
5278     for(; it!=res.end(); it++)
5279       Angles.push_back( *it );
5280   }
5281 }
5282
5283
5284 //================================================================================
5285 /*!
5286  * \brief Move or copy theElements applying theTrsf to their nodes
5287  *  \param theElems - elements to transform, if theElems is empty then apply to all mesh nodes
5288  *  \param theTrsf - transformation to apply
5289  *  \param theCopy - if true, create translated copies of theElems
5290  *  \param theMakeGroups - if true and theCopy, create translated groups
5291  *  \param theTargetMesh - mesh to copy translated elements into
5292  *  \return SMESH_MeshEditor::PGroupIDs - list of ids of created groups
5293  */
5294 //================================================================================
5295
5296 SMESH_MeshEditor::PGroupIDs
5297 SMESH_MeshEditor::Transform (TIDSortedElemSet & theElems,
5298                              const gp_Trsf&     theTrsf,
5299                              const bool         theCopy,
5300                              const bool         theMakeGroups,
5301                              SMESH_Mesh*        theTargetMesh)
5302 {
5303   myLastCreatedElems.Clear();
5304   myLastCreatedNodes.Clear();
5305
5306   bool needReverse = false;
5307   string groupPostfix;
5308   switch ( theTrsf.Form() ) {
5309   case gp_PntMirror:
5310     MESSAGE("gp_PntMirror");
5311     needReverse = true;
5312     groupPostfix = "mirrored";
5313     break;
5314   case gp_Ax1Mirror:
5315     MESSAGE("gp_Ax1Mirror");
5316     groupPostfix = "mirrored";
5317     break;
5318   case gp_Ax2Mirror:
5319     MESSAGE("gp_Ax2Mirror");
5320     needReverse = true;
5321     groupPostfix = "mirrored";
5322     break;
5323   case gp_Rotation:
5324     MESSAGE("gp_Rotation");
5325     groupPostfix = "rotated";
5326     break;
5327   case gp_Translation:
5328     MESSAGE("gp_Translation");
5329     groupPostfix = "translated";
5330     break;
5331   case gp_Scale:
5332     MESSAGE("gp_Scale");
5333     groupPostfix = "scaled";
5334     break;
5335   case gp_CompoundTrsf: // different scale by axis
5336     MESSAGE("gp_CompoundTrsf");
5337     groupPostfix = "scaled";
5338     break;
5339   default:
5340     MESSAGE("default");
5341     needReverse = false;
5342     groupPostfix = "transformed";
5343   }
5344
5345   SMESH_MeshEditor targetMeshEditor( theTargetMesh );
5346   SMESHDS_Mesh* aTgtMesh = theTargetMesh ? theTargetMesh->GetMeshDS() : 0;
5347   SMESHDS_Mesh* aMesh    = GetMeshDS();
5348
5349
5350   // map old node to new one
5351   TNodeNodeMap nodeMap;
5352
5353   // elements sharing moved nodes; those of them which have all
5354   // nodes mirrored but are not in theElems are to be reversed
5355   TIDSortedElemSet inverseElemSet;
5356
5357   // source elements for each generated one
5358   SMESH_SequenceOfElemPtr srcElems, srcNodes;
5359
5360   // issue 021015: EDF 1578 SMESH: Free nodes are removed when translating a mesh
5361   TIDSortedElemSet orphanNode;
5362
5363   if ( theElems.empty() ) // transform the whole mesh
5364   {
5365     // add all elements
5366     SMDS_ElemIteratorPtr eIt = aMesh->elementsIterator();
5367     while ( eIt->more() ) theElems.insert( eIt->next() );
5368     // add orphan nodes
5369     SMDS_NodeIteratorPtr nIt = aMesh->nodesIterator();
5370     while ( nIt->more() )
5371     {
5372       const SMDS_MeshNode* node = nIt->next();
5373       if ( node->NbInverseElements() == 0)
5374         orphanNode.insert( node );
5375     }
5376   }
5377
5378   // loop on elements to transform nodes : first orphan nodes then elems
5379   TIDSortedElemSet::iterator itElem;
5380   TIDSortedElemSet *elements[] = {&orphanNode, &theElems };
5381   for (int i=0; i<2; i++)
5382   for ( itElem = elements[i]->begin(); itElem != elements[i]->end(); itElem++ ) {
5383     const SMDS_MeshElement* elem = *itElem;
5384     if ( !elem )
5385       continue;
5386
5387     // loop on elem nodes
5388     SMDS_ElemIteratorPtr itN = elem->nodesIterator();
5389     while ( itN->more() ) {
5390
5391       const SMDS_MeshNode* node = cast2Node( itN->next() );
5392       // check if a node has been already transformed
5393       pair<TNodeNodeMap::iterator,bool> n2n_isnew =
5394         nodeMap.insert( make_pair ( node, node ));
5395       if ( !n2n_isnew.second )
5396         continue;
5397
5398       double coord[3];
5399       coord[0] = node->X();
5400       coord[1] = node->Y();
5401       coord[2] = node->Z();
5402       theTrsf.Transforms( coord[0], coord[1], coord[2] );
5403       if ( theTargetMesh ) {
5404         const SMDS_MeshNode * newNode = aTgtMesh->AddNode( coord[0], coord[1], coord[2] );
5405         n2n_isnew.first->second = newNode;
5406         myLastCreatedNodes.Append(newNode);
5407         srcNodes.Append( node );
5408       }
5409       else if ( theCopy ) {
5410         const SMDS_MeshNode * newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
5411         n2n_isnew.first->second = newNode;
5412         myLastCreatedNodes.Append(newNode);
5413         srcNodes.Append( node );
5414       }
5415       else {
5416         aMesh->MoveNode( node, coord[0], coord[1], coord[2] );
5417         // node position on shape becomes invalid
5418         const_cast< SMDS_MeshNode* > ( node )->SetPosition
5419           ( SMDS_SpacePosition::originSpacePosition() );
5420       }
5421
5422       // keep inverse elements
5423       if ( !theCopy && !theTargetMesh && needReverse ) {
5424         SMDS_ElemIteratorPtr invElemIt = node->GetInverseElementIterator();
5425         while ( invElemIt->more() ) {
5426           const SMDS_MeshElement* iel = invElemIt->next();
5427           inverseElemSet.insert( iel );
5428         }
5429       }
5430     }
5431   }
5432
5433   // either create new elements or reverse mirrored ones
5434   if ( !theCopy && !needReverse && !theTargetMesh )
5435     return PGroupIDs();
5436
5437   TIDSortedElemSet::iterator invElemIt = inverseElemSet.begin();
5438   for ( ; invElemIt != inverseElemSet.end(); invElemIt++ )
5439     theElems.insert( *invElemIt );
5440
5441   // replicate or reverse elements
5442   // TODO revoir ordre reverse vtk
5443   enum {
5444     REV_TETRA   = 0,  //  = nbNodes - 4
5445     REV_PYRAMID = 1,  //  = nbNodes - 4
5446     REV_PENTA   = 2,  //  = nbNodes - 4
5447     REV_FACE    = 3,
5448     REV_HEXA    = 4,  //  = nbNodes - 4
5449     FORWARD     = 5
5450   };
5451   int index[][8] = {
5452     { 2, 1, 0, 3, 4, 0, 0, 0 },  // REV_TETRA
5453     { 2, 1, 0, 3, 4, 0, 0, 0 },  // REV_PYRAMID
5454     { 2, 1, 0, 5, 4, 3, 0, 0 },  // REV_PENTA
5455     { 2, 1, 0, 3, 0, 0, 0, 0 },  // REV_FACE
5456     { 2, 1, 0, 3, 6, 5, 4, 7 },  // REV_HEXA
5457     { 0, 1, 2, 3, 4, 5, 6, 7 }   // FORWARD
5458   };
5459
5460   for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ )
5461   {
5462     const SMDS_MeshElement* elem = *itElem;
5463     if ( !elem || elem->GetType() == SMDSAbs_Node )
5464       continue;
5465
5466     int nbNodes = elem->NbNodes();
5467     int elemType = elem->GetType();
5468
5469     if (elem->IsPoly()) {
5470       // Polygon or Polyhedral Volume
5471       switch ( elemType ) {
5472       case SMDSAbs_Face:
5473         {
5474           vector<const SMDS_MeshNode*> poly_nodes (nbNodes);
5475           int iNode = 0;
5476           SMDS_ElemIteratorPtr itN = elem->nodesIterator();
5477           while (itN->more()) {
5478             const SMDS_MeshNode* node =
5479               static_cast<const SMDS_MeshNode*>(itN->next());
5480             TNodeNodeMap::iterator nodeMapIt = nodeMap.find(node);
5481             if (nodeMapIt == nodeMap.end())
5482               break; // not all nodes transformed
5483             if (needReverse) {
5484               // reverse mirrored faces and volumes
5485               poly_nodes[nbNodes - iNode - 1] = (*nodeMapIt).second;
5486             } else {
5487               poly_nodes[iNode] = (*nodeMapIt).second;
5488             }
5489             iNode++;
5490           }
5491           if ( iNode != nbNodes )
5492             continue; // not all nodes transformed
5493
5494           if ( theTargetMesh ) {
5495             myLastCreatedElems.Append(aTgtMesh->AddPolygonalFace(poly_nodes));
5496             srcElems.Append( elem );
5497           }
5498           else if ( theCopy ) {
5499             myLastCreatedElems.Append(aMesh->AddPolygonalFace(poly_nodes));
5500             srcElems.Append( elem );
5501           }
5502           else {
5503             aMesh->ChangePolygonNodes(elem, poly_nodes);
5504           }
5505         }
5506         break;
5507       case SMDSAbs_Volume:
5508         {
5509           // ATTENTION: Reversing is not yet done!!!
5510           const SMDS_VtkVolume* aPolyedre =
5511             dynamic_cast<const SMDS_VtkVolume*>( elem );
5512           if (!aPolyedre) {
5513             MESSAGE("Warning: bad volumic element");
5514             continue;
5515           }
5516
5517           vector<const SMDS_MeshNode*> poly_nodes;
5518           vector<int> quantities;
5519
5520           bool allTransformed = true;
5521           int nbFaces = aPolyedre->NbFaces();
5522           for (int iface = 1; iface <= nbFaces && allTransformed; iface++) {
5523             int nbFaceNodes = aPolyedre->NbFaceNodes(iface);
5524             for (int inode = 1; inode <= nbFaceNodes && allTransformed; inode++) {
5525               const SMDS_MeshNode* node = aPolyedre->GetFaceNode(iface, inode);
5526               TNodeNodeMap::iterator nodeMapIt = nodeMap.find(node);
5527               if (nodeMapIt == nodeMap.end()) {
5528                 allTransformed = false; // not all nodes transformed
5529               } else {
5530                 poly_nodes.push_back((*nodeMapIt).second);
5531               }
5532             }
5533             quantities.push_back(nbFaceNodes);
5534           }
5535           if ( !allTransformed )
5536             continue; // not all nodes transformed
5537
5538           if ( theTargetMesh ) {
5539             myLastCreatedElems.Append(aTgtMesh->AddPolyhedralVolume(poly_nodes, quantities));
5540             srcElems.Append( elem );
5541           }
5542           else if ( theCopy ) {
5543             myLastCreatedElems.Append(aMesh->AddPolyhedralVolume(poly_nodes, quantities));
5544             srcElems.Append( elem );
5545           }
5546           else {
5547             aMesh->ChangePolyhedronNodes(elem, poly_nodes, quantities);
5548           }
5549         }
5550         break;
5551       default:;
5552       }
5553       continue;
5554     }
5555
5556     // Regular elements
5557     int* i = index[ FORWARD ];
5558     if ( needReverse && nbNodes > 2) {// reverse mirrored faces and volumes
5559       if ( elemType == SMDSAbs_Face )
5560         i = index[ REV_FACE ];
5561       else
5562         i = index[ nbNodes - 4 ];
5563     }
5564     if(elem->IsQuadratic()) {
5565       static int anIds[] = {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19};
5566       i = anIds;
5567       if(needReverse) {
5568         if(nbNodes==3) { // quadratic edge
5569           static int anIds[] = {1,0,2};
5570           i = anIds;
5571         }
5572         else if(nbNodes==6) { // quadratic triangle
5573           static int anIds[] = {0,2,1,5,4,3};
5574           i = anIds;
5575         }
5576         else if(nbNodes==8) { // quadratic quadrangle
5577           static int anIds[] = {0,3,2,1,7,6,5,4};
5578           i = anIds;
5579         }
5580         else if(nbNodes==10) { // quadratic tetrahedron of 10 nodes
5581           static int anIds[] = {0,2,1,3,6,5,4,7,9,8};
5582           i = anIds;
5583         }
5584         else if(nbNodes==13) { // quadratic pyramid of 13 nodes
5585           static int anIds[] = {0,3,2,1,4,8,7,6,5,9,12,11,10};
5586           i = anIds;
5587         }
5588         else if(nbNodes==15) { // quadratic pentahedron with 15 nodes
5589           static int anIds[] = {0,2,1,3,5,4,8,7,6,11,10,9,12,14,13};
5590           i = anIds;
5591         }
5592         else { // nbNodes==20 - quadratic hexahedron with 20 nodes
5593           static int anIds[] = {0,3,2,1,4,7,6,5,11,10,9,8,15,14,13,12,16,19,18,17};
5594           i = anIds;
5595         }
5596       }
5597     }
5598
5599     // find transformed nodes
5600     vector<const SMDS_MeshNode*> nodes(nbNodes);
5601     int iNode = 0;
5602     SMDS_ElemIteratorPtr itN = elem->nodesIterator();
5603     while ( itN->more() ) {
5604       const SMDS_MeshNode* node =
5605         static_cast<const SMDS_MeshNode*>( itN->next() );
5606       TNodeNodeMap::iterator nodeMapIt = nodeMap.find( node );
5607       if ( nodeMapIt == nodeMap.end() )
5608         break; // not all nodes transformed
5609       nodes[ i [ iNode++ ]] = (*nodeMapIt).second;
5610     }
5611     if ( iNode != nbNodes )
5612       continue; // not all nodes transformed
5613
5614     if ( theTargetMesh ) {
5615       if ( SMDS_MeshElement* copy =
5616            targetMeshEditor.AddElement( nodes, elem->GetType(), elem->IsPoly() )) {
5617         myLastCreatedElems.Append( copy );
5618         srcElems.Append( elem );
5619       }
5620     }
5621     else if ( theCopy ) {
5622       if ( AddElement( nodes, elem->GetType(), elem->IsPoly() ))
5623         srcElems.Append( elem );
5624     }
5625     else {
5626       // reverse element as it was reversed by transformation
5627       if ( nbNodes > 2 )
5628         aMesh->ChangeElementNodes( elem, &nodes[0], nbNodes );
5629     }
5630   }
5631
5632   PGroupIDs newGroupIDs;
5633
5634   if ( ( theMakeGroups && theCopy ) ||
5635        ( theMakeGroups && theTargetMesh ) )
5636     newGroupIDs = generateGroups( srcNodes, srcElems, groupPostfix, theTargetMesh );
5637
5638   return newGroupIDs;
5639 }
5640
5641
5642 ////=======================================================================
5643 ////function : Scale
5644 ////purpose  :
5645 ////=======================================================================
5646 //
5647 //SMESH_MeshEditor::PGroupIDs
5648 //SMESH_MeshEditor::Scale (TIDSortedElemSet & theElems,
5649 //                         const gp_Pnt&            thePoint,
5650 //                         const std::list<double>& theScaleFact,
5651 //                         const bool         theCopy,
5652 //                         const bool         theMakeGroups,
5653 //                         SMESH_Mesh*        theTargetMesh)
5654 //{
5655 //  MESSAGE("Scale");
5656 //  myLastCreatedElems.Clear();
5657 //  myLastCreatedNodes.Clear();
5658 //
5659 //  SMESH_MeshEditor targetMeshEditor( theTargetMesh );
5660 //  SMESHDS_Mesh* aTgtMesh = theTargetMesh ? theTargetMesh->GetMeshDS() : 0;
5661 //  SMESHDS_Mesh* aMesh    = GetMeshDS();
5662 //
5663 //  double scaleX=1.0, scaleY=1.0, scaleZ=1.0;
5664 //  std::list<double>::const_iterator itS = theScaleFact.begin();
5665 //  scaleX = (*itS);
5666 //  if(theScaleFact.size()==1) {
5667 //    scaleY = (*itS);
5668 //    scaleZ= (*itS);
5669 //  }
5670 //  if(theScaleFact.size()==2) {
5671 //    itS++;
5672 //    scaleY = (*itS);
5673 //    scaleZ= (*itS);
5674 //  }
5675 //  if(theScaleFact.size()>2) {
5676 //    itS++;
5677 //    scaleY = (*itS);
5678 //    itS++;
5679 //    scaleZ= (*itS);
5680 //  }
5681 //
5682 //  // map old node to new one
5683 //  TNodeNodeMap nodeMap;
5684 //
5685 //  // elements sharing moved nodes; those of them which have all
5686 //  // nodes mirrored but are not in theElems are to be reversed
5687 //  TIDSortedElemSet inverseElemSet;
5688 //
5689 //  // source elements for each generated one
5690 //  SMESH_SequenceOfElemPtr srcElems, srcNodes;
5691 //
5692 //  // loop on theElems
5693 //  TIDSortedElemSet::iterator itElem;
5694 //  for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
5695 //    const SMDS_MeshElement* elem = *itElem;
5696 //    if ( !elem )
5697 //      continue;
5698 //
5699 //    // loop on elem nodes
5700 //    SMDS_ElemIteratorPtr itN = elem->nodesIterator();
5701 //    while ( itN->more() ) {
5702 //
5703 //      // check if a node has been already transformed
5704 //      const SMDS_MeshNode* node = cast2Node( itN->next() );
5705 //      pair<TNodeNodeMap::iterator,bool> n2n_isnew =
5706 //        nodeMap.insert( make_pair ( node, node ));
5707 //      if ( !n2n_isnew.second )
5708 //        continue;
5709 //
5710 //      //double coord[3];
5711 //      //coord[0] = node->X();
5712 //      //coord[1] = node->Y();
5713 //      //coord[2] = node->Z();
5714 //      //theTrsf.Transforms( coord[0], coord[1], coord[2] );
5715 //      double dx = (node->X() - thePoint.X()) * scaleX;
5716 //      double dy = (node->Y() - thePoint.Y()) * scaleY;
5717 //      double dz = (node->Z() - thePoint.Z()) * scaleZ;
5718 //      if ( theTargetMesh ) {
5719 //        //const SMDS_MeshNode * newNode = aTgtMesh->AddNode( coord[0], coord[1], coord[2] );
5720 //        const SMDS_MeshNode * newNode =
5721 //          aTgtMesh->AddNode( thePoint.X()+dx, thePoint.Y()+dy, thePoint.Z()+dz );
5722 //        n2n_isnew.first->second = newNode;
5723 //        myLastCreatedNodes.Append(newNode);
5724 //        srcNodes.Append( node );
5725 //      }
5726 //      else if ( theCopy ) {
5727 //        //const SMDS_MeshNode * newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
5728 //        const SMDS_MeshNode * newNode =
5729 //          aMesh->AddNode( thePoint.X()+dx, thePoint.Y()+dy, thePoint.Z()+dz );
5730 //        n2n_isnew.first->second = newNode;
5731 //        myLastCreatedNodes.Append(newNode);
5732 //        srcNodes.Append( node );
5733 //      }
5734 //      else {
5735 //        //aMesh->MoveNode( node, coord[0], coord[1], coord[2] );
5736 //        aMesh->MoveNode( node, thePoint.X()+dx, thePoint.Y()+dy, thePoint.Z()+dz );
5737 //        // node position on shape becomes invalid
5738 //        const_cast< SMDS_MeshNode* > ( node )->SetPosition
5739 //          ( SMDS_SpacePosition::originSpacePosition() );
5740 //      }
5741 //
5742 //      // keep inverse elements
5743 //      //if ( !theCopy && !theTargetMesh && needReverse ) {
5744 //      //  SMDS_ElemIteratorPtr invElemIt = node->GetInverseElementIterator();
5745 //      //  while ( invElemIt->more() ) {
5746 //      //    const SMDS_MeshElement* iel = invElemIt->next();
5747 //      //    inverseElemSet.insert( iel );
5748 //      //  }
5749 //      //}
5750 //    }
5751 //  }
5752 //
5753 //  // either create new elements or reverse mirrored ones
5754 //  //if ( !theCopy && !needReverse && !theTargetMesh )
5755 //  if ( !theCopy && !theTargetMesh )
5756 //    return PGroupIDs();
5757 //
5758 //  TIDSortedElemSet::iterator invElemIt = inverseElemSet.begin();
5759 //  for ( ; invElemIt != inverseElemSet.end(); invElemIt++ )
5760 //    theElems.insert( *invElemIt );
5761 //
5762 //  // replicate or reverse elements
5763 //
5764 //  enum {
5765 //    REV_TETRA   = 0,  //  = nbNodes - 4
5766 //    REV_PYRAMID = 1,  //  = nbNodes - 4
5767 //    REV_PENTA   = 2,  //  = nbNodes - 4
5768 //    REV_FACE    = 3,
5769 //    REV_HEXA    = 4,  //  = nbNodes - 4
5770 //    FORWARD     = 5
5771 //  };
5772 //  int index[][8] = {
5773 //    { 2, 1, 0, 3, 4, 0, 0, 0 },  // REV_TETRA
5774 //    { 2, 1, 0, 3, 4, 0, 0, 0 },  // REV_PYRAMID
5775 //    { 2, 1, 0, 5, 4, 3, 0, 0 },  // REV_PENTA
5776 //    { 2, 1, 0, 3, 0, 0, 0, 0 },  // REV_FACE
5777 //    { 2, 1, 0, 3, 6, 5, 4, 7 },  // REV_HEXA
5778 //    { 0, 1, 2, 3, 4, 5, 6, 7 }   // FORWARD
5779 //  };
5780 //
5781 //  for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ )
5782 //  {
5783 //    const SMDS_MeshElement* elem = *itElem;
5784 //    if ( !elem || elem->GetType() == SMDSAbs_Node )
5785 //      continue;
5786 //
5787 //    int nbNodes = elem->NbNodes();
5788 //    int elemType = elem->GetType();
5789 //
5790 //    if (elem->IsPoly()) {
5791 //      // Polygon or Polyhedral Volume
5792 //      switch ( elemType ) {
5793 //      case SMDSAbs_Face:
5794 //        {
5795 //          vector<const SMDS_MeshNode*> poly_nodes (nbNodes);
5796 //          int iNode = 0;
5797 //          SMDS_ElemIteratorPtr itN = elem->nodesIterator();
5798 //          while (itN->more()) {
5799 //            const SMDS_MeshNode* node =
5800 //              static_cast<const SMDS_MeshNode*>(itN->next());
5801 //            TNodeNodeMap::iterator nodeMapIt = nodeMap.find(node);
5802 //            if (nodeMapIt == nodeMap.end())
5803 //              break; // not all nodes transformed
5804 //            //if (needReverse) {
5805 //            //  // reverse mirrored faces and volumes
5806 //            //  poly_nodes[nbNodes - iNode - 1] = (*nodeMapIt).second;
5807 //            //} else {
5808 //            poly_nodes[iNode] = (*nodeMapIt).second;
5809 //            //}
5810 //            iNode++;
5811 //          }
5812 //          if ( iNode != nbNodes )
5813 //            continue; // not all nodes transformed
5814 //
5815 //          if ( theTargetMesh ) {
5816 //            myLastCreatedElems.Append(aTgtMesh->AddPolygonalFace(poly_nodes));
5817 //            srcElems.Append( elem );
5818 //          }
5819 //          else if ( theCopy ) {
5820 //            myLastCreatedElems.Append(aMesh->AddPolygonalFace(poly_nodes));
5821 //            srcElems.Append( elem );
5822 //          }
5823 //          else {
5824 //            aMesh->ChangePolygonNodes(elem, poly_nodes);
5825 //          }
5826 //        }
5827 //        break;
5828 //      case SMDSAbs_Volume:
5829 //        {
5830 //          // ATTENTION: Reversing is not yet done!!!
5831 //          const SMDS_VtkVolume* aPolyedre =
5832 //            dynamic_cast<const SMDS_VtkVolume*>( elem );
5833 //          if (!aPolyedre) {
5834 //            MESSAGE("Warning: bad volumic element");
5835 //            continue;
5836 //          }
5837 //
5838 //          vector<const SMDS_MeshNode*> poly_nodes;
5839 //          vector<int> quantities;
5840 //
5841 //          bool allTransformed = true;
5842 //          int nbFaces = aPolyedre->NbFaces();
5843 //          for (int iface = 1; iface <= nbFaces && allTransformed; iface++) {
5844 //            int nbFaceNodes = aPolyedre->NbFaceNodes(iface);
5845 //            for (int inode = 1; inode <= nbFaceNodes && allTransformed; inode++) {
5846 //              const SMDS_MeshNode* node = aPolyedre->GetFaceNode(iface, inode);
5847 //              TNodeNodeMap::iterator nodeMapIt = nodeMap.find(node);
5848 //              if (nodeMapIt == nodeMap.end()) {
5849 //                allTransformed = false; // not all nodes transformed
5850 //              } else {
5851 //                poly_nodes.push_back((*nodeMapIt).second);
5852 //              }
5853 //            }
5854 //            quantities.push_back(nbFaceNodes);
5855 //          }
5856 //          if ( !allTransformed )
5857 //            continue; // not all nodes transformed
5858 //
5859 //          if ( theTargetMesh ) {
5860 //            myLastCreatedElems.Append(aTgtMesh->AddPolyhedralVolume(poly_nodes, quantities));
5861 //            srcElems.Append( elem );
5862 //          }
5863 //          else if ( theCopy ) {
5864 //            myLastCreatedElems.Append(aMesh->AddPolyhedralVolume(poly_nodes, quantities));
5865 //            srcElems.Append( elem );
5866 //          }
5867 //          else {
5868 //            aMesh->ChangePolyhedronNodes(elem, poly_nodes, quantities);
5869 //          }
5870 //        }
5871 //        break;
5872 //      default:;
5873 //      }
5874 //      continue;
5875 //    }
5876 //
5877 //    // Regular elements
5878 //    int* i = index[ FORWARD ];
5879 //    //if ( needReverse && nbNodes > 2) // reverse mirrored faces and volumes
5880 //    //  if ( elemType == SMDSAbs_Face )
5881 //    //    i = index[ REV_FACE ];
5882 //    //  else
5883 //    //    i = index[ nbNodes - 4 ];
5884 //
5885 //    if(elem->IsQuadratic()) {
5886 //      static int anIds[] = {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19};
5887 //      i = anIds;
5888 //      //if(needReverse) {
5889 //      //  if(nbNodes==3) { // quadratic edge
5890 //      //    static int anIds[] = {1,0,2};
5891 //      //    i = anIds;
5892 //      //  }
5893 //      //  else if(nbNodes==6) { // quadratic triangle
5894 //      //    static int anIds[] = {0,2,1,5,4,3};
5895 //      //    i = anIds;
5896 //      //  }
5897 //      //  else if(nbNodes==8) { // quadratic quadrangle
5898 //      //    static int anIds[] = {0,3,2,1,7,6,5,4};
5899 //      //    i = anIds;
5900 //      //  }
5901 //      //  else if(nbNodes==10) { // quadratic tetrahedron of 10 nodes
5902 //      //    static int anIds[] = {0,2,1,3,6,5,4,7,9,8};
5903 //      //    i = anIds;
5904 //      //  }
5905 //      //  else if(nbNodes==13) { // quadratic pyramid of 13 nodes
5906 //      //    static int anIds[] = {0,3,2,1,4,8,7,6,5,9,12,11,10};
5907 //      //    i = anIds;
5908 //      //  }
5909 //      //  else if(nbNodes==15) { // quadratic pentahedron with 15 nodes
5910 //      //    static int anIds[] = {0,2,1,3,5,4,8,7,6,11,10,9,12,14,13};
5911 //      //    i = anIds;
5912 //      //  }
5913 //      //  else { // nbNodes==20 - quadratic hexahedron with 20 nodes
5914 //      //    static int anIds[] = {0,3,2,1,4,7,6,5,11,10,9,8,15,14,13,12,16,19,18,17};
5915 //      //    i = anIds;
5916 //      //  }
5917 //      //}
5918 //    }
5919 //
5920 //    // find transformed nodes
5921 //    vector<const SMDS_MeshNode*> nodes(nbNodes);
5922 //    int iNode = 0;
5923 //    SMDS_ElemIteratorPtr itN = elem->nodesIterator();
5924 //    while ( itN->more() ) {
5925 //      const SMDS_MeshNode* node =
5926 //        static_cast<const SMDS_MeshNode*>( itN->next() );
5927 //      TNodeNodeMap::iterator nodeMapIt = nodeMap.find( node );
5928 //      if ( nodeMapIt == nodeMap.end() )
5929 //        break; // not all nodes transformed
5930 //      nodes[ i [ iNode++ ]] = (*nodeMapIt).second;
5931 //    }
5932 //    if ( iNode != nbNodes )
5933 //      continue; // not all nodes transformed
5934 //
5935 //    if ( theTargetMesh ) {
5936 //      if ( SMDS_MeshElement* copy =
5937 //           targetMeshEditor.AddElement( nodes, elem->GetType(), elem->IsPoly() )) {
5938 //        myLastCreatedElems.Append( copy );
5939 //        srcElems.Append( elem );
5940 //      }
5941 //    }
5942 //    else if ( theCopy ) {
5943 //      if ( SMDS_MeshElement* copy = AddElement( nodes, elem->GetType(), elem->IsPoly() )) {
5944 //        myLastCreatedElems.Append( copy );
5945 //        srcElems.Append( elem );
5946 //      }
5947 //    }
5948 //    else {
5949 //      // reverse element as it was reversed by transformation
5950 //      if ( nbNodes > 2 )
5951 //        aMesh->ChangeElementNodes( elem, &nodes[0], nbNodes );
5952 //    }
5953 //  }
5954 //
5955 //  PGroupIDs newGroupIDs;
5956 //
5957 //  if ( theMakeGroups && theCopy ||
5958 //       theMakeGroups && theTargetMesh ) {
5959 //    string groupPostfix = "scaled";
5960 //    newGroupIDs = generateGroups( srcNodes, srcElems, groupPostfix, theTargetMesh );
5961 //  }
5962 //
5963 //  return newGroupIDs;
5964 //}
5965
5966
5967 //=======================================================================
5968 /*!
5969  * \brief Create groups of elements made during transformation
5970  * \param nodeGens - nodes making corresponding myLastCreatedNodes
5971  * \param elemGens - elements making corresponding myLastCreatedElems
5972  * \param postfix - to append to names of new groups
5973  */
5974 //=======================================================================
5975
5976 SMESH_MeshEditor::PGroupIDs
5977 SMESH_MeshEditor::generateGroups(const SMESH_SequenceOfElemPtr& nodeGens,
5978                                  const SMESH_SequenceOfElemPtr& elemGens,
5979                                  const std::string&             postfix,
5980                                  SMESH_Mesh*                    targetMesh)
5981 {
5982   PGroupIDs newGroupIDs( new list<int> );
5983   SMESH_Mesh* mesh = targetMesh ? targetMesh : GetMesh();
5984
5985   // Sort existing groups by types and collect their names
5986
5987   // to store an old group and a generated new one
5988   typedef pair< SMESHDS_GroupBase*, SMDS_MeshGroup* > TOldNewGroup;
5989   vector< list< TOldNewGroup > > groupsByType( SMDSAbs_NbElementTypes );
5990   // group names
5991   set< string > groupNames;
5992   //
5993   SMDS_MeshGroup* nullNewGroup = (SMDS_MeshGroup*) 0;
5994   SMESH_Mesh::GroupIteratorPtr groupIt = GetMesh()->GetGroups();
5995   while ( groupIt->more() ) {
5996     SMESH_Group * group = groupIt->next();
5997     if ( !group ) continue;
5998     SMESHDS_GroupBase* groupDS = group->GetGroupDS();
5999     if ( !groupDS || groupDS->IsEmpty() ) continue;
6000     groupNames.insert( group->GetName() );
6001     groupDS->SetStoreName( group->GetName() );
6002     groupsByType[ groupDS->GetType() ].push_back( make_pair( groupDS, nullNewGroup ));
6003   }
6004
6005   // Groups creation
6006
6007   // loop on nodes and elements
6008   for ( int isNodes = 0; isNodes < 2; ++isNodes )
6009   {
6010     const SMESH_SequenceOfElemPtr& gens  = isNodes ? nodeGens : elemGens;
6011     const SMESH_SequenceOfElemPtr& elems = isNodes ? myLastCreatedNodes : myLastCreatedElems;
6012     if ( gens.Length() != elems.Length() )
6013       throw SALOME_Exception(LOCALIZED("invalid args"));
6014
6015     // loop on created elements
6016     for (int iElem = 1; iElem <= elems.Length(); ++iElem )
6017     {
6018       const SMDS_MeshElement* sourceElem = gens( iElem );
6019       if ( !sourceElem ) {
6020         MESSAGE("generateGroups(): NULL source element");
6021         continue;
6022       }
6023       list< TOldNewGroup > & groupsOldNew = groupsByType[ sourceElem->GetType() ];
6024       if ( groupsOldNew.empty() ) {
6025         while ( iElem < gens.Length() && gens( iElem+1 ) == sourceElem )
6026           ++iElem; // skip all elements made by sourceElem
6027         continue;
6028       }
6029       // collect all elements made by sourceElem
6030       list< const SMDS_MeshElement* > resultElems;
6031       if ( const SMDS_MeshElement* resElem = elems( iElem ))
6032         if ( resElem != sourceElem )
6033           resultElems.push_back( resElem );
6034       while ( iElem < gens.Length() && gens( iElem+1 ) == sourceElem )
6035         if ( const SMDS_MeshElement* resElem = elems( ++iElem ))
6036           if ( resElem != sourceElem )
6037             resultElems.push_back( resElem );
6038       // do not generate element groups from node ones
6039       if ( sourceElem->GetType() == SMDSAbs_Node &&
6040            elems( iElem )->GetType() != SMDSAbs_Node )
6041         continue;
6042
6043       // add resultElems to groups made by ones the sourceElem belongs to
6044       list< TOldNewGroup >::iterator gOldNew, gLast = groupsOldNew.end();
6045       for ( gOldNew = groupsOldNew.begin(); gOldNew != gLast; ++gOldNew )
6046       {
6047         SMESHDS_GroupBase* oldGroup = gOldNew->first;
6048         if ( oldGroup->Contains( sourceElem )) // sourceElem in oldGroup
6049         {
6050           SMDS_MeshGroup* & newGroup = gOldNew->second;
6051           if ( !newGroup )// create a new group
6052           {
6053             // make a name
6054             string name = oldGroup->GetStoreName();
6055             if ( !targetMesh ) {
6056               name += "_";
6057               name += postfix;
6058               int nb = 0;
6059               while ( !groupNames.insert( name ).second ) // name exists
6060               {
6061                 if ( nb == 0 ) {
6062                   name += "_1";
6063                 }
6064                 else {
6065                   TCollection_AsciiString nbStr(nb+1);
6066                   name.resize( name.rfind('_')+1 );
6067                   name += nbStr.ToCString();
6068                 }
6069                 ++nb;
6070               }
6071             }
6072             // make a group
6073             int id;
6074             SMESH_Group* group = mesh->AddGroup( resultElems.back()->GetType(),
6075                                                  name.c_str(), id );
6076             SMESHDS_Group* groupDS = static_cast<SMESHDS_Group*>(group->GetGroupDS());
6077             newGroup = & groupDS->SMDSGroup();
6078             newGroupIDs->push_back( id );
6079           }
6080
6081           // fill in a new group
6082           list< const SMDS_MeshElement* >::iterator resLast = resultElems.end(), resElemIt;
6083           for ( resElemIt = resultElems.begin(); resElemIt != resLast; ++resElemIt )
6084             newGroup->Add( *resElemIt );
6085         }
6086       }
6087     } // loop on created elements
6088   }// loop on nodes and elements
6089
6090   return newGroupIDs;
6091 }
6092
6093 //================================================================================
6094 /*!
6095  * \brief Return list of group of nodes close to each other within theTolerance
6096  *        Search among theNodes or in the whole mesh if theNodes is empty using
6097  *        an Octree algorithm
6098  */
6099 //================================================================================
6100
6101 void SMESH_MeshEditor::FindCoincidentNodes (TIDSortedNodeSet &   theNodes,
6102                                             const double         theTolerance,
6103                                             TListOfListOfNodes & theGroupsOfNodes)
6104 {
6105   myLastCreatedElems.Clear();
6106   myLastCreatedNodes.Clear();
6107
6108   if ( theNodes.empty() )
6109   { // get all nodes in the mesh
6110     SMDS_NodeIteratorPtr nIt = GetMeshDS()->nodesIterator(/*idInceasingOrder=*/true);
6111     while ( nIt->more() )
6112       theNodes.insert( theNodes.end(),nIt->next());
6113   }
6114
6115   SMESH_OctreeNode::FindCoincidentNodes ( theNodes, &theGroupsOfNodes, theTolerance);
6116 }
6117
6118
6119 //=======================================================================
6120 /*!
6121  * \brief Implementation of search for the node closest to point
6122  */
6123 //=======================================================================
6124
6125 struct SMESH_NodeSearcherImpl: public SMESH_NodeSearcher
6126 {
6127   //---------------------------------------------------------------------
6128   /*!
6129    * \brief Constructor
6130    */
6131   SMESH_NodeSearcherImpl( const SMESHDS_Mesh* theMesh )
6132   {
6133     myMesh = ( SMESHDS_Mesh* ) theMesh;
6134
6135     TIDSortedNodeSet nodes;
6136     if ( theMesh ) {
6137       SMDS_NodeIteratorPtr nIt = theMesh->nodesIterator(/*idInceasingOrder=*/true);
6138       while ( nIt->more() )
6139         nodes.insert( nodes.end(), nIt->next() );
6140     }
6141     myOctreeNode = new SMESH_OctreeNode(nodes) ;
6142
6143     // get max size of a leaf box
6144     SMESH_OctreeNode* tree = myOctreeNode;
6145     while ( !tree->isLeaf() )
6146     {
6147       SMESH_OctreeNodeIteratorPtr cIt = tree->GetChildrenIterator();
6148       if ( cIt->more() )
6149         tree = cIt->next();
6150     }
6151     myHalfLeafSize = tree->maxSize() / 2.;
6152   }
6153
6154   //---------------------------------------------------------------------
6155   /*!
6156    * \brief Move node and update myOctreeNode accordingly
6157    */
6158   void MoveNode( const SMDS_MeshNode* node, const gp_Pnt& toPnt )
6159   {
6160     myOctreeNode->UpdateByMoveNode( node, toPnt );
6161     myMesh->MoveNode( node, toPnt.X(), toPnt.Y(), toPnt.Z() );
6162   }
6163
6164   //---------------------------------------------------------------------
6165   /*!
6166    * \brief Do it's job
6167    */
6168   const SMDS_MeshNode* FindClosestTo( const gp_Pnt& thePnt )
6169   {
6170     map<double, const SMDS_MeshNode*> dist2Nodes;
6171     myOctreeNode->NodesAround( thePnt.Coord(), dist2Nodes, myHalfLeafSize );
6172     if ( !dist2Nodes.empty() )
6173       return dist2Nodes.begin()->second;
6174     list<const SMDS_MeshNode*> nodes;
6175     //myOctreeNode->NodesAround( &tgtNode, &nodes, myHalfLeafSize );
6176
6177     double minSqDist = DBL_MAX;
6178     if ( nodes.empty() )  // get all nodes of OctreeNode's closest to thePnt
6179     {
6180       // sort leafs by their distance from thePnt
6181       typedef map< double, SMESH_OctreeNode* > TDistTreeMap;
6182       TDistTreeMap treeMap;
6183       list< SMESH_OctreeNode* > treeList;
6184       list< SMESH_OctreeNode* >::iterator trIt;
6185       treeList.push_back( myOctreeNode );
6186
6187       gp_XYZ pointNode( thePnt.X(), thePnt.Y(), thePnt.Z() );
6188       bool pointInside = myOctreeNode->isInside( pointNode, myHalfLeafSize );
6189       for ( trIt = treeList.begin(); trIt != treeList.end(); ++trIt)
6190       {
6191         SMESH_OctreeNode* tree = *trIt;
6192         if ( !tree->isLeaf() ) // put children to the queue
6193         {
6194           if ( pointInside && !tree->isInside( pointNode, myHalfLeafSize )) continue;
6195           SMESH_OctreeNodeIteratorPtr cIt = tree->GetChildrenIterator();
6196           while ( cIt->more() )
6197             treeList.push_back( cIt->next() );
6198         }
6199         else if ( tree->NbNodes() ) // put a tree to the treeMap
6200         {
6201           const Bnd_B3d& box = tree->getBox();
6202           double sqDist = thePnt.SquareDistance( 0.5 * ( box.CornerMin() + box.CornerMax() ));
6203           pair<TDistTreeMap::iterator,bool> it_in = treeMap.insert( make_pair( sqDist, tree ));
6204           if ( !it_in.second ) // not unique distance to box center
6205             treeMap.insert( it_in.first, make_pair( sqDist + 1e-13*treeMap.size(), tree ));
6206         }
6207       }
6208       // find distance after which there is no sense to check tree's
6209       double sqLimit = DBL_MAX;
6210       TDistTreeMap::iterator sqDist_tree = treeMap.begin();
6211       if ( treeMap.size() > 5 ) {
6212         SMESH_OctreeNode* closestTree = sqDist_tree->second;
6213         const Bnd_B3d& box = closestTree->getBox();
6214         double limit = sqrt( sqDist_tree->first ) + sqrt ( box.SquareExtent() );
6215         sqLimit = limit * limit;
6216       }
6217       // get all nodes from trees
6218       for ( ; sqDist_tree != treeMap.end(); ++sqDist_tree) {
6219         if ( sqDist_tree->first > sqLimit )
6220           break;
6221         SMESH_OctreeNode* tree = sqDist_tree->second;
6222         tree->NodesAround( tree->GetNodeIterator()->next(), &nodes );
6223       }
6224     }
6225     // find closest among nodes
6226     minSqDist = DBL_MAX;
6227     const SMDS_MeshNode* closestNode = 0;
6228     list<const SMDS_MeshNode*>::iterator nIt = nodes.begin();
6229     for ( ; nIt != nodes.end(); ++nIt ) {
6230       double sqDist = thePnt.SquareDistance( SMESH_TNodeXYZ( *nIt ) );
6231       if ( minSqDist > sqDist ) {
6232         closestNode = *nIt;
6233         minSqDist = sqDist;
6234       }
6235     }
6236     return closestNode;
6237   }
6238
6239   //---------------------------------------------------------------------
6240   /*!
6241    * \brief Destructor
6242    */
6243   ~SMESH_NodeSearcherImpl() { delete myOctreeNode; }
6244
6245   //---------------------------------------------------------------------
6246   /*!
6247    * \brief Return the node tree
6248    */
6249   const SMESH_OctreeNode* getTree() const { return myOctreeNode; }
6250
6251 private:
6252   SMESH_OctreeNode* myOctreeNode;
6253   SMESHDS_Mesh*     myMesh;
6254   double            myHalfLeafSize; // max size of a leaf box
6255 };
6256
6257 //=======================================================================
6258 /*!
6259  * \brief Return SMESH_NodeSearcher
6260  */
6261 //=======================================================================
6262
6263 SMESH_NodeSearcher* SMESH_MeshEditor::GetNodeSearcher() 
6264 {
6265   return new SMESH_NodeSearcherImpl( GetMeshDS() );
6266 }
6267
6268 // ========================================================================
6269 namespace // Utils used in SMESH_ElementSearcherImpl::FindElementsByPoint()
6270 {
6271   const int MaxNbElemsInLeaf = 10; // maximal number of elements in a leaf of tree
6272   const int MaxLevel         = 7;  // maximal tree height -> nb terminal boxes: 8^7 = 2097152
6273   const double NodeRadius = 1e-9;  // to enlarge bnd box of element
6274
6275   //=======================================================================
6276   /*!
6277    * \brief Octal tree of bounding boxes of elements
6278    */
6279   //=======================================================================
6280
6281   class ElementBndBoxTree : public SMESH_Octree
6282   {
6283   public:
6284
6285     ElementBndBoxTree(const SMDS_Mesh& mesh, SMDSAbs_ElementType elemType, SMDS_ElemIteratorPtr theElemIt = SMDS_ElemIteratorPtr(), double tolerance = NodeRadius );
6286     void getElementsNearPoint( const gp_Pnt& point, TIDSortedElemSet& foundElems);
6287     void getElementsNearLine ( const gp_Ax1& line, TIDSortedElemSet& foundElems);
6288     ~ElementBndBoxTree();
6289
6290   protected:
6291     ElementBndBoxTree() {}
6292     SMESH_Octree* allocateOctreeChild() const { return new ElementBndBoxTree; }
6293     void buildChildrenData();
6294     Bnd_B3d* buildRootBox();
6295   private:
6296     //!< Bounding box of element
6297     struct ElementBox : public Bnd_B3d
6298     {
6299       const SMDS_MeshElement* _element;
6300       int                     _refCount; // an ElementBox can be included in several tree branches
6301       ElementBox(const SMDS_MeshElement* elem, double tolerance);
6302     };
6303     vector< ElementBox* > _elements;
6304   };
6305
6306   //================================================================================
6307   /*!
6308    * \brief ElementBndBoxTree creation
6309    */
6310   //================================================================================
6311
6312   ElementBndBoxTree::ElementBndBoxTree(const SMDS_Mesh& mesh, SMDSAbs_ElementType elemType, SMDS_ElemIteratorPtr theElemIt, double tolerance)
6313     :SMESH_Octree( new SMESH_Octree::Limit( MaxLevel, /*minSize=*/0. ))
6314   {
6315     int nbElems = mesh.GetMeshInfo().NbElements( elemType );
6316     _elements.reserve( nbElems );
6317
6318     SMDS_ElemIteratorPtr elemIt = theElemIt ? theElemIt : mesh.elementsIterator( elemType );
6319     while ( elemIt->more() )
6320       _elements.push_back( new ElementBox( elemIt->next(),tolerance  ));
6321
6322     if ( _elements.size() > MaxNbElemsInLeaf )
6323       compute();
6324     else
6325       myIsLeaf = true;
6326   }
6327
6328   //================================================================================
6329   /*!
6330    * \brief Destructor
6331    */
6332   //================================================================================
6333
6334   ElementBndBoxTree::~ElementBndBoxTree()
6335   {
6336     for ( int i = 0; i < _elements.size(); ++i )
6337       if ( --_elements[i]->_refCount <= 0 )
6338         delete _elements[i];
6339   }
6340
6341   //================================================================================
6342   /*!
6343    * \brief Return the maximal box
6344    */
6345   //================================================================================
6346
6347   Bnd_B3d* ElementBndBoxTree::buildRootBox()
6348   {
6349     Bnd_B3d* box = new Bnd_B3d;
6350     for ( int i = 0; i < _elements.size(); ++i )
6351       box->Add( *_elements[i] );
6352     return box;
6353   }
6354
6355   //================================================================================
6356   /*!
6357    * \brief Redistrubute element boxes among children
6358    */
6359   //================================================================================
6360
6361   void ElementBndBoxTree::buildChildrenData()
6362   {
6363     for ( int i = 0; i < _elements.size(); ++i )
6364     {
6365       for (int j = 0; j < 8; j++)
6366       {
6367         if ( !_elements[i]->IsOut( myChildren[j]->getBox() ))
6368         {
6369           _elements[i]->_refCount++;
6370           ((ElementBndBoxTree*)myChildren[j])->_elements.push_back( _elements[i]);
6371         }
6372       }
6373       _elements[i]->_refCount--;
6374     }
6375     _elements.clear();
6376
6377     for (int j = 0; j < 8; j++)
6378     {
6379       ElementBndBoxTree* child = static_cast<ElementBndBoxTree*>( myChildren[j]);
6380       if ( child->_elements.size() <= MaxNbElemsInLeaf )
6381         child->myIsLeaf = true;
6382
6383       if ( child->_elements.capacity() - child->_elements.size() > 1000 )
6384         child->_elements.resize( child->_elements.size() ); // compact
6385     }
6386   }
6387
6388   //================================================================================
6389   /*!
6390    * \brief Return elements which can include the point
6391    */
6392   //================================================================================
6393
6394   void ElementBndBoxTree::getElementsNearPoint( const gp_Pnt&     point,
6395                                                 TIDSortedElemSet& foundElems)
6396   {
6397     if ( level() && getBox().IsOut( point.XYZ() ))
6398       return;
6399
6400     if ( isLeaf() )
6401     {
6402       for ( int i = 0; i < _elements.size(); ++i )
6403         if ( !_elements[i]->IsOut( point.XYZ() ))
6404           foundElems.insert( _elements[i]->_element );
6405     }
6406     else
6407     {
6408       for (int i = 0; i < 8; i++)
6409         ((ElementBndBoxTree*) myChildren[i])->getElementsNearPoint( point, foundElems );
6410     }
6411   }
6412
6413   //================================================================================
6414   /*!
6415    * \brief Return elements which can be intersected by the line
6416    */
6417   //================================================================================
6418
6419   void ElementBndBoxTree::getElementsNearLine( const gp_Ax1&     line,
6420                                                TIDSortedElemSet& foundElems)
6421   {
6422     if ( level() && getBox().IsOut( line ))
6423       return;
6424
6425     if ( isLeaf() )
6426     {
6427       for ( int i = 0; i < _elements.size(); ++i )
6428         if ( !_elements[i]->IsOut( line ))
6429           foundElems.insert( _elements[i]->_element );
6430     }
6431     else
6432     {
6433       for (int i = 0; i < 8; i++)
6434         ((ElementBndBoxTree*) myChildren[i])->getElementsNearLine( line, foundElems );
6435     }
6436   }
6437
6438   //================================================================================
6439   /*!
6440    * \brief Construct the element box
6441    */
6442   //================================================================================
6443
6444   ElementBndBoxTree::ElementBox::ElementBox(const SMDS_MeshElement* elem, double tolerance)
6445   {
6446     _element  = elem;
6447     _refCount = 1;
6448     SMDS_ElemIteratorPtr nIt = elem->nodesIterator();
6449     while ( nIt->more() )
6450       Add( SMESH_TNodeXYZ( cast2Node( nIt->next() )));
6451     Enlarge( tolerance );
6452   }
6453
6454 } // namespace
6455
6456 //=======================================================================
6457 /*!
6458  * \brief Implementation of search for the elements by point and
6459  *        of classification of point in 2D mesh
6460  */
6461 //=======================================================================
6462
6463 struct SMESH_ElementSearcherImpl: public SMESH_ElementSearcher
6464 {
6465   SMESHDS_Mesh*                _mesh;
6466   SMDS_ElemIteratorPtr         _meshPartIt;
6467   ElementBndBoxTree*           _ebbTree;
6468   SMESH_NodeSearcherImpl*      _nodeSearcher;
6469   SMDSAbs_ElementType          _elementType;
6470   double                       _tolerance;
6471   bool                         _outerFacesFound;
6472   set<const SMDS_MeshElement*> _outerFaces; // empty means "no internal faces at all"
6473
6474   SMESH_ElementSearcherImpl( SMESHDS_Mesh& mesh, SMDS_ElemIteratorPtr elemIt=SMDS_ElemIteratorPtr())
6475     : _mesh(&mesh),_meshPartIt(elemIt),_ebbTree(0),_nodeSearcher(0),_tolerance(-1),_outerFacesFound(false) {}
6476   ~SMESH_ElementSearcherImpl()
6477   {
6478     if ( _ebbTree )      delete _ebbTree;      _ebbTree      = 0;
6479     if ( _nodeSearcher ) delete _nodeSearcher; _nodeSearcher = 0;
6480   }
6481   virtual int FindElementsByPoint(const gp_Pnt&                      point,
6482                                   SMDSAbs_ElementType                type,
6483                                   vector< const SMDS_MeshElement* >& foundElements);
6484   virtual TopAbs_State GetPointState(const gp_Pnt& point);
6485
6486   void GetElementsNearLine( const gp_Ax1&                      line,
6487                             SMDSAbs_ElementType                type,
6488                             vector< const SMDS_MeshElement* >& foundElems);
6489   double getTolerance();
6490   bool getIntersParamOnLine(const gp_Lin& line, const SMDS_MeshElement* face,
6491                             const double tolerance, double & param);
6492   void findOuterBoundary(const SMDS_MeshElement* anyOuterFace);
6493   bool isOuterBoundary(const SMDS_MeshElement* face) const
6494   {
6495     return _outerFaces.empty() || _outerFaces.count(face);
6496   }
6497   struct TInters //!< data of intersection of the line and the mesh face (used in GetPointState())
6498   {
6499     const SMDS_MeshElement* _face;
6500     gp_Vec                  _faceNorm;
6501     bool                    _coincides; //!< the line lays in face plane
6502     TInters(const SMDS_MeshElement* face, const gp_Vec& faceNorm, bool coinc=false)
6503       : _face(face), _faceNorm( faceNorm ), _coincides( coinc ) {}
6504   };
6505   struct TFaceLink //!< link and faces sharing it (used in findOuterBoundary())
6506   {
6507     SMESH_TLink      _link;
6508     TIDSortedElemSet _faces;
6509     TFaceLink( const SMDS_MeshNode* n1, const SMDS_MeshNode* n2, const SMDS_MeshElement* face)
6510       : _link( n1, n2 ), _faces( &face, &face + 1) {}
6511   };
6512 };
6513
6514 ostream& operator<< (ostream& out, const SMESH_ElementSearcherImpl::TInters& i)
6515 {
6516   return out << "TInters(face=" << ( i._face ? i._face->GetID() : 0)
6517              << ", _coincides="<<i._coincides << ")";
6518 }
6519
6520 //=======================================================================
6521 /*!
6522  * \brief define tolerance for search
6523  */
6524 //=======================================================================
6525
6526 double SMESH_ElementSearcherImpl::getTolerance()
6527 {
6528   if ( _tolerance < 0 )
6529   {
6530     const SMDS_MeshInfo& meshInfo = _mesh->GetMeshInfo();
6531
6532     _tolerance = 0;
6533     if ( _nodeSearcher && meshInfo.NbNodes() > 1 )
6534     {
6535       double boxSize = _nodeSearcher->getTree()->maxSize();
6536       _tolerance = 1e-8 * boxSize/* / meshInfo.NbNodes()*/;
6537     }
6538     else if ( _ebbTree && meshInfo.NbElements() > 0 )
6539     {
6540       double boxSize = _ebbTree->maxSize();
6541       _tolerance = 1e-8 * boxSize/* / meshInfo.NbElements()*/;
6542     }
6543     if ( _tolerance == 0 )
6544     {
6545       // define tolerance by size of a most complex element
6546       int complexType = SMDSAbs_Volume;
6547       while ( complexType > SMDSAbs_All &&
6548               meshInfo.NbElements( SMDSAbs_ElementType( complexType )) < 1 )
6549         --complexType;
6550       if ( complexType == SMDSAbs_All ) return 0; // empty mesh
6551       double elemSize;
6552       if ( complexType == int( SMDSAbs_Node ))
6553       {
6554         SMDS_NodeIteratorPtr nodeIt = _mesh->nodesIterator();
6555         elemSize = 1;
6556         if ( meshInfo.NbNodes() > 2 )
6557           elemSize = SMESH_TNodeXYZ( nodeIt->next() ).Distance( nodeIt->next() );
6558       }
6559       else
6560       {
6561         SMDS_ElemIteratorPtr elemIt =
6562             _mesh->elementsIterator( SMDSAbs_ElementType( complexType ));
6563         const SMDS_MeshElement* elem = elemIt->next();
6564         SMDS_ElemIteratorPtr nodeIt = elem->nodesIterator();
6565         SMESH_TNodeXYZ n1( cast2Node( nodeIt->next() ));
6566         elemSize = 0;
6567         while ( nodeIt->more() )
6568         {
6569           double dist = n1.Distance( cast2Node( nodeIt->next() ));
6570           elemSize = max( dist, elemSize );
6571         }
6572       }
6573       _tolerance = 1e-4 * elemSize;
6574     }
6575   }
6576   return _tolerance;
6577 }
6578
6579 //================================================================================
6580 /*!
6581  * \brief Find intersection of the line and an edge of face and return parameter on line
6582  */
6583 //================================================================================
6584
6585 bool SMESH_ElementSearcherImpl::getIntersParamOnLine(const gp_Lin&           line,
6586                                                      const SMDS_MeshElement* face,
6587                                                      const double            tol,
6588                                                      double &                param)
6589 {
6590   int nbInts = 0;
6591   param = 0;
6592
6593   GeomAPI_ExtremaCurveCurve anExtCC;
6594   Handle(Geom_Curve) lineCurve = new Geom_Line( line );
6595   
6596   int nbNodes = face->IsQuadratic() ? face->NbNodes()/2 : face->NbNodes();
6597   for ( int i = 0; i < nbNodes && nbInts < 2; ++i )
6598   {
6599     GC_MakeSegment edge( SMESH_TNodeXYZ( face->GetNode( i )),
6600                          SMESH_TNodeXYZ( face->GetNode( (i+1)%nbNodes) )); 
6601     anExtCC.Init( lineCurve, edge);
6602     if ( anExtCC.NbExtrema() > 0 && anExtCC.LowerDistance() <= tol)
6603     {
6604       Quantity_Parameter pl, pe;
6605       anExtCC.LowerDistanceParameters( pl, pe );
6606       param += pl;
6607       if ( ++nbInts == 2 )
6608         break;
6609     }
6610   }
6611   if ( nbInts > 0 ) param /= nbInts;
6612   return nbInts > 0;
6613 }
6614 //================================================================================
6615 /*!
6616  * \brief Find all faces belonging to the outer boundary of mesh
6617  */
6618 //================================================================================
6619
6620 void SMESH_ElementSearcherImpl::findOuterBoundary(const SMDS_MeshElement* outerFace)
6621 {
6622   if ( _outerFacesFound ) return;
6623
6624   // Collect all outer faces by passing from one outer face to another via their links
6625   // and BTW find out if there are internal faces at all.
6626
6627   // checked links and links where outer boundary meets internal one
6628   set< SMESH_TLink > visitedLinks, seamLinks;
6629
6630   // links to treat with already visited faces sharing them
6631   list < TFaceLink > startLinks;
6632
6633   // load startLinks with the first outerFace
6634   startLinks.push_back( TFaceLink( outerFace->GetNode(0), outerFace->GetNode(1), outerFace));
6635   _outerFaces.insert( outerFace );
6636
6637   TIDSortedElemSet emptySet;
6638   while ( !startLinks.empty() )
6639   {
6640     const SMESH_TLink& link  = startLinks.front()._link;
6641     TIDSortedElemSet&  faces = startLinks.front()._faces;
6642
6643     outerFace = *faces.begin();
6644     // find other faces sharing the link
6645     const SMDS_MeshElement* f;
6646     while (( f = SMESH_MeshEditor::FindFaceInSet(link.node1(), link.node2(), emptySet, faces )))
6647       faces.insert( f );
6648
6649     // select another outer face among the found 
6650     const SMDS_MeshElement* outerFace2 = 0;
6651     if ( faces.size() == 2 )
6652     {
6653       outerFace2 = (outerFace == *faces.begin() ? *faces.rbegin() : *faces.begin());
6654     }
6655     else if ( faces.size() > 2 )
6656     {
6657       seamLinks.insert( link );
6658
6659       // link direction within the outerFace
6660       gp_Vec n1n2( SMESH_TNodeXYZ( link.node1()),
6661                    SMESH_TNodeXYZ( link.node2()));
6662       int i1 = outerFace->GetNodeIndex( link.node1() );
6663       int i2 = outerFace->GetNodeIndex( link.node2() );
6664       bool rev = ( abs(i2-i1) == 1 ? i1 > i2 : i2 > i1 );
6665       if ( rev ) n1n2.Reverse();
6666       // outerFace normal
6667       gp_XYZ ofNorm, fNorm;
6668       if ( SMESH_Algo::FaceNormal( outerFace, ofNorm, /*normalized=*/false ))
6669       {
6670         // direction from the link inside outerFace
6671         gp_Vec dirInOF = gp_Vec( ofNorm ) ^ n1n2;
6672         // sort all other faces by angle with the dirInOF
6673         map< double, const SMDS_MeshElement* > angle2Face;
6674         set< const SMDS_MeshElement*, TIDCompare >::const_iterator face = faces.begin();
6675         for ( ; face != faces.end(); ++face )
6676         {
6677           if ( !SMESH_Algo::FaceNormal( *face, fNorm, /*normalized=*/false ))
6678             continue;
6679           gp_Vec dirInF = gp_Vec( fNorm ) ^ n1n2;
6680           double angle = dirInOF.AngleWithRef( dirInF, n1n2 );
6681           if ( angle < 0 ) angle += 2*PI;
6682           angle2Face.insert( make_pair( angle, *face ));
6683         }
6684         if ( !angle2Face.empty() )
6685           outerFace2 = angle2Face.begin()->second;
6686       }
6687     }
6688     // store the found outer face and add its links to continue seaching from
6689     if ( outerFace2 )
6690     {
6691       _outerFaces.insert( outerFace );
6692       int nbNodes = outerFace2->NbNodes()/( outerFace2->IsQuadratic() ? 2 : 1 );
6693       for ( int i = 0; i < nbNodes; ++i )
6694       {
6695         SMESH_TLink link2( outerFace2->GetNode(i), outerFace2->GetNode((i+1)%nbNodes));
6696         if ( visitedLinks.insert( link2 ).second )
6697           startLinks.push_back( TFaceLink( link2.node1(), link2.node2(), outerFace2 ));
6698       }
6699     }
6700     startLinks.pop_front();
6701   }
6702   _outerFacesFound = true;
6703
6704   if ( !seamLinks.empty() )
6705   {
6706     // There are internal boundaries touching the outher one,
6707     // find all faces of internal boundaries in order to find
6708     // faces of boundaries of holes, if any.
6709     
6710   }
6711   else
6712   {
6713     _outerFaces.clear();
6714   }
6715 }
6716
6717 //=======================================================================
6718 /*!
6719  * \brief Find elements of given type where the given point is IN or ON.
6720  *        Returns nb of found elements and elements them-selves.
6721  *
6722  * 'ALL' type means elements of any type excluding nodes and 0D elements
6723  */
6724 //=======================================================================
6725
6726 int SMESH_ElementSearcherImpl::
6727 FindElementsByPoint(const gp_Pnt&                      point,
6728                     SMDSAbs_ElementType                type,
6729                     vector< const SMDS_MeshElement* >& foundElements)
6730 {
6731   foundElements.clear();
6732
6733   double tolerance = getTolerance();
6734
6735   // =================================================================================
6736   if ( type == SMDSAbs_Node || type == SMDSAbs_0DElement )
6737   {
6738     if ( !_nodeSearcher )
6739       _nodeSearcher = new SMESH_NodeSearcherImpl( _mesh );
6740
6741     const SMDS_MeshNode* closeNode = _nodeSearcher->FindClosestTo( point );
6742     if ( !closeNode ) return foundElements.size();
6743
6744     if ( point.Distance( SMESH_TNodeXYZ( closeNode )) > tolerance )
6745       return foundElements.size(); // to far from any node
6746
6747     if ( type == SMDSAbs_Node )
6748     {
6749       foundElements.push_back( closeNode );
6750     }
6751     else
6752     {
6753       SMDS_ElemIteratorPtr elemIt = closeNode->GetInverseElementIterator( SMDSAbs_0DElement );
6754       while ( elemIt->more() )
6755         foundElements.push_back( elemIt->next() );
6756     }
6757   }
6758   // =================================================================================
6759   else // elements more complex than 0D
6760   {
6761     if ( !_ebbTree || _elementType != type )
6762     {
6763       if ( _ebbTree ) delete _ebbTree;
6764       _ebbTree = new ElementBndBoxTree( *_mesh, _elementType = type, _meshPartIt, tolerance );
6765     }
6766     TIDSortedElemSet suspectElems;
6767     _ebbTree->getElementsNearPoint( point, suspectElems );
6768     TIDSortedElemSet::iterator elem = suspectElems.begin();
6769     for ( ; elem != suspectElems.end(); ++elem )
6770       if ( !SMESH_MeshEditor::isOut( *elem, point, tolerance ))
6771         foundElements.push_back( *elem );
6772   }
6773   return foundElements.size();
6774 }
6775
6776 //================================================================================
6777 /*!
6778  * \brief Classify the given point in the closed 2D mesh
6779  */
6780 //================================================================================
6781
6782 TopAbs_State SMESH_ElementSearcherImpl::GetPointState(const gp_Pnt& point)
6783 {
6784   double tolerance = getTolerance();
6785   if ( !_ebbTree || _elementType != SMDSAbs_Face )
6786   {
6787     if ( _ebbTree ) delete _ebbTree;
6788     _ebbTree = new ElementBndBoxTree( *_mesh, _elementType = SMDSAbs_Face, _meshPartIt );
6789   }
6790   // Algo: analyse transition of a line starting at the point through mesh boundary;
6791   // try three lines parallel to axis of the coordinate system and perform rough
6792   // analysis. If solution is not clear perform thorough analysis.
6793
6794   const int nbAxes = 3;
6795   gp_Dir axisDir[ nbAxes ] = { gp::DX(), gp::DY(), gp::DZ() };
6796   map< double, TInters >   paramOnLine2TInters[ nbAxes ];
6797   list< TInters > tangentInters[ nbAxes ]; // of faces whose plane includes the line
6798   multimap< int, int > nbInt2Axis; // to find the simplest case
6799   for ( int axis = 0; axis < nbAxes; ++axis )
6800   {
6801     gp_Ax1 lineAxis( point, axisDir[axis]);
6802     gp_Lin line    ( lineAxis );
6803
6804     TIDSortedElemSet suspectFaces; // faces possibly intersecting the line
6805     _ebbTree->getElementsNearLine( lineAxis, suspectFaces );
6806
6807     // Intersect faces with the line
6808
6809     map< double, TInters > & u2inters = paramOnLine2TInters[ axis ];
6810     TIDSortedElemSet::iterator face = suspectFaces.begin();
6811     for ( ; face != suspectFaces.end(); ++face )
6812     {
6813       // get face plane
6814       gp_XYZ fNorm;
6815       if ( !SMESH_Algo::FaceNormal( *face, fNorm, /*normalized=*/false)) continue;
6816       gp_Pln facePlane( SMESH_TNodeXYZ( (*face)->GetNode(0)), fNorm );
6817
6818       // perform intersection
6819       IntAna_IntConicQuad intersection( line, IntAna_Quadric( facePlane ));
6820       if ( !intersection.IsDone() )
6821         continue;
6822       if ( intersection.IsInQuadric() )
6823       {
6824         tangentInters[ axis ].push_back( TInters( *face, fNorm, true ));
6825       }
6826       else if ( ! intersection.IsParallel() && intersection.NbPoints() > 0 )
6827       {
6828         gp_Pnt intersectionPoint = intersection.Point(1);
6829         if ( !SMESH_MeshEditor::isOut( *face, intersectionPoint, tolerance ))
6830           u2inters.insert(make_pair( intersection.ParamOnConic(1), TInters( *face, fNorm )));
6831       }
6832     }
6833     // Analyse intersections roughly
6834
6835     int nbInter = u2inters.size();
6836     if ( nbInter == 0 )
6837       return TopAbs_OUT; 
6838
6839     double f = u2inters.begin()->first, l = u2inters.rbegin()->first;
6840     if ( nbInter == 1 ) // not closed mesh
6841       return fabs( f ) < tolerance ? TopAbs_ON : TopAbs_UNKNOWN;
6842
6843     if ( fabs( f ) < tolerance || fabs( l ) < tolerance )
6844       return TopAbs_ON;
6845
6846     if ( (f<0) == (l<0) )
6847       return TopAbs_OUT;
6848
6849     int nbIntBeforePoint = std::distance( u2inters.begin(), u2inters.lower_bound(0));
6850     int nbIntAfterPoint  = nbInter - nbIntBeforePoint;
6851     if ( nbIntBeforePoint == 1 || nbIntAfterPoint == 1 )
6852       return TopAbs_IN;
6853
6854     nbInt2Axis.insert( make_pair( min( nbIntBeforePoint, nbIntAfterPoint ), axis ));
6855
6856     if ( _outerFacesFound ) break; // pass to thorough analysis
6857
6858   } // three attempts - loop on CS axes
6859
6860   // Analyse intersections thoroughly.
6861   // We make two loops maximum, on the first one we only exclude touching intersections,
6862   // on the second, if situation is still unclear, we gather and use information on
6863   // position of faces (internal or outer). If faces position is already gathered,
6864   // we make the second loop right away.
6865
6866   for ( int hasPositionInfo = _outerFacesFound; hasPositionInfo < 2; ++hasPositionInfo )
6867   {
6868     multimap< int, int >::const_iterator nb_axis = nbInt2Axis.begin();
6869     for ( ; nb_axis != nbInt2Axis.end(); ++nb_axis )
6870     {
6871       int axis = nb_axis->second;
6872       map< double, TInters > & u2inters = paramOnLine2TInters[ axis ];
6873
6874       gp_Ax1 lineAxis( point, axisDir[axis]);
6875       gp_Lin line    ( lineAxis );
6876
6877       // add tangent intersections to u2inters
6878       double param;
6879       list< TInters >::const_iterator tgtInt = tangentInters[ axis ].begin();
6880       for ( ; tgtInt != tangentInters[ axis ].end(); ++tgtInt )
6881         if ( getIntersParamOnLine( line, tgtInt->_face, tolerance, param ))
6882           u2inters.insert(make_pair( param, *tgtInt ));
6883       tangentInters[ axis ].clear();
6884
6885       // Count intersections before and after the point excluding touching ones.
6886       // If hasPositionInfo we count intersections of outer boundary only
6887
6888       int nbIntBeforePoint = 0, nbIntAfterPoint = 0;
6889       double f = numeric_limits<double>::max(), l = -numeric_limits<double>::max();
6890       map< double, TInters >::iterator u_int1 = u2inters.begin(), u_int2 = u_int1;
6891       bool ok = ! u_int1->second._coincides;
6892       while ( ok && u_int1 != u2inters.end() )
6893       {
6894         double u = u_int1->first;
6895         bool touchingInt = false;
6896         if ( ++u_int2 != u2inters.end() )
6897         {
6898           // skip intersections at the same point (if the line passes through edge or node)
6899           int nbSamePnt = 0;
6900           while ( u_int2 != u2inters.end() && fabs( u_int2->first - u ) < tolerance )
6901           {
6902             ++nbSamePnt;
6903             ++u_int2;
6904           }
6905
6906           // skip tangent intersections
6907           int nbTgt = 0;
6908           const SMDS_MeshElement* prevFace = u_int1->second._face;
6909           while ( ok && u_int2->second._coincides )
6910           {
6911             if ( SMESH_Algo::GetCommonNodes(prevFace , u_int2->second._face).empty() )
6912               ok = false;
6913             else
6914             {
6915               nbTgt++;
6916               u_int2++;
6917               ok = ( u_int2 != u2inters.end() );
6918             }
6919           }
6920           if ( !ok ) break;
6921
6922           // skip intersections at the same point after tangent intersections
6923           if ( nbTgt > 0 )
6924           {
6925             double u2 = u_int2->first;
6926             ++u_int2;
6927             while ( u_int2 != u2inters.end() && fabs( u_int2->first - u2 ) < tolerance )
6928             {
6929               ++nbSamePnt;
6930               ++u_int2;
6931             }
6932           }
6933           // decide if we skipped a touching intersection
6934           if ( nbSamePnt + nbTgt > 0 )
6935           {
6936             double minDot = numeric_limits<double>::max(), maxDot = -numeric_limits<double>::max();
6937             map< double, TInters >::iterator u_int = u_int1;
6938             for ( ; u_int != u_int2; ++u_int )
6939             {
6940               if ( u_int->second._coincides ) continue;
6941               double dot = u_int->second._faceNorm * line.Direction();
6942               if ( dot > maxDot ) maxDot = dot;
6943               if ( dot < minDot ) minDot = dot;
6944             }
6945             touchingInt = ( minDot*maxDot < 0 );
6946           }
6947         }
6948         if ( !touchingInt )
6949         {
6950           if ( !hasPositionInfo || isOuterBoundary( u_int1->second._face ))
6951           {
6952             if ( u < 0 )
6953               ++nbIntBeforePoint;
6954             else
6955               ++nbIntAfterPoint;
6956           }
6957           if ( u < f ) f = u;
6958           if ( u > l ) l = u;
6959         }
6960
6961         u_int1 = u_int2; // to next intersection
6962
6963       } // loop on intersections with one line
6964
6965       if ( ok )
6966       {
6967         if ( fabs( f ) < tolerance || fabs( l ) < tolerance )
6968           return TopAbs_ON;
6969
6970         if ( nbIntBeforePoint == 0  || nbIntAfterPoint == 0)
6971           return TopAbs_OUT; 
6972
6973         if ( nbIntBeforePoint + nbIntAfterPoint == 1 ) // not closed mesh
6974           return fabs( f ) < tolerance ? TopAbs_ON : TopAbs_UNKNOWN;
6975
6976         if ( nbIntBeforePoint == 1 || nbIntAfterPoint == 1 )
6977           return TopAbs_IN;
6978
6979         if ( (f<0) == (l<0) )
6980           return TopAbs_OUT;
6981
6982         if ( hasPositionInfo )
6983           return nbIntBeforePoint % 2 ? TopAbs_IN : TopAbs_OUT;
6984       }
6985     } // loop on intersections of the tree lines - thorough analysis
6986
6987     if ( !hasPositionInfo )
6988     {
6989       // gather info on faces position - is face in the outer boundary or not
6990       map< double, TInters > & u2inters = paramOnLine2TInters[ 0 ];
6991       findOuterBoundary( u2inters.begin()->second._face );
6992     }
6993
6994   } // two attempts - with and w/o faces position info in the mesh
6995
6996   return TopAbs_UNKNOWN;
6997 }
6998
6999 //=======================================================================
7000 /*!
7001  * \brief Return elements possibly intersecting the line
7002  */
7003 //=======================================================================
7004
7005 void SMESH_ElementSearcherImpl::GetElementsNearLine( const gp_Ax1&                      line,
7006                                                      SMDSAbs_ElementType                type,
7007                                                      vector< const SMDS_MeshElement* >& foundElems)
7008 {
7009   if ( !_ebbTree || _elementType != type )
7010   {
7011     if ( _ebbTree ) delete _ebbTree;
7012     _ebbTree = new ElementBndBoxTree( *_mesh, _elementType = type, _meshPartIt );
7013   }
7014   TIDSortedElemSet suspectFaces; // elements possibly intersecting the line
7015   _ebbTree->getElementsNearLine( line, suspectFaces );
7016   foundElems.assign( suspectFaces.begin(), suspectFaces.end());
7017 }
7018
7019 //=======================================================================
7020 /*!
7021  * \brief Return SMESH_ElementSearcher
7022  */
7023 //=======================================================================
7024
7025 SMESH_ElementSearcher* SMESH_MeshEditor::GetElementSearcher()
7026 {
7027   return new SMESH_ElementSearcherImpl( *GetMeshDS() );
7028 }
7029
7030 //=======================================================================
7031 /*!
7032  * \brief Return SMESH_ElementSearcher
7033  */
7034 //=======================================================================
7035
7036 SMESH_ElementSearcher* SMESH_MeshEditor::GetElementSearcher(SMDS_ElemIteratorPtr elemIt)
7037 {
7038   return new SMESH_ElementSearcherImpl( *GetMeshDS(), elemIt );
7039 }
7040
7041 //=======================================================================
7042 /*!
7043  * \brief Return true if the point is IN or ON of the element
7044  */
7045 //=======================================================================
7046
7047 bool SMESH_MeshEditor::isOut( const SMDS_MeshElement* element, const gp_Pnt& point, double tol )
7048 {
7049   if ( element->GetType() == SMDSAbs_Volume)
7050   {
7051     return SMDS_VolumeTool( element ).IsOut( point.X(), point.Y(), point.Z(), tol );
7052   }
7053
7054   // get ordered nodes
7055
7056   vector< gp_XYZ > xyz;
7057   vector<const SMDS_MeshNode*> nodeList;
7058
7059   SMDS_ElemIteratorPtr nodeIt = element->nodesIterator();
7060   if ( element->IsQuadratic() ) {
7061     if (const SMDS_VtkFace* f=dynamic_cast<const SMDS_VtkFace*>(element))
7062       nodeIt = f->interlacedNodesElemIterator();
7063     else if (const SMDS_VtkEdge*  e =dynamic_cast<const SMDS_VtkEdge*>(element))
7064       nodeIt = e->interlacedNodesElemIterator();
7065   }
7066   while ( nodeIt->more() )
7067     {
7068       const SMDS_MeshNode* node = cast2Node( nodeIt->next() );
7069       xyz.push_back( SMESH_TNodeXYZ(node) );
7070       nodeList.push_back(node);
7071     }
7072
7073   int i, nbNodes = element->NbNodes();
7074
7075   if ( element->GetType() == SMDSAbs_Face ) // --------------------------------------------------
7076   {
7077     // compute face normal
7078     gp_Vec faceNorm(0,0,0);
7079     xyz.push_back( xyz.front() );
7080     nodeList.push_back( nodeList.front() );
7081     for ( i = 0; i < nbNodes; ++i )
7082     {
7083       gp_Vec edge1( xyz[i+1], xyz[i]);
7084       gp_Vec edge2( xyz[i+1], xyz[(i+2)%nbNodes] );
7085       faceNorm += edge1 ^ edge2;
7086     }
7087     double normSize = faceNorm.Magnitude();
7088     if ( normSize <= tol )
7089     {
7090       // degenerated face: point is out if it is out of all face edges
7091       for ( i = 0; i < nbNodes; ++i )
7092       {
7093         SMDS_LinearEdge edge( nodeList[i], nodeList[i+1] );
7094         if ( !isOut( &edge, point, tol ))
7095           return false;
7096       }
7097       return true;
7098     }
7099     faceNorm /= normSize;
7100
7101     // check if the point lays on face plane
7102     gp_Vec n2p( xyz[0], point );
7103     if ( fabs( n2p * faceNorm ) > tol )
7104       return true; // not on face plane
7105
7106     // check if point is out of face boundary:
7107     // define it by closest transition of a ray point->infinity through face boundary
7108     // on the face plane.
7109     // First, find normal of a plane perpendicular to face plane, to be used as a cutting tool
7110     // to find intersections of the ray with the boundary.
7111     gp_Vec ray = n2p;
7112     gp_Vec plnNorm = ray ^ faceNorm;
7113     normSize = plnNorm.Magnitude();
7114     if ( normSize <= tol ) return false; // point coincides with the first node
7115     plnNorm /= normSize;
7116     // for each node of the face, compute its signed distance to the plane
7117     vector<double> dist( nbNodes + 1);
7118     for ( i = 0; i < nbNodes; ++i )
7119     {
7120       gp_Vec n2p( xyz[i], point );
7121       dist[i] = n2p * plnNorm;
7122     }
7123     dist.back() = dist.front();
7124     // find the closest intersection
7125     int    iClosest = -1;
7126     double rClosest, distClosest = 1e100;;
7127     gp_Pnt pClosest;
7128     for ( i = 0; i < nbNodes; ++i )
7129     {
7130       double r;
7131       if ( fabs( dist[i]) < tol )
7132         r = 0.;
7133       else if ( fabs( dist[i+1]) < tol )
7134         r = 1.;
7135       else if ( dist[i] * dist[i+1] < 0 )
7136         r = dist[i] / ( dist[i] - dist[i+1] );
7137       else
7138         continue; // no intersection
7139       gp_Pnt pInt = xyz[i] * (1.-r) + xyz[i+1] * r;
7140       gp_Vec p2int ( point, pInt);
7141       if ( p2int * ray > -tol ) // right half-space
7142       {
7143         double intDist = p2int.SquareMagnitude();
7144         if ( intDist < distClosest )
7145         {
7146           iClosest = i;
7147           rClosest = r;
7148           pClosest = pInt;
7149           distClosest = intDist;
7150         }
7151       }
7152     }
7153     if ( iClosest < 0 )
7154       return true; // no intesections - out
7155
7156     // analyse transition
7157     gp_Vec edge( xyz[iClosest], xyz[iClosest+1] );
7158     gp_Vec edgeNorm = -( edge ^ faceNorm ); // normal to intersected edge pointing out of face
7159     gp_Vec p2int ( point, pClosest );
7160     bool out = (edgeNorm * p2int) < -tol;
7161     if ( rClosest > 0. && rClosest < 1. ) // not node intersection
7162       return out;
7163
7164     // ray pass through a face node; analyze transition through an adjacent edge
7165     gp_Pnt p1 = xyz[ (rClosest == 0.) ? ((iClosest+nbNodes-1) % nbNodes) : (iClosest+1) ];
7166     gp_Pnt p2 = xyz[ (rClosest == 0.) ? iClosest : ((iClosest+2) % nbNodes) ];
7167     gp_Vec edgeAdjacent( p1, p2 );
7168     gp_Vec edgeNorm2 = -( edgeAdjacent ^ faceNorm );
7169     bool out2 = (edgeNorm2 * p2int) < -tol;
7170
7171     bool covexCorner = ( edgeNorm * edgeAdjacent * (rClosest==1. ? 1. : -1.)) < 0;
7172     return covexCorner ? (out || out2) : (out && out2);
7173   }
7174   if ( element->GetType() == SMDSAbs_Edge ) // --------------------------------------------------
7175   {
7176     // point is out of edge if it is NOT ON any straight part of edge
7177     // (we consider quadratic edge as being composed of two straight parts)
7178     for ( i = 1; i < nbNodes; ++i )
7179     {
7180       gp_Vec edge( xyz[i-1], xyz[i]);
7181       gp_Vec n1p ( xyz[i-1], point);
7182       double dist = ( edge ^ n1p ).Magnitude() / edge.Magnitude();
7183       if ( dist > tol )
7184         continue;
7185       gp_Vec n2p( xyz[i], point );
7186       if ( fabs( edge.Magnitude() - n1p.Magnitude() - n2p.Magnitude()) > tol )
7187         continue;
7188       return false; // point is ON this part
7189     }
7190     return true;
7191   }
7192   // Node or 0D element -------------------------------------------------------------------------
7193   {
7194     gp_Vec n2p ( xyz[0], point );
7195     return n2p.Magnitude() <= tol;
7196   }
7197   return true;
7198 }
7199
7200 //=======================================================================
7201 //function : SimplifyFace
7202 //purpose  :
7203 //=======================================================================
7204 int SMESH_MeshEditor::SimplifyFace (const vector<const SMDS_MeshNode *> faceNodes,
7205                                     vector<const SMDS_MeshNode *>&      poly_nodes,
7206                                     vector<int>&                        quantities) const
7207 {
7208   int nbNodes = faceNodes.size();
7209
7210   if (nbNodes < 3)
7211     return 0;
7212
7213   set<const SMDS_MeshNode*> nodeSet;
7214
7215   // get simple seq of nodes
7216   //const SMDS_MeshNode* simpleNodes[ nbNodes ];
7217   vector<const SMDS_MeshNode*> simpleNodes( nbNodes );
7218   int iSimple = 0, nbUnique = 0;
7219
7220   simpleNodes[iSimple++] = faceNodes[0];
7221   nbUnique++;
7222   for (int iCur = 1; iCur < nbNodes; iCur++) {
7223     if (faceNodes[iCur] != simpleNodes[iSimple - 1]) {
7224       simpleNodes[iSimple++] = faceNodes[iCur];
7225       if (nodeSet.insert( faceNodes[iCur] ).second)
7226         nbUnique++;
7227     }
7228   }
7229   int nbSimple = iSimple;
7230   if (simpleNodes[nbSimple - 1] == simpleNodes[0]) {
7231     nbSimple--;
7232     iSimple--;
7233   }
7234
7235   if (nbUnique < 3)
7236     return 0;
7237
7238   // separate loops
7239   int nbNew = 0;
7240   bool foundLoop = (nbSimple > nbUnique);
7241   while (foundLoop) {
7242     foundLoop = false;
7243     set<const SMDS_MeshNode*> loopSet;
7244     for (iSimple = 0; iSimple < nbSimple && !foundLoop; iSimple++) {
7245       const SMDS_MeshNode* n = simpleNodes[iSimple];
7246       if (!loopSet.insert( n ).second) {
7247         foundLoop = true;
7248
7249         // separate loop
7250         int iC = 0, curLast = iSimple;
7251         for (; iC < curLast; iC++) {
7252           if (simpleNodes[iC] == n) break;
7253         }
7254         int loopLen = curLast - iC;
7255         if (loopLen > 2) {
7256           // create sub-element
7257           nbNew++;
7258           quantities.push_back(loopLen);
7259           for (; iC < curLast; iC++) {
7260             poly_nodes.push_back(simpleNodes[iC]);
7261           }
7262         }
7263         // shift the rest nodes (place from the first loop position)
7264         for (iC = curLast + 1; iC < nbSimple; iC++) {
7265           simpleNodes[iC - loopLen] = simpleNodes[iC];
7266         }
7267         nbSimple -= loopLen;
7268         iSimple -= loopLen;
7269       }
7270     } // for (iSimple = 0; iSimple < nbSimple; iSimple++)
7271   } // while (foundLoop)
7272
7273   if (iSimple > 2) {
7274     nbNew++;
7275     quantities.push_back(iSimple);
7276     for (int i = 0; i < iSimple; i++)
7277       poly_nodes.push_back(simpleNodes[i]);
7278   }
7279
7280   return nbNew;
7281 }
7282
7283 //=======================================================================
7284 //function : MergeNodes
7285 //purpose  : In each group, the cdr of nodes are substituted by the first one
7286 //           in all elements.
7287 //=======================================================================
7288
7289 void SMESH_MeshEditor::MergeNodes (TListOfListOfNodes & theGroupsOfNodes)
7290 {
7291   MESSAGE("MergeNodes");
7292   myLastCreatedElems.Clear();
7293   myLastCreatedNodes.Clear();
7294
7295   SMESHDS_Mesh* aMesh = GetMeshDS();
7296
7297   TNodeNodeMap nodeNodeMap; // node to replace - new node
7298   set<const SMDS_MeshElement*> elems; // all elements with changed nodes
7299   list< int > rmElemIds, rmNodeIds;
7300
7301   // Fill nodeNodeMap and elems
7302
7303   TListOfListOfNodes::iterator grIt = theGroupsOfNodes.begin();
7304   for ( ; grIt != theGroupsOfNodes.end(); grIt++ ) {
7305     list<const SMDS_MeshNode*>& nodes = *grIt;
7306     list<const SMDS_MeshNode*>::iterator nIt = nodes.begin();
7307     const SMDS_MeshNode* nToKeep = *nIt;
7308     //MESSAGE("node to keep " << nToKeep->GetID());
7309     for ( ++nIt; nIt != nodes.end(); nIt++ ) {
7310       const SMDS_MeshNode* nToRemove = *nIt;
7311       nodeNodeMap.insert( TNodeNodeMap::value_type( nToRemove, nToKeep ));
7312       if ( nToRemove != nToKeep ) {
7313         //MESSAGE("  node to remove " << nToRemove->GetID());
7314         rmNodeIds.push_back( nToRemove->GetID() );
7315         AddToSameGroups( nToKeep, nToRemove, aMesh );
7316       }
7317
7318       SMDS_ElemIteratorPtr invElemIt = nToRemove->GetInverseElementIterator();
7319       while ( invElemIt->more() ) {
7320         const SMDS_MeshElement* elem = invElemIt->next();
7321         elems.insert(elem);
7322       }
7323     }
7324   }
7325   // Change element nodes or remove an element
7326
7327   set<const SMDS_MeshElement*>::iterator eIt = elems.begin();
7328   for ( ; eIt != elems.end(); eIt++ ) {
7329     const SMDS_MeshElement* elem = *eIt;
7330     //MESSAGE(" ---- inverse elem on node to remove " << elem->GetID());
7331     int nbNodes = elem->NbNodes();
7332     int aShapeId = FindShape( elem );
7333
7334     set<const SMDS_MeshNode*> nodeSet;
7335     vector< const SMDS_MeshNode*> curNodes( nbNodes ), uniqueNodes( nbNodes );
7336     int iUnique = 0, iCur = 0, nbRepl = 0;
7337     vector<int> iRepl( nbNodes );
7338
7339     // get new seq of nodes
7340     SMDS_ElemIteratorPtr itN = elem->nodesIterator();
7341     while ( itN->more() ) {
7342       const SMDS_MeshNode* n =
7343         static_cast<const SMDS_MeshNode*>( itN->next() );
7344
7345       TNodeNodeMap::iterator nnIt = nodeNodeMap.find( n );
7346       if ( nnIt != nodeNodeMap.end() ) { // n sticks
7347         n = (*nnIt).second;
7348         // BUG 0020185: begin
7349         {
7350           bool stopRecur = false;
7351           set<const SMDS_MeshNode*> nodesRecur;
7352           nodesRecur.insert(n);
7353           while (!stopRecur) {
7354             TNodeNodeMap::iterator nnIt_i = nodeNodeMap.find( n );
7355             if ( nnIt_i != nodeNodeMap.end() ) { // n sticks
7356               n = (*nnIt_i).second;
7357               if (!nodesRecur.insert(n).second) {
7358                 // error: recursive dependancy
7359                 stopRecur = true;
7360               }
7361             }
7362             else
7363               stopRecur = true;
7364           }
7365         }
7366         // BUG 0020185: end
7367         iRepl[ nbRepl++ ] = iCur;
7368       }
7369       curNodes[ iCur ] = n;
7370       bool isUnique = nodeSet.insert( n ).second;
7371       if ( isUnique )
7372         uniqueNodes[ iUnique++ ] = n;
7373       iCur++;
7374     }
7375
7376     // Analyse element topology after replacement
7377
7378     bool isOk = true;
7379     int nbUniqueNodes = nodeSet.size();
7380     //MESSAGE("nbNodes nbUniqueNodes " << nbNodes << " " << nbUniqueNodes);
7381     if ( nbNodes != nbUniqueNodes ) { // some nodes stick
7382       // Polygons and Polyhedral volumes
7383       if (elem->IsPoly()) {
7384
7385         if (elem->GetType() == SMDSAbs_Face) {
7386           // Polygon
7387           vector<const SMDS_MeshNode *> face_nodes (nbNodes);
7388           int inode = 0;
7389           for (; inode < nbNodes; inode++) {
7390             face_nodes[inode] = curNodes[inode];
7391           }
7392
7393           vector<const SMDS_MeshNode *> polygons_nodes;
7394           vector<int> quantities;
7395           int nbNew = SimplifyFace(face_nodes, polygons_nodes, quantities);
7396           if (nbNew > 0) {
7397             inode = 0;
7398             for (int iface = 0; iface < nbNew; iface++) {
7399               int nbNodes = quantities[iface];
7400               vector<const SMDS_MeshNode *> poly_nodes (nbNodes);
7401               for (int ii = 0; ii < nbNodes; ii++, inode++) {
7402                 poly_nodes[ii] = polygons_nodes[inode];
7403               }
7404               SMDS_MeshElement* newElem = aMesh->AddPolygonalFace(poly_nodes);
7405               myLastCreatedElems.Append(newElem);
7406               if (aShapeId)
7407                 aMesh->SetMeshElementOnShape(newElem, aShapeId);
7408             }
7409
7410             MESSAGE("ChangeElementNodes MergeNodes Polygon");
7411             //aMesh->ChangeElementNodes(elem, &polygons_nodes[inode], quantities[nbNew - 1]);
7412             vector<const SMDS_MeshNode *> polynodes(polygons_nodes.begin()+inode,polygons_nodes.end());
7413             int quid =0;
7414             if (nbNew > 0) quid = nbNew - 1;
7415             vector<int> newquant(quantities.begin()+quid, quantities.end());
7416             const SMDS_MeshElement* newElem = 0;
7417             newElem = aMesh->AddPolyhedralVolume(polynodes, newquant);
7418             myLastCreatedElems.Append(newElem);
7419             if ( aShapeId && newElem )
7420               aMesh->SetMeshElementOnShape( newElem, aShapeId );
7421             rmElemIds.push_back(elem->GetID());
7422           }
7423           else {
7424             rmElemIds.push_back(elem->GetID());
7425           }
7426
7427         }
7428         else if (elem->GetType() == SMDSAbs_Volume) {
7429           // Polyhedral volume
7430           if (nbUniqueNodes < 4) {
7431             rmElemIds.push_back(elem->GetID());
7432           }
7433           else {
7434             // each face has to be analyzed in order to check volume validity
7435             const SMDS_VtkVolume* aPolyedre =
7436               dynamic_cast<const SMDS_VtkVolume*>( elem );
7437             if (aPolyedre) {
7438               int nbFaces = aPolyedre->NbFaces();
7439
7440               vector<const SMDS_MeshNode *> poly_nodes;
7441               vector<int> quantities;
7442
7443               for (int iface = 1; iface <= nbFaces; iface++) {
7444                 int nbFaceNodes = aPolyedre->NbFaceNodes(iface);
7445                 vector<const SMDS_MeshNode *> faceNodes (nbFaceNodes);
7446
7447                 for (int inode = 1; inode <= nbFaceNodes; inode++) {
7448                   const SMDS_MeshNode * faceNode = aPolyedre->GetFaceNode(iface, inode);
7449                   TNodeNodeMap::iterator nnIt = nodeNodeMap.find(faceNode);
7450                   if (nnIt != nodeNodeMap.end()) { // faceNode sticks
7451                     faceNode = (*nnIt).second;
7452                   }
7453                   faceNodes[inode - 1] = faceNode;
7454                 }
7455
7456                 SimplifyFace(faceNodes, poly_nodes, quantities);
7457               }
7458
7459               if (quantities.size() > 3) {
7460                 // to be done: remove coincident faces
7461               }
7462
7463               if (quantities.size() > 3)
7464                 {
7465                   MESSAGE("ChangeElementNodes MergeNodes Polyhedron");
7466                   //aMesh->ChangePolyhedronNodes(elem, poly_nodes, quantities);
7467                   const SMDS_MeshElement* newElem = 0;
7468                   newElem = aMesh->AddPolyhedralVolume(poly_nodes, quantities);
7469                   myLastCreatedElems.Append(newElem);
7470                   if ( aShapeId && newElem )
7471                     aMesh->SetMeshElementOnShape( newElem, aShapeId );
7472                   rmElemIds.push_back(elem->GetID());
7473                 }
7474             }
7475             else {
7476               rmElemIds.push_back(elem->GetID());
7477             }
7478           }
7479         }
7480         else {
7481         }
7482
7483         continue;
7484       }
7485
7486       // Regular elements
7487       // TODO not all the possible cases are solved. Find something more generic?
7488       switch ( nbNodes ) {
7489       case 2: ///////////////////////////////////// EDGE
7490         isOk = false; break;
7491       case 3: ///////////////////////////////////// TRIANGLE
7492         isOk = false; break;
7493       case 4:
7494         if ( elem->GetType() == SMDSAbs_Volume ) // TETRAHEDRON
7495           isOk = false;
7496         else { //////////////////////////////////// QUADRANGLE
7497           if ( nbUniqueNodes < 3 )
7498             isOk = false;
7499           else if ( nbRepl == 2 && iRepl[ 1 ] - iRepl[ 0 ] == 2 )
7500             isOk = false; // opposite nodes stick
7501           //MESSAGE("isOk " << isOk);
7502         }
7503         break;
7504       case 6: ///////////////////////////////////// PENTAHEDRON
7505         if ( nbUniqueNodes == 4 ) {
7506           // ---------------------------------> tetrahedron
7507           if (nbRepl == 3 &&
7508               iRepl[ 0 ] > 2 && iRepl[ 1 ] > 2 && iRepl[ 2 ] > 2 ) {
7509             // all top nodes stick: reverse a bottom
7510             uniqueNodes[ 0 ] = curNodes [ 1 ];
7511             uniqueNodes[ 1 ] = curNodes [ 0 ];
7512           }
7513           else if (nbRepl == 3 &&
7514                    iRepl[ 0 ] < 3 && iRepl[ 1 ] < 3 && iRepl[ 2 ] < 3 ) {
7515             // all bottom nodes stick: set a top before
7516             uniqueNodes[ 3 ] = uniqueNodes [ 0 ];
7517             uniqueNodes[ 0 ] = curNodes [ 3 ];
7518             uniqueNodes[ 1 ] = curNodes [ 4 ];
7519             uniqueNodes[ 2 ] = curNodes [ 5 ];
7520           }
7521           else if (nbRepl == 4 &&
7522                    iRepl[ 2 ] - iRepl [ 0 ] == 3 && iRepl[ 3 ] - iRepl [ 1 ] == 3 ) {
7523             // a lateral face turns into a line: reverse a bottom
7524             uniqueNodes[ 0 ] = curNodes [ 1 ];
7525             uniqueNodes[ 1 ] = curNodes [ 0 ];
7526           }
7527           else
7528             isOk = false;
7529         }
7530         else if ( nbUniqueNodes == 5 ) {
7531           // PENTAHEDRON --------------------> 2 tetrahedrons
7532           if ( nbRepl == 2 && iRepl[ 1 ] - iRepl [ 0 ] == 3 ) {
7533             // a bottom node sticks with a linked top one
7534             // 1.
7535             SMDS_MeshElement* newElem =
7536               aMesh->AddVolume(curNodes[ 3 ],
7537                                curNodes[ 4 ],
7538                                curNodes[ 5 ],
7539                                curNodes[ iRepl[ 0 ] == 2 ? 1 : 2 ]);
7540             myLastCreatedElems.Append(newElem);
7541             if ( aShapeId )
7542               aMesh->SetMeshElementOnShape( newElem, aShapeId );
7543             // 2. : reverse a bottom
7544             uniqueNodes[ 0 ] = curNodes [ 1 ];
7545             uniqueNodes[ 1 ] = curNodes [ 0 ];
7546             nbUniqueNodes = 4;
7547           }
7548           else
7549             isOk = false;
7550         }
7551         else
7552           isOk = false;
7553         break;
7554       case 8: {
7555         if(elem->IsQuadratic()) { // Quadratic quadrangle
7556           //   1    5    2
7557           //    +---+---+
7558           //    |       |
7559           //    |       |
7560           //   4+       +6
7561           //    |       |
7562           //    |       |
7563           //    +---+---+
7564           //   0    7    3
7565           isOk = false;
7566           if(nbRepl==2) {
7567             MESSAGE("nbRepl=2: " << iRepl[0] << " " << iRepl[1]);
7568           }
7569           if(nbRepl==3) {
7570             MESSAGE("nbRepl=3: " << iRepl[0] << " " << iRepl[1]  << " " << iRepl[2]);
7571             nbUniqueNodes = 6;
7572             if( iRepl[0]==0 && iRepl[1]==1 && iRepl[2]==4 ) {
7573               uniqueNodes[0] = curNodes[0];
7574               uniqueNodes[1] = curNodes[2];
7575               uniqueNodes[2] = curNodes[3];
7576               uniqueNodes[3] = curNodes[5];
7577               uniqueNodes[4] = curNodes[6];
7578               uniqueNodes[5] = curNodes[7];
7579               isOk = true;
7580             }
7581             if( iRepl[0]==0 && iRepl[1]==3 && iRepl[2]==7 ) {
7582               uniqueNodes[0] = curNodes[0];
7583               uniqueNodes[1] = curNodes[1];
7584               uniqueNodes[2] = curNodes[2];
7585               uniqueNodes[3] = curNodes[4];
7586               uniqueNodes[4] = curNodes[5];
7587               uniqueNodes[5] = curNodes[6];
7588               isOk = true;
7589             }
7590             if( iRepl[0]==0 && iRepl[1]==4 && iRepl[2]==7 ) {
7591               uniqueNodes[0] = curNodes[1];
7592               uniqueNodes[1] = curNodes[2];
7593               uniqueNodes[2] = curNodes[3];
7594               uniqueNodes[3] = curNodes[5];
7595               uniqueNodes[4] = curNodes[6];
7596               uniqueNodes[5] = curNodes[0];
7597               isOk = true;
7598             }
7599             if( iRepl[0]==1 && iRepl[1]==2 && iRepl[2]==5 ) {
7600               uniqueNodes[0] = curNodes[0];
7601               uniqueNodes[1] = curNodes[1];
7602               uniqueNodes[2] = curNodes[3];
7603               uniqueNodes[3] = curNodes[4];
7604               uniqueNodes[4] = curNodes[6];
7605               uniqueNodes[5] = curNodes[7];
7606               isOk = true;
7607             }
7608             if( iRepl[0]==1 && iRepl[1]==4 && iRepl[2]==5 ) {
7609               uniqueNodes[0] = curNodes[0];
7610               uniqueNodes[1] = curNodes[2];
7611               uniqueNodes[2] = curNodes[3];
7612               uniqueNodes[3] = curNodes[1];
7613               uniqueNodes[4] = curNodes[6];
7614               uniqueNodes[5] = curNodes[7];
7615               isOk = true;
7616             }
7617             if( iRepl[0]==2 && iRepl[1]==3 && iRepl[2]==6 ) {
7618               uniqueNodes[0] = curNodes[0];
7619               uniqueNodes[1] = curNodes[1];
7620               uniqueNodes[2] = curNodes[2];
7621               uniqueNodes[3] = curNodes[4];
7622               uniqueNodes[4] = curNodes[5];
7623               uniqueNodes[5] = curNodes[7];
7624               isOk = true;
7625             }
7626             if( iRepl[0]==2 && iRepl[1]==5 && iRepl[2]==6 ) {
7627               uniqueNodes[0] = curNodes[0];
7628               uniqueNodes[1] = curNodes[1];
7629               uniqueNodes[2] = curNodes[3];
7630               uniqueNodes[3] = curNodes[4];
7631               uniqueNodes[4] = curNodes[2];
7632               uniqueNodes[5] = curNodes[7];
7633               isOk = true;
7634             }
7635             if( iRepl[0]==3 && iRepl[1]==6 && iRepl[2]==7 ) {
7636               uniqueNodes[0] = curNodes[0];
7637               uniqueNodes[1] = curNodes[1];
7638               uniqueNodes[2] = curNodes[2];
7639               uniqueNodes[3] = curNodes[4];
7640               uniqueNodes[4] = curNodes[5];
7641               uniqueNodes[5] = curNodes[3];
7642               isOk = true;
7643             }
7644           }
7645           if(nbRepl==4) {
7646             MESSAGE("nbRepl=4: " << iRepl[0] << " " << iRepl[1]  << " " << iRepl[2] << " " << iRepl[3]);
7647           }
7648           if(nbRepl==5) {
7649             MESSAGE("nbRepl=5: " << iRepl[0] << " " << iRepl[1]  << " " << iRepl[2] << " " << iRepl[3] << " " << iRepl[4]);
7650           }
7651           break;
7652         }
7653         //////////////////////////////////// HEXAHEDRON
7654         isOk = false;
7655         SMDS_VolumeTool hexa (elem);
7656         hexa.SetExternalNormal();
7657         if ( nbUniqueNodes == 4 && nbRepl == 6 ) {
7658           //////////////////////// ---> tetrahedron
7659           for ( int iFace = 0; iFace < 6; iFace++ ) {
7660             const int *ind = hexa.GetFaceNodesIndices( iFace ); // indices of face nodes
7661             if (curNodes[ind[ 0 ]] == curNodes[ind[ 1 ]] &&
7662                 curNodes[ind[ 0 ]] == curNodes[ind[ 2 ]] &&
7663                 curNodes[ind[ 0 ]] == curNodes[ind[ 3 ]] ) {
7664               // one face turns into a point ...
7665               int iOppFace = hexa.GetOppFaceIndex( iFace );
7666               ind = hexa.GetFaceNodesIndices( iOppFace );
7667               int nbStick = 0;
7668               iUnique = 2; // reverse a tetrahedron bottom
7669               for ( iCur = 0; iCur < 4 && nbStick < 2; iCur++ ) {
7670                 if ( curNodes[ind[ iCur ]] == curNodes[ind[ iCur + 1 ]] )
7671                   nbStick++;
7672                 else if ( iUnique >= 0 )
7673                   uniqueNodes[ iUnique-- ] = curNodes[ind[ iCur ]];
7674               }
7675               if ( nbStick == 1 ) {
7676                 // ... and the opposite one - into a triangle.
7677                 // set a top node
7678                 ind = hexa.GetFaceNodesIndices( iFace );
7679                 uniqueNodes[ 3 ] = curNodes[ind[ 0 ]];
7680                 isOk = true;
7681               }
7682               break;
7683             }
7684           }
7685         }
7686         else if (nbUniqueNodes == 5 && nbRepl == 4 ) {
7687           //////////////////// HEXAHEDRON ---> 2 tetrahedrons
7688           for ( int iFace = 0; iFace < 6; iFace++ ) {
7689             const int *ind = hexa.GetFaceNodesIndices( iFace ); // indices of face nodes
7690             if (curNodes[ind[ 0 ]] == curNodes[ind[ 1 ]] &&
7691                 curNodes[ind[ 0 ]] == curNodes[ind[ 2 ]] &&
7692                 curNodes[ind[ 0 ]] == curNodes[ind[ 3 ]] ) {
7693               // one face turns into a point ...
7694               int iOppFace = hexa.GetOppFaceIndex( iFace );
7695               ind = hexa.GetFaceNodesIndices( iOppFace );
7696               int nbStick = 0;
7697               iUnique = 2;  // reverse a tetrahedron 1 bottom
7698               for ( iCur = 0; iCur < 4 && nbStick == 0; iCur++ ) {
7699                 if ( curNodes[ind[ iCur ]] == curNodes[ind[ iCur + 1 ]] )
7700                   nbStick++;
7701                 else if ( iUnique >= 0 )
7702                   uniqueNodes[ iUnique-- ] = curNodes[ind[ iCur ]];
7703               }
7704               if ( nbStick == 0 ) {
7705                 // ... and the opposite one is a quadrangle
7706                 // set a top node
7707                 const int* indTop = hexa.GetFaceNodesIndices( iFace );
7708                 uniqueNodes[ 3 ] = curNodes[indTop[ 0 ]];
7709                 nbUniqueNodes = 4;
7710                 // tetrahedron 2
7711                 SMDS_MeshElement* newElem =
7712                   aMesh->AddVolume(curNodes[ind[ 0 ]],
7713                                    curNodes[ind[ 3 ]],
7714                                    curNodes[ind[ 2 ]],
7715                                    curNodes[indTop[ 0 ]]);
7716                 myLastCreatedElems.Append(newElem);
7717                 if ( aShapeId )
7718                   aMesh->SetMeshElementOnShape( newElem, aShapeId );
7719                 isOk = true;
7720               }
7721               break;
7722             }
7723           }
7724         }
7725         else if ( nbUniqueNodes == 6 && nbRepl == 4 ) {
7726           ////////////////// HEXAHEDRON ---> 2 tetrahedrons or 1 prism
7727           // find indices of quad and tri faces
7728           int iQuadFace[ 6 ], iTriFace[ 6 ], nbQuad = 0, nbTri = 0, iFace;
7729           for ( iFace = 0; iFace < 6; iFace++ ) {
7730             const int *ind = hexa.GetFaceNodesIndices( iFace ); // indices of face nodes
7731             nodeSet.clear();
7732             for ( iCur = 0; iCur < 4; iCur++ )
7733               nodeSet.insert( curNodes[ind[ iCur ]] );
7734             nbUniqueNodes = nodeSet.size();
7735             if ( nbUniqueNodes == 3 )
7736               iTriFace[ nbTri++ ] = iFace;
7737             else if ( nbUniqueNodes == 4 )
7738               iQuadFace[ nbQuad++ ] = iFace;
7739           }
7740           if (nbQuad == 2 && nbTri == 4 &&
7741               hexa.GetOppFaceIndex( iQuadFace[ 0 ] ) == iQuadFace[ 1 ]) {
7742             // 2 opposite quadrangles stuck with a diagonal;
7743             // sample groups of merged indices: (0-4)(2-6)
7744             // --------------------------------------------> 2 tetrahedrons
7745             const int *ind1 = hexa.GetFaceNodesIndices( iQuadFace[ 0 ]); // indices of quad1 nodes
7746             const int *ind2 = hexa.GetFaceNodesIndices( iQuadFace[ 1 ]);
7747             int i0, i1d, i2, i3d, i0t, i2t; // d-daigonal, t-top
7748             if (curNodes[ind1[ 0 ]] == curNodes[ind2[ 0 ]] &&
7749                 curNodes[ind1[ 2 ]] == curNodes[ind2[ 2 ]]) {
7750               // stuck with 0-2 diagonal
7751               i0  = ind1[ 3 ];
7752               i1d = ind1[ 0 ];
7753               i2  = ind1[ 1 ];
7754               i3d = ind1[ 2 ];
7755               i0t = ind2[ 1 ];
7756               i2t = ind2[ 3 ];
7757             }
7758             else if (curNodes[ind1[ 1 ]] == curNodes[ind2[ 3 ]] &&
7759                      curNodes[ind1[ 3 ]] == curNodes[ind2[ 1 ]]) {
7760               // stuck with 1-3 diagonal
7761               i0  = ind1[ 0 ];
7762               i1d = ind1[ 1 ];
7763               i2  = ind1[ 2 ];
7764               i3d = ind1[ 3 ];
7765               i0t = ind2[ 0 ];
7766               i2t = ind2[ 1 ];
7767             }
7768             else {
7769               ASSERT(0);
7770             }
7771             // tetrahedron 1
7772             uniqueNodes[ 0 ] = curNodes [ i0 ];
7773             uniqueNodes[ 1 ] = curNodes [ i1d ];
7774             uniqueNodes[ 2 ] = curNodes [ i3d ];
7775             uniqueNodes[ 3 ] = curNodes [ i0t ];
7776             nbUniqueNodes = 4;
7777             // tetrahedron 2
7778             SMDS_MeshElement* newElem = aMesh->AddVolume(curNodes[ i1d ],
7779                                                          curNodes[ i2 ],
7780                                                          curNodes[ i3d ],
7781                                                          curNodes[ i2t ]);
7782             myLastCreatedElems.Append(newElem);
7783             if ( aShapeId )
7784               aMesh->SetMeshElementOnShape( newElem, aShapeId );
7785             isOk = true;
7786           }
7787           else if (( nbTri == 2 && nbQuad == 3 ) || // merged (0-4)(1-5)
7788                    ( nbTri == 4 && nbQuad == 2 )) { // merged (7-4)(1-5)
7789             // --------------------------------------------> prism
7790             // find 2 opposite triangles
7791             nbUniqueNodes = 6;
7792             for ( iFace = 0; iFace + 1 < nbTri; iFace++ ) {
7793               if ( hexa.GetOppFaceIndex( iTriFace[ iFace ] ) == iTriFace[ iFace + 1 ]) {
7794                 // find indices of kept and replaced nodes
7795                 // and fill unique nodes of 2 opposite triangles
7796                 const int *ind1 = hexa.GetFaceNodesIndices( iTriFace[ iFace ]);
7797                 const int *ind2 = hexa.GetFaceNodesIndices( iTriFace[ iFace + 1 ]);
7798                 const SMDS_MeshNode** hexanodes = hexa.GetNodes();
7799                 // fill unique nodes
7800                 iUnique = 0;
7801                 isOk = true;
7802                 for ( iCur = 0; iCur < 4 && isOk; iCur++ ) {
7803                   const SMDS_MeshNode* n     = curNodes[ind1[ iCur ]];
7804                   const SMDS_MeshNode* nInit = hexanodes[ind1[ iCur ]];
7805                   if ( n == nInit ) {
7806                     // iCur of a linked node of the opposite face (make normals co-directed):
7807                     int iCurOpp = ( iCur == 1 || iCur == 3 ) ? 4 - iCur : iCur;
7808                     // check that correspondent corners of triangles are linked
7809                     if ( !hexa.IsLinked( ind1[ iCur ], ind2[ iCurOpp ] ))
7810                       isOk = false;
7811                     else {
7812                       uniqueNodes[ iUnique ] = n;
7813                       uniqueNodes[ iUnique + 3 ] = curNodes[ind2[ iCurOpp ]];
7814                       iUnique++;
7815                     }
7816                   }
7817                 }
7818                 break;
7819               }
7820             }
7821           }
7822         } // if ( nbUniqueNodes == 6 && nbRepl == 4 )
7823         break;
7824       } // HEXAHEDRON
7825
7826       default:
7827         isOk = false;
7828       } // switch ( nbNodes )
7829
7830     } // if ( nbNodes != nbUniqueNodes ) // some nodes stick
7831
7832     if ( isOk ) { // the elem remains valid after sticking nodes
7833       if (elem->IsPoly() && elem->GetType() == SMDSAbs_Volume)
7834       {
7835         // Change nodes of polyedre
7836         const SMDS_VtkVolume* aPolyedre =
7837           dynamic_cast<const SMDS_VtkVolume*>( elem );
7838         if (aPolyedre) {
7839           int nbFaces = aPolyedre->NbFaces();
7840
7841           vector<const SMDS_MeshNode *> poly_nodes;
7842           vector<int> quantities (nbFaces);
7843
7844           for (int iface = 1; iface <= nbFaces; iface++) {
7845             int inode, nbFaceNodes = aPolyedre->NbFaceNodes(iface);
7846             quantities[iface - 1] = nbFaceNodes;
7847
7848             for (inode = 1; inode <= nbFaceNodes; inode++) {
7849               const SMDS_MeshNode* curNode = aPolyedre->GetFaceNode(iface, inode);
7850
7851               TNodeNodeMap::iterator nnIt = nodeNodeMap.find( curNode );
7852               if (nnIt != nodeNodeMap.end()) { // curNode sticks
7853                 curNode = (*nnIt).second;
7854               }
7855               poly_nodes.push_back(curNode);
7856             }
7857           }
7858           aMesh->ChangePolyhedronNodes( elem, poly_nodes, quantities );
7859         }
7860       }
7861       else // replace non-polyhedron elements
7862       {
7863         const SMDSAbs_ElementType etyp = elem->GetType();
7864         const int elemId               = elem->GetID();
7865         const bool isPoly              = (elem->GetEntityType() == SMDSEntity_Polygon);
7866         uniqueNodes.resize(nbUniqueNodes);
7867
7868         SMESHDS_SubMesh * sm = aShapeId > 0 ? aMesh->MeshElements(aShapeId) : 0;
7869
7870         aMesh->RemoveFreeElement(elem, sm, /*fromGroups=*/false);
7871         SMDS_MeshElement* newElem = this->AddElement(uniqueNodes, etyp, isPoly, elemId);
7872         if ( sm && newElem )
7873           sm->AddElement( newElem );
7874         if ( elem != newElem )
7875           ReplaceElemInGroups( elem, newElem, aMesh );
7876       }
7877     }
7878     else {
7879       // Remove invalid regular element or invalid polygon
7880       rmElemIds.push_back( elem->GetID() );
7881     }
7882
7883   } // loop on elements
7884
7885   // Remove bad elements, then equal nodes (order important)
7886
7887   Remove( rmElemIds, false );
7888   Remove( rmNodeIds, true );
7889
7890 }
7891
7892
7893 // ========================================================
7894 // class   : SortableElement
7895 // purpose : allow sorting elements basing on their nodes
7896 // ========================================================
7897 class SortableElement : public set <const SMDS_MeshElement*>
7898 {
7899 public:
7900
7901   SortableElement( const SMDS_MeshElement* theElem )
7902   {
7903     myElem = theElem;
7904     SMDS_ElemIteratorPtr nodeIt = theElem->nodesIterator();
7905     while ( nodeIt->more() )
7906       this->insert( nodeIt->next() );
7907   }
7908
7909   const SMDS_MeshElement* Get() const
7910   { return myElem; }
7911
7912   void Set(const SMDS_MeshElement* e) const
7913   { myElem = e; }
7914
7915
7916 private:
7917   mutable const SMDS_MeshElement* myElem;
7918 };
7919
7920 //=======================================================================
7921 //function : FindEqualElements
7922 //purpose  : Return list of group of elements built on the same nodes.
7923 //           Search among theElements or in the whole mesh if theElements is empty
7924 //=======================================================================
7925 void SMESH_MeshEditor::FindEqualElements(set<const SMDS_MeshElement*> & theElements,
7926                                          TListOfListOfElementsID &      theGroupsOfElementsID)
7927 {
7928   myLastCreatedElems.Clear();
7929   myLastCreatedNodes.Clear();
7930
7931   typedef set<const SMDS_MeshElement*> TElemsSet;
7932   typedef map< SortableElement, int > TMapOfNodeSet;
7933   typedef list<int> TGroupOfElems;
7934
7935   TElemsSet elems;
7936   if ( theElements.empty() )
7937   { // get all elements in the mesh
7938     SMDS_ElemIteratorPtr eIt = GetMeshDS()->elementsIterator();
7939     while ( eIt->more() )
7940       elems.insert( elems.end(), eIt->next());
7941   }
7942   else
7943     elems = theElements;
7944
7945   vector< TGroupOfElems > arrayOfGroups;
7946   TGroupOfElems groupOfElems;
7947   TMapOfNodeSet mapOfNodeSet;
7948
7949   TElemsSet::iterator elemIt = elems.begin();
7950   for ( int i = 0, j=0; elemIt != elems.end(); ++elemIt, ++j ) {
7951     const SMDS_MeshElement* curElem = *elemIt;
7952     SortableElement SE(curElem);
7953     int ind = -1;
7954     // check uniqueness
7955     pair< TMapOfNodeSet::iterator, bool> pp = mapOfNodeSet.insert(make_pair(SE, i));
7956     if( !(pp.second) ) {
7957       TMapOfNodeSet::iterator& itSE = pp.first;
7958       ind = (*itSE).second;
7959       arrayOfGroups[ind].push_back(curElem->GetID());
7960     }
7961     else {
7962       groupOfElems.clear();
7963       groupOfElems.push_back(curElem->GetID());
7964       arrayOfGroups.push_back(groupOfElems);
7965       i++;
7966     }
7967   }
7968
7969   vector< TGroupOfElems >::iterator groupIt = arrayOfGroups.begin();
7970   for ( ; groupIt != arrayOfGroups.end(); ++groupIt ) {
7971     groupOfElems = *groupIt;
7972     if ( groupOfElems.size() > 1 ) {
7973       groupOfElems.sort();
7974       theGroupsOfElementsID.push_back(groupOfElems);
7975     }
7976   }
7977 }
7978
7979 //=======================================================================
7980 //function : MergeElements
7981 //purpose  : In each given group, substitute all elements by the first one.
7982 //=======================================================================
7983
7984 void SMESH_MeshEditor::MergeElements(TListOfListOfElementsID & theGroupsOfElementsID)
7985 {
7986   myLastCreatedElems.Clear();
7987   myLastCreatedNodes.Clear();
7988
7989   typedef list<int> TListOfIDs;
7990   TListOfIDs rmElemIds; // IDs of elems to remove
7991
7992   SMESHDS_Mesh* aMesh = GetMeshDS();
7993
7994   TListOfListOfElementsID::iterator groupsIt = theGroupsOfElementsID.begin();
7995   while ( groupsIt != theGroupsOfElementsID.end() ) {
7996     TListOfIDs& aGroupOfElemID = *groupsIt;
7997     aGroupOfElemID.sort();
7998     int elemIDToKeep = aGroupOfElemID.front();
7999     const SMDS_MeshElement* elemToKeep = aMesh->FindElement(elemIDToKeep);
8000     aGroupOfElemID.pop_front();
8001     TListOfIDs::iterator idIt = aGroupOfElemID.begin();
8002     while ( idIt != aGroupOfElemID.end() ) {
8003       int elemIDToRemove = *idIt;
8004       const SMDS_MeshElement* elemToRemove = aMesh->FindElement(elemIDToRemove);
8005       // add the kept element in groups of removed one (PAL15188)
8006       AddToSameGroups( elemToKeep, elemToRemove, aMesh );
8007       rmElemIds.push_back( elemIDToRemove );
8008       ++idIt;
8009     }
8010     ++groupsIt;
8011   }
8012
8013   Remove( rmElemIds, false );
8014 }
8015
8016 //=======================================================================
8017 //function : MergeEqualElements
8018 //purpose  : Remove all but one of elements built on the same nodes.
8019 //=======================================================================
8020
8021 void SMESH_MeshEditor::MergeEqualElements()
8022 {
8023   set<const SMDS_MeshElement*> aMeshElements; /* empty input -
8024                                                  to merge equal elements in the whole mesh */
8025   TListOfListOfElementsID aGroupsOfElementsID;
8026   FindEqualElements(aMeshElements, aGroupsOfElementsID);
8027   MergeElements(aGroupsOfElementsID);
8028 }
8029
8030 //=======================================================================
8031 //function : FindFaceInSet
8032 //purpose  : Return a face having linked nodes n1 and n2 and which is
8033 //           - not in avoidSet,
8034 //           - in elemSet provided that !elemSet.empty()
8035 //           i1 and i2 optionally returns indices of n1 and n2
8036 //=======================================================================
8037
8038 const SMDS_MeshElement*
8039 SMESH_MeshEditor::FindFaceInSet(const SMDS_MeshNode*    n1,
8040                                 const SMDS_MeshNode*    n2,
8041                                 const TIDSortedElemSet& elemSet,
8042                                 const TIDSortedElemSet& avoidSet,
8043                                 int*                    n1ind,
8044                                 int*                    n2ind)
8045
8046 {
8047   int i1, i2;
8048   const SMDS_MeshElement* face = 0;
8049
8050   SMDS_ElemIteratorPtr invElemIt = n1->GetInverseElementIterator(SMDSAbs_Face);
8051   //MESSAGE("n1->GetInverseElementIterator(SMDSAbs_Face) " << invElemIt);
8052   while ( invElemIt->more() && !face ) // loop on inverse faces of n1
8053   {
8054     //MESSAGE("in while ( invElemIt->more() && !face )");
8055     const SMDS_MeshElement* elem = invElemIt->next();
8056     if (avoidSet.count( elem ))
8057       continue;
8058     if ( !elemSet.empty() && !elemSet.count( elem ))
8059       continue;
8060     // index of n1
8061     i1 = elem->GetNodeIndex( n1 );
8062     // find a n2 linked to n1
8063     int nbN = elem->IsQuadratic() ? elem->NbNodes()/2 : elem->NbNodes();
8064     for ( int di = -1; di < 2 && !face; di += 2 )
8065     {
8066       i2 = (i1+di+nbN) % nbN;
8067       if ( elem->GetNode( i2 ) == n2 )
8068         face = elem;
8069     }
8070     if ( !face && elem->IsQuadratic())
8071     {
8072       // analysis for quadratic elements using all nodes
8073       const SMDS_VtkFace* F =
8074         dynamic_cast<const SMDS_VtkFace*>(elem);
8075       if (!F) throw SALOME_Exception(LOCALIZED("not an SMDS_VtkFace"));
8076       // use special nodes iterator
8077       SMDS_ElemIteratorPtr anIter = F->interlacedNodesElemIterator();
8078       const SMDS_MeshNode* prevN = cast2Node( anIter->next() );
8079       for ( i1 = -1, i2 = 0; anIter->more() && !face; i1++, i2++ )
8080       {
8081         const SMDS_MeshNode* n = cast2Node( anIter->next() );
8082         if ( n1 == prevN && n2 == n )
8083         {
8084           face = elem;
8085         }
8086         else if ( n2 == prevN && n1 == n )
8087         {
8088           face = elem; swap( i1, i2 );
8089         }
8090         prevN = n;
8091       }
8092     }
8093   }
8094   if ( n1ind ) *n1ind = i1;
8095   if ( n2ind ) *n2ind = i2;
8096   return face;
8097 }
8098
8099 //=======================================================================
8100 //function : findAdjacentFace
8101 //purpose  :
8102 //=======================================================================
8103
8104 static const SMDS_MeshElement* findAdjacentFace(const SMDS_MeshNode* n1,
8105                                                 const SMDS_MeshNode* n2,
8106                                                 const SMDS_MeshElement* elem)
8107 {
8108   TIDSortedElemSet elemSet, avoidSet;
8109   if ( elem )
8110     avoidSet.insert ( elem );
8111   return SMESH_MeshEditor::FindFaceInSet( n1, n2, elemSet, avoidSet );
8112 }
8113
8114 //=======================================================================
8115 //function : FindFreeBorder
8116 //purpose  :
8117 //=======================================================================
8118
8119 #define ControlFreeBorder SMESH::Controls::FreeEdges::IsFreeEdge
8120
8121 bool SMESH_MeshEditor::FindFreeBorder (const SMDS_MeshNode*             theFirstNode,
8122                                        const SMDS_MeshNode*             theSecondNode,
8123                                        const SMDS_MeshNode*             theLastNode,
8124                                        list< const SMDS_MeshNode* > &   theNodes,
8125                                        list< const SMDS_MeshElement* >& theFaces)
8126 {
8127   if ( !theFirstNode || !theSecondNode )
8128     return false;
8129   // find border face between theFirstNode and theSecondNode
8130   const SMDS_MeshElement* curElem = findAdjacentFace( theFirstNode, theSecondNode, 0 );
8131   if ( !curElem )
8132     return false;
8133
8134   theFaces.push_back( curElem );
8135   theNodes.push_back( theFirstNode );
8136   theNodes.push_back( theSecondNode );
8137
8138   //vector<const SMDS_MeshNode*> nodes;
8139   const SMDS_MeshNode *nIgnore = theFirstNode, *nStart = theSecondNode;
8140   TIDSortedElemSet foundElems;
8141   bool needTheLast = ( theLastNode != 0 );
8142
8143   while ( nStart != theLastNode ) {
8144     if ( nStart == theFirstNode )
8145       return !needTheLast;
8146
8147     // find all free border faces sharing form nStart
8148
8149     list< const SMDS_MeshElement* > curElemList;
8150     list< const SMDS_MeshNode* > nStartList;
8151     SMDS_ElemIteratorPtr invElemIt = nStart->GetInverseElementIterator(SMDSAbs_Face);
8152     while ( invElemIt->more() ) {
8153       const SMDS_MeshElement* e = invElemIt->next();
8154       if ( e == curElem || foundElems.insert( e ).second ) {
8155         // get nodes
8156         int iNode = 0, nbNodes = e->NbNodes();
8157         //const SMDS_MeshNode* nodes[nbNodes+1];
8158         vector<const SMDS_MeshNode*> nodes(nbNodes+1);
8159
8160         if(e->IsQuadratic()) {
8161           const SMDS_VtkFace* F =
8162             dynamic_cast<const SMDS_VtkFace*>(e);
8163           if (!F) throw SALOME_Exception(LOCALIZED("not an SMDS_VtkFace"));
8164           // use special nodes iterator
8165           SMDS_ElemIteratorPtr anIter = F->interlacedNodesElemIterator();
8166           while( anIter->more() ) {
8167             nodes[ iNode++ ] = cast2Node(anIter->next());
8168           }
8169         }
8170         else {
8171           SMDS_ElemIteratorPtr nIt = e->nodesIterator();
8172           while ( nIt->more() )
8173             nodes[ iNode++ ] = static_cast<const SMDS_MeshNode*>( nIt->next() );
8174         }
8175         nodes[ iNode ] = nodes[ 0 ];
8176         // check 2 links
8177         for ( iNode = 0; iNode < nbNodes; iNode++ )
8178           if (((nodes[ iNode ] == nStart && nodes[ iNode + 1] != nIgnore ) ||
8179                (nodes[ iNode + 1] == nStart && nodes[ iNode ] != nIgnore )) &&
8180               ControlFreeBorder( &nodes[ iNode ], e->GetID() ))
8181           {
8182             nStartList.push_back( nodes[ iNode + ( nodes[ iNode ] == nStart ? 1 : 0 )]);
8183             curElemList.push_back( e );
8184           }
8185       }
8186     }
8187     // analyse the found
8188
8189     int nbNewBorders = curElemList.size();
8190     if ( nbNewBorders == 0 ) {
8191       // no free border furthermore
8192       return !needTheLast;
8193     }
8194     else if ( nbNewBorders == 1 ) {
8195       // one more element found
8196       nIgnore = nStart;
8197       nStart = nStartList.front();
8198       curElem = curElemList.front();
8199       theFaces.push_back( curElem );
8200       theNodes.push_back( nStart );
8201     }
8202     else {
8203       // several continuations found
8204       list< const SMDS_MeshElement* >::iterator curElemIt;
8205       list< const SMDS_MeshNode* >::iterator nStartIt;
8206       // check if one of them reached the last node
8207       if ( needTheLast ) {
8208         for (curElemIt = curElemList.begin(), nStartIt = nStartList.begin();
8209              curElemIt!= curElemList.end();
8210              curElemIt++, nStartIt++ )
8211           if ( *nStartIt == theLastNode ) {
8212             theFaces.push_back( *curElemIt );
8213             theNodes.push_back( *nStartIt );
8214             return true;
8215           }
8216       }
8217       // find the best free border by the continuations
8218       list<const SMDS_MeshNode*>    contNodes[ 2 ], *cNL;
8219       list<const SMDS_MeshElement*> contFaces[ 2 ], *cFL;
8220       for (curElemIt = curElemList.begin(), nStartIt = nStartList.begin();
8221            curElemIt!= curElemList.end();
8222            curElemIt++, nStartIt++ )
8223       {
8224         cNL = & contNodes[ contNodes[0].empty() ? 0 : 1 ];
8225         cFL = & contFaces[ contFaces[0].empty() ? 0 : 1 ];
8226         // find one more free border
8227         if ( ! FindFreeBorder( nStart, *nStartIt, theLastNode, *cNL, *cFL )) {
8228           cNL->clear();
8229           cFL->clear();
8230         }
8231         else if ( !contNodes[0].empty() && !contNodes[1].empty() ) {
8232           // choice: clear a worse one
8233           int iLongest = ( contNodes[0].size() < contNodes[1].size() ? 1 : 0 );
8234           int iWorse = ( needTheLast ? 1 - iLongest : iLongest );
8235           contNodes[ iWorse ].clear();
8236           contFaces[ iWorse ].clear();
8237         }
8238       }
8239       if ( contNodes[0].empty() && contNodes[1].empty() )
8240         return false;
8241
8242       // append the best free border
8243       cNL = & contNodes[ contNodes[0].empty() ? 1 : 0 ];
8244       cFL = & contFaces[ contFaces[0].empty() ? 1 : 0 ];
8245       theNodes.pop_back(); // remove nIgnore
8246       theNodes.pop_back(); // remove nStart
8247       theFaces.pop_back(); // remove curElem
8248       list< const SMDS_MeshNode* >::iterator nIt = cNL->begin();
8249       list< const SMDS_MeshElement* >::iterator fIt = cFL->begin();
8250       for ( ; nIt != cNL->end(); nIt++ ) theNodes.push_back( *nIt );
8251       for ( ; fIt != cFL->end(); fIt++ ) theFaces.push_back( *fIt );
8252       return true;
8253
8254     } // several continuations found
8255   } // while ( nStart != theLastNode )
8256
8257   return true;
8258 }
8259
8260 //=======================================================================
8261 //function : CheckFreeBorderNodes
8262 //purpose  : Return true if the tree nodes are on a free border
8263 //=======================================================================
8264
8265 bool SMESH_MeshEditor::CheckFreeBorderNodes(const SMDS_MeshNode* theNode1,
8266                                             const SMDS_MeshNode* theNode2,
8267                                             const SMDS_MeshNode* theNode3)
8268 {
8269   list< const SMDS_MeshNode* > nodes;
8270   list< const SMDS_MeshElement* > faces;
8271   return FindFreeBorder( theNode1, theNode2, theNode3, nodes, faces);
8272 }
8273
8274 //=======================================================================
8275 //function : SewFreeBorder
8276 //purpose  :
8277 //=======================================================================
8278
8279 SMESH_MeshEditor::Sew_Error
8280 SMESH_MeshEditor::SewFreeBorder (const SMDS_MeshNode* theBordFirstNode,
8281                                  const SMDS_MeshNode* theBordSecondNode,
8282                                  const SMDS_MeshNode* theBordLastNode,
8283                                  const SMDS_MeshNode* theSideFirstNode,
8284                                  const SMDS_MeshNode* theSideSecondNode,
8285                                  const SMDS_MeshNode* theSideThirdNode,
8286                                  const bool           theSideIsFreeBorder,
8287                                  const bool           toCreatePolygons,
8288                                  const bool           toCreatePolyedrs)
8289 {
8290   myLastCreatedElems.Clear();
8291   myLastCreatedNodes.Clear();
8292
8293   MESSAGE("::SewFreeBorder()");
8294   Sew_Error aResult = SEW_OK;
8295
8296   // ====================================
8297   //    find side nodes and elements
8298   // ====================================
8299
8300   list< const SMDS_MeshNode* > nSide[ 2 ];
8301   list< const SMDS_MeshElement* > eSide[ 2 ];
8302   list< const SMDS_MeshNode* >::iterator nIt[ 2 ];
8303   list< const SMDS_MeshElement* >::iterator eIt[ 2 ];
8304
8305   // Free border 1
8306   // --------------
8307   if (!FindFreeBorder(theBordFirstNode,theBordSecondNode,theBordLastNode,
8308                       nSide[0], eSide[0])) {
8309     MESSAGE(" Free Border 1 not found " );
8310     aResult = SEW_BORDER1_NOT_FOUND;
8311   }
8312   if (theSideIsFreeBorder) {
8313     // Free border 2
8314     // --------------
8315     if (!FindFreeBorder(theSideFirstNode, theSideSecondNode, theSideThirdNode,
8316                         nSide[1], eSide[1])) {
8317       MESSAGE(" Free Border 2 not found " );
8318       aResult = ( aResult != SEW_OK ? SEW_BOTH_BORDERS_NOT_FOUND : SEW_BORDER2_NOT_FOUND );
8319     }
8320   }
8321   if ( aResult != SEW_OK )
8322     return aResult;
8323
8324   if (!theSideIsFreeBorder) {
8325     // Side 2
8326     // --------------
8327
8328     // -------------------------------------------------------------------------
8329     // Algo:
8330     // 1. If nodes to merge are not coincident, move nodes of the free border
8331     //    from the coord sys defined by the direction from the first to last
8332     //    nodes of the border to the correspondent sys of the side 2
8333     // 2. On the side 2, find the links most co-directed with the correspondent
8334     //    links of the free border
8335     // -------------------------------------------------------------------------
8336
8337     // 1. Since sewing may break if there are volumes to split on the side 2,
8338     //    we wont move nodes but just compute new coordinates for them
8339     typedef map<const SMDS_MeshNode*, gp_XYZ> TNodeXYZMap;
8340     TNodeXYZMap nBordXYZ;
8341     list< const SMDS_MeshNode* >& bordNodes = nSide[ 0 ];
8342     list< const SMDS_MeshNode* >::iterator nBordIt;
8343
8344     gp_XYZ Pb1( theBordFirstNode->X(), theBordFirstNode->Y(), theBordFirstNode->Z() );
8345     gp_XYZ Pb2( theBordLastNode->X(), theBordLastNode->Y(), theBordLastNode->Z() );
8346     gp_XYZ Ps1( theSideFirstNode->X(), theSideFirstNode->Y(), theSideFirstNode->Z() );
8347     gp_XYZ Ps2( theSideSecondNode->X(), theSideSecondNode->Y(), theSideSecondNode->Z() );
8348     double tol2 = 1.e-8;
8349     gp_Vec Vbs1( Pb1 - Ps1 ),Vbs2( Pb2 - Ps2 );
8350     if ( Vbs1.SquareMagnitude() > tol2 || Vbs2.SquareMagnitude() > tol2 ) {
8351       // Need node movement.
8352
8353       // find X and Z axes to create trsf
8354       gp_Vec Zb( Pb1 - Pb2 ), Zs( Ps1 - Ps2 );
8355       gp_Vec X = Zs ^ Zb;
8356       if ( X.SquareMagnitude() <= gp::Resolution() * gp::Resolution() )
8357         // Zb || Zs
8358         X = gp_Ax2( gp::Origin(), Zb ).XDirection();
8359
8360       // coord systems
8361       gp_Ax3 toBordAx( Pb1, Zb, X );
8362       gp_Ax3 fromSideAx( Ps1, Zs, X );
8363       gp_Ax3 toGlobalAx( gp::Origin(), gp::DZ(), gp::DX() );
8364       // set trsf
8365       gp_Trsf toBordSys, fromSide2Sys;
8366       toBordSys.SetTransformation( toBordAx );
8367       fromSide2Sys.SetTransformation( fromSideAx, toGlobalAx );
8368       fromSide2Sys.SetScaleFactor( Zs.Magnitude() / Zb.Magnitude() );
8369
8370       // move
8371       for ( nBordIt = bordNodes.begin(); nBordIt != bordNodes.end(); nBordIt++ ) {
8372         const SMDS_MeshNode* n = *nBordIt;
8373         gp_XYZ xyz( n->X(),n->Y(),n->Z() );
8374         toBordSys.Transforms( xyz );
8375         fromSide2Sys.Transforms( xyz );
8376         nBordXYZ.insert( TNodeXYZMap::value_type( n, xyz ));
8377       }
8378     }
8379     else {
8380       // just insert nodes XYZ in the nBordXYZ map
8381       for ( nBordIt = bordNodes.begin(); nBordIt != bordNodes.end(); nBordIt++ ) {
8382         const SMDS_MeshNode* n = *nBordIt;
8383         nBordXYZ.insert( TNodeXYZMap::value_type( n, gp_XYZ( n->X(),n->Y(),n->Z() )));
8384       }
8385     }
8386
8387     // 2. On the side 2, find the links most co-directed with the correspondent
8388     //    links of the free border
8389
8390     list< const SMDS_MeshElement* >& sideElems = eSide[ 1 ];
8391     list< const SMDS_MeshNode* >& sideNodes = nSide[ 1 ];
8392     sideNodes.push_back( theSideFirstNode );
8393
8394     bool hasVolumes = false;
8395     LinkID_Gen aLinkID_Gen( GetMeshDS() );
8396     set<long> foundSideLinkIDs, checkedLinkIDs;
8397     SMDS_VolumeTool volume;
8398     //const SMDS_MeshNode* faceNodes[ 4 ];
8399
8400     const SMDS_MeshNode*    sideNode;
8401     const SMDS_MeshElement* sideElem;
8402     const SMDS_MeshNode* prevSideNode = theSideFirstNode;
8403     const SMDS_MeshNode* prevBordNode = theBordFirstNode;
8404     nBordIt = bordNodes.begin();
8405     nBordIt++;
8406     // border node position and border link direction to compare with
8407     gp_XYZ bordPos = nBordXYZ[ *nBordIt ];
8408     gp_XYZ bordDir = bordPos - nBordXYZ[ prevBordNode ];
8409     // choose next side node by link direction or by closeness to
8410     // the current border node:
8411     bool searchByDir = ( *nBordIt != theBordLastNode );
8412     do {
8413       // find the next node on the Side 2
8414       sideNode = 0;
8415       double maxDot = -DBL_MAX, minDist = DBL_MAX;
8416       long linkID;
8417       checkedLinkIDs.clear();
8418       gp_XYZ prevXYZ( prevSideNode->X(), prevSideNode->Y(), prevSideNode->Z() );
8419
8420       // loop on inverse elements of current node (prevSideNode) on the Side 2
8421       SMDS_ElemIteratorPtr invElemIt = prevSideNode->GetInverseElementIterator();
8422       while ( invElemIt->more() )
8423       {
8424         const SMDS_MeshElement* elem = invElemIt->next();
8425         // prepare data for a loop on links coming to prevSideNode, of a face or a volume
8426         int iPrevNode, iNode = 0, nbNodes = elem->NbNodes();
8427         vector< const SMDS_MeshNode* > faceNodes( nbNodes, (const SMDS_MeshNode*)0 );
8428         bool isVolume = volume.Set( elem );
8429         const SMDS_MeshNode** nodes = isVolume ? volume.GetNodes() : & faceNodes[0];
8430         if ( isVolume ) // --volume
8431           hasVolumes = true;
8432         else if ( elem->GetType()==SMDSAbs_Face ) { // --face
8433           // retrieve all face nodes and find iPrevNode - an index of the prevSideNode
8434           if(elem->IsQuadratic()) {
8435             const SMDS_VtkFace* F =
8436               dynamic_cast<const SMDS_VtkFace*>(elem);
8437             if (!F) throw SALOME_Exception(LOCALIZED("not an SMDS_VtkFace"));
8438             // use special nodes iterator
8439             SMDS_ElemIteratorPtr anIter = F->interlacedNodesElemIterator();
8440             while( anIter->more() ) {
8441               nodes[ iNode ] = cast2Node(anIter->next());
8442               if ( nodes[ iNode++ ] == prevSideNode )
8443                 iPrevNode = iNode - 1;
8444             }
8445           }
8446           else {
8447             SMDS_ElemIteratorPtr nIt = elem->nodesIterator();
8448             while ( nIt->more() ) {
8449               nodes[ iNode ] = cast2Node( nIt->next() );
8450               if ( nodes[ iNode++ ] == prevSideNode )
8451                 iPrevNode = iNode - 1;
8452             }
8453           }
8454           // there are 2 links to check
8455           nbNodes = 2;
8456         }
8457         else // --edge
8458           continue;
8459         // loop on links, to be precise, on the second node of links
8460         for ( iNode = 0; iNode < nbNodes; iNode++ ) {
8461           const SMDS_MeshNode* n = nodes[ iNode ];
8462           if ( isVolume ) {
8463             if ( !volume.IsLinked( n, prevSideNode ))
8464               continue;
8465           }
8466           else {
8467             if ( iNode ) // a node before prevSideNode
8468               n = nodes[ iPrevNode == 0 ? elem->NbNodes() - 1 : iPrevNode - 1 ];
8469             else         // a node after prevSideNode
8470               n = nodes[ iPrevNode + 1 == elem->NbNodes() ? 0 : iPrevNode + 1 ];
8471           }
8472           // check if this link was already used
8473           long iLink = aLinkID_Gen.GetLinkID( prevSideNode, n );
8474           bool isJustChecked = !checkedLinkIDs.insert( iLink ).second;
8475           if (!isJustChecked &&
8476               foundSideLinkIDs.find( iLink ) == foundSideLinkIDs.end() )
8477           {
8478             // test a link geometrically
8479             gp_XYZ nextXYZ ( n->X(), n->Y(), n->Z() );
8480             bool linkIsBetter = false;
8481             double dot = 0.0, dist = 0.0;
8482             if ( searchByDir ) { // choose most co-directed link
8483               dot = bordDir * ( nextXYZ - prevXYZ ).Normalized();
8484               linkIsBetter = ( dot > maxDot );
8485             }
8486             else { // choose link with the node closest to bordPos
8487               dist = ( nextXYZ - bordPos ).SquareModulus();
8488               linkIsBetter = ( dist < minDist );
8489             }
8490             if ( linkIsBetter ) {
8491               maxDot = dot;
8492               minDist = dist;
8493               linkID = iLink;
8494               sideNode = n;
8495               sideElem = elem;
8496             }
8497           }
8498         }
8499       } // loop on inverse elements of prevSideNode
8500
8501       if ( !sideNode ) {
8502         MESSAGE(" Cant find path by links of the Side 2 ");
8503         return SEW_BAD_SIDE_NODES;
8504       }
8505       sideNodes.push_back( sideNode );
8506       sideElems.push_back( sideElem );
8507       foundSideLinkIDs.insert ( linkID );
8508       prevSideNode = sideNode;
8509
8510       if ( *nBordIt == theBordLastNode )
8511         searchByDir = false;
8512       else {
8513         // find the next border link to compare with
8514         gp_XYZ sidePos( sideNode->X(), sideNode->Y(), sideNode->Z() );
8515         searchByDir = ( bordDir * ( sidePos - bordPos ) <= 0 );
8516         // move to next border node if sideNode is before forward border node (bordPos)
8517         while ( *nBordIt != theBordLastNode && !searchByDir ) {
8518           prevBordNode = *nBordIt;
8519           nBordIt++;
8520           bordPos = nBordXYZ[ *nBordIt ];
8521           bordDir = bordPos - nBordXYZ[ prevBordNode ];
8522           searchByDir = ( bordDir * ( sidePos - bordPos ) <= 0 );
8523         }
8524       }
8525     }
8526     while ( sideNode != theSideSecondNode );
8527
8528     if ( hasVolumes && sideNodes.size () != bordNodes.size() && !toCreatePolyedrs) {
8529       MESSAGE("VOLUME SPLITTING IS FORBIDDEN");
8530       return SEW_VOLUMES_TO_SPLIT; // volume splitting is forbidden
8531     }
8532   } // end nodes search on the side 2
8533
8534   // ============================
8535   // sew the border to the side 2
8536   // ============================
8537
8538   int nbNodes[]  = { nSide[0].size(), nSide[1].size() };
8539   int maxNbNodes = Max( nbNodes[0], nbNodes[1] );
8540
8541   TListOfListOfNodes nodeGroupsToMerge;
8542   if ( nbNodes[0] == nbNodes[1] ||
8543        ( theSideIsFreeBorder && !theSideThirdNode)) {
8544
8545     // all nodes are to be merged
8546
8547     for (nIt[0] = nSide[0].begin(), nIt[1] = nSide[1].begin();
8548          nIt[0] != nSide[0].end() && nIt[1] != nSide[1].end();
8549          nIt[0]++, nIt[1]++ )
8550     {
8551       nodeGroupsToMerge.push_back( list<const SMDS_MeshNode*>() );
8552       nodeGroupsToMerge.back().push_back( *nIt[1] ); // to keep
8553       nodeGroupsToMerge.back().push_back( *nIt[0] ); // to remove
8554     }
8555   }
8556   else {
8557
8558     // insert new nodes into the border and the side to get equal nb of segments
8559
8560     // get normalized parameters of nodes on the borders
8561     //double param[ 2 ][ maxNbNodes ];
8562     double* param[ 2 ];
8563     param[0] = new double [ maxNbNodes ];
8564     param[1] = new double [ maxNbNodes ];
8565     int iNode, iBord;
8566     for ( iBord = 0; iBord < 2; iBord++ ) { // loop on 2 borders
8567       list< const SMDS_MeshNode* >& nodes = nSide[ iBord ];
8568       list< const SMDS_MeshNode* >::iterator nIt = nodes.begin();
8569       const SMDS_MeshNode* nPrev = *nIt;
8570       double bordLength = 0;
8571       for ( iNode = 0; nIt != nodes.end(); nIt++, iNode++ ) { // loop on border nodes
8572         const SMDS_MeshNode* nCur = *nIt;
8573         gp_XYZ segment (nCur->X() - nPrev->X(),
8574                         nCur->Y() - nPrev->Y(),
8575                         nCur->Z() - nPrev->Z());
8576         double segmentLen = segment.Modulus();
8577         bordLength += segmentLen;
8578         param[ iBord ][ iNode ] = bordLength;
8579         nPrev = nCur;
8580       }
8581       // normalize within [0,1]
8582       for ( iNode = 0; iNode < nbNodes[ iBord ]; iNode++ ) {
8583         param[ iBord ][ iNode ] /= bordLength;
8584       }
8585     }
8586
8587     // loop on border segments
8588     const SMDS_MeshNode *nPrev[ 2 ] = { 0, 0 };
8589     int i[ 2 ] = { 0, 0 };
8590     nIt[0] = nSide[0].begin(); eIt[0] = eSide[0].begin();
8591     nIt[1] = nSide[1].begin(); eIt[1] = eSide[1].begin();
8592
8593     TElemOfNodeListMap insertMap;
8594     TElemOfNodeListMap::iterator insertMapIt;
8595     // insertMap is
8596     // key:   elem to insert nodes into
8597     // value: 2 nodes to insert between + nodes to be inserted
8598     do {
8599       bool next[ 2 ] = { false, false };
8600
8601       // find min adjacent segment length after sewing
8602       double nextParam = 10., prevParam = 0;
8603       for ( iBord = 0; iBord < 2; iBord++ ) { // loop on 2 borders
8604         if ( i[ iBord ] + 1 < nbNodes[ iBord ])
8605           nextParam = Min( nextParam, param[iBord][ i[iBord] + 1 ]);
8606         if ( i[ iBord ] > 0 )
8607           prevParam = Max( prevParam, param[iBord][ i[iBord] - 1 ]);
8608       }
8609       double minParam = Min( param[ 0 ][ i[0] ], param[ 1 ][ i[1] ]);
8610       double maxParam = Max( param[ 0 ][ i[0] ], param[ 1 ][ i[1] ]);
8611       double minSegLen = Min( nextParam - minParam, maxParam - prevParam );
8612
8613       // choose to insert or to merge nodes
8614       double du = param[ 1 ][ i[1] ] - param[ 0 ][ i[0] ];
8615       if ( Abs( du ) <= minSegLen * 0.2 ) {
8616         // merge
8617         // ------
8618         nodeGroupsToMerge.push_back( list<const SMDS_MeshNode*>() );
8619         const SMDS_MeshNode* n0 = *nIt[0];
8620         const SMDS_MeshNode* n1 = *nIt[1];
8621         nodeGroupsToMerge.back().push_back( n1 );
8622         nodeGroupsToMerge.back().push_back( n0 );
8623         // position of node of the border changes due to merge
8624         param[ 0 ][ i[0] ] += du;
8625         // move n1 for the sake of elem shape evaluation during insertion.
8626         // n1 will be removed by MergeNodes() anyway
8627         const_cast<SMDS_MeshNode*>( n0 )->setXYZ( n1->X(), n1->Y(), n1->Z() );
8628         next[0] = next[1] = true;
8629       }
8630       else {
8631         // insert
8632         // ------
8633         int intoBord = ( du < 0 ) ? 0 : 1;
8634         const SMDS_MeshElement* elem = *eIt[ intoBord ];
8635         const SMDS_MeshNode*    n1   = nPrev[ intoBord ];
8636         const SMDS_MeshNode*    n2   = *nIt[ intoBord ];
8637         const SMDS_MeshNode*    nIns = *nIt[ 1 - intoBord ];
8638         if ( intoBord == 1 ) {
8639           // move node of the border to be on a link of elem of the side
8640           gp_XYZ p1 (n1->X(), n1->Y(), n1->Z());
8641           gp_XYZ p2 (n2->X(), n2->Y(), n2->Z());
8642           double ratio = du / ( param[ 1 ][ i[1] ] - param[ 1 ][ i[1]-1 ]);
8643           gp_XYZ p = p2 * ( 1 - ratio ) + p1 * ratio;
8644           GetMeshDS()->MoveNode( nIns, p.X(), p.Y(), p.Z() );
8645         }
8646         insertMapIt = insertMap.find( elem );
8647         bool notFound = ( insertMapIt == insertMap.end() );
8648         bool otherLink = ( !notFound && (*insertMapIt).second.front() != n1 );
8649         if ( otherLink ) {
8650           // insert into another link of the same element:
8651           // 1. perform insertion into the other link of the elem
8652           list<const SMDS_MeshNode*> & nodeList = (*insertMapIt).second;
8653           const SMDS_MeshNode* n12 = nodeList.front(); nodeList.pop_front();
8654           const SMDS_MeshNode* n22 = nodeList.front(); nodeList.pop_front();
8655           InsertNodesIntoLink( elem, n12, n22, nodeList, toCreatePolygons );
8656           // 2. perform insertion into the link of adjacent faces
8657           while (true) {
8658             const SMDS_MeshElement* adjElem = findAdjacentFace( n12, n22, elem );
8659             if ( adjElem )
8660               InsertNodesIntoLink( adjElem, n12, n22, nodeList, toCreatePolygons );
8661             else
8662               break;
8663           }
8664           if (toCreatePolyedrs) {
8665             // perform insertion into the links of adjacent volumes
8666             UpdateVolumes(n12, n22, nodeList);
8667           }
8668           // 3. find an element appeared on n1 and n2 after the insertion
8669           insertMap.erase( elem );
8670           elem = findAdjacentFace( n1, n2, 0 );
8671         }
8672         if ( notFound || otherLink ) {
8673           // add element and nodes of the side into the insertMap
8674           insertMapIt = insertMap.insert
8675             ( TElemOfNodeListMap::value_type( elem, list<const SMDS_MeshNode*>() )).first;
8676           (*insertMapIt).second.push_back( n1 );
8677           (*insertMapIt).second.push_back( n2 );
8678         }
8679         // add node to be inserted into elem
8680         (*insertMapIt).second.push_back( nIns );
8681         next[ 1 - intoBord ] = true;
8682       }
8683
8684       // go to the next segment
8685       for ( iBord = 0; iBord < 2; iBord++ ) { // loop on 2 borders
8686         if ( next[ iBord ] ) {
8687           if ( i[ iBord ] != 0 && eIt[ iBord ] != eSide[ iBord ].end())
8688             eIt[ iBord ]++;
8689           nPrev[ iBord ] = *nIt[ iBord ];
8690           nIt[ iBord ]++; i[ iBord ]++;
8691         }
8692       }
8693     }
8694     while ( nIt[0] != nSide[0].end() && nIt[1] != nSide[1].end());
8695
8696     // perform insertion of nodes into elements
8697
8698     for (insertMapIt = insertMap.begin();
8699          insertMapIt != insertMap.end();
8700          insertMapIt++ )
8701     {
8702       const SMDS_MeshElement* elem = (*insertMapIt).first;
8703       list<const SMDS_MeshNode*> & nodeList = (*insertMapIt).second;
8704       const SMDS_MeshNode* n1 = nodeList.front(); nodeList.pop_front();
8705       const SMDS_MeshNode* n2 = nodeList.front(); nodeList.pop_front();
8706
8707       InsertNodesIntoLink( elem, n1, n2, nodeList, toCreatePolygons );
8708
8709       if ( !theSideIsFreeBorder ) {
8710         // look for and insert nodes into the faces adjacent to elem
8711         while (true) {
8712           const SMDS_MeshElement* adjElem = findAdjacentFace( n1, n2, elem );
8713           if ( adjElem )
8714             InsertNodesIntoLink( adjElem, n1, n2, nodeList, toCreatePolygons );
8715           else
8716             break;
8717         }
8718       }
8719       if (toCreatePolyedrs) {
8720         // perform insertion into the links of adjacent volumes
8721         UpdateVolumes(n1, n2, nodeList);
8722       }
8723     }
8724
8725     delete param[0];
8726     delete param[1];
8727   } // end: insert new nodes
8728
8729   MergeNodes ( nodeGroupsToMerge );
8730
8731   return aResult;
8732 }
8733
8734 //=======================================================================
8735 //function : InsertNodesIntoLink
8736 //purpose  : insert theNodesToInsert into theFace between theBetweenNode1
8737 //           and theBetweenNode2 and split theElement
8738 //=======================================================================
8739
8740 void SMESH_MeshEditor::InsertNodesIntoLink(const SMDS_MeshElement*     theFace,
8741                                            const SMDS_MeshNode*        theBetweenNode1,
8742                                            const SMDS_MeshNode*        theBetweenNode2,
8743                                            list<const SMDS_MeshNode*>& theNodesToInsert,
8744                                            const bool                  toCreatePoly)
8745 {
8746   if ( theFace->GetType() != SMDSAbs_Face ) return;
8747
8748   // find indices of 2 link nodes and of the rest nodes
8749   int iNode = 0, il1, il2, i3, i4;
8750   il1 = il2 = i3 = i4 = -1;
8751   //const SMDS_MeshNode* nodes[ theFace->NbNodes() ];
8752   vector<const SMDS_MeshNode*> nodes( theFace->NbNodes() );
8753
8754   if(theFace->IsQuadratic()) {
8755     const SMDS_VtkFace* F =
8756       dynamic_cast<const SMDS_VtkFace*>(theFace);
8757     if (!F) throw SALOME_Exception(LOCALIZED("not an SMDS_VtkFace"));
8758     // use special nodes iterator
8759     SMDS_ElemIteratorPtr anIter = F->interlacedNodesElemIterator();
8760     while( anIter->more() ) {
8761       const SMDS_MeshNode* n = cast2Node(anIter->next());
8762       if ( n == theBetweenNode1 )
8763         il1 = iNode;
8764       else if ( n == theBetweenNode2 )
8765         il2 = iNode;
8766       else if ( i3 < 0 )
8767         i3 = iNode;
8768       else
8769         i4 = iNode;
8770       nodes[ iNode++ ] = n;
8771     }
8772   }
8773   else {
8774     SMDS_ElemIteratorPtr nodeIt = theFace->nodesIterator();
8775     while ( nodeIt->more() ) {
8776       const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
8777       if ( n == theBetweenNode1 )
8778         il1 = iNode;
8779       else if ( n == theBetweenNode2 )
8780         il2 = iNode;
8781       else if ( i3 < 0 )
8782         i3 = iNode;
8783       else
8784         i4 = iNode;
8785       nodes[ iNode++ ] = n;
8786     }
8787   }
8788   if ( il1 < 0 || il2 < 0 || i3 < 0 )
8789     return ;
8790
8791   // arrange link nodes to go one after another regarding the face orientation
8792   bool reverse = ( Abs( il2 - il1 ) == 1 ? il2 < il1 : il1 < il2 );
8793   list<const SMDS_MeshNode *> aNodesToInsert = theNodesToInsert;
8794   if ( reverse ) {
8795     iNode = il1;
8796     il1 = il2;
8797     il2 = iNode;
8798     aNodesToInsert.reverse();
8799   }
8800   // check that not link nodes of a quadrangles are in good order
8801   int nbFaceNodes = theFace->NbNodes();
8802   if ( nbFaceNodes == 4 && i4 - i3 != 1 ) {
8803     iNode = i3;
8804     i3 = i4;
8805     i4 = iNode;
8806   }
8807
8808   if (toCreatePoly || theFace->IsPoly()) {
8809
8810     iNode = 0;
8811     vector<const SMDS_MeshNode *> poly_nodes (nbFaceNodes + aNodesToInsert.size());
8812
8813     // add nodes of face up to first node of link
8814     bool isFLN = false;
8815
8816     if(theFace->IsQuadratic()) {
8817       const SMDS_VtkFace* F =
8818         dynamic_cast<const SMDS_VtkFace*>(theFace);
8819       if (!F) throw SALOME_Exception(LOCALIZED("not an SMDS_VtkFace"));
8820       // use special nodes iterator
8821       SMDS_ElemIteratorPtr anIter = F->interlacedNodesElemIterator();
8822       while( anIter->more()  && !isFLN ) {
8823         const SMDS_MeshNode* n = cast2Node(anIter->next());
8824         poly_nodes[iNode++] = n;
8825         if (n == nodes[il1]) {
8826           isFLN = true;
8827         }
8828       }
8829       // add nodes to insert
8830       list<const SMDS_MeshNode*>::iterator nIt = aNodesToInsert.begin();
8831       for (; nIt != aNodesToInsert.end(); nIt++) {
8832         poly_nodes[iNode++] = *nIt;
8833       }
8834       // add nodes of face starting from last node of link
8835       while ( anIter->more() ) {
8836         poly_nodes[iNode++] = cast2Node(anIter->next());
8837       }
8838     }
8839     else {
8840       SMDS_ElemIteratorPtr nodeIt = theFace->nodesIterator();
8841       while ( nodeIt->more() && !isFLN ) {
8842         const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
8843         poly_nodes[iNode++] = n;
8844         if (n == nodes[il1]) {
8845           isFLN = true;
8846         }
8847       }
8848       // add nodes to insert
8849       list<const SMDS_MeshNode*>::iterator nIt = aNodesToInsert.begin();
8850       for (; nIt != aNodesToInsert.end(); nIt++) {
8851         poly_nodes[iNode++] = *nIt;
8852       }
8853       // add nodes of face starting from last node of link
8854       while ( nodeIt->more() ) {
8855         const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
8856         poly_nodes[iNode++] = n;
8857       }
8858     }
8859
8860     // edit or replace the face
8861     SMESHDS_Mesh *aMesh = GetMeshDS();
8862
8863     if (theFace->IsPoly()) {
8864       aMesh->ChangePolygonNodes(theFace, poly_nodes);
8865     }
8866     else {
8867       int aShapeId = FindShape( theFace );
8868
8869       SMDS_MeshElement* newElem = aMesh->AddPolygonalFace(poly_nodes);
8870       myLastCreatedElems.Append(newElem);
8871       if ( aShapeId && newElem )
8872         aMesh->SetMeshElementOnShape( newElem, aShapeId );
8873
8874       aMesh->RemoveElement(theFace);
8875     }
8876     return;
8877   }
8878
8879   SMESHDS_Mesh *aMesh = GetMeshDS();
8880   if( !theFace->IsQuadratic() ) {
8881
8882     // put aNodesToInsert between theBetweenNode1 and theBetweenNode2
8883     int nbLinkNodes = 2 + aNodesToInsert.size();
8884     //const SMDS_MeshNode* linkNodes[ nbLinkNodes ];
8885     vector<const SMDS_MeshNode*> linkNodes( nbLinkNodes );
8886     linkNodes[ 0 ] = nodes[ il1 ];
8887     linkNodes[ nbLinkNodes - 1 ] = nodes[ il2 ];
8888     list<const SMDS_MeshNode*>::iterator nIt = aNodesToInsert.begin();
8889     for ( iNode = 1; nIt != aNodesToInsert.end(); nIt++ ) {
8890       linkNodes[ iNode++ ] = *nIt;
8891     }
8892     // decide how to split a quadrangle: compare possible variants
8893     // and choose which of splits to be a quadrangle
8894     int i1, i2, iSplit, nbSplits = nbLinkNodes - 1, iBestQuad;
8895     if ( nbFaceNodes == 3 ) {
8896       iBestQuad = nbSplits;
8897       i4 = i3;
8898     }
8899     else if ( nbFaceNodes == 4 ) {
8900       SMESH::Controls::NumericalFunctorPtr aCrit( new SMESH::Controls::AspectRatio);
8901       double aBestRate = DBL_MAX;
8902       for ( int iQuad = 0; iQuad < nbSplits; iQuad++ ) {
8903         i1 = 0; i2 = 1;
8904         double aBadRate = 0;
8905         // evaluate elements quality
8906         for ( iSplit = 0; iSplit < nbSplits; iSplit++ ) {
8907           if ( iSplit == iQuad ) {
8908             SMDS_FaceOfNodes quad (linkNodes[ i1++ ],
8909                                    linkNodes[ i2++ ],
8910                                    nodes[ i3 ],
8911                                    nodes[ i4 ]);
8912             aBadRate += getBadRate( &quad, aCrit );
8913           }
8914           else {
8915             SMDS_FaceOfNodes tria (linkNodes[ i1++ ],
8916                                    linkNodes[ i2++ ],
8917                                    nodes[ iSplit < iQuad ? i4 : i3 ]);
8918             aBadRate += getBadRate( &tria, aCrit );
8919           }
8920         }
8921         // choice
8922         if ( aBadRate < aBestRate ) {
8923           iBestQuad = iQuad;
8924           aBestRate = aBadRate;
8925         }
8926       }
8927     }
8928
8929     // create new elements
8930     int aShapeId = FindShape( theFace );
8931
8932     i1 = 0; i2 = 1;
8933     for ( iSplit = 0; iSplit < nbSplits - 1; iSplit++ ) {
8934       SMDS_MeshElement* newElem = 0;
8935       if ( iSplit == iBestQuad )
8936         newElem = aMesh->AddFace (linkNodes[ i1++ ],
8937                                   linkNodes[ i2++ ],
8938                                   nodes[ i3 ],
8939                                   nodes[ i4 ]);
8940       else
8941         newElem = aMesh->AddFace (linkNodes[ i1++ ],
8942                                   linkNodes[ i2++ ],
8943                                   nodes[ iSplit < iBestQuad ? i4 : i3 ]);
8944       myLastCreatedElems.Append(newElem);
8945       if ( aShapeId && newElem )
8946         aMesh->SetMeshElementOnShape( newElem, aShapeId );
8947     }
8948
8949     // change nodes of theFace
8950     const SMDS_MeshNode* newNodes[ 4 ];
8951     newNodes[ 0 ] = linkNodes[ i1 ];
8952     newNodes[ 1 ] = linkNodes[ i2 ];
8953     newNodes[ 2 ] = nodes[ iSplit >= iBestQuad ? i3 : i4 ];
8954     newNodes[ 3 ] = nodes[ i4 ];
8955     //aMesh->ChangeElementNodes( theFace, newNodes, iSplit == iBestQuad ? 4 : 3 );
8956     const SMDS_MeshElement* newElem = 0;
8957     if (iSplit == iBestQuad)
8958       newElem = aMesh->AddFace( newNodes[0], newNodes[1], newNodes[2], newNodes[3] );
8959     else
8960       newElem = aMesh->AddFace( newNodes[0], newNodes[1], newNodes[2] );
8961     myLastCreatedElems.Append(newElem);
8962     if ( aShapeId && newElem )
8963       aMesh->SetMeshElementOnShape( newElem, aShapeId );
8964 } // end if(!theFace->IsQuadratic())
8965   else { // theFace is quadratic
8966     // we have to split theFace on simple triangles and one simple quadrangle
8967     int tmp = il1/2;
8968     int nbshift = tmp*2;
8969     // shift nodes in nodes[] by nbshift
8970     int i,j;
8971     for(i=0; i<nbshift; i++) {
8972       const SMDS_MeshNode* n = nodes[0];
8973       for(j=0; j<nbFaceNodes-1; j++) {
8974         nodes[j] = nodes[j+1];
8975       }
8976       nodes[nbFaceNodes-1] = n;
8977     }
8978     il1 = il1 - nbshift;
8979     // now have to insert nodes between n0 and n1 or n1 and n2 (see below)
8980     //   n0      n1     n2    n0      n1     n2
8981     //     +-----+-----+        +-----+-----+
8982     //      \         /         |           |
8983     //       \       /          |           |
8984     //      n5+     +n3       n7+           +n3
8985     //         \   /            |           |
8986     //          \ /             |           |
8987     //           +              +-----+-----+
8988     //           n4           n6      n5     n4
8989
8990     // create new elements
8991     int aShapeId = FindShape( theFace );
8992
8993     int n1,n2,n3;
8994     if(nbFaceNodes==6) { // quadratic triangle
8995       SMDS_MeshElement* newElem =
8996         aMesh->AddFace(nodes[3],nodes[4],nodes[5]);
8997       myLastCreatedElems.Append(newElem);
8998       if ( aShapeId && newElem )
8999         aMesh->SetMeshElementOnShape( newElem, aShapeId );
9000       if(theFace->IsMediumNode(nodes[il1])) {
9001         // create quadrangle
9002         newElem = aMesh->AddFace(nodes[0],nodes[1],nodes[3],nodes[5]);
9003         myLastCreatedElems.Append(newElem);
9004         if ( aShapeId && newElem )
9005           aMesh->SetMeshElementOnShape( newElem, aShapeId );
9006         n1 = 1;
9007         n2 = 2;
9008         n3 = 3;
9009       }
9010       else {
9011         // create quadrangle
9012         newElem = aMesh->AddFace(nodes[1],nodes[2],nodes[3],nodes[5]);
9013         myLastCreatedElems.Append(newElem);
9014         if ( aShapeId && newElem )
9015           aMesh->SetMeshElementOnShape( newElem, aShapeId );
9016         n1 = 0;
9017         n2 = 1;
9018         n3 = 5;
9019       }
9020     }
9021     else { // nbFaceNodes==8 - quadratic quadrangle
9022       SMDS_MeshElement* newElem =
9023         aMesh->AddFace(nodes[3],nodes[4],nodes[5]);
9024       myLastCreatedElems.Append(newElem);
9025       if ( aShapeId && newElem )
9026         aMesh->SetMeshElementOnShape( newElem, aShapeId );
9027       newElem = aMesh->AddFace(nodes[5],nodes[6],nodes[7]);
9028       myLastCreatedElems.Append(newElem);
9029       if ( aShapeId && newElem )
9030         aMesh->SetMeshElementOnShape( newElem, aShapeId );
9031       newElem = aMesh->AddFace(nodes[5],nodes[7],nodes[3]);
9032       myLastCreatedElems.Append(newElem);
9033       if ( aShapeId && newElem )
9034         aMesh->SetMeshElementOnShape( newElem, aShapeId );
9035       if(theFace->IsMediumNode(nodes[il1])) {
9036         // create quadrangle
9037         newElem = aMesh->AddFace(nodes[0],nodes[1],nodes[3],nodes[7]);
9038         myLastCreatedElems.Append(newElem);
9039         if ( aShapeId && newElem )
9040           aMesh->SetMeshElementOnShape( newElem, aShapeId );
9041         n1 = 1;
9042         n2 = 2;
9043         n3 = 3;
9044       }
9045       else {
9046         // create quadrangle
9047         newElem = aMesh->AddFace(nodes[1],nodes[2],nodes[3],nodes[7]);
9048         myLastCreatedElems.Append(newElem);
9049         if ( aShapeId && newElem )
9050           aMesh->SetMeshElementOnShape( newElem, aShapeId );
9051         n1 = 0;
9052         n2 = 1;
9053         n3 = 7;
9054       }
9055     }
9056     // create needed triangles using n1,n2,n3 and inserted nodes
9057     int nbn = 2 + aNodesToInsert.size();
9058     //const SMDS_MeshNode* aNodes[nbn];
9059     vector<const SMDS_MeshNode*> aNodes(nbn);
9060     aNodes[0] = nodes[n1];
9061     aNodes[nbn-1] = nodes[n2];
9062     list<const SMDS_MeshNode*>::iterator nIt = aNodesToInsert.begin();
9063     for ( iNode = 1; nIt != aNodesToInsert.end(); nIt++ ) {
9064       aNodes[iNode++] = *nIt;
9065     }
9066     for(i=1; i<nbn; i++) {
9067       SMDS_MeshElement* newElem =
9068         aMesh->AddFace(aNodes[i-1],aNodes[i],nodes[n3]);
9069       myLastCreatedElems.Append(newElem);
9070       if ( aShapeId && newElem )
9071         aMesh->SetMeshElementOnShape( newElem, aShapeId );
9072     }
9073   }
9074   // remove old face
9075   aMesh->RemoveElement(theFace);
9076 }
9077
9078 //=======================================================================
9079 //function : UpdateVolumes
9080 //purpose  :
9081 //=======================================================================
9082 void SMESH_MeshEditor::UpdateVolumes (const SMDS_MeshNode*        theBetweenNode1,
9083                                       const SMDS_MeshNode*        theBetweenNode2,
9084                                       list<const SMDS_MeshNode*>& theNodesToInsert)
9085 {
9086   myLastCreatedElems.Clear();
9087   myLastCreatedNodes.Clear();
9088
9089   SMDS_ElemIteratorPtr invElemIt = theBetweenNode1->GetInverseElementIterator(SMDSAbs_Volume);
9090   while (invElemIt->more()) { // loop on inverse elements of theBetweenNode1
9091     const SMDS_MeshElement* elem = invElemIt->next();
9092
9093     // check, if current volume has link theBetweenNode1 - theBetweenNode2
9094     SMDS_VolumeTool aVolume (elem);
9095     if (!aVolume.IsLinked(theBetweenNode1, theBetweenNode2))
9096       continue;
9097
9098     // insert new nodes in all faces of the volume, sharing link theBetweenNode1 - theBetweenNode2
9099     int iface, nbFaces = aVolume.NbFaces();
9100     vector<const SMDS_MeshNode *> poly_nodes;
9101     vector<int> quantities (nbFaces);
9102
9103     for (iface = 0; iface < nbFaces; iface++) {
9104       int nbFaceNodes = aVolume.NbFaceNodes(iface), nbInserted = 0;
9105       // faceNodes will contain (nbFaceNodes + 1) nodes, last = first
9106       const SMDS_MeshNode** faceNodes = aVolume.GetFaceNodes(iface);
9107
9108       for (int inode = 0; inode < nbFaceNodes; inode++) {
9109         poly_nodes.push_back(faceNodes[inode]);
9110
9111         if (nbInserted == 0) {
9112           if (faceNodes[inode] == theBetweenNode1) {
9113             if (faceNodes[inode + 1] == theBetweenNode2) {
9114               nbInserted = theNodesToInsert.size();
9115
9116               // add nodes to insert
9117               list<const SMDS_MeshNode*>::iterator nIt = theNodesToInsert.begin();
9118               for (; nIt != theNodesToInsert.end(); nIt++) {
9119                 poly_nodes.push_back(*nIt);
9120               }
9121             }
9122           }
9123           else if (faceNodes[inode] == theBetweenNode2) {
9124             if (faceNodes[inode + 1] == theBetweenNode1) {
9125               nbInserted = theNodesToInsert.size();
9126
9127               // add nodes to insert in reversed order
9128               list<const SMDS_MeshNode*>::iterator nIt = theNodesToInsert.end();
9129               nIt--;
9130               for (; nIt != theNodesToInsert.begin(); nIt--) {
9131                 poly_nodes.push_back(*nIt);
9132               }
9133               poly_nodes.push_back(*nIt);
9134             }
9135           }
9136           else {
9137           }
9138         }
9139       }
9140       quantities[iface] = nbFaceNodes + nbInserted;
9141     }
9142
9143     // Replace or update the volume
9144     SMESHDS_Mesh *aMesh = GetMeshDS();
9145
9146     if (elem->IsPoly()) {
9147       aMesh->ChangePolyhedronNodes(elem, poly_nodes, quantities);
9148
9149     }
9150     else {
9151       int aShapeId = FindShape( elem );
9152
9153       SMDS_MeshElement* newElem =
9154         aMesh->AddPolyhedralVolume(poly_nodes, quantities);
9155       myLastCreatedElems.Append(newElem);
9156       if (aShapeId && newElem)
9157         aMesh->SetMeshElementOnShape(newElem, aShapeId);
9158
9159       aMesh->RemoveElement(elem);
9160     }
9161   }
9162 }
9163
9164 //=======================================================================
9165 /*!
9166  * \brief Convert elements contained in a submesh to quadratic
9167  * \return int - nb of checked elements
9168  */
9169 //=======================================================================
9170
9171 int SMESH_MeshEditor::convertElemToQuadratic(SMESHDS_SubMesh *   theSm,
9172                                              SMESH_MesherHelper& theHelper,
9173                                              const bool          theForce3d)
9174 {
9175   int nbElem = 0;
9176   if( !theSm ) return nbElem;
9177
9178   vector<int> nbNodeInFaces;
9179   SMDS_ElemIteratorPtr ElemItr = theSm->GetElements();
9180   while(ElemItr->more())
9181   {
9182     nbElem++;
9183     const SMDS_MeshElement* elem = ElemItr->next();
9184     if( !elem || elem->IsQuadratic() ) continue;
9185
9186     int id = elem->GetID();
9187     int nbNodes = elem->NbNodes();
9188     SMDSAbs_ElementType aType = elem->GetType();
9189
9190     vector<const SMDS_MeshNode *> nodes (elem->begin_nodes(), elem->end_nodes());
9191     if ( elem->GetEntityType() == SMDSEntity_Polyhedra )
9192       nbNodeInFaces = static_cast<const SMDS_VtkVolume* >( elem )->GetQuantities();
9193
9194     GetMeshDS()->RemoveFreeElement(elem, theSm, /*fromGroups=*/false);
9195
9196     const SMDS_MeshElement* NewElem = 0;
9197
9198     switch( aType )
9199     {
9200     case SMDSAbs_Edge :
9201       {
9202         NewElem = theHelper.AddEdge(nodes[0], nodes[1], id, theForce3d);
9203         break;
9204       }
9205     case SMDSAbs_Face :
9206       {
9207         switch(nbNodes)
9208         {
9209         case 3:
9210           NewElem = theHelper.AddFace(nodes[0], nodes[1], nodes[2], id, theForce3d);
9211           break;
9212         case 4:
9213           NewElem = theHelper.AddFace(nodes[0], nodes[1], nodes[2], nodes[3], id, theForce3d);
9214           break;
9215         default:
9216           NewElem = theHelper.AddPolygonalFace(nodes, id, theForce3d);
9217           continue;
9218         }
9219         break;
9220       }
9221     case SMDSAbs_Volume :
9222       {
9223         switch(nbNodes)
9224         {
9225         case 4:
9226           NewElem = theHelper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3], id, theForce3d);
9227           break;
9228         case 5:
9229           NewElem = theHelper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3], nodes[4], id, theForce3d);
9230           break;
9231         case 6:
9232           NewElem = theHelper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3], nodes[4], nodes[5], id, theForce3d);
9233           break;
9234         case 8:
9235           NewElem = theHelper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3],
9236                                         nodes[4], nodes[5], nodes[6], nodes[7], id, theForce3d);
9237           break;
9238         default:
9239           NewElem = theHelper.AddPolyhedralVolume(nodes, nbNodeInFaces, id, theForce3d);
9240         }
9241         break;
9242       }
9243     default :
9244       continue;
9245     }
9246     ReplaceElemInGroups( elem, NewElem, GetMeshDS());
9247     if( NewElem )
9248       theSm->AddElement( NewElem );
9249   }
9250 //  if (!GetMeshDS()->isCompacted())
9251 //    GetMeshDS()->compactMesh();
9252   return nbElem;
9253 }
9254
9255 //=======================================================================
9256 //function : ConvertToQuadratic
9257 //purpose  :
9258 //=======================================================================
9259 void SMESH_MeshEditor::ConvertToQuadratic(const bool theForce3d)
9260 {
9261   SMESHDS_Mesh* meshDS = GetMeshDS();
9262
9263   SMESH_MesherHelper aHelper(*myMesh);
9264   aHelper.SetIsQuadratic( true );
9265
9266   int nbCheckedElems = 0;
9267   if ( myMesh->HasShapeToMesh() )
9268   {
9269     if ( SMESH_subMesh *aSubMesh = myMesh->GetSubMeshContaining(myMesh->GetShapeToMesh()))
9270     {
9271       SMESH_subMeshIteratorPtr smIt = aSubMesh->getDependsOnIterator(true,false);
9272       while ( smIt->more() ) {
9273         SMESH_subMesh* sm = smIt->next();
9274         if ( SMESHDS_SubMesh *smDS = sm->GetSubMeshDS() ) {
9275           aHelper.SetSubShape( sm->GetSubShape() );
9276           nbCheckedElems += convertElemToQuadratic(smDS, aHelper, theForce3d);
9277         }
9278       }
9279     }
9280   }
9281   int totalNbElems = meshDS->NbEdges() + meshDS->NbFaces() + meshDS->NbVolumes();
9282   if ( nbCheckedElems < totalNbElems ) // not all elements are in submeshes
9283   {
9284     SMESHDS_SubMesh *smDS = 0;
9285     SMDS_EdgeIteratorPtr aEdgeItr = meshDS->edgesIterator();
9286     while(aEdgeItr->more())
9287     {
9288       const SMDS_MeshEdge* edge = aEdgeItr->next();
9289       if(edge && !edge->IsQuadratic())
9290       {
9291         int id = edge->GetID();
9292         //MESSAGE("edge->GetID() " << id);
9293         const SMDS_MeshNode* n1 = edge->GetNode(0);
9294         const SMDS_MeshNode* n2 = edge->GetNode(1);
9295
9296         meshDS->RemoveFreeElement(edge, smDS, /*fromGroups=*/false);
9297
9298         const SMDS_MeshEdge* NewEdge = aHelper.AddEdge(n1, n2, id, theForce3d);
9299         ReplaceElemInGroups( edge, NewEdge, GetMeshDS());
9300       }
9301     }
9302     SMDS_FaceIteratorPtr aFaceItr = meshDS->facesIterator();
9303     while(aFaceItr->more())
9304     {
9305       const SMDS_MeshFace* face = aFaceItr->next();
9306       if(!face || face->IsQuadratic() ) continue;
9307
9308       int id = face->GetID();
9309       int nbNodes = face->NbNodes();
9310       vector<const SMDS_MeshNode *> nodes ( face->begin_nodes(), face->end_nodes());
9311
9312       meshDS->RemoveFreeElement(face, smDS, /*fromGroups=*/false);
9313
9314       SMDS_MeshFace * NewFace = 0;
9315       switch(nbNodes)
9316       {
9317       case 3:
9318         NewFace = aHelper.AddFace(nodes[0], nodes[1], nodes[2], id, theForce3d);
9319         break;
9320       case 4:
9321         NewFace = aHelper.AddFace(nodes[0], nodes[1], nodes[2], nodes[3], id, theForce3d);
9322         break;
9323       default:
9324         NewFace = aHelper.AddPolygonalFace(nodes, id, theForce3d);
9325       }
9326       ReplaceElemInGroups( face, NewFace, GetMeshDS());
9327     }
9328     vector<int> nbNodeInFaces;
9329     SMDS_VolumeIteratorPtr aVolumeItr = meshDS->volumesIterator();
9330     while(aVolumeItr->more())
9331     {
9332       const SMDS_MeshVolume* volume = aVolumeItr->next();
9333       if(!volume || volume->IsQuadratic() ) continue;
9334
9335       int id = volume->GetID();
9336       int nbNodes = volume->NbNodes();
9337       vector<const SMDS_MeshNode *> nodes (volume->begin_nodes(), volume->end_nodes());
9338       if ( volume->GetEntityType() == SMDSEntity_Polyhedra )
9339         nbNodeInFaces = static_cast<const SMDS_VtkVolume* >(volume)->GetQuantities();
9340
9341       meshDS->RemoveFreeElement(volume, smDS, /*fromGroups=*/false);
9342
9343       SMDS_MeshVolume * NewVolume = 0;
9344       switch(nbNodes)
9345       {
9346       case 4:
9347         NewVolume = aHelper.AddVolume(nodes[0], nodes[1], nodes[2],
9348                                       nodes[3], id, theForce3d );
9349         break;
9350       case 5:
9351         NewVolume = aHelper.AddVolume(nodes[0], nodes[1], nodes[2],
9352                                       nodes[3], nodes[4], id, theForce3d);
9353         break;
9354       case 6:
9355         NewVolume = aHelper.AddVolume(nodes[0], nodes[1], nodes[2],
9356                                       nodes[3], nodes[4], nodes[5], id, theForce3d);
9357         break;
9358       case 8:
9359         NewVolume = aHelper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3],
9360                                       nodes[4], nodes[5], nodes[6], nodes[7], id, theForce3d);
9361         break;
9362       default:
9363         NewVolume = aHelper.AddPolyhedralVolume(nodes, nbNodeInFaces, id, theForce3d);
9364       }
9365       ReplaceElemInGroups(volume, NewVolume, meshDS);
9366     }
9367   }
9368
9369   if ( !theForce3d  && !getenv("NO_FixQuadraticElements"))
9370   { // setenv NO_FixQuadraticElements to know if FixQuadraticElements() is guilty of bad conversion
9371     aHelper.SetSubShape(0); // apply FixQuadraticElements() to the whole mesh
9372     aHelper.FixQuadraticElements();
9373   }
9374 }
9375
9376 //================================================================================
9377 /*!
9378  * \brief Makes given elements quadratic
9379  *  \param theForce3d - if true, the medium nodes will be placed in the middle of link
9380  *  \param theElements - elements to make quadratic 
9381  */
9382 //================================================================================
9383
9384 void SMESH_MeshEditor::ConvertToQuadratic(const bool        theForce3d,
9385                                           TIDSortedElemSet& theElements)
9386 {
9387   if ( theElements.empty() ) return;
9388
9389   // we believe that all theElements are of the same type
9390   SMDSAbs_ElementType elemType = (*theElements.begin())->GetType();
9391   
9392   // get all nodes shared by theElements
9393   TIDSortedNodeSet allNodes;
9394   TIDSortedElemSet::iterator eIt = theElements.begin();
9395   for ( ; eIt != theElements.end(); ++eIt )
9396     allNodes.insert( (*eIt)->begin_nodes(), (*eIt)->end_nodes() );
9397
9398   // complete theElements with elements of lower dim whose all nodes are in allNodes
9399
9400   TIDSortedElemSet quadAdjacentElems    [ SMDSAbs_NbElementTypes ]; // quadratic adjacent elements
9401   TIDSortedElemSet checkedAdjacentElems [ SMDSAbs_NbElementTypes ];
9402   TIDSortedNodeSet::iterator nIt = allNodes.begin();
9403   for ( ; nIt != allNodes.end(); ++nIt )
9404   {
9405     const SMDS_MeshNode* n = *nIt;
9406     SMDS_ElemIteratorPtr invIt = n->GetInverseElementIterator();
9407     while ( invIt->more() )
9408     {
9409       const SMDS_MeshElement* e = invIt->next();
9410       if ( e->IsQuadratic() )
9411       {
9412         quadAdjacentElems[ e->GetType() ].insert( e );
9413         continue;
9414       }
9415       if ( e->GetType() >= elemType )
9416       {
9417         continue; // same type of more complex linear element
9418       }
9419
9420       if ( !checkedAdjacentElems[ e->GetType() ].insert( e ).second )
9421         continue; // e is already checked
9422
9423       // check nodes
9424       bool allIn = true;
9425       SMDS_ElemIteratorPtr nodeIt = e->nodesIterator();
9426       while ( nodeIt->more() && allIn )
9427         allIn = allNodes.count( cast2Node( nodeIt->next() ));
9428       if ( allIn )
9429         theElements.insert(e );
9430     }
9431   }
9432
9433   SMESH_MesherHelper helper(*myMesh);
9434   helper.SetIsQuadratic( true );
9435
9436   // add links of quadratic adjacent elements to the helper
9437
9438   if ( !quadAdjacentElems[SMDSAbs_Edge].empty() )
9439     for ( eIt  = quadAdjacentElems[SMDSAbs_Edge].begin();
9440           eIt != quadAdjacentElems[SMDSAbs_Edge].end(); ++eIt )
9441     {
9442       helper.AddTLinks( static_cast< const SMDS_MeshEdge*> (*eIt) );
9443     }
9444   if ( !quadAdjacentElems[SMDSAbs_Face].empty() )
9445     for ( eIt  = quadAdjacentElems[SMDSAbs_Face].begin();
9446           eIt != quadAdjacentElems[SMDSAbs_Face].end(); ++eIt )
9447     {
9448       helper.AddTLinks( static_cast< const SMDS_MeshFace*> (*eIt) );
9449     }
9450   if ( !quadAdjacentElems[SMDSAbs_Volume].empty() )
9451     for ( eIt  = quadAdjacentElems[SMDSAbs_Volume].begin();
9452           eIt != quadAdjacentElems[SMDSAbs_Volume].end(); ++eIt )
9453     {
9454       helper.AddTLinks( static_cast< const SMDS_MeshVolume*> (*eIt) );
9455     }
9456
9457   // make quadratic elements instead of linear ones
9458
9459   SMESHDS_Mesh* meshDS = GetMeshDS();
9460   SMESHDS_SubMesh* smDS = 0;
9461   for ( eIt = theElements.begin(); eIt != theElements.end(); ++eIt )
9462   {
9463     const SMDS_MeshElement* elem = *eIt;
9464     if( elem->IsQuadratic() || elem->NbNodes() < 2 || elem->IsPoly() )
9465       continue;
9466
9467     int id = elem->GetID();
9468     SMDSAbs_ElementType type = elem->GetType();
9469     vector<const SMDS_MeshNode *> nodes ( elem->begin_nodes(), elem->end_nodes());
9470
9471     if ( !smDS || !smDS->Contains( elem ))
9472       smDS = meshDS->MeshElements( elem->getshapeId() );
9473     meshDS->RemoveFreeElement(elem, smDS, /*fromGroups=*/false);
9474
9475     SMDS_MeshElement * newElem = 0;
9476     switch( nodes.size() )
9477     {
9478     case 4: // cases for most multiple element types go first (for optimization)
9479       if ( type == SMDSAbs_Volume )
9480         newElem = helper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3], id, theForce3d);
9481       else
9482         newElem = helper.AddFace  (nodes[0], nodes[1], nodes[2], nodes[3], id, theForce3d);
9483       break;
9484     case 8:
9485       newElem = helper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3],
9486                                  nodes[4], nodes[5], nodes[6], nodes[7], id, theForce3d);
9487       break;
9488     case 3:
9489       newElem = helper.AddFace  (nodes[0], nodes[1], nodes[2], id, theForce3d);
9490       break;
9491     case 2:
9492       newElem = helper.AddEdge(nodes[0], nodes[1], id, theForce3d);
9493       break;
9494     case 5:
9495       newElem = helper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3],
9496                                  nodes[4], id, theForce3d);
9497       break;
9498     case 6:
9499       newElem = helper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3],
9500                                  nodes[4], nodes[5], id, theForce3d);
9501       break;
9502     default:;
9503     }
9504     ReplaceElemInGroups( elem, newElem, meshDS);
9505     if( newElem && smDS )
9506       smDS->AddElement( newElem );
9507   }
9508
9509   if ( !theForce3d  && !getenv("NO_FixQuadraticElements"))
9510   { // setenv NO_FixQuadraticElements to know if FixQuadraticElements() is guilty of bad conversion
9511     helper.SetSubShape(0); // apply FixQuadraticElements() to the whole mesh
9512     helper.FixQuadraticElements();
9513   }
9514 }
9515
9516 //=======================================================================
9517 /*!
9518  * \brief Convert quadratic elements to linear ones and remove quadratic nodes
9519  * \return int - nb of checked elements
9520  */
9521 //=======================================================================
9522
9523 int SMESH_MeshEditor::removeQuadElem(SMESHDS_SubMesh *    theSm,
9524                                      SMDS_ElemIteratorPtr theItr,
9525                                      const int            theShapeID)
9526 {
9527   int nbElem = 0;
9528   SMESHDS_Mesh* meshDS = GetMeshDS();
9529
9530   while( theItr->more() )
9531   {
9532     const SMDS_MeshElement* elem = theItr->next();
9533     nbElem++;
9534     if( elem && elem->IsQuadratic())
9535     {
9536       int id                    = elem->GetID();
9537       int nbCornerNodes         = elem->NbCornerNodes();
9538       SMDSAbs_ElementType aType = elem->GetType();
9539
9540       vector<const SMDS_MeshNode *> nodes( elem->begin_nodes(), elem->end_nodes() );
9541
9542       //remove a quadratic element
9543       if ( !theSm || !theSm->Contains( elem ))
9544         theSm = meshDS->MeshElements( elem->getshapeId() );
9545       meshDS->RemoveFreeElement( elem, theSm, /*fromGroups=*/false );
9546
9547       // remove medium nodes
9548       for ( unsigned i = nbCornerNodes; i < nodes.size(); ++i )
9549         if ( nodes[i]->NbInverseElements() == 0 )
9550           meshDS->RemoveFreeNode( nodes[i], theSm );
9551
9552       // add a linear element
9553       nodes.resize( nbCornerNodes );
9554       SMDS_MeshElement * newElem = AddElement( nodes, aType, false, id );
9555       ReplaceElemInGroups(elem, newElem, meshDS);
9556       if( theSm && newElem )
9557         theSm->AddElement( newElem );
9558     }
9559   }
9560   return nbElem;
9561 }
9562
9563 //=======================================================================
9564 //function : ConvertFromQuadratic
9565 //purpose  :
9566 //=======================================================================
9567
9568 bool SMESH_MeshEditor::ConvertFromQuadratic()
9569 {
9570   int nbCheckedElems = 0;
9571   if ( myMesh->HasShapeToMesh() )
9572   {
9573     if ( SMESH_subMesh *aSubMesh = myMesh->GetSubMeshContaining(myMesh->GetShapeToMesh()))
9574     {
9575       SMESH_subMeshIteratorPtr smIt = aSubMesh->getDependsOnIterator(true,false);
9576       while ( smIt->more() ) {
9577         SMESH_subMesh* sm = smIt->next();
9578         if ( SMESHDS_SubMesh *smDS = sm->GetSubMeshDS() )
9579           nbCheckedElems += removeQuadElem( smDS, smDS->GetElements(), sm->GetId() );
9580       }
9581     }
9582   }
9583
9584   int totalNbElems =
9585     GetMeshDS()->NbEdges() + GetMeshDS()->NbFaces() + GetMeshDS()->NbVolumes();
9586   if ( nbCheckedElems < totalNbElems ) // not all elements are in submeshes
9587   {
9588     SMESHDS_SubMesh *aSM = 0;
9589     removeQuadElem( aSM, GetMeshDS()->elementsIterator(), 0 );
9590   }
9591
9592   return true;
9593 }
9594
9595 namespace
9596 {
9597   //================================================================================
9598   /*!
9599    * \brief Return true if all medium nodes of the element are in the node set
9600    */
9601   //================================================================================
9602
9603   bool allMediumNodesIn(const SMDS_MeshElement* elem, TIDSortedNodeSet& nodeSet )
9604   {
9605     for ( int i = elem->NbCornerNodes(); i < elem->NbNodes(); ++i )
9606       if ( !nodeSet.count( elem->GetNode(i) ))
9607         return false;
9608     return true;
9609   }
9610 }
9611
9612 //================================================================================
9613 /*!
9614  * \brief Makes given elements linear
9615  */
9616 //================================================================================
9617
9618 void SMESH_MeshEditor::ConvertFromQuadratic(TIDSortedElemSet& theElements)
9619 {
9620   if ( theElements.empty() ) return;
9621
9622   // collect IDs of medium nodes of theElements; some of these nodes will be removed
9623   set<int> mediumNodeIDs;
9624   TIDSortedElemSet::iterator eIt = theElements.begin();
9625   for ( ; eIt != theElements.end(); ++eIt )
9626   {
9627     const SMDS_MeshElement* e = *eIt;
9628     for ( int i = e->NbCornerNodes(); i < e->NbNodes(); ++i )
9629       mediumNodeIDs.insert( e->GetNode(i)->GetID() );
9630   }
9631
9632   // replace given elements by linear ones
9633   typedef SMDS_SetIterator<const SMDS_MeshElement*, TIDSortedElemSet::iterator> TSetIterator;
9634   SMDS_ElemIteratorPtr elemIt( new TSetIterator( theElements.begin(), theElements.end() ));
9635   removeQuadElem( /*theSm=*/0, elemIt, /*theShapeID=*/0 );
9636
9637   // we need to convert remaining elements whose all medium nodes are in mediumNodeIDs
9638   // except those elements sharing medium nodes of quadratic element whose medium nodes
9639   // are not all in mediumNodeIDs
9640
9641   // get remaining medium nodes
9642   TIDSortedNodeSet mediumNodes;
9643   set<int>::iterator nIdsIt = mediumNodeIDs.begin();
9644   for ( ; nIdsIt != mediumNodeIDs.end(); ++nIdsIt )
9645     if ( const SMDS_MeshNode* n = GetMeshDS()->FindNode( *nIdsIt ))
9646       mediumNodes.insert( mediumNodes.end(), n );
9647
9648   // find more quadratic elements to convert
9649   TIDSortedElemSet moreElemsToConvert;
9650   TIDSortedNodeSet::iterator nIt = mediumNodes.begin();
9651   for ( ; nIt != mediumNodes.end(); ++nIt )
9652   {
9653     SMDS_ElemIteratorPtr invIt = (*nIt)->GetInverseElementIterator();
9654     while ( invIt->more() )
9655     {
9656       const SMDS_MeshElement* e = invIt->next();
9657       if ( e->IsQuadratic() && allMediumNodesIn( e, mediumNodes ))
9658       {
9659         // find a more complex element including e and
9660         // whose medium nodes are not in mediumNodes
9661         bool complexFound = false;
9662         for ( int type = e->GetType() + 1; type < SMDSAbs_0DElement; ++type )
9663         {
9664           SMDS_ElemIteratorPtr invIt2 =
9665             (*nIt)->GetInverseElementIterator( SMDSAbs_ElementType( type ));
9666           while ( invIt2->more() )
9667           {
9668             const SMDS_MeshElement* eComplex = invIt2->next();
9669             if ( eComplex->IsQuadratic() && !allMediumNodesIn( eComplex, mediumNodes))
9670             {
9671               int nbCommonNodes = SMESH_Algo::GetCommonNodes( e, eComplex ).size();
9672               if ( nbCommonNodes == e->NbNodes())
9673               {
9674                 complexFound = true;
9675                 type = SMDSAbs_NbElementTypes; // to quit from the outer loop
9676                 break;
9677               }
9678             }
9679           }
9680         }
9681         if ( !complexFound )
9682           moreElemsToConvert.insert( e );
9683       }
9684     }
9685   }
9686   elemIt = SMDS_ElemIteratorPtr
9687     (new TSetIterator( moreElemsToConvert.begin(), moreElemsToConvert.end() ));
9688   removeQuadElem( /*theSm=*/0, elemIt, /*theShapeID=*/0 );
9689 }
9690
9691 //=======================================================================
9692 //function : SewSideElements
9693 //purpose  :
9694 //=======================================================================
9695
9696 SMESH_MeshEditor::Sew_Error
9697 SMESH_MeshEditor::SewSideElements (TIDSortedElemSet&    theSide1,
9698                                    TIDSortedElemSet&    theSide2,
9699                                    const SMDS_MeshNode* theFirstNode1,
9700                                    const SMDS_MeshNode* theFirstNode2,
9701                                    const SMDS_MeshNode* theSecondNode1,
9702                                    const SMDS_MeshNode* theSecondNode2)
9703 {
9704   myLastCreatedElems.Clear();
9705   myLastCreatedNodes.Clear();
9706
9707   MESSAGE ("::::SewSideElements()");
9708   if ( theSide1.size() != theSide2.size() )
9709     return SEW_DIFF_NB_OF_ELEMENTS;
9710
9711   Sew_Error aResult = SEW_OK;
9712   // Algo:
9713   // 1. Build set of faces representing each side
9714   // 2. Find which nodes of the side 1 to merge with ones on the side 2
9715   // 3. Replace nodes in elements of the side 1 and remove replaced nodes
9716
9717   // =======================================================================
9718   // 1. Build set of faces representing each side:
9719   // =======================================================================
9720   // a. build set of nodes belonging to faces
9721   // b. complete set of faces: find missing faces whose nodes are in set of nodes
9722   // c. create temporary faces representing side of volumes if correspondent
9723   //    face does not exist
9724
9725   SMESHDS_Mesh* aMesh = GetMeshDS();
9726   // TODO algoritm not OK with vtkUnstructuredGrid: 2 meshes can't share nodes
9727   //SMDS_Mesh aTmpFacesMesh; // try to use the same mesh
9728   set<const SMDS_MeshElement*> faceSet1, faceSet2;
9729   set<const SMDS_MeshElement*> volSet1,  volSet2;
9730   set<const SMDS_MeshNode*>    nodeSet1, nodeSet2;
9731   set<const SMDS_MeshElement*> * faceSetPtr[] = { &faceSet1, &faceSet2 };
9732   set<const SMDS_MeshElement*>  * volSetPtr[] = { &volSet1,  &volSet2  };
9733   set<const SMDS_MeshNode*>    * nodeSetPtr[] = { &nodeSet1, &nodeSet2 };
9734   TIDSortedElemSet * elemSetPtr[] = { &theSide1, &theSide2 };
9735   int iSide, iFace, iNode;
9736
9737   list<const SMDS_MeshElement* > tempFaceList;
9738   for ( iSide = 0; iSide < 2; iSide++ ) {
9739     set<const SMDS_MeshNode*>    * nodeSet = nodeSetPtr[ iSide ];
9740     TIDSortedElemSet * elemSet = elemSetPtr[ iSide ];
9741     set<const SMDS_MeshElement*> * faceSet = faceSetPtr[ iSide ];
9742     set<const SMDS_MeshElement*> * volSet  = volSetPtr [ iSide ];
9743     set<const SMDS_MeshElement*>::iterator vIt;
9744     TIDSortedElemSet::iterator eIt;
9745     set<const SMDS_MeshNode*>::iterator    nIt;
9746
9747     // check that given nodes belong to given elements
9748     const SMDS_MeshNode* n1 = ( iSide == 0 ) ? theFirstNode1 : theFirstNode2;
9749     const SMDS_MeshNode* n2 = ( iSide == 0 ) ? theSecondNode1 : theSecondNode2;
9750     int firstIndex = -1, secondIndex = -1;
9751     for (eIt = elemSet->begin(); eIt != elemSet->end(); eIt++ ) {
9752       const SMDS_MeshElement* elem = *eIt;
9753       if ( firstIndex  < 0 ) firstIndex  = elem->GetNodeIndex( n1 );
9754       if ( secondIndex < 0 ) secondIndex = elem->GetNodeIndex( n2 );
9755       if ( firstIndex > -1 && secondIndex > -1 ) break;
9756     }
9757     if ( firstIndex < 0 || secondIndex < 0 ) {
9758       // we can simply return until temporary faces created
9759       return (iSide == 0 ) ? SEW_BAD_SIDE1_NODES : SEW_BAD_SIDE2_NODES;
9760     }
9761
9762     // -----------------------------------------------------------
9763     // 1a. Collect nodes of existing faces
9764     //     and build set of face nodes in order to detect missing
9765     //     faces corresponding to sides of volumes
9766     // -----------------------------------------------------------
9767
9768     set< set <const SMDS_MeshNode*> > setOfFaceNodeSet;
9769
9770     // loop on the given element of a side
9771     for (eIt = elemSet->begin(); eIt != elemSet->end(); eIt++ ) {
9772       //const SMDS_MeshElement* elem = *eIt;
9773       const SMDS_MeshElement* elem = *eIt;
9774       if ( elem->GetType() == SMDSAbs_Face ) {
9775         faceSet->insert( elem );
9776         set <const SMDS_MeshNode*> faceNodeSet;
9777         SMDS_ElemIteratorPtr nodeIt = elem->nodesIterator();
9778         while ( nodeIt->more() ) {
9779           const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
9780           nodeSet->insert( n );
9781           faceNodeSet.insert( n );
9782         }
9783         setOfFaceNodeSet.insert( faceNodeSet );
9784       }
9785       else if ( elem->GetType() == SMDSAbs_Volume )
9786         volSet->insert( elem );
9787     }
9788     // ------------------------------------------------------------------------------
9789     // 1b. Complete set of faces: find missing faces whose nodes are in set of nodes
9790     // ------------------------------------------------------------------------------
9791
9792     for ( nIt = nodeSet->begin(); nIt != nodeSet->end(); nIt++ ) { // loop on nodes of iSide
9793       SMDS_ElemIteratorPtr fIt = (*nIt)->GetInverseElementIterator(SMDSAbs_Face);
9794       while ( fIt->more() ) { // loop on faces sharing a node
9795         const SMDS_MeshElement* f = fIt->next();
9796         if ( faceSet->find( f ) == faceSet->end() ) {
9797           // check if all nodes are in nodeSet and
9798           // complete setOfFaceNodeSet if they are
9799           set <const SMDS_MeshNode*> faceNodeSet;
9800           SMDS_ElemIteratorPtr nodeIt = f->nodesIterator();
9801           bool allInSet = true;
9802           while ( nodeIt->more() && allInSet ) { // loop on nodes of a face
9803             const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
9804             if ( nodeSet->find( n ) == nodeSet->end() )
9805               allInSet = false;
9806             else
9807               faceNodeSet.insert( n );
9808           }
9809           if ( allInSet ) {
9810             faceSet->insert( f );
9811             setOfFaceNodeSet.insert( faceNodeSet );
9812           }
9813         }
9814       }
9815     }
9816
9817     // -------------------------------------------------------------------------
9818     // 1c. Create temporary faces representing sides of volumes if correspondent
9819     //     face does not exist
9820     // -------------------------------------------------------------------------
9821
9822     if ( !volSet->empty() ) {
9823       //int nodeSetSize = nodeSet->size();
9824
9825       // loop on given volumes
9826       for ( vIt = volSet->begin(); vIt != volSet->end(); vIt++ ) {
9827         SMDS_VolumeTool vol (*vIt);
9828         // loop on volume faces: find free faces
9829         // --------------------------------------
9830         list<const SMDS_MeshElement* > freeFaceList;
9831         for ( iFace = 0; iFace < vol.NbFaces(); iFace++ ) {
9832           if ( !vol.IsFreeFace( iFace ))
9833             continue;
9834           // check if there is already a face with same nodes in a face set
9835           const SMDS_MeshElement* aFreeFace = 0;
9836           const SMDS_MeshNode** fNodes = vol.GetFaceNodes( iFace );
9837           int nbNodes = vol.NbFaceNodes( iFace );
9838           set <const SMDS_MeshNode*> faceNodeSet;
9839           vol.GetFaceNodes( iFace, faceNodeSet );
9840           bool isNewFace = setOfFaceNodeSet.insert( faceNodeSet ).second;
9841           if ( isNewFace ) {
9842             // no such a face is given but it still can exist, check it
9843             if ( nbNodes == 3 ) {
9844               aFreeFace = aMesh->FindFace( fNodes[0],fNodes[1],fNodes[2] );
9845             }
9846             else if ( nbNodes == 4 ) {
9847               aFreeFace = aMesh->FindFace( fNodes[0],fNodes[1],fNodes[2],fNodes[3] );
9848             }
9849             else {
9850               vector<const SMDS_MeshNode *> poly_nodes ( fNodes, & fNodes[nbNodes]);
9851               aFreeFace = aMesh->FindFace(poly_nodes);
9852             }
9853           }
9854           if ( !aFreeFace ) {
9855             // create a temporary face
9856             if ( nbNodes == 3 ) {
9857               //aFreeFace = aTmpFacesMesh.AddFace( fNodes[0],fNodes[1],fNodes[2] );
9858               aFreeFace = aMesh->AddFace( fNodes[0],fNodes[1],fNodes[2] );
9859             }
9860             else if ( nbNodes == 4 ) {
9861               //aFreeFace = aTmpFacesMesh.AddFace( fNodes[0],fNodes[1],fNodes[2],fNodes[3] );
9862               aFreeFace = aMesh->AddFace( fNodes[0],fNodes[1],fNodes[2],fNodes[3] );
9863             }
9864             else {
9865               vector<const SMDS_MeshNode *> poly_nodes ( fNodes, & fNodes[nbNodes]);
9866               //aFreeFace = aTmpFacesMesh.AddPolygonalFace(poly_nodes);
9867               aFreeFace = aMesh->AddPolygonalFace(poly_nodes);
9868             }
9869           }
9870           if ( aFreeFace ) {
9871             freeFaceList.push_back( aFreeFace );
9872             tempFaceList.push_back( aFreeFace );
9873           }
9874
9875         } // loop on faces of a volume
9876
9877         // choose one of several free faces
9878         // --------------------------------------
9879         if ( freeFaceList.size() > 1 ) {
9880           // choose a face having max nb of nodes shared by other elems of a side
9881           int maxNbNodes = -1/*, nbExcludedFaces = 0*/;
9882           list<const SMDS_MeshElement* >::iterator fIt = freeFaceList.begin();
9883           while ( fIt != freeFaceList.end() ) { // loop on free faces
9884             int nbSharedNodes = 0;
9885             SMDS_ElemIteratorPtr nodeIt = (*fIt)->nodesIterator();
9886             while ( nodeIt->more() ) { // loop on free face nodes
9887               const SMDS_MeshNode* n =
9888                 static_cast<const SMDS_MeshNode*>( nodeIt->next() );
9889               SMDS_ElemIteratorPtr invElemIt = n->GetInverseElementIterator();
9890               while ( invElemIt->more() ) {
9891                 const SMDS_MeshElement* e = invElemIt->next();
9892                 if ( faceSet->find( e ) != faceSet->end() )
9893                   nbSharedNodes++;
9894                 if ( elemSet->find( e ) != elemSet->end() )
9895                   nbSharedNodes++;
9896               }
9897             }
9898             if ( nbSharedNodes >= maxNbNodes ) {
9899               maxNbNodes = nbSharedNodes;
9900               fIt++;
9901             }
9902             else
9903               freeFaceList.erase( fIt++ ); // here fIt++ occurs before erase
9904           }
9905           if ( freeFaceList.size() > 1 )
9906           {
9907             // could not choose one face, use another way
9908             // choose a face most close to the bary center of the opposite side
9909             gp_XYZ aBC( 0., 0., 0. );
9910             set <const SMDS_MeshNode*> addedNodes;
9911             TIDSortedElemSet * elemSet2 = elemSetPtr[ 1 - iSide ];
9912             eIt = elemSet2->begin();
9913             for ( eIt = elemSet2->begin(); eIt != elemSet2->end(); eIt++ ) {
9914               SMDS_ElemIteratorPtr nodeIt = (*eIt)->nodesIterator();
9915               while ( nodeIt->more() ) { // loop on free face nodes
9916                 const SMDS_MeshNode* n =
9917                   static_cast<const SMDS_MeshNode*>( nodeIt->next() );
9918                 if ( addedNodes.insert( n ).second )
9919                   aBC += gp_XYZ( n->X(),n->Y(),n->Z() );
9920               }
9921             }
9922             aBC /= addedNodes.size();
9923             double minDist = DBL_MAX;
9924             fIt = freeFaceList.begin();
9925             while ( fIt != freeFaceList.end() ) { // loop on free faces
9926               double dist = 0;
9927               SMDS_ElemIteratorPtr nodeIt = (*fIt)->nodesIterator();
9928               while ( nodeIt->more() ) { // loop on free face nodes
9929                 const SMDS_MeshNode* n =
9930                   static_cast<const SMDS_MeshNode*>( nodeIt->next() );
9931                 gp_XYZ p( n->X(),n->Y(),n->Z() );
9932                 dist += ( aBC - p ).SquareModulus();
9933               }
9934               if ( dist < minDist ) {
9935                 minDist = dist;
9936                 freeFaceList.erase( freeFaceList.begin(), fIt++ );
9937               }
9938               else
9939                 fIt = freeFaceList.erase( fIt++ );
9940             }
9941           }
9942         } // choose one of several free faces of a volume
9943
9944         if ( freeFaceList.size() == 1 ) {
9945           const SMDS_MeshElement* aFreeFace = freeFaceList.front();
9946           faceSet->insert( aFreeFace );
9947           // complete a node set with nodes of a found free face
9948           //           for ( iNode = 0; iNode < ; iNode++ )
9949           //             nodeSet->insert( fNodes[ iNode ] );
9950         }
9951
9952       } // loop on volumes of a side
9953
9954       //       // complete a set of faces if new nodes in a nodeSet appeared
9955       //       // ----------------------------------------------------------
9956       //       if ( nodeSetSize != nodeSet->size() ) {
9957       //         for ( ; nIt != nodeSet->end(); nIt++ ) { // loop on nodes of iSide
9958       //           SMDS_ElemIteratorPtr fIt = (*nIt)->GetInverseElementIterator(SMDSAbs_Face);
9959       //           while ( fIt->more() ) { // loop on faces sharing a node
9960       //             const SMDS_MeshElement* f = fIt->next();
9961       //             if ( faceSet->find( f ) == faceSet->end() ) {
9962       //               // check if all nodes are in nodeSet and
9963       //               // complete setOfFaceNodeSet if they are
9964       //               set <const SMDS_MeshNode*> faceNodeSet;
9965       //               SMDS_ElemIteratorPtr nodeIt = f->nodesIterator();
9966       //               bool allInSet = true;
9967       //               while ( nodeIt->more() && allInSet ) { // loop on nodes of a face
9968       //                 const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
9969       //                 if ( nodeSet->find( n ) == nodeSet->end() )
9970       //                   allInSet = false;
9971       //                 else
9972       //                   faceNodeSet.insert( n );
9973       //               }
9974       //               if ( allInSet ) {
9975       //                 faceSet->insert( f );
9976       //                 setOfFaceNodeSet.insert( faceNodeSet );
9977       //               }
9978       //             }
9979       //           }
9980       //         }
9981       //       }
9982     } // Create temporary faces, if there are volumes given
9983   } // loop on sides
9984
9985   if ( faceSet1.size() != faceSet2.size() ) {
9986     // delete temporary faces: they are in reverseElements of actual nodes
9987 //    SMDS_FaceIteratorPtr tmpFaceIt = aTmpFacesMesh.facesIterator();
9988 //    while ( tmpFaceIt->more() )
9989 //      aTmpFacesMesh.RemoveElement( tmpFaceIt->next() );
9990 //    list<const SMDS_MeshElement* >::iterator tmpFaceIt = tempFaceList.begin();
9991 //    for (; tmpFaceIt !=tempFaceList.end(); ++tmpFaceIt)
9992 //      aMesh->RemoveElement(*tmpFaceIt);
9993     MESSAGE("Diff nb of faces");
9994     return SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
9995   }
9996
9997   // ============================================================
9998   // 2. Find nodes to merge:
9999   //              bind a node to remove to a node to put instead
10000   // ============================================================
10001
10002   TNodeNodeMap nReplaceMap; // bind a node to remove to a node to put instead
10003   if ( theFirstNode1 != theFirstNode2 )
10004     nReplaceMap.insert( TNodeNodeMap::value_type( theFirstNode1, theFirstNode2 ));
10005   if ( theSecondNode1 != theSecondNode2 )
10006     nReplaceMap.insert( TNodeNodeMap::value_type( theSecondNode1, theSecondNode2 ));
10007
10008   LinkID_Gen aLinkID_Gen( GetMeshDS() );
10009   set< long > linkIdSet; // links to process
10010   linkIdSet.insert( aLinkID_Gen.GetLinkID( theFirstNode1, theSecondNode1 ));
10011
10012   typedef pair< const SMDS_MeshNode*, const SMDS_MeshNode* > NLink;
10013   list< NLink > linkList[2];
10014   linkList[0].push_back( NLink( theFirstNode1, theSecondNode1 ));
10015   linkList[1].push_back( NLink( theFirstNode2, theSecondNode2 ));
10016   // loop on links in linkList; find faces by links and append links
10017   // of the found faces to linkList
10018   list< NLink >::iterator linkIt[] = { linkList[0].begin(), linkList[1].begin() } ;
10019   for ( ; linkIt[0] != linkList[0].end(); linkIt[0]++, linkIt[1]++ ) {
10020     NLink link[] = { *linkIt[0], *linkIt[1] };
10021     long linkID = aLinkID_Gen.GetLinkID( link[0].first, link[0].second );
10022     if ( linkIdSet.find( linkID ) == linkIdSet.end() )
10023       continue;
10024
10025     // by links, find faces in the face sets,
10026     // and find indices of link nodes in the found faces;
10027     // in a face set, there is only one or no face sharing a link
10028     // ---------------------------------------------------------------
10029
10030     const SMDS_MeshElement* face[] = { 0, 0 };
10031     //const SMDS_MeshNode* faceNodes[ 2 ][ 5 ];
10032     vector<const SMDS_MeshNode*> fnodes1(9);
10033     vector<const SMDS_MeshNode*> fnodes2(9);
10034     //const SMDS_MeshNode* notLinkNodes[ 2 ][ 2 ] = {{ 0, 0 },{ 0, 0 }} ;
10035     vector<const SMDS_MeshNode*> notLinkNodes1(6);
10036     vector<const SMDS_MeshNode*> notLinkNodes2(6);
10037     int iLinkNode[2][2];
10038     for ( iSide = 0; iSide < 2; iSide++ ) { // loop on 2 sides
10039       const SMDS_MeshNode* n1 = link[iSide].first;
10040       const SMDS_MeshNode* n2 = link[iSide].second;
10041       set<const SMDS_MeshElement*> * faceSet = faceSetPtr[ iSide ];
10042       set< const SMDS_MeshElement* > fMap;
10043       for ( int i = 0; i < 2; i++ ) { // loop on 2 nodes of a link
10044         const SMDS_MeshNode* n = i ? n1 : n2; // a node of a link
10045         SMDS_ElemIteratorPtr fIt = n->GetInverseElementIterator(SMDSAbs_Face);
10046         while ( fIt->more() ) { // loop on faces sharing a node
10047           const SMDS_MeshElement* f = fIt->next();
10048           if (faceSet->find( f ) != faceSet->end() && // f is in face set
10049               ! fMap.insert( f ).second ) // f encounters twice
10050           {
10051             if ( face[ iSide ] ) {
10052               MESSAGE( "2 faces per link " );
10053               aResult = iSide ? SEW_BAD_SIDE2_NODES : SEW_BAD_SIDE1_NODES;
10054               break;
10055             }
10056             face[ iSide ] = f;
10057             faceSet->erase( f );
10058             // get face nodes and find ones of a link
10059             iNode = 0;
10060             int nbl = -1;
10061             if(f->IsPoly()) {
10062               if(iSide==0) {
10063                 fnodes1.resize(f->NbNodes()+1);
10064                 notLinkNodes1.resize(f->NbNodes()-2);
10065               }
10066               else {
10067                 fnodes2.resize(f->NbNodes()+1);
10068                 notLinkNodes2.resize(f->NbNodes()-2);
10069               }
10070             }
10071             if(!f->IsQuadratic()) {
10072               SMDS_ElemIteratorPtr nIt = f->nodesIterator();
10073               while ( nIt->more() ) {
10074                 const SMDS_MeshNode* n =
10075                   static_cast<const SMDS_MeshNode*>( nIt->next() );
10076                 if ( n == n1 ) {
10077                   iLinkNode[ iSide ][ 0 ] = iNode;
10078                 }
10079                 else if ( n == n2 ) {
10080                   iLinkNode[ iSide ][ 1 ] = iNode;
10081                 }
10082                 //else if ( notLinkNodes[ iSide ][ 0 ] )
10083                 //  notLinkNodes[ iSide ][ 1 ] = n;
10084                 //else
10085                 //  notLinkNodes[ iSide ][ 0 ] = n;
10086                 else {
10087                   nbl++;
10088                   if(iSide==0)
10089                     notLinkNodes1[nbl] = n;
10090                   //notLinkNodes1.push_back(n);
10091                   else
10092                     notLinkNodes2[nbl] = n;
10093                   //notLinkNodes2.push_back(n);
10094                 }
10095                 //faceNodes[ iSide ][ iNode++ ] = n;
10096                 if(iSide==0) {
10097                   fnodes1[iNode++] = n;
10098                 }
10099                 else {
10100                   fnodes2[iNode++] = n;
10101                 }
10102               }
10103             }
10104             else { // f->IsQuadratic()
10105               const SMDS_VtkFace* F =
10106                 dynamic_cast<const SMDS_VtkFace*>(f);
10107               if (!F) throw SALOME_Exception(LOCALIZED("not an SMDS_VtkFace"));
10108               // use special nodes iterator
10109               SMDS_ElemIteratorPtr anIter = F->interlacedNodesElemIterator();
10110               while ( anIter->more() ) {
10111                 const SMDS_MeshNode* n =
10112                   static_cast<const SMDS_MeshNode*>( anIter->next() );
10113                 if ( n == n1 ) {
10114                   iLinkNode[ iSide ][ 0 ] = iNode;
10115                 }
10116                 else if ( n == n2 ) {
10117                   iLinkNode[ iSide ][ 1 ] = iNode;
10118                 }
10119                 else {
10120                   nbl++;
10121                   if(iSide==0) {
10122                     notLinkNodes1[nbl] = n;
10123                   }
10124                   else {
10125                     notLinkNodes2[nbl] = n;
10126                   }
10127                 }
10128                 if(iSide==0) {
10129                   fnodes1[iNode++] = n;
10130                 }
10131                 else {
10132                   fnodes2[iNode++] = n;
10133                 }
10134               }
10135             }
10136             //faceNodes[ iSide ][ iNode ] = faceNodes[ iSide ][ 0 ];
10137             if(iSide==0) {
10138               fnodes1[iNode] = fnodes1[0];
10139             }
10140             else {
10141               fnodes2[iNode] = fnodes1[0];
10142             }
10143           }
10144         }
10145       }
10146     }
10147
10148     // check similarity of elements of the sides
10149     if (aResult == SEW_OK && (( face[0] && !face[1] ) || ( !face[0] && face[1] ))) {
10150       MESSAGE("Correspondent face not found on side " << ( face[0] ? 1 : 0 ));
10151       if ( nReplaceMap.size() == 2 ) { // faces on input nodes not found
10152         aResult = ( face[0] ? SEW_BAD_SIDE2_NODES : SEW_BAD_SIDE1_NODES );
10153       }
10154       else {
10155         aResult = SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
10156       }
10157       break; // do not return because it s necessary to remove tmp faces
10158     }
10159
10160     // set nodes to merge
10161     // -------------------
10162
10163     if ( face[0] && face[1] )  {
10164       int nbNodes = face[0]->NbNodes();
10165       if ( nbNodes != face[1]->NbNodes() ) {
10166         MESSAGE("Diff nb of face nodes");
10167         aResult = SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
10168         break; // do not return because it s necessary to remove tmp faces
10169       }
10170       bool reverse[] = { false, false }; // order of notLinkNodes of quadrangle
10171       if ( nbNodes == 3 ) {
10172         //nReplaceMap.insert( TNodeNodeMap::value_type
10173         //                   ( notLinkNodes[0][0], notLinkNodes[1][0] ));
10174         nReplaceMap.insert( TNodeNodeMap::value_type
10175                             ( notLinkNodes1[0], notLinkNodes2[0] ));
10176       }
10177       else {
10178         for ( iSide = 0; iSide < 2; iSide++ ) { // loop on 2 sides
10179           // analyse link orientation in faces
10180           int i1 = iLinkNode[ iSide ][ 0 ];
10181           int i2 = iLinkNode[ iSide ][ 1 ];
10182           reverse[ iSide ] = Abs( i1 - i2 ) == 1 ? i1 > i2 : i2 > i1;
10183           // if notLinkNodes are the first and the last ones, then
10184           // their order does not correspond to the link orientation
10185           if (( i1 == 1 && i2 == 2 ) ||
10186               ( i1 == 2 && i2 == 1 ))
10187             reverse[ iSide ] = !reverse[ iSide ];
10188         }
10189         if ( reverse[0] == reverse[1] ) {
10190           //nReplaceMap.insert( TNodeNodeMap::value_type
10191           //                   ( notLinkNodes[0][0], notLinkNodes[1][0] ));
10192           //nReplaceMap.insert( TNodeNodeMap::value_type
10193           //                   ( notLinkNodes[0][1], notLinkNodes[1][1] ));
10194           for(int nn=0; nn<nbNodes-2; nn++) {
10195             nReplaceMap.insert( TNodeNodeMap::value_type
10196                                 ( notLinkNodes1[nn], notLinkNodes2[nn] ));
10197           }
10198         }
10199         else {
10200           //nReplaceMap.insert( TNodeNodeMap::value_type
10201           //                   ( notLinkNodes[0][0], notLinkNodes[1][1] ));
10202           //nReplaceMap.insert( TNodeNodeMap::value_type
10203           //                   ( notLinkNodes[0][1], notLinkNodes[1][0] ));
10204           for(int nn=0; nn<nbNodes-2; nn++) {
10205             nReplaceMap.insert( TNodeNodeMap::value_type
10206                                 ( notLinkNodes1[nn], notLinkNodes2[nbNodes-3-nn] ));
10207           }
10208         }
10209       }
10210
10211       // add other links of the faces to linkList
10212       // -----------------------------------------
10213
10214       //const SMDS_MeshNode** nodes = faceNodes[ 0 ];
10215       for ( iNode = 0; iNode < nbNodes; iNode++ )  {
10216         //linkID = aLinkID_Gen.GetLinkID( nodes[iNode], nodes[iNode+1] );
10217         linkID = aLinkID_Gen.GetLinkID( fnodes1[iNode], fnodes1[iNode+1] );
10218         pair< set<long>::iterator, bool > iter_isnew = linkIdSet.insert( linkID );
10219         if ( !iter_isnew.second ) { // already in a set: no need to process
10220           linkIdSet.erase( iter_isnew.first );
10221         }
10222         else // new in set == encountered for the first time: add
10223         {
10224           //const SMDS_MeshNode* n1 = nodes[ iNode ];
10225           //const SMDS_MeshNode* n2 = nodes[ iNode + 1];
10226           const SMDS_MeshNode* n1 = fnodes1[ iNode ];
10227           const SMDS_MeshNode* n2 = fnodes1[ iNode + 1];
10228           linkList[0].push_back ( NLink( n1, n2 ));
10229           linkList[1].push_back ( NLink( nReplaceMap[n1], nReplaceMap[n2] ));
10230         }
10231       }
10232     } // 2 faces found
10233   } // loop on link lists
10234
10235   if ( aResult == SEW_OK &&
10236        ( linkIt[0] != linkList[0].end() ||
10237          !faceSetPtr[0]->empty() || !faceSetPtr[1]->empty() )) {
10238     MESSAGE( (linkIt[0] != linkList[0].end()) <<" "<< (faceSetPtr[0]->empty()) <<
10239              " " << (faceSetPtr[1]->empty()));
10240     aResult = SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
10241   }
10242
10243   // ====================================================================
10244   // 3. Replace nodes in elements of the side 1 and remove replaced nodes
10245   // ====================================================================
10246
10247   // delete temporary faces: they are in reverseElements of actual nodes
10248 //  SMDS_FaceIteratorPtr tmpFaceIt = aTmpFacesMesh.facesIterator();
10249 //  while ( tmpFaceIt->more() )
10250 //    aTmpFacesMesh.RemoveElement( tmpFaceIt->next() );
10251 //  list<const SMDS_MeshElement* >::iterator tmpFaceIt = tempFaceList.begin();
10252 //  for (; tmpFaceIt !=tempFaceList.end(); ++tmpFaceIt)
10253 //    aMesh->RemoveElement(*tmpFaceIt);
10254
10255   if ( aResult != SEW_OK)
10256     return aResult;
10257
10258   list< int > nodeIDsToRemove/*, elemIDsToRemove*/;
10259   // loop on nodes replacement map
10260   TNodeNodeMap::iterator nReplaceMapIt = nReplaceMap.begin(), nnIt;
10261   for ( ; nReplaceMapIt != nReplaceMap.end(); nReplaceMapIt++ )
10262     if ( (*nReplaceMapIt).first != (*nReplaceMapIt).second ) {
10263       const SMDS_MeshNode* nToRemove = (*nReplaceMapIt).first;
10264       nodeIDsToRemove.push_back( nToRemove->GetID() );
10265       // loop on elements sharing nToRemove
10266       SMDS_ElemIteratorPtr invElemIt = nToRemove->GetInverseElementIterator();
10267       while ( invElemIt->more() ) {
10268         const SMDS_MeshElement* e = invElemIt->next();
10269         // get a new suite of nodes: make replacement
10270         int nbReplaced = 0, i = 0, nbNodes = e->NbNodes();
10271         vector< const SMDS_MeshNode*> nodes( nbNodes );
10272         SMDS_ElemIteratorPtr nIt = e->nodesIterator();
10273         while ( nIt->more() ) {
10274           const SMDS_MeshNode* n =
10275             static_cast<const SMDS_MeshNode*>( nIt->next() );
10276           nnIt = nReplaceMap.find( n );
10277           if ( nnIt != nReplaceMap.end() ) {
10278             nbReplaced++;
10279             n = (*nnIt).second;
10280           }
10281           nodes[ i++ ] = n;
10282         }
10283         //       if ( nbReplaced == nbNodes && e->GetType() == SMDSAbs_Face )
10284         //         elemIDsToRemove.push_back( e->GetID() );
10285         //       else
10286         if ( nbReplaced )
10287           {
10288             SMDSAbs_ElementType etyp = e->GetType();
10289             SMDS_MeshElement* newElem = this->AddElement(nodes, etyp, false);
10290             if (newElem)
10291               {
10292                 myLastCreatedElems.Append(newElem);
10293                 AddToSameGroups(newElem, e, aMesh);
10294                 int aShapeId = e->getshapeId();
10295                 if ( aShapeId )
10296                   {
10297                     aMesh->SetMeshElementOnShape( newElem, aShapeId );
10298                   }
10299               }
10300             aMesh->RemoveElement(e);
10301           }
10302       }
10303     }
10304
10305   Remove( nodeIDsToRemove, true );
10306
10307   return aResult;
10308 }
10309
10310 //================================================================================
10311 /*!
10312  * \brief Find corresponding nodes in two sets of faces
10313  * \param theSide1 - first face set
10314  * \param theSide2 - second first face
10315  * \param theFirstNode1 - a boundary node of set 1
10316  * \param theFirstNode2 - a node of set 2 corresponding to theFirstNode1
10317  * \param theSecondNode1 - a boundary node of set 1 linked with theFirstNode1
10318  * \param theSecondNode2 - a node of set 2 corresponding to theSecondNode1
10319  * \param nReplaceMap - output map of corresponding nodes
10320  * \return bool  - is a success or not
10321  */
10322 //================================================================================
10323
10324 #ifdef _DEBUG_
10325 //#define DEBUG_MATCHING_NODES
10326 #endif
10327
10328 SMESH_MeshEditor::Sew_Error
10329 SMESH_MeshEditor::FindMatchingNodes(set<const SMDS_MeshElement*>& theSide1,
10330                                     set<const SMDS_MeshElement*>& theSide2,
10331                                     const SMDS_MeshNode*          theFirstNode1,
10332                                     const SMDS_MeshNode*          theFirstNode2,
10333                                     const SMDS_MeshNode*          theSecondNode1,
10334                                     const SMDS_MeshNode*          theSecondNode2,
10335                                     TNodeNodeMap &                nReplaceMap)
10336 {
10337   set<const SMDS_MeshElement*> * faceSetPtr[] = { &theSide1, &theSide2 };
10338
10339   nReplaceMap.clear();
10340   if ( theFirstNode1 != theFirstNode2 )
10341     nReplaceMap.insert( make_pair( theFirstNode1, theFirstNode2 ));
10342   if ( theSecondNode1 != theSecondNode2 )
10343     nReplaceMap.insert( make_pair( theSecondNode1, theSecondNode2 ));
10344
10345   set< SMESH_TLink > linkSet; // set of nodes where order of nodes is ignored
10346   linkSet.insert( SMESH_TLink( theFirstNode1, theSecondNode1 ));
10347
10348   list< NLink > linkList[2];
10349   linkList[0].push_back( NLink( theFirstNode1, theSecondNode1 ));
10350   linkList[1].push_back( NLink( theFirstNode2, theSecondNode2 ));
10351
10352   // loop on links in linkList; find faces by links and append links
10353   // of the found faces to linkList
10354   list< NLink >::iterator linkIt[] = { linkList[0].begin(), linkList[1].begin() } ;
10355   for ( ; linkIt[0] != linkList[0].end(); linkIt[0]++, linkIt[1]++ ) {
10356     NLink link[] = { *linkIt[0], *linkIt[1] };
10357     if ( linkSet.find( link[0] ) == linkSet.end() )
10358       continue;
10359
10360     // by links, find faces in the face sets,
10361     // and find indices of link nodes in the found faces;
10362     // in a face set, there is only one or no face sharing a link
10363     // ---------------------------------------------------------------
10364
10365     const SMDS_MeshElement* face[] = { 0, 0 };
10366     list<const SMDS_MeshNode*> notLinkNodes[2];
10367     //bool reverse[] = { false, false }; // order of notLinkNodes
10368     int nbNodes[2];
10369     for ( int iSide = 0; iSide < 2; iSide++ ) // loop on 2 sides
10370     {
10371       const SMDS_MeshNode* n1 = link[iSide].first;
10372       const SMDS_MeshNode* n2 = link[iSide].second;
10373       set<const SMDS_MeshElement*> * faceSet = faceSetPtr[ iSide ];
10374       set< const SMDS_MeshElement* > facesOfNode1;
10375       for ( int iNode = 0; iNode < 2; iNode++ ) // loop on 2 nodes of a link
10376       {
10377         // during a loop of the first node, we find all faces around n1,
10378         // during a loop of the second node, we find one face sharing both n1 and n2
10379         const SMDS_MeshNode* n = iNode ? n1 : n2; // a node of a link
10380         SMDS_ElemIteratorPtr fIt = n->GetInverseElementIterator(SMDSAbs_Face);
10381         while ( fIt->more() ) { // loop on faces sharing a node
10382           const SMDS_MeshElement* f = fIt->next();
10383           if (faceSet->find( f ) != faceSet->end() && // f is in face set
10384               ! facesOfNode1.insert( f ).second ) // f encounters twice
10385           {
10386             if ( face[ iSide ] ) {
10387               MESSAGE( "2 faces per link " );
10388               return ( iSide ? SEW_BAD_SIDE2_NODES : SEW_BAD_SIDE1_NODES );
10389             }
10390             face[ iSide ] = f;
10391             faceSet->erase( f );
10392
10393             // get not link nodes
10394             int nbN = f->NbNodes();
10395             if ( f->IsQuadratic() )
10396               nbN /= 2;
10397             nbNodes[ iSide ] = nbN;
10398             list< const SMDS_MeshNode* > & nodes = notLinkNodes[ iSide ];
10399             int i1 = f->GetNodeIndex( n1 );
10400             int i2 = f->GetNodeIndex( n2 );
10401             int iEnd = nbN, iBeg = -1, iDelta = 1;
10402             bool reverse = ( Abs( i1 - i2 ) == 1 ? i1 > i2 : i2 > i1 );
10403             if ( reverse ) {
10404               std::swap( iEnd, iBeg ); iDelta = -1;
10405             }
10406             int i = i2;
10407             while ( true ) {
10408               i += iDelta;
10409               if ( i == iEnd ) i = iBeg + iDelta;
10410               if ( i == i1 ) break;
10411               nodes.push_back ( f->GetNode( i ) );
10412             }
10413           }
10414         }
10415       }
10416     }
10417     // check similarity of elements of the sides
10418     if (( face[0] && !face[1] ) || ( !face[0] && face[1] )) {
10419       MESSAGE("Correspondent face not found on side " << ( face[0] ? 1 : 0 ));
10420       if ( nReplaceMap.size() == 2 ) { // faces on input nodes not found
10421         return ( face[0] ? SEW_BAD_SIDE2_NODES : SEW_BAD_SIDE1_NODES );
10422       }
10423       else {
10424         return SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
10425       }
10426     }
10427
10428     // set nodes to merge
10429     // -------------------
10430
10431     if ( face[0] && face[1] )  {
10432       if ( nbNodes[0] != nbNodes[1] ) {
10433         MESSAGE("Diff nb of face nodes");
10434         return SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
10435       }
10436 #ifdef DEBUG_MATCHING_NODES
10437       MESSAGE ( " Link 1: " << link[0].first->GetID() <<" "<< link[0].second->GetID()
10438                 << " F 1: " << face[0] << "| Link 2: " << link[1].first->GetID() <<" "
10439                 << link[1].second->GetID() << " F 2: " << face[1] << " | Bind: " ) ;
10440 #endif
10441       int nbN = nbNodes[0];
10442       {
10443         list<const SMDS_MeshNode*>::iterator n1 = notLinkNodes[0].begin();
10444         list<const SMDS_MeshNode*>::iterator n2 = notLinkNodes[1].begin();
10445         for ( int i = 0 ; i < nbN - 2; ++i ) {
10446 #ifdef DEBUG_MATCHING_NODES
10447           MESSAGE ( (*n1)->GetID() << " to " << (*n2)->GetID() );
10448 #endif
10449           nReplaceMap.insert( make_pair( *(n1++), *(n2++) ));
10450         }
10451       }
10452
10453       // add other links of the face 1 to linkList
10454       // -----------------------------------------
10455
10456       const SMDS_MeshElement* f0 = face[0];
10457       const SMDS_MeshNode* n1 = f0->GetNode( nbN - 1 );
10458       for ( int i = 0; i < nbN; i++ )
10459       {
10460         const SMDS_MeshNode* n2 = f0->GetNode( i );
10461         pair< set< SMESH_TLink >::iterator, bool > iter_isnew =
10462           linkSet.insert( SMESH_TLink( n1, n2 ));
10463         if ( !iter_isnew.second ) { // already in a set: no need to process
10464           linkSet.erase( iter_isnew.first );
10465         }
10466         else // new in set == encountered for the first time: add
10467         {
10468 #ifdef DEBUG_MATCHING_NODES
10469           MESSAGE ( "Add link 1: " << n1->GetID() << " " << n2->GetID() << " "
10470                     << " | link 2: " << nReplaceMap[n1]->GetID() << " " << nReplaceMap[n2]->GetID() << " " );
10471 #endif
10472           linkList[0].push_back ( NLink( n1, n2 ));
10473           linkList[1].push_back ( NLink( nReplaceMap[n1], nReplaceMap[n2] ));
10474         }
10475         n1 = n2;
10476       }
10477     } // 2 faces found
10478   } // loop on link lists
10479
10480   return SEW_OK;
10481 }
10482
10483 //================================================================================
10484 /*!
10485   \brief Creates a hole in a mesh by doubling the nodes of some particular elements
10486   \param theElems - the list of elements (edges or faces) to be replicated
10487   The nodes for duplication could be found from these elements
10488   \param theNodesNot - list of nodes to NOT replicate
10489   \param theAffectedElems - the list of elements (cells and edges) to which the 
10490   replicated nodes should be associated to.
10491   \return TRUE if operation has been completed successfully, FALSE otherwise
10492 */
10493 //================================================================================
10494
10495 bool SMESH_MeshEditor::DoubleNodes( const TIDSortedElemSet& theElems,
10496                                     const TIDSortedElemSet& theNodesNot,
10497                                     const TIDSortedElemSet& theAffectedElems )
10498 {
10499   myLastCreatedElems.Clear();
10500   myLastCreatedNodes.Clear();
10501
10502   if ( theElems.size() == 0 )
10503     return false;
10504
10505   SMESHDS_Mesh* aMeshDS = GetMeshDS();
10506   if ( !aMeshDS )
10507     return false;
10508
10509   bool res = false;
10510   std::map< const SMDS_MeshNode*, const SMDS_MeshNode* > anOldNodeToNewNode;
10511   // duplicate elements and nodes
10512   res = doubleNodes( aMeshDS, theElems, theNodesNot, anOldNodeToNewNode, true );
10513   // replce nodes by duplications
10514   res = doubleNodes( aMeshDS, theAffectedElems, theNodesNot, anOldNodeToNewNode, false );
10515   return res;
10516 }
10517
10518 //================================================================================
10519 /*!
10520   \brief Creates a hole in a mesh by doubling the nodes of some particular elements
10521   \param theMeshDS - mesh instance
10522   \param theElems - the elements replicated or modified (nodes should be changed)
10523   \param theNodesNot - nodes to NOT replicate
10524   \param theNodeNodeMap - relation of old node to new created node
10525   \param theIsDoubleElem - flag os to replicate element or modify
10526   \return TRUE if operation has been completed successfully, FALSE otherwise
10527 */
10528 //================================================================================
10529
10530 bool SMESH_MeshEditor::doubleNodes( SMESHDS_Mesh*     theMeshDS,
10531                                     const TIDSortedElemSet& theElems,
10532                                     const TIDSortedElemSet& theNodesNot,
10533                                     std::map< const SMDS_MeshNode*,
10534                                     const SMDS_MeshNode* >& theNodeNodeMap,
10535                                     const bool theIsDoubleElem )
10536 {
10537   MESSAGE("doubleNodes");
10538   // iterate on through element and duplicate them (by nodes duplication)
10539   bool res = false;
10540   TIDSortedElemSet::const_iterator elemItr = theElems.begin();
10541   for ( ;  elemItr != theElems.end(); ++elemItr )
10542   {
10543     const SMDS_MeshElement* anElem = *elemItr;
10544     if (!anElem)
10545       continue;
10546
10547     bool isDuplicate = false;
10548     // duplicate nodes to duplicate element
10549     std::vector<const SMDS_MeshNode*> newNodes( anElem->NbNodes() );
10550     SMDS_ElemIteratorPtr anIter = anElem->nodesIterator();
10551     int ind = 0;
10552     while ( anIter->more() ) 
10553     { 
10554
10555       SMDS_MeshNode* aCurrNode = (SMDS_MeshNode*)anIter->next();
10556       SMDS_MeshNode* aNewNode = aCurrNode;
10557       if ( theNodeNodeMap.find( aCurrNode ) != theNodeNodeMap.end() )
10558         aNewNode = (SMDS_MeshNode*)theNodeNodeMap[ aCurrNode ];
10559       else if ( theIsDoubleElem && theNodesNot.find( aCurrNode ) == theNodesNot.end() )
10560       {
10561         // duplicate node
10562         aNewNode = theMeshDS->AddNode( aCurrNode->X(), aCurrNode->Y(), aCurrNode->Z() );
10563         theNodeNodeMap[ aCurrNode ] = aNewNode;
10564         myLastCreatedNodes.Append( aNewNode );
10565       }
10566       isDuplicate |= (aCurrNode != aNewNode);
10567       newNodes[ ind++ ] = aNewNode;
10568     }
10569     if ( !isDuplicate )
10570       continue;
10571
10572     if ( theIsDoubleElem )
10573       AddElement(newNodes, anElem->GetType(), anElem->IsPoly());
10574     else
10575       {
10576       MESSAGE("ChangeElementNodes");
10577       theMeshDS->ChangeElementNodes( anElem, &newNodes[ 0 ], anElem->NbNodes() );
10578       }
10579     res = true;
10580   }
10581   return res;
10582 }
10583
10584 //================================================================================
10585 /*!
10586   \brief Creates a hole in a mesh by doubling the nodes of some particular elements
10587   \param theNodes - identifiers of nodes to be doubled
10588   \param theModifiedElems - identifiers of elements to be updated by the new (doubled) 
10589          nodes. If list of element identifiers is empty then nodes are doubled but 
10590          they not assigned to elements
10591   \return TRUE if operation has been completed successfully, FALSE otherwise
10592 */
10593 //================================================================================
10594
10595 bool SMESH_MeshEditor::DoubleNodes( const std::list< int >& theListOfNodes, 
10596                                     const std::list< int >& theListOfModifiedElems )
10597 {
10598   MESSAGE("DoubleNodes");
10599   myLastCreatedElems.Clear();
10600   myLastCreatedNodes.Clear();
10601
10602   if ( theListOfNodes.size() == 0 )
10603     return false;
10604
10605   SMESHDS_Mesh* aMeshDS = GetMeshDS();
10606   if ( !aMeshDS )
10607     return false;
10608
10609   // iterate through nodes and duplicate them
10610
10611   std::map< const SMDS_MeshNode*, const SMDS_MeshNode* > anOldNodeToNewNode;
10612
10613   std::list< int >::const_iterator aNodeIter;
10614   for ( aNodeIter = theListOfNodes.begin(); aNodeIter != theListOfNodes.end(); ++aNodeIter )
10615   {
10616     int aCurr = *aNodeIter;
10617     SMDS_MeshNode* aNode = (SMDS_MeshNode*)aMeshDS->FindNode( aCurr );
10618     if ( !aNode )
10619       continue;
10620
10621     // duplicate node
10622
10623     const SMDS_MeshNode* aNewNode = aMeshDS->AddNode( aNode->X(), aNode->Y(), aNode->Z() );
10624     if ( aNewNode )
10625     {
10626       anOldNodeToNewNode[ aNode ] = aNewNode;
10627       myLastCreatedNodes.Append( aNewNode );
10628     }
10629   }
10630
10631   // Create map of new nodes for modified elements
10632
10633   std::map< SMDS_MeshElement*, vector<const SMDS_MeshNode*> > anElemToNodes;
10634
10635   std::list< int >::const_iterator anElemIter;
10636   for ( anElemIter = theListOfModifiedElems.begin(); 
10637         anElemIter != theListOfModifiedElems.end(); ++anElemIter )
10638   {
10639     int aCurr = *anElemIter;
10640     SMDS_MeshElement* anElem = (SMDS_MeshElement*)aMeshDS->FindElement( aCurr );
10641     if ( !anElem )
10642       continue;
10643
10644     vector<const SMDS_MeshNode*> aNodeArr( anElem->NbNodes() );
10645
10646     SMDS_ElemIteratorPtr anIter = anElem->nodesIterator();
10647     int ind = 0;
10648     while ( anIter->more() ) 
10649     { 
10650       SMDS_MeshNode* aCurrNode = (SMDS_MeshNode*)anIter->next();
10651       if ( aCurr && anOldNodeToNewNode.find( aCurrNode ) != anOldNodeToNewNode.end() )
10652       {
10653         const SMDS_MeshNode* aNewNode = anOldNodeToNewNode[ aCurrNode ];
10654         aNodeArr[ ind++ ] = aNewNode;
10655       }
10656       else
10657         aNodeArr[ ind++ ] = aCurrNode;
10658     }
10659     anElemToNodes[ anElem ] = aNodeArr;
10660   }
10661
10662   // Change nodes of elements  
10663
10664   std::map< SMDS_MeshElement*, vector<const SMDS_MeshNode*> >::iterator
10665     anElemToNodesIter = anElemToNodes.begin();
10666   for ( ; anElemToNodesIter != anElemToNodes.end(); ++anElemToNodesIter )
10667   {
10668     const SMDS_MeshElement* anElem = anElemToNodesIter->first;
10669     vector<const SMDS_MeshNode*> aNodeArr = anElemToNodesIter->second;
10670     if ( anElem )
10671       {
10672       MESSAGE("ChangeElementNodes");
10673       aMeshDS->ChangeElementNodes( anElem, &aNodeArr[ 0 ], anElem->NbNodes() );
10674       }
10675   }
10676
10677   return true;
10678 }
10679
10680 namespace {
10681
10682   //================================================================================
10683   /*!
10684   \brief Check if element located inside shape
10685   \return TRUE if IN or ON shape, FALSE otherwise
10686   */
10687   //================================================================================
10688
10689   template<class Classifier>
10690   bool isInside(const SMDS_MeshElement* theElem,
10691                 Classifier&             theClassifier,
10692                 const double            theTol)
10693   {
10694     gp_XYZ centerXYZ (0, 0, 0);
10695     SMDS_ElemIteratorPtr aNodeItr = theElem->nodesIterator();
10696     while (aNodeItr->more())
10697       centerXYZ += SMESH_TNodeXYZ(cast2Node( aNodeItr->next()));
10698
10699     gp_Pnt aPnt = centerXYZ / theElem->NbNodes();
10700     theClassifier.Perform(aPnt, theTol);
10701     TopAbs_State aState = theClassifier.State();
10702     return (aState == TopAbs_IN || aState == TopAbs_ON );
10703   }
10704
10705   //================================================================================
10706   /*!
10707    * \brief Classifier of the 3D point on the TopoDS_Face
10708    *        with interaface suitable for isInside()
10709    */
10710   //================================================================================
10711
10712   struct _FaceClassifier
10713   {
10714     Extrema_ExtPS       _extremum;
10715     BRepAdaptor_Surface _surface;
10716     TopAbs_State        _state;
10717
10718     _FaceClassifier(const TopoDS_Face& face):_extremum(),_surface(face),_state(TopAbs_OUT)
10719     {
10720       _extremum.Initialize( _surface,
10721                             _surface.FirstUParameter(), _surface.LastUParameter(),
10722                             _surface.FirstVParameter(), _surface.LastVParameter(),
10723                             _surface.Tolerance(), _surface.Tolerance() );
10724     }
10725     void Perform(const gp_Pnt& aPnt, double theTol)
10726     {
10727       _state = TopAbs_OUT;
10728       _extremum.Perform(aPnt);
10729       if ( _extremum.IsDone() )
10730         for ( int iSol = 1; iSol <= _extremum.NbExt() && _state == TopAbs_OUT; ++iSol)
10731           _state = ( _extremum.Value(iSol) <= theTol ? TopAbs_IN : TopAbs_OUT );
10732     }
10733     TopAbs_State State() const
10734     {
10735       return _state;
10736     }
10737   };
10738 }
10739
10740 //================================================================================
10741 /*!
10742   \brief Creates a hole in a mesh by doubling the nodes of some particular elements
10743   \param theElems - group of of elements (edges or faces) to be replicated
10744   \param theNodesNot - group of nodes not to replicate
10745   \param theShape - shape to detect affected elements (element which geometric center
10746   located on or inside shape).
10747   The replicated nodes should be associated to affected elements.
10748   \return TRUE if operation has been completed successfully, FALSE otherwise
10749 */
10750 //================================================================================
10751
10752 bool SMESH_MeshEditor::DoubleNodesInRegion( const TIDSortedElemSet& theElems,
10753                                             const TIDSortedElemSet& theNodesNot,
10754                                             const TopoDS_Shape&     theShape )
10755 {
10756   if ( theShape.IsNull() )
10757     return false;
10758
10759   const double aTol = Precision::Confusion();
10760   auto_ptr< BRepClass3d_SolidClassifier> bsc3d;
10761   auto_ptr<_FaceClassifier>              aFaceClassifier;
10762   if ( theShape.ShapeType() == TopAbs_SOLID )
10763   {
10764     bsc3d.reset( new BRepClass3d_SolidClassifier(theShape));;
10765     bsc3d->PerformInfinitePoint(aTol);
10766   }
10767   else if (theShape.ShapeType() == TopAbs_FACE )
10768   {
10769     aFaceClassifier.reset( new _FaceClassifier(TopoDS::Face(theShape)));
10770   }
10771
10772   // iterates on indicated elements and get elements by back references from their nodes
10773   TIDSortedElemSet anAffected;
10774   TIDSortedElemSet::const_iterator elemItr = theElems.begin();
10775   for ( ;  elemItr != theElems.end(); ++elemItr )
10776   {
10777     SMDS_MeshElement* anElem = (SMDS_MeshElement*)*elemItr;
10778     if (!anElem)
10779       continue;
10780
10781     SMDS_ElemIteratorPtr nodeItr = anElem->nodesIterator();
10782     while ( nodeItr->more() )
10783     {
10784       const SMDS_MeshNode* aNode = cast2Node(nodeItr->next());
10785       if ( !aNode || theNodesNot.find(aNode) != theNodesNot.end() )
10786         continue;
10787       SMDS_ElemIteratorPtr backElemItr = aNode->GetInverseElementIterator();
10788       while ( backElemItr->more() )
10789       {
10790         const SMDS_MeshElement* curElem = backElemItr->next();
10791         if ( curElem && theElems.find(curElem) == theElems.end() &&
10792              ( bsc3d.get() ?
10793                isInside( curElem, *bsc3d, aTol ) :
10794                isInside( curElem, *aFaceClassifier, aTol )))
10795           anAffected.insert( curElem );
10796       }
10797     }
10798   }
10799   return DoubleNodes( theElems, theNodesNot, anAffected );
10800 }
10801
10802 /*!
10803  *  \brief compute an oriented angle between two planes defined by four points.
10804  *  The vector (p0,p1) defines the intersection of the 2 planes (p0,p1,g1) and (p0,p1,g2)
10805  *  @param p0 base of the rotation axe
10806  *  @param p1 extremity of the rotation axe
10807  *  @param g1 belongs to the first plane
10808  *  @param g2 belongs to the second plane
10809  */
10810 double SMESH_MeshEditor::OrientedAngle(const gp_Pnt& p0, const gp_Pnt& p1, const gp_Pnt& g1, const gp_Pnt& g2)
10811 {
10812 //  MESSAGE("    p0: " << p0.X() << " " << p0.Y() << " " << p0.Z());
10813 //  MESSAGE("    p1: " << p1.X() << " " << p1.Y() << " " << p1.Z());
10814 //  MESSAGE("    g1: " << g1.X() << " " << g1.Y() << " " << g1.Z());
10815 //  MESSAGE("    g2: " << g2.X() << " " << g2.Y() << " " << g2.Z());
10816   gp_Vec vref(p0, p1);
10817   gp_Vec v1(p0, g1);
10818   gp_Vec v2(p0, g2);
10819   gp_Vec n1 = vref.Crossed(v1);
10820   gp_Vec n2 = vref.Crossed(v2);
10821   return n2.AngleWithRef(n1, vref);
10822 }
10823
10824 /*!
10825  * \brief Double nodes on shared faces between groups of volumes and create flat elements on demand.
10826  * The list of groups must describe a partition of the mesh volumes.
10827  * The nodes of the internal faces at the boundaries of the groups are doubled.
10828  * In option, the internal faces are replaced by flat elements.
10829  * Triangles are transformed in prisms, and quadrangles in hexahedrons.
10830  * The flat elements are stored in groups of volumes.
10831  * @param theElems - list of groups of volumes, where a group of volume is a set of
10832  * SMDS_MeshElements sorted by Id.
10833  * @param createJointElems - if TRUE, create the elements
10834  * @return TRUE if operation has been completed successfully, FALSE otherwise
10835  */
10836 bool SMESH_MeshEditor::DoubleNodesOnGroupBoundaries( const std::vector<TIDSortedElemSet>& theElems,
10837                                                      bool createJointElems)
10838 {
10839   MESSAGE("----------------------------------------------");
10840   MESSAGE("SMESH_MeshEditor::doubleNodesOnGroupBoundaries");
10841   MESSAGE("----------------------------------------------");
10842
10843   SMESHDS_Mesh *meshDS = this->myMesh->GetMeshDS();
10844   meshDS->BuildDownWardConnectivity(true);
10845   CHRONO(50);
10846   SMDS_UnstructuredGrid *grid = meshDS->getGrid();
10847
10848   // --- build the list of faces shared by 2 domains (group of elements), with their domain and volume indexes
10849   //     build the list of cells with only a node or an edge on the border, with their domain and volume indexes
10850   //     build the list of nodes shared by 2 or more domains, with their domain indexes
10851
10852   std::map<DownIdType, std::map<int,int>, DownIdCompare> faceDomains; // face --> (id domain --> id volume)
10853   std::map<int,int>celldom; // cell vtkId --> domain
10854   std::map<DownIdType, std::map<int,int>, DownIdCompare> cellDomains;  // oldNode --> (id domain --> id cell)
10855   std::map<int, std::map<int,int> > nodeDomains; // oldId -->  (domainId --> newId)
10856   faceDomains.clear();
10857   celldom.clear();
10858   cellDomains.clear();
10859   nodeDomains.clear();
10860   std::map<int,int> emptyMap;
10861   std::set<int> emptySet;
10862   emptyMap.clear();
10863
10864   for (int idom = 0; idom < theElems.size(); idom++)
10865     {
10866
10867       // --- build a map (face to duplicate --> volume to modify)
10868       //     with all the faces shared by 2 domains (group of elements)
10869       //     and corresponding volume of this domain, for each shared face.
10870       //     a volume has a face shared by 2 domains if it has a neighbor which is not in is domain.
10871
10872       const TIDSortedElemSet& domain = theElems[idom];
10873       TIDSortedElemSet::const_iterator elemItr = domain.begin();
10874       for (; elemItr != domain.end(); ++elemItr)
10875         {
10876           SMDS_MeshElement* anElem = (SMDS_MeshElement*) *elemItr;
10877           if (!anElem)
10878             continue;
10879           int vtkId = anElem->getVtkId();
10880           int neighborsVtkIds[NBMAXNEIGHBORS];
10881           int downIds[NBMAXNEIGHBORS];
10882           unsigned char downTypes[NBMAXNEIGHBORS];
10883           int nbNeighbors = grid->GetNeighbors(neighborsVtkIds, downIds, downTypes, vtkId);
10884           for (int n = 0; n < nbNeighbors; n++)
10885             {
10886               int smdsId = meshDS->fromVtkToSmds(neighborsVtkIds[n]);
10887               const SMDS_MeshElement* elem = meshDS->FindElement(smdsId);
10888               if (! domain.count(elem)) // neighbor is in another domain : face is shared
10889                 {
10890                   DownIdType face(downIds[n], downTypes[n]);
10891                   if (!faceDomains.count(face))
10892                     faceDomains[face] = emptyMap; // create an empty entry for face
10893                   if (!faceDomains[face].count(idom))
10894                     {
10895                       faceDomains[face][idom] = vtkId; // volume associated to face in this domain
10896                       celldom[vtkId] = idom;
10897                     }
10898                 }
10899             }
10900         }
10901     }
10902
10903   //MESSAGE("Number of shared faces " << faceDomains.size());
10904   std::map<DownIdType, std::map<int, int>, DownIdCompare>::iterator itface;
10905
10906   // --- explore the shared faces domain by domain,
10907   //     explore the nodes of the face and see if they belong to a cell in the domain,
10908   //     which has only a node or an edge on the border (not a shared face)
10909
10910   for (int idomain = 0; idomain < theElems.size(); idomain++)
10911     {
10912       const TIDSortedElemSet& domain = theElems[idomain];
10913       itface = faceDomains.begin();
10914       for (; itface != faceDomains.end(); ++itface)
10915         {
10916           std::map<int, int> domvol = itface->second;
10917           if (!domvol.count(idomain))
10918             continue;
10919           DownIdType face = itface->first;
10920           //MESSAGE(" --- face " << face.cellId);
10921           std::set<int> oldNodes;
10922           oldNodes.clear();
10923           grid->GetNodeIds(oldNodes, face.cellId, face.cellType);
10924           std::set<int>::iterator itn = oldNodes.begin();
10925           for (; itn != oldNodes.end(); ++itn)
10926             {
10927               int oldId = *itn;
10928               //MESSAGE("     node " << oldId);
10929               std::set<int> cells;
10930               cells.clear();
10931               vtkCellLinks::Link l = grid->GetCellLinks()->GetLink(oldId);
10932               for (int i=0; i<l.ncells; i++)
10933                 {
10934                   int vtkId = l.cells[i];
10935                   const SMDS_MeshElement* anElem = GetMeshDS()->FindElement(GetMeshDS()->fromVtkToSmds(vtkId));
10936                   if (!domain.count(anElem))
10937                     continue;
10938                   int vtkType = grid->GetCellType(vtkId);
10939                   int downId = grid->CellIdToDownId(vtkId);
10940                   if (downId < 0)
10941                     {
10942                       MESSAGE("doubleNodesOnGroupBoundaries: internal algorithm problem");
10943                       continue; // not OK at this stage of the algorithm:
10944                                 //no cells created after BuildDownWardConnectivity
10945                     }
10946                   DownIdType aCell(downId, vtkType);
10947                   if (celldom.count(vtkId))
10948                     continue;
10949                   cellDomains[aCell][idomain] = vtkId;
10950                   celldom[vtkId] = idomain;
10951                 }
10952             }
10953         }
10954     }
10955
10956   // --- explore the shared faces domain by domain, to duplicate the nodes in a coherent way
10957   //     for each shared face, get the nodes
10958   //     for each node, for each domain of the face, create a clone of the node
10959
10960   // --- edges at the intersection of 3 or 4 domains, with the order of domains to build
10961   //     junction elements of type prism or hexa. the key is the pair of nodesId (lower first)
10962   //     the value is the ordered domain ids. (more than 4 domains not taken into account)
10963
10964   std::map<std::vector<int>, std::vector<int> > edgesMultiDomains; // nodes of edge --> ordered domains
10965   std::map<int, std::vector<int> > mutipleNodes; // nodes muti domains with domain order
10966
10967   for (int idomain = 0; idomain < theElems.size(); idomain++)
10968     {
10969       itface = faceDomains.begin();
10970       for (; itface != faceDomains.end(); ++itface)
10971         {
10972           std::map<int, int> domvol = itface->second;
10973           if (!domvol.count(idomain))
10974             continue;
10975           DownIdType face = itface->first;
10976           //MESSAGE(" --- face " << face.cellId);
10977           std::set<int> oldNodes;
10978           oldNodes.clear();
10979           grid->GetNodeIds(oldNodes, face.cellId, face.cellType);
10980           bool isMultipleDetected = false;
10981           std::set<int>::iterator itn = oldNodes.begin();
10982           for (; itn != oldNodes.end(); ++itn)
10983             {
10984               int oldId = *itn;
10985               //MESSAGE("     node " << oldId);
10986               if (!nodeDomains.count(oldId))
10987                 nodeDomains[oldId] = emptyMap; // create an empty entry for node
10988               if (nodeDomains[oldId].empty())
10989                 nodeDomains[oldId][idomain] = oldId; // keep the old node in the first domain
10990               std::map<int, int>::iterator itdom = domvol.begin();
10991               for (; itdom != domvol.end(); ++itdom)
10992                 {
10993                   int idom = itdom->first;
10994                   //MESSAGE("         domain " << idom);
10995                   if (!nodeDomains[oldId].count(idom)) // --- node to clone
10996                     {
10997                       if (nodeDomains[oldId].size() >= 2) // a multiple node
10998                         {
10999                           vector<int> orderedDoms;
11000                           //MESSAGE("multiple node " << oldId);
11001                           isMultipleDetected =true;
11002                           if (mutipleNodes.count(oldId))
11003                             orderedDoms = mutipleNodes[oldId];
11004                           else
11005                             {
11006                               map<int,int>::iterator it = nodeDomains[oldId].begin();
11007                               for (; it != nodeDomains[oldId].end(); ++it)
11008                                 orderedDoms.push_back(it->first);
11009                             }
11010                           orderedDoms.push_back(idom); // TODO order ==> push_front or back
11011                           //stringstream txt;
11012                           //for (int i=0; i<orderedDoms.size(); i++)
11013                           //  txt << orderedDoms[i] << " ";
11014                           //MESSAGE("orderedDoms " << txt.str());
11015                           mutipleNodes[oldId] = orderedDoms;
11016                         }
11017                       double *coords = grid->GetPoint(oldId);
11018                       SMDS_MeshNode *newNode = meshDS->AddNode(coords[0], coords[1], coords[2]);
11019                       int newId = newNode->getVtkId();
11020                       nodeDomains[oldId][idom] = newId; // cloned node for other domains
11021                       //MESSAGE("   newNode " << newId << " oldNode " << oldId << " size=" <<nodeDomains[oldId].size());
11022                     }
11023                   if (nodeDomains[oldId].size() >= 3)
11024                     {
11025                       //MESSAGE("confirm multiple node " << oldId);
11026                       isMultipleDetected =true;
11027                     }
11028                 }
11029             }
11030           if (isMultipleDetected) // check if an edge of the face is shared between 3 or more domains
11031             {
11032               //MESSAGE("multiple Nodes detected on a shared face");
11033               int downId = itface->first.cellId;
11034               unsigned char cellType = itface->first.cellType;
11035               int nbEdges = grid->getDownArray(cellType)->getNumberOfDownCells(downId);
11036               const int *downEdgeIds = grid->getDownArray(cellType)->getDownCells(downId);
11037               const unsigned char* edgeType = grid->getDownArray(cellType)->getDownTypes(downId);
11038               for (int ie =0; ie < nbEdges; ie++)
11039                 {
11040                   int nodes[3];
11041                   int nbNodes = grid->getDownArray(edgeType[ie])->getNodes(downEdgeIds[ie], nodes);
11042                   if (mutipleNodes.count(nodes[0]) && mutipleNodes.count(nodes[nbNodes-1]))
11043                     {
11044                       vector<int> vn0 = mutipleNodes[nodes[0]];
11045                       vector<int> vn1 = mutipleNodes[nodes[nbNodes - 1]];
11046                       sort( vn0.begin(), vn0.end() );
11047                       sort( vn1.begin(), vn1.end() );
11048                       if (vn0 == vn1)
11049                         {
11050                           //MESSAGE(" detect edgesMultiDomains " << nodes[0] << " " << nodes[nbNodes - 1]);
11051                           double *coords = grid->GetPoint(nodes[0]);
11052                           gp_Pnt p0(coords[0], coords[1], coords[2]);
11053                           coords = grid->GetPoint(nodes[nbNodes - 1]);
11054                           gp_Pnt p1(coords[0], coords[1], coords[2]);
11055                           gp_Pnt gref;
11056                           int vtkVolIds[1000];  // an edge can belong to a lot of volumes
11057                           map<int, SMDS_VtkVolume*> domvol; // domain --> a volume with the edge
11058                           map<int, double> angleDom; // oriented angles between planes defined by edge and volume centers
11059                           int nbvol = grid->GetParentVolumes(vtkVolIds, downEdgeIds[ie], edgeType[ie]);
11060                           for (int id=0; id < vn0.size(); id++)
11061                             {
11062                               int idom = vn0[id];
11063                               for (int ivol=0; ivol<nbvol; ivol++)
11064                                 {
11065                                   int smdsId = meshDS->fromVtkToSmds(vtkVolIds[ivol]);
11066                                   SMDS_MeshElement* elem = (SMDS_MeshElement*)meshDS->FindElement(smdsId);
11067                                   if (theElems[idom].count(elem))
11068                                     {
11069                                       SMDS_VtkVolume* svol = dynamic_cast<SMDS_VtkVolume*>(elem);
11070                                       domvol[idom] = svol;
11071                                       //MESSAGE("  domain " << idom << " volume " << elem->GetID());
11072                                       double values[3];
11073                                       vtkIdType npts = 0;
11074                                       vtkIdType* pts = 0;
11075                                       grid->GetCellPoints(vtkVolIds[ivol], npts, pts);
11076                                       SMDS_VtkVolume::gravityCenter(grid, pts, npts, values);
11077                                       if (id ==0)
11078                                         {
11079                                           gref.SetXYZ(gp_XYZ(values[0], values[1], values[2]));
11080                                           angleDom[idom] = 0;
11081                                         }
11082                                       else
11083                                         {
11084                                           gp_Pnt g(values[0], values[1], values[2]);
11085                                           angleDom[idom] = OrientedAngle(p0, p1, gref, g); // -pi<angle<+pi
11086                                           //MESSAGE("  angle=" << angleDom[idom]);
11087                                         }
11088                                       break;
11089                                     }
11090                                 }
11091                             }
11092                           map<double, int> sortedDom; // sort domains by angle
11093                           for (map<int, double>::iterator ia = angleDom.begin(); ia != angleDom.end(); ++ia)
11094                             sortedDom[ia->second] = ia->first;
11095                           vector<int> vnodes;
11096                           vector<int> vdom;
11097                           for (map<double, int>::iterator ib = sortedDom.begin(); ib != sortedDom.end(); ++ib)
11098                             {
11099                               vdom.push_back(ib->second);
11100                               //MESSAGE("  ordered domain " << ib->second << "  angle " << ib->first);
11101                             }
11102                           for (int ino = 0; ino < nbNodes; ino++)
11103                             vnodes.push_back(nodes[ino]);
11104                           edgesMultiDomains[vnodes] = vdom; // nodes vector --> ordered domains
11105                         }
11106                     }
11107                 }
11108             }
11109         }
11110     }
11111
11112   // --- iterate on shared faces (volumes to modify, face to extrude)
11113   //     get node id's of the face (id SMDS = id VTK)
11114   //     create flat element with old and new nodes if requested
11115
11116   // --- new quad nodes on flat quad elements: oldId --> ((domain1 X domain2) --> newId)
11117   //     (domain1 X domain2) = domain1 + MAXINT*domain2
11118
11119   std::map<int, std::map<long,int> > nodeQuadDomains;
11120   std::map<std::string, SMESH_Group*> mapOfJunctionGroups;
11121
11122   if (createJointElems)
11123     {
11124       itface = faceDomains.begin();
11125       for (; itface != faceDomains.end(); ++itface)
11126         {
11127           DownIdType face = itface->first;
11128           std::set<int> oldNodes;
11129           std::set<int>::iterator itn;
11130           oldNodes.clear();
11131           grid->GetNodeIds(oldNodes, face.cellId, face.cellType);
11132
11133           std::map<int, int> domvol = itface->second;
11134           std::map<int, int>::iterator itdom = domvol.begin();
11135           int dom1 = itdom->first;
11136           int vtkVolId = itdom->second;
11137           itdom++;
11138           int dom2 = itdom->first;
11139           SMDS_MeshVolume *vol = grid->extrudeVolumeFromFace(vtkVolId, dom1, dom2, oldNodes, nodeDomains,
11140                                                              nodeQuadDomains);
11141           stringstream grpname;
11142           grpname << "j_";
11143           if (dom1 < dom2)
11144             grpname << dom1 << "_" << dom2;
11145           else
11146             grpname << dom2 << "_" << dom1;
11147           int idg;
11148           string namegrp = grpname.str();
11149           if (!mapOfJunctionGroups.count(namegrp))
11150             mapOfJunctionGroups[namegrp] = this->myMesh->AddGroup(SMDSAbs_Volume, namegrp.c_str(), idg);
11151           SMESHDS_Group *sgrp = dynamic_cast<SMESHDS_Group*>(mapOfJunctionGroups[namegrp]->GetGroupDS());
11152           if (sgrp)
11153             sgrp->Add(vol->GetID());
11154         }
11155     }
11156
11157   // --- create volumes on multiple domain intersection if requested
11158   //     iterate on edgesMultiDomains
11159
11160   if (createJointElems)
11161     {
11162       std::map<std::vector<int>, std::vector<int> >::iterator ite = edgesMultiDomains.begin();
11163       for (; ite != edgesMultiDomains.end(); ++ite)
11164         {
11165           vector<int> nodes = ite->first;
11166           vector<int> orderDom = ite->second;
11167           vector<vtkIdType> orderedNodes;
11168           if (nodes.size() == 2)
11169             {
11170               //MESSAGE(" use edgesMultiDomains " << nodes[0] << " " << nodes[1]);
11171               for (int ino=0; ino < nodes.size(); ino++)
11172                 if (orderDom.size() == 3)
11173                   for (int idom = 0; idom <orderDom.size(); idom++)
11174                     orderedNodes.push_back( nodeDomains[nodes[ino]][orderDom[idom]] );
11175                 else
11176                   for (int idom = orderDom.size()-1; idom >=0; idom--)
11177                     orderedNodes.push_back( nodeDomains[nodes[ino]][orderDom[idom]] );
11178               SMDS_MeshVolume* vol = this->GetMeshDS()->AddVolumeFromVtkIds(orderedNodes);
11179
11180               stringstream grpname;
11181               grpname << "mj_";
11182               grpname << 0 << "_" << 0;
11183               int idg;
11184               string namegrp = grpname.str();
11185               if (!mapOfJunctionGroups.count(namegrp))
11186                 mapOfJunctionGroups[namegrp] = this->myMesh->AddGroup(SMDSAbs_Volume, namegrp.c_str(), idg);
11187               SMESHDS_Group *sgrp = dynamic_cast<SMESHDS_Group*>(mapOfJunctionGroups[namegrp]->GetGroupDS());
11188               if (sgrp)
11189                 sgrp->Add(vol->GetID());
11190             }
11191           else
11192             {
11193               //MESSAGE("Quadratic multiple joints not implemented");
11194               // TODO quadratic nodes
11195             }
11196         }
11197     }
11198
11199   // --- list the explicit faces and edges of the mesh that need to be modified,
11200   //     i.e. faces and edges built with one or more duplicated nodes.
11201   //     associate these faces or edges to their corresponding domain.
11202   //     only the first domain found is kept when a face or edge is shared
11203
11204   std::map<DownIdType, std::map<int,int>, DownIdCompare> faceOrEdgeDom; // cellToModify --> (id domain --> id cell)
11205   std::map<int,int> feDom; // vtk id of cell to modify --> id domain
11206   faceOrEdgeDom.clear();
11207   feDom.clear();
11208
11209   for (int idomain = 0; idomain < theElems.size(); idomain++)
11210     {
11211       std::map<int, std::map<int, int> >::const_iterator itnod = nodeDomains.begin();
11212       for (; itnod != nodeDomains.end(); ++itnod)
11213         {
11214           int oldId = itnod->first;
11215           //MESSAGE("     node " << oldId);
11216           vtkCellLinks::Link l = grid->GetCellLinks()->GetLink(oldId);
11217           for (int i = 0; i < l.ncells; i++)
11218             {
11219               int vtkId = l.cells[i];
11220               int vtkType = grid->GetCellType(vtkId);
11221               int downId = grid->CellIdToDownId(vtkId);
11222               if (downId < 0)
11223                 continue; // new cells: not to be modified
11224               DownIdType aCell(downId, vtkType);
11225               int volParents[1000];
11226               int nbvol = grid->GetParentVolumes(volParents, vtkId);
11227               for (int j = 0; j < nbvol; j++)
11228                 if (celldom.count(volParents[j]) && (celldom[volParents[j]] == idomain))
11229                   if (!feDom.count(vtkId))
11230                     {
11231                       feDom[vtkId] = idomain;
11232                       faceOrEdgeDom[aCell] = emptyMap;
11233                       faceOrEdgeDom[aCell][idomain] = vtkId; // affect face or edge to the first domain only
11234                       //MESSAGE("affect cell " << this->GetMeshDS()->fromVtkToSmds(vtkId) << " domain " << idomain
11235                       //        << " type " << vtkType << " downId " << downId);
11236                     }
11237             }
11238         }
11239     }
11240
11241   // --- iterate on shared faces (volumes to modify, face to extrude)
11242   //     get node id's of the face
11243   //     replace old nodes by new nodes in volumes, and update inverse connectivity
11244
11245   std::map<DownIdType, std::map<int,int>, DownIdCompare>* maps[3] = {&faceDomains, &cellDomains, &faceOrEdgeDom};
11246   for (int m=0; m<3; m++)
11247     {
11248       std::map<DownIdType, std::map<int,int>, DownIdCompare>* amap = maps[m];
11249       itface = (*amap).begin();
11250       for (; itface != (*amap).end(); ++itface)
11251         {
11252           DownIdType face = itface->first;
11253           std::set<int> oldNodes;
11254           std::set<int>::iterator itn;
11255           oldNodes.clear();
11256           grid->GetNodeIds(oldNodes, face.cellId, face.cellType);
11257           //MESSAGE("examine cell, downId " << face.cellId << " type " << int(face.cellType));
11258           std::map<int, int> localClonedNodeIds;
11259
11260           std::map<int, int> domvol = itface->second;
11261           std::map<int, int>::iterator itdom = domvol.begin();
11262           for (; itdom != domvol.end(); ++itdom)
11263             {
11264               int idom = itdom->first;
11265               int vtkVolId = itdom->second;
11266               //MESSAGE("modify nodes of cell " << this->GetMeshDS()->fromVtkToSmds(vtkVolId) << " domain " << idom);
11267               localClonedNodeIds.clear();
11268               for (itn = oldNodes.begin(); itn != oldNodes.end(); ++itn)
11269                 {
11270                   int oldId = *itn;
11271                   if (nodeDomains[oldId].count(idom))
11272                     {
11273                       localClonedNodeIds[oldId] = nodeDomains[oldId][idom];
11274                       //MESSAGE("     node " << oldId << " --> " << localClonedNodeIds[oldId]);
11275                     }
11276                 }
11277               meshDS->ModifyCellNodes(vtkVolId, localClonedNodeIds);
11278             }
11279         }
11280     }
11281
11282   meshDS->CleanDownWardConnectivity(); // Mesh has been modified, downward connectivity is no more usable, free memory
11283   grid->BuildLinks();
11284
11285   CHRONOSTOP(50);
11286   counters::stats();
11287   return true;
11288 }
11289
11290 /*!
11291  * \brief Double nodes on some external faces and create flat elements.
11292  * Flat elements are mainly used by some types of mechanic calculations.
11293  *
11294  * Each group of the list must be constituted of faces.
11295  * Triangles are transformed in prisms, and quadrangles in hexahedrons.
11296  * @param theElems - list of groups of faces, where a group of faces is a set of
11297  * SMDS_MeshElements sorted by Id.
11298  * @return TRUE if operation has been completed successfully, FALSE otherwise
11299  */
11300 bool SMESH_MeshEditor::CreateFlatElementsOnFacesGroups(const std::vector<TIDSortedElemSet>& theElems)
11301 {
11302   MESSAGE("-------------------------------------------------");
11303   MESSAGE("SMESH_MeshEditor::CreateFlatElementsOnFacesGroups");
11304   MESSAGE("-------------------------------------------------");
11305
11306   SMESHDS_Mesh *meshDS = this->myMesh->GetMeshDS();
11307
11308   // --- For each group of faces
11309   //     duplicate the nodes, create a flat element based on the face
11310   //     replace the nodes of the faces by their clones
11311
11312   std::map<const SMDS_MeshNode*, const SMDS_MeshNode*> clonedNodes;
11313   std::map<const SMDS_MeshNode*, const SMDS_MeshNode*> intermediateNodes;
11314   clonedNodes.clear();
11315   intermediateNodes.clear();
11316   std::map<std::string, SMESH_Group*> mapOfJunctionGroups;
11317   mapOfJunctionGroups.clear();
11318
11319   for (int idom = 0; idom < theElems.size(); idom++)
11320     {
11321       const TIDSortedElemSet& domain = theElems[idom];
11322       TIDSortedElemSet::const_iterator elemItr = domain.begin();
11323       for (; elemItr != domain.end(); ++elemItr)
11324         {
11325           SMDS_MeshElement* anElem = (SMDS_MeshElement*) *elemItr;
11326           SMDS_MeshFace* aFace = dynamic_cast<SMDS_MeshFace*> (anElem);
11327           if (!aFace)
11328             continue;
11329           // MESSAGE("aFace=" << aFace->GetID());
11330           bool isQuad = aFace->IsQuadratic();
11331           vector<const SMDS_MeshNode*> ln0, ln1, ln2, ln3, ln4;
11332
11333           // --- clone the nodes, create intermediate nodes for non medium nodes of a quad face
11334
11335           SMDS_ElemIteratorPtr nodeIt = aFace->nodesIterator();
11336           while (nodeIt->more())
11337             {
11338               const SMDS_MeshNode* node = static_cast<const SMDS_MeshNode*> (nodeIt->next());
11339               bool isMedium = isQuad && (aFace->IsMediumNode(node));
11340               if (isMedium)
11341                 ln2.push_back(node);
11342               else
11343                 ln0.push_back(node);
11344
11345               const SMDS_MeshNode* clone = 0;
11346               if (!clonedNodes.count(node))
11347                 {
11348                   clone = meshDS->AddNode(node->X(), node->Y(), node->Z());
11349                   clonedNodes[node] = clone;
11350                 }
11351               else
11352                 clone = clonedNodes[node];
11353
11354               if (isMedium)
11355                 ln3.push_back(clone);
11356               else
11357                 ln1.push_back(clone);
11358
11359               const SMDS_MeshNode* inter = 0;
11360               if (isQuad && (!isMedium))
11361                 {
11362                   if (!intermediateNodes.count(node))
11363                     {
11364                       inter = meshDS->AddNode(node->X(), node->Y(), node->Z());
11365                       intermediateNodes[node] = inter;
11366                     }
11367                   else
11368                     inter = intermediateNodes[node];
11369                   ln4.push_back(inter);
11370                 }
11371             }
11372
11373           // --- extrude the face
11374
11375           vector<const SMDS_MeshNode*> ln;
11376           SMDS_MeshVolume* vol = 0;
11377           vtkIdType aType = aFace->GetVtkType();
11378           switch (aType)
11379           {
11380             case VTK_TRIANGLE:
11381               vol = meshDS->AddVolume(ln0[2], ln0[1], ln0[0], ln1[2], ln1[1], ln1[0]);
11382               // MESSAGE("vol prism " << vol->GetID());
11383               ln.push_back(ln1[0]);
11384               ln.push_back(ln1[1]);
11385               ln.push_back(ln1[2]);
11386               break;
11387             case VTK_QUAD:
11388               vol = meshDS->AddVolume(ln0[3], ln0[2], ln0[1], ln0[0], ln1[3], ln1[2], ln1[1], ln1[0]);
11389               // MESSAGE("vol hexa " << vol->GetID());
11390               ln.push_back(ln1[0]);
11391               ln.push_back(ln1[1]);
11392               ln.push_back(ln1[2]);
11393               ln.push_back(ln1[3]);
11394               break;
11395             case VTK_QUADRATIC_TRIANGLE:
11396               vol = meshDS->AddVolume(ln1[0], ln1[1], ln1[2], ln0[0], ln0[1], ln0[2], ln3[0], ln3[1], ln3[2],
11397                                       ln2[0], ln2[1], ln2[2], ln4[0], ln4[1], ln4[2]);
11398               // MESSAGE("vol quad prism " << vol->GetID());
11399               ln.push_back(ln1[0]);
11400               ln.push_back(ln1[1]);
11401               ln.push_back(ln1[2]);
11402               ln.push_back(ln3[0]);
11403               ln.push_back(ln3[1]);
11404               ln.push_back(ln3[2]);
11405               break;
11406             case VTK_QUADRATIC_QUAD:
11407 //              vol = meshDS->AddVolume(ln0[0], ln0[1], ln0[2], ln0[3], ln1[0], ln1[1], ln1[2], ln1[3],
11408 //                                      ln2[0], ln2[1], ln2[2], ln2[3], ln3[0], ln3[1], ln3[2], ln3[3],
11409 //                                      ln4[0], ln4[1], ln4[2], ln4[3]);
11410               vol = meshDS->AddVolume(ln1[0], ln1[1], ln1[2], ln1[3], ln0[0], ln0[1], ln0[2], ln0[3],
11411                                       ln3[0], ln3[1], ln3[2], ln3[3], ln2[0], ln2[1], ln2[2], ln2[3],
11412                                       ln4[0], ln4[1], ln4[2], ln4[3]);
11413               // MESSAGE("vol quad hexa " << vol->GetID());
11414               ln.push_back(ln1[0]);
11415               ln.push_back(ln1[1]);
11416               ln.push_back(ln1[2]);
11417               ln.push_back(ln1[3]);
11418               ln.push_back(ln3[0]);
11419               ln.push_back(ln3[1]);
11420               ln.push_back(ln3[2]);
11421               ln.push_back(ln3[3]);
11422               break;
11423             case VTK_POLYGON:
11424               break;
11425             default:
11426               break;
11427           }
11428
11429           if (vol)
11430             {
11431               stringstream grpname;
11432               grpname << "jf_";
11433               grpname << idom;
11434               int idg;
11435               string namegrp = grpname.str();
11436               if (!mapOfJunctionGroups.count(namegrp))
11437                 mapOfJunctionGroups[namegrp] = this->myMesh->AddGroup(SMDSAbs_Volume, namegrp.c_str(), idg);
11438               SMESHDS_Group *sgrp = dynamic_cast<SMESHDS_Group*>(mapOfJunctionGroups[namegrp]->GetGroupDS());
11439               if (sgrp)
11440                 sgrp->Add(vol->GetID());
11441             }
11442
11443           // --- modify the face
11444
11445           aFace->ChangeNodes(&ln[0], ln.size());
11446         }
11447     }
11448   return true;
11449 }
11450
11451 //================================================================================
11452 /*!
11453  * \brief Generates skin mesh (containing 2D cells) from 3D mesh
11454  * The created 2D mesh elements based on nodes of free faces of boundary volumes
11455  * \return TRUE if operation has been completed successfully, FALSE otherwise
11456  */
11457 //================================================================================
11458
11459 bool SMESH_MeshEditor::Make2DMeshFrom3D()
11460 {
11461   // iterates on volume elements and detect all free faces on them
11462   SMESHDS_Mesh* aMesh = GetMeshDS();
11463   if (!aMesh)
11464     return false;
11465   //bool res = false;
11466   int nbFree = 0, nbExisted = 0, nbCreated = 0;
11467   SMDS_VolumeIteratorPtr vIt = aMesh->volumesIterator();
11468   while(vIt->more())
11469   {
11470     const SMDS_MeshVolume* volume = vIt->next();
11471     SMDS_VolumeTool vTool( volume );
11472     vTool.SetExternalNormal();
11473     const bool isPoly = volume->IsPoly();
11474     const bool isQuad = volume->IsQuadratic();
11475     for ( int iface = 0, n = vTool.NbFaces(); iface < n; iface++ )
11476     {
11477       if (!vTool.IsFreeFace(iface))
11478         continue;
11479       nbFree++;
11480       vector<const SMDS_MeshNode *> nodes;
11481       int nbFaceNodes = vTool.NbFaceNodes(iface);
11482       const SMDS_MeshNode** faceNodes = vTool.GetFaceNodes(iface);
11483       int inode = 0;
11484       for ( ; inode < nbFaceNodes; inode += isQuad ? 2 : 1)
11485         nodes.push_back(faceNodes[inode]);
11486       if (isQuad)
11487         for ( inode = 1; inode < nbFaceNodes; inode += 2)
11488           nodes.push_back(faceNodes[inode]);
11489
11490       // add new face based on volume nodes
11491       if (aMesh->FindFace( nodes ) ) {
11492         nbExisted++;
11493         continue; // face already exsist
11494       }
11495       AddElement(nodes, SMDSAbs_Face, isPoly && iface == 1);
11496       nbCreated++;
11497     }
11498   }
11499   return ( nbFree==(nbExisted+nbCreated) );
11500 }
11501
11502 namespace
11503 {
11504   inline const SMDS_MeshNode* getNodeWithSameID(SMESHDS_Mesh* mesh, const SMDS_MeshNode* node)
11505   {
11506     if ( const SMDS_MeshNode* n = mesh->FindNode( node->GetID() ))
11507       return n;
11508     return mesh->AddNodeWithID( node->X(),node->Y(),node->Z(), node->GetID() );
11509   }
11510 }
11511 //================================================================================
11512 /*!
11513  * \brief Creates missing boundary elements
11514  *  \param elements - elements whose boundary is to be checked
11515  *  \param dimension - defines type of boundary elements to create
11516  *  \param group - a group to store created boundary elements in
11517  *  \param targetMesh - a mesh to store created boundary elements in
11518  *  \param toCopyElements - if true, the checked elements will be copied into the targetMesh
11519  *  \param toCopyExistingBondary - if true, not only new but also pre-existing
11520  *                                boundary elements will be copied into the targetMesh
11521  *  \param toAddExistingBondary - if true, not only new but also pre-existing
11522  *                                boundary elements will be added into the new group
11523  *  \param aroundElements - if true, elements will be created on boundary of given
11524  *                          elements else, on boundary of the whole mesh. This
11525  *                          option works for 2D elements only.
11526  * \return nb of added boundary elements
11527  */
11528 //================================================================================
11529
11530 int SMESH_MeshEditor::MakeBoundaryMesh(const TIDSortedElemSet& elements,
11531                                        Bnd_Dimension           dimension,
11532                                        SMESH_Group*            group/*=0*/,
11533                                        SMESH_Mesh*             targetMesh/*=0*/,
11534                                        bool                    toCopyElements/*=false*/,
11535                                        bool                    toCopyExistingBondary/*=false*/,
11536                                        bool                    toAddExistingBondary/*= false*/,
11537                                        bool                    aroundElements/*= false*/)
11538 {
11539   SMDSAbs_ElementType missType = (dimension == BND_2DFROM3D) ? SMDSAbs_Face : SMDSAbs_Edge;
11540   SMDSAbs_ElementType elemType = (dimension == BND_1DFROM2D) ? SMDSAbs_Face : SMDSAbs_Volume;
11541   // hope that all elements are of the same type, do not check them all
11542   if ( !elements.empty() && (*elements.begin())->GetType() != elemType )
11543     throw SALOME_Exception(LOCALIZED("wrong element type"));
11544
11545   if ( aroundElements && elemType == SMDSAbs_Volume )
11546     throw SALOME_Exception(LOCALIZED("wrong element type for aroundElements==true"));
11547
11548   if ( !targetMesh )
11549     toCopyElements = toCopyExistingBondary = false;
11550
11551   SMESH_MeshEditor tgtEditor( targetMesh ? targetMesh : myMesh );
11552   SMESHDS_Mesh* aMesh = GetMeshDS(), *tgtMeshDS = tgtEditor.GetMeshDS();
11553   int nbAddedBnd = 0;
11554
11555   // editor adding present bnd elements and optionally holding elements to add to the group
11556   SMESH_MeshEditor* presentEditor;
11557   SMESH_MeshEditor tgtEditor2( tgtEditor.GetMesh() );
11558   presentEditor = toAddExistingBondary ? &tgtEditor : &tgtEditor2;
11559
11560   SMDS_VolumeTool vTool;
11561   TIDSortedElemSet avoidSet;
11562   const TIDSortedElemSet emptySet, *elemSet = aroundElements ? &elements : &emptySet;
11563   int inode;
11564
11565   typedef vector<const SMDS_MeshNode*> TConnectivity;
11566
11567   SMDS_ElemIteratorPtr eIt;
11568   if (elements.empty())
11569     eIt = aMesh->elementsIterator(elemType);
11570   else
11571     eIt = SMDS_ElemIteratorPtr( new TSetIterator( elements.begin(), elements.end() ));
11572
11573   while (eIt->more())
11574   {
11575     const SMDS_MeshElement* elem = eIt->next();
11576     const int iQuad = elem->IsQuadratic();
11577
11578     // ------------------------------------------------------------------------------------
11579     // 1. For an elem, get present bnd elements and connectivities of missing bnd elements
11580     // ------------------------------------------------------------------------------------
11581     vector<const SMDS_MeshElement*> presentBndElems;
11582     vector<TConnectivity>           missingBndElems;
11583     TConnectivity nodes;
11584     if ( vTool.Set(elem) ) // elem is a volume ------------------------------------------
11585     {
11586       vTool.SetExternalNormal();
11587       for ( int iface = 0, n = vTool.NbFaces(); iface < n; iface++ )
11588       {
11589         if (!vTool.IsFreeFace(iface))
11590           continue;
11591         int nbFaceNodes = vTool.NbFaceNodes(iface);
11592         const SMDS_MeshNode** nn = vTool.GetFaceNodes(iface);
11593         if ( missType == SMDSAbs_Edge ) // boundary edges
11594         {
11595           nodes.resize( 2+iQuad );
11596           for ( int i = 0; i < nbFaceNodes; i += 1+iQuad)
11597           {
11598             for ( int j = 0; j < nodes.size(); ++j )
11599               nodes[j] =nn[i+j];
11600             if ( const SMDS_MeshElement* edge =
11601                  aMesh->FindElement(nodes,SMDSAbs_Edge,/*noMedium=*/0))
11602               presentBndElems.push_back( edge );
11603             else
11604               missingBndElems.push_back( nodes );
11605           }
11606         }
11607         else // boundary face
11608         {
11609           nodes.clear();
11610           for ( inode = 0; inode < nbFaceNodes; inode += 1+iQuad)
11611             nodes.push_back( nn[inode] );
11612           if (iQuad)
11613             for ( inode = 1; inode < nbFaceNodes; inode += 2)
11614               nodes.push_back( nn[inode] );
11615
11616           if (const SMDS_MeshFace * f = aMesh->FindFace( nodes ) )
11617             presentBndElems.push_back( f );
11618           else
11619             missingBndElems.push_back( nodes );
11620         }
11621       }
11622     }
11623     else                     // elem is a face ------------------------------------------
11624     {
11625       avoidSet.clear(), avoidSet.insert( elem );
11626       int nbNodes = elem->NbCornerNodes();
11627       nodes.resize( 2 /*+ iQuad*/);
11628       for ( int i = 0; i < nbNodes; i++ )
11629       {
11630         nodes[0] = elem->GetNode(i);
11631         nodes[1] = elem->GetNode((i+1)%nbNodes);
11632         if ( FindFaceInSet( nodes[0], nodes[1], *elemSet, avoidSet))
11633           continue; // not free link
11634
11635         //if ( iQuad )
11636         //nodes[2] = elem->GetNode( i + nbNodes );
11637         if ( const SMDS_MeshElement* edge =
11638              aMesh->FindElement(nodes,SMDSAbs_Edge,/*noMedium=*/true))
11639           presentBndElems.push_back( edge );
11640         else
11641           missingBndElems.push_back( nodes );
11642       }
11643     }
11644
11645     // ---------------------------------
11646     // 2. Add missing boundary elements
11647     // ---------------------------------
11648     if ( targetMesh != myMesh )
11649       // instead of making a map of nodes in this mesh and targetMesh,
11650       // we create nodes with same IDs. We can renumber them later, if needed
11651       for ( int i = 0; i < missingBndElems.size(); ++i )
11652       {
11653         TConnectivity& srcNodes = missingBndElems[i];
11654         TConnectivity  nodes( srcNodes.size() );
11655         for ( inode = 0; inode < nodes.size(); ++inode )
11656           nodes[inode] = getNodeWithSameID( tgtMeshDS, srcNodes[inode] );
11657         if ( aroundElements && tgtEditor.GetMeshDS()->FindElement( nodes,
11658                                                                    missType,
11659                                                                    /*noMedium=*/true))
11660           continue;
11661         tgtEditor.AddElement(nodes, missType, elem->IsPoly() && nodes.size()/(iQuad+1)>4);
11662         ++nbAddedBnd;
11663       }
11664     else
11665       for ( int i = 0; i < missingBndElems.size(); ++i )
11666       {
11667         TConnectivity& nodes = missingBndElems[i];
11668         if ( aroundElements && tgtEditor.GetMeshDS()->FindElement( nodes,
11669                                                                    missType,
11670                                                                    /*noMedium=*/true))
11671           continue;
11672         tgtEditor.AddElement(nodes, missType, elem->IsPoly() && nodes.size()/(iQuad+1)>4);
11673         ++nbAddedBnd;
11674       }
11675
11676     // ----------------------------------
11677     // 3. Copy present boundary elements
11678     // ----------------------------------
11679     if ( toCopyExistingBondary )
11680       for ( int i = 0 ; i < presentBndElems.size(); ++i )
11681       {
11682         const SMDS_MeshElement* e = presentBndElems[i];
11683         TConnectivity nodes( e->NbNodes() );
11684         for ( inode = 0; inode < nodes.size(); ++inode )
11685           nodes[inode] = getNodeWithSameID( tgtMeshDS, e->GetNode(inode) );
11686         presentEditor->AddElement(nodes, missType, e->IsPoly());
11687       }
11688     else // store present elements to add them to a group
11689       for ( int i = 0 ; i < presentBndElems.size(); ++i )
11690       {
11691         presentEditor->myLastCreatedElems.Append(presentBndElems[i]);
11692       }
11693       
11694   } // loop on given elements
11695
11696   // ---------------------------------------------
11697   // 4. Fill group with boundary elements
11698   // ---------------------------------------------
11699   if ( group )
11700   {
11701     if ( SMESHDS_Group* g = dynamic_cast<SMESHDS_Group*>( group->GetGroupDS() ))
11702       for ( int i = 0; i < tgtEditor.myLastCreatedElems.Size(); ++i )
11703         g->SMDSGroup().Add( tgtEditor.myLastCreatedElems( i+1 ));
11704   }
11705   tgtEditor.myLastCreatedElems.Clear();
11706   tgtEditor2.myLastCreatedElems.Clear();
11707
11708   // -----------------------
11709   // 5. Copy given elements
11710   // -----------------------
11711   if ( toCopyElements && targetMesh != myMesh )
11712   {
11713     if (elements.empty())
11714       eIt = aMesh->elementsIterator(elemType);
11715     else
11716       eIt = SMDS_ElemIteratorPtr( new TSetIterator( elements.begin(), elements.end() ));
11717     while (eIt->more())
11718     {
11719       const SMDS_MeshElement* elem = eIt->next();
11720       TConnectivity nodes( elem->NbNodes() );
11721       for ( inode = 0; inode < nodes.size(); ++inode )
11722         nodes[inode] = getNodeWithSameID( tgtMeshDS, elem->GetNode(inode) );
11723       tgtEditor.AddElement(nodes, elemType, elem->IsPoly());
11724
11725       tgtEditor.myLastCreatedElems.Clear();
11726     }
11727   }
11728   return nbAddedBnd;
11729 }