Salome HOME
Merge from V6_3_BR 06/06/2011
[modules/smesh.git] / src / SMESH / SMESH_MeshEditor.cxx
1 // Copyright (C) 2007-2011  CEA/DEN, EDF R&D, OPEN CASCADE
2 //
3 // Copyright (C) 2003-2007  OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN,
4 // CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS
5 //
6 // This library is free software; you can redistribute it and/or
7 // modify it under the terms of the GNU Lesser General Public
8 // License as published by the Free Software Foundation; either
9 // version 2.1 of the License.
10 //
11 // This library is distributed in the hope that it will be useful,
12 // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14 // Lesser General Public License for more details.
15 //
16 // You should have received a copy of the GNU Lesser General Public
17 // License along with this library; if not, write to the Free Software
18 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
19 //
20 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
21 //
22
23 //  SMESH SMESH : idl implementation based on 'SMESH' unit's classes
24 // File      : SMESH_MeshEditor.cxx
25 // Created   : Mon Apr 12 16:10:22 2004
26 // Author    : Edward AGAPOV (eap)
27 //
28 #define CHRONODEF
29 #include "SMESH_MeshEditor.hxx"
30
31 #include "SMDS_FaceOfNodes.hxx"
32 #include "SMDS_VolumeTool.hxx"
33 #include "SMDS_EdgePosition.hxx"
34 #include "SMDS_PolyhedralVolumeOfNodes.hxx"
35 #include "SMDS_FacePosition.hxx"
36 #include "SMDS_SpacePosition.hxx"
37 //#include "SMDS_QuadraticFaceOfNodes.hxx"
38 #include "SMDS_MeshGroup.hxx"
39 #include "SMDS_LinearEdge.hxx"
40 #include "SMDS_Downward.hxx"
41 #include "SMDS_SetIterator.hxx"
42
43 #include "SMESHDS_Group.hxx"
44 #include "SMESHDS_Mesh.hxx"
45
46 #include "SMESH_Algo.hxx"
47 #include "SMESH_ControlsDef.hxx"
48 #include "SMESH_Group.hxx"
49 #include "SMESH_MesherHelper.hxx"
50 #include "SMESH_OctreeNode.hxx"
51 #include "SMESH_subMesh.hxx"
52
53 #include "utilities.h"
54
55 #include <BRepAdaptor_Surface.hxx>
56 #include <BRepClass3d_SolidClassifier.hxx>
57 #include <BRep_Tool.hxx>
58 #include <ElCLib.hxx>
59 #include <Extrema_GenExtPS.hxx>
60 #include <Extrema_POnCurv.hxx>
61 #include <Extrema_POnSurf.hxx>
62 #include <GC_MakeSegment.hxx>
63 #include <Geom2d_Curve.hxx>
64 #include <GeomAPI_ExtremaCurveCurve.hxx>
65 #include <GeomAdaptor_Surface.hxx>
66 #include <Geom_Curve.hxx>
67 #include <Geom_Line.hxx>
68 #include <Geom_Surface.hxx>
69 #include <IntAna_IntConicQuad.hxx>
70 #include <IntAna_Quadric.hxx>
71 #include <Precision.hxx>
72 #include <TColStd_ListOfInteger.hxx>
73 #include <TopAbs_State.hxx>
74 #include <TopExp.hxx>
75 #include <TopExp_Explorer.hxx>
76 #include <TopTools_ListIteratorOfListOfShape.hxx>
77 #include <TopTools_ListOfShape.hxx>
78 #include <TopTools_SequenceOfShape.hxx>
79 #include <TopoDS.hxx>
80 #include <TopoDS_Face.hxx>
81 #include <gp.hxx>
82 #include <gp_Ax1.hxx>
83 #include <gp_Dir.hxx>
84 #include <gp_Lin.hxx>
85 #include <gp_Pln.hxx>
86 #include <gp_Trsf.hxx>
87 #include <gp_Vec.hxx>
88 #include <gp_XY.hxx>
89 #include <gp_XYZ.hxx>
90
91 #include <math.h>
92
93 #include <map>
94 #include <set>
95 #include <numeric>
96 #include <limits>
97 #include <algorithm>
98 #include <sstream>
99
100 #define cast2Node(elem) static_cast<const SMDS_MeshNode*>( elem )
101
102 using namespace std;
103 using namespace SMESH::Controls;
104
105 typedef map<const SMDS_MeshElement*, list<const SMDS_MeshNode*> >    TElemOfNodeListMap;
106 typedef map<const SMDS_MeshElement*, list<const SMDS_MeshElement*> > TElemOfElemListMap;
107
108 typedef SMDS_SetIterator< SMDS_pElement, TIDSortedElemSet::const_iterator> TSetIterator;
109
110 //=======================================================================
111 //function : SMESH_MeshEditor
112 //purpose  :
113 //=======================================================================
114
115 SMESH_MeshEditor::SMESH_MeshEditor( SMESH_Mesh* theMesh )
116   :myMesh( theMesh ) // theMesh may be NULL
117 {
118 }
119
120 //=======================================================================
121 /*!
122  * \brief Add element
123  */
124 //=======================================================================
125
126 SMDS_MeshElement*
127 SMESH_MeshEditor::AddElement(const vector<const SMDS_MeshNode*> & node,
128                              const SMDSAbs_ElementType            type,
129                              const bool                           isPoly,
130                              const int                            ID)
131 {
132   //MESSAGE("AddElement " <<node.size() << " " << type << " " << isPoly << " " << ID);
133   SMDS_MeshElement* e = 0;
134   int nbnode = node.size();
135   SMESHDS_Mesh* mesh = GetMeshDS();
136   switch ( type ) {
137   case SMDSAbs_Face:
138     if ( !isPoly ) {
139       if      (nbnode == 3) {
140         if ( ID >= 1 ) e = mesh->AddFaceWithID(node[0], node[1], node[2], ID);
141         else           e = mesh->AddFace      (node[0], node[1], node[2] );
142       }
143       else if (nbnode == 4) {
144         if ( ID >= 1 ) e = mesh->AddFaceWithID(node[0], node[1], node[2], node[3], ID);
145         else           e = mesh->AddFace      (node[0], node[1], node[2], node[3] );
146       }
147       else if (nbnode == 6) {
148         if ( ID >= 1 ) e = mesh->AddFaceWithID(node[0], node[1], node[2], node[3],
149                                                node[4], node[5], ID);
150         else           e = mesh->AddFace      (node[0], node[1], node[2], node[3],
151                                                node[4], node[5] );
152       }
153       else if (nbnode == 8) {
154         if ( ID >= 1 ) e = mesh->AddFaceWithID(node[0], node[1], node[2], node[3],
155                                                node[4], node[5], node[6], node[7], ID);
156         else           e = mesh->AddFace      (node[0], node[1], node[2], node[3],
157                                                node[4], node[5], node[6], node[7] );
158       }
159     } else {
160       if ( ID >= 1 ) e = mesh->AddPolygonalFaceWithID(node, ID);
161       else           e = mesh->AddPolygonalFace      (node    );
162     }
163     break;
164
165   case SMDSAbs_Volume:
166     if ( !isPoly ) {
167       if      (nbnode == 4) {
168         if ( ID >= 1 ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3], ID);
169         else           e = mesh->AddVolume      (node[0], node[1], node[2], node[3] );
170       }
171       else if (nbnode == 5) {
172         if ( ID >= 1 ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
173                                                  node[4], ID);
174         else           e = mesh->AddVolume      (node[0], node[1], node[2], node[3],
175                                                  node[4] );
176       }
177       else if (nbnode == 6) {
178         if ( ID >= 1 ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
179                                                  node[4], node[5], ID);
180         else           e = mesh->AddVolume      (node[0], node[1], node[2], node[3],
181                                                  node[4], node[5] );
182       }
183       else if (nbnode == 8) {
184         if ( ID >= 1 ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
185                                                  node[4], node[5], node[6], node[7], ID);
186         else           e = mesh->AddVolume      (node[0], node[1], node[2], node[3],
187                                                  node[4], node[5], node[6], node[7] );
188       }
189       else if (nbnode == 10) {
190         if ( ID >= 1 ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
191                                                  node[4], node[5], node[6], node[7],
192                                                  node[8], node[9], ID);
193         else           e = mesh->AddVolume      (node[0], node[1], node[2], node[3],
194                                                  node[4], node[5], node[6], node[7],
195                                                  node[8], node[9] );
196       }
197       else if (nbnode == 13) {
198         if ( ID >= 1 ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
199                                                  node[4], node[5], node[6], node[7],
200                                                  node[8], node[9], node[10],node[11],
201                                                  node[12],ID);
202         else           e = mesh->AddVolume      (node[0], node[1], node[2], node[3],
203                                                  node[4], node[5], node[6], node[7],
204                                                  node[8], node[9], node[10],node[11],
205                                                  node[12] );
206       }
207       else if (nbnode == 15) {
208         if ( ID >= 1 ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
209                                                  node[4], node[5], node[6], node[7],
210                                                  node[8], node[9], node[10],node[11],
211                                                  node[12],node[13],node[14],ID);
212         else           e = mesh->AddVolume      (node[0], node[1], node[2], node[3],
213                                                  node[4], node[5], node[6], node[7],
214                                                  node[8], node[9], node[10],node[11],
215                                                  node[12],node[13],node[14] );
216       }
217       else if (nbnode == 20) {
218         if ( ID >= 1 ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
219                                                  node[4], node[5], node[6], node[7],
220                                                  node[8], node[9], node[10],node[11],
221                                                  node[12],node[13],node[14],node[15],
222                                                  node[16],node[17],node[18],node[19],ID);
223         else           e = mesh->AddVolume      (node[0], node[1], node[2], node[3],
224                                                  node[4], node[5], node[6], node[7],
225                                                  node[8], node[9], node[10],node[11],
226                                                  node[12],node[13],node[14],node[15],
227                                                  node[16],node[17],node[18],node[19] );
228       }
229     }
230     break;
231
232   case SMDSAbs_Edge:
233     if ( nbnode == 2 ) {
234       if ( ID >= 1 ) e = mesh->AddEdgeWithID(node[0], node[1], ID);
235       else           e = mesh->AddEdge      (node[0], node[1] );
236     }
237     else if ( nbnode == 3 ) {
238       if ( ID >= 1 ) e = mesh->AddEdgeWithID(node[0], node[1], node[2], ID);
239       else           e = mesh->AddEdge      (node[0], node[1], node[2] );
240     }
241     break;
242
243   case SMDSAbs_0DElement:
244     if ( nbnode == 1 ) {
245       if ( ID >= 1 ) e = mesh->Add0DElementWithID(node[0], ID);
246       else           e = mesh->Add0DElement      (node[0] );
247     }
248     break;
249
250   case SMDSAbs_Node:
251     if ( ID >= 1 ) e = mesh->AddNodeWithID(node[0]->X(), node[0]->Y(), node[0]->Z(), ID);
252     else           e = mesh->AddNode      (node[0]->X(), node[0]->Y(), node[0]->Z());
253     break;
254
255   default:;
256   }
257   if ( e ) myLastCreatedElems.Append( e );
258   return e;
259 }
260
261 //=======================================================================
262 /*!
263  * \brief Add element
264  */
265 //=======================================================================
266
267 SMDS_MeshElement* SMESH_MeshEditor::AddElement(const vector<int> &       nodeIDs,
268                                                const SMDSAbs_ElementType type,
269                                                const bool                isPoly,
270                                                const int                 ID)
271 {
272   vector<const SMDS_MeshNode*> nodes;
273   nodes.reserve( nodeIDs.size() );
274   vector<int>::const_iterator id = nodeIDs.begin();
275   while ( id != nodeIDs.end() ) {
276     if ( const SMDS_MeshNode* node = GetMeshDS()->FindNode( *id++ ))
277       nodes.push_back( node );
278     else
279       return 0;
280   }
281   return AddElement( nodes, type, isPoly, ID );
282 }
283
284 //=======================================================================
285 //function : Remove
286 //purpose  : Remove a node or an element.
287 //           Modify a compute state of sub-meshes which become empty
288 //=======================================================================
289
290 int SMESH_MeshEditor::Remove (const list< int >& theIDs,
291                               const bool         isNodes )
292 {
293   myLastCreatedElems.Clear();
294   myLastCreatedNodes.Clear();
295
296   SMESHDS_Mesh* aMesh = GetMeshDS();
297   set< SMESH_subMesh *> smmap;
298
299   int removed = 0;
300   list<int>::const_iterator it = theIDs.begin();
301   for ( ; it != theIDs.end(); it++ ) {
302     const SMDS_MeshElement * elem;
303     if ( isNodes )
304       elem = aMesh->FindNode( *it );
305     else
306       elem = aMesh->FindElement( *it );
307     if ( !elem )
308       continue;
309
310     // Notify VERTEX sub-meshes about modification
311     if ( isNodes ) {
312       const SMDS_MeshNode* node = cast2Node( elem );
313       if ( node->GetPosition()->GetTypeOfPosition() == SMDS_TOP_VERTEX )
314         if ( int aShapeID = node->getshapeId() )
315           if ( SMESH_subMesh * sm = GetMesh()->GetSubMeshContaining( aShapeID ) )
316             smmap.insert( sm );
317     }
318     // Find sub-meshes to notify about modification
319     //     SMDS_ElemIteratorPtr nodeIt = elem->nodesIterator();
320     //     while ( nodeIt->more() ) {
321     //       const SMDS_MeshNode* node = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
322     //       const SMDS_PositionPtr& aPosition = node->GetPosition();
323     //       if ( aPosition.get() ) {
324     //         if ( int aShapeID = aPosition->GetShapeId() ) {
325     //           if ( SMESH_subMesh * sm = GetMesh()->GetSubMeshContaining( aShapeID ) )
326     //             smmap.insert( sm );
327     //         }
328     //       }
329     //     }
330
331     // Do remove
332     if ( isNodes )
333       aMesh->RemoveNode( static_cast< const SMDS_MeshNode* >( elem ));
334     else
335       aMesh->RemoveElement( elem );
336     removed++;
337   }
338
339   // Notify sub-meshes about modification
340   if ( !smmap.empty() ) {
341     set< SMESH_subMesh *>::iterator smIt;
342     for ( smIt = smmap.begin(); smIt != smmap.end(); smIt++ )
343       (*smIt)->ComputeStateEngine( SMESH_subMesh::MESH_ENTITY_REMOVED );
344   }
345
346   //   // Check if the whole mesh becomes empty
347   //   if ( SMESH_subMesh * sm = GetMesh()->GetSubMeshContaining( 1 ) )
348   //     sm->ComputeStateEngine( SMESH_subMesh::CHECK_COMPUTE_STATE );
349
350   return removed;
351 }
352
353 //=======================================================================
354 //function : FindShape
355 //purpose  : Return an index of the shape theElem is on
356 //           or zero if a shape not found
357 //=======================================================================
358
359 int SMESH_MeshEditor::FindShape (const SMDS_MeshElement * theElem)
360 {
361   myLastCreatedElems.Clear();
362   myLastCreatedNodes.Clear();
363
364   SMESHDS_Mesh * aMesh = GetMeshDS();
365   if ( aMesh->ShapeToMesh().IsNull() )
366     return 0;
367
368   int aShapeID = theElem->getshapeId();
369   if ( aShapeID < 1 )
370     return 0;
371
372   if ( SMESHDS_SubMesh * sm = aMesh->MeshElements( aShapeID ))
373     if ( sm->Contains( theElem ))
374       return aShapeID;
375
376   if ( theElem->GetType() == SMDSAbs_Node ) {
377     MESSAGE( ":( Error: invalid myShapeId of node " << theElem->GetID() );
378   }
379   else {
380     MESSAGE( ":( Error: invalid myShapeId of element " << theElem->GetID() );
381   }
382
383   TopoDS_Shape aShape; // the shape a node of theElem is on
384   if ( theElem->GetType() != SMDSAbs_Node )
385   {
386     SMDS_ElemIteratorPtr nodeIt = theElem->nodesIterator();
387     while ( nodeIt->more() ) {
388       const SMDS_MeshNode* node = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
389       if ((aShapeID = node->getshapeId()) > 0) {
390         if ( SMESHDS_SubMesh * sm = aMesh->MeshElements( aShapeID ) ) {
391           if ( sm->Contains( theElem ))
392             return aShapeID;
393           if ( aShape.IsNull() )
394             aShape = aMesh->IndexToShape( aShapeID );
395         }
396       }
397     }
398   }
399
400   // None of nodes is on a proper shape,
401   // find the shape among ancestors of aShape on which a node is
402   if ( !aShape.IsNull() ) {
403     TopTools_ListIteratorOfListOfShape ancIt( GetMesh()->GetAncestors( aShape ));
404     for ( ; ancIt.More(); ancIt.Next() ) {
405       SMESHDS_SubMesh * sm = aMesh->MeshElements( ancIt.Value() );
406       if ( sm && sm->Contains( theElem ))
407         return aMesh->ShapeToIndex( ancIt.Value() );
408     }
409   }
410   else
411   {
412     const map<int,SMESHDS_SubMesh*>& id2sm = GetMeshDS()->SubMeshes();
413     map<int,SMESHDS_SubMesh*>::const_iterator id_sm = id2sm.begin();
414     for ( ; id_sm != id2sm.end(); ++id_sm )
415       if ( id_sm->second->Contains( theElem ))
416         return id_sm->first;
417   }
418
419   //MESSAGE ("::FindShape() - SHAPE NOT FOUND")
420   return 0;
421 }
422
423 //=======================================================================
424 //function : IsMedium
425 //purpose  :
426 //=======================================================================
427
428 bool SMESH_MeshEditor::IsMedium(const SMDS_MeshNode*      node,
429                                 const SMDSAbs_ElementType typeToCheck)
430 {
431   bool isMedium = false;
432   SMDS_ElemIteratorPtr it = node->GetInverseElementIterator(typeToCheck);
433   while (it->more() && !isMedium ) {
434     const SMDS_MeshElement* elem = it->next();
435     isMedium = elem->IsMediumNode(node);
436   }
437   return isMedium;
438 }
439
440 //=======================================================================
441 //function : ShiftNodesQuadTria
442 //purpose  : auxilary
443 //           Shift nodes in the array corresponded to quadratic triangle
444 //           example: (0,1,2,3,4,5) -> (1,2,0,4,5,3)
445 //=======================================================================
446 static void ShiftNodesQuadTria(const SMDS_MeshNode* aNodes[])
447 {
448   const SMDS_MeshNode* nd1 = aNodes[0];
449   aNodes[0] = aNodes[1];
450   aNodes[1] = aNodes[2];
451   aNodes[2] = nd1;
452   const SMDS_MeshNode* nd2 = aNodes[3];
453   aNodes[3] = aNodes[4];
454   aNodes[4] = aNodes[5];
455   aNodes[5] = nd2;
456 }
457
458 //=======================================================================
459 //function : GetNodesFromTwoTria
460 //purpose  : auxilary
461 //           Shift nodes in the array corresponded to quadratic triangle
462 //           example: (0,1,2,3,4,5) -> (1,2,0,4,5,3)
463 //=======================================================================
464 static bool GetNodesFromTwoTria(const SMDS_MeshElement * theTria1,
465                                 const SMDS_MeshElement * theTria2,
466                                 const SMDS_MeshNode* N1[],
467                                 const SMDS_MeshNode* N2[])
468 {
469   SMDS_ElemIteratorPtr it = theTria1->nodesIterator();
470   int i=0;
471   while(i<6) {
472     N1[i] = static_cast<const SMDS_MeshNode*>( it->next() );
473     i++;
474   }
475   if(it->more()) return false;
476   it = theTria2->nodesIterator();
477   i=0;
478   while(i<6) {
479     N2[i] = static_cast<const SMDS_MeshNode*>( it->next() );
480     i++;
481   }
482   if(it->more()) return false;
483
484   int sames[3] = {-1,-1,-1};
485   int nbsames = 0;
486   int j;
487   for(i=0; i<3; i++) {
488     for(j=0; j<3; j++) {
489       if(N1[i]==N2[j]) {
490         sames[i] = j;
491         nbsames++;
492         break;
493       }
494     }
495   }
496   if(nbsames!=2) return false;
497   if(sames[0]>-1) {
498     ShiftNodesQuadTria(N1);
499     if(sames[1]>-1) {
500       ShiftNodesQuadTria(N1);
501     }
502   }
503   i = sames[0] + sames[1] + sames[2];
504   for(; i<2; i++) {
505     ShiftNodesQuadTria(N2);
506   }
507   // now we receive following N1 and N2 (using numeration as above image)
508   // tria1 : (1 2 4 5 9 7)  and  tria2 : (3 4 2 8 9 6)
509   // i.e. first nodes from both arrays determ new diagonal
510   return true;
511 }
512
513 //=======================================================================
514 //function : InverseDiag
515 //purpose  : Replace two neighbour triangles with ones built on the same 4 nodes
516 //           but having other common link.
517 //           Return False if args are improper
518 //=======================================================================
519
520 bool SMESH_MeshEditor::InverseDiag (const SMDS_MeshElement * theTria1,
521                                     const SMDS_MeshElement * theTria2 )
522 {
523   MESSAGE("InverseDiag");
524   myLastCreatedElems.Clear();
525   myLastCreatedNodes.Clear();
526
527   if (!theTria1 || !theTria2)
528     return false;
529
530   const SMDS_VtkFace* F1 = dynamic_cast<const SMDS_VtkFace*>( theTria1 );
531   if (!F1) return false;
532   const SMDS_VtkFace* F2 = dynamic_cast<const SMDS_VtkFace*>( theTria2 );
533   if (!F2) return false;
534   if ((theTria1->GetEntityType() == SMDSEntity_Triangle) &&
535       (theTria2->GetEntityType() == SMDSEntity_Triangle)) {
536
537     //  1 +--+ A  theTria1: ( 1 A B ) A->2 ( 1 2 B ) 1 +--+ A
538     //    | /|    theTria2: ( B A 2 ) B->1 ( 1 A 2 )   |\ |
539     //    |/ |                                         | \|
540     //  B +--+ 2                                     B +--+ 2
541
542     // put nodes in array and find out indices of the same ones
543     const SMDS_MeshNode* aNodes [6];
544     int sameInd [] = { 0, 0, 0, 0, 0, 0 };
545     int i = 0;
546     SMDS_ElemIteratorPtr it = theTria1->nodesIterator();
547     while ( it->more() ) {
548       aNodes[ i ] = static_cast<const SMDS_MeshNode*>( it->next() );
549
550       if ( i > 2 ) // theTria2
551         // find same node of theTria1
552         for ( int j = 0; j < 3; j++ )
553           if ( aNodes[ i ] == aNodes[ j ]) {
554             sameInd[ j ] = i;
555             sameInd[ i ] = j;
556             break;
557           }
558       // next
559       i++;
560       if ( i == 3 ) {
561         if ( it->more() )
562           return false; // theTria1 is not a triangle
563         it = theTria2->nodesIterator();
564       }
565       if ( i == 6 && it->more() )
566         return false; // theTria2 is not a triangle
567     }
568
569     // find indices of 1,2 and of A,B in theTria1
570     int iA = 0, iB = 0, i1 = 0, i2 = 0;
571     for ( i = 0; i < 6; i++ ) {
572       if ( sameInd [ i ] == 0 ) {
573         if ( i < 3 ) i1 = i;
574         else         i2 = i;
575       }
576       else if (i < 3) {
577         if ( iA ) iB = i;
578         else      iA = i;
579       }
580     }
581     // nodes 1 and 2 should not be the same
582     if ( aNodes[ i1 ] == aNodes[ i2 ] )
583       return false;
584
585     // theTria1: A->2
586     aNodes[ iA ] = aNodes[ i2 ];
587     // theTria2: B->1
588     aNodes[ sameInd[ iB ]] = aNodes[ i1 ];
589
590     GetMeshDS()->ChangeElementNodes( theTria1, aNodes, 3 );
591     GetMeshDS()->ChangeElementNodes( theTria2, &aNodes[ 3 ], 3 );
592
593     return true;
594
595   } // end if(F1 && F2)
596
597   // check case of quadratic faces
598   if (theTria1->GetEntityType() != SMDSEntity_Quad_Triangle)
599     return false;
600   if (theTria2->GetEntityType() != SMDSEntity_Quad_Triangle)
601     return false;
602
603   //       5
604   //  1 +--+--+ 2  theTria1: (1 2 4 5 9 7) or (2 4 1 9 7 5) or (4 1 2 7 5 9)
605   //    |    /|    theTria2: (2 3 4 6 8 9) or (3 4 2 8 9 6) or (4 2 3 9 6 8)
606   //    |   / |
607   //  7 +  +  + 6
608   //    | /9  |
609   //    |/    |
610   //  4 +--+--+ 3
611   //       8
612
613   const SMDS_MeshNode* N1 [6];
614   const SMDS_MeshNode* N2 [6];
615   if(!GetNodesFromTwoTria(theTria1,theTria2,N1,N2))
616     return false;
617   // now we receive following N1 and N2 (using numeration as above image)
618   // tria1 : (1 2 4 5 9 7)  and  tria2 : (3 4 2 8 9 6)
619   // i.e. first nodes from both arrays determ new diagonal
620
621   const SMDS_MeshNode* N1new [6];
622   const SMDS_MeshNode* N2new [6];
623   N1new[0] = N1[0];
624   N1new[1] = N2[0];
625   N1new[2] = N2[1];
626   N1new[3] = N1[4];
627   N1new[4] = N2[3];
628   N1new[5] = N1[5];
629   N2new[0] = N1[0];
630   N2new[1] = N1[1];
631   N2new[2] = N2[0];
632   N2new[3] = N1[3];
633   N2new[4] = N2[5];
634   N2new[5] = N1[4];
635   // replaces nodes in faces
636   GetMeshDS()->ChangeElementNodes( theTria1, N1new, 6 );
637   GetMeshDS()->ChangeElementNodes( theTria2, N2new, 6 );
638
639   return true;
640 }
641
642 //=======================================================================
643 //function : findTriangles
644 //purpose  : find triangles sharing theNode1-theNode2 link
645 //=======================================================================
646
647 static bool findTriangles(const SMDS_MeshNode *    theNode1,
648                           const SMDS_MeshNode *    theNode2,
649                           const SMDS_MeshElement*& theTria1,
650                           const SMDS_MeshElement*& theTria2)
651 {
652   if ( !theNode1 || !theNode2 ) return false;
653
654   theTria1 = theTria2 = 0;
655
656   set< const SMDS_MeshElement* > emap;
657   SMDS_ElemIteratorPtr it = theNode1->GetInverseElementIterator(SMDSAbs_Face);
658   while (it->more()) {
659     const SMDS_MeshElement* elem = it->next();
660     if ( elem->NbNodes() == 3 )
661       emap.insert( elem );
662   }
663   it = theNode2->GetInverseElementIterator(SMDSAbs_Face);
664   while (it->more()) {
665     const SMDS_MeshElement* elem = it->next();
666     if ( emap.find( elem ) != emap.end() ) {
667       if ( theTria1 ) {
668         // theTria1 must be element with minimum ID
669         if( theTria1->GetID() < elem->GetID() ) {
670           theTria2 = elem;
671         }
672         else {
673           theTria2 = theTria1;
674           theTria1 = elem;
675         }
676         break;
677       }
678       else {
679         theTria1 = elem;
680       }
681     }
682   }
683   return ( theTria1 && theTria2 );
684 }
685
686 //=======================================================================
687 //function : InverseDiag
688 //purpose  : Replace two neighbour triangles sharing theNode1-theNode2 link
689 //           with ones built on the same 4 nodes but having other common link.
690 //           Return false if proper faces not found
691 //=======================================================================
692
693 bool SMESH_MeshEditor::InverseDiag (const SMDS_MeshNode * theNode1,
694                                     const SMDS_MeshNode * theNode2)
695 {
696   myLastCreatedElems.Clear();
697   myLastCreatedNodes.Clear();
698
699   MESSAGE( "::InverseDiag()" );
700
701   const SMDS_MeshElement *tr1, *tr2;
702   if ( !findTriangles( theNode1, theNode2, tr1, tr2 ))
703     return false;
704
705   const SMDS_VtkFace* F1 = dynamic_cast<const SMDS_VtkFace*>( tr1 );
706   if (!F1) return false;
707   const SMDS_VtkFace* F2 = dynamic_cast<const SMDS_VtkFace*>( tr2 );
708   if (!F2) return false;
709   if ((tr1->GetEntityType() == SMDSEntity_Triangle) &&
710       (tr2->GetEntityType() == SMDSEntity_Triangle)) {
711
712     //  1 +--+ A  tr1: ( 1 A B ) A->2 ( 1 2 B ) 1 +--+ A
713     //    | /|    tr2: ( B A 2 ) B->1 ( 1 A 2 )   |\ |
714     //    |/ |                                    | \|
715     //  B +--+ 2                                B +--+ 2
716
717     // put nodes in array
718     // and find indices of 1,2 and of A in tr1 and of B in tr2
719     int i, iA1 = 0, i1 = 0;
720     const SMDS_MeshNode* aNodes1 [3];
721     SMDS_ElemIteratorPtr it;
722     for (i = 0, it = tr1->nodesIterator(); it->more(); i++ ) {
723       aNodes1[ i ] = static_cast<const SMDS_MeshNode*>( it->next() );
724       if ( aNodes1[ i ] == theNode1 )
725         iA1 = i; // node A in tr1
726       else if ( aNodes1[ i ] != theNode2 )
727         i1 = i;  // node 1
728     }
729     int iB2 = 0, i2 = 0;
730     const SMDS_MeshNode* aNodes2 [3];
731     for (i = 0, it = tr2->nodesIterator(); it->more(); i++ ) {
732       aNodes2[ i ] = static_cast<const SMDS_MeshNode*>( it->next() );
733       if ( aNodes2[ i ] == theNode2 )
734         iB2 = i; // node B in tr2
735       else if ( aNodes2[ i ] != theNode1 )
736         i2 = i;  // node 2
737     }
738
739     // nodes 1 and 2 should not be the same
740     if ( aNodes1[ i1 ] == aNodes2[ i2 ] )
741       return false;
742
743     // tr1: A->2
744     aNodes1[ iA1 ] = aNodes2[ i2 ];
745     // tr2: B->1
746     aNodes2[ iB2 ] = aNodes1[ i1 ];
747
748     GetMeshDS()->ChangeElementNodes( tr1, aNodes1, 3 );
749     GetMeshDS()->ChangeElementNodes( tr2, aNodes2, 3 );
750
751     return true;
752   }
753
754   // check case of quadratic faces
755   return InverseDiag(tr1,tr2);
756 }
757
758 //=======================================================================
759 //function : getQuadrangleNodes
760 //purpose  : fill theQuadNodes - nodes of a quadrangle resulting from
761 //           fusion of triangles tr1 and tr2 having shared link on
762 //           theNode1 and theNode2
763 //=======================================================================
764
765 bool getQuadrangleNodes(const SMDS_MeshNode *    theQuadNodes [],
766                         const SMDS_MeshNode *    theNode1,
767                         const SMDS_MeshNode *    theNode2,
768                         const SMDS_MeshElement * tr1,
769                         const SMDS_MeshElement * tr2 )
770 {
771   if( tr1->NbNodes() != tr2->NbNodes() )
772     return false;
773   // find the 4-th node to insert into tr1
774   const SMDS_MeshNode* n4 = 0;
775   SMDS_ElemIteratorPtr it = tr2->nodesIterator();
776   int i=0;
777   while ( !n4 && i<3 ) {
778     const SMDS_MeshNode * n = cast2Node( it->next() );
779     i++;
780     bool isDiag = ( n == theNode1 || n == theNode2 );
781     if ( !isDiag )
782       n4 = n;
783   }
784   // Make an array of nodes to be in a quadrangle
785   int iNode = 0, iFirstDiag = -1;
786   it = tr1->nodesIterator();
787   i=0;
788   while ( i<3 ) {
789     const SMDS_MeshNode * n = cast2Node( it->next() );
790     i++;
791     bool isDiag = ( n == theNode1 || n == theNode2 );
792     if ( isDiag ) {
793       if ( iFirstDiag < 0 )
794         iFirstDiag = iNode;
795       else if ( iNode - iFirstDiag == 1 )
796         theQuadNodes[ iNode++ ] = n4; // insert the 4-th node between diagonal nodes
797     }
798     else if ( n == n4 ) {
799       return false; // tr1 and tr2 should not have all the same nodes
800     }
801     theQuadNodes[ iNode++ ] = n;
802   }
803   if ( iNode == 3 ) // diagonal nodes have 0 and 2 indices
804     theQuadNodes[ iNode ] = n4;
805
806   return true;
807 }
808
809 //=======================================================================
810 //function : DeleteDiag
811 //purpose  : Replace two neighbour triangles sharing theNode1-theNode2 link
812 //           with a quadrangle built on the same 4 nodes.
813 //           Return false if proper faces not found
814 //=======================================================================
815
816 bool SMESH_MeshEditor::DeleteDiag (const SMDS_MeshNode * theNode1,
817                                    const SMDS_MeshNode * theNode2)
818 {
819   myLastCreatedElems.Clear();
820   myLastCreatedNodes.Clear();
821
822   MESSAGE( "::DeleteDiag()" );
823
824   const SMDS_MeshElement *tr1, *tr2;
825   if ( !findTriangles( theNode1, theNode2, tr1, tr2 ))
826     return false;
827
828   const SMDS_VtkFace* F1 = dynamic_cast<const SMDS_VtkFace*>( tr1 );
829   if (!F1) return false;
830   const SMDS_VtkFace* F2 = dynamic_cast<const SMDS_VtkFace*>( tr2 );
831   if (!F2) return false;
832   SMESHDS_Mesh * aMesh = GetMeshDS();
833
834   if ((tr1->GetEntityType() == SMDSEntity_Triangle) &&
835       (tr2->GetEntityType() == SMDSEntity_Triangle)) {
836
837     const SMDS_MeshNode* aNodes [ 4 ];
838     if ( ! getQuadrangleNodes( aNodes, theNode1, theNode2, tr1, tr2 ))
839       return false;
840
841     const SMDS_MeshElement* newElem = 0;
842     newElem = aMesh->AddFace( aNodes[0], aNodes[1], aNodes[2], aNodes[3] );
843     myLastCreatedElems.Append(newElem);
844     AddToSameGroups( newElem, tr1, aMesh );
845     int aShapeId = tr1->getshapeId();
846     if ( aShapeId )
847       {
848         aMesh->SetMeshElementOnShape( newElem, aShapeId );
849       }
850     aMesh->RemoveElement( tr1 );
851     aMesh->RemoveElement( tr2 );
852
853     return true;
854   }
855
856   // check case of quadratic faces
857   if (tr1->GetEntityType() != SMDSEntity_Quad_Triangle)
858     return false;
859   if (tr2->GetEntityType() != SMDSEntity_Quad_Triangle)
860     return false;
861
862   //       5
863   //  1 +--+--+ 2  tr1: (1 2 4 5 9 7) or (2 4 1 9 7 5) or (4 1 2 7 5 9)
864   //    |    /|    tr2: (2 3 4 6 8 9) or (3 4 2 8 9 6) or (4 2 3 9 6 8)
865   //    |   / |
866   //  7 +  +  + 6
867   //    | /9  |
868   //    |/    |
869   //  4 +--+--+ 3
870   //       8
871
872   const SMDS_MeshNode* N1 [6];
873   const SMDS_MeshNode* N2 [6];
874   if(!GetNodesFromTwoTria(tr1,tr2,N1,N2))
875     return false;
876   // now we receive following N1 and N2 (using numeration as above image)
877   // tria1 : (1 2 4 5 9 7)  and  tria2 : (3 4 2 8 9 6)
878   // i.e. first nodes from both arrays determ new diagonal
879
880   const SMDS_MeshNode* aNodes[8];
881   aNodes[0] = N1[0];
882   aNodes[1] = N1[1];
883   aNodes[2] = N2[0];
884   aNodes[3] = N2[1];
885   aNodes[4] = N1[3];
886   aNodes[5] = N2[5];
887   aNodes[6] = N2[3];
888   aNodes[7] = N1[5];
889
890   const SMDS_MeshElement* newElem = 0;
891   newElem = aMesh->AddFace( aNodes[0], aNodes[1], aNodes[2], aNodes[3],
892                             aNodes[4], aNodes[5], aNodes[6], aNodes[7]);
893   myLastCreatedElems.Append(newElem);
894   AddToSameGroups( newElem, tr1, aMesh );
895   int aShapeId = tr1->getshapeId();
896   if ( aShapeId )
897     {
898       aMesh->SetMeshElementOnShape( newElem, aShapeId );
899     }
900   aMesh->RemoveElement( tr1 );
901   aMesh->RemoveElement( tr2 );
902
903   // remove middle node (9)
904   GetMeshDS()->RemoveNode( N1[4] );
905
906   return true;
907 }
908
909 //=======================================================================
910 //function : Reorient
911 //purpose  : Reverse theElement orientation
912 //=======================================================================
913
914 bool SMESH_MeshEditor::Reorient (const SMDS_MeshElement * theElem)
915 {
916   MESSAGE("Reorient");
917   myLastCreatedElems.Clear();
918   myLastCreatedNodes.Clear();
919
920   if (!theElem)
921     return false;
922   SMDS_ElemIteratorPtr it = theElem->nodesIterator();
923   if ( !it || !it->more() )
924     return false;
925
926   switch ( theElem->GetType() ) {
927
928   case SMDSAbs_Edge:
929   case SMDSAbs_Face: {
930     if(!theElem->IsQuadratic()) {
931       int i = theElem->NbNodes();
932       vector<const SMDS_MeshNode*> aNodes( i );
933       while ( it->more() )
934         aNodes[ --i ]= static_cast<const SMDS_MeshNode*>( it->next() );
935       return GetMeshDS()->ChangeElementNodes( theElem, &aNodes[0], theElem->NbNodes() );
936     }
937     else {
938       // quadratic elements
939       if(theElem->GetType()==SMDSAbs_Edge) {
940         vector<const SMDS_MeshNode*> aNodes(3);
941         aNodes[1]= static_cast<const SMDS_MeshNode*>( it->next() );
942         aNodes[0]= static_cast<const SMDS_MeshNode*>( it->next() );
943         aNodes[2]= static_cast<const SMDS_MeshNode*>( it->next() );
944         return GetMeshDS()->ChangeElementNodes( theElem, &aNodes[0], 3 );
945       }
946       else {
947         int nbn = theElem->NbNodes();
948         vector<const SMDS_MeshNode*> aNodes(nbn);
949         aNodes[0]= static_cast<const SMDS_MeshNode*>( it->next() );
950         int i=1;
951         for(; i<nbn/2; i++) {
952           aNodes[nbn/2-i]= static_cast<const SMDS_MeshNode*>( it->next() );
953         }
954         for(i=0; i<nbn/2; i++) {
955           aNodes[nbn-i-1]= static_cast<const SMDS_MeshNode*>( it->next() );
956         }
957         return GetMeshDS()->ChangeElementNodes( theElem, &aNodes[0], nbn );
958       }
959     }
960   }
961   case SMDSAbs_Volume: {
962     if (theElem->IsPoly()) {
963       // TODO reorient vtk polyhedron
964       MESSAGE("reorient vtk polyhedron ?");
965       const SMDS_VtkVolume* aPolyedre =
966         dynamic_cast<const SMDS_VtkVolume*>( theElem );
967       if (!aPolyedre) {
968         MESSAGE("Warning: bad volumic element");
969         return false;
970       }
971
972       int nbFaces = aPolyedre->NbFaces();
973       vector<const SMDS_MeshNode *> poly_nodes;
974       vector<int> quantities (nbFaces);
975
976       // reverse each face of the polyedre
977       for (int iface = 1; iface <= nbFaces; iface++) {
978         int inode, nbFaceNodes = aPolyedre->NbFaceNodes(iface);
979         quantities[iface - 1] = nbFaceNodes;
980
981         for (inode = nbFaceNodes; inode >= 1; inode--) {
982           const SMDS_MeshNode* curNode = aPolyedre->GetFaceNode(iface, inode);
983           poly_nodes.push_back(curNode);
984         }
985       }
986
987       return GetMeshDS()->ChangePolyhedronNodes( theElem, poly_nodes, quantities );
988
989     }
990     else {
991       SMDS_VolumeTool vTool;
992       if ( !vTool.Set( theElem ))
993         return false;
994       vTool.Inverse();
995       MESSAGE("ChangeElementNodes reorient: check vTool.Inverse");
996       return GetMeshDS()->ChangeElementNodes( theElem, vTool.GetNodes(), vTool.NbNodes() );
997     }
998   }
999   default:;
1000   }
1001
1002   return false;
1003 }
1004
1005 //=======================================================================
1006 //function : getBadRate
1007 //purpose  :
1008 //=======================================================================
1009
1010 static double getBadRate (const SMDS_MeshElement*               theElem,
1011                           SMESH::Controls::NumericalFunctorPtr& theCrit)
1012 {
1013   SMESH::Controls::TSequenceOfXYZ P;
1014   if ( !theElem || !theCrit->GetPoints( theElem, P ))
1015     return 1e100;
1016   return theCrit->GetBadRate( theCrit->GetValue( P ), theElem->NbNodes() );
1017   //return theCrit->GetBadRate( theCrit->GetValue( theElem->GetID() ), theElem->NbNodes() );
1018 }
1019
1020 //=======================================================================
1021 //function : QuadToTri
1022 //purpose  : Cut quadrangles into triangles.
1023 //           theCrit is used to select a diagonal to cut
1024 //=======================================================================
1025
1026 bool SMESH_MeshEditor::QuadToTri (TIDSortedElemSet &                   theElems,
1027                                   SMESH::Controls::NumericalFunctorPtr theCrit)
1028 {
1029   myLastCreatedElems.Clear();
1030   myLastCreatedNodes.Clear();
1031
1032   MESSAGE( "::QuadToTri()" );
1033
1034   if ( !theCrit.get() )
1035     return false;
1036
1037   SMESHDS_Mesh * aMesh = GetMeshDS();
1038
1039   Handle(Geom_Surface) surface;
1040   SMESH_MesherHelper   helper( *GetMesh() );
1041
1042   TIDSortedElemSet::iterator itElem;
1043   for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
1044     const SMDS_MeshElement* elem = *itElem;
1045     if ( !elem || elem->GetType() != SMDSAbs_Face )
1046       continue;
1047     if ( elem->NbNodes() != ( elem->IsQuadratic() ? 8 : 4 ))
1048       continue;
1049
1050     // retrieve element nodes
1051     const SMDS_MeshNode* aNodes [8];
1052     SMDS_ElemIteratorPtr itN = elem->nodesIterator();
1053     int i = 0;
1054     while ( itN->more() )
1055       aNodes[ i++ ] = static_cast<const SMDS_MeshNode*>( itN->next() );
1056
1057     // compare two sets of possible triangles
1058     double aBadRate1, aBadRate2; // to what extent a set is bad
1059     SMDS_FaceOfNodes tr1 ( aNodes[0], aNodes[1], aNodes[2] );
1060     SMDS_FaceOfNodes tr2 ( aNodes[2], aNodes[3], aNodes[0] );
1061     aBadRate1 = getBadRate( &tr1, theCrit ) + getBadRate( &tr2, theCrit );
1062
1063     SMDS_FaceOfNodes tr3 ( aNodes[1], aNodes[2], aNodes[3] );
1064     SMDS_FaceOfNodes tr4 ( aNodes[3], aNodes[0], aNodes[1] );
1065     aBadRate2 = getBadRate( &tr3, theCrit ) + getBadRate( &tr4, theCrit );
1066
1067     int aShapeId = FindShape( elem );
1068     const SMDS_MeshElement* newElem1 = 0;
1069     const SMDS_MeshElement* newElem2 = 0;
1070
1071     if( !elem->IsQuadratic() ) {
1072
1073       // split liner quadrangle
1074       if ( aBadRate1 <= aBadRate2 ) {
1075         // tr1 + tr2 is better
1076         newElem1 = aMesh->AddFace( aNodes[2], aNodes[3], aNodes[0] );
1077         newElem2 = aMesh->AddFace( aNodes[2], aNodes[0], aNodes[1] );
1078       }
1079       else {
1080         // tr3 + tr4 is better
1081         newElem1 = aMesh->AddFace( aNodes[3], aNodes[0], aNodes[1] );
1082         newElem2 = aMesh->AddFace( aNodes[3], aNodes[1], aNodes[2] );
1083       }
1084     }
1085     else {
1086
1087       // split quadratic quadrangle
1088
1089       // get surface elem is on
1090       if ( aShapeId != helper.GetSubShapeID() ) {
1091         surface.Nullify();
1092         TopoDS_Shape shape;
1093         if ( aShapeId > 0 )
1094           shape = aMesh->IndexToShape( aShapeId );
1095         if ( !shape.IsNull() && shape.ShapeType() == TopAbs_FACE ) {
1096           TopoDS_Face face = TopoDS::Face( shape );
1097           surface = BRep_Tool::Surface( face );
1098           if ( !surface.IsNull() )
1099             helper.SetSubShape( shape );
1100         }
1101       }
1102       // get elem nodes
1103       const SMDS_MeshNode* aNodes [8];
1104       const SMDS_MeshNode* inFaceNode = 0;
1105       SMDS_ElemIteratorPtr itN = elem->nodesIterator();
1106       int i = 0;
1107       while ( itN->more() ) {
1108         aNodes[ i++ ] = static_cast<const SMDS_MeshNode*>( itN->next() );
1109         if ( !inFaceNode && helper.GetNodeUVneedInFaceNode() &&
1110              aNodes[ i-1 ]->GetPosition()->GetTypeOfPosition() == SMDS_TOP_FACE )
1111         {
1112           inFaceNode = aNodes[ i-1 ];
1113         }
1114       }
1115       // find middle point for (0,1,2,3)
1116       // and create a node in this point;
1117       gp_XYZ p( 0,0,0 );
1118       if ( surface.IsNull() ) {
1119         for(i=0; i<4; i++)
1120           p += gp_XYZ(aNodes[i]->X(), aNodes[i]->Y(), aNodes[i]->Z() );
1121         p /= 4;
1122       }
1123       else {
1124         TopoDS_Face face = TopoDS::Face( helper.GetSubShape() );
1125         gp_XY uv( 0,0 );
1126         for(i=0; i<4; i++)
1127           uv += helper.GetNodeUV( face, aNodes[i], inFaceNode );
1128         uv /= 4.;
1129         p = surface->Value( uv.X(), uv.Y() ).XYZ();
1130       }
1131       const SMDS_MeshNode* newN = aMesh->AddNode( p.X(), p.Y(), p.Z() );
1132       myLastCreatedNodes.Append(newN);
1133
1134       // create a new element
1135       if ( aBadRate1 <= aBadRate2 ) {
1136         newElem1 = aMesh->AddFace(aNodes[2], aNodes[3], aNodes[0],
1137                                   aNodes[6], aNodes[7], newN );
1138         newElem2 = aMesh->AddFace(aNodes[2], aNodes[0], aNodes[1],
1139                                   newN,      aNodes[4], aNodes[5] );
1140       }
1141       else {
1142         newElem1 = aMesh->AddFace(aNodes[3], aNodes[0], aNodes[1],
1143                                   aNodes[7], aNodes[4], newN );
1144         newElem2 = aMesh->AddFace(aNodes[3], aNodes[1], aNodes[2],
1145                                   newN,      aNodes[5], aNodes[6] );
1146       }
1147     } // quadratic case
1148
1149     // care of a new element
1150
1151     myLastCreatedElems.Append(newElem1);
1152     myLastCreatedElems.Append(newElem2);
1153     AddToSameGroups( newElem1, elem, aMesh );
1154     AddToSameGroups( newElem2, elem, aMesh );
1155
1156     // put a new triangle on the same shape
1157     if ( aShapeId )
1158       {
1159         aMesh->SetMeshElementOnShape( newElem1, aShapeId );
1160         aMesh->SetMeshElementOnShape( newElem2, aShapeId );
1161       }
1162     aMesh->RemoveElement( elem );
1163   }
1164   return true;
1165 }
1166
1167 //=======================================================================
1168 //function : BestSplit
1169 //purpose  : Find better diagonal for cutting.
1170 //=======================================================================
1171
1172 int SMESH_MeshEditor::BestSplit (const SMDS_MeshElement*              theQuad,
1173                                  SMESH::Controls::NumericalFunctorPtr theCrit)
1174 {
1175   myLastCreatedElems.Clear();
1176   myLastCreatedNodes.Clear();
1177
1178   if (!theCrit.get())
1179     return -1;
1180
1181   if (!theQuad || theQuad->GetType() != SMDSAbs_Face )
1182     return -1;
1183
1184   if( theQuad->NbNodes()==4 ||
1185       (theQuad->NbNodes()==8 && theQuad->IsQuadratic()) ) {
1186
1187     // retrieve element nodes
1188     const SMDS_MeshNode* aNodes [4];
1189     SMDS_ElemIteratorPtr itN = theQuad->nodesIterator();
1190     int i = 0;
1191     //while (itN->more())
1192     while (i<4) {
1193       aNodes[ i++ ] = static_cast<const SMDS_MeshNode*>( itN->next() );
1194     }
1195     // compare two sets of possible triangles
1196     double aBadRate1, aBadRate2; // to what extent a set is bad
1197     SMDS_FaceOfNodes tr1 ( aNodes[0], aNodes[1], aNodes[2] );
1198     SMDS_FaceOfNodes tr2 ( aNodes[2], aNodes[3], aNodes[0] );
1199     aBadRate1 = getBadRate( &tr1, theCrit ) + getBadRate( &tr2, theCrit );
1200
1201     SMDS_FaceOfNodes tr3 ( aNodes[1], aNodes[2], aNodes[3] );
1202     SMDS_FaceOfNodes tr4 ( aNodes[3], aNodes[0], aNodes[1] );
1203     aBadRate2 = getBadRate( &tr3, theCrit ) + getBadRate( &tr4, theCrit );
1204
1205     if (aBadRate1 <= aBadRate2) // tr1 + tr2 is better
1206       return 1; // diagonal 1-3
1207
1208     return 2; // diagonal 2-4
1209   }
1210   return -1;
1211 }
1212
1213 namespace
1214 {
1215   // Methods of splitting volumes into tetra
1216
1217   const int theHexTo5_1[5*4+1] =
1218     {
1219       0, 1, 2, 5,    0, 4, 5, 7,     0, 2, 3, 7,    2, 5, 6, 7,     0, 5, 2, 7,   -1
1220     };
1221   const int theHexTo5_2[5*4+1] =
1222     {
1223       1, 2, 3, 6,    1, 4, 5, 6,     0, 1, 3, 4,    3, 4, 6, 7,     1, 3, 4, 6,   -1
1224     };
1225   const int* theHexTo5[2] = { theHexTo5_1, theHexTo5_2 };
1226
1227   const int theHexTo6_1[6*4+1] =
1228     {
1229       1, 5, 6, 0,    0, 1, 2, 6,     0, 4, 5, 6,    0, 4, 6, 7,     0, 2, 3, 6,   0, 3, 7, 6,  -1
1230     };
1231   const int theHexTo6_2[6*4+1] =
1232     {
1233       2, 6, 7, 1,    1, 2, 3, 7,     1, 5, 6, 7,    1, 5, 7, 4,     1, 3, 0, 7,   1, 0, 4, 7,  -1
1234     };
1235   const int theHexTo6_3[6*4+1] =
1236     {
1237       3, 7, 4, 2,    2, 3, 0, 4,     2, 6, 7, 4,    2, 6, 4, 5,     2, 0, 1, 4,   2, 1, 5, 4,  -1
1238     };
1239   const int theHexTo6_4[6*4+1] =
1240     {
1241       0, 4, 5, 3,    3, 0, 1, 5,     3, 7, 4, 5,    3, 7, 5, 6,     3, 1, 2, 5,   3, 2, 6, 5,  -1
1242     };
1243   const int* theHexTo6[4] = { theHexTo6_1, theHexTo6_2, theHexTo6_3, theHexTo6_4 };
1244
1245   const int thePyraTo2_1[2*4+1] =
1246     {
1247       0, 1, 2, 4,    0, 2, 3, 4,   -1
1248     };
1249   const int thePyraTo2_2[2*4+1] =
1250     {
1251       1, 2, 3, 4,    1, 3, 0, 4,   -1
1252     };
1253   const int* thePyraTo2[2] = { thePyraTo2_1, thePyraTo2_2 };
1254
1255   const int thePentaTo3_1[3*4+1] =
1256     {
1257       0, 1, 2, 3,    1, 3, 4, 2,     2, 3, 4, 5,    -1
1258     };
1259   const int thePentaTo3_2[3*4+1] =
1260     {
1261       1, 2, 0, 4,    2, 4, 5, 0,     0, 4, 5, 3,    -1
1262     };
1263   const int thePentaTo3_3[3*4+1] =
1264     {
1265       2, 0, 1, 5,    0, 5, 3, 1,     1, 5, 3, 4,    -1
1266     };
1267   const int thePentaTo3_4[3*4+1] =
1268     {
1269       0, 1, 2, 3,    1, 3, 4, 5,     2, 3, 1, 5,    -1
1270     };
1271   const int thePentaTo3_5[3*4+1] =
1272     {
1273       1, 2, 0, 4,    2, 4, 5, 3,     0, 4, 2, 3,    -1
1274     };
1275   const int thePentaTo3_6[3*4+1] =
1276     {
1277       2, 0, 1, 5,    0, 5, 3, 4,     1, 5, 0, 4,    -1
1278     };
1279   const int* thePentaTo3[6] = { thePentaTo3_1, thePentaTo3_2, thePentaTo3_3,
1280                                 thePentaTo3_4, thePentaTo3_5, thePentaTo3_6 };
1281
1282   struct TTriangleFacet //!< stores indices of three nodes of tetra facet
1283   {
1284     int _n1, _n2, _n3;
1285     TTriangleFacet(int n1, int n2, int n3): _n1(n1), _n2(n2), _n3(n3) {}
1286     bool contains(int n) const { return ( n == _n1 || n == _n2 || n == _n3 ); }
1287     bool hasAdjacentTetra( const SMDS_MeshElement* elem ) const;
1288   };
1289   struct TSplitMethod
1290   {
1291     int        _nbTetra;
1292     const int* _connectivity; //!< foursomes of tetra connectivy finished by -1
1293     bool       _baryNode;     //!< additional node is to be created at cell barycenter
1294     bool       _ownConn;      //!< to delete _connectivity in destructor
1295     map<int, const SMDS_MeshNode*> _faceBaryNode; //!< map face index to node at BC of face
1296
1297     TSplitMethod( int nbTet=0, const int* conn=0, bool addNode=false)
1298       : _nbTetra(nbTet), _connectivity(conn), _baryNode(addNode), _ownConn(false) {}
1299     ~TSplitMethod() { if ( _ownConn ) delete [] _connectivity; _connectivity = 0; }
1300     bool hasFacet( const TTriangleFacet& facet ) const
1301     {
1302       const int* tetConn = _connectivity;
1303       for ( ; tetConn[0] >= 0; tetConn += 4 )
1304         if (( facet.contains( tetConn[0] ) +
1305               facet.contains( tetConn[1] ) +
1306               facet.contains( tetConn[2] ) +
1307               facet.contains( tetConn[3] )) == 3 )
1308           return true;
1309       return false;
1310     }
1311   };
1312
1313   //=======================================================================
1314   /*!
1315    * \brief return TSplitMethod for the given element
1316    */
1317   //=======================================================================
1318
1319   TSplitMethod getSplitMethod( SMDS_VolumeTool& vol, const int theMethodFlags)
1320   {
1321     const int iQ = vol.Element()->IsQuadratic() ? 2 : 1;
1322
1323     // at HEXA_TO_24 method, each face of volume is split into triangles each based on
1324     // an edge and a face barycenter; tertaherdons are based on triangles and
1325     // a volume barycenter
1326     const bool is24TetMode = ( theMethodFlags == SMESH_MeshEditor::HEXA_TO_24 );
1327
1328     // Find out how adjacent volumes are split
1329
1330     vector < list< TTriangleFacet > > triaSplitsByFace( vol.NbFaces() ); // splits of each side
1331     int hasAdjacentSplits = 0, maxTetConnSize = 0;
1332     for ( int iF = 0; iF < vol.NbFaces(); ++iF )
1333     {
1334       int nbNodes = vol.NbFaceNodes( iF ) / iQ;
1335       maxTetConnSize += 4 * ( nbNodes - (is24TetMode ? 0 : 2));
1336       if ( nbNodes < 4 ) continue;
1337
1338       list< TTriangleFacet >& triaSplits = triaSplitsByFace[ iF ];
1339       const int* nInd = vol.GetFaceNodesIndices( iF );
1340       if ( nbNodes == 4 )
1341       {
1342         TTriangleFacet t012( nInd[0*iQ], nInd[1*iQ], nInd[2*iQ] );
1343         TTriangleFacet t123( nInd[1*iQ], nInd[2*iQ], nInd[3*iQ] );
1344         if      ( t012.hasAdjacentTetra( vol.Element() )) triaSplits.push_back( t012 );
1345         else if ( t123.hasAdjacentTetra( vol.Element() )) triaSplits.push_back( t123 );
1346       }
1347       else
1348       {
1349         int iCom = 0; // common node of triangle faces to split into
1350         for ( int iVar = 0; iVar < nbNodes; ++iVar, ++iCom )
1351         {
1352           TTriangleFacet t012( nInd[ iQ * ( iCom             )],
1353                                nInd[ iQ * ( (iCom+1)%nbNodes )],
1354                                nInd[ iQ * ( (iCom+2)%nbNodes )]);
1355           TTriangleFacet t023( nInd[ iQ * ( iCom             )],
1356                                nInd[ iQ * ( (iCom+2)%nbNodes )],
1357                                nInd[ iQ * ( (iCom+3)%nbNodes )]);
1358           if ( t012.hasAdjacentTetra( vol.Element() ) && t023.hasAdjacentTetra( vol.Element() ))
1359           {
1360             triaSplits.push_back( t012 );
1361             triaSplits.push_back( t023 );
1362             break;
1363           }
1364         }
1365       }
1366       if ( !triaSplits.empty() )
1367         hasAdjacentSplits = true;
1368     }
1369
1370     // Among variants of split method select one compliant with adjacent volumes
1371
1372     TSplitMethod method;
1373     if ( !vol.Element()->IsPoly() && !is24TetMode )
1374     {
1375       int nbVariants = 2, nbTet = 0;
1376       const int** connVariants = 0;
1377       switch ( vol.Element()->GetEntityType() )
1378       {
1379       case SMDSEntity_Hexa:
1380       case SMDSEntity_Quad_Hexa:
1381         if ( theMethodFlags == SMESH_MeshEditor::HEXA_TO_5 )
1382           connVariants = theHexTo5, nbTet = 5;
1383         else
1384           connVariants = theHexTo6, nbTet = 6, nbVariants = 4;
1385         break;
1386       case SMDSEntity_Pyramid:
1387       case SMDSEntity_Quad_Pyramid:
1388         connVariants = thePyraTo2;  nbTet = 2;
1389         break;
1390       case SMDSEntity_Penta:
1391       case SMDSEntity_Quad_Penta:
1392         connVariants = thePentaTo3; nbTet = 3; nbVariants = 6;
1393         break;
1394       default:
1395         nbVariants = 0;
1396       }
1397       for ( int variant = 0; variant < nbVariants && method._nbTetra == 0; ++variant )
1398       {
1399         // check method compliancy with adjacent tetras,
1400         // all found splits must be among facets of tetras described by this method
1401         method = TSplitMethod( nbTet, connVariants[variant] );
1402         if ( hasAdjacentSplits && method._nbTetra > 0 )
1403         {
1404           bool facetCreated = true;
1405           for ( int iF = 0; facetCreated && iF < triaSplitsByFace.size(); ++iF )
1406           {
1407             list< TTriangleFacet >::const_iterator facet = triaSplitsByFace[iF].begin();
1408             for ( ; facetCreated && facet != triaSplitsByFace[iF].end(); ++facet )
1409               facetCreated = method.hasFacet( *facet );
1410           }
1411           if ( !facetCreated )
1412             method = TSplitMethod(0); // incompatible method
1413         }
1414       }
1415     }
1416     if ( method._nbTetra < 1 )
1417     {
1418       // No standard method is applicable, use a generic solution:
1419       // each facet of a volume is split into triangles and
1420       // each of triangles and a volume barycenter form a tetrahedron.
1421
1422       int* connectivity = new int[ maxTetConnSize + 1 ];
1423       method._connectivity = connectivity;
1424       method._ownConn = true;
1425       method._baryNode = true;
1426
1427       int connSize = 0;
1428       int baryCenInd = vol.NbNodes();
1429       for ( int iF = 0; iF < vol.NbFaces(); ++iF )
1430       {
1431         const int nbNodes = vol.NbFaceNodes( iF ) / iQ;
1432         const int*   nInd = vol.GetFaceNodesIndices( iF );
1433         // find common node of triangle facets of tetra to create
1434         int iCommon = 0; // index in linear numeration
1435         const list< TTriangleFacet >& triaSplits = triaSplitsByFace[ iF ];
1436         if ( !triaSplits.empty() )
1437         {
1438           // by found facets
1439           const TTriangleFacet* facet = &triaSplits.front();
1440           for ( ; iCommon < nbNodes-1 ; ++iCommon )
1441             if ( facet->contains( nInd[ iQ * iCommon ]) &&
1442                  facet->contains( nInd[ iQ * ((iCommon+2)%nbNodes) ]))
1443               break;
1444         }
1445         else if ( nbNodes > 3 && !is24TetMode )
1446         {
1447           // find the best method of splitting into triangles by aspect ratio
1448           SMESH::Controls::NumericalFunctorPtr aspectRatio( new SMESH::Controls::AspectRatio);
1449           map< double, int > badness2iCommon;
1450           const SMDS_MeshNode** nodes = vol.GetFaceNodes( iF );
1451           int nbVariants = ( nbNodes == 4 ? 2 : nbNodes );
1452           for ( int iVar = 0; iVar < nbVariants; ++iVar, ++iCommon )
1453             for ( int iLast = iCommon+2; iLast < iCommon+nbNodes; ++iLast )
1454             {
1455               SMDS_FaceOfNodes tria ( nodes[ iQ*( iCommon         )],
1456                                       nodes[ iQ*((iLast-1)%nbNodes)],
1457                                       nodes[ iQ*((iLast  )%nbNodes)]);
1458               double badness = getBadRate( &tria, aspectRatio );
1459               badness2iCommon.insert( make_pair( badness, iCommon ));
1460             }
1461           // use iCommon with lowest badness
1462           iCommon = badness2iCommon.begin()->second;
1463         }
1464         if ( iCommon >= nbNodes )
1465           iCommon = 0; // something wrong
1466
1467         // fill connectivity of tetrahedra based on a current face
1468         int nbTet = nbNodes - 2;
1469         if ( is24TetMode && nbNodes > 3 && triaSplits.empty())
1470         {
1471           method._faceBaryNode.insert( make_pair( iF, (const SMDS_MeshNode*)0 ));
1472           int faceBaryCenInd = baryCenInd + method._faceBaryNode.size();
1473           nbTet = nbNodes;
1474           for ( int i = 0; i < nbTet; ++i )
1475           {
1476             int i1 = i, i2 = (i+1) % nbNodes;
1477             if ( !vol.IsFaceExternal( iF )) swap( i1, i2 );
1478             connectivity[ connSize++ ] = nInd[ iQ * i1 ];
1479             connectivity[ connSize++ ] = nInd[ iQ * i2 ];
1480             connectivity[ connSize++ ] = faceBaryCenInd;
1481             connectivity[ connSize++ ] = baryCenInd;
1482           }
1483         }
1484         else
1485         {
1486           for ( int i = 0; i < nbTet; ++i )
1487           {
1488             int i1 = (iCommon+1+i) % nbNodes, i2 = (iCommon+2+i) % nbNodes;
1489             if ( !vol.IsFaceExternal( iF )) swap( i1, i2 );
1490             connectivity[ connSize++ ] = nInd[ iQ * iCommon ];
1491             connectivity[ connSize++ ] = nInd[ iQ * i1 ];
1492             connectivity[ connSize++ ] = nInd[ iQ * i2 ];
1493             connectivity[ connSize++ ] = baryCenInd;
1494           }
1495         }
1496         method._nbTetra += nbTet;
1497       }
1498       connectivity[ connSize++ ] = -1;
1499     }
1500     return method;
1501   }
1502   //================================================================================
1503   /*!
1504    * \brief Check if there is a tetraherdon adjacent to the given element via this facet
1505    */
1506   //================================================================================
1507
1508   bool TTriangleFacet::hasAdjacentTetra( const SMDS_MeshElement* elem ) const
1509   {
1510     // find the tetrahedron including the three nodes of facet
1511     const SMDS_MeshNode* n1 = elem->GetNode(_n1);
1512     const SMDS_MeshNode* n2 = elem->GetNode(_n2);
1513     const SMDS_MeshNode* n3 = elem->GetNode(_n3);
1514     SMDS_ElemIteratorPtr volIt1 = n1->GetInverseElementIterator(SMDSAbs_Volume);
1515     while ( volIt1->more() )
1516     {
1517       const SMDS_MeshElement* v = volIt1->next();
1518       if ( v->GetEntityType() != ( v->IsQuadratic() ? SMDSEntity_Quad_Tetra : SMDSEntity_Tetra ))
1519         continue;
1520       SMDS_ElemIteratorPtr volIt2 = n2->GetInverseElementIterator(SMDSAbs_Volume);
1521       while ( volIt2->more() )
1522         if ( v != volIt2->next() )
1523           continue;
1524       SMDS_ElemIteratorPtr volIt3 = n3->GetInverseElementIterator(SMDSAbs_Volume);
1525       while ( volIt3->more() )
1526         if ( v == volIt3->next() )
1527           return true;
1528     }
1529     return false;
1530   }
1531
1532   //=======================================================================
1533   /*!
1534    * \brief A key of a face of volume
1535    */
1536   //=======================================================================
1537
1538   struct TVolumeFaceKey: pair< int, pair< int, int> >
1539   {
1540     TVolumeFaceKey( SMDS_VolumeTool& vol, int iF )
1541     {
1542       TIDSortedNodeSet sortedNodes;
1543       const int iQ = vol.Element()->IsQuadratic() ? 2 : 1;
1544       int nbNodes = vol.NbFaceNodes( iF );
1545       const SMDS_MeshNode** fNodes = vol.GetFaceNodes( iF );
1546       for ( int i = 0; i < nbNodes; i += iQ )
1547         sortedNodes.insert( fNodes[i] );
1548       TIDSortedNodeSet::iterator n = sortedNodes.begin();
1549       first = (*(n++))->GetID();
1550       second.first = (*(n++))->GetID();
1551       second.second = (*(n++))->GetID();
1552     }
1553   };
1554 } // namespace
1555
1556 //=======================================================================
1557 //function : SplitVolumesIntoTetra
1558 //purpose  : Split volumic elements into tetrahedra.
1559 //=======================================================================
1560
1561 void SMESH_MeshEditor::SplitVolumesIntoTetra (const TIDSortedElemSet & theElems,
1562                                               const int                theMethodFlags)
1563 {
1564   // std-like iterator on coordinates of nodes of mesh element
1565   typedef SMDS_StdIterator< SMESH_TNodeXYZ, SMDS_ElemIteratorPtr > NXyzIterator;
1566   NXyzIterator xyzEnd;
1567
1568   SMDS_VolumeTool    volTool;
1569   SMESH_MesherHelper helper( *GetMesh());
1570
1571   SMESHDS_SubMesh* subMesh = 0;//GetMeshDS()->MeshElements(1);
1572   SMESHDS_SubMesh* fSubMesh = 0;//subMesh;
1573   
1574   SMESH_SequenceOfElemPtr newNodes, newElems;
1575
1576   // map face of volume to it's baricenrtic node
1577   map< TVolumeFaceKey, const SMDS_MeshNode* > volFace2BaryNode;
1578   double bc[3];
1579
1580   TIDSortedElemSet::const_iterator elem = theElems.begin();
1581   for ( ; elem != theElems.end(); ++elem )
1582   {
1583     SMDSAbs_EntityType geomType = (*elem)->GetEntityType();
1584     if ( geomType <= SMDSEntity_Quad_Tetra )
1585       continue; // tetra or face or ...
1586
1587     if ( !volTool.Set( *elem )) continue; // not volume? strange...
1588
1589     TSplitMethod splitMethod = getSplitMethod( volTool, theMethodFlags );
1590     if ( splitMethod._nbTetra < 1 ) continue;
1591
1592     // find submesh to add new tetras to
1593     if ( !subMesh || !subMesh->Contains( *elem ))
1594     {
1595       int shapeID = FindShape( *elem );
1596       helper.SetSubShape( shapeID ); // helper will add tetras to the found submesh
1597       subMesh = GetMeshDS()->MeshElements( shapeID );
1598     }
1599     int iQ;
1600     if ( (*elem)->IsQuadratic() )
1601     {
1602       iQ = 2;
1603       // add quadratic links to the helper
1604       for ( int iF = 0; iF < volTool.NbFaces(); ++iF )
1605       {
1606         const SMDS_MeshNode** fNodes = volTool.GetFaceNodes( iF );
1607         for ( int iN = 0; iN < volTool.NbFaceNodes( iF ); iN += iQ )
1608           helper.AddTLinkNode( fNodes[iF], fNodes[iF+2], fNodes[iF+1] );
1609       }
1610       helper.SetIsQuadratic( true );
1611     }
1612     else
1613     {
1614       iQ = 1;
1615       helper.SetIsQuadratic( false );
1616     }
1617     vector<const SMDS_MeshNode*> nodes( (*elem)->begin_nodes(), (*elem)->end_nodes() );
1618     if ( splitMethod._baryNode )
1619     {
1620       // make a node at barycenter
1621       volTool.GetBaryCenter( bc[0], bc[1], bc[2] );
1622       SMDS_MeshNode* gcNode = helper.AddNode( bc[0], bc[1], bc[2] );
1623       nodes.push_back( gcNode );
1624       newNodes.Append( gcNode );
1625     }
1626     if ( !splitMethod._faceBaryNode.empty() )
1627     {
1628       // make or find baricentric nodes of faces
1629       map<int, const SMDS_MeshNode*>::iterator iF_n = splitMethod._faceBaryNode.begin();
1630       for ( ; iF_n != splitMethod._faceBaryNode.end(); ++iF_n )
1631       {
1632         map< TVolumeFaceKey, const SMDS_MeshNode* >::iterator f_n =
1633           volFace2BaryNode.insert
1634           ( make_pair( TVolumeFaceKey( volTool,iF_n->first ), (const SMDS_MeshNode*)0) ).first;
1635         if ( !f_n->second )
1636         {
1637           volTool.GetFaceBaryCenter( iF_n->first, bc[0], bc[1], bc[2] );
1638           newNodes.Append( f_n->second = helper.AddNode( bc[0], bc[1], bc[2] ));
1639         }
1640         nodes.push_back( iF_n->second = f_n->second );
1641       }
1642     }
1643
1644     // make tetras
1645     helper.SetElementsOnShape( true );
1646     vector<const SMDS_MeshElement* > tetras( splitMethod._nbTetra ); // splits of a volume
1647     const int* tetConn = splitMethod._connectivity;
1648     for ( int i = 0; i < splitMethod._nbTetra; ++i, tetConn += 4 )
1649       newElems.Append( tetras[ i ] = helper.AddVolume( nodes[ tetConn[0] ],
1650                                                        nodes[ tetConn[1] ],
1651                                                        nodes[ tetConn[2] ],
1652                                                        nodes[ tetConn[3] ]));
1653
1654     ReplaceElemInGroups( *elem, tetras, GetMeshDS() );
1655
1656     // Split faces on sides of the split volume
1657
1658     const SMDS_MeshNode** volNodes = volTool.GetNodes();
1659     for ( int iF = 0; iF < volTool.NbFaces(); ++iF )
1660     {
1661       const int nbNodes = volTool.NbFaceNodes( iF ) / iQ;
1662       if ( nbNodes < 4 ) continue;
1663
1664       // find an existing face
1665       vector<const SMDS_MeshNode*> fNodes( volTool.GetFaceNodes( iF ),
1666                                            volTool.GetFaceNodes( iF ) + nbNodes*iQ );
1667       while ( const SMDS_MeshElement* face = GetMeshDS()->FindFace( fNodes ))
1668       {
1669         // make triangles
1670         helper.SetElementsOnShape( false );
1671         vector< const SMDS_MeshElement* > triangles;
1672
1673         map<int, const SMDS_MeshNode*>::iterator iF_n = splitMethod._faceBaryNode.find(iF);
1674         if ( iF_n != splitMethod._faceBaryNode.end() )
1675         {
1676           for ( int iN = 0; iN < nbNodes*iQ; iN += iQ )
1677           {
1678             const SMDS_MeshNode* n1 = fNodes[iN];
1679             const SMDS_MeshNode *n2 = fNodes[(iN+iQ)%nbNodes*iQ];
1680             const SMDS_MeshNode *n3 = iF_n->second;
1681             if ( !volTool.IsFaceExternal( iF ))
1682               swap( n2, n3 );
1683             triangles.push_back( helper.AddFace( n1,n2,n3 ));
1684           }
1685         }
1686         else
1687         {
1688           // among possible triangles create ones discribed by split method
1689           const int* nInd = volTool.GetFaceNodesIndices( iF );
1690           int nbVariants = ( nbNodes == 4 ? 2 : nbNodes );
1691           int iCom = 0; // common node of triangle faces to split into
1692           list< TTriangleFacet > facets;
1693           for ( int iVar = 0; iVar < nbVariants; ++iVar, ++iCom )
1694           {
1695             TTriangleFacet t012( nInd[ iQ * ( iCom                )],
1696                                  nInd[ iQ * ( (iCom+1)%nbNodes )],
1697                                  nInd[ iQ * ( (iCom+2)%nbNodes )]);
1698             TTriangleFacet t023( nInd[ iQ * ( iCom                )],
1699                                  nInd[ iQ * ( (iCom+2)%nbNodes )],
1700                                  nInd[ iQ * ( (iCom+3)%nbNodes )]);
1701             if ( splitMethod.hasFacet( t012 ) && splitMethod.hasFacet( t023 ))
1702             {
1703               facets.push_back( t012 );
1704               facets.push_back( t023 );
1705               for ( int iLast = iCom+4; iLast < iCom+nbNodes; ++iLast )
1706                 facets.push_back( TTriangleFacet( nInd[ iQ * ( iCom             )],
1707                                                   nInd[ iQ * ((iLast-1)%nbNodes )],
1708                                                   nInd[ iQ * ((iLast  )%nbNodes )]));
1709               break;
1710             }
1711           }
1712           list< TTriangleFacet >::iterator facet = facets.begin();
1713           for ( ; facet != facets.end(); ++facet )
1714           {
1715             if ( !volTool.IsFaceExternal( iF ))
1716               swap( facet->_n2, facet->_n3 );
1717             triangles.push_back( helper.AddFace( volNodes[ facet->_n1 ],
1718                                                  volNodes[ facet->_n2 ],
1719                                                  volNodes[ facet->_n3 ]));
1720           }
1721         }
1722         // find submesh to add new triangles in
1723         if ( !fSubMesh || !fSubMesh->Contains( face ))
1724         {
1725           int shapeID = FindShape( face );
1726           fSubMesh = GetMeshDS()->MeshElements( shapeID );
1727         }
1728         for ( int i = 0; i < triangles.size(); ++i )
1729         {
1730           if ( !triangles[i] ) continue;
1731           if ( fSubMesh )
1732             fSubMesh->AddElement( triangles[i]);
1733           newElems.Append( triangles[i] );
1734         }
1735         ReplaceElemInGroups( face, triangles, GetMeshDS() );
1736         GetMeshDS()->RemoveFreeElement( face, fSubMesh, /*fromGroups=*/false );
1737       }
1738
1739     } // loop on volume faces to split them into triangles
1740
1741     GetMeshDS()->RemoveFreeElement( *elem, subMesh, /*fromGroups=*/false );
1742
1743   } // loop on volumes to split
1744
1745   myLastCreatedNodes = newNodes;
1746   myLastCreatedElems = newElems;
1747 }
1748
1749 //=======================================================================
1750 //function : AddToSameGroups
1751 //purpose  : add elemToAdd to the groups the elemInGroups belongs to
1752 //=======================================================================
1753
1754 void SMESH_MeshEditor::AddToSameGroups (const SMDS_MeshElement* elemToAdd,
1755                                         const SMDS_MeshElement* elemInGroups,
1756                                         SMESHDS_Mesh *          aMesh)
1757 {
1758   const set<SMESHDS_GroupBase*>& groups = aMesh->GetGroups();
1759   if (!groups.empty()) {
1760     set<SMESHDS_GroupBase*>::const_iterator grIt = groups.begin();
1761     for ( ; grIt != groups.end(); grIt++ ) {
1762       SMESHDS_Group* group = dynamic_cast<SMESHDS_Group*>( *grIt );
1763       if ( group && group->Contains( elemInGroups ))
1764         group->SMDSGroup().Add( elemToAdd );
1765     }
1766   }
1767 }
1768
1769
1770 //=======================================================================
1771 //function : RemoveElemFromGroups
1772 //purpose  : Remove removeelem to the groups the elemInGroups belongs to
1773 //=======================================================================
1774 void SMESH_MeshEditor::RemoveElemFromGroups (const SMDS_MeshElement* removeelem,
1775                                              SMESHDS_Mesh *          aMesh)
1776 {
1777   const set<SMESHDS_GroupBase*>& groups = aMesh->GetGroups();
1778   if (!groups.empty())
1779   {
1780     set<SMESHDS_GroupBase*>::const_iterator GrIt = groups.begin();
1781     for (; GrIt != groups.end(); GrIt++)
1782     {
1783       SMESHDS_Group* grp = dynamic_cast<SMESHDS_Group*>(*GrIt);
1784       if (!grp || grp->IsEmpty()) continue;
1785       grp->SMDSGroup().Remove(removeelem);
1786     }
1787   }
1788 }
1789
1790 //================================================================================
1791 /*!
1792  * \brief Replace elemToRm by elemToAdd in the all groups
1793  */
1794 //================================================================================
1795
1796 void SMESH_MeshEditor::ReplaceElemInGroups (const SMDS_MeshElement* elemToRm,
1797                                             const SMDS_MeshElement* elemToAdd,
1798                                             SMESHDS_Mesh *          aMesh)
1799 {
1800   const set<SMESHDS_GroupBase*>& groups = aMesh->GetGroups();
1801   if (!groups.empty()) {
1802     set<SMESHDS_GroupBase*>::const_iterator grIt = groups.begin();
1803     for ( ; grIt != groups.end(); grIt++ ) {
1804       SMESHDS_Group* group = dynamic_cast<SMESHDS_Group*>( *grIt );
1805       if ( group && group->SMDSGroup().Remove( elemToRm ) && elemToAdd )
1806         group->SMDSGroup().Add( elemToAdd );
1807     }
1808   }
1809 }
1810
1811 //================================================================================
1812 /*!
1813  * \brief Replace elemToRm by elemToAdd in the all groups
1814  */
1815 //================================================================================
1816
1817 void SMESH_MeshEditor::ReplaceElemInGroups (const SMDS_MeshElement*                elemToRm,
1818                                             const vector<const SMDS_MeshElement*>& elemToAdd,
1819                                             SMESHDS_Mesh *                         aMesh)
1820 {
1821   const set<SMESHDS_GroupBase*>& groups = aMesh->GetGroups();
1822   if (!groups.empty())
1823   {
1824     set<SMESHDS_GroupBase*>::const_iterator grIt = groups.begin();
1825     for ( ; grIt != groups.end(); grIt++ ) {
1826       SMESHDS_Group* group = dynamic_cast<SMESHDS_Group*>( *grIt );
1827       if ( group && group->SMDSGroup().Remove( elemToRm ) )
1828         for ( int i = 0; i < elemToAdd.size(); ++i )
1829           group->SMDSGroup().Add( elemToAdd[ i ] );
1830     }
1831   }
1832 }
1833
1834 //=======================================================================
1835 //function : QuadToTri
1836 //purpose  : Cut quadrangles into triangles.
1837 //           theCrit is used to select a diagonal to cut
1838 //=======================================================================
1839
1840 bool SMESH_MeshEditor::QuadToTri (TIDSortedElemSet & theElems,
1841                                   const bool         the13Diag)
1842 {
1843   myLastCreatedElems.Clear();
1844   myLastCreatedNodes.Clear();
1845
1846   MESSAGE( "::QuadToTri()" );
1847
1848   SMESHDS_Mesh * aMesh = GetMeshDS();
1849
1850   Handle(Geom_Surface) surface;
1851   SMESH_MesherHelper   helper( *GetMesh() );
1852
1853   TIDSortedElemSet::iterator itElem;
1854   for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
1855     const SMDS_MeshElement* elem = *itElem;
1856     if ( !elem || elem->GetType() != SMDSAbs_Face )
1857       continue;
1858     bool isquad = elem->NbNodes()==4 || elem->NbNodes()==8;
1859     if(!isquad) continue;
1860
1861     if(elem->NbNodes()==4) {
1862       // retrieve element nodes
1863       const SMDS_MeshNode* aNodes [4];
1864       SMDS_ElemIteratorPtr itN = elem->nodesIterator();
1865       int i = 0;
1866       while ( itN->more() )
1867         aNodes[ i++ ] = static_cast<const SMDS_MeshNode*>( itN->next() );
1868
1869       int aShapeId = FindShape( elem );
1870       const SMDS_MeshElement* newElem1 = 0;
1871       const SMDS_MeshElement* newElem2 = 0;
1872       if ( the13Diag ) {
1873         newElem1 = aMesh->AddFace( aNodes[2], aNodes[0], aNodes[1] );
1874         newElem2 = aMesh->AddFace( aNodes[2], aNodes[3], aNodes[0] );
1875       }
1876       else {
1877         newElem1 = aMesh->AddFace( aNodes[3], aNodes[0], aNodes[1] );
1878         newElem2 = aMesh->AddFace( aNodes[3], aNodes[1], aNodes[2] );
1879       }
1880       myLastCreatedElems.Append(newElem1);
1881       myLastCreatedElems.Append(newElem2);
1882       // put a new triangle on the same shape and add to the same groups
1883       if ( aShapeId )
1884         {
1885           aMesh->SetMeshElementOnShape( newElem1, aShapeId );
1886           aMesh->SetMeshElementOnShape( newElem2, aShapeId );
1887         }
1888       AddToSameGroups( newElem1, elem, aMesh );
1889       AddToSameGroups( newElem2, elem, aMesh );
1890       //aMesh->RemoveFreeElement(elem, aMesh->MeshElements(aShapeId), true);
1891       aMesh->RemoveElement( elem );
1892     }
1893
1894     // Quadratic quadrangle
1895
1896     if( elem->NbNodes()==8 && elem->IsQuadratic() ) {
1897
1898       // get surface elem is on
1899       int aShapeId = FindShape( elem );
1900       if ( aShapeId != helper.GetSubShapeID() ) {
1901         surface.Nullify();
1902         TopoDS_Shape shape;
1903         if ( aShapeId > 0 )
1904           shape = aMesh->IndexToShape( aShapeId );
1905         if ( !shape.IsNull() && shape.ShapeType() == TopAbs_FACE ) {
1906           TopoDS_Face face = TopoDS::Face( shape );
1907           surface = BRep_Tool::Surface( face );
1908           if ( !surface.IsNull() )
1909             helper.SetSubShape( shape );
1910         }
1911       }
1912
1913       const SMDS_MeshNode* aNodes [8];
1914       const SMDS_MeshNode* inFaceNode = 0;
1915       SMDS_ElemIteratorPtr itN = elem->nodesIterator();
1916       int i = 0;
1917       while ( itN->more() ) {
1918         aNodes[ i++ ] = static_cast<const SMDS_MeshNode*>( itN->next() );
1919         if ( !inFaceNode && helper.GetNodeUVneedInFaceNode() &&
1920              aNodes[ i-1 ]->GetPosition()->GetTypeOfPosition() == SMDS_TOP_FACE )
1921         {
1922           inFaceNode = aNodes[ i-1 ];
1923         }
1924       }
1925
1926       // find middle point for (0,1,2,3)
1927       // and create a node in this point;
1928       gp_XYZ p( 0,0,0 );
1929       if ( surface.IsNull() ) {
1930         for(i=0; i<4; i++)
1931           p += gp_XYZ(aNodes[i]->X(), aNodes[i]->Y(), aNodes[i]->Z() );
1932         p /= 4;
1933       }
1934       else {
1935         TopoDS_Face geomFace = TopoDS::Face( helper.GetSubShape() );
1936         gp_XY uv( 0,0 );
1937         for(i=0; i<4; i++)
1938           uv += helper.GetNodeUV( geomFace, aNodes[i], inFaceNode );
1939         uv /= 4.;
1940         p = surface->Value( uv.X(), uv.Y() ).XYZ();
1941       }
1942       const SMDS_MeshNode* newN = aMesh->AddNode( p.X(), p.Y(), p.Z() );
1943       myLastCreatedNodes.Append(newN);
1944
1945       // create a new element
1946       const SMDS_MeshElement* newElem1 = 0;
1947       const SMDS_MeshElement* newElem2 = 0;
1948       if ( the13Diag ) {
1949         newElem1 = aMesh->AddFace(aNodes[2], aNodes[3], aNodes[0],
1950                                   aNodes[6], aNodes[7], newN );
1951         newElem2 = aMesh->AddFace(aNodes[2], aNodes[0], aNodes[1],
1952                                   newN,      aNodes[4], aNodes[5] );
1953       }
1954       else {
1955         newElem1 = aMesh->AddFace(aNodes[3], aNodes[0], aNodes[1],
1956                                   aNodes[7], aNodes[4], newN );
1957         newElem2 = aMesh->AddFace(aNodes[3], aNodes[1], aNodes[2],
1958                                   newN,      aNodes[5], aNodes[6] );
1959       }
1960       myLastCreatedElems.Append(newElem1);
1961       myLastCreatedElems.Append(newElem2);
1962       // put a new triangle on the same shape and add to the same groups
1963       if ( aShapeId )
1964         {
1965           aMesh->SetMeshElementOnShape( newElem1, aShapeId );
1966           aMesh->SetMeshElementOnShape( newElem2, aShapeId );
1967         }
1968       AddToSameGroups( newElem1, elem, aMesh );
1969       AddToSameGroups( newElem2, elem, aMesh );
1970       aMesh->RemoveElement( elem );
1971     }
1972   }
1973
1974   return true;
1975 }
1976
1977 //=======================================================================
1978 //function : getAngle
1979 //purpose  :
1980 //=======================================================================
1981
1982 double getAngle(const SMDS_MeshElement * tr1,
1983                 const SMDS_MeshElement * tr2,
1984                 const SMDS_MeshNode *    n1,
1985                 const SMDS_MeshNode *    n2)
1986 {
1987   double angle = 2*PI; // bad angle
1988
1989   // get normals
1990   SMESH::Controls::TSequenceOfXYZ P1, P2;
1991   if ( !SMESH::Controls::NumericalFunctor::GetPoints( tr1, P1 ) ||
1992        !SMESH::Controls::NumericalFunctor::GetPoints( tr2, P2 ))
1993     return angle;
1994   gp_Vec N1,N2;
1995   if(!tr1->IsQuadratic())
1996     N1 = gp_Vec( P1(2) - P1(1) ) ^ gp_Vec( P1(3) - P1(1) );
1997   else
1998     N1 = gp_Vec( P1(3) - P1(1) ) ^ gp_Vec( P1(5) - P1(1) );
1999   if ( N1.SquareMagnitude() <= gp::Resolution() )
2000     return angle;
2001   if(!tr2->IsQuadratic())
2002     N2 = gp_Vec( P2(2) - P2(1) ) ^ gp_Vec( P2(3) - P2(1) );
2003   else
2004     N2 = gp_Vec( P2(3) - P2(1) ) ^ gp_Vec( P2(5) - P2(1) );
2005   if ( N2.SquareMagnitude() <= gp::Resolution() )
2006     return angle;
2007
2008   // find the first diagonal node n1 in the triangles:
2009   // take in account a diagonal link orientation
2010   const SMDS_MeshElement *nFirst[2], *tr[] = { tr1, tr2 };
2011   for ( int t = 0; t < 2; t++ ) {
2012     SMDS_ElemIteratorPtr it = tr[ t ]->nodesIterator();
2013     int i = 0, iDiag = -1;
2014     while ( it->more()) {
2015       const SMDS_MeshElement *n = it->next();
2016       if ( n == n1 || n == n2 ) {
2017         if ( iDiag < 0)
2018           iDiag = i;
2019         else {
2020           if ( i - iDiag == 1 )
2021             nFirst[ t ] = ( n == n1 ? n2 : n1 );
2022           else
2023             nFirst[ t ] = n;
2024           break;
2025         }
2026       }
2027       i++;
2028     }
2029   }
2030   if ( nFirst[ 0 ] == nFirst[ 1 ] )
2031     N2.Reverse();
2032
2033   angle = N1.Angle( N2 );
2034   //SCRUTE( angle );
2035   return angle;
2036 }
2037
2038 // =================================================
2039 // class generating a unique ID for a pair of nodes
2040 // and able to return nodes by that ID
2041 // =================================================
2042 class LinkID_Gen {
2043 public:
2044
2045   LinkID_Gen( const SMESHDS_Mesh* theMesh )
2046     :myMesh( theMesh ), myMaxID( theMesh->MaxNodeID() + 1)
2047   {}
2048
2049   long GetLinkID (const SMDS_MeshNode * n1,
2050                   const SMDS_MeshNode * n2) const
2051   {
2052     return ( Min(n1->GetID(),n2->GetID()) * myMaxID + Max(n1->GetID(),n2->GetID()));
2053   }
2054
2055   bool GetNodes (const long             theLinkID,
2056                  const SMDS_MeshNode* & theNode1,
2057                  const SMDS_MeshNode* & theNode2) const
2058   {
2059     theNode1 = myMesh->FindNode( theLinkID / myMaxID );
2060     if ( !theNode1 ) return false;
2061     theNode2 = myMesh->FindNode( theLinkID % myMaxID );
2062     if ( !theNode2 ) return false;
2063     return true;
2064   }
2065
2066 private:
2067   LinkID_Gen();
2068   const SMESHDS_Mesh* myMesh;
2069   long                myMaxID;
2070 };
2071
2072
2073 //=======================================================================
2074 //function : TriToQuad
2075 //purpose  : Fuse neighbour triangles into quadrangles.
2076 //           theCrit is used to select a neighbour to fuse with.
2077 //           theMaxAngle is a max angle between element normals at which
2078 //           fusion is still performed.
2079 //=======================================================================
2080
2081 bool SMESH_MeshEditor::TriToQuad (TIDSortedElemSet &                   theElems,
2082                                   SMESH::Controls::NumericalFunctorPtr theCrit,
2083                                   const double                         theMaxAngle)
2084 {
2085   myLastCreatedElems.Clear();
2086   myLastCreatedNodes.Clear();
2087
2088   MESSAGE( "::TriToQuad()" );
2089
2090   if ( !theCrit.get() )
2091     return false;
2092
2093   SMESHDS_Mesh * aMesh = GetMeshDS();
2094
2095   // Prepare data for algo: build
2096   // 1. map of elements with their linkIDs
2097   // 2. map of linkIDs with their elements
2098
2099   map< SMESH_TLink, list< const SMDS_MeshElement* > > mapLi_listEl;
2100   map< SMESH_TLink, list< const SMDS_MeshElement* > >::iterator itLE;
2101   map< const SMDS_MeshElement*, set< SMESH_TLink > >  mapEl_setLi;
2102   map< const SMDS_MeshElement*, set< SMESH_TLink > >::iterator itEL;
2103
2104   TIDSortedElemSet::iterator itElem;
2105   for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
2106     const SMDS_MeshElement* elem = *itElem;
2107     if(!elem || elem->GetType() != SMDSAbs_Face ) continue;
2108     bool IsTria = elem->NbNodes()==3 || (elem->NbNodes()==6 && elem->IsQuadratic());
2109     if(!IsTria) continue;
2110
2111     // retrieve element nodes
2112     const SMDS_MeshNode* aNodes [4];
2113     SMDS_ElemIteratorPtr itN = elem->nodesIterator();
2114     int i = 0;
2115     while ( i<3 )
2116       aNodes[ i++ ] = cast2Node( itN->next() );
2117     aNodes[ 3 ] = aNodes[ 0 ];
2118
2119     // fill maps
2120     for ( i = 0; i < 3; i++ ) {
2121       SMESH_TLink link( aNodes[i], aNodes[i+1] );
2122       // check if elements sharing a link can be fused
2123       itLE = mapLi_listEl.find( link );
2124       if ( itLE != mapLi_listEl.end() ) {
2125         if ((*itLE).second.size() > 1 ) // consider only 2 elems adjacent by a link
2126           continue;
2127         const SMDS_MeshElement* elem2 = (*itLE).second.front();
2128         //if ( FindShape( elem ) != FindShape( elem2 ))
2129         //  continue; // do not fuse triangles laying on different shapes
2130         if ( getAngle( elem, elem2, aNodes[i], aNodes[i+1] ) > theMaxAngle )
2131           continue; // avoid making badly shaped quads
2132         (*itLE).second.push_back( elem );
2133       }
2134       else {
2135         mapLi_listEl[ link ].push_back( elem );
2136       }
2137       mapEl_setLi [ elem ].insert( link );
2138     }
2139   }
2140   // Clean the maps from the links shared by a sole element, ie
2141   // links to which only one element is bound in mapLi_listEl
2142
2143   for ( itLE = mapLi_listEl.begin(); itLE != mapLi_listEl.end(); itLE++ ) {
2144     int nbElems = (*itLE).second.size();
2145     if ( nbElems < 2  ) {
2146       const SMDS_MeshElement* elem = (*itLE).second.front();
2147       SMESH_TLink link = (*itLE).first;
2148       mapEl_setLi[ elem ].erase( link );
2149       if ( mapEl_setLi[ elem ].empty() )
2150         mapEl_setLi.erase( elem );
2151     }
2152   }
2153
2154   // Algo: fuse triangles into quadrangles
2155
2156   while ( ! mapEl_setLi.empty() ) {
2157     // Look for the start element:
2158     // the element having the least nb of shared links
2159     const SMDS_MeshElement* startElem = 0;
2160     int minNbLinks = 4;
2161     for ( itEL = mapEl_setLi.begin(); itEL != mapEl_setLi.end(); itEL++ ) {
2162       int nbLinks = (*itEL).second.size();
2163       if ( nbLinks < minNbLinks ) {
2164         startElem = (*itEL).first;
2165         minNbLinks = nbLinks;
2166         if ( minNbLinks == 1 )
2167           break;
2168       }
2169     }
2170
2171     // search elements to fuse starting from startElem or links of elements
2172     // fused earlyer - startLinks
2173     list< SMESH_TLink > startLinks;
2174     while ( startElem || !startLinks.empty() ) {
2175       while ( !startElem && !startLinks.empty() ) {
2176         // Get an element to start, by a link
2177         SMESH_TLink linkId = startLinks.front();
2178         startLinks.pop_front();
2179         itLE = mapLi_listEl.find( linkId );
2180         if ( itLE != mapLi_listEl.end() ) {
2181           list< const SMDS_MeshElement* > & listElem = (*itLE).second;
2182           list< const SMDS_MeshElement* >::iterator itE = listElem.begin();
2183           for ( ; itE != listElem.end() ; itE++ )
2184             if ( mapEl_setLi.find( (*itE) ) != mapEl_setLi.end() )
2185               startElem = (*itE);
2186           mapLi_listEl.erase( itLE );
2187         }
2188       }
2189
2190       if ( startElem ) {
2191         // Get candidates to be fused
2192         const SMDS_MeshElement *tr1 = startElem, *tr2 = 0, *tr3 = 0;
2193         const SMESH_TLink *link12, *link13;
2194         startElem = 0;
2195         ASSERT( mapEl_setLi.find( tr1 ) != mapEl_setLi.end() );
2196         set< SMESH_TLink >& setLi = mapEl_setLi[ tr1 ];
2197         ASSERT( !setLi.empty() );
2198         set< SMESH_TLink >::iterator itLi;
2199         for ( itLi = setLi.begin(); itLi != setLi.end(); itLi++ )
2200         {
2201           const SMESH_TLink & link = (*itLi);
2202           itLE = mapLi_listEl.find( link );
2203           if ( itLE == mapLi_listEl.end() )
2204             continue;
2205
2206           const SMDS_MeshElement* elem = (*itLE).second.front();
2207           if ( elem == tr1 )
2208             elem = (*itLE).second.back();
2209           mapLi_listEl.erase( itLE );
2210           if ( mapEl_setLi.find( elem ) == mapEl_setLi.end())
2211             continue;
2212           if ( tr2 ) {
2213             tr3 = elem;
2214             link13 = &link;
2215           }
2216           else {
2217             tr2 = elem;
2218             link12 = &link;
2219           }
2220
2221           // add other links of elem to list of links to re-start from
2222           set< SMESH_TLink >& links = mapEl_setLi[ elem ];
2223           set< SMESH_TLink >::iterator it;
2224           for ( it = links.begin(); it != links.end(); it++ ) {
2225             const SMESH_TLink& link2 = (*it);
2226             if ( link2 != link )
2227               startLinks.push_back( link2 );
2228           }
2229         }
2230
2231         // Get nodes of possible quadrangles
2232         const SMDS_MeshNode *n12 [4], *n13 [4];
2233         bool Ok12 = false, Ok13 = false;
2234         const SMDS_MeshNode *linkNode1, *linkNode2;
2235         if(tr2) {
2236           linkNode1 = link12->first;
2237           linkNode2 = link12->second;
2238           if ( tr2 && getQuadrangleNodes( n12, linkNode1, linkNode2, tr1, tr2 ))
2239             Ok12 = true;
2240         }
2241         if(tr3) {
2242           linkNode1 = link13->first;
2243           linkNode2 = link13->second;
2244           if ( tr3 && getQuadrangleNodes( n13, linkNode1, linkNode2, tr1, tr3 ))
2245             Ok13 = true;
2246         }
2247
2248         // Choose a pair to fuse
2249         if ( Ok12 && Ok13 ) {
2250           SMDS_FaceOfNodes quad12 ( n12[ 0 ], n12[ 1 ], n12[ 2 ], n12[ 3 ] );
2251           SMDS_FaceOfNodes quad13 ( n13[ 0 ], n13[ 1 ], n13[ 2 ], n13[ 3 ] );
2252           double aBadRate12 = getBadRate( &quad12, theCrit );
2253           double aBadRate13 = getBadRate( &quad13, theCrit );
2254           if (  aBadRate13 < aBadRate12 )
2255             Ok12 = false;
2256           else
2257             Ok13 = false;
2258         }
2259
2260         // Make quadrangles
2261         // and remove fused elems and removed links from the maps
2262         mapEl_setLi.erase( tr1 );
2263         if ( Ok12 ) {
2264           mapEl_setLi.erase( tr2 );
2265           mapLi_listEl.erase( *link12 );
2266           if(tr1->NbNodes()==3) {
2267             const SMDS_MeshElement* newElem = 0;
2268             newElem = aMesh->AddFace(n12[0], n12[1], n12[2], n12[3] );
2269             myLastCreatedElems.Append(newElem);
2270             AddToSameGroups( newElem, tr1, aMesh );
2271             int aShapeId = tr1->getshapeId();
2272             if ( aShapeId )
2273               {
2274                 aMesh->SetMeshElementOnShape( newElem, aShapeId );
2275               }
2276             aMesh->RemoveElement( tr1 );
2277             aMesh->RemoveElement( tr2 );
2278           }
2279           else {
2280             const SMDS_MeshNode* N1 [6];
2281             const SMDS_MeshNode* N2 [6];
2282             GetNodesFromTwoTria(tr1,tr2,N1,N2);
2283             // now we receive following N1 and N2 (using numeration as above image)
2284             // tria1 : (1 2 4 5 9 7)  and  tria2 : (3 4 2 8 9 6)
2285             // i.e. first nodes from both arrays determ new diagonal
2286             const SMDS_MeshNode* aNodes[8];
2287             aNodes[0] = N1[0];
2288             aNodes[1] = N1[1];
2289             aNodes[2] = N2[0];
2290             aNodes[3] = N2[1];
2291             aNodes[4] = N1[3];
2292             aNodes[5] = N2[5];
2293             aNodes[6] = N2[3];
2294             aNodes[7] = N1[5];
2295             const SMDS_MeshElement* newElem = 0;
2296             newElem = aMesh->AddFace(aNodes[0], aNodes[1], aNodes[2], aNodes[3],
2297                                      aNodes[4], aNodes[5], aNodes[6], aNodes[7]);
2298             myLastCreatedElems.Append(newElem);
2299             AddToSameGroups( newElem, tr1, aMesh );
2300             int aShapeId = tr1->getshapeId();
2301             if ( aShapeId )
2302               {
2303                 aMesh->SetMeshElementOnShape( newElem, aShapeId );
2304               }
2305             aMesh->RemoveElement( tr1 );
2306             aMesh->RemoveElement( tr2 );
2307             // remove middle node (9)
2308             GetMeshDS()->RemoveNode( N1[4] );
2309           }
2310         }
2311         else if ( Ok13 ) {
2312           mapEl_setLi.erase( tr3 );
2313           mapLi_listEl.erase( *link13 );
2314           if(tr1->NbNodes()==3) {
2315             const SMDS_MeshElement* newElem = 0;
2316             newElem = aMesh->AddFace(n13[0], n13[1], n13[2], n13[3] );
2317             myLastCreatedElems.Append(newElem);
2318             AddToSameGroups( newElem, tr1, aMesh );
2319             int aShapeId = tr1->getshapeId();
2320             if ( aShapeId )
2321               {
2322                 aMesh->SetMeshElementOnShape( newElem, aShapeId );
2323               }
2324             aMesh->RemoveElement( tr1 );
2325             aMesh->RemoveElement( tr3 );
2326           }
2327           else {
2328             const SMDS_MeshNode* N1 [6];
2329             const SMDS_MeshNode* N2 [6];
2330             GetNodesFromTwoTria(tr1,tr3,N1,N2);
2331             // now we receive following N1 and N2 (using numeration as above image)
2332             // tria1 : (1 2 4 5 9 7)  and  tria2 : (3 4 2 8 9 6)
2333             // i.e. first nodes from both arrays determ new diagonal
2334             const SMDS_MeshNode* aNodes[8];
2335             aNodes[0] = N1[0];
2336             aNodes[1] = N1[1];
2337             aNodes[2] = N2[0];
2338             aNodes[3] = N2[1];
2339             aNodes[4] = N1[3];
2340             aNodes[5] = N2[5];
2341             aNodes[6] = N2[3];
2342             aNodes[7] = N1[5];
2343             const SMDS_MeshElement* newElem = 0;
2344             newElem = aMesh->AddFace(aNodes[0], aNodes[1], aNodes[2], aNodes[3],
2345                                      aNodes[4], aNodes[5], aNodes[6], aNodes[7]);
2346             myLastCreatedElems.Append(newElem);
2347             AddToSameGroups( newElem, tr1, aMesh );
2348             int aShapeId = tr1->getshapeId();
2349             if ( aShapeId )
2350               {
2351                 aMesh->SetMeshElementOnShape( newElem, aShapeId );
2352               }
2353             aMesh->RemoveElement( tr1 );
2354             aMesh->RemoveElement( tr3 );
2355             // remove middle node (9)
2356             GetMeshDS()->RemoveNode( N1[4] );
2357           }
2358         }
2359
2360         // Next element to fuse: the rejected one
2361         if ( tr3 )
2362           startElem = Ok12 ? tr3 : tr2;
2363
2364       } // if ( startElem )
2365     } // while ( startElem || !startLinks.empty() )
2366   } // while ( ! mapEl_setLi.empty() )
2367
2368   return true;
2369 }
2370
2371
2372 /*#define DUMPSO(txt) \
2373 //  cout << txt << endl;
2374 //=============================================================================
2375 //
2376 //
2377 //
2378 //=============================================================================
2379 static void swap( int i1, int i2, int idNodes[], gp_Pnt P[] )
2380 {
2381 if ( i1 == i2 )
2382 return;
2383 int tmp = idNodes[ i1 ];
2384 idNodes[ i1 ] = idNodes[ i2 ];
2385 idNodes[ i2 ] = tmp;
2386 gp_Pnt Ptmp = P[ i1 ];
2387 P[ i1 ] = P[ i2 ];
2388 P[ i2 ] = Ptmp;
2389 DUMPSO( i1 << "(" << idNodes[ i2 ] << ") <-> " << i2 << "(" << idNodes[ i1 ] << ")");
2390 }
2391
2392 //=======================================================================
2393 //function : SortQuadNodes
2394 //purpose  : Set 4 nodes of a quadrangle face in a good order.
2395 //           Swap 1<->2 or 2<->3 nodes and correspondingly return
2396 //           1 or 2 else 0.
2397 //=======================================================================
2398
2399 int SMESH_MeshEditor::SortQuadNodes (const SMDS_Mesh * theMesh,
2400 int               idNodes[] )
2401 {
2402   gp_Pnt P[4];
2403   int i;
2404   for ( i = 0; i < 4; i++ ) {
2405     const SMDS_MeshNode *n = theMesh->FindNode( idNodes[i] );
2406     if ( !n ) return 0;
2407     P[ i ].SetCoord( n->X(), n->Y(), n->Z() );
2408   }
2409
2410   gp_Vec V1(P[0], P[1]);
2411   gp_Vec V2(P[0], P[2]);
2412   gp_Vec V3(P[0], P[3]);
2413
2414   gp_Vec Cross1 = V1 ^ V2;
2415   gp_Vec Cross2 = V2 ^ V3;
2416
2417   i = 0;
2418   if (Cross1.Dot(Cross2) < 0)
2419   {
2420     Cross1 = V2 ^ V1;
2421     Cross2 = V1 ^ V3;
2422
2423     if (Cross1.Dot(Cross2) < 0)
2424       i = 2;
2425     else
2426       i = 1;
2427     swap ( i, i + 1, idNodes, P );
2428
2429     //     for ( int ii = 0; ii < 4; ii++ ) {
2430     //       const SMDS_MeshNode *n = theMesh->FindNode( idNodes[ii] );
2431     //       DUMPSO( ii << "(" << idNodes[ii] <<") : "<<n->X()<<" "<<n->Y()<<" "<<n->Z());
2432     //     }
2433   }
2434   return i;
2435 }
2436
2437 //=======================================================================
2438 //function : SortHexaNodes
2439 //purpose  : Set 8 nodes of a hexahedron in a good order.
2440 //           Return success status
2441 //=======================================================================
2442
2443 bool SMESH_MeshEditor::SortHexaNodes (const SMDS_Mesh * theMesh,
2444                                       int               idNodes[] )
2445 {
2446   gp_Pnt P[8];
2447   int i;
2448   DUMPSO( "INPUT: ========================================");
2449   for ( i = 0; i < 8; i++ ) {
2450     const SMDS_MeshNode *n = theMesh->FindNode( idNodes[i] );
2451     if ( !n ) return false;
2452     P[ i ].SetCoord( n->X(), n->Y(), n->Z() );
2453     DUMPSO( i << "(" << idNodes[i] <<") : "<<n->X()<<" "<<n->Y()<<" "<<n->Z());
2454   }
2455   DUMPSO( "========================================");
2456
2457
2458   set<int> faceNodes;  // ids of bottom face nodes, to be found
2459   set<int> checkedId1; // ids of tried 2-nd nodes
2460   Standard_Real leastDist = DBL_MAX; // dist of the 4-th node from 123 plane
2461   const Standard_Real tol = 1.e-6;   // tolerance to find nodes in plane
2462   int iMin, iLoop1 = 0;
2463
2464   // Loop to try the 2-nd nodes
2465
2466   while ( leastDist > DBL_MIN && ++iLoop1 < 8 )
2467   {
2468     // Find not checked 2-nd node
2469     for ( i = 1; i < 8; i++ )
2470       if ( checkedId1.find( idNodes[i] ) == checkedId1.end() ) {
2471         int id1 = idNodes[i];
2472         swap ( 1, i, idNodes, P );
2473         checkedId1.insert ( id1 );
2474         break;
2475       }
2476
2477     // Find the 3-d node so that 1-2-3 triangle to be on a hexa face,
2478     // ie that all but meybe one (id3 which is on the same face) nodes
2479     // lay on the same side from the triangle plane.
2480
2481     bool manyInPlane = false; // more than 4 nodes lay in plane
2482     int iLoop2 = 0;
2483     while ( ++iLoop2 < 6 ) {
2484
2485       // get 1-2-3 plane coeffs
2486       Standard_Real A, B, C, D;
2487       gp_Vec N = gp_Vec (P[0], P[1]).Crossed( gp_Vec (P[0], P[2]) );
2488       if ( N.SquareMagnitude() > gp::Resolution() )
2489       {
2490         gp_Pln pln ( P[0], N );
2491         pln.Coefficients( A, B, C, D );
2492
2493         // find the node (iMin) closest to pln
2494         Standard_Real dist[ 8 ], minDist = DBL_MAX;
2495         set<int> idInPln;
2496         for ( i = 3; i < 8; i++ ) {
2497           dist[i] = A * P[i].X() + B * P[i].Y() + C * P[i].Z() + D;
2498           if ( fabs( dist[i] ) < minDist ) {
2499             minDist = fabs( dist[i] );
2500             iMin = i;
2501           }
2502           if ( fabs( dist[i] ) <= tol )
2503             idInPln.insert( idNodes[i] );
2504         }
2505
2506         // there should not be more than 4 nodes in bottom plane
2507         if ( idInPln.size() > 1 )
2508         {
2509           DUMPSO( "### idInPln.size() = " << idInPln.size());
2510           // idInPlane does not contain the first 3 nodes
2511           if ( manyInPlane || idInPln.size() == 5)
2512             return false; // all nodes in one plane
2513           manyInPlane = true;
2514
2515           // set the 1-st node to be not in plane
2516           for ( i = 3; i < 8; i++ ) {
2517             if ( idInPln.find( idNodes[ i ] ) == idInPln.end() ) {
2518               DUMPSO( "### Reset 0-th node");
2519               swap( 0, i, idNodes, P );
2520               break;
2521             }
2522           }
2523
2524           // reset to re-check second nodes
2525           leastDist = DBL_MAX;
2526           faceNodes.clear();
2527           checkedId1.clear();
2528           iLoop1 = 0;
2529           break; // from iLoop2;
2530         }
2531
2532         // check that the other 4 nodes are on the same side
2533         bool sameSide = true;
2534         bool isNeg = dist[ iMin == 3 ? 4 : 3 ] <= 0.;
2535         for ( i = 3; sameSide && i < 8; i++ ) {
2536           if ( i != iMin )
2537             sameSide = ( isNeg == dist[i] <= 0.);
2538         }
2539
2540         // keep best solution
2541         if ( sameSide && minDist < leastDist ) {
2542           leastDist = minDist;
2543           faceNodes.clear();
2544           faceNodes.insert( idNodes[ 1 ] );
2545           faceNodes.insert( idNodes[ 2 ] );
2546           faceNodes.insert( idNodes[ iMin ] );
2547           DUMPSO( "loop " << iLoop2 << " id2 " << idNodes[ 1 ] << " id3 " << idNodes[ 2 ]
2548                   << " leastDist = " << leastDist);
2549           if ( leastDist <= DBL_MIN )
2550             break;
2551         }
2552       }
2553
2554       // set next 3-d node to check
2555       int iNext = 2 + iLoop2;
2556       if ( iNext < 8 ) {
2557         DUMPSO( "Try 2-nd");
2558         swap ( 2, iNext, idNodes, P );
2559       }
2560     } // while ( iLoop2 < 6 )
2561   } // iLoop1
2562
2563   if ( faceNodes.empty() ) return false;
2564
2565   // Put the faceNodes in proper places
2566   for ( i = 4; i < 8; i++ ) {
2567     if ( faceNodes.find( idNodes[ i ] ) != faceNodes.end() ) {
2568       // find a place to put
2569       int iTo = 1;
2570       while ( faceNodes.find( idNodes[ iTo ] ) != faceNodes.end() )
2571         iTo++;
2572       DUMPSO( "Set faceNodes");
2573       swap ( iTo, i, idNodes, P );
2574     }
2575   }
2576
2577
2578   // Set nodes of the found bottom face in good order
2579   DUMPSO( " Found bottom face: ");
2580   i = SortQuadNodes( theMesh, idNodes );
2581   if ( i ) {
2582     gp_Pnt Ptmp = P[ i ];
2583     P[ i ] = P[ i+1 ];
2584     P[ i+1 ] = Ptmp;
2585   }
2586   //   else
2587   //     for ( int ii = 0; ii < 4; ii++ ) {
2588   //       const SMDS_MeshNode *n = theMesh->FindNode( idNodes[ii] );
2589   //       DUMPSO( ii << "(" << idNodes[ii] <<") : "<<n->X()<<" "<<n->Y()<<" "<<n->Z());
2590   //    }
2591
2592   // Gravity center of the top and bottom faces
2593   gp_Pnt aGCb = ( P[0].XYZ() + P[1].XYZ() + P[2].XYZ() + P[3].XYZ() ) / 4.;
2594   gp_Pnt aGCt = ( P[4].XYZ() + P[5].XYZ() + P[6].XYZ() + P[7].XYZ() ) / 4.;
2595
2596   // Get direction from the bottom to the top face
2597   gp_Vec upDir ( aGCb, aGCt );
2598   Standard_Real upDirSize = upDir.Magnitude();
2599   if ( upDirSize <= gp::Resolution() ) return false;
2600   upDir / upDirSize;
2601
2602   // Assure that the bottom face normal points up
2603   gp_Vec Nb = gp_Vec (P[0], P[1]).Crossed( gp_Vec (P[0], P[2]) );
2604   Nb += gp_Vec (P[0], P[2]).Crossed( gp_Vec (P[0], P[3]) );
2605   if ( Nb.Dot( upDir ) < 0 ) {
2606     DUMPSO( "Reverse bottom face");
2607     swap( 1, 3, idNodes, P );
2608   }
2609
2610   // Find 5-th node - the one closest to the 1-st among the last 4 nodes.
2611   Standard_Real minDist = DBL_MAX;
2612   for ( i = 4; i < 8; i++ ) {
2613     // projection of P[i] to the plane defined by P[0] and upDir
2614     gp_Pnt Pp = P[i].Translated( upDir * ( upDir.Dot( gp_Vec( P[i], P[0] ))));
2615     Standard_Real sqDist = P[0].SquareDistance( Pp );
2616     if ( sqDist < minDist ) {
2617       minDist = sqDist;
2618       iMin = i;
2619     }
2620   }
2621   DUMPSO( "Set 4-th");
2622   swap ( 4, iMin, idNodes, P );
2623
2624   // Set nodes of the top face in good order
2625   DUMPSO( "Sort top face");
2626   i = SortQuadNodes( theMesh, &idNodes[4] );
2627   if ( i ) {
2628     i += 4;
2629     gp_Pnt Ptmp = P[ i ];
2630     P[ i ] = P[ i+1 ];
2631     P[ i+1 ] = Ptmp;
2632   }
2633
2634   // Assure that direction of the top face normal is from the bottom face
2635   gp_Vec Nt = gp_Vec (P[4], P[5]).Crossed( gp_Vec (P[4], P[6]) );
2636   Nt += gp_Vec (P[4], P[6]).Crossed( gp_Vec (P[4], P[7]) );
2637   if ( Nt.Dot( upDir ) < 0 ) {
2638     DUMPSO( "Reverse top face");
2639     swap( 5, 7, idNodes, P );
2640   }
2641
2642   //   DUMPSO( "OUTPUT: ========================================");
2643   //   for ( i = 0; i < 8; i++ ) {
2644   //     float *p = ugrid->GetPoint(idNodes[i]);
2645   //     DUMPSO( i << "(" << idNodes[i] << ") : " << p[0] << " " << p[1] << " " << p[2]);
2646   //   }
2647
2648   return true;
2649 }*/
2650
2651 //================================================================================
2652 /*!
2653  * \brief Return nodes linked to the given one
2654  * \param theNode - the node
2655  * \param linkedNodes - the found nodes
2656  * \param type - the type of elements to check
2657  *
2658  * Medium nodes are ignored
2659  */
2660 //================================================================================
2661
2662 void SMESH_MeshEditor::GetLinkedNodes( const SMDS_MeshNode* theNode,
2663                                        TIDSortedElemSet &   linkedNodes,
2664                                        SMDSAbs_ElementType  type )
2665 {
2666   SMDS_ElemIteratorPtr elemIt = theNode->GetInverseElementIterator(type);
2667   while ( elemIt->more() )
2668   {
2669     const SMDS_MeshElement* elem = elemIt->next();
2670     if(elem->GetType() == SMDSAbs_0DElement)
2671       continue;
2672     
2673     SMDS_ElemIteratorPtr nodeIt = elem->nodesIterator();
2674     if ( elem->GetType() == SMDSAbs_Volume )
2675     {
2676       SMDS_VolumeTool vol( elem );
2677       while ( nodeIt->more() ) {
2678         const SMDS_MeshNode* n = cast2Node( nodeIt->next() );
2679         if ( theNode != n && vol.IsLinked( theNode, n ))
2680           linkedNodes.insert( n );
2681       }
2682     }
2683     else
2684     {
2685       for ( int i = 0; nodeIt->more(); ++i ) {
2686         const SMDS_MeshNode* n = cast2Node( nodeIt->next() );
2687         if ( n == theNode ) {
2688           int iBefore = i - 1;
2689           int iAfter  = i + 1;
2690           if ( elem->IsQuadratic() ) {
2691             int nb = elem->NbNodes() / 2;
2692             iAfter  = SMESH_MesherHelper::WrapIndex( iAfter, nb );
2693             iBefore = SMESH_MesherHelper::WrapIndex( iBefore, nb );
2694           }
2695           linkedNodes.insert( elem->GetNodeWrap( iAfter ));
2696           linkedNodes.insert( elem->GetNodeWrap( iBefore ));
2697         }
2698       }
2699     }
2700   }
2701 }
2702
2703 //=======================================================================
2704 //function : laplacianSmooth
2705 //purpose  : pulls theNode toward the center of surrounding nodes directly
2706 //           connected to that node along an element edge
2707 //=======================================================================
2708
2709 void laplacianSmooth(const SMDS_MeshNode*                 theNode,
2710                      const Handle(Geom_Surface)&          theSurface,
2711                      map< const SMDS_MeshNode*, gp_XY* >& theUVMap)
2712 {
2713   // find surrounding nodes
2714
2715   TIDSortedElemSet nodeSet;
2716   SMESH_MeshEditor::GetLinkedNodes( theNode, nodeSet, SMDSAbs_Face );
2717
2718   // compute new coodrs
2719
2720   double coord[] = { 0., 0., 0. };
2721   TIDSortedElemSet::iterator nodeSetIt = nodeSet.begin();
2722   for ( ; nodeSetIt != nodeSet.end(); nodeSetIt++ ) {
2723     const SMDS_MeshNode* node = cast2Node(*nodeSetIt);
2724     if ( theSurface.IsNull() ) { // smooth in 3D
2725       coord[0] += node->X();
2726       coord[1] += node->Y();
2727       coord[2] += node->Z();
2728     }
2729     else { // smooth in 2D
2730       ASSERT( theUVMap.find( node ) != theUVMap.end() );
2731       gp_XY* uv = theUVMap[ node ];
2732       coord[0] += uv->X();
2733       coord[1] += uv->Y();
2734     }
2735   }
2736   int nbNodes = nodeSet.size();
2737   if ( !nbNodes )
2738     return;
2739   coord[0] /= nbNodes;
2740   coord[1] /= nbNodes;
2741
2742   if ( !theSurface.IsNull() ) {
2743     ASSERT( theUVMap.find( theNode ) != theUVMap.end() );
2744     theUVMap[ theNode ]->SetCoord( coord[0], coord[1] );
2745     gp_Pnt p3d = theSurface->Value( coord[0], coord[1] );
2746     coord[0] = p3d.X();
2747     coord[1] = p3d.Y();
2748     coord[2] = p3d.Z();
2749   }
2750   else
2751     coord[2] /= nbNodes;
2752
2753   // move node
2754
2755   const_cast< SMDS_MeshNode* >( theNode )->setXYZ(coord[0],coord[1],coord[2]);
2756 }
2757
2758 //=======================================================================
2759 //function : centroidalSmooth
2760 //purpose  : pulls theNode toward the element-area-weighted centroid of the
2761 //           surrounding elements
2762 //=======================================================================
2763
2764 void centroidalSmooth(const SMDS_MeshNode*                 theNode,
2765                       const Handle(Geom_Surface)&          theSurface,
2766                       map< const SMDS_MeshNode*, gp_XY* >& theUVMap)
2767 {
2768   gp_XYZ aNewXYZ(0.,0.,0.);
2769   SMESH::Controls::Area anAreaFunc;
2770   double totalArea = 0.;
2771   int nbElems = 0;
2772
2773   // compute new XYZ
2774
2775   SMDS_ElemIteratorPtr elemIt = theNode->GetInverseElementIterator(SMDSAbs_Face);
2776   while ( elemIt->more() )
2777   {
2778     const SMDS_MeshElement* elem = elemIt->next();
2779     nbElems++;
2780
2781     gp_XYZ elemCenter(0.,0.,0.);
2782     SMESH::Controls::TSequenceOfXYZ aNodePoints;
2783     SMDS_ElemIteratorPtr itN = elem->nodesIterator();
2784     int nn = elem->NbNodes();
2785     if(elem->IsQuadratic()) nn = nn/2;
2786     int i=0;
2787     //while ( itN->more() ) {
2788     while ( i<nn ) {
2789       const SMDS_MeshNode* aNode = static_cast<const SMDS_MeshNode*>( itN->next() );
2790       i++;
2791       gp_XYZ aP( aNode->X(), aNode->Y(), aNode->Z() );
2792       aNodePoints.push_back( aP );
2793       if ( !theSurface.IsNull() ) { // smooth in 2D
2794         ASSERT( theUVMap.find( aNode ) != theUVMap.end() );
2795         gp_XY* uv = theUVMap[ aNode ];
2796         aP.SetCoord( uv->X(), uv->Y(), 0. );
2797       }
2798       elemCenter += aP;
2799     }
2800     double elemArea = anAreaFunc.GetValue( aNodePoints );
2801     totalArea += elemArea;
2802     elemCenter /= nn;
2803     aNewXYZ += elemCenter * elemArea;
2804   }
2805   aNewXYZ /= totalArea;
2806   if ( !theSurface.IsNull() ) {
2807     theUVMap[ theNode ]->SetCoord( aNewXYZ.X(), aNewXYZ.Y() );
2808     aNewXYZ = theSurface->Value( aNewXYZ.X(), aNewXYZ.Y() ).XYZ();
2809   }
2810
2811   // move node
2812
2813   const_cast< SMDS_MeshNode* >( theNode )->setXYZ(aNewXYZ.X(),aNewXYZ.Y(),aNewXYZ.Z());
2814 }
2815
2816 //=======================================================================
2817 //function : getClosestUV
2818 //purpose  : return UV of closest projection
2819 //=======================================================================
2820
2821 static bool getClosestUV (Extrema_GenExtPS& projector,
2822                           const gp_Pnt&     point,
2823                           gp_XY &           result)
2824 {
2825   projector.Perform( point );
2826   if ( projector.IsDone() ) {
2827     double u, v, minVal = DBL_MAX;
2828     for ( int i = projector.NbExt(); i > 0; i-- )
2829       if ( projector.Value( i ) < minVal ) {
2830         minVal = projector.Value( i );
2831         projector.Point( i ).Parameter( u, v );
2832       }
2833     result.SetCoord( u, v );
2834     return true;
2835   }
2836   return false;
2837 }
2838
2839 //=======================================================================
2840 //function : Smooth
2841 //purpose  : Smooth theElements during theNbIterations or until a worst
2842 //           element has aspect ratio <= theTgtAspectRatio.
2843 //           Aspect Ratio varies in range [1.0, inf].
2844 //           If theElements is empty, the whole mesh is smoothed.
2845 //           theFixedNodes contains additionally fixed nodes. Nodes built
2846 //           on edges and boundary nodes are always fixed.
2847 //=======================================================================
2848
2849 void SMESH_MeshEditor::Smooth (TIDSortedElemSet &          theElems,
2850                                set<const SMDS_MeshNode*> & theFixedNodes,
2851                                const SmoothMethod          theSmoothMethod,
2852                                const int                   theNbIterations,
2853                                double                      theTgtAspectRatio,
2854                                const bool                  the2D)
2855 {
2856   myLastCreatedElems.Clear();
2857   myLastCreatedNodes.Clear();
2858
2859   MESSAGE((theSmoothMethod==LAPLACIAN ? "LAPLACIAN" : "CENTROIDAL") << "--::Smooth()");
2860
2861   if ( theTgtAspectRatio < 1.0 )
2862     theTgtAspectRatio = 1.0;
2863
2864   const double disttol = 1.e-16;
2865
2866   SMESH::Controls::AspectRatio aQualityFunc;
2867
2868   SMESHDS_Mesh* aMesh = GetMeshDS();
2869
2870   if ( theElems.empty() ) {
2871     // add all faces to theElems
2872     SMDS_FaceIteratorPtr fIt = aMesh->facesIterator();
2873     while ( fIt->more() ) {
2874       const SMDS_MeshElement* face = fIt->next();
2875       theElems.insert( face );
2876     }
2877   }
2878   // get all face ids theElems are on
2879   set< int > faceIdSet;
2880   TIDSortedElemSet::iterator itElem;
2881   if ( the2D )
2882     for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
2883       int fId = FindShape( *itElem );
2884       // check that corresponding submesh exists and a shape is face
2885       if (fId &&
2886           faceIdSet.find( fId ) == faceIdSet.end() &&
2887           aMesh->MeshElements( fId )) {
2888         TopoDS_Shape F = aMesh->IndexToShape( fId );
2889         if ( !F.IsNull() && F.ShapeType() == TopAbs_FACE )
2890           faceIdSet.insert( fId );
2891       }
2892     }
2893   faceIdSet.insert( 0 ); // to smooth elements that are not on any TopoDS_Face
2894
2895   // ===============================================
2896   // smooth elements on each TopoDS_Face separately
2897   // ===============================================
2898
2899   set< int >::reverse_iterator fId = faceIdSet.rbegin(); // treate 0 fId at the end
2900   for ( ; fId != faceIdSet.rend(); ++fId ) {
2901     // get face surface and submesh
2902     Handle(Geom_Surface) surface;
2903     SMESHDS_SubMesh* faceSubMesh = 0;
2904     TopoDS_Face face;
2905     double fToler2 = 0, f,l;
2906     double u1 = 0, u2 = 0, v1 = 0, v2 = 0;
2907     bool isUPeriodic = false, isVPeriodic = false;
2908     if ( *fId ) {
2909       face = TopoDS::Face( aMesh->IndexToShape( *fId ));
2910       surface = BRep_Tool::Surface( face );
2911       faceSubMesh = aMesh->MeshElements( *fId );
2912       fToler2 = BRep_Tool::Tolerance( face );
2913       fToler2 *= fToler2 * 10.;
2914       isUPeriodic = surface->IsUPeriodic();
2915       if ( isUPeriodic )
2916         surface->UPeriod();
2917       isVPeriodic = surface->IsVPeriodic();
2918       if ( isVPeriodic )
2919         surface->VPeriod();
2920       surface->Bounds( u1, u2, v1, v2 );
2921     }
2922     // ---------------------------------------------------------
2923     // for elements on a face, find movable and fixed nodes and
2924     // compute UV for them
2925     // ---------------------------------------------------------
2926     bool checkBoundaryNodes = false;
2927     bool isQuadratic = false;
2928     set<const SMDS_MeshNode*> setMovableNodes;
2929     map< const SMDS_MeshNode*, gp_XY* > uvMap, uvMap2;
2930     list< gp_XY > listUV; // uvs the 2 uvMaps refer to
2931     list< const SMDS_MeshElement* > elemsOnFace;
2932
2933     Extrema_GenExtPS projector;
2934     GeomAdaptor_Surface surfAdaptor;
2935     if ( !surface.IsNull() ) {
2936       surfAdaptor.Load( surface );
2937       projector.Initialize( surfAdaptor, 20,20, 1e-5,1e-5 );
2938     }
2939     int nbElemOnFace = 0;
2940     itElem = theElems.begin();
2941     // loop on not yet smoothed elements: look for elems on a face
2942     while ( itElem != theElems.end() ) {
2943       if ( faceSubMesh && nbElemOnFace == faceSubMesh->NbElements() )
2944         break; // all elements found
2945
2946       const SMDS_MeshElement* elem = *itElem;
2947       if ( !elem || elem->GetType() != SMDSAbs_Face || elem->NbNodes() < 3 ||
2948            ( faceSubMesh && !faceSubMesh->Contains( elem ))) {
2949         ++itElem;
2950         continue;
2951       }
2952       elemsOnFace.push_back( elem );
2953       theElems.erase( itElem++ );
2954       nbElemOnFace++;
2955
2956       if ( !isQuadratic )
2957         isQuadratic = elem->IsQuadratic();
2958
2959       // get movable nodes of elem
2960       const SMDS_MeshNode* node;
2961       SMDS_TypeOfPosition posType;
2962       SMDS_ElemIteratorPtr itN = elem->nodesIterator();
2963       int nn = 0, nbn =  elem->NbNodes();
2964       if(elem->IsQuadratic())
2965         nbn = nbn/2;
2966       while ( nn++ < nbn ) {
2967         node = static_cast<const SMDS_MeshNode*>( itN->next() );
2968         const SMDS_PositionPtr& pos = node->GetPosition();
2969         posType = pos ? pos->GetTypeOfPosition() : SMDS_TOP_3DSPACE;
2970         if (posType != SMDS_TOP_EDGE &&
2971             posType != SMDS_TOP_VERTEX &&
2972             theFixedNodes.find( node ) == theFixedNodes.end())
2973         {
2974           // check if all faces around the node are on faceSubMesh
2975           // because a node on edge may be bound to face
2976           SMDS_ElemIteratorPtr eIt = node->GetInverseElementIterator(SMDSAbs_Face);
2977           bool all = true;
2978           if ( faceSubMesh ) {
2979             while ( eIt->more() && all ) {
2980               const SMDS_MeshElement* e = eIt->next();
2981               all = faceSubMesh->Contains( e );
2982             }
2983           }
2984           if ( all )
2985             setMovableNodes.insert( node );
2986           else
2987             checkBoundaryNodes = true;
2988         }
2989         if ( posType == SMDS_TOP_3DSPACE )
2990           checkBoundaryNodes = true;
2991       }
2992
2993       if ( surface.IsNull() )
2994         continue;
2995
2996       // get nodes to check UV
2997       list< const SMDS_MeshNode* > uvCheckNodes;
2998       itN = elem->nodesIterator();
2999       nn = 0; nbn =  elem->NbNodes();
3000       if(elem->IsQuadratic())
3001         nbn = nbn/2;
3002       while ( nn++ < nbn ) {
3003         node = static_cast<const SMDS_MeshNode*>( itN->next() );
3004         if ( uvMap.find( node ) == uvMap.end() )
3005           uvCheckNodes.push_back( node );
3006         // add nodes of elems sharing node
3007         //         SMDS_ElemIteratorPtr eIt = node->GetInverseElementIterator(SMDSAbs_Face);
3008         //         while ( eIt->more() ) {
3009         //           const SMDS_MeshElement* e = eIt->next();
3010         //           if ( e != elem ) {
3011         //             SMDS_ElemIteratorPtr nIt = e->nodesIterator();
3012         //             while ( nIt->more() ) {
3013         //               const SMDS_MeshNode* n =
3014         //                 static_cast<const SMDS_MeshNode*>( nIt->next() );
3015         //               if ( uvMap.find( n ) == uvMap.end() )
3016         //                 uvCheckNodes.push_back( n );
3017         //             }
3018         //           }
3019         //         }
3020       }
3021       // check UV on face
3022       list< const SMDS_MeshNode* >::iterator n = uvCheckNodes.begin();
3023       for ( ; n != uvCheckNodes.end(); ++n ) {
3024         node = *n;
3025         gp_XY uv( 0, 0 );
3026         const SMDS_PositionPtr& pos = node->GetPosition();
3027         posType = pos ? pos->GetTypeOfPosition() : SMDS_TOP_3DSPACE;
3028         // get existing UV
3029         switch ( posType ) {
3030         case SMDS_TOP_FACE: {
3031           SMDS_FacePosition* fPos = ( SMDS_FacePosition* ) pos;
3032           uv.SetCoord( fPos->GetUParameter(), fPos->GetVParameter() );
3033           break;
3034         }
3035         case SMDS_TOP_EDGE: {
3036           TopoDS_Shape S = aMesh->IndexToShape( node->getshapeId() );
3037           Handle(Geom2d_Curve) pcurve;
3038           if ( !S.IsNull() && S.ShapeType() == TopAbs_EDGE )
3039             pcurve = BRep_Tool::CurveOnSurface( TopoDS::Edge( S ), face, f,l );
3040           if ( !pcurve.IsNull() ) {
3041             double u = (( SMDS_EdgePosition* ) pos )->GetUParameter();
3042             uv = pcurve->Value( u ).XY();
3043           }
3044           break;
3045         }
3046         case SMDS_TOP_VERTEX: {
3047           TopoDS_Shape S = aMesh->IndexToShape( node->getshapeId() );
3048           if ( !S.IsNull() && S.ShapeType() == TopAbs_VERTEX )
3049             uv = BRep_Tool::Parameters( TopoDS::Vertex( S ), face ).XY();
3050           break;
3051         }
3052         default:;
3053         }
3054         // check existing UV
3055         bool project = true;
3056         gp_Pnt pNode ( node->X(), node->Y(), node->Z() );
3057         double dist1 = DBL_MAX, dist2 = 0;
3058         if ( posType != SMDS_TOP_3DSPACE ) {
3059           dist1 = pNode.SquareDistance( surface->Value( uv.X(), uv.Y() ));
3060           project = dist1 > fToler2;
3061         }
3062         if ( project ) { // compute new UV
3063           gp_XY newUV;
3064           if ( !getClosestUV( projector, pNode, newUV )) {
3065             MESSAGE("Node Projection Failed " << node);
3066           }
3067           else {
3068             if ( isUPeriodic )
3069               newUV.SetX( ElCLib::InPeriod( newUV.X(), u1, u2 ));
3070             if ( isVPeriodic )
3071               newUV.SetY( ElCLib::InPeriod( newUV.Y(), v1, v2 ));
3072             // check new UV
3073             if ( posType != SMDS_TOP_3DSPACE )
3074               dist2 = pNode.SquareDistance( surface->Value( newUV.X(), newUV.Y() ));
3075             if ( dist2 < dist1 )
3076               uv = newUV;
3077           }
3078         }
3079         // store UV in the map
3080         listUV.push_back( uv );
3081         uvMap.insert( make_pair( node, &listUV.back() ));
3082       }
3083     } // loop on not yet smoothed elements
3084
3085     if ( !faceSubMesh || nbElemOnFace != faceSubMesh->NbElements() )
3086       checkBoundaryNodes = true;
3087
3088     // fix nodes on mesh boundary
3089
3090     if ( checkBoundaryNodes ) {
3091       map< NLink, int > linkNbMap; // how many times a link encounters in elemsOnFace
3092       map< NLink, int >::iterator link_nb;
3093       // put all elements links to linkNbMap
3094       list< const SMDS_MeshElement* >::iterator elemIt = elemsOnFace.begin();
3095       for ( ; elemIt != elemsOnFace.end(); ++elemIt ) {
3096         const SMDS_MeshElement* elem = (*elemIt);
3097         int nbn =  elem->NbNodes();
3098         if(elem->IsQuadratic())
3099           nbn = nbn/2;
3100         // loop on elem links: insert them in linkNbMap
3101         const SMDS_MeshNode* curNode, *prevNode = elem->GetNodeWrap( nbn );
3102         for ( int iN = 0; iN < nbn; ++iN ) {
3103           curNode = elem->GetNode( iN );
3104           NLink link;
3105           if ( curNode < prevNode ) link = make_pair( curNode , prevNode );
3106           else                      link = make_pair( prevNode , curNode );
3107           prevNode = curNode;
3108           link_nb = linkNbMap.find( link );
3109           if ( link_nb == linkNbMap.end() )
3110             linkNbMap.insert( make_pair ( link, 1 ));
3111           else
3112             link_nb->second++;
3113         }
3114       }
3115       // remove nodes that are in links encountered only once from setMovableNodes
3116       for ( link_nb = linkNbMap.begin(); link_nb != linkNbMap.end(); ++link_nb ) {
3117         if ( link_nb->second == 1 ) {
3118           setMovableNodes.erase( link_nb->first.first );
3119           setMovableNodes.erase( link_nb->first.second );
3120         }
3121       }
3122     }
3123
3124     // -----------------------------------------------------
3125     // for nodes on seam edge, compute one more UV ( uvMap2 );
3126     // find movable nodes linked to nodes on seam and which
3127     // are to be smoothed using the second UV ( uvMap2 )
3128     // -----------------------------------------------------
3129
3130     set<const SMDS_MeshNode*> nodesNearSeam; // to smooth using uvMap2
3131     if ( !surface.IsNull() ) {
3132       TopExp_Explorer eExp( face, TopAbs_EDGE );
3133       for ( ; eExp.More(); eExp.Next() ) {
3134         TopoDS_Edge edge = TopoDS::Edge( eExp.Current() );
3135         if ( !BRep_Tool::IsClosed( edge, face ))
3136           continue;
3137         SMESHDS_SubMesh* sm = aMesh->MeshElements( edge );
3138         if ( !sm ) continue;
3139         // find out which parameter varies for a node on seam
3140         double f,l;
3141         gp_Pnt2d uv1, uv2;
3142         Handle(Geom2d_Curve) pcurve = BRep_Tool::CurveOnSurface( edge, face, f, l );
3143         if ( pcurve.IsNull() ) continue;
3144         uv1 = pcurve->Value( f );
3145         edge.Reverse();
3146         pcurve = BRep_Tool::CurveOnSurface( edge, face, f, l );
3147         if ( pcurve.IsNull() ) continue;
3148         uv2 = pcurve->Value( f );
3149         int iPar = Abs( uv1.X() - uv2.X() ) > Abs( uv1.Y() - uv2.Y() ) ? 1 : 2;
3150         // assure uv1 < uv2
3151         if ( uv1.Coord( iPar ) > uv2.Coord( iPar )) {
3152           gp_Pnt2d tmp = uv1; uv1 = uv2; uv2 = tmp;
3153         }
3154         // get nodes on seam and its vertices
3155         list< const SMDS_MeshNode* > seamNodes;
3156         SMDS_NodeIteratorPtr nSeamIt = sm->GetNodes();
3157         while ( nSeamIt->more() ) {
3158           const SMDS_MeshNode* node = nSeamIt->next();
3159           if ( !isQuadratic || !IsMedium( node ))
3160             seamNodes.push_back( node );
3161         }
3162         TopExp_Explorer vExp( edge, TopAbs_VERTEX );
3163         for ( ; vExp.More(); vExp.Next() ) {
3164           sm = aMesh->MeshElements( vExp.Current() );
3165           if ( sm ) {
3166             nSeamIt = sm->GetNodes();
3167             while ( nSeamIt->more() )
3168               seamNodes.push_back( nSeamIt->next() );
3169           }
3170         }
3171         // loop on nodes on seam
3172         list< const SMDS_MeshNode* >::iterator noSeIt = seamNodes.begin();
3173         for ( ; noSeIt != seamNodes.end(); ++noSeIt ) {
3174           const SMDS_MeshNode* nSeam = *noSeIt;
3175           map< const SMDS_MeshNode*, gp_XY* >::iterator n_uv = uvMap.find( nSeam );
3176           if ( n_uv == uvMap.end() )
3177             continue;
3178           // set the first UV
3179           n_uv->second->SetCoord( iPar, uv1.Coord( iPar ));
3180           // set the second UV
3181           listUV.push_back( *n_uv->second );
3182           listUV.back().SetCoord( iPar, uv2.Coord( iPar ));
3183           if ( uvMap2.empty() )
3184             uvMap2 = uvMap; // copy the uvMap contents
3185           uvMap2[ nSeam ] = &listUV.back();
3186
3187           // collect movable nodes linked to ones on seam in nodesNearSeam
3188           SMDS_ElemIteratorPtr eIt = nSeam->GetInverseElementIterator(SMDSAbs_Face);
3189           while ( eIt->more() ) {
3190             const SMDS_MeshElement* e = eIt->next();
3191             int nbUseMap1 = 0, nbUseMap2 = 0;
3192             SMDS_ElemIteratorPtr nIt = e->nodesIterator();
3193             int nn = 0, nbn =  e->NbNodes();
3194             if(e->IsQuadratic()) nbn = nbn/2;
3195             while ( nn++ < nbn )
3196             {
3197               const SMDS_MeshNode* n =
3198                 static_cast<const SMDS_MeshNode*>( nIt->next() );
3199               if (n == nSeam ||
3200                   setMovableNodes.find( n ) == setMovableNodes.end() )
3201                 continue;
3202               // add only nodes being closer to uv2 than to uv1
3203               gp_Pnt pMid (0.5 * ( n->X() + nSeam->X() ),
3204                            0.5 * ( n->Y() + nSeam->Y() ),
3205                            0.5 * ( n->Z() + nSeam->Z() ));
3206               gp_XY uv;
3207               getClosestUV( projector, pMid, uv );
3208               if ( uv.Coord( iPar ) > uvMap[ n ]->Coord( iPar ) ) {
3209                 nodesNearSeam.insert( n );
3210                 nbUseMap2++;
3211               }
3212               else
3213                 nbUseMap1++;
3214             }
3215             // for centroidalSmooth all element nodes must
3216             // be on one side of a seam
3217             if ( theSmoothMethod == CENTROIDAL && nbUseMap1 && nbUseMap2 ) {
3218               SMDS_ElemIteratorPtr nIt = e->nodesIterator();
3219               nn = 0;
3220               while ( nn++ < nbn ) {
3221                 const SMDS_MeshNode* n =
3222                   static_cast<const SMDS_MeshNode*>( nIt->next() );
3223                 setMovableNodes.erase( n );
3224               }
3225             }
3226           }
3227         } // loop on nodes on seam
3228       } // loop on edge of a face
3229     } // if ( !face.IsNull() )
3230
3231     if ( setMovableNodes.empty() ) {
3232       MESSAGE( "Face id : " << *fId << " - NO SMOOTHING: no nodes to move!!!");
3233       continue; // goto next face
3234     }
3235
3236     // -------------
3237     // SMOOTHING //
3238     // -------------
3239
3240     int it = -1;
3241     double maxRatio = -1., maxDisplacement = -1.;
3242     set<const SMDS_MeshNode*>::iterator nodeToMove;
3243     for ( it = 0; it < theNbIterations; it++ ) {
3244       maxDisplacement = 0.;
3245       nodeToMove = setMovableNodes.begin();
3246       for ( ; nodeToMove != setMovableNodes.end(); nodeToMove++ ) {
3247         const SMDS_MeshNode* node = (*nodeToMove);
3248         gp_XYZ aPrevPos ( node->X(), node->Y(), node->Z() );
3249
3250         // smooth
3251         bool map2 = ( nodesNearSeam.find( node ) != nodesNearSeam.end() );
3252         if ( theSmoothMethod == LAPLACIAN )
3253           laplacianSmooth( node, surface, map2 ? uvMap2 : uvMap );
3254         else
3255           centroidalSmooth( node, surface, map2 ? uvMap2 : uvMap );
3256
3257         // node displacement
3258         gp_XYZ aNewPos ( node->X(), node->Y(), node->Z() );
3259         Standard_Real aDispl = (aPrevPos - aNewPos).SquareModulus();
3260         if ( aDispl > maxDisplacement )
3261           maxDisplacement = aDispl;
3262       }
3263       // no node movement => exit
3264       //if ( maxDisplacement < 1.e-16 ) {
3265       if ( maxDisplacement < disttol ) {
3266         MESSAGE("-- no node movement --");
3267         break;
3268       }
3269
3270       // check elements quality
3271       maxRatio  = 0;
3272       list< const SMDS_MeshElement* >::iterator elemIt = elemsOnFace.begin();
3273       for ( ; elemIt != elemsOnFace.end(); ++elemIt ) {
3274         const SMDS_MeshElement* elem = (*elemIt);
3275         if ( !elem || elem->GetType() != SMDSAbs_Face )
3276           continue;
3277         SMESH::Controls::TSequenceOfXYZ aPoints;
3278         if ( aQualityFunc.GetPoints( elem, aPoints )) {
3279           double aValue = aQualityFunc.GetValue( aPoints );
3280           if ( aValue > maxRatio )
3281             maxRatio = aValue;
3282         }
3283       }
3284       if ( maxRatio <= theTgtAspectRatio ) {
3285         MESSAGE("-- quality achived --");
3286         break;
3287       }
3288       if (it+1 == theNbIterations) {
3289         MESSAGE("-- Iteration limit exceeded --");
3290       }
3291     } // smoothing iterations
3292
3293     MESSAGE(" Face id: " << *fId <<
3294             " Nb iterstions: " << it <<
3295             " Displacement: " << maxDisplacement <<
3296             " Aspect Ratio " << maxRatio);
3297
3298     // ---------------------------------------
3299     // new nodes positions are computed,
3300     // record movement in DS and set new UV
3301     // ---------------------------------------
3302     nodeToMove = setMovableNodes.begin();
3303     for ( ; nodeToMove != setMovableNodes.end(); nodeToMove++ ) {
3304       SMDS_MeshNode* node = const_cast< SMDS_MeshNode* > (*nodeToMove);
3305       aMesh->MoveNode( node, node->X(), node->Y(), node->Z() );
3306       map< const SMDS_MeshNode*, gp_XY* >::iterator node_uv = uvMap.find( node );
3307       if ( node_uv != uvMap.end() ) {
3308         gp_XY* uv = node_uv->second;
3309         node->SetPosition
3310           ( SMDS_PositionPtr( new SMDS_FacePosition( uv->X(), uv->Y() )));
3311       }
3312     }
3313
3314     // move medium nodes of quadratic elements
3315     if ( isQuadratic )
3316     {
3317       SMESH_MesherHelper helper( *GetMesh() );
3318       if ( !face.IsNull() )
3319         helper.SetSubShape( face );
3320       list< const SMDS_MeshElement* >::iterator elemIt = elemsOnFace.begin();
3321       for ( ; elemIt != elemsOnFace.end(); ++elemIt ) {
3322         const SMDS_VtkFace* QF =
3323           dynamic_cast<const SMDS_VtkFace*> (*elemIt);
3324         if(QF && QF->IsQuadratic()) {
3325           vector<const SMDS_MeshNode*> Ns;
3326           Ns.reserve(QF->NbNodes()+1);
3327           SMDS_ElemIteratorPtr anIter = QF->interlacedNodesElemIterator();
3328           while ( anIter->more() )
3329             Ns.push_back( cast2Node(anIter->next()) );
3330           Ns.push_back( Ns[0] );
3331           double x, y, z;
3332           for(int i=0; i<QF->NbNodes(); i=i+2) {
3333             if ( !surface.IsNull() ) {
3334               gp_XY uv1 = helper.GetNodeUV( face, Ns[i], Ns[i+2] );
3335               gp_XY uv2 = helper.GetNodeUV( face, Ns[i+2], Ns[i] );
3336               gp_XY uv = ( uv1 + uv2 ) / 2.;
3337               gp_Pnt xyz = surface->Value( uv.X(), uv.Y() );
3338               x = xyz.X(); y = xyz.Y(); z = xyz.Z();
3339             }
3340             else {
3341               x = (Ns[i]->X() + Ns[i+2]->X())/2;
3342               y = (Ns[i]->Y() + Ns[i+2]->Y())/2;
3343               z = (Ns[i]->Z() + Ns[i+2]->Z())/2;
3344             }
3345             if( fabs( Ns[i+1]->X() - x ) > disttol ||
3346                 fabs( Ns[i+1]->Y() - y ) > disttol ||
3347                 fabs( Ns[i+1]->Z() - z ) > disttol ) {
3348               // we have to move i+1 node
3349               aMesh->MoveNode( Ns[i+1], x, y, z );
3350             }
3351           }
3352         }
3353       }
3354     }
3355
3356   } // loop on face ids
3357
3358 }
3359
3360 //=======================================================================
3361 //function : isReverse
3362 //purpose  : Return true if normal of prevNodes is not co-directied with
3363 //           gp_Vec(prevNodes[iNotSame],nextNodes[iNotSame]).
3364 //           iNotSame is where prevNodes and nextNodes are different
3365 //=======================================================================
3366
3367 static bool isReverse(vector<const SMDS_MeshNode*> prevNodes,
3368                       vector<const SMDS_MeshNode*> nextNodes,
3369                       const int            nbNodes,
3370                       const int            iNotSame)
3371 {
3372   int iBeforeNotSame = ( iNotSame == 0 ? nbNodes - 1 : iNotSame - 1 );
3373   int iAfterNotSame  = ( iNotSame + 1 == nbNodes ? 0 : iNotSame + 1 );
3374
3375   const SMDS_MeshNode* nB = prevNodes[ iBeforeNotSame ];
3376   const SMDS_MeshNode* nA = prevNodes[ iAfterNotSame ];
3377   const SMDS_MeshNode* nP = prevNodes[ iNotSame ];
3378   const SMDS_MeshNode* nN = nextNodes[ iNotSame ];
3379
3380   gp_Pnt pB ( nB->X(), nB->Y(), nB->Z() );
3381   gp_Pnt pA ( nA->X(), nA->Y(), nA->Z() );
3382   gp_Pnt pP ( nP->X(), nP->Y(), nP->Z() );
3383   gp_Pnt pN ( nN->X(), nN->Y(), nN->Z() );
3384
3385   gp_Vec vB ( pP, pB ), vA ( pP, pA ), vN ( pP, pN );
3386
3387   return (vA ^ vB) * vN < 0.0;
3388 }
3389
3390 //=======================================================================
3391 /*!
3392  * \brief Create elements by sweeping an element
3393  * \param elem - element to sweep
3394  * \param newNodesItVec - nodes generated from each node of the element
3395  * \param newElems - generated elements
3396  * \param nbSteps - number of sweeping steps
3397  * \param srcElements - to append elem for each generated element
3398  */
3399 //=======================================================================
3400
3401 void SMESH_MeshEditor::sweepElement(const SMDS_MeshElement*               elem,
3402                                     const vector<TNodeOfNodeListMapItr> & newNodesItVec,
3403                                     list<const SMDS_MeshElement*>&        newElems,
3404                                     const int                             nbSteps,
3405                                     SMESH_SequenceOfElemPtr&              srcElements)
3406 {
3407   //MESSAGE("sweepElement " << nbSteps);
3408   SMESHDS_Mesh* aMesh = GetMeshDS();
3409
3410   // Loop on elem nodes:
3411   // find new nodes and detect same nodes indices
3412   int nbNodes = elem->NbNodes();
3413   vector < list< const SMDS_MeshNode* >::const_iterator > itNN( nbNodes );
3414   vector<const SMDS_MeshNode*> prevNod( nbNodes );
3415   vector<const SMDS_MeshNode*> nextNod( nbNodes );
3416   vector<const SMDS_MeshNode*> midlNod( nbNodes );
3417
3418   int iNode, nbSame = 0, iNotSameNode = 0, iSameNode = 0;
3419   vector<int> sames(nbNodes);
3420   vector<bool> issimple(nbNodes);
3421
3422   for ( iNode = 0; iNode < nbNodes; iNode++ ) {
3423     TNodeOfNodeListMapItr nnIt = newNodesItVec[ iNode ];
3424     const SMDS_MeshNode*                 node         = nnIt->first;
3425     const list< const SMDS_MeshNode* > & listNewNodes = nnIt->second;
3426     if ( listNewNodes.empty() ) {
3427       return;
3428     }
3429
3430     issimple[iNode] = (listNewNodes.size()==nbSteps); // is node medium
3431
3432     itNN[ iNode ] = listNewNodes.begin();
3433     prevNod[ iNode ] = node;
3434     nextNod[ iNode ] = listNewNodes.front();
3435     if( !elem->IsQuadratic() || !issimple[iNode] ) {
3436       if ( prevNod[ iNode ] != nextNod [ iNode ])
3437         iNotSameNode = iNode;
3438       else {
3439         iSameNode = iNode;
3440         //nbSame++;
3441         sames[nbSame++] = iNode;
3442       }
3443     }
3444   }
3445
3446   //cerr<<"  nbSame = "<<nbSame<<endl;
3447   if ( nbSame == nbNodes || nbSame > 2) {
3448     MESSAGE( " Too many same nodes of element " << elem->GetID() );
3449     //INFOS( " Too many same nodes of element " << elem->GetID() );
3450     return;
3451   }
3452
3453   //  if( elem->IsQuadratic() && nbSame>0 ) {
3454   //    MESSAGE( "Can not rotate quadratic element " << elem->GetID() );
3455   //    return;
3456   //  }
3457
3458   int iBeforeSame = 0, iAfterSame = 0, iOpposSame = 0;
3459   int nbBaseNodes = ( elem->IsQuadratic() ? nbNodes/2 : nbNodes );
3460   if ( nbSame > 0 ) {
3461     iBeforeSame = ( iSameNode == 0 ? nbBaseNodes - 1 : iSameNode - 1 );
3462     iAfterSame  = ( iSameNode + 1 == nbBaseNodes ? 0 : iSameNode + 1 );
3463     iOpposSame  = ( iSameNode - 2 < 0  ? iSameNode + 2 : iSameNode - 2 );
3464   }
3465
3466   //if(nbNodes==8)
3467   //cout<<" prevNod[0]="<< prevNod[0]<<" prevNod[1]="<< prevNod[1]
3468   //    <<" prevNod[2]="<< prevNod[2]<<" prevNod[3]="<< prevNod[4]
3469   //    <<" prevNod[4]="<< prevNod[4]<<" prevNod[5]="<< prevNod[5]
3470   //    <<" prevNod[6]="<< prevNod[6]<<" prevNod[7]="<< prevNod[7]<<endl;
3471
3472   // check element orientation
3473   int i0 = 0, i2 = 2;
3474   if ( nbNodes > 2 && !isReverse( prevNod, nextNod, nbNodes, iNotSameNode )) {
3475     //MESSAGE("Reversed elem " << elem );
3476     i0 = 2;
3477     i2 = 0;
3478     if ( nbSame > 0 )
3479       std::swap( iBeforeSame, iAfterSame );
3480   }
3481
3482   // make new elements
3483   const SMDS_MeshElement* lastElem = elem;
3484   for (int iStep = 0; iStep < nbSteps; iStep++ ) {
3485     // get next nodes
3486     for ( iNode = 0; iNode < nbNodes; iNode++ ) {
3487       if(issimple[iNode]) {
3488         nextNod[ iNode ] = *itNN[ iNode ];
3489         itNN[ iNode ]++;
3490       }
3491       else {
3492         if( elem->GetType()==SMDSAbs_Node ) {
3493           // we have to use two nodes
3494           midlNod[ iNode ] = *itNN[ iNode ];
3495           itNN[ iNode ]++;
3496           nextNod[ iNode ] = *itNN[ iNode ];
3497           itNN[ iNode ]++;
3498         }
3499         else if(!elem->IsQuadratic() || lastElem->IsMediumNode(prevNod[iNode]) ) {
3500           // we have to use each second node
3501           //itNN[ iNode ]++;
3502           nextNod[ iNode ] = *itNN[ iNode ];
3503           itNN[ iNode ]++;
3504         }
3505         else {
3506           // we have to use two nodes
3507           midlNod[ iNode ] = *itNN[ iNode ];
3508           itNN[ iNode ]++;
3509           nextNod[ iNode ] = *itNN[ iNode ];
3510           itNN[ iNode ]++;
3511         }
3512       }
3513     }
3514     SMDS_MeshElement* aNewElem = 0;
3515     if(!elem->IsPoly()) {
3516       switch ( nbNodes ) {
3517       case 0:
3518         return;
3519       case 1: { // NODE
3520         if ( nbSame == 0 ) {
3521           if(issimple[0])
3522             aNewElem = aMesh->AddEdge( prevNod[ 0 ], nextNod[ 0 ] );
3523           else
3524             aNewElem = aMesh->AddEdge( prevNod[ 0 ], nextNod[ 0 ], midlNod[ 0 ] );
3525         }
3526         break;
3527       }
3528       case 2: { // EDGE
3529         if ( nbSame == 0 )
3530           aNewElem = aMesh->AddFace(prevNod[ 0 ], prevNod[ 1 ],
3531                                     nextNod[ 1 ], nextNod[ 0 ] );
3532         else
3533           aNewElem = aMesh->AddFace(prevNod[ 0 ], prevNod[ 1 ],
3534                                     nextNod[ iNotSameNode ] );
3535         break;
3536       }
3537
3538       case 3: { // TRIANGLE or quadratic edge
3539         if(elem->GetType() == SMDSAbs_Face) { // TRIANGLE
3540
3541           if ( nbSame == 0 )       // --- pentahedron
3542             aNewElem = aMesh->AddVolume (prevNod[ i0 ], prevNod[ 1 ], prevNod[ i2 ],
3543                                          nextNod[ i0 ], nextNod[ 1 ], nextNod[ i2 ] );
3544
3545           else if ( nbSame == 1 )  // --- pyramid
3546             aNewElem = aMesh->AddVolume (prevNod[ iBeforeSame ],  prevNod[ iAfterSame ],
3547                                          nextNod[ iAfterSame ], nextNod[ iBeforeSame ],
3548                                          nextNod[ iSameNode ]);
3549
3550           else // 2 same nodes:      --- tetrahedron
3551             aNewElem = aMesh->AddVolume (prevNod[ i0 ], prevNod[ 1 ], prevNod[ i2 ],
3552                                          nextNod[ iNotSameNode ]);
3553         }
3554         else { // quadratic edge
3555           if(nbSame==0) {     // quadratic quadrangle
3556             aNewElem = aMesh->AddFace(prevNod[0], nextNod[0], nextNod[1], prevNod[1],
3557                                       midlNod[0], nextNod[2], midlNod[1], prevNod[2]);
3558           }
3559           else if(nbSame==1) { // quadratic triangle
3560             if(sames[0]==2) {
3561               return; // medium node on axis
3562             }
3563             else if(sames[0]==0) {
3564               aNewElem = aMesh->AddFace(prevNod[0], nextNod[1], prevNod[1],
3565                                         nextNod[2], midlNod[1], prevNod[2]);
3566             }
3567             else { // sames[0]==1
3568               aNewElem = aMesh->AddFace(prevNod[0], nextNod[0], prevNod[1],
3569                                         midlNod[0], nextNod[2], prevNod[2]);
3570             }
3571           }
3572           else {
3573             return;
3574           }
3575         }
3576         break;
3577       }
3578       case 4: { // QUADRANGLE
3579
3580         if ( nbSame == 0 )       // --- hexahedron
3581           aNewElem = aMesh->AddVolume (prevNod[ i0 ], prevNod[ 1 ], prevNod[ i2 ], prevNod[ 3 ],
3582                                        nextNod[ i0 ], nextNod[ 1 ], nextNod[ i2 ], nextNod[ 3 ]);
3583
3584         else if ( nbSame == 1 ) { // --- pyramid + pentahedron
3585           aNewElem = aMesh->AddVolume (prevNod[ iBeforeSame ],  prevNod[ iAfterSame ],
3586                                        nextNod[ iAfterSame ], nextNod[ iBeforeSame ],
3587                                        nextNod[ iSameNode ]);
3588           newElems.push_back( aNewElem );
3589           aNewElem = aMesh->AddVolume (prevNod[ iAfterSame ], prevNod[ iOpposSame ],
3590                                        prevNod[ iBeforeSame ],  nextNod[ iAfterSame ],
3591                                        nextNod[ iOpposSame ],  nextNod[ iBeforeSame ] );
3592         }
3593         else if ( nbSame == 2 ) { // pentahedron
3594           if ( prevNod[ iBeforeSame ] == nextNod[ iBeforeSame ] )
3595             // iBeforeSame is same too
3596             aNewElem = aMesh->AddVolume (prevNod[ iBeforeSame ], prevNod[ iOpposSame ],
3597                                          nextNod[ iOpposSame ], prevNod[ iSameNode ],
3598                                          prevNod[ iAfterSame ],  nextNod[ iAfterSame ]);
3599           else
3600             // iAfterSame is same too
3601             aNewElem = aMesh->AddVolume (prevNod[ iSameNode ], prevNod[ iBeforeSame ],
3602                                          nextNod[ iBeforeSame ], prevNod[ iAfterSame ],
3603                                          prevNod[ iOpposSame ],  nextNod[ iOpposSame ]);
3604         }
3605         break;
3606       }
3607       case 6: { // quadratic triangle
3608         // create pentahedron with 15 nodes
3609         if(nbSame==0) {
3610           if(i0>0) { // reversed case
3611             aNewElem = aMesh->AddVolume (prevNod[0], prevNod[2], prevNod[1],
3612                                          nextNod[0], nextNod[2], nextNod[1],
3613                                          prevNod[5], prevNod[4], prevNod[3],
3614                                          nextNod[5], nextNod[4], nextNod[3],
3615                                          midlNod[0], midlNod[2], midlNod[1]);
3616           }
3617           else { // not reversed case
3618             aNewElem = aMesh->AddVolume (prevNod[0], prevNod[1], prevNod[2],
3619                                          nextNod[0], nextNod[1], nextNod[2],
3620                                          prevNod[3], prevNod[4], prevNod[5],
3621                                          nextNod[3], nextNod[4], nextNod[5],
3622                                          midlNod[0], midlNod[1], midlNod[2]);
3623           }
3624         }
3625         else if(nbSame==1) {
3626           // 2d order pyramid of 13 nodes
3627           //SMDS_MeshVolume* AddVolumeWithID(int n1, int n2, int n3, int n4, int n5,
3628           //                                 int n12,int n23,int n34,int n41,
3629           //                                 int n15,int n25,int n35,int n45, int ID);
3630           int n5 = iSameNode;
3631           int n1,n4,n41,n15,n45;
3632           if(i0>0) { // reversed case
3633             n1 = ( n5 + 1 == nbBaseNodes ? 0 : n5 + 1 );
3634             n4 = ( n5 == 0 ? nbBaseNodes - 1 : n5 - 1 );
3635             n41 = n1 + 3;
3636             n15 = n5 + 3;
3637             n45 = n4 + 3;
3638           }
3639           else {
3640             n1 = ( n5 == 0 ? nbBaseNodes - 1 : n5 - 1 );
3641             n4 = ( n5 + 1 == nbBaseNodes ? 0 : n5 + 1 );
3642             n41 = n4 + 3;
3643             n15 = n1 + 3;
3644             n45 = n5 + 3;
3645           }
3646           aNewElem = aMesh->AddVolume(prevNod[n1], nextNod[n1],
3647                                       nextNod[n4], prevNod[n4], prevNod[n5],
3648                                       midlNod[n1], nextNod[n41],
3649                                       midlNod[n4], prevNod[n41],
3650                                       prevNod[n15], nextNod[n15],
3651                                       nextNod[n45], prevNod[n45]);
3652         }
3653         else if(nbSame==2) {
3654           // 2d order tetrahedron of 10 nodes
3655           //SMDS_MeshVolume* AddVolumeWithID(int n1, int n2, int n3, int n4,
3656           //                                 int n12,int n23,int n31,
3657           //                                 int n14,int n24,int n34, int ID);
3658           int n1 = iNotSameNode;
3659           int n2,n3,n12,n23,n31;
3660           if(i0>0) { // reversed case
3661             n2 = ( n1 == 0 ? nbBaseNodes - 1 : n1 - 1 );
3662             n3 = ( n1 + 1 == nbBaseNodes ? 0 : n1 + 1 );
3663             n12 = n2 + 3;
3664             n23 = n3 + 3;
3665             n31 = n1 + 3;
3666           }
3667           else {
3668             n2 = ( n1 + 1 == nbBaseNodes ? 0 : n1 + 1 );
3669             n3 = ( n1 == 0 ? nbBaseNodes - 1 : n1 - 1 );
3670             n12 = n1 + 3;
3671             n23 = n2 + 3;
3672             n31 = n3 + 3;
3673           }
3674           aNewElem = aMesh->AddVolume (prevNod[n1], prevNod[n2], prevNod[n3], nextNod[n1],
3675                                        prevNod[n12], prevNod[n23], prevNod[n31],
3676                                        midlNod[n1], nextNod[n12], nextNod[n31]);
3677         }
3678         break;
3679       }
3680       case 8: { // quadratic quadrangle
3681         if(nbSame==0) {
3682           // create hexahedron with 20 nodes
3683           if(i0>0) { // reversed case
3684             aNewElem = aMesh->AddVolume (prevNod[0], prevNod[3], prevNod[2], prevNod[1],
3685                                          nextNod[0], nextNod[3], nextNod[2], nextNod[1],
3686                                          prevNod[7], prevNod[6], prevNod[5], prevNod[4],
3687                                          nextNod[7], nextNod[6], nextNod[5], nextNod[4],
3688                                          midlNod[0], midlNod[3], midlNod[2], midlNod[1]);
3689           }
3690           else { // not reversed case
3691             aNewElem = aMesh->AddVolume (prevNod[0], prevNod[1], prevNod[2], prevNod[3],
3692                                          nextNod[0], nextNod[1], nextNod[2], nextNod[3],
3693                                          prevNod[4], prevNod[5], prevNod[6], prevNod[7],
3694                                          nextNod[4], nextNod[5], nextNod[6], nextNod[7],
3695                                          midlNod[0], midlNod[1], midlNod[2], midlNod[3]);
3696           }
3697         }
3698         else if(nbSame==1) { 
3699           // --- pyramid + pentahedron - can not be created since it is needed 
3700           // additional middle node ot the center of face
3701           INFOS( " Sweep for face " << elem->GetID() << " can not be created" );
3702           return;
3703         }
3704         else if(nbSame==2) {
3705           // 2d order Pentahedron with 15 nodes
3706           //SMDS_MeshVolume* AddVolumeWithID(int n1, int n2, int n3, int n4, int n5, int n6,
3707           //                                 int n12,int n23,int n31,int n45,int n56,int n64,
3708           //                                 int n14,int n25,int n36, int ID);
3709           int n1,n2,n4,n5;
3710           if ( prevNod[ iBeforeSame ] == nextNod[ iBeforeSame ] ) {
3711             // iBeforeSame is same too
3712             n1 = iBeforeSame;
3713             n2 = iOpposSame;
3714             n4 = iSameNode;
3715             n5 = iAfterSame;
3716           }
3717           else {
3718             // iAfterSame is same too
3719             n1 = iSameNode;
3720             n2 = iBeforeSame;
3721             n4 = iAfterSame;
3722             n5 = iOpposSame;
3723           }
3724           int n12,n45,n14,n25;
3725           if(i0>0) { //reversed case
3726             n12 = n1 + 4;
3727             n45 = n5 + 4;
3728             n14 = n4 + 4;
3729             n25 = n2 + 4;
3730           }
3731           else {
3732             n12 = n2 + 4;
3733             n45 = n4 + 4;
3734             n14 = n1 + 4;
3735             n25 = n5 + 4;
3736           }
3737           aNewElem = aMesh->AddVolume (prevNod[n1], prevNod[n2], nextNod[n2],
3738                                        prevNod[n4], prevNod[n5], nextNod[n5],
3739                                        prevNod[n12], midlNod[n2], nextNod[n12],
3740                                        prevNod[n45], midlNod[n5], nextNod[n45],
3741                                        prevNod[n14], prevNod[n25], nextNod[n25]);
3742         }
3743         break;
3744       }
3745       default: {
3746         // realized for extrusion only
3747         //vector<const SMDS_MeshNode*> polyedre_nodes (nbNodes*2 + 4*nbNodes);
3748         //vector<int> quantities (nbNodes + 2);
3749
3750         //quantities[0] = nbNodes; // bottom of prism
3751         //for (int inode = 0; inode < nbNodes; inode++) {
3752         //  polyedre_nodes[inode] = prevNod[inode];
3753         //}
3754
3755         //quantities[1] = nbNodes; // top of prism
3756         //for (int inode = 0; inode < nbNodes; inode++) {
3757         //  polyedre_nodes[nbNodes + inode] = nextNod[inode];
3758         //}
3759
3760         //for (int iface = 0; iface < nbNodes; iface++) {
3761         //  quantities[iface + 2] = 4;
3762         //  int inextface = (iface == nbNodes - 1) ? 0 : iface + 1;
3763         //  polyedre_nodes[2*nbNodes + 4*iface + 0] = prevNod[iface];
3764         //  polyedre_nodes[2*nbNodes + 4*iface + 1] = prevNod[inextface];
3765         //  polyedre_nodes[2*nbNodes + 4*iface + 2] = nextNod[inextface];
3766         //  polyedre_nodes[2*nbNodes + 4*iface + 3] = nextNod[iface];
3767         //}
3768         //aNewElem = aMesh->AddPolyhedralVolume (polyedre_nodes, quantities);
3769         break;
3770       }
3771       }
3772     }
3773
3774     if(!aNewElem) {
3775       // realized for extrusion only
3776       vector<const SMDS_MeshNode*> polyedre_nodes (nbNodes*2 + 4*nbNodes);
3777       vector<int> quantities (nbNodes + 2);
3778
3779       quantities[0] = nbNodes; // bottom of prism
3780       for (int inode = 0; inode < nbNodes; inode++) {
3781         polyedre_nodes[inode] = prevNod[inode];
3782       }
3783
3784       quantities[1] = nbNodes; // top of prism
3785       for (int inode = 0; inode < nbNodes; inode++) {
3786         polyedre_nodes[nbNodes + inode] = nextNod[inode];
3787       }
3788
3789       for (int iface = 0; iface < nbNodes; iface++) {
3790         quantities[iface + 2] = 4;
3791         int inextface = (iface == nbNodes - 1) ? 0 : iface + 1;
3792         polyedre_nodes[2*nbNodes + 4*iface + 0] = prevNod[iface];
3793         polyedre_nodes[2*nbNodes + 4*iface + 1] = prevNod[inextface];
3794         polyedre_nodes[2*nbNodes + 4*iface + 2] = nextNod[inextface];
3795         polyedre_nodes[2*nbNodes + 4*iface + 3] = nextNod[iface];
3796       }
3797       aNewElem = aMesh->AddPolyhedralVolume (polyedre_nodes, quantities);
3798     }
3799
3800     if ( aNewElem ) {
3801       newElems.push_back( aNewElem );
3802       myLastCreatedElems.Append(aNewElem);
3803       srcElements.Append( elem );
3804       lastElem = aNewElem;
3805     }
3806
3807     // set new prev nodes
3808     for ( iNode = 0; iNode < nbNodes; iNode++ )
3809       prevNod[ iNode ] = nextNod[ iNode ];
3810
3811   } // for steps
3812 }
3813
3814 //=======================================================================
3815 /*!
3816  * \brief Create 1D and 2D elements around swept elements
3817  * \param mapNewNodes - source nodes and ones generated from them
3818  * \param newElemsMap - source elements and ones generated from them
3819  * \param elemNewNodesMap - nodes generated from each node of each element
3820  * \param elemSet - all swept elements
3821  * \param nbSteps - number of sweeping steps
3822  * \param srcElements - to append elem for each generated element
3823  */
3824 //=======================================================================
3825
3826 void SMESH_MeshEditor::makeWalls (TNodeOfNodeListMap &     mapNewNodes,
3827                                   TElemOfElemListMap &     newElemsMap,
3828                                   TElemOfVecOfNnlmiMap &   elemNewNodesMap,
3829                                   TIDSortedElemSet&        elemSet,
3830                                   const int                nbSteps,
3831                                   SMESH_SequenceOfElemPtr& srcElements)
3832 {
3833   MESSAGE("makeWalls");
3834   ASSERT( newElemsMap.size() == elemNewNodesMap.size() );
3835   SMESHDS_Mesh* aMesh = GetMeshDS();
3836
3837   // Find nodes belonging to only one initial element - sweep them to get edges.
3838
3839   TNodeOfNodeListMapItr nList = mapNewNodes.begin();
3840   for ( ; nList != mapNewNodes.end(); nList++ ) {
3841     const SMDS_MeshNode* node =
3842       static_cast<const SMDS_MeshNode*>( nList->first );
3843     SMDS_ElemIteratorPtr eIt = node->GetInverseElementIterator();
3844     int nbInitElems = 0;
3845     const SMDS_MeshElement* el = 0;
3846     SMDSAbs_ElementType highType = SMDSAbs_Edge; // count most complex elements only
3847     while ( eIt->more() && nbInitElems < 2 ) {
3848       el = eIt->next();
3849       SMDSAbs_ElementType type = el->GetType();
3850       if ( type == SMDSAbs_Volume || type < highType ) continue;
3851       if ( type > highType ) {
3852         nbInitElems = 0;
3853         highType = type;
3854       }
3855       if ( elemSet.find(el) != elemSet.end() )
3856         nbInitElems++;
3857     }
3858     if ( nbInitElems < 2 ) {
3859       bool NotCreateEdge = el && el->IsQuadratic() && el->IsMediumNode(node);
3860       if(!NotCreateEdge) {
3861         vector<TNodeOfNodeListMapItr> newNodesItVec( 1, nList );
3862         list<const SMDS_MeshElement*> newEdges;
3863         sweepElement( node, newNodesItVec, newEdges, nbSteps, srcElements );
3864       }
3865     }
3866   }
3867
3868   // Make a ceiling for each element ie an equal element of last new nodes.
3869   // Find free links of faces - make edges and sweep them into faces.
3870
3871   TElemOfElemListMap::iterator   itElem      = newElemsMap.begin();
3872   TElemOfVecOfNnlmiMap::iterator itElemNodes = elemNewNodesMap.begin();
3873   for ( ; itElem != newElemsMap.end(); itElem++, itElemNodes++ ) {
3874     const SMDS_MeshElement* elem = itElem->first;
3875     vector<TNodeOfNodeListMapItr>& vecNewNodes = itElemNodes->second;
3876
3877     if(itElem->second.size()==0) continue;
3878
3879     if ( elem->GetType() == SMDSAbs_Edge ) {
3880       // create a ceiling edge
3881       if (!elem->IsQuadratic()) {
3882         if ( !aMesh->FindEdge( vecNewNodes[ 0 ]->second.back(),
3883                                vecNewNodes[ 1 ]->second.back())) {
3884           myLastCreatedElems.Append(aMesh->AddEdge(vecNewNodes[ 0 ]->second.back(),
3885                                                    vecNewNodes[ 1 ]->second.back()));
3886           srcElements.Append( myLastCreatedElems.Last() );
3887         }
3888       }
3889       else {
3890         if ( !aMesh->FindEdge( vecNewNodes[ 0 ]->second.back(),
3891                                vecNewNodes[ 1 ]->second.back(),
3892                                vecNewNodes[ 2 ]->second.back())) {
3893           myLastCreatedElems.Append(aMesh->AddEdge(vecNewNodes[ 0 ]->second.back(),
3894                                                    vecNewNodes[ 1 ]->second.back(),
3895                                                    vecNewNodes[ 2 ]->second.back()));
3896           srcElements.Append( myLastCreatedElems.Last() );
3897         }
3898       }
3899     }
3900     if ( elem->GetType() != SMDSAbs_Face )
3901       continue;
3902
3903     bool hasFreeLinks = false;
3904
3905     TIDSortedElemSet avoidSet;
3906     avoidSet.insert( elem );
3907
3908     set<const SMDS_MeshNode*> aFaceLastNodes;
3909     int iNode, nbNodes = vecNewNodes.size();
3910     if(!elem->IsQuadratic()) {
3911       // loop on the face nodes
3912       for ( iNode = 0; iNode < nbNodes; iNode++ ) {
3913         aFaceLastNodes.insert( vecNewNodes[ iNode ]->second.back() );
3914         // look for free links of the face
3915         int iNext = ( iNode + 1 == nbNodes ) ? 0 : iNode + 1;
3916         const SMDS_MeshNode* n1 = vecNewNodes[ iNode ]->first;
3917         const SMDS_MeshNode* n2 = vecNewNodes[ iNext ]->first;
3918         // check if a link is free
3919         if ( ! SMESH_MeshEditor::FindFaceInSet ( n1, n2, elemSet, avoidSet )) {
3920           hasFreeLinks = true;
3921           // make an edge and a ceiling for a new edge
3922           if ( !aMesh->FindEdge( n1, n2 )) {
3923             myLastCreatedElems.Append(aMesh->AddEdge( n1, n2 )); // free link edge
3924             srcElements.Append( myLastCreatedElems.Last() );
3925           }
3926           n1 = vecNewNodes[ iNode ]->second.back();
3927           n2 = vecNewNodes[ iNext ]->second.back();
3928           if ( !aMesh->FindEdge( n1, n2 )) {
3929             myLastCreatedElems.Append(aMesh->AddEdge( n1, n2 )); // ceiling edge
3930             srcElements.Append( myLastCreatedElems.Last() );
3931           }
3932         }
3933       }
3934     }
3935     else { // elem is quadratic face
3936       int nbn = nbNodes/2;
3937       for ( iNode = 0; iNode < nbn; iNode++ ) {
3938         aFaceLastNodes.insert( vecNewNodes[ iNode ]->second.back() );
3939         int iNext = ( iNode + 1 == nbn ) ? 0 : iNode + 1;
3940         const SMDS_MeshNode* n1 = vecNewNodes[ iNode ]->first;
3941         const SMDS_MeshNode* n2 = vecNewNodes[ iNext ]->first;
3942         // check if a link is free
3943         if ( ! SMESH_MeshEditor::FindFaceInSet ( n1, n2, elemSet, avoidSet )) {
3944           hasFreeLinks = true;
3945           // make an edge and a ceiling for a new edge
3946           // find medium node
3947           const SMDS_MeshNode* n3 = vecNewNodes[ iNode+nbn ]->first;
3948           if ( !aMesh->FindEdge( n1, n2, n3 )) {
3949             myLastCreatedElems.Append(aMesh->AddEdge( n1, n2, n3 )); // free link edge
3950             srcElements.Append( myLastCreatedElems.Last() );
3951           }
3952           n1 = vecNewNodes[ iNode ]->second.back();
3953           n2 = vecNewNodes[ iNext ]->second.back();
3954           n3 = vecNewNodes[ iNode+nbn ]->second.back();
3955           if ( !aMesh->FindEdge( n1, n2, n3 )) {
3956             myLastCreatedElems.Append(aMesh->AddEdge( n1, n2, n3 )); // ceiling edge
3957             srcElements.Append( myLastCreatedElems.Last() );
3958           }
3959         }
3960       }
3961       for ( iNode = nbn; iNode < 2*nbn; iNode++ ) {
3962         aFaceLastNodes.insert( vecNewNodes[ iNode ]->second.back() );
3963       }
3964     }
3965
3966     // sweep free links into faces
3967
3968     if ( hasFreeLinks )  {
3969       list<const SMDS_MeshElement*> & newVolumes = itElem->second;
3970       int iVol, volNb, nbVolumesByStep = newVolumes.size() / nbSteps;
3971
3972       set<const SMDS_MeshNode*> initNodeSet, topNodeSet, faceNodeSet;
3973       for ( iNode = 0; iNode < nbNodes; iNode++ ) {
3974         initNodeSet.insert( vecNewNodes[ iNode ]->first );
3975         topNodeSet .insert( vecNewNodes[ iNode ]->second.back() );
3976       }
3977       for ( volNb = 0; volNb < nbVolumesByStep; volNb++ ) {
3978         list<const SMDS_MeshElement*>::iterator v = newVolumes.begin();
3979         iVol = 0;
3980         while ( iVol++ < volNb ) v++;
3981         // find indices of free faces of a volume and their source edges
3982         list< int > freeInd;
3983         list< const SMDS_MeshElement* > srcEdges; // source edges of free faces
3984         SMDS_VolumeTool vTool( *v );
3985         int iF, nbF = vTool.NbFaces();
3986         for ( iF = 0; iF < nbF; iF ++ ) {
3987           if (vTool.IsFreeFace( iF ) &&
3988               vTool.GetFaceNodes( iF, faceNodeSet ) &&
3989               initNodeSet != faceNodeSet) // except an initial face
3990           {
3991             if ( nbSteps == 1 && faceNodeSet == topNodeSet )
3992               continue;
3993             freeInd.push_back( iF );
3994             // find source edge of a free face iF
3995             vector<const SMDS_MeshNode*> commonNodes; // shared by the initial and free faces
3996             commonNodes.resize( initNodeSet.size(), NULL ); // avoid spoiling memory
3997             std::set_intersection( faceNodeSet.begin(), faceNodeSet.end(),
3998                                    initNodeSet.begin(), initNodeSet.end(),
3999                                    commonNodes.begin());
4000             if ( (*v)->IsQuadratic() )
4001               srcEdges.push_back(aMesh->FindEdge (commonNodes[0],commonNodes[1],commonNodes[2]));
4002             else
4003               srcEdges.push_back(aMesh->FindEdge (commonNodes[0],commonNodes[1]));
4004 #ifdef _DEBUG_
4005             if ( !srcEdges.back() )
4006             {
4007               cout << "SMESH_MeshEditor::makeWalls(), no source edge found for a free face #"
4008                    << iF << " of volume #" << vTool.ID() << endl;
4009             }
4010 #endif
4011           }
4012         }
4013         if ( freeInd.empty() )
4014           continue;
4015
4016         // create faces for all steps;
4017         // if such a face has been already created by sweep of edge,
4018         // assure that its orientation is OK
4019         for ( int iStep = 0; iStep < nbSteps; iStep++ )  {
4020           vTool.Set( *v );
4021           vTool.SetExternalNormal();
4022           const int nextShift = vTool.IsForward() ? +1 : -1;
4023           list< int >::iterator ind = freeInd.begin();
4024           list< const SMDS_MeshElement* >::iterator srcEdge = srcEdges.begin();
4025           for ( ; ind != freeInd.end(); ++ind, ++srcEdge ) // loop on free faces
4026           {
4027             const SMDS_MeshNode** nodes = vTool.GetFaceNodes( *ind );
4028             int nbn = vTool.NbFaceNodes( *ind );
4029             if ( ! (*v)->IsPoly() )
4030               switch ( nbn ) {
4031               case 3: { ///// triangle
4032                 const SMDS_MeshFace * f = aMesh->FindFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ]);
4033                 if ( !f ||
4034                      nodes[ 1 ] != f->GetNodeWrap( f->GetNodeIndex( nodes[ 0 ]) + nextShift ))
4035                 {
4036                   const SMDS_MeshNode* newOrder[3] = { nodes[ 1 - nextShift ],
4037                                                        nodes[ 1 ],
4038                                                        nodes[ 1 + nextShift ] };
4039                   if ( f )
4040                     aMesh->ChangeElementNodes( f, &newOrder[0], nbn );
4041                   else
4042                     myLastCreatedElems.Append(aMesh->AddFace( newOrder[ 0 ], newOrder[ 1 ],
4043                                                               newOrder[ 2 ] ));
4044                 }
4045                 break;
4046               }
4047               case 4: { ///// quadrangle
4048                 const SMDS_MeshFace * f =
4049                   aMesh->FindFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ], nodes[ 3 ]);
4050                 if ( !f ||
4051                      nodes[ 1 ] != f->GetNodeWrap( f->GetNodeIndex( nodes[ 0 ]) + nextShift ))
4052                 {
4053                   const SMDS_MeshNode* newOrder[4] = { nodes[ 0 ], nodes[ 2-nextShift ],
4054                                                        nodes[ 2 ], nodes[ 2+nextShift ] };
4055                   if ( f )
4056                     aMesh->ChangeElementNodes( f, &newOrder[0], nbn );
4057                   else
4058                     myLastCreatedElems.Append(aMesh->AddFace( newOrder[ 0 ], newOrder[ 1 ],
4059                                                               newOrder[ 2 ], newOrder[ 3 ]));
4060                 }
4061                 break;
4062               }
4063               case 6: { /////// quadratic triangle
4064                 const SMDS_MeshFace * f = aMesh->FindFace( nodes[0], nodes[2], nodes[4],
4065                                                            nodes[1], nodes[3], nodes[5] );
4066                 if ( !f ||
4067                      nodes[2] != f->GetNodeWrap( f->GetNodeIndex( nodes[0] ) + 2*nextShift ))
4068                 {
4069                   const SMDS_MeshNode* newOrder[6] = { nodes[2 - 2*nextShift],
4070                                                        nodes[2],
4071                                                        nodes[2 + 2*nextShift],
4072                                                        nodes[3 - 2*nextShift],
4073                                                        nodes[3],
4074                                                        nodes[3 + 2*nextShift]};
4075                   if ( f )
4076                     aMesh->ChangeElementNodes( f, &newOrder[0], nbn );
4077                   else
4078                     myLastCreatedElems.Append(aMesh->AddFace( newOrder[ 0 ],
4079                                                               newOrder[ 1 ],
4080                                                               newOrder[ 2 ],
4081                                                               newOrder[ 3 ],
4082                                                               newOrder[ 4 ],
4083                                                               newOrder[ 5 ] ));
4084                 }
4085                 break;
4086               }
4087               default:       /////// quadratic quadrangle
4088                 const SMDS_MeshFace * f = aMesh->FindFace( nodes[0], nodes[2], nodes[4], nodes[6],
4089                                                            nodes[1], nodes[3], nodes[5], nodes[7] );
4090                 if ( !f ||
4091                      nodes[ 2 ] != f->GetNodeWrap( f->GetNodeIndex( nodes[ 0 ] ) + 2*nextShift ))
4092                 {
4093                   const SMDS_MeshNode* newOrder[8] = { nodes[0],
4094                                                        nodes[4 - 2*nextShift],
4095                                                        nodes[4],
4096                                                        nodes[4 + 2*nextShift],
4097                                                        nodes[1],
4098                                                        nodes[5 - 2*nextShift],
4099                                                        nodes[5],
4100                                                        nodes[5 + 2*nextShift] };
4101                   if ( f )
4102                     aMesh->ChangeElementNodes( f, &newOrder[0], nbn );
4103                   else
4104                     myLastCreatedElems.Append(aMesh->AddFace(newOrder[ 0 ], newOrder[ 1 ],
4105                                                              newOrder[ 2 ], newOrder[ 3 ],
4106                                                              newOrder[ 4 ], newOrder[ 5 ],
4107                                                              newOrder[ 6 ], newOrder[ 7 ]));
4108                 }
4109               } // switch ( nbn )
4110
4111             else { //////// polygon
4112
4113               vector<const SMDS_MeshNode*> polygon_nodes ( nodes, &nodes[nbn] );
4114               const SMDS_MeshFace * f = aMesh->FindFace( polygon_nodes );
4115               if ( !f ||
4116                    nodes[ 1 ] != f->GetNodeWrap( f->GetNodeIndex( nodes[ 0 ] ) + nextShift ))
4117               {
4118                 if ( !vTool.IsForward() )
4119                   std::reverse( polygon_nodes.begin(), polygon_nodes.end());
4120                 if ( f )
4121                   aMesh->ChangeElementNodes( f, &polygon_nodes[0], nbn );
4122                 else
4123                   myLastCreatedElems.Append(aMesh->AddPolygonalFace(polygon_nodes));
4124               }
4125             }
4126
4127             while ( srcElements.Length() < myLastCreatedElems.Length() )
4128               srcElements.Append( *srcEdge );
4129
4130           }  // loop on free faces
4131
4132           // go to the next volume
4133           iVol = 0;
4134           while ( iVol++ < nbVolumesByStep ) v++;
4135
4136         } // loop on steps
4137       } // loop on volumes of one step
4138     } // sweep free links into faces
4139
4140     // Make a ceiling face with a normal external to a volume
4141
4142     SMDS_VolumeTool lastVol( itElem->second.back() );
4143
4144     int iF = lastVol.GetFaceIndex( aFaceLastNodes );
4145     if ( iF >= 0 ) {
4146       lastVol.SetExternalNormal();
4147       const SMDS_MeshNode** nodes = lastVol.GetFaceNodes( iF );
4148       int nbn = lastVol.NbFaceNodes( iF );
4149       switch ( nbn ) {
4150       case 3:
4151         if (!hasFreeLinks ||
4152             !aMesh->FindFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ]))
4153           myLastCreatedElems.Append(aMesh->AddFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ] ));
4154         break;
4155       case 4:
4156         if (!hasFreeLinks ||
4157             !aMesh->FindFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ], nodes[ 3 ]))
4158           myLastCreatedElems.Append(aMesh->AddFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ], nodes[ 3 ] ));
4159         break;
4160       default:
4161         if(itElem->second.back()->IsQuadratic()) {
4162           if(nbn==6) {
4163             if (!hasFreeLinks ||
4164                 !aMesh->FindFace(nodes[0], nodes[2], nodes[4],
4165                                  nodes[1], nodes[3], nodes[5]) ) {
4166               myLastCreatedElems.Append(aMesh->AddFace(nodes[0], nodes[2], nodes[4],
4167                                                        nodes[1], nodes[3], nodes[5]));
4168             }
4169           }
4170           else { // nbn==8
4171             if (!hasFreeLinks ||
4172                 !aMesh->FindFace(nodes[0], nodes[2], nodes[4], nodes[6],
4173                                  nodes[1], nodes[3], nodes[5], nodes[7]) )
4174               myLastCreatedElems.Append(aMesh->AddFace(nodes[0], nodes[2], nodes[4], nodes[6],
4175                                                        nodes[1], nodes[3], nodes[5], nodes[7]));
4176           }
4177         }
4178         else {
4179           vector<const SMDS_MeshNode*> polygon_nodes ( nodes, &nodes[nbn] );
4180           if (!hasFreeLinks || !aMesh->FindFace(polygon_nodes))
4181             myLastCreatedElems.Append(aMesh->AddPolygonalFace(polygon_nodes));
4182         }
4183       } // switch
4184
4185       while ( srcElements.Length() < myLastCreatedElems.Length() )
4186         srcElements.Append( myLastCreatedElems.Last() );
4187     }
4188   } // loop on swept elements
4189 }
4190
4191 //=======================================================================
4192 //function : RotationSweep
4193 //purpose  :
4194 //=======================================================================
4195
4196 SMESH_MeshEditor::PGroupIDs
4197 SMESH_MeshEditor::RotationSweep(TIDSortedElemSet & theElems,
4198                                 const gp_Ax1&      theAxis,
4199                                 const double       theAngle,
4200                                 const int          theNbSteps,
4201                                 const double       theTol,
4202                                 const bool         theMakeGroups,
4203                                 const bool         theMakeWalls)
4204 {
4205   myLastCreatedElems.Clear();
4206   myLastCreatedNodes.Clear();
4207
4208   // source elements for each generated one
4209   SMESH_SequenceOfElemPtr srcElems, srcNodes;
4210
4211   MESSAGE( "RotationSweep()");
4212   gp_Trsf aTrsf;
4213   aTrsf.SetRotation( theAxis, theAngle );
4214   gp_Trsf aTrsf2;
4215   aTrsf2.SetRotation( theAxis, theAngle/2. );
4216
4217   gp_Lin aLine( theAxis );
4218   double aSqTol = theTol * theTol;
4219
4220   SMESHDS_Mesh* aMesh = GetMeshDS();
4221
4222   TNodeOfNodeListMap mapNewNodes;
4223   TElemOfVecOfNnlmiMap mapElemNewNodes;
4224   TElemOfElemListMap newElemsMap;
4225
4226   // loop on theElems
4227   TIDSortedElemSet::iterator itElem;
4228   for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
4229     const SMDS_MeshElement* elem = *itElem;
4230     if ( !elem || elem->GetType() == SMDSAbs_Volume )
4231       continue;
4232     vector<TNodeOfNodeListMapItr> & newNodesItVec = mapElemNewNodes[ elem ];
4233     newNodesItVec.reserve( elem->NbNodes() );
4234
4235     // loop on elem nodes
4236     SMDS_ElemIteratorPtr itN = elem->nodesIterator();
4237     while ( itN->more() ) {
4238       // check if a node has been already sweeped
4239       const SMDS_MeshNode* node = cast2Node( itN->next() );
4240
4241       gp_XYZ aXYZ( node->X(), node->Y(), node->Z() );
4242       double coord[3];
4243       aXYZ.Coord( coord[0], coord[1], coord[2] );
4244       bool isOnAxis = ( aLine.SquareDistance( aXYZ ) <= aSqTol );
4245
4246       TNodeOfNodeListMapItr nIt = mapNewNodes.find( node );
4247       if ( nIt == mapNewNodes.end() ) {
4248         nIt = mapNewNodes.insert( make_pair( node, list<const SMDS_MeshNode*>() )).first;
4249         list<const SMDS_MeshNode*>& listNewNodes = nIt->second;
4250
4251         // make new nodes
4252         //gp_XYZ aXYZ( node->X(), node->Y(), node->Z() );
4253         //double coord[3];
4254         //aXYZ.Coord( coord[0], coord[1], coord[2] );
4255         //bool isOnAxis = ( aLine.SquareDistance( aXYZ ) <= aSqTol );
4256         const SMDS_MeshNode * newNode = node;
4257         for ( int i = 0; i < theNbSteps; i++ ) {
4258           if ( !isOnAxis ) {
4259             if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
4260               // create two nodes
4261               aTrsf2.Transforms( coord[0], coord[1], coord[2] );
4262               //aTrsf.Transforms( coord[0], coord[1], coord[2] );
4263               newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
4264               myLastCreatedNodes.Append(newNode);
4265               srcNodes.Append( node );
4266               listNewNodes.push_back( newNode );
4267               aTrsf2.Transforms( coord[0], coord[1], coord[2] );
4268               //aTrsf.Transforms( coord[0], coord[1], coord[2] );
4269             }
4270             else {
4271               aTrsf.Transforms( coord[0], coord[1], coord[2] );
4272             }
4273             newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
4274             myLastCreatedNodes.Append(newNode);
4275             srcNodes.Append( node );
4276             listNewNodes.push_back( newNode );
4277           }
4278           else {
4279             listNewNodes.push_back( newNode );
4280             if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
4281               listNewNodes.push_back( newNode );
4282             }
4283           }
4284         }
4285       }
4286       /*
4287         else {
4288         // if current elem is quadratic and current node is not medium
4289         // we have to check - may be it is needed to insert additional nodes
4290         if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
4291         list< const SMDS_MeshNode* > & listNewNodes = nIt->second;
4292         if(listNewNodes.size()==theNbSteps) {
4293         listNewNodes.clear();
4294         // make new nodes
4295         //gp_XYZ aXYZ( node->X(), node->Y(), node->Z() );
4296         //double coord[3];
4297         //aXYZ.Coord( coord[0], coord[1], coord[2] );
4298         const SMDS_MeshNode * newNode = node;
4299         if ( !isOnAxis ) {
4300         for(int i = 0; i<theNbSteps; i++) {
4301         aTrsf2.Transforms( coord[0], coord[1], coord[2] );
4302         newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
4303         cout<<"    3 AddNode:  "<<newNode;
4304         myLastCreatedNodes.Append(newNode);
4305         listNewNodes.push_back( newNode );
4306         srcNodes.Append( node );
4307         aTrsf2.Transforms( coord[0], coord[1], coord[2] );
4308         newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
4309         cout<<"    4 AddNode:  "<<newNode;
4310         myLastCreatedNodes.Append(newNode);
4311         srcNodes.Append( node );
4312         listNewNodes.push_back( newNode );
4313         }
4314         }
4315         else {
4316         listNewNodes.push_back( newNode );
4317         }
4318         }
4319         }
4320         }
4321       */
4322       newNodesItVec.push_back( nIt );
4323     }
4324     // make new elements
4325     sweepElement( elem, newNodesItVec, newElemsMap[elem], theNbSteps, srcElems );
4326   }
4327
4328   if ( theMakeWalls )
4329     makeWalls( mapNewNodes, newElemsMap, mapElemNewNodes, theElems, theNbSteps, srcElems );
4330
4331   PGroupIDs newGroupIDs;
4332   if ( theMakeGroups )
4333     newGroupIDs = generateGroups( srcNodes, srcElems, "rotated");
4334
4335   return newGroupIDs;
4336 }
4337
4338
4339 //=======================================================================
4340 //function : CreateNode
4341 //purpose  :
4342 //=======================================================================
4343 const SMDS_MeshNode* SMESH_MeshEditor::CreateNode(const double x,
4344                                                   const double y,
4345                                                   const double z,
4346                                                   const double tolnode,
4347                                                   SMESH_SequenceOfNode& aNodes)
4348 {
4349   myLastCreatedElems.Clear();
4350   myLastCreatedNodes.Clear();
4351
4352   gp_Pnt P1(x,y,z);
4353   SMESHDS_Mesh * aMesh = myMesh->GetMeshDS();
4354
4355   // try to search in sequence of existing nodes
4356   // if aNodes.Length()>0 we 'nave to use given sequence
4357   // else - use all nodes of mesh
4358   if(aNodes.Length()>0) {
4359     int i;
4360     for(i=1; i<=aNodes.Length(); i++) {
4361       gp_Pnt P2(aNodes.Value(i)->X(),aNodes.Value(i)->Y(),aNodes.Value(i)->Z());
4362       if(P1.Distance(P2)<tolnode)
4363         return aNodes.Value(i);
4364     }
4365   }
4366   else {
4367     SMDS_NodeIteratorPtr itn = aMesh->nodesIterator();
4368     while(itn->more()) {
4369       const SMDS_MeshNode* aN = static_cast<const SMDS_MeshNode*> (itn->next());
4370       gp_Pnt P2(aN->X(),aN->Y(),aN->Z());
4371       if(P1.Distance(P2)<tolnode)
4372         return aN;
4373     }
4374   }
4375
4376   // create new node and return it
4377   const SMDS_MeshNode* NewNode = aMesh->AddNode(x,y,z);
4378   myLastCreatedNodes.Append(NewNode);
4379   return NewNode;
4380 }
4381
4382
4383 //=======================================================================
4384 //function : ExtrusionSweep
4385 //purpose  :
4386 //=======================================================================
4387
4388 SMESH_MeshEditor::PGroupIDs
4389 SMESH_MeshEditor::ExtrusionSweep (TIDSortedElemSet &  theElems,
4390                                   const gp_Vec&       theStep,
4391                                   const int           theNbSteps,
4392                                   TElemOfElemListMap& newElemsMap,
4393                                   const bool          theMakeGroups,
4394                                   const int           theFlags,
4395                                   const double        theTolerance)
4396 {
4397   ExtrusParam aParams;
4398   aParams.myDir = gp_Dir(theStep);
4399   aParams.myNodes.Clear();
4400   aParams.mySteps = new TColStd_HSequenceOfReal;
4401   int i;
4402   for(i=1; i<=theNbSteps; i++)
4403     aParams.mySteps->Append(theStep.Magnitude());
4404
4405   return
4406     ExtrusionSweep(theElems,aParams,newElemsMap,theMakeGroups,theFlags,theTolerance);
4407 }
4408
4409
4410 //=======================================================================
4411 //function : ExtrusionSweep
4412 //purpose  :
4413 //=======================================================================
4414
4415 SMESH_MeshEditor::PGroupIDs
4416 SMESH_MeshEditor::ExtrusionSweep (TIDSortedElemSet &  theElems,
4417                                   ExtrusParam&        theParams,
4418                                   TElemOfElemListMap& newElemsMap,
4419                                   const bool          theMakeGroups,
4420                                   const int           theFlags,
4421                                   const double        theTolerance)
4422 {
4423   MESSAGE("ExtrusionSweep " << theMakeGroups << " " << theFlags << " " << theTolerance);
4424   myLastCreatedElems.Clear();
4425   myLastCreatedNodes.Clear();
4426
4427   // source elements for each generated one
4428   SMESH_SequenceOfElemPtr srcElems, srcNodes;
4429
4430   SMESHDS_Mesh* aMesh = GetMeshDS();
4431
4432   int nbsteps = theParams.mySteps->Length();
4433
4434   TNodeOfNodeListMap mapNewNodes;
4435   //TNodeOfNodeVecMap mapNewNodes;
4436   TElemOfVecOfNnlmiMap mapElemNewNodes;
4437   //TElemOfVecOfMapNodesMap mapElemNewNodes;
4438
4439   // loop on theElems
4440   TIDSortedElemSet::iterator itElem;
4441   for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
4442     // check element type
4443     const SMDS_MeshElement* elem = *itElem;
4444     if ( !elem  || elem->GetType() == SMDSAbs_Volume )
4445       continue;
4446
4447     vector<TNodeOfNodeListMapItr> & newNodesItVec = mapElemNewNodes[ elem ];
4448     //vector<TNodeOfNodeVecMapItr> & newNodesItVec = mapElemNewNodes[ elem ];
4449     newNodesItVec.reserve( elem->NbNodes() );
4450
4451     // loop on elem nodes
4452     SMDS_ElemIteratorPtr itN = elem->nodesIterator();
4453     while ( itN->more() )
4454     {
4455       // check if a node has been already sweeped
4456       const SMDS_MeshNode* node = cast2Node( itN->next() );
4457       TNodeOfNodeListMap::iterator nIt = mapNewNodes.find( node );
4458       //TNodeOfNodeVecMap::iterator nIt = mapNewNodes.find( node );
4459       if ( nIt == mapNewNodes.end() ) {
4460         nIt = mapNewNodes.insert( make_pair( node, list<const SMDS_MeshNode*>() )).first;
4461         //nIt = mapNewNodes.insert( make_pair( node, vector<const SMDS_MeshNode*>() )).first;
4462         list<const SMDS_MeshNode*>& listNewNodes = nIt->second;
4463         //vector<const SMDS_MeshNode*>& vecNewNodes = nIt->second;
4464         //vecNewNodes.reserve(nbsteps);
4465
4466         // make new nodes
4467         double coord[] = { node->X(), node->Y(), node->Z() };
4468         //int nbsteps = theParams.mySteps->Length();
4469         for ( int i = 0; i < nbsteps; i++ ) {
4470           if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
4471             // create additional node
4472             double x = coord[0] + theParams.myDir.X()*theParams.mySteps->Value(i+1)/2.;
4473             double y = coord[1] + theParams.myDir.Y()*theParams.mySteps->Value(i+1)/2.;
4474             double z = coord[2] + theParams.myDir.Z()*theParams.mySteps->Value(i+1)/2.;
4475             if( theFlags & EXTRUSION_FLAG_SEW ) {
4476               const SMDS_MeshNode * newNode = CreateNode(x, y, z,
4477                                                          theTolerance, theParams.myNodes);
4478               listNewNodes.push_back( newNode );
4479             }
4480             else {
4481               const SMDS_MeshNode * newNode = aMesh->AddNode(x, y, z);
4482               myLastCreatedNodes.Append(newNode);
4483               srcNodes.Append( node );
4484               listNewNodes.push_back( newNode );
4485             }
4486           }
4487           //aTrsf.Transforms( coord[0], coord[1], coord[2] );
4488           coord[0] = coord[0] + theParams.myDir.X()*theParams.mySteps->Value(i+1);
4489           coord[1] = coord[1] + theParams.myDir.Y()*theParams.mySteps->Value(i+1);
4490           coord[2] = coord[2] + theParams.myDir.Z()*theParams.mySteps->Value(i+1);
4491           if( theFlags & EXTRUSION_FLAG_SEW ) {
4492             const SMDS_MeshNode * newNode = CreateNode(coord[0], coord[1], coord[2],
4493                                                        theTolerance, theParams.myNodes);
4494             listNewNodes.push_back( newNode );
4495             //vecNewNodes[i]=newNode;
4496           }
4497           else {
4498             const SMDS_MeshNode * newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
4499             myLastCreatedNodes.Append(newNode);
4500             srcNodes.Append( node );
4501             listNewNodes.push_back( newNode );
4502             //vecNewNodes[i]=newNode;
4503           }
4504         }
4505       }
4506       else {
4507         // if current elem is quadratic and current node is not medium
4508         // we have to check - may be it is needed to insert additional nodes
4509         if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
4510           list< const SMDS_MeshNode* > & listNewNodes = nIt->second;
4511           if(listNewNodes.size()==nbsteps) {
4512             listNewNodes.clear();
4513             double coord[] = { node->X(), node->Y(), node->Z() };
4514             for ( int i = 0; i < nbsteps; i++ ) {
4515               double x = coord[0] + theParams.myDir.X()*theParams.mySteps->Value(i+1);
4516               double y = coord[1] + theParams.myDir.Y()*theParams.mySteps->Value(i+1);
4517               double z = coord[2] + theParams.myDir.Z()*theParams.mySteps->Value(i+1);
4518               if( theFlags & EXTRUSION_FLAG_SEW ) {
4519                 const SMDS_MeshNode * newNode = CreateNode(x, y, z,
4520                                                            theTolerance, theParams.myNodes);
4521                 listNewNodes.push_back( newNode );
4522               }
4523               else {
4524                 const SMDS_MeshNode * newNode = aMesh->AddNode(x, y, z);
4525                 myLastCreatedNodes.Append(newNode);
4526                 srcNodes.Append( node );
4527                 listNewNodes.push_back( newNode );
4528               }
4529               coord[0] = coord[0] + theParams.myDir.X()*theParams.mySteps->Value(i+1);
4530               coord[1] = coord[1] + theParams.myDir.Y()*theParams.mySteps->Value(i+1);
4531               coord[2] = coord[2] + theParams.myDir.Z()*theParams.mySteps->Value(i+1);
4532               if( theFlags & EXTRUSION_FLAG_SEW ) {
4533                 const SMDS_MeshNode * newNode = CreateNode(coord[0], coord[1], coord[2],
4534                                                            theTolerance, theParams.myNodes);
4535                 listNewNodes.push_back( newNode );
4536               }
4537               else {
4538                 const SMDS_MeshNode * newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
4539                 myLastCreatedNodes.Append(newNode);
4540                 srcNodes.Append( node );
4541                 listNewNodes.push_back( newNode );
4542               }
4543             }
4544           }
4545         }
4546       }
4547       newNodesItVec.push_back( nIt );
4548     }
4549     // make new elements
4550     sweepElement( elem, newNodesItVec, newElemsMap[elem], nbsteps, srcElems );
4551   }
4552
4553   if( theFlags & EXTRUSION_FLAG_BOUNDARY ) {
4554     makeWalls( mapNewNodes, newElemsMap, mapElemNewNodes, theElems, nbsteps, srcElems );
4555   }
4556   PGroupIDs newGroupIDs;
4557   if ( theMakeGroups )
4558     newGroupIDs = generateGroups( srcNodes, srcElems, "extruded");
4559
4560   return newGroupIDs;
4561 }
4562
4563 /*
4564 //=======================================================================
4565 //class    : SMESH_MeshEditor_PathPoint
4566 //purpose  : auxiliary class
4567 //=======================================================================
4568 class SMESH_MeshEditor_PathPoint {
4569 public:
4570 SMESH_MeshEditor_PathPoint() {
4571 myPnt.SetCoord(99., 99., 99.);
4572 myTgt.SetCoord(1.,0.,0.);
4573 myAngle=0.;
4574 myPrm=0.;
4575 }
4576 void SetPnt(const gp_Pnt& aP3D){
4577 myPnt=aP3D;
4578 }
4579 void SetTangent(const gp_Dir& aTgt){
4580 myTgt=aTgt;
4581 }
4582 void SetAngle(const double& aBeta){
4583 myAngle=aBeta;
4584 }
4585 void SetParameter(const double& aPrm){
4586 myPrm=aPrm;
4587 }
4588 const gp_Pnt& Pnt()const{
4589 return myPnt;
4590 }
4591 const gp_Dir& Tangent()const{
4592 return myTgt;
4593 }
4594 double Angle()const{
4595 return myAngle;
4596 }
4597 double Parameter()const{
4598 return myPrm;
4599 }
4600
4601 protected:
4602 gp_Pnt myPnt;
4603 gp_Dir myTgt;
4604 double myAngle;
4605 double myPrm;
4606 };
4607 */
4608
4609 //=======================================================================
4610 //function : ExtrusionAlongTrack
4611 //purpose  :
4612 //=======================================================================
4613 SMESH_MeshEditor::Extrusion_Error
4614 SMESH_MeshEditor::ExtrusionAlongTrack (TIDSortedElemSet &   theElements,
4615                                        SMESH_subMesh*       theTrack,
4616                                        const SMDS_MeshNode* theN1,
4617                                        const bool           theHasAngles,
4618                                        list<double>&        theAngles,
4619                                        const bool           theLinearVariation,
4620                                        const bool           theHasRefPoint,
4621                                        const gp_Pnt&        theRefPoint,
4622                                        const bool           theMakeGroups)
4623 {
4624   MESSAGE("ExtrusionAlongTrack");
4625   myLastCreatedElems.Clear();
4626   myLastCreatedNodes.Clear();
4627
4628   int aNbE;
4629   std::list<double> aPrms;
4630   TIDSortedElemSet::iterator itElem;
4631
4632   gp_XYZ aGC;
4633   TopoDS_Edge aTrackEdge;
4634   TopoDS_Vertex aV1, aV2;
4635
4636   SMDS_ElemIteratorPtr aItE;
4637   SMDS_NodeIteratorPtr aItN;
4638   SMDSAbs_ElementType aTypeE;
4639
4640   TNodeOfNodeListMap mapNewNodes;
4641
4642   // 1. Check data
4643   aNbE = theElements.size();
4644   // nothing to do
4645   if ( !aNbE )
4646     return EXTR_NO_ELEMENTS;
4647
4648   // 1.1 Track Pattern
4649   ASSERT( theTrack );
4650
4651   SMESHDS_SubMesh* pSubMeshDS = theTrack->GetSubMeshDS();
4652
4653   aItE = pSubMeshDS->GetElements();
4654   while ( aItE->more() ) {
4655     const SMDS_MeshElement* pE = aItE->next();
4656     aTypeE = pE->GetType();
4657     // Pattern must contain links only
4658     if ( aTypeE != SMDSAbs_Edge )
4659       return EXTR_PATH_NOT_EDGE;
4660   }
4661
4662   list<SMESH_MeshEditor_PathPoint> fullList;
4663
4664   const TopoDS_Shape& aS = theTrack->GetSubShape();
4665   // Sub shape for the Pattern must be an Edge or Wire
4666   if( aS.ShapeType() == TopAbs_EDGE ) {
4667     aTrackEdge = TopoDS::Edge( aS );
4668     // the Edge must not be degenerated
4669     if ( BRep_Tool::Degenerated( aTrackEdge ) )
4670       return EXTR_BAD_PATH_SHAPE;
4671     TopExp::Vertices( aTrackEdge, aV1, aV2 );
4672     aItN = theTrack->GetFather()->GetSubMesh( aV1 )->GetSubMeshDS()->GetNodes();
4673     const SMDS_MeshNode* aN1 = aItN->next();
4674     aItN = theTrack->GetFather()->GetSubMesh( aV2 )->GetSubMeshDS()->GetNodes();
4675     const SMDS_MeshNode* aN2 = aItN->next();
4676     // starting node must be aN1 or aN2
4677     if ( !( aN1 == theN1 || aN2 == theN1 ) )
4678       return EXTR_BAD_STARTING_NODE;
4679     aItN = pSubMeshDS->GetNodes();
4680     while ( aItN->more() ) {
4681       const SMDS_MeshNode* pNode = aItN->next();
4682       const SMDS_EdgePosition* pEPos =
4683         static_cast<const SMDS_EdgePosition*>( pNode->GetPosition() );
4684       double aT = pEPos->GetUParameter();
4685       aPrms.push_back( aT );
4686     }
4687     //Extrusion_Error err =
4688     MakeEdgePathPoints(aPrms, aTrackEdge, (aN1==theN1), fullList);
4689   }
4690   else if( aS.ShapeType() == TopAbs_WIRE ) {
4691     list< SMESH_subMesh* > LSM;
4692     TopTools_SequenceOfShape Edges;
4693     SMESH_subMeshIteratorPtr itSM = theTrack->getDependsOnIterator(false,true);
4694     while(itSM->more()) {
4695       SMESH_subMesh* SM = itSM->next();
4696       LSM.push_back(SM);
4697       const TopoDS_Shape& aS = SM->GetSubShape();
4698       Edges.Append(aS);
4699     }
4700     list< list<SMESH_MeshEditor_PathPoint> > LLPPs;
4701     int startNid = theN1->GetID();
4702     TColStd_MapOfInteger UsedNums;
4703     int NbEdges = Edges.Length();
4704     int i = 1;
4705     for(; i<=NbEdges; i++) {
4706       int k = 0;
4707       list< SMESH_subMesh* >::iterator itLSM = LSM.begin();
4708       for(; itLSM!=LSM.end(); itLSM++) {
4709         k++;
4710         if(UsedNums.Contains(k)) continue;
4711         aTrackEdge = TopoDS::Edge( Edges.Value(k) );
4712         SMESH_subMesh* locTrack = *itLSM;
4713         SMESHDS_SubMesh* locMeshDS = locTrack->GetSubMeshDS();
4714         TopExp::Vertices( aTrackEdge, aV1, aV2 );
4715         aItN = locTrack->GetFather()->GetSubMesh(aV1)->GetSubMeshDS()->GetNodes();
4716         const SMDS_MeshNode* aN1 = aItN->next();
4717         aItN = locTrack->GetFather()->GetSubMesh(aV2)->GetSubMeshDS()->GetNodes();
4718         const SMDS_MeshNode* aN2 = aItN->next();
4719         // starting node must be aN1 or aN2
4720         if ( !( aN1->GetID() == startNid || aN2->GetID() == startNid ) ) continue;
4721         // 2. Collect parameters on the track edge
4722         aPrms.clear();
4723         aItN = locMeshDS->GetNodes();
4724         while ( aItN->more() ) {
4725           const SMDS_MeshNode* pNode = aItN->next();
4726           const SMDS_EdgePosition* pEPos =
4727             static_cast<const SMDS_EdgePosition*>( pNode->GetPosition() );
4728           double aT = pEPos->GetUParameter();
4729           aPrms.push_back( aT );
4730         }
4731         list<SMESH_MeshEditor_PathPoint> LPP;
4732         //Extrusion_Error err =
4733         MakeEdgePathPoints(aPrms, aTrackEdge,(aN1->GetID()==startNid), LPP);
4734         LLPPs.push_back(LPP);
4735         UsedNums.Add(k);
4736         // update startN for search following egde
4737         if( aN1->GetID() == startNid ) startNid = aN2->GetID();
4738         else startNid = aN1->GetID();
4739         break;
4740       }
4741     }
4742     list< list<SMESH_MeshEditor_PathPoint> >::iterator itLLPP = LLPPs.begin();
4743     list<SMESH_MeshEditor_PathPoint> firstList = *itLLPP;
4744     list<SMESH_MeshEditor_PathPoint>::iterator itPP = firstList.begin();
4745     for(; itPP!=firstList.end(); itPP++) {
4746       fullList.push_back( *itPP );
4747     }
4748     SMESH_MeshEditor_PathPoint PP1 = fullList.back();
4749     fullList.pop_back();
4750     itLLPP++;
4751     for(; itLLPP!=LLPPs.end(); itLLPP++) {
4752       list<SMESH_MeshEditor_PathPoint> currList = *itLLPP;
4753       itPP = currList.begin();
4754       SMESH_MeshEditor_PathPoint PP2 = currList.front();
4755       gp_Dir D1 = PP1.Tangent();
4756       gp_Dir D2 = PP2.Tangent();
4757       gp_Dir Dnew( gp_Vec( (D1.X()+D2.X())/2, (D1.Y()+D2.Y())/2,
4758                            (D1.Z()+D2.Z())/2 ) );
4759       PP1.SetTangent(Dnew);
4760       fullList.push_back(PP1);
4761       itPP++;
4762       for(; itPP!=firstList.end(); itPP++) {
4763         fullList.push_back( *itPP );
4764       }
4765       PP1 = fullList.back();
4766       fullList.pop_back();
4767     }
4768     // if wire not closed
4769     fullList.push_back(PP1);
4770     // else ???
4771   }
4772   else {
4773     return EXTR_BAD_PATH_SHAPE;
4774   }
4775
4776   return MakeExtrElements(theElements, fullList, theHasAngles, theAngles, theLinearVariation,
4777                           theHasRefPoint, theRefPoint, theMakeGroups);
4778 }
4779
4780
4781 //=======================================================================
4782 //function : ExtrusionAlongTrack
4783 //purpose  :
4784 //=======================================================================
4785 SMESH_MeshEditor::Extrusion_Error
4786 SMESH_MeshEditor::ExtrusionAlongTrack (TIDSortedElemSet &   theElements,
4787                                        SMESH_Mesh*          theTrack,
4788                                        const SMDS_MeshNode* theN1,
4789                                        const bool           theHasAngles,
4790                                        list<double>&        theAngles,
4791                                        const bool           theLinearVariation,
4792                                        const bool           theHasRefPoint,
4793                                        const gp_Pnt&        theRefPoint,
4794                                        const bool           theMakeGroups)
4795 {
4796   myLastCreatedElems.Clear();
4797   myLastCreatedNodes.Clear();
4798
4799   int aNbE;
4800   std::list<double> aPrms;
4801   TIDSortedElemSet::iterator itElem;
4802
4803   gp_XYZ aGC;
4804   TopoDS_Edge aTrackEdge;
4805   TopoDS_Vertex aV1, aV2;
4806
4807   SMDS_ElemIteratorPtr aItE;
4808   SMDS_NodeIteratorPtr aItN;
4809   SMDSAbs_ElementType aTypeE;
4810
4811   TNodeOfNodeListMap mapNewNodes;
4812
4813   // 1. Check data
4814   aNbE = theElements.size();
4815   // nothing to do
4816   if ( !aNbE )
4817     return EXTR_NO_ELEMENTS;
4818
4819   // 1.1 Track Pattern
4820   ASSERT( theTrack );
4821
4822   SMESHDS_Mesh* pMeshDS = theTrack->GetMeshDS();
4823
4824   aItE = pMeshDS->elementsIterator();
4825   while ( aItE->more() ) {
4826     const SMDS_MeshElement* pE = aItE->next();
4827     aTypeE = pE->GetType();
4828     // Pattern must contain links only
4829     if ( aTypeE != SMDSAbs_Edge )
4830       return EXTR_PATH_NOT_EDGE;
4831   }
4832
4833   list<SMESH_MeshEditor_PathPoint> fullList;
4834
4835   const TopoDS_Shape& aS = theTrack->GetShapeToMesh();
4836   // Sub shape for the Pattern must be an Edge or Wire
4837   if( aS.ShapeType() == TopAbs_EDGE ) {
4838     aTrackEdge = TopoDS::Edge( aS );
4839     // the Edge must not be degenerated
4840     if ( BRep_Tool::Degenerated( aTrackEdge ) )
4841       return EXTR_BAD_PATH_SHAPE;
4842     TopExp::Vertices( aTrackEdge, aV1, aV2 );
4843     aItN = theTrack->GetSubMesh( aV1 )->GetSubMeshDS()->GetNodes();
4844     const SMDS_MeshNode* aN1 = aItN->next();
4845     aItN = theTrack->GetSubMesh( aV2 )->GetSubMeshDS()->GetNodes();
4846     const SMDS_MeshNode* aN2 = aItN->next();
4847     // starting node must be aN1 or aN2
4848     if ( !( aN1 == theN1 || aN2 == theN1 ) )
4849       return EXTR_BAD_STARTING_NODE;
4850     aItN = pMeshDS->nodesIterator();
4851     while ( aItN->more() ) {
4852       const SMDS_MeshNode* pNode = aItN->next();
4853       if( pNode==aN1 || pNode==aN2 ) continue;
4854       const SMDS_EdgePosition* pEPos =
4855         static_cast<const SMDS_EdgePosition*>( pNode->GetPosition() );
4856       double aT = pEPos->GetUParameter();
4857       aPrms.push_back( aT );
4858     }
4859     //Extrusion_Error err =
4860     MakeEdgePathPoints(aPrms, aTrackEdge, (aN1==theN1), fullList);
4861   }
4862   else if( aS.ShapeType() == TopAbs_WIRE ) {
4863     list< SMESH_subMesh* > LSM;
4864     TopTools_SequenceOfShape Edges;
4865     TopExp_Explorer eExp(aS, TopAbs_EDGE);
4866     for(; eExp.More(); eExp.Next()) {
4867       TopoDS_Edge E = TopoDS::Edge( eExp.Current() );
4868       if( BRep_Tool::Degenerated(E) ) continue;
4869       SMESH_subMesh* SM = theTrack->GetSubMesh(E);
4870       if(SM) {
4871         LSM.push_back(SM);
4872         Edges.Append(E);
4873       }
4874     }
4875     list< list<SMESH_MeshEditor_PathPoint> > LLPPs;
4876     int startNid = theN1->GetID();
4877     TColStd_MapOfInteger UsedNums;
4878     int NbEdges = Edges.Length();
4879     int i = 1;
4880     for(; i<=NbEdges; i++) {
4881       int k = 0;
4882       list< SMESH_subMesh* >::iterator itLSM = LSM.begin();
4883       for(; itLSM!=LSM.end(); itLSM++) {
4884         k++;
4885         if(UsedNums.Contains(k)) continue;
4886         aTrackEdge = TopoDS::Edge( Edges.Value(k) );
4887         SMESH_subMesh* locTrack = *itLSM;
4888         SMESHDS_SubMesh* locMeshDS = locTrack->GetSubMeshDS();
4889         TopExp::Vertices( aTrackEdge, aV1, aV2 );
4890         aItN = locTrack->GetFather()->GetSubMesh(aV1)->GetSubMeshDS()->GetNodes();
4891         const SMDS_MeshNode* aN1 = aItN->next();
4892         aItN = locTrack->GetFather()->GetSubMesh(aV2)->GetSubMeshDS()->GetNodes();
4893         const SMDS_MeshNode* aN2 = aItN->next();
4894         // starting node must be aN1 or aN2
4895         if ( !( aN1->GetID() == startNid || aN2->GetID() == startNid ) ) continue;
4896         // 2. Collect parameters on the track edge
4897         aPrms.clear();
4898         aItN = locMeshDS->GetNodes();
4899         while ( aItN->more() ) {
4900           const SMDS_MeshNode* pNode = aItN->next();
4901           const SMDS_EdgePosition* pEPos =
4902             static_cast<const SMDS_EdgePosition*>( pNode->GetPosition() );
4903           double aT = pEPos->GetUParameter();
4904           aPrms.push_back( aT );
4905         }
4906         list<SMESH_MeshEditor_PathPoint> LPP;
4907         //Extrusion_Error err =
4908         MakeEdgePathPoints(aPrms, aTrackEdge,(aN1->GetID()==startNid), LPP);
4909         LLPPs.push_back(LPP);
4910         UsedNums.Add(k);
4911         // update startN for search following egde
4912         if( aN1->GetID() == startNid ) startNid = aN2->GetID();
4913         else startNid = aN1->GetID();
4914         break;
4915       }
4916     }
4917     list< list<SMESH_MeshEditor_PathPoint> >::iterator itLLPP = LLPPs.begin();
4918     list<SMESH_MeshEditor_PathPoint> firstList = *itLLPP;
4919     list<SMESH_MeshEditor_PathPoint>::iterator itPP = firstList.begin();
4920     for(; itPP!=firstList.end(); itPP++) {
4921       fullList.push_back( *itPP );
4922     }
4923     SMESH_MeshEditor_PathPoint PP1 = fullList.back();
4924     fullList.pop_back();
4925     itLLPP++;
4926     for(; itLLPP!=LLPPs.end(); itLLPP++) {
4927       list<SMESH_MeshEditor_PathPoint> currList = *itLLPP;
4928       itPP = currList.begin();
4929       SMESH_MeshEditor_PathPoint PP2 = currList.front();
4930       gp_Dir D1 = PP1.Tangent();
4931       gp_Dir D2 = PP2.Tangent();
4932       gp_Dir Dnew( gp_Vec( (D1.X()+D2.X())/2, (D1.Y()+D2.Y())/2,
4933                            (D1.Z()+D2.Z())/2 ) );
4934       PP1.SetTangent(Dnew);
4935       fullList.push_back(PP1);
4936       itPP++;
4937       for(; itPP!=currList.end(); itPP++) {
4938         fullList.push_back( *itPP );
4939       }
4940       PP1 = fullList.back();
4941       fullList.pop_back();
4942     }
4943     // if wire not closed
4944     fullList.push_back(PP1);
4945     // else ???
4946   }
4947   else {
4948     return EXTR_BAD_PATH_SHAPE;
4949   }
4950
4951   return MakeExtrElements(theElements, fullList, theHasAngles, theAngles, theLinearVariation,
4952                           theHasRefPoint, theRefPoint, theMakeGroups);
4953 }
4954
4955
4956 //=======================================================================
4957 //function : MakeEdgePathPoints
4958 //purpose  : auxilary for ExtrusionAlongTrack
4959 //=======================================================================
4960 SMESH_MeshEditor::Extrusion_Error
4961 SMESH_MeshEditor::MakeEdgePathPoints(std::list<double>& aPrms,
4962                                      const TopoDS_Edge& aTrackEdge,
4963                                      bool FirstIsStart,
4964                                      list<SMESH_MeshEditor_PathPoint>& LPP)
4965 {
4966   Standard_Real aTx1, aTx2, aL2, aTolVec, aTolVec2;
4967   aTolVec=1.e-7;
4968   aTolVec2=aTolVec*aTolVec;
4969   double aT1, aT2;
4970   TopoDS_Vertex aV1, aV2;
4971   TopExp::Vertices( aTrackEdge, aV1, aV2 );
4972   aT1=BRep_Tool::Parameter( aV1, aTrackEdge );
4973   aT2=BRep_Tool::Parameter( aV2, aTrackEdge );
4974   // 2. Collect parameters on the track edge
4975   aPrms.push_front( aT1 );
4976   aPrms.push_back( aT2 );
4977   // sort parameters
4978   aPrms.sort();
4979   if( FirstIsStart ) {
4980     if ( aT1 > aT2 ) {
4981       aPrms.reverse();
4982     }
4983   }
4984   else {
4985     if ( aT2 > aT1 ) {
4986       aPrms.reverse();
4987     }
4988   }
4989   // 3. Path Points
4990   SMESH_MeshEditor_PathPoint aPP;
4991   Handle(Geom_Curve) aC3D = BRep_Tool::Curve( aTrackEdge, aTx1, aTx2 );
4992   std::list<double>::iterator aItD = aPrms.begin();
4993   for(; aItD != aPrms.end(); ++aItD) {
4994     double aT = *aItD;
4995     gp_Pnt aP3D;
4996     gp_Vec aVec;
4997     aC3D->D1( aT, aP3D, aVec );
4998     aL2 = aVec.SquareMagnitude();
4999     if ( aL2 < aTolVec2 )
5000       return EXTR_CANT_GET_TANGENT;
5001     gp_Dir aTgt( aVec );
5002     aPP.SetPnt( aP3D );
5003     aPP.SetTangent( aTgt );
5004     aPP.SetParameter( aT );
5005     LPP.push_back(aPP);
5006   }
5007   return EXTR_OK;
5008 }
5009
5010
5011 //=======================================================================
5012 //function : MakeExtrElements
5013 //purpose  : auxilary for ExtrusionAlongTrack
5014 //=======================================================================
5015 SMESH_MeshEditor::Extrusion_Error
5016 SMESH_MeshEditor::MakeExtrElements(TIDSortedElemSet&  theElements,
5017                                    list<SMESH_MeshEditor_PathPoint>& fullList,
5018                                    const bool theHasAngles,
5019                                    list<double>& theAngles,
5020                                    const bool theLinearVariation,
5021                                    const bool theHasRefPoint,
5022                                    const gp_Pnt& theRefPoint,
5023                                    const bool theMakeGroups)
5024 {
5025   MESSAGE("MakeExtrElements");
5026   //cout<<"MakeExtrElements  fullList.size() = "<<fullList.size()<<endl;
5027   int aNbTP = fullList.size();
5028   vector<SMESH_MeshEditor_PathPoint> aPPs(aNbTP);
5029   // Angles
5030   if( theHasAngles && theAngles.size()>0 && theLinearVariation ) {
5031     LinearAngleVariation(aNbTP-1, theAngles);
5032   }
5033   vector<double> aAngles( aNbTP );
5034   int j = 0;
5035   for(; j<aNbTP; ++j) {
5036     aAngles[j] = 0.;
5037   }
5038   if ( theHasAngles ) {
5039     double anAngle;;
5040     std::list<double>::iterator aItD = theAngles.begin();
5041     for ( j=1; (aItD != theAngles.end()) && (j<aNbTP); ++aItD, ++j ) {
5042       anAngle = *aItD;
5043       aAngles[j] = anAngle;
5044     }
5045   }
5046   // fill vector of path points with angles
5047   //aPPs.resize(fullList.size());
5048   j = -1;
5049   list<SMESH_MeshEditor_PathPoint>::iterator itPP = fullList.begin();
5050   for(; itPP!=fullList.end(); itPP++) {
5051     j++;
5052     SMESH_MeshEditor_PathPoint PP = *itPP;
5053     PP.SetAngle(aAngles[j]);
5054     aPPs[j] = PP;
5055   }
5056
5057   TNodeOfNodeListMap mapNewNodes;
5058   TElemOfVecOfNnlmiMap mapElemNewNodes;
5059   TElemOfElemListMap newElemsMap;
5060   TIDSortedElemSet::iterator itElem;
5061   double aX, aY, aZ;
5062   int aNb;
5063   SMDSAbs_ElementType aTypeE;
5064   // source elements for each generated one
5065   SMESH_SequenceOfElemPtr srcElems, srcNodes;
5066
5067   // 3. Center of rotation aV0
5068   gp_Pnt aV0 = theRefPoint;
5069   gp_XYZ aGC;
5070   if ( !theHasRefPoint ) {
5071     aNb = 0;
5072     aGC.SetCoord( 0.,0.,0. );
5073
5074     itElem = theElements.begin();
5075     for ( ; itElem != theElements.end(); itElem++ ) {
5076       const SMDS_MeshElement* elem = *itElem;
5077
5078       SMDS_ElemIteratorPtr itN = elem->nodesIterator();
5079       while ( itN->more() ) {
5080         const SMDS_MeshNode* node = static_cast<const SMDS_MeshNode*>( itN->next() );
5081         aX = node->X();
5082         aY = node->Y();
5083         aZ = node->Z();
5084
5085         if ( mapNewNodes.find( node ) == mapNewNodes.end() ) {
5086           list<const SMDS_MeshNode*> aLNx;
5087           mapNewNodes[node] = aLNx;
5088           //
5089           gp_XYZ aXYZ( aX, aY, aZ );
5090           aGC += aXYZ;
5091           ++aNb;
5092         }
5093       }
5094     }
5095     aGC /= aNb;
5096     aV0.SetXYZ( aGC );
5097   } // if (!theHasRefPoint) {
5098   mapNewNodes.clear();
5099
5100   // 4. Processing the elements
5101   SMESHDS_Mesh* aMesh = GetMeshDS();
5102
5103   for ( itElem = theElements.begin(); itElem != theElements.end(); itElem++ ) {
5104     // check element type
5105     const SMDS_MeshElement* elem = *itElem;
5106     aTypeE = elem->GetType();
5107     if ( !elem || ( aTypeE != SMDSAbs_Face && aTypeE != SMDSAbs_Edge ) )
5108       continue;
5109
5110     vector<TNodeOfNodeListMapItr> & newNodesItVec = mapElemNewNodes[ elem ];
5111     newNodesItVec.reserve( elem->NbNodes() );
5112
5113     // loop on elem nodes
5114     int nodeIndex = -1;
5115     SMDS_ElemIteratorPtr itN = elem->nodesIterator();
5116     while ( itN->more() )
5117     {
5118       ++nodeIndex;
5119       // check if a node has been already processed
5120       const SMDS_MeshNode* node =
5121         static_cast<const SMDS_MeshNode*>( itN->next() );
5122       TNodeOfNodeListMap::iterator nIt = mapNewNodes.find( node );
5123       if ( nIt == mapNewNodes.end() ) {
5124         nIt = mapNewNodes.insert( make_pair( node, list<const SMDS_MeshNode*>() )).first;
5125         list<const SMDS_MeshNode*>& listNewNodes = nIt->second;
5126
5127         // make new nodes
5128         aX = node->X();  aY = node->Y(); aZ = node->Z();
5129
5130         Standard_Real aAngle1x, aAngleT1T0, aTolAng;
5131         gp_Pnt aP0x, aP1x, aPN0, aPN1, aV0x, aV1x;
5132         gp_Ax1 anAx1, anAxT1T0;
5133         gp_Dir aDT1x, aDT0x, aDT1T0;
5134
5135         aTolAng=1.e-4;
5136
5137         aV0x = aV0;
5138         aPN0.SetCoord(aX, aY, aZ);
5139
5140         const SMESH_MeshEditor_PathPoint& aPP0 = aPPs[0];
5141         aP0x = aPP0.Pnt();
5142         aDT0x= aPP0.Tangent();
5143         //cout<<"j = 0   PP: Pnt("<<aP0x.X()<<","<<aP0x.Y()<<","<<aP0x.Z()<<")"<<endl;
5144
5145         for ( j = 1; j < aNbTP; ++j ) {
5146           const SMESH_MeshEditor_PathPoint& aPP1 = aPPs[j];
5147           aP1x = aPP1.Pnt();
5148           aDT1x = aPP1.Tangent();
5149           aAngle1x = aPP1.Angle();
5150
5151           gp_Trsf aTrsf, aTrsfRot, aTrsfRotT1T0;
5152           // Translation
5153           gp_Vec aV01x( aP0x, aP1x );
5154           aTrsf.SetTranslation( aV01x );
5155
5156           // traslated point
5157           aV1x = aV0x.Transformed( aTrsf );
5158           aPN1 = aPN0.Transformed( aTrsf );
5159
5160           // rotation 1 [ T1,T0 ]
5161           aAngleT1T0=-aDT1x.Angle( aDT0x );
5162           if (fabs(aAngleT1T0) > aTolAng) {
5163             aDT1T0=aDT1x^aDT0x;
5164             anAxT1T0.SetLocation( aV1x );
5165             anAxT1T0.SetDirection( aDT1T0 );
5166             aTrsfRotT1T0.SetRotation( anAxT1T0, aAngleT1T0 );
5167
5168             aPN1 = aPN1.Transformed( aTrsfRotT1T0 );
5169           }
5170
5171           // rotation 2
5172           if ( theHasAngles ) {
5173             anAx1.SetLocation( aV1x );
5174             anAx1.SetDirection( aDT1x );
5175             aTrsfRot.SetRotation( anAx1, aAngle1x );
5176
5177             aPN1 = aPN1.Transformed( aTrsfRot );
5178           }
5179
5180           // make new node
5181           //MESSAGE("elem->IsQuadratic " << elem->IsQuadratic() << " " << elem->IsMediumNode(node));
5182           if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
5183             // create additional node
5184             double x = ( aPN1.X() + aPN0.X() )/2.;
5185             double y = ( aPN1.Y() + aPN0.Y() )/2.;
5186             double z = ( aPN1.Z() + aPN0.Z() )/2.;
5187             const SMDS_MeshNode* newNode = aMesh->AddNode(x,y,z);
5188             myLastCreatedNodes.Append(newNode);
5189             srcNodes.Append( node );
5190             listNewNodes.push_back( newNode );
5191           }
5192           aX = aPN1.X();
5193           aY = aPN1.Y();
5194           aZ = aPN1.Z();
5195           const SMDS_MeshNode* newNode = aMesh->AddNode( aX, aY, aZ );
5196           myLastCreatedNodes.Append(newNode);
5197           srcNodes.Append( node );
5198           listNewNodes.push_back( newNode );
5199
5200           aPN0 = aPN1;
5201           aP0x = aP1x;
5202           aV0x = aV1x;
5203           aDT0x = aDT1x;
5204         }
5205       }
5206
5207       else {
5208         // if current elem is quadratic and current node is not medium
5209         // we have to check - may be it is needed to insert additional nodes
5210         if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
5211           list< const SMDS_MeshNode* > & listNewNodes = nIt->second;
5212           if(listNewNodes.size()==aNbTP-1) {
5213             vector<const SMDS_MeshNode*> aNodes(2*(aNbTP-1));
5214             gp_XYZ P(node->X(), node->Y(), node->Z());
5215             list< const SMDS_MeshNode* >::iterator it = listNewNodes.begin();
5216             int i;
5217             for(i=0; i<aNbTP-1; i++) {
5218               const SMDS_MeshNode* N = *it;
5219               double x = ( N->X() + P.X() )/2.;
5220               double y = ( N->Y() + P.Y() )/2.;
5221               double z = ( N->Z() + P.Z() )/2.;
5222               const SMDS_MeshNode* newN = aMesh->AddNode(x,y,z);
5223               srcNodes.Append( node );
5224               myLastCreatedNodes.Append(newN);
5225               aNodes[2*i] = newN;
5226               aNodes[2*i+1] = N;
5227               P = gp_XYZ(N->X(),N->Y(),N->Z());
5228             }
5229             listNewNodes.clear();
5230             for(i=0; i<2*(aNbTP-1); i++) {
5231               listNewNodes.push_back(aNodes[i]);
5232             }
5233           }
5234         }
5235       }
5236
5237       newNodesItVec.push_back( nIt );
5238     }
5239     // make new elements
5240     //sweepElement( aMesh, elem, newNodesItVec, newElemsMap[elem],
5241     //              newNodesItVec[0]->second.size(), myLastCreatedElems );
5242     sweepElement( elem, newNodesItVec, newElemsMap[elem], aNbTP-1, srcElems );
5243   }
5244
5245   makeWalls( mapNewNodes, newElemsMap, mapElemNewNodes, theElements, aNbTP-1, srcElems );
5246
5247   if ( theMakeGroups )
5248     generateGroups( srcNodes, srcElems, "extruded");
5249
5250   return EXTR_OK;
5251 }
5252
5253
5254 //=======================================================================
5255 //function : LinearAngleVariation
5256 //purpose  : auxilary for ExtrusionAlongTrack
5257 //=======================================================================
5258 void SMESH_MeshEditor::LinearAngleVariation(const int nbSteps,
5259                                             list<double>& Angles)
5260 {
5261   int nbAngles = Angles.size();
5262   if( nbSteps > nbAngles ) {
5263     vector<double> theAngles(nbAngles);
5264     list<double>::iterator it = Angles.begin();
5265     int i = -1;
5266     for(; it!=Angles.end(); it++) {
5267       i++;
5268       theAngles[i] = (*it);
5269     }
5270     list<double> res;
5271     double rAn2St = double( nbAngles ) / double( nbSteps );
5272     double angPrev = 0, angle;
5273     for ( int iSt = 0; iSt < nbSteps; ++iSt ) {
5274       double angCur = rAn2St * ( iSt+1 );
5275       double angCurFloor  = floor( angCur );
5276       double angPrevFloor = floor( angPrev );
5277       if ( angPrevFloor == angCurFloor )
5278         angle = rAn2St * theAngles[ int( angCurFloor ) ];
5279       else {
5280         int iP = int( angPrevFloor );
5281         double angPrevCeil = ceil(angPrev);
5282         angle = ( angPrevCeil - angPrev ) * theAngles[ iP ];
5283
5284         int iC = int( angCurFloor );
5285         if ( iC < nbAngles )
5286           angle += ( angCur - angCurFloor ) * theAngles[ iC ];
5287
5288         iP = int( angPrevCeil );
5289         while ( iC-- > iP )
5290           angle += theAngles[ iC ];
5291       }
5292       res.push_back(angle);
5293       angPrev = angCur;
5294     }
5295     Angles.clear();
5296     it = res.begin();
5297     for(; it!=res.end(); it++)
5298       Angles.push_back( *it );
5299   }
5300 }
5301
5302
5303 //================================================================================
5304 /*!
5305  * \brief Move or copy theElements applying theTrsf to their nodes
5306  *  \param theElems - elements to transform, if theElems is empty then apply to all mesh nodes
5307  *  \param theTrsf - transformation to apply
5308  *  \param theCopy - if true, create translated copies of theElems
5309  *  \param theMakeGroups - if true and theCopy, create translated groups
5310  *  \param theTargetMesh - mesh to copy translated elements into
5311  *  \return SMESH_MeshEditor::PGroupIDs - list of ids of created groups
5312  */
5313 //================================================================================
5314
5315 SMESH_MeshEditor::PGroupIDs
5316 SMESH_MeshEditor::Transform (TIDSortedElemSet & theElems,
5317                              const gp_Trsf&     theTrsf,
5318                              const bool         theCopy,
5319                              const bool         theMakeGroups,
5320                              SMESH_Mesh*        theTargetMesh)
5321 {
5322   myLastCreatedElems.Clear();
5323   myLastCreatedNodes.Clear();
5324
5325   bool needReverse = false;
5326   string groupPostfix;
5327   switch ( theTrsf.Form() ) {
5328   case gp_PntMirror:
5329     MESSAGE("gp_PntMirror");
5330     needReverse = true;
5331     groupPostfix = "mirrored";
5332     break;
5333   case gp_Ax1Mirror:
5334     MESSAGE("gp_Ax1Mirror");
5335     groupPostfix = "mirrored";
5336     break;
5337   case gp_Ax2Mirror:
5338     MESSAGE("gp_Ax2Mirror");
5339     needReverse = true;
5340     groupPostfix = "mirrored";
5341     break;
5342   case gp_Rotation:
5343     MESSAGE("gp_Rotation");
5344     groupPostfix = "rotated";
5345     break;
5346   case gp_Translation:
5347     MESSAGE("gp_Translation");
5348     groupPostfix = "translated";
5349     break;
5350   case gp_Scale:
5351     MESSAGE("gp_Scale");
5352     groupPostfix = "scaled";
5353     break;
5354   case gp_CompoundTrsf: // different scale by axis
5355     MESSAGE("gp_CompoundTrsf");
5356     groupPostfix = "scaled";
5357     break;
5358   default:
5359     MESSAGE("default");
5360     needReverse = false;
5361     groupPostfix = "transformed";
5362   }
5363
5364   SMESH_MeshEditor targetMeshEditor( theTargetMesh );
5365   SMESHDS_Mesh* aTgtMesh = theTargetMesh ? theTargetMesh->GetMeshDS() : 0;
5366   SMESHDS_Mesh* aMesh    = GetMeshDS();
5367
5368
5369   // map old node to new one
5370   TNodeNodeMap nodeMap;
5371
5372   // elements sharing moved nodes; those of them which have all
5373   // nodes mirrored but are not in theElems are to be reversed
5374   TIDSortedElemSet inverseElemSet;
5375
5376   // source elements for each generated one
5377   SMESH_SequenceOfElemPtr srcElems, srcNodes;
5378
5379   // issue 021015: EDF 1578 SMESH: Free nodes are removed when translating a mesh
5380   TIDSortedElemSet orphanNode;
5381
5382   if ( theElems.empty() ) // transform the whole mesh
5383   {
5384     // add all elements
5385     SMDS_ElemIteratorPtr eIt = aMesh->elementsIterator();
5386     while ( eIt->more() ) theElems.insert( eIt->next() );
5387     // add orphan nodes
5388     SMDS_NodeIteratorPtr nIt = aMesh->nodesIterator();
5389     while ( nIt->more() )
5390     {
5391       const SMDS_MeshNode* node = nIt->next();
5392       if ( node->NbInverseElements() == 0)
5393         orphanNode.insert( node );
5394     }
5395   }
5396
5397   // loop on elements to transform nodes : first orphan nodes then elems
5398   TIDSortedElemSet::iterator itElem;
5399   TIDSortedElemSet *elements[] = {&orphanNode, &theElems };
5400   for (int i=0; i<2; i++)
5401   for ( itElem = elements[i]->begin(); itElem != elements[i]->end(); itElem++ ) {
5402     const SMDS_MeshElement* elem = *itElem;
5403     if ( !elem )
5404       continue;
5405
5406     // loop on elem nodes
5407     SMDS_ElemIteratorPtr itN = elem->nodesIterator();
5408     while ( itN->more() ) {
5409
5410       const SMDS_MeshNode* node = cast2Node( itN->next() );
5411       // check if a node has been already transformed
5412       pair<TNodeNodeMap::iterator,bool> n2n_isnew =
5413         nodeMap.insert( make_pair ( node, node ));
5414       if ( !n2n_isnew.second )
5415         continue;
5416
5417       double coord[3];
5418       coord[0] = node->X();
5419       coord[1] = node->Y();
5420       coord[2] = node->Z();
5421       theTrsf.Transforms( coord[0], coord[1], coord[2] );
5422       if ( theTargetMesh ) {
5423         const SMDS_MeshNode * newNode = aTgtMesh->AddNode( coord[0], coord[1], coord[2] );
5424         n2n_isnew.first->second = newNode;
5425         myLastCreatedNodes.Append(newNode);
5426         srcNodes.Append( node );
5427       }
5428       else if ( theCopy ) {
5429         const SMDS_MeshNode * newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
5430         n2n_isnew.first->second = newNode;
5431         myLastCreatedNodes.Append(newNode);
5432         srcNodes.Append( node );
5433       }
5434       else {
5435         aMesh->MoveNode( node, coord[0], coord[1], coord[2] );
5436         // node position on shape becomes invalid
5437         const_cast< SMDS_MeshNode* > ( node )->SetPosition
5438           ( SMDS_SpacePosition::originSpacePosition() );
5439       }
5440
5441       // keep inverse elements
5442       if ( !theCopy && !theTargetMesh && needReverse ) {
5443         SMDS_ElemIteratorPtr invElemIt = node->GetInverseElementIterator();
5444         while ( invElemIt->more() ) {
5445           const SMDS_MeshElement* iel = invElemIt->next();
5446           inverseElemSet.insert( iel );
5447         }
5448       }
5449     }
5450   }
5451
5452   // either create new elements or reverse mirrored ones
5453   if ( !theCopy && !needReverse && !theTargetMesh )
5454     return PGroupIDs();
5455
5456   TIDSortedElemSet::iterator invElemIt = inverseElemSet.begin();
5457   for ( ; invElemIt != inverseElemSet.end(); invElemIt++ )
5458     theElems.insert( *invElemIt );
5459
5460   // replicate or reverse elements
5461   // TODO revoir ordre reverse vtk
5462   enum {
5463     REV_TETRA   = 0,  //  = nbNodes - 4
5464     REV_PYRAMID = 1,  //  = nbNodes - 4
5465     REV_PENTA   = 2,  //  = nbNodes - 4
5466     REV_FACE    = 3,
5467     REV_HEXA    = 4,  //  = nbNodes - 4
5468     FORWARD     = 5
5469   };
5470   int index[][8] = {
5471     { 2, 1, 0, 3, 4, 0, 0, 0 },  // REV_TETRA
5472     { 2, 1, 0, 3, 4, 0, 0, 0 },  // REV_PYRAMID
5473     { 2, 1, 0, 5, 4, 3, 0, 0 },  // REV_PENTA
5474     { 2, 1, 0, 3, 0, 0, 0, 0 },  // REV_FACE
5475     { 2, 1, 0, 3, 6, 5, 4, 7 },  // REV_HEXA
5476     { 0, 1, 2, 3, 4, 5, 6, 7 }   // FORWARD
5477   };
5478
5479   for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ )
5480   {
5481     const SMDS_MeshElement* elem = *itElem;
5482     if ( !elem || elem->GetType() == SMDSAbs_Node )
5483       continue;
5484
5485     int nbNodes = elem->NbNodes();
5486     int elemType = elem->GetType();
5487
5488     if (elem->IsPoly()) {
5489       // Polygon or Polyhedral Volume
5490       switch ( elemType ) {
5491       case SMDSAbs_Face:
5492         {
5493           vector<const SMDS_MeshNode*> poly_nodes (nbNodes);
5494           int iNode = 0;
5495           SMDS_ElemIteratorPtr itN = elem->nodesIterator();
5496           while (itN->more()) {
5497             const SMDS_MeshNode* node =
5498               static_cast<const SMDS_MeshNode*>(itN->next());
5499             TNodeNodeMap::iterator nodeMapIt = nodeMap.find(node);
5500             if (nodeMapIt == nodeMap.end())
5501               break; // not all nodes transformed
5502             if (needReverse) {
5503               // reverse mirrored faces and volumes
5504               poly_nodes[nbNodes - iNode - 1] = (*nodeMapIt).second;
5505             } else {
5506               poly_nodes[iNode] = (*nodeMapIt).second;
5507             }
5508             iNode++;
5509           }
5510           if ( iNode != nbNodes )
5511             continue; // not all nodes transformed
5512
5513           if ( theTargetMesh ) {
5514             myLastCreatedElems.Append(aTgtMesh->AddPolygonalFace(poly_nodes));
5515             srcElems.Append( elem );
5516           }
5517           else if ( theCopy ) {
5518             myLastCreatedElems.Append(aMesh->AddPolygonalFace(poly_nodes));
5519             srcElems.Append( elem );
5520           }
5521           else {
5522             aMesh->ChangePolygonNodes(elem, poly_nodes);
5523           }
5524         }
5525         break;
5526       case SMDSAbs_Volume:
5527         {
5528           // ATTENTION: Reversing is not yet done!!!
5529           const SMDS_VtkVolume* aPolyedre =
5530             dynamic_cast<const SMDS_VtkVolume*>( elem );
5531           if (!aPolyedre) {
5532             MESSAGE("Warning: bad volumic element");
5533             continue;
5534           }
5535
5536           vector<const SMDS_MeshNode*> poly_nodes;
5537           vector<int> quantities;
5538
5539           bool allTransformed = true;
5540           int nbFaces = aPolyedre->NbFaces();
5541           for (int iface = 1; iface <= nbFaces && allTransformed; iface++) {
5542             int nbFaceNodes = aPolyedre->NbFaceNodes(iface);
5543             for (int inode = 1; inode <= nbFaceNodes && allTransformed; inode++) {
5544               const SMDS_MeshNode* node = aPolyedre->GetFaceNode(iface, inode);
5545               TNodeNodeMap::iterator nodeMapIt = nodeMap.find(node);
5546               if (nodeMapIt == nodeMap.end()) {
5547                 allTransformed = false; // not all nodes transformed
5548               } else {
5549                 poly_nodes.push_back((*nodeMapIt).second);
5550               }
5551             }
5552             quantities.push_back(nbFaceNodes);
5553           }
5554           if ( !allTransformed )
5555             continue; // not all nodes transformed
5556
5557           if ( theTargetMesh ) {
5558             myLastCreatedElems.Append(aTgtMesh->AddPolyhedralVolume(poly_nodes, quantities));
5559             srcElems.Append( elem );
5560           }
5561           else if ( theCopy ) {
5562             myLastCreatedElems.Append(aMesh->AddPolyhedralVolume(poly_nodes, quantities));
5563             srcElems.Append( elem );
5564           }
5565           else {
5566             aMesh->ChangePolyhedronNodes(elem, poly_nodes, quantities);
5567           }
5568         }
5569         break;
5570       default:;
5571       }
5572       continue;
5573     }
5574
5575     // Regular elements
5576     int* i = index[ FORWARD ];
5577     if ( needReverse && nbNodes > 2) {// reverse mirrored faces and volumes
5578       if ( elemType == SMDSAbs_Face )
5579         i = index[ REV_FACE ];
5580       else
5581         i = index[ nbNodes - 4 ];
5582     }
5583     if(elem->IsQuadratic()) {
5584       static int anIds[] = {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19};
5585       i = anIds;
5586       if(needReverse) {
5587         if(nbNodes==3) { // quadratic edge
5588           static int anIds[] = {1,0,2};
5589           i = anIds;
5590         }
5591         else if(nbNodes==6) { // quadratic triangle
5592           static int anIds[] = {0,2,1,5,4,3};
5593           i = anIds;
5594         }
5595         else if(nbNodes==8) { // quadratic quadrangle
5596           static int anIds[] = {0,3,2,1,7,6,5,4};
5597           i = anIds;
5598         }
5599         else if(nbNodes==10) { // quadratic tetrahedron of 10 nodes
5600           static int anIds[] = {0,2,1,3,6,5,4,7,9,8};
5601           i = anIds;
5602         }
5603         else if(nbNodes==13) { // quadratic pyramid of 13 nodes
5604           static int anIds[] = {0,3,2,1,4,8,7,6,5,9,12,11,10};
5605           i = anIds;
5606         }
5607         else if(nbNodes==15) { // quadratic pentahedron with 15 nodes
5608           static int anIds[] = {0,2,1,3,5,4,8,7,6,11,10,9,12,14,13};
5609           i = anIds;
5610         }
5611         else { // nbNodes==20 - quadratic hexahedron with 20 nodes
5612           static int anIds[] = {0,3,2,1,4,7,6,5,11,10,9,8,15,14,13,12,16,19,18,17};
5613           i = anIds;
5614         }
5615       }
5616     }
5617
5618     // find transformed nodes
5619     vector<const SMDS_MeshNode*> nodes(nbNodes);
5620     int iNode = 0;
5621     SMDS_ElemIteratorPtr itN = elem->nodesIterator();
5622     while ( itN->more() ) {
5623       const SMDS_MeshNode* node =
5624         static_cast<const SMDS_MeshNode*>( itN->next() );
5625       TNodeNodeMap::iterator nodeMapIt = nodeMap.find( node );
5626       if ( nodeMapIt == nodeMap.end() )
5627         break; // not all nodes transformed
5628       nodes[ i [ iNode++ ]] = (*nodeMapIt).second;
5629     }
5630     if ( iNode != nbNodes )
5631       continue; // not all nodes transformed
5632
5633     if ( theTargetMesh ) {
5634       if ( SMDS_MeshElement* copy =
5635            targetMeshEditor.AddElement( nodes, elem->GetType(), elem->IsPoly() )) {
5636         myLastCreatedElems.Append( copy );
5637         srcElems.Append( elem );
5638       }
5639     }
5640     else if ( theCopy ) {
5641       if ( AddElement( nodes, elem->GetType(), elem->IsPoly() ))
5642         srcElems.Append( elem );
5643     }
5644     else {
5645       // reverse element as it was reversed by transformation
5646       if ( nbNodes > 2 )
5647         aMesh->ChangeElementNodes( elem, &nodes[0], nbNodes );
5648     }
5649   }
5650
5651   PGroupIDs newGroupIDs;
5652
5653   if ( ( theMakeGroups && theCopy ) ||
5654        ( theMakeGroups && theTargetMesh ) )
5655     newGroupIDs = generateGroups( srcNodes, srcElems, groupPostfix, theTargetMesh );
5656
5657   return newGroupIDs;
5658 }
5659
5660
5661 ////=======================================================================
5662 ////function : Scale
5663 ////purpose  :
5664 ////=======================================================================
5665 //
5666 //SMESH_MeshEditor::PGroupIDs
5667 //SMESH_MeshEditor::Scale (TIDSortedElemSet & theElems,
5668 //                         const gp_Pnt&            thePoint,
5669 //                         const std::list<double>& theScaleFact,
5670 //                         const bool         theCopy,
5671 //                         const bool         theMakeGroups,
5672 //                         SMESH_Mesh*        theTargetMesh)
5673 //{
5674 //  MESSAGE("Scale");
5675 //  myLastCreatedElems.Clear();
5676 //  myLastCreatedNodes.Clear();
5677 //
5678 //  SMESH_MeshEditor targetMeshEditor( theTargetMesh );
5679 //  SMESHDS_Mesh* aTgtMesh = theTargetMesh ? theTargetMesh->GetMeshDS() : 0;
5680 //  SMESHDS_Mesh* aMesh    = GetMeshDS();
5681 //
5682 //  double scaleX=1.0, scaleY=1.0, scaleZ=1.0;
5683 //  std::list<double>::const_iterator itS = theScaleFact.begin();
5684 //  scaleX = (*itS);
5685 //  if(theScaleFact.size()==1) {
5686 //    scaleY = (*itS);
5687 //    scaleZ= (*itS);
5688 //  }
5689 //  if(theScaleFact.size()==2) {
5690 //    itS++;
5691 //    scaleY = (*itS);
5692 //    scaleZ= (*itS);
5693 //  }
5694 //  if(theScaleFact.size()>2) {
5695 //    itS++;
5696 //    scaleY = (*itS);
5697 //    itS++;
5698 //    scaleZ= (*itS);
5699 //  }
5700 //
5701 //  // map old node to new one
5702 //  TNodeNodeMap nodeMap;
5703 //
5704 //  // elements sharing moved nodes; those of them which have all
5705 //  // nodes mirrored but are not in theElems are to be reversed
5706 //  TIDSortedElemSet inverseElemSet;
5707 //
5708 //  // source elements for each generated one
5709 //  SMESH_SequenceOfElemPtr srcElems, srcNodes;
5710 //
5711 //  // loop on theElems
5712 //  TIDSortedElemSet::iterator itElem;
5713 //  for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
5714 //    const SMDS_MeshElement* elem = *itElem;
5715 //    if ( !elem )
5716 //      continue;
5717 //
5718 //    // loop on elem nodes
5719 //    SMDS_ElemIteratorPtr itN = elem->nodesIterator();
5720 //    while ( itN->more() ) {
5721 //
5722 //      // check if a node has been already transformed
5723 //      const SMDS_MeshNode* node = cast2Node( itN->next() );
5724 //      pair<TNodeNodeMap::iterator,bool> n2n_isnew =
5725 //        nodeMap.insert( make_pair ( node, node ));
5726 //      if ( !n2n_isnew.second )
5727 //        continue;
5728 //
5729 //      //double coord[3];
5730 //      //coord[0] = node->X();
5731 //      //coord[1] = node->Y();
5732 //      //coord[2] = node->Z();
5733 //      //theTrsf.Transforms( coord[0], coord[1], coord[2] );
5734 //      double dx = (node->X() - thePoint.X()) * scaleX;
5735 //      double dy = (node->Y() - thePoint.Y()) * scaleY;
5736 //      double dz = (node->Z() - thePoint.Z()) * scaleZ;
5737 //      if ( theTargetMesh ) {
5738 //        //const SMDS_MeshNode * newNode = aTgtMesh->AddNode( coord[0], coord[1], coord[2] );
5739 //        const SMDS_MeshNode * newNode =
5740 //          aTgtMesh->AddNode( thePoint.X()+dx, thePoint.Y()+dy, thePoint.Z()+dz );
5741 //        n2n_isnew.first->second = newNode;
5742 //        myLastCreatedNodes.Append(newNode);
5743 //        srcNodes.Append( node );
5744 //      }
5745 //      else if ( theCopy ) {
5746 //        //const SMDS_MeshNode * newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
5747 //        const SMDS_MeshNode * newNode =
5748 //          aMesh->AddNode( thePoint.X()+dx, thePoint.Y()+dy, thePoint.Z()+dz );
5749 //        n2n_isnew.first->second = newNode;
5750 //        myLastCreatedNodes.Append(newNode);
5751 //        srcNodes.Append( node );
5752 //      }
5753 //      else {
5754 //        //aMesh->MoveNode( node, coord[0], coord[1], coord[2] );
5755 //        aMesh->MoveNode( node, thePoint.X()+dx, thePoint.Y()+dy, thePoint.Z()+dz );
5756 //        // node position on shape becomes invalid
5757 //        const_cast< SMDS_MeshNode* > ( node )->SetPosition
5758 //          ( SMDS_SpacePosition::originSpacePosition() );
5759 //      }
5760 //
5761 //      // keep inverse elements
5762 //      //if ( !theCopy && !theTargetMesh && needReverse ) {
5763 //      //  SMDS_ElemIteratorPtr invElemIt = node->GetInverseElementIterator();
5764 //      //  while ( invElemIt->more() ) {
5765 //      //    const SMDS_MeshElement* iel = invElemIt->next();
5766 //      //    inverseElemSet.insert( iel );
5767 //      //  }
5768 //      //}
5769 //    }
5770 //  }
5771 //
5772 //  // either create new elements or reverse mirrored ones
5773 //  //if ( !theCopy && !needReverse && !theTargetMesh )
5774 //  if ( !theCopy && !theTargetMesh )
5775 //    return PGroupIDs();
5776 //
5777 //  TIDSortedElemSet::iterator invElemIt = inverseElemSet.begin();
5778 //  for ( ; invElemIt != inverseElemSet.end(); invElemIt++ )
5779 //    theElems.insert( *invElemIt );
5780 //
5781 //  // replicate or reverse elements
5782 //
5783 //  enum {
5784 //    REV_TETRA   = 0,  //  = nbNodes - 4
5785 //    REV_PYRAMID = 1,  //  = nbNodes - 4
5786 //    REV_PENTA   = 2,  //  = nbNodes - 4
5787 //    REV_FACE    = 3,
5788 //    REV_HEXA    = 4,  //  = nbNodes - 4
5789 //    FORWARD     = 5
5790 //  };
5791 //  int index[][8] = {
5792 //    { 2, 1, 0, 3, 4, 0, 0, 0 },  // REV_TETRA
5793 //    { 2, 1, 0, 3, 4, 0, 0, 0 },  // REV_PYRAMID
5794 //    { 2, 1, 0, 5, 4, 3, 0, 0 },  // REV_PENTA
5795 //    { 2, 1, 0, 3, 0, 0, 0, 0 },  // REV_FACE
5796 //    { 2, 1, 0, 3, 6, 5, 4, 7 },  // REV_HEXA
5797 //    { 0, 1, 2, 3, 4, 5, 6, 7 }   // FORWARD
5798 //  };
5799 //
5800 //  for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ )
5801 //  {
5802 //    const SMDS_MeshElement* elem = *itElem;
5803 //    if ( !elem || elem->GetType() == SMDSAbs_Node )
5804 //      continue;
5805 //
5806 //    int nbNodes = elem->NbNodes();
5807 //    int elemType = elem->GetType();
5808 //
5809 //    if (elem->IsPoly()) {
5810 //      // Polygon or Polyhedral Volume
5811 //      switch ( elemType ) {
5812 //      case SMDSAbs_Face:
5813 //        {
5814 //          vector<const SMDS_MeshNode*> poly_nodes (nbNodes);
5815 //          int iNode = 0;
5816 //          SMDS_ElemIteratorPtr itN = elem->nodesIterator();
5817 //          while (itN->more()) {
5818 //            const SMDS_MeshNode* node =
5819 //              static_cast<const SMDS_MeshNode*>(itN->next());
5820 //            TNodeNodeMap::iterator nodeMapIt = nodeMap.find(node);
5821 //            if (nodeMapIt == nodeMap.end())
5822 //              break; // not all nodes transformed
5823 //            //if (needReverse) {
5824 //            //  // reverse mirrored faces and volumes
5825 //            //  poly_nodes[nbNodes - iNode - 1] = (*nodeMapIt).second;
5826 //            //} else {
5827 //            poly_nodes[iNode] = (*nodeMapIt).second;
5828 //            //}
5829 //            iNode++;
5830 //          }
5831 //          if ( iNode != nbNodes )
5832 //            continue; // not all nodes transformed
5833 //
5834 //          if ( theTargetMesh ) {
5835 //            myLastCreatedElems.Append(aTgtMesh->AddPolygonalFace(poly_nodes));
5836 //            srcElems.Append( elem );
5837 //          }
5838 //          else if ( theCopy ) {
5839 //            myLastCreatedElems.Append(aMesh->AddPolygonalFace(poly_nodes));
5840 //            srcElems.Append( elem );
5841 //          }
5842 //          else {
5843 //            aMesh->ChangePolygonNodes(elem, poly_nodes);
5844 //          }
5845 //        }
5846 //        break;
5847 //      case SMDSAbs_Volume:
5848 //        {
5849 //          // ATTENTION: Reversing is not yet done!!!
5850 //          const SMDS_VtkVolume* aPolyedre =
5851 //            dynamic_cast<const SMDS_VtkVolume*>( elem );
5852 //          if (!aPolyedre) {
5853 //            MESSAGE("Warning: bad volumic element");
5854 //            continue;
5855 //          }
5856 //
5857 //          vector<const SMDS_MeshNode*> poly_nodes;
5858 //          vector<int> quantities;
5859 //
5860 //          bool allTransformed = true;
5861 //          int nbFaces = aPolyedre->NbFaces();
5862 //          for (int iface = 1; iface <= nbFaces && allTransformed; iface++) {
5863 //            int nbFaceNodes = aPolyedre->NbFaceNodes(iface);
5864 //            for (int inode = 1; inode <= nbFaceNodes && allTransformed; inode++) {
5865 //              const SMDS_MeshNode* node = aPolyedre->GetFaceNode(iface, inode);
5866 //              TNodeNodeMap::iterator nodeMapIt = nodeMap.find(node);
5867 //              if (nodeMapIt == nodeMap.end()) {
5868 //                allTransformed = false; // not all nodes transformed
5869 //              } else {
5870 //                poly_nodes.push_back((*nodeMapIt).second);
5871 //              }
5872 //            }
5873 //            quantities.push_back(nbFaceNodes);
5874 //          }
5875 //          if ( !allTransformed )
5876 //            continue; // not all nodes transformed
5877 //
5878 //          if ( theTargetMesh ) {
5879 //            myLastCreatedElems.Append(aTgtMesh->AddPolyhedralVolume(poly_nodes, quantities));
5880 //            srcElems.Append( elem );
5881 //          }
5882 //          else if ( theCopy ) {
5883 //            myLastCreatedElems.Append(aMesh->AddPolyhedralVolume(poly_nodes, quantities));
5884 //            srcElems.Append( elem );
5885 //          }
5886 //          else {
5887 //            aMesh->ChangePolyhedronNodes(elem, poly_nodes, quantities);
5888 //          }
5889 //        }
5890 //        break;
5891 //      default:;
5892 //      }
5893 //      continue;
5894 //    }
5895 //
5896 //    // Regular elements
5897 //    int* i = index[ FORWARD ];
5898 //    //if ( needReverse && nbNodes > 2) // reverse mirrored faces and volumes
5899 //    //  if ( elemType == SMDSAbs_Face )
5900 //    //    i = index[ REV_FACE ];
5901 //    //  else
5902 //    //    i = index[ nbNodes - 4 ];
5903 //
5904 //    if(elem->IsQuadratic()) {
5905 //      static int anIds[] = {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19};
5906 //      i = anIds;
5907 //      //if(needReverse) {
5908 //      //  if(nbNodes==3) { // quadratic edge
5909 //      //    static int anIds[] = {1,0,2};
5910 //      //    i = anIds;
5911 //      //  }
5912 //      //  else if(nbNodes==6) { // quadratic triangle
5913 //      //    static int anIds[] = {0,2,1,5,4,3};
5914 //      //    i = anIds;
5915 //      //  }
5916 //      //  else if(nbNodes==8) { // quadratic quadrangle
5917 //      //    static int anIds[] = {0,3,2,1,7,6,5,4};
5918 //      //    i = anIds;
5919 //      //  }
5920 //      //  else if(nbNodes==10) { // quadratic tetrahedron of 10 nodes
5921 //      //    static int anIds[] = {0,2,1,3,6,5,4,7,9,8};
5922 //      //    i = anIds;
5923 //      //  }
5924 //      //  else if(nbNodes==13) { // quadratic pyramid of 13 nodes
5925 //      //    static int anIds[] = {0,3,2,1,4,8,7,6,5,9,12,11,10};
5926 //      //    i = anIds;
5927 //      //  }
5928 //      //  else if(nbNodes==15) { // quadratic pentahedron with 15 nodes
5929 //      //    static int anIds[] = {0,2,1,3,5,4,8,7,6,11,10,9,12,14,13};
5930 //      //    i = anIds;
5931 //      //  }
5932 //      //  else { // nbNodes==20 - quadratic hexahedron with 20 nodes
5933 //      //    static int anIds[] = {0,3,2,1,4,7,6,5,11,10,9,8,15,14,13,12,16,19,18,17};
5934 //      //    i = anIds;
5935 //      //  }
5936 //      //}
5937 //    }
5938 //
5939 //    // find transformed nodes
5940 //    vector<const SMDS_MeshNode*> nodes(nbNodes);
5941 //    int iNode = 0;
5942 //    SMDS_ElemIteratorPtr itN = elem->nodesIterator();
5943 //    while ( itN->more() ) {
5944 //      const SMDS_MeshNode* node =
5945 //        static_cast<const SMDS_MeshNode*>( itN->next() );
5946 //      TNodeNodeMap::iterator nodeMapIt = nodeMap.find( node );
5947 //      if ( nodeMapIt == nodeMap.end() )
5948 //        break; // not all nodes transformed
5949 //      nodes[ i [ iNode++ ]] = (*nodeMapIt).second;
5950 //    }
5951 //    if ( iNode != nbNodes )
5952 //      continue; // not all nodes transformed
5953 //
5954 //    if ( theTargetMesh ) {
5955 //      if ( SMDS_MeshElement* copy =
5956 //           targetMeshEditor.AddElement( nodes, elem->GetType(), elem->IsPoly() )) {
5957 //        myLastCreatedElems.Append( copy );
5958 //        srcElems.Append( elem );
5959 //      }
5960 //    }
5961 //    else if ( theCopy ) {
5962 //      if ( SMDS_MeshElement* copy = AddElement( nodes, elem->GetType(), elem->IsPoly() )) {
5963 //        myLastCreatedElems.Append( copy );
5964 //        srcElems.Append( elem );
5965 //      }
5966 //    }
5967 //    else {
5968 //      // reverse element as it was reversed by transformation
5969 //      if ( nbNodes > 2 )
5970 //        aMesh->ChangeElementNodes( elem, &nodes[0], nbNodes );
5971 //    }
5972 //  }
5973 //
5974 //  PGroupIDs newGroupIDs;
5975 //
5976 //  if ( theMakeGroups && theCopy ||
5977 //       theMakeGroups && theTargetMesh ) {
5978 //    string groupPostfix = "scaled";
5979 //    newGroupIDs = generateGroups( srcNodes, srcElems, groupPostfix, theTargetMesh );
5980 //  }
5981 //
5982 //  return newGroupIDs;
5983 //}
5984
5985
5986 //=======================================================================
5987 /*!
5988  * \brief Create groups of elements made during transformation
5989  * \param nodeGens - nodes making corresponding myLastCreatedNodes
5990  * \param elemGens - elements making corresponding myLastCreatedElems
5991  * \param postfix - to append to names of new groups
5992  */
5993 //=======================================================================
5994
5995 SMESH_MeshEditor::PGroupIDs
5996 SMESH_MeshEditor::generateGroups(const SMESH_SequenceOfElemPtr& nodeGens,
5997                                  const SMESH_SequenceOfElemPtr& elemGens,
5998                                  const std::string&             postfix,
5999                                  SMESH_Mesh*                    targetMesh)
6000 {
6001   PGroupIDs newGroupIDs( new list<int> );
6002   SMESH_Mesh* mesh = targetMesh ? targetMesh : GetMesh();
6003
6004   // Sort existing groups by types and collect their names
6005
6006   // to store an old group and a generated new one
6007   typedef pair< SMESHDS_GroupBase*, SMDS_MeshGroup* > TOldNewGroup;
6008   vector< list< TOldNewGroup > > groupsByType( SMDSAbs_NbElementTypes );
6009   // group names
6010   set< string > groupNames;
6011   //
6012   SMDS_MeshGroup* nullNewGroup = (SMDS_MeshGroup*) 0;
6013   SMESH_Mesh::GroupIteratorPtr groupIt = GetMesh()->GetGroups();
6014   while ( groupIt->more() ) {
6015     SMESH_Group * group = groupIt->next();
6016     if ( !group ) continue;
6017     SMESHDS_GroupBase* groupDS = group->GetGroupDS();
6018     if ( !groupDS || groupDS->IsEmpty() ) continue;
6019     groupNames.insert( group->GetName() );
6020     groupDS->SetStoreName( group->GetName() );
6021     groupsByType[ groupDS->GetType() ].push_back( make_pair( groupDS, nullNewGroup ));
6022   }
6023
6024   // Groups creation
6025
6026   // loop on nodes and elements
6027   for ( int isNodes = 0; isNodes < 2; ++isNodes )
6028   {
6029     const SMESH_SequenceOfElemPtr& gens  = isNodes ? nodeGens : elemGens;
6030     const SMESH_SequenceOfElemPtr& elems = isNodes ? myLastCreatedNodes : myLastCreatedElems;
6031     if ( gens.Length() != elems.Length() )
6032       throw SALOME_Exception(LOCALIZED("invalid args"));
6033
6034     // loop on created elements
6035     for (int iElem = 1; iElem <= elems.Length(); ++iElem )
6036     {
6037       const SMDS_MeshElement* sourceElem = gens( iElem );
6038       if ( !sourceElem ) {
6039         MESSAGE("generateGroups(): NULL source element");
6040         continue;
6041       }
6042       list< TOldNewGroup > & groupsOldNew = groupsByType[ sourceElem->GetType() ];
6043       if ( groupsOldNew.empty() ) {
6044         while ( iElem < gens.Length() && gens( iElem+1 ) == sourceElem )
6045           ++iElem; // skip all elements made by sourceElem
6046         continue;
6047       }
6048       // collect all elements made by sourceElem
6049       list< const SMDS_MeshElement* > resultElems;
6050       if ( const SMDS_MeshElement* resElem = elems( iElem ))
6051         if ( resElem != sourceElem )
6052           resultElems.push_back( resElem );
6053       while ( iElem < gens.Length() && gens( iElem+1 ) == sourceElem )
6054         if ( const SMDS_MeshElement* resElem = elems( ++iElem ))
6055           if ( resElem != sourceElem )
6056             resultElems.push_back( resElem );
6057       // do not generate element groups from node ones
6058       if ( sourceElem->GetType() == SMDSAbs_Node &&
6059            elems( iElem )->GetType() != SMDSAbs_Node )
6060         continue;
6061
6062       // add resultElems to groups made by ones the sourceElem belongs to
6063       list< TOldNewGroup >::iterator gOldNew, gLast = groupsOldNew.end();
6064       for ( gOldNew = groupsOldNew.begin(); gOldNew != gLast; ++gOldNew )
6065       {
6066         SMESHDS_GroupBase* oldGroup = gOldNew->first;
6067         if ( oldGroup->Contains( sourceElem )) // sourceElem in oldGroup
6068         {
6069           SMDS_MeshGroup* & newGroup = gOldNew->second;
6070           if ( !newGroup )// create a new group
6071           {
6072             // make a name
6073             string name = oldGroup->GetStoreName();
6074             if ( !targetMesh ) {
6075               name += "_";
6076               name += postfix;
6077               int nb = 0;
6078               while ( !groupNames.insert( name ).second ) // name exists
6079               {
6080                 if ( nb == 0 ) {
6081                   name += "_1";
6082                 }
6083                 else {
6084                   TCollection_AsciiString nbStr(nb+1);
6085                   name.resize( name.rfind('_')+1 );
6086                   name += nbStr.ToCString();
6087                 }
6088                 ++nb;
6089               }
6090             }
6091             // make a group
6092             int id;
6093             SMESH_Group* group = mesh->AddGroup( resultElems.back()->GetType(),
6094                                                  name.c_str(), id );
6095             SMESHDS_Group* groupDS = static_cast<SMESHDS_Group*>(group->GetGroupDS());
6096             newGroup = & groupDS->SMDSGroup();
6097             newGroupIDs->push_back( id );
6098           }
6099
6100           // fill in a new group
6101           list< const SMDS_MeshElement* >::iterator resLast = resultElems.end(), resElemIt;
6102           for ( resElemIt = resultElems.begin(); resElemIt != resLast; ++resElemIt )
6103             newGroup->Add( *resElemIt );
6104         }
6105       }
6106     } // loop on created elements
6107   }// loop on nodes and elements
6108
6109   return newGroupIDs;
6110 }
6111
6112 //================================================================================
6113 /*!
6114  * \brief Return list of group of nodes close to each other within theTolerance
6115  *        Search among theNodes or in the whole mesh if theNodes is empty using
6116  *        an Octree algorithm
6117  */
6118 //================================================================================
6119
6120 void SMESH_MeshEditor::FindCoincidentNodes (TIDSortedNodeSet &   theNodes,
6121                                             const double         theTolerance,
6122                                             TListOfListOfNodes & theGroupsOfNodes)
6123 {
6124   myLastCreatedElems.Clear();
6125   myLastCreatedNodes.Clear();
6126
6127   if ( theNodes.empty() )
6128   { // get all nodes in the mesh
6129     SMDS_NodeIteratorPtr nIt = GetMeshDS()->nodesIterator(/*idInceasingOrder=*/true);
6130     while ( nIt->more() )
6131       theNodes.insert( theNodes.end(),nIt->next());
6132   }
6133
6134   SMESH_OctreeNode::FindCoincidentNodes ( theNodes, &theGroupsOfNodes, theTolerance);
6135 }
6136
6137
6138 //=======================================================================
6139 /*!
6140  * \brief Implementation of search for the node closest to point
6141  */
6142 //=======================================================================
6143
6144 struct SMESH_NodeSearcherImpl: public SMESH_NodeSearcher
6145 {
6146   //---------------------------------------------------------------------
6147   /*!
6148    * \brief Constructor
6149    */
6150   SMESH_NodeSearcherImpl( const SMESHDS_Mesh* theMesh )
6151   {
6152     myMesh = ( SMESHDS_Mesh* ) theMesh;
6153
6154     TIDSortedNodeSet nodes;
6155     if ( theMesh ) {
6156       SMDS_NodeIteratorPtr nIt = theMesh->nodesIterator(/*idInceasingOrder=*/true);
6157       while ( nIt->more() )
6158         nodes.insert( nodes.end(), nIt->next() );
6159     }
6160     myOctreeNode = new SMESH_OctreeNode(nodes) ;
6161
6162     // get max size of a leaf box
6163     SMESH_OctreeNode* tree = myOctreeNode;
6164     while ( !tree->isLeaf() )
6165     {
6166       SMESH_OctreeNodeIteratorPtr cIt = tree->GetChildrenIterator();
6167       if ( cIt->more() )
6168         tree = cIt->next();
6169     }
6170     myHalfLeafSize = tree->maxSize() / 2.;
6171   }
6172
6173   //---------------------------------------------------------------------
6174   /*!
6175    * \brief Move node and update myOctreeNode accordingly
6176    */
6177   void MoveNode( const SMDS_MeshNode* node, const gp_Pnt& toPnt )
6178   {
6179     myOctreeNode->UpdateByMoveNode( node, toPnt );
6180     myMesh->MoveNode( node, toPnt.X(), toPnt.Y(), toPnt.Z() );
6181   }
6182
6183   //---------------------------------------------------------------------
6184   /*!
6185    * \brief Do it's job
6186    */
6187   const SMDS_MeshNode* FindClosestTo( const gp_Pnt& thePnt )
6188   {
6189     map<double, const SMDS_MeshNode*> dist2Nodes;
6190     myOctreeNode->NodesAround( thePnt.Coord(), dist2Nodes, myHalfLeafSize );
6191     if ( !dist2Nodes.empty() )
6192       return dist2Nodes.begin()->second;
6193     list<const SMDS_MeshNode*> nodes;
6194     //myOctreeNode->NodesAround( &tgtNode, &nodes, myHalfLeafSize );
6195
6196     double minSqDist = DBL_MAX;
6197     if ( nodes.empty() )  // get all nodes of OctreeNode's closest to thePnt
6198     {
6199       // sort leafs by their distance from thePnt
6200       typedef map< double, SMESH_OctreeNode* > TDistTreeMap;
6201       TDistTreeMap treeMap;
6202       list< SMESH_OctreeNode* > treeList;
6203       list< SMESH_OctreeNode* >::iterator trIt;
6204       treeList.push_back( myOctreeNode );
6205
6206       gp_XYZ pointNode( thePnt.X(), thePnt.Y(), thePnt.Z() );
6207       bool pointInside = myOctreeNode->isInside( pointNode, myHalfLeafSize );
6208       for ( trIt = treeList.begin(); trIt != treeList.end(); ++trIt)
6209       {
6210         SMESH_OctreeNode* tree = *trIt;
6211         if ( !tree->isLeaf() ) // put children to the queue
6212         {
6213           if ( pointInside && !tree->isInside( pointNode, myHalfLeafSize )) continue;
6214           SMESH_OctreeNodeIteratorPtr cIt = tree->GetChildrenIterator();
6215           while ( cIt->more() )
6216             treeList.push_back( cIt->next() );
6217         }
6218         else if ( tree->NbNodes() ) // put a tree to the treeMap
6219         {
6220           const Bnd_B3d& box = tree->getBox();
6221           double sqDist = thePnt.SquareDistance( 0.5 * ( box.CornerMin() + box.CornerMax() ));
6222           pair<TDistTreeMap::iterator,bool> it_in = treeMap.insert( make_pair( sqDist, tree ));
6223           if ( !it_in.second ) // not unique distance to box center
6224             treeMap.insert( it_in.first, make_pair( sqDist + 1e-13*treeMap.size(), tree ));
6225         }
6226       }
6227       // find distance after which there is no sense to check tree's
6228       double sqLimit = DBL_MAX;
6229       TDistTreeMap::iterator sqDist_tree = treeMap.begin();
6230       if ( treeMap.size() > 5 ) {
6231         SMESH_OctreeNode* closestTree = sqDist_tree->second;
6232         const Bnd_B3d& box = closestTree->getBox();
6233         double limit = sqrt( sqDist_tree->first ) + sqrt ( box.SquareExtent() );
6234         sqLimit = limit * limit;
6235       }
6236       // get all nodes from trees
6237       for ( ; sqDist_tree != treeMap.end(); ++sqDist_tree) {
6238         if ( sqDist_tree->first > sqLimit )
6239           break;
6240         SMESH_OctreeNode* tree = sqDist_tree->second;
6241         tree->NodesAround( tree->GetNodeIterator()->next(), &nodes );
6242       }
6243     }
6244     // find closest among nodes
6245     minSqDist = DBL_MAX;
6246     const SMDS_MeshNode* closestNode = 0;
6247     list<const SMDS_MeshNode*>::iterator nIt = nodes.begin();
6248     for ( ; nIt != nodes.end(); ++nIt ) {
6249       double sqDist = thePnt.SquareDistance( SMESH_TNodeXYZ( *nIt ) );
6250       if ( minSqDist > sqDist ) {
6251         closestNode = *nIt;
6252         minSqDist = sqDist;
6253       }
6254     }
6255     return closestNode;
6256   }
6257
6258   //---------------------------------------------------------------------
6259   /*!
6260    * \brief Destructor
6261    */
6262   ~SMESH_NodeSearcherImpl() { delete myOctreeNode; }
6263
6264   //---------------------------------------------------------------------
6265   /*!
6266    * \brief Return the node tree
6267    */
6268   const SMESH_OctreeNode* getTree() const { return myOctreeNode; }
6269
6270 private:
6271   SMESH_OctreeNode* myOctreeNode;
6272   SMESHDS_Mesh*     myMesh;
6273   double            myHalfLeafSize; // max size of a leaf box
6274 };
6275
6276 //=======================================================================
6277 /*!
6278  * \brief Return SMESH_NodeSearcher
6279  */
6280 //=======================================================================
6281
6282 SMESH_NodeSearcher* SMESH_MeshEditor::GetNodeSearcher() 
6283 {
6284   return new SMESH_NodeSearcherImpl( GetMeshDS() );
6285 }
6286
6287 // ========================================================================
6288 namespace // Utils used in SMESH_ElementSearcherImpl::FindElementsByPoint()
6289 {
6290   const int MaxNbElemsInLeaf = 10; // maximal number of elements in a leaf of tree
6291   const int MaxLevel         = 7;  // maximal tree height -> nb terminal boxes: 8^7 = 2097152
6292   const double NodeRadius = 1e-9;  // to enlarge bnd box of element
6293
6294   //=======================================================================
6295   /*!
6296    * \brief Octal tree of bounding boxes of elements
6297    */
6298   //=======================================================================
6299
6300   class ElementBndBoxTree : public SMESH_Octree
6301   {
6302   public:
6303
6304     ElementBndBoxTree(const SMDS_Mesh& mesh, SMDSAbs_ElementType elemType, SMDS_ElemIteratorPtr theElemIt = SMDS_ElemIteratorPtr(), double tolerance = NodeRadius );
6305     void getElementsNearPoint( const gp_Pnt& point, TIDSortedElemSet& foundElems);
6306     void getElementsNearLine ( const gp_Ax1& line, TIDSortedElemSet& foundElems);
6307     ~ElementBndBoxTree();
6308
6309   protected:
6310     ElementBndBoxTree() {}
6311     SMESH_Octree* allocateOctreeChild() const { return new ElementBndBoxTree; }
6312     void buildChildrenData();
6313     Bnd_B3d* buildRootBox();
6314   private:
6315     //!< Bounding box of element
6316     struct ElementBox : public Bnd_B3d
6317     {
6318       const SMDS_MeshElement* _element;
6319       int                     _refCount; // an ElementBox can be included in several tree branches
6320       ElementBox(const SMDS_MeshElement* elem, double tolerance);
6321     };
6322     vector< ElementBox* > _elements;
6323   };
6324
6325   //================================================================================
6326   /*!
6327    * \brief ElementBndBoxTree creation
6328    */
6329   //================================================================================
6330
6331   ElementBndBoxTree::ElementBndBoxTree(const SMDS_Mesh& mesh, SMDSAbs_ElementType elemType, SMDS_ElemIteratorPtr theElemIt, double tolerance)
6332     :SMESH_Octree( new SMESH_Octree::Limit( MaxLevel, /*minSize=*/0. ))
6333   {
6334     int nbElems = mesh.GetMeshInfo().NbElements( elemType );
6335     _elements.reserve( nbElems );
6336
6337     SMDS_ElemIteratorPtr elemIt = theElemIt ? theElemIt : mesh.elementsIterator( elemType );
6338     while ( elemIt->more() )
6339       _elements.push_back( new ElementBox( elemIt->next(),tolerance  ));
6340
6341     if ( _elements.size() > MaxNbElemsInLeaf )
6342       compute();
6343     else
6344       myIsLeaf = true;
6345   }
6346
6347   //================================================================================
6348   /*!
6349    * \brief Destructor
6350    */
6351   //================================================================================
6352
6353   ElementBndBoxTree::~ElementBndBoxTree()
6354   {
6355     for ( int i = 0; i < _elements.size(); ++i )
6356       if ( --_elements[i]->_refCount <= 0 )
6357         delete _elements[i];
6358   }
6359
6360   //================================================================================
6361   /*!
6362    * \brief Return the maximal box
6363    */
6364   //================================================================================
6365
6366   Bnd_B3d* ElementBndBoxTree::buildRootBox()
6367   {
6368     Bnd_B3d* box = new Bnd_B3d;
6369     for ( int i = 0; i < _elements.size(); ++i )
6370       box->Add( *_elements[i] );
6371     return box;
6372   }
6373
6374   //================================================================================
6375   /*!
6376    * \brief Redistrubute element boxes among children
6377    */
6378   //================================================================================
6379
6380   void ElementBndBoxTree::buildChildrenData()
6381   {
6382     for ( int i = 0; i < _elements.size(); ++i )
6383     {
6384       for (int j = 0; j < 8; j++)
6385       {
6386         if ( !_elements[i]->IsOut( myChildren[j]->getBox() ))
6387         {
6388           _elements[i]->_refCount++;
6389           ((ElementBndBoxTree*)myChildren[j])->_elements.push_back( _elements[i]);
6390         }
6391       }
6392       _elements[i]->_refCount--;
6393     }
6394     _elements.clear();
6395
6396     for (int j = 0; j < 8; j++)
6397     {
6398       ElementBndBoxTree* child = static_cast<ElementBndBoxTree*>( myChildren[j]);
6399       if ( child->_elements.size() <= MaxNbElemsInLeaf )
6400         child->myIsLeaf = true;
6401
6402       if ( child->_elements.capacity() - child->_elements.size() > 1000 )
6403         child->_elements.resize( child->_elements.size() ); // compact
6404     }
6405   }
6406
6407   //================================================================================
6408   /*!
6409    * \brief Return elements which can include the point
6410    */
6411   //================================================================================
6412
6413   void ElementBndBoxTree::getElementsNearPoint( const gp_Pnt&     point,
6414                                                 TIDSortedElemSet& foundElems)
6415   {
6416     if ( level() && getBox().IsOut( point.XYZ() ))
6417       return;
6418
6419     if ( isLeaf() )
6420     {
6421       for ( int i = 0; i < _elements.size(); ++i )
6422         if ( !_elements[i]->IsOut( point.XYZ() ))
6423           foundElems.insert( _elements[i]->_element );
6424     }
6425     else
6426     {
6427       for (int i = 0; i < 8; i++)
6428         ((ElementBndBoxTree*) myChildren[i])->getElementsNearPoint( point, foundElems );
6429     }
6430   }
6431
6432   //================================================================================
6433   /*!
6434    * \brief Return elements which can be intersected by the line
6435    */
6436   //================================================================================
6437
6438   void ElementBndBoxTree::getElementsNearLine( const gp_Ax1&     line,
6439                                                TIDSortedElemSet& foundElems)
6440   {
6441     if ( level() && getBox().IsOut( line ))
6442       return;
6443
6444     if ( isLeaf() )
6445     {
6446       for ( int i = 0; i < _elements.size(); ++i )
6447         if ( !_elements[i]->IsOut( line ))
6448           foundElems.insert( _elements[i]->_element );
6449     }
6450     else
6451     {
6452       for (int i = 0; i < 8; i++)
6453         ((ElementBndBoxTree*) myChildren[i])->getElementsNearLine( line, foundElems );
6454     }
6455   }
6456
6457   //================================================================================
6458   /*!
6459    * \brief Construct the element box
6460    */
6461   //================================================================================
6462
6463   ElementBndBoxTree::ElementBox::ElementBox(const SMDS_MeshElement* elem, double tolerance)
6464   {
6465     _element  = elem;
6466     _refCount = 1;
6467     SMDS_ElemIteratorPtr nIt = elem->nodesIterator();
6468     while ( nIt->more() )
6469       Add( SMESH_TNodeXYZ( cast2Node( nIt->next() )));
6470     Enlarge( tolerance );
6471   }
6472
6473 } // namespace
6474
6475 //=======================================================================
6476 /*!
6477  * \brief Implementation of search for the elements by point and
6478  *        of classification of point in 2D mesh
6479  */
6480 //=======================================================================
6481
6482 struct SMESH_ElementSearcherImpl: public SMESH_ElementSearcher
6483 {
6484   SMESHDS_Mesh*                _mesh;
6485   SMDS_ElemIteratorPtr         _meshPartIt;
6486   ElementBndBoxTree*           _ebbTree;
6487   SMESH_NodeSearcherImpl*      _nodeSearcher;
6488   SMDSAbs_ElementType          _elementType;
6489   double                       _tolerance;
6490   bool                         _outerFacesFound;
6491   set<const SMDS_MeshElement*> _outerFaces; // empty means "no internal faces at all"
6492
6493   SMESH_ElementSearcherImpl( SMESHDS_Mesh& mesh, SMDS_ElemIteratorPtr elemIt=SMDS_ElemIteratorPtr())
6494     : _mesh(&mesh),_meshPartIt(elemIt),_ebbTree(0),_nodeSearcher(0),_tolerance(-1),_outerFacesFound(false) {}
6495   ~SMESH_ElementSearcherImpl()
6496   {
6497     if ( _ebbTree )      delete _ebbTree;      _ebbTree      = 0;
6498     if ( _nodeSearcher ) delete _nodeSearcher; _nodeSearcher = 0;
6499   }
6500   virtual int FindElementsByPoint(const gp_Pnt&                      point,
6501                                   SMDSAbs_ElementType                type,
6502                                   vector< const SMDS_MeshElement* >& foundElements);
6503   virtual TopAbs_State GetPointState(const gp_Pnt& point);
6504
6505   void GetElementsNearLine( const gp_Ax1&                      line,
6506                             SMDSAbs_ElementType                type,
6507                             vector< const SMDS_MeshElement* >& foundElems);
6508   double getTolerance();
6509   bool getIntersParamOnLine(const gp_Lin& line, const SMDS_MeshElement* face,
6510                             const double tolerance, double & param);
6511   void findOuterBoundary(const SMDS_MeshElement* anyOuterFace);
6512   bool isOuterBoundary(const SMDS_MeshElement* face) const
6513   {
6514     return _outerFaces.empty() || _outerFaces.count(face);
6515   }
6516   struct TInters //!< data of intersection of the line and the mesh face (used in GetPointState())
6517   {
6518     const SMDS_MeshElement* _face;
6519     gp_Vec                  _faceNorm;
6520     bool                    _coincides; //!< the line lays in face plane
6521     TInters(const SMDS_MeshElement* face, const gp_Vec& faceNorm, bool coinc=false)
6522       : _face(face), _faceNorm( faceNorm ), _coincides( coinc ) {}
6523   };
6524   struct TFaceLink //!< link and faces sharing it (used in findOuterBoundary())
6525   {
6526     SMESH_TLink      _link;
6527     TIDSortedElemSet _faces;
6528     TFaceLink( const SMDS_MeshNode* n1, const SMDS_MeshNode* n2, const SMDS_MeshElement* face)
6529       : _link( n1, n2 ), _faces( &face, &face + 1) {}
6530   };
6531 };
6532
6533 ostream& operator<< (ostream& out, const SMESH_ElementSearcherImpl::TInters& i)
6534 {
6535   return out << "TInters(face=" << ( i._face ? i._face->GetID() : 0)
6536              << ", _coincides="<<i._coincides << ")";
6537 }
6538
6539 //=======================================================================
6540 /*!
6541  * \brief define tolerance for search
6542  */
6543 //=======================================================================
6544
6545 double SMESH_ElementSearcherImpl::getTolerance()
6546 {
6547   if ( _tolerance < 0 )
6548   {
6549     const SMDS_MeshInfo& meshInfo = _mesh->GetMeshInfo();
6550
6551     _tolerance = 0;
6552     if ( _nodeSearcher && meshInfo.NbNodes() > 1 )
6553     {
6554       double boxSize = _nodeSearcher->getTree()->maxSize();
6555       _tolerance = 1e-8 * boxSize/* / meshInfo.NbNodes()*/;
6556     }
6557     else if ( _ebbTree && meshInfo.NbElements() > 0 )
6558     {
6559       double boxSize = _ebbTree->maxSize();
6560       _tolerance = 1e-8 * boxSize/* / meshInfo.NbElements()*/;
6561     }
6562     if ( _tolerance == 0 )
6563     {
6564       // define tolerance by size of a most complex element
6565       int complexType = SMDSAbs_Volume;
6566       while ( complexType > SMDSAbs_All &&
6567               meshInfo.NbElements( SMDSAbs_ElementType( complexType )) < 1 )
6568         --complexType;
6569       if ( complexType == SMDSAbs_All ) return 0; // empty mesh
6570       double elemSize;
6571       if ( complexType == int( SMDSAbs_Node ))
6572       {
6573         SMDS_NodeIteratorPtr nodeIt = _mesh->nodesIterator();
6574         elemSize = 1;
6575         if ( meshInfo.NbNodes() > 2 )
6576           elemSize = SMESH_TNodeXYZ( nodeIt->next() ).Distance( nodeIt->next() );
6577       }
6578       else
6579       {
6580         SMDS_ElemIteratorPtr elemIt =
6581             _mesh->elementsIterator( SMDSAbs_ElementType( complexType ));
6582         const SMDS_MeshElement* elem = elemIt->next();
6583         SMDS_ElemIteratorPtr nodeIt = elem->nodesIterator();
6584         SMESH_TNodeXYZ n1( cast2Node( nodeIt->next() ));
6585         elemSize = 0;
6586         while ( nodeIt->more() )
6587         {
6588           double dist = n1.Distance( cast2Node( nodeIt->next() ));
6589           elemSize = max( dist, elemSize );
6590         }
6591       }
6592       _tolerance = 1e-4 * elemSize;
6593     }
6594   }
6595   return _tolerance;
6596 }
6597
6598 //================================================================================
6599 /*!
6600  * \brief Find intersection of the line and an edge of face and return parameter on line
6601  */
6602 //================================================================================
6603
6604 bool SMESH_ElementSearcherImpl::getIntersParamOnLine(const gp_Lin&           line,
6605                                                      const SMDS_MeshElement* face,
6606                                                      const double            tol,
6607                                                      double &                param)
6608 {
6609   int nbInts = 0;
6610   param = 0;
6611
6612   GeomAPI_ExtremaCurveCurve anExtCC;
6613   Handle(Geom_Curve) lineCurve = new Geom_Line( line );
6614   
6615   int nbNodes = face->IsQuadratic() ? face->NbNodes()/2 : face->NbNodes();
6616   for ( int i = 0; i < nbNodes && nbInts < 2; ++i )
6617   {
6618     GC_MakeSegment edge( SMESH_TNodeXYZ( face->GetNode( i )),
6619                          SMESH_TNodeXYZ( face->GetNode( (i+1)%nbNodes) )); 
6620     anExtCC.Init( lineCurve, edge);
6621     if ( anExtCC.NbExtrema() > 0 && anExtCC.LowerDistance() <= tol)
6622     {
6623       Quantity_Parameter pl, pe;
6624       anExtCC.LowerDistanceParameters( pl, pe );
6625       param += pl;
6626       if ( ++nbInts == 2 )
6627         break;
6628     }
6629   }
6630   if ( nbInts > 0 ) param /= nbInts;
6631   return nbInts > 0;
6632 }
6633 //================================================================================
6634 /*!
6635  * \brief Find all faces belonging to the outer boundary of mesh
6636  */
6637 //================================================================================
6638
6639 void SMESH_ElementSearcherImpl::findOuterBoundary(const SMDS_MeshElement* outerFace)
6640 {
6641   if ( _outerFacesFound ) return;
6642
6643   // Collect all outer faces by passing from one outer face to another via their links
6644   // and BTW find out if there are internal faces at all.
6645
6646   // checked links and links where outer boundary meets internal one
6647   set< SMESH_TLink > visitedLinks, seamLinks;
6648
6649   // links to treat with already visited faces sharing them
6650   list < TFaceLink > startLinks;
6651
6652   // load startLinks with the first outerFace
6653   startLinks.push_back( TFaceLink( outerFace->GetNode(0), outerFace->GetNode(1), outerFace));
6654   _outerFaces.insert( outerFace );
6655
6656   TIDSortedElemSet emptySet;
6657   while ( !startLinks.empty() )
6658   {
6659     const SMESH_TLink& link  = startLinks.front()._link;
6660     TIDSortedElemSet&  faces = startLinks.front()._faces;
6661
6662     outerFace = *faces.begin();
6663     // find other faces sharing the link
6664     const SMDS_MeshElement* f;
6665     while (( f = SMESH_MeshEditor::FindFaceInSet(link.node1(), link.node2(), emptySet, faces )))
6666       faces.insert( f );
6667
6668     // select another outer face among the found 
6669     const SMDS_MeshElement* outerFace2 = 0;
6670     if ( faces.size() == 2 )
6671     {
6672       outerFace2 = (outerFace == *faces.begin() ? *faces.rbegin() : *faces.begin());
6673     }
6674     else if ( faces.size() > 2 )
6675     {
6676       seamLinks.insert( link );
6677
6678       // link direction within the outerFace
6679       gp_Vec n1n2( SMESH_TNodeXYZ( link.node1()),
6680                    SMESH_TNodeXYZ( link.node2()));
6681       int i1 = outerFace->GetNodeIndex( link.node1() );
6682       int i2 = outerFace->GetNodeIndex( link.node2() );
6683       bool rev = ( abs(i2-i1) == 1 ? i1 > i2 : i2 > i1 );
6684       if ( rev ) n1n2.Reverse();
6685       // outerFace normal
6686       gp_XYZ ofNorm, fNorm;
6687       if ( SMESH_Algo::FaceNormal( outerFace, ofNorm, /*normalized=*/false ))
6688       {
6689         // direction from the link inside outerFace
6690         gp_Vec dirInOF = gp_Vec( ofNorm ) ^ n1n2;
6691         // sort all other faces by angle with the dirInOF
6692         map< double, const SMDS_MeshElement* > angle2Face;
6693         set< const SMDS_MeshElement*, TIDCompare >::const_iterator face = faces.begin();
6694         for ( ; face != faces.end(); ++face )
6695         {
6696           if ( !SMESH_Algo::FaceNormal( *face, fNorm, /*normalized=*/false ))
6697             continue;
6698           gp_Vec dirInF = gp_Vec( fNorm ) ^ n1n2;
6699           double angle = dirInOF.AngleWithRef( dirInF, n1n2 );
6700           if ( angle < 0 ) angle += 2*PI;
6701           angle2Face.insert( make_pair( angle, *face ));
6702         }
6703         if ( !angle2Face.empty() )
6704           outerFace2 = angle2Face.begin()->second;
6705       }
6706     }
6707     // store the found outer face and add its links to continue seaching from
6708     if ( outerFace2 )
6709     {
6710       _outerFaces.insert( outerFace );
6711       int nbNodes = outerFace2->NbNodes()/( outerFace2->IsQuadratic() ? 2 : 1 );
6712       for ( int i = 0; i < nbNodes; ++i )
6713       {
6714         SMESH_TLink link2( outerFace2->GetNode(i), outerFace2->GetNode((i+1)%nbNodes));
6715         if ( visitedLinks.insert( link2 ).second )
6716           startLinks.push_back( TFaceLink( link2.node1(), link2.node2(), outerFace2 ));
6717       }
6718     }
6719     startLinks.pop_front();
6720   }
6721   _outerFacesFound = true;
6722
6723   if ( !seamLinks.empty() )
6724   {
6725     // There are internal boundaries touching the outher one,
6726     // find all faces of internal boundaries in order to find
6727     // faces of boundaries of holes, if any.
6728     
6729   }
6730   else
6731   {
6732     _outerFaces.clear();
6733   }
6734 }
6735
6736 //=======================================================================
6737 /*!
6738  * \brief Find elements of given type where the given point is IN or ON.
6739  *        Returns nb of found elements and elements them-selves.
6740  *
6741  * 'ALL' type means elements of any type excluding nodes and 0D elements
6742  */
6743 //=======================================================================
6744
6745 int SMESH_ElementSearcherImpl::
6746 FindElementsByPoint(const gp_Pnt&                      point,
6747                     SMDSAbs_ElementType                type,
6748                     vector< const SMDS_MeshElement* >& foundElements)
6749 {
6750   foundElements.clear();
6751
6752   double tolerance = getTolerance();
6753
6754   // =================================================================================
6755   if ( type == SMDSAbs_Node || type == SMDSAbs_0DElement )
6756   {
6757     if ( !_nodeSearcher )
6758       _nodeSearcher = new SMESH_NodeSearcherImpl( _mesh );
6759
6760     const SMDS_MeshNode* closeNode = _nodeSearcher->FindClosestTo( point );
6761     if ( !closeNode ) return foundElements.size();
6762
6763     if ( point.Distance( SMESH_TNodeXYZ( closeNode )) > tolerance )
6764       return foundElements.size(); // to far from any node
6765
6766     if ( type == SMDSAbs_Node )
6767     {
6768       foundElements.push_back( closeNode );
6769     }
6770     else
6771     {
6772       SMDS_ElemIteratorPtr elemIt = closeNode->GetInverseElementIterator( SMDSAbs_0DElement );
6773       while ( elemIt->more() )
6774         foundElements.push_back( elemIt->next() );
6775     }
6776   }
6777   // =================================================================================
6778   else // elements more complex than 0D
6779   {
6780     if ( !_ebbTree || _elementType != type )
6781     {
6782       if ( _ebbTree ) delete _ebbTree;
6783       _ebbTree = new ElementBndBoxTree( *_mesh, _elementType = type, _meshPartIt, tolerance );
6784     }
6785     TIDSortedElemSet suspectElems;
6786     _ebbTree->getElementsNearPoint( point, suspectElems );
6787     TIDSortedElemSet::iterator elem = suspectElems.begin();
6788     for ( ; elem != suspectElems.end(); ++elem )
6789       if ( !SMESH_MeshEditor::isOut( *elem, point, tolerance ))
6790         foundElements.push_back( *elem );
6791   }
6792   return foundElements.size();
6793 }
6794
6795 //================================================================================
6796 /*!
6797  * \brief Classify the given point in the closed 2D mesh
6798  */
6799 //================================================================================
6800
6801 TopAbs_State SMESH_ElementSearcherImpl::GetPointState(const gp_Pnt& point)
6802 {
6803   double tolerance = getTolerance();
6804   if ( !_ebbTree || _elementType != SMDSAbs_Face )
6805   {
6806     if ( _ebbTree ) delete _ebbTree;
6807     _ebbTree = new ElementBndBoxTree( *_mesh, _elementType = SMDSAbs_Face, _meshPartIt );
6808   }
6809   // Algo: analyse transition of a line starting at the point through mesh boundary;
6810   // try three lines parallel to axis of the coordinate system and perform rough
6811   // analysis. If solution is not clear perform thorough analysis.
6812
6813   const int nbAxes = 3;
6814   gp_Dir axisDir[ nbAxes ] = { gp::DX(), gp::DY(), gp::DZ() };
6815   map< double, TInters >   paramOnLine2TInters[ nbAxes ];
6816   list< TInters > tangentInters[ nbAxes ]; // of faces whose plane includes the line
6817   multimap< int, int > nbInt2Axis; // to find the simplest case
6818   for ( int axis = 0; axis < nbAxes; ++axis )
6819   {
6820     gp_Ax1 lineAxis( point, axisDir[axis]);
6821     gp_Lin line    ( lineAxis );
6822
6823     TIDSortedElemSet suspectFaces; // faces possibly intersecting the line
6824     _ebbTree->getElementsNearLine( lineAxis, suspectFaces );
6825
6826     // Intersect faces with the line
6827
6828     map< double, TInters > & u2inters = paramOnLine2TInters[ axis ];
6829     TIDSortedElemSet::iterator face = suspectFaces.begin();
6830     for ( ; face != suspectFaces.end(); ++face )
6831     {
6832       // get face plane
6833       gp_XYZ fNorm;
6834       if ( !SMESH_Algo::FaceNormal( *face, fNorm, /*normalized=*/false)) continue;
6835       gp_Pln facePlane( SMESH_TNodeXYZ( (*face)->GetNode(0)), fNorm );
6836
6837       // perform intersection
6838       IntAna_IntConicQuad intersection( line, IntAna_Quadric( facePlane ));
6839       if ( !intersection.IsDone() )
6840         continue;
6841       if ( intersection.IsInQuadric() )
6842       {
6843         tangentInters[ axis ].push_back( TInters( *face, fNorm, true ));
6844       }
6845       else if ( ! intersection.IsParallel() && intersection.NbPoints() > 0 )
6846       {
6847         gp_Pnt intersectionPoint = intersection.Point(1);
6848         if ( !SMESH_MeshEditor::isOut( *face, intersectionPoint, tolerance ))
6849           u2inters.insert(make_pair( intersection.ParamOnConic(1), TInters( *face, fNorm )));
6850       }
6851     }
6852     // Analyse intersections roughly
6853
6854     int nbInter = u2inters.size();
6855     if ( nbInter == 0 )
6856       return TopAbs_OUT; 
6857
6858     double f = u2inters.begin()->first, l = u2inters.rbegin()->first;
6859     if ( nbInter == 1 ) // not closed mesh
6860       return fabs( f ) < tolerance ? TopAbs_ON : TopAbs_UNKNOWN;
6861
6862     if ( fabs( f ) < tolerance || fabs( l ) < tolerance )
6863       return TopAbs_ON;
6864
6865     if ( (f<0) == (l<0) )
6866       return TopAbs_OUT;
6867
6868     int nbIntBeforePoint = std::distance( u2inters.begin(), u2inters.lower_bound(0));
6869     int nbIntAfterPoint  = nbInter - nbIntBeforePoint;
6870     if ( nbIntBeforePoint == 1 || nbIntAfterPoint == 1 )
6871       return TopAbs_IN;
6872
6873     nbInt2Axis.insert( make_pair( min( nbIntBeforePoint, nbIntAfterPoint ), axis ));
6874
6875     if ( _outerFacesFound ) break; // pass to thorough analysis
6876
6877   } // three attempts - loop on CS axes
6878
6879   // Analyse intersections thoroughly.
6880   // We make two loops maximum, on the first one we only exclude touching intersections,
6881   // on the second, if situation is still unclear, we gather and use information on
6882   // position of faces (internal or outer). If faces position is already gathered,
6883   // we make the second loop right away.
6884
6885   for ( int hasPositionInfo = _outerFacesFound; hasPositionInfo < 2; ++hasPositionInfo )
6886   {
6887     multimap< int, int >::const_iterator nb_axis = nbInt2Axis.begin();
6888     for ( ; nb_axis != nbInt2Axis.end(); ++nb_axis )
6889     {
6890       int axis = nb_axis->second;
6891       map< double, TInters > & u2inters = paramOnLine2TInters[ axis ];
6892
6893       gp_Ax1 lineAxis( point, axisDir[axis]);
6894       gp_Lin line    ( lineAxis );
6895
6896       // add tangent intersections to u2inters
6897       double param;
6898       list< TInters >::const_iterator tgtInt = tangentInters[ axis ].begin();
6899       for ( ; tgtInt != tangentInters[ axis ].end(); ++tgtInt )
6900         if ( getIntersParamOnLine( line, tgtInt->_face, tolerance, param ))
6901           u2inters.insert(make_pair( param, *tgtInt ));
6902       tangentInters[ axis ].clear();
6903
6904       // Count intersections before and after the point excluding touching ones.
6905       // If hasPositionInfo we count intersections of outer boundary only
6906
6907       int nbIntBeforePoint = 0, nbIntAfterPoint = 0;
6908       double f = numeric_limits<double>::max(), l = -numeric_limits<double>::max();
6909       map< double, TInters >::iterator u_int1 = u2inters.begin(), u_int2 = u_int1;
6910       bool ok = ! u_int1->second._coincides;
6911       while ( ok && u_int1 != u2inters.end() )
6912       {
6913         double u = u_int1->first;
6914         bool touchingInt = false;
6915         if ( ++u_int2 != u2inters.end() )
6916         {
6917           // skip intersections at the same point (if the line passes through edge or node)
6918           int nbSamePnt = 0;
6919           while ( u_int2 != u2inters.end() && fabs( u_int2->first - u ) < tolerance )
6920           {
6921             ++nbSamePnt;
6922             ++u_int2;
6923           }
6924
6925           // skip tangent intersections
6926           int nbTgt = 0;
6927           const SMDS_MeshElement* prevFace = u_int1->second._face;
6928           while ( ok && u_int2->second._coincides )
6929           {
6930             if ( SMESH_Algo::GetCommonNodes(prevFace , u_int2->second._face).empty() )
6931               ok = false;
6932             else
6933             {
6934               nbTgt++;
6935               u_int2++;
6936               ok = ( u_int2 != u2inters.end() );
6937             }
6938           }
6939           if ( !ok ) break;
6940
6941           // skip intersections at the same point after tangent intersections
6942           if ( nbTgt > 0 )
6943           {
6944             double u2 = u_int2->first;
6945             ++u_int2;
6946             while ( u_int2 != u2inters.end() && fabs( u_int2->first - u2 ) < tolerance )
6947             {
6948               ++nbSamePnt;
6949               ++u_int2;
6950             }
6951           }
6952           // decide if we skipped a touching intersection
6953           if ( nbSamePnt + nbTgt > 0 )
6954           {
6955             double minDot = numeric_limits<double>::max(), maxDot = -numeric_limits<double>::max();
6956             map< double, TInters >::iterator u_int = u_int1;
6957             for ( ; u_int != u_int2; ++u_int )
6958             {
6959               if ( u_int->second._coincides ) continue;
6960               double dot = u_int->second._faceNorm * line.Direction();
6961               if ( dot > maxDot ) maxDot = dot;
6962               if ( dot < minDot ) minDot = dot;
6963             }
6964             touchingInt = ( minDot*maxDot < 0 );
6965           }
6966         }
6967         if ( !touchingInt )
6968         {
6969           if ( !hasPositionInfo || isOuterBoundary( u_int1->second._face ))
6970           {
6971             if ( u < 0 )
6972               ++nbIntBeforePoint;
6973             else
6974               ++nbIntAfterPoint;
6975           }
6976           if ( u < f ) f = u;
6977           if ( u > l ) l = u;
6978         }
6979
6980         u_int1 = u_int2; // to next intersection
6981
6982       } // loop on intersections with one line
6983
6984       if ( ok )
6985       {
6986         if ( fabs( f ) < tolerance || fabs( l ) < tolerance )
6987           return TopAbs_ON;
6988
6989         if ( nbIntBeforePoint == 0  || nbIntAfterPoint == 0)
6990           return TopAbs_OUT; 
6991
6992         if ( nbIntBeforePoint + nbIntAfterPoint == 1 ) // not closed mesh
6993           return fabs( f ) < tolerance ? TopAbs_ON : TopAbs_UNKNOWN;
6994
6995         if ( nbIntBeforePoint == 1 || nbIntAfterPoint == 1 )
6996           return TopAbs_IN;
6997
6998         if ( (f<0) == (l<0) )
6999           return TopAbs_OUT;
7000
7001         if ( hasPositionInfo )
7002           return nbIntBeforePoint % 2 ? TopAbs_IN : TopAbs_OUT;
7003       }
7004     } // loop on intersections of the tree lines - thorough analysis
7005
7006     if ( !hasPositionInfo )
7007     {
7008       // gather info on faces position - is face in the outer boundary or not
7009       map< double, TInters > & u2inters = paramOnLine2TInters[ 0 ];
7010       findOuterBoundary( u2inters.begin()->second._face );
7011     }
7012
7013   } // two attempts - with and w/o faces position info in the mesh
7014
7015   return TopAbs_UNKNOWN;
7016 }
7017
7018 //=======================================================================
7019 /*!
7020  * \brief Return elements possibly intersecting the line
7021  */
7022 //=======================================================================
7023
7024 void SMESH_ElementSearcherImpl::GetElementsNearLine( const gp_Ax1&                      line,
7025                                                      SMDSAbs_ElementType                type,
7026                                                      vector< const SMDS_MeshElement* >& foundElems)
7027 {
7028   if ( !_ebbTree || _elementType != type )
7029   {
7030     if ( _ebbTree ) delete _ebbTree;
7031     _ebbTree = new ElementBndBoxTree( *_mesh, _elementType = type, _meshPartIt );
7032   }
7033   TIDSortedElemSet suspectFaces; // elements possibly intersecting the line
7034   _ebbTree->getElementsNearLine( line, suspectFaces );
7035   foundElems.assign( suspectFaces.begin(), suspectFaces.end());
7036 }
7037
7038 //=======================================================================
7039 /*!
7040  * \brief Return SMESH_ElementSearcher
7041  */
7042 //=======================================================================
7043
7044 SMESH_ElementSearcher* SMESH_MeshEditor::GetElementSearcher()
7045 {
7046   return new SMESH_ElementSearcherImpl( *GetMeshDS() );
7047 }
7048
7049 //=======================================================================
7050 /*!
7051  * \brief Return SMESH_ElementSearcher
7052  */
7053 //=======================================================================
7054
7055 SMESH_ElementSearcher* SMESH_MeshEditor::GetElementSearcher(SMDS_ElemIteratorPtr elemIt)
7056 {
7057   return new SMESH_ElementSearcherImpl( *GetMeshDS(), elemIt );
7058 }
7059
7060 //=======================================================================
7061 /*!
7062  * \brief Return true if the point is IN or ON of the element
7063  */
7064 //=======================================================================
7065
7066 bool SMESH_MeshEditor::isOut( const SMDS_MeshElement* element, const gp_Pnt& point, double tol )
7067 {
7068   if ( element->GetType() == SMDSAbs_Volume)
7069   {
7070     return SMDS_VolumeTool( element ).IsOut( point.X(), point.Y(), point.Z(), tol );
7071   }
7072
7073   // get ordered nodes
7074
7075   vector< gp_XYZ > xyz;
7076   vector<const SMDS_MeshNode*> nodeList;
7077
7078   SMDS_ElemIteratorPtr nodeIt = element->nodesIterator();
7079   if ( element->IsQuadratic() ) {
7080     if (const SMDS_VtkFace* f=dynamic_cast<const SMDS_VtkFace*>(element))
7081       nodeIt = f->interlacedNodesElemIterator();
7082     else if (const SMDS_VtkEdge*  e =dynamic_cast<const SMDS_VtkEdge*>(element))
7083       nodeIt = e->interlacedNodesElemIterator();
7084   }
7085   while ( nodeIt->more() )
7086     {
7087       const SMDS_MeshNode* node = cast2Node( nodeIt->next() );
7088       xyz.push_back( SMESH_TNodeXYZ(node) );
7089       nodeList.push_back(node);
7090     }
7091
7092   int i, nbNodes = element->NbNodes();
7093
7094   if ( element->GetType() == SMDSAbs_Face ) // --------------------------------------------------
7095   {
7096     // compute face normal
7097     gp_Vec faceNorm(0,0,0);
7098     xyz.push_back( xyz.front() );
7099     nodeList.push_back( nodeList.front() );
7100     for ( i = 0; i < nbNodes; ++i )
7101     {
7102       gp_Vec edge1( xyz[i+1], xyz[i]);
7103       gp_Vec edge2( xyz[i+1], xyz[(i+2)%nbNodes] );
7104       faceNorm += edge1 ^ edge2;
7105     }
7106     double normSize = faceNorm.Magnitude();
7107     if ( normSize <= tol )
7108     {
7109       // degenerated face: point is out if it is out of all face edges
7110       for ( i = 0; i < nbNodes; ++i )
7111       {
7112         SMDS_LinearEdge edge( nodeList[i], nodeList[i+1] );
7113         if ( !isOut( &edge, point, tol ))
7114           return false;
7115       }
7116       return true;
7117     }
7118     faceNorm /= normSize;
7119
7120     // check if the point lays on face plane
7121     gp_Vec n2p( xyz[0], point );
7122     if ( fabs( n2p * faceNorm ) > tol )
7123       return true; // not on face plane
7124
7125     // check if point is out of face boundary:
7126     // define it by closest transition of a ray point->infinity through face boundary
7127     // on the face plane.
7128     // First, find normal of a plane perpendicular to face plane, to be used as a cutting tool
7129     // to find intersections of the ray with the boundary.
7130     gp_Vec ray = n2p;
7131     gp_Vec plnNorm = ray ^ faceNorm;
7132     normSize = plnNorm.Magnitude();
7133     if ( normSize <= tol ) return false; // point coincides with the first node
7134     plnNorm /= normSize;
7135     // for each node of the face, compute its signed distance to the plane
7136     vector<double> dist( nbNodes + 1);
7137     for ( i = 0; i < nbNodes; ++i )
7138     {
7139       gp_Vec n2p( xyz[i], point );
7140       dist[i] = n2p * plnNorm;
7141     }
7142     dist.back() = dist.front();
7143     // find the closest intersection
7144     int    iClosest = -1;
7145     double rClosest, distClosest = 1e100;;
7146     gp_Pnt pClosest;
7147     for ( i = 0; i < nbNodes; ++i )
7148     {
7149       double r;
7150       if ( fabs( dist[i]) < tol )
7151         r = 0.;
7152       else if ( fabs( dist[i+1]) < tol )
7153         r = 1.;
7154       else if ( dist[i] * dist[i+1] < 0 )
7155         r = dist[i] / ( dist[i] - dist[i+1] );
7156       else
7157         continue; // no intersection
7158       gp_Pnt pInt = xyz[i] * (1.-r) + xyz[i+1] * r;
7159       gp_Vec p2int ( point, pInt);
7160       if ( p2int * ray > -tol ) // right half-space
7161       {
7162         double intDist = p2int.SquareMagnitude();
7163         if ( intDist < distClosest )
7164         {
7165           iClosest = i;
7166           rClosest = r;
7167           pClosest = pInt;
7168           distClosest = intDist;
7169         }
7170       }
7171     }
7172     if ( iClosest < 0 )
7173       return true; // no intesections - out
7174
7175     // analyse transition
7176     gp_Vec edge( xyz[iClosest], xyz[iClosest+1] );
7177     gp_Vec edgeNorm = -( edge ^ faceNorm ); // normal to intersected edge pointing out of face
7178     gp_Vec p2int ( point, pClosest );
7179     bool out = (edgeNorm * p2int) < -tol;
7180     if ( rClosest > 0. && rClosest < 1. ) // not node intersection
7181       return out;
7182
7183     // ray pass through a face node; analyze transition through an adjacent edge
7184     gp_Pnt p1 = xyz[ (rClosest == 0.) ? ((iClosest+nbNodes-1) % nbNodes) : (iClosest+1) ];
7185     gp_Pnt p2 = xyz[ (rClosest == 0.) ? iClosest : ((iClosest+2) % nbNodes) ];
7186     gp_Vec edgeAdjacent( p1, p2 );
7187     gp_Vec edgeNorm2 = -( edgeAdjacent ^ faceNorm );
7188     bool out2 = (edgeNorm2 * p2int) < -tol;
7189
7190     bool covexCorner = ( edgeNorm * edgeAdjacent * (rClosest==1. ? 1. : -1.)) < 0;
7191     return covexCorner ? (out || out2) : (out && out2);
7192   }
7193   if ( element->GetType() == SMDSAbs_Edge ) // --------------------------------------------------
7194   {
7195     // point is out of edge if it is NOT ON any straight part of edge
7196     // (we consider quadratic edge as being composed of two straight parts)
7197     for ( i = 1; i < nbNodes; ++i )
7198     {
7199       gp_Vec edge( xyz[i-1], xyz[i]);
7200       gp_Vec n1p ( xyz[i-1], point);
7201       double dist = ( edge ^ n1p ).Magnitude() / edge.Magnitude();
7202       if ( dist > tol )
7203         continue;
7204       gp_Vec n2p( xyz[i], point );
7205       if ( fabs( edge.Magnitude() - n1p.Magnitude() - n2p.Magnitude()) > tol )
7206         continue;
7207       return false; // point is ON this part
7208     }
7209     return true;
7210   }
7211   // Node or 0D element -------------------------------------------------------------------------
7212   {
7213     gp_Vec n2p ( xyz[0], point );
7214     return n2p.Magnitude() <= tol;
7215   }
7216   return true;
7217 }
7218
7219 //=======================================================================
7220 //function : SimplifyFace
7221 //purpose  :
7222 //=======================================================================
7223 int SMESH_MeshEditor::SimplifyFace (const vector<const SMDS_MeshNode *> faceNodes,
7224                                     vector<const SMDS_MeshNode *>&      poly_nodes,
7225                                     vector<int>&                        quantities) const
7226 {
7227   int nbNodes = faceNodes.size();
7228
7229   if (nbNodes < 3)
7230     return 0;
7231
7232   set<const SMDS_MeshNode*> nodeSet;
7233
7234   // get simple seq of nodes
7235   //const SMDS_MeshNode* simpleNodes[ nbNodes ];
7236   vector<const SMDS_MeshNode*> simpleNodes( nbNodes );
7237   int iSimple = 0, nbUnique = 0;
7238
7239   simpleNodes[iSimple++] = faceNodes[0];
7240   nbUnique++;
7241   for (int iCur = 1; iCur < nbNodes; iCur++) {
7242     if (faceNodes[iCur] != simpleNodes[iSimple - 1]) {
7243       simpleNodes[iSimple++] = faceNodes[iCur];
7244       if (nodeSet.insert( faceNodes[iCur] ).second)
7245         nbUnique++;
7246     }
7247   }
7248   int nbSimple = iSimple;
7249   if (simpleNodes[nbSimple - 1] == simpleNodes[0]) {
7250     nbSimple--;
7251     iSimple--;
7252   }
7253
7254   if (nbUnique < 3)
7255     return 0;
7256
7257   // separate loops
7258   int nbNew = 0;
7259   bool foundLoop = (nbSimple > nbUnique);
7260   while (foundLoop) {
7261     foundLoop = false;
7262     set<const SMDS_MeshNode*> loopSet;
7263     for (iSimple = 0; iSimple < nbSimple && !foundLoop; iSimple++) {
7264       const SMDS_MeshNode* n = simpleNodes[iSimple];
7265       if (!loopSet.insert( n ).second) {
7266         foundLoop = true;
7267
7268         // separate loop
7269         int iC = 0, curLast = iSimple;
7270         for (; iC < curLast; iC++) {
7271           if (simpleNodes[iC] == n) break;
7272         }
7273         int loopLen = curLast - iC;
7274         if (loopLen > 2) {
7275           // create sub-element
7276           nbNew++;
7277           quantities.push_back(loopLen);
7278           for (; iC < curLast; iC++) {
7279             poly_nodes.push_back(simpleNodes[iC]);
7280           }
7281         }
7282         // shift the rest nodes (place from the first loop position)
7283         for (iC = curLast + 1; iC < nbSimple; iC++) {
7284           simpleNodes[iC - loopLen] = simpleNodes[iC];
7285         }
7286         nbSimple -= loopLen;
7287         iSimple -= loopLen;
7288       }
7289     } // for (iSimple = 0; iSimple < nbSimple; iSimple++)
7290   } // while (foundLoop)
7291
7292   if (iSimple > 2) {
7293     nbNew++;
7294     quantities.push_back(iSimple);
7295     for (int i = 0; i < iSimple; i++)
7296       poly_nodes.push_back(simpleNodes[i]);
7297   }
7298
7299   return nbNew;
7300 }
7301
7302 //=======================================================================
7303 //function : MergeNodes
7304 //purpose  : In each group, the cdr of nodes are substituted by the first one
7305 //           in all elements.
7306 //=======================================================================
7307
7308 void SMESH_MeshEditor::MergeNodes (TListOfListOfNodes & theGroupsOfNodes)
7309 {
7310   MESSAGE("MergeNodes");
7311   myLastCreatedElems.Clear();
7312   myLastCreatedNodes.Clear();
7313
7314   SMESHDS_Mesh* aMesh = GetMeshDS();
7315
7316   TNodeNodeMap nodeNodeMap; // node to replace - new node
7317   set<const SMDS_MeshElement*> elems; // all elements with changed nodes
7318   list< int > rmElemIds, rmNodeIds;
7319
7320   // Fill nodeNodeMap and elems
7321
7322   TListOfListOfNodes::iterator grIt = theGroupsOfNodes.begin();
7323   for ( ; grIt != theGroupsOfNodes.end(); grIt++ ) {
7324     list<const SMDS_MeshNode*>& nodes = *grIt;
7325     list<const SMDS_MeshNode*>::iterator nIt = nodes.begin();
7326     const SMDS_MeshNode* nToKeep = *nIt;
7327     //MESSAGE("node to keep " << nToKeep->GetID());
7328     for ( ++nIt; nIt != nodes.end(); nIt++ ) {
7329       const SMDS_MeshNode* nToRemove = *nIt;
7330       nodeNodeMap.insert( TNodeNodeMap::value_type( nToRemove, nToKeep ));
7331       if ( nToRemove != nToKeep ) {
7332         //MESSAGE("  node to remove " << nToRemove->GetID());
7333         rmNodeIds.push_back( nToRemove->GetID() );
7334         AddToSameGroups( nToKeep, nToRemove, aMesh );
7335       }
7336
7337       SMDS_ElemIteratorPtr invElemIt = nToRemove->GetInverseElementIterator();
7338       while ( invElemIt->more() ) {
7339         const SMDS_MeshElement* elem = invElemIt->next();
7340         elems.insert(elem);
7341       }
7342     }
7343   }
7344   // Change element nodes or remove an element
7345
7346   set<const SMDS_MeshElement*>::iterator eIt = elems.begin();
7347   for ( ; eIt != elems.end(); eIt++ ) {
7348     const SMDS_MeshElement* elem = *eIt;
7349     //MESSAGE(" ---- inverse elem on node to remove " << elem->GetID());
7350     int nbNodes = elem->NbNodes();
7351     int aShapeId = FindShape( elem );
7352
7353     set<const SMDS_MeshNode*> nodeSet;
7354     vector< const SMDS_MeshNode*> curNodes( nbNodes ), uniqueNodes( nbNodes );
7355     int iUnique = 0, iCur = 0, nbRepl = 0;
7356     vector<int> iRepl( nbNodes );
7357
7358     // get new seq of nodes
7359     SMDS_ElemIteratorPtr itN = elem->nodesIterator();
7360     while ( itN->more() ) {
7361       const SMDS_MeshNode* n =
7362         static_cast<const SMDS_MeshNode*>( itN->next() );
7363
7364       TNodeNodeMap::iterator nnIt = nodeNodeMap.find( n );
7365       if ( nnIt != nodeNodeMap.end() ) { // n sticks
7366         n = (*nnIt).second;
7367         // BUG 0020185: begin
7368         {
7369           bool stopRecur = false;
7370           set<const SMDS_MeshNode*> nodesRecur;
7371           nodesRecur.insert(n);
7372           while (!stopRecur) {
7373             TNodeNodeMap::iterator nnIt_i = nodeNodeMap.find( n );
7374             if ( nnIt_i != nodeNodeMap.end() ) { // n sticks
7375               n = (*nnIt_i).second;
7376               if (!nodesRecur.insert(n).second) {
7377                 // error: recursive dependancy
7378                 stopRecur = true;
7379               }
7380             }
7381             else
7382               stopRecur = true;
7383           }
7384         }
7385         // BUG 0020185: end
7386         iRepl[ nbRepl++ ] = iCur;
7387       }
7388       curNodes[ iCur ] = n;
7389       bool isUnique = nodeSet.insert( n ).second;
7390       if ( isUnique ) {
7391         uniqueNodes[ iUnique++ ] = n;
7392         if ( nbRepl && iRepl[ nbRepl-1 ] == iCur )
7393           --nbRepl; // n do not stick to a node of the elem
7394       }
7395       iCur++;
7396     }
7397
7398     // Analyse element topology after replacement
7399
7400     bool isOk = true;
7401     int nbUniqueNodes = nodeSet.size();
7402     //MESSAGE("nbNodes nbUniqueNodes " << nbNodes << " " << nbUniqueNodes);
7403     if ( nbNodes != nbUniqueNodes ) { // some nodes stick
7404       // Polygons and Polyhedral volumes
7405       if (elem->IsPoly()) {
7406
7407         if (elem->GetType() == SMDSAbs_Face) {
7408           // Polygon
7409           vector<const SMDS_MeshNode *> face_nodes (nbNodes);
7410           int inode = 0;
7411           for (; inode < nbNodes; inode++) {
7412             face_nodes[inode] = curNodes[inode];
7413           }
7414
7415           vector<const SMDS_MeshNode *> polygons_nodes;
7416           vector<int> quantities;
7417           int nbNew = SimplifyFace(face_nodes, polygons_nodes, quantities);
7418           if (nbNew > 0) {
7419             inode = 0;
7420             for (int iface = 0; iface < nbNew; iface++) {
7421               int nbNodes = quantities[iface];
7422               vector<const SMDS_MeshNode *> poly_nodes (nbNodes);
7423               for (int ii = 0; ii < nbNodes; ii++, inode++) {
7424                 poly_nodes[ii] = polygons_nodes[inode];
7425               }
7426               SMDS_MeshElement* newElem = aMesh->AddPolygonalFace(poly_nodes);
7427               myLastCreatedElems.Append(newElem);
7428               if (aShapeId)
7429                 aMesh->SetMeshElementOnShape(newElem, aShapeId);
7430             }
7431
7432             MESSAGE("ChangeElementNodes MergeNodes Polygon");
7433             //aMesh->ChangeElementNodes(elem, &polygons_nodes[inode], quantities[nbNew - 1]);
7434             vector<const SMDS_MeshNode *> polynodes(polygons_nodes.begin()+inode,polygons_nodes.end());
7435             int quid =0;
7436             if (nbNew > 0) quid = nbNew - 1;
7437             vector<int> newquant(quantities.begin()+quid, quantities.end());
7438             const SMDS_MeshElement* newElem = 0;
7439             newElem = aMesh->AddPolyhedralVolume(polynodes, newquant);
7440             myLastCreatedElems.Append(newElem);
7441             if ( aShapeId && newElem )
7442               aMesh->SetMeshElementOnShape( newElem, aShapeId );
7443             rmElemIds.push_back(elem->GetID());
7444           }
7445           else {
7446             rmElemIds.push_back(elem->GetID());
7447           }
7448
7449         }
7450         else if (elem->GetType() == SMDSAbs_Volume) {
7451           // Polyhedral volume
7452           if (nbUniqueNodes < 4) {
7453             rmElemIds.push_back(elem->GetID());
7454           }
7455           else {
7456             // each face has to be analyzed in order to check volume validity
7457             const SMDS_VtkVolume* aPolyedre =
7458               dynamic_cast<const SMDS_VtkVolume*>( elem );
7459             if (aPolyedre) {
7460               int nbFaces = aPolyedre->NbFaces();
7461
7462               vector<const SMDS_MeshNode *> poly_nodes;
7463               vector<int> quantities;
7464
7465               for (int iface = 1; iface <= nbFaces; iface++) {
7466                 int nbFaceNodes = aPolyedre->NbFaceNodes(iface);
7467                 vector<const SMDS_MeshNode *> faceNodes (nbFaceNodes);
7468
7469                 for (int inode = 1; inode <= nbFaceNodes; inode++) {
7470                   const SMDS_MeshNode * faceNode = aPolyedre->GetFaceNode(iface, inode);
7471                   TNodeNodeMap::iterator nnIt = nodeNodeMap.find(faceNode);
7472                   if (nnIt != nodeNodeMap.end()) { // faceNode sticks
7473                     faceNode = (*nnIt).second;
7474                   }
7475                   faceNodes[inode - 1] = faceNode;
7476                 }
7477
7478                 SimplifyFace(faceNodes, poly_nodes, quantities);
7479               }
7480
7481               if (quantities.size() > 3) {
7482                 // to be done: remove coincident faces
7483               }
7484
7485               if (quantities.size() > 3)
7486                 {
7487                   MESSAGE("ChangeElementNodes MergeNodes Polyhedron");
7488                   //aMesh->ChangePolyhedronNodes(elem, poly_nodes, quantities);
7489                   const SMDS_MeshElement* newElem = 0;
7490                   newElem = aMesh->AddPolyhedralVolume(poly_nodes, quantities);
7491                   myLastCreatedElems.Append(newElem);
7492                   if ( aShapeId && newElem )
7493                     aMesh->SetMeshElementOnShape( newElem, aShapeId );
7494                   rmElemIds.push_back(elem->GetID());
7495                 }
7496             }
7497             else {
7498               rmElemIds.push_back(elem->GetID());
7499             }
7500           }
7501         }
7502         else {
7503         }
7504
7505         continue;
7506       } // poly element
7507
7508       // Regular elements
7509       // TODO not all the possible cases are solved. Find something more generic?
7510       switch ( nbNodes ) {
7511       case 2: ///////////////////////////////////// EDGE
7512         isOk = false; break;
7513       case 3: ///////////////////////////////////// TRIANGLE
7514         isOk = false; break;
7515       case 4:
7516         if ( elem->GetType() == SMDSAbs_Volume ) // TETRAHEDRON
7517           isOk = false;
7518         else { //////////////////////////////////// QUADRANGLE
7519           if ( nbUniqueNodes < 3 )
7520             isOk = false;
7521           else if ( nbRepl == 2 && iRepl[ 1 ] - iRepl[ 0 ] == 2 )
7522             isOk = false; // opposite nodes stick
7523           //MESSAGE("isOk " << isOk);
7524         }
7525         break;
7526       case 6: ///////////////////////////////////// PENTAHEDRON
7527         if ( nbUniqueNodes == 4 ) {
7528           // ---------------------------------> tetrahedron
7529           if (nbRepl == 3 &&
7530               iRepl[ 0 ] > 2 && iRepl[ 1 ] > 2 && iRepl[ 2 ] > 2 ) {
7531             // all top nodes stick: reverse a bottom
7532             uniqueNodes[ 0 ] = curNodes [ 1 ];
7533             uniqueNodes[ 1 ] = curNodes [ 0 ];
7534           }
7535           else if (nbRepl == 3 &&
7536                    iRepl[ 0 ] < 3 && iRepl[ 1 ] < 3 && iRepl[ 2 ] < 3 ) {
7537             // all bottom nodes stick: set a top before
7538             uniqueNodes[ 3 ] = uniqueNodes [ 0 ];
7539             uniqueNodes[ 0 ] = curNodes [ 3 ];
7540             uniqueNodes[ 1 ] = curNodes [ 4 ];
7541             uniqueNodes[ 2 ] = curNodes [ 5 ];
7542           }
7543           else if (nbRepl == 4 &&
7544                    iRepl[ 2 ] - iRepl [ 0 ] == 3 && iRepl[ 3 ] - iRepl [ 1 ] == 3 ) {
7545             // a lateral face turns into a line: reverse a bottom
7546             uniqueNodes[ 0 ] = curNodes [ 1 ];
7547             uniqueNodes[ 1 ] = curNodes [ 0 ];
7548           }
7549           else
7550             isOk = false;
7551         }
7552         else if ( nbUniqueNodes == 5 ) {
7553           // PENTAHEDRON --------------------> 2 tetrahedrons
7554           if ( nbRepl == 2 && iRepl[ 1 ] - iRepl [ 0 ] == 3 ) {
7555             // a bottom node sticks with a linked top one
7556             // 1.
7557             SMDS_MeshElement* newElem =
7558               aMesh->AddVolume(curNodes[ 3 ],
7559                                curNodes[ 4 ],
7560                                curNodes[ 5 ],
7561                                curNodes[ iRepl[ 0 ] == 2 ? 1 : 2 ]);
7562             myLastCreatedElems.Append(newElem);
7563             if ( aShapeId )
7564               aMesh->SetMeshElementOnShape( newElem, aShapeId );
7565             // 2. : reverse a bottom
7566             uniqueNodes[ 0 ] = curNodes [ 1 ];
7567             uniqueNodes[ 1 ] = curNodes [ 0 ];
7568             nbUniqueNodes = 4;
7569           }
7570           else
7571             isOk = false;
7572         }
7573         else
7574           isOk = false;
7575         break;
7576       case 8: {
7577         if(elem->IsQuadratic()) { // Quadratic quadrangle
7578           //   1    5    2
7579           //    +---+---+
7580           //    |       |
7581           //    |       |
7582           //   4+       +6
7583           //    |       |
7584           //    |       |
7585           //    +---+---+
7586           //   0    7    3
7587           isOk = false;
7588           if(nbRepl==2) {
7589             MESSAGE("nbRepl=2: " << iRepl[0] << " " << iRepl[1]);
7590           }
7591           if(nbRepl==3) {
7592             MESSAGE("nbRepl=3: " << iRepl[0] << " " << iRepl[1]  << " " << iRepl[2]);
7593             nbUniqueNodes = 6;
7594             if( iRepl[0]==0 && iRepl[1]==1 && iRepl[2]==4 ) {
7595               uniqueNodes[0] = curNodes[0];
7596               uniqueNodes[1] = curNodes[2];
7597               uniqueNodes[2] = curNodes[3];
7598               uniqueNodes[3] = curNodes[5];
7599               uniqueNodes[4] = curNodes[6];
7600               uniqueNodes[5] = curNodes[7];
7601               isOk = true;
7602             }
7603             if( iRepl[0]==0 && iRepl[1]==3 && iRepl[2]==7 ) {
7604               uniqueNodes[0] = curNodes[0];
7605               uniqueNodes[1] = curNodes[1];
7606               uniqueNodes[2] = curNodes[2];
7607               uniqueNodes[3] = curNodes[4];
7608               uniqueNodes[4] = curNodes[5];
7609               uniqueNodes[5] = curNodes[6];
7610               isOk = true;
7611             }
7612             if( iRepl[0]==0 && iRepl[1]==4 && iRepl[2]==7 ) {
7613               uniqueNodes[0] = curNodes[1];
7614               uniqueNodes[1] = curNodes[2];
7615               uniqueNodes[2] = curNodes[3];
7616               uniqueNodes[3] = curNodes[5];
7617               uniqueNodes[4] = curNodes[6];
7618               uniqueNodes[5] = curNodes[0];
7619               isOk = true;
7620             }
7621             if( iRepl[0]==1 && iRepl[1]==2 && iRepl[2]==5 ) {
7622               uniqueNodes[0] = curNodes[0];
7623               uniqueNodes[1] = curNodes[1];
7624               uniqueNodes[2] = curNodes[3];
7625               uniqueNodes[3] = curNodes[4];
7626               uniqueNodes[4] = curNodes[6];
7627               uniqueNodes[5] = curNodes[7];
7628               isOk = true;
7629             }
7630             if( iRepl[0]==1 && iRepl[1]==4 && iRepl[2]==5 ) {
7631               uniqueNodes[0] = curNodes[0];
7632               uniqueNodes[1] = curNodes[2];
7633               uniqueNodes[2] = curNodes[3];
7634               uniqueNodes[3] = curNodes[1];
7635               uniqueNodes[4] = curNodes[6];
7636               uniqueNodes[5] = curNodes[7];
7637               isOk = true;
7638             }
7639             if( iRepl[0]==2 && iRepl[1]==3 && iRepl[2]==6 ) {
7640               uniqueNodes[0] = curNodes[0];
7641               uniqueNodes[1] = curNodes[1];
7642               uniqueNodes[2] = curNodes[2];
7643               uniqueNodes[3] = curNodes[4];
7644               uniqueNodes[4] = curNodes[5];
7645               uniqueNodes[5] = curNodes[7];
7646               isOk = true;
7647             }
7648             if( iRepl[0]==2 && iRepl[1]==5 && iRepl[2]==6 ) {
7649               uniqueNodes[0] = curNodes[0];
7650               uniqueNodes[1] = curNodes[1];
7651               uniqueNodes[2] = curNodes[3];
7652               uniqueNodes[3] = curNodes[4];
7653               uniqueNodes[4] = curNodes[2];
7654               uniqueNodes[5] = curNodes[7];
7655               isOk = true;
7656             }
7657             if( iRepl[0]==3 && iRepl[1]==6 && iRepl[2]==7 ) {
7658               uniqueNodes[0] = curNodes[0];
7659               uniqueNodes[1] = curNodes[1];
7660               uniqueNodes[2] = curNodes[2];
7661               uniqueNodes[3] = curNodes[4];
7662               uniqueNodes[4] = curNodes[5];
7663               uniqueNodes[5] = curNodes[3];
7664               isOk = true;
7665             }
7666           }
7667           if(nbRepl==4) {
7668             MESSAGE("nbRepl=4: " << iRepl[0] << " " << iRepl[1]  << " " << iRepl[2] << " " << iRepl[3]);
7669           }
7670           if(nbRepl==5) {
7671             MESSAGE("nbRepl=5: " << iRepl[0] << " " << iRepl[1]  << " " << iRepl[2] << " " << iRepl[3] << " " << iRepl[4]);
7672           }
7673           break;
7674         }
7675         //////////////////////////////////// HEXAHEDRON
7676         isOk = false;
7677         SMDS_VolumeTool hexa (elem);
7678         hexa.SetExternalNormal();
7679         if ( nbUniqueNodes == 4 && nbRepl == 4 ) {
7680           //////////////////////// HEX ---> 1 tetrahedron
7681           for ( int iFace = 0; iFace < 6; iFace++ ) {
7682             const int *ind = hexa.GetFaceNodesIndices( iFace ); // indices of face nodes
7683             if (curNodes[ind[ 0 ]] == curNodes[ind[ 1 ]] &&
7684                 curNodes[ind[ 0 ]] == curNodes[ind[ 2 ]] &&
7685                 curNodes[ind[ 0 ]] == curNodes[ind[ 3 ]] ) {
7686               // one face turns into a point ...
7687               int iOppFace = hexa.GetOppFaceIndex( iFace );
7688               ind = hexa.GetFaceNodesIndices( iOppFace );
7689               int nbStick = 0;
7690               for ( iCur = 0; iCur < 4 && nbStick < 2; iCur++ ) {
7691                 if ( curNodes[ind[ iCur ]] == curNodes[ind[ iCur + 1 ]] )
7692                   nbStick++;
7693               }
7694               if ( nbStick == 1 ) {
7695                 // ... and the opposite one - into a triangle.
7696                 // set a top node
7697                 ind = hexa.GetFaceNodesIndices( iFace );
7698                 uniqueNodes[ 3 ] = curNodes[ind[ 0 ]];
7699                 isOk = true;
7700               }
7701               break;
7702             }
7703           }
7704         }
7705         else if ( nbUniqueNodes == 6 && nbRepl == 2 ) {
7706           //////////////////////// HEX ---> 1 prism
7707           int nbTria = 0, iTria[3];
7708           const int *ind; // indices of face nodes
7709           // look for triangular faces
7710           for ( int iFace = 0; iFace < 6 && nbTria < 3; iFace++ ) {
7711             ind = hexa.GetFaceNodesIndices( iFace );
7712             TIDSortedNodeSet faceNodes;
7713             for ( iCur = 0; iCur < 4; iCur++ )
7714               faceNodes.insert( curNodes[ind[iCur]] );
7715             if ( faceNodes.size() == 3 )
7716               iTria[ nbTria++ ] = iFace;
7717           }
7718           // check if triangles are opposite
7719           if ( nbTria == 2 && iTria[0] == hexa.GetOppFaceIndex( iTria[1] ))
7720           {
7721             isOk = true;
7722             // set nodes of the bottom triangle
7723             ind = hexa.GetFaceNodesIndices( iTria[ 0 ]);
7724             vector<int> indB;
7725             for ( iCur = 0; iCur < 4; iCur++ )
7726               if ( ind[iCur] != iRepl[0] && ind[iCur] != iRepl[1])
7727                 indB.push_back( ind[iCur] );
7728             if ( !hexa.IsForward() )
7729               std::swap( indB[0], indB[2] );
7730             for ( iCur = 0; iCur < 3; iCur++ )
7731               uniqueNodes[ iCur ] = curNodes[indB[iCur]];
7732             // set nodes of the top triangle
7733             const int *indT = hexa.GetFaceNodesIndices( iTria[ 1 ]);
7734             for ( iCur = 0; iCur < 3; ++iCur )
7735               for ( int j = 0; j < 4; ++j )
7736                 if ( hexa.IsLinked( indB[ iCur ], indT[ j ] ))
7737                 {
7738                   uniqueNodes[ iCur + 3 ] = curNodes[ indT[ j ]];
7739                   break;
7740                 }
7741           }
7742           break;
7743         }
7744         else if (nbUniqueNodes == 5 && nbRepl == 4 ) {
7745           //////////////////// HEXAHEDRON ---> 2 tetrahedrons
7746           for ( int iFace = 0; iFace < 6; iFace++ ) {
7747             const int *ind = hexa.GetFaceNodesIndices( iFace ); // indices of face nodes
7748             if (curNodes[ind[ 0 ]] == curNodes[ind[ 1 ]] &&
7749                 curNodes[ind[ 0 ]] == curNodes[ind[ 2 ]] &&
7750                 curNodes[ind[ 0 ]] == curNodes[ind[ 3 ]] ) {
7751               // one face turns into a point ...
7752               int iOppFace = hexa.GetOppFaceIndex( iFace );
7753               ind = hexa.GetFaceNodesIndices( iOppFace );
7754               int nbStick = 0;
7755               iUnique = 2;  // reverse a tetrahedron 1 bottom
7756               for ( iCur = 0; iCur < 4 && nbStick == 0; iCur++ ) {
7757                 if ( curNodes[ind[ iCur ]] == curNodes[ind[ iCur + 1 ]] )
7758                   nbStick++;
7759                 else if ( iUnique >= 0 )
7760                   uniqueNodes[ iUnique-- ] = curNodes[ind[ iCur ]];
7761               }
7762               if ( nbStick == 0 ) {
7763                 // ... and the opposite one is a quadrangle
7764                 // set a top node
7765                 const int* indTop = hexa.GetFaceNodesIndices( iFace );
7766                 uniqueNodes[ 3 ] = curNodes[indTop[ 0 ]];
7767                 nbUniqueNodes = 4;
7768                 // tetrahedron 2
7769                 SMDS_MeshElement* newElem =
7770                   aMesh->AddVolume(curNodes[ind[ 0 ]],
7771                                    curNodes[ind[ 3 ]],
7772                                    curNodes[ind[ 2 ]],
7773                                    curNodes[indTop[ 0 ]]);
7774                 myLastCreatedElems.Append(newElem);
7775                 if ( aShapeId )
7776                   aMesh->SetMeshElementOnShape( newElem, aShapeId );
7777                 isOk = true;
7778               }
7779               break;
7780             }
7781           }
7782         }
7783         else if ( nbUniqueNodes == 6 && nbRepl == 4 ) {
7784           ////////////////// HEXAHEDRON ---> 2 tetrahedrons or 1 prism
7785           // find indices of quad and tri faces
7786           int iQuadFace[ 6 ], iTriFace[ 6 ], nbQuad = 0, nbTri = 0, iFace;
7787           for ( iFace = 0; iFace < 6; iFace++ ) {
7788             const int *ind = hexa.GetFaceNodesIndices( iFace ); // indices of face nodes
7789             nodeSet.clear();
7790             for ( iCur = 0; iCur < 4; iCur++ )
7791               nodeSet.insert( curNodes[ind[ iCur ]] );
7792             nbUniqueNodes = nodeSet.size();
7793             if ( nbUniqueNodes == 3 )
7794               iTriFace[ nbTri++ ] = iFace;
7795             else if ( nbUniqueNodes == 4 )
7796               iQuadFace[ nbQuad++ ] = iFace;
7797           }
7798           if (nbQuad == 2 && nbTri == 4 &&
7799               hexa.GetOppFaceIndex( iQuadFace[ 0 ] ) == iQuadFace[ 1 ]) {
7800             // 2 opposite quadrangles stuck with a diagonal;
7801             // sample groups of merged indices: (0-4)(2-6)
7802             // --------------------------------------------> 2 tetrahedrons
7803             const int *ind1 = hexa.GetFaceNodesIndices( iQuadFace[ 0 ]); // indices of quad1 nodes
7804             const int *ind2 = hexa.GetFaceNodesIndices( iQuadFace[ 1 ]);
7805             int i0, i1d, i2, i3d, i0t, i2t; // d-daigonal, t-top
7806             if (curNodes[ind1[ 0 ]] == curNodes[ind2[ 0 ]] &&
7807                 curNodes[ind1[ 2 ]] == curNodes[ind2[ 2 ]]) {
7808               // stuck with 0-2 diagonal
7809               i0  = ind1[ 3 ];
7810               i1d = ind1[ 0 ];
7811               i2  = ind1[ 1 ];
7812               i3d = ind1[ 2 ];
7813               i0t = ind2[ 1 ];
7814               i2t = ind2[ 3 ];
7815             }
7816             else if (curNodes[ind1[ 1 ]] == curNodes[ind2[ 3 ]] &&
7817                      curNodes[ind1[ 3 ]] == curNodes[ind2[ 1 ]]) {
7818               // stuck with 1-3 diagonal
7819               i0  = ind1[ 0 ];
7820               i1d = ind1[ 1 ];
7821               i2  = ind1[ 2 ];
7822               i3d = ind1[ 3 ];
7823               i0t = ind2[ 0 ];
7824               i2t = ind2[ 1 ];
7825             }
7826             else {
7827               ASSERT(0);
7828             }
7829             // tetrahedron 1
7830             uniqueNodes[ 0 ] = curNodes [ i0 ];
7831             uniqueNodes[ 1 ] = curNodes [ i1d ];
7832             uniqueNodes[ 2 ] = curNodes [ i3d ];
7833             uniqueNodes[ 3 ] = curNodes [ i0t ];
7834             nbUniqueNodes = 4;
7835             // tetrahedron 2
7836             SMDS_MeshElement* newElem = aMesh->AddVolume(curNodes[ i1d ],
7837                                                          curNodes[ i2 ],
7838                                                          curNodes[ i3d ],
7839                                                          curNodes[ i2t ]);
7840             myLastCreatedElems.Append(newElem);
7841             if ( aShapeId )
7842               aMesh->SetMeshElementOnShape( newElem, aShapeId );
7843             isOk = true;
7844           }
7845           else if (( nbTri == 2 && nbQuad == 3 ) || // merged (0-4)(1-5)
7846                    ( nbTri == 4 && nbQuad == 2 )) { // merged (7-4)(1-5)
7847             // --------------------------------------------> prism
7848             // find 2 opposite triangles
7849             nbUniqueNodes = 6;
7850             for ( iFace = 0; iFace + 1 < nbTri; iFace++ ) {
7851               if ( hexa.GetOppFaceIndex( iTriFace[ iFace ] ) == iTriFace[ iFace + 1 ]) {
7852                 // find indices of kept and replaced nodes
7853                 // and fill unique nodes of 2 opposite triangles
7854                 const int *ind1 = hexa.GetFaceNodesIndices( iTriFace[ iFace ]);
7855                 const int *ind2 = hexa.GetFaceNodesIndices( iTriFace[ iFace + 1 ]);
7856                 const SMDS_MeshNode** hexanodes = hexa.GetNodes();
7857                 // fill unique nodes
7858                 iUnique = 0;
7859                 isOk = true;
7860                 for ( iCur = 0; iCur < 4 && isOk; iCur++ ) {
7861                   const SMDS_MeshNode* n     = curNodes[ind1[ iCur ]];
7862                   const SMDS_MeshNode* nInit = hexanodes[ind1[ iCur ]];
7863                   if ( n == nInit ) {
7864                     // iCur of a linked node of the opposite face (make normals co-directed):
7865                     int iCurOpp = ( iCur == 1 || iCur == 3 ) ? 4 - iCur : iCur;
7866                     // check that correspondent corners of triangles are linked
7867                     if ( !hexa.IsLinked( ind1[ iCur ], ind2[ iCurOpp ] ))
7868                       isOk = false;
7869                     else {
7870                       uniqueNodes[ iUnique ] = n;
7871                       uniqueNodes[ iUnique + 3 ] = curNodes[ind2[ iCurOpp ]];
7872                       iUnique++;
7873                     }
7874                   }
7875                 }
7876                 break;
7877               }
7878             }
7879           }
7880         } // if ( nbUniqueNodes == 6 && nbRepl == 4 )
7881         else
7882         {
7883           MESSAGE("MergeNodes() removes hexahedron "<< elem);
7884         }
7885         break;
7886       } // HEXAHEDRON
7887
7888       default:
7889         isOk = false;
7890       } // switch ( nbNodes )
7891
7892     } // if ( nbNodes != nbUniqueNodes ) // some nodes stick
7893
7894     if ( isOk ) { // the elem remains valid after sticking nodes
7895       if (elem->IsPoly() && elem->GetType() == SMDSAbs_Volume)
7896       {
7897         // Change nodes of polyedre
7898         const SMDS_VtkVolume* aPolyedre =
7899           dynamic_cast<const SMDS_VtkVolume*>( elem );
7900         if (aPolyedre) {
7901           int nbFaces = aPolyedre->NbFaces();
7902
7903           vector<const SMDS_MeshNode *> poly_nodes;
7904           vector<int> quantities (nbFaces);
7905
7906           for (int iface = 1; iface <= nbFaces; iface++) {
7907             int inode, nbFaceNodes = aPolyedre->NbFaceNodes(iface);
7908             quantities[iface - 1] = nbFaceNodes;
7909
7910             for (inode = 1; inode <= nbFaceNodes; inode++) {
7911               const SMDS_MeshNode* curNode = aPolyedre->GetFaceNode(iface, inode);
7912
7913               TNodeNodeMap::iterator nnIt = nodeNodeMap.find( curNode );
7914               if (nnIt != nodeNodeMap.end()) { // curNode sticks
7915                 curNode = (*nnIt).second;
7916               }
7917               poly_nodes.push_back(curNode);
7918             }
7919           }
7920           aMesh->ChangePolyhedronNodes( elem, poly_nodes, quantities );
7921         }
7922       }
7923       else // replace non-polyhedron elements
7924       {
7925         const SMDSAbs_ElementType etyp = elem->GetType();
7926         const int elemId               = elem->GetID();
7927         const bool isPoly              = (elem->GetEntityType() == SMDSEntity_Polygon);
7928         uniqueNodes.resize(nbUniqueNodes);
7929
7930         SMESHDS_SubMesh * sm = aShapeId > 0 ? aMesh->MeshElements(aShapeId) : 0;
7931
7932         aMesh->RemoveFreeElement(elem, sm, /*fromGroups=*/false);
7933         SMDS_MeshElement* newElem = this->AddElement(uniqueNodes, etyp, isPoly, elemId);
7934         if ( sm && newElem )
7935           sm->AddElement( newElem );
7936         if ( elem != newElem )
7937           ReplaceElemInGroups( elem, newElem, aMesh );
7938       }
7939     }
7940     else {
7941       // Remove invalid regular element or invalid polygon
7942       rmElemIds.push_back( elem->GetID() );
7943     }
7944
7945   } // loop on elements
7946
7947   // Remove bad elements, then equal nodes (order important)
7948
7949   Remove( rmElemIds, false );
7950   Remove( rmNodeIds, true );
7951
7952 }
7953
7954
7955 // ========================================================
7956 // class   : SortableElement
7957 // purpose : allow sorting elements basing on their nodes
7958 // ========================================================
7959 class SortableElement : public set <const SMDS_MeshElement*>
7960 {
7961 public:
7962
7963   SortableElement( const SMDS_MeshElement* theElem )
7964   {
7965     myElem = theElem;
7966     SMDS_ElemIteratorPtr nodeIt = theElem->nodesIterator();
7967     while ( nodeIt->more() )
7968       this->insert( nodeIt->next() );
7969   }
7970
7971   const SMDS_MeshElement* Get() const
7972   { return myElem; }
7973
7974   void Set(const SMDS_MeshElement* e) const
7975   { myElem = e; }
7976
7977
7978 private:
7979   mutable const SMDS_MeshElement* myElem;
7980 };
7981
7982 //=======================================================================
7983 //function : FindEqualElements
7984 //purpose  : Return list of group of elements built on the same nodes.
7985 //           Search among theElements or in the whole mesh if theElements is empty
7986 //=======================================================================
7987 void SMESH_MeshEditor::FindEqualElements(set<const SMDS_MeshElement*> & theElements,
7988                                          TListOfListOfElementsID &      theGroupsOfElementsID)
7989 {
7990   myLastCreatedElems.Clear();
7991   myLastCreatedNodes.Clear();
7992
7993   typedef set<const SMDS_MeshElement*> TElemsSet;
7994   typedef map< SortableElement, int > TMapOfNodeSet;
7995   typedef list<int> TGroupOfElems;
7996
7997   TElemsSet elems;
7998   if ( theElements.empty() )
7999   { // get all elements in the mesh
8000     SMDS_ElemIteratorPtr eIt = GetMeshDS()->elementsIterator();
8001     while ( eIt->more() )
8002       elems.insert( elems.end(), eIt->next());
8003   }
8004   else
8005     elems = theElements;
8006
8007   vector< TGroupOfElems > arrayOfGroups;
8008   TGroupOfElems groupOfElems;
8009   TMapOfNodeSet mapOfNodeSet;
8010
8011   TElemsSet::iterator elemIt = elems.begin();
8012   for ( int i = 0, j=0; elemIt != elems.end(); ++elemIt, ++j ) {
8013     const SMDS_MeshElement* curElem = *elemIt;
8014     SortableElement SE(curElem);
8015     int ind = -1;
8016     // check uniqueness
8017     pair< TMapOfNodeSet::iterator, bool> pp = mapOfNodeSet.insert(make_pair(SE, i));
8018     if( !(pp.second) ) {
8019       TMapOfNodeSet::iterator& itSE = pp.first;
8020       ind = (*itSE).second;
8021       arrayOfGroups[ind].push_back(curElem->GetID());
8022     }
8023     else {
8024       groupOfElems.clear();
8025       groupOfElems.push_back(curElem->GetID());
8026       arrayOfGroups.push_back(groupOfElems);
8027       i++;
8028     }
8029   }
8030
8031   vector< TGroupOfElems >::iterator groupIt = arrayOfGroups.begin();
8032   for ( ; groupIt != arrayOfGroups.end(); ++groupIt ) {
8033     groupOfElems = *groupIt;
8034     if ( groupOfElems.size() > 1 ) {
8035       groupOfElems.sort();
8036       theGroupsOfElementsID.push_back(groupOfElems);
8037     }
8038   }
8039 }
8040
8041 //=======================================================================
8042 //function : MergeElements
8043 //purpose  : In each given group, substitute all elements by the first one.
8044 //=======================================================================
8045
8046 void SMESH_MeshEditor::MergeElements(TListOfListOfElementsID & theGroupsOfElementsID)
8047 {
8048   myLastCreatedElems.Clear();
8049   myLastCreatedNodes.Clear();
8050
8051   typedef list<int> TListOfIDs;
8052   TListOfIDs rmElemIds; // IDs of elems to remove
8053
8054   SMESHDS_Mesh* aMesh = GetMeshDS();
8055
8056   TListOfListOfElementsID::iterator groupsIt = theGroupsOfElementsID.begin();
8057   while ( groupsIt != theGroupsOfElementsID.end() ) {
8058     TListOfIDs& aGroupOfElemID = *groupsIt;
8059     aGroupOfElemID.sort();
8060     int elemIDToKeep = aGroupOfElemID.front();
8061     const SMDS_MeshElement* elemToKeep = aMesh->FindElement(elemIDToKeep);
8062     aGroupOfElemID.pop_front();
8063     TListOfIDs::iterator idIt = aGroupOfElemID.begin();
8064     while ( idIt != aGroupOfElemID.end() ) {
8065       int elemIDToRemove = *idIt;
8066       const SMDS_MeshElement* elemToRemove = aMesh->FindElement(elemIDToRemove);
8067       // add the kept element in groups of removed one (PAL15188)
8068       AddToSameGroups( elemToKeep, elemToRemove, aMesh );
8069       rmElemIds.push_back( elemIDToRemove );
8070       ++idIt;
8071     }
8072     ++groupsIt;
8073   }
8074
8075   Remove( rmElemIds, false );
8076 }
8077
8078 //=======================================================================
8079 //function : MergeEqualElements
8080 //purpose  : Remove all but one of elements built on the same nodes.
8081 //=======================================================================
8082
8083 void SMESH_MeshEditor::MergeEqualElements()
8084 {
8085   set<const SMDS_MeshElement*> aMeshElements; /* empty input -
8086                                                  to merge equal elements in the whole mesh */
8087   TListOfListOfElementsID aGroupsOfElementsID;
8088   FindEqualElements(aMeshElements, aGroupsOfElementsID);
8089   MergeElements(aGroupsOfElementsID);
8090 }
8091
8092 //=======================================================================
8093 //function : FindFaceInSet
8094 //purpose  : Return a face having linked nodes n1 and n2 and which is
8095 //           - not in avoidSet,
8096 //           - in elemSet provided that !elemSet.empty()
8097 //           i1 and i2 optionally returns indices of n1 and n2
8098 //=======================================================================
8099
8100 const SMDS_MeshElement*
8101 SMESH_MeshEditor::FindFaceInSet(const SMDS_MeshNode*    n1,
8102                                 const SMDS_MeshNode*    n2,
8103                                 const TIDSortedElemSet& elemSet,
8104                                 const TIDSortedElemSet& avoidSet,
8105                                 int*                    n1ind,
8106                                 int*                    n2ind)
8107
8108 {
8109   int i1, i2;
8110   const SMDS_MeshElement* face = 0;
8111
8112   SMDS_ElemIteratorPtr invElemIt = n1->GetInverseElementIterator(SMDSAbs_Face);
8113   //MESSAGE("n1->GetInverseElementIterator(SMDSAbs_Face) " << invElemIt);
8114   while ( invElemIt->more() && !face ) // loop on inverse faces of n1
8115   {
8116     //MESSAGE("in while ( invElemIt->more() && !face )");
8117     const SMDS_MeshElement* elem = invElemIt->next();
8118     if (avoidSet.count( elem ))
8119       continue;
8120     if ( !elemSet.empty() && !elemSet.count( elem ))
8121       continue;
8122     // index of n1
8123     i1 = elem->GetNodeIndex( n1 );
8124     // find a n2 linked to n1
8125     int nbN = elem->IsQuadratic() ? elem->NbNodes()/2 : elem->NbNodes();
8126     for ( int di = -1; di < 2 && !face; di += 2 )
8127     {
8128       i2 = (i1+di+nbN) % nbN;
8129       if ( elem->GetNode( i2 ) == n2 )
8130         face = elem;
8131     }
8132     if ( !face && elem->IsQuadratic())
8133     {
8134       // analysis for quadratic elements using all nodes
8135       const SMDS_VtkFace* F =
8136         dynamic_cast<const SMDS_VtkFace*>(elem);
8137       if (!F) throw SALOME_Exception(LOCALIZED("not an SMDS_VtkFace"));
8138       // use special nodes iterator
8139       SMDS_ElemIteratorPtr anIter = F->interlacedNodesElemIterator();
8140       const SMDS_MeshNode* prevN = cast2Node( anIter->next() );
8141       for ( i1 = -1, i2 = 0; anIter->more() && !face; i1++, i2++ )
8142       {
8143         const SMDS_MeshNode* n = cast2Node( anIter->next() );
8144         if ( n1 == prevN && n2 == n )
8145         {
8146           face = elem;
8147         }
8148         else if ( n2 == prevN && n1 == n )
8149         {
8150           face = elem; swap( i1, i2 );
8151         }
8152         prevN = n;
8153       }
8154     }
8155   }
8156   if ( n1ind ) *n1ind = i1;
8157   if ( n2ind ) *n2ind = i2;
8158   return face;
8159 }
8160
8161 //=======================================================================
8162 //function : findAdjacentFace
8163 //purpose  :
8164 //=======================================================================
8165
8166 static const SMDS_MeshElement* findAdjacentFace(const SMDS_MeshNode* n1,
8167                                                 const SMDS_MeshNode* n2,
8168                                                 const SMDS_MeshElement* elem)
8169 {
8170   TIDSortedElemSet elemSet, avoidSet;
8171   if ( elem )
8172     avoidSet.insert ( elem );
8173   return SMESH_MeshEditor::FindFaceInSet( n1, n2, elemSet, avoidSet );
8174 }
8175
8176 //=======================================================================
8177 //function : FindFreeBorder
8178 //purpose  :
8179 //=======================================================================
8180
8181 #define ControlFreeBorder SMESH::Controls::FreeEdges::IsFreeEdge
8182
8183 bool SMESH_MeshEditor::FindFreeBorder (const SMDS_MeshNode*             theFirstNode,
8184                                        const SMDS_MeshNode*             theSecondNode,
8185                                        const SMDS_MeshNode*             theLastNode,
8186                                        list< const SMDS_MeshNode* > &   theNodes,
8187                                        list< const SMDS_MeshElement* >& theFaces)
8188 {
8189   if ( !theFirstNode || !theSecondNode )
8190     return false;
8191   // find border face between theFirstNode and theSecondNode
8192   const SMDS_MeshElement* curElem = findAdjacentFace( theFirstNode, theSecondNode, 0 );
8193   if ( !curElem )
8194     return false;
8195
8196   theFaces.push_back( curElem );
8197   theNodes.push_back( theFirstNode );
8198   theNodes.push_back( theSecondNode );
8199
8200   //vector<const SMDS_MeshNode*> nodes;
8201   const SMDS_MeshNode *nIgnore = theFirstNode, *nStart = theSecondNode;
8202   TIDSortedElemSet foundElems;
8203   bool needTheLast = ( theLastNode != 0 );
8204
8205   while ( nStart != theLastNode ) {
8206     if ( nStart == theFirstNode )
8207       return !needTheLast;
8208
8209     // find all free border faces sharing form nStart
8210
8211     list< const SMDS_MeshElement* > curElemList;
8212     list< const SMDS_MeshNode* > nStartList;
8213     SMDS_ElemIteratorPtr invElemIt = nStart->GetInverseElementIterator(SMDSAbs_Face);
8214     while ( invElemIt->more() ) {
8215       const SMDS_MeshElement* e = invElemIt->next();
8216       if ( e == curElem || foundElems.insert( e ).second ) {
8217         // get nodes
8218         int iNode = 0, nbNodes = e->NbNodes();
8219         //const SMDS_MeshNode* nodes[nbNodes+1];
8220         vector<const SMDS_MeshNode*> nodes(nbNodes+1);
8221
8222         if(e->IsQuadratic()) {
8223           const SMDS_VtkFace* F =
8224             dynamic_cast<const SMDS_VtkFace*>(e);
8225           if (!F) throw SALOME_Exception(LOCALIZED("not an SMDS_VtkFace"));
8226           // use special nodes iterator
8227           SMDS_ElemIteratorPtr anIter = F->interlacedNodesElemIterator();
8228           while( anIter->more() ) {
8229             nodes[ iNode++ ] = cast2Node(anIter->next());
8230           }
8231         }
8232         else {
8233           SMDS_ElemIteratorPtr nIt = e->nodesIterator();
8234           while ( nIt->more() )
8235             nodes[ iNode++ ] = static_cast<const SMDS_MeshNode*>( nIt->next() );
8236         }
8237         nodes[ iNode ] = nodes[ 0 ];
8238         // check 2 links
8239         for ( iNode = 0; iNode < nbNodes; iNode++ )
8240           if (((nodes[ iNode ] == nStart && nodes[ iNode + 1] != nIgnore ) ||
8241                (nodes[ iNode + 1] == nStart && nodes[ iNode ] != nIgnore )) &&
8242               ControlFreeBorder( &nodes[ iNode ], e->GetID() ))
8243           {
8244             nStartList.push_back( nodes[ iNode + ( nodes[ iNode ] == nStart ? 1 : 0 )]);
8245             curElemList.push_back( e );
8246           }
8247       }
8248     }
8249     // analyse the found
8250
8251     int nbNewBorders = curElemList.size();
8252     if ( nbNewBorders == 0 ) {
8253       // no free border furthermore
8254       return !needTheLast;
8255     }
8256     else if ( nbNewBorders == 1 ) {
8257       // one more element found
8258       nIgnore = nStart;
8259       nStart = nStartList.front();
8260       curElem = curElemList.front();
8261       theFaces.push_back( curElem );
8262       theNodes.push_back( nStart );
8263     }
8264     else {
8265       // several continuations found
8266       list< const SMDS_MeshElement* >::iterator curElemIt;
8267       list< const SMDS_MeshNode* >::iterator nStartIt;
8268       // check if one of them reached the last node
8269       if ( needTheLast ) {
8270         for (curElemIt = curElemList.begin(), nStartIt = nStartList.begin();
8271              curElemIt!= curElemList.end();
8272              curElemIt++, nStartIt++ )
8273           if ( *nStartIt == theLastNode ) {
8274             theFaces.push_back( *curElemIt );
8275             theNodes.push_back( *nStartIt );
8276             return true;
8277           }
8278       }
8279       // find the best free border by the continuations
8280       list<const SMDS_MeshNode*>    contNodes[ 2 ], *cNL;
8281       list<const SMDS_MeshElement*> contFaces[ 2 ], *cFL;
8282       for (curElemIt = curElemList.begin(), nStartIt = nStartList.begin();
8283            curElemIt!= curElemList.end();
8284            curElemIt++, nStartIt++ )
8285       {
8286         cNL = & contNodes[ contNodes[0].empty() ? 0 : 1 ];
8287         cFL = & contFaces[ contFaces[0].empty() ? 0 : 1 ];
8288         // find one more free border
8289         if ( ! FindFreeBorder( nStart, *nStartIt, theLastNode, *cNL, *cFL )) {
8290           cNL->clear();
8291           cFL->clear();
8292         }
8293         else if ( !contNodes[0].empty() && !contNodes[1].empty() ) {
8294           // choice: clear a worse one
8295           int iLongest = ( contNodes[0].size() < contNodes[1].size() ? 1 : 0 );
8296           int iWorse = ( needTheLast ? 1 - iLongest : iLongest );
8297           contNodes[ iWorse ].clear();
8298           contFaces[ iWorse ].clear();
8299         }
8300       }
8301       if ( contNodes[0].empty() && contNodes[1].empty() )
8302         return false;
8303
8304       // append the best free border
8305       cNL = & contNodes[ contNodes[0].empty() ? 1 : 0 ];
8306       cFL = & contFaces[ contFaces[0].empty() ? 1 : 0 ];
8307       theNodes.pop_back(); // remove nIgnore
8308       theNodes.pop_back(); // remove nStart
8309       theFaces.pop_back(); // remove curElem
8310       list< const SMDS_MeshNode* >::iterator nIt = cNL->begin();
8311       list< const SMDS_MeshElement* >::iterator fIt = cFL->begin();
8312       for ( ; nIt != cNL->end(); nIt++ ) theNodes.push_back( *nIt );
8313       for ( ; fIt != cFL->end(); fIt++ ) theFaces.push_back( *fIt );
8314       return true;
8315
8316     } // several continuations found
8317   } // while ( nStart != theLastNode )
8318
8319   return true;
8320 }
8321
8322 //=======================================================================
8323 //function : CheckFreeBorderNodes
8324 //purpose  : Return true if the tree nodes are on a free border
8325 //=======================================================================
8326
8327 bool SMESH_MeshEditor::CheckFreeBorderNodes(const SMDS_MeshNode* theNode1,
8328                                             const SMDS_MeshNode* theNode2,
8329                                             const SMDS_MeshNode* theNode3)
8330 {
8331   list< const SMDS_MeshNode* > nodes;
8332   list< const SMDS_MeshElement* > faces;
8333   return FindFreeBorder( theNode1, theNode2, theNode3, nodes, faces);
8334 }
8335
8336 //=======================================================================
8337 //function : SewFreeBorder
8338 //purpose  :
8339 //=======================================================================
8340
8341 SMESH_MeshEditor::Sew_Error
8342 SMESH_MeshEditor::SewFreeBorder (const SMDS_MeshNode* theBordFirstNode,
8343                                  const SMDS_MeshNode* theBordSecondNode,
8344                                  const SMDS_MeshNode* theBordLastNode,
8345                                  const SMDS_MeshNode* theSideFirstNode,
8346                                  const SMDS_MeshNode* theSideSecondNode,
8347                                  const SMDS_MeshNode* theSideThirdNode,
8348                                  const bool           theSideIsFreeBorder,
8349                                  const bool           toCreatePolygons,
8350                                  const bool           toCreatePolyedrs)
8351 {
8352   myLastCreatedElems.Clear();
8353   myLastCreatedNodes.Clear();
8354
8355   MESSAGE("::SewFreeBorder()");
8356   Sew_Error aResult = SEW_OK;
8357
8358   // ====================================
8359   //    find side nodes and elements
8360   // ====================================
8361
8362   list< const SMDS_MeshNode* > nSide[ 2 ];
8363   list< const SMDS_MeshElement* > eSide[ 2 ];
8364   list< const SMDS_MeshNode* >::iterator nIt[ 2 ];
8365   list< const SMDS_MeshElement* >::iterator eIt[ 2 ];
8366
8367   // Free border 1
8368   // --------------
8369   if (!FindFreeBorder(theBordFirstNode,theBordSecondNode,theBordLastNode,
8370                       nSide[0], eSide[0])) {
8371     MESSAGE(" Free Border 1 not found " );
8372     aResult = SEW_BORDER1_NOT_FOUND;
8373   }
8374   if (theSideIsFreeBorder) {
8375     // Free border 2
8376     // --------------
8377     if (!FindFreeBorder(theSideFirstNode, theSideSecondNode, theSideThirdNode,
8378                         nSide[1], eSide[1])) {
8379       MESSAGE(" Free Border 2 not found " );
8380       aResult = ( aResult != SEW_OK ? SEW_BOTH_BORDERS_NOT_FOUND : SEW_BORDER2_NOT_FOUND );
8381     }
8382   }
8383   if ( aResult != SEW_OK )
8384     return aResult;
8385
8386   if (!theSideIsFreeBorder) {
8387     // Side 2
8388     // --------------
8389
8390     // -------------------------------------------------------------------------
8391     // Algo:
8392     // 1. If nodes to merge are not coincident, move nodes of the free border
8393     //    from the coord sys defined by the direction from the first to last
8394     //    nodes of the border to the correspondent sys of the side 2
8395     // 2. On the side 2, find the links most co-directed with the correspondent
8396     //    links of the free border
8397     // -------------------------------------------------------------------------
8398
8399     // 1. Since sewing may break if there are volumes to split on the side 2,
8400     //    we wont move nodes but just compute new coordinates for them
8401     typedef map<const SMDS_MeshNode*, gp_XYZ> TNodeXYZMap;
8402     TNodeXYZMap nBordXYZ;
8403     list< const SMDS_MeshNode* >& bordNodes = nSide[ 0 ];
8404     list< const SMDS_MeshNode* >::iterator nBordIt;
8405
8406     gp_XYZ Pb1( theBordFirstNode->X(), theBordFirstNode->Y(), theBordFirstNode->Z() );
8407     gp_XYZ Pb2( theBordLastNode->X(), theBordLastNode->Y(), theBordLastNode->Z() );
8408     gp_XYZ Ps1( theSideFirstNode->X(), theSideFirstNode->Y(), theSideFirstNode->Z() );
8409     gp_XYZ Ps2( theSideSecondNode->X(), theSideSecondNode->Y(), theSideSecondNode->Z() );
8410     double tol2 = 1.e-8;
8411     gp_Vec Vbs1( Pb1 - Ps1 ),Vbs2( Pb2 - Ps2 );
8412     if ( Vbs1.SquareMagnitude() > tol2 || Vbs2.SquareMagnitude() > tol2 ) {
8413       // Need node movement.
8414
8415       // find X and Z axes to create trsf
8416       gp_Vec Zb( Pb1 - Pb2 ), Zs( Ps1 - Ps2 );
8417       gp_Vec X = Zs ^ Zb;
8418       if ( X.SquareMagnitude() <= gp::Resolution() * gp::Resolution() )
8419         // Zb || Zs
8420         X = gp_Ax2( gp::Origin(), Zb ).XDirection();
8421
8422       // coord systems
8423       gp_Ax3 toBordAx( Pb1, Zb, X );
8424       gp_Ax3 fromSideAx( Ps1, Zs, X );
8425       gp_Ax3 toGlobalAx( gp::Origin(), gp::DZ(), gp::DX() );
8426       // set trsf
8427       gp_Trsf toBordSys, fromSide2Sys;
8428       toBordSys.SetTransformation( toBordAx );
8429       fromSide2Sys.SetTransformation( fromSideAx, toGlobalAx );
8430       fromSide2Sys.SetScaleFactor( Zs.Magnitude() / Zb.Magnitude() );
8431
8432       // move
8433       for ( nBordIt = bordNodes.begin(); nBordIt != bordNodes.end(); nBordIt++ ) {
8434         const SMDS_MeshNode* n = *nBordIt;
8435         gp_XYZ xyz( n->X(),n->Y(),n->Z() );
8436         toBordSys.Transforms( xyz );
8437         fromSide2Sys.Transforms( xyz );
8438         nBordXYZ.insert( TNodeXYZMap::value_type( n, xyz ));
8439       }
8440     }
8441     else {
8442       // just insert nodes XYZ in the nBordXYZ map
8443       for ( nBordIt = bordNodes.begin(); nBordIt != bordNodes.end(); nBordIt++ ) {
8444         const SMDS_MeshNode* n = *nBordIt;
8445         nBordXYZ.insert( TNodeXYZMap::value_type( n, gp_XYZ( n->X(),n->Y(),n->Z() )));
8446       }
8447     }
8448
8449     // 2. On the side 2, find the links most co-directed with the correspondent
8450     //    links of the free border
8451
8452     list< const SMDS_MeshElement* >& sideElems = eSide[ 1 ];
8453     list< const SMDS_MeshNode* >& sideNodes = nSide[ 1 ];
8454     sideNodes.push_back( theSideFirstNode );
8455
8456     bool hasVolumes = false;
8457     LinkID_Gen aLinkID_Gen( GetMeshDS() );
8458     set<long> foundSideLinkIDs, checkedLinkIDs;
8459     SMDS_VolumeTool volume;
8460     //const SMDS_MeshNode* faceNodes[ 4 ];
8461
8462     const SMDS_MeshNode*    sideNode;
8463     const SMDS_MeshElement* sideElem;
8464     const SMDS_MeshNode* prevSideNode = theSideFirstNode;
8465     const SMDS_MeshNode* prevBordNode = theBordFirstNode;
8466     nBordIt = bordNodes.begin();
8467     nBordIt++;
8468     // border node position and border link direction to compare with
8469     gp_XYZ bordPos = nBordXYZ[ *nBordIt ];
8470     gp_XYZ bordDir = bordPos - nBordXYZ[ prevBordNode ];
8471     // choose next side node by link direction or by closeness to
8472     // the current border node:
8473     bool searchByDir = ( *nBordIt != theBordLastNode );
8474     do {
8475       // find the next node on the Side 2
8476       sideNode = 0;
8477       double maxDot = -DBL_MAX, minDist = DBL_MAX;
8478       long linkID;
8479       checkedLinkIDs.clear();
8480       gp_XYZ prevXYZ( prevSideNode->X(), prevSideNode->Y(), prevSideNode->Z() );
8481
8482       // loop on inverse elements of current node (prevSideNode) on the Side 2
8483       SMDS_ElemIteratorPtr invElemIt = prevSideNode->GetInverseElementIterator();
8484       while ( invElemIt->more() )
8485       {
8486         const SMDS_MeshElement* elem = invElemIt->next();
8487         // prepare data for a loop on links coming to prevSideNode, of a face or a volume
8488         int iPrevNode, iNode = 0, nbNodes = elem->NbNodes();
8489         vector< const SMDS_MeshNode* > faceNodes( nbNodes, (const SMDS_MeshNode*)0 );
8490         bool isVolume = volume.Set( elem );
8491         const SMDS_MeshNode** nodes = isVolume ? volume.GetNodes() : & faceNodes[0];
8492         if ( isVolume ) // --volume
8493           hasVolumes = true;
8494         else if ( elem->GetType()==SMDSAbs_Face ) { // --face
8495           // retrieve all face nodes and find iPrevNode - an index of the prevSideNode
8496           if(elem->IsQuadratic()) {
8497             const SMDS_VtkFace* F =
8498               dynamic_cast<const SMDS_VtkFace*>(elem);
8499             if (!F) throw SALOME_Exception(LOCALIZED("not an SMDS_VtkFace"));
8500             // use special nodes iterator
8501             SMDS_ElemIteratorPtr anIter = F->interlacedNodesElemIterator();
8502             while( anIter->more() ) {
8503               nodes[ iNode ] = cast2Node(anIter->next());
8504               if ( nodes[ iNode++ ] == prevSideNode )
8505                 iPrevNode = iNode - 1;
8506             }
8507           }
8508           else {
8509             SMDS_ElemIteratorPtr nIt = elem->nodesIterator();
8510             while ( nIt->more() ) {
8511               nodes[ iNode ] = cast2Node( nIt->next() );
8512               if ( nodes[ iNode++ ] == prevSideNode )
8513                 iPrevNode = iNode - 1;
8514             }
8515           }
8516           // there are 2 links to check
8517           nbNodes = 2;
8518         }
8519         else // --edge
8520           continue;
8521         // loop on links, to be precise, on the second node of links
8522         for ( iNode = 0; iNode < nbNodes; iNode++ ) {
8523           const SMDS_MeshNode* n = nodes[ iNode ];
8524           if ( isVolume ) {
8525             if ( !volume.IsLinked( n, prevSideNode ))
8526               continue;
8527           }
8528           else {
8529             if ( iNode ) // a node before prevSideNode
8530               n = nodes[ iPrevNode == 0 ? elem->NbNodes() - 1 : iPrevNode - 1 ];
8531             else         // a node after prevSideNode
8532               n = nodes[ iPrevNode + 1 == elem->NbNodes() ? 0 : iPrevNode + 1 ];
8533           }
8534           // check if this link was already used
8535           long iLink = aLinkID_Gen.GetLinkID( prevSideNode, n );
8536           bool isJustChecked = !checkedLinkIDs.insert( iLink ).second;
8537           if (!isJustChecked &&
8538               foundSideLinkIDs.find( iLink ) == foundSideLinkIDs.end() )
8539           {
8540             // test a link geometrically
8541             gp_XYZ nextXYZ ( n->X(), n->Y(), n->Z() );
8542             bool linkIsBetter = false;
8543             double dot = 0.0, dist = 0.0;
8544             if ( searchByDir ) { // choose most co-directed link
8545               dot = bordDir * ( nextXYZ - prevXYZ ).Normalized();
8546               linkIsBetter = ( dot > maxDot );
8547             }
8548             else { // choose link with the node closest to bordPos
8549               dist = ( nextXYZ - bordPos ).SquareModulus();
8550               linkIsBetter = ( dist < minDist );
8551             }
8552             if ( linkIsBetter ) {
8553               maxDot = dot;
8554               minDist = dist;
8555               linkID = iLink;
8556               sideNode = n;
8557               sideElem = elem;
8558             }
8559           }
8560         }
8561       } // loop on inverse elements of prevSideNode
8562
8563       if ( !sideNode ) {
8564         MESSAGE(" Cant find path by links of the Side 2 ");
8565         return SEW_BAD_SIDE_NODES;
8566       }
8567       sideNodes.push_back( sideNode );
8568       sideElems.push_back( sideElem );
8569       foundSideLinkIDs.insert ( linkID );
8570       prevSideNode = sideNode;
8571
8572       if ( *nBordIt == theBordLastNode )
8573         searchByDir = false;
8574       else {
8575         // find the next border link to compare with
8576         gp_XYZ sidePos( sideNode->X(), sideNode->Y(), sideNode->Z() );
8577         searchByDir = ( bordDir * ( sidePos - bordPos ) <= 0 );
8578         // move to next border node if sideNode is before forward border node (bordPos)
8579         while ( *nBordIt != theBordLastNode && !searchByDir ) {
8580           prevBordNode = *nBordIt;
8581           nBordIt++;
8582           bordPos = nBordXYZ[ *nBordIt ];
8583           bordDir = bordPos - nBordXYZ[ prevBordNode ];
8584           searchByDir = ( bordDir * ( sidePos - bordPos ) <= 0 );
8585         }
8586       }
8587     }
8588     while ( sideNode != theSideSecondNode );
8589
8590     if ( hasVolumes && sideNodes.size () != bordNodes.size() && !toCreatePolyedrs) {
8591       MESSAGE("VOLUME SPLITTING IS FORBIDDEN");
8592       return SEW_VOLUMES_TO_SPLIT; // volume splitting is forbidden
8593     }
8594   } // end nodes search on the side 2
8595
8596   // ============================
8597   // sew the border to the side 2
8598   // ============================
8599
8600   int nbNodes[]  = { nSide[0].size(), nSide[1].size() };
8601   int maxNbNodes = Max( nbNodes[0], nbNodes[1] );
8602
8603   TListOfListOfNodes nodeGroupsToMerge;
8604   if ( nbNodes[0] == nbNodes[1] ||
8605        ( theSideIsFreeBorder && !theSideThirdNode)) {
8606
8607     // all nodes are to be merged
8608
8609     for (nIt[0] = nSide[0].begin(), nIt[1] = nSide[1].begin();
8610          nIt[0] != nSide[0].end() && nIt[1] != nSide[1].end();
8611          nIt[0]++, nIt[1]++ )
8612     {
8613       nodeGroupsToMerge.push_back( list<const SMDS_MeshNode*>() );
8614       nodeGroupsToMerge.back().push_back( *nIt[1] ); // to keep
8615       nodeGroupsToMerge.back().push_back( *nIt[0] ); // to remove
8616     }
8617   }
8618   else {
8619
8620     // insert new nodes into the border and the side to get equal nb of segments
8621
8622     // get normalized parameters of nodes on the borders
8623     //double param[ 2 ][ maxNbNodes ];
8624     double* param[ 2 ];
8625     param[0] = new double [ maxNbNodes ];
8626     param[1] = new double [ maxNbNodes ];
8627     int iNode, iBord;
8628     for ( iBord = 0; iBord < 2; iBord++ ) { // loop on 2 borders
8629       list< const SMDS_MeshNode* >& nodes = nSide[ iBord ];
8630       list< const SMDS_MeshNode* >::iterator nIt = nodes.begin();
8631       const SMDS_MeshNode* nPrev = *nIt;
8632       double bordLength = 0;
8633       for ( iNode = 0; nIt != nodes.end(); nIt++, iNode++ ) { // loop on border nodes
8634         const SMDS_MeshNode* nCur = *nIt;
8635         gp_XYZ segment (nCur->X() - nPrev->X(),
8636                         nCur->Y() - nPrev->Y(),
8637                         nCur->Z() - nPrev->Z());
8638         double segmentLen = segment.Modulus();
8639         bordLength += segmentLen;
8640         param[ iBord ][ iNode ] = bordLength;
8641         nPrev = nCur;
8642       }
8643       // normalize within [0,1]
8644       for ( iNode = 0; iNode < nbNodes[ iBord ]; iNode++ ) {
8645         param[ iBord ][ iNode ] /= bordLength;
8646       }
8647     }
8648
8649     // loop on border segments
8650     const SMDS_MeshNode *nPrev[ 2 ] = { 0, 0 };
8651     int i[ 2 ] = { 0, 0 };
8652     nIt[0] = nSide[0].begin(); eIt[0] = eSide[0].begin();
8653     nIt[1] = nSide[1].begin(); eIt[1] = eSide[1].begin();
8654
8655     TElemOfNodeListMap insertMap;
8656     TElemOfNodeListMap::iterator insertMapIt;
8657     // insertMap is
8658     // key:   elem to insert nodes into
8659     // value: 2 nodes to insert between + nodes to be inserted
8660     do {
8661       bool next[ 2 ] = { false, false };
8662
8663       // find min adjacent segment length after sewing
8664       double nextParam = 10., prevParam = 0;
8665       for ( iBord = 0; iBord < 2; iBord++ ) { // loop on 2 borders
8666         if ( i[ iBord ] + 1 < nbNodes[ iBord ])
8667           nextParam = Min( nextParam, param[iBord][ i[iBord] + 1 ]);
8668         if ( i[ iBord ] > 0 )
8669           prevParam = Max( prevParam, param[iBord][ i[iBord] - 1 ]);
8670       }
8671       double minParam = Min( param[ 0 ][ i[0] ], param[ 1 ][ i[1] ]);
8672       double maxParam = Max( param[ 0 ][ i[0] ], param[ 1 ][ i[1] ]);
8673       double minSegLen = Min( nextParam - minParam, maxParam - prevParam );
8674
8675       // choose to insert or to merge nodes
8676       double du = param[ 1 ][ i[1] ] - param[ 0 ][ i[0] ];
8677       if ( Abs( du ) <= minSegLen * 0.2 ) {
8678         // merge
8679         // ------
8680         nodeGroupsToMerge.push_back( list<const SMDS_MeshNode*>() );
8681         const SMDS_MeshNode* n0 = *nIt[0];
8682         const SMDS_MeshNode* n1 = *nIt[1];
8683         nodeGroupsToMerge.back().push_back( n1 );
8684         nodeGroupsToMerge.back().push_back( n0 );
8685         // position of node of the border changes due to merge
8686         param[ 0 ][ i[0] ] += du;
8687         // move n1 for the sake of elem shape evaluation during insertion.
8688         // n1 will be removed by MergeNodes() anyway
8689         const_cast<SMDS_MeshNode*>( n0 )->setXYZ( n1->X(), n1->Y(), n1->Z() );
8690         next[0] = next[1] = true;
8691       }
8692       else {
8693         // insert
8694         // ------
8695         int intoBord = ( du < 0 ) ? 0 : 1;
8696         const SMDS_MeshElement* elem = *eIt[ intoBord ];
8697         const SMDS_MeshNode*    n1   = nPrev[ intoBord ];
8698         const SMDS_MeshNode*    n2   = *nIt[ intoBord ];
8699         const SMDS_MeshNode*    nIns = *nIt[ 1 - intoBord ];
8700         if ( intoBord == 1 ) {
8701           // move node of the border to be on a link of elem of the side
8702           gp_XYZ p1 (n1->X(), n1->Y(), n1->Z());
8703           gp_XYZ p2 (n2->X(), n2->Y(), n2->Z());
8704           double ratio = du / ( param[ 1 ][ i[1] ] - param[ 1 ][ i[1]-1 ]);
8705           gp_XYZ p = p2 * ( 1 - ratio ) + p1 * ratio;
8706           GetMeshDS()->MoveNode( nIns, p.X(), p.Y(), p.Z() );
8707         }
8708         insertMapIt = insertMap.find( elem );
8709         bool notFound = ( insertMapIt == insertMap.end() );
8710         bool otherLink = ( !notFound && (*insertMapIt).second.front() != n1 );
8711         if ( otherLink ) {
8712           // insert into another link of the same element:
8713           // 1. perform insertion into the other link of the elem
8714           list<const SMDS_MeshNode*> & nodeList = (*insertMapIt).second;
8715           const SMDS_MeshNode* n12 = nodeList.front(); nodeList.pop_front();
8716           const SMDS_MeshNode* n22 = nodeList.front(); nodeList.pop_front();
8717           InsertNodesIntoLink( elem, n12, n22, nodeList, toCreatePolygons );
8718           // 2. perform insertion into the link of adjacent faces
8719           while (true) {
8720             const SMDS_MeshElement* adjElem = findAdjacentFace( n12, n22, elem );
8721             if ( adjElem )
8722               InsertNodesIntoLink( adjElem, n12, n22, nodeList, toCreatePolygons );
8723             else
8724               break;
8725           }
8726           if (toCreatePolyedrs) {
8727             // perform insertion into the links of adjacent volumes
8728             UpdateVolumes(n12, n22, nodeList);
8729           }
8730           // 3. find an element appeared on n1 and n2 after the insertion
8731           insertMap.erase( elem );
8732           elem = findAdjacentFace( n1, n2, 0 );
8733         }
8734         if ( notFound || otherLink ) {
8735           // add element and nodes of the side into the insertMap
8736           insertMapIt = insertMap.insert
8737             ( TElemOfNodeListMap::value_type( elem, list<const SMDS_MeshNode*>() )).first;
8738           (*insertMapIt).second.push_back( n1 );
8739           (*insertMapIt).second.push_back( n2 );
8740         }
8741         // add node to be inserted into elem
8742         (*insertMapIt).second.push_back( nIns );
8743         next[ 1 - intoBord ] = true;
8744       }
8745
8746       // go to the next segment
8747       for ( iBord = 0; iBord < 2; iBord++ ) { // loop on 2 borders
8748         if ( next[ iBord ] ) {
8749           if ( i[ iBord ] != 0 && eIt[ iBord ] != eSide[ iBord ].end())
8750             eIt[ iBord ]++;
8751           nPrev[ iBord ] = *nIt[ iBord ];
8752           nIt[ iBord ]++; i[ iBord ]++;
8753         }
8754       }
8755     }
8756     while ( nIt[0] != nSide[0].end() && nIt[1] != nSide[1].end());
8757
8758     // perform insertion of nodes into elements
8759
8760     for (insertMapIt = insertMap.begin();
8761          insertMapIt != insertMap.end();
8762          insertMapIt++ )
8763     {
8764       const SMDS_MeshElement* elem = (*insertMapIt).first;
8765       list<const SMDS_MeshNode*> & nodeList = (*insertMapIt).second;
8766       const SMDS_MeshNode* n1 = nodeList.front(); nodeList.pop_front();
8767       const SMDS_MeshNode* n2 = nodeList.front(); nodeList.pop_front();
8768
8769       InsertNodesIntoLink( elem, n1, n2, nodeList, toCreatePolygons );
8770
8771       if ( !theSideIsFreeBorder ) {
8772         // look for and insert nodes into the faces adjacent to elem
8773         while (true) {
8774           const SMDS_MeshElement* adjElem = findAdjacentFace( n1, n2, elem );
8775           if ( adjElem )
8776             InsertNodesIntoLink( adjElem, n1, n2, nodeList, toCreatePolygons );
8777           else
8778             break;
8779         }
8780       }
8781       if (toCreatePolyedrs) {
8782         // perform insertion into the links of adjacent volumes
8783         UpdateVolumes(n1, n2, nodeList);
8784       }
8785     }
8786
8787     delete param[0];
8788     delete param[1];
8789   } // end: insert new nodes
8790
8791   MergeNodes ( nodeGroupsToMerge );
8792
8793   return aResult;
8794 }
8795
8796 //=======================================================================
8797 //function : InsertNodesIntoLink
8798 //purpose  : insert theNodesToInsert into theFace between theBetweenNode1
8799 //           and theBetweenNode2 and split theElement
8800 //=======================================================================
8801
8802 void SMESH_MeshEditor::InsertNodesIntoLink(const SMDS_MeshElement*     theFace,
8803                                            const SMDS_MeshNode*        theBetweenNode1,
8804                                            const SMDS_MeshNode*        theBetweenNode2,
8805                                            list<const SMDS_MeshNode*>& theNodesToInsert,
8806                                            const bool                  toCreatePoly)
8807 {
8808   if ( theFace->GetType() != SMDSAbs_Face ) return;
8809
8810   // find indices of 2 link nodes and of the rest nodes
8811   int iNode = 0, il1, il2, i3, i4;
8812   il1 = il2 = i3 = i4 = -1;
8813   //const SMDS_MeshNode* nodes[ theFace->NbNodes() ];
8814   vector<const SMDS_MeshNode*> nodes( theFace->NbNodes() );
8815
8816   if(theFace->IsQuadratic()) {
8817     const SMDS_VtkFace* F =
8818       dynamic_cast<const SMDS_VtkFace*>(theFace);
8819     if (!F) throw SALOME_Exception(LOCALIZED("not an SMDS_VtkFace"));
8820     // use special nodes iterator
8821     SMDS_ElemIteratorPtr anIter = F->interlacedNodesElemIterator();
8822     while( anIter->more() ) {
8823       const SMDS_MeshNode* n = cast2Node(anIter->next());
8824       if ( n == theBetweenNode1 )
8825         il1 = iNode;
8826       else if ( n == theBetweenNode2 )
8827         il2 = iNode;
8828       else if ( i3 < 0 )
8829         i3 = iNode;
8830       else
8831         i4 = iNode;
8832       nodes[ iNode++ ] = n;
8833     }
8834   }
8835   else {
8836     SMDS_ElemIteratorPtr nodeIt = theFace->nodesIterator();
8837     while ( nodeIt->more() ) {
8838       const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
8839       if ( n == theBetweenNode1 )
8840         il1 = iNode;
8841       else if ( n == theBetweenNode2 )
8842         il2 = iNode;
8843       else if ( i3 < 0 )
8844         i3 = iNode;
8845       else
8846         i4 = iNode;
8847       nodes[ iNode++ ] = n;
8848     }
8849   }
8850   if ( il1 < 0 || il2 < 0 || i3 < 0 )
8851     return ;
8852
8853   // arrange link nodes to go one after another regarding the face orientation
8854   bool reverse = ( Abs( il2 - il1 ) == 1 ? il2 < il1 : il1 < il2 );
8855   list<const SMDS_MeshNode *> aNodesToInsert = theNodesToInsert;
8856   if ( reverse ) {
8857     iNode = il1;
8858     il1 = il2;
8859     il2 = iNode;
8860     aNodesToInsert.reverse();
8861   }
8862   // check that not link nodes of a quadrangles are in good order
8863   int nbFaceNodes = theFace->NbNodes();
8864   if ( nbFaceNodes == 4 && i4 - i3 != 1 ) {
8865     iNode = i3;
8866     i3 = i4;
8867     i4 = iNode;
8868   }
8869
8870   if (toCreatePoly || theFace->IsPoly()) {
8871
8872     iNode = 0;
8873     vector<const SMDS_MeshNode *> poly_nodes (nbFaceNodes + aNodesToInsert.size());
8874
8875     // add nodes of face up to first node of link
8876     bool isFLN = false;
8877
8878     if(theFace->IsQuadratic()) {
8879       const SMDS_VtkFace* F =
8880         dynamic_cast<const SMDS_VtkFace*>(theFace);
8881       if (!F) throw SALOME_Exception(LOCALIZED("not an SMDS_VtkFace"));
8882       // use special nodes iterator
8883       SMDS_ElemIteratorPtr anIter = F->interlacedNodesElemIterator();
8884       while( anIter->more()  && !isFLN ) {
8885         const SMDS_MeshNode* n = cast2Node(anIter->next());
8886         poly_nodes[iNode++] = n;
8887         if (n == nodes[il1]) {
8888           isFLN = true;
8889         }
8890       }
8891       // add nodes to insert
8892       list<const SMDS_MeshNode*>::iterator nIt = aNodesToInsert.begin();
8893       for (; nIt != aNodesToInsert.end(); nIt++) {
8894         poly_nodes[iNode++] = *nIt;
8895       }
8896       // add nodes of face starting from last node of link
8897       while ( anIter->more() ) {
8898         poly_nodes[iNode++] = cast2Node(anIter->next());
8899       }
8900     }
8901     else {
8902       SMDS_ElemIteratorPtr nodeIt = theFace->nodesIterator();
8903       while ( nodeIt->more() && !isFLN ) {
8904         const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
8905         poly_nodes[iNode++] = n;
8906         if (n == nodes[il1]) {
8907           isFLN = true;
8908         }
8909       }
8910       // add nodes to insert
8911       list<const SMDS_MeshNode*>::iterator nIt = aNodesToInsert.begin();
8912       for (; nIt != aNodesToInsert.end(); nIt++) {
8913         poly_nodes[iNode++] = *nIt;
8914       }
8915       // add nodes of face starting from last node of link
8916       while ( nodeIt->more() ) {
8917         const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
8918         poly_nodes[iNode++] = n;
8919       }
8920     }
8921
8922     // edit or replace the face
8923     SMESHDS_Mesh *aMesh = GetMeshDS();
8924
8925     if (theFace->IsPoly()) {
8926       aMesh->ChangePolygonNodes(theFace, poly_nodes);
8927     }
8928     else {
8929       int aShapeId = FindShape( theFace );
8930
8931       SMDS_MeshElement* newElem = aMesh->AddPolygonalFace(poly_nodes);
8932       myLastCreatedElems.Append(newElem);
8933       if ( aShapeId && newElem )
8934         aMesh->SetMeshElementOnShape( newElem, aShapeId );
8935
8936       aMesh->RemoveElement(theFace);
8937     }
8938     return;
8939   }
8940
8941   SMESHDS_Mesh *aMesh = GetMeshDS();
8942   if( !theFace->IsQuadratic() ) {
8943
8944     // put aNodesToInsert between theBetweenNode1 and theBetweenNode2
8945     int nbLinkNodes = 2 + aNodesToInsert.size();
8946     //const SMDS_MeshNode* linkNodes[ nbLinkNodes ];
8947     vector<const SMDS_MeshNode*> linkNodes( nbLinkNodes );
8948     linkNodes[ 0 ] = nodes[ il1 ];
8949     linkNodes[ nbLinkNodes - 1 ] = nodes[ il2 ];
8950     list<const SMDS_MeshNode*>::iterator nIt = aNodesToInsert.begin();
8951     for ( iNode = 1; nIt != aNodesToInsert.end(); nIt++ ) {
8952       linkNodes[ iNode++ ] = *nIt;
8953     }
8954     // decide how to split a quadrangle: compare possible variants
8955     // and choose which of splits to be a quadrangle
8956     int i1, i2, iSplit, nbSplits = nbLinkNodes - 1, iBestQuad;
8957     if ( nbFaceNodes == 3 ) {
8958       iBestQuad = nbSplits;
8959       i4 = i3;
8960     }
8961     else if ( nbFaceNodes == 4 ) {
8962       SMESH::Controls::NumericalFunctorPtr aCrit( new SMESH::Controls::AspectRatio);
8963       double aBestRate = DBL_MAX;
8964       for ( int iQuad = 0; iQuad < nbSplits; iQuad++ ) {
8965         i1 = 0; i2 = 1;
8966         double aBadRate = 0;
8967         // evaluate elements quality
8968         for ( iSplit = 0; iSplit < nbSplits; iSplit++ ) {
8969           if ( iSplit == iQuad ) {
8970             SMDS_FaceOfNodes quad (linkNodes[ i1++ ],
8971                                    linkNodes[ i2++ ],
8972                                    nodes[ i3 ],
8973                                    nodes[ i4 ]);
8974             aBadRate += getBadRate( &quad, aCrit );
8975           }
8976           else {
8977             SMDS_FaceOfNodes tria (linkNodes[ i1++ ],
8978                                    linkNodes[ i2++ ],
8979                                    nodes[ iSplit < iQuad ? i4 : i3 ]);
8980             aBadRate += getBadRate( &tria, aCrit );
8981           }
8982         }
8983         // choice
8984         if ( aBadRate < aBestRate ) {
8985           iBestQuad = iQuad;
8986           aBestRate = aBadRate;
8987         }
8988       }
8989     }
8990
8991     // create new elements
8992     int aShapeId = FindShape( theFace );
8993
8994     i1 = 0; i2 = 1;
8995     for ( iSplit = 0; iSplit < nbSplits - 1; iSplit++ ) {
8996       SMDS_MeshElement* newElem = 0;
8997       if ( iSplit == iBestQuad )
8998         newElem = aMesh->AddFace (linkNodes[ i1++ ],
8999                                   linkNodes[ i2++ ],
9000                                   nodes[ i3 ],
9001                                   nodes[ i4 ]);
9002       else
9003         newElem = aMesh->AddFace (linkNodes[ i1++ ],
9004                                   linkNodes[ i2++ ],
9005                                   nodes[ iSplit < iBestQuad ? i4 : i3 ]);
9006       myLastCreatedElems.Append(newElem);
9007       if ( aShapeId && newElem )
9008         aMesh->SetMeshElementOnShape( newElem, aShapeId );
9009     }
9010
9011     // change nodes of theFace
9012     const SMDS_MeshNode* newNodes[ 4 ];
9013     newNodes[ 0 ] = linkNodes[ i1 ];
9014     newNodes[ 1 ] = linkNodes[ i2 ];
9015     newNodes[ 2 ] = nodes[ iSplit >= iBestQuad ? i3 : i4 ];
9016     newNodes[ 3 ] = nodes[ i4 ];
9017     //aMesh->ChangeElementNodes( theFace, newNodes, iSplit == iBestQuad ? 4 : 3 );
9018     const SMDS_MeshElement* newElem = 0;
9019     if (iSplit == iBestQuad)
9020       newElem = aMesh->AddFace( newNodes[0], newNodes[1], newNodes[2], newNodes[3] );
9021     else
9022       newElem = aMesh->AddFace( newNodes[0], newNodes[1], newNodes[2] );
9023     myLastCreatedElems.Append(newElem);
9024     if ( aShapeId && newElem )
9025       aMesh->SetMeshElementOnShape( newElem, aShapeId );
9026 } // end if(!theFace->IsQuadratic())
9027   else { // theFace is quadratic
9028     // we have to split theFace on simple triangles and one simple quadrangle
9029     int tmp = il1/2;
9030     int nbshift = tmp*2;
9031     // shift nodes in nodes[] by nbshift
9032     int i,j;
9033     for(i=0; i<nbshift; i++) {
9034       const SMDS_MeshNode* n = nodes[0];
9035       for(j=0; j<nbFaceNodes-1; j++) {
9036         nodes[j] = nodes[j+1];
9037       }
9038       nodes[nbFaceNodes-1] = n;
9039     }
9040     il1 = il1 - nbshift;
9041     // now have to insert nodes between n0 and n1 or n1 and n2 (see below)
9042     //   n0      n1     n2    n0      n1     n2
9043     //     +-----+-----+        +-----+-----+
9044     //      \         /         |           |
9045     //       \       /          |           |
9046     //      n5+     +n3       n7+           +n3
9047     //         \   /            |           |
9048     //          \ /             |           |
9049     //           +              +-----+-----+
9050     //           n4           n6      n5     n4
9051
9052     // create new elements
9053     int aShapeId = FindShape( theFace );
9054
9055     int n1,n2,n3;
9056     if(nbFaceNodes==6) { // quadratic triangle
9057       SMDS_MeshElement* newElem =
9058         aMesh->AddFace(nodes[3],nodes[4],nodes[5]);
9059       myLastCreatedElems.Append(newElem);
9060       if ( aShapeId && newElem )
9061         aMesh->SetMeshElementOnShape( newElem, aShapeId );
9062       if(theFace->IsMediumNode(nodes[il1])) {
9063         // create quadrangle
9064         newElem = aMesh->AddFace(nodes[0],nodes[1],nodes[3],nodes[5]);
9065         myLastCreatedElems.Append(newElem);
9066         if ( aShapeId && newElem )
9067           aMesh->SetMeshElementOnShape( newElem, aShapeId );
9068         n1 = 1;
9069         n2 = 2;
9070         n3 = 3;
9071       }
9072       else {
9073         // create quadrangle
9074         newElem = aMesh->AddFace(nodes[1],nodes[2],nodes[3],nodes[5]);
9075         myLastCreatedElems.Append(newElem);
9076         if ( aShapeId && newElem )
9077           aMesh->SetMeshElementOnShape( newElem, aShapeId );
9078         n1 = 0;
9079         n2 = 1;
9080         n3 = 5;
9081       }
9082     }
9083     else { // nbFaceNodes==8 - quadratic quadrangle
9084       SMDS_MeshElement* newElem =
9085         aMesh->AddFace(nodes[3],nodes[4],nodes[5]);
9086       myLastCreatedElems.Append(newElem);
9087       if ( aShapeId && newElem )
9088         aMesh->SetMeshElementOnShape( newElem, aShapeId );
9089       newElem = aMesh->AddFace(nodes[5],nodes[6],nodes[7]);
9090       myLastCreatedElems.Append(newElem);
9091       if ( aShapeId && newElem )
9092         aMesh->SetMeshElementOnShape( newElem, aShapeId );
9093       newElem = aMesh->AddFace(nodes[5],nodes[7],nodes[3]);
9094       myLastCreatedElems.Append(newElem);
9095       if ( aShapeId && newElem )
9096         aMesh->SetMeshElementOnShape( newElem, aShapeId );
9097       if(theFace->IsMediumNode(nodes[il1])) {
9098         // create quadrangle
9099         newElem = aMesh->AddFace(nodes[0],nodes[1],nodes[3],nodes[7]);
9100         myLastCreatedElems.Append(newElem);
9101         if ( aShapeId && newElem )
9102           aMesh->SetMeshElementOnShape( newElem, aShapeId );
9103         n1 = 1;
9104         n2 = 2;
9105         n3 = 3;
9106       }
9107       else {
9108         // create quadrangle
9109         newElem = aMesh->AddFace(nodes[1],nodes[2],nodes[3],nodes[7]);
9110         myLastCreatedElems.Append(newElem);
9111         if ( aShapeId && newElem )
9112           aMesh->SetMeshElementOnShape( newElem, aShapeId );
9113         n1 = 0;
9114         n2 = 1;
9115         n3 = 7;
9116       }
9117     }
9118     // create needed triangles using n1,n2,n3 and inserted nodes
9119     int nbn = 2 + aNodesToInsert.size();
9120     //const SMDS_MeshNode* aNodes[nbn];
9121     vector<const SMDS_MeshNode*> aNodes(nbn);
9122     aNodes[0] = nodes[n1];
9123     aNodes[nbn-1] = nodes[n2];
9124     list<const SMDS_MeshNode*>::iterator nIt = aNodesToInsert.begin();
9125     for ( iNode = 1; nIt != aNodesToInsert.end(); nIt++ ) {
9126       aNodes[iNode++] = *nIt;
9127     }
9128     for(i=1; i<nbn; i++) {
9129       SMDS_MeshElement* newElem =
9130         aMesh->AddFace(aNodes[i-1],aNodes[i],nodes[n3]);
9131       myLastCreatedElems.Append(newElem);
9132       if ( aShapeId && newElem )
9133         aMesh->SetMeshElementOnShape( newElem, aShapeId );
9134     }
9135   }
9136   // remove old face
9137   aMesh->RemoveElement(theFace);
9138 }
9139
9140 //=======================================================================
9141 //function : UpdateVolumes
9142 //purpose  :
9143 //=======================================================================
9144 void SMESH_MeshEditor::UpdateVolumes (const SMDS_MeshNode*        theBetweenNode1,
9145                                       const SMDS_MeshNode*        theBetweenNode2,
9146                                       list<const SMDS_MeshNode*>& theNodesToInsert)
9147 {
9148   myLastCreatedElems.Clear();
9149   myLastCreatedNodes.Clear();
9150
9151   SMDS_ElemIteratorPtr invElemIt = theBetweenNode1->GetInverseElementIterator(SMDSAbs_Volume);
9152   while (invElemIt->more()) { // loop on inverse elements of theBetweenNode1
9153     const SMDS_MeshElement* elem = invElemIt->next();
9154
9155     // check, if current volume has link theBetweenNode1 - theBetweenNode2
9156     SMDS_VolumeTool aVolume (elem);
9157     if (!aVolume.IsLinked(theBetweenNode1, theBetweenNode2))
9158       continue;
9159
9160     // insert new nodes in all faces of the volume, sharing link theBetweenNode1 - theBetweenNode2
9161     int iface, nbFaces = aVolume.NbFaces();
9162     vector<const SMDS_MeshNode *> poly_nodes;
9163     vector<int> quantities (nbFaces);
9164
9165     for (iface = 0; iface < nbFaces; iface++) {
9166       int nbFaceNodes = aVolume.NbFaceNodes(iface), nbInserted = 0;
9167       // faceNodes will contain (nbFaceNodes + 1) nodes, last = first
9168       const SMDS_MeshNode** faceNodes = aVolume.GetFaceNodes(iface);
9169
9170       for (int inode = 0; inode < nbFaceNodes; inode++) {
9171         poly_nodes.push_back(faceNodes[inode]);
9172
9173         if (nbInserted == 0) {
9174           if (faceNodes[inode] == theBetweenNode1) {
9175             if (faceNodes[inode + 1] == theBetweenNode2) {
9176               nbInserted = theNodesToInsert.size();
9177
9178               // add nodes to insert
9179               list<const SMDS_MeshNode*>::iterator nIt = theNodesToInsert.begin();
9180               for (; nIt != theNodesToInsert.end(); nIt++) {
9181                 poly_nodes.push_back(*nIt);
9182               }
9183             }
9184           }
9185           else if (faceNodes[inode] == theBetweenNode2) {
9186             if (faceNodes[inode + 1] == theBetweenNode1) {
9187               nbInserted = theNodesToInsert.size();
9188
9189               // add nodes to insert in reversed order
9190               list<const SMDS_MeshNode*>::iterator nIt = theNodesToInsert.end();
9191               nIt--;
9192               for (; nIt != theNodesToInsert.begin(); nIt--) {
9193                 poly_nodes.push_back(*nIt);
9194               }
9195               poly_nodes.push_back(*nIt);
9196             }
9197           }
9198           else {
9199           }
9200         }
9201       }
9202       quantities[iface] = nbFaceNodes + nbInserted;
9203     }
9204
9205     // Replace or update the volume
9206     SMESHDS_Mesh *aMesh = GetMeshDS();
9207
9208     if (elem->IsPoly()) {
9209       aMesh->ChangePolyhedronNodes(elem, poly_nodes, quantities);
9210
9211     }
9212     else {
9213       int aShapeId = FindShape( elem );
9214
9215       SMDS_MeshElement* newElem =
9216         aMesh->AddPolyhedralVolume(poly_nodes, quantities);
9217       myLastCreatedElems.Append(newElem);
9218       if (aShapeId && newElem)
9219         aMesh->SetMeshElementOnShape(newElem, aShapeId);
9220
9221       aMesh->RemoveElement(elem);
9222     }
9223   }
9224 }
9225
9226 //=======================================================================
9227 /*!
9228  * \brief Convert elements contained in a submesh to quadratic
9229  * \return int - nb of checked elements
9230  */
9231 //=======================================================================
9232
9233 int SMESH_MeshEditor::convertElemToQuadratic(SMESHDS_SubMesh *   theSm,
9234                                              SMESH_MesherHelper& theHelper,
9235                                              const bool          theForce3d)
9236 {
9237   int nbElem = 0;
9238   if( !theSm ) return nbElem;
9239
9240   vector<int> nbNodeInFaces;
9241   SMDS_ElemIteratorPtr ElemItr = theSm->GetElements();
9242   while(ElemItr->more())
9243   {
9244     nbElem++;
9245     const SMDS_MeshElement* elem = ElemItr->next();
9246     if( !elem || elem->IsQuadratic() ) continue;
9247
9248     int id = elem->GetID();
9249     int nbNodes = elem->NbNodes();
9250     SMDSAbs_ElementType aType = elem->GetType();
9251
9252     vector<const SMDS_MeshNode *> nodes (elem->begin_nodes(), elem->end_nodes());
9253     if ( elem->GetEntityType() == SMDSEntity_Polyhedra )
9254       nbNodeInFaces = static_cast<const SMDS_VtkVolume* >( elem )->GetQuantities();
9255
9256     GetMeshDS()->RemoveFreeElement(elem, theSm, /*fromGroups=*/false);
9257
9258     const SMDS_MeshElement* NewElem = 0;
9259
9260     switch( aType )
9261     {
9262     case SMDSAbs_Edge :
9263       {
9264         NewElem = theHelper.AddEdge(nodes[0], nodes[1], id, theForce3d);
9265         break;
9266       }
9267     case SMDSAbs_Face :
9268       {
9269         switch(nbNodes)
9270         {
9271         case 3:
9272           NewElem = theHelper.AddFace(nodes[0], nodes[1], nodes[2], id, theForce3d);
9273           break;
9274         case 4:
9275           NewElem = theHelper.AddFace(nodes[0], nodes[1], nodes[2], nodes[3], id, theForce3d);
9276           break;
9277         default:
9278           NewElem = theHelper.AddPolygonalFace(nodes, id, theForce3d);
9279           continue;
9280         }
9281         break;
9282       }
9283     case SMDSAbs_Volume :
9284       {
9285         switch(nbNodes)
9286         {
9287         case 4:
9288           NewElem = theHelper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3], id, theForce3d);
9289           break;
9290         case 5:
9291           NewElem = theHelper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3], nodes[4], id, theForce3d);
9292           break;
9293         case 6:
9294           NewElem = theHelper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3], nodes[4], nodes[5], id, theForce3d);
9295           break;
9296         case 8:
9297           NewElem = theHelper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3],
9298                                         nodes[4], nodes[5], nodes[6], nodes[7], id, theForce3d);
9299           break;
9300         default:
9301           NewElem = theHelper.AddPolyhedralVolume(nodes, nbNodeInFaces, id, theForce3d);
9302         }
9303         break;
9304       }
9305     default :
9306       continue;
9307     }
9308     ReplaceElemInGroups( elem, NewElem, GetMeshDS());
9309     if( NewElem )
9310       theSm->AddElement( NewElem );
9311   }
9312 //  if (!GetMeshDS()->isCompacted())
9313 //    GetMeshDS()->compactMesh();
9314   return nbElem;
9315 }
9316
9317 //=======================================================================
9318 //function : ConvertToQuadratic
9319 //purpose  :
9320 //=======================================================================
9321 void SMESH_MeshEditor::ConvertToQuadratic(const bool theForce3d)
9322 {
9323   SMESHDS_Mesh* meshDS = GetMeshDS();
9324
9325   SMESH_MesherHelper aHelper(*myMesh);
9326   aHelper.SetIsQuadratic( true );
9327
9328   int nbCheckedElems = 0;
9329   if ( myMesh->HasShapeToMesh() )
9330   {
9331     if ( SMESH_subMesh *aSubMesh = myMesh->GetSubMeshContaining(myMesh->GetShapeToMesh()))
9332     {
9333       SMESH_subMeshIteratorPtr smIt = aSubMesh->getDependsOnIterator(true,false);
9334       while ( smIt->more() ) {
9335         SMESH_subMesh* sm = smIt->next();
9336         if ( SMESHDS_SubMesh *smDS = sm->GetSubMeshDS() ) {
9337           aHelper.SetSubShape( sm->GetSubShape() );
9338           nbCheckedElems += convertElemToQuadratic(smDS, aHelper, theForce3d);
9339         }
9340       }
9341     }
9342   }
9343   int totalNbElems = meshDS->NbEdges() + meshDS->NbFaces() + meshDS->NbVolumes();
9344   if ( nbCheckedElems < totalNbElems ) // not all elements are in submeshes
9345   {
9346     SMESHDS_SubMesh *smDS = 0;
9347     SMDS_EdgeIteratorPtr aEdgeItr = meshDS->edgesIterator();
9348     while(aEdgeItr->more())
9349     {
9350       const SMDS_MeshEdge* edge = aEdgeItr->next();
9351       if(edge && !edge->IsQuadratic())
9352       {
9353         int id = edge->GetID();
9354         //MESSAGE("edge->GetID() " << id);
9355         const SMDS_MeshNode* n1 = edge->GetNode(0);
9356         const SMDS_MeshNode* n2 = edge->GetNode(1);
9357
9358         meshDS->RemoveFreeElement(edge, smDS, /*fromGroups=*/false);
9359
9360         const SMDS_MeshEdge* NewEdge = aHelper.AddEdge(n1, n2, id, theForce3d);
9361         ReplaceElemInGroups( edge, NewEdge, GetMeshDS());
9362       }
9363     }
9364     SMDS_FaceIteratorPtr aFaceItr = meshDS->facesIterator();
9365     while(aFaceItr->more())
9366     {
9367       const SMDS_MeshFace* face = aFaceItr->next();
9368       if(!face || face->IsQuadratic() ) continue;
9369
9370       int id = face->GetID();
9371       int nbNodes = face->NbNodes();
9372       vector<const SMDS_MeshNode *> nodes ( face->begin_nodes(), face->end_nodes());
9373
9374       meshDS->RemoveFreeElement(face, smDS, /*fromGroups=*/false);
9375
9376       SMDS_MeshFace * NewFace = 0;
9377       switch(nbNodes)
9378       {
9379       case 3:
9380         NewFace = aHelper.AddFace(nodes[0], nodes[1], nodes[2], id, theForce3d);
9381         break;
9382       case 4:
9383         NewFace = aHelper.AddFace(nodes[0], nodes[1], nodes[2], nodes[3], id, theForce3d);
9384         break;
9385       default:
9386         NewFace = aHelper.AddPolygonalFace(nodes, id, theForce3d);
9387       }
9388       ReplaceElemInGroups( face, NewFace, GetMeshDS());
9389     }
9390     vector<int> nbNodeInFaces;
9391     SMDS_VolumeIteratorPtr aVolumeItr = meshDS->volumesIterator();
9392     while(aVolumeItr->more())
9393     {
9394       const SMDS_MeshVolume* volume = aVolumeItr->next();
9395       if(!volume || volume->IsQuadratic() ) continue;
9396
9397       int id = volume->GetID();
9398       int nbNodes = volume->NbNodes();
9399       vector<const SMDS_MeshNode *> nodes (volume->begin_nodes(), volume->end_nodes());
9400       if ( volume->GetEntityType() == SMDSEntity_Polyhedra )
9401         nbNodeInFaces = static_cast<const SMDS_VtkVolume* >(volume)->GetQuantities();
9402
9403       meshDS->RemoveFreeElement(volume, smDS, /*fromGroups=*/false);
9404
9405       SMDS_MeshVolume * NewVolume = 0;
9406       switch(nbNodes)
9407       {
9408       case 4:
9409         NewVolume = aHelper.AddVolume(nodes[0], nodes[1], nodes[2],
9410                                       nodes[3], id, theForce3d );
9411         break;
9412       case 5:
9413         NewVolume = aHelper.AddVolume(nodes[0], nodes[1], nodes[2],
9414                                       nodes[3], nodes[4], id, theForce3d);
9415         break;
9416       case 6:
9417         NewVolume = aHelper.AddVolume(nodes[0], nodes[1], nodes[2],
9418                                       nodes[3], nodes[4], nodes[5], id, theForce3d);
9419         break;
9420       case 8:
9421         NewVolume = aHelper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3],
9422                                       nodes[4], nodes[5], nodes[6], nodes[7], id, theForce3d);
9423         break;
9424       default:
9425         NewVolume = aHelper.AddPolyhedralVolume(nodes, nbNodeInFaces, id, theForce3d);
9426       }
9427       ReplaceElemInGroups(volume, NewVolume, meshDS);
9428     }
9429   }
9430
9431   if ( !theForce3d )
9432   { // setenv NO_FixQuadraticElements to know if FixQuadraticElements() is guilty of bad conversion
9433     aHelper.SetSubShape(0); // apply FixQuadraticElements() to the whole mesh
9434     aHelper.FixQuadraticElements();
9435   }
9436 }
9437
9438 //================================================================================
9439 /*!
9440  * \brief Makes given elements quadratic
9441  *  \param theForce3d - if true, the medium nodes will be placed in the middle of link
9442  *  \param theElements - elements to make quadratic 
9443  */
9444 //================================================================================
9445
9446 void SMESH_MeshEditor::ConvertToQuadratic(const bool        theForce3d,
9447                                           TIDSortedElemSet& theElements)
9448 {
9449   if ( theElements.empty() ) return;
9450
9451   // we believe that all theElements are of the same type
9452   SMDSAbs_ElementType elemType = (*theElements.begin())->GetType();
9453   
9454   // get all nodes shared by theElements
9455   TIDSortedNodeSet allNodes;
9456   TIDSortedElemSet::iterator eIt = theElements.begin();
9457   for ( ; eIt != theElements.end(); ++eIt )
9458     allNodes.insert( (*eIt)->begin_nodes(), (*eIt)->end_nodes() );
9459
9460   // complete theElements with elements of lower dim whose all nodes are in allNodes
9461
9462   TIDSortedElemSet quadAdjacentElems    [ SMDSAbs_NbElementTypes ]; // quadratic adjacent elements
9463   TIDSortedElemSet checkedAdjacentElems [ SMDSAbs_NbElementTypes ];
9464   TIDSortedNodeSet::iterator nIt = allNodes.begin();
9465   for ( ; nIt != allNodes.end(); ++nIt )
9466   {
9467     const SMDS_MeshNode* n = *nIt;
9468     SMDS_ElemIteratorPtr invIt = n->GetInverseElementIterator();
9469     while ( invIt->more() )
9470     {
9471       const SMDS_MeshElement* e = invIt->next();
9472       if ( e->IsQuadratic() )
9473       {
9474         quadAdjacentElems[ e->GetType() ].insert( e );
9475         continue;
9476       }
9477       if ( e->GetType() >= elemType )
9478       {
9479         continue; // same type of more complex linear element
9480       }
9481
9482       if ( !checkedAdjacentElems[ e->GetType() ].insert( e ).second )
9483         continue; // e is already checked
9484
9485       // check nodes
9486       bool allIn = true;
9487       SMDS_ElemIteratorPtr nodeIt = e->nodesIterator();
9488       while ( nodeIt->more() && allIn )
9489         allIn = allNodes.count( cast2Node( nodeIt->next() ));
9490       if ( allIn )
9491         theElements.insert(e );
9492     }
9493   }
9494
9495   SMESH_MesherHelper helper(*myMesh);
9496   helper.SetIsQuadratic( true );
9497
9498   // add links of quadratic adjacent elements to the helper
9499
9500   if ( !quadAdjacentElems[SMDSAbs_Edge].empty() )
9501     for ( eIt  = quadAdjacentElems[SMDSAbs_Edge].begin();
9502           eIt != quadAdjacentElems[SMDSAbs_Edge].end(); ++eIt )
9503     {
9504       helper.AddTLinks( static_cast< const SMDS_MeshEdge*> (*eIt) );
9505     }
9506   if ( !quadAdjacentElems[SMDSAbs_Face].empty() )
9507     for ( eIt  = quadAdjacentElems[SMDSAbs_Face].begin();
9508           eIt != quadAdjacentElems[SMDSAbs_Face].end(); ++eIt )
9509     {
9510       helper.AddTLinks( static_cast< const SMDS_MeshFace*> (*eIt) );
9511     }
9512   if ( !quadAdjacentElems[SMDSAbs_Volume].empty() )
9513     for ( eIt  = quadAdjacentElems[SMDSAbs_Volume].begin();
9514           eIt != quadAdjacentElems[SMDSAbs_Volume].end(); ++eIt )
9515     {
9516       helper.AddTLinks( static_cast< const SMDS_MeshVolume*> (*eIt) );
9517     }
9518
9519   // make quadratic elements instead of linear ones
9520
9521   SMESHDS_Mesh* meshDS = GetMeshDS();
9522   SMESHDS_SubMesh* smDS = 0;
9523   for ( eIt = theElements.begin(); eIt != theElements.end(); ++eIt )
9524   {
9525     const SMDS_MeshElement* elem = *eIt;
9526     if( elem->IsQuadratic() || elem->NbNodes() < 2 || elem->IsPoly() )
9527       continue;
9528
9529     int id = elem->GetID();
9530     SMDSAbs_ElementType type = elem->GetType();
9531     vector<const SMDS_MeshNode *> nodes ( elem->begin_nodes(), elem->end_nodes());
9532
9533     if ( !smDS || !smDS->Contains( elem ))
9534       smDS = meshDS->MeshElements( elem->getshapeId() );
9535     meshDS->RemoveFreeElement(elem, smDS, /*fromGroups=*/false);
9536
9537     SMDS_MeshElement * newElem = 0;
9538     switch( nodes.size() )
9539     {
9540     case 4: // cases for most multiple element types go first (for optimization)
9541       if ( type == SMDSAbs_Volume )
9542         newElem = helper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3], id, theForce3d);
9543       else
9544         newElem = helper.AddFace  (nodes[0], nodes[1], nodes[2], nodes[3], id, theForce3d);
9545       break;
9546     case 8:
9547       newElem = helper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3],
9548                                  nodes[4], nodes[5], nodes[6], nodes[7], id, theForce3d);
9549       break;
9550     case 3:
9551       newElem = helper.AddFace  (nodes[0], nodes[1], nodes[2], id, theForce3d);
9552       break;
9553     case 2:
9554       newElem = helper.AddEdge(nodes[0], nodes[1], id, theForce3d);
9555       break;
9556     case 5:
9557       newElem = helper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3],
9558                                  nodes[4], id, theForce3d);
9559       break;
9560     case 6:
9561       newElem = helper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3],
9562                                  nodes[4], nodes[5], id, theForce3d);
9563       break;
9564     default:;
9565     }
9566     ReplaceElemInGroups( elem, newElem, meshDS);
9567     if( newElem && smDS )
9568       smDS->AddElement( newElem );
9569   }
9570
9571   if ( !theForce3d  && !getenv("NO_FixQuadraticElements"))
9572   { // setenv NO_FixQuadraticElements to know if FixQuadraticElements() is guilty of bad conversion
9573     helper.SetSubShape(0); // apply FixQuadraticElements() to the whole mesh
9574     helper.FixQuadraticElements();
9575   }
9576 }
9577
9578 //=======================================================================
9579 /*!
9580  * \brief Convert quadratic elements to linear ones and remove quadratic nodes
9581  * \return int - nb of checked elements
9582  */
9583 //=======================================================================
9584
9585 int SMESH_MeshEditor::removeQuadElem(SMESHDS_SubMesh *    theSm,
9586                                      SMDS_ElemIteratorPtr theItr,
9587                                      const int            theShapeID)
9588 {
9589   int nbElem = 0;
9590   SMESHDS_Mesh* meshDS = GetMeshDS();
9591
9592   while( theItr->more() )
9593   {
9594     const SMDS_MeshElement* elem = theItr->next();
9595     nbElem++;
9596     if( elem && elem->IsQuadratic())
9597     {
9598       int id                    = elem->GetID();
9599       int nbCornerNodes         = elem->NbCornerNodes();
9600       SMDSAbs_ElementType aType = elem->GetType();
9601
9602       vector<const SMDS_MeshNode *> nodes( elem->begin_nodes(), elem->end_nodes() );
9603
9604       //remove a quadratic element
9605       if ( !theSm || !theSm->Contains( elem ))
9606         theSm = meshDS->MeshElements( elem->getshapeId() );
9607       meshDS->RemoveFreeElement( elem, theSm, /*fromGroups=*/false );
9608
9609       // remove medium nodes
9610       for ( unsigned i = nbCornerNodes; i < nodes.size(); ++i )
9611         if ( nodes[i]->NbInverseElements() == 0 )
9612           meshDS->RemoveFreeNode( nodes[i], theSm );
9613
9614       // add a linear element
9615       nodes.resize( nbCornerNodes );
9616       SMDS_MeshElement * newElem = AddElement( nodes, aType, false, id );
9617       ReplaceElemInGroups(elem, newElem, meshDS);
9618       if( theSm && newElem )
9619         theSm->AddElement( newElem );
9620     }
9621   }
9622   return nbElem;
9623 }
9624
9625 //=======================================================================
9626 //function : ConvertFromQuadratic
9627 //purpose  :
9628 //=======================================================================
9629
9630 bool SMESH_MeshEditor::ConvertFromQuadratic()
9631 {
9632   int nbCheckedElems = 0;
9633   if ( myMesh->HasShapeToMesh() )
9634   {
9635     if ( SMESH_subMesh *aSubMesh = myMesh->GetSubMeshContaining(myMesh->GetShapeToMesh()))
9636     {
9637       SMESH_subMeshIteratorPtr smIt = aSubMesh->getDependsOnIterator(true,false);
9638       while ( smIt->more() ) {
9639         SMESH_subMesh* sm = smIt->next();
9640         if ( SMESHDS_SubMesh *smDS = sm->GetSubMeshDS() )
9641           nbCheckedElems += removeQuadElem( smDS, smDS->GetElements(), sm->GetId() );
9642       }
9643     }
9644   }
9645
9646   int totalNbElems =
9647     GetMeshDS()->NbEdges() + GetMeshDS()->NbFaces() + GetMeshDS()->NbVolumes();
9648   if ( nbCheckedElems < totalNbElems ) // not all elements are in submeshes
9649   {
9650     SMESHDS_SubMesh *aSM = 0;
9651     removeQuadElem( aSM, GetMeshDS()->elementsIterator(), 0 );
9652   }
9653
9654   return true;
9655 }
9656
9657 namespace
9658 {
9659   //================================================================================
9660   /*!
9661    * \brief Return true if all medium nodes of the element are in the node set
9662    */
9663   //================================================================================
9664
9665   bool allMediumNodesIn(const SMDS_MeshElement* elem, TIDSortedNodeSet& nodeSet )
9666   {
9667     for ( int i = elem->NbCornerNodes(); i < elem->NbNodes(); ++i )
9668       if ( !nodeSet.count( elem->GetNode(i) ))
9669         return false;
9670     return true;
9671   }
9672 }
9673
9674 //================================================================================
9675 /*!
9676  * \brief Makes given elements linear
9677  */
9678 //================================================================================
9679
9680 void SMESH_MeshEditor::ConvertFromQuadratic(TIDSortedElemSet& theElements)
9681 {
9682   if ( theElements.empty() ) return;
9683
9684   // collect IDs of medium nodes of theElements; some of these nodes will be removed
9685   set<int> mediumNodeIDs;
9686   TIDSortedElemSet::iterator eIt = theElements.begin();
9687   for ( ; eIt != theElements.end(); ++eIt )
9688   {
9689     const SMDS_MeshElement* e = *eIt;
9690     for ( int i = e->NbCornerNodes(); i < e->NbNodes(); ++i )
9691       mediumNodeIDs.insert( e->GetNode(i)->GetID() );
9692   }
9693
9694   // replace given elements by linear ones
9695   typedef SMDS_SetIterator<const SMDS_MeshElement*, TIDSortedElemSet::iterator> TSetIterator;
9696   SMDS_ElemIteratorPtr elemIt( new TSetIterator( theElements.begin(), theElements.end() ));
9697   removeQuadElem( /*theSm=*/0, elemIt, /*theShapeID=*/0 );
9698
9699   // we need to convert remaining elements whose all medium nodes are in mediumNodeIDs
9700   // except those elements sharing medium nodes of quadratic element whose medium nodes
9701   // are not all in mediumNodeIDs
9702
9703   // get remaining medium nodes
9704   TIDSortedNodeSet mediumNodes;
9705   set<int>::iterator nIdsIt = mediumNodeIDs.begin();
9706   for ( ; nIdsIt != mediumNodeIDs.end(); ++nIdsIt )
9707     if ( const SMDS_MeshNode* n = GetMeshDS()->FindNode( *nIdsIt ))
9708       mediumNodes.insert( mediumNodes.end(), n );
9709
9710   // find more quadratic elements to convert
9711   TIDSortedElemSet moreElemsToConvert;
9712   TIDSortedNodeSet::iterator nIt = mediumNodes.begin();
9713   for ( ; nIt != mediumNodes.end(); ++nIt )
9714   {
9715     SMDS_ElemIteratorPtr invIt = (*nIt)->GetInverseElementIterator();
9716     while ( invIt->more() )
9717     {
9718       const SMDS_MeshElement* e = invIt->next();
9719       if ( e->IsQuadratic() && allMediumNodesIn( e, mediumNodes ))
9720       {
9721         // find a more complex element including e and
9722         // whose medium nodes are not in mediumNodes
9723         bool complexFound = false;
9724         for ( int type = e->GetType() + 1; type < SMDSAbs_0DElement; ++type )
9725         {
9726           SMDS_ElemIteratorPtr invIt2 =
9727             (*nIt)->GetInverseElementIterator( SMDSAbs_ElementType( type ));
9728           while ( invIt2->more() )
9729           {
9730             const SMDS_MeshElement* eComplex = invIt2->next();
9731             if ( eComplex->IsQuadratic() && !allMediumNodesIn( eComplex, mediumNodes))
9732             {
9733               int nbCommonNodes = SMESH_Algo::GetCommonNodes( e, eComplex ).size();
9734               if ( nbCommonNodes == e->NbNodes())
9735               {
9736                 complexFound = true;
9737                 type = SMDSAbs_NbElementTypes; // to quit from the outer loop
9738                 break;
9739               }
9740             }
9741           }
9742         }
9743         if ( !complexFound )
9744           moreElemsToConvert.insert( e );
9745       }
9746     }
9747   }
9748   elemIt = SMDS_ElemIteratorPtr
9749     (new TSetIterator( moreElemsToConvert.begin(), moreElemsToConvert.end() ));
9750   removeQuadElem( /*theSm=*/0, elemIt, /*theShapeID=*/0 );
9751 }
9752
9753 //=======================================================================
9754 //function : SewSideElements
9755 //purpose  :
9756 //=======================================================================
9757
9758 SMESH_MeshEditor::Sew_Error
9759 SMESH_MeshEditor::SewSideElements (TIDSortedElemSet&    theSide1,
9760                                    TIDSortedElemSet&    theSide2,
9761                                    const SMDS_MeshNode* theFirstNode1,
9762                                    const SMDS_MeshNode* theFirstNode2,
9763                                    const SMDS_MeshNode* theSecondNode1,
9764                                    const SMDS_MeshNode* theSecondNode2)
9765 {
9766   myLastCreatedElems.Clear();
9767   myLastCreatedNodes.Clear();
9768
9769   MESSAGE ("::::SewSideElements()");
9770   if ( theSide1.size() != theSide2.size() )
9771     return SEW_DIFF_NB_OF_ELEMENTS;
9772
9773   Sew_Error aResult = SEW_OK;
9774   // Algo:
9775   // 1. Build set of faces representing each side
9776   // 2. Find which nodes of the side 1 to merge with ones on the side 2
9777   // 3. Replace nodes in elements of the side 1 and remove replaced nodes
9778
9779   // =======================================================================
9780   // 1. Build set of faces representing each side:
9781   // =======================================================================
9782   // a. build set of nodes belonging to faces
9783   // b. complete set of faces: find missing faces whose nodes are in set of nodes
9784   // c. create temporary faces representing side of volumes if correspondent
9785   //    face does not exist
9786
9787   SMESHDS_Mesh* aMesh = GetMeshDS();
9788   // TODO algoritm not OK with vtkUnstructuredGrid: 2 meshes can't share nodes
9789   //SMDS_Mesh aTmpFacesMesh; // try to use the same mesh
9790   set<const SMDS_MeshElement*> faceSet1, faceSet2;
9791   set<const SMDS_MeshElement*> volSet1,  volSet2;
9792   set<const SMDS_MeshNode*>    nodeSet1, nodeSet2;
9793   set<const SMDS_MeshElement*> * faceSetPtr[] = { &faceSet1, &faceSet2 };
9794   set<const SMDS_MeshElement*>  * volSetPtr[] = { &volSet1,  &volSet2  };
9795   set<const SMDS_MeshNode*>    * nodeSetPtr[] = { &nodeSet1, &nodeSet2 };
9796   TIDSortedElemSet * elemSetPtr[] = { &theSide1, &theSide2 };
9797   int iSide, iFace, iNode;
9798
9799   list<const SMDS_MeshElement* > tempFaceList;
9800   for ( iSide = 0; iSide < 2; iSide++ ) {
9801     set<const SMDS_MeshNode*>    * nodeSet = nodeSetPtr[ iSide ];
9802     TIDSortedElemSet * elemSet = elemSetPtr[ iSide ];
9803     set<const SMDS_MeshElement*> * faceSet = faceSetPtr[ iSide ];
9804     set<const SMDS_MeshElement*> * volSet  = volSetPtr [ iSide ];
9805     set<const SMDS_MeshElement*>::iterator vIt;
9806     TIDSortedElemSet::iterator eIt;
9807     set<const SMDS_MeshNode*>::iterator    nIt;
9808
9809     // check that given nodes belong to given elements
9810     const SMDS_MeshNode* n1 = ( iSide == 0 ) ? theFirstNode1 : theFirstNode2;
9811     const SMDS_MeshNode* n2 = ( iSide == 0 ) ? theSecondNode1 : theSecondNode2;
9812     int firstIndex = -1, secondIndex = -1;
9813     for (eIt = elemSet->begin(); eIt != elemSet->end(); eIt++ ) {
9814       const SMDS_MeshElement* elem = *eIt;
9815       if ( firstIndex  < 0 ) firstIndex  = elem->GetNodeIndex( n1 );
9816       if ( secondIndex < 0 ) secondIndex = elem->GetNodeIndex( n2 );
9817       if ( firstIndex > -1 && secondIndex > -1 ) break;
9818     }
9819     if ( firstIndex < 0 || secondIndex < 0 ) {
9820       // we can simply return until temporary faces created
9821       return (iSide == 0 ) ? SEW_BAD_SIDE1_NODES : SEW_BAD_SIDE2_NODES;
9822     }
9823
9824     // -----------------------------------------------------------
9825     // 1a. Collect nodes of existing faces
9826     //     and build set of face nodes in order to detect missing
9827     //     faces corresponding to sides of volumes
9828     // -----------------------------------------------------------
9829
9830     set< set <const SMDS_MeshNode*> > setOfFaceNodeSet;
9831
9832     // loop on the given element of a side
9833     for (eIt = elemSet->begin(); eIt != elemSet->end(); eIt++ ) {
9834       //const SMDS_MeshElement* elem = *eIt;
9835       const SMDS_MeshElement* elem = *eIt;
9836       if ( elem->GetType() == SMDSAbs_Face ) {
9837         faceSet->insert( elem );
9838         set <const SMDS_MeshNode*> faceNodeSet;
9839         SMDS_ElemIteratorPtr nodeIt = elem->nodesIterator();
9840         while ( nodeIt->more() ) {
9841           const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
9842           nodeSet->insert( n );
9843           faceNodeSet.insert( n );
9844         }
9845         setOfFaceNodeSet.insert( faceNodeSet );
9846       }
9847       else if ( elem->GetType() == SMDSAbs_Volume )
9848         volSet->insert( elem );
9849     }
9850     // ------------------------------------------------------------------------------
9851     // 1b. Complete set of faces: find missing faces whose nodes are in set of nodes
9852     // ------------------------------------------------------------------------------
9853
9854     for ( nIt = nodeSet->begin(); nIt != nodeSet->end(); nIt++ ) { // loop on nodes of iSide
9855       SMDS_ElemIteratorPtr fIt = (*nIt)->GetInverseElementIterator(SMDSAbs_Face);
9856       while ( fIt->more() ) { // loop on faces sharing a node
9857         const SMDS_MeshElement* f = fIt->next();
9858         if ( faceSet->find( f ) == faceSet->end() ) {
9859           // check if all nodes are in nodeSet and
9860           // complete setOfFaceNodeSet if they are
9861           set <const SMDS_MeshNode*> faceNodeSet;
9862           SMDS_ElemIteratorPtr nodeIt = f->nodesIterator();
9863           bool allInSet = true;
9864           while ( nodeIt->more() && allInSet ) { // loop on nodes of a face
9865             const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
9866             if ( nodeSet->find( n ) == nodeSet->end() )
9867               allInSet = false;
9868             else
9869               faceNodeSet.insert( n );
9870           }
9871           if ( allInSet ) {
9872             faceSet->insert( f );
9873             setOfFaceNodeSet.insert( faceNodeSet );
9874           }
9875         }
9876       }
9877     }
9878
9879     // -------------------------------------------------------------------------
9880     // 1c. Create temporary faces representing sides of volumes if correspondent
9881     //     face does not exist
9882     // -------------------------------------------------------------------------
9883
9884     if ( !volSet->empty() ) {
9885       //int nodeSetSize = nodeSet->size();
9886
9887       // loop on given volumes
9888       for ( vIt = volSet->begin(); vIt != volSet->end(); vIt++ ) {
9889         SMDS_VolumeTool vol (*vIt);
9890         // loop on volume faces: find free faces
9891         // --------------------------------------
9892         list<const SMDS_MeshElement* > freeFaceList;
9893         for ( iFace = 0; iFace < vol.NbFaces(); iFace++ ) {
9894           if ( !vol.IsFreeFace( iFace ))
9895             continue;
9896           // check if there is already a face with same nodes in a face set
9897           const SMDS_MeshElement* aFreeFace = 0;
9898           const SMDS_MeshNode** fNodes = vol.GetFaceNodes( iFace );
9899           int nbNodes = vol.NbFaceNodes( iFace );
9900           set <const SMDS_MeshNode*> faceNodeSet;
9901           vol.GetFaceNodes( iFace, faceNodeSet );
9902           bool isNewFace = setOfFaceNodeSet.insert( faceNodeSet ).second;
9903           if ( isNewFace ) {
9904             // no such a face is given but it still can exist, check it
9905             if ( nbNodes == 3 ) {
9906               aFreeFace = aMesh->FindFace( fNodes[0],fNodes[1],fNodes[2] );
9907             }
9908             else if ( nbNodes == 4 ) {
9909               aFreeFace = aMesh->FindFace( fNodes[0],fNodes[1],fNodes[2],fNodes[3] );
9910             }
9911             else {
9912               vector<const SMDS_MeshNode *> poly_nodes ( fNodes, & fNodes[nbNodes]);
9913               aFreeFace = aMesh->FindFace(poly_nodes);
9914             }
9915           }
9916           if ( !aFreeFace ) {
9917             // create a temporary face
9918             if ( nbNodes == 3 ) {
9919               //aFreeFace = aTmpFacesMesh.AddFace( fNodes[0],fNodes[1],fNodes[2] );
9920               aFreeFace = aMesh->AddFace( fNodes[0],fNodes[1],fNodes[2] );
9921             }
9922             else if ( nbNodes == 4 ) {
9923               //aFreeFace = aTmpFacesMesh.AddFace( fNodes[0],fNodes[1],fNodes[2],fNodes[3] );
9924               aFreeFace = aMesh->AddFace( fNodes[0],fNodes[1],fNodes[2],fNodes[3] );
9925             }
9926             else {
9927               vector<const SMDS_MeshNode *> poly_nodes ( fNodes, & fNodes[nbNodes]);
9928               //aFreeFace = aTmpFacesMesh.AddPolygonalFace(poly_nodes);
9929               aFreeFace = aMesh->AddPolygonalFace(poly_nodes);
9930             }
9931           }
9932           if ( aFreeFace ) {
9933             freeFaceList.push_back( aFreeFace );
9934             tempFaceList.push_back( aFreeFace );
9935           }
9936
9937         } // loop on faces of a volume
9938
9939         // choose one of several free faces
9940         // --------------------------------------
9941         if ( freeFaceList.size() > 1 ) {
9942           // choose a face having max nb of nodes shared by other elems of a side
9943           int maxNbNodes = -1/*, nbExcludedFaces = 0*/;
9944           list<const SMDS_MeshElement* >::iterator fIt = freeFaceList.begin();
9945           while ( fIt != freeFaceList.end() ) { // loop on free faces
9946             int nbSharedNodes = 0;
9947             SMDS_ElemIteratorPtr nodeIt = (*fIt)->nodesIterator();
9948             while ( nodeIt->more() ) { // loop on free face nodes
9949               const SMDS_MeshNode* n =
9950                 static_cast<const SMDS_MeshNode*>( nodeIt->next() );
9951               SMDS_ElemIteratorPtr invElemIt = n->GetInverseElementIterator();
9952               while ( invElemIt->more() ) {
9953                 const SMDS_MeshElement* e = invElemIt->next();
9954                 if ( faceSet->find( e ) != faceSet->end() )
9955                   nbSharedNodes++;
9956                 if ( elemSet->find( e ) != elemSet->end() )
9957                   nbSharedNodes++;
9958               }
9959             }
9960             if ( nbSharedNodes >= maxNbNodes ) {
9961               maxNbNodes = nbSharedNodes;
9962               fIt++;
9963             }
9964             else
9965               freeFaceList.erase( fIt++ ); // here fIt++ occurs before erase
9966           }
9967           if ( freeFaceList.size() > 1 )
9968           {
9969             // could not choose one face, use another way
9970             // choose a face most close to the bary center of the opposite side
9971             gp_XYZ aBC( 0., 0., 0. );
9972             set <const SMDS_MeshNode*> addedNodes;
9973             TIDSortedElemSet * elemSet2 = elemSetPtr[ 1 - iSide ];
9974             eIt = elemSet2->begin();
9975             for ( eIt = elemSet2->begin(); eIt != elemSet2->end(); eIt++ ) {
9976               SMDS_ElemIteratorPtr nodeIt = (*eIt)->nodesIterator();
9977               while ( nodeIt->more() ) { // loop on free face nodes
9978                 const SMDS_MeshNode* n =
9979                   static_cast<const SMDS_MeshNode*>( nodeIt->next() );
9980                 if ( addedNodes.insert( n ).second )
9981                   aBC += gp_XYZ( n->X(),n->Y(),n->Z() );
9982               }
9983             }
9984             aBC /= addedNodes.size();
9985             double minDist = DBL_MAX;
9986             fIt = freeFaceList.begin();
9987             while ( fIt != freeFaceList.end() ) { // loop on free faces
9988               double dist = 0;
9989               SMDS_ElemIteratorPtr nodeIt = (*fIt)->nodesIterator();
9990               while ( nodeIt->more() ) { // loop on free face nodes
9991                 const SMDS_MeshNode* n =
9992                   static_cast<const SMDS_MeshNode*>( nodeIt->next() );
9993                 gp_XYZ p( n->X(),n->Y(),n->Z() );
9994                 dist += ( aBC - p ).SquareModulus();
9995               }
9996               if ( dist < minDist ) {
9997                 minDist = dist;
9998                 freeFaceList.erase( freeFaceList.begin(), fIt++ );
9999               }
10000               else
10001                 fIt = freeFaceList.erase( fIt++ );
10002             }
10003           }
10004         } // choose one of several free faces of a volume
10005
10006         if ( freeFaceList.size() == 1 ) {
10007           const SMDS_MeshElement* aFreeFace = freeFaceList.front();
10008           faceSet->insert( aFreeFace );
10009           // complete a node set with nodes of a found free face
10010           //           for ( iNode = 0; iNode < ; iNode++ )
10011           //             nodeSet->insert( fNodes[ iNode ] );
10012         }
10013
10014       } // loop on volumes of a side
10015
10016       //       // complete a set of faces if new nodes in a nodeSet appeared
10017       //       // ----------------------------------------------------------
10018       //       if ( nodeSetSize != nodeSet->size() ) {
10019       //         for ( ; nIt != nodeSet->end(); nIt++ ) { // loop on nodes of iSide
10020       //           SMDS_ElemIteratorPtr fIt = (*nIt)->GetInverseElementIterator(SMDSAbs_Face);
10021       //           while ( fIt->more() ) { // loop on faces sharing a node
10022       //             const SMDS_MeshElement* f = fIt->next();
10023       //             if ( faceSet->find( f ) == faceSet->end() ) {
10024       //               // check if all nodes are in nodeSet and
10025       //               // complete setOfFaceNodeSet if they are
10026       //               set <const SMDS_MeshNode*> faceNodeSet;
10027       //               SMDS_ElemIteratorPtr nodeIt = f->nodesIterator();
10028       //               bool allInSet = true;
10029       //               while ( nodeIt->more() && allInSet ) { // loop on nodes of a face
10030       //                 const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
10031       //                 if ( nodeSet->find( n ) == nodeSet->end() )
10032       //                   allInSet = false;
10033       //                 else
10034       //                   faceNodeSet.insert( n );
10035       //               }
10036       //               if ( allInSet ) {
10037       //                 faceSet->insert( f );
10038       //                 setOfFaceNodeSet.insert( faceNodeSet );
10039       //               }
10040       //             }
10041       //           }
10042       //         }
10043       //       }
10044     } // Create temporary faces, if there are volumes given
10045   } // loop on sides
10046
10047   if ( faceSet1.size() != faceSet2.size() ) {
10048     // delete temporary faces: they are in reverseElements of actual nodes
10049 //    SMDS_FaceIteratorPtr tmpFaceIt = aTmpFacesMesh.facesIterator();
10050 //    while ( tmpFaceIt->more() )
10051 //      aTmpFacesMesh.RemoveElement( tmpFaceIt->next() );
10052 //    list<const SMDS_MeshElement* >::iterator tmpFaceIt = tempFaceList.begin();
10053 //    for (; tmpFaceIt !=tempFaceList.end(); ++tmpFaceIt)
10054 //      aMesh->RemoveElement(*tmpFaceIt);
10055     MESSAGE("Diff nb of faces");
10056     return SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
10057   }
10058
10059   // ============================================================
10060   // 2. Find nodes to merge:
10061   //              bind a node to remove to a node to put instead
10062   // ============================================================
10063
10064   TNodeNodeMap nReplaceMap; // bind a node to remove to a node to put instead
10065   if ( theFirstNode1 != theFirstNode2 )
10066     nReplaceMap.insert( TNodeNodeMap::value_type( theFirstNode1, theFirstNode2 ));
10067   if ( theSecondNode1 != theSecondNode2 )
10068     nReplaceMap.insert( TNodeNodeMap::value_type( theSecondNode1, theSecondNode2 ));
10069
10070   LinkID_Gen aLinkID_Gen( GetMeshDS() );
10071   set< long > linkIdSet; // links to process
10072   linkIdSet.insert( aLinkID_Gen.GetLinkID( theFirstNode1, theSecondNode1 ));
10073
10074   typedef pair< const SMDS_MeshNode*, const SMDS_MeshNode* > NLink;
10075   list< NLink > linkList[2];
10076   linkList[0].push_back( NLink( theFirstNode1, theSecondNode1 ));
10077   linkList[1].push_back( NLink( theFirstNode2, theSecondNode2 ));
10078   // loop on links in linkList; find faces by links and append links
10079   // of the found faces to linkList
10080   list< NLink >::iterator linkIt[] = { linkList[0].begin(), linkList[1].begin() } ;
10081   for ( ; linkIt[0] != linkList[0].end(); linkIt[0]++, linkIt[1]++ ) {
10082     NLink link[] = { *linkIt[0], *linkIt[1] };
10083     long linkID = aLinkID_Gen.GetLinkID( link[0].first, link[0].second );
10084     if ( linkIdSet.find( linkID ) == linkIdSet.end() )
10085       continue;
10086
10087     // by links, find faces in the face sets,
10088     // and find indices of link nodes in the found faces;
10089     // in a face set, there is only one or no face sharing a link
10090     // ---------------------------------------------------------------
10091
10092     const SMDS_MeshElement* face[] = { 0, 0 };
10093     //const SMDS_MeshNode* faceNodes[ 2 ][ 5 ];
10094     vector<const SMDS_MeshNode*> fnodes1(9);
10095     vector<const SMDS_MeshNode*> fnodes2(9);
10096     //const SMDS_MeshNode* notLinkNodes[ 2 ][ 2 ] = {{ 0, 0 },{ 0, 0 }} ;
10097     vector<const SMDS_MeshNode*> notLinkNodes1(6);
10098     vector<const SMDS_MeshNode*> notLinkNodes2(6);
10099     int iLinkNode[2][2];
10100     for ( iSide = 0; iSide < 2; iSide++ ) { // loop on 2 sides
10101       const SMDS_MeshNode* n1 = link[iSide].first;
10102       const SMDS_MeshNode* n2 = link[iSide].second;
10103       set<const SMDS_MeshElement*> * faceSet = faceSetPtr[ iSide ];
10104       set< const SMDS_MeshElement* > fMap;
10105       for ( int i = 0; i < 2; i++ ) { // loop on 2 nodes of a link
10106         const SMDS_MeshNode* n = i ? n1 : n2; // a node of a link
10107         SMDS_ElemIteratorPtr fIt = n->GetInverseElementIterator(SMDSAbs_Face);
10108         while ( fIt->more() ) { // loop on faces sharing a node
10109           const SMDS_MeshElement* f = fIt->next();
10110           if (faceSet->find( f ) != faceSet->end() && // f is in face set
10111               ! fMap.insert( f ).second ) // f encounters twice
10112           {
10113             if ( face[ iSide ] ) {
10114               MESSAGE( "2 faces per link " );
10115               aResult = iSide ? SEW_BAD_SIDE2_NODES : SEW_BAD_SIDE1_NODES;
10116               break;
10117             }
10118             face[ iSide ] = f;
10119             faceSet->erase( f );
10120             // get face nodes and find ones of a link
10121             iNode = 0;
10122             int nbl = -1;
10123             if(f->IsPoly()) {
10124               if(iSide==0) {
10125                 fnodes1.resize(f->NbNodes()+1);
10126                 notLinkNodes1.resize(f->NbNodes()-2);
10127               }
10128               else {
10129                 fnodes2.resize(f->NbNodes()+1);
10130                 notLinkNodes2.resize(f->NbNodes()-2);
10131               }
10132             }
10133             if(!f->IsQuadratic()) {
10134               SMDS_ElemIteratorPtr nIt = f->nodesIterator();
10135               while ( nIt->more() ) {
10136                 const SMDS_MeshNode* n =
10137                   static_cast<const SMDS_MeshNode*>( nIt->next() );
10138                 if ( n == n1 ) {
10139                   iLinkNode[ iSide ][ 0 ] = iNode;
10140                 }
10141                 else if ( n == n2 ) {
10142                   iLinkNode[ iSide ][ 1 ] = iNode;
10143                 }
10144                 //else if ( notLinkNodes[ iSide ][ 0 ] )
10145                 //  notLinkNodes[ iSide ][ 1 ] = n;
10146                 //else
10147                 //  notLinkNodes[ iSide ][ 0 ] = n;
10148                 else {
10149                   nbl++;
10150                   if(iSide==0)
10151                     notLinkNodes1[nbl] = n;
10152                   //notLinkNodes1.push_back(n);
10153                   else
10154                     notLinkNodes2[nbl] = n;
10155                   //notLinkNodes2.push_back(n);
10156                 }
10157                 //faceNodes[ iSide ][ iNode++ ] = n;
10158                 if(iSide==0) {
10159                   fnodes1[iNode++] = n;
10160                 }
10161                 else {
10162                   fnodes2[iNode++] = n;
10163                 }
10164               }
10165             }
10166             else { // f->IsQuadratic()
10167               const SMDS_VtkFace* F =
10168                 dynamic_cast<const SMDS_VtkFace*>(f);
10169               if (!F) throw SALOME_Exception(LOCALIZED("not an SMDS_VtkFace"));
10170               // use special nodes iterator
10171               SMDS_ElemIteratorPtr anIter = F->interlacedNodesElemIterator();
10172               while ( anIter->more() ) {
10173                 const SMDS_MeshNode* n =
10174                   static_cast<const SMDS_MeshNode*>( anIter->next() );
10175                 if ( n == n1 ) {
10176                   iLinkNode[ iSide ][ 0 ] = iNode;
10177                 }
10178                 else if ( n == n2 ) {
10179                   iLinkNode[ iSide ][ 1 ] = iNode;
10180                 }
10181                 else {
10182                   nbl++;
10183                   if(iSide==0) {
10184                     notLinkNodes1[nbl] = n;
10185                   }
10186                   else {
10187                     notLinkNodes2[nbl] = n;
10188                   }
10189                 }
10190                 if(iSide==0) {
10191                   fnodes1[iNode++] = n;
10192                 }
10193                 else {
10194                   fnodes2[iNode++] = n;
10195                 }
10196               }
10197             }
10198             //faceNodes[ iSide ][ iNode ] = faceNodes[ iSide ][ 0 ];
10199             if(iSide==0) {
10200               fnodes1[iNode] = fnodes1[0];
10201             }
10202             else {
10203               fnodes2[iNode] = fnodes1[0];
10204             }
10205           }
10206         }
10207       }
10208     }
10209
10210     // check similarity of elements of the sides
10211     if (aResult == SEW_OK && (( face[0] && !face[1] ) || ( !face[0] && face[1] ))) {
10212       MESSAGE("Correspondent face not found on side " << ( face[0] ? 1 : 0 ));
10213       if ( nReplaceMap.size() == 2 ) { // faces on input nodes not found
10214         aResult = ( face[0] ? SEW_BAD_SIDE2_NODES : SEW_BAD_SIDE1_NODES );
10215       }
10216       else {
10217         aResult = SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
10218       }
10219       break; // do not return because it s necessary to remove tmp faces
10220     }
10221
10222     // set nodes to merge
10223     // -------------------
10224
10225     if ( face[0] && face[1] )  {
10226       int nbNodes = face[0]->NbNodes();
10227       if ( nbNodes != face[1]->NbNodes() ) {
10228         MESSAGE("Diff nb of face nodes");
10229         aResult = SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
10230         break; // do not return because it s necessary to remove tmp faces
10231       }
10232       bool reverse[] = { false, false }; // order of notLinkNodes of quadrangle
10233       if ( nbNodes == 3 ) {
10234         //nReplaceMap.insert( TNodeNodeMap::value_type
10235         //                   ( notLinkNodes[0][0], notLinkNodes[1][0] ));
10236         nReplaceMap.insert( TNodeNodeMap::value_type
10237                             ( notLinkNodes1[0], notLinkNodes2[0] ));
10238       }
10239       else {
10240         for ( iSide = 0; iSide < 2; iSide++ ) { // loop on 2 sides
10241           // analyse link orientation in faces
10242           int i1 = iLinkNode[ iSide ][ 0 ];
10243           int i2 = iLinkNode[ iSide ][ 1 ];
10244           reverse[ iSide ] = Abs( i1 - i2 ) == 1 ? i1 > i2 : i2 > i1;
10245           // if notLinkNodes are the first and the last ones, then
10246           // their order does not correspond to the link orientation
10247           if (( i1 == 1 && i2 == 2 ) ||
10248               ( i1 == 2 && i2 == 1 ))
10249             reverse[ iSide ] = !reverse[ iSide ];
10250         }
10251         if ( reverse[0] == reverse[1] ) {
10252           //nReplaceMap.insert( TNodeNodeMap::value_type
10253           //                   ( notLinkNodes[0][0], notLinkNodes[1][0] ));
10254           //nReplaceMap.insert( TNodeNodeMap::value_type
10255           //                   ( notLinkNodes[0][1], notLinkNodes[1][1] ));
10256           for(int nn=0; nn<nbNodes-2; nn++) {
10257             nReplaceMap.insert( TNodeNodeMap::value_type
10258                                 ( notLinkNodes1[nn], notLinkNodes2[nn] ));
10259           }
10260         }
10261         else {
10262           //nReplaceMap.insert( TNodeNodeMap::value_type
10263           //                   ( notLinkNodes[0][0], notLinkNodes[1][1] ));
10264           //nReplaceMap.insert( TNodeNodeMap::value_type
10265           //                   ( notLinkNodes[0][1], notLinkNodes[1][0] ));
10266           for(int nn=0; nn<nbNodes-2; nn++) {
10267             nReplaceMap.insert( TNodeNodeMap::value_type
10268                                 ( notLinkNodes1[nn], notLinkNodes2[nbNodes-3-nn] ));
10269           }
10270         }
10271       }
10272
10273       // add other links of the faces to linkList
10274       // -----------------------------------------
10275
10276       //const SMDS_MeshNode** nodes = faceNodes[ 0 ];
10277       for ( iNode = 0; iNode < nbNodes; iNode++ )  {
10278         //linkID = aLinkID_Gen.GetLinkID( nodes[iNode], nodes[iNode+1] );
10279         linkID = aLinkID_Gen.GetLinkID( fnodes1[iNode], fnodes1[iNode+1] );
10280         pair< set<long>::iterator, bool > iter_isnew = linkIdSet.insert( linkID );
10281         if ( !iter_isnew.second ) { // already in a set: no need to process
10282           linkIdSet.erase( iter_isnew.first );
10283         }
10284         else // new in set == encountered for the first time: add
10285         {
10286           //const SMDS_MeshNode* n1 = nodes[ iNode ];
10287           //const SMDS_MeshNode* n2 = nodes[ iNode + 1];
10288           const SMDS_MeshNode* n1 = fnodes1[ iNode ];
10289           const SMDS_MeshNode* n2 = fnodes1[ iNode + 1];
10290           linkList[0].push_back ( NLink( n1, n2 ));
10291           linkList[1].push_back ( NLink( nReplaceMap[n1], nReplaceMap[n2] ));
10292         }
10293       }
10294     } // 2 faces found
10295   } // loop on link lists
10296
10297   if ( aResult == SEW_OK &&
10298        ( linkIt[0] != linkList[0].end() ||
10299          !faceSetPtr[0]->empty() || !faceSetPtr[1]->empty() )) {
10300     MESSAGE( (linkIt[0] != linkList[0].end()) <<" "<< (faceSetPtr[0]->empty()) <<
10301              " " << (faceSetPtr[1]->empty()));
10302     aResult = SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
10303   }
10304
10305   // ====================================================================
10306   // 3. Replace nodes in elements of the side 1 and remove replaced nodes
10307   // ====================================================================
10308
10309   // delete temporary faces: they are in reverseElements of actual nodes
10310 //  SMDS_FaceIteratorPtr tmpFaceIt = aTmpFacesMesh.facesIterator();
10311 //  while ( tmpFaceIt->more() )
10312 //    aTmpFacesMesh.RemoveElement( tmpFaceIt->next() );
10313 //  list<const SMDS_MeshElement* >::iterator tmpFaceIt = tempFaceList.begin();
10314 //  for (; tmpFaceIt !=tempFaceList.end(); ++tmpFaceIt)
10315 //    aMesh->RemoveElement(*tmpFaceIt);
10316
10317   if ( aResult != SEW_OK)
10318     return aResult;
10319
10320   list< int > nodeIDsToRemove/*, elemIDsToRemove*/;
10321   // loop on nodes replacement map
10322   TNodeNodeMap::iterator nReplaceMapIt = nReplaceMap.begin(), nnIt;
10323   for ( ; nReplaceMapIt != nReplaceMap.end(); nReplaceMapIt++ )
10324     if ( (*nReplaceMapIt).first != (*nReplaceMapIt).second ) {
10325       const SMDS_MeshNode* nToRemove = (*nReplaceMapIt).first;
10326       nodeIDsToRemove.push_back( nToRemove->GetID() );
10327       // loop on elements sharing nToRemove
10328       SMDS_ElemIteratorPtr invElemIt = nToRemove->GetInverseElementIterator();
10329       while ( invElemIt->more() ) {
10330         const SMDS_MeshElement* e = invElemIt->next();
10331         // get a new suite of nodes: make replacement
10332         int nbReplaced = 0, i = 0, nbNodes = e->NbNodes();
10333         vector< const SMDS_MeshNode*> nodes( nbNodes );
10334         SMDS_ElemIteratorPtr nIt = e->nodesIterator();
10335         while ( nIt->more() ) {
10336           const SMDS_MeshNode* n =
10337             static_cast<const SMDS_MeshNode*>( nIt->next() );
10338           nnIt = nReplaceMap.find( n );
10339           if ( nnIt != nReplaceMap.end() ) {
10340             nbReplaced++;
10341             n = (*nnIt).second;
10342           }
10343           nodes[ i++ ] = n;
10344         }
10345         //       if ( nbReplaced == nbNodes && e->GetType() == SMDSAbs_Face )
10346         //         elemIDsToRemove.push_back( e->GetID() );
10347         //       else
10348         if ( nbReplaced )
10349           {
10350             SMDSAbs_ElementType etyp = e->GetType();
10351             SMDS_MeshElement* newElem = this->AddElement(nodes, etyp, false);
10352             if (newElem)
10353               {
10354                 myLastCreatedElems.Append(newElem);
10355                 AddToSameGroups(newElem, e, aMesh);
10356                 int aShapeId = e->getshapeId();
10357                 if ( aShapeId )
10358                   {
10359                     aMesh->SetMeshElementOnShape( newElem, aShapeId );
10360                   }
10361               }
10362             aMesh->RemoveElement(e);
10363           }
10364       }
10365     }
10366
10367   Remove( nodeIDsToRemove, true );
10368
10369   return aResult;
10370 }
10371
10372 //================================================================================
10373 /*!
10374  * \brief Find corresponding nodes in two sets of faces
10375  * \param theSide1 - first face set
10376  * \param theSide2 - second first face
10377  * \param theFirstNode1 - a boundary node of set 1
10378  * \param theFirstNode2 - a node of set 2 corresponding to theFirstNode1
10379  * \param theSecondNode1 - a boundary node of set 1 linked with theFirstNode1
10380  * \param theSecondNode2 - a node of set 2 corresponding to theSecondNode1
10381  * \param nReplaceMap - output map of corresponding nodes
10382  * \return bool  - is a success or not
10383  */
10384 //================================================================================
10385
10386 #ifdef _DEBUG_
10387 //#define DEBUG_MATCHING_NODES
10388 #endif
10389
10390 SMESH_MeshEditor::Sew_Error
10391 SMESH_MeshEditor::FindMatchingNodes(set<const SMDS_MeshElement*>& theSide1,
10392                                     set<const SMDS_MeshElement*>& theSide2,
10393                                     const SMDS_MeshNode*          theFirstNode1,
10394                                     const SMDS_MeshNode*          theFirstNode2,
10395                                     const SMDS_MeshNode*          theSecondNode1,
10396                                     const SMDS_MeshNode*          theSecondNode2,
10397                                     TNodeNodeMap &                nReplaceMap)
10398 {
10399   set<const SMDS_MeshElement*> * faceSetPtr[] = { &theSide1, &theSide2 };
10400
10401   nReplaceMap.clear();
10402   if ( theFirstNode1 != theFirstNode2 )
10403     nReplaceMap.insert( make_pair( theFirstNode1, theFirstNode2 ));
10404   if ( theSecondNode1 != theSecondNode2 )
10405     nReplaceMap.insert( make_pair( theSecondNode1, theSecondNode2 ));
10406
10407   set< SMESH_TLink > linkSet; // set of nodes where order of nodes is ignored
10408   linkSet.insert( SMESH_TLink( theFirstNode1, theSecondNode1 ));
10409
10410   list< NLink > linkList[2];
10411   linkList[0].push_back( NLink( theFirstNode1, theSecondNode1 ));
10412   linkList[1].push_back( NLink( theFirstNode2, theSecondNode2 ));
10413
10414   // loop on links in linkList; find faces by links and append links
10415   // of the found faces to linkList
10416   list< NLink >::iterator linkIt[] = { linkList[0].begin(), linkList[1].begin() } ;
10417   for ( ; linkIt[0] != linkList[0].end(); linkIt[0]++, linkIt[1]++ ) {
10418     NLink link[] = { *linkIt[0], *linkIt[1] };
10419     if ( linkSet.find( link[0] ) == linkSet.end() )
10420       continue;
10421
10422     // by links, find faces in the face sets,
10423     // and find indices of link nodes in the found faces;
10424     // in a face set, there is only one or no face sharing a link
10425     // ---------------------------------------------------------------
10426
10427     const SMDS_MeshElement* face[] = { 0, 0 };
10428     list<const SMDS_MeshNode*> notLinkNodes[2];
10429     //bool reverse[] = { false, false }; // order of notLinkNodes
10430     int nbNodes[2];
10431     for ( int iSide = 0; iSide < 2; iSide++ ) // loop on 2 sides
10432     {
10433       const SMDS_MeshNode* n1 = link[iSide].first;
10434       const SMDS_MeshNode* n2 = link[iSide].second;
10435       set<const SMDS_MeshElement*> * faceSet = faceSetPtr[ iSide ];
10436       set< const SMDS_MeshElement* > facesOfNode1;
10437       for ( int iNode = 0; iNode < 2; iNode++ ) // loop on 2 nodes of a link
10438       {
10439         // during a loop of the first node, we find all faces around n1,
10440         // during a loop of the second node, we find one face sharing both n1 and n2
10441         const SMDS_MeshNode* n = iNode ? n1 : n2; // a node of a link
10442         SMDS_ElemIteratorPtr fIt = n->GetInverseElementIterator(SMDSAbs_Face);
10443         while ( fIt->more() ) { // loop on faces sharing a node
10444           const SMDS_MeshElement* f = fIt->next();
10445           if (faceSet->find( f ) != faceSet->end() && // f is in face set
10446               ! facesOfNode1.insert( f ).second ) // f encounters twice
10447           {
10448             if ( face[ iSide ] ) {
10449               MESSAGE( "2 faces per link " );
10450               return ( iSide ? SEW_BAD_SIDE2_NODES : SEW_BAD_SIDE1_NODES );
10451             }
10452             face[ iSide ] = f;
10453             faceSet->erase( f );
10454
10455             // get not link nodes
10456             int nbN = f->NbNodes();
10457             if ( f->IsQuadratic() )
10458               nbN /= 2;
10459             nbNodes[ iSide ] = nbN;
10460             list< const SMDS_MeshNode* > & nodes = notLinkNodes[ iSide ];
10461             int i1 = f->GetNodeIndex( n1 );
10462             int i2 = f->GetNodeIndex( n2 );
10463             int iEnd = nbN, iBeg = -1, iDelta = 1;
10464             bool reverse = ( Abs( i1 - i2 ) == 1 ? i1 > i2 : i2 > i1 );
10465             if ( reverse ) {
10466               std::swap( iEnd, iBeg ); iDelta = -1;
10467             }
10468             int i = i2;
10469             while ( true ) {
10470               i += iDelta;
10471               if ( i == iEnd ) i = iBeg + iDelta;
10472               if ( i == i1 ) break;
10473               nodes.push_back ( f->GetNode( i ) );
10474             }
10475           }
10476         }
10477       }
10478     }
10479     // check similarity of elements of the sides
10480     if (( face[0] && !face[1] ) || ( !face[0] && face[1] )) {
10481       MESSAGE("Correspondent face not found on side " << ( face[0] ? 1 : 0 ));
10482       if ( nReplaceMap.size() == 2 ) { // faces on input nodes not found
10483         return ( face[0] ? SEW_BAD_SIDE2_NODES : SEW_BAD_SIDE1_NODES );
10484       }
10485       else {
10486         return SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
10487       }
10488     }
10489
10490     // set nodes to merge
10491     // -------------------
10492
10493     if ( face[0] && face[1] )  {
10494       if ( nbNodes[0] != nbNodes[1] ) {
10495         MESSAGE("Diff nb of face nodes");
10496         return SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
10497       }
10498 #ifdef DEBUG_MATCHING_NODES
10499       MESSAGE ( " Link 1: " << link[0].first->GetID() <<" "<< link[0].second->GetID()
10500                 << " F 1: " << face[0] << "| Link 2: " << link[1].first->GetID() <<" "
10501                 << link[1].second->GetID() << " F 2: " << face[1] << " | Bind: " ) ;
10502 #endif
10503       int nbN = nbNodes[0];
10504       {
10505         list<const SMDS_MeshNode*>::iterator n1 = notLinkNodes[0].begin();
10506         list<const SMDS_MeshNode*>::iterator n2 = notLinkNodes[1].begin();
10507         for ( int i = 0 ; i < nbN - 2; ++i ) {
10508 #ifdef DEBUG_MATCHING_NODES
10509           MESSAGE ( (*n1)->GetID() << " to " << (*n2)->GetID() );
10510 #endif
10511           nReplaceMap.insert( make_pair( *(n1++), *(n2++) ));
10512         }
10513       }
10514
10515       // add other links of the face 1 to linkList
10516       // -----------------------------------------
10517
10518       const SMDS_MeshElement* f0 = face[0];
10519       const SMDS_MeshNode* n1 = f0->GetNode( nbN - 1 );
10520       for ( int i = 0; i < nbN; i++ )
10521       {
10522         const SMDS_MeshNode* n2 = f0->GetNode( i );
10523         pair< set< SMESH_TLink >::iterator, bool > iter_isnew =
10524           linkSet.insert( SMESH_TLink( n1, n2 ));
10525         if ( !iter_isnew.second ) { // already in a set: no need to process
10526           linkSet.erase( iter_isnew.first );
10527         }
10528         else // new in set == encountered for the first time: add
10529         {
10530 #ifdef DEBUG_MATCHING_NODES
10531           MESSAGE ( "Add link 1: " << n1->GetID() << " " << n2->GetID() << " "
10532                     << " | link 2: " << nReplaceMap[n1]->GetID() << " " << nReplaceMap[n2]->GetID() << " " );
10533 #endif
10534           linkList[0].push_back ( NLink( n1, n2 ));
10535           linkList[1].push_back ( NLink( nReplaceMap[n1], nReplaceMap[n2] ));
10536         }
10537         n1 = n2;
10538       }
10539     } // 2 faces found
10540   } // loop on link lists
10541
10542   return SEW_OK;
10543 }
10544
10545 //================================================================================
10546 /*!
10547   \brief Creates a hole in a mesh by doubling the nodes of some particular elements
10548   \param theElems - the list of elements (edges or faces) to be replicated
10549   The nodes for duplication could be found from these elements
10550   \param theNodesNot - list of nodes to NOT replicate
10551   \param theAffectedElems - the list of elements (cells and edges) to which the 
10552   replicated nodes should be associated to.
10553   \return TRUE if operation has been completed successfully, FALSE otherwise
10554 */
10555 //================================================================================
10556
10557 bool SMESH_MeshEditor::DoubleNodes( const TIDSortedElemSet& theElems,
10558                                     const TIDSortedElemSet& theNodesNot,
10559                                     const TIDSortedElemSet& theAffectedElems )
10560 {
10561   myLastCreatedElems.Clear();
10562   myLastCreatedNodes.Clear();
10563
10564   if ( theElems.size() == 0 )
10565     return false;
10566
10567   SMESHDS_Mesh* aMeshDS = GetMeshDS();
10568   if ( !aMeshDS )
10569     return false;
10570
10571   bool res = false;
10572   std::map< const SMDS_MeshNode*, const SMDS_MeshNode* > anOldNodeToNewNode;
10573   // duplicate elements and nodes
10574   res = doubleNodes( aMeshDS, theElems, theNodesNot, anOldNodeToNewNode, true );
10575   // replce nodes by duplications
10576   res = doubleNodes( aMeshDS, theAffectedElems, theNodesNot, anOldNodeToNewNode, false );
10577   return res;
10578 }
10579
10580 //================================================================================
10581 /*!
10582   \brief Creates a hole in a mesh by doubling the nodes of some particular elements
10583   \param theMeshDS - mesh instance
10584   \param theElems - the elements replicated or modified (nodes should be changed)
10585   \param theNodesNot - nodes to NOT replicate
10586   \param theNodeNodeMap - relation of old node to new created node
10587   \param theIsDoubleElem - flag os to replicate element or modify
10588   \return TRUE if operation has been completed successfully, FALSE otherwise
10589 */
10590 //================================================================================
10591
10592 bool SMESH_MeshEditor::doubleNodes( SMESHDS_Mesh*     theMeshDS,
10593                                     const TIDSortedElemSet& theElems,
10594                                     const TIDSortedElemSet& theNodesNot,
10595                                     std::map< const SMDS_MeshNode*,
10596                                     const SMDS_MeshNode* >& theNodeNodeMap,
10597                                     const bool theIsDoubleElem )
10598 {
10599   MESSAGE("doubleNodes");
10600   // iterate on through element and duplicate them (by nodes duplication)
10601   bool res = false;
10602   TIDSortedElemSet::const_iterator elemItr = theElems.begin();
10603   for ( ;  elemItr != theElems.end(); ++elemItr )
10604   {
10605     const SMDS_MeshElement* anElem = *elemItr;
10606     if (!anElem)
10607       continue;
10608
10609     bool isDuplicate = false;
10610     // duplicate nodes to duplicate element
10611     std::vector<const SMDS_MeshNode*> newNodes( anElem->NbNodes() );
10612     SMDS_ElemIteratorPtr anIter = anElem->nodesIterator();
10613     int ind = 0;
10614     while ( anIter->more() ) 
10615     { 
10616
10617       SMDS_MeshNode* aCurrNode = (SMDS_MeshNode*)anIter->next();
10618       SMDS_MeshNode* aNewNode = aCurrNode;
10619       if ( theNodeNodeMap.find( aCurrNode ) != theNodeNodeMap.end() )
10620         aNewNode = (SMDS_MeshNode*)theNodeNodeMap[ aCurrNode ];
10621       else if ( theIsDoubleElem && theNodesNot.find( aCurrNode ) == theNodesNot.end() )
10622       {
10623         // duplicate node
10624         aNewNode = theMeshDS->AddNode( aCurrNode->X(), aCurrNode->Y(), aCurrNode->Z() );
10625         theNodeNodeMap[ aCurrNode ] = aNewNode;
10626         myLastCreatedNodes.Append( aNewNode );
10627       }
10628       isDuplicate |= (aCurrNode != aNewNode);
10629       newNodes[ ind++ ] = aNewNode;
10630     }
10631     if ( !isDuplicate )
10632       continue;
10633
10634     if ( theIsDoubleElem )
10635       AddElement(newNodes, anElem->GetType(), anElem->IsPoly());
10636     else
10637       {
10638       MESSAGE("ChangeElementNodes");
10639       theMeshDS->ChangeElementNodes( anElem, &newNodes[ 0 ], anElem->NbNodes() );
10640       }
10641     res = true;
10642   }
10643   return res;
10644 }
10645
10646 //================================================================================
10647 /*!
10648   \brief Creates a hole in a mesh by doubling the nodes of some particular elements
10649   \param theNodes - identifiers of nodes to be doubled
10650   \param theModifiedElems - identifiers of elements to be updated by the new (doubled) 
10651          nodes. If list of element identifiers is empty then nodes are doubled but 
10652          they not assigned to elements
10653   \return TRUE if operation has been completed successfully, FALSE otherwise
10654 */
10655 //================================================================================
10656
10657 bool SMESH_MeshEditor::DoubleNodes( const std::list< int >& theListOfNodes, 
10658                                     const std::list< int >& theListOfModifiedElems )
10659 {
10660   MESSAGE("DoubleNodes");
10661   myLastCreatedElems.Clear();
10662   myLastCreatedNodes.Clear();
10663
10664   if ( theListOfNodes.size() == 0 )
10665     return false;
10666
10667   SMESHDS_Mesh* aMeshDS = GetMeshDS();
10668   if ( !aMeshDS )
10669     return false;
10670
10671   // iterate through nodes and duplicate them
10672
10673   std::map< const SMDS_MeshNode*, const SMDS_MeshNode* > anOldNodeToNewNode;
10674
10675   std::list< int >::const_iterator aNodeIter;
10676   for ( aNodeIter = theListOfNodes.begin(); aNodeIter != theListOfNodes.end(); ++aNodeIter )
10677   {
10678     int aCurr = *aNodeIter;
10679     SMDS_MeshNode* aNode = (SMDS_MeshNode*)aMeshDS->FindNode( aCurr );
10680     if ( !aNode )
10681       continue;
10682
10683     // duplicate node
10684
10685     const SMDS_MeshNode* aNewNode = aMeshDS->AddNode( aNode->X(), aNode->Y(), aNode->Z() );
10686     if ( aNewNode )
10687     {
10688       anOldNodeToNewNode[ aNode ] = aNewNode;
10689       myLastCreatedNodes.Append( aNewNode );
10690     }
10691   }
10692
10693   // Create map of new nodes for modified elements
10694
10695   std::map< SMDS_MeshElement*, vector<const SMDS_MeshNode*> > anElemToNodes;
10696
10697   std::list< int >::const_iterator anElemIter;
10698   for ( anElemIter = theListOfModifiedElems.begin(); 
10699         anElemIter != theListOfModifiedElems.end(); ++anElemIter )
10700   {
10701     int aCurr = *anElemIter;
10702     SMDS_MeshElement* anElem = (SMDS_MeshElement*)aMeshDS->FindElement( aCurr );
10703     if ( !anElem )
10704       continue;
10705
10706     vector<const SMDS_MeshNode*> aNodeArr( anElem->NbNodes() );
10707
10708     SMDS_ElemIteratorPtr anIter = anElem->nodesIterator();
10709     int ind = 0;
10710     while ( anIter->more() ) 
10711     { 
10712       SMDS_MeshNode* aCurrNode = (SMDS_MeshNode*)anIter->next();
10713       if ( aCurr && anOldNodeToNewNode.find( aCurrNode ) != anOldNodeToNewNode.end() )
10714       {
10715         const SMDS_MeshNode* aNewNode = anOldNodeToNewNode[ aCurrNode ];
10716         aNodeArr[ ind++ ] = aNewNode;
10717       }
10718       else
10719         aNodeArr[ ind++ ] = aCurrNode;
10720     }
10721     anElemToNodes[ anElem ] = aNodeArr;
10722   }
10723
10724   // Change nodes of elements  
10725
10726   std::map< SMDS_MeshElement*, vector<const SMDS_MeshNode*> >::iterator
10727     anElemToNodesIter = anElemToNodes.begin();
10728   for ( ; anElemToNodesIter != anElemToNodes.end(); ++anElemToNodesIter )
10729   {
10730     const SMDS_MeshElement* anElem = anElemToNodesIter->first;
10731     vector<const SMDS_MeshNode*> aNodeArr = anElemToNodesIter->second;
10732     if ( anElem )
10733       {
10734       MESSAGE("ChangeElementNodes");
10735       aMeshDS->ChangeElementNodes( anElem, &aNodeArr[ 0 ], anElem->NbNodes() );
10736       }
10737   }
10738
10739   return true;
10740 }
10741
10742 namespace {
10743
10744   //================================================================================
10745   /*!
10746   \brief Check if element located inside shape
10747   \return TRUE if IN or ON shape, FALSE otherwise
10748   */
10749   //================================================================================
10750
10751   template<class Classifier>
10752   bool isInside(const SMDS_MeshElement* theElem,
10753                 Classifier&             theClassifier,
10754                 const double            theTol)
10755   {
10756     gp_XYZ centerXYZ (0, 0, 0);
10757     SMDS_ElemIteratorPtr aNodeItr = theElem->nodesIterator();
10758     while (aNodeItr->more())
10759       centerXYZ += SMESH_TNodeXYZ(cast2Node( aNodeItr->next()));
10760
10761     gp_Pnt aPnt = centerXYZ / theElem->NbNodes();
10762     theClassifier.Perform(aPnt, theTol);
10763     TopAbs_State aState = theClassifier.State();
10764     return (aState == TopAbs_IN || aState == TopAbs_ON );
10765   }
10766
10767   //================================================================================
10768   /*!
10769    * \brief Classifier of the 3D point on the TopoDS_Face
10770    *        with interaface suitable for isInside()
10771    */
10772   //================================================================================
10773
10774   struct _FaceClassifier
10775   {
10776     Extrema_ExtPS       _extremum;
10777     BRepAdaptor_Surface _surface;
10778     TopAbs_State        _state;
10779
10780     _FaceClassifier(const TopoDS_Face& face):_extremum(),_surface(face),_state(TopAbs_OUT)
10781     {
10782       _extremum.Initialize( _surface,
10783                             _surface.FirstUParameter(), _surface.LastUParameter(),
10784                             _surface.FirstVParameter(), _surface.LastVParameter(),
10785                             _surface.Tolerance(), _surface.Tolerance() );
10786     }
10787     void Perform(const gp_Pnt& aPnt, double theTol)
10788     {
10789       _state = TopAbs_OUT;
10790       _extremum.Perform(aPnt);
10791       if ( _extremum.IsDone() )
10792         for ( int iSol = 1; iSol <= _extremum.NbExt() && _state == TopAbs_OUT; ++iSol)
10793           _state = ( _extremum.Value(iSol) <= theTol ? TopAbs_IN : TopAbs_OUT );
10794     }
10795     TopAbs_State State() const
10796     {
10797       return _state;
10798     }
10799   };
10800 }
10801
10802 //================================================================================
10803 /*!
10804   \brief Creates a hole in a mesh by doubling the nodes of some particular elements
10805   \param theElems - group of of elements (edges or faces) to be replicated
10806   \param theNodesNot - group of nodes not to replicate
10807   \param theShape - shape to detect affected elements (element which geometric center
10808   located on or inside shape).
10809   The replicated nodes should be associated to affected elements.
10810   \return TRUE if operation has been completed successfully, FALSE otherwise
10811 */
10812 //================================================================================
10813
10814 bool SMESH_MeshEditor::DoubleNodesInRegion( const TIDSortedElemSet& theElems,
10815                                             const TIDSortedElemSet& theNodesNot,
10816                                             const TopoDS_Shape&     theShape )
10817 {
10818   if ( theShape.IsNull() )
10819     return false;
10820
10821   const double aTol = Precision::Confusion();
10822   auto_ptr< BRepClass3d_SolidClassifier> bsc3d;
10823   auto_ptr<_FaceClassifier>              aFaceClassifier;
10824   if ( theShape.ShapeType() == TopAbs_SOLID )
10825   {
10826     bsc3d.reset( new BRepClass3d_SolidClassifier(theShape));;
10827     bsc3d->PerformInfinitePoint(aTol);
10828   }
10829   else if (theShape.ShapeType() == TopAbs_FACE )
10830   {
10831     aFaceClassifier.reset( new _FaceClassifier(TopoDS::Face(theShape)));
10832   }
10833
10834   // iterates on indicated elements and get elements by back references from their nodes
10835   TIDSortedElemSet anAffected;
10836   TIDSortedElemSet::const_iterator elemItr = theElems.begin();
10837   for ( ;  elemItr != theElems.end(); ++elemItr )
10838   {
10839     SMDS_MeshElement* anElem = (SMDS_MeshElement*)*elemItr;
10840     if (!anElem)
10841       continue;
10842
10843     SMDS_ElemIteratorPtr nodeItr = anElem->nodesIterator();
10844     while ( nodeItr->more() )
10845     {
10846       const SMDS_MeshNode* aNode = cast2Node(nodeItr->next());
10847       if ( !aNode || theNodesNot.find(aNode) != theNodesNot.end() )
10848         continue;
10849       SMDS_ElemIteratorPtr backElemItr = aNode->GetInverseElementIterator();
10850       while ( backElemItr->more() )
10851       {
10852         const SMDS_MeshElement* curElem = backElemItr->next();
10853         if ( curElem && theElems.find(curElem) == theElems.end() &&
10854              ( bsc3d.get() ?
10855                isInside( curElem, *bsc3d, aTol ) :
10856                isInside( curElem, *aFaceClassifier, aTol )))
10857           anAffected.insert( curElem );
10858       }
10859     }
10860   }
10861   return DoubleNodes( theElems, theNodesNot, anAffected );
10862 }
10863
10864 /*!
10865  *  \brief compute an oriented angle between two planes defined by four points.
10866  *  The vector (p0,p1) defines the intersection of the 2 planes (p0,p1,g1) and (p0,p1,g2)
10867  *  @param p0 base of the rotation axe
10868  *  @param p1 extremity of the rotation axe
10869  *  @param g1 belongs to the first plane
10870  *  @param g2 belongs to the second plane
10871  */
10872 double SMESH_MeshEditor::OrientedAngle(const gp_Pnt& p0, const gp_Pnt& p1, const gp_Pnt& g1, const gp_Pnt& g2)
10873 {
10874 //  MESSAGE("    p0: " << p0.X() << " " << p0.Y() << " " << p0.Z());
10875 //  MESSAGE("    p1: " << p1.X() << " " << p1.Y() << " " << p1.Z());
10876 //  MESSAGE("    g1: " << g1.X() << " " << g1.Y() << " " << g1.Z());
10877 //  MESSAGE("    g2: " << g2.X() << " " << g2.Y() << " " << g2.Z());
10878   gp_Vec vref(p0, p1);
10879   gp_Vec v1(p0, g1);
10880   gp_Vec v2(p0, g2);
10881   gp_Vec n1 = vref.Crossed(v1);
10882   gp_Vec n2 = vref.Crossed(v2);
10883   return n2.AngleWithRef(n1, vref);
10884 }
10885
10886 /*!
10887  * \brief Double nodes on shared faces between groups of volumes and create flat elements on demand.
10888  * The list of groups must describe a partition of the mesh volumes.
10889  * The nodes of the internal faces at the boundaries of the groups are doubled.
10890  * In option, the internal faces are replaced by flat elements.
10891  * Triangles are transformed in prisms, and quadrangles in hexahedrons.
10892  * The flat elements are stored in groups of volumes.
10893  * @param theElems - list of groups of volumes, where a group of volume is a set of
10894  * SMDS_MeshElements sorted by Id.
10895  * @param createJointElems - if TRUE, create the elements
10896  * @return TRUE if operation has been completed successfully, FALSE otherwise
10897  */
10898 bool SMESH_MeshEditor::DoubleNodesOnGroupBoundaries( const std::vector<TIDSortedElemSet>& theElems,
10899                                                      bool createJointElems)
10900 {
10901   MESSAGE("----------------------------------------------");
10902   MESSAGE("SMESH_MeshEditor::doubleNodesOnGroupBoundaries");
10903   MESSAGE("----------------------------------------------");
10904
10905   SMESHDS_Mesh *meshDS = this->myMesh->GetMeshDS();
10906   meshDS->BuildDownWardConnectivity(true);
10907   CHRONO(50);
10908   SMDS_UnstructuredGrid *grid = meshDS->getGrid();
10909
10910   // --- build the list of faces shared by 2 domains (group of elements), with their domain and volume indexes
10911   //     build the list of cells with only a node or an edge on the border, with their domain and volume indexes
10912   //     build the list of nodes shared by 2 or more domains, with their domain indexes
10913
10914   std::map<DownIdType, std::map<int,int>, DownIdCompare> faceDomains; // face --> (id domain --> id volume)
10915   std::map<int,int>celldom; // cell vtkId --> domain
10916   std::map<DownIdType, std::map<int,int>, DownIdCompare> cellDomains;  // oldNode --> (id domain --> id cell)
10917   std::map<int, std::map<int,int> > nodeDomains; // oldId -->  (domainId --> newId)
10918   faceDomains.clear();
10919   celldom.clear();
10920   cellDomains.clear();
10921   nodeDomains.clear();
10922   std::map<int,int> emptyMap;
10923   std::set<int> emptySet;
10924   emptyMap.clear();
10925
10926   for (int idom = 0; idom < theElems.size(); idom++)
10927     {
10928
10929       // --- build a map (face to duplicate --> volume to modify)
10930       //     with all the faces shared by 2 domains (group of elements)
10931       //     and corresponding volume of this domain, for each shared face.
10932       //     a volume has a face shared by 2 domains if it has a neighbor which is not in is domain.
10933
10934       const TIDSortedElemSet& domain = theElems[idom];
10935       TIDSortedElemSet::const_iterator elemItr = domain.begin();
10936       for (; elemItr != domain.end(); ++elemItr)
10937         {
10938           SMDS_MeshElement* anElem = (SMDS_MeshElement*) *elemItr;
10939           if (!anElem)
10940             continue;
10941           int vtkId = anElem->getVtkId();
10942           int neighborsVtkIds[NBMAXNEIGHBORS];
10943           int downIds[NBMAXNEIGHBORS];
10944           unsigned char downTypes[NBMAXNEIGHBORS];
10945           int nbNeighbors = grid->GetNeighbors(neighborsVtkIds, downIds, downTypes, vtkId);
10946           for (int n = 0; n < nbNeighbors; n++)
10947             {
10948               int smdsId = meshDS->fromVtkToSmds(neighborsVtkIds[n]);
10949               const SMDS_MeshElement* elem = meshDS->FindElement(smdsId);
10950               if (! domain.count(elem)) // neighbor is in another domain : face is shared
10951                 {
10952                   DownIdType face(downIds[n], downTypes[n]);
10953                   if (!faceDomains.count(face))
10954                     faceDomains[face] = emptyMap; // create an empty entry for face
10955                   if (!faceDomains[face].count(idom))
10956                     {
10957                       faceDomains[face][idom] = vtkId; // volume associated to face in this domain
10958                       celldom[vtkId] = idom;
10959                     }
10960                 }
10961             }
10962         }
10963     }
10964
10965   //MESSAGE("Number of shared faces " << faceDomains.size());
10966   std::map<DownIdType, std::map<int, int>, DownIdCompare>::iterator itface;
10967
10968   // --- explore the shared faces domain by domain,
10969   //     explore the nodes of the face and see if they belong to a cell in the domain,
10970   //     which has only a node or an edge on the border (not a shared face)
10971
10972   for (int idomain = 0; idomain < theElems.size(); idomain++)
10973     {
10974       const TIDSortedElemSet& domain = theElems[idomain];
10975       itface = faceDomains.begin();
10976       for (; itface != faceDomains.end(); ++itface)
10977         {
10978           std::map<int, int> domvol = itface->second;
10979           if (!domvol.count(idomain))
10980             continue;
10981           DownIdType face = itface->first;
10982           //MESSAGE(" --- face " << face.cellId);
10983           std::set<int> oldNodes;
10984           oldNodes.clear();
10985           grid->GetNodeIds(oldNodes, face.cellId, face.cellType);
10986           std::set<int>::iterator itn = oldNodes.begin();
10987           for (; itn != oldNodes.end(); ++itn)
10988             {
10989               int oldId = *itn;
10990               //MESSAGE("     node " << oldId);
10991               std::set<int> cells;
10992               cells.clear();
10993               vtkCellLinks::Link l = grid->GetCellLinks()->GetLink(oldId);
10994               for (int i=0; i<l.ncells; i++)
10995                 {
10996                   int vtkId = l.cells[i];
10997                   const SMDS_MeshElement* anElem = GetMeshDS()->FindElement(GetMeshDS()->fromVtkToSmds(vtkId));
10998                   if (!domain.count(anElem))
10999                     continue;
11000                   int vtkType = grid->GetCellType(vtkId);
11001                   int downId = grid->CellIdToDownId(vtkId);
11002                   if (downId < 0)
11003                     {
11004                       MESSAGE("doubleNodesOnGroupBoundaries: internal algorithm problem");
11005                       continue; // not OK at this stage of the algorithm:
11006                                 //no cells created after BuildDownWardConnectivity
11007                     }
11008                   DownIdType aCell(downId, vtkType);
11009                   if (celldom.count(vtkId))
11010                     continue;
11011                   cellDomains[aCell][idomain] = vtkId;
11012                   celldom[vtkId] = idomain;
11013                 }
11014             }
11015         }
11016     }
11017
11018   // --- explore the shared faces domain by domain, to duplicate the nodes in a coherent way
11019   //     for each shared face, get the nodes
11020   //     for each node, for each domain of the face, create a clone of the node
11021
11022   // --- edges at the intersection of 3 or 4 domains, with the order of domains to build
11023   //     junction elements of type prism or hexa. the key is the pair of nodesId (lower first)
11024   //     the value is the ordered domain ids. (more than 4 domains not taken into account)
11025
11026   std::map<std::vector<int>, std::vector<int> > edgesMultiDomains; // nodes of edge --> ordered domains
11027   std::map<int, std::vector<int> > mutipleNodes; // nodes muti domains with domain order
11028
11029   for (int idomain = 0; idomain < theElems.size(); idomain++)
11030     {
11031       itface = faceDomains.begin();
11032       for (; itface != faceDomains.end(); ++itface)
11033         {
11034           std::map<int, int> domvol = itface->second;
11035           if (!domvol.count(idomain))
11036             continue;
11037           DownIdType face = itface->first;
11038           //MESSAGE(" --- face " << face.cellId);
11039           std::set<int> oldNodes;
11040           oldNodes.clear();
11041           grid->GetNodeIds(oldNodes, face.cellId, face.cellType);
11042           bool isMultipleDetected = false;
11043           std::set<int>::iterator itn = oldNodes.begin();
11044           for (; itn != oldNodes.end(); ++itn)
11045             {
11046               int oldId = *itn;
11047               //MESSAGE("     node " << oldId);
11048               if (!nodeDomains.count(oldId))
11049                 nodeDomains[oldId] = emptyMap; // create an empty entry for node
11050               if (nodeDomains[oldId].empty())
11051                 nodeDomains[oldId][idomain] = oldId; // keep the old node in the first domain
11052               std::map<int, int>::iterator itdom = domvol.begin();
11053               for (; itdom != domvol.end(); ++itdom)
11054                 {
11055                   int idom = itdom->first;
11056                   //MESSAGE("         domain " << idom);
11057                   if (!nodeDomains[oldId].count(idom)) // --- node to clone
11058                     {
11059                       if (nodeDomains[oldId].size() >= 2) // a multiple node
11060                         {
11061                           vector<int> orderedDoms;
11062                           //MESSAGE("multiple node " << oldId);
11063                           isMultipleDetected =true;
11064                           if (mutipleNodes.count(oldId))
11065                             orderedDoms = mutipleNodes[oldId];
11066                           else
11067                             {
11068                               map<int,int>::iterator it = nodeDomains[oldId].begin();
11069                               for (; it != nodeDomains[oldId].end(); ++it)
11070                                 orderedDoms.push_back(it->first);
11071                             }
11072                           orderedDoms.push_back(idom); // TODO order ==> push_front or back
11073                           //stringstream txt;
11074                           //for (int i=0; i<orderedDoms.size(); i++)
11075                           //  txt << orderedDoms[i] << " ";
11076                           //MESSAGE("orderedDoms " << txt.str());
11077                           mutipleNodes[oldId] = orderedDoms;
11078                         }
11079                       double *coords = grid->GetPoint(oldId);
11080                       SMDS_MeshNode *newNode = meshDS->AddNode(coords[0], coords[1], coords[2]);
11081                       int newId = newNode->getVtkId();
11082                       nodeDomains[oldId][idom] = newId; // cloned node for other domains
11083                       //MESSAGE("   newNode " << newId << " oldNode " << oldId << " size=" <<nodeDomains[oldId].size());
11084                     }
11085                   if (nodeDomains[oldId].size() >= 3)
11086                     {
11087                       //MESSAGE("confirm multiple node " << oldId);
11088                       isMultipleDetected =true;
11089                     }
11090                 }
11091             }
11092           if (isMultipleDetected) // check if an edge of the face is shared between 3 or more domains
11093             {
11094               //MESSAGE("multiple Nodes detected on a shared face");
11095               int downId = itface->first.cellId;
11096               unsigned char cellType = itface->first.cellType;
11097               int nbEdges = grid->getDownArray(cellType)->getNumberOfDownCells(downId);
11098               const int *downEdgeIds = grid->getDownArray(cellType)->getDownCells(downId);
11099               const unsigned char* edgeType = grid->getDownArray(cellType)->getDownTypes(downId);
11100               for (int ie =0; ie < nbEdges; ie++)
11101                 {
11102                   int nodes[3];
11103                   int nbNodes = grid->getDownArray(edgeType[ie])->getNodes(downEdgeIds[ie], nodes);
11104                   if (mutipleNodes.count(nodes[0]) && mutipleNodes.count(nodes[nbNodes-1]))
11105                     {
11106                       vector<int> vn0 = mutipleNodes[nodes[0]];
11107                       vector<int> vn1 = mutipleNodes[nodes[nbNodes - 1]];
11108                       sort( vn0.begin(), vn0.end() );
11109                       sort( vn1.begin(), vn1.end() );
11110                       if (vn0 == vn1)
11111                         {
11112                           //MESSAGE(" detect edgesMultiDomains " << nodes[0] << " " << nodes[nbNodes - 1]);
11113                           double *coords = grid->GetPoint(nodes[0]);
11114                           gp_Pnt p0(coords[0], coords[1], coords[2]);
11115                           coords = grid->GetPoint(nodes[nbNodes - 1]);
11116                           gp_Pnt p1(coords[0], coords[1], coords[2]);
11117                           gp_Pnt gref;
11118                           int vtkVolIds[1000];  // an edge can belong to a lot of volumes
11119                           map<int, SMDS_VtkVolume*> domvol; // domain --> a volume with the edge
11120                           map<int, double> angleDom; // oriented angles between planes defined by edge and volume centers
11121                           int nbvol = grid->GetParentVolumes(vtkVolIds, downEdgeIds[ie], edgeType[ie]);
11122                           for (int id=0; id < vn0.size(); id++)
11123                             {
11124                               int idom = vn0[id];
11125                               for (int ivol=0; ivol<nbvol; ivol++)
11126                                 {
11127                                   int smdsId = meshDS->fromVtkToSmds(vtkVolIds[ivol]);
11128                                   SMDS_MeshElement* elem = (SMDS_MeshElement*)meshDS->FindElement(smdsId);
11129                                   if (theElems[idom].count(elem))
11130                                     {
11131                                       SMDS_VtkVolume* svol = dynamic_cast<SMDS_VtkVolume*>(elem);
11132                                       domvol[idom] = svol;
11133                                       //MESSAGE("  domain " << idom << " volume " << elem->GetID());
11134                                       double values[3];
11135                                       vtkIdType npts = 0;
11136                                       vtkIdType* pts = 0;
11137                                       grid->GetCellPoints(vtkVolIds[ivol], npts, pts);
11138                                       SMDS_VtkVolume::gravityCenter(grid, pts, npts, values);
11139                                       if (id ==0)
11140                                         {
11141                                           gref.SetXYZ(gp_XYZ(values[0], values[1], values[2]));
11142                                           angleDom[idom] = 0;
11143                                         }
11144                                       else
11145                                         {
11146                                           gp_Pnt g(values[0], values[1], values[2]);
11147                                           angleDom[idom] = OrientedAngle(p0, p1, gref, g); // -pi<angle<+pi
11148                                           //MESSAGE("  angle=" << angleDom[idom]);
11149                                         }
11150                                       break;
11151                                     }
11152                                 }
11153                             }
11154                           map<double, int> sortedDom; // sort domains by angle
11155                           for (map<int, double>::iterator ia = angleDom.begin(); ia != angleDom.end(); ++ia)
11156                             sortedDom[ia->second] = ia->first;
11157                           vector<int> vnodes;
11158                           vector<int> vdom;
11159                           for (map<double, int>::iterator ib = sortedDom.begin(); ib != sortedDom.end(); ++ib)
11160                             {
11161                               vdom.push_back(ib->second);
11162                               //MESSAGE("  ordered domain " << ib->second << "  angle " << ib->first);
11163                             }
11164                           for (int ino = 0; ino < nbNodes; ino++)
11165                             vnodes.push_back(nodes[ino]);
11166                           edgesMultiDomains[vnodes] = vdom; // nodes vector --> ordered domains
11167                         }
11168                     }
11169                 }
11170             }
11171         }
11172     }
11173
11174   // --- iterate on shared faces (volumes to modify, face to extrude)
11175   //     get node id's of the face (id SMDS = id VTK)
11176   //     create flat element with old and new nodes if requested
11177
11178   // --- new quad nodes on flat quad elements: oldId --> ((domain1 X domain2) --> newId)
11179   //     (domain1 X domain2) = domain1 + MAXINT*domain2
11180
11181   std::map<int, std::map<long,int> > nodeQuadDomains;
11182   std::map<std::string, SMESH_Group*> mapOfJunctionGroups;
11183
11184   if (createJointElems)
11185     {
11186       itface = faceDomains.begin();
11187       for (; itface != faceDomains.end(); ++itface)
11188         {
11189           DownIdType face = itface->first;
11190           std::set<int> oldNodes;
11191           std::set<int>::iterator itn;
11192           oldNodes.clear();
11193           grid->GetNodeIds(oldNodes, face.cellId, face.cellType);
11194
11195           std::map<int, int> domvol = itface->second;
11196           std::map<int, int>::iterator itdom = domvol.begin();
11197           int dom1 = itdom->first;
11198           int vtkVolId = itdom->second;
11199           itdom++;
11200           int dom2 = itdom->first;
11201           SMDS_MeshVolume *vol = grid->extrudeVolumeFromFace(vtkVolId, dom1, dom2, oldNodes, nodeDomains,
11202                                                              nodeQuadDomains);
11203           stringstream grpname;
11204           grpname << "j_";
11205           if (dom1 < dom2)
11206             grpname << dom1 << "_" << dom2;
11207           else
11208             grpname << dom2 << "_" << dom1;
11209           int idg;
11210           string namegrp = grpname.str();
11211           if (!mapOfJunctionGroups.count(namegrp))
11212             mapOfJunctionGroups[namegrp] = this->myMesh->AddGroup(SMDSAbs_Volume, namegrp.c_str(), idg);
11213           SMESHDS_Group *sgrp = dynamic_cast<SMESHDS_Group*>(mapOfJunctionGroups[namegrp]->GetGroupDS());
11214           if (sgrp)
11215             sgrp->Add(vol->GetID());
11216         }
11217     }
11218
11219   // --- create volumes on multiple domain intersection if requested
11220   //     iterate on edgesMultiDomains
11221
11222   if (createJointElems)
11223     {
11224       std::map<std::vector<int>, std::vector<int> >::iterator ite = edgesMultiDomains.begin();
11225       for (; ite != edgesMultiDomains.end(); ++ite)
11226         {
11227           vector<int> nodes = ite->first;
11228           vector<int> orderDom = ite->second;
11229           vector<vtkIdType> orderedNodes;
11230           if (nodes.size() == 2)
11231             {
11232               //MESSAGE(" use edgesMultiDomains " << nodes[0] << " " << nodes[1]);
11233               for (int ino=0; ino < nodes.size(); ino++)
11234                 if (orderDom.size() == 3)
11235                   for (int idom = 0; idom <orderDom.size(); idom++)
11236                     orderedNodes.push_back( nodeDomains[nodes[ino]][orderDom[idom]] );
11237                 else
11238                   for (int idom = orderDom.size()-1; idom >=0; idom--)
11239                     orderedNodes.push_back( nodeDomains[nodes[ino]][orderDom[idom]] );
11240               SMDS_MeshVolume* vol = this->GetMeshDS()->AddVolumeFromVtkIds(orderedNodes);
11241
11242               stringstream grpname;
11243               grpname << "mj_";
11244               grpname << 0 << "_" << 0;
11245               int idg;
11246               string namegrp = grpname.str();
11247               if (!mapOfJunctionGroups.count(namegrp))
11248                 mapOfJunctionGroups[namegrp] = this->myMesh->AddGroup(SMDSAbs_Volume, namegrp.c_str(), idg);
11249               SMESHDS_Group *sgrp = dynamic_cast<SMESHDS_Group*>(mapOfJunctionGroups[namegrp]->GetGroupDS());
11250               if (sgrp)
11251                 sgrp->Add(vol->GetID());
11252             }
11253           else
11254             {
11255               //MESSAGE("Quadratic multiple joints not implemented");
11256               // TODO quadratic nodes
11257             }
11258         }
11259     }
11260
11261   // --- list the explicit faces and edges of the mesh that need to be modified,
11262   //     i.e. faces and edges built with one or more duplicated nodes.
11263   //     associate these faces or edges to their corresponding domain.
11264   //     only the first domain found is kept when a face or edge is shared
11265
11266   std::map<DownIdType, std::map<int,int>, DownIdCompare> faceOrEdgeDom; // cellToModify --> (id domain --> id cell)
11267   std::map<int,int> feDom; // vtk id of cell to modify --> id domain
11268   faceOrEdgeDom.clear();
11269   feDom.clear();
11270
11271   for (int idomain = 0; idomain < theElems.size(); idomain++)
11272     {
11273       std::map<int, std::map<int, int> >::const_iterator itnod = nodeDomains.begin();
11274       for (; itnod != nodeDomains.end(); ++itnod)
11275         {
11276           int oldId = itnod->first;
11277           //MESSAGE("     node " << oldId);
11278           vtkCellLinks::Link l = grid->GetCellLinks()->GetLink(oldId);
11279           for (int i = 0; i < l.ncells; i++)
11280             {
11281               int vtkId = l.cells[i];
11282               int vtkType = grid->GetCellType(vtkId);
11283               int downId = grid->CellIdToDownId(vtkId);
11284               if (downId < 0)
11285                 continue; // new cells: not to be modified
11286               DownIdType aCell(downId, vtkType);
11287               int volParents[1000];
11288               int nbvol = grid->GetParentVolumes(volParents, vtkId);
11289               for (int j = 0; j < nbvol; j++)
11290                 if (celldom.count(volParents[j]) && (celldom[volParents[j]] == idomain))
11291                   if (!feDom.count(vtkId))
11292                     {
11293                       feDom[vtkId] = idomain;
11294                       faceOrEdgeDom[aCell] = emptyMap;
11295                       faceOrEdgeDom[aCell][idomain] = vtkId; // affect face or edge to the first domain only
11296                       //MESSAGE("affect cell " << this->GetMeshDS()->fromVtkToSmds(vtkId) << " domain " << idomain
11297                       //        << " type " << vtkType << " downId " << downId);
11298                     }
11299             }
11300         }
11301     }
11302
11303   // --- iterate on shared faces (volumes to modify, face to extrude)
11304   //     get node id's of the face
11305   //     replace old nodes by new nodes in volumes, and update inverse connectivity
11306
11307   std::map<DownIdType, std::map<int,int>, DownIdCompare>* maps[3] = {&faceDomains, &cellDomains, &faceOrEdgeDom};
11308   for (int m=0; m<3; m++)
11309     {
11310       std::map<DownIdType, std::map<int,int>, DownIdCompare>* amap = maps[m];
11311       itface = (*amap).begin();
11312       for (; itface != (*amap).end(); ++itface)
11313         {
11314           DownIdType face = itface->first;
11315           std::set<int> oldNodes;
11316           std::set<int>::iterator itn;
11317           oldNodes.clear();
11318           grid->GetNodeIds(oldNodes, face.cellId, face.cellType);
11319           //MESSAGE("examine cell, downId " << face.cellId << " type " << int(face.cellType));
11320           std::map<int, int> localClonedNodeIds;
11321
11322           std::map<int, int> domvol = itface->second;
11323           std::map<int, int>::iterator itdom = domvol.begin();
11324           for (; itdom != domvol.end(); ++itdom)
11325             {
11326               int idom = itdom->first;
11327               int vtkVolId = itdom->second;
11328               //MESSAGE("modify nodes of cell " << this->GetMeshDS()->fromVtkToSmds(vtkVolId) << " domain " << idom);
11329               localClonedNodeIds.clear();
11330               for (itn = oldNodes.begin(); itn != oldNodes.end(); ++itn)
11331                 {
11332                   int oldId = *itn;
11333                   if (nodeDomains[oldId].count(idom))
11334                     {
11335                       localClonedNodeIds[oldId] = nodeDomains[oldId][idom];
11336                       //MESSAGE("     node " << oldId << " --> " << localClonedNodeIds[oldId]);
11337                     }
11338                 }
11339               meshDS->ModifyCellNodes(vtkVolId, localClonedNodeIds);
11340             }
11341         }
11342     }
11343
11344   meshDS->CleanDownWardConnectivity(); // Mesh has been modified, downward connectivity is no more usable, free memory
11345   grid->BuildLinks();
11346
11347   CHRONOSTOP(50);
11348   counters::stats();
11349   return true;
11350 }
11351
11352 /*!
11353  * \brief Double nodes on some external faces and create flat elements.
11354  * Flat elements are mainly used by some types of mechanic calculations.
11355  *
11356  * Each group of the list must be constituted of faces.
11357  * Triangles are transformed in prisms, and quadrangles in hexahedrons.
11358  * @param theElems - list of groups of faces, where a group of faces is a set of
11359  * SMDS_MeshElements sorted by Id.
11360  * @return TRUE if operation has been completed successfully, FALSE otherwise
11361  */
11362 bool SMESH_MeshEditor::CreateFlatElementsOnFacesGroups(const std::vector<TIDSortedElemSet>& theElems)
11363 {
11364   MESSAGE("-------------------------------------------------");
11365   MESSAGE("SMESH_MeshEditor::CreateFlatElementsOnFacesGroups");
11366   MESSAGE("-------------------------------------------------");
11367
11368   SMESHDS_Mesh *meshDS = this->myMesh->GetMeshDS();
11369
11370   // --- For each group of faces
11371   //     duplicate the nodes, create a flat element based on the face
11372   //     replace the nodes of the faces by their clones
11373
11374   std::map<const SMDS_MeshNode*, const SMDS_MeshNode*> clonedNodes;
11375   std::map<const SMDS_MeshNode*, const SMDS_MeshNode*> intermediateNodes;
11376   clonedNodes.clear();
11377   intermediateNodes.clear();
11378   std::map<std::string, SMESH_Group*> mapOfJunctionGroups;
11379   mapOfJunctionGroups.clear();
11380
11381   for (int idom = 0; idom < theElems.size(); idom++)
11382     {
11383       const TIDSortedElemSet& domain = theElems[idom];
11384       TIDSortedElemSet::const_iterator elemItr = domain.begin();
11385       for (; elemItr != domain.end(); ++elemItr)
11386         {
11387           SMDS_MeshElement* anElem = (SMDS_MeshElement*) *elemItr;
11388           SMDS_MeshFace* aFace = dynamic_cast<SMDS_MeshFace*> (anElem);
11389           if (!aFace)
11390             continue;
11391           // MESSAGE("aFace=" << aFace->GetID());
11392           bool isQuad = aFace->IsQuadratic();
11393           vector<const SMDS_MeshNode*> ln0, ln1, ln2, ln3, ln4;
11394
11395           // --- clone the nodes, create intermediate nodes for non medium nodes of a quad face
11396
11397           SMDS_ElemIteratorPtr nodeIt = aFace->nodesIterator();
11398           while (nodeIt->more())
11399             {
11400               const SMDS_MeshNode* node = static_cast<const SMDS_MeshNode*> (nodeIt->next());
11401               bool isMedium = isQuad && (aFace->IsMediumNode(node));
11402               if (isMedium)
11403                 ln2.push_back(node);
11404               else
11405                 ln0.push_back(node);
11406
11407               const SMDS_MeshNode* clone = 0;
11408               if (!clonedNodes.count(node))
11409                 {
11410                   clone = meshDS->AddNode(node->X(), node->Y(), node->Z());
11411                   clonedNodes[node] = clone;
11412                 }
11413               else
11414                 clone = clonedNodes[node];
11415
11416               if (isMedium)
11417                 ln3.push_back(clone);
11418               else
11419                 ln1.push_back(clone);
11420
11421               const SMDS_MeshNode* inter = 0;
11422               if (isQuad && (!isMedium))
11423                 {
11424                   if (!intermediateNodes.count(node))
11425                     {
11426                       inter = meshDS->AddNode(node->X(), node->Y(), node->Z());
11427                       intermediateNodes[node] = inter;
11428                     }
11429                   else
11430                     inter = intermediateNodes[node];
11431                   ln4.push_back(inter);
11432                 }
11433             }
11434
11435           // --- extrude the face
11436
11437           vector<const SMDS_MeshNode*> ln;
11438           SMDS_MeshVolume* vol = 0;
11439           vtkIdType aType = aFace->GetVtkType();
11440           switch (aType)
11441           {
11442             case VTK_TRIANGLE:
11443               vol = meshDS->AddVolume(ln0[2], ln0[1], ln0[0], ln1[2], ln1[1], ln1[0]);
11444               // MESSAGE("vol prism " << vol->GetID());
11445               ln.push_back(ln1[0]);
11446               ln.push_back(ln1[1]);
11447               ln.push_back(ln1[2]);
11448               break;
11449             case VTK_QUAD:
11450               vol = meshDS->AddVolume(ln0[3], ln0[2], ln0[1], ln0[0], ln1[3], ln1[2], ln1[1], ln1[0]);
11451               // MESSAGE("vol hexa " << vol->GetID());
11452               ln.push_back(ln1[0]);
11453               ln.push_back(ln1[1]);
11454               ln.push_back(ln1[2]);
11455               ln.push_back(ln1[3]);
11456               break;
11457             case VTK_QUADRATIC_TRIANGLE:
11458               vol = meshDS->AddVolume(ln1[0], ln1[1], ln1[2], ln0[0], ln0[1], ln0[2], ln3[0], ln3[1], ln3[2],
11459                                       ln2[0], ln2[1], ln2[2], ln4[0], ln4[1], ln4[2]);
11460               // MESSAGE("vol quad prism " << vol->GetID());
11461               ln.push_back(ln1[0]);
11462               ln.push_back(ln1[1]);
11463               ln.push_back(ln1[2]);
11464               ln.push_back(ln3[0]);
11465               ln.push_back(ln3[1]);
11466               ln.push_back(ln3[2]);
11467               break;
11468             case VTK_QUADRATIC_QUAD:
11469 //              vol = meshDS->AddVolume(ln0[0], ln0[1], ln0[2], ln0[3], ln1[0], ln1[1], ln1[2], ln1[3],
11470 //                                      ln2[0], ln2[1], ln2[2], ln2[3], ln3[0], ln3[1], ln3[2], ln3[3],
11471 //                                      ln4[0], ln4[1], ln4[2], ln4[3]);
11472               vol = meshDS->AddVolume(ln1[0], ln1[1], ln1[2], ln1[3], ln0[0], ln0[1], ln0[2], ln0[3],
11473                                       ln3[0], ln3[1], ln3[2], ln3[3], ln2[0], ln2[1], ln2[2], ln2[3],
11474                                       ln4[0], ln4[1], ln4[2], ln4[3]);
11475               // MESSAGE("vol quad hexa " << vol->GetID());
11476               ln.push_back(ln1[0]);
11477               ln.push_back(ln1[1]);
11478               ln.push_back(ln1[2]);
11479               ln.push_back(ln1[3]);
11480               ln.push_back(ln3[0]);
11481               ln.push_back(ln3[1]);
11482               ln.push_back(ln3[2]);
11483               ln.push_back(ln3[3]);
11484               break;
11485             case VTK_POLYGON:
11486               break;
11487             default:
11488               break;
11489           }
11490
11491           if (vol)
11492             {
11493               stringstream grpname;
11494               grpname << "jf_";
11495               grpname << idom;
11496               int idg;
11497               string namegrp = grpname.str();
11498               if (!mapOfJunctionGroups.count(namegrp))
11499                 mapOfJunctionGroups[namegrp] = this->myMesh->AddGroup(SMDSAbs_Volume, namegrp.c_str(), idg);
11500               SMESHDS_Group *sgrp = dynamic_cast<SMESHDS_Group*>(mapOfJunctionGroups[namegrp]->GetGroupDS());
11501               if (sgrp)
11502                 sgrp->Add(vol->GetID());
11503             }
11504
11505           // --- modify the face
11506
11507           aFace->ChangeNodes(&ln[0], ln.size());
11508         }
11509     }
11510   return true;
11511 }
11512
11513 //================================================================================
11514 /*!
11515  * \brief Generates skin mesh (containing 2D cells) from 3D mesh
11516  * The created 2D mesh elements based on nodes of free faces of boundary volumes
11517  * \return TRUE if operation has been completed successfully, FALSE otherwise
11518  */
11519 //================================================================================
11520
11521 bool SMESH_MeshEditor::Make2DMeshFrom3D()
11522 {
11523   // iterates on volume elements and detect all free faces on them
11524   SMESHDS_Mesh* aMesh = GetMeshDS();
11525   if (!aMesh)
11526     return false;
11527   //bool res = false;
11528   int nbFree = 0, nbExisted = 0, nbCreated = 0;
11529   SMDS_VolumeIteratorPtr vIt = aMesh->volumesIterator();
11530   while(vIt->more())
11531   {
11532     const SMDS_MeshVolume* volume = vIt->next();
11533     SMDS_VolumeTool vTool( volume );
11534     vTool.SetExternalNormal();
11535     const bool isPoly = volume->IsPoly();
11536     const bool isQuad = volume->IsQuadratic();
11537     for ( int iface = 0, n = vTool.NbFaces(); iface < n; iface++ )
11538     {
11539       if (!vTool.IsFreeFace(iface))
11540         continue;
11541       nbFree++;
11542       vector<const SMDS_MeshNode *> nodes;
11543       int nbFaceNodes = vTool.NbFaceNodes(iface);
11544       const SMDS_MeshNode** faceNodes = vTool.GetFaceNodes(iface);
11545       int inode = 0;
11546       for ( ; inode < nbFaceNodes; inode += isQuad ? 2 : 1)
11547         nodes.push_back(faceNodes[inode]);
11548       if (isQuad)
11549         for ( inode = 1; inode < nbFaceNodes; inode += 2)
11550           nodes.push_back(faceNodes[inode]);
11551
11552       // add new face based on volume nodes
11553       if (aMesh->FindFace( nodes ) ) {
11554         nbExisted++;
11555         continue; // face already exsist
11556       }
11557       AddElement(nodes, SMDSAbs_Face, isPoly && iface == 1);
11558       nbCreated++;
11559     }
11560   }
11561   return ( nbFree==(nbExisted+nbCreated) );
11562 }
11563
11564 namespace
11565 {
11566   inline const SMDS_MeshNode* getNodeWithSameID(SMESHDS_Mesh* mesh, const SMDS_MeshNode* node)
11567   {
11568     if ( const SMDS_MeshNode* n = mesh->FindNode( node->GetID() ))
11569       return n;
11570     return mesh->AddNodeWithID( node->X(),node->Y(),node->Z(), node->GetID() );
11571   }
11572 }
11573 //================================================================================
11574 /*!
11575  * \brief Creates missing boundary elements
11576  *  \param elements - elements whose boundary is to be checked
11577  *  \param dimension - defines type of boundary elements to create
11578  *  \param group - a group to store created boundary elements in
11579  *  \param targetMesh - a mesh to store created boundary elements in
11580  *  \param toCopyElements - if true, the checked elements will be copied into the targetMesh
11581  *  \param toCopyExistingBondary - if true, not only new but also pre-existing
11582  *                                boundary elements will be copied into the targetMesh
11583  *  \param toAddExistingBondary - if true, not only new but also pre-existing
11584  *                                boundary elements will be added into the new group
11585  *  \param aroundElements - if true, elements will be created on boundary of given
11586  *                          elements else, on boundary of the whole mesh. This
11587  *                          option works for 2D elements only.
11588  * \return nb of added boundary elements
11589  */
11590 //================================================================================
11591
11592 int SMESH_MeshEditor::MakeBoundaryMesh(const TIDSortedElemSet& elements,
11593                                        Bnd_Dimension           dimension,
11594                                        SMESH_Group*            group/*=0*/,
11595                                        SMESH_Mesh*             targetMesh/*=0*/,
11596                                        bool                    toCopyElements/*=false*/,
11597                                        bool                    toCopyExistingBondary/*=false*/,
11598                                        bool                    toAddExistingBondary/*= false*/,
11599                                        bool                    aroundElements/*= false*/)
11600 {
11601   SMDSAbs_ElementType missType = (dimension == BND_2DFROM3D) ? SMDSAbs_Face : SMDSAbs_Edge;
11602   SMDSAbs_ElementType elemType = (dimension == BND_1DFROM2D) ? SMDSAbs_Face : SMDSAbs_Volume;
11603   // hope that all elements are of the same type, do not check them all
11604   if ( !elements.empty() && (*elements.begin())->GetType() != elemType )
11605     throw SALOME_Exception(LOCALIZED("wrong element type"));
11606
11607   if ( aroundElements && elemType == SMDSAbs_Volume )
11608     throw SALOME_Exception(LOCALIZED("wrong element type for aroundElements==true"));
11609
11610   if ( !targetMesh )
11611     toCopyElements = toCopyExistingBondary = false;
11612
11613   SMESH_MeshEditor tgtEditor( targetMesh ? targetMesh : myMesh );
11614   SMESHDS_Mesh* aMesh = GetMeshDS(), *tgtMeshDS = tgtEditor.GetMeshDS();
11615   int nbAddedBnd = 0;
11616
11617   // editor adding present bnd elements and optionally holding elements to add to the group
11618   SMESH_MeshEditor* presentEditor;
11619   SMESH_MeshEditor tgtEditor2( tgtEditor.GetMesh() );
11620   presentEditor = toAddExistingBondary ? &tgtEditor : &tgtEditor2;
11621
11622   SMDS_VolumeTool vTool;
11623   TIDSortedElemSet avoidSet;
11624   const TIDSortedElemSet emptySet, *elemSet = aroundElements ? &elements : &emptySet;
11625   int inode;
11626
11627   typedef vector<const SMDS_MeshNode*> TConnectivity;
11628
11629   SMDS_ElemIteratorPtr eIt;
11630   if (elements.empty())
11631     eIt = aMesh->elementsIterator(elemType);
11632   else
11633     eIt = SMDS_ElemIteratorPtr( new TSetIterator( elements.begin(), elements.end() ));
11634
11635   while (eIt->more())
11636   {
11637     const SMDS_MeshElement* elem = eIt->next();
11638     const int iQuad = elem->IsQuadratic();
11639
11640     // ------------------------------------------------------------------------------------
11641     // 1. For an elem, get present bnd elements and connectivities of missing bnd elements
11642     // ------------------------------------------------------------------------------------
11643     vector<const SMDS_MeshElement*> presentBndElems;
11644     vector<TConnectivity>           missingBndElems;
11645     TConnectivity nodes;
11646     if ( vTool.Set(elem) ) // elem is a volume ------------------------------------------
11647     {
11648       vTool.SetExternalNormal();
11649       for ( int iface = 0, n = vTool.NbFaces(); iface < n; iface++ )
11650       {
11651         if (!vTool.IsFreeFace(iface))
11652           continue;
11653         int nbFaceNodes = vTool.NbFaceNodes(iface);
11654         const SMDS_MeshNode** nn = vTool.GetFaceNodes(iface);
11655         if ( missType == SMDSAbs_Edge ) // boundary edges
11656         {
11657           nodes.resize( 2+iQuad );
11658           for ( int i = 0; i < nbFaceNodes; i += 1+iQuad)
11659           {
11660             for ( int j = 0; j < nodes.size(); ++j )
11661               nodes[j] =nn[i+j];
11662             if ( const SMDS_MeshElement* edge =
11663                  aMesh->FindElement(nodes,SMDSAbs_Edge,/*noMedium=*/0))
11664               presentBndElems.push_back( edge );
11665             else
11666               missingBndElems.push_back( nodes );
11667           }
11668         }
11669         else // boundary face
11670         {
11671           nodes.clear();
11672           for ( inode = 0; inode < nbFaceNodes; inode += 1+iQuad)
11673             nodes.push_back( nn[inode] );
11674           if (iQuad)
11675             for ( inode = 1; inode < nbFaceNodes; inode += 2)
11676               nodes.push_back( nn[inode] );
11677
11678           if (const SMDS_MeshFace * f = aMesh->FindFace( nodes ) )
11679             presentBndElems.push_back( f );
11680           else
11681             missingBndElems.push_back( nodes );
11682         }
11683       }
11684     }
11685     else                     // elem is a face ------------------------------------------
11686     {
11687       avoidSet.clear(), avoidSet.insert( elem );
11688       int nbNodes = elem->NbCornerNodes();
11689       nodes.resize( 2 /*+ iQuad*/);
11690       for ( int i = 0; i < nbNodes; i++ )
11691       {
11692         nodes[0] = elem->GetNode(i);
11693         nodes[1] = elem->GetNode((i+1)%nbNodes);
11694         if ( FindFaceInSet( nodes[0], nodes[1], *elemSet, avoidSet))
11695           continue; // not free link
11696
11697         //if ( iQuad )
11698         //nodes[2] = elem->GetNode( i + nbNodes );
11699         if ( const SMDS_MeshElement* edge =
11700              aMesh->FindElement(nodes,SMDSAbs_Edge,/*noMedium=*/true))
11701           presentBndElems.push_back( edge );
11702         else
11703           missingBndElems.push_back( nodes );
11704       }
11705     }
11706
11707     // ---------------------------------
11708     // 2. Add missing boundary elements
11709     // ---------------------------------
11710     if ( targetMesh != myMesh )
11711       // instead of making a map of nodes in this mesh and targetMesh,
11712       // we create nodes with same IDs. We can renumber them later, if needed
11713       for ( int i = 0; i < missingBndElems.size(); ++i )
11714       {
11715         TConnectivity& srcNodes = missingBndElems[i];
11716         TConnectivity  nodes( srcNodes.size() );
11717         for ( inode = 0; inode < nodes.size(); ++inode )
11718           nodes[inode] = getNodeWithSameID( tgtMeshDS, srcNodes[inode] );
11719         if ( aroundElements && tgtEditor.GetMeshDS()->FindElement( nodes,
11720                                                                    missType,
11721                                                                    /*noMedium=*/true))
11722           continue;
11723         tgtEditor.AddElement(nodes, missType, elem->IsPoly() && nodes.size()/(iQuad+1)>4);
11724         ++nbAddedBnd;
11725       }
11726     else
11727       for ( int i = 0; i < missingBndElems.size(); ++i )
11728       {
11729         TConnectivity& nodes = missingBndElems[i];
11730         if ( aroundElements && tgtEditor.GetMeshDS()->FindElement( nodes,
11731                                                                    missType,
11732                                                                    /*noMedium=*/true))
11733           continue;
11734         tgtEditor.AddElement(nodes, missType, elem->IsPoly() && nodes.size()/(iQuad+1)>4);
11735         ++nbAddedBnd;
11736       }
11737
11738     // ----------------------------------
11739     // 3. Copy present boundary elements
11740     // ----------------------------------
11741     if ( toCopyExistingBondary )
11742       for ( int i = 0 ; i < presentBndElems.size(); ++i )
11743       {
11744         const SMDS_MeshElement* e = presentBndElems[i];
11745         TConnectivity nodes( e->NbNodes() );
11746         for ( inode = 0; inode < nodes.size(); ++inode )
11747           nodes[inode] = getNodeWithSameID( tgtMeshDS, e->GetNode(inode) );
11748         presentEditor->AddElement(nodes, missType, e->IsPoly());
11749       }
11750     else // store present elements to add them to a group
11751       for ( int i = 0 ; i < presentBndElems.size(); ++i )
11752       {
11753         presentEditor->myLastCreatedElems.Append(presentBndElems[i]);
11754       }
11755       
11756   } // loop on given elements
11757
11758   // ---------------------------------------------
11759   // 4. Fill group with boundary elements
11760   // ---------------------------------------------
11761   if ( group )
11762   {
11763     if ( SMESHDS_Group* g = dynamic_cast<SMESHDS_Group*>( group->GetGroupDS() ))
11764       for ( int i = 0; i < tgtEditor.myLastCreatedElems.Size(); ++i )
11765         g->SMDSGroup().Add( tgtEditor.myLastCreatedElems( i+1 ));
11766   }
11767   tgtEditor.myLastCreatedElems.Clear();
11768   tgtEditor2.myLastCreatedElems.Clear();
11769
11770   // -----------------------
11771   // 5. Copy given elements
11772   // -----------------------
11773   if ( toCopyElements && targetMesh != myMesh )
11774   {
11775     if (elements.empty())
11776       eIt = aMesh->elementsIterator(elemType);
11777     else
11778       eIt = SMDS_ElemIteratorPtr( new TSetIterator( elements.begin(), elements.end() ));
11779     while (eIt->more())
11780     {
11781       const SMDS_MeshElement* elem = eIt->next();
11782       TConnectivity nodes( elem->NbNodes() );
11783       for ( inode = 0; inode < nodes.size(); ++inode )
11784         nodes[inode] = getNodeWithSameID( tgtMeshDS, elem->GetNode(inode) );
11785       tgtEditor.AddElement(nodes, elemType, elem->IsPoly());
11786
11787       tgtEditor.myLastCreatedElems.Clear();
11788     }
11789   }
11790   return nbAddedBnd;
11791 }