Salome HOME
0021262: EDF 1867 SMESH: Problem with concatenate that causes failure in an important...
[modules/smesh.git] / src / SMESH / SMESH_MeshEditor.cxx
1 //  Copyright (C) 2007-2010  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       const SMDS_MeshNode* N[6];
1136       if ( aBadRate1 <= aBadRate2 ) {
1137         N[0] = aNodes[0];
1138         N[1] = aNodes[1];
1139         N[2] = aNodes[2];
1140         N[3] = aNodes[4];
1141         N[4] = aNodes[5];
1142         N[5] = newN;
1143         newElem1 = aMesh->AddFace(aNodes[2], aNodes[3], aNodes[0],
1144                                   aNodes[6], aNodes[7], newN );
1145         newElem2 = aMesh->AddFace(aNodes[2], aNodes[0], aNodes[1],
1146                                   newN,      aNodes[4], aNodes[5] );
1147       }
1148       else {
1149         N[0] = aNodes[1];
1150         N[1] = aNodes[2];
1151         N[2] = aNodes[3];
1152         N[3] = aNodes[5];
1153         N[4] = aNodes[6];
1154         N[5] = newN;
1155         newElem1 = aMesh->AddFace(aNodes[3], aNodes[0], aNodes[1],
1156                                   aNodes[7], aNodes[4], newN );
1157         newElem2 = aMesh->AddFace(aNodes[3], aNodes[1], aNodes[2],
1158                                   newN,      aNodes[5], aNodes[6] );
1159       }
1160     } // quadratic case
1161
1162     // care of a new element
1163
1164     myLastCreatedElems.Append(newElem1);
1165     myLastCreatedElems.Append(newElem2);
1166     AddToSameGroups( newElem1, elem, aMesh );
1167     AddToSameGroups( newElem2, elem, aMesh );
1168
1169     // put a new triangle on the same shape
1170     if ( aShapeId )
1171       {
1172         aMesh->SetMeshElementOnShape( newElem1, aShapeId );
1173         aMesh->SetMeshElementOnShape( newElem2, aShapeId );
1174       }
1175     aMesh->RemoveElement( elem );
1176   }
1177   return true;
1178 }
1179
1180 //=======================================================================
1181 //function : BestSplit
1182 //purpose  : Find better diagonal for cutting.
1183 //=======================================================================
1184
1185 int SMESH_MeshEditor::BestSplit (const SMDS_MeshElement*              theQuad,
1186                                  SMESH::Controls::NumericalFunctorPtr theCrit)
1187 {
1188   myLastCreatedElems.Clear();
1189   myLastCreatedNodes.Clear();
1190
1191   if (!theCrit.get())
1192     return -1;
1193
1194   if (!theQuad || theQuad->GetType() != SMDSAbs_Face )
1195     return -1;
1196
1197   if( theQuad->NbNodes()==4 ||
1198       (theQuad->NbNodes()==8 && theQuad->IsQuadratic()) ) {
1199
1200     // retrieve element nodes
1201     const SMDS_MeshNode* aNodes [4];
1202     SMDS_ElemIteratorPtr itN = theQuad->nodesIterator();
1203     int i = 0;
1204     //while (itN->more())
1205     while (i<4) {
1206       aNodes[ i++ ] = static_cast<const SMDS_MeshNode*>( itN->next() );
1207     }
1208     // compare two sets of possible triangles
1209     double aBadRate1, aBadRate2; // to what extent a set is bad
1210     SMDS_FaceOfNodes tr1 ( aNodes[0], aNodes[1], aNodes[2] );
1211     SMDS_FaceOfNodes tr2 ( aNodes[2], aNodes[3], aNodes[0] );
1212     aBadRate1 = getBadRate( &tr1, theCrit ) + getBadRate( &tr2, theCrit );
1213
1214     SMDS_FaceOfNodes tr3 ( aNodes[1], aNodes[2], aNodes[3] );
1215     SMDS_FaceOfNodes tr4 ( aNodes[3], aNodes[0], aNodes[1] );
1216     aBadRate2 = getBadRate( &tr3, theCrit ) + getBadRate( &tr4, theCrit );
1217
1218     if (aBadRate1 <= aBadRate2) // tr1 + tr2 is better
1219       return 1; // diagonal 1-3
1220
1221     return 2; // diagonal 2-4
1222   }
1223   return -1;
1224 }
1225
1226 namespace
1227 {
1228   // Methods of splitting volumes into tetra
1229
1230   const int theHexTo5_1[5*4+1] =
1231     {
1232       0, 1, 2, 5,    0, 4, 5, 7,     0, 2, 3, 7,    2, 5, 6, 7,     0, 5, 2, 7,   -1
1233     };
1234   const int theHexTo5_2[5*4+1] =
1235     {
1236       1, 2, 3, 6,    1, 4, 5, 6,     0, 1, 3, 4,    3, 4, 6, 7,     1, 3, 4, 6,   -1
1237     };
1238   const int* theHexTo5[2] = { theHexTo5_1, theHexTo5_2 };
1239
1240   const int theHexTo6_1[6*4+1] =
1241     {
1242       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
1243     };
1244   const int theHexTo6_2[6*4+1] =
1245     {
1246       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
1247     };
1248   const int theHexTo6_3[6*4+1] =
1249     {
1250       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
1251     };
1252   const int theHexTo6_4[6*4+1] =
1253     {
1254       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
1255     };
1256   const int* theHexTo6[4] = { theHexTo6_1, theHexTo6_2, theHexTo6_3, theHexTo6_4 };
1257
1258   const int thePyraTo2_1[2*4+1] =
1259     {
1260       0, 1, 2, 4,    0, 2, 3, 4,   -1
1261     };
1262   const int thePyraTo2_2[2*4+1] =
1263     {
1264       1, 2, 3, 4,    1, 3, 0, 4,   -1
1265     };
1266   const int* thePyraTo2[2] = { thePyraTo2_1, thePyraTo2_2 };
1267
1268   const int thePentaTo3_1[3*4+1] =
1269     {
1270       0, 1, 2, 3,    1, 3, 4, 2,     2, 3, 4, 5,    -1
1271     };
1272   const int thePentaTo3_2[3*4+1] =
1273     {
1274       1, 2, 0, 4,    2, 4, 5, 0,     0, 4, 5, 3,    -1
1275     };
1276   const int thePentaTo3_3[3*4+1] =
1277     {
1278       2, 0, 1, 5,    0, 5, 3, 1,     1, 5, 3, 4,    -1
1279     };
1280   const int thePentaTo3_4[3*4+1] =
1281     {
1282       0, 1, 2, 3,    1, 3, 4, 5,     2, 3, 1, 5,    -1
1283     };
1284   const int thePentaTo3_5[3*4+1] =
1285     {
1286       1, 2, 0, 4,    2, 4, 5, 3,     0, 4, 2, 3,    -1
1287     };
1288   const int thePentaTo3_6[3*4+1] =
1289     {
1290       2, 0, 1, 5,    0, 5, 3, 4,     1, 5, 0, 4,    -1
1291     };
1292   const int* thePentaTo3[6] = { thePentaTo3_1, thePentaTo3_2, thePentaTo3_3,
1293                                 thePentaTo3_4, thePentaTo3_5, thePentaTo3_6 };
1294
1295   struct TTriangleFacet //!< stores indices of three nodes of tetra facet
1296   {
1297     int _n1, _n2, _n3;
1298     TTriangleFacet(int n1, int n2, int n3): _n1(n1), _n2(n2), _n3(n3) {}
1299     bool contains(int n) const { return ( n == _n1 || n == _n2 || n == _n3 ); }
1300     bool hasAdjacentTetra( const SMDS_MeshElement* elem ) const;
1301   };
1302   struct TSplitMethod
1303   {
1304     int        _nbTetra;
1305     const int* _connectivity; //!< foursomes of tetra connectivy finished by -1
1306     bool       _baryNode;     //!< additional node is to be created at cell barycenter
1307     bool       _ownConn;      //!< to delete _connectivity in destructor
1308     map<int, const SMDS_MeshNode*> _faceBaryNode; //!< map face index to node at BC of face
1309
1310     TSplitMethod( int nbTet=0, const int* conn=0, bool addNode=false)
1311       : _nbTetra(nbTet), _connectivity(conn), _baryNode(addNode), _ownConn(false) {}
1312     ~TSplitMethod() { if ( _ownConn ) delete [] _connectivity; _connectivity = 0; }
1313     bool hasFacet( const TTriangleFacet& facet ) const
1314     {
1315       const int* tetConn = _connectivity;
1316       for ( ; tetConn[0] >= 0; tetConn += 4 )
1317         if (( facet.contains( tetConn[0] ) +
1318               facet.contains( tetConn[1] ) +
1319               facet.contains( tetConn[2] ) +
1320               facet.contains( tetConn[3] )) == 3 )
1321           return true;
1322       return false;
1323     }
1324   };
1325
1326   //=======================================================================
1327   /*!
1328    * \brief return TSplitMethod for the given element
1329    */
1330   //=======================================================================
1331
1332   TSplitMethod getSplitMethod( SMDS_VolumeTool& vol, const int theMethodFlags)
1333   {
1334     const int iQ = vol.Element()->IsQuadratic() ? 2 : 1;
1335
1336     // at HEXA_TO_24 method, each face of volume is split into triangles each based on
1337     // an edge and a face barycenter; tertaherdons are based on triangles and
1338     // a volume barycenter
1339     const bool is24TetMode = ( theMethodFlags == SMESH_MeshEditor::HEXA_TO_24 );
1340
1341     // Find out how adjacent volumes are split
1342
1343     vector < list< TTriangleFacet > > triaSplitsByFace( vol.NbFaces() ); // splits of each side
1344     int hasAdjacentSplits = 0, maxTetConnSize = 0;
1345     for ( int iF = 0; iF < vol.NbFaces(); ++iF )
1346     {
1347       int nbNodes = vol.NbFaceNodes( iF ) / iQ;
1348       maxTetConnSize += 4 * ( nbNodes - (is24TetMode ? 0 : 2));
1349       if ( nbNodes < 4 ) continue;
1350
1351       list< TTriangleFacet >& triaSplits = triaSplitsByFace[ iF ];
1352       const int* nInd = vol.GetFaceNodesIndices( iF );
1353       if ( nbNodes == 4 )
1354       {
1355         TTriangleFacet t012( nInd[0*iQ], nInd[1*iQ], nInd[2*iQ] );
1356         TTriangleFacet t123( nInd[1*iQ], nInd[2*iQ], nInd[3*iQ] );
1357         if      ( t012.hasAdjacentTetra( vol.Element() )) triaSplits.push_back( t012 );
1358         else if ( t123.hasAdjacentTetra( vol.Element() )) triaSplits.push_back( t123 );
1359       }
1360       else
1361       {
1362         int iCom = 0; // common node of triangle faces to split into
1363         for ( int iVar = 0; iVar < nbNodes; ++iVar, ++iCom )
1364         {
1365           TTriangleFacet t012( nInd[ iQ * ( iCom             )],
1366                                nInd[ iQ * ( (iCom+1)%nbNodes )],
1367                                nInd[ iQ * ( (iCom+2)%nbNodes )]);
1368           TTriangleFacet t023( nInd[ iQ * ( iCom             )],
1369                                nInd[ iQ * ( (iCom+2)%nbNodes )],
1370                                nInd[ iQ * ( (iCom+3)%nbNodes )]);
1371           if ( t012.hasAdjacentTetra( vol.Element() ) && t023.hasAdjacentTetra( vol.Element() ))
1372           {
1373             triaSplits.push_back( t012 );
1374             triaSplits.push_back( t023 );
1375             break;
1376           }
1377         }
1378       }
1379       if ( !triaSplits.empty() )
1380         hasAdjacentSplits = true;
1381     }
1382
1383     // Among variants of split method select one compliant with adjacent volumes
1384
1385     TSplitMethod method;
1386     if ( !vol.Element()->IsPoly() && !is24TetMode )
1387     {
1388       int nbVariants = 2, nbTet = 0;
1389       const int** connVariants = 0;
1390       switch ( vol.Element()->GetEntityType() )
1391       {
1392       case SMDSEntity_Hexa:
1393       case SMDSEntity_Quad_Hexa:
1394         if ( theMethodFlags == SMESH_MeshEditor::HEXA_TO_5 )
1395           connVariants = theHexTo5, nbTet = 5;
1396         else
1397           connVariants = theHexTo6, nbTet = 6, nbVariants = 4;
1398         break;
1399       case SMDSEntity_Pyramid:
1400       case SMDSEntity_Quad_Pyramid:
1401         connVariants = thePyraTo2;  nbTet = 2;
1402         break;
1403       case SMDSEntity_Penta:
1404       case SMDSEntity_Quad_Penta:
1405         connVariants = thePentaTo3; nbTet = 3; nbVariants = 6;
1406         break;
1407       default:
1408         nbVariants = 0;
1409       }
1410       for ( int variant = 0; variant < nbVariants && method._nbTetra == 0; ++variant )
1411       {
1412         // check method compliancy with adjacent tetras,
1413         // all found splits must be among facets of tetras described by this method
1414         method = TSplitMethod( nbTet, connVariants[variant] );
1415         if ( hasAdjacentSplits && method._nbTetra > 0 )
1416         {
1417           bool facetCreated = true;
1418           for ( int iF = 0; facetCreated && iF < triaSplitsByFace.size(); ++iF )
1419           {
1420             list< TTriangleFacet >::const_iterator facet = triaSplitsByFace[iF].begin();
1421             for ( ; facetCreated && facet != triaSplitsByFace[iF].end(); ++facet )
1422               facetCreated = method.hasFacet( *facet );
1423           }
1424           if ( !facetCreated )
1425             method = TSplitMethod(0); // incompatible method
1426         }
1427       }
1428     }
1429     if ( method._nbTetra < 1 )
1430     {
1431       // No standard method is applicable, use a generic solution:
1432       // each facet of a volume is split into triangles and
1433       // each of triangles and a volume barycenter form a tetrahedron.
1434
1435       int* connectivity = new int[ maxTetConnSize + 1 ];
1436       method._connectivity = connectivity;
1437       method._ownConn = true;
1438       method._baryNode = true;
1439
1440       int connSize = 0;
1441       int baryCenInd = vol.NbNodes();
1442       for ( int iF = 0; iF < vol.NbFaces(); ++iF )
1443       {
1444         const int nbNodes = vol.NbFaceNodes( iF ) / iQ;
1445         const int*   nInd = vol.GetFaceNodesIndices( iF );
1446         // find common node of triangle facets of tetra to create
1447         int iCommon = 0; // index in linear numeration
1448         const list< TTriangleFacet >& triaSplits = triaSplitsByFace[ iF ];
1449         if ( !triaSplits.empty() )
1450         {
1451           // by found facets
1452           const TTriangleFacet* facet = &triaSplits.front();
1453           for ( ; iCommon < nbNodes-1 ; ++iCommon )
1454             if ( facet->contains( nInd[ iQ * iCommon ]) &&
1455                  facet->contains( nInd[ iQ * ((iCommon+2)%nbNodes) ]))
1456               break;
1457         }
1458         else if ( nbNodes > 3 && !is24TetMode )
1459         {
1460           // find the best method of splitting into triangles by aspect ratio
1461           SMESH::Controls::NumericalFunctorPtr aspectRatio( new SMESH::Controls::AspectRatio);
1462           map< double, int > badness2iCommon;
1463           const SMDS_MeshNode** nodes = vol.GetFaceNodes( iF );
1464           int nbVariants = ( nbNodes == 4 ? 2 : nbNodes );
1465           for ( int iVar = 0; iVar < nbVariants; ++iVar, ++iCommon )
1466             for ( int iLast = iCommon+2; iLast < iCommon+nbNodes; ++iLast )
1467             {
1468               SMDS_FaceOfNodes tria ( nodes[ iQ*( iCommon         )],
1469                                       nodes[ iQ*((iLast-1)%nbNodes)],
1470                                       nodes[ iQ*((iLast  )%nbNodes)]);
1471               double badness = getBadRate( &tria, aspectRatio );
1472               badness2iCommon.insert( make_pair( badness, iCommon ));
1473             }
1474           // use iCommon with lowest badness
1475           iCommon = badness2iCommon.begin()->second;
1476         }
1477         if ( iCommon >= nbNodes )
1478           iCommon = 0; // something wrong
1479
1480         // fill connectivity of tetrahedra based on a current face
1481         int nbTet = nbNodes - 2;
1482         if ( is24TetMode && nbNodes > 3 && triaSplits.empty())
1483         {
1484           method._faceBaryNode.insert( make_pair( iF, (const SMDS_MeshNode*)0 ));
1485           int faceBaryCenInd = baryCenInd + method._faceBaryNode.size();
1486           nbTet = nbNodes;
1487           for ( int i = 0; i < nbTet; ++i )
1488           {
1489             int i1 = i, i2 = (i+1) % nbNodes;
1490             if ( !vol.IsFaceExternal( iF )) swap( i1, i2 );
1491             connectivity[ connSize++ ] = nInd[ iQ * i1 ];
1492             connectivity[ connSize++ ] = nInd[ iQ * i2 ];
1493             connectivity[ connSize++ ] = faceBaryCenInd;
1494             connectivity[ connSize++ ] = baryCenInd;
1495           }
1496         }
1497         else
1498         {
1499           for ( int i = 0; i < nbTet; ++i )
1500           {
1501             int i1 = (iCommon+1+i) % nbNodes, i2 = (iCommon+2+i) % nbNodes;
1502             if ( !vol.IsFaceExternal( iF )) swap( i1, i2 );
1503             connectivity[ connSize++ ] = nInd[ iQ * iCommon ];
1504             connectivity[ connSize++ ] = nInd[ iQ * i1 ];
1505             connectivity[ connSize++ ] = nInd[ iQ * i2 ];
1506             connectivity[ connSize++ ] = baryCenInd;
1507           }
1508         }
1509         method._nbTetra += nbTet;
1510       }
1511       connectivity[ connSize++ ] = -1;
1512     }
1513     return method;
1514   }
1515   //================================================================================
1516   /*!
1517    * \brief Check if there is a tetraherdon adjacent to the given element via this facet
1518    */
1519   //================================================================================
1520
1521   bool TTriangleFacet::hasAdjacentTetra( const SMDS_MeshElement* elem ) const
1522   {
1523     // find the tetrahedron including the three nodes of facet
1524     const SMDS_MeshNode* n1 = elem->GetNode(_n1);
1525     const SMDS_MeshNode* n2 = elem->GetNode(_n2);
1526     const SMDS_MeshNode* n3 = elem->GetNode(_n3);
1527     SMDS_ElemIteratorPtr volIt1 = n1->GetInverseElementIterator(SMDSAbs_Volume);
1528     while ( volIt1->more() )
1529     {
1530       const SMDS_MeshElement* v = volIt1->next();
1531       if ( v->GetEntityType() != ( v->IsQuadratic() ? SMDSEntity_Quad_Tetra : SMDSEntity_Tetra ))
1532         continue;
1533       SMDS_ElemIteratorPtr volIt2 = n2->GetInverseElementIterator(SMDSAbs_Volume);
1534       while ( volIt2->more() )
1535         if ( v != volIt2->next() )
1536           continue;
1537       SMDS_ElemIteratorPtr volIt3 = n3->GetInverseElementIterator(SMDSAbs_Volume);
1538       while ( volIt3->more() )
1539         if ( v == volIt3->next() )
1540           return true;
1541     }
1542     return false;
1543   }
1544
1545   //=======================================================================
1546   /*!
1547    * \brief A key of a face of volume
1548    */
1549   //=======================================================================
1550
1551   struct TVolumeFaceKey: pair< int, pair< int, int> >
1552   {
1553     TVolumeFaceKey( SMDS_VolumeTool& vol, int iF )
1554     {
1555       TIDSortedNodeSet sortedNodes;
1556       const int iQ = vol.Element()->IsQuadratic() ? 2 : 1;
1557       int nbNodes = vol.NbFaceNodes( iF );
1558       const SMDS_MeshNode** fNodes = vol.GetFaceNodes( iF );
1559       for ( int i = 0; i < nbNodes; i += iQ )
1560         sortedNodes.insert( fNodes[i] );
1561       TIDSortedNodeSet::iterator n = sortedNodes.begin();
1562       first = (*(n++))->GetID();
1563       second.first = (*(n++))->GetID();
1564       second.second = (*(n++))->GetID();
1565     }
1566   };
1567 } // namespace
1568
1569 //=======================================================================
1570 //function : SplitVolumesIntoTetra
1571 //purpose  : Split volumic elements into tetrahedra.
1572 //=======================================================================
1573
1574 void SMESH_MeshEditor::SplitVolumesIntoTetra (const TIDSortedElemSet & theElems,
1575                                               const int                theMethodFlags)
1576 {
1577   // std-like iterator on coordinates of nodes of mesh element
1578   typedef SMDS_StdIterator< SMESH_TNodeXYZ, SMDS_ElemIteratorPtr > NXyzIterator;
1579   NXyzIterator xyzEnd;
1580
1581   SMDS_VolumeTool    volTool;
1582   SMESH_MesherHelper helper( *GetMesh());
1583
1584   SMESHDS_SubMesh* subMesh = 0;//GetMeshDS()->MeshElements(1);
1585   SMESHDS_SubMesh* fSubMesh = 0;//subMesh;
1586   
1587   SMESH_SequenceOfElemPtr newNodes, newElems;
1588
1589   // map face of volume to it's baricenrtic node
1590   map< TVolumeFaceKey, const SMDS_MeshNode* > volFace2BaryNode;
1591   double bc[3];
1592
1593   TIDSortedElemSet::const_iterator elem = theElems.begin();
1594   for ( ; elem != theElems.end(); ++elem )
1595   {
1596     SMDSAbs_EntityType geomType = (*elem)->GetEntityType();
1597     if ( geomType <= SMDSEntity_Quad_Tetra )
1598       continue; // tetra or face or ...
1599
1600     if ( !volTool.Set( *elem )) continue; // not volume? strange...
1601
1602     TSplitMethod splitMethod = getSplitMethod( volTool, theMethodFlags );
1603     if ( splitMethod._nbTetra < 1 ) continue;
1604
1605     // find submesh to add new tetras to
1606     if ( !subMesh || !subMesh->Contains( *elem ))
1607     {
1608       int shapeID = FindShape( *elem );
1609       helper.SetSubShape( shapeID ); // helper will add tetras to the found submesh
1610       subMesh = GetMeshDS()->MeshElements( shapeID );
1611     }
1612     int iQ;
1613     if ( (*elem)->IsQuadratic() )
1614     {
1615       iQ = 2;
1616       // add quadratic links to the helper
1617       for ( int iF = 0; iF < volTool.NbFaces(); ++iF )
1618       {
1619         const SMDS_MeshNode** fNodes = volTool.GetFaceNodes( iF );
1620         for ( int iN = 0; iN < volTool.NbFaceNodes( iF ); iN += iQ )
1621           helper.AddTLinkNode( fNodes[iF], fNodes[iF+2], fNodes[iF+1] );
1622       }
1623       helper.SetIsQuadratic( true );
1624     }
1625     else
1626     {
1627       iQ = 1;
1628       helper.SetIsQuadratic( false );
1629     }
1630     vector<const SMDS_MeshNode*> nodes( (*elem)->begin_nodes(), (*elem)->end_nodes() );
1631     if ( splitMethod._baryNode )
1632     {
1633       // make a node at barycenter
1634       volTool.GetBaryCenter( bc[0], bc[1], bc[2] );
1635       SMDS_MeshNode* gcNode = helper.AddNode( bc[0], bc[1], bc[2] );
1636       nodes.push_back( gcNode );
1637       newNodes.Append( gcNode );
1638     }
1639     if ( !splitMethod._faceBaryNode.empty() )
1640     {
1641       // make or find baricentric nodes of faces
1642       map<int, const SMDS_MeshNode*>::iterator iF_n = splitMethod._faceBaryNode.begin();
1643       for ( ; iF_n != splitMethod._faceBaryNode.end(); ++iF_n )
1644       {
1645         map< TVolumeFaceKey, const SMDS_MeshNode* >::iterator f_n =
1646           volFace2BaryNode.insert
1647           ( make_pair( TVolumeFaceKey( volTool,iF_n->first ), (const SMDS_MeshNode*)0) ).first;
1648         if ( !f_n->second )
1649         {
1650           volTool.GetFaceBaryCenter( iF_n->first, bc[0], bc[1], bc[2] );
1651           newNodes.Append( f_n->second = helper.AddNode( bc[0], bc[1], bc[2] ));
1652         }
1653         nodes.push_back( iF_n->second = f_n->second );
1654       }
1655     }
1656
1657     // make tetras
1658     helper.SetElementsOnShape( true );
1659     vector<const SMDS_MeshElement* > tetras( splitMethod._nbTetra ); // splits of a volume
1660     const int* tetConn = splitMethod._connectivity;
1661     for ( int i = 0; i < splitMethod._nbTetra; ++i, tetConn += 4 )
1662       newElems.Append( tetras[ i ] = helper.AddVolume( nodes[ tetConn[0] ],
1663                                                        nodes[ tetConn[1] ],
1664                                                        nodes[ tetConn[2] ],
1665                                                        nodes[ tetConn[3] ]));
1666
1667     ReplaceElemInGroups( *elem, tetras, GetMeshDS() );
1668
1669     // Split faces on sides of the split volume
1670
1671     const SMDS_MeshNode** volNodes = volTool.GetNodes();
1672     for ( int iF = 0; iF < volTool.NbFaces(); ++iF )
1673     {
1674       const int nbNodes = volTool.NbFaceNodes( iF ) / iQ;
1675       if ( nbNodes < 4 ) continue;
1676
1677       // find an existing face
1678       vector<const SMDS_MeshNode*> fNodes( volTool.GetFaceNodes( iF ),
1679                                            volTool.GetFaceNodes( iF ) + nbNodes*iQ );
1680       while ( const SMDS_MeshElement* face = GetMeshDS()->FindFace( fNodes ))
1681       {
1682         // make triangles
1683         helper.SetElementsOnShape( false );
1684         vector< const SMDS_MeshElement* > triangles;
1685
1686         map<int, const SMDS_MeshNode*>::iterator iF_n = splitMethod._faceBaryNode.find(iF);
1687         if ( iF_n != splitMethod._faceBaryNode.end() )
1688         {
1689           for ( int iN = 0; iN < nbNodes*iQ; iN += iQ )
1690           {
1691             const SMDS_MeshNode* n1 = fNodes[iN];
1692             const SMDS_MeshNode *n2 = fNodes[(iN+iQ)%nbNodes*iQ];
1693             const SMDS_MeshNode *n3 = iF_n->second;
1694             if ( !volTool.IsFaceExternal( iF ))
1695               swap( n2, n3 );
1696             triangles.push_back( helper.AddFace( n1,n2,n3 ));
1697           }
1698         }
1699         else
1700         {
1701           // among possible triangles create ones discribed by split method
1702           const int* nInd = volTool.GetFaceNodesIndices( iF );
1703           int nbVariants = ( nbNodes == 4 ? 2 : nbNodes );
1704           int iCom = 0; // common node of triangle faces to split into
1705           list< TTriangleFacet > facets;
1706           for ( int iVar = 0; iVar < nbVariants; ++iVar, ++iCom )
1707           {
1708             TTriangleFacet t012( nInd[ iQ * ( iCom                )],
1709                                  nInd[ iQ * ( (iCom+1)%nbNodes )],
1710                                  nInd[ iQ * ( (iCom+2)%nbNodes )]);
1711             TTriangleFacet t023( nInd[ iQ * ( iCom                )],
1712                                  nInd[ iQ * ( (iCom+2)%nbNodes )],
1713                                  nInd[ iQ * ( (iCom+3)%nbNodes )]);
1714             if ( splitMethod.hasFacet( t012 ) && splitMethod.hasFacet( t023 ))
1715             {
1716               facets.push_back( t012 );
1717               facets.push_back( t023 );
1718               for ( int iLast = iCom+4; iLast < iCom+nbNodes; ++iLast )
1719                 facets.push_back( TTriangleFacet( nInd[ iQ * ( iCom             )],
1720                                                   nInd[ iQ * ((iLast-1)%nbNodes )],
1721                                                   nInd[ iQ * ((iLast  )%nbNodes )]));
1722               break;
1723             }
1724           }
1725           list< TTriangleFacet >::iterator facet = facets.begin();
1726           for ( ; facet != facets.end(); ++facet )
1727           {
1728             if ( !volTool.IsFaceExternal( iF ))
1729               swap( facet->_n2, facet->_n3 );
1730             triangles.push_back( helper.AddFace( volNodes[ facet->_n1 ],
1731                                                  volNodes[ facet->_n2 ],
1732                                                  volNodes[ facet->_n3 ]));
1733           }
1734         }
1735         // find submesh to add new triangles in
1736         if ( !fSubMesh || !fSubMesh->Contains( face ))
1737         {
1738           int shapeID = FindShape( face );
1739           fSubMesh = GetMeshDS()->MeshElements( shapeID );
1740         }
1741         for ( int i = 0; i < triangles.size(); ++i )
1742         {
1743           if ( !triangles[i] ) continue;
1744           if ( fSubMesh )
1745             fSubMesh->AddElement( triangles[i]);
1746           newElems.Append( triangles[i] );
1747         }
1748         ReplaceElemInGroups( face, triangles, GetMeshDS() );
1749         GetMeshDS()->RemoveFreeElement( face, fSubMesh, /*fromGroups=*/false );
1750       }
1751
1752     } // loop on volume faces to split them into triangles
1753
1754     GetMeshDS()->RemoveFreeElement( *elem, subMesh, /*fromGroups=*/false );
1755
1756   } // loop on volumes to split
1757
1758   myLastCreatedNodes = newNodes;
1759   myLastCreatedElems = newElems;
1760 }
1761
1762 //=======================================================================
1763 //function : AddToSameGroups
1764 //purpose  : add elemToAdd to the groups the elemInGroups belongs to
1765 //=======================================================================
1766
1767 void SMESH_MeshEditor::AddToSameGroups (const SMDS_MeshElement* elemToAdd,
1768                                         const SMDS_MeshElement* elemInGroups,
1769                                         SMESHDS_Mesh *          aMesh)
1770 {
1771   const set<SMESHDS_GroupBase*>& groups = aMesh->GetGroups();
1772   if (!groups.empty()) {
1773     set<SMESHDS_GroupBase*>::const_iterator grIt = groups.begin();
1774     for ( ; grIt != groups.end(); grIt++ ) {
1775       SMESHDS_Group* group = dynamic_cast<SMESHDS_Group*>( *grIt );
1776       if ( group && group->Contains( elemInGroups ))
1777         group->SMDSGroup().Add( elemToAdd );
1778     }
1779   }
1780 }
1781
1782
1783 //=======================================================================
1784 //function : RemoveElemFromGroups
1785 //purpose  : Remove removeelem to the groups the elemInGroups belongs to
1786 //=======================================================================
1787 void SMESH_MeshEditor::RemoveElemFromGroups (const SMDS_MeshElement* removeelem,
1788                                              SMESHDS_Mesh *          aMesh)
1789 {
1790   const set<SMESHDS_GroupBase*>& groups = aMesh->GetGroups();
1791   if (!groups.empty())
1792   {
1793     set<SMESHDS_GroupBase*>::const_iterator GrIt = groups.begin();
1794     for (; GrIt != groups.end(); GrIt++)
1795     {
1796       SMESHDS_Group* grp = dynamic_cast<SMESHDS_Group*>(*GrIt);
1797       if (!grp || grp->IsEmpty()) continue;
1798       grp->SMDSGroup().Remove(removeelem);
1799     }
1800   }
1801 }
1802
1803 //================================================================================
1804 /*!
1805  * \brief Replace elemToRm by elemToAdd in the all groups
1806  */
1807 //================================================================================
1808
1809 void SMESH_MeshEditor::ReplaceElemInGroups (const SMDS_MeshElement* elemToRm,
1810                                             const SMDS_MeshElement* elemToAdd,
1811                                             SMESHDS_Mesh *          aMesh)
1812 {
1813   const set<SMESHDS_GroupBase*>& groups = aMesh->GetGroups();
1814   if (!groups.empty()) {
1815     set<SMESHDS_GroupBase*>::const_iterator grIt = groups.begin();
1816     for ( ; grIt != groups.end(); grIt++ ) {
1817       SMESHDS_Group* group = dynamic_cast<SMESHDS_Group*>( *grIt );
1818       if ( group && group->SMDSGroup().Remove( elemToRm ) && elemToAdd )
1819         group->SMDSGroup().Add( elemToAdd );
1820     }
1821   }
1822 }
1823
1824 //================================================================================
1825 /*!
1826  * \brief Replace elemToRm by elemToAdd in the all groups
1827  */
1828 //================================================================================
1829
1830 void SMESH_MeshEditor::ReplaceElemInGroups (const SMDS_MeshElement*                elemToRm,
1831                                             const vector<const SMDS_MeshElement*>& elemToAdd,
1832                                             SMESHDS_Mesh *                         aMesh)
1833 {
1834   const set<SMESHDS_GroupBase*>& groups = aMesh->GetGroups();
1835   if (!groups.empty())
1836   {
1837     set<SMESHDS_GroupBase*>::const_iterator grIt = groups.begin();
1838     for ( ; grIt != groups.end(); grIt++ ) {
1839       SMESHDS_Group* group = dynamic_cast<SMESHDS_Group*>( *grIt );
1840       if ( group && group->SMDSGroup().Remove( elemToRm ) )
1841         for ( int i = 0; i < elemToAdd.size(); ++i )
1842           group->SMDSGroup().Add( elemToAdd[ i ] );
1843     }
1844   }
1845 }
1846
1847 //=======================================================================
1848 //function : QuadToTri
1849 //purpose  : Cut quadrangles into triangles.
1850 //           theCrit is used to select a diagonal to cut
1851 //=======================================================================
1852
1853 bool SMESH_MeshEditor::QuadToTri (TIDSortedElemSet & theElems,
1854                                   const bool         the13Diag)
1855 {
1856   myLastCreatedElems.Clear();
1857   myLastCreatedNodes.Clear();
1858
1859   MESSAGE( "::QuadToTri()" );
1860
1861   SMESHDS_Mesh * aMesh = GetMeshDS();
1862
1863   Handle(Geom_Surface) surface;
1864   SMESH_MesherHelper   helper( *GetMesh() );
1865
1866   TIDSortedElemSet::iterator itElem;
1867   for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
1868     const SMDS_MeshElement* elem = *itElem;
1869     if ( !elem || elem->GetType() != SMDSAbs_Face )
1870       continue;
1871     bool isquad = elem->NbNodes()==4 || elem->NbNodes()==8;
1872     if(!isquad) continue;
1873
1874     if(elem->NbNodes()==4) {
1875       // retrieve element nodes
1876       const SMDS_MeshNode* aNodes [4];
1877       SMDS_ElemIteratorPtr itN = elem->nodesIterator();
1878       int i = 0;
1879       while ( itN->more() )
1880         aNodes[ i++ ] = static_cast<const SMDS_MeshNode*>( itN->next() );
1881
1882       int aShapeId = FindShape( elem );
1883       const SMDS_MeshElement* newElem1 = 0;
1884       const SMDS_MeshElement* newElem2 = 0;
1885       if ( the13Diag ) {
1886         newElem1 = aMesh->AddFace( aNodes[2], aNodes[0], aNodes[1] );
1887         newElem2 = aMesh->AddFace( aNodes[2], aNodes[3], aNodes[0] );
1888       }
1889       else {
1890         newElem1 = aMesh->AddFace( aNodes[3], aNodes[0], aNodes[1] );
1891         newElem2 = aMesh->AddFace( aNodes[3], aNodes[1], aNodes[2] );
1892       }
1893       myLastCreatedElems.Append(newElem1);
1894       myLastCreatedElems.Append(newElem2);
1895       // put a new triangle on the same shape and add to the same groups
1896       if ( aShapeId )
1897         {
1898           aMesh->SetMeshElementOnShape( newElem1, aShapeId );
1899           aMesh->SetMeshElementOnShape( newElem2, aShapeId );
1900         }
1901       AddToSameGroups( newElem1, elem, aMesh );
1902       AddToSameGroups( newElem2, elem, aMesh );
1903       //aMesh->RemoveFreeElement(elem, aMesh->MeshElements(aShapeId), true);
1904       aMesh->RemoveElement( elem );
1905     }
1906
1907     // Quadratic quadrangle
1908
1909     if( elem->NbNodes()==8 && elem->IsQuadratic() ) {
1910
1911       // get surface elem is on
1912       int aShapeId = FindShape( elem );
1913       if ( aShapeId != helper.GetSubShapeID() ) {
1914         surface.Nullify();
1915         TopoDS_Shape shape;
1916         if ( aShapeId > 0 )
1917           shape = aMesh->IndexToShape( aShapeId );
1918         if ( !shape.IsNull() && shape.ShapeType() == TopAbs_FACE ) {
1919           TopoDS_Face face = TopoDS::Face( shape );
1920           surface = BRep_Tool::Surface( face );
1921           if ( !surface.IsNull() )
1922             helper.SetSubShape( shape );
1923         }
1924       }
1925
1926       const SMDS_MeshNode* aNodes [8];
1927       const SMDS_MeshNode* inFaceNode = 0;
1928       SMDS_ElemIteratorPtr itN = elem->nodesIterator();
1929       int i = 0;
1930       while ( itN->more() ) {
1931         aNodes[ i++ ] = static_cast<const SMDS_MeshNode*>( itN->next() );
1932         if ( !inFaceNode && helper.GetNodeUVneedInFaceNode() &&
1933              aNodes[ i-1 ]->GetPosition()->GetTypeOfPosition() == SMDS_TOP_FACE )
1934         {
1935           inFaceNode = aNodes[ i-1 ];
1936         }
1937       }
1938
1939       // find middle point for (0,1,2,3)
1940       // and create a node in this point;
1941       gp_XYZ p( 0,0,0 );
1942       if ( surface.IsNull() ) {
1943         for(i=0; i<4; i++)
1944           p += gp_XYZ(aNodes[i]->X(), aNodes[i]->Y(), aNodes[i]->Z() );
1945         p /= 4;
1946       }
1947       else {
1948         TopoDS_Face geomFace = TopoDS::Face( helper.GetSubShape() );
1949         gp_XY uv( 0,0 );
1950         for(i=0; i<4; i++)
1951           uv += helper.GetNodeUV( geomFace, aNodes[i], inFaceNode );
1952         uv /= 4.;
1953         p = surface->Value( uv.X(), uv.Y() ).XYZ();
1954       }
1955       const SMDS_MeshNode* newN = aMesh->AddNode( p.X(), p.Y(), p.Z() );
1956       myLastCreatedNodes.Append(newN);
1957
1958       // create a new element
1959       const SMDS_MeshElement* newElem1 = 0;
1960       const SMDS_MeshElement* newElem2 = 0;
1961       const SMDS_MeshNode* N[6];
1962       if ( the13Diag ) {
1963         N[0] = aNodes[0];
1964         N[1] = aNodes[1];
1965         N[2] = aNodes[2];
1966         N[3] = aNodes[4];
1967         N[4] = aNodes[5];
1968         N[5] = newN;
1969         newElem1 = aMesh->AddFace(aNodes[2], aNodes[3], aNodes[0],
1970                                   aNodes[6], aNodes[7], newN );
1971         newElem2 = aMesh->AddFace(aNodes[2], aNodes[0], aNodes[1],
1972                                   newN,      aNodes[4], aNodes[5] );
1973       }
1974       else {
1975         N[0] = aNodes[1];
1976         N[1] = aNodes[2];
1977         N[2] = aNodes[3];
1978         N[3] = aNodes[5];
1979         N[4] = aNodes[6];
1980         N[5] = newN;
1981         newElem1 = aMesh->AddFace(aNodes[3], aNodes[0], aNodes[1],
1982                                   aNodes[7], aNodes[4], newN );
1983         newElem2 = aMesh->AddFace(aNodes[3], aNodes[1], aNodes[2],
1984                                   newN,      aNodes[5], aNodes[6] );
1985       }
1986       myLastCreatedElems.Append(newElem1);
1987       myLastCreatedElems.Append(newElem2);
1988       // put a new triangle on the same shape and add to the same groups
1989       if ( aShapeId )
1990         {
1991           aMesh->SetMeshElementOnShape( newElem1, aShapeId );
1992           aMesh->SetMeshElementOnShape( newElem2, aShapeId );
1993         }
1994       AddToSameGroups( newElem1, elem, aMesh );
1995       AddToSameGroups( newElem2, elem, aMesh );
1996       aMesh->RemoveElement( elem );
1997     }
1998   }
1999
2000   return true;
2001 }
2002
2003 //=======================================================================
2004 //function : getAngle
2005 //purpose  :
2006 //=======================================================================
2007
2008 double getAngle(const SMDS_MeshElement * tr1,
2009                 const SMDS_MeshElement * tr2,
2010                 const SMDS_MeshNode *    n1,
2011                 const SMDS_MeshNode *    n2)
2012 {
2013   double angle = 2*PI; // bad angle
2014
2015   // get normals
2016   SMESH::Controls::TSequenceOfXYZ P1, P2;
2017   if ( !SMESH::Controls::NumericalFunctor::GetPoints( tr1, P1 ) ||
2018        !SMESH::Controls::NumericalFunctor::GetPoints( tr2, P2 ))
2019     return angle;
2020   gp_Vec N1,N2;
2021   if(!tr1->IsQuadratic())
2022     N1 = gp_Vec( P1(2) - P1(1) ) ^ gp_Vec( P1(3) - P1(1) );
2023   else
2024     N1 = gp_Vec( P1(3) - P1(1) ) ^ gp_Vec( P1(5) - P1(1) );
2025   if ( N1.SquareMagnitude() <= gp::Resolution() )
2026     return angle;
2027   if(!tr2->IsQuadratic())
2028     N2 = gp_Vec( P2(2) - P2(1) ) ^ gp_Vec( P2(3) - P2(1) );
2029   else
2030     N2 = gp_Vec( P2(3) - P2(1) ) ^ gp_Vec( P2(5) - P2(1) );
2031   if ( N2.SquareMagnitude() <= gp::Resolution() )
2032     return angle;
2033
2034   // find the first diagonal node n1 in the triangles:
2035   // take in account a diagonal link orientation
2036   const SMDS_MeshElement *nFirst[2], *tr[] = { tr1, tr2 };
2037   for ( int t = 0; t < 2; t++ ) {
2038     SMDS_ElemIteratorPtr it = tr[ t ]->nodesIterator();
2039     int i = 0, iDiag = -1;
2040     while ( it->more()) {
2041       const SMDS_MeshElement *n = it->next();
2042       if ( n == n1 || n == n2 ) {
2043         if ( iDiag < 0)
2044           iDiag = i;
2045         else {
2046           if ( i - iDiag == 1 )
2047             nFirst[ t ] = ( n == n1 ? n2 : n1 );
2048           else
2049             nFirst[ t ] = n;
2050           break;
2051         }
2052       }
2053       i++;
2054     }
2055   }
2056   if ( nFirst[ 0 ] == nFirst[ 1 ] )
2057     N2.Reverse();
2058
2059   angle = N1.Angle( N2 );
2060   //SCRUTE( angle );
2061   return angle;
2062 }
2063
2064 // =================================================
2065 // class generating a unique ID for a pair of nodes
2066 // and able to return nodes by that ID
2067 // =================================================
2068 class LinkID_Gen {
2069 public:
2070
2071   LinkID_Gen( const SMESHDS_Mesh* theMesh )
2072     :myMesh( theMesh ), myMaxID( theMesh->MaxNodeID() + 1)
2073   {}
2074
2075   long GetLinkID (const SMDS_MeshNode * n1,
2076                   const SMDS_MeshNode * n2) const
2077   {
2078     return ( Min(n1->GetID(),n2->GetID()) * myMaxID + Max(n1->GetID(),n2->GetID()));
2079   }
2080
2081   bool GetNodes (const long             theLinkID,
2082                  const SMDS_MeshNode* & theNode1,
2083                  const SMDS_MeshNode* & theNode2) const
2084   {
2085     theNode1 = myMesh->FindNode( theLinkID / myMaxID );
2086     if ( !theNode1 ) return false;
2087     theNode2 = myMesh->FindNode( theLinkID % myMaxID );
2088     if ( !theNode2 ) return false;
2089     return true;
2090   }
2091
2092 private:
2093   LinkID_Gen();
2094   const SMESHDS_Mesh* myMesh;
2095   long                myMaxID;
2096 };
2097
2098
2099 //=======================================================================
2100 //function : TriToQuad
2101 //purpose  : Fuse neighbour triangles into quadrangles.
2102 //           theCrit is used to select a neighbour to fuse with.
2103 //           theMaxAngle is a max angle between element normals at which
2104 //           fusion is still performed.
2105 //=======================================================================
2106
2107 bool SMESH_MeshEditor::TriToQuad (TIDSortedElemSet &                   theElems,
2108                                   SMESH::Controls::NumericalFunctorPtr theCrit,
2109                                   const double                         theMaxAngle)
2110 {
2111   myLastCreatedElems.Clear();
2112   myLastCreatedNodes.Clear();
2113
2114   MESSAGE( "::TriToQuad()" );
2115
2116   if ( !theCrit.get() )
2117     return false;
2118
2119   SMESHDS_Mesh * aMesh = GetMeshDS();
2120
2121   // Prepare data for algo: build
2122   // 1. map of elements with their linkIDs
2123   // 2. map of linkIDs with their elements
2124
2125   map< SMESH_TLink, list< const SMDS_MeshElement* > > mapLi_listEl;
2126   map< SMESH_TLink, list< const SMDS_MeshElement* > >::iterator itLE;
2127   map< const SMDS_MeshElement*, set< SMESH_TLink > >  mapEl_setLi;
2128   map< const SMDS_MeshElement*, set< SMESH_TLink > >::iterator itEL;
2129
2130   TIDSortedElemSet::iterator itElem;
2131   for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
2132     const SMDS_MeshElement* elem = *itElem;
2133     if(!elem || elem->GetType() != SMDSAbs_Face ) continue;
2134     bool IsTria = elem->NbNodes()==3 || (elem->NbNodes()==6 && elem->IsQuadratic());
2135     if(!IsTria) continue;
2136
2137     // retrieve element nodes
2138     const SMDS_MeshNode* aNodes [4];
2139     SMDS_ElemIteratorPtr itN = elem->nodesIterator();
2140     int i = 0;
2141     while ( i<3 )
2142       aNodes[ i++ ] = cast2Node( itN->next() );
2143     aNodes[ 3 ] = aNodes[ 0 ];
2144
2145     // fill maps
2146     for ( i = 0; i < 3; i++ ) {
2147       SMESH_TLink link( aNodes[i], aNodes[i+1] );
2148       // check if elements sharing a link can be fused
2149       itLE = mapLi_listEl.find( link );
2150       if ( itLE != mapLi_listEl.end() ) {
2151         if ((*itLE).second.size() > 1 ) // consider only 2 elems adjacent by a link
2152           continue;
2153         const SMDS_MeshElement* elem2 = (*itLE).second.front();
2154         //if ( FindShape( elem ) != FindShape( elem2 ))
2155         //  continue; // do not fuse triangles laying on different shapes
2156         if ( getAngle( elem, elem2, aNodes[i], aNodes[i+1] ) > theMaxAngle )
2157           continue; // avoid making badly shaped quads
2158         (*itLE).second.push_back( elem );
2159       }
2160       else {
2161         mapLi_listEl[ link ].push_back( elem );
2162       }
2163       mapEl_setLi [ elem ].insert( link );
2164     }
2165   }
2166   // Clean the maps from the links shared by a sole element, ie
2167   // links to which only one element is bound in mapLi_listEl
2168
2169   for ( itLE = mapLi_listEl.begin(); itLE != mapLi_listEl.end(); itLE++ ) {
2170     int nbElems = (*itLE).second.size();
2171     if ( nbElems < 2  ) {
2172       const SMDS_MeshElement* elem = (*itLE).second.front();
2173       SMESH_TLink link = (*itLE).first;
2174       mapEl_setLi[ elem ].erase( link );
2175       if ( mapEl_setLi[ elem ].empty() )
2176         mapEl_setLi.erase( elem );
2177     }
2178   }
2179
2180   // Algo: fuse triangles into quadrangles
2181
2182   while ( ! mapEl_setLi.empty() ) {
2183     // Look for the start element:
2184     // the element having the least nb of shared links
2185     const SMDS_MeshElement* startElem = 0;
2186     int minNbLinks = 4;
2187     for ( itEL = mapEl_setLi.begin(); itEL != mapEl_setLi.end(); itEL++ ) {
2188       int nbLinks = (*itEL).second.size();
2189       if ( nbLinks < minNbLinks ) {
2190         startElem = (*itEL).first;
2191         minNbLinks = nbLinks;
2192         if ( minNbLinks == 1 )
2193           break;
2194       }
2195     }
2196
2197     // search elements to fuse starting from startElem or links of elements
2198     // fused earlyer - startLinks
2199     list< SMESH_TLink > startLinks;
2200     while ( startElem || !startLinks.empty() ) {
2201       while ( !startElem && !startLinks.empty() ) {
2202         // Get an element to start, by a link
2203         SMESH_TLink linkId = startLinks.front();
2204         startLinks.pop_front();
2205         itLE = mapLi_listEl.find( linkId );
2206         if ( itLE != mapLi_listEl.end() ) {
2207           list< const SMDS_MeshElement* > & listElem = (*itLE).second;
2208           list< const SMDS_MeshElement* >::iterator itE = listElem.begin();
2209           for ( ; itE != listElem.end() ; itE++ )
2210             if ( mapEl_setLi.find( (*itE) ) != mapEl_setLi.end() )
2211               startElem = (*itE);
2212           mapLi_listEl.erase( itLE );
2213         }
2214       }
2215
2216       if ( startElem ) {
2217         // Get candidates to be fused
2218         const SMDS_MeshElement *tr1 = startElem, *tr2 = 0, *tr3 = 0;
2219         const SMESH_TLink *link12, *link13;
2220         startElem = 0;
2221         ASSERT( mapEl_setLi.find( tr1 ) != mapEl_setLi.end() );
2222         set< SMESH_TLink >& setLi = mapEl_setLi[ tr1 ];
2223         ASSERT( !setLi.empty() );
2224         set< SMESH_TLink >::iterator itLi;
2225         for ( itLi = setLi.begin(); itLi != setLi.end(); itLi++ )
2226         {
2227           const SMESH_TLink & link = (*itLi);
2228           itLE = mapLi_listEl.find( link );
2229           if ( itLE == mapLi_listEl.end() )
2230             continue;
2231
2232           const SMDS_MeshElement* elem = (*itLE).second.front();
2233           if ( elem == tr1 )
2234             elem = (*itLE).second.back();
2235           mapLi_listEl.erase( itLE );
2236           if ( mapEl_setLi.find( elem ) == mapEl_setLi.end())
2237             continue;
2238           if ( tr2 ) {
2239             tr3 = elem;
2240             link13 = &link;
2241           }
2242           else {
2243             tr2 = elem;
2244             link12 = &link;
2245           }
2246
2247           // add other links of elem to list of links to re-start from
2248           set< SMESH_TLink >& links = mapEl_setLi[ elem ];
2249           set< SMESH_TLink >::iterator it;
2250           for ( it = links.begin(); it != links.end(); it++ ) {
2251             const SMESH_TLink& link2 = (*it);
2252             if ( link2 != link )
2253               startLinks.push_back( link2 );
2254           }
2255         }
2256
2257         // Get nodes of possible quadrangles
2258         const SMDS_MeshNode *n12 [4], *n13 [4];
2259         bool Ok12 = false, Ok13 = false;
2260         const SMDS_MeshNode *linkNode1, *linkNode2;
2261         if(tr2) {
2262           linkNode1 = link12->first;
2263           linkNode2 = link12->second;
2264           if ( tr2 && getQuadrangleNodes( n12, linkNode1, linkNode2, tr1, tr2 ))
2265             Ok12 = true;
2266         }
2267         if(tr3) {
2268           linkNode1 = link13->first;
2269           linkNode2 = link13->second;
2270           if ( tr3 && getQuadrangleNodes( n13, linkNode1, linkNode2, tr1, tr3 ))
2271             Ok13 = true;
2272         }
2273
2274         // Choose a pair to fuse
2275         if ( Ok12 && Ok13 ) {
2276           SMDS_FaceOfNodes quad12 ( n12[ 0 ], n12[ 1 ], n12[ 2 ], n12[ 3 ] );
2277           SMDS_FaceOfNodes quad13 ( n13[ 0 ], n13[ 1 ], n13[ 2 ], n13[ 3 ] );
2278           double aBadRate12 = getBadRate( &quad12, theCrit );
2279           double aBadRate13 = getBadRate( &quad13, theCrit );
2280           if (  aBadRate13 < aBadRate12 )
2281             Ok12 = false;
2282           else
2283             Ok13 = false;
2284         }
2285
2286         // Make quadrangles
2287         // and remove fused elems and removed links from the maps
2288         mapEl_setLi.erase( tr1 );
2289         if ( Ok12 ) {
2290           mapEl_setLi.erase( tr2 );
2291           mapLi_listEl.erase( *link12 );
2292           if(tr1->NbNodes()==3) {
2293             const SMDS_MeshElement* newElem = 0;
2294             newElem = aMesh->AddFace(n12[0], n12[1], n12[2], n12[3] );
2295             myLastCreatedElems.Append(newElem);
2296             AddToSameGroups( newElem, tr1, aMesh );
2297             int aShapeId = tr1->getshapeId();
2298             if ( aShapeId )
2299               {
2300                 aMesh->SetMeshElementOnShape( newElem, aShapeId );
2301               }
2302             aMesh->RemoveElement( tr1 );
2303             aMesh->RemoveElement( tr2 );
2304           }
2305           else {
2306             const SMDS_MeshNode* N1 [6];
2307             const SMDS_MeshNode* N2 [6];
2308             GetNodesFromTwoTria(tr1,tr2,N1,N2);
2309             // now we receive following N1 and N2 (using numeration as above image)
2310             // tria1 : (1 2 4 5 9 7)  and  tria2 : (3 4 2 8 9 6)
2311             // i.e. first nodes from both arrays determ new diagonal
2312             const SMDS_MeshNode* aNodes[8];
2313             aNodes[0] = N1[0];
2314             aNodes[1] = N1[1];
2315             aNodes[2] = N2[0];
2316             aNodes[3] = N2[1];
2317             aNodes[4] = N1[3];
2318             aNodes[5] = N2[5];
2319             aNodes[6] = N2[3];
2320             aNodes[7] = N1[5];
2321             const SMDS_MeshElement* newElem = 0;
2322             newElem = aMesh->AddFace(aNodes[0], aNodes[1], aNodes[2], aNodes[3],
2323                                      aNodes[4], aNodes[5], aNodes[6], aNodes[7]);
2324             myLastCreatedElems.Append(newElem);
2325             AddToSameGroups( newElem, tr1, aMesh );
2326             int aShapeId = tr1->getshapeId();
2327             if ( aShapeId )
2328               {
2329                 aMesh->SetMeshElementOnShape( newElem, aShapeId );
2330               }
2331             aMesh->RemoveElement( tr1 );
2332             aMesh->RemoveElement( tr2 );
2333             // remove middle node (9)
2334             GetMeshDS()->RemoveNode( N1[4] );
2335           }
2336         }
2337         else if ( Ok13 ) {
2338           mapEl_setLi.erase( tr3 );
2339           mapLi_listEl.erase( *link13 );
2340           if(tr1->NbNodes()==3) {
2341             const SMDS_MeshElement* newElem = 0;
2342             newElem = aMesh->AddFace(n13[0], n13[1], n13[2], n13[3] );
2343             myLastCreatedElems.Append(newElem);
2344             AddToSameGroups( newElem, tr1, aMesh );
2345             int aShapeId = tr1->getshapeId();
2346             if ( aShapeId )
2347               {
2348                 aMesh->SetMeshElementOnShape( newElem, aShapeId );
2349               }
2350             aMesh->RemoveElement( tr1 );
2351             aMesh->RemoveElement( tr3 );
2352           }
2353           else {
2354             const SMDS_MeshNode* N1 [6];
2355             const SMDS_MeshNode* N2 [6];
2356             GetNodesFromTwoTria(tr1,tr3,N1,N2);
2357             // now we receive following N1 and N2 (using numeration as above image)
2358             // tria1 : (1 2 4 5 9 7)  and  tria2 : (3 4 2 8 9 6)
2359             // i.e. first nodes from both arrays determ new diagonal
2360             const SMDS_MeshNode* aNodes[8];
2361             aNodes[0] = N1[0];
2362             aNodes[1] = N1[1];
2363             aNodes[2] = N2[0];
2364             aNodes[3] = N2[1];
2365             aNodes[4] = N1[3];
2366             aNodes[5] = N2[5];
2367             aNodes[6] = N2[3];
2368             aNodes[7] = N1[5];
2369             const SMDS_MeshElement* newElem = 0;
2370             newElem = aMesh->AddFace(aNodes[0], aNodes[1], aNodes[2], aNodes[3],
2371                                      aNodes[4], aNodes[5], aNodes[6], aNodes[7]);
2372             myLastCreatedElems.Append(newElem);
2373             AddToSameGroups( newElem, tr1, aMesh );
2374             int aShapeId = tr1->getshapeId();
2375             if ( aShapeId )
2376               {
2377                 aMesh->SetMeshElementOnShape( newElem, aShapeId );
2378               }
2379             aMesh->RemoveElement( tr1 );
2380             aMesh->RemoveElement( tr3 );
2381             // remove middle node (9)
2382             GetMeshDS()->RemoveNode( N1[4] );
2383           }
2384         }
2385
2386         // Next element to fuse: the rejected one
2387         if ( tr3 )
2388           startElem = Ok12 ? tr3 : tr2;
2389
2390       } // if ( startElem )
2391     } // while ( startElem || !startLinks.empty() )
2392   } // while ( ! mapEl_setLi.empty() )
2393
2394   return true;
2395 }
2396
2397
2398 /*#define DUMPSO(txt) \
2399 //  cout << txt << endl;
2400 //=============================================================================
2401 //
2402 //
2403 //
2404 //=============================================================================
2405 static void swap( int i1, int i2, int idNodes[], gp_Pnt P[] )
2406 {
2407 if ( i1 == i2 )
2408 return;
2409 int tmp = idNodes[ i1 ];
2410 idNodes[ i1 ] = idNodes[ i2 ];
2411 idNodes[ i2 ] = tmp;
2412 gp_Pnt Ptmp = P[ i1 ];
2413 P[ i1 ] = P[ i2 ];
2414 P[ i2 ] = Ptmp;
2415 DUMPSO( i1 << "(" << idNodes[ i2 ] << ") <-> " << i2 << "(" << idNodes[ i1 ] << ")");
2416 }
2417
2418 //=======================================================================
2419 //function : SortQuadNodes
2420 //purpose  : Set 4 nodes of a quadrangle face in a good order.
2421 //           Swap 1<->2 or 2<->3 nodes and correspondingly return
2422 //           1 or 2 else 0.
2423 //=======================================================================
2424
2425 int SMESH_MeshEditor::SortQuadNodes (const SMDS_Mesh * theMesh,
2426 int               idNodes[] )
2427 {
2428   gp_Pnt P[4];
2429   int i;
2430   for ( i = 0; i < 4; i++ ) {
2431     const SMDS_MeshNode *n = theMesh->FindNode( idNodes[i] );
2432     if ( !n ) return 0;
2433     P[ i ].SetCoord( n->X(), n->Y(), n->Z() );
2434   }
2435
2436   gp_Vec V1(P[0], P[1]);
2437   gp_Vec V2(P[0], P[2]);
2438   gp_Vec V3(P[0], P[3]);
2439
2440   gp_Vec Cross1 = V1 ^ V2;
2441   gp_Vec Cross2 = V2 ^ V3;
2442
2443   i = 0;
2444   if (Cross1.Dot(Cross2) < 0)
2445   {
2446     Cross1 = V2 ^ V1;
2447     Cross2 = V1 ^ V3;
2448
2449     if (Cross1.Dot(Cross2) < 0)
2450       i = 2;
2451     else
2452       i = 1;
2453     swap ( i, i + 1, idNodes, P );
2454
2455     //     for ( int ii = 0; ii < 4; ii++ ) {
2456     //       const SMDS_MeshNode *n = theMesh->FindNode( idNodes[ii] );
2457     //       DUMPSO( ii << "(" << idNodes[ii] <<") : "<<n->X()<<" "<<n->Y()<<" "<<n->Z());
2458     //     }
2459   }
2460   return i;
2461 }
2462
2463 //=======================================================================
2464 //function : SortHexaNodes
2465 //purpose  : Set 8 nodes of a hexahedron in a good order.
2466 //           Return success status
2467 //=======================================================================
2468
2469 bool SMESH_MeshEditor::SortHexaNodes (const SMDS_Mesh * theMesh,
2470                                       int               idNodes[] )
2471 {
2472   gp_Pnt P[8];
2473   int i;
2474   DUMPSO( "INPUT: ========================================");
2475   for ( i = 0; i < 8; i++ ) {
2476     const SMDS_MeshNode *n = theMesh->FindNode( idNodes[i] );
2477     if ( !n ) return false;
2478     P[ i ].SetCoord( n->X(), n->Y(), n->Z() );
2479     DUMPSO( i << "(" << idNodes[i] <<") : "<<n->X()<<" "<<n->Y()<<" "<<n->Z());
2480   }
2481   DUMPSO( "========================================");
2482
2483
2484   set<int> faceNodes;  // ids of bottom face nodes, to be found
2485   set<int> checkedId1; // ids of tried 2-nd nodes
2486   Standard_Real leastDist = DBL_MAX; // dist of the 4-th node from 123 plane
2487   const Standard_Real tol = 1.e-6;   // tolerance to find nodes in plane
2488   int iMin, iLoop1 = 0;
2489
2490   // Loop to try the 2-nd nodes
2491
2492   while ( leastDist > DBL_MIN && ++iLoop1 < 8 )
2493   {
2494     // Find not checked 2-nd node
2495     for ( i = 1; i < 8; i++ )
2496       if ( checkedId1.find( idNodes[i] ) == checkedId1.end() ) {
2497         int id1 = idNodes[i];
2498         swap ( 1, i, idNodes, P );
2499         checkedId1.insert ( id1 );
2500         break;
2501       }
2502
2503     // Find the 3-d node so that 1-2-3 triangle to be on a hexa face,
2504     // ie that all but meybe one (id3 which is on the same face) nodes
2505     // lay on the same side from the triangle plane.
2506
2507     bool manyInPlane = false; // more than 4 nodes lay in plane
2508     int iLoop2 = 0;
2509     while ( ++iLoop2 < 6 ) {
2510
2511       // get 1-2-3 plane coeffs
2512       Standard_Real A, B, C, D;
2513       gp_Vec N = gp_Vec (P[0], P[1]).Crossed( gp_Vec (P[0], P[2]) );
2514       if ( N.SquareMagnitude() > gp::Resolution() )
2515       {
2516         gp_Pln pln ( P[0], N );
2517         pln.Coefficients( A, B, C, D );
2518
2519         // find the node (iMin) closest to pln
2520         Standard_Real dist[ 8 ], minDist = DBL_MAX;
2521         set<int> idInPln;
2522         for ( i = 3; i < 8; i++ ) {
2523           dist[i] = A * P[i].X() + B * P[i].Y() + C * P[i].Z() + D;
2524           if ( fabs( dist[i] ) < minDist ) {
2525             minDist = fabs( dist[i] );
2526             iMin = i;
2527           }
2528           if ( fabs( dist[i] ) <= tol )
2529             idInPln.insert( idNodes[i] );
2530         }
2531
2532         // there should not be more than 4 nodes in bottom plane
2533         if ( idInPln.size() > 1 )
2534         {
2535           DUMPSO( "### idInPln.size() = " << idInPln.size());
2536           // idInPlane does not contain the first 3 nodes
2537           if ( manyInPlane || idInPln.size() == 5)
2538             return false; // all nodes in one plane
2539           manyInPlane = true;
2540
2541           // set the 1-st node to be not in plane
2542           for ( i = 3; i < 8; i++ ) {
2543             if ( idInPln.find( idNodes[ i ] ) == idInPln.end() ) {
2544               DUMPSO( "### Reset 0-th node");
2545               swap( 0, i, idNodes, P );
2546               break;
2547             }
2548           }
2549
2550           // reset to re-check second nodes
2551           leastDist = DBL_MAX;
2552           faceNodes.clear();
2553           checkedId1.clear();
2554           iLoop1 = 0;
2555           break; // from iLoop2;
2556         }
2557
2558         // check that the other 4 nodes are on the same side
2559         bool sameSide = true;
2560         bool isNeg = dist[ iMin == 3 ? 4 : 3 ] <= 0.;
2561         for ( i = 3; sameSide && i < 8; i++ ) {
2562           if ( i != iMin )
2563             sameSide = ( isNeg == dist[i] <= 0.);
2564         }
2565
2566         // keep best solution
2567         if ( sameSide && minDist < leastDist ) {
2568           leastDist = minDist;
2569           faceNodes.clear();
2570           faceNodes.insert( idNodes[ 1 ] );
2571           faceNodes.insert( idNodes[ 2 ] );
2572           faceNodes.insert( idNodes[ iMin ] );
2573           DUMPSO( "loop " << iLoop2 << " id2 " << idNodes[ 1 ] << " id3 " << idNodes[ 2 ]
2574                   << " leastDist = " << leastDist);
2575           if ( leastDist <= DBL_MIN )
2576             break;
2577         }
2578       }
2579
2580       // set next 3-d node to check
2581       int iNext = 2 + iLoop2;
2582       if ( iNext < 8 ) {
2583         DUMPSO( "Try 2-nd");
2584         swap ( 2, iNext, idNodes, P );
2585       }
2586     } // while ( iLoop2 < 6 )
2587   } // iLoop1
2588
2589   if ( faceNodes.empty() ) return false;
2590
2591   // Put the faceNodes in proper places
2592   for ( i = 4; i < 8; i++ ) {
2593     if ( faceNodes.find( idNodes[ i ] ) != faceNodes.end() ) {
2594       // find a place to put
2595       int iTo = 1;
2596       while ( faceNodes.find( idNodes[ iTo ] ) != faceNodes.end() )
2597         iTo++;
2598       DUMPSO( "Set faceNodes");
2599       swap ( iTo, i, idNodes, P );
2600     }
2601   }
2602
2603
2604   // Set nodes of the found bottom face in good order
2605   DUMPSO( " Found bottom face: ");
2606   i = SortQuadNodes( theMesh, idNodes );
2607   if ( i ) {
2608     gp_Pnt Ptmp = P[ i ];
2609     P[ i ] = P[ i+1 ];
2610     P[ i+1 ] = Ptmp;
2611   }
2612   //   else
2613   //     for ( int ii = 0; ii < 4; ii++ ) {
2614   //       const SMDS_MeshNode *n = theMesh->FindNode( idNodes[ii] );
2615   //       DUMPSO( ii << "(" << idNodes[ii] <<") : "<<n->X()<<" "<<n->Y()<<" "<<n->Z());
2616   //    }
2617
2618   // Gravity center of the top and bottom faces
2619   gp_Pnt aGCb = ( P[0].XYZ() + P[1].XYZ() + P[2].XYZ() + P[3].XYZ() ) / 4.;
2620   gp_Pnt aGCt = ( P[4].XYZ() + P[5].XYZ() + P[6].XYZ() + P[7].XYZ() ) / 4.;
2621
2622   // Get direction from the bottom to the top face
2623   gp_Vec upDir ( aGCb, aGCt );
2624   Standard_Real upDirSize = upDir.Magnitude();
2625   if ( upDirSize <= gp::Resolution() ) return false;
2626   upDir / upDirSize;
2627
2628   // Assure that the bottom face normal points up
2629   gp_Vec Nb = gp_Vec (P[0], P[1]).Crossed( gp_Vec (P[0], P[2]) );
2630   Nb += gp_Vec (P[0], P[2]).Crossed( gp_Vec (P[0], P[3]) );
2631   if ( Nb.Dot( upDir ) < 0 ) {
2632     DUMPSO( "Reverse bottom face");
2633     swap( 1, 3, idNodes, P );
2634   }
2635
2636   // Find 5-th node - the one closest to the 1-st among the last 4 nodes.
2637   Standard_Real minDist = DBL_MAX;
2638   for ( i = 4; i < 8; i++ ) {
2639     // projection of P[i] to the plane defined by P[0] and upDir
2640     gp_Pnt Pp = P[i].Translated( upDir * ( upDir.Dot( gp_Vec( P[i], P[0] ))));
2641     Standard_Real sqDist = P[0].SquareDistance( Pp );
2642     if ( sqDist < minDist ) {
2643       minDist = sqDist;
2644       iMin = i;
2645     }
2646   }
2647   DUMPSO( "Set 4-th");
2648   swap ( 4, iMin, idNodes, P );
2649
2650   // Set nodes of the top face in good order
2651   DUMPSO( "Sort top face");
2652   i = SortQuadNodes( theMesh, &idNodes[4] );
2653   if ( i ) {
2654     i += 4;
2655     gp_Pnt Ptmp = P[ i ];
2656     P[ i ] = P[ i+1 ];
2657     P[ i+1 ] = Ptmp;
2658   }
2659
2660   // Assure that direction of the top face normal is from the bottom face
2661   gp_Vec Nt = gp_Vec (P[4], P[5]).Crossed( gp_Vec (P[4], P[6]) );
2662   Nt += gp_Vec (P[4], P[6]).Crossed( gp_Vec (P[4], P[7]) );
2663   if ( Nt.Dot( upDir ) < 0 ) {
2664     DUMPSO( "Reverse top face");
2665     swap( 5, 7, idNodes, P );
2666   }
2667
2668   //   DUMPSO( "OUTPUT: ========================================");
2669   //   for ( i = 0; i < 8; i++ ) {
2670   //     float *p = ugrid->GetPoint(idNodes[i]);
2671   //     DUMPSO( i << "(" << idNodes[i] << ") : " << p[0] << " " << p[1] << " " << p[2]);
2672   //   }
2673
2674   return true;
2675 }*/
2676
2677 //================================================================================
2678 /*!
2679  * \brief Return nodes linked to the given one
2680  * \param theNode - the node
2681  * \param linkedNodes - the found nodes
2682  * \param type - the type of elements to check
2683  *
2684  * Medium nodes are ignored
2685  */
2686 //================================================================================
2687
2688 void SMESH_MeshEditor::GetLinkedNodes( const SMDS_MeshNode* theNode,
2689                                        TIDSortedElemSet &   linkedNodes,
2690                                        SMDSAbs_ElementType  type )
2691 {
2692   SMDS_ElemIteratorPtr elemIt = theNode->GetInverseElementIterator(type);
2693   while ( elemIt->more() )
2694   {
2695     const SMDS_MeshElement* elem = elemIt->next();
2696     if(elem->GetType() == SMDSAbs_0DElement)
2697       continue;
2698     
2699     SMDS_ElemIteratorPtr nodeIt = elem->nodesIterator();
2700     if ( elem->GetType() == SMDSAbs_Volume )
2701     {
2702       SMDS_VolumeTool vol( elem );
2703       while ( nodeIt->more() ) {
2704         const SMDS_MeshNode* n = cast2Node( nodeIt->next() );
2705         if ( theNode != n && vol.IsLinked( theNode, n ))
2706           linkedNodes.insert( n );
2707       }
2708     }
2709     else
2710     {
2711       for ( int i = 0; nodeIt->more(); ++i ) {
2712         const SMDS_MeshNode* n = cast2Node( nodeIt->next() );
2713         if ( n == theNode ) {
2714           int iBefore = i - 1;
2715           int iAfter  = i + 1;
2716           if ( elem->IsQuadratic() ) {
2717             int nb = elem->NbNodes() / 2;
2718             iAfter  = SMESH_MesherHelper::WrapIndex( iAfter, nb );
2719             iBefore = SMESH_MesherHelper::WrapIndex( iBefore, nb );
2720           }
2721           linkedNodes.insert( elem->GetNodeWrap( iAfter ));
2722           linkedNodes.insert( elem->GetNodeWrap( iBefore ));
2723         }
2724       }
2725     }
2726   }
2727 }
2728
2729 //=======================================================================
2730 //function : laplacianSmooth
2731 //purpose  : pulls theNode toward the center of surrounding nodes directly
2732 //           connected to that node along an element edge
2733 //=======================================================================
2734
2735 void laplacianSmooth(const SMDS_MeshNode*                 theNode,
2736                      const Handle(Geom_Surface)&          theSurface,
2737                      map< const SMDS_MeshNode*, gp_XY* >& theUVMap)
2738 {
2739   // find surrounding nodes
2740
2741   TIDSortedElemSet nodeSet;
2742   SMESH_MeshEditor::GetLinkedNodes( theNode, nodeSet, SMDSAbs_Face );
2743
2744   // compute new coodrs
2745
2746   double coord[] = { 0., 0., 0. };
2747   TIDSortedElemSet::iterator nodeSetIt = nodeSet.begin();
2748   for ( ; nodeSetIt != nodeSet.end(); nodeSetIt++ ) {
2749     const SMDS_MeshNode* node = cast2Node(*nodeSetIt);
2750     if ( theSurface.IsNull() ) { // smooth in 3D
2751       coord[0] += node->X();
2752       coord[1] += node->Y();
2753       coord[2] += node->Z();
2754     }
2755     else { // smooth in 2D
2756       ASSERT( theUVMap.find( node ) != theUVMap.end() );
2757       gp_XY* uv = theUVMap[ node ];
2758       coord[0] += uv->X();
2759       coord[1] += uv->Y();
2760     }
2761   }
2762   int nbNodes = nodeSet.size();
2763   if ( !nbNodes )
2764     return;
2765   coord[0] /= nbNodes;
2766   coord[1] /= nbNodes;
2767
2768   if ( !theSurface.IsNull() ) {
2769     ASSERT( theUVMap.find( theNode ) != theUVMap.end() );
2770     theUVMap[ theNode ]->SetCoord( coord[0], coord[1] );
2771     gp_Pnt p3d = theSurface->Value( coord[0], coord[1] );
2772     coord[0] = p3d.X();
2773     coord[1] = p3d.Y();
2774     coord[2] = p3d.Z();
2775   }
2776   else
2777     coord[2] /= nbNodes;
2778
2779   // move node
2780
2781   const_cast< SMDS_MeshNode* >( theNode )->setXYZ(coord[0],coord[1],coord[2]);
2782 }
2783
2784 //=======================================================================
2785 //function : centroidalSmooth
2786 //purpose  : pulls theNode toward the element-area-weighted centroid of the
2787 //           surrounding elements
2788 //=======================================================================
2789
2790 void centroidalSmooth(const SMDS_MeshNode*                 theNode,
2791                       const Handle(Geom_Surface)&          theSurface,
2792                       map< const SMDS_MeshNode*, gp_XY* >& theUVMap)
2793 {
2794   gp_XYZ aNewXYZ(0.,0.,0.);
2795   SMESH::Controls::Area anAreaFunc;
2796   double totalArea = 0.;
2797   int nbElems = 0;
2798
2799   // compute new XYZ
2800
2801   SMDS_ElemIteratorPtr elemIt = theNode->GetInverseElementIterator(SMDSAbs_Face);
2802   while ( elemIt->more() )
2803   {
2804     const SMDS_MeshElement* elem = elemIt->next();
2805     nbElems++;
2806
2807     gp_XYZ elemCenter(0.,0.,0.);
2808     SMESH::Controls::TSequenceOfXYZ aNodePoints;
2809     SMDS_ElemIteratorPtr itN = elem->nodesIterator();
2810     int nn = elem->NbNodes();
2811     if(elem->IsQuadratic()) nn = nn/2;
2812     int i=0;
2813     //while ( itN->more() ) {
2814     while ( i<nn ) {
2815       const SMDS_MeshNode* aNode = static_cast<const SMDS_MeshNode*>( itN->next() );
2816       i++;
2817       gp_XYZ aP( aNode->X(), aNode->Y(), aNode->Z() );
2818       aNodePoints.push_back( aP );
2819       if ( !theSurface.IsNull() ) { // smooth in 2D
2820         ASSERT( theUVMap.find( aNode ) != theUVMap.end() );
2821         gp_XY* uv = theUVMap[ aNode ];
2822         aP.SetCoord( uv->X(), uv->Y(), 0. );
2823       }
2824       elemCenter += aP;
2825     }
2826     double elemArea = anAreaFunc.GetValue( aNodePoints );
2827     totalArea += elemArea;
2828     elemCenter /= nn;
2829     aNewXYZ += elemCenter * elemArea;
2830   }
2831   aNewXYZ /= totalArea;
2832   if ( !theSurface.IsNull() ) {
2833     theUVMap[ theNode ]->SetCoord( aNewXYZ.X(), aNewXYZ.Y() );
2834     aNewXYZ = theSurface->Value( aNewXYZ.X(), aNewXYZ.Y() ).XYZ();
2835   }
2836
2837   // move node
2838
2839   const_cast< SMDS_MeshNode* >( theNode )->setXYZ(aNewXYZ.X(),aNewXYZ.Y(),aNewXYZ.Z());
2840 }
2841
2842 //=======================================================================
2843 //function : getClosestUV
2844 //purpose  : return UV of closest projection
2845 //=======================================================================
2846
2847 static bool getClosestUV (Extrema_GenExtPS& projector,
2848                           const gp_Pnt&     point,
2849                           gp_XY &           result)
2850 {
2851   projector.Perform( point );
2852   if ( projector.IsDone() ) {
2853     double u, v, minVal = DBL_MAX;
2854     for ( int i = projector.NbExt(); i > 0; i-- )
2855       if ( projector.Value( i ) < minVal ) {
2856         minVal = projector.Value( i );
2857         projector.Point( i ).Parameter( u, v );
2858       }
2859     result.SetCoord( u, v );
2860     return true;
2861   }
2862   return false;
2863 }
2864
2865 //=======================================================================
2866 //function : Smooth
2867 //purpose  : Smooth theElements during theNbIterations or until a worst
2868 //           element has aspect ratio <= theTgtAspectRatio.
2869 //           Aspect Ratio varies in range [1.0, inf].
2870 //           If theElements is empty, the whole mesh is smoothed.
2871 //           theFixedNodes contains additionally fixed nodes. Nodes built
2872 //           on edges and boundary nodes are always fixed.
2873 //=======================================================================
2874
2875 void SMESH_MeshEditor::Smooth (TIDSortedElemSet &          theElems,
2876                                set<const SMDS_MeshNode*> & theFixedNodes,
2877                                const SmoothMethod          theSmoothMethod,
2878                                const int                   theNbIterations,
2879                                double                      theTgtAspectRatio,
2880                                const bool                  the2D)
2881 {
2882   myLastCreatedElems.Clear();
2883   myLastCreatedNodes.Clear();
2884
2885   MESSAGE((theSmoothMethod==LAPLACIAN ? "LAPLACIAN" : "CENTROIDAL") << "--::Smooth()");
2886
2887   if ( theTgtAspectRatio < 1.0 )
2888     theTgtAspectRatio = 1.0;
2889
2890   const double disttol = 1.e-16;
2891
2892   SMESH::Controls::AspectRatio aQualityFunc;
2893
2894   SMESHDS_Mesh* aMesh = GetMeshDS();
2895
2896   if ( theElems.empty() ) {
2897     // add all faces to theElems
2898     SMDS_FaceIteratorPtr fIt = aMesh->facesIterator();
2899     while ( fIt->more() ) {
2900       const SMDS_MeshElement* face = fIt->next();
2901       theElems.insert( face );
2902     }
2903   }
2904   // get all face ids theElems are on
2905   set< int > faceIdSet;
2906   TIDSortedElemSet::iterator itElem;
2907   if ( the2D )
2908     for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
2909       int fId = FindShape( *itElem );
2910       // check that corresponding submesh exists and a shape is face
2911       if (fId &&
2912           faceIdSet.find( fId ) == faceIdSet.end() &&
2913           aMesh->MeshElements( fId )) {
2914         TopoDS_Shape F = aMesh->IndexToShape( fId );
2915         if ( !F.IsNull() && F.ShapeType() == TopAbs_FACE )
2916           faceIdSet.insert( fId );
2917       }
2918     }
2919   faceIdSet.insert( 0 ); // to smooth elements that are not on any TopoDS_Face
2920
2921   // ===============================================
2922   // smooth elements on each TopoDS_Face separately
2923   // ===============================================
2924
2925   set< int >::reverse_iterator fId = faceIdSet.rbegin(); // treate 0 fId at the end
2926   for ( ; fId != faceIdSet.rend(); ++fId ) {
2927     // get face surface and submesh
2928     Handle(Geom_Surface) surface;
2929     SMESHDS_SubMesh* faceSubMesh = 0;
2930     TopoDS_Face face;
2931     double fToler2 = 0, vPeriod = 0., uPeriod = 0., f,l;
2932     double u1 = 0, u2 = 0, v1 = 0, v2 = 0;
2933     bool isUPeriodic = false, isVPeriodic = false;
2934     if ( *fId ) {
2935       face = TopoDS::Face( aMesh->IndexToShape( *fId ));
2936       surface = BRep_Tool::Surface( face );
2937       faceSubMesh = aMesh->MeshElements( *fId );
2938       fToler2 = BRep_Tool::Tolerance( face );
2939       fToler2 *= fToler2 * 10.;
2940       isUPeriodic = surface->IsUPeriodic();
2941       if ( isUPeriodic )
2942         vPeriod = surface->UPeriod();
2943       isVPeriodic = surface->IsVPeriodic();
2944       if ( isVPeriodic )
2945         uPeriod = surface->VPeriod();
2946       surface->Bounds( u1, u2, v1, v2 );
2947     }
2948     // ---------------------------------------------------------
2949     // for elements on a face, find movable and fixed nodes and
2950     // compute UV for them
2951     // ---------------------------------------------------------
2952     bool checkBoundaryNodes = false;
2953     bool isQuadratic = false;
2954     set<const SMDS_MeshNode*> setMovableNodes;
2955     map< const SMDS_MeshNode*, gp_XY* > uvMap, uvMap2;
2956     list< gp_XY > listUV; // uvs the 2 uvMaps refer to
2957     list< const SMDS_MeshElement* > elemsOnFace;
2958
2959     Extrema_GenExtPS projector;
2960     GeomAdaptor_Surface surfAdaptor;
2961     if ( !surface.IsNull() ) {
2962       surfAdaptor.Load( surface );
2963       projector.Initialize( surfAdaptor, 20,20, 1e-5,1e-5 );
2964     }
2965     int nbElemOnFace = 0;
2966     itElem = theElems.begin();
2967     // loop on not yet smoothed elements: look for elems on a face
2968     while ( itElem != theElems.end() ) {
2969       if ( faceSubMesh && nbElemOnFace == faceSubMesh->NbElements() )
2970         break; // all elements found
2971
2972       const SMDS_MeshElement* elem = *itElem;
2973       if ( !elem || elem->GetType() != SMDSAbs_Face || elem->NbNodes() < 3 ||
2974            ( faceSubMesh && !faceSubMesh->Contains( elem ))) {
2975         ++itElem;
2976         continue;
2977       }
2978       elemsOnFace.push_back( elem );
2979       theElems.erase( itElem++ );
2980       nbElemOnFace++;
2981
2982       if ( !isQuadratic )
2983         isQuadratic = elem->IsQuadratic();
2984
2985       // get movable nodes of elem
2986       const SMDS_MeshNode* node;
2987       SMDS_TypeOfPosition posType;
2988       SMDS_ElemIteratorPtr itN = elem->nodesIterator();
2989       int nn = 0, nbn =  elem->NbNodes();
2990       if(elem->IsQuadratic())
2991         nbn = nbn/2;
2992       while ( nn++ < nbn ) {
2993         node = static_cast<const SMDS_MeshNode*>( itN->next() );
2994         const SMDS_PositionPtr& pos = node->GetPosition();
2995         posType = pos ? pos->GetTypeOfPosition() : SMDS_TOP_3DSPACE;
2996         if (posType != SMDS_TOP_EDGE &&
2997             posType != SMDS_TOP_VERTEX &&
2998             theFixedNodes.find( node ) == theFixedNodes.end())
2999         {
3000           // check if all faces around the node are on faceSubMesh
3001           // because a node on edge may be bound to face
3002           SMDS_ElemIteratorPtr eIt = node->GetInverseElementIterator(SMDSAbs_Face);
3003           bool all = true;
3004           if ( faceSubMesh ) {
3005             while ( eIt->more() && all ) {
3006               const SMDS_MeshElement* e = eIt->next();
3007               all = faceSubMesh->Contains( e );
3008             }
3009           }
3010           if ( all )
3011             setMovableNodes.insert( node );
3012           else
3013             checkBoundaryNodes = true;
3014         }
3015         if ( posType == SMDS_TOP_3DSPACE )
3016           checkBoundaryNodes = true;
3017       }
3018
3019       if ( surface.IsNull() )
3020         continue;
3021
3022       // get nodes to check UV
3023       list< const SMDS_MeshNode* > uvCheckNodes;
3024       itN = elem->nodesIterator();
3025       nn = 0; nbn =  elem->NbNodes();
3026       if(elem->IsQuadratic())
3027         nbn = nbn/2;
3028       while ( nn++ < nbn ) {
3029         node = static_cast<const SMDS_MeshNode*>( itN->next() );
3030         if ( uvMap.find( node ) == uvMap.end() )
3031           uvCheckNodes.push_back( node );
3032         // add nodes of elems sharing node
3033         //         SMDS_ElemIteratorPtr eIt = node->GetInverseElementIterator(SMDSAbs_Face);
3034         //         while ( eIt->more() ) {
3035         //           const SMDS_MeshElement* e = eIt->next();
3036         //           if ( e != elem ) {
3037         //             SMDS_ElemIteratorPtr nIt = e->nodesIterator();
3038         //             while ( nIt->more() ) {
3039         //               const SMDS_MeshNode* n =
3040         //                 static_cast<const SMDS_MeshNode*>( nIt->next() );
3041         //               if ( uvMap.find( n ) == uvMap.end() )
3042         //                 uvCheckNodes.push_back( n );
3043         //             }
3044         //           }
3045         //         }
3046       }
3047       // check UV on face
3048       list< const SMDS_MeshNode* >::iterator n = uvCheckNodes.begin();
3049       for ( ; n != uvCheckNodes.end(); ++n ) {
3050         node = *n;
3051         gp_XY uv( 0, 0 );
3052         const SMDS_PositionPtr& pos = node->GetPosition();
3053         posType = pos ? pos->GetTypeOfPosition() : SMDS_TOP_3DSPACE;
3054         // get existing UV
3055         switch ( posType ) {
3056         case SMDS_TOP_FACE: {
3057           SMDS_FacePosition* fPos = ( SMDS_FacePosition* ) pos;
3058           uv.SetCoord( fPos->GetUParameter(), fPos->GetVParameter() );
3059           break;
3060         }
3061         case SMDS_TOP_EDGE: {
3062           TopoDS_Shape S = aMesh->IndexToShape( node->getshapeId() );
3063           Handle(Geom2d_Curve) pcurve;
3064           if ( !S.IsNull() && S.ShapeType() == TopAbs_EDGE )
3065             pcurve = BRep_Tool::CurveOnSurface( TopoDS::Edge( S ), face, f,l );
3066           if ( !pcurve.IsNull() ) {
3067             double u = (( SMDS_EdgePosition* ) pos )->GetUParameter();
3068             uv = pcurve->Value( u ).XY();
3069           }
3070           break;
3071         }
3072         case SMDS_TOP_VERTEX: {
3073           TopoDS_Shape S = aMesh->IndexToShape( node->getshapeId() );
3074           if ( !S.IsNull() && S.ShapeType() == TopAbs_VERTEX )
3075             uv = BRep_Tool::Parameters( TopoDS::Vertex( S ), face ).XY();
3076           break;
3077         }
3078         default:;
3079         }
3080         // check existing UV
3081         bool project = true;
3082         gp_Pnt pNode ( node->X(), node->Y(), node->Z() );
3083         double dist1 = DBL_MAX, dist2 = 0;
3084         if ( posType != SMDS_TOP_3DSPACE ) {
3085           dist1 = pNode.SquareDistance( surface->Value( uv.X(), uv.Y() ));
3086           project = dist1 > fToler2;
3087         }
3088         if ( project ) { // compute new UV
3089           gp_XY newUV;
3090           if ( !getClosestUV( projector, pNode, newUV )) {
3091             MESSAGE("Node Projection Failed " << node);
3092           }
3093           else {
3094             if ( isUPeriodic )
3095               newUV.SetX( ElCLib::InPeriod( newUV.X(), u1, u2 ));
3096             if ( isVPeriodic )
3097               newUV.SetY( ElCLib::InPeriod( newUV.Y(), v1, v2 ));
3098             // check new UV
3099             if ( posType != SMDS_TOP_3DSPACE )
3100               dist2 = pNode.SquareDistance( surface->Value( newUV.X(), newUV.Y() ));
3101             if ( dist2 < dist1 )
3102               uv = newUV;
3103           }
3104         }
3105         // store UV in the map
3106         listUV.push_back( uv );
3107         uvMap.insert( make_pair( node, &listUV.back() ));
3108       }
3109     } // loop on not yet smoothed elements
3110
3111     if ( !faceSubMesh || nbElemOnFace != faceSubMesh->NbElements() )
3112       checkBoundaryNodes = true;
3113
3114     // fix nodes on mesh boundary
3115
3116     if ( checkBoundaryNodes ) {
3117       map< NLink, int > linkNbMap; // how many times a link encounters in elemsOnFace
3118       map< NLink, int >::iterator link_nb;
3119       // put all elements links to linkNbMap
3120       list< const SMDS_MeshElement* >::iterator elemIt = elemsOnFace.begin();
3121       for ( ; elemIt != elemsOnFace.end(); ++elemIt ) {
3122         const SMDS_MeshElement* elem = (*elemIt);
3123         int nbn =  elem->NbNodes();
3124         if(elem->IsQuadratic())
3125           nbn = nbn/2;
3126         // loop on elem links: insert them in linkNbMap
3127         const SMDS_MeshNode* curNode, *prevNode = elem->GetNodeWrap( nbn );
3128         for ( int iN = 0; iN < nbn; ++iN ) {
3129           curNode = elem->GetNode( iN );
3130           NLink link;
3131           if ( curNode < prevNode ) link = make_pair( curNode , prevNode );
3132           else                      link = make_pair( prevNode , curNode );
3133           prevNode = curNode;
3134           link_nb = linkNbMap.find( link );
3135           if ( link_nb == linkNbMap.end() )
3136             linkNbMap.insert( make_pair ( link, 1 ));
3137           else
3138             link_nb->second++;
3139         }
3140       }
3141       // remove nodes that are in links encountered only once from setMovableNodes
3142       for ( link_nb = linkNbMap.begin(); link_nb != linkNbMap.end(); ++link_nb ) {
3143         if ( link_nb->second == 1 ) {
3144           setMovableNodes.erase( link_nb->first.first );
3145           setMovableNodes.erase( link_nb->first.second );
3146         }
3147       }
3148     }
3149
3150     // -----------------------------------------------------
3151     // for nodes on seam edge, compute one more UV ( uvMap2 );
3152     // find movable nodes linked to nodes on seam and which
3153     // are to be smoothed using the second UV ( uvMap2 )
3154     // -----------------------------------------------------
3155
3156     set<const SMDS_MeshNode*> nodesNearSeam; // to smooth using uvMap2
3157     if ( !surface.IsNull() ) {
3158       TopExp_Explorer eExp( face, TopAbs_EDGE );
3159       for ( ; eExp.More(); eExp.Next() ) {
3160         TopoDS_Edge edge = TopoDS::Edge( eExp.Current() );
3161         if ( !BRep_Tool::IsClosed( edge, face ))
3162           continue;
3163         SMESHDS_SubMesh* sm = aMesh->MeshElements( edge );
3164         if ( !sm ) continue;
3165         // find out which parameter varies for a node on seam
3166         double f,l;
3167         gp_Pnt2d uv1, uv2;
3168         Handle(Geom2d_Curve) pcurve = BRep_Tool::CurveOnSurface( edge, face, f, l );
3169         if ( pcurve.IsNull() ) continue;
3170         uv1 = pcurve->Value( f );
3171         edge.Reverse();
3172         pcurve = BRep_Tool::CurveOnSurface( edge, face, f, l );
3173         if ( pcurve.IsNull() ) continue;
3174         uv2 = pcurve->Value( f );
3175         int iPar = Abs( uv1.X() - uv2.X() ) > Abs( uv1.Y() - uv2.Y() ) ? 1 : 2;
3176         // assure uv1 < uv2
3177         if ( uv1.Coord( iPar ) > uv2.Coord( iPar )) {
3178           gp_Pnt2d tmp = uv1; uv1 = uv2; uv2 = tmp;
3179         }
3180         // get nodes on seam and its vertices
3181         list< const SMDS_MeshNode* > seamNodes;
3182         SMDS_NodeIteratorPtr nSeamIt = sm->GetNodes();
3183         while ( nSeamIt->more() ) {
3184           const SMDS_MeshNode* node = nSeamIt->next();
3185           if ( !isQuadratic || !IsMedium( node ))
3186             seamNodes.push_back( node );
3187         }
3188         TopExp_Explorer vExp( edge, TopAbs_VERTEX );
3189         for ( ; vExp.More(); vExp.Next() ) {
3190           sm = aMesh->MeshElements( vExp.Current() );
3191           if ( sm ) {
3192             nSeamIt = sm->GetNodes();
3193             while ( nSeamIt->more() )
3194               seamNodes.push_back( nSeamIt->next() );
3195           }
3196         }
3197         // loop on nodes on seam
3198         list< const SMDS_MeshNode* >::iterator noSeIt = seamNodes.begin();
3199         for ( ; noSeIt != seamNodes.end(); ++noSeIt ) {
3200           const SMDS_MeshNode* nSeam = *noSeIt;
3201           map< const SMDS_MeshNode*, gp_XY* >::iterator n_uv = uvMap.find( nSeam );
3202           if ( n_uv == uvMap.end() )
3203             continue;
3204           // set the first UV
3205           n_uv->second->SetCoord( iPar, uv1.Coord( iPar ));
3206           // set the second UV
3207           listUV.push_back( *n_uv->second );
3208           listUV.back().SetCoord( iPar, uv2.Coord( iPar ));
3209           if ( uvMap2.empty() )
3210             uvMap2 = uvMap; // copy the uvMap contents
3211           uvMap2[ nSeam ] = &listUV.back();
3212
3213           // collect movable nodes linked to ones on seam in nodesNearSeam
3214           SMDS_ElemIteratorPtr eIt = nSeam->GetInverseElementIterator(SMDSAbs_Face);
3215           while ( eIt->more() ) {
3216             const SMDS_MeshElement* e = eIt->next();
3217             int nbUseMap1 = 0, nbUseMap2 = 0;
3218             SMDS_ElemIteratorPtr nIt = e->nodesIterator();
3219             int nn = 0, nbn =  e->NbNodes();
3220             if(e->IsQuadratic()) nbn = nbn/2;
3221             while ( nn++ < nbn )
3222             {
3223               const SMDS_MeshNode* n =
3224                 static_cast<const SMDS_MeshNode*>( nIt->next() );
3225               if (n == nSeam ||
3226                   setMovableNodes.find( n ) == setMovableNodes.end() )
3227                 continue;
3228               // add only nodes being closer to uv2 than to uv1
3229               gp_Pnt pMid (0.5 * ( n->X() + nSeam->X() ),
3230                            0.5 * ( n->Y() + nSeam->Y() ),
3231                            0.5 * ( n->Z() + nSeam->Z() ));
3232               gp_XY uv;
3233               getClosestUV( projector, pMid, uv );
3234               if ( uv.Coord( iPar ) > uvMap[ n ]->Coord( iPar ) ) {
3235                 nodesNearSeam.insert( n );
3236                 nbUseMap2++;
3237               }
3238               else
3239                 nbUseMap1++;
3240             }
3241             // for centroidalSmooth all element nodes must
3242             // be on one side of a seam
3243             if ( theSmoothMethod == CENTROIDAL && nbUseMap1 && nbUseMap2 ) {
3244               SMDS_ElemIteratorPtr nIt = e->nodesIterator();
3245               nn = 0;
3246               while ( nn++ < nbn ) {
3247                 const SMDS_MeshNode* n =
3248                   static_cast<const SMDS_MeshNode*>( nIt->next() );
3249                 setMovableNodes.erase( n );
3250               }
3251             }
3252           }
3253         } // loop on nodes on seam
3254       } // loop on edge of a face
3255     } // if ( !face.IsNull() )
3256
3257     if ( setMovableNodes.empty() ) {
3258       MESSAGE( "Face id : " << *fId << " - NO SMOOTHING: no nodes to move!!!");
3259       continue; // goto next face
3260     }
3261
3262     // -------------
3263     // SMOOTHING //
3264     // -------------
3265
3266     int it = -1;
3267     double maxRatio = -1., maxDisplacement = -1.;
3268     set<const SMDS_MeshNode*>::iterator nodeToMove;
3269     for ( it = 0; it < theNbIterations; it++ ) {
3270       maxDisplacement = 0.;
3271       nodeToMove = setMovableNodes.begin();
3272       for ( ; nodeToMove != setMovableNodes.end(); nodeToMove++ ) {
3273         const SMDS_MeshNode* node = (*nodeToMove);
3274         gp_XYZ aPrevPos ( node->X(), node->Y(), node->Z() );
3275
3276         // smooth
3277         bool map2 = ( nodesNearSeam.find( node ) != nodesNearSeam.end() );
3278         if ( theSmoothMethod == LAPLACIAN )
3279           laplacianSmooth( node, surface, map2 ? uvMap2 : uvMap );
3280         else
3281           centroidalSmooth( node, surface, map2 ? uvMap2 : uvMap );
3282
3283         // node displacement
3284         gp_XYZ aNewPos ( node->X(), node->Y(), node->Z() );
3285         Standard_Real aDispl = (aPrevPos - aNewPos).SquareModulus();
3286         if ( aDispl > maxDisplacement )
3287           maxDisplacement = aDispl;
3288       }
3289       // no node movement => exit
3290       //if ( maxDisplacement < 1.e-16 ) {
3291       if ( maxDisplacement < disttol ) {
3292         MESSAGE("-- no node movement --");
3293         break;
3294       }
3295
3296       // check elements quality
3297       maxRatio  = 0;
3298       list< const SMDS_MeshElement* >::iterator elemIt = elemsOnFace.begin();
3299       for ( ; elemIt != elemsOnFace.end(); ++elemIt ) {
3300         const SMDS_MeshElement* elem = (*elemIt);
3301         if ( !elem || elem->GetType() != SMDSAbs_Face )
3302           continue;
3303         SMESH::Controls::TSequenceOfXYZ aPoints;
3304         if ( aQualityFunc.GetPoints( elem, aPoints )) {
3305           double aValue = aQualityFunc.GetValue( aPoints );
3306           if ( aValue > maxRatio )
3307             maxRatio = aValue;
3308         }
3309       }
3310       if ( maxRatio <= theTgtAspectRatio ) {
3311         MESSAGE("-- quality achived --");
3312         break;
3313       }
3314       if (it+1 == theNbIterations) {
3315         MESSAGE("-- Iteration limit exceeded --");
3316       }
3317     } // smoothing iterations
3318
3319     MESSAGE(" Face id: " << *fId <<
3320             " Nb iterstions: " << it <<
3321             " Displacement: " << maxDisplacement <<
3322             " Aspect Ratio " << maxRatio);
3323
3324     // ---------------------------------------
3325     // new nodes positions are computed,
3326     // record movement in DS and set new UV
3327     // ---------------------------------------
3328     nodeToMove = setMovableNodes.begin();
3329     for ( ; nodeToMove != setMovableNodes.end(); nodeToMove++ ) {
3330       SMDS_MeshNode* node = const_cast< SMDS_MeshNode* > (*nodeToMove);
3331       aMesh->MoveNode( node, node->X(), node->Y(), node->Z() );
3332       map< const SMDS_MeshNode*, gp_XY* >::iterator node_uv = uvMap.find( node );
3333       if ( node_uv != uvMap.end() ) {
3334         gp_XY* uv = node_uv->second;
3335         node->SetPosition
3336           ( SMDS_PositionPtr( new SMDS_FacePosition( uv->X(), uv->Y() )));
3337       }
3338     }
3339
3340     // move medium nodes of quadratic elements
3341     if ( isQuadratic )
3342     {
3343       SMESH_MesherHelper helper( *GetMesh() );
3344       if ( !face.IsNull() )
3345         helper.SetSubShape( face );
3346       list< const SMDS_MeshElement* >::iterator elemIt = elemsOnFace.begin();
3347       for ( ; elemIt != elemsOnFace.end(); ++elemIt ) {
3348         const SMDS_VtkFace* QF =
3349           dynamic_cast<const SMDS_VtkFace*> (*elemIt);
3350         if(QF && QF->IsQuadratic()) {
3351           vector<const SMDS_MeshNode*> Ns;
3352           Ns.reserve(QF->NbNodes()+1);
3353           SMDS_ElemIteratorPtr anIter = QF->interlacedNodesElemIterator();
3354           while ( anIter->more() )
3355             Ns.push_back( cast2Node(anIter->next()) );
3356           Ns.push_back( Ns[0] );
3357           double x, y, z;
3358           for(int i=0; i<QF->NbNodes(); i=i+2) {
3359             if ( !surface.IsNull() ) {
3360               gp_XY uv1 = helper.GetNodeUV( face, Ns[i], Ns[i+2] );
3361               gp_XY uv2 = helper.GetNodeUV( face, Ns[i+2], Ns[i] );
3362               gp_XY uv = ( uv1 + uv2 ) / 2.;
3363               gp_Pnt xyz = surface->Value( uv.X(), uv.Y() );
3364               x = xyz.X(); y = xyz.Y(); z = xyz.Z();
3365             }
3366             else {
3367               x = (Ns[i]->X() + Ns[i+2]->X())/2;
3368               y = (Ns[i]->Y() + Ns[i+2]->Y())/2;
3369               z = (Ns[i]->Z() + Ns[i+2]->Z())/2;
3370             }
3371             if( fabs( Ns[i+1]->X() - x ) > disttol ||
3372                 fabs( Ns[i+1]->Y() - y ) > disttol ||
3373                 fabs( Ns[i+1]->Z() - z ) > disttol ) {
3374               // we have to move i+1 node
3375               aMesh->MoveNode( Ns[i+1], x, y, z );
3376             }
3377           }
3378         }
3379       }
3380     }
3381
3382   } // loop on face ids
3383
3384 }
3385
3386 //=======================================================================
3387 //function : isReverse
3388 //purpose  : Return true if normal of prevNodes is not co-directied with
3389 //           gp_Vec(prevNodes[iNotSame],nextNodes[iNotSame]).
3390 //           iNotSame is where prevNodes and nextNodes are different
3391 //=======================================================================
3392
3393 static bool isReverse(vector<const SMDS_MeshNode*> prevNodes,
3394                       vector<const SMDS_MeshNode*> nextNodes,
3395                       const int            nbNodes,
3396                       const int            iNotSame)
3397 {
3398   int iBeforeNotSame = ( iNotSame == 0 ? nbNodes - 1 : iNotSame - 1 );
3399   int iAfterNotSame  = ( iNotSame + 1 == nbNodes ? 0 : iNotSame + 1 );
3400
3401   const SMDS_MeshNode* nB = prevNodes[ iBeforeNotSame ];
3402   const SMDS_MeshNode* nA = prevNodes[ iAfterNotSame ];
3403   const SMDS_MeshNode* nP = prevNodes[ iNotSame ];
3404   const SMDS_MeshNode* nN = nextNodes[ iNotSame ];
3405
3406   gp_Pnt pB ( nB->X(), nB->Y(), nB->Z() );
3407   gp_Pnt pA ( nA->X(), nA->Y(), nA->Z() );
3408   gp_Pnt pP ( nP->X(), nP->Y(), nP->Z() );
3409   gp_Pnt pN ( nN->X(), nN->Y(), nN->Z() );
3410
3411   gp_Vec vB ( pP, pB ), vA ( pP, pA ), vN ( pP, pN );
3412
3413   return (vA ^ vB) * vN < 0.0;
3414 }
3415
3416 //=======================================================================
3417 /*!
3418  * \brief Create elements by sweeping an element
3419  * \param elem - element to sweep
3420  * \param newNodesItVec - nodes generated from each node of the element
3421  * \param newElems - generated elements
3422  * \param nbSteps - number of sweeping steps
3423  * \param srcElements - to append elem for each generated element
3424  */
3425 //=======================================================================
3426
3427 void SMESH_MeshEditor::sweepElement(const SMDS_MeshElement*               elem,
3428                                     const vector<TNodeOfNodeListMapItr> & newNodesItVec,
3429                                     list<const SMDS_MeshElement*>&        newElems,
3430                                     const int                             nbSteps,
3431                                     SMESH_SequenceOfElemPtr&              srcElements)
3432 {
3433   //MESSAGE("sweepElement " << nbSteps);
3434   SMESHDS_Mesh* aMesh = GetMeshDS();
3435
3436   // Loop on elem nodes:
3437   // find new nodes and detect same nodes indices
3438   int nbNodes = elem->NbNodes();
3439   vector < list< const SMDS_MeshNode* >::const_iterator > itNN( nbNodes );
3440   vector<const SMDS_MeshNode*> prevNod( nbNodes );
3441   vector<const SMDS_MeshNode*> nextNod( nbNodes );
3442   vector<const SMDS_MeshNode*> midlNod( nbNodes );
3443
3444   int iNode, nbSame = 0, iNotSameNode = 0, iSameNode = 0;
3445   vector<int> sames(nbNodes);
3446   vector<bool> issimple(nbNodes);
3447
3448   for ( iNode = 0; iNode < nbNodes; iNode++ ) {
3449     TNodeOfNodeListMapItr nnIt = newNodesItVec[ iNode ];
3450     const SMDS_MeshNode*                 node         = nnIt->first;
3451     const list< const SMDS_MeshNode* > & listNewNodes = nnIt->second;
3452     if ( listNewNodes.empty() ) {
3453       return;
3454     }
3455
3456     issimple[iNode] = (listNewNodes.size()==nbSteps); // is node medium
3457
3458     itNN[ iNode ] = listNewNodes.begin();
3459     prevNod[ iNode ] = node;
3460     nextNod[ iNode ] = listNewNodes.front();
3461     if( !elem->IsQuadratic() || !issimple[iNode] ) {
3462       if ( prevNod[ iNode ] != nextNod [ iNode ])
3463         iNotSameNode = iNode;
3464       else {
3465         iSameNode = iNode;
3466         //nbSame++;
3467         sames[nbSame++] = iNode;
3468       }
3469     }
3470   }
3471
3472   //cerr<<"  nbSame = "<<nbSame<<endl;
3473   if ( nbSame == nbNodes || nbSame > 2) {
3474     MESSAGE( " Too many same nodes of element " << elem->GetID() );
3475     //INFOS( " Too many same nodes of element " << elem->GetID() );
3476     return;
3477   }
3478
3479   //  if( elem->IsQuadratic() && nbSame>0 ) {
3480   //    MESSAGE( "Can not rotate quadratic element " << elem->GetID() );
3481   //    return;
3482   //  }
3483
3484   int iBeforeSame = 0, iAfterSame = 0, iOpposSame = 0;
3485   int nbBaseNodes = ( elem->IsQuadratic() ? nbNodes/2 : nbNodes );
3486   if ( nbSame > 0 ) {
3487     iBeforeSame = ( iSameNode == 0 ? nbBaseNodes - 1 : iSameNode - 1 );
3488     iAfterSame  = ( iSameNode + 1 == nbBaseNodes ? 0 : iSameNode + 1 );
3489     iOpposSame  = ( iSameNode - 2 < 0  ? iSameNode + 2 : iSameNode - 2 );
3490   }
3491
3492   //if(nbNodes==8)
3493   //cout<<" prevNod[0]="<< prevNod[0]<<" prevNod[1]="<< prevNod[1]
3494   //    <<" prevNod[2]="<< prevNod[2]<<" prevNod[3]="<< prevNod[4]
3495   //    <<" prevNod[4]="<< prevNod[4]<<" prevNod[5]="<< prevNod[5]
3496   //    <<" prevNod[6]="<< prevNod[6]<<" prevNod[7]="<< prevNod[7]<<endl;
3497
3498   // check element orientation
3499   int i0 = 0, i2 = 2;
3500   if ( nbNodes > 2 && !isReverse( prevNod, nextNod, nbNodes, iNotSameNode )) {
3501     //MESSAGE("Reversed elem " << elem );
3502     i0 = 2;
3503     i2 = 0;
3504     if ( nbSame > 0 )
3505       std::swap( iBeforeSame, iAfterSame );
3506   }
3507
3508   // make new elements
3509   const SMDS_MeshElement* lastElem = elem;
3510   for (int iStep = 0; iStep < nbSteps; iStep++ ) {
3511     // get next nodes
3512     for ( iNode = 0; iNode < nbNodes; iNode++ ) {
3513       if(issimple[iNode]) {
3514         nextNod[ iNode ] = *itNN[ iNode ];
3515         itNN[ iNode ]++;
3516       }
3517       else {
3518         if( elem->GetType()==SMDSAbs_Node ) {
3519           // we have to use two nodes
3520           midlNod[ iNode ] = *itNN[ iNode ];
3521           itNN[ iNode ]++;
3522           nextNod[ iNode ] = *itNN[ iNode ];
3523           itNN[ iNode ]++;
3524         }
3525         else if(!elem->IsQuadratic() || lastElem->IsMediumNode(prevNod[iNode]) ) {
3526           // we have to use each second node
3527           //itNN[ iNode ]++;
3528           nextNod[ iNode ] = *itNN[ iNode ];
3529           itNN[ iNode ]++;
3530         }
3531         else {
3532           // we have to use two nodes
3533           midlNod[ iNode ] = *itNN[ iNode ];
3534           itNN[ iNode ]++;
3535           nextNod[ iNode ] = *itNN[ iNode ];
3536           itNN[ iNode ]++;
3537         }
3538       }
3539     }
3540     SMDS_MeshElement* aNewElem = 0;
3541     if(!elem->IsPoly()) {
3542       switch ( nbNodes ) {
3543       case 0:
3544         return;
3545       case 1: { // NODE
3546         if ( nbSame == 0 ) {
3547           if(issimple[0])
3548             aNewElem = aMesh->AddEdge( prevNod[ 0 ], nextNod[ 0 ] );
3549           else
3550             aNewElem = aMesh->AddEdge( prevNod[ 0 ], nextNod[ 0 ], midlNod[ 0 ] );
3551         }
3552         break;
3553       }
3554       case 2: { // EDGE
3555         if ( nbSame == 0 )
3556           aNewElem = aMesh->AddFace(prevNod[ 0 ], prevNod[ 1 ],
3557                                     nextNod[ 1 ], nextNod[ 0 ] );
3558         else
3559           aNewElem = aMesh->AddFace(prevNod[ 0 ], prevNod[ 1 ],
3560                                     nextNod[ iNotSameNode ] );
3561         break;
3562       }
3563
3564       case 3: { // TRIANGLE or quadratic edge
3565         if(elem->GetType() == SMDSAbs_Face) { // TRIANGLE
3566
3567           if ( nbSame == 0 )       // --- pentahedron
3568             aNewElem = aMesh->AddVolume (prevNod[ i0 ], prevNod[ 1 ], prevNod[ i2 ],
3569                                          nextNod[ i0 ], nextNod[ 1 ], nextNod[ i2 ] );
3570
3571           else if ( nbSame == 1 )  // --- pyramid
3572             aNewElem = aMesh->AddVolume (prevNod[ iBeforeSame ],  prevNod[ iAfterSame ],
3573                                          nextNod[ iAfterSame ], nextNod[ iBeforeSame ],
3574                                          nextNod[ iSameNode ]);
3575
3576           else // 2 same nodes:      --- tetrahedron
3577             aNewElem = aMesh->AddVolume (prevNod[ i0 ], prevNod[ 1 ], prevNod[ i2 ],
3578                                          nextNod[ iNotSameNode ]);
3579         }
3580         else { // quadratic edge
3581           if(nbSame==0) {     // quadratic quadrangle
3582             aNewElem = aMesh->AddFace(prevNod[0], nextNod[0], nextNod[1], prevNod[1],
3583                                       midlNod[0], nextNod[2], midlNod[1], prevNod[2]);
3584           }
3585           else if(nbSame==1) { // quadratic triangle
3586             if(sames[0]==2) {
3587               return; // medium node on axis
3588             }
3589             else if(sames[0]==0) {
3590               aNewElem = aMesh->AddFace(prevNod[0], nextNod[1], prevNod[1],
3591                                         nextNod[2], midlNod[1], prevNod[2]);
3592             }
3593             else { // sames[0]==1
3594               aNewElem = aMesh->AddFace(prevNod[0], nextNod[0], prevNod[1],
3595                                         midlNod[0], nextNod[2], prevNod[2]);
3596             }
3597           }
3598           else {
3599             return;
3600           }
3601         }
3602         break;
3603       }
3604       case 4: { // QUADRANGLE
3605
3606         if ( nbSame == 0 )       // --- hexahedron
3607           aNewElem = aMesh->AddVolume (prevNod[ i0 ], prevNod[ 1 ], prevNod[ i2 ], prevNod[ 3 ],
3608                                        nextNod[ i0 ], nextNod[ 1 ], nextNod[ i2 ], nextNod[ 3 ]);
3609
3610         else if ( nbSame == 1 ) { // --- pyramid + pentahedron
3611           aNewElem = aMesh->AddVolume (prevNod[ iBeforeSame ],  prevNod[ iAfterSame ],
3612                                        nextNod[ iAfterSame ], nextNod[ iBeforeSame ],
3613                                        nextNod[ iSameNode ]);
3614           newElems.push_back( aNewElem );
3615           aNewElem = aMesh->AddVolume (prevNod[ iAfterSame ], prevNod[ iOpposSame ],
3616                                        prevNod[ iBeforeSame ],  nextNod[ iAfterSame ],
3617                                        nextNod[ iOpposSame ],  nextNod[ iBeforeSame ] );
3618         }
3619         else if ( nbSame == 2 ) { // pentahedron
3620           if ( prevNod[ iBeforeSame ] == nextNod[ iBeforeSame ] )
3621             // iBeforeSame is same too
3622             aNewElem = aMesh->AddVolume (prevNod[ iBeforeSame ], prevNod[ iOpposSame ],
3623                                          nextNod[ iOpposSame ], prevNod[ iSameNode ],
3624                                          prevNod[ iAfterSame ],  nextNod[ iAfterSame ]);
3625           else
3626             // iAfterSame is same too
3627             aNewElem = aMesh->AddVolume (prevNod[ iSameNode ], prevNod[ iBeforeSame ],
3628                                          nextNod[ iBeforeSame ], prevNod[ iAfterSame ],
3629                                          prevNod[ iOpposSame ],  nextNod[ iOpposSame ]);
3630         }
3631         break;
3632       }
3633       case 6: { // quadratic triangle
3634         // create pentahedron with 15 nodes
3635         if(nbSame==0) {
3636           if(i0>0) { // reversed case
3637             aNewElem = aMesh->AddVolume (prevNod[0], prevNod[2], prevNod[1],
3638                                          nextNod[0], nextNod[2], nextNod[1],
3639                                          prevNod[5], prevNod[4], prevNod[3],
3640                                          nextNod[5], nextNod[4], nextNod[3],
3641                                          midlNod[0], midlNod[2], midlNod[1]);
3642           }
3643           else { // not reversed case
3644             aNewElem = aMesh->AddVolume (prevNod[0], prevNod[1], prevNod[2],
3645                                          nextNod[0], nextNod[1], nextNod[2],
3646                                          prevNod[3], prevNod[4], prevNod[5],
3647                                          nextNod[3], nextNod[4], nextNod[5],
3648                                          midlNod[0], midlNod[1], midlNod[2]);
3649           }
3650         }
3651         else if(nbSame==1) {
3652           // 2d order pyramid of 13 nodes
3653           //SMDS_MeshVolume* AddVolumeWithID(int n1, int n2, int n3, int n4, int n5,
3654           //                                 int n12,int n23,int n34,int n41,
3655           //                                 int n15,int n25,int n35,int n45, int ID);
3656           int n5 = iSameNode;
3657           int n1,n4,n41,n15,n45;
3658           if(i0>0) { // reversed case
3659             n1 = ( n5 + 1 == nbBaseNodes ? 0 : n5 + 1 );
3660             n4 = ( n5 == 0 ? nbBaseNodes - 1 : n5 - 1 );
3661             n41 = n1 + 3;
3662             n15 = n5 + 3;
3663             n45 = n4 + 3;
3664           }
3665           else {
3666             n1 = ( n5 == 0 ? nbBaseNodes - 1 : n5 - 1 );
3667             n4 = ( n5 + 1 == nbBaseNodes ? 0 : n5 + 1 );
3668             n41 = n4 + 3;
3669             n15 = n1 + 3;
3670             n45 = n5 + 3;
3671           }
3672           aNewElem = aMesh->AddVolume(prevNod[n1], nextNod[n1],
3673                                       nextNod[n4], prevNod[n4], prevNod[n5],
3674                                       midlNod[n1], nextNod[n41],
3675                                       midlNod[n4], prevNod[n41],
3676                                       prevNod[n15], nextNod[n15],
3677                                       nextNod[n45], prevNod[n45]);
3678         }
3679         else if(nbSame==2) {
3680           // 2d order tetrahedron of 10 nodes
3681           //SMDS_MeshVolume* AddVolumeWithID(int n1, int n2, int n3, int n4,
3682           //                                 int n12,int n23,int n31,
3683           //                                 int n14,int n24,int n34, int ID);
3684           int n1 = iNotSameNode;
3685           int n2,n3,n12,n23,n31;
3686           if(i0>0) { // reversed case
3687             n2 = ( n1 == 0 ? nbBaseNodes - 1 : n1 - 1 );
3688             n3 = ( n1 + 1 == nbBaseNodes ? 0 : n1 + 1 );
3689             n12 = n2 + 3;
3690             n23 = n3 + 3;
3691             n31 = n1 + 3;
3692           }
3693           else {
3694             n2 = ( n1 + 1 == nbBaseNodes ? 0 : n1 + 1 );
3695             n3 = ( n1 == 0 ? nbBaseNodes - 1 : n1 - 1 );
3696             n12 = n1 + 3;
3697             n23 = n2 + 3;
3698             n31 = n3 + 3;
3699           }
3700           aNewElem = aMesh->AddVolume (prevNod[n1], prevNod[n2], prevNod[n3], nextNod[n1],
3701                                        prevNod[n12], prevNod[n23], prevNod[n31],
3702                                        midlNod[n1], nextNod[n12], nextNod[n31]);
3703         }
3704         break;
3705       }
3706       case 8: { // quadratic quadrangle
3707         if(nbSame==0) {
3708           // create hexahedron with 20 nodes
3709           if(i0>0) { // reversed case
3710             aNewElem = aMesh->AddVolume (prevNod[0], prevNod[3], prevNod[2], prevNod[1],
3711                                          nextNod[0], nextNod[3], nextNod[2], nextNod[1],
3712                                          prevNod[7], prevNod[6], prevNod[5], prevNod[4],
3713                                          nextNod[7], nextNod[6], nextNod[5], nextNod[4],
3714                                          midlNod[0], midlNod[3], midlNod[2], midlNod[1]);
3715           }
3716           else { // not reversed case
3717             aNewElem = aMesh->AddVolume (prevNod[0], prevNod[1], prevNod[2], prevNod[3],
3718                                          nextNod[0], nextNod[1], nextNod[2], nextNod[3],
3719                                          prevNod[4], prevNod[5], prevNod[6], prevNod[7],
3720                                          nextNod[4], nextNod[5], nextNod[6], nextNod[7],
3721                                          midlNod[0], midlNod[1], midlNod[2], midlNod[3]);
3722           }
3723         }
3724         else if(nbSame==1) { 
3725           // --- pyramid + pentahedron - can not be created since it is needed 
3726           // additional middle node ot the center of face
3727           INFOS( " Sweep for face " << elem->GetID() << " can not be created" );
3728           return;
3729         }
3730         else if(nbSame==2) {
3731           // 2d order Pentahedron with 15 nodes
3732           //SMDS_MeshVolume* AddVolumeWithID(int n1, int n2, int n3, int n4, int n5, int n6,
3733           //                                 int n12,int n23,int n31,int n45,int n56,int n64,
3734           //                                 int n14,int n25,int n36, int ID);
3735           int n1,n2,n4,n5;
3736           if ( prevNod[ iBeforeSame ] == nextNod[ iBeforeSame ] ) {
3737             // iBeforeSame is same too
3738             n1 = iBeforeSame;
3739             n2 = iOpposSame;
3740             n4 = iSameNode;
3741             n5 = iAfterSame;
3742           }
3743           else {
3744             // iAfterSame is same too
3745             n1 = iSameNode;
3746             n2 = iBeforeSame;
3747             n4 = iAfterSame;
3748             n5 = iOpposSame;
3749           }
3750           int n12,n45,n14,n25;
3751           if(i0>0) { //reversed case
3752             n12 = n1 + 4;
3753             n45 = n5 + 4;
3754             n14 = n4 + 4;
3755             n25 = n2 + 4;
3756           }
3757           else {
3758             n12 = n2 + 4;
3759             n45 = n4 + 4;
3760             n14 = n1 + 4;
3761             n25 = n5 + 4;
3762           }
3763           aNewElem = aMesh->AddVolume (prevNod[n1], prevNod[n2], nextNod[n2],
3764                                        prevNod[n4], prevNod[n5], nextNod[n5],
3765                                        prevNod[n12], midlNod[n2], nextNod[n12],
3766                                        prevNod[n45], midlNod[n5], nextNod[n45],
3767                                        prevNod[n14], prevNod[n25], nextNod[n25]);
3768         }
3769         break;
3770       }
3771       default: {
3772         // realized for extrusion only
3773         //vector<const SMDS_MeshNode*> polyedre_nodes (nbNodes*2 + 4*nbNodes);
3774         //vector<int> quantities (nbNodes + 2);
3775
3776         //quantities[0] = nbNodes; // bottom of prism
3777         //for (int inode = 0; inode < nbNodes; inode++) {
3778         //  polyedre_nodes[inode] = prevNod[inode];
3779         //}
3780
3781         //quantities[1] = nbNodes; // top of prism
3782         //for (int inode = 0; inode < nbNodes; inode++) {
3783         //  polyedre_nodes[nbNodes + inode] = nextNod[inode];
3784         //}
3785
3786         //for (int iface = 0; iface < nbNodes; iface++) {
3787         //  quantities[iface + 2] = 4;
3788         //  int inextface = (iface == nbNodes - 1) ? 0 : iface + 1;
3789         //  polyedre_nodes[2*nbNodes + 4*iface + 0] = prevNod[iface];
3790         //  polyedre_nodes[2*nbNodes + 4*iface + 1] = prevNod[inextface];
3791         //  polyedre_nodes[2*nbNodes + 4*iface + 2] = nextNod[inextface];
3792         //  polyedre_nodes[2*nbNodes + 4*iface + 3] = nextNod[iface];
3793         //}
3794         //aNewElem = aMesh->AddPolyhedralVolume (polyedre_nodes, quantities);
3795         break;
3796       }
3797       }
3798     }
3799
3800     if(!aNewElem) {
3801       // realized for extrusion only
3802       vector<const SMDS_MeshNode*> polyedre_nodes (nbNodes*2 + 4*nbNodes);
3803       vector<int> quantities (nbNodes + 2);
3804
3805       quantities[0] = nbNodes; // bottom of prism
3806       for (int inode = 0; inode < nbNodes; inode++) {
3807         polyedre_nodes[inode] = prevNod[inode];
3808       }
3809
3810       quantities[1] = nbNodes; // top of prism
3811       for (int inode = 0; inode < nbNodes; inode++) {
3812         polyedre_nodes[nbNodes + inode] = nextNod[inode];
3813       }
3814
3815       for (int iface = 0; iface < nbNodes; iface++) {
3816         quantities[iface + 2] = 4;
3817         int inextface = (iface == nbNodes - 1) ? 0 : iface + 1;
3818         polyedre_nodes[2*nbNodes + 4*iface + 0] = prevNod[iface];
3819         polyedre_nodes[2*nbNodes + 4*iface + 1] = prevNod[inextface];
3820         polyedre_nodes[2*nbNodes + 4*iface + 2] = nextNod[inextface];
3821         polyedre_nodes[2*nbNodes + 4*iface + 3] = nextNod[iface];
3822       }
3823       aNewElem = aMesh->AddPolyhedralVolume (polyedre_nodes, quantities);
3824     }
3825
3826     if ( aNewElem ) {
3827       newElems.push_back( aNewElem );
3828       myLastCreatedElems.Append(aNewElem);
3829       srcElements.Append( elem );
3830       lastElem = aNewElem;
3831     }
3832
3833     // set new prev nodes
3834     for ( iNode = 0; iNode < nbNodes; iNode++ )
3835       prevNod[ iNode ] = nextNod[ iNode ];
3836
3837   } // for steps
3838 }
3839
3840 //=======================================================================
3841 /*!
3842  * \brief Create 1D and 2D elements around swept elements
3843  * \param mapNewNodes - source nodes and ones generated from them
3844  * \param newElemsMap - source elements and ones generated from them
3845  * \param elemNewNodesMap - nodes generated from each node of each element
3846  * \param elemSet - all swept elements
3847  * \param nbSteps - number of sweeping steps
3848  * \param srcElements - to append elem for each generated element
3849  */
3850 //=======================================================================
3851
3852 void SMESH_MeshEditor::makeWalls (TNodeOfNodeListMap &     mapNewNodes,
3853                                   TElemOfElemListMap &     newElemsMap,
3854                                   TElemOfVecOfNnlmiMap &   elemNewNodesMap,
3855                                   TIDSortedElemSet&        elemSet,
3856                                   const int                nbSteps,
3857                                   SMESH_SequenceOfElemPtr& srcElements)
3858 {
3859   MESSAGE("makeWalls");
3860   ASSERT( newElemsMap.size() == elemNewNodesMap.size() );
3861   SMESHDS_Mesh* aMesh = GetMeshDS();
3862
3863   // Find nodes belonging to only one initial element - sweep them to get edges.
3864
3865   TNodeOfNodeListMapItr nList = mapNewNodes.begin();
3866   for ( ; nList != mapNewNodes.end(); nList++ ) {
3867     const SMDS_MeshNode* node =
3868       static_cast<const SMDS_MeshNode*>( nList->first );
3869     SMDS_ElemIteratorPtr eIt = node->GetInverseElementIterator();
3870     int nbInitElems = 0;
3871     const SMDS_MeshElement* el = 0;
3872     SMDSAbs_ElementType highType = SMDSAbs_Edge; // count most complex elements only
3873     while ( eIt->more() && nbInitElems < 2 ) {
3874       el = eIt->next();
3875       SMDSAbs_ElementType type = el->GetType();
3876       if ( type == SMDSAbs_Volume || type < highType ) continue;
3877       if ( type > highType ) {
3878         nbInitElems = 0;
3879         highType = type;
3880       }
3881       if ( elemSet.find(el) != elemSet.end() )
3882         nbInitElems++;
3883     }
3884     if ( nbInitElems < 2 ) {
3885       bool NotCreateEdge = el && el->IsQuadratic() && el->IsMediumNode(node);
3886       if(!NotCreateEdge) {
3887         vector<TNodeOfNodeListMapItr> newNodesItVec( 1, nList );
3888         list<const SMDS_MeshElement*> newEdges;
3889         sweepElement( node, newNodesItVec, newEdges, nbSteps, srcElements );
3890       }
3891     }
3892   }
3893
3894   // Make a ceiling for each element ie an equal element of last new nodes.
3895   // Find free links of faces - make edges and sweep them into faces.
3896
3897   TElemOfElemListMap::iterator   itElem      = newElemsMap.begin();
3898   TElemOfVecOfNnlmiMap::iterator itElemNodes = elemNewNodesMap.begin();
3899   for ( ; itElem != newElemsMap.end(); itElem++, itElemNodes++ ) {
3900     const SMDS_MeshElement* elem = itElem->first;
3901     vector<TNodeOfNodeListMapItr>& vecNewNodes = itElemNodes->second;
3902
3903     if(itElem->second.size()==0) continue;
3904
3905     if ( elem->GetType() == SMDSAbs_Edge ) {
3906       // create a ceiling edge
3907       if (!elem->IsQuadratic()) {
3908         if ( !aMesh->FindEdge( vecNewNodes[ 0 ]->second.back(),
3909                                vecNewNodes[ 1 ]->second.back())) {
3910           myLastCreatedElems.Append(aMesh->AddEdge(vecNewNodes[ 0 ]->second.back(),
3911                                                    vecNewNodes[ 1 ]->second.back()));
3912           srcElements.Append( myLastCreatedElems.Last() );
3913         }
3914       }
3915       else {
3916         if ( !aMesh->FindEdge( vecNewNodes[ 0 ]->second.back(),
3917                                vecNewNodes[ 1 ]->second.back(),
3918                                vecNewNodes[ 2 ]->second.back())) {
3919           myLastCreatedElems.Append(aMesh->AddEdge(vecNewNodes[ 0 ]->second.back(),
3920                                                    vecNewNodes[ 1 ]->second.back(),
3921                                                    vecNewNodes[ 2 ]->second.back()));
3922           srcElements.Append( myLastCreatedElems.Last() );
3923         }
3924       }
3925     }
3926     if ( elem->GetType() != SMDSAbs_Face )
3927       continue;
3928
3929     bool hasFreeLinks = false;
3930
3931     TIDSortedElemSet avoidSet;
3932     avoidSet.insert( elem );
3933
3934     set<const SMDS_MeshNode*> aFaceLastNodes;
3935     int iNode, nbNodes = vecNewNodes.size();
3936     if(!elem->IsQuadratic()) {
3937       // loop on the face nodes
3938       for ( iNode = 0; iNode < nbNodes; iNode++ ) {
3939         aFaceLastNodes.insert( vecNewNodes[ iNode ]->second.back() );
3940         // look for free links of the face
3941         int iNext = ( iNode + 1 == nbNodes ) ? 0 : iNode + 1;
3942         const SMDS_MeshNode* n1 = vecNewNodes[ iNode ]->first;
3943         const SMDS_MeshNode* n2 = vecNewNodes[ iNext ]->first;
3944         // check if a link is free
3945         if ( ! SMESH_MeshEditor::FindFaceInSet ( n1, n2, elemSet, avoidSet )) {
3946           hasFreeLinks = true;
3947           // make an edge and a ceiling for a new edge
3948           if ( !aMesh->FindEdge( n1, n2 )) {
3949             myLastCreatedElems.Append(aMesh->AddEdge( n1, n2 )); // free link edge
3950             srcElements.Append( myLastCreatedElems.Last() );
3951           }
3952           n1 = vecNewNodes[ iNode ]->second.back();
3953           n2 = vecNewNodes[ iNext ]->second.back();
3954           if ( !aMesh->FindEdge( n1, n2 )) {
3955             myLastCreatedElems.Append(aMesh->AddEdge( n1, n2 )); // ceiling edge
3956             srcElements.Append( myLastCreatedElems.Last() );
3957           }
3958         }
3959       }
3960     }
3961     else { // elem is quadratic face
3962       int nbn = nbNodes/2;
3963       for ( iNode = 0; iNode < nbn; iNode++ ) {
3964         aFaceLastNodes.insert( vecNewNodes[ iNode ]->second.back() );
3965         int iNext = ( iNode + 1 == nbn ) ? 0 : iNode + 1;
3966         const SMDS_MeshNode* n1 = vecNewNodes[ iNode ]->first;
3967         const SMDS_MeshNode* n2 = vecNewNodes[ iNext ]->first;
3968         // check if a link is free
3969         if ( ! SMESH_MeshEditor::FindFaceInSet ( n1, n2, elemSet, avoidSet )) {
3970           hasFreeLinks = true;
3971           // make an edge and a ceiling for a new edge
3972           // find medium node
3973           const SMDS_MeshNode* n3 = vecNewNodes[ iNode+nbn ]->first;
3974           if ( !aMesh->FindEdge( n1, n2, n3 )) {
3975             myLastCreatedElems.Append(aMesh->AddEdge( n1, n2, n3 )); // free link edge
3976             srcElements.Append( myLastCreatedElems.Last() );
3977           }
3978           n1 = vecNewNodes[ iNode ]->second.back();
3979           n2 = vecNewNodes[ iNext ]->second.back();
3980           n3 = vecNewNodes[ iNode+nbn ]->second.back();
3981           if ( !aMesh->FindEdge( n1, n2, n3 )) {
3982             myLastCreatedElems.Append(aMesh->AddEdge( n1, n2, n3 )); // ceiling edge
3983             srcElements.Append( myLastCreatedElems.Last() );
3984           }
3985         }
3986       }
3987       for ( iNode = nbn; iNode < 2*nbn; iNode++ ) {
3988         aFaceLastNodes.insert( vecNewNodes[ iNode ]->second.back() );
3989       }
3990     }
3991
3992     // sweep free links into faces
3993
3994     if ( hasFreeLinks )  {
3995       list<const SMDS_MeshElement*> & newVolumes = itElem->second;
3996       int iVol, volNb, nbVolumesByStep = newVolumes.size() / nbSteps;
3997
3998       set<const SMDS_MeshNode*> initNodeSet, topNodeSet, faceNodeSet;
3999       for ( iNode = 0; iNode < nbNodes; iNode++ ) {
4000         initNodeSet.insert( vecNewNodes[ iNode ]->first );
4001         topNodeSet .insert( vecNewNodes[ iNode ]->second.back() );
4002       }
4003       for ( volNb = 0; volNb < nbVolumesByStep; volNb++ ) {
4004         list<const SMDS_MeshElement*>::iterator v = newVolumes.begin();
4005         iVol = 0;
4006         while ( iVol++ < volNb ) v++;
4007         // find indices of free faces of a volume and their source edges
4008         list< int > freeInd;
4009         list< const SMDS_MeshElement* > srcEdges; // source edges of free faces
4010         SMDS_VolumeTool vTool( *v );
4011         int iF, nbF = vTool.NbFaces();
4012         for ( iF = 0; iF < nbF; iF ++ ) {
4013           if (vTool.IsFreeFace( iF ) &&
4014               vTool.GetFaceNodes( iF, faceNodeSet ) &&
4015               initNodeSet != faceNodeSet) // except an initial face
4016           {
4017             if ( nbSteps == 1 && faceNodeSet == topNodeSet )
4018               continue;
4019             freeInd.push_back( iF );
4020             // find source edge of a free face iF
4021             vector<const SMDS_MeshNode*> commonNodes; // shared by the initial and free faces
4022             commonNodes.resize( initNodeSet.size(), NULL ); // avoid spoiling memory
4023             std::set_intersection( faceNodeSet.begin(), faceNodeSet.end(),
4024                                    initNodeSet.begin(), initNodeSet.end(),
4025                                    commonNodes.begin());
4026             if ( (*v)->IsQuadratic() )
4027               srcEdges.push_back(aMesh->FindEdge (commonNodes[0],commonNodes[1],commonNodes[2]));
4028             else
4029               srcEdges.push_back(aMesh->FindEdge (commonNodes[0],commonNodes[1]));
4030 #ifdef _DEBUG_
4031             if ( !srcEdges.back() )
4032             {
4033               cout << "SMESH_MeshEditor::makeWalls(), no source edge found for a free face #"
4034                    << iF << " of volume #" << vTool.ID() << endl;
4035             }
4036 #endif
4037           }
4038         }
4039         if ( freeInd.empty() )
4040           continue;
4041
4042         // create faces for all steps;
4043         // if such a face has been already created by sweep of edge,
4044         // assure that its orientation is OK
4045         for ( int iStep = 0; iStep < nbSteps; iStep++ )  {
4046           vTool.Set( *v );
4047           vTool.SetExternalNormal();
4048           list< int >::iterator ind = freeInd.begin();
4049           list< const SMDS_MeshElement* >::iterator srcEdge = srcEdges.begin();
4050           for ( ; ind != freeInd.end(); ++ind, ++srcEdge ) // loop on free faces
4051           {
4052             const SMDS_MeshNode** nodes = vTool.GetFaceNodes( *ind );
4053             int nbn = vTool.NbFaceNodes( *ind );
4054             switch ( nbn ) {
4055             case 3: { ///// triangle
4056               const SMDS_MeshFace * f = aMesh->FindFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ]);
4057               if ( !f )
4058                 myLastCreatedElems.Append(aMesh->AddFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ] ));
4059               else if ( nodes[ 1 ] != f->GetNodeWrap( f->GetNodeIndex( nodes[ 0 ] ) + 1 ))
4060                 {
4061                   myLastCreatedElems.Append(aMesh->AddFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ] ));
4062                   aMesh->RemoveElement(f);
4063                 }
4064               break;
4065             }
4066             case 4: { ///// quadrangle
4067               const SMDS_MeshFace * f = aMesh->FindFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ], nodes[ 3 ]);
4068               if ( !f )
4069                 myLastCreatedElems.Append(aMesh->AddFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ], nodes[ 3 ] ));
4070               else if ( nodes[ 1 ] != f->GetNodeWrap( f->GetNodeIndex( nodes[ 0 ] ) + 1 ))
4071                 {
4072                   myLastCreatedElems.Append(aMesh->AddFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ], nodes[ 3 ] ));
4073                   aMesh->RemoveElement(f);
4074                 }
4075               break;
4076             }
4077             default:
4078               if( (*v)->IsQuadratic() ) {
4079                 if(nbn==6) { /////// quadratic triangle
4080                   const SMDS_MeshFace * f = aMesh->FindFace( nodes[0], nodes[2], nodes[4],
4081                                                              nodes[1], nodes[3], nodes[5] );
4082                   if ( !f ) {
4083                     myLastCreatedElems.Append(aMesh->AddFace(nodes[0], nodes[2], nodes[4],
4084                                                              nodes[1], nodes[3], nodes[5]));
4085                   }
4086                   else if ( nodes[ 2 ] != f->GetNodeWrap( f->GetNodeIndex( nodes[ 0 ] ) + 1 )) {
4087                     const SMDS_MeshNode** tmpnodes = new const SMDS_MeshNode*[6];
4088                     tmpnodes[0] = nodes[0];
4089                     tmpnodes[1] = nodes[2];
4090                     tmpnodes[2] = nodes[4];
4091                     tmpnodes[3] = nodes[1];
4092                     tmpnodes[4] = nodes[3];
4093                     tmpnodes[5] = nodes[5];
4094                     myLastCreatedElems.Append(aMesh->AddFace(nodes[0], nodes[2], nodes[4],
4095                                                              nodes[1], nodes[3], nodes[5]));
4096                     aMesh->RemoveElement(f);
4097                   }
4098                 }
4099                 else {       /////// quadratic quadrangle
4100                   const SMDS_MeshFace * f = aMesh->FindFace( nodes[0], nodes[2], nodes[4], nodes[6],
4101                                                              nodes[1], nodes[3], nodes[5], nodes[7] );
4102                   if ( !f ) {
4103                     myLastCreatedElems.Append(aMesh->AddFace(nodes[0], nodes[2], nodes[4], nodes[6],
4104                                                              nodes[1], nodes[3], nodes[5], nodes[7]));
4105                   }
4106                   else if ( nodes[ 2 ] != f->GetNodeWrap( f->GetNodeIndex( nodes[ 0 ] ) + 1 )) {
4107                     const SMDS_MeshNode** tmpnodes = new const SMDS_MeshNode*[8];
4108                     tmpnodes[0] = nodes[0];
4109                     tmpnodes[1] = nodes[2];
4110                     tmpnodes[2] = nodes[4];
4111                     tmpnodes[3] = nodes[6];
4112                     tmpnodes[4] = nodes[1];
4113                     tmpnodes[5] = nodes[3];
4114                     tmpnodes[6] = nodes[5];
4115                     tmpnodes[7] = nodes[7];
4116                     myLastCreatedElems.Append(aMesh->AddFace(nodes[0], nodes[2], nodes[4], nodes[6],
4117                                                              nodes[1], nodes[3], nodes[5], nodes[7]));
4118                     aMesh->RemoveElement(f);
4119                   }
4120                 }
4121               }
4122               else { //////// polygon
4123                 vector<const SMDS_MeshNode*> polygon_nodes ( nodes, &nodes[nbn] );
4124                 const SMDS_MeshFace * f = aMesh->FindFace( polygon_nodes );
4125                 if ( !f )
4126                   myLastCreatedElems.Append(aMesh->AddPolygonalFace(polygon_nodes));
4127                 else if ( nodes[ 1 ] != f->GetNodeWrap( f->GetNodeIndex( nodes[ 0 ] ) + 1 ))
4128                   {
4129                   // TODO problem ChangeElementNodes : not the same number of nodes, not the same type
4130                   MESSAGE("ChangeElementNodes");
4131                   aMesh->ChangeElementNodes( f, nodes, nbn );
4132                   }
4133               }
4134             }
4135             while ( srcElements.Length() < myLastCreatedElems.Length() )
4136               srcElements.Append( *srcEdge );
4137
4138           }  // loop on free faces
4139
4140           // go to the next volume
4141           iVol = 0;
4142           while ( iVol++ < nbVolumesByStep ) v++;
4143         }
4144       }
4145     } // sweep free links into faces
4146
4147     // Make a ceiling face with a normal external to a volume
4148
4149     SMDS_VolumeTool lastVol( itElem->second.back() );
4150
4151     int iF = lastVol.GetFaceIndex( aFaceLastNodes );
4152     if ( iF >= 0 ) {
4153       lastVol.SetExternalNormal();
4154       const SMDS_MeshNode** nodes = lastVol.GetFaceNodes( iF );
4155       int nbn = lastVol.NbFaceNodes( iF );
4156       switch ( nbn ) {
4157       case 3:
4158         if (!hasFreeLinks ||
4159             !aMesh->FindFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ]))
4160           myLastCreatedElems.Append(aMesh->AddFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ] ));
4161         break;
4162       case 4:
4163         if (!hasFreeLinks ||
4164             !aMesh->FindFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ], nodes[ 3 ]))
4165           myLastCreatedElems.Append(aMesh->AddFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ], nodes[ 3 ] ));
4166         break;
4167       default:
4168         if(itElem->second.back()->IsQuadratic()) {
4169           if(nbn==6) {
4170             if (!hasFreeLinks ||
4171                 !aMesh->FindFace(nodes[0], nodes[2], nodes[4],
4172                                  nodes[1], nodes[3], nodes[5]) ) {
4173               myLastCreatedElems.Append(aMesh->AddFace(nodes[0], nodes[2], nodes[4],
4174                                                        nodes[1], nodes[3], nodes[5]));
4175             }
4176           }
4177           else { // nbn==8
4178             if (!hasFreeLinks ||
4179                 !aMesh->FindFace(nodes[0], nodes[2], nodes[4], nodes[6],
4180                                  nodes[1], nodes[3], nodes[5], nodes[7]) )
4181               myLastCreatedElems.Append(aMesh->AddFace(nodes[0], nodes[2], nodes[4], nodes[6],
4182                                                        nodes[1], nodes[3], nodes[5], nodes[7]));
4183           }
4184         }
4185         else {
4186           vector<const SMDS_MeshNode*> polygon_nodes ( nodes, &nodes[nbn] );
4187           if (!hasFreeLinks || !aMesh->FindFace(polygon_nodes))
4188             myLastCreatedElems.Append(aMesh->AddPolygonalFace(polygon_nodes));
4189         }
4190       } // switch
4191
4192       while ( srcElements.Length() < myLastCreatedElems.Length() )
4193         srcElements.Append( myLastCreatedElems.Last() );
4194     }
4195   } // loop on swept elements
4196 }
4197
4198 //=======================================================================
4199 //function : RotationSweep
4200 //purpose  :
4201 //=======================================================================
4202
4203 SMESH_MeshEditor::PGroupIDs
4204 SMESH_MeshEditor::RotationSweep(TIDSortedElemSet & theElems,
4205                                 const gp_Ax1&      theAxis,
4206                                 const double       theAngle,
4207                                 const int          theNbSteps,
4208                                 const double       theTol,
4209                                 const bool         theMakeGroups,
4210                                 const bool         theMakeWalls)
4211 {
4212   myLastCreatedElems.Clear();
4213   myLastCreatedNodes.Clear();
4214
4215   // source elements for each generated one
4216   SMESH_SequenceOfElemPtr srcElems, srcNodes;
4217
4218   MESSAGE( "RotationSweep()");
4219   gp_Trsf aTrsf;
4220   aTrsf.SetRotation( theAxis, theAngle );
4221   gp_Trsf aTrsf2;
4222   aTrsf2.SetRotation( theAxis, theAngle/2. );
4223
4224   gp_Lin aLine( theAxis );
4225   double aSqTol = theTol * theTol;
4226
4227   SMESHDS_Mesh* aMesh = GetMeshDS();
4228
4229   TNodeOfNodeListMap mapNewNodes;
4230   TElemOfVecOfNnlmiMap mapElemNewNodes;
4231   TElemOfElemListMap newElemsMap;
4232
4233   // loop on theElems
4234   TIDSortedElemSet::iterator itElem;
4235   for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
4236     const SMDS_MeshElement* elem = *itElem;
4237     if ( !elem || elem->GetType() == SMDSAbs_Volume )
4238       continue;
4239     vector<TNodeOfNodeListMapItr> & newNodesItVec = mapElemNewNodes[ elem ];
4240     newNodesItVec.reserve( elem->NbNodes() );
4241
4242     // loop on elem nodes
4243     SMDS_ElemIteratorPtr itN = elem->nodesIterator();
4244     while ( itN->more() ) {
4245       // check if a node has been already sweeped
4246       const SMDS_MeshNode* node = cast2Node( itN->next() );
4247
4248       gp_XYZ aXYZ( node->X(), node->Y(), node->Z() );
4249       double coord[3];
4250       aXYZ.Coord( coord[0], coord[1], coord[2] );
4251       bool isOnAxis = ( aLine.SquareDistance( aXYZ ) <= aSqTol );
4252
4253       TNodeOfNodeListMapItr nIt = mapNewNodes.find( node );
4254       if ( nIt == mapNewNodes.end() ) {
4255         nIt = mapNewNodes.insert( make_pair( node, list<const SMDS_MeshNode*>() )).first;
4256         list<const SMDS_MeshNode*>& listNewNodes = nIt->second;
4257
4258         // make new nodes
4259         //gp_XYZ aXYZ( node->X(), node->Y(), node->Z() );
4260         //double coord[3];
4261         //aXYZ.Coord( coord[0], coord[1], coord[2] );
4262         //bool isOnAxis = ( aLine.SquareDistance( aXYZ ) <= aSqTol );
4263         const SMDS_MeshNode * newNode = node;
4264         for ( int i = 0; i < theNbSteps; i++ ) {
4265           if ( !isOnAxis ) {
4266             if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
4267               // create two nodes
4268               aTrsf2.Transforms( coord[0], coord[1], coord[2] );
4269               //aTrsf.Transforms( coord[0], coord[1], coord[2] );
4270               newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
4271               myLastCreatedNodes.Append(newNode);
4272               srcNodes.Append( node );
4273               listNewNodes.push_back( newNode );
4274               aTrsf2.Transforms( coord[0], coord[1], coord[2] );
4275               //aTrsf.Transforms( coord[0], coord[1], coord[2] );
4276             }
4277             else {
4278               aTrsf.Transforms( coord[0], coord[1], coord[2] );
4279             }
4280             newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
4281             myLastCreatedNodes.Append(newNode);
4282             srcNodes.Append( node );
4283             listNewNodes.push_back( newNode );
4284           }
4285           else {
4286             listNewNodes.push_back( newNode );
4287             if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
4288               listNewNodes.push_back( newNode );
4289             }
4290           }
4291         }
4292       }
4293       /*
4294         else {
4295         // if current elem is quadratic and current node is not medium
4296         // we have to check - may be it is needed to insert additional nodes
4297         if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
4298         list< const SMDS_MeshNode* > & listNewNodes = nIt->second;
4299         if(listNewNodes.size()==theNbSteps) {
4300         listNewNodes.clear();
4301         // make new nodes
4302         //gp_XYZ aXYZ( node->X(), node->Y(), node->Z() );
4303         //double coord[3];
4304         //aXYZ.Coord( coord[0], coord[1], coord[2] );
4305         const SMDS_MeshNode * newNode = node;
4306         if ( !isOnAxis ) {
4307         for(int i = 0; i<theNbSteps; i++) {
4308         aTrsf2.Transforms( coord[0], coord[1], coord[2] );
4309         newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
4310         cout<<"    3 AddNode:  "<<newNode;
4311         myLastCreatedNodes.Append(newNode);
4312         listNewNodes.push_back( newNode );
4313         srcNodes.Append( node );
4314         aTrsf2.Transforms( coord[0], coord[1], coord[2] );
4315         newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
4316         cout<<"    4 AddNode:  "<<newNode;
4317         myLastCreatedNodes.Append(newNode);
4318         srcNodes.Append( node );
4319         listNewNodes.push_back( newNode );
4320         }
4321         }
4322         else {
4323         listNewNodes.push_back( newNode );
4324         }
4325         }
4326         }
4327         }
4328       */
4329       newNodesItVec.push_back( nIt );
4330     }
4331     // make new elements
4332     sweepElement( elem, newNodesItVec, newElemsMap[elem], theNbSteps, srcElems );
4333   }
4334
4335   if ( theMakeWalls )
4336     makeWalls( mapNewNodes, newElemsMap, mapElemNewNodes, theElems, theNbSteps, srcElems );
4337
4338   PGroupIDs newGroupIDs;
4339   if ( theMakeGroups )
4340     newGroupIDs = generateGroups( srcNodes, srcElems, "rotated");
4341
4342   return newGroupIDs;
4343 }
4344
4345
4346 //=======================================================================
4347 //function : CreateNode
4348 //purpose  :
4349 //=======================================================================
4350 const SMDS_MeshNode* SMESH_MeshEditor::CreateNode(const double x,
4351                                                   const double y,
4352                                                   const double z,
4353                                                   const double tolnode,
4354                                                   SMESH_SequenceOfNode& aNodes)
4355 {
4356   myLastCreatedElems.Clear();
4357   myLastCreatedNodes.Clear();
4358
4359   gp_Pnt P1(x,y,z);
4360   SMESHDS_Mesh * aMesh = myMesh->GetMeshDS();
4361
4362   // try to search in sequence of existing nodes
4363   // if aNodes.Length()>0 we 'nave to use given sequence
4364   // else - use all nodes of mesh
4365   if(aNodes.Length()>0) {
4366     int i;
4367     for(i=1; i<=aNodes.Length(); i++) {
4368       gp_Pnt P2(aNodes.Value(i)->X(),aNodes.Value(i)->Y(),aNodes.Value(i)->Z());
4369       if(P1.Distance(P2)<tolnode)
4370         return aNodes.Value(i);
4371     }
4372   }
4373   else {
4374     SMDS_NodeIteratorPtr itn = aMesh->nodesIterator();
4375     while(itn->more()) {
4376       const SMDS_MeshNode* aN = static_cast<const SMDS_MeshNode*> (itn->next());
4377       gp_Pnt P2(aN->X(),aN->Y(),aN->Z());
4378       if(P1.Distance(P2)<tolnode)
4379         return aN;
4380     }
4381   }
4382
4383   // create new node and return it
4384   const SMDS_MeshNode* NewNode = aMesh->AddNode(x,y,z);
4385   myLastCreatedNodes.Append(NewNode);
4386   return NewNode;
4387 }
4388
4389
4390 //=======================================================================
4391 //function : ExtrusionSweep
4392 //purpose  :
4393 //=======================================================================
4394
4395 SMESH_MeshEditor::PGroupIDs
4396 SMESH_MeshEditor::ExtrusionSweep (TIDSortedElemSet &  theElems,
4397                                   const gp_Vec&       theStep,
4398                                   const int           theNbSteps,
4399                                   TElemOfElemListMap& newElemsMap,
4400                                   const bool          theMakeGroups,
4401                                   const int           theFlags,
4402                                   const double        theTolerance)
4403 {
4404   ExtrusParam aParams;
4405   aParams.myDir = gp_Dir(theStep);
4406   aParams.myNodes.Clear();
4407   aParams.mySteps = new TColStd_HSequenceOfReal;
4408   int i;
4409   for(i=1; i<=theNbSteps; i++)
4410     aParams.mySteps->Append(theStep.Magnitude());
4411
4412   return
4413     ExtrusionSweep(theElems,aParams,newElemsMap,theMakeGroups,theFlags,theTolerance);
4414 }
4415
4416
4417 //=======================================================================
4418 //function : ExtrusionSweep
4419 //purpose  :
4420 //=======================================================================
4421
4422 SMESH_MeshEditor::PGroupIDs
4423 SMESH_MeshEditor::ExtrusionSweep (TIDSortedElemSet &  theElems,
4424                                   ExtrusParam&        theParams,
4425                                   TElemOfElemListMap& newElemsMap,
4426                                   const bool          theMakeGroups,
4427                                   const int           theFlags,
4428                                   const double        theTolerance)
4429 {
4430   MESSAGE("ExtrusionSweep " << theMakeGroups << " " << theFlags << " " << theTolerance);
4431   myLastCreatedElems.Clear();
4432   myLastCreatedNodes.Clear();
4433
4434   // source elements for each generated one
4435   SMESH_SequenceOfElemPtr srcElems, srcNodes;
4436
4437   SMESHDS_Mesh* aMesh = GetMeshDS();
4438
4439   int nbsteps = theParams.mySteps->Length();
4440
4441   TNodeOfNodeListMap mapNewNodes;
4442   //TNodeOfNodeVecMap mapNewNodes;
4443   TElemOfVecOfNnlmiMap mapElemNewNodes;
4444   //TElemOfVecOfMapNodesMap mapElemNewNodes;
4445
4446   // loop on theElems
4447   TIDSortedElemSet::iterator itElem;
4448   for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
4449     // check element type
4450     const SMDS_MeshElement* elem = *itElem;
4451     if ( !elem  || elem->GetType() == SMDSAbs_Volume )
4452       continue;
4453
4454     vector<TNodeOfNodeListMapItr> & newNodesItVec = mapElemNewNodes[ elem ];
4455     //vector<TNodeOfNodeVecMapItr> & newNodesItVec = mapElemNewNodes[ elem ];
4456     newNodesItVec.reserve( elem->NbNodes() );
4457
4458     // loop on elem nodes
4459     SMDS_ElemIteratorPtr itN = elem->nodesIterator();
4460     while ( itN->more() )
4461     {
4462       // check if a node has been already sweeped
4463       const SMDS_MeshNode* node = cast2Node( itN->next() );
4464       TNodeOfNodeListMap::iterator nIt = mapNewNodes.find( node );
4465       //TNodeOfNodeVecMap::iterator nIt = mapNewNodes.find( node );
4466       if ( nIt == mapNewNodes.end() ) {
4467         nIt = mapNewNodes.insert( make_pair( node, list<const SMDS_MeshNode*>() )).first;
4468         //nIt = mapNewNodes.insert( make_pair( node, vector<const SMDS_MeshNode*>() )).first;
4469         list<const SMDS_MeshNode*>& listNewNodes = nIt->second;
4470         //vector<const SMDS_MeshNode*>& vecNewNodes = nIt->second;
4471         //vecNewNodes.reserve(nbsteps);
4472
4473         // make new nodes
4474         double coord[] = { node->X(), node->Y(), node->Z() };
4475         //int nbsteps = theParams.mySteps->Length();
4476         for ( int i = 0; i < nbsteps; i++ ) {
4477           if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
4478             // create additional node
4479             double x = coord[0] + theParams.myDir.X()*theParams.mySteps->Value(i+1)/2.;
4480             double y = coord[1] + theParams.myDir.Y()*theParams.mySteps->Value(i+1)/2.;
4481             double z = coord[2] + theParams.myDir.Z()*theParams.mySteps->Value(i+1)/2.;
4482             if( theFlags & EXTRUSION_FLAG_SEW ) {
4483               const SMDS_MeshNode * newNode = CreateNode(x, y, z,
4484                                                          theTolerance, theParams.myNodes);
4485               listNewNodes.push_back( newNode );
4486             }
4487             else {
4488               const SMDS_MeshNode * newNode = aMesh->AddNode(x, y, z);
4489               myLastCreatedNodes.Append(newNode);
4490               srcNodes.Append( node );
4491               listNewNodes.push_back( newNode );
4492             }
4493           }
4494           //aTrsf.Transforms( coord[0], coord[1], coord[2] );
4495           coord[0] = coord[0] + theParams.myDir.X()*theParams.mySteps->Value(i+1);
4496           coord[1] = coord[1] + theParams.myDir.Y()*theParams.mySteps->Value(i+1);
4497           coord[2] = coord[2] + theParams.myDir.Z()*theParams.mySteps->Value(i+1);
4498           if( theFlags & EXTRUSION_FLAG_SEW ) {
4499             const SMDS_MeshNode * newNode = CreateNode(coord[0], coord[1], coord[2],
4500                                                        theTolerance, theParams.myNodes);
4501             listNewNodes.push_back( newNode );
4502             //vecNewNodes[i]=newNode;
4503           }
4504           else {
4505             const SMDS_MeshNode * newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
4506             myLastCreatedNodes.Append(newNode);
4507             srcNodes.Append( node );
4508             listNewNodes.push_back( newNode );
4509             //vecNewNodes[i]=newNode;
4510           }
4511         }
4512       }
4513       else {
4514         // if current elem is quadratic and current node is not medium
4515         // we have to check - may be it is needed to insert additional nodes
4516         if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
4517           list< const SMDS_MeshNode* > & listNewNodes = nIt->second;
4518           if(listNewNodes.size()==nbsteps) {
4519             listNewNodes.clear();
4520             double coord[] = { node->X(), node->Y(), node->Z() };
4521             for ( int i = 0; i < nbsteps; i++ ) {
4522               double x = coord[0] + theParams.myDir.X()*theParams.mySteps->Value(i+1);
4523               double y = coord[1] + theParams.myDir.Y()*theParams.mySteps->Value(i+1);
4524               double z = coord[2] + theParams.myDir.Z()*theParams.mySteps->Value(i+1);
4525               if( theFlags & EXTRUSION_FLAG_SEW ) {
4526                 const SMDS_MeshNode * newNode = CreateNode(x, y, z,
4527                                                            theTolerance, theParams.myNodes);
4528                 listNewNodes.push_back( newNode );
4529               }
4530               else {
4531                 const SMDS_MeshNode * newNode = aMesh->AddNode(x, y, z);
4532                 myLastCreatedNodes.Append(newNode);
4533                 srcNodes.Append( node );
4534                 listNewNodes.push_back( newNode );
4535               }
4536               coord[0] = coord[0] + theParams.myDir.X()*theParams.mySteps->Value(i+1);
4537               coord[1] = coord[1] + theParams.myDir.Y()*theParams.mySteps->Value(i+1);
4538               coord[2] = coord[2] + theParams.myDir.Z()*theParams.mySteps->Value(i+1);
4539               if( theFlags & EXTRUSION_FLAG_SEW ) {
4540                 const SMDS_MeshNode * newNode = CreateNode(coord[0], coord[1], coord[2],
4541                                                            theTolerance, theParams.myNodes);
4542                 listNewNodes.push_back( newNode );
4543               }
4544               else {
4545                 const SMDS_MeshNode * newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
4546                 myLastCreatedNodes.Append(newNode);
4547                 srcNodes.Append( node );
4548                 listNewNodes.push_back( newNode );
4549               }
4550             }
4551           }
4552         }
4553       }
4554       newNodesItVec.push_back( nIt );
4555     }
4556     // make new elements
4557     sweepElement( elem, newNodesItVec, newElemsMap[elem], nbsteps, srcElems );
4558   }
4559
4560   if( theFlags & EXTRUSION_FLAG_BOUNDARY ) {
4561     makeWalls( mapNewNodes, newElemsMap, mapElemNewNodes, theElems, nbsteps, srcElems );
4562   }
4563   PGroupIDs newGroupIDs;
4564   if ( theMakeGroups )
4565     newGroupIDs = generateGroups( srcNodes, srcElems, "extruded");
4566
4567   return newGroupIDs;
4568 }
4569
4570 /*
4571 //=======================================================================
4572 //class    : SMESH_MeshEditor_PathPoint
4573 //purpose  : auxiliary class
4574 //=======================================================================
4575 class SMESH_MeshEditor_PathPoint {
4576 public:
4577 SMESH_MeshEditor_PathPoint() {
4578 myPnt.SetCoord(99., 99., 99.);
4579 myTgt.SetCoord(1.,0.,0.);
4580 myAngle=0.;
4581 myPrm=0.;
4582 }
4583 void SetPnt(const gp_Pnt& aP3D){
4584 myPnt=aP3D;
4585 }
4586 void SetTangent(const gp_Dir& aTgt){
4587 myTgt=aTgt;
4588 }
4589 void SetAngle(const double& aBeta){
4590 myAngle=aBeta;
4591 }
4592 void SetParameter(const double& aPrm){
4593 myPrm=aPrm;
4594 }
4595 const gp_Pnt& Pnt()const{
4596 return myPnt;
4597 }
4598 const gp_Dir& Tangent()const{
4599 return myTgt;
4600 }
4601 double Angle()const{
4602 return myAngle;
4603 }
4604 double Parameter()const{
4605 return myPrm;
4606 }
4607
4608 protected:
4609 gp_Pnt myPnt;
4610 gp_Dir myTgt;
4611 double myAngle;
4612 double myPrm;
4613 };
4614 */
4615
4616 //=======================================================================
4617 //function : ExtrusionAlongTrack
4618 //purpose  :
4619 //=======================================================================
4620 SMESH_MeshEditor::Extrusion_Error
4621 SMESH_MeshEditor::ExtrusionAlongTrack (TIDSortedElemSet &   theElements,
4622                                        SMESH_subMesh*       theTrack,
4623                                        const SMDS_MeshNode* theN1,
4624                                        const bool           theHasAngles,
4625                                        list<double>&        theAngles,
4626                                        const bool           theLinearVariation,
4627                                        const bool           theHasRefPoint,
4628                                        const gp_Pnt&        theRefPoint,
4629                                        const bool           theMakeGroups)
4630 {
4631   MESSAGE("ExtrusionAlongTrack");
4632   myLastCreatedElems.Clear();
4633   myLastCreatedNodes.Clear();
4634
4635   int aNbE;
4636   std::list<double> aPrms;
4637   TIDSortedElemSet::iterator itElem;
4638
4639   gp_XYZ aGC;
4640   TopoDS_Edge aTrackEdge;
4641   TopoDS_Vertex aV1, aV2;
4642
4643   SMDS_ElemIteratorPtr aItE;
4644   SMDS_NodeIteratorPtr aItN;
4645   SMDSAbs_ElementType aTypeE;
4646
4647   TNodeOfNodeListMap mapNewNodes;
4648
4649   // 1. Check data
4650   aNbE = theElements.size();
4651   // nothing to do
4652   if ( !aNbE )
4653     return EXTR_NO_ELEMENTS;
4654
4655   // 1.1 Track Pattern
4656   ASSERT( theTrack );
4657
4658   SMESHDS_SubMesh* pSubMeshDS = theTrack->GetSubMeshDS();
4659
4660   aItE = pSubMeshDS->GetElements();
4661   while ( aItE->more() ) {
4662     const SMDS_MeshElement* pE = aItE->next();
4663     aTypeE = pE->GetType();
4664     // Pattern must contain links only
4665     if ( aTypeE != SMDSAbs_Edge )
4666       return EXTR_PATH_NOT_EDGE;
4667   }
4668
4669   list<SMESH_MeshEditor_PathPoint> fullList;
4670
4671   const TopoDS_Shape& aS = theTrack->GetSubShape();
4672   // Sub shape for the Pattern must be an Edge or Wire
4673   if( aS.ShapeType() == TopAbs_EDGE ) {
4674     aTrackEdge = TopoDS::Edge( aS );
4675     // the Edge must not be degenerated
4676     if ( BRep_Tool::Degenerated( aTrackEdge ) )
4677       return EXTR_BAD_PATH_SHAPE;
4678     TopExp::Vertices( aTrackEdge, aV1, aV2 );
4679     aItN = theTrack->GetFather()->GetSubMesh( aV1 )->GetSubMeshDS()->GetNodes();
4680     const SMDS_MeshNode* aN1 = aItN->next();
4681     aItN = theTrack->GetFather()->GetSubMesh( aV2 )->GetSubMeshDS()->GetNodes();
4682     const SMDS_MeshNode* aN2 = aItN->next();
4683     // starting node must be aN1 or aN2
4684     if ( !( aN1 == theN1 || aN2 == theN1 ) )
4685       return EXTR_BAD_STARTING_NODE;
4686     aItN = pSubMeshDS->GetNodes();
4687     while ( aItN->more() ) {
4688       const SMDS_MeshNode* pNode = aItN->next();
4689       const SMDS_EdgePosition* pEPos =
4690         static_cast<const SMDS_EdgePosition*>( pNode->GetPosition() );
4691       double aT = pEPos->GetUParameter();
4692       aPrms.push_back( aT );
4693     }
4694     //Extrusion_Error err =
4695     MakeEdgePathPoints(aPrms, aTrackEdge, (aN1==theN1), fullList);
4696   }
4697   else if( aS.ShapeType() == TopAbs_WIRE ) {
4698     list< SMESH_subMesh* > LSM;
4699     TopTools_SequenceOfShape Edges;
4700     SMESH_subMeshIteratorPtr itSM = theTrack->getDependsOnIterator(false,true);
4701     while(itSM->more()) {
4702       SMESH_subMesh* SM = itSM->next();
4703       LSM.push_back(SM);
4704       const TopoDS_Shape& aS = SM->GetSubShape();
4705       Edges.Append(aS);
4706     }
4707     list< list<SMESH_MeshEditor_PathPoint> > LLPPs;
4708     int startNid = theN1->GetID();
4709     TColStd_MapOfInteger UsedNums;
4710     int NbEdges = Edges.Length();
4711     int i = 1;
4712     for(; i<=NbEdges; i++) {
4713       int k = 0;
4714       list< SMESH_subMesh* >::iterator itLSM = LSM.begin();
4715       for(; itLSM!=LSM.end(); itLSM++) {
4716         k++;
4717         if(UsedNums.Contains(k)) continue;
4718         aTrackEdge = TopoDS::Edge( Edges.Value(k) );
4719         SMESH_subMesh* locTrack = *itLSM;
4720         SMESHDS_SubMesh* locMeshDS = locTrack->GetSubMeshDS();
4721         TopExp::Vertices( aTrackEdge, aV1, aV2 );
4722         aItN = locTrack->GetFather()->GetSubMesh(aV1)->GetSubMeshDS()->GetNodes();
4723         const SMDS_MeshNode* aN1 = aItN->next();
4724         aItN = locTrack->GetFather()->GetSubMesh(aV2)->GetSubMeshDS()->GetNodes();
4725         const SMDS_MeshNode* aN2 = aItN->next();
4726         // starting node must be aN1 or aN2
4727         if ( !( aN1->GetID() == startNid || aN2->GetID() == startNid ) ) continue;
4728         // 2. Collect parameters on the track edge
4729         aPrms.clear();
4730         aItN = locMeshDS->GetNodes();
4731         while ( aItN->more() ) {
4732           const SMDS_MeshNode* pNode = aItN->next();
4733           const SMDS_EdgePosition* pEPos =
4734             static_cast<const SMDS_EdgePosition*>( pNode->GetPosition() );
4735           double aT = pEPos->GetUParameter();
4736           aPrms.push_back( aT );
4737         }
4738         list<SMESH_MeshEditor_PathPoint> LPP;
4739         //Extrusion_Error err =
4740         MakeEdgePathPoints(aPrms, aTrackEdge,(aN1->GetID()==startNid), LPP);
4741         LLPPs.push_back(LPP);
4742         UsedNums.Add(k);
4743         // update startN for search following egde
4744         if( aN1->GetID() == startNid ) startNid = aN2->GetID();
4745         else startNid = aN1->GetID();
4746         break;
4747       }
4748     }
4749     list< list<SMESH_MeshEditor_PathPoint> >::iterator itLLPP = LLPPs.begin();
4750     list<SMESH_MeshEditor_PathPoint> firstList = *itLLPP;
4751     list<SMESH_MeshEditor_PathPoint>::iterator itPP = firstList.begin();
4752     for(; itPP!=firstList.end(); itPP++) {
4753       fullList.push_back( *itPP );
4754     }
4755     SMESH_MeshEditor_PathPoint PP1 = fullList.back();
4756     fullList.pop_back();
4757     itLLPP++;
4758     for(; itLLPP!=LLPPs.end(); itLLPP++) {
4759       list<SMESH_MeshEditor_PathPoint> currList = *itLLPP;
4760       itPP = currList.begin();
4761       SMESH_MeshEditor_PathPoint PP2 = currList.front();
4762       gp_Dir D1 = PP1.Tangent();
4763       gp_Dir D2 = PP2.Tangent();
4764       gp_Dir Dnew( gp_Vec( (D1.X()+D2.X())/2, (D1.Y()+D2.Y())/2,
4765                            (D1.Z()+D2.Z())/2 ) );
4766       PP1.SetTangent(Dnew);
4767       fullList.push_back(PP1);
4768       itPP++;
4769       for(; itPP!=firstList.end(); itPP++) {
4770         fullList.push_back( *itPP );
4771       }
4772       PP1 = fullList.back();
4773       fullList.pop_back();
4774     }
4775     // if wire not closed
4776     fullList.push_back(PP1);
4777     // else ???
4778   }
4779   else {
4780     return EXTR_BAD_PATH_SHAPE;
4781   }
4782
4783   return MakeExtrElements(theElements, fullList, theHasAngles, theAngles, theLinearVariation,
4784                           theHasRefPoint, theRefPoint, theMakeGroups);
4785 }
4786
4787
4788 //=======================================================================
4789 //function : ExtrusionAlongTrack
4790 //purpose  :
4791 //=======================================================================
4792 SMESH_MeshEditor::Extrusion_Error
4793 SMESH_MeshEditor::ExtrusionAlongTrack (TIDSortedElemSet &   theElements,
4794                                        SMESH_Mesh*          theTrack,
4795                                        const SMDS_MeshNode* theN1,
4796                                        const bool           theHasAngles,
4797                                        list<double>&        theAngles,
4798                                        const bool           theLinearVariation,
4799                                        const bool           theHasRefPoint,
4800                                        const gp_Pnt&        theRefPoint,
4801                                        const bool           theMakeGroups)
4802 {
4803   myLastCreatedElems.Clear();
4804   myLastCreatedNodes.Clear();
4805
4806   int aNbE;
4807   std::list<double> aPrms;
4808   TIDSortedElemSet::iterator itElem;
4809
4810   gp_XYZ aGC;
4811   TopoDS_Edge aTrackEdge;
4812   TopoDS_Vertex aV1, aV2;
4813
4814   SMDS_ElemIteratorPtr aItE;
4815   SMDS_NodeIteratorPtr aItN;
4816   SMDSAbs_ElementType aTypeE;
4817
4818   TNodeOfNodeListMap mapNewNodes;
4819
4820   // 1. Check data
4821   aNbE = theElements.size();
4822   // nothing to do
4823   if ( !aNbE )
4824     return EXTR_NO_ELEMENTS;
4825
4826   // 1.1 Track Pattern
4827   ASSERT( theTrack );
4828
4829   SMESHDS_Mesh* pMeshDS = theTrack->GetMeshDS();
4830
4831   aItE = pMeshDS->elementsIterator();
4832   while ( aItE->more() ) {
4833     const SMDS_MeshElement* pE = aItE->next();
4834     aTypeE = pE->GetType();
4835     // Pattern must contain links only
4836     if ( aTypeE != SMDSAbs_Edge )
4837       return EXTR_PATH_NOT_EDGE;
4838   }
4839
4840   list<SMESH_MeshEditor_PathPoint> fullList;
4841
4842   const TopoDS_Shape& aS = theTrack->GetShapeToMesh();
4843   // Sub shape for the Pattern must be an Edge or Wire
4844   if( aS.ShapeType() == TopAbs_EDGE ) {
4845     aTrackEdge = TopoDS::Edge( aS );
4846     // the Edge must not be degenerated
4847     if ( BRep_Tool::Degenerated( aTrackEdge ) )
4848       return EXTR_BAD_PATH_SHAPE;
4849     TopExp::Vertices( aTrackEdge, aV1, aV2 );
4850     aItN = theTrack->GetSubMesh( aV1 )->GetSubMeshDS()->GetNodes();
4851     const SMDS_MeshNode* aN1 = aItN->next();
4852     aItN = theTrack->GetSubMesh( aV2 )->GetSubMeshDS()->GetNodes();
4853     const SMDS_MeshNode* aN2 = aItN->next();
4854     // starting node must be aN1 or aN2
4855     if ( !( aN1 == theN1 || aN2 == theN1 ) )
4856       return EXTR_BAD_STARTING_NODE;
4857     aItN = pMeshDS->nodesIterator();
4858     while ( aItN->more() ) {
4859       const SMDS_MeshNode* pNode = aItN->next();
4860       if( pNode==aN1 || pNode==aN2 ) continue;
4861       const SMDS_EdgePosition* pEPos =
4862         static_cast<const SMDS_EdgePosition*>( pNode->GetPosition() );
4863       double aT = pEPos->GetUParameter();
4864       aPrms.push_back( aT );
4865     }
4866     //Extrusion_Error err =
4867     MakeEdgePathPoints(aPrms, aTrackEdge, (aN1==theN1), fullList);
4868   }
4869   else if( aS.ShapeType() == TopAbs_WIRE ) {
4870     list< SMESH_subMesh* > LSM;
4871     TopTools_SequenceOfShape Edges;
4872     TopExp_Explorer eExp(aS, TopAbs_EDGE);
4873     for(; eExp.More(); eExp.Next()) {
4874       TopoDS_Edge E = TopoDS::Edge( eExp.Current() );
4875       if( BRep_Tool::Degenerated(E) ) continue;
4876       SMESH_subMesh* SM = theTrack->GetSubMesh(E);
4877       if(SM) {
4878         LSM.push_back(SM);
4879         Edges.Append(E);
4880       }
4881     }
4882     list< list<SMESH_MeshEditor_PathPoint> > LLPPs;
4883     int startNid = theN1->GetID();
4884     TColStd_MapOfInteger UsedNums;
4885     int NbEdges = Edges.Length();
4886     int i = 1;
4887     for(; i<=NbEdges; i++) {
4888       int k = 0;
4889       list< SMESH_subMesh* >::iterator itLSM = LSM.begin();
4890       for(; itLSM!=LSM.end(); itLSM++) {
4891         k++;
4892         if(UsedNums.Contains(k)) continue;
4893         aTrackEdge = TopoDS::Edge( Edges.Value(k) );
4894         SMESH_subMesh* locTrack = *itLSM;
4895         SMESHDS_SubMesh* locMeshDS = locTrack->GetSubMeshDS();
4896         TopExp::Vertices( aTrackEdge, aV1, aV2 );
4897         aItN = locTrack->GetFather()->GetSubMesh(aV1)->GetSubMeshDS()->GetNodes();
4898         const SMDS_MeshNode* aN1 = aItN->next();
4899         aItN = locTrack->GetFather()->GetSubMesh(aV2)->GetSubMeshDS()->GetNodes();
4900         const SMDS_MeshNode* aN2 = aItN->next();
4901         // starting node must be aN1 or aN2
4902         if ( !( aN1->GetID() == startNid || aN2->GetID() == startNid ) ) continue;
4903         // 2. Collect parameters on the track edge
4904         aPrms.clear();
4905         aItN = locMeshDS->GetNodes();
4906         while ( aItN->more() ) {
4907           const SMDS_MeshNode* pNode = aItN->next();
4908           const SMDS_EdgePosition* pEPos =
4909             static_cast<const SMDS_EdgePosition*>( pNode->GetPosition() );
4910           double aT = pEPos->GetUParameter();
4911           aPrms.push_back( aT );
4912         }
4913         list<SMESH_MeshEditor_PathPoint> LPP;
4914         //Extrusion_Error err =
4915         MakeEdgePathPoints(aPrms, aTrackEdge,(aN1->GetID()==startNid), LPP);
4916         LLPPs.push_back(LPP);
4917         UsedNums.Add(k);
4918         // update startN for search following egde
4919         if( aN1->GetID() == startNid ) startNid = aN2->GetID();
4920         else startNid = aN1->GetID();
4921         break;
4922       }
4923     }
4924     list< list<SMESH_MeshEditor_PathPoint> >::iterator itLLPP = LLPPs.begin();
4925     list<SMESH_MeshEditor_PathPoint> firstList = *itLLPP;
4926     list<SMESH_MeshEditor_PathPoint>::iterator itPP = firstList.begin();
4927     for(; itPP!=firstList.end(); itPP++) {
4928       fullList.push_back( *itPP );
4929     }
4930     SMESH_MeshEditor_PathPoint PP1 = fullList.back();
4931     fullList.pop_back();
4932     itLLPP++;
4933     for(; itLLPP!=LLPPs.end(); itLLPP++) {
4934       list<SMESH_MeshEditor_PathPoint> currList = *itLLPP;
4935       itPP = currList.begin();
4936       SMESH_MeshEditor_PathPoint PP2 = currList.front();
4937       gp_Pnt P1 = PP1.Pnt();
4938       //cout<<"    PP1: Pnt("<<P1.X()<<","<<P1.Y()<<","<<P1.Z()<<")"<<endl;
4939       gp_Pnt P2 = PP2.Pnt();
4940       gp_Dir D1 = PP1.Tangent();
4941       gp_Dir D2 = PP2.Tangent();
4942       gp_Dir Dnew( gp_Vec( (D1.X()+D2.X())/2, (D1.Y()+D2.Y())/2,
4943                            (D1.Z()+D2.Z())/2 ) );
4944       PP1.SetTangent(Dnew);
4945       fullList.push_back(PP1);
4946       itPP++;
4947       for(; itPP!=currList.end(); itPP++) {
4948         fullList.push_back( *itPP );
4949       }
4950       PP1 = fullList.back();
4951       fullList.pop_back();
4952     }
4953     // if wire not closed
4954     fullList.push_back(PP1);
4955     // else ???
4956   }
4957   else {
4958     return EXTR_BAD_PATH_SHAPE;
4959   }
4960
4961   return MakeExtrElements(theElements, fullList, theHasAngles, theAngles, theLinearVariation,
4962                           theHasRefPoint, theRefPoint, theMakeGroups);
4963 }
4964
4965
4966 //=======================================================================
4967 //function : MakeEdgePathPoints
4968 //purpose  : auxilary for ExtrusionAlongTrack
4969 //=======================================================================
4970 SMESH_MeshEditor::Extrusion_Error
4971 SMESH_MeshEditor::MakeEdgePathPoints(std::list<double>& aPrms,
4972                                      const TopoDS_Edge& aTrackEdge,
4973                                      bool FirstIsStart,
4974                                      list<SMESH_MeshEditor_PathPoint>& LPP)
4975 {
4976   Standard_Real aTx1, aTx2, aL2, aTolVec, aTolVec2;
4977   aTolVec=1.e-7;
4978   aTolVec2=aTolVec*aTolVec;
4979   double aT1, aT2;
4980   TopoDS_Vertex aV1, aV2;
4981   TopExp::Vertices( aTrackEdge, aV1, aV2 );
4982   aT1=BRep_Tool::Parameter( aV1, aTrackEdge );
4983   aT2=BRep_Tool::Parameter( aV2, aTrackEdge );
4984   // 2. Collect parameters on the track edge
4985   aPrms.push_front( aT1 );
4986   aPrms.push_back( aT2 );
4987   // sort parameters
4988   aPrms.sort();
4989   if( FirstIsStart ) {
4990     if ( aT1 > aT2 ) {
4991       aPrms.reverse();
4992     }
4993   }
4994   else {
4995     if ( aT2 > aT1 ) {
4996       aPrms.reverse();
4997     }
4998   }
4999   // 3. Path Points
5000   SMESH_MeshEditor_PathPoint aPP;
5001   Handle(Geom_Curve) aC3D = BRep_Tool::Curve( aTrackEdge, aTx1, aTx2 );
5002   std::list<double>::iterator aItD = aPrms.begin();
5003   for(; aItD != aPrms.end(); ++aItD) {
5004     double aT = *aItD;
5005     gp_Pnt aP3D;
5006     gp_Vec aVec;
5007     aC3D->D1( aT, aP3D, aVec );
5008     aL2 = aVec.SquareMagnitude();
5009     if ( aL2 < aTolVec2 )
5010       return EXTR_CANT_GET_TANGENT;
5011     gp_Dir aTgt( aVec );
5012     aPP.SetPnt( aP3D );
5013     aPP.SetTangent( aTgt );
5014     aPP.SetParameter( aT );
5015     LPP.push_back(aPP);
5016   }
5017   return EXTR_OK;
5018 }
5019
5020
5021 //=======================================================================
5022 //function : MakeExtrElements
5023 //purpose  : auxilary for ExtrusionAlongTrack
5024 //=======================================================================
5025 SMESH_MeshEditor::Extrusion_Error
5026 SMESH_MeshEditor::MakeExtrElements(TIDSortedElemSet&  theElements,
5027                                    list<SMESH_MeshEditor_PathPoint>& fullList,
5028                                    const bool theHasAngles,
5029                                    list<double>& theAngles,
5030                                    const bool theLinearVariation,
5031                                    const bool theHasRefPoint,
5032                                    const gp_Pnt& theRefPoint,
5033                                    const bool theMakeGroups)
5034 {
5035   MESSAGE("MakeExtrElements");
5036   //cout<<"MakeExtrElements  fullList.size() = "<<fullList.size()<<endl;
5037   int aNbTP = fullList.size();
5038   vector<SMESH_MeshEditor_PathPoint> aPPs(aNbTP);
5039   // Angles
5040   if( theHasAngles && theAngles.size()>0 && theLinearVariation ) {
5041     LinearAngleVariation(aNbTP-1, theAngles);
5042   }
5043   vector<double> aAngles( aNbTP );
5044   int j = 0;
5045   for(; j<aNbTP; ++j) {
5046     aAngles[j] = 0.;
5047   }
5048   if ( theHasAngles ) {
5049     double anAngle;;
5050     std::list<double>::iterator aItD = theAngles.begin();
5051     for ( j=1; (aItD != theAngles.end()) && (j<aNbTP); ++aItD, ++j ) {
5052       anAngle = *aItD;
5053       aAngles[j] = anAngle;
5054     }
5055   }
5056   // fill vector of path points with angles
5057   //aPPs.resize(fullList.size());
5058   j = -1;
5059   list<SMESH_MeshEditor_PathPoint>::iterator itPP = fullList.begin();
5060   for(; itPP!=fullList.end(); itPP++) {
5061     j++;
5062     SMESH_MeshEditor_PathPoint PP = *itPP;
5063     PP.SetAngle(aAngles[j]);
5064     aPPs[j] = PP;
5065   }
5066
5067   TNodeOfNodeListMap mapNewNodes;
5068   TElemOfVecOfNnlmiMap mapElemNewNodes;
5069   TElemOfElemListMap newElemsMap;
5070   TIDSortedElemSet::iterator itElem;
5071   double aX, aY, aZ;
5072   int aNb;
5073   SMDSAbs_ElementType aTypeE;
5074   // source elements for each generated one
5075   SMESH_SequenceOfElemPtr srcElems, srcNodes;
5076
5077   // 3. Center of rotation aV0
5078   gp_Pnt aV0 = theRefPoint;
5079   gp_XYZ aGC;
5080   if ( !theHasRefPoint ) {
5081     aNb = 0;
5082     aGC.SetCoord( 0.,0.,0. );
5083
5084     itElem = theElements.begin();
5085     for ( ; itElem != theElements.end(); itElem++ ) {
5086       const SMDS_MeshElement* elem = *itElem;
5087
5088       SMDS_ElemIteratorPtr itN = elem->nodesIterator();
5089       while ( itN->more() ) {
5090         const SMDS_MeshNode* node = static_cast<const SMDS_MeshNode*>( itN->next() );
5091         aX = node->X();
5092         aY = node->Y();
5093         aZ = node->Z();
5094
5095         if ( mapNewNodes.find( node ) == mapNewNodes.end() ) {
5096           list<const SMDS_MeshNode*> aLNx;
5097           mapNewNodes[node] = aLNx;
5098           //
5099           gp_XYZ aXYZ( aX, aY, aZ );
5100           aGC += aXYZ;
5101           ++aNb;
5102         }
5103       }
5104     }
5105     aGC /= aNb;
5106     aV0.SetXYZ( aGC );
5107   } // if (!theHasRefPoint) {
5108   mapNewNodes.clear();
5109
5110   // 4. Processing the elements
5111   SMESHDS_Mesh* aMesh = GetMeshDS();
5112
5113   for ( itElem = theElements.begin(); itElem != theElements.end(); itElem++ ) {
5114     // check element type
5115     const SMDS_MeshElement* elem = *itElem;
5116     aTypeE = elem->GetType();
5117     if ( !elem || ( aTypeE != SMDSAbs_Face && aTypeE != SMDSAbs_Edge ) )
5118       continue;
5119
5120     vector<TNodeOfNodeListMapItr> & newNodesItVec = mapElemNewNodes[ elem ];
5121     newNodesItVec.reserve( elem->NbNodes() );
5122
5123     // loop on elem nodes
5124     int nodeIndex = -1;
5125     SMDS_ElemIteratorPtr itN = elem->nodesIterator();
5126     while ( itN->more() )
5127     {
5128       ++nodeIndex;
5129       // check if a node has been already processed
5130       const SMDS_MeshNode* node =
5131         static_cast<const SMDS_MeshNode*>( itN->next() );
5132       TNodeOfNodeListMap::iterator nIt = mapNewNodes.find( node );
5133       if ( nIt == mapNewNodes.end() ) {
5134         nIt = mapNewNodes.insert( make_pair( node, list<const SMDS_MeshNode*>() )).first;
5135         list<const SMDS_MeshNode*>& listNewNodes = nIt->second;
5136
5137         // make new nodes
5138         aX = node->X();  aY = node->Y(); aZ = node->Z();
5139
5140         Standard_Real aAngle1x, aAngleT1T0, aTolAng;
5141         gp_Pnt aP0x, aP1x, aPN0, aPN1, aV0x, aV1x;
5142         gp_Ax1 anAx1, anAxT1T0;
5143         gp_Dir aDT1x, aDT0x, aDT1T0;
5144
5145         aTolAng=1.e-4;
5146
5147         aV0x = aV0;
5148         aPN0.SetCoord(aX, aY, aZ);
5149
5150         const SMESH_MeshEditor_PathPoint& aPP0 = aPPs[0];
5151         aP0x = aPP0.Pnt();
5152         aDT0x= aPP0.Tangent();
5153         //cout<<"j = 0   PP: Pnt("<<aP0x.X()<<","<<aP0x.Y()<<","<<aP0x.Z()<<")"<<endl;
5154
5155         for ( j = 1; j < aNbTP; ++j ) {
5156           const SMESH_MeshEditor_PathPoint& aPP1 = aPPs[j];
5157           aP1x = aPP1.Pnt();
5158           aDT1x = aPP1.Tangent();
5159           aAngle1x = aPP1.Angle();
5160
5161           gp_Trsf aTrsf, aTrsfRot, aTrsfRotT1T0;
5162           // Translation
5163           gp_Vec aV01x( aP0x, aP1x );
5164           aTrsf.SetTranslation( aV01x );
5165
5166           // traslated point
5167           aV1x = aV0x.Transformed( aTrsf );
5168           aPN1 = aPN0.Transformed( aTrsf );
5169
5170           // rotation 1 [ T1,T0 ]
5171           aAngleT1T0=-aDT1x.Angle( aDT0x );
5172           if (fabs(aAngleT1T0) > aTolAng) {
5173             aDT1T0=aDT1x^aDT0x;
5174             anAxT1T0.SetLocation( aV1x );
5175             anAxT1T0.SetDirection( aDT1T0 );
5176             aTrsfRotT1T0.SetRotation( anAxT1T0, aAngleT1T0 );
5177
5178             aPN1 = aPN1.Transformed( aTrsfRotT1T0 );
5179           }
5180
5181           // rotation 2
5182           if ( theHasAngles ) {
5183             anAx1.SetLocation( aV1x );
5184             anAx1.SetDirection( aDT1x );
5185             aTrsfRot.SetRotation( anAx1, aAngle1x );
5186
5187             aPN1 = aPN1.Transformed( aTrsfRot );
5188           }
5189
5190           // make new node
5191           //MESSAGE("elem->IsQuadratic " << elem->IsQuadratic() << " " << elem->IsMediumNode(node));
5192           if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
5193             // create additional node
5194             double x = ( aPN1.X() + aPN0.X() )/2.;
5195             double y = ( aPN1.Y() + aPN0.Y() )/2.;
5196             double z = ( aPN1.Z() + aPN0.Z() )/2.;
5197             const SMDS_MeshNode* newNode = aMesh->AddNode(x,y,z);
5198             myLastCreatedNodes.Append(newNode);
5199             srcNodes.Append( node );
5200             listNewNodes.push_back( newNode );
5201           }
5202           aX = aPN1.X();
5203           aY = aPN1.Y();
5204           aZ = aPN1.Z();
5205           const SMDS_MeshNode* newNode = aMesh->AddNode( aX, aY, aZ );
5206           myLastCreatedNodes.Append(newNode);
5207           srcNodes.Append( node );
5208           listNewNodes.push_back( newNode );
5209
5210           aPN0 = aPN1;
5211           aP0x = aP1x;
5212           aV0x = aV1x;
5213           aDT0x = aDT1x;
5214         }
5215       }
5216
5217       else {
5218         // if current elem is quadratic and current node is not medium
5219         // we have to check - may be it is needed to insert additional nodes
5220         if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
5221           list< const SMDS_MeshNode* > & listNewNodes = nIt->second;
5222           if(listNewNodes.size()==aNbTP-1) {
5223             vector<const SMDS_MeshNode*> aNodes(2*(aNbTP-1));
5224             gp_XYZ P(node->X(), node->Y(), node->Z());
5225             list< const SMDS_MeshNode* >::iterator it = listNewNodes.begin();
5226             int i;
5227             for(i=0; i<aNbTP-1; i++) {
5228               const SMDS_MeshNode* N = *it;
5229               double x = ( N->X() + P.X() )/2.;
5230               double y = ( N->Y() + P.Y() )/2.;
5231               double z = ( N->Z() + P.Z() )/2.;
5232               const SMDS_MeshNode* newN = aMesh->AddNode(x,y,z);
5233               srcNodes.Append( node );
5234               myLastCreatedNodes.Append(newN);
5235               aNodes[2*i] = newN;
5236               aNodes[2*i+1] = N;
5237               P = gp_XYZ(N->X(),N->Y(),N->Z());
5238             }
5239             listNewNodes.clear();
5240             for(i=0; i<2*(aNbTP-1); i++) {
5241               listNewNodes.push_back(aNodes[i]);
5242             }
5243           }
5244         }
5245       }
5246
5247       newNodesItVec.push_back( nIt );
5248     }
5249     // make new elements
5250     //sweepElement( aMesh, elem, newNodesItVec, newElemsMap[elem],
5251     //              newNodesItVec[0]->second.size(), myLastCreatedElems );
5252     sweepElement( elem, newNodesItVec, newElemsMap[elem], aNbTP-1, srcElems );
5253   }
5254
5255   makeWalls( mapNewNodes, newElemsMap, mapElemNewNodes, theElements, aNbTP-1, srcElems );
5256
5257   if ( theMakeGroups )
5258     generateGroups( srcNodes, srcElems, "extruded");
5259
5260   return EXTR_OK;
5261 }
5262
5263
5264 //=======================================================================
5265 //function : LinearAngleVariation
5266 //purpose  : auxilary for ExtrusionAlongTrack
5267 //=======================================================================
5268 void SMESH_MeshEditor::LinearAngleVariation(const int nbSteps,
5269                                             list<double>& Angles)
5270 {
5271   int nbAngles = Angles.size();
5272   if( nbSteps > nbAngles ) {
5273     vector<double> theAngles(nbAngles);
5274     list<double>::iterator it = Angles.begin();
5275     int i = -1;
5276     for(; it!=Angles.end(); it++) {
5277       i++;
5278       theAngles[i] = (*it);
5279     }
5280     list<double> res;
5281     double rAn2St = double( nbAngles ) / double( nbSteps );
5282     double angPrev = 0, angle;
5283     for ( int iSt = 0; iSt < nbSteps; ++iSt ) {
5284       double angCur = rAn2St * ( iSt+1 );
5285       double angCurFloor  = floor( angCur );
5286       double angPrevFloor = floor( angPrev );
5287       if ( angPrevFloor == angCurFloor )
5288         angle = rAn2St * theAngles[ int( angCurFloor ) ];
5289       else {
5290         int iP = int( angPrevFloor );
5291         double angPrevCeil = ceil(angPrev);
5292         angle = ( angPrevCeil - angPrev ) * theAngles[ iP ];
5293
5294         int iC = int( angCurFloor );
5295         if ( iC < nbAngles )
5296           angle += ( angCur - angCurFloor ) * theAngles[ iC ];
5297
5298         iP = int( angPrevCeil );
5299         while ( iC-- > iP )
5300           angle += theAngles[ iC ];
5301       }
5302       res.push_back(angle);
5303       angPrev = angCur;
5304     }
5305     Angles.clear();
5306     it = res.begin();
5307     for(; it!=res.end(); it++)
5308       Angles.push_back( *it );
5309   }
5310 }
5311
5312
5313 //================================================================================
5314 /*!
5315  * \brief Move or copy theElements applying theTrsf to their nodes
5316  *  \param theElems - elements to transform, if theElems is empty then apply to all mesh nodes
5317  *  \param theTrsf - transformation to apply
5318  *  \param theCopy - if true, create translated copies of theElems
5319  *  \param theMakeGroups - if true and theCopy, create translated groups
5320  *  \param theTargetMesh - mesh to copy translated elements into
5321  *  \return SMESH_MeshEditor::PGroupIDs - list of ids of created groups
5322  */
5323 //================================================================================
5324
5325 SMESH_MeshEditor::PGroupIDs
5326 SMESH_MeshEditor::Transform (TIDSortedElemSet & theElems,
5327                              const gp_Trsf&     theTrsf,
5328                              const bool         theCopy,
5329                              const bool         theMakeGroups,
5330                              SMESH_Mesh*        theTargetMesh)
5331 {
5332   myLastCreatedElems.Clear();
5333   myLastCreatedNodes.Clear();
5334
5335   bool needReverse = false;
5336   string groupPostfix;
5337   switch ( theTrsf.Form() ) {
5338   case gp_PntMirror:
5339     MESSAGE("gp_PntMirror");
5340     needReverse = true;
5341     groupPostfix = "mirrored";
5342     break;
5343   case gp_Ax1Mirror:
5344     MESSAGE("gp_Ax1Mirror");
5345     groupPostfix = "mirrored";
5346     break;
5347   case gp_Ax2Mirror:
5348     MESSAGE("gp_Ax2Mirror");
5349     needReverse = true;
5350     groupPostfix = "mirrored";
5351     break;
5352   case gp_Rotation:
5353     MESSAGE("gp_Rotation");
5354     groupPostfix = "rotated";
5355     break;
5356   case gp_Translation:
5357     MESSAGE("gp_Translation");
5358     groupPostfix = "translated";
5359     break;
5360   case gp_Scale:
5361     MESSAGE("gp_Scale");
5362     groupPostfix = "scaled";
5363     break;
5364   case gp_CompoundTrsf: // different scale by axis
5365     MESSAGE("gp_CompoundTrsf");
5366     groupPostfix = "scaled";
5367     break;
5368   default:
5369     MESSAGE("default");
5370     needReverse = false;
5371     groupPostfix = "transformed";
5372   }
5373
5374   SMESH_MeshEditor targetMeshEditor( theTargetMesh );
5375   SMESHDS_Mesh* aTgtMesh = theTargetMesh ? theTargetMesh->GetMeshDS() : 0;
5376   SMESHDS_Mesh* aMesh    = GetMeshDS();
5377
5378
5379   // map old node to new one
5380   TNodeNodeMap nodeMap;
5381
5382   // elements sharing moved nodes; those of them which have all
5383   // nodes mirrored but are not in theElems are to be reversed
5384   TIDSortedElemSet inverseElemSet;
5385
5386   // source elements for each generated one
5387   SMESH_SequenceOfElemPtr srcElems, srcNodes;
5388
5389   // issue 021015: EDF 1578 SMESH: Free nodes are removed when translating a mesh
5390   TIDSortedElemSet orphanNode;
5391
5392   if ( theElems.empty() ) // transform the whole mesh
5393   {
5394     // add all elements
5395     SMDS_ElemIteratorPtr eIt = aMesh->elementsIterator();
5396     while ( eIt->more() ) theElems.insert( eIt->next() );
5397     // add orphan nodes
5398     SMDS_NodeIteratorPtr nIt = aMesh->nodesIterator();
5399     while ( nIt->more() )
5400     {
5401       const SMDS_MeshNode* node = nIt->next();
5402       if ( node->NbInverseElements() == 0)
5403         orphanNode.insert( node );
5404     }
5405   }
5406
5407   // loop on elements to transform nodes : first orphan nodes then elems
5408   TIDSortedElemSet::iterator itElem;
5409   TIDSortedElemSet *elements[] = {&orphanNode, &theElems };
5410   for (int i=0; i<2; i++)
5411   for ( itElem = elements[i]->begin(); itElem != elements[i]->end(); itElem++ ) {
5412     const SMDS_MeshElement* elem = *itElem;
5413     if ( !elem )
5414       continue;
5415
5416     // loop on elem nodes
5417     SMDS_ElemIteratorPtr itN = elem->nodesIterator();
5418     while ( itN->more() ) {
5419
5420       const SMDS_MeshNode* node = cast2Node( itN->next() );
5421       // check if a node has been already transformed
5422       pair<TNodeNodeMap::iterator,bool> n2n_isnew =
5423         nodeMap.insert( make_pair ( node, node ));
5424       if ( !n2n_isnew.second )
5425         continue;
5426
5427       double coord[3];
5428       coord[0] = node->X();
5429       coord[1] = node->Y();
5430       coord[2] = node->Z();
5431       theTrsf.Transforms( coord[0], coord[1], coord[2] );
5432       if ( theTargetMesh ) {
5433         const SMDS_MeshNode * newNode = aTgtMesh->AddNode( coord[0], coord[1], coord[2] );
5434         n2n_isnew.first->second = newNode;
5435         myLastCreatedNodes.Append(newNode);
5436         srcNodes.Append( node );
5437       }
5438       else if ( theCopy ) {
5439         const SMDS_MeshNode * newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
5440         n2n_isnew.first->second = newNode;
5441         myLastCreatedNodes.Append(newNode);
5442         srcNodes.Append( node );
5443       }
5444       else {
5445         aMesh->MoveNode( node, coord[0], coord[1], coord[2] );
5446         // node position on shape becomes invalid
5447         const_cast< SMDS_MeshNode* > ( node )->SetPosition
5448           ( SMDS_SpacePosition::originSpacePosition() );
5449       }
5450
5451       // keep inverse elements
5452       if ( !theCopy && !theTargetMesh && needReverse ) {
5453         SMDS_ElemIteratorPtr invElemIt = node->GetInverseElementIterator();
5454         while ( invElemIt->more() ) {
5455           const SMDS_MeshElement* iel = invElemIt->next();
5456           inverseElemSet.insert( iel );
5457         }
5458       }
5459     }
5460   }
5461
5462   // either create new elements or reverse mirrored ones
5463   if ( !theCopy && !needReverse && !theTargetMesh )
5464     return PGroupIDs();
5465
5466   TIDSortedElemSet::iterator invElemIt = inverseElemSet.begin();
5467   for ( ; invElemIt != inverseElemSet.end(); invElemIt++ )
5468     theElems.insert( *invElemIt );
5469
5470   // replicate or reverse elements
5471   // TODO revoir ordre reverse vtk
5472   enum {
5473     REV_TETRA   = 0,  //  = nbNodes - 4
5474     REV_PYRAMID = 1,  //  = nbNodes - 4
5475     REV_PENTA   = 2,  //  = nbNodes - 4
5476     REV_FACE    = 3,
5477     REV_HEXA    = 4,  //  = nbNodes - 4
5478     FORWARD     = 5
5479   };
5480   int index[][8] = {
5481     { 2, 1, 0, 3, 4, 0, 0, 0 },  // REV_TETRA
5482     { 2, 1, 0, 3, 4, 0, 0, 0 },  // REV_PYRAMID
5483     { 2, 1, 0, 5, 4, 3, 0, 0 },  // REV_PENTA
5484     { 2, 1, 0, 3, 0, 0, 0, 0 },  // REV_FACE
5485     { 2, 1, 0, 3, 6, 5, 4, 7 },  // REV_HEXA
5486     { 0, 1, 2, 3, 4, 5, 6, 7 }   // FORWARD
5487   };
5488
5489   for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ )
5490   {
5491     const SMDS_MeshElement* elem = *itElem;
5492     if ( !elem || elem->GetType() == SMDSAbs_Node )
5493       continue;
5494
5495     int nbNodes = elem->NbNodes();
5496     int elemType = elem->GetType();
5497
5498     if (elem->IsPoly()) {
5499       // Polygon or Polyhedral Volume
5500       switch ( elemType ) {
5501       case SMDSAbs_Face:
5502         {
5503           vector<const SMDS_MeshNode*> poly_nodes (nbNodes);
5504           int iNode = 0;
5505           SMDS_ElemIteratorPtr itN = elem->nodesIterator();
5506           while (itN->more()) {
5507             const SMDS_MeshNode* node =
5508               static_cast<const SMDS_MeshNode*>(itN->next());
5509             TNodeNodeMap::iterator nodeMapIt = nodeMap.find(node);
5510             if (nodeMapIt == nodeMap.end())
5511               break; // not all nodes transformed
5512             if (needReverse) {
5513               // reverse mirrored faces and volumes
5514               poly_nodes[nbNodes - iNode - 1] = (*nodeMapIt).second;
5515             } else {
5516               poly_nodes[iNode] = (*nodeMapIt).second;
5517             }
5518             iNode++;
5519           }
5520           if ( iNode != nbNodes )
5521             continue; // not all nodes transformed
5522
5523           if ( theTargetMesh ) {
5524             myLastCreatedElems.Append(aTgtMesh->AddPolygonalFace(poly_nodes));
5525             srcElems.Append( elem );
5526           }
5527           else if ( theCopy ) {
5528             myLastCreatedElems.Append(aMesh->AddPolygonalFace(poly_nodes));
5529             srcElems.Append( elem );
5530           }
5531           else {
5532             aMesh->ChangePolygonNodes(elem, poly_nodes);
5533           }
5534         }
5535         break;
5536       case SMDSAbs_Volume:
5537         {
5538           // ATTENTION: Reversing is not yet done!!!
5539           const SMDS_VtkVolume* aPolyedre =
5540             dynamic_cast<const SMDS_VtkVolume*>( elem );
5541           if (!aPolyedre) {
5542             MESSAGE("Warning: bad volumic element");
5543             continue;
5544           }
5545
5546           vector<const SMDS_MeshNode*> poly_nodes;
5547           vector<int> quantities;
5548
5549           bool allTransformed = true;
5550           int nbFaces = aPolyedre->NbFaces();
5551           for (int iface = 1; iface <= nbFaces && allTransformed; iface++) {
5552             int nbFaceNodes = aPolyedre->NbFaceNodes(iface);
5553             for (int inode = 1; inode <= nbFaceNodes && allTransformed; inode++) {
5554               const SMDS_MeshNode* node = aPolyedre->GetFaceNode(iface, inode);
5555               TNodeNodeMap::iterator nodeMapIt = nodeMap.find(node);
5556               if (nodeMapIt == nodeMap.end()) {
5557                 allTransformed = false; // not all nodes transformed
5558               } else {
5559                 poly_nodes.push_back((*nodeMapIt).second);
5560               }
5561             }
5562             quantities.push_back(nbFaceNodes);
5563           }
5564           if ( !allTransformed )
5565             continue; // not all nodes transformed
5566
5567           if ( theTargetMesh ) {
5568             myLastCreatedElems.Append(aTgtMesh->AddPolyhedralVolume(poly_nodes, quantities));
5569             srcElems.Append( elem );
5570           }
5571           else if ( theCopy ) {
5572             myLastCreatedElems.Append(aMesh->AddPolyhedralVolume(poly_nodes, quantities));
5573             srcElems.Append( elem );
5574           }
5575           else {
5576             aMesh->ChangePolyhedronNodes(elem, poly_nodes, quantities);
5577           }
5578         }
5579         break;
5580       default:;
5581       }
5582       continue;
5583     }
5584
5585     // Regular elements
5586     int* i = index[ FORWARD ];
5587     if ( needReverse && nbNodes > 2) {// reverse mirrored faces and volumes
5588       if ( elemType == SMDSAbs_Face )
5589         i = index[ REV_FACE ];
5590       else
5591         i = index[ nbNodes - 4 ];
5592     }
5593     if(elem->IsQuadratic()) {
5594       static int anIds[] = {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19};
5595       i = anIds;
5596       if(needReverse) {
5597         if(nbNodes==3) { // quadratic edge
5598           static int anIds[] = {1,0,2};
5599           i = anIds;
5600         }
5601         else if(nbNodes==6) { // quadratic triangle
5602           static int anIds[] = {0,2,1,5,4,3};
5603           i = anIds;
5604         }
5605         else if(nbNodes==8) { // quadratic quadrangle
5606           static int anIds[] = {0,3,2,1,7,6,5,4};
5607           i = anIds;
5608         }
5609         else if(nbNodes==10) { // quadratic tetrahedron of 10 nodes
5610           static int anIds[] = {0,2,1,3,6,5,4,7,9,8};
5611           i = anIds;
5612         }
5613         else if(nbNodes==13) { // quadratic pyramid of 13 nodes
5614           static int anIds[] = {0,3,2,1,4,8,7,6,5,9,12,11,10};
5615           i = anIds;
5616         }
5617         else if(nbNodes==15) { // quadratic pentahedron with 15 nodes
5618           static int anIds[] = {0,2,1,3,5,4,8,7,6,11,10,9,12,14,13};
5619           i = anIds;
5620         }
5621         else { // nbNodes==20 - quadratic hexahedron with 20 nodes
5622           static int anIds[] = {0,3,2,1,4,7,6,5,11,10,9,8,15,14,13,12,16,19,18,17};
5623           i = anIds;
5624         }
5625       }
5626     }
5627
5628     // find transformed nodes
5629     vector<const SMDS_MeshNode*> nodes(nbNodes);
5630     int iNode = 0;
5631     SMDS_ElemIteratorPtr itN = elem->nodesIterator();
5632     while ( itN->more() ) {
5633       const SMDS_MeshNode* node =
5634         static_cast<const SMDS_MeshNode*>( itN->next() );
5635       TNodeNodeMap::iterator nodeMapIt = nodeMap.find( node );
5636       if ( nodeMapIt == nodeMap.end() )
5637         break; // not all nodes transformed
5638       nodes[ i [ iNode++ ]] = (*nodeMapIt).second;
5639     }
5640     if ( iNode != nbNodes )
5641       continue; // not all nodes transformed
5642
5643     if ( theTargetMesh ) {
5644       if ( SMDS_MeshElement* copy =
5645            targetMeshEditor.AddElement( nodes, elem->GetType(), elem->IsPoly() )) {
5646         myLastCreatedElems.Append( copy );
5647         srcElems.Append( elem );
5648       }
5649     }
5650     else if ( theCopy ) {
5651       if ( AddElement( nodes, elem->GetType(), elem->IsPoly() ))
5652         srcElems.Append( elem );
5653     }
5654     else {
5655       // reverse element as it was reversed by transformation
5656       if ( nbNodes > 2 )
5657         aMesh->ChangeElementNodes( elem, &nodes[0], nbNodes );
5658     }
5659   }
5660
5661   PGroupIDs newGroupIDs;
5662
5663   if ( theMakeGroups && theCopy ||
5664        theMakeGroups && theTargetMesh )
5665     newGroupIDs = generateGroups( srcNodes, srcElems, groupPostfix, theTargetMesh );
5666
5667   return newGroupIDs;
5668 }
5669
5670
5671 ////=======================================================================
5672 ////function : Scale
5673 ////purpose  :
5674 ////=======================================================================
5675 //
5676 //SMESH_MeshEditor::PGroupIDs
5677 //SMESH_MeshEditor::Scale (TIDSortedElemSet & theElems,
5678 //                         const gp_Pnt&            thePoint,
5679 //                         const std::list<double>& theScaleFact,
5680 //                         const bool         theCopy,
5681 //                         const bool         theMakeGroups,
5682 //                         SMESH_Mesh*        theTargetMesh)
5683 //{
5684 //  MESSAGE("Scale");
5685 //  myLastCreatedElems.Clear();
5686 //  myLastCreatedNodes.Clear();
5687 //
5688 //  SMESH_MeshEditor targetMeshEditor( theTargetMesh );
5689 //  SMESHDS_Mesh* aTgtMesh = theTargetMesh ? theTargetMesh->GetMeshDS() : 0;
5690 //  SMESHDS_Mesh* aMesh    = GetMeshDS();
5691 //
5692 //  double scaleX=1.0, scaleY=1.0, scaleZ=1.0;
5693 //  std::list<double>::const_iterator itS = theScaleFact.begin();
5694 //  scaleX = (*itS);
5695 //  if(theScaleFact.size()==1) {
5696 //    scaleY = (*itS);
5697 //    scaleZ= (*itS);
5698 //  }
5699 //  if(theScaleFact.size()==2) {
5700 //    itS++;
5701 //    scaleY = (*itS);
5702 //    scaleZ= (*itS);
5703 //  }
5704 //  if(theScaleFact.size()>2) {
5705 //    itS++;
5706 //    scaleY = (*itS);
5707 //    itS++;
5708 //    scaleZ= (*itS);
5709 //  }
5710 //
5711 //  // map old node to new one
5712 //  TNodeNodeMap nodeMap;
5713 //
5714 //  // elements sharing moved nodes; those of them which have all
5715 //  // nodes mirrored but are not in theElems are to be reversed
5716 //  TIDSortedElemSet inverseElemSet;
5717 //
5718 //  // source elements for each generated one
5719 //  SMESH_SequenceOfElemPtr srcElems, srcNodes;
5720 //
5721 //  // loop on theElems
5722 //  TIDSortedElemSet::iterator itElem;
5723 //  for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
5724 //    const SMDS_MeshElement* elem = *itElem;
5725 //    if ( !elem )
5726 //      continue;
5727 //
5728 //    // loop on elem nodes
5729 //    SMDS_ElemIteratorPtr itN = elem->nodesIterator();
5730 //    while ( itN->more() ) {
5731 //
5732 //      // check if a node has been already transformed
5733 //      const SMDS_MeshNode* node = cast2Node( itN->next() );
5734 //      pair<TNodeNodeMap::iterator,bool> n2n_isnew =
5735 //        nodeMap.insert( make_pair ( node, node ));
5736 //      if ( !n2n_isnew.second )
5737 //        continue;
5738 //
5739 //      //double coord[3];
5740 //      //coord[0] = node->X();
5741 //      //coord[1] = node->Y();
5742 //      //coord[2] = node->Z();
5743 //      //theTrsf.Transforms( coord[0], coord[1], coord[2] );
5744 //      double dx = (node->X() - thePoint.X()) * scaleX;
5745 //      double dy = (node->Y() - thePoint.Y()) * scaleY;
5746 //      double dz = (node->Z() - thePoint.Z()) * scaleZ;
5747 //      if ( theTargetMesh ) {
5748 //        //const SMDS_MeshNode * newNode = aTgtMesh->AddNode( coord[0], coord[1], coord[2] );
5749 //        const SMDS_MeshNode * newNode =
5750 //          aTgtMesh->AddNode( thePoint.X()+dx, thePoint.Y()+dy, thePoint.Z()+dz );
5751 //        n2n_isnew.first->second = newNode;
5752 //        myLastCreatedNodes.Append(newNode);
5753 //        srcNodes.Append( node );
5754 //      }
5755 //      else if ( theCopy ) {
5756 //        //const SMDS_MeshNode * newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
5757 //        const SMDS_MeshNode * newNode =
5758 //          aMesh->AddNode( thePoint.X()+dx, thePoint.Y()+dy, thePoint.Z()+dz );
5759 //        n2n_isnew.first->second = newNode;
5760 //        myLastCreatedNodes.Append(newNode);
5761 //        srcNodes.Append( node );
5762 //      }
5763 //      else {
5764 //        //aMesh->MoveNode( node, coord[0], coord[1], coord[2] );
5765 //        aMesh->MoveNode( node, thePoint.X()+dx, thePoint.Y()+dy, thePoint.Z()+dz );
5766 //        // node position on shape becomes invalid
5767 //        const_cast< SMDS_MeshNode* > ( node )->SetPosition
5768 //          ( SMDS_SpacePosition::originSpacePosition() );
5769 //      }
5770 //
5771 //      // keep inverse elements
5772 //      //if ( !theCopy && !theTargetMesh && needReverse ) {
5773 //      //  SMDS_ElemIteratorPtr invElemIt = node->GetInverseElementIterator();
5774 //      //  while ( invElemIt->more() ) {
5775 //      //    const SMDS_MeshElement* iel = invElemIt->next();
5776 //      //    inverseElemSet.insert( iel );
5777 //      //  }
5778 //      //}
5779 //    }
5780 //  }
5781 //
5782 //  // either create new elements or reverse mirrored ones
5783 //  //if ( !theCopy && !needReverse && !theTargetMesh )
5784 //  if ( !theCopy && !theTargetMesh )
5785 //    return PGroupIDs();
5786 //
5787 //  TIDSortedElemSet::iterator invElemIt = inverseElemSet.begin();
5788 //  for ( ; invElemIt != inverseElemSet.end(); invElemIt++ )
5789 //    theElems.insert( *invElemIt );
5790 //
5791 //  // replicate or reverse elements
5792 //
5793 //  enum {
5794 //    REV_TETRA   = 0,  //  = nbNodes - 4
5795 //    REV_PYRAMID = 1,  //  = nbNodes - 4
5796 //    REV_PENTA   = 2,  //  = nbNodes - 4
5797 //    REV_FACE    = 3,
5798 //    REV_HEXA    = 4,  //  = nbNodes - 4
5799 //    FORWARD     = 5
5800 //  };
5801 //  int index[][8] = {
5802 //    { 2, 1, 0, 3, 4, 0, 0, 0 },  // REV_TETRA
5803 //    { 2, 1, 0, 3, 4, 0, 0, 0 },  // REV_PYRAMID
5804 //    { 2, 1, 0, 5, 4, 3, 0, 0 },  // REV_PENTA
5805 //    { 2, 1, 0, 3, 0, 0, 0, 0 },  // REV_FACE
5806 //    { 2, 1, 0, 3, 6, 5, 4, 7 },  // REV_HEXA
5807 //    { 0, 1, 2, 3, 4, 5, 6, 7 }   // FORWARD
5808 //  };
5809 //
5810 //  for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ )
5811 //  {
5812 //    const SMDS_MeshElement* elem = *itElem;
5813 //    if ( !elem || elem->GetType() == SMDSAbs_Node )
5814 //      continue;
5815 //
5816 //    int nbNodes = elem->NbNodes();
5817 //    int elemType = elem->GetType();
5818 //
5819 //    if (elem->IsPoly()) {
5820 //      // Polygon or Polyhedral Volume
5821 //      switch ( elemType ) {
5822 //      case SMDSAbs_Face:
5823 //        {
5824 //          vector<const SMDS_MeshNode*> poly_nodes (nbNodes);
5825 //          int iNode = 0;
5826 //          SMDS_ElemIteratorPtr itN = elem->nodesIterator();
5827 //          while (itN->more()) {
5828 //            const SMDS_MeshNode* node =
5829 //              static_cast<const SMDS_MeshNode*>(itN->next());
5830 //            TNodeNodeMap::iterator nodeMapIt = nodeMap.find(node);
5831 //            if (nodeMapIt == nodeMap.end())
5832 //              break; // not all nodes transformed
5833 //            //if (needReverse) {
5834 //            //  // reverse mirrored faces and volumes
5835 //            //  poly_nodes[nbNodes - iNode - 1] = (*nodeMapIt).second;
5836 //            //} else {
5837 //            poly_nodes[iNode] = (*nodeMapIt).second;
5838 //            //}
5839 //            iNode++;
5840 //          }
5841 //          if ( iNode != nbNodes )
5842 //            continue; // not all nodes transformed
5843 //
5844 //          if ( theTargetMesh ) {
5845 //            myLastCreatedElems.Append(aTgtMesh->AddPolygonalFace(poly_nodes));
5846 //            srcElems.Append( elem );
5847 //          }
5848 //          else if ( theCopy ) {
5849 //            myLastCreatedElems.Append(aMesh->AddPolygonalFace(poly_nodes));
5850 //            srcElems.Append( elem );
5851 //          }
5852 //          else {
5853 //            aMesh->ChangePolygonNodes(elem, poly_nodes);
5854 //          }
5855 //        }
5856 //        break;
5857 //      case SMDSAbs_Volume:
5858 //        {
5859 //          // ATTENTION: Reversing is not yet done!!!
5860 //          const SMDS_VtkVolume* aPolyedre =
5861 //            dynamic_cast<const SMDS_VtkVolume*>( elem );
5862 //          if (!aPolyedre) {
5863 //            MESSAGE("Warning: bad volumic element");
5864 //            continue;
5865 //          }
5866 //
5867 //          vector<const SMDS_MeshNode*> poly_nodes;
5868 //          vector<int> quantities;
5869 //
5870 //          bool allTransformed = true;
5871 //          int nbFaces = aPolyedre->NbFaces();
5872 //          for (int iface = 1; iface <= nbFaces && allTransformed; iface++) {
5873 //            int nbFaceNodes = aPolyedre->NbFaceNodes(iface);
5874 //            for (int inode = 1; inode <= nbFaceNodes && allTransformed; inode++) {
5875 //              const SMDS_MeshNode* node = aPolyedre->GetFaceNode(iface, inode);
5876 //              TNodeNodeMap::iterator nodeMapIt = nodeMap.find(node);
5877 //              if (nodeMapIt == nodeMap.end()) {
5878 //                allTransformed = false; // not all nodes transformed
5879 //              } else {
5880 //                poly_nodes.push_back((*nodeMapIt).second);
5881 //              }
5882 //            }
5883 //            quantities.push_back(nbFaceNodes);
5884 //          }
5885 //          if ( !allTransformed )
5886 //            continue; // not all nodes transformed
5887 //
5888 //          if ( theTargetMesh ) {
5889 //            myLastCreatedElems.Append(aTgtMesh->AddPolyhedralVolume(poly_nodes, quantities));
5890 //            srcElems.Append( elem );
5891 //          }
5892 //          else if ( theCopy ) {
5893 //            myLastCreatedElems.Append(aMesh->AddPolyhedralVolume(poly_nodes, quantities));
5894 //            srcElems.Append( elem );
5895 //          }
5896 //          else {
5897 //            aMesh->ChangePolyhedronNodes(elem, poly_nodes, quantities);
5898 //          }
5899 //        }
5900 //        break;
5901 //      default:;
5902 //      }
5903 //      continue;
5904 //    }
5905 //
5906 //    // Regular elements
5907 //    int* i = index[ FORWARD ];
5908 //    //if ( needReverse && nbNodes > 2) // reverse mirrored faces and volumes
5909 //    //  if ( elemType == SMDSAbs_Face )
5910 //    //    i = index[ REV_FACE ];
5911 //    //  else
5912 //    //    i = index[ nbNodes - 4 ];
5913 //
5914 //    if(elem->IsQuadratic()) {
5915 //      static int anIds[] = {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19};
5916 //      i = anIds;
5917 //      //if(needReverse) {
5918 //      //  if(nbNodes==3) { // quadratic edge
5919 //      //    static int anIds[] = {1,0,2};
5920 //      //    i = anIds;
5921 //      //  }
5922 //      //  else if(nbNodes==6) { // quadratic triangle
5923 //      //    static int anIds[] = {0,2,1,5,4,3};
5924 //      //    i = anIds;
5925 //      //  }
5926 //      //  else if(nbNodes==8) { // quadratic quadrangle
5927 //      //    static int anIds[] = {0,3,2,1,7,6,5,4};
5928 //      //    i = anIds;
5929 //      //  }
5930 //      //  else if(nbNodes==10) { // quadratic tetrahedron of 10 nodes
5931 //      //    static int anIds[] = {0,2,1,3,6,5,4,7,9,8};
5932 //      //    i = anIds;
5933 //      //  }
5934 //      //  else if(nbNodes==13) { // quadratic pyramid of 13 nodes
5935 //      //    static int anIds[] = {0,3,2,1,4,8,7,6,5,9,12,11,10};
5936 //      //    i = anIds;
5937 //      //  }
5938 //      //  else if(nbNodes==15) { // quadratic pentahedron with 15 nodes
5939 //      //    static int anIds[] = {0,2,1,3,5,4,8,7,6,11,10,9,12,14,13};
5940 //      //    i = anIds;
5941 //      //  }
5942 //      //  else { // nbNodes==20 - quadratic hexahedron with 20 nodes
5943 //      //    static int anIds[] = {0,3,2,1,4,7,6,5,11,10,9,8,15,14,13,12,16,19,18,17};
5944 //      //    i = anIds;
5945 //      //  }
5946 //      //}
5947 //    }
5948 //
5949 //    // find transformed nodes
5950 //    vector<const SMDS_MeshNode*> nodes(nbNodes);
5951 //    int iNode = 0;
5952 //    SMDS_ElemIteratorPtr itN = elem->nodesIterator();
5953 //    while ( itN->more() ) {
5954 //      const SMDS_MeshNode* node =
5955 //        static_cast<const SMDS_MeshNode*>( itN->next() );
5956 //      TNodeNodeMap::iterator nodeMapIt = nodeMap.find( node );
5957 //      if ( nodeMapIt == nodeMap.end() )
5958 //        break; // not all nodes transformed
5959 //      nodes[ i [ iNode++ ]] = (*nodeMapIt).second;
5960 //    }
5961 //    if ( iNode != nbNodes )
5962 //      continue; // not all nodes transformed
5963 //
5964 //    if ( theTargetMesh ) {
5965 //      if ( SMDS_MeshElement* copy =
5966 //           targetMeshEditor.AddElement( nodes, elem->GetType(), elem->IsPoly() )) {
5967 //        myLastCreatedElems.Append( copy );
5968 //        srcElems.Append( elem );
5969 //      }
5970 //    }
5971 //    else if ( theCopy ) {
5972 //      if ( SMDS_MeshElement* copy = AddElement( nodes, elem->GetType(), elem->IsPoly() )) {
5973 //        myLastCreatedElems.Append( copy );
5974 //        srcElems.Append( elem );
5975 //      }
5976 //    }
5977 //    else {
5978 //      // reverse element as it was reversed by transformation
5979 //      if ( nbNodes > 2 )
5980 //        aMesh->ChangeElementNodes( elem, &nodes[0], nbNodes );
5981 //    }
5982 //  }
5983 //
5984 //  PGroupIDs newGroupIDs;
5985 //
5986 //  if ( theMakeGroups && theCopy ||
5987 //       theMakeGroups && theTargetMesh ) {
5988 //    string groupPostfix = "scaled";
5989 //    newGroupIDs = generateGroups( srcNodes, srcElems, groupPostfix, theTargetMesh );
5990 //  }
5991 //
5992 //  return newGroupIDs;
5993 //}
5994
5995
5996 //=======================================================================
5997 /*!
5998  * \brief Create groups of elements made during transformation
5999  * \param nodeGens - nodes making corresponding myLastCreatedNodes
6000  * \param elemGens - elements making corresponding myLastCreatedElems
6001  * \param postfix - to append to names of new groups
6002  */
6003 //=======================================================================
6004
6005 SMESH_MeshEditor::PGroupIDs
6006 SMESH_MeshEditor::generateGroups(const SMESH_SequenceOfElemPtr& nodeGens,
6007                                  const SMESH_SequenceOfElemPtr& elemGens,
6008                                  const std::string&             postfix,
6009                                  SMESH_Mesh*                    targetMesh)
6010 {
6011   PGroupIDs newGroupIDs( new list<int> );
6012   SMESH_Mesh* mesh = targetMesh ? targetMesh : GetMesh();
6013
6014   // Sort existing groups by types and collect their names
6015
6016   // to store an old group and a generated new one
6017   typedef pair< SMESHDS_GroupBase*, SMDS_MeshGroup* > TOldNewGroup;
6018   vector< list< TOldNewGroup > > groupsByType( SMDSAbs_NbElementTypes );
6019   // group names
6020   set< string > groupNames;
6021   //
6022   SMDS_MeshGroup* nullNewGroup = (SMDS_MeshGroup*) 0;
6023   SMESH_Mesh::GroupIteratorPtr groupIt = GetMesh()->GetGroups();
6024   while ( groupIt->more() ) {
6025     SMESH_Group * group = groupIt->next();
6026     if ( !group ) continue;
6027     SMESHDS_GroupBase* groupDS = group->GetGroupDS();
6028     if ( !groupDS || groupDS->IsEmpty() ) continue;
6029     groupNames.insert( group->GetName() );
6030     groupDS->SetStoreName( group->GetName() );
6031     groupsByType[ groupDS->GetType() ].push_back( make_pair( groupDS, nullNewGroup ));
6032   }
6033
6034   // Groups creation
6035
6036   // loop on nodes and elements
6037   for ( int isNodes = 0; isNodes < 2; ++isNodes )
6038   {
6039     const SMESH_SequenceOfElemPtr& gens  = isNodes ? nodeGens : elemGens;
6040     const SMESH_SequenceOfElemPtr& elems = isNodes ? myLastCreatedNodes : myLastCreatedElems;
6041     if ( gens.Length() != elems.Length() )
6042       throw SALOME_Exception(LOCALIZED("invalid args"));
6043
6044     // loop on created elements
6045     for (int iElem = 1; iElem <= elems.Length(); ++iElem )
6046     {
6047       const SMDS_MeshElement* sourceElem = gens( iElem );
6048       if ( !sourceElem ) {
6049         MESSAGE("generateGroups(): NULL source element");
6050         continue;
6051       }
6052       list< TOldNewGroup > & groupsOldNew = groupsByType[ sourceElem->GetType() ];
6053       if ( groupsOldNew.empty() ) {
6054         while ( iElem < gens.Length() && gens( iElem+1 ) == sourceElem )
6055           ++iElem; // skip all elements made by sourceElem
6056         continue;
6057       }
6058       // collect all elements made by sourceElem
6059       list< const SMDS_MeshElement* > resultElems;
6060       if ( const SMDS_MeshElement* resElem = elems( iElem ))
6061         if ( resElem != sourceElem )
6062           resultElems.push_back( resElem );
6063       while ( iElem < gens.Length() && gens( iElem+1 ) == sourceElem )
6064         if ( const SMDS_MeshElement* resElem = elems( ++iElem ))
6065           if ( resElem != sourceElem )
6066             resultElems.push_back( resElem );
6067       // do not generate element groups from node ones
6068       if ( sourceElem->GetType() == SMDSAbs_Node &&
6069            elems( iElem )->GetType() != SMDSAbs_Node )
6070         continue;
6071
6072       // add resultElems to groups made by ones the sourceElem belongs to
6073       list< TOldNewGroup >::iterator gOldNew, gLast = groupsOldNew.end();
6074       for ( gOldNew = groupsOldNew.begin(); gOldNew != gLast; ++gOldNew )
6075       {
6076         SMESHDS_GroupBase* oldGroup = gOldNew->first;
6077         if ( oldGroup->Contains( sourceElem )) // sourceElem in oldGroup
6078         {
6079           SMDS_MeshGroup* & newGroup = gOldNew->second;
6080           if ( !newGroup )// create a new group
6081           {
6082             // make a name
6083             string name = oldGroup->GetStoreName();
6084             if ( !targetMesh ) {
6085               name += "_";
6086               name += postfix;
6087               int nb = 0;
6088               while ( !groupNames.insert( name ).second ) // name exists
6089               {
6090                 if ( nb == 0 ) {
6091                   name += "_1";
6092                 }
6093                 else {
6094                   TCollection_AsciiString nbStr(nb+1);
6095                   name.resize( name.rfind('_')+1 );
6096                   name += nbStr.ToCString();
6097                 }
6098                 ++nb;
6099               }
6100             }
6101             // make a group
6102             int id;
6103             SMESH_Group* group = mesh->AddGroup( resultElems.back()->GetType(),
6104                                                  name.c_str(), id );
6105             SMESHDS_Group* groupDS = static_cast<SMESHDS_Group*>(group->GetGroupDS());
6106             newGroup = & groupDS->SMDSGroup();
6107             newGroupIDs->push_back( id );
6108           }
6109
6110           // fill in a new group
6111           list< const SMDS_MeshElement* >::iterator resLast = resultElems.end(), resElemIt;
6112           for ( resElemIt = resultElems.begin(); resElemIt != resLast; ++resElemIt )
6113             newGroup->Add( *resElemIt );
6114         }
6115       }
6116     } // loop on created elements
6117   }// loop on nodes and elements
6118
6119   return newGroupIDs;
6120 }
6121
6122 //================================================================================
6123 /*!
6124  * \brief Return list of group of nodes close to each other within theTolerance
6125  *        Search among theNodes or in the whole mesh if theNodes is empty using
6126  *        an Octree algorithm
6127  */
6128 //================================================================================
6129
6130 void SMESH_MeshEditor::FindCoincidentNodes (TIDSortedNodeSet &   theNodes,
6131                                             const double         theTolerance,
6132                                             TListOfListOfNodes & theGroupsOfNodes)
6133 {
6134   myLastCreatedElems.Clear();
6135   myLastCreatedNodes.Clear();
6136
6137   if ( theNodes.empty() )
6138   { // get all nodes in the mesh
6139     SMDS_NodeIteratorPtr nIt = GetMeshDS()->nodesIterator(/*idInceasingOrder=*/true);
6140     while ( nIt->more() )
6141       theNodes.insert( theNodes.end(),nIt->next());
6142   }
6143
6144   SMESH_OctreeNode::FindCoincidentNodes ( theNodes, &theGroupsOfNodes, theTolerance);
6145 }
6146
6147
6148 //=======================================================================
6149 /*!
6150  * \brief Implementation of search for the node closest to point
6151  */
6152 //=======================================================================
6153
6154 struct SMESH_NodeSearcherImpl: public SMESH_NodeSearcher
6155 {
6156   //---------------------------------------------------------------------
6157   /*!
6158    * \brief Constructor
6159    */
6160   SMESH_NodeSearcherImpl( const SMESHDS_Mesh* theMesh )
6161   {
6162     myMesh = ( SMESHDS_Mesh* ) theMesh;
6163
6164     TIDSortedNodeSet nodes;
6165     if ( theMesh ) {
6166       SMDS_NodeIteratorPtr nIt = theMesh->nodesIterator(/*idInceasingOrder=*/true);
6167       while ( nIt->more() )
6168         nodes.insert( nodes.end(), nIt->next() );
6169     }
6170     myOctreeNode = new SMESH_OctreeNode(nodes) ;
6171
6172     // get max size of a leaf box
6173     SMESH_OctreeNode* tree = myOctreeNode;
6174     while ( !tree->isLeaf() )
6175     {
6176       SMESH_OctreeNodeIteratorPtr cIt = tree->GetChildrenIterator();
6177       if ( cIt->more() )
6178         tree = cIt->next();
6179     }
6180     myHalfLeafSize = tree->maxSize() / 2.;
6181   }
6182
6183   //---------------------------------------------------------------------
6184   /*!
6185    * \brief Move node and update myOctreeNode accordingly
6186    */
6187   void MoveNode( const SMDS_MeshNode* node, const gp_Pnt& toPnt )
6188   {
6189     myOctreeNode->UpdateByMoveNode( node, toPnt );
6190     myMesh->MoveNode( node, toPnt.X(), toPnt.Y(), toPnt.Z() );
6191   }
6192
6193   //---------------------------------------------------------------------
6194   /*!
6195    * \brief Do it's job
6196    */
6197   const SMDS_MeshNode* FindClosestTo( const gp_Pnt& thePnt )
6198   {
6199     map<double, const SMDS_MeshNode*> dist2Nodes;
6200     myOctreeNode->NodesAround( thePnt.Coord(), dist2Nodes, myHalfLeafSize );
6201     if ( !dist2Nodes.empty() )
6202       return dist2Nodes.begin()->second;
6203     list<const SMDS_MeshNode*> nodes;
6204     //myOctreeNode->NodesAround( &tgtNode, &nodes, myHalfLeafSize );
6205
6206     double minSqDist = DBL_MAX;
6207     if ( nodes.empty() )  // get all nodes of OctreeNode's closest to thePnt
6208     {
6209       // sort leafs by their distance from thePnt
6210       typedef map< double, SMESH_OctreeNode* > TDistTreeMap;
6211       TDistTreeMap treeMap;
6212       list< SMESH_OctreeNode* > treeList;
6213       list< SMESH_OctreeNode* >::iterator trIt;
6214       treeList.push_back( myOctreeNode );
6215
6216       gp_XYZ pointNode( thePnt.X(), thePnt.Y(), thePnt.Z() );
6217       bool pointInside = myOctreeNode->isInside( pointNode, myHalfLeafSize );
6218       for ( trIt = treeList.begin(); trIt != treeList.end(); ++trIt)
6219       {
6220         SMESH_OctreeNode* tree = *trIt;
6221         if ( !tree->isLeaf() ) // put children to the queue
6222         {
6223           if ( pointInside && !tree->isInside( pointNode, myHalfLeafSize )) continue;
6224           SMESH_OctreeNodeIteratorPtr cIt = tree->GetChildrenIterator();
6225           while ( cIt->more() )
6226             treeList.push_back( cIt->next() );
6227         }
6228         else if ( tree->NbNodes() ) // put a tree to the treeMap
6229         {
6230           const Bnd_B3d& box = tree->getBox();
6231           double sqDist = thePnt.SquareDistance( 0.5 * ( box.CornerMin() + box.CornerMax() ));
6232           pair<TDistTreeMap::iterator,bool> it_in = treeMap.insert( make_pair( sqDist, tree ));
6233           if ( !it_in.second ) // not unique distance to box center
6234             treeMap.insert( it_in.first, make_pair( sqDist + 1e-13*treeMap.size(), tree ));
6235         }
6236       }
6237       // find distance after which there is no sense to check tree's
6238       double sqLimit = DBL_MAX;
6239       TDistTreeMap::iterator sqDist_tree = treeMap.begin();
6240       if ( treeMap.size() > 5 ) {
6241         SMESH_OctreeNode* closestTree = sqDist_tree->second;
6242         const Bnd_B3d& box = closestTree->getBox();
6243         double limit = sqrt( sqDist_tree->first ) + sqrt ( box.SquareExtent() );
6244         sqLimit = limit * limit;
6245       }
6246       // get all nodes from trees
6247       for ( ; sqDist_tree != treeMap.end(); ++sqDist_tree) {
6248         if ( sqDist_tree->first > sqLimit )
6249           break;
6250         SMESH_OctreeNode* tree = sqDist_tree->second;
6251         tree->NodesAround( tree->GetNodeIterator()->next(), &nodes );
6252       }
6253     }
6254     // find closest among nodes
6255     minSqDist = DBL_MAX;
6256     const SMDS_MeshNode* closestNode = 0;
6257     list<const SMDS_MeshNode*>::iterator nIt = nodes.begin();
6258     for ( ; nIt != nodes.end(); ++nIt ) {
6259       double sqDist = thePnt.SquareDistance( SMESH_TNodeXYZ( *nIt ) );
6260       if ( minSqDist > sqDist ) {
6261         closestNode = *nIt;
6262         minSqDist = sqDist;
6263       }
6264     }
6265     return closestNode;
6266   }
6267
6268   //---------------------------------------------------------------------
6269   /*!
6270    * \brief Destructor
6271    */
6272   ~SMESH_NodeSearcherImpl() { delete myOctreeNode; }
6273
6274   //---------------------------------------------------------------------
6275   /*!
6276    * \brief Return the node tree
6277    */
6278   const SMESH_OctreeNode* getTree() const { return myOctreeNode; }
6279
6280 private:
6281   SMESH_OctreeNode* myOctreeNode;
6282   SMESHDS_Mesh*     myMesh;
6283   double            myHalfLeafSize; // max size of a leaf box
6284 };
6285
6286 //=======================================================================
6287 /*!
6288  * \brief Return SMESH_NodeSearcher
6289  */
6290 //=======================================================================
6291
6292 SMESH_NodeSearcher* SMESH_MeshEditor::GetNodeSearcher() 
6293 {
6294   return new SMESH_NodeSearcherImpl( GetMeshDS() );
6295 }
6296
6297 // ========================================================================
6298 namespace // Utils used in SMESH_ElementSearcherImpl::FindElementsByPoint()
6299 {
6300   const int MaxNbElemsInLeaf = 10; // maximal number of elements in a leaf of tree
6301   const int MaxLevel         = 7;  // maximal tree height -> nb terminal boxes: 8^7 = 2097152
6302   const double NodeRadius = 1e-9;  // to enlarge bnd box of element
6303
6304   //=======================================================================
6305   /*!
6306    * \brief Octal tree of bounding boxes of elements
6307    */
6308   //=======================================================================
6309
6310   class ElementBndBoxTree : public SMESH_Octree
6311   {
6312   public:
6313
6314     ElementBndBoxTree(const SMDS_Mesh& mesh, SMDSAbs_ElementType elemType, SMDS_ElemIteratorPtr theElemIt = SMDS_ElemIteratorPtr(), double tolerance = NodeRadius );
6315     void getElementsNearPoint( const gp_Pnt& point, TIDSortedElemSet& foundElems);
6316     void getElementsNearLine ( const gp_Ax1& line, TIDSortedElemSet& foundElems);
6317     ~ElementBndBoxTree();
6318
6319   protected:
6320     ElementBndBoxTree() {}
6321     SMESH_Octree* allocateOctreeChild() const { return new ElementBndBoxTree; }
6322     void buildChildrenData();
6323     Bnd_B3d* buildRootBox();
6324   private:
6325     //!< Bounding box of element
6326     struct ElementBox : public Bnd_B3d
6327     {
6328       const SMDS_MeshElement* _element;
6329       int                     _refCount; // an ElementBox can be included in several tree branches
6330       ElementBox(const SMDS_MeshElement* elem, double tolerance);
6331     };
6332     vector< ElementBox* > _elements;
6333   };
6334
6335   //================================================================================
6336   /*!
6337    * \brief ElementBndBoxTree creation
6338    */
6339   //================================================================================
6340
6341   ElementBndBoxTree::ElementBndBoxTree(const SMDS_Mesh& mesh, SMDSAbs_ElementType elemType, SMDS_ElemIteratorPtr theElemIt, double tolerance)
6342     :SMESH_Octree( new SMESH_Octree::Limit( MaxLevel, /*minSize=*/0. ))
6343   {
6344     int nbElems = mesh.GetMeshInfo().NbElements( elemType );
6345     _elements.reserve( nbElems );
6346
6347     SMDS_ElemIteratorPtr elemIt = theElemIt ? theElemIt : mesh.elementsIterator( elemType );
6348     while ( elemIt->more() )
6349       _elements.push_back( new ElementBox( elemIt->next(),tolerance  ));
6350
6351     if ( _elements.size() > MaxNbElemsInLeaf )
6352       compute();
6353     else
6354       myIsLeaf = true;
6355   }
6356
6357   //================================================================================
6358   /*!
6359    * \brief Destructor
6360    */
6361   //================================================================================
6362
6363   ElementBndBoxTree::~ElementBndBoxTree()
6364   {
6365     for ( int i = 0; i < _elements.size(); ++i )
6366       if ( --_elements[i]->_refCount <= 0 )
6367         delete _elements[i];
6368   }
6369
6370   //================================================================================
6371   /*!
6372    * \brief Return the maximal box
6373    */
6374   //================================================================================
6375
6376   Bnd_B3d* ElementBndBoxTree::buildRootBox()
6377   {
6378     Bnd_B3d* box = new Bnd_B3d;
6379     for ( int i = 0; i < _elements.size(); ++i )
6380       box->Add( *_elements[i] );
6381     return box;
6382   }
6383
6384   //================================================================================
6385   /*!
6386    * \brief Redistrubute element boxes among children
6387    */
6388   //================================================================================
6389
6390   void ElementBndBoxTree::buildChildrenData()
6391   {
6392     for ( int i = 0; i < _elements.size(); ++i )
6393     {
6394       for (int j = 0; j < 8; j++)
6395       {
6396         if ( !_elements[i]->IsOut( myChildren[j]->getBox() ))
6397         {
6398           _elements[i]->_refCount++;
6399           ((ElementBndBoxTree*)myChildren[j])->_elements.push_back( _elements[i]);
6400         }
6401       }
6402       _elements[i]->_refCount--;
6403     }
6404     _elements.clear();
6405
6406     for (int j = 0; j < 8; j++)
6407     {
6408       ElementBndBoxTree* child = static_cast<ElementBndBoxTree*>( myChildren[j]);
6409       if ( child->_elements.size() <= MaxNbElemsInLeaf )
6410         child->myIsLeaf = true;
6411
6412       if ( child->_elements.capacity() - child->_elements.size() > 1000 )
6413         child->_elements.resize( child->_elements.size() ); // compact
6414     }
6415   }
6416
6417   //================================================================================
6418   /*!
6419    * \brief Return elements which can include the point
6420    */
6421   //================================================================================
6422
6423   void ElementBndBoxTree::getElementsNearPoint( const gp_Pnt&     point,
6424                                                 TIDSortedElemSet& foundElems)
6425   {
6426     if ( level() && getBox().IsOut( point.XYZ() ))
6427       return;
6428
6429     if ( isLeaf() )
6430     {
6431       for ( int i = 0; i < _elements.size(); ++i )
6432         if ( !_elements[i]->IsOut( point.XYZ() ))
6433           foundElems.insert( _elements[i]->_element );
6434     }
6435     else
6436     {
6437       for (int i = 0; i < 8; i++)
6438         ((ElementBndBoxTree*) myChildren[i])->getElementsNearPoint( point, foundElems );
6439     }
6440   }
6441
6442   //================================================================================
6443   /*!
6444    * \brief Return elements which can be intersected by the line
6445    */
6446   //================================================================================
6447
6448   void ElementBndBoxTree::getElementsNearLine( const gp_Ax1&     line,
6449                                                TIDSortedElemSet& foundElems)
6450   {
6451     if ( level() && getBox().IsOut( line ))
6452       return;
6453
6454     if ( isLeaf() )
6455     {
6456       for ( int i = 0; i < _elements.size(); ++i )
6457         if ( !_elements[i]->IsOut( line ))
6458           foundElems.insert( _elements[i]->_element );
6459     }
6460     else
6461     {
6462       for (int i = 0; i < 8; i++)
6463         ((ElementBndBoxTree*) myChildren[i])->getElementsNearLine( line, foundElems );
6464     }
6465   }
6466
6467   //================================================================================
6468   /*!
6469    * \brief Construct the element box
6470    */
6471   //================================================================================
6472
6473   ElementBndBoxTree::ElementBox::ElementBox(const SMDS_MeshElement* elem, double tolerance)
6474   {
6475     _element  = elem;
6476     _refCount = 1;
6477     SMDS_ElemIteratorPtr nIt = elem->nodesIterator();
6478     while ( nIt->more() )
6479       Add( SMESH_TNodeXYZ( cast2Node( nIt->next() )));
6480     Enlarge( tolerance );
6481   }
6482
6483 } // namespace
6484
6485 //=======================================================================
6486 /*!
6487  * \brief Implementation of search for the elements by point and
6488  *        of classification of point in 2D mesh
6489  */
6490 //=======================================================================
6491
6492 struct SMESH_ElementSearcherImpl: public SMESH_ElementSearcher
6493 {
6494   SMESHDS_Mesh*                _mesh;
6495   SMDS_ElemIteratorPtr         _meshPartIt;
6496   ElementBndBoxTree*           _ebbTree;
6497   SMESH_NodeSearcherImpl*      _nodeSearcher;
6498   SMDSAbs_ElementType          _elementType;
6499   double                       _tolerance;
6500   bool                         _outerFacesFound;
6501   set<const SMDS_MeshElement*> _outerFaces; // empty means "no internal faces at all"
6502
6503   SMESH_ElementSearcherImpl( SMESHDS_Mesh& mesh, SMDS_ElemIteratorPtr elemIt=SMDS_ElemIteratorPtr())
6504     : _mesh(&mesh),_meshPartIt(elemIt),_ebbTree(0),_nodeSearcher(0),_tolerance(-1),_outerFacesFound(false) {}
6505   ~SMESH_ElementSearcherImpl()
6506   {
6507     if ( _ebbTree )      delete _ebbTree;      _ebbTree      = 0;
6508     if ( _nodeSearcher ) delete _nodeSearcher; _nodeSearcher = 0;
6509   }
6510   virtual int FindElementsByPoint(const gp_Pnt&                      point,
6511                                   SMDSAbs_ElementType                type,
6512                                   vector< const SMDS_MeshElement* >& foundElements);
6513   virtual TopAbs_State GetPointState(const gp_Pnt& point);
6514
6515   void GetElementsNearLine( const gp_Ax1&                      line,
6516                             SMDSAbs_ElementType                type,
6517                             vector< const SMDS_MeshElement* >& foundElems);
6518   double getTolerance();
6519   bool getIntersParamOnLine(const gp_Lin& line, const SMDS_MeshElement* face,
6520                             const double tolerance, double & param);
6521   void findOuterBoundary(const SMDS_MeshElement* anyOuterFace);
6522   bool isOuterBoundary(const SMDS_MeshElement* face) const
6523   {
6524     return _outerFaces.empty() || _outerFaces.count(face);
6525   }
6526   struct TInters //!< data of intersection of the line and the mesh face (used in GetPointState())
6527   {
6528     const SMDS_MeshElement* _face;
6529     gp_Vec                  _faceNorm;
6530     bool                    _coincides; //!< the line lays in face plane
6531     TInters(const SMDS_MeshElement* face, const gp_Vec& faceNorm, bool coinc=false)
6532       : _face(face), _faceNorm( faceNorm ), _coincides( coinc ) {}
6533   };
6534   struct TFaceLink //!< link and faces sharing it (used in findOuterBoundary())
6535   {
6536     SMESH_TLink      _link;
6537     TIDSortedElemSet _faces;
6538     TFaceLink( const SMDS_MeshNode* n1, const SMDS_MeshNode* n2, const SMDS_MeshElement* face)
6539       : _link( n1, n2 ), _faces( &face, &face + 1) {}
6540   };
6541 };
6542
6543 ostream& operator<< (ostream& out, const SMESH_ElementSearcherImpl::TInters& i)
6544 {
6545   return out << "TInters(face=" << ( i._face ? i._face->GetID() : 0)
6546              << ", _coincides="<<i._coincides << ")";
6547 }
6548
6549 //=======================================================================
6550 /*!
6551  * \brief define tolerance for search
6552  */
6553 //=======================================================================
6554
6555 double SMESH_ElementSearcherImpl::getTolerance()
6556 {
6557   if ( _tolerance < 0 )
6558   {
6559     const SMDS_MeshInfo& meshInfo = _mesh->GetMeshInfo();
6560
6561     _tolerance = 0;
6562     if ( _nodeSearcher && meshInfo.NbNodes() > 1 )
6563     {
6564       double boxSize = _nodeSearcher->getTree()->maxSize();
6565       _tolerance = 1e-8 * boxSize/* / meshInfo.NbNodes()*/;
6566     }
6567     else if ( _ebbTree && meshInfo.NbElements() > 0 )
6568     {
6569       double boxSize = _ebbTree->maxSize();
6570       _tolerance = 1e-8 * boxSize/* / meshInfo.NbElements()*/;
6571     }
6572     if ( _tolerance == 0 )
6573     {
6574       // define tolerance by size of a most complex element
6575       int complexType = SMDSAbs_Volume;
6576       while ( complexType > SMDSAbs_All &&
6577               meshInfo.NbElements( SMDSAbs_ElementType( complexType )) < 1 )
6578         --complexType;
6579       if ( complexType == SMDSAbs_All ) return 0; // empty mesh
6580       double elemSize;
6581       if ( complexType == int( SMDSAbs_Node ))
6582       {
6583         SMDS_NodeIteratorPtr nodeIt = _mesh->nodesIterator();
6584         elemSize = 1;
6585         if ( meshInfo.NbNodes() > 2 )
6586           elemSize = SMESH_TNodeXYZ( nodeIt->next() ).Distance( nodeIt->next() );
6587       }
6588       else
6589       {
6590         SMDS_ElemIteratorPtr elemIt =
6591             _mesh->elementsIterator( SMDSAbs_ElementType( complexType ));
6592         const SMDS_MeshElement* elem = elemIt->next();
6593         SMDS_ElemIteratorPtr nodeIt = elem->nodesIterator();
6594         SMESH_TNodeXYZ n1( cast2Node( nodeIt->next() ));
6595         elemSize = 0;
6596         while ( nodeIt->more() )
6597         {
6598           double dist = n1.Distance( cast2Node( nodeIt->next() ));
6599           elemSize = max( dist, elemSize );
6600         }
6601       }
6602       _tolerance = 1e-4 * elemSize;
6603     }
6604   }
6605   return _tolerance;
6606 }
6607
6608 //================================================================================
6609 /*!
6610  * \brief Find intersection of the line and an edge of face and return parameter on line
6611  */
6612 //================================================================================
6613
6614 bool SMESH_ElementSearcherImpl::getIntersParamOnLine(const gp_Lin&           line,
6615                                                      const SMDS_MeshElement* face,
6616                                                      const double            tol,
6617                                                      double &                param)
6618 {
6619   int nbInts = 0;
6620   param = 0;
6621
6622   GeomAPI_ExtremaCurveCurve anExtCC;
6623   Handle(Geom_Curve) lineCurve = new Geom_Line( line );
6624   
6625   int nbNodes = face->IsQuadratic() ? face->NbNodes()/2 : face->NbNodes();
6626   for ( int i = 0; i < nbNodes && nbInts < 2; ++i )
6627   {
6628     GC_MakeSegment edge( SMESH_TNodeXYZ( face->GetNode( i )),
6629                          SMESH_TNodeXYZ( face->GetNode( (i+1)%nbNodes) )); 
6630     anExtCC.Init( lineCurve, edge);
6631     if ( anExtCC.NbExtrema() > 0 && anExtCC.LowerDistance() <= tol)
6632     {
6633       Quantity_Parameter pl, pe;
6634       anExtCC.LowerDistanceParameters( pl, pe );
6635       param += pl;
6636       if ( ++nbInts == 2 )
6637         break;
6638     }
6639   }
6640   if ( nbInts > 0 ) param /= nbInts;
6641   return nbInts > 0;
6642 }
6643 //================================================================================
6644 /*!
6645  * \brief Find all faces belonging to the outer boundary of mesh
6646  */
6647 //================================================================================
6648
6649 void SMESH_ElementSearcherImpl::findOuterBoundary(const SMDS_MeshElement* outerFace)
6650 {
6651   if ( _outerFacesFound ) return;
6652
6653   // Collect all outer faces by passing from one outer face to another via their links
6654   // and BTW find out if there are internal faces at all.
6655
6656   // checked links and links where outer boundary meets internal one
6657   set< SMESH_TLink > visitedLinks, seamLinks;
6658
6659   // links to treat with already visited faces sharing them
6660   list < TFaceLink > startLinks;
6661
6662   // load startLinks with the first outerFace
6663   startLinks.push_back( TFaceLink( outerFace->GetNode(0), outerFace->GetNode(1), outerFace));
6664   _outerFaces.insert( outerFace );
6665
6666   TIDSortedElemSet emptySet;
6667   while ( !startLinks.empty() )
6668   {
6669     const SMESH_TLink& link  = startLinks.front()._link;
6670     TIDSortedElemSet&  faces = startLinks.front()._faces;
6671
6672     outerFace = *faces.begin();
6673     // find other faces sharing the link
6674     const SMDS_MeshElement* f;
6675     while (( f = SMESH_MeshEditor::FindFaceInSet(link.node1(), link.node2(), emptySet, faces )))
6676       faces.insert( f );
6677
6678     // select another outer face among the found 
6679     const SMDS_MeshElement* outerFace2 = 0;
6680     if ( faces.size() == 2 )
6681     {
6682       outerFace2 = (outerFace == *faces.begin() ? *faces.rbegin() : *faces.begin());
6683     }
6684     else if ( faces.size() > 2 )
6685     {
6686       seamLinks.insert( link );
6687
6688       // link direction within the outerFace
6689       gp_Vec n1n2( SMESH_TNodeXYZ( link.node1()),
6690                    SMESH_TNodeXYZ( link.node2()));
6691       int i1 = outerFace->GetNodeIndex( link.node1() );
6692       int i2 = outerFace->GetNodeIndex( link.node2() );
6693       bool rev = ( abs(i2-i1) == 1 ? i1 > i2 : i2 > i1 );
6694       if ( rev ) n1n2.Reverse();
6695       // outerFace normal
6696       gp_XYZ ofNorm, fNorm;
6697       if ( SMESH_Algo::FaceNormal( outerFace, ofNorm, /*normalized=*/false ))
6698       {
6699         // direction from the link inside outerFace
6700         gp_Vec dirInOF = gp_Vec( ofNorm ) ^ n1n2;
6701         // sort all other faces by angle with the dirInOF
6702         map< double, const SMDS_MeshElement* > angle2Face;
6703         set< const SMDS_MeshElement*, TIDCompare >::const_iterator face = faces.begin();
6704         for ( ; face != faces.end(); ++face )
6705         {
6706           if ( !SMESH_Algo::FaceNormal( *face, fNorm, /*normalized=*/false ))
6707             continue;
6708           gp_Vec dirInF = gp_Vec( fNorm ) ^ n1n2;
6709           double angle = dirInOF.AngleWithRef( dirInF, n1n2 );
6710           if ( angle < 0 ) angle += 2*PI;
6711           angle2Face.insert( make_pair( angle, *face ));
6712         }
6713         if ( !angle2Face.empty() )
6714           outerFace2 = angle2Face.begin()->second;
6715       }
6716     }
6717     // store the found outer face and add its links to continue seaching from
6718     if ( outerFace2 )
6719     {
6720       _outerFaces.insert( outerFace );
6721       int nbNodes = outerFace2->NbNodes()/( outerFace2->IsQuadratic() ? 2 : 1 );
6722       for ( int i = 0; i < nbNodes; ++i )
6723       {
6724         SMESH_TLink link2( outerFace2->GetNode(i), outerFace2->GetNode((i+1)%nbNodes));
6725         if ( visitedLinks.insert( link2 ).second )
6726           startLinks.push_back( TFaceLink( link2.node1(), link2.node2(), outerFace2 ));
6727       }
6728     }
6729     startLinks.pop_front();
6730   }
6731   _outerFacesFound = true;
6732
6733   if ( !seamLinks.empty() )
6734   {
6735     // There are internal boundaries touching the outher one,
6736     // find all faces of internal boundaries in order to find
6737     // faces of boundaries of holes, if any.
6738     
6739   }
6740   else
6741   {
6742     _outerFaces.clear();
6743   }
6744 }
6745
6746 //=======================================================================
6747 /*!
6748  * \brief Find elements of given type where the given point is IN or ON.
6749  *        Returns nb of found elements and elements them-selves.
6750  *
6751  * 'ALL' type means elements of any type excluding nodes and 0D elements
6752  */
6753 //=======================================================================
6754
6755 int SMESH_ElementSearcherImpl::
6756 FindElementsByPoint(const gp_Pnt&                      point,
6757                     SMDSAbs_ElementType                type,
6758                     vector< const SMDS_MeshElement* >& foundElements)
6759 {
6760   foundElements.clear();
6761
6762   double tolerance = getTolerance();
6763
6764   // =================================================================================
6765   if ( type == SMDSAbs_Node || type == SMDSAbs_0DElement )
6766   {
6767     if ( !_nodeSearcher )
6768       _nodeSearcher = new SMESH_NodeSearcherImpl( _mesh );
6769
6770     const SMDS_MeshNode* closeNode = _nodeSearcher->FindClosestTo( point );
6771     if ( !closeNode ) return foundElements.size();
6772
6773     if ( point.Distance( SMESH_TNodeXYZ( closeNode )) > tolerance )
6774       return foundElements.size(); // to far from any node
6775
6776     if ( type == SMDSAbs_Node )
6777     {
6778       foundElements.push_back( closeNode );
6779     }
6780     else
6781     {
6782       SMDS_ElemIteratorPtr elemIt = closeNode->GetInverseElementIterator( SMDSAbs_0DElement );
6783       while ( elemIt->more() )
6784         foundElements.push_back( elemIt->next() );
6785     }
6786   }
6787   // =================================================================================
6788   else // elements more complex than 0D
6789   {
6790     if ( !_ebbTree || _elementType != type )
6791     {
6792       if ( _ebbTree ) delete _ebbTree;
6793       _ebbTree = new ElementBndBoxTree( *_mesh, _elementType = type, _meshPartIt, tolerance );
6794     }
6795     TIDSortedElemSet suspectElems;
6796     _ebbTree->getElementsNearPoint( point, suspectElems );
6797     TIDSortedElemSet::iterator elem = suspectElems.begin();
6798     for ( ; elem != suspectElems.end(); ++elem )
6799       if ( !SMESH_MeshEditor::isOut( *elem, point, tolerance ))
6800         foundElements.push_back( *elem );
6801   }
6802   return foundElements.size();
6803 }
6804
6805 //================================================================================
6806 /*!
6807  * \brief Classify the given point in the closed 2D mesh
6808  */
6809 //================================================================================
6810
6811 TopAbs_State SMESH_ElementSearcherImpl::GetPointState(const gp_Pnt& point)
6812 {
6813   double tolerance = getTolerance();
6814   if ( !_ebbTree || _elementType != SMDSAbs_Face )
6815   {
6816     if ( _ebbTree ) delete _ebbTree;
6817     _ebbTree = new ElementBndBoxTree( *_mesh, _elementType = SMDSAbs_Face, _meshPartIt );
6818   }
6819   // Algo: analyse transition of a line starting at the point through mesh boundary;
6820   // try three lines parallel to axis of the coordinate system and perform rough
6821   // analysis. If solution is not clear perform thorough analysis.
6822
6823   const int nbAxes = 3;
6824   gp_Dir axisDir[ nbAxes ] = { gp::DX(), gp::DY(), gp::DZ() };
6825   map< double, TInters >   paramOnLine2TInters[ nbAxes ];
6826   list< TInters > tangentInters[ nbAxes ]; // of faces whose plane includes the line
6827   multimap< int, int > nbInt2Axis; // to find the simplest case
6828   for ( int axis = 0; axis < nbAxes; ++axis )
6829   {
6830     gp_Ax1 lineAxis( point, axisDir[axis]);
6831     gp_Lin line    ( lineAxis );
6832
6833     TIDSortedElemSet suspectFaces; // faces possibly intersecting the line
6834     _ebbTree->getElementsNearLine( lineAxis, suspectFaces );
6835
6836     // Intersect faces with the line
6837
6838     map< double, TInters > & u2inters = paramOnLine2TInters[ axis ];
6839     TIDSortedElemSet::iterator face = suspectFaces.begin();
6840     for ( ; face != suspectFaces.end(); ++face )
6841     {
6842       // get face plane
6843       gp_XYZ fNorm;
6844       if ( !SMESH_Algo::FaceNormal( *face, fNorm, /*normalized=*/false)) continue;
6845       gp_Pln facePlane( SMESH_TNodeXYZ( (*face)->GetNode(0)), fNorm );
6846
6847       // perform intersection
6848       IntAna_IntConicQuad intersection( line, IntAna_Quadric( facePlane ));
6849       if ( !intersection.IsDone() )
6850         continue;
6851       if ( intersection.IsInQuadric() )
6852       {
6853         tangentInters[ axis ].push_back( TInters( *face, fNorm, true ));
6854       }
6855       else if ( ! intersection.IsParallel() && intersection.NbPoints() > 0 )
6856       {
6857         gp_Pnt intersectionPoint = intersection.Point(1);
6858         if ( !SMESH_MeshEditor::isOut( *face, intersectionPoint, tolerance ))
6859           u2inters.insert(make_pair( intersection.ParamOnConic(1), TInters( *face, fNorm )));
6860       }
6861     }
6862     // Analyse intersections roughly
6863
6864     int nbInter = u2inters.size();
6865     if ( nbInter == 0 )
6866       return TopAbs_OUT; 
6867
6868     double f = u2inters.begin()->first, l = u2inters.rbegin()->first;
6869     if ( nbInter == 1 ) // not closed mesh
6870       return fabs( f ) < tolerance ? TopAbs_ON : TopAbs_UNKNOWN;
6871
6872     if ( fabs( f ) < tolerance || fabs( l ) < tolerance )
6873       return TopAbs_ON;
6874
6875     if ( (f<0) == (l<0) )
6876       return TopAbs_OUT;
6877
6878     int nbIntBeforePoint = std::distance( u2inters.begin(), u2inters.lower_bound(0));
6879     int nbIntAfterPoint  = nbInter - nbIntBeforePoint;
6880     if ( nbIntBeforePoint == 1 || nbIntAfterPoint == 1 )
6881       return TopAbs_IN;
6882
6883     nbInt2Axis.insert( make_pair( min( nbIntBeforePoint, nbIntAfterPoint ), axis ));
6884
6885     if ( _outerFacesFound ) break; // pass to thorough analysis
6886
6887   } // three attempts - loop on CS axes
6888
6889   // Analyse intersections thoroughly.
6890   // We make two loops maximum, on the first one we only exclude touching intersections,
6891   // on the second, if situation is still unclear, we gather and use information on
6892   // position of faces (internal or outer). If faces position is already gathered,
6893   // we make the second loop right away.
6894
6895   for ( int hasPositionInfo = _outerFacesFound; hasPositionInfo < 2; ++hasPositionInfo )
6896   {
6897     multimap< int, int >::const_iterator nb_axis = nbInt2Axis.begin();
6898     for ( ; nb_axis != nbInt2Axis.end(); ++nb_axis )
6899     {
6900       int axis = nb_axis->second;
6901       map< double, TInters > & u2inters = paramOnLine2TInters[ axis ];
6902
6903       gp_Ax1 lineAxis( point, axisDir[axis]);
6904       gp_Lin line    ( lineAxis );
6905
6906       // add tangent intersections to u2inters
6907       double param;
6908       list< TInters >::const_iterator tgtInt = tangentInters[ axis ].begin();
6909       for ( ; tgtInt != tangentInters[ axis ].end(); ++tgtInt )
6910         if ( getIntersParamOnLine( line, tgtInt->_face, tolerance, param ))
6911           u2inters.insert(make_pair( param, *tgtInt ));
6912       tangentInters[ axis ].clear();
6913
6914       // Count intersections before and after the point excluding touching ones.
6915       // If hasPositionInfo we count intersections of outer boundary only
6916
6917       int nbIntBeforePoint = 0, nbIntAfterPoint = 0;
6918       double f = numeric_limits<double>::max(), l = -numeric_limits<double>::max();
6919       map< double, TInters >::iterator u_int1 = u2inters.begin(), u_int2 = u_int1;
6920       bool ok = ! u_int1->second._coincides;
6921       while ( ok && u_int1 != u2inters.end() )
6922       {
6923         double u = u_int1->first;
6924         bool touchingInt = false;
6925         if ( ++u_int2 != u2inters.end() )
6926         {
6927           // skip intersections at the same point (if the line passes through edge or node)
6928           int nbSamePnt = 0;
6929           while ( u_int2 != u2inters.end() && fabs( u_int2->first - u ) < tolerance )
6930           {
6931             ++nbSamePnt;
6932             ++u_int2;
6933           }
6934
6935           // skip tangent intersections
6936           int nbTgt = 0;
6937           const SMDS_MeshElement* prevFace = u_int1->second._face;
6938           while ( ok && u_int2->second._coincides )
6939           {
6940             if ( SMESH_Algo::GetCommonNodes(prevFace , u_int2->second._face).empty() )
6941               ok = false;
6942             else
6943             {
6944               nbTgt++;
6945               u_int2++;
6946               ok = ( u_int2 != u2inters.end() );
6947             }
6948           }
6949           if ( !ok ) break;
6950
6951           // skip intersections at the same point after tangent intersections
6952           if ( nbTgt > 0 )
6953           {
6954             double u2 = u_int2->first;
6955             ++u_int2;
6956             while ( u_int2 != u2inters.end() && fabs( u_int2->first - u2 ) < tolerance )
6957             {
6958               ++nbSamePnt;
6959               ++u_int2;
6960             }
6961           }
6962           // decide if we skipped a touching intersection
6963           if ( nbSamePnt + nbTgt > 0 )
6964           {
6965             double minDot = numeric_limits<double>::max(), maxDot = -numeric_limits<double>::max();
6966             map< double, TInters >::iterator u_int = u_int1;
6967             for ( ; u_int != u_int2; ++u_int )
6968             {
6969               if ( u_int->second._coincides ) continue;
6970               double dot = u_int->second._faceNorm * line.Direction();
6971               if ( dot > maxDot ) maxDot = dot;
6972               if ( dot < minDot ) minDot = dot;
6973             }
6974             touchingInt = ( minDot*maxDot < 0 );
6975           }
6976         }
6977         if ( !touchingInt )
6978         {
6979           if ( !hasPositionInfo || isOuterBoundary( u_int1->second._face ))
6980           {
6981             if ( u < 0 )
6982               ++nbIntBeforePoint;
6983             else
6984               ++nbIntAfterPoint;
6985           }
6986           if ( u < f ) f = u;
6987           if ( u > l ) l = u;
6988         }
6989
6990         u_int1 = u_int2; // to next intersection
6991
6992       } // loop on intersections with one line
6993
6994       if ( ok )
6995       {
6996         if ( fabs( f ) < tolerance || fabs( l ) < tolerance )
6997           return TopAbs_ON;
6998
6999         if ( nbIntBeforePoint == 0  || nbIntAfterPoint == 0)
7000           return TopAbs_OUT; 
7001
7002         if ( nbIntBeforePoint + nbIntAfterPoint == 1 ) // not closed mesh
7003           return fabs( f ) < tolerance ? TopAbs_ON : TopAbs_UNKNOWN;
7004
7005         if ( nbIntBeforePoint == 1 || nbIntAfterPoint == 1 )
7006           return TopAbs_IN;
7007
7008         if ( (f<0) == (l<0) )
7009           return TopAbs_OUT;
7010
7011         if ( hasPositionInfo )
7012           return nbIntBeforePoint % 2 ? TopAbs_IN : TopAbs_OUT;
7013       }
7014     } // loop on intersections of the tree lines - thorough analysis
7015
7016     if ( !hasPositionInfo )
7017     {
7018       // gather info on faces position - is face in the outer boundary or not
7019       map< double, TInters > & u2inters = paramOnLine2TInters[ 0 ];
7020       findOuterBoundary( u2inters.begin()->second._face );
7021     }
7022
7023   } // two attempts - with and w/o faces position info in the mesh
7024
7025   return TopAbs_UNKNOWN;
7026 }
7027
7028 //=======================================================================
7029 /*!
7030  * \brief Return elements possibly intersecting the line
7031  */
7032 //=======================================================================
7033
7034 void SMESH_ElementSearcherImpl::GetElementsNearLine( const gp_Ax1&                      line,
7035                                                      SMDSAbs_ElementType                type,
7036                                                      vector< const SMDS_MeshElement* >& foundElems)
7037 {
7038   if ( !_ebbTree || _elementType != type )
7039   {
7040     if ( _ebbTree ) delete _ebbTree;
7041     _ebbTree = new ElementBndBoxTree( *_mesh, _elementType = type, _meshPartIt );
7042   }
7043   TIDSortedElemSet suspectFaces; // elements possibly intersecting the line
7044   _ebbTree->getElementsNearLine( line, suspectFaces );
7045   foundElems.assign( suspectFaces.begin(), suspectFaces.end());
7046 }
7047
7048 //=======================================================================
7049 /*!
7050  * \brief Return SMESH_ElementSearcher
7051  */
7052 //=======================================================================
7053
7054 SMESH_ElementSearcher* SMESH_MeshEditor::GetElementSearcher()
7055 {
7056   return new SMESH_ElementSearcherImpl( *GetMeshDS() );
7057 }
7058
7059 //=======================================================================
7060 /*!
7061  * \brief Return SMESH_ElementSearcher
7062  */
7063 //=======================================================================
7064
7065 SMESH_ElementSearcher* SMESH_MeshEditor::GetElementSearcher(SMDS_ElemIteratorPtr elemIt)
7066 {
7067   return new SMESH_ElementSearcherImpl( *GetMeshDS(), elemIt );
7068 }
7069
7070 //=======================================================================
7071 /*!
7072  * \brief Return true if the point is IN or ON of the element
7073  */
7074 //=======================================================================
7075
7076 bool SMESH_MeshEditor::isOut( const SMDS_MeshElement* element, const gp_Pnt& point, double tol )
7077 {
7078   if ( element->GetType() == SMDSAbs_Volume)
7079   {
7080     return SMDS_VolumeTool( element ).IsOut( point.X(), point.Y(), point.Z(), tol );
7081   }
7082
7083   // get ordered nodes
7084
7085   vector< gp_XYZ > xyz;
7086   vector<const SMDS_MeshNode*> nodeList;
7087
7088   SMDS_ElemIteratorPtr nodeIt = element->nodesIterator();
7089   if ( element->IsQuadratic() ) {
7090     if (const SMDS_VtkFace* f=dynamic_cast<const SMDS_VtkFace*>(element))
7091       nodeIt = f->interlacedNodesElemIterator();
7092     else if (const SMDS_VtkEdge*  e =dynamic_cast<const SMDS_VtkEdge*>(element))
7093       nodeIt = e->interlacedNodesElemIterator();
7094   }
7095   while ( nodeIt->more() )
7096     {
7097       const SMDS_MeshNode* node = cast2Node( nodeIt->next() );
7098       xyz.push_back( SMESH_TNodeXYZ(node) );
7099       nodeList.push_back(node);
7100     }
7101
7102   int i, nbNodes = element->NbNodes();
7103
7104   if ( element->GetType() == SMDSAbs_Face ) // --------------------------------------------------
7105   {
7106     // compute face normal
7107     gp_Vec faceNorm(0,0,0);
7108     xyz.push_back( xyz.front() );
7109     nodeList.push_back( nodeList.front() );
7110     for ( i = 0; i < nbNodes; ++i )
7111     {
7112       gp_Vec edge1( xyz[i+1], xyz[i]);
7113       gp_Vec edge2( xyz[i+1], xyz[(i+2)%nbNodes] );
7114       faceNorm += edge1 ^ edge2;
7115     }
7116     double normSize = faceNorm.Magnitude();
7117     if ( normSize <= tol )
7118     {
7119       // degenerated face: point is out if it is out of all face edges
7120       for ( i = 0; i < nbNodes; ++i )
7121       {
7122         SMDS_LinearEdge edge( nodeList[i], nodeList[i+1] );
7123         if ( !isOut( &edge, point, tol ))
7124           return false;
7125       }
7126       return true;
7127     }
7128     faceNorm /= normSize;
7129
7130     // check if the point lays on face plane
7131     gp_Vec n2p( xyz[0], point );
7132     if ( fabs( n2p * faceNorm ) > tol )
7133       return true; // not on face plane
7134
7135     // check if point is out of face boundary:
7136     // define it by closest transition of a ray point->infinity through face boundary
7137     // on the face plane.
7138     // First, find normal of a plane perpendicular to face plane, to be used as a cutting tool
7139     // to find intersections of the ray with the boundary.
7140     gp_Vec ray = n2p;
7141     gp_Vec plnNorm = ray ^ faceNorm;
7142     normSize = plnNorm.Magnitude();
7143     if ( normSize <= tol ) return false; // point coincides with the first node
7144     plnNorm /= normSize;
7145     // for each node of the face, compute its signed distance to the plane
7146     vector<double> dist( nbNodes + 1);
7147     for ( i = 0; i < nbNodes; ++i )
7148     {
7149       gp_Vec n2p( xyz[i], point );
7150       dist[i] = n2p * plnNorm;
7151     }
7152     dist.back() = dist.front();
7153     // find the closest intersection
7154     int    iClosest = -1;
7155     double rClosest, distClosest = 1e100;;
7156     gp_Pnt pClosest;
7157     for ( i = 0; i < nbNodes; ++i )
7158     {
7159       double r;
7160       if ( fabs( dist[i]) < tol )
7161         r = 0.;
7162       else if ( fabs( dist[i+1]) < tol )
7163         r = 1.;
7164       else if ( dist[i] * dist[i+1] < 0 )
7165         r = dist[i] / ( dist[i] - dist[i+1] );
7166       else
7167         continue; // no intersection
7168       gp_Pnt pInt = xyz[i] * (1.-r) + xyz[i+1] * r;
7169       gp_Vec p2int ( point, pInt);
7170       if ( p2int * ray > -tol ) // right half-space
7171       {
7172         double intDist = p2int.SquareMagnitude();
7173         if ( intDist < distClosest )
7174         {
7175           iClosest = i;
7176           rClosest = r;
7177           pClosest = pInt;
7178           distClosest = intDist;
7179         }
7180       }
7181     }
7182     if ( iClosest < 0 )
7183       return true; // no intesections - out
7184
7185     // analyse transition
7186     gp_Vec edge( xyz[iClosest], xyz[iClosest+1] );
7187     gp_Vec edgeNorm = -( edge ^ faceNorm ); // normal to intersected edge pointing out of face
7188     gp_Vec p2int ( point, pClosest );
7189     bool out = (edgeNorm * p2int) < -tol;
7190     if ( rClosest > 0. && rClosest < 1. ) // not node intersection
7191       return out;
7192
7193     // ray pass through a face node; analyze transition through an adjacent edge
7194     gp_Pnt p1 = xyz[ (rClosest == 0.) ? ((iClosest+nbNodes-1) % nbNodes) : (iClosest+1) ];
7195     gp_Pnt p2 = xyz[ (rClosest == 0.) ? iClosest : ((iClosest+2) % nbNodes) ];
7196     gp_Vec edgeAdjacent( p1, p2 );
7197     gp_Vec edgeNorm2 = -( edgeAdjacent ^ faceNorm );
7198     bool out2 = (edgeNorm2 * p2int) < -tol;
7199
7200     bool covexCorner = ( edgeNorm * edgeAdjacent * (rClosest==1. ? 1. : -1.)) < 0;
7201     return covexCorner ? (out || out2) : (out && out2);
7202   }
7203   if ( element->GetType() == SMDSAbs_Edge ) // --------------------------------------------------
7204   {
7205     // point is out of edge if it is NOT ON any straight part of edge
7206     // (we consider quadratic edge as being composed of two straight parts)
7207     for ( i = 1; i < nbNodes; ++i )
7208     {
7209       gp_Vec edge( xyz[i-1], xyz[i]);
7210       gp_Vec n1p ( xyz[i-1], point);
7211       double dist = ( edge ^ n1p ).Magnitude() / edge.Magnitude();
7212       if ( dist > tol )
7213         continue;
7214       gp_Vec n2p( xyz[i], point );
7215       if ( fabs( edge.Magnitude() - n1p.Magnitude() - n2p.Magnitude()) > tol )
7216         continue;
7217       return false; // point is ON this part
7218     }
7219     return true;
7220   }
7221   // Node or 0D element -------------------------------------------------------------------------
7222   {
7223     gp_Vec n2p ( xyz[0], point );
7224     return n2p.Magnitude() <= tol;
7225   }
7226   return true;
7227 }
7228
7229 //=======================================================================
7230 //function : SimplifyFace
7231 //purpose  :
7232 //=======================================================================
7233 int SMESH_MeshEditor::SimplifyFace (const vector<const SMDS_MeshNode *> faceNodes,
7234                                     vector<const SMDS_MeshNode *>&      poly_nodes,
7235                                     vector<int>&                        quantities) const
7236 {
7237   int nbNodes = faceNodes.size();
7238
7239   if (nbNodes < 3)
7240     return 0;
7241
7242   set<const SMDS_MeshNode*> nodeSet;
7243
7244   // get simple seq of nodes
7245   //const SMDS_MeshNode* simpleNodes[ nbNodes ];
7246   vector<const SMDS_MeshNode*> simpleNodes( nbNodes );
7247   int iSimple = 0, nbUnique = 0;
7248
7249   simpleNodes[iSimple++] = faceNodes[0];
7250   nbUnique++;
7251   for (int iCur = 1; iCur < nbNodes; iCur++) {
7252     if (faceNodes[iCur] != simpleNodes[iSimple - 1]) {
7253       simpleNodes[iSimple++] = faceNodes[iCur];
7254       if (nodeSet.insert( faceNodes[iCur] ).second)
7255         nbUnique++;
7256     }
7257   }
7258   int nbSimple = iSimple;
7259   if (simpleNodes[nbSimple - 1] == simpleNodes[0]) {
7260     nbSimple--;
7261     iSimple--;
7262   }
7263
7264   if (nbUnique < 3)
7265     return 0;
7266
7267   // separate loops
7268   int nbNew = 0;
7269   bool foundLoop = (nbSimple > nbUnique);
7270   while (foundLoop) {
7271     foundLoop = false;
7272     set<const SMDS_MeshNode*> loopSet;
7273     for (iSimple = 0; iSimple < nbSimple && !foundLoop; iSimple++) {
7274       const SMDS_MeshNode* n = simpleNodes[iSimple];
7275       if (!loopSet.insert( n ).second) {
7276         foundLoop = true;
7277
7278         // separate loop
7279         int iC = 0, curLast = iSimple;
7280         for (; iC < curLast; iC++) {
7281           if (simpleNodes[iC] == n) break;
7282         }
7283         int loopLen = curLast - iC;
7284         if (loopLen > 2) {
7285           // create sub-element
7286           nbNew++;
7287           quantities.push_back(loopLen);
7288           for (; iC < curLast; iC++) {
7289             poly_nodes.push_back(simpleNodes[iC]);
7290           }
7291         }
7292         // shift the rest nodes (place from the first loop position)
7293         for (iC = curLast + 1; iC < nbSimple; iC++) {
7294           simpleNodes[iC - loopLen] = simpleNodes[iC];
7295         }
7296         nbSimple -= loopLen;
7297         iSimple -= loopLen;
7298       }
7299     } // for (iSimple = 0; iSimple < nbSimple; iSimple++)
7300   } // while (foundLoop)
7301
7302   if (iSimple > 2) {
7303     nbNew++;
7304     quantities.push_back(iSimple);
7305     for (int i = 0; i < iSimple; i++)
7306       poly_nodes.push_back(simpleNodes[i]);
7307   }
7308
7309   return nbNew;
7310 }
7311
7312 //=======================================================================
7313 //function : MergeNodes
7314 //purpose  : In each group, the cdr of nodes are substituted by the first one
7315 //           in all elements.
7316 //=======================================================================
7317
7318 void SMESH_MeshEditor::MergeNodes (TListOfListOfNodes & theGroupsOfNodes)
7319 {
7320   MESSAGE("MergeNodes");
7321   myLastCreatedElems.Clear();
7322   myLastCreatedNodes.Clear();
7323
7324   SMESHDS_Mesh* aMesh = GetMeshDS();
7325
7326   TNodeNodeMap nodeNodeMap; // node to replace - new node
7327   set<const SMDS_MeshElement*> elems; // all elements with changed nodes
7328   list< int > rmElemIds, rmNodeIds;
7329
7330   // Fill nodeNodeMap and elems
7331
7332   TListOfListOfNodes::iterator grIt = theGroupsOfNodes.begin();
7333   for ( ; grIt != theGroupsOfNodes.end(); grIt++ ) {
7334     list<const SMDS_MeshNode*>& nodes = *grIt;
7335     list<const SMDS_MeshNode*>::iterator nIt = nodes.begin();
7336     const SMDS_MeshNode* nToKeep = *nIt;
7337     //MESSAGE("node to keep " << nToKeep->GetID());
7338     for ( ++nIt; nIt != nodes.end(); nIt++ ) {
7339       const SMDS_MeshNode* nToRemove = *nIt;
7340       nodeNodeMap.insert( TNodeNodeMap::value_type( nToRemove, nToKeep ));
7341       if ( nToRemove != nToKeep ) {
7342         //MESSAGE("  node to remove " << nToRemove->GetID());
7343         rmNodeIds.push_back( nToRemove->GetID() );
7344         AddToSameGroups( nToKeep, nToRemove, aMesh );
7345       }
7346
7347       SMDS_ElemIteratorPtr invElemIt = nToRemove->GetInverseElementIterator();
7348       while ( invElemIt->more() ) {
7349         const SMDS_MeshElement* elem = invElemIt->next();
7350         elems.insert(elem);
7351       }
7352     }
7353   }
7354   // Change element nodes or remove an element
7355
7356   set<const SMDS_MeshElement*>::iterator eIt = elems.begin();
7357   for ( ; eIt != elems.end(); eIt++ ) {
7358     const SMDS_MeshElement* elem = *eIt;
7359     //MESSAGE(" ---- inverse elem on node to remove " << elem->GetID());
7360     int nbNodes = elem->NbNodes();
7361     int aShapeId = FindShape( elem );
7362
7363     set<const SMDS_MeshNode*> nodeSet;
7364     vector< const SMDS_MeshNode*> curNodes( nbNodes ), uniqueNodes( nbNodes );
7365     int iUnique = 0, iCur = 0, nbRepl = 0;
7366     vector<int> iRepl( nbNodes );
7367
7368     // get new seq of nodes
7369     SMDS_ElemIteratorPtr itN = elem->nodesIterator();
7370     while ( itN->more() ) {
7371       const SMDS_MeshNode* n =
7372         static_cast<const SMDS_MeshNode*>( itN->next() );
7373
7374       TNodeNodeMap::iterator nnIt = nodeNodeMap.find( n );
7375       if ( nnIt != nodeNodeMap.end() ) { // n sticks
7376         n = (*nnIt).second;
7377         // BUG 0020185: begin
7378         {
7379           bool stopRecur = false;
7380           set<const SMDS_MeshNode*> nodesRecur;
7381           nodesRecur.insert(n);
7382           while (!stopRecur) {
7383             TNodeNodeMap::iterator nnIt_i = nodeNodeMap.find( n );
7384             if ( nnIt_i != nodeNodeMap.end() ) { // n sticks
7385               n = (*nnIt_i).second;
7386               if (!nodesRecur.insert(n).second) {
7387                 // error: recursive dependancy
7388                 stopRecur = true;
7389               }
7390             }
7391             else
7392               stopRecur = true;
7393           }
7394         }
7395         // BUG 0020185: end
7396         iRepl[ nbRepl++ ] = iCur;
7397       }
7398       curNodes[ iCur ] = n;
7399       bool isUnique = nodeSet.insert( n ).second;
7400       if ( isUnique )
7401         uniqueNodes[ iUnique++ ] = n;
7402       iCur++;
7403     }
7404
7405     // Analyse element topology after replacement
7406
7407     bool isOk = true;
7408     int nbUniqueNodes = nodeSet.size();
7409     //MESSAGE("nbNodes nbUniqueNodes " << nbNodes << " " << nbUniqueNodes);
7410     if ( nbNodes != nbUniqueNodes ) { // some nodes stick
7411       // Polygons and Polyhedral volumes
7412       if (elem->IsPoly()) {
7413
7414         if (elem->GetType() == SMDSAbs_Face) {
7415           // Polygon
7416           vector<const SMDS_MeshNode *> face_nodes (nbNodes);
7417           int inode = 0;
7418           for (; inode < nbNodes; inode++) {
7419             face_nodes[inode] = curNodes[inode];
7420           }
7421
7422           vector<const SMDS_MeshNode *> polygons_nodes;
7423           vector<int> quantities;
7424           int nbNew = SimplifyFace(face_nodes, polygons_nodes, quantities);
7425           if (nbNew > 0) {
7426             inode = 0;
7427             for (int iface = 0; iface < nbNew; iface++) {
7428               int nbNodes = quantities[iface];
7429               vector<const SMDS_MeshNode *> poly_nodes (nbNodes);
7430               for (int ii = 0; ii < nbNodes; ii++, inode++) {
7431                 poly_nodes[ii] = polygons_nodes[inode];
7432               }
7433               SMDS_MeshElement* newElem = aMesh->AddPolygonalFace(poly_nodes);
7434               myLastCreatedElems.Append(newElem);
7435               if (aShapeId)
7436                 aMesh->SetMeshElementOnShape(newElem, aShapeId);
7437             }
7438
7439             MESSAGE("ChangeElementNodes MergeNodes Polygon");
7440             //aMesh->ChangeElementNodes(elem, &polygons_nodes[inode], quantities[nbNew - 1]);
7441             vector<const SMDS_MeshNode *> polynodes(polygons_nodes.begin()+inode,polygons_nodes.end());
7442             int quid =0;
7443             if (nbNew > 0) quid = nbNew - 1;
7444             vector<int> newquant(quantities.begin()+quid, quantities.end());
7445             const SMDS_MeshElement* newElem = 0;
7446             newElem = aMesh->AddPolyhedralVolume(polynodes, newquant);
7447             myLastCreatedElems.Append(newElem);
7448             if ( aShapeId && newElem )
7449               aMesh->SetMeshElementOnShape( newElem, aShapeId );
7450             rmElemIds.push_back(elem->GetID());
7451           }
7452           else {
7453             rmElemIds.push_back(elem->GetID());
7454           }
7455
7456         }
7457         else if (elem->GetType() == SMDSAbs_Volume) {
7458           // Polyhedral volume
7459           if (nbUniqueNodes < 4) {
7460             rmElemIds.push_back(elem->GetID());
7461           }
7462           else {
7463             // each face has to be analyzed in order to check volume validity
7464             const SMDS_VtkVolume* aPolyedre =
7465               dynamic_cast<const SMDS_VtkVolume*>( elem );
7466             if (aPolyedre) {
7467               int nbFaces = aPolyedre->NbFaces();
7468
7469               vector<const SMDS_MeshNode *> poly_nodes;
7470               vector<int> quantities;
7471
7472               for (int iface = 1; iface <= nbFaces; iface++) {
7473                 int nbFaceNodes = aPolyedre->NbFaceNodes(iface);
7474                 vector<const SMDS_MeshNode *> faceNodes (nbFaceNodes);
7475
7476                 for (int inode = 1; inode <= nbFaceNodes; inode++) {
7477                   const SMDS_MeshNode * faceNode = aPolyedre->GetFaceNode(iface, inode);
7478                   TNodeNodeMap::iterator nnIt = nodeNodeMap.find(faceNode);
7479                   if (nnIt != nodeNodeMap.end()) { // faceNode sticks
7480                     faceNode = (*nnIt).second;
7481                   }
7482                   faceNodes[inode - 1] = faceNode;
7483                 }
7484
7485                 SimplifyFace(faceNodes, poly_nodes, quantities);
7486               }
7487
7488               if (quantities.size() > 3) {
7489                 // to be done: remove coincident faces
7490               }
7491
7492               if (quantities.size() > 3)
7493                 {
7494                   MESSAGE("ChangeElementNodes MergeNodes Polyhedron");
7495                   //aMesh->ChangePolyhedronNodes(elem, poly_nodes, quantities);
7496                   const SMDS_MeshElement* newElem = 0;
7497                   newElem = aMesh->AddPolyhedralVolume(poly_nodes, quantities);
7498                   myLastCreatedElems.Append(newElem);
7499                   if ( aShapeId && newElem )
7500                     aMesh->SetMeshElementOnShape( newElem, aShapeId );
7501                   rmElemIds.push_back(elem->GetID());
7502                 }
7503             }
7504             else {
7505               rmElemIds.push_back(elem->GetID());
7506             }
7507           }
7508         }
7509         else {
7510         }
7511
7512         continue;
7513       }
7514
7515       // Regular elements
7516       // TODO not all the possible cases are solved. Find something more generic?
7517       switch ( nbNodes ) {
7518       case 2: ///////////////////////////////////// EDGE
7519         isOk = false; break;
7520       case 3: ///////////////////////////////////// TRIANGLE
7521         isOk = false; break;
7522       case 4:
7523         if ( elem->GetType() == SMDSAbs_Volume ) // TETRAHEDRON
7524           isOk = false;
7525         else { //////////////////////////////////// QUADRANGLE
7526           if ( nbUniqueNodes < 3 )
7527             isOk = false;
7528           else if ( nbRepl == 2 && iRepl[ 1 ] - iRepl[ 0 ] == 2 )
7529             isOk = false; // opposite nodes stick
7530           //MESSAGE("isOk " << isOk);
7531         }
7532         break;
7533       case 6: ///////////////////////////////////// PENTAHEDRON
7534         if ( nbUniqueNodes == 4 ) {
7535           // ---------------------------------> tetrahedron
7536           if (nbRepl == 3 &&
7537               iRepl[ 0 ] > 2 && iRepl[ 1 ] > 2 && iRepl[ 2 ] > 2 ) {
7538             // all top nodes stick: reverse a bottom
7539             uniqueNodes[ 0 ] = curNodes [ 1 ];
7540             uniqueNodes[ 1 ] = curNodes [ 0 ];
7541           }
7542           else if (nbRepl == 3 &&
7543                    iRepl[ 0 ] < 3 && iRepl[ 1 ] < 3 && iRepl[ 2 ] < 3 ) {
7544             // all bottom nodes stick: set a top before
7545             uniqueNodes[ 3 ] = uniqueNodes [ 0 ];
7546             uniqueNodes[ 0 ] = curNodes [ 3 ];
7547             uniqueNodes[ 1 ] = curNodes [ 4 ];
7548             uniqueNodes[ 2 ] = curNodes [ 5 ];
7549           }
7550           else if (nbRepl == 4 &&
7551                    iRepl[ 2 ] - iRepl [ 0 ] == 3 && iRepl[ 3 ] - iRepl [ 1 ] == 3 ) {
7552             // a lateral face turns into a line: reverse a bottom
7553             uniqueNodes[ 0 ] = curNodes [ 1 ];
7554             uniqueNodes[ 1 ] = curNodes [ 0 ];
7555           }
7556           else
7557             isOk = false;
7558         }
7559         else if ( nbUniqueNodes == 5 ) {
7560           // PENTAHEDRON --------------------> 2 tetrahedrons
7561           if ( nbRepl == 2 && iRepl[ 1 ] - iRepl [ 0 ] == 3 ) {
7562             // a bottom node sticks with a linked top one
7563             // 1.
7564             SMDS_MeshElement* newElem =
7565               aMesh->AddVolume(curNodes[ 3 ],
7566                                curNodes[ 4 ],
7567                                curNodes[ 5 ],
7568                                curNodes[ iRepl[ 0 ] == 2 ? 1 : 2 ]);
7569             myLastCreatedElems.Append(newElem);
7570             if ( aShapeId )
7571               aMesh->SetMeshElementOnShape( newElem, aShapeId );
7572             // 2. : reverse a bottom
7573             uniqueNodes[ 0 ] = curNodes [ 1 ];
7574             uniqueNodes[ 1 ] = curNodes [ 0 ];
7575             nbUniqueNodes = 4;
7576           }
7577           else
7578             isOk = false;
7579         }
7580         else
7581           isOk = false;
7582         break;
7583       case 8: {
7584         if(elem->IsQuadratic()) { // Quadratic quadrangle
7585           //   1    5    2
7586           //    +---+---+
7587           //    |       |
7588           //    |       |
7589           //   4+       +6
7590           //    |       |
7591           //    |       |
7592           //    +---+---+
7593           //   0    7    3
7594           isOk = false;
7595           if(nbRepl==2) {
7596             MESSAGE("nbRepl=2: " << iRepl[0] << " " << iRepl[1]);
7597           }
7598           if(nbRepl==3) {
7599             MESSAGE("nbRepl=3: " << iRepl[0] << " " << iRepl[1]  << " " << iRepl[2]);
7600             nbUniqueNodes = 6;
7601             if( iRepl[0]==0 && iRepl[1]==1 && iRepl[2]==4 ) {
7602               uniqueNodes[0] = curNodes[0];
7603               uniqueNodes[1] = curNodes[2];
7604               uniqueNodes[2] = curNodes[3];
7605               uniqueNodes[3] = curNodes[5];
7606               uniqueNodes[4] = curNodes[6];
7607               uniqueNodes[5] = curNodes[7];
7608               isOk = true;
7609             }
7610             if( iRepl[0]==0 && iRepl[1]==3 && iRepl[2]==7 ) {
7611               uniqueNodes[0] = curNodes[0];
7612               uniqueNodes[1] = curNodes[1];
7613               uniqueNodes[2] = curNodes[2];
7614               uniqueNodes[3] = curNodes[4];
7615               uniqueNodes[4] = curNodes[5];
7616               uniqueNodes[5] = curNodes[6];
7617               isOk = true;
7618             }
7619             if( iRepl[0]==0 && iRepl[1]==4 && iRepl[2]==7 ) {
7620               uniqueNodes[0] = curNodes[1];
7621               uniqueNodes[1] = curNodes[2];
7622               uniqueNodes[2] = curNodes[3];
7623               uniqueNodes[3] = curNodes[5];
7624               uniqueNodes[4] = curNodes[6];
7625               uniqueNodes[5] = curNodes[0];
7626               isOk = true;
7627             }
7628             if( iRepl[0]==1 && iRepl[1]==2 && iRepl[2]==5 ) {
7629               uniqueNodes[0] = curNodes[0];
7630               uniqueNodes[1] = curNodes[1];
7631               uniqueNodes[2] = curNodes[3];
7632               uniqueNodes[3] = curNodes[4];
7633               uniqueNodes[4] = curNodes[6];
7634               uniqueNodes[5] = curNodes[7];
7635               isOk = true;
7636             }
7637             if( iRepl[0]==1 && iRepl[1]==4 && iRepl[2]==5 ) {
7638               uniqueNodes[0] = curNodes[0];
7639               uniqueNodes[1] = curNodes[2];
7640               uniqueNodes[2] = curNodes[3];
7641               uniqueNodes[3] = curNodes[1];
7642               uniqueNodes[4] = curNodes[6];
7643               uniqueNodes[5] = curNodes[7];
7644               isOk = true;
7645             }
7646             if( iRepl[0]==2 && iRepl[1]==3 && iRepl[2]==6 ) {
7647               uniqueNodes[0] = curNodes[0];
7648               uniqueNodes[1] = curNodes[1];
7649               uniqueNodes[2] = curNodes[2];
7650               uniqueNodes[3] = curNodes[4];
7651               uniqueNodes[4] = curNodes[5];
7652               uniqueNodes[5] = curNodes[7];
7653               isOk = true;
7654             }
7655             if( iRepl[0]==2 && iRepl[1]==5 && iRepl[2]==6 ) {
7656               uniqueNodes[0] = curNodes[0];
7657               uniqueNodes[1] = curNodes[1];
7658               uniqueNodes[2] = curNodes[3];
7659               uniqueNodes[3] = curNodes[4];
7660               uniqueNodes[4] = curNodes[2];
7661               uniqueNodes[5] = curNodes[7];
7662               isOk = true;
7663             }
7664             if( iRepl[0]==3 && iRepl[1]==6 && iRepl[2]==7 ) {
7665               uniqueNodes[0] = curNodes[0];
7666               uniqueNodes[1] = curNodes[1];
7667               uniqueNodes[2] = curNodes[2];
7668               uniqueNodes[3] = curNodes[4];
7669               uniqueNodes[4] = curNodes[5];
7670               uniqueNodes[5] = curNodes[3];
7671               isOk = true;
7672             }
7673           }
7674           if(nbRepl==4) {
7675             MESSAGE("nbRepl=4: " << iRepl[0] << " " << iRepl[1]  << " " << iRepl[2] << " " << iRepl[3]);
7676           }
7677           if(nbRepl==5) {
7678             MESSAGE("nbRepl=5: " << iRepl[0] << " " << iRepl[1]  << " " << iRepl[2] << " " << iRepl[3] << " " << iRepl[4]);
7679           }
7680           break;
7681         }
7682         //////////////////////////////////// HEXAHEDRON
7683         isOk = false;
7684         SMDS_VolumeTool hexa (elem);
7685         hexa.SetExternalNormal();
7686         if ( nbUniqueNodes == 4 && nbRepl == 6 ) {
7687           //////////////////////// ---> tetrahedron
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 bottom
7698               for ( iCur = 0; iCur < 4 && nbStick < 2; 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 == 1 ) {
7705                 // ... and the opposite one - into a triangle.
7706                 // set a top node
7707                 ind = hexa.GetFaceNodesIndices( iFace );
7708                 uniqueNodes[ 3 ] = curNodes[ind[ 0 ]];
7709                 isOk = true;
7710               }
7711               break;
7712             }
7713           }
7714         }
7715         else if (nbUniqueNodes == 5 && nbRepl == 4 ) {
7716           //////////////////// HEXAHEDRON ---> 2 tetrahedrons
7717           for ( int iFace = 0; iFace < 6; iFace++ ) {
7718             const int *ind = hexa.GetFaceNodesIndices( iFace ); // indices of face nodes
7719             if (curNodes[ind[ 0 ]] == curNodes[ind[ 1 ]] &&
7720                 curNodes[ind[ 0 ]] == curNodes[ind[ 2 ]] &&
7721                 curNodes[ind[ 0 ]] == curNodes[ind[ 3 ]] ) {
7722               // one face turns into a point ...
7723               int iOppFace = hexa.GetOppFaceIndex( iFace );
7724               ind = hexa.GetFaceNodesIndices( iOppFace );
7725               int nbStick = 0;
7726               iUnique = 2;  // reverse a tetrahedron 1 bottom
7727               for ( iCur = 0; iCur < 4 && nbStick == 0; iCur++ ) {
7728                 if ( curNodes[ind[ iCur ]] == curNodes[ind[ iCur + 1 ]] )
7729                   nbStick++;
7730                 else if ( iUnique >= 0 )
7731                   uniqueNodes[ iUnique-- ] = curNodes[ind[ iCur ]];
7732               }
7733               if ( nbStick == 0 ) {
7734                 // ... and the opposite one is a quadrangle
7735                 // set a top node
7736                 const int* indTop = hexa.GetFaceNodesIndices( iFace );
7737                 uniqueNodes[ 3 ] = curNodes[indTop[ 0 ]];
7738                 nbUniqueNodes = 4;
7739                 // tetrahedron 2
7740                 SMDS_MeshElement* newElem =
7741                   aMesh->AddVolume(curNodes[ind[ 0 ]],
7742                                    curNodes[ind[ 3 ]],
7743                                    curNodes[ind[ 2 ]],
7744                                    curNodes[indTop[ 0 ]]);
7745                 myLastCreatedElems.Append(newElem);
7746                 if ( aShapeId )
7747                   aMesh->SetMeshElementOnShape( newElem, aShapeId );
7748                 isOk = true;
7749               }
7750               break;
7751             }
7752           }
7753         }
7754         else if ( nbUniqueNodes == 6 && nbRepl == 4 ) {
7755           ////////////////// HEXAHEDRON ---> 2 tetrahedrons or 1 prism
7756           // find indices of quad and tri faces
7757           int iQuadFace[ 6 ], iTriFace[ 6 ], nbQuad = 0, nbTri = 0, iFace;
7758           for ( iFace = 0; iFace < 6; iFace++ ) {
7759             const int *ind = hexa.GetFaceNodesIndices( iFace ); // indices of face nodes
7760             nodeSet.clear();
7761             for ( iCur = 0; iCur < 4; iCur++ )
7762               nodeSet.insert( curNodes[ind[ iCur ]] );
7763             nbUniqueNodes = nodeSet.size();
7764             if ( nbUniqueNodes == 3 )
7765               iTriFace[ nbTri++ ] = iFace;
7766             else if ( nbUniqueNodes == 4 )
7767               iQuadFace[ nbQuad++ ] = iFace;
7768           }
7769           if (nbQuad == 2 && nbTri == 4 &&
7770               hexa.GetOppFaceIndex( iQuadFace[ 0 ] ) == iQuadFace[ 1 ]) {
7771             // 2 opposite quadrangles stuck with a diagonal;
7772             // sample groups of merged indices: (0-4)(2-6)
7773             // --------------------------------------------> 2 tetrahedrons
7774             const int *ind1 = hexa.GetFaceNodesIndices( iQuadFace[ 0 ]); // indices of quad1 nodes
7775             const int *ind2 = hexa.GetFaceNodesIndices( iQuadFace[ 1 ]);
7776             int i0, i1d, i2, i3d, i0t, i2t; // d-daigonal, t-top
7777             if (curNodes[ind1[ 0 ]] == curNodes[ind2[ 0 ]] &&
7778                 curNodes[ind1[ 2 ]] == curNodes[ind2[ 2 ]]) {
7779               // stuck with 0-2 diagonal
7780               i0  = ind1[ 3 ];
7781               i1d = ind1[ 0 ];
7782               i2  = ind1[ 1 ];
7783               i3d = ind1[ 2 ];
7784               i0t = ind2[ 1 ];
7785               i2t = ind2[ 3 ];
7786             }
7787             else if (curNodes[ind1[ 1 ]] == curNodes[ind2[ 3 ]] &&
7788                      curNodes[ind1[ 3 ]] == curNodes[ind2[ 1 ]]) {
7789               // stuck with 1-3 diagonal
7790               i0  = ind1[ 0 ];
7791               i1d = ind1[ 1 ];
7792               i2  = ind1[ 2 ];
7793               i3d = ind1[ 3 ];
7794               i0t = ind2[ 0 ];
7795               i2t = ind2[ 1 ];
7796             }
7797             else {
7798               ASSERT(0);
7799             }
7800             // tetrahedron 1
7801             uniqueNodes[ 0 ] = curNodes [ i0 ];
7802             uniqueNodes[ 1 ] = curNodes [ i1d ];
7803             uniqueNodes[ 2 ] = curNodes [ i3d ];
7804             uniqueNodes[ 3 ] = curNodes [ i0t ];
7805             nbUniqueNodes = 4;
7806             // tetrahedron 2
7807             SMDS_MeshElement* newElem = aMesh->AddVolume(curNodes[ i1d ],
7808                                                          curNodes[ i2 ],
7809                                                          curNodes[ i3d ],
7810                                                          curNodes[ i2t ]);
7811             myLastCreatedElems.Append(newElem);
7812             if ( aShapeId )
7813               aMesh->SetMeshElementOnShape( newElem, aShapeId );
7814             isOk = true;
7815           }
7816           else if (( nbTri == 2 && nbQuad == 3 ) || // merged (0-4)(1-5)
7817                    ( nbTri == 4 && nbQuad == 2 )) { // merged (7-4)(1-5)
7818             // --------------------------------------------> prism
7819             // find 2 opposite triangles
7820             nbUniqueNodes = 6;
7821             for ( iFace = 0; iFace + 1 < nbTri; iFace++ ) {
7822               if ( hexa.GetOppFaceIndex( iTriFace[ iFace ] ) == iTriFace[ iFace + 1 ]) {
7823                 // find indices of kept and replaced nodes
7824                 // and fill unique nodes of 2 opposite triangles
7825                 const int *ind1 = hexa.GetFaceNodesIndices( iTriFace[ iFace ]);
7826                 const int *ind2 = hexa.GetFaceNodesIndices( iTriFace[ iFace + 1 ]);
7827                 const SMDS_MeshNode** hexanodes = hexa.GetNodes();
7828                 // fill unique nodes
7829                 iUnique = 0;
7830                 isOk = true;
7831                 for ( iCur = 0; iCur < 4 && isOk; iCur++ ) {
7832                   const SMDS_MeshNode* n     = curNodes[ind1[ iCur ]];
7833                   const SMDS_MeshNode* nInit = hexanodes[ind1[ iCur ]];
7834                   if ( n == nInit ) {
7835                     // iCur of a linked node of the opposite face (make normals co-directed):
7836                     int iCurOpp = ( iCur == 1 || iCur == 3 ) ? 4 - iCur : iCur;
7837                     // check that correspondent corners of triangles are linked
7838                     if ( !hexa.IsLinked( ind1[ iCur ], ind2[ iCurOpp ] ))
7839                       isOk = false;
7840                     else {
7841                       uniqueNodes[ iUnique ] = n;
7842                       uniqueNodes[ iUnique + 3 ] = curNodes[ind2[ iCurOpp ]];
7843                       iUnique++;
7844                     }
7845                   }
7846                 }
7847                 break;
7848               }
7849             }
7850           }
7851         } // if ( nbUniqueNodes == 6 && nbRepl == 4 )
7852         break;
7853       } // HEXAHEDRON
7854
7855       default:
7856         isOk = false;
7857       } // switch ( nbNodes )
7858
7859     } // if ( nbNodes != nbUniqueNodes ) // some nodes stick
7860
7861     if ( isOk ) { // the elem remains valid after sticking nodes
7862       if (elem->IsPoly() && elem->GetType() == SMDSAbs_Volume)
7863       {
7864         // Change nodes of polyedre
7865         const SMDS_VtkVolume* aPolyedre =
7866           dynamic_cast<const SMDS_VtkVolume*>( elem );
7867         if (aPolyedre) {
7868           int nbFaces = aPolyedre->NbFaces();
7869
7870           vector<const SMDS_MeshNode *> poly_nodes;
7871           vector<int> quantities (nbFaces);
7872
7873           for (int iface = 1; iface <= nbFaces; iface++) {
7874             int inode, nbFaceNodes = aPolyedre->NbFaceNodes(iface);
7875             quantities[iface - 1] = nbFaceNodes;
7876
7877             for (inode = 1; inode <= nbFaceNodes; inode++) {
7878               const SMDS_MeshNode* curNode = aPolyedre->GetFaceNode(iface, inode);
7879
7880               TNodeNodeMap::iterator nnIt = nodeNodeMap.find( curNode );
7881               if (nnIt != nodeNodeMap.end()) { // curNode sticks
7882                 curNode = (*nnIt).second;
7883               }
7884               poly_nodes.push_back(curNode);
7885             }
7886           }
7887           aMesh->ChangePolyhedronNodes( elem, poly_nodes, quantities );
7888         }
7889       }
7890       else // replace non-polyhedron elements
7891       {
7892         const SMDSAbs_ElementType etyp = elem->GetType();
7893         const int elemId               = elem->GetID();
7894         const bool isPoly              = (elem->GetEntityType() == SMDSEntity_Polygon);
7895         uniqueNodes.resize(nbUniqueNodes);
7896
7897         SMESHDS_SubMesh * sm = aShapeId > 0 ? aMesh->MeshElements(aShapeId) : 0;
7898
7899         aMesh->RemoveFreeElement(elem, sm, /*fromGroups=*/false);
7900         SMDS_MeshElement* newElem = this->AddElement(uniqueNodes, etyp, isPoly, elemId);
7901         if ( sm && newElem )
7902           sm->AddElement( newElem );
7903         if ( elem != newElem )
7904           ReplaceElemInGroups( elem, newElem, aMesh );
7905       }
7906     }
7907     else {
7908       // Remove invalid regular element or invalid polygon
7909       rmElemIds.push_back( elem->GetID() );
7910     }
7911
7912   } // loop on elements
7913
7914   // Remove bad elements, then equal nodes (order important)
7915
7916   Remove( rmElemIds, false );
7917   Remove( rmNodeIds, true );
7918
7919 }
7920
7921
7922 // ========================================================
7923 // class   : SortableElement
7924 // purpose : allow sorting elements basing on their nodes
7925 // ========================================================
7926 class SortableElement : public set <const SMDS_MeshElement*>
7927 {
7928 public:
7929
7930   SortableElement( const SMDS_MeshElement* theElem )
7931   {
7932     myElem = theElem;
7933     SMDS_ElemIteratorPtr nodeIt = theElem->nodesIterator();
7934     while ( nodeIt->more() )
7935       this->insert( nodeIt->next() );
7936   }
7937
7938   const SMDS_MeshElement* Get() const
7939   { return myElem; }
7940
7941   void Set(const SMDS_MeshElement* e) const
7942   { myElem = e; }
7943
7944
7945 private:
7946   mutable const SMDS_MeshElement* myElem;
7947 };
7948
7949 //=======================================================================
7950 //function : FindEqualElements
7951 //purpose  : Return list of group of elements built on the same nodes.
7952 //           Search among theElements or in the whole mesh if theElements is empty
7953 //=======================================================================
7954 void SMESH_MeshEditor::FindEqualElements(set<const SMDS_MeshElement*> & theElements,
7955                                          TListOfListOfElementsID &      theGroupsOfElementsID)
7956 {
7957   myLastCreatedElems.Clear();
7958   myLastCreatedNodes.Clear();
7959
7960   typedef set<const SMDS_MeshElement*> TElemsSet;
7961   typedef map< SortableElement, int > TMapOfNodeSet;
7962   typedef list<int> TGroupOfElems;
7963
7964   TElemsSet elems;
7965   if ( theElements.empty() )
7966   { // get all elements in the mesh
7967     SMDS_ElemIteratorPtr eIt = GetMeshDS()->elementsIterator();
7968     while ( eIt->more() )
7969       elems.insert( elems.end(), eIt->next());
7970   }
7971   else
7972     elems = theElements;
7973
7974   vector< TGroupOfElems > arrayOfGroups;
7975   TGroupOfElems groupOfElems;
7976   TMapOfNodeSet mapOfNodeSet;
7977
7978   TElemsSet::iterator elemIt = elems.begin();
7979   for ( int i = 0, j=0; elemIt != elems.end(); ++elemIt, ++j ) {
7980     const SMDS_MeshElement* curElem = *elemIt;
7981     SortableElement SE(curElem);
7982     int ind = -1;
7983     // check uniqueness
7984     pair< TMapOfNodeSet::iterator, bool> pp = mapOfNodeSet.insert(make_pair(SE, i));
7985     if( !(pp.second) ) {
7986       TMapOfNodeSet::iterator& itSE = pp.first;
7987       ind = (*itSE).second;
7988       arrayOfGroups[ind].push_back(curElem->GetID());
7989     }
7990     else {
7991       groupOfElems.clear();
7992       groupOfElems.push_back(curElem->GetID());
7993       arrayOfGroups.push_back(groupOfElems);
7994       i++;
7995     }
7996   }
7997
7998   vector< TGroupOfElems >::iterator groupIt = arrayOfGroups.begin();
7999   for ( ; groupIt != arrayOfGroups.end(); ++groupIt ) {
8000     groupOfElems = *groupIt;
8001     if ( groupOfElems.size() > 1 ) {
8002       groupOfElems.sort();
8003       theGroupsOfElementsID.push_back(groupOfElems);
8004     }
8005   }
8006 }
8007
8008 //=======================================================================
8009 //function : MergeElements
8010 //purpose  : In each given group, substitute all elements by the first one.
8011 //=======================================================================
8012
8013 void SMESH_MeshEditor::MergeElements(TListOfListOfElementsID & theGroupsOfElementsID)
8014 {
8015   myLastCreatedElems.Clear();
8016   myLastCreatedNodes.Clear();
8017
8018   typedef list<int> TListOfIDs;
8019   TListOfIDs rmElemIds; // IDs of elems to remove
8020
8021   SMESHDS_Mesh* aMesh = GetMeshDS();
8022
8023   TListOfListOfElementsID::iterator groupsIt = theGroupsOfElementsID.begin();
8024   while ( groupsIt != theGroupsOfElementsID.end() ) {
8025     TListOfIDs& aGroupOfElemID = *groupsIt;
8026     aGroupOfElemID.sort();
8027     int elemIDToKeep = aGroupOfElemID.front();
8028     const SMDS_MeshElement* elemToKeep = aMesh->FindElement(elemIDToKeep);
8029     aGroupOfElemID.pop_front();
8030     TListOfIDs::iterator idIt = aGroupOfElemID.begin();
8031     while ( idIt != aGroupOfElemID.end() ) {
8032       int elemIDToRemove = *idIt;
8033       const SMDS_MeshElement* elemToRemove = aMesh->FindElement(elemIDToRemove);
8034       // add the kept element in groups of removed one (PAL15188)
8035       AddToSameGroups( elemToKeep, elemToRemove, aMesh );
8036       rmElemIds.push_back( elemIDToRemove );
8037       ++idIt;
8038     }
8039     ++groupsIt;
8040   }
8041
8042   Remove( rmElemIds, false );
8043 }
8044
8045 //=======================================================================
8046 //function : MergeEqualElements
8047 //purpose  : Remove all but one of elements built on the same nodes.
8048 //=======================================================================
8049
8050 void SMESH_MeshEditor::MergeEqualElements()
8051 {
8052   set<const SMDS_MeshElement*> aMeshElements; /* empty input -
8053                                                  to merge equal elements in the whole mesh */
8054   TListOfListOfElementsID aGroupsOfElementsID;
8055   FindEqualElements(aMeshElements, aGroupsOfElementsID);
8056   MergeElements(aGroupsOfElementsID);
8057 }
8058
8059 //=======================================================================
8060 //function : FindFaceInSet
8061 //purpose  : Return a face having linked nodes n1 and n2 and which is
8062 //           - not in avoidSet,
8063 //           - in elemSet provided that !elemSet.empty()
8064 //           i1 and i2 optionally returns indices of n1 and n2
8065 //=======================================================================
8066
8067 const SMDS_MeshElement*
8068 SMESH_MeshEditor::FindFaceInSet(const SMDS_MeshNode*    n1,
8069                                 const SMDS_MeshNode*    n2,
8070                                 const TIDSortedElemSet& elemSet,
8071                                 const TIDSortedElemSet& avoidSet,
8072                                 int*                    n1ind,
8073                                 int*                    n2ind)
8074
8075 {
8076   int i1, i2;
8077   const SMDS_MeshElement* face = 0;
8078
8079   SMDS_ElemIteratorPtr invElemIt = n1->GetInverseElementIterator(SMDSAbs_Face);
8080   //MESSAGE("n1->GetInverseElementIterator(SMDSAbs_Face) " << invElemIt);
8081   while ( invElemIt->more() && !face ) // loop on inverse faces of n1
8082   {
8083     //MESSAGE("in while ( invElemIt->more() && !face )");
8084     const SMDS_MeshElement* elem = invElemIt->next();
8085     if (avoidSet.count( elem ))
8086       continue;
8087     if ( !elemSet.empty() && !elemSet.count( elem ))
8088       continue;
8089     // index of n1
8090     i1 = elem->GetNodeIndex( n1 );
8091     // find a n2 linked to n1
8092     int nbN = elem->IsQuadratic() ? elem->NbNodes()/2 : elem->NbNodes();
8093     for ( int di = -1; di < 2 && !face; di += 2 )
8094     {
8095       i2 = (i1+di+nbN) % nbN;
8096       if ( elem->GetNode( i2 ) == n2 )
8097         face = elem;
8098     }
8099     if ( !face && elem->IsQuadratic())
8100     {
8101       // analysis for quadratic elements using all nodes
8102       const SMDS_VtkFace* F =
8103         dynamic_cast<const SMDS_VtkFace*>(elem);
8104       if (!F) throw SALOME_Exception(LOCALIZED("not an SMDS_VtkFace"));
8105       // use special nodes iterator
8106       SMDS_ElemIteratorPtr anIter = F->interlacedNodesElemIterator();
8107       const SMDS_MeshNode* prevN = cast2Node( anIter->next() );
8108       for ( i1 = -1, i2 = 0; anIter->more() && !face; i1++, i2++ )
8109       {
8110         const SMDS_MeshNode* n = cast2Node( anIter->next() );
8111         if ( n1 == prevN && n2 == n )
8112         {
8113           face = elem;
8114         }
8115         else if ( n2 == prevN && n1 == n )
8116         {
8117           face = elem; swap( i1, i2 );
8118         }
8119         prevN = n;
8120       }
8121     }
8122   }
8123   if ( n1ind ) *n1ind = i1;
8124   if ( n2ind ) *n2ind = i2;
8125   return face;
8126 }
8127
8128 //=======================================================================
8129 //function : findAdjacentFace
8130 //purpose  :
8131 //=======================================================================
8132
8133 static const SMDS_MeshElement* findAdjacentFace(const SMDS_MeshNode* n1,
8134                                                 const SMDS_MeshNode* n2,
8135                                                 const SMDS_MeshElement* elem)
8136 {
8137   TIDSortedElemSet elemSet, avoidSet;
8138   if ( elem )
8139     avoidSet.insert ( elem );
8140   return SMESH_MeshEditor::FindFaceInSet( n1, n2, elemSet, avoidSet );
8141 }
8142
8143 //=======================================================================
8144 //function : FindFreeBorder
8145 //purpose  :
8146 //=======================================================================
8147
8148 #define ControlFreeBorder SMESH::Controls::FreeEdges::IsFreeEdge
8149
8150 bool SMESH_MeshEditor::FindFreeBorder (const SMDS_MeshNode*             theFirstNode,
8151                                        const SMDS_MeshNode*             theSecondNode,
8152                                        const SMDS_MeshNode*             theLastNode,
8153                                        list< const SMDS_MeshNode* > &   theNodes,
8154                                        list< const SMDS_MeshElement* >& theFaces)
8155 {
8156   if ( !theFirstNode || !theSecondNode )
8157     return false;
8158   // find border face between theFirstNode and theSecondNode
8159   const SMDS_MeshElement* curElem = findAdjacentFace( theFirstNode, theSecondNode, 0 );
8160   if ( !curElem )
8161     return false;
8162
8163   theFaces.push_back( curElem );
8164   theNodes.push_back( theFirstNode );
8165   theNodes.push_back( theSecondNode );
8166
8167   //vector<const SMDS_MeshNode*> nodes;
8168   const SMDS_MeshNode *nIgnore = theFirstNode, *nStart = theSecondNode;
8169   TIDSortedElemSet foundElems;
8170   bool needTheLast = ( theLastNode != 0 );
8171
8172   while ( nStart != theLastNode ) {
8173     if ( nStart == theFirstNode )
8174       return !needTheLast;
8175
8176     // find all free border faces sharing form nStart
8177
8178     list< const SMDS_MeshElement* > curElemList;
8179     list< const SMDS_MeshNode* > nStartList;
8180     SMDS_ElemIteratorPtr invElemIt = nStart->GetInverseElementIterator(SMDSAbs_Face);
8181     while ( invElemIt->more() ) {
8182       const SMDS_MeshElement* e = invElemIt->next();
8183       if ( e == curElem || foundElems.insert( e ).second ) {
8184         // get nodes
8185         int iNode = 0, nbNodes = e->NbNodes();
8186         //const SMDS_MeshNode* nodes[nbNodes+1];
8187         vector<const SMDS_MeshNode*> nodes(nbNodes+1);
8188
8189         if(e->IsQuadratic()) {
8190           const SMDS_VtkFace* F =
8191             dynamic_cast<const SMDS_VtkFace*>(e);
8192           if (!F) throw SALOME_Exception(LOCALIZED("not an SMDS_VtkFace"));
8193           // use special nodes iterator
8194           SMDS_ElemIteratorPtr anIter = F->interlacedNodesElemIterator();
8195           while( anIter->more() ) {
8196             nodes[ iNode++ ] = cast2Node(anIter->next());
8197           }
8198         }
8199         else {
8200           SMDS_ElemIteratorPtr nIt = e->nodesIterator();
8201           while ( nIt->more() )
8202             nodes[ iNode++ ] = static_cast<const SMDS_MeshNode*>( nIt->next() );
8203         }
8204         nodes[ iNode ] = nodes[ 0 ];
8205         // check 2 links
8206         for ( iNode = 0; iNode < nbNodes; iNode++ )
8207           if (((nodes[ iNode ] == nStart && nodes[ iNode + 1] != nIgnore ) ||
8208                (nodes[ iNode + 1] == nStart && nodes[ iNode ] != nIgnore )) &&
8209               ControlFreeBorder( &nodes[ iNode ], e->GetID() ))
8210           {
8211             nStartList.push_back( nodes[ iNode + ( nodes[ iNode ] == nStart ? 1 : 0 )]);
8212             curElemList.push_back( e );
8213           }
8214       }
8215     }
8216     // analyse the found
8217
8218     int nbNewBorders = curElemList.size();
8219     if ( nbNewBorders == 0 ) {
8220       // no free border furthermore
8221       return !needTheLast;
8222     }
8223     else if ( nbNewBorders == 1 ) {
8224       // one more element found
8225       nIgnore = nStart;
8226       nStart = nStartList.front();
8227       curElem = curElemList.front();
8228       theFaces.push_back( curElem );
8229       theNodes.push_back( nStart );
8230     }
8231     else {
8232       // several continuations found
8233       list< const SMDS_MeshElement* >::iterator curElemIt;
8234       list< const SMDS_MeshNode* >::iterator nStartIt;
8235       // check if one of them reached the last node
8236       if ( needTheLast ) {
8237         for (curElemIt = curElemList.begin(), nStartIt = nStartList.begin();
8238              curElemIt!= curElemList.end();
8239              curElemIt++, nStartIt++ )
8240           if ( *nStartIt == theLastNode ) {
8241             theFaces.push_back( *curElemIt );
8242             theNodes.push_back( *nStartIt );
8243             return true;
8244           }
8245       }
8246       // find the best free border by the continuations
8247       list<const SMDS_MeshNode*>    contNodes[ 2 ], *cNL;
8248       list<const SMDS_MeshElement*> contFaces[ 2 ], *cFL;
8249       for (curElemIt = curElemList.begin(), nStartIt = nStartList.begin();
8250            curElemIt!= curElemList.end();
8251            curElemIt++, nStartIt++ )
8252       {
8253         cNL = & contNodes[ contNodes[0].empty() ? 0 : 1 ];
8254         cFL = & contFaces[ contFaces[0].empty() ? 0 : 1 ];
8255         // find one more free border
8256         if ( ! FindFreeBorder( nStart, *nStartIt, theLastNode, *cNL, *cFL )) {
8257           cNL->clear();
8258           cFL->clear();
8259         }
8260         else if ( !contNodes[0].empty() && !contNodes[1].empty() ) {
8261           // choice: clear a worse one
8262           int iLongest = ( contNodes[0].size() < contNodes[1].size() ? 1 : 0 );
8263           int iWorse = ( needTheLast ? 1 - iLongest : iLongest );
8264           contNodes[ iWorse ].clear();
8265           contFaces[ iWorse ].clear();
8266         }
8267       }
8268       if ( contNodes[0].empty() && contNodes[1].empty() )
8269         return false;
8270
8271       // append the best free border
8272       cNL = & contNodes[ contNodes[0].empty() ? 1 : 0 ];
8273       cFL = & contFaces[ contFaces[0].empty() ? 1 : 0 ];
8274       theNodes.pop_back(); // remove nIgnore
8275       theNodes.pop_back(); // remove nStart
8276       theFaces.pop_back(); // remove curElem
8277       list< const SMDS_MeshNode* >::iterator nIt = cNL->begin();
8278       list< const SMDS_MeshElement* >::iterator fIt = cFL->begin();
8279       for ( ; nIt != cNL->end(); nIt++ ) theNodes.push_back( *nIt );
8280       for ( ; fIt != cFL->end(); fIt++ ) theFaces.push_back( *fIt );
8281       return true;
8282
8283     } // several continuations found
8284   } // while ( nStart != theLastNode )
8285
8286   return true;
8287 }
8288
8289 //=======================================================================
8290 //function : CheckFreeBorderNodes
8291 //purpose  : Return true if the tree nodes are on a free border
8292 //=======================================================================
8293
8294 bool SMESH_MeshEditor::CheckFreeBorderNodes(const SMDS_MeshNode* theNode1,
8295                                             const SMDS_MeshNode* theNode2,
8296                                             const SMDS_MeshNode* theNode3)
8297 {
8298   list< const SMDS_MeshNode* > nodes;
8299   list< const SMDS_MeshElement* > faces;
8300   return FindFreeBorder( theNode1, theNode2, theNode3, nodes, faces);
8301 }
8302
8303 //=======================================================================
8304 //function : SewFreeBorder
8305 //purpose  :
8306 //=======================================================================
8307
8308 SMESH_MeshEditor::Sew_Error
8309 SMESH_MeshEditor::SewFreeBorder (const SMDS_MeshNode* theBordFirstNode,
8310                                  const SMDS_MeshNode* theBordSecondNode,
8311                                  const SMDS_MeshNode* theBordLastNode,
8312                                  const SMDS_MeshNode* theSideFirstNode,
8313                                  const SMDS_MeshNode* theSideSecondNode,
8314                                  const SMDS_MeshNode* theSideThirdNode,
8315                                  const bool           theSideIsFreeBorder,
8316                                  const bool           toCreatePolygons,
8317                                  const bool           toCreatePolyedrs)
8318 {
8319   myLastCreatedElems.Clear();
8320   myLastCreatedNodes.Clear();
8321
8322   MESSAGE("::SewFreeBorder()");
8323   Sew_Error aResult = SEW_OK;
8324
8325   // ====================================
8326   //    find side nodes and elements
8327   // ====================================
8328
8329   list< const SMDS_MeshNode* > nSide[ 2 ];
8330   list< const SMDS_MeshElement* > eSide[ 2 ];
8331   list< const SMDS_MeshNode* >::iterator nIt[ 2 ];
8332   list< const SMDS_MeshElement* >::iterator eIt[ 2 ];
8333
8334   // Free border 1
8335   // --------------
8336   if (!FindFreeBorder(theBordFirstNode,theBordSecondNode,theBordLastNode,
8337                       nSide[0], eSide[0])) {
8338     MESSAGE(" Free Border 1 not found " );
8339     aResult = SEW_BORDER1_NOT_FOUND;
8340   }
8341   if (theSideIsFreeBorder) {
8342     // Free border 2
8343     // --------------
8344     if (!FindFreeBorder(theSideFirstNode, theSideSecondNode, theSideThirdNode,
8345                         nSide[1], eSide[1])) {
8346       MESSAGE(" Free Border 2 not found " );
8347       aResult = ( aResult != SEW_OK ? SEW_BOTH_BORDERS_NOT_FOUND : SEW_BORDER2_NOT_FOUND );
8348     }
8349   }
8350   if ( aResult != SEW_OK )
8351     return aResult;
8352
8353   if (!theSideIsFreeBorder) {
8354     // Side 2
8355     // --------------
8356
8357     // -------------------------------------------------------------------------
8358     // Algo:
8359     // 1. If nodes to merge are not coincident, move nodes of the free border
8360     //    from the coord sys defined by the direction from the first to last
8361     //    nodes of the border to the correspondent sys of the side 2
8362     // 2. On the side 2, find the links most co-directed with the correspondent
8363     //    links of the free border
8364     // -------------------------------------------------------------------------
8365
8366     // 1. Since sewing may break if there are volumes to split on the side 2,
8367     //    we wont move nodes but just compute new coordinates for them
8368     typedef map<const SMDS_MeshNode*, gp_XYZ> TNodeXYZMap;
8369     TNodeXYZMap nBordXYZ;
8370     list< const SMDS_MeshNode* >& bordNodes = nSide[ 0 ];
8371     list< const SMDS_MeshNode* >::iterator nBordIt;
8372
8373     gp_XYZ Pb1( theBordFirstNode->X(), theBordFirstNode->Y(), theBordFirstNode->Z() );
8374     gp_XYZ Pb2( theBordLastNode->X(), theBordLastNode->Y(), theBordLastNode->Z() );
8375     gp_XYZ Ps1( theSideFirstNode->X(), theSideFirstNode->Y(), theSideFirstNode->Z() );
8376     gp_XYZ Ps2( theSideSecondNode->X(), theSideSecondNode->Y(), theSideSecondNode->Z() );
8377     double tol2 = 1.e-8;
8378     gp_Vec Vbs1( Pb1 - Ps1 ),Vbs2( Pb2 - Ps2 );
8379     if ( Vbs1.SquareMagnitude() > tol2 || Vbs2.SquareMagnitude() > tol2 ) {
8380       // Need node movement.
8381
8382       // find X and Z axes to create trsf
8383       gp_Vec Zb( Pb1 - Pb2 ), Zs( Ps1 - Ps2 );
8384       gp_Vec X = Zs ^ Zb;
8385       if ( X.SquareMagnitude() <= gp::Resolution() * gp::Resolution() )
8386         // Zb || Zs
8387         X = gp_Ax2( gp::Origin(), Zb ).XDirection();
8388
8389       // coord systems
8390       gp_Ax3 toBordAx( Pb1, Zb, X );
8391       gp_Ax3 fromSideAx( Ps1, Zs, X );
8392       gp_Ax3 toGlobalAx( gp::Origin(), gp::DZ(), gp::DX() );
8393       // set trsf
8394       gp_Trsf toBordSys, fromSide2Sys;
8395       toBordSys.SetTransformation( toBordAx );
8396       fromSide2Sys.SetTransformation( fromSideAx, toGlobalAx );
8397       fromSide2Sys.SetScaleFactor( Zs.Magnitude() / Zb.Magnitude() );
8398
8399       // move
8400       for ( nBordIt = bordNodes.begin(); nBordIt != bordNodes.end(); nBordIt++ ) {
8401         const SMDS_MeshNode* n = *nBordIt;
8402         gp_XYZ xyz( n->X(),n->Y(),n->Z() );
8403         toBordSys.Transforms( xyz );
8404         fromSide2Sys.Transforms( xyz );
8405         nBordXYZ.insert( TNodeXYZMap::value_type( n, xyz ));
8406       }
8407     }
8408     else {
8409       // just insert nodes XYZ in the nBordXYZ map
8410       for ( nBordIt = bordNodes.begin(); nBordIt != bordNodes.end(); nBordIt++ ) {
8411         const SMDS_MeshNode* n = *nBordIt;
8412         nBordXYZ.insert( TNodeXYZMap::value_type( n, gp_XYZ( n->X(),n->Y(),n->Z() )));
8413       }
8414     }
8415
8416     // 2. On the side 2, find the links most co-directed with the correspondent
8417     //    links of the free border
8418
8419     list< const SMDS_MeshElement* >& sideElems = eSide[ 1 ];
8420     list< const SMDS_MeshNode* >& sideNodes = nSide[ 1 ];
8421     sideNodes.push_back( theSideFirstNode );
8422
8423     bool hasVolumes = false;
8424     LinkID_Gen aLinkID_Gen( GetMeshDS() );
8425     set<long> foundSideLinkIDs, checkedLinkIDs;
8426     SMDS_VolumeTool volume;
8427     //const SMDS_MeshNode* faceNodes[ 4 ];
8428
8429     const SMDS_MeshNode*    sideNode;
8430     const SMDS_MeshElement* sideElem;
8431     const SMDS_MeshNode* prevSideNode = theSideFirstNode;
8432     const SMDS_MeshNode* prevBordNode = theBordFirstNode;
8433     nBordIt = bordNodes.begin();
8434     nBordIt++;
8435     // border node position and border link direction to compare with
8436     gp_XYZ bordPos = nBordXYZ[ *nBordIt ];
8437     gp_XYZ bordDir = bordPos - nBordXYZ[ prevBordNode ];
8438     // choose next side node by link direction or by closeness to
8439     // the current border node:
8440     bool searchByDir = ( *nBordIt != theBordLastNode );
8441     do {
8442       // find the next node on the Side 2
8443       sideNode = 0;
8444       double maxDot = -DBL_MAX, minDist = DBL_MAX;
8445       long linkID;
8446       checkedLinkIDs.clear();
8447       gp_XYZ prevXYZ( prevSideNode->X(), prevSideNode->Y(), prevSideNode->Z() );
8448
8449       // loop on inverse elements of current node (prevSideNode) on the Side 2
8450       SMDS_ElemIteratorPtr invElemIt = prevSideNode->GetInverseElementIterator();
8451       while ( invElemIt->more() )
8452       {
8453         const SMDS_MeshElement* elem = invElemIt->next();
8454         // prepare data for a loop on links coming to prevSideNode, of a face or a volume
8455         int iPrevNode, iNode = 0, nbNodes = elem->NbNodes();
8456         vector< const SMDS_MeshNode* > faceNodes( nbNodes, (const SMDS_MeshNode*)0 );
8457         bool isVolume = volume.Set( elem );
8458         const SMDS_MeshNode** nodes = isVolume ? volume.GetNodes() : & faceNodes[0];
8459         if ( isVolume ) // --volume
8460           hasVolumes = true;
8461         else if ( elem->GetType()==SMDSAbs_Face ) { // --face
8462           // retrieve all face nodes and find iPrevNode - an index of the prevSideNode
8463           if(elem->IsQuadratic()) {
8464             const SMDS_VtkFace* F =
8465               dynamic_cast<const SMDS_VtkFace*>(elem);
8466             if (!F) throw SALOME_Exception(LOCALIZED("not an SMDS_VtkFace"));
8467             // use special nodes iterator
8468             SMDS_ElemIteratorPtr anIter = F->interlacedNodesElemIterator();
8469             while( anIter->more() ) {
8470               nodes[ iNode ] = cast2Node(anIter->next());
8471               if ( nodes[ iNode++ ] == prevSideNode )
8472                 iPrevNode = iNode - 1;
8473             }
8474           }
8475           else {
8476             SMDS_ElemIteratorPtr nIt = elem->nodesIterator();
8477             while ( nIt->more() ) {
8478               nodes[ iNode ] = cast2Node( nIt->next() );
8479               if ( nodes[ iNode++ ] == prevSideNode )
8480                 iPrevNode = iNode - 1;
8481             }
8482           }
8483           // there are 2 links to check
8484           nbNodes = 2;
8485         }
8486         else // --edge
8487           continue;
8488         // loop on links, to be precise, on the second node of links
8489         for ( iNode = 0; iNode < nbNodes; iNode++ ) {
8490           const SMDS_MeshNode* n = nodes[ iNode ];
8491           if ( isVolume ) {
8492             if ( !volume.IsLinked( n, prevSideNode ))
8493               continue;
8494           }
8495           else {
8496             if ( iNode ) // a node before prevSideNode
8497               n = nodes[ iPrevNode == 0 ? elem->NbNodes() - 1 : iPrevNode - 1 ];
8498             else         // a node after prevSideNode
8499               n = nodes[ iPrevNode + 1 == elem->NbNodes() ? 0 : iPrevNode + 1 ];
8500           }
8501           // check if this link was already used
8502           long iLink = aLinkID_Gen.GetLinkID( prevSideNode, n );
8503           bool isJustChecked = !checkedLinkIDs.insert( iLink ).second;
8504           if (!isJustChecked &&
8505               foundSideLinkIDs.find( iLink ) == foundSideLinkIDs.end() )
8506           {
8507             // test a link geometrically
8508             gp_XYZ nextXYZ ( n->X(), n->Y(), n->Z() );
8509             bool linkIsBetter = false;
8510             double dot = 0.0, dist = 0.0;
8511             if ( searchByDir ) { // choose most co-directed link
8512               dot = bordDir * ( nextXYZ - prevXYZ ).Normalized();
8513               linkIsBetter = ( dot > maxDot );
8514             }
8515             else { // choose link with the node closest to bordPos
8516               dist = ( nextXYZ - bordPos ).SquareModulus();
8517               linkIsBetter = ( dist < minDist );
8518             }
8519             if ( linkIsBetter ) {
8520               maxDot = dot;
8521               minDist = dist;
8522               linkID = iLink;
8523               sideNode = n;
8524               sideElem = elem;
8525             }
8526           }
8527         }
8528       } // loop on inverse elements of prevSideNode
8529
8530       if ( !sideNode ) {
8531         MESSAGE(" Cant find path by links of the Side 2 ");
8532         return SEW_BAD_SIDE_NODES;
8533       }
8534       sideNodes.push_back( sideNode );
8535       sideElems.push_back( sideElem );
8536       foundSideLinkIDs.insert ( linkID );
8537       prevSideNode = sideNode;
8538
8539       if ( *nBordIt == theBordLastNode )
8540         searchByDir = false;
8541       else {
8542         // find the next border link to compare with
8543         gp_XYZ sidePos( sideNode->X(), sideNode->Y(), sideNode->Z() );
8544         searchByDir = ( bordDir * ( sidePos - bordPos ) <= 0 );
8545         // move to next border node if sideNode is before forward border node (bordPos)
8546         while ( *nBordIt != theBordLastNode && !searchByDir ) {
8547           prevBordNode = *nBordIt;
8548           nBordIt++;
8549           bordPos = nBordXYZ[ *nBordIt ];
8550           bordDir = bordPos - nBordXYZ[ prevBordNode ];
8551           searchByDir = ( bordDir * ( sidePos - bordPos ) <= 0 );
8552         }
8553       }
8554     }
8555     while ( sideNode != theSideSecondNode );
8556
8557     if ( hasVolumes && sideNodes.size () != bordNodes.size() && !toCreatePolyedrs) {
8558       MESSAGE("VOLUME SPLITTING IS FORBIDDEN");
8559       return SEW_VOLUMES_TO_SPLIT; // volume splitting is forbidden
8560     }
8561   } // end nodes search on the side 2
8562
8563   // ============================
8564   // sew the border to the side 2
8565   // ============================
8566
8567   int nbNodes[]  = { nSide[0].size(), nSide[1].size() };
8568   int maxNbNodes = Max( nbNodes[0], nbNodes[1] );
8569
8570   TListOfListOfNodes nodeGroupsToMerge;
8571   if ( nbNodes[0] == nbNodes[1] ||
8572        ( theSideIsFreeBorder && !theSideThirdNode)) {
8573
8574     // all nodes are to be merged
8575
8576     for (nIt[0] = nSide[0].begin(), nIt[1] = nSide[1].begin();
8577          nIt[0] != nSide[0].end() && nIt[1] != nSide[1].end();
8578          nIt[0]++, nIt[1]++ )
8579     {
8580       nodeGroupsToMerge.push_back( list<const SMDS_MeshNode*>() );
8581       nodeGroupsToMerge.back().push_back( *nIt[1] ); // to keep
8582       nodeGroupsToMerge.back().push_back( *nIt[0] ); // to remove
8583     }
8584   }
8585   else {
8586
8587     // insert new nodes into the border and the side to get equal nb of segments
8588
8589     // get normalized parameters of nodes on the borders
8590     //double param[ 2 ][ maxNbNodes ];
8591     double* param[ 2 ];
8592     param[0] = new double [ maxNbNodes ];
8593     param[1] = new double [ maxNbNodes ];
8594     int iNode, iBord;
8595     for ( iBord = 0; iBord < 2; iBord++ ) { // loop on 2 borders
8596       list< const SMDS_MeshNode* >& nodes = nSide[ iBord ];
8597       list< const SMDS_MeshNode* >::iterator nIt = nodes.begin();
8598       const SMDS_MeshNode* nPrev = *nIt;
8599       double bordLength = 0;
8600       for ( iNode = 0; nIt != nodes.end(); nIt++, iNode++ ) { // loop on border nodes
8601         const SMDS_MeshNode* nCur = *nIt;
8602         gp_XYZ segment (nCur->X() - nPrev->X(),
8603                         nCur->Y() - nPrev->Y(),
8604                         nCur->Z() - nPrev->Z());
8605         double segmentLen = segment.Modulus();
8606         bordLength += segmentLen;
8607         param[ iBord ][ iNode ] = bordLength;
8608         nPrev = nCur;
8609       }
8610       // normalize within [0,1]
8611       for ( iNode = 0; iNode < nbNodes[ iBord ]; iNode++ ) {
8612         param[ iBord ][ iNode ] /= bordLength;
8613       }
8614     }
8615
8616     // loop on border segments
8617     const SMDS_MeshNode *nPrev[ 2 ] = { 0, 0 };
8618     int i[ 2 ] = { 0, 0 };
8619     nIt[0] = nSide[0].begin(); eIt[0] = eSide[0].begin();
8620     nIt[1] = nSide[1].begin(); eIt[1] = eSide[1].begin();
8621
8622     TElemOfNodeListMap insertMap;
8623     TElemOfNodeListMap::iterator insertMapIt;
8624     // insertMap is
8625     // key:   elem to insert nodes into
8626     // value: 2 nodes to insert between + nodes to be inserted
8627     do {
8628       bool next[ 2 ] = { false, false };
8629
8630       // find min adjacent segment length after sewing
8631       double nextParam = 10., prevParam = 0;
8632       for ( iBord = 0; iBord < 2; iBord++ ) { // loop on 2 borders
8633         if ( i[ iBord ] + 1 < nbNodes[ iBord ])
8634           nextParam = Min( nextParam, param[iBord][ i[iBord] + 1 ]);
8635         if ( i[ iBord ] > 0 )
8636           prevParam = Max( prevParam, param[iBord][ i[iBord] - 1 ]);
8637       }
8638       double minParam = Min( param[ 0 ][ i[0] ], param[ 1 ][ i[1] ]);
8639       double maxParam = Max( param[ 0 ][ i[0] ], param[ 1 ][ i[1] ]);
8640       double minSegLen = Min( nextParam - minParam, maxParam - prevParam );
8641
8642       // choose to insert or to merge nodes
8643       double du = param[ 1 ][ i[1] ] - param[ 0 ][ i[0] ];
8644       if ( Abs( du ) <= minSegLen * 0.2 ) {
8645         // merge
8646         // ------
8647         nodeGroupsToMerge.push_back( list<const SMDS_MeshNode*>() );
8648         const SMDS_MeshNode* n0 = *nIt[0];
8649         const SMDS_MeshNode* n1 = *nIt[1];
8650         nodeGroupsToMerge.back().push_back( n1 );
8651         nodeGroupsToMerge.back().push_back( n0 );
8652         // position of node of the border changes due to merge
8653         param[ 0 ][ i[0] ] += du;
8654         // move n1 for the sake of elem shape evaluation during insertion.
8655         // n1 will be removed by MergeNodes() anyway
8656         const_cast<SMDS_MeshNode*>( n0 )->setXYZ( n1->X(), n1->Y(), n1->Z() );
8657         next[0] = next[1] = true;
8658       }
8659       else {
8660         // insert
8661         // ------
8662         int intoBord = ( du < 0 ) ? 0 : 1;
8663         const SMDS_MeshElement* elem = *eIt[ intoBord ];
8664         const SMDS_MeshNode*    n1   = nPrev[ intoBord ];
8665         const SMDS_MeshNode*    n2   = *nIt[ intoBord ];
8666         const SMDS_MeshNode*    nIns = *nIt[ 1 - intoBord ];
8667         if ( intoBord == 1 ) {
8668           // move node of the border to be on a link of elem of the side
8669           gp_XYZ p1 (n1->X(), n1->Y(), n1->Z());
8670           gp_XYZ p2 (n2->X(), n2->Y(), n2->Z());
8671           double ratio = du / ( param[ 1 ][ i[1] ] - param[ 1 ][ i[1]-1 ]);
8672           gp_XYZ p = p2 * ( 1 - ratio ) + p1 * ratio;
8673           GetMeshDS()->MoveNode( nIns, p.X(), p.Y(), p.Z() );
8674         }
8675         insertMapIt = insertMap.find( elem );
8676         bool notFound = ( insertMapIt == insertMap.end() );
8677         bool otherLink = ( !notFound && (*insertMapIt).second.front() != n1 );
8678         if ( otherLink ) {
8679           // insert into another link of the same element:
8680           // 1. perform insertion into the other link of the elem
8681           list<const SMDS_MeshNode*> & nodeList = (*insertMapIt).second;
8682           const SMDS_MeshNode* n12 = nodeList.front(); nodeList.pop_front();
8683           const SMDS_MeshNode* n22 = nodeList.front(); nodeList.pop_front();
8684           InsertNodesIntoLink( elem, n12, n22, nodeList, toCreatePolygons );
8685           // 2. perform insertion into the link of adjacent faces
8686           while (true) {
8687             const SMDS_MeshElement* adjElem = findAdjacentFace( n12, n22, elem );
8688             if ( adjElem )
8689               InsertNodesIntoLink( adjElem, n12, n22, nodeList, toCreatePolygons );
8690             else
8691               break;
8692           }
8693           if (toCreatePolyedrs) {
8694             // perform insertion into the links of adjacent volumes
8695             UpdateVolumes(n12, n22, nodeList);
8696           }
8697           // 3. find an element appeared on n1 and n2 after the insertion
8698           insertMap.erase( elem );
8699           elem = findAdjacentFace( n1, n2, 0 );
8700         }
8701         if ( notFound || otherLink ) {
8702           // add element and nodes of the side into the insertMap
8703           insertMapIt = insertMap.insert
8704             ( TElemOfNodeListMap::value_type( elem, list<const SMDS_MeshNode*>() )).first;
8705           (*insertMapIt).second.push_back( n1 );
8706           (*insertMapIt).second.push_back( n2 );
8707         }
8708         // add node to be inserted into elem
8709         (*insertMapIt).second.push_back( nIns );
8710         next[ 1 - intoBord ] = true;
8711       }
8712
8713       // go to the next segment
8714       for ( iBord = 0; iBord < 2; iBord++ ) { // loop on 2 borders
8715         if ( next[ iBord ] ) {
8716           if ( i[ iBord ] != 0 && eIt[ iBord ] != eSide[ iBord ].end())
8717             eIt[ iBord ]++;
8718           nPrev[ iBord ] = *nIt[ iBord ];
8719           nIt[ iBord ]++; i[ iBord ]++;
8720         }
8721       }
8722     }
8723     while ( nIt[0] != nSide[0].end() && nIt[1] != nSide[1].end());
8724
8725     // perform insertion of nodes into elements
8726
8727     for (insertMapIt = insertMap.begin();
8728          insertMapIt != insertMap.end();
8729          insertMapIt++ )
8730     {
8731       const SMDS_MeshElement* elem = (*insertMapIt).first;
8732       list<const SMDS_MeshNode*> & nodeList = (*insertMapIt).second;
8733       const SMDS_MeshNode* n1 = nodeList.front(); nodeList.pop_front();
8734       const SMDS_MeshNode* n2 = nodeList.front(); nodeList.pop_front();
8735
8736       InsertNodesIntoLink( elem, n1, n2, nodeList, toCreatePolygons );
8737
8738       if ( !theSideIsFreeBorder ) {
8739         // look for and insert nodes into the faces adjacent to elem
8740         while (true) {
8741           const SMDS_MeshElement* adjElem = findAdjacentFace( n1, n2, elem );
8742           if ( adjElem )
8743             InsertNodesIntoLink( adjElem, n1, n2, nodeList, toCreatePolygons );
8744           else
8745             break;
8746         }
8747       }
8748       if (toCreatePolyedrs) {
8749         // perform insertion into the links of adjacent volumes
8750         UpdateVolumes(n1, n2, nodeList);
8751       }
8752     }
8753
8754     delete param[0];
8755     delete param[1];
8756   } // end: insert new nodes
8757
8758   MergeNodes ( nodeGroupsToMerge );
8759
8760   return aResult;
8761 }
8762
8763 //=======================================================================
8764 //function : InsertNodesIntoLink
8765 //purpose  : insert theNodesToInsert into theFace between theBetweenNode1
8766 //           and theBetweenNode2 and split theElement
8767 //=======================================================================
8768
8769 void SMESH_MeshEditor::InsertNodesIntoLink(const SMDS_MeshElement*     theFace,
8770                                            const SMDS_MeshNode*        theBetweenNode1,
8771                                            const SMDS_MeshNode*        theBetweenNode2,
8772                                            list<const SMDS_MeshNode*>& theNodesToInsert,
8773                                            const bool                  toCreatePoly)
8774 {
8775   if ( theFace->GetType() != SMDSAbs_Face ) return;
8776
8777   // find indices of 2 link nodes and of the rest nodes
8778   int iNode = 0, il1, il2, i3, i4;
8779   il1 = il2 = i3 = i4 = -1;
8780   //const SMDS_MeshNode* nodes[ theFace->NbNodes() ];
8781   vector<const SMDS_MeshNode*> nodes( theFace->NbNodes() );
8782
8783   if(theFace->IsQuadratic()) {
8784     const SMDS_VtkFace* F =
8785       dynamic_cast<const SMDS_VtkFace*>(theFace);
8786     if (!F) throw SALOME_Exception(LOCALIZED("not an SMDS_VtkFace"));
8787     // use special nodes iterator
8788     SMDS_ElemIteratorPtr anIter = F->interlacedNodesElemIterator();
8789     while( anIter->more() ) {
8790       const SMDS_MeshNode* n = cast2Node(anIter->next());
8791       if ( n == theBetweenNode1 )
8792         il1 = iNode;
8793       else if ( n == theBetweenNode2 )
8794         il2 = iNode;
8795       else if ( i3 < 0 )
8796         i3 = iNode;
8797       else
8798         i4 = iNode;
8799       nodes[ iNode++ ] = n;
8800     }
8801   }
8802   else {
8803     SMDS_ElemIteratorPtr nodeIt = theFace->nodesIterator();
8804     while ( nodeIt->more() ) {
8805       const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
8806       if ( n == theBetweenNode1 )
8807         il1 = iNode;
8808       else if ( n == theBetweenNode2 )
8809         il2 = iNode;
8810       else if ( i3 < 0 )
8811         i3 = iNode;
8812       else
8813         i4 = iNode;
8814       nodes[ iNode++ ] = n;
8815     }
8816   }
8817   if ( il1 < 0 || il2 < 0 || i3 < 0 )
8818     return ;
8819
8820   // arrange link nodes to go one after another regarding the face orientation
8821   bool reverse = ( Abs( il2 - il1 ) == 1 ? il2 < il1 : il1 < il2 );
8822   list<const SMDS_MeshNode *> aNodesToInsert = theNodesToInsert;
8823   if ( reverse ) {
8824     iNode = il1;
8825     il1 = il2;
8826     il2 = iNode;
8827     aNodesToInsert.reverse();
8828   }
8829   // check that not link nodes of a quadrangles are in good order
8830   int nbFaceNodes = theFace->NbNodes();
8831   if ( nbFaceNodes == 4 && i4 - i3 != 1 ) {
8832     iNode = i3;
8833     i3 = i4;
8834     i4 = iNode;
8835   }
8836
8837   if (toCreatePoly || theFace->IsPoly()) {
8838
8839     iNode = 0;
8840     vector<const SMDS_MeshNode *> poly_nodes (nbFaceNodes + aNodesToInsert.size());
8841
8842     // add nodes of face up to first node of link
8843     bool isFLN = false;
8844
8845     if(theFace->IsQuadratic()) {
8846       const SMDS_VtkFace* F =
8847         dynamic_cast<const SMDS_VtkFace*>(theFace);
8848       if (!F) throw SALOME_Exception(LOCALIZED("not an SMDS_VtkFace"));
8849       // use special nodes iterator
8850       SMDS_ElemIteratorPtr anIter = F->interlacedNodesElemIterator();
8851       while( anIter->more()  && !isFLN ) {
8852         const SMDS_MeshNode* n = cast2Node(anIter->next());
8853         poly_nodes[iNode++] = n;
8854         if (n == nodes[il1]) {
8855           isFLN = true;
8856         }
8857       }
8858       // add nodes to insert
8859       list<const SMDS_MeshNode*>::iterator nIt = aNodesToInsert.begin();
8860       for (; nIt != aNodesToInsert.end(); nIt++) {
8861         poly_nodes[iNode++] = *nIt;
8862       }
8863       // add nodes of face starting from last node of link
8864       while ( anIter->more() ) {
8865         poly_nodes[iNode++] = cast2Node(anIter->next());
8866       }
8867     }
8868     else {
8869       SMDS_ElemIteratorPtr nodeIt = theFace->nodesIterator();
8870       while ( nodeIt->more() && !isFLN ) {
8871         const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
8872         poly_nodes[iNode++] = n;
8873         if (n == nodes[il1]) {
8874           isFLN = true;
8875         }
8876       }
8877       // add nodes to insert
8878       list<const SMDS_MeshNode*>::iterator nIt = aNodesToInsert.begin();
8879       for (; nIt != aNodesToInsert.end(); nIt++) {
8880         poly_nodes[iNode++] = *nIt;
8881       }
8882       // add nodes of face starting from last node of link
8883       while ( nodeIt->more() ) {
8884         const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
8885         poly_nodes[iNode++] = n;
8886       }
8887     }
8888
8889     // edit or replace the face
8890     SMESHDS_Mesh *aMesh = GetMeshDS();
8891
8892     if (theFace->IsPoly()) {
8893       aMesh->ChangePolygonNodes(theFace, poly_nodes);
8894     }
8895     else {
8896       int aShapeId = FindShape( theFace );
8897
8898       SMDS_MeshElement* newElem = aMesh->AddPolygonalFace(poly_nodes);
8899       myLastCreatedElems.Append(newElem);
8900       if ( aShapeId && newElem )
8901         aMesh->SetMeshElementOnShape( newElem, aShapeId );
8902
8903       aMesh->RemoveElement(theFace);
8904     }
8905     return;
8906   }
8907
8908   SMESHDS_Mesh *aMesh = GetMeshDS();
8909   if( !theFace->IsQuadratic() ) {
8910
8911     // put aNodesToInsert between theBetweenNode1 and theBetweenNode2
8912     int nbLinkNodes = 2 + aNodesToInsert.size();
8913     //const SMDS_MeshNode* linkNodes[ nbLinkNodes ];
8914     vector<const SMDS_MeshNode*> linkNodes( nbLinkNodes );
8915     linkNodes[ 0 ] = nodes[ il1 ];
8916     linkNodes[ nbLinkNodes - 1 ] = nodes[ il2 ];
8917     list<const SMDS_MeshNode*>::iterator nIt = aNodesToInsert.begin();
8918     for ( iNode = 1; nIt != aNodesToInsert.end(); nIt++ ) {
8919       linkNodes[ iNode++ ] = *nIt;
8920     }
8921     // decide how to split a quadrangle: compare possible variants
8922     // and choose which of splits to be a quadrangle
8923     int i1, i2, iSplit, nbSplits = nbLinkNodes - 1, iBestQuad;
8924     if ( nbFaceNodes == 3 ) {
8925       iBestQuad = nbSplits;
8926       i4 = i3;
8927     }
8928     else if ( nbFaceNodes == 4 ) {
8929       SMESH::Controls::NumericalFunctorPtr aCrit( new SMESH::Controls::AspectRatio);
8930       double aBestRate = DBL_MAX;
8931       for ( int iQuad = 0; iQuad < nbSplits; iQuad++ ) {
8932         i1 = 0; i2 = 1;
8933         double aBadRate = 0;
8934         // evaluate elements quality
8935         for ( iSplit = 0; iSplit < nbSplits; iSplit++ ) {
8936           if ( iSplit == iQuad ) {
8937             SMDS_FaceOfNodes quad (linkNodes[ i1++ ],
8938                                    linkNodes[ i2++ ],
8939                                    nodes[ i3 ],
8940                                    nodes[ i4 ]);
8941             aBadRate += getBadRate( &quad, aCrit );
8942           }
8943           else {
8944             SMDS_FaceOfNodes tria (linkNodes[ i1++ ],
8945                                    linkNodes[ i2++ ],
8946                                    nodes[ iSplit < iQuad ? i4 : i3 ]);
8947             aBadRate += getBadRate( &tria, aCrit );
8948           }
8949         }
8950         // choice
8951         if ( aBadRate < aBestRate ) {
8952           iBestQuad = iQuad;
8953           aBestRate = aBadRate;
8954         }
8955       }
8956     }
8957
8958     // create new elements
8959     int aShapeId = FindShape( theFace );
8960
8961     i1 = 0; i2 = 1;
8962     for ( iSplit = 0; iSplit < nbSplits - 1; iSplit++ ) {
8963       SMDS_MeshElement* newElem = 0;
8964       if ( iSplit == iBestQuad )
8965         newElem = aMesh->AddFace (linkNodes[ i1++ ],
8966                                   linkNodes[ i2++ ],
8967                                   nodes[ i3 ],
8968                                   nodes[ i4 ]);
8969       else
8970         newElem = aMesh->AddFace (linkNodes[ i1++ ],
8971                                   linkNodes[ i2++ ],
8972                                   nodes[ iSplit < iBestQuad ? i4 : i3 ]);
8973       myLastCreatedElems.Append(newElem);
8974       if ( aShapeId && newElem )
8975         aMesh->SetMeshElementOnShape( newElem, aShapeId );
8976     }
8977
8978     // change nodes of theFace
8979     const SMDS_MeshNode* newNodes[ 4 ];
8980     newNodes[ 0 ] = linkNodes[ i1 ];
8981     newNodes[ 1 ] = linkNodes[ i2 ];
8982     newNodes[ 2 ] = nodes[ iSplit >= iBestQuad ? i3 : i4 ];
8983     newNodes[ 3 ] = nodes[ i4 ];
8984     //aMesh->ChangeElementNodes( theFace, newNodes, iSplit == iBestQuad ? 4 : 3 );
8985     const SMDS_MeshElement* newElem = 0;
8986     if (iSplit == iBestQuad)
8987       newElem = aMesh->AddFace( newNodes[0], newNodes[1], newNodes[2], newNodes[3] );
8988     else
8989       newElem = aMesh->AddFace( newNodes[0], newNodes[1], newNodes[2] );
8990     myLastCreatedElems.Append(newElem);
8991     if ( aShapeId && newElem )
8992       aMesh->SetMeshElementOnShape( newElem, aShapeId );
8993 } // end if(!theFace->IsQuadratic())
8994   else { // theFace is quadratic
8995     // we have to split theFace on simple triangles and one simple quadrangle
8996     int tmp = il1/2;
8997     int nbshift = tmp*2;
8998     // shift nodes in nodes[] by nbshift
8999     int i,j;
9000     for(i=0; i<nbshift; i++) {
9001       const SMDS_MeshNode* n = nodes[0];
9002       for(j=0; j<nbFaceNodes-1; j++) {
9003         nodes[j] = nodes[j+1];
9004       }
9005       nodes[nbFaceNodes-1] = n;
9006     }
9007     il1 = il1 - nbshift;
9008     // now have to insert nodes between n0 and n1 or n1 and n2 (see below)
9009     //   n0      n1     n2    n0      n1     n2
9010     //     +-----+-----+        +-----+-----+
9011     //      \         /         |           |
9012     //       \       /          |           |
9013     //      n5+     +n3       n7+           +n3
9014     //         \   /            |           |
9015     //          \ /             |           |
9016     //           +              +-----+-----+
9017     //           n4           n6      n5     n4
9018
9019     // create new elements
9020     int aShapeId = FindShape( theFace );
9021
9022     int n1,n2,n3;
9023     if(nbFaceNodes==6) { // quadratic triangle
9024       SMDS_MeshElement* newElem =
9025         aMesh->AddFace(nodes[3],nodes[4],nodes[5]);
9026       myLastCreatedElems.Append(newElem);
9027       if ( aShapeId && newElem )
9028         aMesh->SetMeshElementOnShape( newElem, aShapeId );
9029       if(theFace->IsMediumNode(nodes[il1])) {
9030         // create quadrangle
9031         newElem = aMesh->AddFace(nodes[0],nodes[1],nodes[3],nodes[5]);
9032         myLastCreatedElems.Append(newElem);
9033         if ( aShapeId && newElem )
9034           aMesh->SetMeshElementOnShape( newElem, aShapeId );
9035         n1 = 1;
9036         n2 = 2;
9037         n3 = 3;
9038       }
9039       else {
9040         // create quadrangle
9041         newElem = aMesh->AddFace(nodes[1],nodes[2],nodes[3],nodes[5]);
9042         myLastCreatedElems.Append(newElem);
9043         if ( aShapeId && newElem )
9044           aMesh->SetMeshElementOnShape( newElem, aShapeId );
9045         n1 = 0;
9046         n2 = 1;
9047         n3 = 5;
9048       }
9049     }
9050     else { // nbFaceNodes==8 - quadratic quadrangle
9051       SMDS_MeshElement* newElem =
9052         aMesh->AddFace(nodes[3],nodes[4],nodes[5]);
9053       myLastCreatedElems.Append(newElem);
9054       if ( aShapeId && newElem )
9055         aMesh->SetMeshElementOnShape( newElem, aShapeId );
9056       newElem = aMesh->AddFace(nodes[5],nodes[6],nodes[7]);
9057       myLastCreatedElems.Append(newElem);
9058       if ( aShapeId && newElem )
9059         aMesh->SetMeshElementOnShape( newElem, aShapeId );
9060       newElem = aMesh->AddFace(nodes[5],nodes[7],nodes[3]);
9061       myLastCreatedElems.Append(newElem);
9062       if ( aShapeId && newElem )
9063         aMesh->SetMeshElementOnShape( newElem, aShapeId );
9064       if(theFace->IsMediumNode(nodes[il1])) {
9065         // create quadrangle
9066         newElem = aMesh->AddFace(nodes[0],nodes[1],nodes[3],nodes[7]);
9067         myLastCreatedElems.Append(newElem);
9068         if ( aShapeId && newElem )
9069           aMesh->SetMeshElementOnShape( newElem, aShapeId );
9070         n1 = 1;
9071         n2 = 2;
9072         n3 = 3;
9073       }
9074       else {
9075         // create quadrangle
9076         newElem = aMesh->AddFace(nodes[1],nodes[2],nodes[3],nodes[7]);
9077         myLastCreatedElems.Append(newElem);
9078         if ( aShapeId && newElem )
9079           aMesh->SetMeshElementOnShape( newElem, aShapeId );
9080         n1 = 0;
9081         n2 = 1;
9082         n3 = 7;
9083       }
9084     }
9085     // create needed triangles using n1,n2,n3 and inserted nodes
9086     int nbn = 2 + aNodesToInsert.size();
9087     //const SMDS_MeshNode* aNodes[nbn];
9088     vector<const SMDS_MeshNode*> aNodes(nbn);
9089     aNodes[0] = nodes[n1];
9090     aNodes[nbn-1] = nodes[n2];
9091     list<const SMDS_MeshNode*>::iterator nIt = aNodesToInsert.begin();
9092     for ( iNode = 1; nIt != aNodesToInsert.end(); nIt++ ) {
9093       aNodes[iNode++] = *nIt;
9094     }
9095     for(i=1; i<nbn; i++) {
9096       SMDS_MeshElement* newElem =
9097         aMesh->AddFace(aNodes[i-1],aNodes[i],nodes[n3]);
9098       myLastCreatedElems.Append(newElem);
9099       if ( aShapeId && newElem )
9100         aMesh->SetMeshElementOnShape( newElem, aShapeId );
9101     }
9102   }
9103   // remove old face
9104   aMesh->RemoveElement(theFace);
9105 }
9106
9107 //=======================================================================
9108 //function : UpdateVolumes
9109 //purpose  :
9110 //=======================================================================
9111 void SMESH_MeshEditor::UpdateVolumes (const SMDS_MeshNode*        theBetweenNode1,
9112                                       const SMDS_MeshNode*        theBetweenNode2,
9113                                       list<const SMDS_MeshNode*>& theNodesToInsert)
9114 {
9115   myLastCreatedElems.Clear();
9116   myLastCreatedNodes.Clear();
9117
9118   SMDS_ElemIteratorPtr invElemIt = theBetweenNode1->GetInverseElementIterator(SMDSAbs_Volume);
9119   while (invElemIt->more()) { // loop on inverse elements of theBetweenNode1
9120     const SMDS_MeshElement* elem = invElemIt->next();
9121
9122     // check, if current volume has link theBetweenNode1 - theBetweenNode2
9123     SMDS_VolumeTool aVolume (elem);
9124     if (!aVolume.IsLinked(theBetweenNode1, theBetweenNode2))
9125       continue;
9126
9127     // insert new nodes in all faces of the volume, sharing link theBetweenNode1 - theBetweenNode2
9128     int iface, nbFaces = aVolume.NbFaces();
9129     vector<const SMDS_MeshNode *> poly_nodes;
9130     vector<int> quantities (nbFaces);
9131
9132     for (iface = 0; iface < nbFaces; iface++) {
9133       int nbFaceNodes = aVolume.NbFaceNodes(iface), nbInserted = 0;
9134       // faceNodes will contain (nbFaceNodes + 1) nodes, last = first
9135       const SMDS_MeshNode** faceNodes = aVolume.GetFaceNodes(iface);
9136
9137       for (int inode = 0; inode < nbFaceNodes; inode++) {
9138         poly_nodes.push_back(faceNodes[inode]);
9139
9140         if (nbInserted == 0) {
9141           if (faceNodes[inode] == theBetweenNode1) {
9142             if (faceNodes[inode + 1] == theBetweenNode2) {
9143               nbInserted = theNodesToInsert.size();
9144
9145               // add nodes to insert
9146               list<const SMDS_MeshNode*>::iterator nIt = theNodesToInsert.begin();
9147               for (; nIt != theNodesToInsert.end(); nIt++) {
9148                 poly_nodes.push_back(*nIt);
9149               }
9150             }
9151           }
9152           else if (faceNodes[inode] == theBetweenNode2) {
9153             if (faceNodes[inode + 1] == theBetweenNode1) {
9154               nbInserted = theNodesToInsert.size();
9155
9156               // add nodes to insert in reversed order
9157               list<const SMDS_MeshNode*>::iterator nIt = theNodesToInsert.end();
9158               nIt--;
9159               for (; nIt != theNodesToInsert.begin(); nIt--) {
9160                 poly_nodes.push_back(*nIt);
9161               }
9162               poly_nodes.push_back(*nIt);
9163             }
9164           }
9165           else {
9166           }
9167         }
9168       }
9169       quantities[iface] = nbFaceNodes + nbInserted;
9170     }
9171
9172     // Replace or update the volume
9173     SMESHDS_Mesh *aMesh = GetMeshDS();
9174
9175     if (elem->IsPoly()) {
9176       aMesh->ChangePolyhedronNodes(elem, poly_nodes, quantities);
9177
9178     }
9179     else {
9180       int aShapeId = FindShape( elem );
9181
9182       SMDS_MeshElement* newElem =
9183         aMesh->AddPolyhedralVolume(poly_nodes, quantities);
9184       myLastCreatedElems.Append(newElem);
9185       if (aShapeId && newElem)
9186         aMesh->SetMeshElementOnShape(newElem, aShapeId);
9187
9188       aMesh->RemoveElement(elem);
9189     }
9190   }
9191 }
9192
9193 //=======================================================================
9194 /*!
9195  * \brief Convert elements contained in a submesh to quadratic
9196  * \return int - nb of checked elements
9197  */
9198 //=======================================================================
9199
9200 int SMESH_MeshEditor::convertElemToQuadratic(SMESHDS_SubMesh *   theSm,
9201                                              SMESH_MesherHelper& theHelper,
9202                                              const bool          theForce3d)
9203 {
9204   int nbElem = 0;
9205   if( !theSm ) return nbElem;
9206
9207   vector<int> nbNodeInFaces;
9208   SMDS_ElemIteratorPtr ElemItr = theSm->GetElements();
9209   while(ElemItr->more())
9210   {
9211     nbElem++;
9212     const SMDS_MeshElement* elem = ElemItr->next();
9213     if( !elem || elem->IsQuadratic() ) continue;
9214
9215     int id = elem->GetID();
9216     int nbNodes = elem->NbNodes();
9217     SMDSAbs_ElementType aType = elem->GetType();
9218
9219     vector<const SMDS_MeshNode *> nodes (elem->begin_nodes(), elem->end_nodes());
9220     if ( elem->GetEntityType() == SMDSEntity_Polyhedra )
9221       nbNodeInFaces = static_cast<const SMDS_VtkVolume* >( elem )->GetQuantities();
9222
9223     GetMeshDS()->RemoveFreeElement(elem, theSm, /*fromGroups=*/false);
9224
9225     const SMDS_MeshElement* NewElem = 0;
9226
9227     switch( aType )
9228     {
9229     case SMDSAbs_Edge :
9230       {
9231         NewElem = theHelper.AddEdge(nodes[0], nodes[1], id, theForce3d);
9232         break;
9233       }
9234     case SMDSAbs_Face :
9235       {
9236         switch(nbNodes)
9237         {
9238         case 3:
9239           NewElem = theHelper.AddFace(nodes[0], nodes[1], nodes[2], id, theForce3d);
9240           break;
9241         case 4:
9242           NewElem = theHelper.AddFace(nodes[0], nodes[1], nodes[2], nodes[3], id, theForce3d);
9243           break;
9244         default:
9245           NewElem = theHelper.AddPolygonalFace(nodes, id, theForce3d);
9246           continue;
9247         }
9248         break;
9249       }
9250     case SMDSAbs_Volume :
9251       {
9252         switch(nbNodes)
9253         {
9254         case 4:
9255           NewElem = theHelper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3], id, theForce3d);
9256           break;
9257         case 5:
9258           NewElem = theHelper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3], nodes[4], id, theForce3d);
9259           break;
9260         case 6:
9261           NewElem = theHelper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3], nodes[4], nodes[5], id, theForce3d);
9262           break;
9263         case 8:
9264           NewElem = theHelper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3],
9265                                         nodes[4], nodes[5], nodes[6], nodes[7], id, theForce3d);
9266           break;
9267         default:
9268           NewElem = theHelper.AddPolyhedralVolume(nodes, nbNodeInFaces, id, theForce3d);
9269         }
9270         break;
9271       }
9272     default :
9273       continue;
9274     }
9275     ReplaceElemInGroups( elem, NewElem, GetMeshDS());
9276     if( NewElem )
9277       theSm->AddElement( NewElem );
9278   }
9279 //  if (!GetMeshDS()->isCompacted())
9280 //    GetMeshDS()->compactMesh();
9281   return nbElem;
9282 }
9283
9284 //=======================================================================
9285 //function : ConvertToQuadratic
9286 //purpose  :
9287 //=======================================================================
9288 void SMESH_MeshEditor::ConvertToQuadratic(const bool theForce3d)
9289 {
9290   SMESHDS_Mesh* meshDS = GetMeshDS();
9291
9292   SMESH_MesherHelper aHelper(*myMesh);
9293   aHelper.SetIsQuadratic( true );
9294
9295   int nbCheckedElems = 0;
9296   if ( myMesh->HasShapeToMesh() )
9297   {
9298     if ( SMESH_subMesh *aSubMesh = myMesh->GetSubMeshContaining(myMesh->GetShapeToMesh()))
9299     {
9300       SMESH_subMeshIteratorPtr smIt = aSubMesh->getDependsOnIterator(true,false);
9301       while ( smIt->more() ) {
9302         SMESH_subMesh* sm = smIt->next();
9303         if ( SMESHDS_SubMesh *smDS = sm->GetSubMeshDS() ) {
9304           aHelper.SetSubShape( sm->GetSubShape() );
9305           nbCheckedElems += convertElemToQuadratic(smDS, aHelper, theForce3d);
9306         }
9307       }
9308     }
9309   }
9310   int totalNbElems = meshDS->NbEdges() + meshDS->NbFaces() + meshDS->NbVolumes();
9311   if ( nbCheckedElems < totalNbElems ) // not all elements are in submeshes
9312   {
9313     SMESHDS_SubMesh *smDS = 0;
9314     SMDS_EdgeIteratorPtr aEdgeItr = meshDS->edgesIterator();
9315     while(aEdgeItr->more())
9316     {
9317       const SMDS_MeshEdge* edge = aEdgeItr->next();
9318       if(edge && !edge->IsQuadratic())
9319       {
9320         int id = edge->GetID();
9321         //MESSAGE("edge->GetID() " << id);
9322         const SMDS_MeshNode* n1 = edge->GetNode(0);
9323         const SMDS_MeshNode* n2 = edge->GetNode(1);
9324
9325         meshDS->RemoveFreeElement(edge, smDS, /*fromGroups=*/false);
9326
9327         const SMDS_MeshEdge* NewEdge = aHelper.AddEdge(n1, n2, id, theForce3d);
9328         ReplaceElemInGroups( edge, NewEdge, GetMeshDS());
9329       }
9330     }
9331     SMDS_FaceIteratorPtr aFaceItr = meshDS->facesIterator();
9332     while(aFaceItr->more())
9333     {
9334       const SMDS_MeshFace* face = aFaceItr->next();
9335       if(!face || face->IsQuadratic() ) continue;
9336
9337       int id = face->GetID();
9338       int nbNodes = face->NbNodes();
9339       vector<const SMDS_MeshNode *> nodes ( face->begin_nodes(), face->end_nodes());
9340
9341       meshDS->RemoveFreeElement(face, smDS, /*fromGroups=*/false);
9342
9343       SMDS_MeshFace * NewFace = 0;
9344       switch(nbNodes)
9345       {
9346       case 3:
9347         NewFace = aHelper.AddFace(nodes[0], nodes[1], nodes[2], id, theForce3d);
9348         break;
9349       case 4:
9350         NewFace = aHelper.AddFace(nodes[0], nodes[1], nodes[2], nodes[3], id, theForce3d);
9351         break;
9352       default:
9353         NewFace = aHelper.AddPolygonalFace(nodes, id, theForce3d);
9354       }
9355       ReplaceElemInGroups( face, NewFace, GetMeshDS());
9356     }
9357     vector<int> nbNodeInFaces;
9358     SMDS_VolumeIteratorPtr aVolumeItr = meshDS->volumesIterator();
9359     while(aVolumeItr->more())
9360     {
9361       const SMDS_MeshVolume* volume = aVolumeItr->next();
9362       if(!volume || volume->IsQuadratic() ) continue;
9363
9364       int id = volume->GetID();
9365       int nbNodes = volume->NbNodes();
9366       vector<const SMDS_MeshNode *> nodes (volume->begin_nodes(), volume->end_nodes());
9367       if ( volume->GetEntityType() == SMDSEntity_Polyhedra )
9368         nbNodeInFaces = static_cast<const SMDS_VtkVolume* >(volume)->GetQuantities();
9369
9370       meshDS->RemoveFreeElement(volume, smDS, /*fromGroups=*/false);
9371
9372       SMDS_MeshVolume * NewVolume = 0;
9373       switch(nbNodes)
9374       {
9375       case 4:
9376         NewVolume = aHelper.AddVolume(nodes[0], nodes[1], nodes[2],
9377                                       nodes[3], id, theForce3d );
9378         break;
9379       case 5:
9380         NewVolume = aHelper.AddVolume(nodes[0], nodes[1], nodes[2],
9381                                       nodes[3], nodes[4], id, theForce3d);
9382         break;
9383       case 6:
9384         NewVolume = aHelper.AddVolume(nodes[0], nodes[1], nodes[2],
9385                                       nodes[3], nodes[4], nodes[5], id, theForce3d);
9386         break;
9387       case 8:
9388         NewVolume = aHelper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3],
9389                                       nodes[4], nodes[5], nodes[6], nodes[7], id, theForce3d);
9390         break;
9391       default:
9392         NewVolume = aHelper.AddPolyhedralVolume(nodes, nbNodeInFaces, id, theForce3d);
9393       }
9394       ReplaceElemInGroups(volume, NewVolume, meshDS);
9395     }
9396   }
9397
9398   if ( !theForce3d  && !getenv("NO_FixQuadraticElements"))
9399   { // setenv NO_FixQuadraticElements to know if FixQuadraticElements() is guilty of bad conversion
9400     aHelper.SetSubShape(0); // apply FixQuadraticElements() to the whole mesh
9401     aHelper.FixQuadraticElements();
9402   }
9403 }
9404
9405 //================================================================================
9406 /*!
9407  * \brief Makes given elements quadratic
9408  *  \param theForce3d - if true, the medium nodes will be placed in the middle of link
9409  *  \param theElements - elements to make quadratic 
9410  */
9411 //================================================================================
9412
9413 void SMESH_MeshEditor::ConvertToQuadratic(const bool        theForce3d,
9414                                           TIDSortedElemSet& theElements)
9415 {
9416   if ( theElements.empty() ) return;
9417
9418   // we believe that all theElements are of the same type
9419   SMDSAbs_ElementType elemType = (*theElements.begin())->GetType();
9420   
9421   // get all nodes shared by theElements
9422   TIDSortedNodeSet allNodes;
9423   TIDSortedElemSet::iterator eIt = theElements.begin();
9424   for ( ; eIt != theElements.end(); ++eIt )
9425     allNodes.insert( (*eIt)->begin_nodes(), (*eIt)->end_nodes() );
9426
9427   // complete theElements with elements of lower dim whose all nodes are in allNodes
9428
9429   TIDSortedElemSet quadAdjacentElems    [ SMDSAbs_NbElementTypes ]; // quadratic adjacent elements
9430   TIDSortedElemSet checkedAdjacentElems [ SMDSAbs_NbElementTypes ];
9431   TIDSortedNodeSet::iterator nIt = allNodes.begin();
9432   for ( ; nIt != allNodes.end(); ++nIt )
9433   {
9434     const SMDS_MeshNode* n = *nIt;
9435     SMDS_ElemIteratorPtr invIt = n->GetInverseElementIterator();
9436     while ( invIt->more() )
9437     {
9438       const SMDS_MeshElement* e = invIt->next();
9439       if ( e->IsQuadratic() )
9440       {
9441         quadAdjacentElems[ e->GetType() ].insert( e );
9442         continue;
9443       }
9444       if ( e->GetType() >= elemType )
9445       {
9446         continue; // same type of more complex linear element
9447       }
9448
9449       if ( !checkedAdjacentElems[ e->GetType() ].insert( e ).second )
9450         continue; // e is already checked
9451
9452       // check nodes
9453       bool allIn = true;
9454       SMDS_ElemIteratorPtr nodeIt = e->nodesIterator();
9455       while ( nodeIt->more() && allIn )
9456         allIn = allNodes.count( cast2Node( nodeIt->next() ));
9457       if ( allIn )
9458         theElements.insert(e );
9459     }
9460   }
9461
9462   SMESH_MesherHelper helper(*myMesh);
9463   helper.SetIsQuadratic( true );
9464
9465   // add links of quadratic adjacent elements to the helper
9466
9467   if ( !quadAdjacentElems[SMDSAbs_Edge].empty() )
9468     for ( eIt  = quadAdjacentElems[SMDSAbs_Edge].begin();
9469           eIt != quadAdjacentElems[SMDSAbs_Edge].end(); ++eIt )
9470     {
9471       helper.AddTLinks( static_cast< const SMDS_MeshEdge*> (*eIt) );
9472     }
9473   if ( !quadAdjacentElems[SMDSAbs_Face].empty() )
9474     for ( eIt  = quadAdjacentElems[SMDSAbs_Face].begin();
9475           eIt != quadAdjacentElems[SMDSAbs_Face].end(); ++eIt )
9476     {
9477       helper.AddTLinks( static_cast< const SMDS_MeshFace*> (*eIt) );
9478     }
9479   if ( !quadAdjacentElems[SMDSAbs_Volume].empty() )
9480     for ( eIt  = quadAdjacentElems[SMDSAbs_Volume].begin();
9481           eIt != quadAdjacentElems[SMDSAbs_Volume].end(); ++eIt )
9482     {
9483       helper.AddTLinks( static_cast< const SMDS_MeshVolume*> (*eIt) );
9484     }
9485
9486   // make quadratic elements instead of linear ones
9487
9488   SMESHDS_Mesh* meshDS = GetMeshDS();
9489   SMESHDS_SubMesh* smDS = 0;
9490   for ( eIt = theElements.begin(); eIt != theElements.end(); ++eIt )
9491   {
9492     const SMDS_MeshElement* elem = *eIt;
9493     if( elem->IsQuadratic() || elem->NbNodes() < 2 || elem->IsPoly() )
9494       continue;
9495
9496     int id = elem->GetID();
9497     SMDSAbs_ElementType type = elem->GetType();
9498     vector<const SMDS_MeshNode *> nodes ( elem->begin_nodes(), elem->end_nodes());
9499
9500     if ( !smDS || !smDS->Contains( elem ))
9501       smDS = meshDS->MeshElements( elem->getshapeId() );
9502     meshDS->RemoveFreeElement(elem, smDS, /*fromGroups=*/false);
9503
9504     SMDS_MeshElement * newElem = 0;
9505     switch( nodes.size() )
9506     {
9507     case 4: // cases for most multiple element types go first (for optimization)
9508       if ( type == SMDSAbs_Volume )
9509         newElem = helper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3], id, theForce3d);
9510       else
9511         newElem = helper.AddFace  (nodes[0], nodes[1], nodes[2], nodes[3], id, theForce3d);
9512       break;
9513     case 8:
9514       newElem = helper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3],
9515                                  nodes[4], nodes[5], nodes[6], nodes[7], id, theForce3d);
9516       break;
9517     case 3:
9518       newElem = helper.AddFace  (nodes[0], nodes[1], nodes[2], id, theForce3d);
9519       break;
9520     case 2:
9521       newElem = helper.AddEdge(nodes[0], nodes[1], id, theForce3d);
9522       break;
9523     case 5:
9524       newElem = helper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3],
9525                                  nodes[4], id, theForce3d);
9526       break;
9527     case 6:
9528       newElem = helper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3],
9529                                  nodes[4], nodes[5], id, theForce3d);
9530       break;
9531     default:;
9532     }
9533     ReplaceElemInGroups( elem, newElem, meshDS);
9534     if( newElem && smDS )
9535       smDS->AddElement( newElem );
9536   }
9537
9538   if ( !theForce3d  && !getenv("NO_FixQuadraticElements"))
9539   { // setenv NO_FixQuadraticElements to know if FixQuadraticElements() is guilty of bad conversion
9540     helper.SetSubShape(0); // apply FixQuadraticElements() to the whole mesh
9541     helper.FixQuadraticElements();
9542   }
9543 }
9544
9545 //=======================================================================
9546 /*!
9547  * \brief Convert quadratic elements to linear ones and remove quadratic nodes
9548  * \return int - nb of checked elements
9549  */
9550 //=======================================================================
9551
9552 int SMESH_MeshEditor::removeQuadElem(SMESHDS_SubMesh *    theSm,
9553                                      SMDS_ElemIteratorPtr theItr,
9554                                      const int            theShapeID)
9555 {
9556   int nbElem = 0;
9557   SMESHDS_Mesh* meshDS = GetMeshDS();
9558
9559   while( theItr->more() )
9560   {
9561     const SMDS_MeshElement* elem = theItr->next();
9562     nbElem++;
9563     if( elem && elem->IsQuadratic())
9564     {
9565       int id                    = elem->GetID();
9566       int nbCornerNodes         = elem->NbCornerNodes();
9567       SMDSAbs_ElementType aType = elem->GetType();
9568
9569       vector<const SMDS_MeshNode *> nodes( elem->begin_nodes(), elem->end_nodes() );
9570
9571       //remove a quadratic element
9572       if ( !theSm || !theSm->Contains( elem ))
9573         theSm = meshDS->MeshElements( elem->getshapeId() );
9574       meshDS->RemoveFreeElement( elem, theSm, /*fromGroups=*/false );
9575
9576       // remove medium nodes
9577       for ( unsigned i = nbCornerNodes; i < nodes.size(); ++i )
9578         if ( nodes[i]->NbInverseElements() == 0 )
9579           meshDS->RemoveFreeNode( nodes[i], theSm );
9580
9581       // add a linear element
9582       nodes.resize( nbCornerNodes );
9583       SMDS_MeshElement * newElem = AddElement( nodes, aType, false, id );
9584       ReplaceElemInGroups(elem, newElem, meshDS);
9585       if( theSm && newElem )
9586         theSm->AddElement( newElem );
9587     }
9588   }
9589   return nbElem;
9590 }
9591
9592 //=======================================================================
9593 //function : ConvertFromQuadratic
9594 //purpose  :
9595 //=======================================================================
9596
9597 bool SMESH_MeshEditor::ConvertFromQuadratic()
9598 {
9599   int nbCheckedElems = 0;
9600   if ( myMesh->HasShapeToMesh() )
9601   {
9602     if ( SMESH_subMesh *aSubMesh = myMesh->GetSubMeshContaining(myMesh->GetShapeToMesh()))
9603     {
9604       SMESH_subMeshIteratorPtr smIt = aSubMesh->getDependsOnIterator(true,false);
9605       while ( smIt->more() ) {
9606         SMESH_subMesh* sm = smIt->next();
9607         if ( SMESHDS_SubMesh *smDS = sm->GetSubMeshDS() )
9608           nbCheckedElems += removeQuadElem( smDS, smDS->GetElements(), sm->GetId() );
9609       }
9610     }
9611   }
9612
9613   int totalNbElems =
9614     GetMeshDS()->NbEdges() + GetMeshDS()->NbFaces() + GetMeshDS()->NbVolumes();
9615   if ( nbCheckedElems < totalNbElems ) // not all elements are in submeshes
9616   {
9617     SMESHDS_SubMesh *aSM = 0;
9618     removeQuadElem( aSM, GetMeshDS()->elementsIterator(), 0 );
9619   }
9620
9621   return true;
9622 }
9623
9624 namespace
9625 {
9626   //================================================================================
9627   /*!
9628    * \brief Return true if all medium nodes of the element are in the node set
9629    */
9630   //================================================================================
9631
9632   bool allMediumNodesIn(const SMDS_MeshElement* elem, TIDSortedNodeSet& nodeSet )
9633   {
9634     for ( int i = elem->NbCornerNodes(); i < elem->NbNodes(); ++i )
9635       if ( !nodeSet.count( elem->GetNode(i) ))
9636         return false;
9637     return true;
9638   }
9639 }
9640
9641 //================================================================================
9642 /*!
9643  * \brief Makes given elements linear
9644  */
9645 //================================================================================
9646
9647 void SMESH_MeshEditor::ConvertFromQuadratic(TIDSortedElemSet& theElements)
9648 {
9649   if ( theElements.empty() ) return;
9650
9651   // collect IDs of medium nodes of theElements; some of these nodes will be removed
9652   set<int> mediumNodeIDs;
9653   TIDSortedElemSet::iterator eIt = theElements.begin();
9654   for ( ; eIt != theElements.end(); ++eIt )
9655   {
9656     const SMDS_MeshElement* e = *eIt;
9657     for ( int i = e->NbCornerNodes(); i < e->NbNodes(); ++i )
9658       mediumNodeIDs.insert( e->GetNode(i)->GetID() );
9659   }
9660
9661   // replace given elements by linear ones
9662   typedef SMDS_SetIterator<const SMDS_MeshElement*, TIDSortedElemSet::iterator> TSetIterator;
9663   SMDS_ElemIteratorPtr elemIt( new TSetIterator( theElements.begin(), theElements.end() ));
9664   removeQuadElem( /*theSm=*/0, elemIt, /*theShapeID=*/0 );
9665
9666   // we need to convert remaining elements whose all medium nodes are in mediumNodeIDs
9667   // except those elements sharing medium nodes of quadratic element whose medium nodes
9668   // are not all in mediumNodeIDs
9669
9670   // get remaining medium nodes
9671   TIDSortedNodeSet mediumNodes;
9672   set<int>::iterator nIdsIt = mediumNodeIDs.begin();
9673   for ( ; nIdsIt != mediumNodeIDs.end(); ++nIdsIt )
9674     if ( const SMDS_MeshNode* n = GetMeshDS()->FindNode( *nIdsIt ))
9675       mediumNodes.insert( mediumNodes.end(), n );
9676
9677   // find more quadratic elements to convert
9678   TIDSortedElemSet moreElemsToConvert;
9679   TIDSortedNodeSet::iterator nIt = mediumNodes.begin();
9680   for ( ; nIt != mediumNodes.end(); ++nIt )
9681   {
9682     SMDS_ElemIteratorPtr invIt = (*nIt)->GetInverseElementIterator();
9683     while ( invIt->more() )
9684     {
9685       const SMDS_MeshElement* e = invIt->next();
9686       if ( e->IsQuadratic() && allMediumNodesIn( e, mediumNodes ))
9687       {
9688         // find a more complex element including e and
9689         // whose medium nodes are not in mediumNodes
9690         bool complexFound = false;
9691         for ( int type = e->GetType() + 1; type < SMDSAbs_0DElement; ++type )
9692         {
9693           SMDS_ElemIteratorPtr invIt2 =
9694             (*nIt)->GetInverseElementIterator( SMDSAbs_ElementType( type ));
9695           while ( invIt2->more() )
9696           {
9697             const SMDS_MeshElement* eComplex = invIt2->next();
9698             if ( eComplex->IsQuadratic() && !allMediumNodesIn( eComplex, mediumNodes))
9699             {
9700               int nbCommonNodes = SMESH_Algo::GetCommonNodes( e, eComplex ).size();
9701               if ( nbCommonNodes == e->NbNodes())
9702               {
9703                 complexFound = true;
9704                 type = SMDSAbs_NbElementTypes; // to quit from the outer loop
9705                 break;
9706               }
9707             }
9708           }
9709         }
9710         if ( !complexFound )
9711           moreElemsToConvert.insert( e );
9712       }
9713     }
9714   }
9715   elemIt = SMDS_ElemIteratorPtr
9716     (new TSetIterator( moreElemsToConvert.begin(), moreElemsToConvert.end() ));
9717   removeQuadElem( /*theSm=*/0, elemIt, /*theShapeID=*/0 );
9718 }
9719
9720 //=======================================================================
9721 //function : SewSideElements
9722 //purpose  :
9723 //=======================================================================
9724
9725 SMESH_MeshEditor::Sew_Error
9726 SMESH_MeshEditor::SewSideElements (TIDSortedElemSet&    theSide1,
9727                                    TIDSortedElemSet&    theSide2,
9728                                    const SMDS_MeshNode* theFirstNode1,
9729                                    const SMDS_MeshNode* theFirstNode2,
9730                                    const SMDS_MeshNode* theSecondNode1,
9731                                    const SMDS_MeshNode* theSecondNode2)
9732 {
9733   myLastCreatedElems.Clear();
9734   myLastCreatedNodes.Clear();
9735
9736   MESSAGE ("::::SewSideElements()");
9737   if ( theSide1.size() != theSide2.size() )
9738     return SEW_DIFF_NB_OF_ELEMENTS;
9739
9740   Sew_Error aResult = SEW_OK;
9741   // Algo:
9742   // 1. Build set of faces representing each side
9743   // 2. Find which nodes of the side 1 to merge with ones on the side 2
9744   // 3. Replace nodes in elements of the side 1 and remove replaced nodes
9745
9746   // =======================================================================
9747   // 1. Build set of faces representing each side:
9748   // =======================================================================
9749   // a. build set of nodes belonging to faces
9750   // b. complete set of faces: find missing faces whose nodes are in set of nodes
9751   // c. create temporary faces representing side of volumes if correspondent
9752   //    face does not exist
9753
9754   SMESHDS_Mesh* aMesh = GetMeshDS();
9755   // TODO algoritm not OK with vtkUnstructuredGrid: 2 meshes can't share nodes
9756   //SMDS_Mesh aTmpFacesMesh; // try to use the same mesh
9757   set<const SMDS_MeshElement*> faceSet1, faceSet2;
9758   set<const SMDS_MeshElement*> volSet1,  volSet2;
9759   set<const SMDS_MeshNode*>    nodeSet1, nodeSet2;
9760   set<const SMDS_MeshElement*> * faceSetPtr[] = { &faceSet1, &faceSet2 };
9761   set<const SMDS_MeshElement*>  * volSetPtr[] = { &volSet1,  &volSet2  };
9762   set<const SMDS_MeshNode*>    * nodeSetPtr[] = { &nodeSet1, &nodeSet2 };
9763   TIDSortedElemSet * elemSetPtr[] = { &theSide1, &theSide2 };
9764   int iSide, iFace, iNode;
9765
9766   list<const SMDS_MeshElement* > tempFaceList;
9767   for ( iSide = 0; iSide < 2; iSide++ ) {
9768     set<const SMDS_MeshNode*>    * nodeSet = nodeSetPtr[ iSide ];
9769     TIDSortedElemSet * elemSet = elemSetPtr[ iSide ];
9770     set<const SMDS_MeshElement*> * faceSet = faceSetPtr[ iSide ];
9771     set<const SMDS_MeshElement*> * volSet  = volSetPtr [ iSide ];
9772     set<const SMDS_MeshElement*>::iterator vIt;
9773     TIDSortedElemSet::iterator eIt;
9774     set<const SMDS_MeshNode*>::iterator    nIt;
9775
9776     // check that given nodes belong to given elements
9777     const SMDS_MeshNode* n1 = ( iSide == 0 ) ? theFirstNode1 : theFirstNode2;
9778     const SMDS_MeshNode* n2 = ( iSide == 0 ) ? theSecondNode1 : theSecondNode2;
9779     int firstIndex = -1, secondIndex = -1;
9780     for (eIt = elemSet->begin(); eIt != elemSet->end(); eIt++ ) {
9781       const SMDS_MeshElement* elem = *eIt;
9782       if ( firstIndex  < 0 ) firstIndex  = elem->GetNodeIndex( n1 );
9783       if ( secondIndex < 0 ) secondIndex = elem->GetNodeIndex( n2 );
9784       if ( firstIndex > -1 && secondIndex > -1 ) break;
9785     }
9786     if ( firstIndex < 0 || secondIndex < 0 ) {
9787       // we can simply return until temporary faces created
9788       return (iSide == 0 ) ? SEW_BAD_SIDE1_NODES : SEW_BAD_SIDE2_NODES;
9789     }
9790
9791     // -----------------------------------------------------------
9792     // 1a. Collect nodes of existing faces
9793     //     and build set of face nodes in order to detect missing
9794     //     faces corresponding to sides of volumes
9795     // -----------------------------------------------------------
9796
9797     set< set <const SMDS_MeshNode*> > setOfFaceNodeSet;
9798
9799     // loop on the given element of a side
9800     for (eIt = elemSet->begin(); eIt != elemSet->end(); eIt++ ) {
9801       //const SMDS_MeshElement* elem = *eIt;
9802       const SMDS_MeshElement* elem = *eIt;
9803       if ( elem->GetType() == SMDSAbs_Face ) {
9804         faceSet->insert( elem );
9805         set <const SMDS_MeshNode*> faceNodeSet;
9806         SMDS_ElemIteratorPtr nodeIt = elem->nodesIterator();
9807         while ( nodeIt->more() ) {
9808           const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
9809           nodeSet->insert( n );
9810           faceNodeSet.insert( n );
9811         }
9812         setOfFaceNodeSet.insert( faceNodeSet );
9813       }
9814       else if ( elem->GetType() == SMDSAbs_Volume )
9815         volSet->insert( elem );
9816     }
9817     // ------------------------------------------------------------------------------
9818     // 1b. Complete set of faces: find missing faces whose nodes are in set of nodes
9819     // ------------------------------------------------------------------------------
9820
9821     for ( nIt = nodeSet->begin(); nIt != nodeSet->end(); nIt++ ) { // loop on nodes of iSide
9822       SMDS_ElemIteratorPtr fIt = (*nIt)->GetInverseElementIterator(SMDSAbs_Face);
9823       while ( fIt->more() ) { // loop on faces sharing a node
9824         const SMDS_MeshElement* f = fIt->next();
9825         if ( faceSet->find( f ) == faceSet->end() ) {
9826           // check if all nodes are in nodeSet and
9827           // complete setOfFaceNodeSet if they are
9828           set <const SMDS_MeshNode*> faceNodeSet;
9829           SMDS_ElemIteratorPtr nodeIt = f->nodesIterator();
9830           bool allInSet = true;
9831           while ( nodeIt->more() && allInSet ) { // loop on nodes of a face
9832             const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
9833             if ( nodeSet->find( n ) == nodeSet->end() )
9834               allInSet = false;
9835             else
9836               faceNodeSet.insert( n );
9837           }
9838           if ( allInSet ) {
9839             faceSet->insert( f );
9840             setOfFaceNodeSet.insert( faceNodeSet );
9841           }
9842         }
9843       }
9844     }
9845
9846     // -------------------------------------------------------------------------
9847     // 1c. Create temporary faces representing sides of volumes if correspondent
9848     //     face does not exist
9849     // -------------------------------------------------------------------------
9850
9851     if ( !volSet->empty() ) {
9852       //int nodeSetSize = nodeSet->size();
9853
9854       // loop on given volumes
9855       for ( vIt = volSet->begin(); vIt != volSet->end(); vIt++ ) {
9856         SMDS_VolumeTool vol (*vIt);
9857         // loop on volume faces: find free faces
9858         // --------------------------------------
9859         list<const SMDS_MeshElement* > freeFaceList;
9860         for ( iFace = 0; iFace < vol.NbFaces(); iFace++ ) {
9861           if ( !vol.IsFreeFace( iFace ))
9862             continue;
9863           // check if there is already a face with same nodes in a face set
9864           const SMDS_MeshElement* aFreeFace = 0;
9865           const SMDS_MeshNode** fNodes = vol.GetFaceNodes( iFace );
9866           int nbNodes = vol.NbFaceNodes( iFace );
9867           set <const SMDS_MeshNode*> faceNodeSet;
9868           vol.GetFaceNodes( iFace, faceNodeSet );
9869           bool isNewFace = setOfFaceNodeSet.insert( faceNodeSet ).second;
9870           if ( isNewFace ) {
9871             // no such a face is given but it still can exist, check it
9872             if ( nbNodes == 3 ) {
9873               aFreeFace = aMesh->FindFace( fNodes[0],fNodes[1],fNodes[2] );
9874             }
9875             else if ( nbNodes == 4 ) {
9876               aFreeFace = aMesh->FindFace( fNodes[0],fNodes[1],fNodes[2],fNodes[3] );
9877             }
9878             else {
9879               vector<const SMDS_MeshNode *> poly_nodes ( fNodes, & fNodes[nbNodes]);
9880               aFreeFace = aMesh->FindFace(poly_nodes);
9881             }
9882           }
9883           if ( !aFreeFace ) {
9884             // create a temporary face
9885             if ( nbNodes == 3 ) {
9886               //aFreeFace = aTmpFacesMesh.AddFace( fNodes[0],fNodes[1],fNodes[2] );
9887               aFreeFace = aMesh->AddFace( fNodes[0],fNodes[1],fNodes[2] );
9888             }
9889             else if ( nbNodes == 4 ) {
9890               //aFreeFace = aTmpFacesMesh.AddFace( fNodes[0],fNodes[1],fNodes[2],fNodes[3] );
9891               aFreeFace = aMesh->AddFace( fNodes[0],fNodes[1],fNodes[2],fNodes[3] );
9892             }
9893             else {
9894               vector<const SMDS_MeshNode *> poly_nodes ( fNodes, & fNodes[nbNodes]);
9895               //aFreeFace = aTmpFacesMesh.AddPolygonalFace(poly_nodes);
9896               aFreeFace = aMesh->AddPolygonalFace(poly_nodes);
9897             }
9898           }
9899           if ( aFreeFace ) {
9900             freeFaceList.push_back( aFreeFace );
9901             tempFaceList.push_back( aFreeFace );
9902           }
9903
9904         } // loop on faces of a volume
9905
9906         // choose one of several free faces
9907         // --------------------------------------
9908         if ( freeFaceList.size() > 1 ) {
9909           // choose a face having max nb of nodes shared by other elems of a side
9910           int maxNbNodes = -1/*, nbExcludedFaces = 0*/;
9911           list<const SMDS_MeshElement* >::iterator fIt = freeFaceList.begin();
9912           while ( fIt != freeFaceList.end() ) { // loop on free faces
9913             int nbSharedNodes = 0;
9914             SMDS_ElemIteratorPtr nodeIt = (*fIt)->nodesIterator();
9915             while ( nodeIt->more() ) { // loop on free face nodes
9916               const SMDS_MeshNode* n =
9917                 static_cast<const SMDS_MeshNode*>( nodeIt->next() );
9918               SMDS_ElemIteratorPtr invElemIt = n->GetInverseElementIterator();
9919               while ( invElemIt->more() ) {
9920                 const SMDS_MeshElement* e = invElemIt->next();
9921                 if ( faceSet->find( e ) != faceSet->end() )
9922                   nbSharedNodes++;
9923                 if ( elemSet->find( e ) != elemSet->end() )
9924                   nbSharedNodes++;
9925               }
9926             }
9927             if ( nbSharedNodes >= maxNbNodes ) {
9928               maxNbNodes = nbSharedNodes;
9929               fIt++;
9930             }
9931             else
9932               freeFaceList.erase( fIt++ ); // here fIt++ occurs before erase
9933           }
9934           if ( freeFaceList.size() > 1 )
9935           {
9936             // could not choose one face, use another way
9937             // choose a face most close to the bary center of the opposite side
9938             gp_XYZ aBC( 0., 0., 0. );
9939             set <const SMDS_MeshNode*> addedNodes;
9940             TIDSortedElemSet * elemSet2 = elemSetPtr[ 1 - iSide ];
9941             eIt = elemSet2->begin();
9942             for ( eIt = elemSet2->begin(); eIt != elemSet2->end(); eIt++ ) {
9943               SMDS_ElemIteratorPtr nodeIt = (*eIt)->nodesIterator();
9944               while ( nodeIt->more() ) { // loop on free face nodes
9945                 const SMDS_MeshNode* n =
9946                   static_cast<const SMDS_MeshNode*>( nodeIt->next() );
9947                 if ( addedNodes.insert( n ).second )
9948                   aBC += gp_XYZ( n->X(),n->Y(),n->Z() );
9949               }
9950             }
9951             aBC /= addedNodes.size();
9952             double minDist = DBL_MAX;
9953             fIt = freeFaceList.begin();
9954             while ( fIt != freeFaceList.end() ) { // loop on free faces
9955               double dist = 0;
9956               SMDS_ElemIteratorPtr nodeIt = (*fIt)->nodesIterator();
9957               while ( nodeIt->more() ) { // loop on free face nodes
9958                 const SMDS_MeshNode* n =
9959                   static_cast<const SMDS_MeshNode*>( nodeIt->next() );
9960                 gp_XYZ p( n->X(),n->Y(),n->Z() );
9961                 dist += ( aBC - p ).SquareModulus();
9962               }
9963               if ( dist < minDist ) {
9964                 minDist = dist;
9965                 freeFaceList.erase( freeFaceList.begin(), fIt++ );
9966               }
9967               else
9968                 fIt = freeFaceList.erase( fIt++ );
9969             }
9970           }
9971         } // choose one of several free faces of a volume
9972
9973         if ( freeFaceList.size() == 1 ) {
9974           const SMDS_MeshElement* aFreeFace = freeFaceList.front();
9975           faceSet->insert( aFreeFace );
9976           // complete a node set with nodes of a found free face
9977           //           for ( iNode = 0; iNode < ; iNode++ )
9978           //             nodeSet->insert( fNodes[ iNode ] );
9979         }
9980
9981       } // loop on volumes of a side
9982
9983       //       // complete a set of faces if new nodes in a nodeSet appeared
9984       //       // ----------------------------------------------------------
9985       //       if ( nodeSetSize != nodeSet->size() ) {
9986       //         for ( ; nIt != nodeSet->end(); nIt++ ) { // loop on nodes of iSide
9987       //           SMDS_ElemIteratorPtr fIt = (*nIt)->GetInverseElementIterator(SMDSAbs_Face);
9988       //           while ( fIt->more() ) { // loop on faces sharing a node
9989       //             const SMDS_MeshElement* f = fIt->next();
9990       //             if ( faceSet->find( f ) == faceSet->end() ) {
9991       //               // check if all nodes are in nodeSet and
9992       //               // complete setOfFaceNodeSet if they are
9993       //               set <const SMDS_MeshNode*> faceNodeSet;
9994       //               SMDS_ElemIteratorPtr nodeIt = f->nodesIterator();
9995       //               bool allInSet = true;
9996       //               while ( nodeIt->more() && allInSet ) { // loop on nodes of a face
9997       //                 const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
9998       //                 if ( nodeSet->find( n ) == nodeSet->end() )
9999       //                   allInSet = false;
10000       //                 else
10001       //                   faceNodeSet.insert( n );
10002       //               }
10003       //               if ( allInSet ) {
10004       //                 faceSet->insert( f );
10005       //                 setOfFaceNodeSet.insert( faceNodeSet );
10006       //               }
10007       //             }
10008       //           }
10009       //         }
10010       //       }
10011     } // Create temporary faces, if there are volumes given
10012   } // loop on sides
10013
10014   if ( faceSet1.size() != faceSet2.size() ) {
10015     // delete temporary faces: they are in reverseElements of actual nodes
10016 //    SMDS_FaceIteratorPtr tmpFaceIt = aTmpFacesMesh.facesIterator();
10017 //    while ( tmpFaceIt->more() )
10018 //      aTmpFacesMesh.RemoveElement( tmpFaceIt->next() );
10019 //    list<const SMDS_MeshElement* >::iterator tmpFaceIt = tempFaceList.begin();
10020 //    for (; tmpFaceIt !=tempFaceList.end(); ++tmpFaceIt)
10021 //      aMesh->RemoveElement(*tmpFaceIt);
10022     MESSAGE("Diff nb of faces");
10023     return SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
10024   }
10025
10026   // ============================================================
10027   // 2. Find nodes to merge:
10028   //              bind a node to remove to a node to put instead
10029   // ============================================================
10030
10031   TNodeNodeMap nReplaceMap; // bind a node to remove to a node to put instead
10032   if ( theFirstNode1 != theFirstNode2 )
10033     nReplaceMap.insert( TNodeNodeMap::value_type( theFirstNode1, theFirstNode2 ));
10034   if ( theSecondNode1 != theSecondNode2 )
10035     nReplaceMap.insert( TNodeNodeMap::value_type( theSecondNode1, theSecondNode2 ));
10036
10037   LinkID_Gen aLinkID_Gen( GetMeshDS() );
10038   set< long > linkIdSet; // links to process
10039   linkIdSet.insert( aLinkID_Gen.GetLinkID( theFirstNode1, theSecondNode1 ));
10040
10041   typedef pair< const SMDS_MeshNode*, const SMDS_MeshNode* > NLink;
10042   list< NLink > linkList[2];
10043   linkList[0].push_back( NLink( theFirstNode1, theSecondNode1 ));
10044   linkList[1].push_back( NLink( theFirstNode2, theSecondNode2 ));
10045   // loop on links in linkList; find faces by links and append links
10046   // of the found faces to linkList
10047   list< NLink >::iterator linkIt[] = { linkList[0].begin(), linkList[1].begin() } ;
10048   for ( ; linkIt[0] != linkList[0].end(); linkIt[0]++, linkIt[1]++ ) {
10049     NLink link[] = { *linkIt[0], *linkIt[1] };
10050     long linkID = aLinkID_Gen.GetLinkID( link[0].first, link[0].second );
10051     if ( linkIdSet.find( linkID ) == linkIdSet.end() )
10052       continue;
10053
10054     // by links, find faces in the face sets,
10055     // and find indices of link nodes in the found faces;
10056     // in a face set, there is only one or no face sharing a link
10057     // ---------------------------------------------------------------
10058
10059     const SMDS_MeshElement* face[] = { 0, 0 };
10060     //const SMDS_MeshNode* faceNodes[ 2 ][ 5 ];
10061     vector<const SMDS_MeshNode*> fnodes1(9);
10062     vector<const SMDS_MeshNode*> fnodes2(9);
10063     //const SMDS_MeshNode* notLinkNodes[ 2 ][ 2 ] = {{ 0, 0 },{ 0, 0 }} ;
10064     vector<const SMDS_MeshNode*> notLinkNodes1(6);
10065     vector<const SMDS_MeshNode*> notLinkNodes2(6);
10066     int iLinkNode[2][2];
10067     for ( iSide = 0; iSide < 2; iSide++ ) { // loop on 2 sides
10068       const SMDS_MeshNode* n1 = link[iSide].first;
10069       const SMDS_MeshNode* n2 = link[iSide].second;
10070       set<const SMDS_MeshElement*> * faceSet = faceSetPtr[ iSide ];
10071       set< const SMDS_MeshElement* > fMap;
10072       for ( int i = 0; i < 2; i++ ) { // loop on 2 nodes of a link
10073         const SMDS_MeshNode* n = i ? n1 : n2; // a node of a link
10074         SMDS_ElemIteratorPtr fIt = n->GetInverseElementIterator(SMDSAbs_Face);
10075         while ( fIt->more() ) { // loop on faces sharing a node
10076           const SMDS_MeshElement* f = fIt->next();
10077           if (faceSet->find( f ) != faceSet->end() && // f is in face set
10078               ! fMap.insert( f ).second ) // f encounters twice
10079           {
10080             if ( face[ iSide ] ) {
10081               MESSAGE( "2 faces per link " );
10082               aResult = iSide ? SEW_BAD_SIDE2_NODES : SEW_BAD_SIDE1_NODES;
10083               break;
10084             }
10085             face[ iSide ] = f;
10086             faceSet->erase( f );
10087             // get face nodes and find ones of a link
10088             iNode = 0;
10089             int nbl = -1;
10090             if(f->IsPoly()) {
10091               if(iSide==0) {
10092                 fnodes1.resize(f->NbNodes()+1);
10093                 notLinkNodes1.resize(f->NbNodes()-2);
10094               }
10095               else {
10096                 fnodes2.resize(f->NbNodes()+1);
10097                 notLinkNodes2.resize(f->NbNodes()-2);
10098               }
10099             }
10100             if(!f->IsQuadratic()) {
10101               SMDS_ElemIteratorPtr nIt = f->nodesIterator();
10102               while ( nIt->more() ) {
10103                 const SMDS_MeshNode* n =
10104                   static_cast<const SMDS_MeshNode*>( nIt->next() );
10105                 if ( n == n1 ) {
10106                   iLinkNode[ iSide ][ 0 ] = iNode;
10107                 }
10108                 else if ( n == n2 ) {
10109                   iLinkNode[ iSide ][ 1 ] = iNode;
10110                 }
10111                 //else if ( notLinkNodes[ iSide ][ 0 ] )
10112                 //  notLinkNodes[ iSide ][ 1 ] = n;
10113                 //else
10114                 //  notLinkNodes[ iSide ][ 0 ] = n;
10115                 else {
10116                   nbl++;
10117                   if(iSide==0)
10118                     notLinkNodes1[nbl] = n;
10119                   //notLinkNodes1.push_back(n);
10120                   else
10121                     notLinkNodes2[nbl] = n;
10122                   //notLinkNodes2.push_back(n);
10123                 }
10124                 //faceNodes[ iSide ][ iNode++ ] = n;
10125                 if(iSide==0) {
10126                   fnodes1[iNode++] = n;
10127                 }
10128                 else {
10129                   fnodes2[iNode++] = n;
10130                 }
10131               }
10132             }
10133             else { // f->IsQuadratic()
10134               const SMDS_VtkFace* F =
10135                 dynamic_cast<const SMDS_VtkFace*>(f);
10136               if (!F) throw SALOME_Exception(LOCALIZED("not an SMDS_VtkFace"));
10137               // use special nodes iterator
10138               SMDS_ElemIteratorPtr anIter = F->interlacedNodesElemIterator();
10139               while ( anIter->more() ) {
10140                 const SMDS_MeshNode* n =
10141                   static_cast<const SMDS_MeshNode*>( anIter->next() );
10142                 if ( n == n1 ) {
10143                   iLinkNode[ iSide ][ 0 ] = iNode;
10144                 }
10145                 else if ( n == n2 ) {
10146                   iLinkNode[ iSide ][ 1 ] = iNode;
10147                 }
10148                 else {
10149                   nbl++;
10150                   if(iSide==0) {
10151                     notLinkNodes1[nbl] = n;
10152                   }
10153                   else {
10154                     notLinkNodes2[nbl] = n;
10155                   }
10156                 }
10157                 if(iSide==0) {
10158                   fnodes1[iNode++] = n;
10159                 }
10160                 else {
10161                   fnodes2[iNode++] = n;
10162                 }
10163               }
10164             }
10165             //faceNodes[ iSide ][ iNode ] = faceNodes[ iSide ][ 0 ];
10166             if(iSide==0) {
10167               fnodes1[iNode] = fnodes1[0];
10168             }
10169             else {
10170               fnodes2[iNode] = fnodes1[0];
10171             }
10172           }
10173         }
10174       }
10175     }
10176
10177     // check similarity of elements of the sides
10178     if (aResult == SEW_OK && ( face[0] && !face[1] ) || ( !face[0] && face[1] )) {
10179       MESSAGE("Correspondent face not found on side " << ( face[0] ? 1 : 0 ));
10180       if ( nReplaceMap.size() == 2 ) { // faces on input nodes not found
10181         aResult = ( face[0] ? SEW_BAD_SIDE2_NODES : SEW_BAD_SIDE1_NODES );
10182       }
10183       else {
10184         aResult = SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
10185       }
10186       break; // do not return because it s necessary to remove tmp faces
10187     }
10188
10189     // set nodes to merge
10190     // -------------------
10191
10192     if ( face[0] && face[1] )  {
10193       int nbNodes = face[0]->NbNodes();
10194       if ( nbNodes != face[1]->NbNodes() ) {
10195         MESSAGE("Diff nb of face nodes");
10196         aResult = SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
10197         break; // do not return because it s necessary to remove tmp faces
10198       }
10199       bool reverse[] = { false, false }; // order of notLinkNodes of quadrangle
10200       if ( nbNodes == 3 ) {
10201         //nReplaceMap.insert( TNodeNodeMap::value_type
10202         //                   ( notLinkNodes[0][0], notLinkNodes[1][0] ));
10203         nReplaceMap.insert( TNodeNodeMap::value_type
10204                             ( notLinkNodes1[0], notLinkNodes2[0] ));
10205       }
10206       else {
10207         for ( iSide = 0; iSide < 2; iSide++ ) { // loop on 2 sides
10208           // analyse link orientation in faces
10209           int i1 = iLinkNode[ iSide ][ 0 ];
10210           int i2 = iLinkNode[ iSide ][ 1 ];
10211           reverse[ iSide ] = Abs( i1 - i2 ) == 1 ? i1 > i2 : i2 > i1;
10212           // if notLinkNodes are the first and the last ones, then
10213           // their order does not correspond to the link orientation
10214           if (( i1 == 1 && i2 == 2 ) ||
10215               ( i1 == 2 && i2 == 1 ))
10216             reverse[ iSide ] = !reverse[ iSide ];
10217         }
10218         if ( reverse[0] == reverse[1] ) {
10219           //nReplaceMap.insert( TNodeNodeMap::value_type
10220           //                   ( notLinkNodes[0][0], notLinkNodes[1][0] ));
10221           //nReplaceMap.insert( TNodeNodeMap::value_type
10222           //                   ( notLinkNodes[0][1], notLinkNodes[1][1] ));
10223           for(int nn=0; nn<nbNodes-2; nn++) {
10224             nReplaceMap.insert( TNodeNodeMap::value_type
10225                                 ( notLinkNodes1[nn], notLinkNodes2[nn] ));
10226           }
10227         }
10228         else {
10229           //nReplaceMap.insert( TNodeNodeMap::value_type
10230           //                   ( notLinkNodes[0][0], notLinkNodes[1][1] ));
10231           //nReplaceMap.insert( TNodeNodeMap::value_type
10232           //                   ( notLinkNodes[0][1], notLinkNodes[1][0] ));
10233           for(int nn=0; nn<nbNodes-2; nn++) {
10234             nReplaceMap.insert( TNodeNodeMap::value_type
10235                                 ( notLinkNodes1[nn], notLinkNodes2[nbNodes-3-nn] ));
10236           }
10237         }
10238       }
10239
10240       // add other links of the faces to linkList
10241       // -----------------------------------------
10242
10243       //const SMDS_MeshNode** nodes = faceNodes[ 0 ];
10244       for ( iNode = 0; iNode < nbNodes; iNode++ )  {
10245         //linkID = aLinkID_Gen.GetLinkID( nodes[iNode], nodes[iNode+1] );
10246         linkID = aLinkID_Gen.GetLinkID( fnodes1[iNode], fnodes1[iNode+1] );
10247         pair< set<long>::iterator, bool > iter_isnew = linkIdSet.insert( linkID );
10248         if ( !iter_isnew.second ) { // already in a set: no need to process
10249           linkIdSet.erase( iter_isnew.first );
10250         }
10251         else // new in set == encountered for the first time: add
10252         {
10253           //const SMDS_MeshNode* n1 = nodes[ iNode ];
10254           //const SMDS_MeshNode* n2 = nodes[ iNode + 1];
10255           const SMDS_MeshNode* n1 = fnodes1[ iNode ];
10256           const SMDS_MeshNode* n2 = fnodes1[ iNode + 1];
10257           linkList[0].push_back ( NLink( n1, n2 ));
10258           linkList[1].push_back ( NLink( nReplaceMap[n1], nReplaceMap[n2] ));
10259         }
10260       }
10261     } // 2 faces found
10262   } // loop on link lists
10263
10264   if ( aResult == SEW_OK &&
10265        ( linkIt[0] != linkList[0].end() ||
10266          !faceSetPtr[0]->empty() || !faceSetPtr[1]->empty() )) {
10267     MESSAGE( (linkIt[0] != linkList[0].end()) <<" "<< (faceSetPtr[0]->empty()) <<
10268              " " << (faceSetPtr[1]->empty()));
10269     aResult = SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
10270   }
10271
10272   // ====================================================================
10273   // 3. Replace nodes in elements of the side 1 and remove replaced nodes
10274   // ====================================================================
10275
10276   // delete temporary faces: they are in reverseElements of actual nodes
10277 //  SMDS_FaceIteratorPtr tmpFaceIt = aTmpFacesMesh.facesIterator();
10278 //  while ( tmpFaceIt->more() )
10279 //    aTmpFacesMesh.RemoveElement( tmpFaceIt->next() );
10280 //  list<const SMDS_MeshElement* >::iterator tmpFaceIt = tempFaceList.begin();
10281 //  for (; tmpFaceIt !=tempFaceList.end(); ++tmpFaceIt)
10282 //    aMesh->RemoveElement(*tmpFaceIt);
10283
10284   if ( aResult != SEW_OK)
10285     return aResult;
10286
10287   list< int > nodeIDsToRemove/*, elemIDsToRemove*/;
10288   // loop on nodes replacement map
10289   TNodeNodeMap::iterator nReplaceMapIt = nReplaceMap.begin(), nnIt;
10290   for ( ; nReplaceMapIt != nReplaceMap.end(); nReplaceMapIt++ )
10291     if ( (*nReplaceMapIt).first != (*nReplaceMapIt).second ) {
10292       const SMDS_MeshNode* nToRemove = (*nReplaceMapIt).first;
10293       nodeIDsToRemove.push_back( nToRemove->GetID() );
10294       // loop on elements sharing nToRemove
10295       SMDS_ElemIteratorPtr invElemIt = nToRemove->GetInverseElementIterator();
10296       while ( invElemIt->more() ) {
10297         const SMDS_MeshElement* e = invElemIt->next();
10298         // get a new suite of nodes: make replacement
10299         int nbReplaced = 0, i = 0, nbNodes = e->NbNodes();
10300         vector< const SMDS_MeshNode*> nodes( nbNodes );
10301         SMDS_ElemIteratorPtr nIt = e->nodesIterator();
10302         while ( nIt->more() ) {
10303           const SMDS_MeshNode* n =
10304             static_cast<const SMDS_MeshNode*>( nIt->next() );
10305           nnIt = nReplaceMap.find( n );
10306           if ( nnIt != nReplaceMap.end() ) {
10307             nbReplaced++;
10308             n = (*nnIt).second;
10309           }
10310           nodes[ i++ ] = n;
10311         }
10312         //       if ( nbReplaced == nbNodes && e->GetType() == SMDSAbs_Face )
10313         //         elemIDsToRemove.push_back( e->GetID() );
10314         //       else
10315         if ( nbReplaced )
10316           {
10317             SMDSAbs_ElementType etyp = e->GetType();
10318             SMDS_MeshElement* newElem = this->AddElement(nodes, etyp, false);
10319             if (newElem)
10320               {
10321                 myLastCreatedElems.Append(newElem);
10322                 AddToSameGroups(newElem, e, aMesh);
10323                 int aShapeId = e->getshapeId();
10324                 if ( aShapeId )
10325                   {
10326                     aMesh->SetMeshElementOnShape( newElem, aShapeId );
10327                   }
10328               }
10329             aMesh->RemoveElement(e);
10330           }
10331       }
10332     }
10333
10334   Remove( nodeIDsToRemove, true );
10335
10336   return aResult;
10337 }
10338
10339 //================================================================================
10340 /*!
10341  * \brief Find corresponding nodes in two sets of faces
10342  * \param theSide1 - first face set
10343  * \param theSide2 - second first face
10344  * \param theFirstNode1 - a boundary node of set 1
10345  * \param theFirstNode2 - a node of set 2 corresponding to theFirstNode1
10346  * \param theSecondNode1 - a boundary node of set 1 linked with theFirstNode1
10347  * \param theSecondNode2 - a node of set 2 corresponding to theSecondNode1
10348  * \param nReplaceMap - output map of corresponding nodes
10349  * \return bool  - is a success or not
10350  */
10351 //================================================================================
10352
10353 #ifdef _DEBUG_
10354 //#define DEBUG_MATCHING_NODES
10355 #endif
10356
10357 SMESH_MeshEditor::Sew_Error
10358 SMESH_MeshEditor::FindMatchingNodes(set<const SMDS_MeshElement*>& theSide1,
10359                                     set<const SMDS_MeshElement*>& theSide2,
10360                                     const SMDS_MeshNode*          theFirstNode1,
10361                                     const SMDS_MeshNode*          theFirstNode2,
10362                                     const SMDS_MeshNode*          theSecondNode1,
10363                                     const SMDS_MeshNode*          theSecondNode2,
10364                                     TNodeNodeMap &                nReplaceMap)
10365 {
10366   set<const SMDS_MeshElement*> * faceSetPtr[] = { &theSide1, &theSide2 };
10367
10368   nReplaceMap.clear();
10369   if ( theFirstNode1 != theFirstNode2 )
10370     nReplaceMap.insert( make_pair( theFirstNode1, theFirstNode2 ));
10371   if ( theSecondNode1 != theSecondNode2 )
10372     nReplaceMap.insert( make_pair( theSecondNode1, theSecondNode2 ));
10373
10374   set< SMESH_TLink > linkSet; // set of nodes where order of nodes is ignored
10375   linkSet.insert( SMESH_TLink( theFirstNode1, theSecondNode1 ));
10376
10377   list< NLink > linkList[2];
10378   linkList[0].push_back( NLink( theFirstNode1, theSecondNode1 ));
10379   linkList[1].push_back( NLink( theFirstNode2, theSecondNode2 ));
10380
10381   // loop on links in linkList; find faces by links and append links
10382   // of the found faces to linkList
10383   list< NLink >::iterator linkIt[] = { linkList[0].begin(), linkList[1].begin() } ;
10384   for ( ; linkIt[0] != linkList[0].end(); linkIt[0]++, linkIt[1]++ ) {
10385     NLink link[] = { *linkIt[0], *linkIt[1] };
10386     if ( linkSet.find( link[0] ) == linkSet.end() )
10387       continue;
10388
10389     // by links, find faces in the face sets,
10390     // and find indices of link nodes in the found faces;
10391     // in a face set, there is only one or no face sharing a link
10392     // ---------------------------------------------------------------
10393
10394     const SMDS_MeshElement* face[] = { 0, 0 };
10395     list<const SMDS_MeshNode*> notLinkNodes[2];
10396     //bool reverse[] = { false, false }; // order of notLinkNodes
10397     int nbNodes[2];
10398     for ( int iSide = 0; iSide < 2; iSide++ ) // loop on 2 sides
10399     {
10400       const SMDS_MeshNode* n1 = link[iSide].first;
10401       const SMDS_MeshNode* n2 = link[iSide].second;
10402       set<const SMDS_MeshElement*> * faceSet = faceSetPtr[ iSide ];
10403       set< const SMDS_MeshElement* > facesOfNode1;
10404       for ( int iNode = 0; iNode < 2; iNode++ ) // loop on 2 nodes of a link
10405       {
10406         // during a loop of the first node, we find all faces around n1,
10407         // during a loop of the second node, we find one face sharing both n1 and n2
10408         const SMDS_MeshNode* n = iNode ? n1 : n2; // a node of a link
10409         SMDS_ElemIteratorPtr fIt = n->GetInverseElementIterator(SMDSAbs_Face);
10410         while ( fIt->more() ) { // loop on faces sharing a node
10411           const SMDS_MeshElement* f = fIt->next();
10412           if (faceSet->find( f ) != faceSet->end() && // f is in face set
10413               ! facesOfNode1.insert( f ).second ) // f encounters twice
10414           {
10415             if ( face[ iSide ] ) {
10416               MESSAGE( "2 faces per link " );
10417               return ( iSide ? SEW_BAD_SIDE2_NODES : SEW_BAD_SIDE1_NODES );
10418             }
10419             face[ iSide ] = f;
10420             faceSet->erase( f );
10421
10422             // get not link nodes
10423             int nbN = f->NbNodes();
10424             if ( f->IsQuadratic() )
10425               nbN /= 2;
10426             nbNodes[ iSide ] = nbN;
10427             list< const SMDS_MeshNode* > & nodes = notLinkNodes[ iSide ];
10428             int i1 = f->GetNodeIndex( n1 );
10429             int i2 = f->GetNodeIndex( n2 );
10430             int iEnd = nbN, iBeg = -1, iDelta = 1;
10431             bool reverse = ( Abs( i1 - i2 ) == 1 ? i1 > i2 : i2 > i1 );
10432             if ( reverse ) {
10433               std::swap( iEnd, iBeg ); iDelta = -1;
10434             }
10435             int i = i2;
10436             while ( true ) {
10437               i += iDelta;
10438               if ( i == iEnd ) i = iBeg + iDelta;
10439               if ( i == i1 ) break;
10440               nodes.push_back ( f->GetNode( i ) );
10441             }
10442           }
10443         }
10444       }
10445     }
10446     // check similarity of elements of the sides
10447     if (( face[0] && !face[1] ) || ( !face[0] && face[1] )) {
10448       MESSAGE("Correspondent face not found on side " << ( face[0] ? 1 : 0 ));
10449       if ( nReplaceMap.size() == 2 ) { // faces on input nodes not found
10450         return ( face[0] ? SEW_BAD_SIDE2_NODES : SEW_BAD_SIDE1_NODES );
10451       }
10452       else {
10453         return SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
10454       }
10455     }
10456
10457     // set nodes to merge
10458     // -------------------
10459
10460     if ( face[0] && face[1] )  {
10461       if ( nbNodes[0] != nbNodes[1] ) {
10462         MESSAGE("Diff nb of face nodes");
10463         return SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
10464       }
10465 #ifdef DEBUG_MATCHING_NODES
10466       MESSAGE ( " Link 1: " << link[0].first->GetID() <<" "<< link[0].second->GetID()
10467                 << " F 1: " << face[0] << "| Link 2: " << link[1].first->GetID() <<" "
10468                 << link[1].second->GetID() << " F 2: " << face[1] << " | Bind: " ) ;
10469 #endif
10470       int nbN = nbNodes[0];
10471       {
10472         list<const SMDS_MeshNode*>::iterator n1 = notLinkNodes[0].begin();
10473         list<const SMDS_MeshNode*>::iterator n2 = notLinkNodes[1].begin();
10474         for ( int i = 0 ; i < nbN - 2; ++i ) {
10475 #ifdef DEBUG_MATCHING_NODES
10476           MESSAGE ( (*n1)->GetID() << " to " << (*n2)->GetID() );
10477 #endif
10478           nReplaceMap.insert( make_pair( *(n1++), *(n2++) ));
10479         }
10480       }
10481
10482       // add other links of the face 1 to linkList
10483       // -----------------------------------------
10484
10485       const SMDS_MeshElement* f0 = face[0];
10486       const SMDS_MeshNode* n1 = f0->GetNode( nbN - 1 );
10487       for ( int i = 0; i < nbN; i++ )
10488       {
10489         const SMDS_MeshNode* n2 = f0->GetNode( i );
10490         pair< set< SMESH_TLink >::iterator, bool > iter_isnew =
10491           linkSet.insert( SMESH_TLink( n1, n2 ));
10492         if ( !iter_isnew.second ) { // already in a set: no need to process
10493           linkSet.erase( iter_isnew.first );
10494         }
10495         else // new in set == encountered for the first time: add
10496         {
10497 #ifdef DEBUG_MATCHING_NODES
10498           MESSAGE ( "Add link 1: " << n1->GetID() << " " << n2->GetID() << " "
10499                     << " | link 2: " << nReplaceMap[n1]->GetID() << " " << nReplaceMap[n2]->GetID() << " " );
10500 #endif
10501           linkList[0].push_back ( NLink( n1, n2 ));
10502           linkList[1].push_back ( NLink( nReplaceMap[n1], nReplaceMap[n2] ));
10503         }
10504         n1 = n2;
10505       }
10506     } // 2 faces found
10507   } // loop on link lists
10508
10509   return SEW_OK;
10510 }
10511
10512 //================================================================================
10513 /*!
10514   \brief Creates a hole in a mesh by doubling the nodes of some particular elements
10515   \param theElems - the list of elements (edges or faces) to be replicated
10516   The nodes for duplication could be found from these elements
10517   \param theNodesNot - list of nodes to NOT replicate
10518   \param theAffectedElems - the list of elements (cells and edges) to which the 
10519   replicated nodes should be associated to.
10520   \return TRUE if operation has been completed successfully, FALSE otherwise
10521 */
10522 //================================================================================
10523
10524 bool SMESH_MeshEditor::DoubleNodes( const TIDSortedElemSet& theElems,
10525                                     const TIDSortedElemSet& theNodesNot,
10526                                     const TIDSortedElemSet& theAffectedElems )
10527 {
10528   myLastCreatedElems.Clear();
10529   myLastCreatedNodes.Clear();
10530
10531   if ( theElems.size() == 0 )
10532     return false;
10533
10534   SMESHDS_Mesh* aMeshDS = GetMeshDS();
10535   if ( !aMeshDS )
10536     return false;
10537
10538   bool res = false;
10539   std::map< const SMDS_MeshNode*, const SMDS_MeshNode* > anOldNodeToNewNode;
10540   // duplicate elements and nodes
10541   res = doubleNodes( aMeshDS, theElems, theNodesNot, anOldNodeToNewNode, true );
10542   // replce nodes by duplications
10543   res = doubleNodes( aMeshDS, theAffectedElems, theNodesNot, anOldNodeToNewNode, false );
10544   return res;
10545 }
10546
10547 //================================================================================
10548 /*!
10549   \brief Creates a hole in a mesh by doubling the nodes of some particular elements
10550   \param theMeshDS - mesh instance
10551   \param theElems - the elements replicated or modified (nodes should be changed)
10552   \param theNodesNot - nodes to NOT replicate
10553   \param theNodeNodeMap - relation of old node to new created node
10554   \param theIsDoubleElem - flag os to replicate element or modify
10555   \return TRUE if operation has been completed successfully, FALSE otherwise
10556 */
10557 //================================================================================
10558
10559 bool SMESH_MeshEditor::doubleNodes( SMESHDS_Mesh*     theMeshDS,
10560                                     const TIDSortedElemSet& theElems,
10561                                     const TIDSortedElemSet& theNodesNot,
10562                                     std::map< const SMDS_MeshNode*,
10563                                     const SMDS_MeshNode* >& theNodeNodeMap,
10564                                     const bool theIsDoubleElem )
10565 {
10566   MESSAGE("doubleNodes");
10567   // iterate on through element and duplicate them (by nodes duplication)
10568   bool res = false;
10569   TIDSortedElemSet::const_iterator elemItr = theElems.begin();
10570   for ( ;  elemItr != theElems.end(); ++elemItr )
10571   {
10572     const SMDS_MeshElement* anElem = *elemItr;
10573     if (!anElem)
10574       continue;
10575
10576     bool isDuplicate = false;
10577     // duplicate nodes to duplicate element
10578     std::vector<const SMDS_MeshNode*> newNodes( anElem->NbNodes() );
10579     SMDS_ElemIteratorPtr anIter = anElem->nodesIterator();
10580     int ind = 0;
10581     while ( anIter->more() ) 
10582     { 
10583
10584       SMDS_MeshNode* aCurrNode = (SMDS_MeshNode*)anIter->next();
10585       SMDS_MeshNode* aNewNode = aCurrNode;
10586       if ( theNodeNodeMap.find( aCurrNode ) != theNodeNodeMap.end() )
10587         aNewNode = (SMDS_MeshNode*)theNodeNodeMap[ aCurrNode ];
10588       else if ( theIsDoubleElem && theNodesNot.find( aCurrNode ) == theNodesNot.end() )
10589       {
10590         // duplicate node
10591         aNewNode = theMeshDS->AddNode( aCurrNode->X(), aCurrNode->Y(), aCurrNode->Z() );
10592         theNodeNodeMap[ aCurrNode ] = aNewNode;
10593         myLastCreatedNodes.Append( aNewNode );
10594       }
10595       isDuplicate |= (aCurrNode != aNewNode);
10596       newNodes[ ind++ ] = aNewNode;
10597     }
10598     if ( !isDuplicate )
10599       continue;
10600
10601     if ( theIsDoubleElem )
10602       AddElement(newNodes, anElem->GetType(), anElem->IsPoly());
10603     else
10604       {
10605       MESSAGE("ChangeElementNodes");
10606       theMeshDS->ChangeElementNodes( anElem, &newNodes[ 0 ], anElem->NbNodes() );
10607       }
10608     res = true;
10609   }
10610   return res;
10611 }
10612
10613 //================================================================================
10614 /*!
10615   \brief Creates a hole in a mesh by doubling the nodes of some particular elements
10616   \param theNodes - identifiers of nodes to be doubled
10617   \param theModifiedElems - identifiers of elements to be updated by the new (doubled) 
10618          nodes. If list of element identifiers is empty then nodes are doubled but 
10619          they not assigned to elements
10620   \return TRUE if operation has been completed successfully, FALSE otherwise
10621 */
10622 //================================================================================
10623
10624 bool SMESH_MeshEditor::DoubleNodes( const std::list< int >& theListOfNodes, 
10625                                     const std::list< int >& theListOfModifiedElems )
10626 {
10627   MESSAGE("DoubleNodes");
10628   myLastCreatedElems.Clear();
10629   myLastCreatedNodes.Clear();
10630
10631   if ( theListOfNodes.size() == 0 )
10632     return false;
10633
10634   SMESHDS_Mesh* aMeshDS = GetMeshDS();
10635   if ( !aMeshDS )
10636     return false;
10637
10638   // iterate through nodes and duplicate them
10639
10640   std::map< const SMDS_MeshNode*, const SMDS_MeshNode* > anOldNodeToNewNode;
10641
10642   std::list< int >::const_iterator aNodeIter;
10643   for ( aNodeIter = theListOfNodes.begin(); aNodeIter != theListOfNodes.end(); ++aNodeIter )
10644   {
10645     int aCurr = *aNodeIter;
10646     SMDS_MeshNode* aNode = (SMDS_MeshNode*)aMeshDS->FindNode( aCurr );
10647     if ( !aNode )
10648       continue;
10649
10650     // duplicate node
10651
10652     const SMDS_MeshNode* aNewNode = aMeshDS->AddNode( aNode->X(), aNode->Y(), aNode->Z() );
10653     if ( aNewNode )
10654     {
10655       anOldNodeToNewNode[ aNode ] = aNewNode;
10656       myLastCreatedNodes.Append( aNewNode );
10657     }
10658   }
10659
10660   // Create map of new nodes for modified elements
10661
10662   std::map< SMDS_MeshElement*, vector<const SMDS_MeshNode*> > anElemToNodes;
10663
10664   std::list< int >::const_iterator anElemIter;
10665   for ( anElemIter = theListOfModifiedElems.begin(); 
10666         anElemIter != theListOfModifiedElems.end(); ++anElemIter )
10667   {
10668     int aCurr = *anElemIter;
10669     SMDS_MeshElement* anElem = (SMDS_MeshElement*)aMeshDS->FindElement( aCurr );
10670     if ( !anElem )
10671       continue;
10672
10673     vector<const SMDS_MeshNode*> aNodeArr( anElem->NbNodes() );
10674
10675     SMDS_ElemIteratorPtr anIter = anElem->nodesIterator();
10676     int ind = 0;
10677     while ( anIter->more() ) 
10678     { 
10679       SMDS_MeshNode* aCurrNode = (SMDS_MeshNode*)anIter->next();
10680       if ( aCurr && anOldNodeToNewNode.find( aCurrNode ) != anOldNodeToNewNode.end() )
10681       {
10682         const SMDS_MeshNode* aNewNode = anOldNodeToNewNode[ aCurrNode ];
10683         aNodeArr[ ind++ ] = aNewNode;
10684       }
10685       else
10686         aNodeArr[ ind++ ] = aCurrNode;
10687     }
10688     anElemToNodes[ anElem ] = aNodeArr;
10689   }
10690
10691   // Change nodes of elements  
10692
10693   std::map< SMDS_MeshElement*, vector<const SMDS_MeshNode*> >::iterator
10694     anElemToNodesIter = anElemToNodes.begin();
10695   for ( ; anElemToNodesIter != anElemToNodes.end(); ++anElemToNodesIter )
10696   {
10697     const SMDS_MeshElement* anElem = anElemToNodesIter->first;
10698     vector<const SMDS_MeshNode*> aNodeArr = anElemToNodesIter->second;
10699     if ( anElem )
10700       {
10701       MESSAGE("ChangeElementNodes");
10702       aMeshDS->ChangeElementNodes( anElem, &aNodeArr[ 0 ], anElem->NbNodes() );
10703       }
10704   }
10705
10706   return true;
10707 }
10708
10709 namespace {
10710
10711   //================================================================================
10712   /*!
10713   \brief Check if element located inside shape
10714   \return TRUE if IN or ON shape, FALSE otherwise
10715   */
10716   //================================================================================
10717
10718   template<class Classifier>
10719   bool isInside(const SMDS_MeshElement* theElem,
10720                 Classifier&             theClassifier,
10721                 const double            theTol)
10722   {
10723     gp_XYZ centerXYZ (0, 0, 0);
10724     SMDS_ElemIteratorPtr aNodeItr = theElem->nodesIterator();
10725     while (aNodeItr->more())
10726       centerXYZ += SMESH_TNodeXYZ(cast2Node( aNodeItr->next()));
10727
10728     gp_Pnt aPnt = centerXYZ / theElem->NbNodes();
10729     theClassifier.Perform(aPnt, theTol);
10730     TopAbs_State aState = theClassifier.State();
10731     return (aState == TopAbs_IN || aState == TopAbs_ON );
10732   }
10733
10734   //================================================================================
10735   /*!
10736    * \brief Classifier of the 3D point on the TopoDS_Face
10737    *        with interaface suitable for isInside()
10738    */
10739   //================================================================================
10740
10741   struct _FaceClassifier
10742   {
10743     Extrema_ExtPS       _extremum;
10744     BRepAdaptor_Surface _surface;
10745     TopAbs_State        _state;
10746
10747     _FaceClassifier(const TopoDS_Face& face):_extremum(),_surface(face),_state(TopAbs_OUT)
10748     {
10749       _extremum.Initialize( _surface,
10750                             _surface.FirstUParameter(), _surface.LastUParameter(),
10751                             _surface.FirstVParameter(), _surface.LastVParameter(),
10752                             _surface.Tolerance(), _surface.Tolerance() );
10753     }
10754     void Perform(const gp_Pnt& aPnt, double theTol)
10755     {
10756       _state = TopAbs_OUT;
10757       _extremum.Perform(aPnt);
10758       if ( _extremum.IsDone() )
10759         for ( int iSol = 1; iSol <= _extremum.NbExt() && _state == TopAbs_OUT; ++iSol)
10760           _state = ( _extremum.Value(iSol) <= theTol ? TopAbs_IN : TopAbs_OUT );
10761     }
10762     TopAbs_State State() const
10763     {
10764       return _state;
10765     }
10766   };
10767 }
10768
10769 //================================================================================
10770 /*!
10771   \brief Creates a hole in a mesh by doubling the nodes of some particular elements
10772   \param theElems - group of of elements (edges or faces) to be replicated
10773   \param theNodesNot - group of nodes not to replicate
10774   \param theShape - shape to detect affected elements (element which geometric center
10775   located on or inside shape).
10776   The replicated nodes should be associated to affected elements.
10777   \return TRUE if operation has been completed successfully, FALSE otherwise
10778 */
10779 //================================================================================
10780
10781 bool SMESH_MeshEditor::DoubleNodesInRegion( const TIDSortedElemSet& theElems,
10782                                             const TIDSortedElemSet& theNodesNot,
10783                                             const TopoDS_Shape&     theShape )
10784 {
10785   if ( theShape.IsNull() )
10786     return false;
10787
10788   const double aTol = Precision::Confusion();
10789   auto_ptr< BRepClass3d_SolidClassifier> bsc3d;
10790   auto_ptr<_FaceClassifier>              aFaceClassifier;
10791   if ( theShape.ShapeType() == TopAbs_SOLID )
10792   {
10793     bsc3d.reset( new BRepClass3d_SolidClassifier(theShape));;
10794     bsc3d->PerformInfinitePoint(aTol);
10795   }
10796   else if (theShape.ShapeType() == TopAbs_FACE )
10797   {
10798     aFaceClassifier.reset( new _FaceClassifier(TopoDS::Face(theShape)));
10799   }
10800
10801   // iterates on indicated elements and get elements by back references from their nodes
10802   TIDSortedElemSet anAffected;
10803   TIDSortedElemSet::const_iterator elemItr = theElems.begin();
10804   for ( ;  elemItr != theElems.end(); ++elemItr )
10805   {
10806     SMDS_MeshElement* anElem = (SMDS_MeshElement*)*elemItr;
10807     if (!anElem)
10808       continue;
10809
10810     SMDS_ElemIteratorPtr nodeItr = anElem->nodesIterator();
10811     while ( nodeItr->more() )
10812     {
10813       const SMDS_MeshNode* aNode = cast2Node(nodeItr->next());
10814       if ( !aNode || theNodesNot.find(aNode) != theNodesNot.end() )
10815         continue;
10816       SMDS_ElemIteratorPtr backElemItr = aNode->GetInverseElementIterator();
10817       while ( backElemItr->more() )
10818       {
10819         const SMDS_MeshElement* curElem = backElemItr->next();
10820         if ( curElem && theElems.find(curElem) == theElems.end() &&
10821              ( bsc3d.get() ?
10822                isInside( curElem, *bsc3d, aTol ) :
10823                isInside( curElem, *aFaceClassifier, aTol )))
10824           anAffected.insert( curElem );
10825       }
10826     }
10827   }
10828   return DoubleNodes( theElems, theNodesNot, anAffected );
10829 }
10830
10831 /*!
10832  *  \brief compute an oriented angle between two planes defined by four points.
10833  *  The vector (p0,p1) defines the intersection of the 2 planes (p0,p1,g1) and (p0,p1,g2)
10834  *  @param p0 base of the rotation axe
10835  *  @param p1 extremity of the rotation axe
10836  *  @param g1 belongs to the first plane
10837  *  @param g2 belongs to the second plane
10838  */
10839 double SMESH_MeshEditor::OrientedAngle(const gp_Pnt& p0, const gp_Pnt& p1, const gp_Pnt& g1, const gp_Pnt& g2)
10840 {
10841 //  MESSAGE("    p0: " << p0.X() << " " << p0.Y() << " " << p0.Z());
10842 //  MESSAGE("    p1: " << p1.X() << " " << p1.Y() << " " << p1.Z());
10843 //  MESSAGE("    g1: " << g1.X() << " " << g1.Y() << " " << g1.Z());
10844 //  MESSAGE("    g2: " << g2.X() << " " << g2.Y() << " " << g2.Z());
10845   gp_Vec vref(p0, p1);
10846   gp_Vec v1(p0, g1);
10847   gp_Vec v2(p0, g2);
10848   gp_Vec n1 = vref.Crossed(v1);
10849   gp_Vec n2 = vref.Crossed(v2);
10850   return n2.AngleWithRef(n1, vref);
10851 }
10852
10853 /*!
10854  * \brief Double nodes on shared faces between groups of volumes and create flat elements on demand.
10855  * The list of groups must describe a partition of the mesh volumes.
10856  * The nodes of the internal faces at the boundaries of the groups are doubled.
10857  * In option, the internal faces are replaced by flat elements.
10858  * Triangles are transformed in prisms, and quadrangles in hexahedrons.
10859  * The flat elements are stored in groups of volumes.
10860  * @param theElems - list of groups of volumes, where a group of volume is a set of
10861  * SMDS_MeshElements sorted by Id.
10862  * @param createJointElems - if TRUE, create the elements
10863  * @return TRUE if operation has been completed successfully, FALSE otherwise
10864  */
10865 bool SMESH_MeshEditor::DoubleNodesOnGroupBoundaries( const std::vector<TIDSortedElemSet>& theElems,
10866                                                      bool createJointElems)
10867 {
10868   MESSAGE("----------------------------------------------");
10869   MESSAGE("SMESH_MeshEditor::doubleNodesOnGroupBoundaries");
10870   MESSAGE("----------------------------------------------");
10871
10872   SMESHDS_Mesh *meshDS = this->myMesh->GetMeshDS();
10873   meshDS->BuildDownWardConnectivity(true);
10874   CHRONO(50);
10875   SMDS_UnstructuredGrid *grid = meshDS->getGrid();
10876
10877   // --- build the list of faces shared by 2 domains (group of elements), with their domain and volume indexes
10878   //     build the list of cells with only a node or an edge on the border, with their domain and volume indexes
10879   //     build the list of nodes shared by 2 or more domains, with their domain indexes
10880
10881   std::map<DownIdType, std::map<int,int>, DownIdCompare> faceDomains; // face --> (id domain --> id volume)
10882   std::map<int,int>celldom; // cell vtkId --> domain
10883   std::map<DownIdType, std::map<int,int>, DownIdCompare> cellDomains;  // oldNode --> (id domain --> id cell)
10884   std::map<int, std::map<int,int> > nodeDomains; // oldId -->  (domainId --> newId)
10885   faceDomains.clear();
10886   celldom.clear();
10887   cellDomains.clear();
10888   nodeDomains.clear();
10889   std::map<int,int> emptyMap;
10890   std::set<int> emptySet;
10891   emptyMap.clear();
10892
10893   for (int idom = 0; idom < theElems.size(); idom++)
10894     {
10895
10896       // --- build a map (face to duplicate --> volume to modify)
10897       //     with all the faces shared by 2 domains (group of elements)
10898       //     and corresponding volume of this domain, for each shared face.
10899       //     a volume has a face shared by 2 domains if it has a neighbor which is not in is domain.
10900
10901       const TIDSortedElemSet& domain = theElems[idom];
10902       TIDSortedElemSet::const_iterator elemItr = domain.begin();
10903       for (; elemItr != domain.end(); ++elemItr)
10904         {
10905           SMDS_MeshElement* anElem = (SMDS_MeshElement*) *elemItr;
10906           if (!anElem)
10907             continue;
10908           int vtkId = anElem->getVtkId();
10909           int neighborsVtkIds[NBMAXNEIGHBORS];
10910           int downIds[NBMAXNEIGHBORS];
10911           unsigned char downTypes[NBMAXNEIGHBORS];
10912           int nbNeighbors = grid->GetNeighbors(neighborsVtkIds, downIds, downTypes, vtkId);
10913           for (int n = 0; n < nbNeighbors; n++)
10914             {
10915               int smdsId = meshDS->fromVtkToSmds(neighborsVtkIds[n]);
10916               const SMDS_MeshElement* elem = meshDS->FindElement(smdsId);
10917               if (! domain.count(elem)) // neighbor is in another domain : face is shared
10918                 {
10919                   DownIdType face(downIds[n], downTypes[n]);
10920                   if (!faceDomains.count(face))
10921                     faceDomains[face] = emptyMap; // create an empty entry for face
10922                   if (!faceDomains[face].count(idom))
10923                     {
10924                       faceDomains[face][idom] = vtkId; // volume associated to face in this domain
10925                       celldom[vtkId] = idom;
10926                     }
10927                 }
10928             }
10929         }
10930     }
10931
10932   //MESSAGE("Number of shared faces " << faceDomains.size());
10933   std::map<DownIdType, std::map<int, int>, DownIdCompare>::iterator itface;
10934
10935   // --- explore the shared faces domain by domain,
10936   //     explore the nodes of the face and see if they belong to a cell in the domain,
10937   //     which has only a node or an edge on the border (not a shared face)
10938
10939   for (int idomain = 0; idomain < theElems.size(); idomain++)
10940     {
10941       const TIDSortedElemSet& domain = theElems[idomain];
10942       itface = faceDomains.begin();
10943       for (; itface != faceDomains.end(); ++itface)
10944         {
10945           std::map<int, int> domvol = itface->second;
10946           if (!domvol.count(idomain))
10947             continue;
10948           DownIdType face = itface->first;
10949           //MESSAGE(" --- face " << face.cellId);
10950           std::set<int> oldNodes;
10951           oldNodes.clear();
10952           grid->GetNodeIds(oldNodes, face.cellId, face.cellType);
10953           std::set<int>::iterator itn = oldNodes.begin();
10954           for (; itn != oldNodes.end(); ++itn)
10955             {
10956               int oldId = *itn;
10957               //MESSAGE("     node " << oldId);
10958               std::set<int> cells;
10959               cells.clear();
10960               vtkCellLinks::Link l = grid->GetCellLinks()->GetLink(oldId);
10961               for (int i=0; i<l.ncells; i++)
10962                 {
10963                   int vtkId = l.cells[i];
10964                   const SMDS_MeshElement* anElem = GetMeshDS()->FindElement(GetMeshDS()->fromVtkToSmds(vtkId));
10965                   if (!domain.count(anElem))
10966                     continue;
10967                   int vtkType = grid->GetCellType(vtkId);
10968                   int downId = grid->CellIdToDownId(vtkId);
10969                   if (downId < 0)
10970                     {
10971                       MESSAGE("doubleNodesOnGroupBoundaries: internal algorithm problem");
10972                       continue; // not OK at this stage of the algorithm:
10973                                 //no cells created after BuildDownWardConnectivity
10974                     }
10975                   DownIdType aCell(downId, vtkType);
10976                   if (celldom.count(vtkId))
10977                     continue;
10978                   cellDomains[aCell][idomain] = vtkId;
10979                   celldom[vtkId] = idomain;
10980                 }
10981             }
10982         }
10983     }
10984
10985   // --- explore the shared faces domain by domain, to duplicate the nodes in a coherent way
10986   //     for each shared face, get the nodes
10987   //     for each node, for each domain of the face, create a clone of the node
10988
10989   // --- edges at the intersection of 3 or 4 domains, with the order of domains to build
10990   //     junction elements of type prism or hexa. the key is the pair of nodesId (lower first)
10991   //     the value is the ordered domain ids. (more than 4 domains not taken into account)
10992
10993   std::map<std::vector<int>, std::vector<int> > edgesMultiDomains; // nodes of edge --> ordered domains
10994   std::map<int, std::vector<int> > mutipleNodes; // nodes muti domains with domain order
10995
10996   for (int idomain = 0; idomain < theElems.size(); idomain++)
10997     {
10998       itface = faceDomains.begin();
10999       for (; itface != faceDomains.end(); ++itface)
11000         {
11001           std::map<int, int> domvol = itface->second;
11002           if (!domvol.count(idomain))
11003             continue;
11004           DownIdType face = itface->first;
11005           //MESSAGE(" --- face " << face.cellId);
11006           std::set<int> oldNodes;
11007           oldNodes.clear();
11008           grid->GetNodeIds(oldNodes, face.cellId, face.cellType);
11009           bool isMultipleDetected = false;
11010           std::set<int>::iterator itn = oldNodes.begin();
11011           for (; itn != oldNodes.end(); ++itn)
11012             {
11013               int oldId = *itn;
11014               //MESSAGE("     node " << oldId);
11015               if (!nodeDomains.count(oldId))
11016                 nodeDomains[oldId] = emptyMap; // create an empty entry for node
11017               if (nodeDomains[oldId].empty())
11018                 nodeDomains[oldId][idomain] = oldId; // keep the old node in the first domain
11019               std::map<int, int>::iterator itdom = domvol.begin();
11020               for (; itdom != domvol.end(); ++itdom)
11021                 {
11022                   int idom = itdom->first;
11023                   //MESSAGE("         domain " << idom);
11024                   if (!nodeDomains[oldId].count(idom)) // --- node to clone
11025                     {
11026                       if (nodeDomains[oldId].size() >= 2) // a multiple node
11027                         {
11028                           vector<int> orderedDoms;
11029                           //MESSAGE("multiple node " << oldId);
11030                           isMultipleDetected =true;
11031                           if (mutipleNodes.count(oldId))
11032                             orderedDoms = mutipleNodes[oldId];
11033                           else
11034                             {
11035                               map<int,int>::iterator it = nodeDomains[oldId].begin();
11036                               for (; it != nodeDomains[oldId].end(); ++it)
11037                                 orderedDoms.push_back(it->first);
11038                             }
11039                           orderedDoms.push_back(idom); // TODO order ==> push_front or back
11040                           //stringstream txt;
11041                           //for (int i=0; i<orderedDoms.size(); i++)
11042                           //  txt << orderedDoms[i] << " ";
11043                           //MESSAGE("orderedDoms " << txt.str());
11044                           mutipleNodes[oldId] = orderedDoms;
11045                         }
11046                       double *coords = grid->GetPoint(oldId);
11047                       SMDS_MeshNode *newNode = meshDS->AddNode(coords[0], coords[1], coords[2]);
11048                       int newId = newNode->getVtkId();
11049                       nodeDomains[oldId][idom] = newId; // cloned node for other domains
11050                       //MESSAGE("   newNode " << newId << " oldNode " << oldId << " size=" <<nodeDomains[oldId].size());
11051                     }
11052                   if (nodeDomains[oldId].size() >= 3)
11053                     {
11054                       //MESSAGE("confirm multiple node " << oldId);
11055                       isMultipleDetected =true;
11056                     }
11057                 }
11058             }
11059           if (isMultipleDetected) // check if an edge of the face is shared between 3 or more domains
11060             {
11061               //MESSAGE("multiple Nodes detected on a shared face");
11062               int downId = itface->first.cellId;
11063               unsigned char cellType = itface->first.cellType;
11064               int nbEdges = grid->getDownArray(cellType)->getNumberOfDownCells(downId);
11065               const int *downEdgeIds = grid->getDownArray(cellType)->getDownCells(downId);
11066               const unsigned char* edgeType = grid->getDownArray(cellType)->getDownTypes(downId);
11067               for (int ie =0; ie < nbEdges; ie++)
11068                 {
11069                   int nodes[3];
11070                   int nbNodes = grid->getDownArray(edgeType[ie])->getNodes(downEdgeIds[ie], nodes);
11071                   if (mutipleNodes.count(nodes[0]) && mutipleNodes.count(nodes[nbNodes-1]))
11072                     {
11073                       vector<int> vn0 = mutipleNodes[nodes[0]];
11074                       vector<int> vn1 = mutipleNodes[nodes[nbNodes - 1]];
11075                       sort( vn0.begin(), vn0.end() );
11076                       sort( vn1.begin(), vn1.end() );
11077                       if (vn0 == vn1)
11078                         {
11079                           //MESSAGE(" detect edgesMultiDomains " << nodes[0] << " " << nodes[nbNodes - 1]);
11080                           double *coords = grid->GetPoint(nodes[0]);
11081                           gp_Pnt p0(coords[0], coords[1], coords[2]);
11082                           coords = grid->GetPoint(nodes[nbNodes - 1]);
11083                           gp_Pnt p1(coords[0], coords[1], coords[2]);
11084                           gp_Pnt gref;
11085                           int vtkVolIds[1000];  // an edge can belong to a lot of volumes
11086                           map<int, SMDS_VtkVolume*> domvol; // domain --> a volume with the edge
11087                           map<int, double> angleDom; // oriented angles between planes defined by edge and volume centers
11088                           int nbvol = grid->GetParentVolumes(vtkVolIds, downEdgeIds[ie], edgeType[ie]);
11089                           for (int id=0; id < vn0.size(); id++)
11090                             {
11091                               int idom = vn0[id];
11092                               for (int ivol=0; ivol<nbvol; ivol++)
11093                                 {
11094                                   int smdsId = meshDS->fromVtkToSmds(vtkVolIds[ivol]);
11095                                   SMDS_MeshElement* elem = (SMDS_MeshElement*)meshDS->FindElement(smdsId);
11096                                   if (theElems[idom].count(elem))
11097                                     {
11098                                       SMDS_VtkVolume* svol = dynamic_cast<SMDS_VtkVolume*>(elem);
11099                                       domvol[idom] = svol;
11100                                       //MESSAGE("  domain " << idom << " volume " << elem->GetID());
11101                                       double values[3];
11102                                       vtkIdType npts = 0;
11103                                       vtkIdType* pts = 0;
11104                                       grid->GetCellPoints(vtkVolIds[ivol], npts, pts);
11105                                       SMDS_VtkVolume::gravityCenter(grid, pts, npts, values);
11106                                       if (id ==0)
11107                                         {
11108                                           gref.SetXYZ(gp_XYZ(values[0], values[1], values[2]));
11109                                           angleDom[idom] = 0;
11110                                         }
11111                                       else
11112                                         {
11113                                           gp_Pnt g(values[0], values[1], values[2]);
11114                                           angleDom[idom] = OrientedAngle(p0, p1, gref, g); // -pi<angle<+pi
11115                                           //MESSAGE("  angle=" << angleDom[idom]);
11116                                         }
11117                                       break;
11118                                     }
11119                                 }
11120                             }
11121                           map<double, int> sortedDom; // sort domains by angle
11122                           for (map<int, double>::iterator ia = angleDom.begin(); ia != angleDom.end(); ++ia)
11123                             sortedDom[ia->second] = ia->first;
11124                           vector<int> vnodes;
11125                           vector<int> vdom;
11126                           for (map<double, int>::iterator ib = sortedDom.begin(); ib != sortedDom.end(); ++ib)
11127                             {
11128                               vdom.push_back(ib->second);
11129                               //MESSAGE("  ordered domain " << ib->second << "  angle " << ib->first);
11130                             }
11131                           for (int ino = 0; ino < nbNodes; ino++)
11132                             vnodes.push_back(nodes[ino]);
11133                           edgesMultiDomains[vnodes] = vdom; // nodes vector --> ordered domains
11134                         }
11135                     }
11136                 }
11137             }
11138         }
11139     }
11140
11141   // --- iterate on shared faces (volumes to modify, face to extrude)
11142   //     get node id's of the face (id SMDS = id VTK)
11143   //     create flat element with old and new nodes if requested
11144
11145   // --- new quad nodes on flat quad elements: oldId --> ((domain1 X domain2) --> newId)
11146   //     (domain1 X domain2) = domain1 + MAXINT*domain2
11147
11148   std::map<int, std::map<long,int> > nodeQuadDomains;
11149   std::map<std::string, SMESH_Group*> mapOfJunctionGroups;
11150
11151   if (createJointElems)
11152     {
11153       itface = faceDomains.begin();
11154       for (; itface != faceDomains.end(); ++itface)
11155         {
11156           DownIdType face = itface->first;
11157           std::set<int> oldNodes;
11158           std::set<int>::iterator itn;
11159           oldNodes.clear();
11160           grid->GetNodeIds(oldNodes, face.cellId, face.cellType);
11161
11162           std::map<int, int> domvol = itface->second;
11163           std::map<int, int>::iterator itdom = domvol.begin();
11164           int dom1 = itdom->first;
11165           int vtkVolId = itdom->second;
11166           itdom++;
11167           int dom2 = itdom->first;
11168           SMDS_MeshVolume *vol = grid->extrudeVolumeFromFace(vtkVolId, dom1, dom2, oldNodes, nodeDomains,
11169                                                              nodeQuadDomains);
11170           stringstream grpname;
11171           grpname << "j_";
11172           if (dom1 < dom2)
11173             grpname << dom1 << "_" << dom2;
11174           else
11175             grpname << dom2 << "_" << dom1;
11176           int idg;
11177           string namegrp = grpname.str();
11178           if (!mapOfJunctionGroups.count(namegrp))
11179             mapOfJunctionGroups[namegrp] = this->myMesh->AddGroup(SMDSAbs_Volume, namegrp.c_str(), idg);
11180           SMESHDS_Group *sgrp = dynamic_cast<SMESHDS_Group*>(mapOfJunctionGroups[namegrp]->GetGroupDS());
11181           if (sgrp)
11182             sgrp->Add(vol->GetID());
11183         }
11184     }
11185
11186   // --- create volumes on multiple domain intersection if requested
11187   //     iterate on edgesMultiDomains
11188
11189   if (createJointElems)
11190     {
11191       std::map<std::vector<int>, std::vector<int> >::iterator ite = edgesMultiDomains.begin();
11192       for (; ite != edgesMultiDomains.end(); ++ite)
11193         {
11194           vector<int> nodes = ite->first;
11195           vector<int> orderDom = ite->second;
11196           vector<vtkIdType> orderedNodes;
11197           if (nodes.size() == 2)
11198             {
11199               //MESSAGE(" use edgesMultiDomains " << nodes[0] << " " << nodes[1]);
11200               for (int ino=0; ino < nodes.size(); ino++)
11201                 if (orderDom.size() == 3)
11202                   for (int idom = 0; idom <orderDom.size(); idom++)
11203                     orderedNodes.push_back( nodeDomains[nodes[ino]][orderDom[idom]] );
11204                 else
11205                   for (int idom = orderDom.size()-1; idom >=0; idom--)
11206                     orderedNodes.push_back( nodeDomains[nodes[ino]][orderDom[idom]] );
11207               SMDS_MeshVolume* vol = this->GetMeshDS()->AddVolumeFromVtkIds(orderedNodes);
11208
11209               stringstream grpname;
11210               grpname << "mj_";
11211               grpname << 0 << "_" << 0;
11212               int idg;
11213               string namegrp = grpname.str();
11214               if (!mapOfJunctionGroups.count(namegrp))
11215                 mapOfJunctionGroups[namegrp] = this->myMesh->AddGroup(SMDSAbs_Volume, namegrp.c_str(), idg);
11216               SMESHDS_Group *sgrp = dynamic_cast<SMESHDS_Group*>(mapOfJunctionGroups[namegrp]->GetGroupDS());
11217               if (sgrp)
11218                 sgrp->Add(vol->GetID());
11219             }
11220           else
11221             {
11222               //MESSAGE("Quadratic multiple joints not implemented");
11223               // TODO quadratic nodes
11224             }
11225         }
11226     }
11227
11228   // --- list the explicit faces and edges of the mesh that need to be modified,
11229   //     i.e. faces and edges built with one or more duplicated nodes.
11230   //     associate these faces or edges to their corresponding domain.
11231   //     only the first domain found is kept when a face or edge is shared
11232
11233   std::map<DownIdType, std::map<int,int>, DownIdCompare> faceOrEdgeDom; // cellToModify --> (id domain --> id cell)
11234   std::map<int,int> feDom; // vtk id of cell to modify --> id domain
11235   faceOrEdgeDom.clear();
11236   feDom.clear();
11237
11238   for (int idomain = 0; idomain < theElems.size(); idomain++)
11239     {
11240       std::map<int, std::map<int, int> >::const_iterator itnod = nodeDomains.begin();
11241       for (; itnod != nodeDomains.end(); ++itnod)
11242         {
11243           int oldId = itnod->first;
11244           //MESSAGE("     node " << oldId);
11245           vtkCellLinks::Link l = grid->GetCellLinks()->GetLink(oldId);
11246           for (int i = 0; i < l.ncells; i++)
11247             {
11248               int vtkId = l.cells[i];
11249               int vtkType = grid->GetCellType(vtkId);
11250               int downId = grid->CellIdToDownId(vtkId);
11251               if (downId < 0)
11252                 continue; // new cells: not to be modified
11253               DownIdType aCell(downId, vtkType);
11254               int volParents[1000];
11255               int nbvol = grid->GetParentVolumes(volParents, vtkId);
11256               for (int j = 0; j < nbvol; j++)
11257                 if (celldom.count(volParents[j]) && (celldom[volParents[j]] == idomain))
11258                   if (!feDom.count(vtkId))
11259                     {
11260                       feDom[vtkId] = idomain;
11261                       faceOrEdgeDom[aCell] = emptyMap;
11262                       faceOrEdgeDom[aCell][idomain] = vtkId; // affect face or edge to the first domain only
11263                       //MESSAGE("affect cell " << this->GetMeshDS()->fromVtkToSmds(vtkId) << " domain " << idomain
11264                       //        << " type " << vtkType << " downId " << downId);
11265                     }
11266             }
11267         }
11268     }
11269
11270   // --- iterate on shared faces (volumes to modify, face to extrude)
11271   //     get node id's of the face
11272   //     replace old nodes by new nodes in volumes, and update inverse connectivity
11273
11274   std::map<DownIdType, std::map<int,int>, DownIdCompare>* maps[3] = {&faceDomains, &cellDomains, &faceOrEdgeDom};
11275   for (int m=0; m<3; m++)
11276     {
11277       std::map<DownIdType, std::map<int,int>, DownIdCompare>* amap = maps[m];
11278       itface = (*amap).begin();
11279       for (; itface != (*amap).end(); ++itface)
11280         {
11281           DownIdType face = itface->first;
11282           std::set<int> oldNodes;
11283           std::set<int>::iterator itn;
11284           oldNodes.clear();
11285           grid->GetNodeIds(oldNodes, face.cellId, face.cellType);
11286           //MESSAGE("examine cell, downId " << face.cellId << " type " << int(face.cellType));
11287           std::map<int, int> localClonedNodeIds;
11288
11289           std::map<int, int> domvol = itface->second;
11290           std::map<int, int>::iterator itdom = domvol.begin();
11291           for (; itdom != domvol.end(); ++itdom)
11292             {
11293               int idom = itdom->first;
11294               int vtkVolId = itdom->second;
11295               //MESSAGE("modify nodes of cell " << this->GetMeshDS()->fromVtkToSmds(vtkVolId) << " domain " << idom);
11296               localClonedNodeIds.clear();
11297               for (itn = oldNodes.begin(); itn != oldNodes.end(); ++itn)
11298                 {
11299                   int oldId = *itn;
11300                   if (nodeDomains[oldId].count(idom))
11301                     {
11302                       localClonedNodeIds[oldId] = nodeDomains[oldId][idom];
11303                       //MESSAGE("     node " << oldId << " --> " << localClonedNodeIds[oldId]);
11304                     }
11305                 }
11306               meshDS->ModifyCellNodes(vtkVolId, localClonedNodeIds);
11307             }
11308         }
11309     }
11310
11311   meshDS->CleanDownWardConnectivity(); // Mesh has been modified, downward connectivity is no more usable, free memory
11312   grid->BuildLinks();
11313
11314   CHRONOSTOP(50);
11315   counters::stats();
11316   return true;
11317 }
11318
11319 /*!
11320  * \brief Double nodes on some external faces and create flat elements.
11321  * Flat elements are mainly used by some types of mechanic calculations.
11322  *
11323  * Each group of the list must be constituted of faces.
11324  * Triangles are transformed in prisms, and quadrangles in hexahedrons.
11325  * @param theElems - list of groups of faces, where a group of faces is a set of
11326  * SMDS_MeshElements sorted by Id.
11327  * @return TRUE if operation has been completed successfully, FALSE otherwise
11328  */
11329 bool SMESH_MeshEditor::CreateFlatElementsOnFacesGroups(const std::vector<TIDSortedElemSet>& theElems)
11330 {
11331   MESSAGE("-------------------------------------------------");
11332   MESSAGE("SMESH_MeshEditor::CreateFlatElementsOnFacesGroups");
11333   MESSAGE("-------------------------------------------------");
11334
11335   SMESHDS_Mesh *meshDS = this->myMesh->GetMeshDS();
11336
11337   // --- For each group of faces
11338   //     duplicate the nodes, create a flat element based on the face
11339   //     replace the nodes of the faces by their clones
11340
11341   std::map<const SMDS_MeshNode*, const SMDS_MeshNode*> clonedNodes;
11342   std::map<const SMDS_MeshNode*, const SMDS_MeshNode*> intermediateNodes;
11343   clonedNodes.clear();
11344   intermediateNodes.clear();
11345   std::map<std::string, SMESH_Group*> mapOfJunctionGroups;
11346   mapOfJunctionGroups.clear();
11347
11348   for (int idom = 0; idom < theElems.size(); idom++)
11349     {
11350       const TIDSortedElemSet& domain = theElems[idom];
11351       TIDSortedElemSet::const_iterator elemItr = domain.begin();
11352       for (; elemItr != domain.end(); ++elemItr)
11353         {
11354           SMDS_MeshElement* anElem = (SMDS_MeshElement*) *elemItr;
11355           SMDS_MeshFace* aFace = dynamic_cast<SMDS_MeshFace*> (anElem);
11356           if (!aFace)
11357             continue;
11358           // MESSAGE("aFace=" << aFace->GetID());
11359           bool isQuad = aFace->IsQuadratic();
11360           vector<const SMDS_MeshNode*> ln0, ln1, ln2, ln3, ln4;
11361
11362           // --- clone the nodes, create intermediate nodes for non medium nodes of a quad face
11363
11364           SMDS_ElemIteratorPtr nodeIt = aFace->nodesIterator();
11365           while (nodeIt->more())
11366             {
11367               const SMDS_MeshNode* node = static_cast<const SMDS_MeshNode*> (nodeIt->next());
11368               bool isMedium = isQuad && (aFace->IsMediumNode(node));
11369               if (isMedium)
11370                 ln2.push_back(node);
11371               else
11372                 ln0.push_back(node);
11373
11374               const SMDS_MeshNode* clone = 0;
11375               if (!clonedNodes.count(node))
11376                 {
11377                   clone = meshDS->AddNode(node->X(), node->Y(), node->Z());
11378                   clonedNodes[node] = clone;
11379                 }
11380               else
11381                 clone = clonedNodes[node];
11382
11383               if (isMedium)
11384                 ln3.push_back(clone);
11385               else
11386                 ln1.push_back(clone);
11387
11388               const SMDS_MeshNode* inter = 0;
11389               if (isQuad && (!isMedium))
11390                 {
11391                   if (!intermediateNodes.count(node))
11392                     {
11393                       inter = meshDS->AddNode(node->X(), node->Y(), node->Z());
11394                       intermediateNodes[node] = inter;
11395                     }
11396                   else
11397                     inter = intermediateNodes[node];
11398                   ln4.push_back(inter);
11399                 }
11400             }
11401
11402           // --- extrude the face
11403
11404           vector<const SMDS_MeshNode*> ln;
11405           SMDS_MeshVolume* vol = 0;
11406           vtkIdType aType = aFace->GetVtkType();
11407           switch (aType)
11408           {
11409             case VTK_TRIANGLE:
11410               vol = meshDS->AddVolume(ln0[2], ln0[1], ln0[0], ln1[2], ln1[1], ln1[0]);
11411               // MESSAGE("vol prism " << vol->GetID());
11412               ln.push_back(ln1[0]);
11413               ln.push_back(ln1[1]);
11414               ln.push_back(ln1[2]);
11415               break;
11416             case VTK_QUAD:
11417               vol = meshDS->AddVolume(ln0[3], ln0[2], ln0[1], ln0[0], ln1[3], ln1[2], ln1[1], ln1[0]);
11418               // MESSAGE("vol hexa " << vol->GetID());
11419               ln.push_back(ln1[0]);
11420               ln.push_back(ln1[1]);
11421               ln.push_back(ln1[2]);
11422               ln.push_back(ln1[3]);
11423               break;
11424             case VTK_QUADRATIC_TRIANGLE:
11425               vol = meshDS->AddVolume(ln1[0], ln1[1], ln1[2], ln0[0], ln0[1], ln0[2], ln3[0], ln3[1], ln3[2],
11426                                       ln2[0], ln2[1], ln2[2], ln4[0], ln4[1], ln4[2]);
11427               // MESSAGE("vol quad prism " << vol->GetID());
11428               ln.push_back(ln1[0]);
11429               ln.push_back(ln1[1]);
11430               ln.push_back(ln1[2]);
11431               ln.push_back(ln3[0]);
11432               ln.push_back(ln3[1]);
11433               ln.push_back(ln3[2]);
11434               break;
11435             case VTK_QUADRATIC_QUAD:
11436 //              vol = meshDS->AddVolume(ln0[0], ln0[1], ln0[2], ln0[3], ln1[0], ln1[1], ln1[2], ln1[3],
11437 //                                      ln2[0], ln2[1], ln2[2], ln2[3], ln3[0], ln3[1], ln3[2], ln3[3],
11438 //                                      ln4[0], ln4[1], ln4[2], ln4[3]);
11439               vol = meshDS->AddVolume(ln1[0], ln1[1], ln1[2], ln1[3], ln0[0], ln0[1], ln0[2], ln0[3],
11440                                       ln3[0], ln3[1], ln3[2], ln3[3], ln2[0], ln2[1], ln2[2], ln2[3],
11441                                       ln4[0], ln4[1], ln4[2], ln4[3]);
11442               // MESSAGE("vol quad hexa " << vol->GetID());
11443               ln.push_back(ln1[0]);
11444               ln.push_back(ln1[1]);
11445               ln.push_back(ln1[2]);
11446               ln.push_back(ln1[3]);
11447               ln.push_back(ln3[0]);
11448               ln.push_back(ln3[1]);
11449               ln.push_back(ln3[2]);
11450               ln.push_back(ln3[3]);
11451               break;
11452             case VTK_POLYGON:
11453               break;
11454             default:
11455               break;
11456           }
11457
11458           if (vol)
11459             {
11460               stringstream grpname;
11461               grpname << "jf_";
11462               grpname << idom;
11463               int idg;
11464               string namegrp = grpname.str();
11465               if (!mapOfJunctionGroups.count(namegrp))
11466                 mapOfJunctionGroups[namegrp] = this->myMesh->AddGroup(SMDSAbs_Volume, namegrp.c_str(), idg);
11467               SMESHDS_Group *sgrp = dynamic_cast<SMESHDS_Group*>(mapOfJunctionGroups[namegrp]->GetGroupDS());
11468               if (sgrp)
11469                 sgrp->Add(vol->GetID());
11470             }
11471
11472           // --- modify the face
11473
11474           aFace->ChangeNodes(&ln[0], ln.size());
11475         }
11476     }
11477   return true;
11478 }
11479
11480 //================================================================================
11481 /*!
11482  * \brief Generates skin mesh (containing 2D cells) from 3D mesh
11483  * The created 2D mesh elements based on nodes of free faces of boundary volumes
11484  * \return TRUE if operation has been completed successfully, FALSE otherwise
11485  */
11486 //================================================================================
11487
11488 bool SMESH_MeshEditor::Make2DMeshFrom3D()
11489 {
11490   // iterates on volume elements and detect all free faces on them
11491   SMESHDS_Mesh* aMesh = GetMeshDS();
11492   if (!aMesh)
11493     return false;
11494   //bool res = false;
11495   int nbFree = 0, nbExisted = 0, nbCreated = 0;
11496   SMDS_VolumeIteratorPtr vIt = aMesh->volumesIterator();
11497   while(vIt->more())
11498   {
11499     const SMDS_MeshVolume* volume = vIt->next();
11500     SMDS_VolumeTool vTool( volume );
11501     vTool.SetExternalNormal();
11502     const bool isPoly = volume->IsPoly();
11503     const bool isQuad = volume->IsQuadratic();
11504     for ( int iface = 0, n = vTool.NbFaces(); iface < n; iface++ )
11505     {
11506       if (!vTool.IsFreeFace(iface))
11507         continue;
11508       nbFree++;
11509       vector<const SMDS_MeshNode *> nodes;
11510       int nbFaceNodes = vTool.NbFaceNodes(iface);
11511       const SMDS_MeshNode** faceNodes = vTool.GetFaceNodes(iface);
11512       int inode = 0;
11513       for ( ; inode < nbFaceNodes; inode += isQuad ? 2 : 1)
11514         nodes.push_back(faceNodes[inode]);
11515       if (isQuad)
11516         for ( inode = 1; inode < nbFaceNodes; inode += 2)
11517           nodes.push_back(faceNodes[inode]);
11518
11519       // add new face based on volume nodes
11520       if (aMesh->FindFace( nodes ) ) {
11521         nbExisted++;
11522         continue; // face already exsist
11523       }
11524       AddElement(nodes, SMDSAbs_Face, isPoly && iface == 1);
11525       nbCreated++;
11526     }
11527   }
11528   return ( nbFree==(nbExisted+nbCreated) );
11529 }
11530
11531 namespace
11532 {
11533   inline const SMDS_MeshNode* getNodeWithSameID(SMESHDS_Mesh* mesh, const SMDS_MeshNode* node)
11534   {
11535     if ( const SMDS_MeshNode* n = mesh->FindNode( node->GetID() ))
11536       return n;
11537     return mesh->AddNodeWithID( node->X(),node->Y(),node->Z(), node->GetID() );
11538   }
11539 }
11540 //================================================================================
11541 /*!
11542  * \brief Creates missing boundary elements
11543  *  \param elements - elements whose boundary is to be checked
11544  *  \param dimension - defines type of boundary elements to create
11545  *  \param group - a group to store created boundary elements in
11546  *  \param targetMesh - a mesh to store created boundary elements in
11547  *  \param toCopyElements - if true, the checked elements will be copied into the targetMesh
11548  *  \param toCopyExistingBondary - if true, not only new but also pre-existing
11549  *                                boundary elements will be copied into the targetMesh
11550  *  \param toAddExistingBondary - if true, not only new but also pre-existing
11551  *                                boundary elements will be added into the new group
11552  *  \param aroundElements - if true, elements will be created on boundary of given
11553  *                          elements else, on boundary of the whole mesh. This
11554  *                          option works for 2D elements only.
11555  * \return nb of added boundary elements
11556  */
11557 //================================================================================
11558
11559 int SMESH_MeshEditor::MakeBoundaryMesh(const TIDSortedElemSet& elements,
11560                                        Bnd_Dimension           dimension,
11561                                        SMESH_Group*            group/*=0*/,
11562                                        SMESH_Mesh*             targetMesh/*=0*/,
11563                                        bool                    toCopyElements/*=false*/,
11564                                        bool                    toCopyExistingBondary/*=false*/,
11565                                        bool                    toAddExistingBondary/*= false*/,
11566                                        bool                    aroundElements/*= false*/)
11567 {
11568   SMDSAbs_ElementType missType = (dimension == BND_2DFROM3D) ? SMDSAbs_Face : SMDSAbs_Edge;
11569   SMDSAbs_ElementType elemType = (dimension == BND_1DFROM2D) ? SMDSAbs_Face : SMDSAbs_Volume;
11570   // hope that all elements are of the same type, do not check them all
11571   if ( !elements.empty() && (*elements.begin())->GetType() != elemType )
11572     throw SALOME_Exception(LOCALIZED("wrong element type"));
11573
11574   if ( aroundElements && elemType == SMDSAbs_Volume )
11575     throw SALOME_Exception(LOCALIZED("wrong element type for aroundElements==true"));
11576
11577   if ( !targetMesh )
11578     toCopyElements = toCopyExistingBondary = false;
11579
11580   SMESH_MeshEditor tgtEditor( targetMesh ? targetMesh : myMesh );
11581   SMESHDS_Mesh* aMesh = GetMeshDS(), *tgtMeshDS = tgtEditor.GetMeshDS();
11582   int nbAddedBnd = 0;
11583
11584   // editor adding present bnd elements and optionally holding elements to add to the group
11585   SMESH_MeshEditor* presentEditor;
11586   SMESH_MeshEditor tgtEditor2( tgtEditor.GetMesh() );
11587   presentEditor = toAddExistingBondary ? &tgtEditor : &tgtEditor2;
11588
11589   SMDS_VolumeTool vTool;
11590   TIDSortedElemSet avoidSet;
11591   const TIDSortedElemSet emptySet, *elemSet = aroundElements ? &elements : &emptySet;
11592   int inode;
11593
11594   typedef vector<const SMDS_MeshNode*> TConnectivity;
11595
11596   SMDS_ElemIteratorPtr eIt;
11597   if (elements.empty())
11598     eIt = aMesh->elementsIterator(elemType);
11599   else
11600     eIt = SMDS_ElemIteratorPtr( new TSetIterator( elements.begin(), elements.end() ));
11601
11602   while (eIt->more())
11603   {
11604     const SMDS_MeshElement* elem = eIt->next();
11605     const int iQuad = elem->IsQuadratic();
11606
11607     // ------------------------------------------------------------------------------------
11608     // 1. For an elem, get present bnd elements and connectivities of missing bnd elements
11609     // ------------------------------------------------------------------------------------
11610     vector<const SMDS_MeshElement*> presentBndElems;
11611     vector<TConnectivity>           missingBndElems;
11612     TConnectivity nodes;
11613     if ( vTool.Set(elem) ) // elem is a volume ------------------------------------------
11614     {
11615       vTool.SetExternalNormal();
11616       for ( int iface = 0, n = vTool.NbFaces(); iface < n; iface++ )
11617       {
11618         if (!vTool.IsFreeFace(iface))
11619           continue;
11620         int nbFaceNodes = vTool.NbFaceNodes(iface);
11621         const SMDS_MeshNode** nn = vTool.GetFaceNodes(iface);
11622         if ( missType == SMDSAbs_Edge ) // boundary edges
11623         {
11624           nodes.resize( 2+iQuad );
11625           for ( int i = 0; i < nbFaceNodes; i += 1+iQuad)
11626           {
11627             for ( int j = 0; j < nodes.size(); ++j )
11628               nodes[j] =nn[i+j];
11629             if ( const SMDS_MeshElement* edge =
11630                  aMesh->FindElement(nodes,SMDSAbs_Edge,/*noMedium=*/0))
11631               presentBndElems.push_back( edge );
11632             else
11633               missingBndElems.push_back( nodes );
11634           }
11635         }
11636         else // boundary face
11637         {
11638           nodes.clear();
11639           for ( inode = 0; inode < nbFaceNodes; inode += 1+iQuad)
11640             nodes.push_back( nn[inode] );
11641           if (iQuad)
11642             for ( inode = 1; inode < nbFaceNodes; inode += 2)
11643               nodes.push_back( nn[inode] );
11644
11645           if (const SMDS_MeshFace * f = aMesh->FindFace( nodes ) )
11646             presentBndElems.push_back( f );
11647           else
11648             missingBndElems.push_back( nodes );
11649         }
11650       }
11651     }
11652     else                     // elem is a face ------------------------------------------
11653     {
11654       avoidSet.clear(), avoidSet.insert( elem );
11655       int nbNodes = elem->NbCornerNodes();
11656       nodes.resize( 2 /*+ iQuad*/);
11657       for ( int i = 0; i < nbNodes; i++ )
11658       {
11659         nodes[0] = elem->GetNode(i);
11660         nodes[1] = elem->GetNode((i+1)%nbNodes);
11661         if ( FindFaceInSet( nodes[0], nodes[1], *elemSet, avoidSet))
11662           continue; // not free link
11663
11664         //if ( iQuad )
11665         //nodes[2] = elem->GetNode( i + nbNodes );
11666         if ( const SMDS_MeshElement* edge =
11667              aMesh->FindElement(nodes,SMDSAbs_Edge,/*noMedium=*/true))
11668           presentBndElems.push_back( edge );
11669         else
11670           missingBndElems.push_back( nodes );
11671       }
11672     }
11673
11674     // ---------------------------------
11675     // 2. Add missing boundary elements
11676     // ---------------------------------
11677     if ( targetMesh != myMesh )
11678       // instead of making a map of nodes in this mesh and targetMesh,
11679       // we create nodes with same IDs. We can renumber them later, if needed
11680       for ( int i = 0; i < missingBndElems.size(); ++i )
11681       {
11682         TConnectivity& srcNodes = missingBndElems[i];
11683         TConnectivity  nodes( srcNodes.size() );
11684         for ( inode = 0; inode < nodes.size(); ++inode )
11685           nodes[inode] = getNodeWithSameID( tgtMeshDS, srcNodes[inode] );
11686         if ( aroundElements && tgtEditor.GetMeshDS()->FindElement( nodes,
11687                                                                    missType,
11688                                                                    /*noMedium=*/true))
11689           continue;
11690         tgtEditor.AddElement(nodes, missType, elem->IsPoly() && nodes.size()/(iQuad+1)>4);
11691         ++nbAddedBnd;
11692       }
11693     else
11694       for ( int i = 0; i < missingBndElems.size(); ++i )
11695       {
11696         TConnectivity& nodes = missingBndElems[i];
11697         if ( aroundElements && tgtEditor.GetMeshDS()->FindElement( nodes,
11698                                                                    missType,
11699                                                                    /*noMedium=*/true))
11700           continue;
11701         tgtEditor.AddElement(nodes, missType, elem->IsPoly() && nodes.size()/(iQuad+1)>4);
11702         ++nbAddedBnd;
11703       }
11704
11705     // ----------------------------------
11706     // 3. Copy present boundary elements
11707     // ----------------------------------
11708     if ( toCopyExistingBondary )
11709       for ( int i = 0 ; i < presentBndElems.size(); ++i )
11710       {
11711         const SMDS_MeshElement* e = presentBndElems[i];
11712         TConnectivity nodes( e->NbNodes() );
11713         for ( inode = 0; inode < nodes.size(); ++inode )
11714           nodes[inode] = getNodeWithSameID( tgtMeshDS, e->GetNode(inode) );
11715         presentEditor->AddElement(nodes, missType, e->IsPoly());
11716       }
11717     else // store present elements to add them to a group
11718       for ( int i = 0 ; i < presentBndElems.size(); ++i )
11719       {
11720         presentEditor->myLastCreatedElems.Append(presentBndElems[i]);
11721       }
11722       
11723   } // loop on given elements
11724
11725   // ---------------------------------------------
11726   // 4. Fill group with boundary elements
11727   // ---------------------------------------------
11728   if ( group )
11729   {
11730     if ( SMESHDS_Group* g = dynamic_cast<SMESHDS_Group*>( group->GetGroupDS() ))
11731       for ( int i = 0; i < tgtEditor.myLastCreatedElems.Size(); ++i )
11732         g->SMDSGroup().Add( tgtEditor.myLastCreatedElems( i+1 ));
11733   }
11734   tgtEditor.myLastCreatedElems.Clear();
11735   tgtEditor2.myLastCreatedElems.Clear();
11736
11737   // -----------------------
11738   // 5. Copy given elements
11739   // -----------------------
11740   if ( toCopyElements && targetMesh != myMesh )
11741   {
11742     if (elements.empty())
11743       eIt = aMesh->elementsIterator(elemType);
11744     else
11745       eIt = SMDS_ElemIteratorPtr( new TSetIterator( elements.begin(), elements.end() ));
11746     while (eIt->more())
11747     {
11748       const SMDS_MeshElement* elem = eIt->next();
11749       TConnectivity nodes( elem->NbNodes() );
11750       for ( inode = 0; inode < nodes.size(); ++inode )
11751         nodes[inode] = getNodeWithSameID( tgtMeshDS, elem->GetNode(inode) );
11752       tgtEditor.AddElement(nodes, elemType, elem->IsPoly());
11753
11754       tgtEditor.myLastCreatedElems.Clear();
11755     }
11756   }
11757   return nbAddedBnd;
11758 }