Salome HOME
48784b5f2b0d0237d653e4623de33ac03eec25d4
[modules/smesh.git] / src / SMESH / SMESH_MeshEditor.cxx
1 //  Copyright (C) 2007-2010  CEA/DEN, EDF R&D, OPEN CASCADE
2 //
3 //  Copyright (C) 2003-2007  OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN,
4 //  CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS
5 //
6 //  This library is free software; you can redistribute it and/or
7 //  modify it under the terms of the GNU Lesser General Public
8 //  License as published by the Free Software Foundation; either
9 //  version 2.1 of the License.
10 //
11 //  This library is distributed in the hope that it will be useful,
12 //  but WITHOUT ANY WARRANTY; without even the implied warranty of
13 //  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14 //  Lesser General Public License for more details.
15 //
16 //  You should have received a copy of the GNU Lesser General Public
17 //  License along with this library; if not, write to the Free Software
18 //  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
19 //
20 //  See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
21 //
22
23 //  SMESH SMESH : idl implementation based on 'SMESH' unit's classes
24 // File      : SMESH_MeshEditor.cxx
25 // Created   : Mon Apr 12 16:10:22 2004
26 // Author    : Edward AGAPOV (eap)
27 //
28 #define CHRONODEF
29 #include "SMESH_MeshEditor.hxx"
30
31 #include "SMDS_FaceOfNodes.hxx"
32 #include "SMDS_VolumeTool.hxx"
33 #include "SMDS_EdgePosition.hxx"
34 #include "SMDS_PolyhedralVolumeOfNodes.hxx"
35 #include "SMDS_FacePosition.hxx"
36 #include "SMDS_SpacePosition.hxx"
37 //#include "SMDS_QuadraticFaceOfNodes.hxx"
38 #include "SMDS_MeshGroup.hxx"
39 #include "SMDS_LinearEdge.hxx"
40 #include "SMDS_Downward.hxx"
41 #include "SMDS_SetIterator.hxx"
42
43 #include "SMESHDS_Group.hxx"
44 #include "SMESHDS_Mesh.hxx"
45
46 #include "SMESH_Algo.hxx"
47 #include "SMESH_ControlsDef.hxx"
48 #include "SMESH_Group.hxx"
49 #include "SMESH_MesherHelper.hxx"
50 #include "SMESH_OctreeNode.hxx"
51 #include "SMESH_subMesh.hxx"
52
53 #include "utilities.h"
54
55 #include <BRepAdaptor_Surface.hxx>
56 #include <BRepClass3d_SolidClassifier.hxx>
57 #include <BRep_Tool.hxx>
58 #include <ElCLib.hxx>
59 #include <Extrema_GenExtPS.hxx>
60 #include <Extrema_POnCurv.hxx>
61 #include <Extrema_POnSurf.hxx>
62 #include <GC_MakeSegment.hxx>
63 #include <Geom2d_Curve.hxx>
64 #include <GeomAPI_ExtremaCurveCurve.hxx>
65 #include <GeomAdaptor_Surface.hxx>
66 #include <Geom_Curve.hxx>
67 #include <Geom_Line.hxx>
68 #include <Geom_Surface.hxx>
69 #include <IntAna_IntConicQuad.hxx>
70 #include <IntAna_Quadric.hxx>
71 #include <Precision.hxx>
72 #include <TColStd_ListOfInteger.hxx>
73 #include <TopAbs_State.hxx>
74 #include <TopExp.hxx>
75 #include <TopExp_Explorer.hxx>
76 #include <TopTools_ListIteratorOfListOfShape.hxx>
77 #include <TopTools_ListOfShape.hxx>
78 #include <TopTools_SequenceOfShape.hxx>
79 #include <TopoDS.hxx>
80 #include <TopoDS_Face.hxx>
81 #include <gp.hxx>
82 #include <gp_Ax1.hxx>
83 #include <gp_Dir.hxx>
84 #include <gp_Lin.hxx>
85 #include <gp_Pln.hxx>
86 #include <gp_Trsf.hxx>
87 #include <gp_Vec.hxx>
88 #include <gp_XY.hxx>
89 #include <gp_XYZ.hxx>
90
91 #include <math.h>
92
93 #include <map>
94 #include <set>
95 #include <numeric>
96 #include <limits>
97
98 #define cast2Node(elem) static_cast<const SMDS_MeshNode*>( elem )
99
100 using namespace std;
101 using namespace SMESH::Controls;
102
103 typedef map<const SMDS_MeshElement*, list<const SMDS_MeshNode*> >    TElemOfNodeListMap;
104 typedef map<const SMDS_MeshElement*, list<const SMDS_MeshElement*> > TElemOfElemListMap;
105
106 typedef SMDS_SetIterator< SMDS_pElement, TIDSortedElemSet::const_iterator> TSetIterator;
107
108 //=======================================================================
109 //function : SMESH_MeshEditor
110 //purpose  :
111 //=======================================================================
112
113 SMESH_MeshEditor::SMESH_MeshEditor( SMESH_Mesh* theMesh )
114   :myMesh( theMesh ) // theMesh may be NULL
115 {
116 }
117
118 //=======================================================================
119 /*!
120  * \brief Add element
121  */
122 //=======================================================================
123
124 SMDS_MeshElement*
125 SMESH_MeshEditor::AddElement(const vector<const SMDS_MeshNode*> & node,
126                              const SMDSAbs_ElementType            type,
127                              const bool                           isPoly,
128                              const int                            ID)
129 {
130   //MESSAGE("AddElement " <<node.size() << " " << type << " " << isPoly << " " << ID);
131   SMDS_MeshElement* e = 0;
132   int nbnode = node.size();
133   SMESHDS_Mesh* mesh = GetMeshDS();
134   switch ( type ) {
135   case SMDSAbs_Face:
136     if ( !isPoly ) {
137       if      (nbnode == 3) {
138         if ( ID >= 1 ) e = mesh->AddFaceWithID(node[0], node[1], node[2], ID);
139         else           e = mesh->AddFace      (node[0], node[1], node[2] );
140       }
141       else if (nbnode == 4) {
142         if ( ID >= 1 ) e = mesh->AddFaceWithID(node[0], node[1], node[2], node[3], ID);
143         else           e = mesh->AddFace      (node[0], node[1], node[2], node[3] );
144       }
145       else if (nbnode == 6) {
146         if ( ID >= 1 ) e = mesh->AddFaceWithID(node[0], node[1], node[2], node[3],
147                                                node[4], node[5], ID);
148         else           e = mesh->AddFace      (node[0], node[1], node[2], node[3],
149                                                node[4], node[5] );
150       }
151       else if (nbnode == 8) {
152         if ( ID >= 1 ) e = mesh->AddFaceWithID(node[0], node[1], node[2], node[3],
153                                                node[4], node[5], node[6], node[7], ID);
154         else           e = mesh->AddFace      (node[0], node[1], node[2], node[3],
155                                                node[4], node[5], node[6], node[7] );
156       }
157     } else {
158       if ( ID >= 1 ) e = mesh->AddPolygonalFaceWithID(node, ID);
159       else           e = mesh->AddPolygonalFace      (node    );
160     }
161     break;
162
163   case SMDSAbs_Volume:
164     if ( !isPoly ) {
165       if      (nbnode == 4) {
166         if ( ID >= 1 ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3], ID);
167         else           e = mesh->AddVolume      (node[0], node[1], node[2], node[3] );
168       }
169       else if (nbnode == 5) {
170         if ( ID >= 1 ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
171                                                  node[4], ID);
172         else           e = mesh->AddVolume      (node[0], node[1], node[2], node[3],
173                                                  node[4] );
174       }
175       else if (nbnode == 6) {
176         if ( ID >= 1 ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
177                                                  node[4], node[5], ID);
178         else           e = mesh->AddVolume      (node[0], node[1], node[2], node[3],
179                                                  node[4], node[5] );
180       }
181       else if (nbnode == 8) {
182         if ( ID >= 1 ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
183                                                  node[4], node[5], node[6], node[7], ID);
184         else           e = mesh->AddVolume      (node[0], node[1], node[2], node[3],
185                                                  node[4], node[5], node[6], node[7] );
186       }
187       else if (nbnode == 10) {
188         if ( ID >= 1 ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
189                                                  node[4], node[5], node[6], node[7],
190                                                  node[8], node[9], ID);
191         else           e = mesh->AddVolume      (node[0], node[1], node[2], node[3],
192                                                  node[4], node[5], node[6], node[7],
193                                                  node[8], node[9] );
194       }
195       else if (nbnode == 13) {
196         if ( ID >= 1 ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
197                                                  node[4], node[5], node[6], node[7],
198                                                  node[8], node[9], node[10],node[11],
199                                                  node[12],ID);
200         else           e = mesh->AddVolume      (node[0], node[1], node[2], node[3],
201                                                  node[4], node[5], node[6], node[7],
202                                                  node[8], node[9], node[10],node[11],
203                                                  node[12] );
204       }
205       else if (nbnode == 15) {
206         if ( ID >= 1 ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
207                                                  node[4], node[5], node[6], node[7],
208                                                  node[8], node[9], node[10],node[11],
209                                                  node[12],node[13],node[14],ID);
210         else           e = mesh->AddVolume      (node[0], node[1], node[2], node[3],
211                                                  node[4], node[5], node[6], node[7],
212                                                  node[8], node[9], node[10],node[11],
213                                                  node[12],node[13],node[14] );
214       }
215       else if (nbnode == 20) {
216         if ( ID >= 1 ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
217                                                  node[4], node[5], node[6], node[7],
218                                                  node[8], node[9], node[10],node[11],
219                                                  node[12],node[13],node[14],node[15],
220                                                  node[16],node[17],node[18],node[19],ID);
221         else           e = mesh->AddVolume      (node[0], node[1], node[2], node[3],
222                                                  node[4], node[5], node[6], node[7],
223                                                  node[8], node[9], node[10],node[11],
224                                                  node[12],node[13],node[14],node[15],
225                                                  node[16],node[17],node[18],node[19] );
226       }
227     }
228     break;
229
230   case SMDSAbs_Edge:
231     if ( nbnode == 2 ) {
232       if ( ID >= 1 ) e = mesh->AddEdgeWithID(node[0], node[1], ID);
233       else           e = mesh->AddEdge      (node[0], node[1] );
234     }
235     else if ( nbnode == 3 ) {
236       if ( ID >= 1 ) e = mesh->AddEdgeWithID(node[0], node[1], node[2], ID);
237       else           e = mesh->AddEdge      (node[0], node[1], node[2] );
238     }
239     break;
240
241   case SMDSAbs_0DElement:
242     if ( nbnode == 1 ) {
243       if ( ID >= 1 ) e = mesh->Add0DElementWithID(node[0], ID);
244       else           e = mesh->Add0DElement      (node[0] );
245     }
246     break;
247
248   case SMDSAbs_Node:
249     if ( ID >= 1 ) e = mesh->AddNodeWithID(node[0]->X(), node[0]->Y(), node[0]->Z(), ID);
250     else           e = mesh->AddNode      (node[0]->X(), node[0]->Y(), node[0]->Z());
251     break;
252
253   default:;
254   }
255   if ( e ) myLastCreatedElems.Append( e );
256   return e;
257 }
258
259 //=======================================================================
260 /*!
261  * \brief Add element
262  */
263 //=======================================================================
264
265 SMDS_MeshElement* SMESH_MeshEditor::AddElement(const vector<int> &       nodeIDs,
266                                                const SMDSAbs_ElementType type,
267                                                const bool                isPoly,
268                                                const int                 ID)
269 {
270   vector<const SMDS_MeshNode*> nodes;
271   nodes.reserve( nodeIDs.size() );
272   vector<int>::const_iterator id = nodeIDs.begin();
273   while ( id != nodeIDs.end() ) {
274     if ( const SMDS_MeshNode* node = GetMeshDS()->FindNode( *id++ ))
275       nodes.push_back( node );
276     else
277       return 0;
278   }
279   return AddElement( nodes, type, isPoly, ID );
280 }
281
282 //=======================================================================
283 //function : Remove
284 //purpose  : Remove a node or an element.
285 //           Modify a compute state of sub-meshes which become empty
286 //=======================================================================
287
288 int SMESH_MeshEditor::Remove (const list< int >& theIDs,
289                               const bool         isNodes )
290 {
291   myLastCreatedElems.Clear();
292   myLastCreatedNodes.Clear();
293
294   SMESHDS_Mesh* aMesh = GetMeshDS();
295   set< SMESH_subMesh *> smmap;
296
297   int removed = 0;
298   list<int>::const_iterator it = theIDs.begin();
299   for ( ; it != theIDs.end(); it++ ) {
300     const SMDS_MeshElement * elem;
301     if ( isNodes )
302       elem = aMesh->FindNode( *it );
303     else
304       elem = aMesh->FindElement( *it );
305     if ( !elem )
306       continue;
307
308     // Notify VERTEX sub-meshes about modification
309     if ( isNodes ) {
310       const SMDS_MeshNode* node = cast2Node( elem );
311       if ( node->GetPosition()->GetTypeOfPosition() == SMDS_TOP_VERTEX )
312         if ( int aShapeID = node->getshapeId() )
313           if ( SMESH_subMesh * sm = GetMesh()->GetSubMeshContaining( aShapeID ) )
314             smmap.insert( sm );
315     }
316     // Find sub-meshes to notify about modification
317     //     SMDS_ElemIteratorPtr nodeIt = elem->nodesIterator();
318     //     while ( nodeIt->more() ) {
319     //       const SMDS_MeshNode* node = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
320     //       const SMDS_PositionPtr& aPosition = node->GetPosition();
321     //       if ( aPosition.get() ) {
322     //         if ( int aShapeID = aPosition->GetShapeId() ) {
323     //           if ( SMESH_subMesh * sm = GetMesh()->GetSubMeshContaining( aShapeID ) )
324     //             smmap.insert( sm );
325     //         }
326     //       }
327     //     }
328
329     // Do remove
330     if ( isNodes )
331       aMesh->RemoveNode( static_cast< const SMDS_MeshNode* >( elem ));
332     else
333       aMesh->RemoveElement( elem );
334     removed++;
335   }
336
337   // Notify sub-meshes about modification
338   if ( !smmap.empty() ) {
339     set< SMESH_subMesh *>::iterator smIt;
340     for ( smIt = smmap.begin(); smIt != smmap.end(); smIt++ )
341       (*smIt)->ComputeStateEngine( SMESH_subMesh::MESH_ENTITY_REMOVED );
342   }
343
344   //   // Check if the whole mesh becomes empty
345   //   if ( SMESH_subMesh * sm = GetMesh()->GetSubMeshContaining( 1 ) )
346   //     sm->ComputeStateEngine( SMESH_subMesh::CHECK_COMPUTE_STATE );
347
348   return removed;
349 }
350
351 //=======================================================================
352 //function : FindShape
353 //purpose  : Return an index of the shape theElem is on
354 //           or zero if a shape not found
355 //=======================================================================
356
357 int SMESH_MeshEditor::FindShape (const SMDS_MeshElement * theElem)
358 {
359   myLastCreatedElems.Clear();
360   myLastCreatedNodes.Clear();
361
362   SMESHDS_Mesh * aMesh = GetMeshDS();
363   if ( aMesh->ShapeToMesh().IsNull() )
364     return 0;
365
366   if ( theElem->GetType() == SMDSAbs_Node )
367     {
368       int aShapeID = theElem->getshapeId();
369       if (aShapeID <= 0)
370         return 0;
371       else
372         return aShapeID;
373     }
374
375   TopoDS_Shape aShape; // the shape a node is on
376   SMDS_ElemIteratorPtr nodeIt = theElem->nodesIterator();
377   while ( nodeIt->more() ) {
378     const SMDS_MeshNode* node = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
379     int aShapeID = node->getshapeId();
380     if (aShapeID > 0) {
381       SMESHDS_SubMesh * sm = aMesh->MeshElements( aShapeID );
382       if ( sm ) {
383         if ( sm->Contains( theElem ))
384           return aShapeID;
385         if ( aShape.IsNull() )
386           aShape = aMesh->IndexToShape( aShapeID );
387       }
388       else {
389         //MESSAGE ( "::FindShape() No SubShape for aShapeID " << aShapeID );
390       }
391     }
392   }
393
394   // None of nodes is on a proper shape,
395   // find the shape among ancestors of aShape on which a node is
396   if ( aShape.IsNull() ) {
397     //MESSAGE ("::FindShape() - NONE node is on shape")
398     return 0;
399   }
400   TopTools_ListIteratorOfListOfShape ancIt( GetMesh()->GetAncestors( aShape ));
401   for ( ; ancIt.More(); ancIt.Next() ) {
402     SMESHDS_SubMesh * sm = aMesh->MeshElements( ancIt.Value() );
403     if ( sm && sm->Contains( theElem ))
404       return aMesh->ShapeToIndex( ancIt.Value() );
405   }
406
407   //MESSAGE ("::FindShape() - SHAPE NOT FOUND")
408   return 0;
409 }
410
411 //=======================================================================
412 //function : IsMedium
413 //purpose  :
414 //=======================================================================
415
416 bool SMESH_MeshEditor::IsMedium(const SMDS_MeshNode*      node,
417                                 const SMDSAbs_ElementType typeToCheck)
418 {
419   bool isMedium = false;
420   SMDS_ElemIteratorPtr it = node->GetInverseElementIterator(typeToCheck);
421   while (it->more() && !isMedium ) {
422     const SMDS_MeshElement* elem = it->next();
423     isMedium = elem->IsMediumNode(node);
424   }
425   return isMedium;
426 }
427
428 //=======================================================================
429 //function : ShiftNodesQuadTria
430 //purpose  : auxilary
431 //           Shift nodes in the array corresponded to quadratic triangle
432 //           example: (0,1,2,3,4,5) -> (1,2,0,4,5,3)
433 //=======================================================================
434 static void ShiftNodesQuadTria(const SMDS_MeshNode* aNodes[])
435 {
436   const SMDS_MeshNode* nd1 = aNodes[0];
437   aNodes[0] = aNodes[1];
438   aNodes[1] = aNodes[2];
439   aNodes[2] = nd1;
440   const SMDS_MeshNode* nd2 = aNodes[3];
441   aNodes[3] = aNodes[4];
442   aNodes[4] = aNodes[5];
443   aNodes[5] = nd2;
444 }
445
446 //=======================================================================
447 //function : GetNodesFromTwoTria
448 //purpose  : auxilary
449 //           Shift nodes in the array corresponded to quadratic triangle
450 //           example: (0,1,2,3,4,5) -> (1,2,0,4,5,3)
451 //=======================================================================
452 static bool GetNodesFromTwoTria(const SMDS_MeshElement * theTria1,
453                                 const SMDS_MeshElement * theTria2,
454                                 const SMDS_MeshNode* N1[],
455                                 const SMDS_MeshNode* N2[])
456 {
457   SMDS_ElemIteratorPtr it = theTria1->nodesIterator();
458   int i=0;
459   while(i<6) {
460     N1[i] = static_cast<const SMDS_MeshNode*>( it->next() );
461     i++;
462   }
463   if(it->more()) return false;
464   it = theTria2->nodesIterator();
465   i=0;
466   while(i<6) {
467     N2[i] = static_cast<const SMDS_MeshNode*>( it->next() );
468     i++;
469   }
470   if(it->more()) return false;
471
472   int sames[3] = {-1,-1,-1};
473   int nbsames = 0;
474   int j;
475   for(i=0; i<3; i++) {
476     for(j=0; j<3; j++) {
477       if(N1[i]==N2[j]) {
478         sames[i] = j;
479         nbsames++;
480         break;
481       }
482     }
483   }
484   if(nbsames!=2) return false;
485   if(sames[0]>-1) {
486     ShiftNodesQuadTria(N1);
487     if(sames[1]>-1) {
488       ShiftNodesQuadTria(N1);
489     }
490   }
491   i = sames[0] + sames[1] + sames[2];
492   for(; i<2; i++) {
493     ShiftNodesQuadTria(N2);
494   }
495   // now we receive following N1 and N2 (using numeration as above image)
496   // tria1 : (1 2 4 5 9 7)  and  tria2 : (3 4 2 8 9 6)
497   // i.e. first nodes from both arrays determ new diagonal
498   return true;
499 }
500
501 //=======================================================================
502 //function : InverseDiag
503 //purpose  : Replace two neighbour triangles with ones built on the same 4 nodes
504 //           but having other common link.
505 //           Return False if args are improper
506 //=======================================================================
507
508 bool SMESH_MeshEditor::InverseDiag (const SMDS_MeshElement * theTria1,
509                                     const SMDS_MeshElement * theTria2 )
510 {
511   MESSAGE("InverseDiag");
512   myLastCreatedElems.Clear();
513   myLastCreatedNodes.Clear();
514
515   if (!theTria1 || !theTria2)
516     return false;
517
518   const SMDS_VtkFace* F1 = dynamic_cast<const SMDS_VtkFace*>( theTria1 );
519   if (!F1) return false;
520   const SMDS_VtkFace* F2 = dynamic_cast<const SMDS_VtkFace*>( theTria2 );
521   if (!F2) return false;
522   if ((theTria1->GetEntityType() == SMDSEntity_Triangle) &&
523       (theTria2->GetEntityType() == SMDSEntity_Triangle)) {
524
525     //  1 +--+ A  theTria1: ( 1 A B ) A->2 ( 1 2 B ) 1 +--+ A
526     //    | /|    theTria2: ( B A 2 ) B->1 ( 1 A 2 )   |\ |
527     //    |/ |                                         | \|
528     //  B +--+ 2                                     B +--+ 2
529
530     // put nodes in array and find out indices of the same ones
531     const SMDS_MeshNode* aNodes [6];
532     int sameInd [] = { 0, 0, 0, 0, 0, 0 };
533     int i = 0;
534     SMDS_ElemIteratorPtr it = theTria1->nodesIterator();
535     while ( it->more() ) {
536       aNodes[ i ] = static_cast<const SMDS_MeshNode*>( it->next() );
537
538       if ( i > 2 ) // theTria2
539         // find same node of theTria1
540         for ( int j = 0; j < 3; j++ )
541           if ( aNodes[ i ] == aNodes[ j ]) {
542             sameInd[ j ] = i;
543             sameInd[ i ] = j;
544             break;
545           }
546       // next
547       i++;
548       if ( i == 3 ) {
549         if ( it->more() )
550           return false; // theTria1 is not a triangle
551         it = theTria2->nodesIterator();
552       }
553       if ( i == 6 && it->more() )
554         return false; // theTria2 is not a triangle
555     }
556
557     // find indices of 1,2 and of A,B in theTria1
558     int iA = 0, iB = 0, i1 = 0, i2 = 0;
559     for ( i = 0; i < 6; i++ ) {
560       if ( sameInd [ i ] == 0 ) {
561         if ( i < 3 ) i1 = i;
562         else         i2 = i;
563       }
564       else if (i < 3) {
565         if ( iA ) iB = i;
566         else      iA = i;
567       }
568     }
569     // nodes 1 and 2 should not be the same
570     if ( aNodes[ i1 ] == aNodes[ i2 ] )
571       return false;
572
573     // theTria1: A->2
574     aNodes[ iA ] = aNodes[ i2 ];
575     // theTria2: B->1
576     aNodes[ sameInd[ iB ]] = aNodes[ i1 ];
577
578     GetMeshDS()->ChangeElementNodes( theTria1, aNodes, 3 );
579     GetMeshDS()->ChangeElementNodes( theTria2, &aNodes[ 3 ], 3 );
580
581     return true;
582
583   } // end if(F1 && F2)
584
585   // check case of quadratic faces
586   if (theTria1->GetEntityType() != SMDSEntity_Quad_Triangle)
587     return false;
588   if (theTria2->GetEntityType() != SMDSEntity_Quad_Triangle)
589     return false;
590
591   //       5
592   //  1 +--+--+ 2  theTria1: (1 2 4 5 9 7) or (2 4 1 9 7 5) or (4 1 2 7 5 9)
593   //    |    /|    theTria2: (2 3 4 6 8 9) or (3 4 2 8 9 6) or (4 2 3 9 6 8)
594   //    |   / |
595   //  7 +  +  + 6
596   //    | /9  |
597   //    |/    |
598   //  4 +--+--+ 3
599   //       8
600
601   const SMDS_MeshNode* N1 [6];
602   const SMDS_MeshNode* N2 [6];
603   if(!GetNodesFromTwoTria(theTria1,theTria2,N1,N2))
604     return false;
605   // now we receive following N1 and N2 (using numeration as above image)
606   // tria1 : (1 2 4 5 9 7)  and  tria2 : (3 4 2 8 9 6)
607   // i.e. first nodes from both arrays determ new diagonal
608
609   const SMDS_MeshNode* N1new [6];
610   const SMDS_MeshNode* N2new [6];
611   N1new[0] = N1[0];
612   N1new[1] = N2[0];
613   N1new[2] = N2[1];
614   N1new[3] = N1[4];
615   N1new[4] = N2[3];
616   N1new[5] = N1[5];
617   N2new[0] = N1[0];
618   N2new[1] = N1[1];
619   N2new[2] = N2[0];
620   N2new[3] = N1[3];
621   N2new[4] = N2[5];
622   N2new[5] = N1[4];
623   // replaces nodes in faces
624   GetMeshDS()->ChangeElementNodes( theTria1, N1new, 6 );
625   GetMeshDS()->ChangeElementNodes( theTria2, N2new, 6 );
626
627   return true;
628 }
629
630 //=======================================================================
631 //function : findTriangles
632 //purpose  : find triangles sharing theNode1-theNode2 link
633 //=======================================================================
634
635 static bool findTriangles(const SMDS_MeshNode *    theNode1,
636                           const SMDS_MeshNode *    theNode2,
637                           const SMDS_MeshElement*& theTria1,
638                           const SMDS_MeshElement*& theTria2)
639 {
640   if ( !theNode1 || !theNode2 ) return false;
641
642   theTria1 = theTria2 = 0;
643
644   set< const SMDS_MeshElement* > emap;
645   SMDS_ElemIteratorPtr it = theNode1->GetInverseElementIterator(SMDSAbs_Face);
646   while (it->more()) {
647     const SMDS_MeshElement* elem = it->next();
648     if ( elem->NbNodes() == 3 )
649       emap.insert( elem );
650   }
651   it = theNode2->GetInverseElementIterator(SMDSAbs_Face);
652   while (it->more()) {
653     const SMDS_MeshElement* elem = it->next();
654     if ( emap.find( elem ) != emap.end() ) {
655       if ( theTria1 ) {
656         // theTria1 must be element with minimum ID
657         if( theTria1->GetID() < elem->GetID() ) {
658           theTria2 = elem;
659         }
660         else {
661           theTria2 = theTria1;
662           theTria1 = elem;
663         }
664         break;
665       }
666       else {
667         theTria1 = elem;
668       }
669     }
670   }
671   return ( theTria1 && theTria2 );
672 }
673
674 //=======================================================================
675 //function : InverseDiag
676 //purpose  : Replace two neighbour triangles sharing theNode1-theNode2 link
677 //           with ones built on the same 4 nodes but having other common link.
678 //           Return false if proper faces not found
679 //=======================================================================
680
681 bool SMESH_MeshEditor::InverseDiag (const SMDS_MeshNode * theNode1,
682                                     const SMDS_MeshNode * theNode2)
683 {
684   myLastCreatedElems.Clear();
685   myLastCreatedNodes.Clear();
686
687   MESSAGE( "::InverseDiag()" );
688
689   const SMDS_MeshElement *tr1, *tr2;
690   if ( !findTriangles( theNode1, theNode2, tr1, tr2 ))
691     return false;
692
693   const SMDS_VtkFace* F1 = dynamic_cast<const SMDS_VtkFace*>( tr1 );
694   if (!F1) return false;
695   const SMDS_VtkFace* F2 = dynamic_cast<const SMDS_VtkFace*>( tr2 );
696   if (!F2) return false;
697   if ((tr1->GetEntityType() == SMDSEntity_Triangle) &&
698       (tr2->GetEntityType() == SMDSEntity_Triangle)) {
699
700     //  1 +--+ A  tr1: ( 1 A B ) A->2 ( 1 2 B ) 1 +--+ A
701     //    | /|    tr2: ( B A 2 ) B->1 ( 1 A 2 )   |\ |
702     //    |/ |                                    | \|
703     //  B +--+ 2                                B +--+ 2
704
705     // put nodes in array
706     // and find indices of 1,2 and of A in tr1 and of B in tr2
707     int i, iA1 = 0, i1 = 0;
708     const SMDS_MeshNode* aNodes1 [3];
709     SMDS_ElemIteratorPtr it;
710     for (i = 0, it = tr1->nodesIterator(); it->more(); i++ ) {
711       aNodes1[ i ] = static_cast<const SMDS_MeshNode*>( it->next() );
712       if ( aNodes1[ i ] == theNode1 )
713         iA1 = i; // node A in tr1
714       else if ( aNodes1[ i ] != theNode2 )
715         i1 = i;  // node 1
716     }
717     int iB2 = 0, i2 = 0;
718     const SMDS_MeshNode* aNodes2 [3];
719     for (i = 0, it = tr2->nodesIterator(); it->more(); i++ ) {
720       aNodes2[ i ] = static_cast<const SMDS_MeshNode*>( it->next() );
721       if ( aNodes2[ i ] == theNode2 )
722         iB2 = i; // node B in tr2
723       else if ( aNodes2[ i ] != theNode1 )
724         i2 = i;  // node 2
725     }
726
727     // nodes 1 and 2 should not be the same
728     if ( aNodes1[ i1 ] == aNodes2[ i2 ] )
729       return false;
730
731     // tr1: A->2
732     aNodes1[ iA1 ] = aNodes2[ i2 ];
733     // tr2: B->1
734     aNodes2[ iB2 ] = aNodes1[ i1 ];
735
736     GetMeshDS()->ChangeElementNodes( tr1, aNodes1, 3 );
737     GetMeshDS()->ChangeElementNodes( tr2, aNodes2, 3 );
738
739     return true;
740   }
741
742   // check case of quadratic faces
743   return InverseDiag(tr1,tr2);
744 }
745
746 //=======================================================================
747 //function : getQuadrangleNodes
748 //purpose  : fill theQuadNodes - nodes of a quadrangle resulting from
749 //           fusion of triangles tr1 and tr2 having shared link on
750 //           theNode1 and theNode2
751 //=======================================================================
752
753 bool getQuadrangleNodes(const SMDS_MeshNode *    theQuadNodes [],
754                         const SMDS_MeshNode *    theNode1,
755                         const SMDS_MeshNode *    theNode2,
756                         const SMDS_MeshElement * tr1,
757                         const SMDS_MeshElement * tr2 )
758 {
759   if( tr1->NbNodes() != tr2->NbNodes() )
760     return false;
761   // find the 4-th node to insert into tr1
762   const SMDS_MeshNode* n4 = 0;
763   SMDS_ElemIteratorPtr it = tr2->nodesIterator();
764   int i=0;
765   while ( !n4 && i<3 ) {
766     const SMDS_MeshNode * n = cast2Node( it->next() );
767     i++;
768     bool isDiag = ( n == theNode1 || n == theNode2 );
769     if ( !isDiag )
770       n4 = n;
771   }
772   // Make an array of nodes to be in a quadrangle
773   int iNode = 0, iFirstDiag = -1;
774   it = tr1->nodesIterator();
775   i=0;
776   while ( i<3 ) {
777     const SMDS_MeshNode * n = cast2Node( it->next() );
778     i++;
779     bool isDiag = ( n == theNode1 || n == theNode2 );
780     if ( isDiag ) {
781       if ( iFirstDiag < 0 )
782         iFirstDiag = iNode;
783       else if ( iNode - iFirstDiag == 1 )
784         theQuadNodes[ iNode++ ] = n4; // insert the 4-th node between diagonal nodes
785     }
786     else if ( n == n4 ) {
787       return false; // tr1 and tr2 should not have all the same nodes
788     }
789     theQuadNodes[ iNode++ ] = n;
790   }
791   if ( iNode == 3 ) // diagonal nodes have 0 and 2 indices
792     theQuadNodes[ iNode ] = n4;
793
794   return true;
795 }
796
797 //=======================================================================
798 //function : DeleteDiag
799 //purpose  : Replace two neighbour triangles sharing theNode1-theNode2 link
800 //           with a quadrangle built on the same 4 nodes.
801 //           Return false if proper faces not found
802 //=======================================================================
803
804 bool SMESH_MeshEditor::DeleteDiag (const SMDS_MeshNode * theNode1,
805                                    const SMDS_MeshNode * theNode2)
806 {
807   myLastCreatedElems.Clear();
808   myLastCreatedNodes.Clear();
809
810   MESSAGE( "::DeleteDiag()" );
811
812   const SMDS_MeshElement *tr1, *tr2;
813   if ( !findTriangles( theNode1, theNode2, tr1, tr2 ))
814     return false;
815
816   const SMDS_VtkFace* F1 = dynamic_cast<const SMDS_VtkFace*>( tr1 );
817   if (!F1) return false;
818   const SMDS_VtkFace* F2 = dynamic_cast<const SMDS_VtkFace*>( tr2 );
819   if (!F2) return false;
820   SMESHDS_Mesh * aMesh = GetMeshDS();
821
822   if ((tr1->GetEntityType() == SMDSEntity_Triangle) &&
823       (tr2->GetEntityType() == SMDSEntity_Triangle)) {
824
825     const SMDS_MeshNode* aNodes [ 4 ];
826     if ( ! getQuadrangleNodes( aNodes, theNode1, theNode2, tr1, tr2 ))
827       return false;
828
829     const SMDS_MeshElement* newElem = 0;
830     newElem = aMesh->AddFace( aNodes[0], aNodes[1], aNodes[2], aNodes[3] );
831     myLastCreatedElems.Append(newElem);
832     AddToSameGroups( newElem, tr1, aMesh );
833     int aShapeId = tr1->getshapeId();
834     if ( aShapeId )
835       {
836         aMesh->SetMeshElementOnShape( newElem, aShapeId );
837       }
838     aMesh->RemoveElement( tr1 );
839     aMesh->RemoveElement( tr2 );
840
841     return true;
842   }
843
844   // check case of quadratic faces
845   if (tr1->GetEntityType() != SMDSEntity_Quad_Triangle)
846     return false;
847   if (tr2->GetEntityType() != SMDSEntity_Quad_Triangle)
848     return false;
849
850   //       5
851   //  1 +--+--+ 2  tr1: (1 2 4 5 9 7) or (2 4 1 9 7 5) or (4 1 2 7 5 9)
852   //    |    /|    tr2: (2 3 4 6 8 9) or (3 4 2 8 9 6) or (4 2 3 9 6 8)
853   //    |   / |
854   //  7 +  +  + 6
855   //    | /9  |
856   //    |/    |
857   //  4 +--+--+ 3
858   //       8
859
860   const SMDS_MeshNode* N1 [6];
861   const SMDS_MeshNode* N2 [6];
862   if(!GetNodesFromTwoTria(tr1,tr2,N1,N2))
863     return false;
864   // now we receive following N1 and N2 (using numeration as above image)
865   // tria1 : (1 2 4 5 9 7)  and  tria2 : (3 4 2 8 9 6)
866   // i.e. first nodes from both arrays determ new diagonal
867
868   const SMDS_MeshNode* aNodes[8];
869   aNodes[0] = N1[0];
870   aNodes[1] = N1[1];
871   aNodes[2] = N2[0];
872   aNodes[3] = N2[1];
873   aNodes[4] = N1[3];
874   aNodes[5] = N2[5];
875   aNodes[6] = N2[3];
876   aNodes[7] = N1[5];
877
878   const SMDS_MeshElement* newElem = 0;
879   newElem = aMesh->AddFace( aNodes[0], aNodes[1], aNodes[2], aNodes[3],
880                             aNodes[4], aNodes[5], aNodes[6], aNodes[7]);
881   myLastCreatedElems.Append(newElem);
882   AddToSameGroups( newElem, tr1, aMesh );
883   int aShapeId = tr1->getshapeId();
884   if ( aShapeId )
885     {
886       aMesh->SetMeshElementOnShape( newElem, aShapeId );
887     }
888   aMesh->RemoveElement( tr1 );
889   aMesh->RemoveElement( tr2 );
890
891   // remove middle node (9)
892   GetMeshDS()->RemoveNode( N1[4] );
893
894   return true;
895 }
896
897 //=======================================================================
898 //function : Reorient
899 //purpose  : Reverse theElement orientation
900 //=======================================================================
901
902 bool SMESH_MeshEditor::Reorient (const SMDS_MeshElement * theElem)
903 {
904   MESSAGE("Reorient");
905   myLastCreatedElems.Clear();
906   myLastCreatedNodes.Clear();
907
908   if (!theElem)
909     return false;
910   SMDS_ElemIteratorPtr it = theElem->nodesIterator();
911   if ( !it || !it->more() )
912     return false;
913
914   switch ( theElem->GetType() ) {
915
916   case SMDSAbs_Edge:
917   case SMDSAbs_Face: {
918     if(!theElem->IsQuadratic()) {
919       int i = theElem->NbNodes();
920       vector<const SMDS_MeshNode*> aNodes( i );
921       while ( it->more() )
922         aNodes[ --i ]= static_cast<const SMDS_MeshNode*>( it->next() );
923       return GetMeshDS()->ChangeElementNodes( theElem, &aNodes[0], theElem->NbNodes() );
924     }
925     else {
926       // quadratic elements
927       if(theElem->GetType()==SMDSAbs_Edge) {
928         vector<const SMDS_MeshNode*> aNodes(3);
929         aNodes[1]= static_cast<const SMDS_MeshNode*>( it->next() );
930         aNodes[0]= static_cast<const SMDS_MeshNode*>( it->next() );
931         aNodes[2]= static_cast<const SMDS_MeshNode*>( it->next() );
932         return GetMeshDS()->ChangeElementNodes( theElem, &aNodes[0], 3 );
933       }
934       else {
935         int nbn = theElem->NbNodes();
936         vector<const SMDS_MeshNode*> aNodes(nbn);
937         aNodes[0]= static_cast<const SMDS_MeshNode*>( it->next() );
938         int i=1;
939         for(; i<nbn/2; i++) {
940           aNodes[nbn/2-i]= static_cast<const SMDS_MeshNode*>( it->next() );
941         }
942         for(i=0; i<nbn/2; i++) {
943           aNodes[nbn-i-1]= static_cast<const SMDS_MeshNode*>( it->next() );
944         }
945         return GetMeshDS()->ChangeElementNodes( theElem, &aNodes[0], nbn );
946       }
947     }
948   }
949   case SMDSAbs_Volume: {
950     if (theElem->IsPoly()) {
951       // TODO reorient vtk polyhedron
952       MESSAGE("reorient vtk polyhedron ?");
953       const SMDS_VtkVolume* aPolyedre =
954         dynamic_cast<const SMDS_VtkVolume*>( theElem );
955       if (!aPolyedre) {
956         MESSAGE("Warning: bad volumic element");
957         return false;
958       }
959
960       int nbFaces = aPolyedre->NbFaces();
961       vector<const SMDS_MeshNode *> poly_nodes;
962       vector<int> quantities (nbFaces);
963
964       // reverse each face of the polyedre
965       for (int iface = 1; iface <= nbFaces; iface++) {
966         int inode, nbFaceNodes = aPolyedre->NbFaceNodes(iface);
967         quantities[iface - 1] = nbFaceNodes;
968
969         for (inode = nbFaceNodes; inode >= 1; inode--) {
970           const SMDS_MeshNode* curNode = aPolyedre->GetFaceNode(iface, inode);
971           poly_nodes.push_back(curNode);
972         }
973       }
974
975       return GetMeshDS()->ChangePolyhedronNodes( theElem, poly_nodes, quantities );
976
977     }
978     else {
979       SMDS_VolumeTool vTool;
980       if ( !vTool.Set( theElem ))
981         return false;
982       vTool.Inverse();
983       MESSAGE("ChangeElementNodes reorient: check vTool.Inverse");
984       return GetMeshDS()->ChangeElementNodes( theElem, vTool.GetNodes(), vTool.NbNodes() );
985     }
986   }
987   default:;
988   }
989
990   return false;
991 }
992
993 //=======================================================================
994 //function : getBadRate
995 //purpose  :
996 //=======================================================================
997
998 static double getBadRate (const SMDS_MeshElement*               theElem,
999                           SMESH::Controls::NumericalFunctorPtr& theCrit)
1000 {
1001   SMESH::Controls::TSequenceOfXYZ P;
1002   if ( !theElem || !theCrit->GetPoints( theElem, P ))
1003     return 1e100;
1004   return theCrit->GetBadRate( theCrit->GetValue( P ), theElem->NbNodes() );
1005   //return theCrit->GetBadRate( theCrit->GetValue( theElem->GetID() ), theElem->NbNodes() );
1006 }
1007
1008 //=======================================================================
1009 //function : QuadToTri
1010 //purpose  : Cut quadrangles into triangles.
1011 //           theCrit is used to select a diagonal to cut
1012 //=======================================================================
1013
1014 bool SMESH_MeshEditor::QuadToTri (TIDSortedElemSet &                   theElems,
1015                                   SMESH::Controls::NumericalFunctorPtr theCrit)
1016 {
1017   myLastCreatedElems.Clear();
1018   myLastCreatedNodes.Clear();
1019
1020   MESSAGE( "::QuadToTri()" );
1021
1022   if ( !theCrit.get() )
1023     return false;
1024
1025   SMESHDS_Mesh * aMesh = GetMeshDS();
1026
1027   Handle(Geom_Surface) surface;
1028   SMESH_MesherHelper   helper( *GetMesh() );
1029
1030   TIDSortedElemSet::iterator itElem;
1031   for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
1032     const SMDS_MeshElement* elem = *itElem;
1033     if ( !elem || elem->GetType() != SMDSAbs_Face )
1034       continue;
1035     if ( elem->NbNodes() != ( elem->IsQuadratic() ? 8 : 4 ))
1036       continue;
1037
1038     // retrieve element nodes
1039     const SMDS_MeshNode* aNodes [8];
1040     SMDS_ElemIteratorPtr itN = elem->nodesIterator();
1041     int i = 0;
1042     while ( itN->more() )
1043       aNodes[ i++ ] = static_cast<const SMDS_MeshNode*>( itN->next() );
1044
1045     // compare two sets of possible triangles
1046     double aBadRate1, aBadRate2; // to what extent a set is bad
1047     SMDS_FaceOfNodes tr1 ( aNodes[0], aNodes[1], aNodes[2] );
1048     SMDS_FaceOfNodes tr2 ( aNodes[2], aNodes[3], aNodes[0] );
1049     aBadRate1 = getBadRate( &tr1, theCrit ) + getBadRate( &tr2, theCrit );
1050
1051     SMDS_FaceOfNodes tr3 ( aNodes[1], aNodes[2], aNodes[3] );
1052     SMDS_FaceOfNodes tr4 ( aNodes[3], aNodes[0], aNodes[1] );
1053     aBadRate2 = getBadRate( &tr3, theCrit ) + getBadRate( &tr4, theCrit );
1054
1055     int aShapeId = FindShape( elem );
1056     const SMDS_MeshElement* newElem1 = 0;
1057     const SMDS_MeshElement* newElem2 = 0;
1058
1059     if( !elem->IsQuadratic() ) {
1060
1061       // split liner quadrangle
1062       if ( aBadRate1 <= aBadRate2 ) {
1063         // tr1 + tr2 is better
1064         newElem1 = aMesh->AddFace( aNodes[2], aNodes[3], aNodes[0] );
1065         newElem2 = aMesh->AddFace( aNodes[2], aNodes[0], aNodes[1] );
1066       }
1067       else {
1068         // tr3 + tr4 is better
1069         newElem1 = aMesh->AddFace( aNodes[3], aNodes[0], aNodes[1] );
1070         newElem2 = aMesh->AddFace( aNodes[3], aNodes[1], aNodes[2] );
1071       }
1072     }
1073     else {
1074
1075       // split quadratic quadrangle
1076
1077       // get surface elem is on
1078       if ( aShapeId != helper.GetSubShapeID() ) {
1079         surface.Nullify();
1080         TopoDS_Shape shape;
1081         if ( aShapeId > 0 )
1082           shape = aMesh->IndexToShape( aShapeId );
1083         if ( !shape.IsNull() && shape.ShapeType() == TopAbs_FACE ) {
1084           TopoDS_Face face = TopoDS::Face( shape );
1085           surface = BRep_Tool::Surface( face );
1086           if ( !surface.IsNull() )
1087             helper.SetSubShape( shape );
1088         }
1089       }
1090       // get elem nodes
1091       const SMDS_MeshNode* aNodes [8];
1092       const SMDS_MeshNode* inFaceNode = 0;
1093       SMDS_ElemIteratorPtr itN = elem->nodesIterator();
1094       int i = 0;
1095       while ( itN->more() ) {
1096         aNodes[ i++ ] = static_cast<const SMDS_MeshNode*>( itN->next() );
1097         if ( !inFaceNode && helper.GetNodeUVneedInFaceNode() &&
1098              aNodes[ i-1 ]->GetPosition()->GetTypeOfPosition() == SMDS_TOP_FACE )
1099         {
1100           inFaceNode = aNodes[ i-1 ];
1101         }
1102       }
1103       // find middle point for (0,1,2,3)
1104       // and create a node in this point;
1105       gp_XYZ p( 0,0,0 );
1106       if ( surface.IsNull() ) {
1107         for(i=0; i<4; i++)
1108           p += gp_XYZ(aNodes[i]->X(), aNodes[i]->Y(), aNodes[i]->Z() );
1109         p /= 4;
1110       }
1111       else {
1112         TopoDS_Face face = TopoDS::Face( helper.GetSubShape() );
1113         gp_XY uv( 0,0 );
1114         for(i=0; i<4; i++)
1115           uv += helper.GetNodeUV( face, aNodes[i], inFaceNode );
1116         uv /= 4.;
1117         p = surface->Value( uv.X(), uv.Y() ).XYZ();
1118       }
1119       const SMDS_MeshNode* newN = aMesh->AddNode( p.X(), p.Y(), p.Z() );
1120       myLastCreatedNodes.Append(newN);
1121
1122       // create a new element
1123       const SMDS_MeshNode* N[6];
1124       if ( aBadRate1 <= aBadRate2 ) {
1125         N[0] = aNodes[0];
1126         N[1] = aNodes[1];
1127         N[2] = aNodes[2];
1128         N[3] = aNodes[4];
1129         N[4] = aNodes[5];
1130         N[5] = newN;
1131         newElem1 = aMesh->AddFace(aNodes[2], aNodes[3], aNodes[0],
1132                                   aNodes[6], aNodes[7], newN );
1133         newElem2 = aMesh->AddFace(aNodes[2], aNodes[0], aNodes[1],
1134                                   newN,      aNodes[4], aNodes[5] );
1135       }
1136       else {
1137         N[0] = aNodes[1];
1138         N[1] = aNodes[2];
1139         N[2] = aNodes[3];
1140         N[3] = aNodes[5];
1141         N[4] = aNodes[6];
1142         N[5] = newN;
1143         newElem1 = aMesh->AddFace(aNodes[3], aNodes[0], aNodes[1],
1144                                   aNodes[7], aNodes[4], newN );
1145         newElem2 = aMesh->AddFace(aNodes[3], aNodes[1], aNodes[2],
1146                                   newN,      aNodes[5], aNodes[6] );
1147       }
1148     } // quadratic case
1149
1150     // care of a new element
1151
1152     myLastCreatedElems.Append(newElem1);
1153     myLastCreatedElems.Append(newElem2);
1154     AddToSameGroups( newElem1, elem, aMesh );
1155     AddToSameGroups( newElem2, elem, aMesh );
1156
1157     // put a new triangle on the same shape
1158     if ( aShapeId )
1159       {
1160         aMesh->SetMeshElementOnShape( newElem1, aShapeId );
1161         aMesh->SetMeshElementOnShape( newElem2, aShapeId );
1162       }
1163     aMesh->RemoveElement( elem );
1164   }
1165   return true;
1166 }
1167
1168 //=======================================================================
1169 //function : BestSplit
1170 //purpose  : Find better diagonal for cutting.
1171 //=======================================================================
1172
1173 int SMESH_MeshEditor::BestSplit (const SMDS_MeshElement*              theQuad,
1174                                  SMESH::Controls::NumericalFunctorPtr theCrit)
1175 {
1176   myLastCreatedElems.Clear();
1177   myLastCreatedNodes.Clear();
1178
1179   if (!theCrit.get())
1180     return -1;
1181
1182   if (!theQuad || theQuad->GetType() != SMDSAbs_Face )
1183     return -1;
1184
1185   if( theQuad->NbNodes()==4 ||
1186       (theQuad->NbNodes()==8 && theQuad->IsQuadratic()) ) {
1187
1188     // retrieve element nodes
1189     const SMDS_MeshNode* aNodes [4];
1190     SMDS_ElemIteratorPtr itN = theQuad->nodesIterator();
1191     int i = 0;
1192     //while (itN->more())
1193     while (i<4) {
1194       aNodes[ i++ ] = static_cast<const SMDS_MeshNode*>( itN->next() );
1195     }
1196     // compare two sets of possible triangles
1197     double aBadRate1, aBadRate2; // to what extent a set is bad
1198     SMDS_FaceOfNodes tr1 ( aNodes[0], aNodes[1], aNodes[2] );
1199     SMDS_FaceOfNodes tr2 ( aNodes[2], aNodes[3], aNodes[0] );
1200     aBadRate1 = getBadRate( &tr1, theCrit ) + getBadRate( &tr2, theCrit );
1201
1202     SMDS_FaceOfNodes tr3 ( aNodes[1], aNodes[2], aNodes[3] );
1203     SMDS_FaceOfNodes tr4 ( aNodes[3], aNodes[0], aNodes[1] );
1204     aBadRate2 = getBadRate( &tr3, theCrit ) + getBadRate( &tr4, theCrit );
1205
1206     if (aBadRate1 <= aBadRate2) // tr1 + tr2 is better
1207       return 1; // diagonal 1-3
1208
1209     return 2; // diagonal 2-4
1210   }
1211   return -1;
1212 }
1213
1214 namespace
1215 {
1216   // Methods of splitting volumes into tetra
1217
1218   const int theHexTo5_1[5*4+1] =
1219     {
1220       0, 1, 2, 5,    0, 4, 5, 7,     0, 2, 3, 7,    2, 5, 6, 7,     0, 5, 2, 7,   -1
1221     };
1222   const int theHexTo5_2[5*4+1] =
1223     {
1224       1, 2, 3, 6,    1, 4, 5, 6,     0, 1, 3, 4,    3, 4, 6, 7,     1, 3, 4, 6,   -1
1225     };
1226   const int* theHexTo5[2] = { theHexTo5_1, theHexTo5_2 };
1227
1228   const int theHexTo6_1[6*4+1] =
1229     {
1230       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
1231     };
1232   const int theHexTo6_2[6*4+1] =
1233     {
1234       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
1235     };
1236   const int theHexTo6_3[6*4+1] =
1237     {
1238       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
1239     };
1240   const int theHexTo6_4[6*4+1] =
1241     {
1242       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
1243     };
1244   const int* theHexTo6[4] = { theHexTo6_1, theHexTo6_2, theHexTo6_3, theHexTo6_4 };
1245
1246   const int thePyraTo2_1[2*4+1] =
1247     {
1248       0, 1, 2, 4,    0, 2, 3, 4,   -1
1249     };
1250   const int thePyraTo2_2[2*4+1] =
1251     {
1252       1, 2, 3, 4,    1, 3, 0, 4,   -1
1253     };
1254   const int* thePyraTo2[2] = { thePyraTo2_1, thePyraTo2_2 };
1255
1256   const int thePentaTo3_1[3*4+1] =
1257     {
1258       0, 1, 2, 3,    1, 3, 4, 2,     2, 3, 4, 5,    -1
1259     };
1260   const int thePentaTo3_2[3*4+1] =
1261     {
1262       1, 2, 0, 4,    2, 4, 5, 0,     0, 4, 5, 3,    -1
1263     };
1264   const int thePentaTo3_3[3*4+1] =
1265     {
1266       2, 0, 1, 5,    0, 5, 3, 1,     1, 5, 3, 4,    -1
1267     };
1268   const int thePentaTo3_4[3*4+1] =
1269     {
1270       0, 1, 2, 3,    1, 3, 4, 5,     2, 3, 1, 5,    -1
1271     };
1272   const int thePentaTo3_5[3*4+1] =
1273     {
1274       1, 2, 0, 4,    2, 4, 5, 3,     0, 4, 2, 3,    -1
1275     };
1276   const int thePentaTo3_6[3*4+1] =
1277     {
1278       2, 0, 1, 5,    0, 5, 3, 4,     1, 5, 0, 4,    -1
1279     };
1280   const int* thePentaTo3[6] = { thePentaTo3_1, thePentaTo3_2, thePentaTo3_3,
1281                                 thePentaTo3_4, thePentaTo3_5, thePentaTo3_6 };
1282
1283   struct TTriangleFacet //!< stores indices of three nodes of tetra facet
1284   {
1285     int _n1, _n2, _n3;
1286     TTriangleFacet(int n1, int n2, int n3): _n1(n1), _n2(n2), _n3(n3) {}
1287     bool contains(int n) const { return ( n == _n1 || n == _n2 || n == _n3 ); }
1288     bool hasAdjacentTetra( const SMDS_MeshElement* elem ) const;
1289   };
1290   struct TSplitMethod
1291   {
1292     int        _nbTetra;
1293     const int* _connectivity; //!< foursomes of tetra connectivy finished by -1
1294     bool       _baryNode;     //!< additional node is to be created at cell barycenter
1295     bool       _ownConn;      //!< to delete _connectivity in destructor
1296     map<int, const SMDS_MeshNode*> _faceBaryNode; //!< map face index to node at BC of face
1297
1298     TSplitMethod( int nbTet=0, const int* conn=0, bool addNode=false)
1299       : _nbTetra(nbTet), _connectivity(conn), _baryNode(addNode), _ownConn(false) {}
1300     ~TSplitMethod() { if ( _ownConn ) delete [] _connectivity; _connectivity = 0; }
1301     bool hasFacet( const TTriangleFacet& facet ) const
1302     {
1303       const int* tetConn = _connectivity;
1304       for ( ; tetConn[0] >= 0; tetConn += 4 )
1305         if (( facet.contains( tetConn[0] ) +
1306               facet.contains( tetConn[1] ) +
1307               facet.contains( tetConn[2] ) +
1308               facet.contains( tetConn[3] )) == 3 )
1309           return true;
1310       return false;
1311     }
1312   };
1313
1314   //=======================================================================
1315   /*!
1316    * \brief return TSplitMethod for the given element
1317    */
1318   //=======================================================================
1319
1320   TSplitMethod getSplitMethod( SMDS_VolumeTool& vol, const int theMethodFlags)
1321   {
1322     const int iQ = vol.Element()->IsQuadratic() ? 2 : 1;
1323
1324     // at HEXA_TO_24 method, each face of volume is split into triangles each based on
1325     // an edge and a face barycenter; tertaherdons are based on triangles and
1326     // a volume barycenter
1327     const bool is24TetMode = ( theMethodFlags == SMESH_MeshEditor::HEXA_TO_24 );
1328
1329     // Find out how adjacent volumes are split
1330
1331     vector < list< TTriangleFacet > > triaSplitsByFace( vol.NbFaces() ); // splits of each side
1332     int hasAdjacentSplits = 0, maxTetConnSize = 0;
1333     for ( int iF = 0; iF < vol.NbFaces(); ++iF )
1334     {
1335       int nbNodes = vol.NbFaceNodes( iF ) / iQ;
1336       maxTetConnSize += 4 * ( nbNodes - (is24TetMode ? 0 : 2));
1337       if ( nbNodes < 4 ) continue;
1338
1339       list< TTriangleFacet >& triaSplits = triaSplitsByFace[ iF ];
1340       const int* nInd = vol.GetFaceNodesIndices( iF );
1341       if ( nbNodes == 4 )
1342       {
1343         TTriangleFacet t012( nInd[0*iQ], nInd[1*iQ], nInd[2*iQ] );
1344         TTriangleFacet t123( nInd[1*iQ], nInd[2*iQ], nInd[3*iQ] );
1345         if      ( t012.hasAdjacentTetra( vol.Element() )) triaSplits.push_back( t012 );
1346         else if ( t123.hasAdjacentTetra( vol.Element() )) triaSplits.push_back( t123 );
1347       }
1348       else
1349       {
1350         int iCom = 0; // common node of triangle faces to split into
1351         for ( int iVar = 0; iVar < nbNodes; ++iVar, ++iCom )
1352         {
1353           TTriangleFacet t012( nInd[ iQ * ( iCom             )],
1354                                nInd[ iQ * ( (iCom+1)%nbNodes )],
1355                                nInd[ iQ * ( (iCom+2)%nbNodes )]);
1356           TTriangleFacet t023( nInd[ iQ * ( iCom             )],
1357                                nInd[ iQ * ( (iCom+2)%nbNodes )],
1358                                nInd[ iQ * ( (iCom+3)%nbNodes )]);
1359           if ( t012.hasAdjacentTetra( vol.Element() ) && t023.hasAdjacentTetra( vol.Element() ))
1360           {
1361             triaSplits.push_back( t012 );
1362             triaSplits.push_back( t023 );
1363             break;
1364           }
1365         }
1366       }
1367       if ( !triaSplits.empty() )
1368         hasAdjacentSplits = true;
1369     }
1370
1371     // Among variants of split method select one compliant with adjacent volumes
1372
1373     TSplitMethod method;
1374     if ( !vol.Element()->IsPoly() && !is24TetMode )
1375     {
1376       int nbVariants = 2, nbTet = 0;
1377       const int** connVariants = 0;
1378       switch ( vol.Element()->GetEntityType() )
1379       {
1380       case SMDSEntity_Hexa:
1381       case SMDSEntity_Quad_Hexa:
1382         if ( theMethodFlags == SMESH_MeshEditor::HEXA_TO_5 )
1383           connVariants = theHexTo5, nbTet = 5;
1384         else
1385           connVariants = theHexTo6, nbTet = 6, nbVariants = 4;
1386         break;
1387       case SMDSEntity_Pyramid:
1388       case SMDSEntity_Quad_Pyramid:
1389         connVariants = thePyraTo2;  nbTet = 2;
1390         break;
1391       case SMDSEntity_Penta:
1392       case SMDSEntity_Quad_Penta:
1393         connVariants = thePentaTo3; nbTet = 3; nbVariants = 6;
1394         break;
1395       default:
1396         nbVariants = 0;
1397       }
1398       for ( int variant = 0; variant < nbVariants && method._nbTetra == 0; ++variant )
1399       {
1400         // check method compliancy with adjacent tetras,
1401         // all found splits must be among facets of tetras described by this method
1402         method = TSplitMethod( nbTet, connVariants[variant] );
1403         if ( hasAdjacentSplits && method._nbTetra > 0 )
1404         {
1405           bool facetCreated = true;
1406           for ( int iF = 0; facetCreated && iF < triaSplitsByFace.size(); ++iF )
1407           {
1408             list< TTriangleFacet >::const_iterator facet = triaSplitsByFace[iF].begin();
1409             for ( ; facetCreated && facet != triaSplitsByFace[iF].end(); ++facet )
1410               facetCreated = method.hasFacet( *facet );
1411           }
1412           if ( !facetCreated )
1413             method = TSplitMethod(0); // incompatible method
1414         }
1415       }
1416     }
1417     if ( method._nbTetra < 1 )
1418     {
1419       // No standard method is applicable, use a generic solution:
1420       // each facet of a volume is split into triangles and
1421       // each of triangles and a volume barycenter form a tetrahedron.
1422
1423       int* connectivity = new int[ maxTetConnSize + 1 ];
1424       method._connectivity = connectivity;
1425       method._ownConn = true;
1426       method._baryNode = true;
1427
1428       int connSize = 0;
1429       int baryCenInd = vol.NbNodes();
1430       for ( int iF = 0; iF < vol.NbFaces(); ++iF )
1431       {
1432         const int nbNodes = vol.NbFaceNodes( iF ) / iQ;
1433         const int*   nInd = vol.GetFaceNodesIndices( iF );
1434         // find common node of triangle facets of tetra to create
1435         int iCommon = 0; // index in linear numeration
1436         const list< TTriangleFacet >& triaSplits = triaSplitsByFace[ iF ];
1437         if ( !triaSplits.empty() )
1438         {
1439           // by found facets
1440           const TTriangleFacet* facet = &triaSplits.front();
1441           for ( ; iCommon < nbNodes-1 ; ++iCommon )
1442             if ( facet->contains( nInd[ iQ * iCommon ]) &&
1443                  facet->contains( nInd[ iQ * ((iCommon+2)%nbNodes) ]))
1444               break;
1445         }
1446         else if ( nbNodes > 3 && !is24TetMode )
1447         {
1448           // find the best method of splitting into triangles by aspect ratio
1449           SMESH::Controls::NumericalFunctorPtr aspectRatio( new SMESH::Controls::AspectRatio);
1450           map< double, int > badness2iCommon;
1451           const SMDS_MeshNode** nodes = vol.GetFaceNodes( iF );
1452           int nbVariants = ( nbNodes == 4 ? 2 : nbNodes );
1453           for ( int iVar = 0; iVar < nbVariants; ++iVar, ++iCommon )
1454             for ( int iLast = iCommon+2; iLast < iCommon+nbNodes; ++iLast )
1455             {
1456               SMDS_FaceOfNodes tria ( nodes[ iQ*( iCommon         )],
1457                                       nodes[ iQ*((iLast-1)%nbNodes)],
1458                                       nodes[ iQ*((iLast  )%nbNodes)]);
1459               double badness = getBadRate( &tria, aspectRatio );
1460               badness2iCommon.insert( make_pair( badness, iCommon ));
1461             }
1462           // use iCommon with lowest badness
1463           iCommon = badness2iCommon.begin()->second;
1464         }
1465         if ( iCommon >= nbNodes )
1466           iCommon = 0; // something wrong
1467
1468         // fill connectivity of tetrahedra based on a current face
1469         int nbTet = nbNodes - 2;
1470         if ( is24TetMode && nbNodes > 3 && triaSplits.empty())
1471         {
1472           method._faceBaryNode.insert( make_pair( iF, (const SMDS_MeshNode*)0 ));
1473           int faceBaryCenInd = baryCenInd + method._faceBaryNode.size();
1474           nbTet = nbNodes;
1475           for ( int i = 0; i < nbTet; ++i )
1476           {
1477             int i1 = i, i2 = (i+1) % nbNodes;
1478             if ( !vol.IsFaceExternal( iF )) swap( i1, i2 );
1479             connectivity[ connSize++ ] = nInd[ iQ * i1 ];
1480             connectivity[ connSize++ ] = nInd[ iQ * i2 ];
1481             connectivity[ connSize++ ] = faceBaryCenInd;
1482             connectivity[ connSize++ ] = baryCenInd;
1483           }
1484         }
1485         else
1486         {
1487           for ( int i = 0; i < nbTet; ++i )
1488           {
1489             int i1 = (iCommon+1+i) % nbNodes, i2 = (iCommon+2+i) % nbNodes;
1490             if ( !vol.IsFaceExternal( iF )) swap( i1, i2 );
1491             connectivity[ connSize++ ] = nInd[ iQ * iCommon ];
1492             connectivity[ connSize++ ] = nInd[ iQ * i1 ];
1493             connectivity[ connSize++ ] = nInd[ iQ * i2 ];
1494             connectivity[ connSize++ ] = baryCenInd;
1495           }
1496         }
1497         method._nbTetra += nbTet;
1498       }
1499       connectivity[ connSize++ ] = -1;
1500     }
1501     return method;
1502   }
1503   //================================================================================
1504   /*!
1505    * \brief Check if there is a tetraherdon adjacent to the given element via this facet
1506    */
1507   //================================================================================
1508
1509   bool TTriangleFacet::hasAdjacentTetra( const SMDS_MeshElement* elem ) const
1510   {
1511     // find the tetrahedron including the three nodes of facet
1512     const SMDS_MeshNode* n1 = elem->GetNode(_n1);
1513     const SMDS_MeshNode* n2 = elem->GetNode(_n2);
1514     const SMDS_MeshNode* n3 = elem->GetNode(_n3);
1515     SMDS_ElemIteratorPtr volIt1 = n1->GetInverseElementIterator(SMDSAbs_Volume);
1516     while ( volIt1->more() )
1517     {
1518       const SMDS_MeshElement* v = volIt1->next();
1519       if ( v->GetEntityType() != ( v->IsQuadratic() ? SMDSEntity_Quad_Tetra : SMDSEntity_Tetra ))
1520         continue;
1521       SMDS_ElemIteratorPtr volIt2 = n2->GetInverseElementIterator(SMDSAbs_Volume);
1522       while ( volIt2->more() )
1523         if ( v != volIt2->next() )
1524           continue;
1525       SMDS_ElemIteratorPtr volIt3 = n3->GetInverseElementIterator(SMDSAbs_Volume);
1526       while ( volIt3->more() )
1527         if ( v == volIt3->next() )
1528           return true;
1529     }
1530     return false;
1531   }
1532
1533   //=======================================================================
1534   /*!
1535    * \brief A key of a face of volume
1536    */
1537   //=======================================================================
1538
1539   struct TVolumeFaceKey: pair< int, pair< int, int> >
1540   {
1541     TVolumeFaceKey( SMDS_VolumeTool& vol, int iF )
1542     {
1543       TIDSortedNodeSet sortedNodes;
1544       const int iQ = vol.Element()->IsQuadratic() ? 2 : 1;
1545       int nbNodes = vol.NbFaceNodes( iF );
1546       const SMDS_MeshNode** fNodes = vol.GetFaceNodes( iF );
1547       for ( int i = 0; i < nbNodes; i += iQ )
1548         sortedNodes.insert( fNodes[i] );
1549       TIDSortedNodeSet::iterator n = sortedNodes.begin();
1550       first = (*(n++))->GetID();
1551       second.first = (*(n++))->GetID();
1552       second.second = (*(n++))->GetID();
1553     }
1554   };
1555 } // namespace
1556
1557 //=======================================================================
1558 //function : SplitVolumesIntoTetra
1559 //purpose  : Split volumic elements into tetrahedra.
1560 //=======================================================================
1561
1562 void SMESH_MeshEditor::SplitVolumesIntoTetra (const TIDSortedElemSet & theElems,
1563                                               const int                theMethodFlags)
1564 {
1565   // std-like iterator on coordinates of nodes of mesh element
1566   typedef SMDS_StdIterator< TNodeXYZ, SMDS_ElemIteratorPtr > NXyzIterator;
1567   NXyzIterator xyzEnd;
1568
1569   SMDS_VolumeTool    volTool;
1570   SMESH_MesherHelper helper( *GetMesh());
1571
1572   SMESHDS_SubMesh* subMesh = 0;//GetMeshDS()->MeshElements(1);
1573   SMESHDS_SubMesh* fSubMesh = 0;//subMesh;
1574   
1575   SMESH_SequenceOfElemPtr newNodes, newElems;
1576
1577   // map face of volume to it's baricenrtic node
1578   map< TVolumeFaceKey, const SMDS_MeshNode* > volFace2BaryNode;
1579   double bc[3];
1580
1581   TIDSortedElemSet::const_iterator elem = theElems.begin();
1582   for ( ; elem != theElems.end(); ++elem )
1583   {
1584     SMDSAbs_EntityType geomType = (*elem)->GetEntityType();
1585     if ( geomType <= SMDSEntity_Quad_Tetra )
1586       continue; // tetra or face or ...
1587
1588     if ( !volTool.Set( *elem )) continue; // not volume? strange...
1589
1590     TSplitMethod splitMethod = getSplitMethod( volTool, theMethodFlags );
1591     if ( splitMethod._nbTetra < 1 ) continue;
1592
1593     // find submesh to add new tetras to
1594     if ( !subMesh || !subMesh->Contains( *elem ))
1595     {
1596       int shapeID = FindShape( *elem );
1597       helper.SetSubShape( shapeID ); // helper will add tetras to the found submesh
1598       subMesh = GetMeshDS()->MeshElements( shapeID );
1599     }
1600     int iQ;
1601     if ( (*elem)->IsQuadratic() )
1602     {
1603       iQ = 2;
1604       // add quadratic links to the helper
1605       for ( int iF = 0; iF < volTool.NbFaces(); ++iF )
1606       {
1607         const SMDS_MeshNode** fNodes = volTool.GetFaceNodes( iF );
1608         for ( int iN = 0; iN < volTool.NbFaceNodes( iF ); iN += iQ )
1609           helper.AddTLinkNode( fNodes[iF], fNodes[iF+2], fNodes[iF+1] );
1610       }
1611       helper.SetIsQuadratic( true );
1612     }
1613     else
1614     {
1615       iQ = 1;
1616       helper.SetIsQuadratic( false );
1617     }
1618     vector<const SMDS_MeshNode*> nodes( (*elem)->begin_nodes(), (*elem)->end_nodes() );
1619     if ( splitMethod._baryNode )
1620     {
1621       // make a node at barycenter
1622       volTool.GetBaryCenter( bc[0], bc[1], bc[2] );
1623       SMDS_MeshNode* gcNode = helper.AddNode( bc[0], bc[1], bc[2] );
1624       nodes.push_back( gcNode );
1625       newNodes.Append( gcNode );
1626     }
1627     if ( !splitMethod._faceBaryNode.empty() )
1628     {
1629       // make or find baricentric nodes of faces
1630       map<int, const SMDS_MeshNode*>::iterator iF_n = splitMethod._faceBaryNode.begin();
1631       for ( ; iF_n != splitMethod._faceBaryNode.end(); ++iF_n )
1632       {
1633         map< TVolumeFaceKey, const SMDS_MeshNode* >::iterator f_n =
1634           volFace2BaryNode.insert
1635           ( make_pair( TVolumeFaceKey( volTool,iF_n->first ), (const SMDS_MeshNode*)0) ).first;
1636         if ( !f_n->second )
1637         {
1638           volTool.GetFaceBaryCenter( iF_n->first, bc[0], bc[1], bc[2] );
1639           newNodes.Append( f_n->second = helper.AddNode( bc[0], bc[1], bc[2] ));
1640         }
1641         nodes.push_back( iF_n->second = f_n->second );
1642       }
1643     }
1644
1645     // make tetras
1646     helper.SetElementsOnShape( true );
1647     vector<const SMDS_MeshElement* > tetras( splitMethod._nbTetra ); // splits of a volume
1648     const int* tetConn = splitMethod._connectivity;
1649     for ( int i = 0; i < splitMethod._nbTetra; ++i, tetConn += 4 )
1650       newElems.Append( tetras[ i ] = helper.AddVolume( nodes[ tetConn[0] ],
1651                                                        nodes[ tetConn[1] ],
1652                                                        nodes[ tetConn[2] ],
1653                                                        nodes[ tetConn[3] ]));
1654
1655     ReplaceElemInGroups( *elem, tetras, GetMeshDS() );
1656
1657     // Split faces on sides of the split volume
1658
1659     const SMDS_MeshNode** volNodes = volTool.GetNodes();
1660     for ( int iF = 0; iF < volTool.NbFaces(); ++iF )
1661     {
1662       const int nbNodes = volTool.NbFaceNodes( iF ) / iQ;
1663       if ( nbNodes < 4 ) continue;
1664
1665       // find an existing face
1666       vector<const SMDS_MeshNode*> fNodes( volTool.GetFaceNodes( iF ),
1667                                            volTool.GetFaceNodes( iF ) + nbNodes*iQ );
1668       while ( const SMDS_MeshElement* face = GetMeshDS()->FindFace( fNodes ))
1669       {
1670         // make triangles
1671         helper.SetElementsOnShape( false );
1672         vector< const SMDS_MeshElement* > triangles;
1673
1674         map<int, const SMDS_MeshNode*>::iterator iF_n = splitMethod._faceBaryNode.find(iF);
1675         if ( iF_n != splitMethod._faceBaryNode.end() )
1676         {
1677           for ( int iN = 0; iN < nbNodes*iQ; iN += iQ )
1678           {
1679             const SMDS_MeshNode* n1 = fNodes[iN];
1680             const SMDS_MeshNode *n2 = fNodes[(iN+iQ)%nbNodes*iQ];
1681             const SMDS_MeshNode *n3 = iF_n->second;
1682             if ( !volTool.IsFaceExternal( iF ))
1683               swap( n2, n3 );
1684             triangles.push_back( helper.AddFace( n1,n2,n3 ));
1685           }
1686         }
1687         else
1688         {
1689           // among possible triangles create ones discribed by split method
1690           const int* nInd = volTool.GetFaceNodesIndices( iF );
1691           int nbVariants = ( nbNodes == 4 ? 2 : nbNodes );
1692           int iCom = 0; // common node of triangle faces to split into
1693           list< TTriangleFacet > facets;
1694           for ( int iVar = 0; iVar < nbVariants; ++iVar, ++iCom )
1695           {
1696             TTriangleFacet t012( nInd[ iQ * ( iCom                )],
1697                                  nInd[ iQ * ( (iCom+1)%nbNodes )],
1698                                  nInd[ iQ * ( (iCom+2)%nbNodes )]);
1699             TTriangleFacet t023( nInd[ iQ * ( iCom                )],
1700                                  nInd[ iQ * ( (iCom+2)%nbNodes )],
1701                                  nInd[ iQ * ( (iCom+3)%nbNodes )]);
1702             if ( splitMethod.hasFacet( t012 ) && splitMethod.hasFacet( t023 ))
1703             {
1704               facets.push_back( t012 );
1705               facets.push_back( t023 );
1706               for ( int iLast = iCom+4; iLast < iCom+nbNodes; ++iLast )
1707                 facets.push_back( TTriangleFacet( nInd[ iQ * ( iCom             )],
1708                                                   nInd[ iQ * ((iLast-1)%nbNodes )],
1709                                                   nInd[ iQ * ((iLast  )%nbNodes )]));
1710               break;
1711             }
1712           }
1713           list< TTriangleFacet >::iterator facet = facets.begin();
1714           for ( ; facet != facets.end(); ++facet )
1715           {
1716             if ( !volTool.IsFaceExternal( iF ))
1717               swap( facet->_n2, facet->_n3 );
1718             triangles.push_back( helper.AddFace( volNodes[ facet->_n1 ],
1719                                                  volNodes[ facet->_n2 ],
1720                                                  volNodes[ facet->_n3 ]));
1721           }
1722         }
1723         // find submesh to add new triangles in
1724         if ( !fSubMesh || !fSubMesh->Contains( face ))
1725         {
1726           int shapeID = FindShape( face );
1727           fSubMesh = GetMeshDS()->MeshElements( shapeID );
1728         }
1729         for ( int i = 0; i < triangles.size(); ++i )
1730         {
1731           if ( !triangles[i] ) continue;
1732           if ( fSubMesh )
1733             fSubMesh->AddElement( triangles[i]);
1734           newElems.Append( triangles[i] );
1735         }
1736         ReplaceElemInGroups( face, triangles, GetMeshDS() );
1737         GetMeshDS()->RemoveFreeElement( face, fSubMesh, /*fromGroups=*/false );
1738       }
1739
1740     } // loop on volume faces to split them into triangles
1741
1742     GetMeshDS()->RemoveFreeElement( *elem, subMesh, /*fromGroups=*/false );
1743
1744   } // loop on volumes to split
1745
1746   myLastCreatedNodes = newNodes;
1747   myLastCreatedElems = newElems;
1748 }
1749
1750 //=======================================================================
1751 //function : AddToSameGroups
1752 //purpose  : add elemToAdd to the groups the elemInGroups belongs to
1753 //=======================================================================
1754
1755 void SMESH_MeshEditor::AddToSameGroups (const SMDS_MeshElement* elemToAdd,
1756                                         const SMDS_MeshElement* elemInGroups,
1757                                         SMESHDS_Mesh *          aMesh)
1758 {
1759   const set<SMESHDS_GroupBase*>& groups = aMesh->GetGroups();
1760   if (!groups.empty()) {
1761     set<SMESHDS_GroupBase*>::const_iterator grIt = groups.begin();
1762     for ( ; grIt != groups.end(); grIt++ ) {
1763       SMESHDS_Group* group = dynamic_cast<SMESHDS_Group*>( *grIt );
1764       if ( group && group->Contains( elemInGroups ))
1765         group->SMDSGroup().Add( elemToAdd );
1766     }
1767   }
1768 }
1769
1770
1771 //=======================================================================
1772 //function : RemoveElemFromGroups
1773 //purpose  : Remove removeelem to the groups the elemInGroups belongs to
1774 //=======================================================================
1775 void SMESH_MeshEditor::RemoveElemFromGroups (const SMDS_MeshElement* removeelem,
1776                                              SMESHDS_Mesh *          aMesh)
1777 {
1778   const set<SMESHDS_GroupBase*>& groups = aMesh->GetGroups();
1779   if (!groups.empty())
1780   {
1781     set<SMESHDS_GroupBase*>::const_iterator GrIt = groups.begin();
1782     for (; GrIt != groups.end(); GrIt++)
1783     {
1784       SMESHDS_Group* grp = dynamic_cast<SMESHDS_Group*>(*GrIt);
1785       if (!grp || grp->IsEmpty()) continue;
1786       grp->SMDSGroup().Remove(removeelem);
1787     }
1788   }
1789 }
1790
1791 //================================================================================
1792 /*!
1793  * \brief Replace elemToRm by elemToAdd in the all groups
1794  */
1795 //================================================================================
1796
1797 void SMESH_MeshEditor::ReplaceElemInGroups (const SMDS_MeshElement* elemToRm,
1798                                             const SMDS_MeshElement* elemToAdd,
1799                                             SMESHDS_Mesh *          aMesh)
1800 {
1801   const set<SMESHDS_GroupBase*>& groups = aMesh->GetGroups();
1802   if (!groups.empty()) {
1803     set<SMESHDS_GroupBase*>::const_iterator grIt = groups.begin();
1804     for ( ; grIt != groups.end(); grIt++ ) {
1805       SMESHDS_Group* group = dynamic_cast<SMESHDS_Group*>( *grIt );
1806       if ( group && group->SMDSGroup().Remove( elemToRm ) && elemToAdd )
1807         group->SMDSGroup().Add( elemToAdd );
1808     }
1809   }
1810 }
1811
1812 //================================================================================
1813 /*!
1814  * \brief Replace elemToRm by elemToAdd in the all groups
1815  */
1816 //================================================================================
1817
1818 void SMESH_MeshEditor::ReplaceElemInGroups (const SMDS_MeshElement*                elemToRm,
1819                                             const vector<const SMDS_MeshElement*>& elemToAdd,
1820                                             SMESHDS_Mesh *                         aMesh)
1821 {
1822   const set<SMESHDS_GroupBase*>& groups = aMesh->GetGroups();
1823   if (!groups.empty())
1824   {
1825     set<SMESHDS_GroupBase*>::const_iterator grIt = groups.begin();
1826     for ( ; grIt != groups.end(); grIt++ ) {
1827       SMESHDS_Group* group = dynamic_cast<SMESHDS_Group*>( *grIt );
1828       if ( group && group->SMDSGroup().Remove( elemToRm ) )
1829         for ( int i = 0; i < elemToAdd.size(); ++i )
1830           group->SMDSGroup().Add( elemToAdd[ i ] );
1831     }
1832   }
1833 }
1834
1835 //=======================================================================
1836 //function : QuadToTri
1837 //purpose  : Cut quadrangles into triangles.
1838 //           theCrit is used to select a diagonal to cut
1839 //=======================================================================
1840
1841 bool SMESH_MeshEditor::QuadToTri (TIDSortedElemSet & theElems,
1842                                   const bool         the13Diag)
1843 {
1844   myLastCreatedElems.Clear();
1845   myLastCreatedNodes.Clear();
1846
1847   MESSAGE( "::QuadToTri()" );
1848
1849   SMESHDS_Mesh * aMesh = GetMeshDS();
1850
1851   Handle(Geom_Surface) surface;
1852   SMESH_MesherHelper   helper( *GetMesh() );
1853
1854   TIDSortedElemSet::iterator itElem;
1855   for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
1856     const SMDS_MeshElement* elem = *itElem;
1857     if ( !elem || elem->GetType() != SMDSAbs_Face )
1858       continue;
1859     bool isquad = elem->NbNodes()==4 || elem->NbNodes()==8;
1860     if(!isquad) continue;
1861
1862     if(elem->NbNodes()==4) {
1863       // retrieve element nodes
1864       const SMDS_MeshNode* aNodes [4];
1865       SMDS_ElemIteratorPtr itN = elem->nodesIterator();
1866       int i = 0;
1867       while ( itN->more() )
1868         aNodes[ i++ ] = static_cast<const SMDS_MeshNode*>( itN->next() );
1869
1870       int aShapeId = FindShape( elem );
1871       const SMDS_MeshElement* newElem1 = 0;
1872       const SMDS_MeshElement* newElem2 = 0;
1873       if ( the13Diag ) {
1874         newElem1 = aMesh->AddFace( aNodes[2], aNodes[0], aNodes[1] );
1875         newElem2 = aMesh->AddFace( aNodes[2], aNodes[3], aNodes[0] );
1876       }
1877       else {
1878         newElem1 = aMesh->AddFace( aNodes[3], aNodes[0], aNodes[1] );
1879         newElem2 = aMesh->AddFace( aNodes[3], aNodes[1], aNodes[2] );
1880       }
1881       myLastCreatedElems.Append(newElem1);
1882       myLastCreatedElems.Append(newElem2);
1883       // put a new triangle on the same shape and add to the same groups
1884       if ( aShapeId )
1885         {
1886           aMesh->SetMeshElementOnShape( newElem1, aShapeId );
1887           aMesh->SetMeshElementOnShape( newElem2, aShapeId );
1888         }
1889       AddToSameGroups( newElem1, elem, aMesh );
1890       AddToSameGroups( newElem2, elem, aMesh );
1891       //aMesh->RemoveFreeElement(elem, aMesh->MeshElements(aShapeId), true);
1892       aMesh->RemoveElement( elem );
1893     }
1894
1895     // Quadratic quadrangle
1896
1897     if( elem->NbNodes()==8 && elem->IsQuadratic() ) {
1898
1899       // get surface elem is on
1900       int aShapeId = FindShape( elem );
1901       if ( aShapeId != helper.GetSubShapeID() ) {
1902         surface.Nullify();
1903         TopoDS_Shape shape;
1904         if ( aShapeId > 0 )
1905           shape = aMesh->IndexToShape( aShapeId );
1906         if ( !shape.IsNull() && shape.ShapeType() == TopAbs_FACE ) {
1907           TopoDS_Face face = TopoDS::Face( shape );
1908           surface = BRep_Tool::Surface( face );
1909           if ( !surface.IsNull() )
1910             helper.SetSubShape( shape );
1911         }
1912       }
1913
1914       const SMDS_MeshNode* aNodes [8];
1915       const SMDS_MeshNode* inFaceNode = 0;
1916       SMDS_ElemIteratorPtr itN = elem->nodesIterator();
1917       int i = 0;
1918       while ( itN->more() ) {
1919         aNodes[ i++ ] = static_cast<const SMDS_MeshNode*>( itN->next() );
1920         if ( !inFaceNode && helper.GetNodeUVneedInFaceNode() &&
1921              aNodes[ i-1 ]->GetPosition()->GetTypeOfPosition() == SMDS_TOP_FACE )
1922         {
1923           inFaceNode = aNodes[ i-1 ];
1924         }
1925       }
1926
1927       // find middle point for (0,1,2,3)
1928       // and create a node in this point;
1929       gp_XYZ p( 0,0,0 );
1930       if ( surface.IsNull() ) {
1931         for(i=0; i<4; i++)
1932           p += gp_XYZ(aNodes[i]->X(), aNodes[i]->Y(), aNodes[i]->Z() );
1933         p /= 4;
1934       }
1935       else {
1936         TopoDS_Face geomFace = TopoDS::Face( helper.GetSubShape() );
1937         gp_XY uv( 0,0 );
1938         for(i=0; i<4; i++)
1939           uv += helper.GetNodeUV( geomFace, aNodes[i], inFaceNode );
1940         uv /= 4.;
1941         p = surface->Value( uv.X(), uv.Y() ).XYZ();
1942       }
1943       const SMDS_MeshNode* newN = aMesh->AddNode( p.X(), p.Y(), p.Z() );
1944       myLastCreatedNodes.Append(newN);
1945
1946       // create a new element
1947       const SMDS_MeshElement* newElem1 = 0;
1948       const SMDS_MeshElement* newElem2 = 0;
1949       const SMDS_MeshNode* N[6];
1950       if ( the13Diag ) {
1951         N[0] = aNodes[0];
1952         N[1] = aNodes[1];
1953         N[2] = aNodes[2];
1954         N[3] = aNodes[4];
1955         N[4] = aNodes[5];
1956         N[5] = newN;
1957         newElem1 = aMesh->AddFace(aNodes[2], aNodes[3], aNodes[0],
1958                                   aNodes[6], aNodes[7], newN );
1959         newElem2 = aMesh->AddFace(aNodes[2], aNodes[0], aNodes[1],
1960                                   newN,      aNodes[4], aNodes[5] );
1961       }
1962       else {
1963         N[0] = aNodes[1];
1964         N[1] = aNodes[2];
1965         N[2] = aNodes[3];
1966         N[3] = aNodes[5];
1967         N[4] = aNodes[6];
1968         N[5] = newN;
1969         newElem1 = aMesh->AddFace(aNodes[3], aNodes[0], aNodes[1],
1970                                   aNodes[7], aNodes[4], newN );
1971         newElem2 = aMesh->AddFace(aNodes[3], aNodes[1], aNodes[2],
1972                                   newN,      aNodes[5], aNodes[6] );
1973       }
1974       myLastCreatedElems.Append(newElem1);
1975       myLastCreatedElems.Append(newElem2);
1976       // put a new triangle on the same shape and add to the same groups
1977       if ( aShapeId )
1978         {
1979           aMesh->SetMeshElementOnShape( newElem1, aShapeId );
1980           aMesh->SetMeshElementOnShape( newElem2, aShapeId );
1981         }
1982       AddToSameGroups( newElem1, elem, aMesh );
1983       AddToSameGroups( newElem2, elem, aMesh );
1984       aMesh->RemoveElement( elem );
1985     }
1986   }
1987
1988   return true;
1989 }
1990
1991 //=======================================================================
1992 //function : getAngle
1993 //purpose  :
1994 //=======================================================================
1995
1996 double getAngle(const SMDS_MeshElement * tr1,
1997                 const SMDS_MeshElement * tr2,
1998                 const SMDS_MeshNode *    n1,
1999                 const SMDS_MeshNode *    n2)
2000 {
2001   double angle = 2*PI; // bad angle
2002
2003   // get normals
2004   SMESH::Controls::TSequenceOfXYZ P1, P2;
2005   if ( !SMESH::Controls::NumericalFunctor::GetPoints( tr1, P1 ) ||
2006        !SMESH::Controls::NumericalFunctor::GetPoints( tr2, P2 ))
2007     return angle;
2008   gp_Vec N1,N2;
2009   if(!tr1->IsQuadratic())
2010     N1 = gp_Vec( P1(2) - P1(1) ) ^ gp_Vec( P1(3) - P1(1) );
2011   else
2012     N1 = gp_Vec( P1(3) - P1(1) ) ^ gp_Vec( P1(5) - P1(1) );
2013   if ( N1.SquareMagnitude() <= gp::Resolution() )
2014     return angle;
2015   if(!tr2->IsQuadratic())
2016     N2 = gp_Vec( P2(2) - P2(1) ) ^ gp_Vec( P2(3) - P2(1) );
2017   else
2018     N2 = gp_Vec( P2(3) - P2(1) ) ^ gp_Vec( P2(5) - P2(1) );
2019   if ( N2.SquareMagnitude() <= gp::Resolution() )
2020     return angle;
2021
2022   // find the first diagonal node n1 in the triangles:
2023   // take in account a diagonal link orientation
2024   const SMDS_MeshElement *nFirst[2], *tr[] = { tr1, tr2 };
2025   for ( int t = 0; t < 2; t++ ) {
2026     SMDS_ElemIteratorPtr it = tr[ t ]->nodesIterator();
2027     int i = 0, iDiag = -1;
2028     while ( it->more()) {
2029       const SMDS_MeshElement *n = it->next();
2030       if ( n == n1 || n == n2 ) {
2031         if ( iDiag < 0)
2032           iDiag = i;
2033         else {
2034           if ( i - iDiag == 1 )
2035             nFirst[ t ] = ( n == n1 ? n2 : n1 );
2036           else
2037             nFirst[ t ] = n;
2038           break;
2039         }
2040       }
2041       i++;
2042     }
2043   }
2044   if ( nFirst[ 0 ] == nFirst[ 1 ] )
2045     N2.Reverse();
2046
2047   angle = N1.Angle( N2 );
2048   //SCRUTE( angle );
2049   return angle;
2050 }
2051
2052 // =================================================
2053 // class generating a unique ID for a pair of nodes
2054 // and able to return nodes by that ID
2055 // =================================================
2056 class LinkID_Gen {
2057 public:
2058
2059   LinkID_Gen( const SMESHDS_Mesh* theMesh )
2060     :myMesh( theMesh ), myMaxID( theMesh->MaxNodeID() + 1)
2061   {}
2062
2063   long GetLinkID (const SMDS_MeshNode * n1,
2064                   const SMDS_MeshNode * n2) const
2065   {
2066     return ( Min(n1->GetID(),n2->GetID()) * myMaxID + Max(n1->GetID(),n2->GetID()));
2067   }
2068
2069   bool GetNodes (const long             theLinkID,
2070                  const SMDS_MeshNode* & theNode1,
2071                  const SMDS_MeshNode* & theNode2) const
2072   {
2073     theNode1 = myMesh->FindNode( theLinkID / myMaxID );
2074     if ( !theNode1 ) return false;
2075     theNode2 = myMesh->FindNode( theLinkID % myMaxID );
2076     if ( !theNode2 ) return false;
2077     return true;
2078   }
2079
2080 private:
2081   LinkID_Gen();
2082   const SMESHDS_Mesh* myMesh;
2083   long                myMaxID;
2084 };
2085
2086
2087 //=======================================================================
2088 //function : TriToQuad
2089 //purpose  : Fuse neighbour triangles into quadrangles.
2090 //           theCrit is used to select a neighbour to fuse with.
2091 //           theMaxAngle is a max angle between element normals at which
2092 //           fusion is still performed.
2093 //=======================================================================
2094
2095 bool SMESH_MeshEditor::TriToQuad (TIDSortedElemSet &                   theElems,
2096                                   SMESH::Controls::NumericalFunctorPtr theCrit,
2097                                   const double                         theMaxAngle)
2098 {
2099   myLastCreatedElems.Clear();
2100   myLastCreatedNodes.Clear();
2101
2102   MESSAGE( "::TriToQuad()" );
2103
2104   if ( !theCrit.get() )
2105     return false;
2106
2107   SMESHDS_Mesh * aMesh = GetMeshDS();
2108
2109   // Prepare data for algo: build
2110   // 1. map of elements with their linkIDs
2111   // 2. map of linkIDs with their elements
2112
2113   map< SMESH_TLink, list< const SMDS_MeshElement* > > mapLi_listEl;
2114   map< SMESH_TLink, list< const SMDS_MeshElement* > >::iterator itLE;
2115   map< const SMDS_MeshElement*, set< SMESH_TLink > >  mapEl_setLi;
2116   map< const SMDS_MeshElement*, set< SMESH_TLink > >::iterator itEL;
2117
2118   TIDSortedElemSet::iterator itElem;
2119   for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
2120     const SMDS_MeshElement* elem = *itElem;
2121     if(!elem || elem->GetType() != SMDSAbs_Face ) continue;
2122     bool IsTria = elem->NbNodes()==3 || (elem->NbNodes()==6 && elem->IsQuadratic());
2123     if(!IsTria) continue;
2124
2125     // retrieve element nodes
2126     const SMDS_MeshNode* aNodes [4];
2127     SMDS_ElemIteratorPtr itN = elem->nodesIterator();
2128     int i = 0;
2129     while ( i<3 )
2130       aNodes[ i++ ] = cast2Node( itN->next() );
2131     aNodes[ 3 ] = aNodes[ 0 ];
2132
2133     // fill maps
2134     for ( i = 0; i < 3; i++ ) {
2135       SMESH_TLink link( aNodes[i], aNodes[i+1] );
2136       // check if elements sharing a link can be fused
2137       itLE = mapLi_listEl.find( link );
2138       if ( itLE != mapLi_listEl.end() ) {
2139         if ((*itLE).second.size() > 1 ) // consider only 2 elems adjacent by a link
2140           continue;
2141         const SMDS_MeshElement* elem2 = (*itLE).second.front();
2142         //if ( FindShape( elem ) != FindShape( elem2 ))
2143         //  continue; // do not fuse triangles laying on different shapes
2144         if ( getAngle( elem, elem2, aNodes[i], aNodes[i+1] ) > theMaxAngle )
2145           continue; // avoid making badly shaped quads
2146         (*itLE).second.push_back( elem );
2147       }
2148       else {
2149         mapLi_listEl[ link ].push_back( elem );
2150       }
2151       mapEl_setLi [ elem ].insert( link );
2152     }
2153   }
2154   // Clean the maps from the links shared by a sole element, ie
2155   // links to which only one element is bound in mapLi_listEl
2156
2157   for ( itLE = mapLi_listEl.begin(); itLE != mapLi_listEl.end(); itLE++ ) {
2158     int nbElems = (*itLE).second.size();
2159     if ( nbElems < 2  ) {
2160       const SMDS_MeshElement* elem = (*itLE).second.front();
2161       SMESH_TLink link = (*itLE).first;
2162       mapEl_setLi[ elem ].erase( link );
2163       if ( mapEl_setLi[ elem ].empty() )
2164         mapEl_setLi.erase( elem );
2165     }
2166   }
2167
2168   // Algo: fuse triangles into quadrangles
2169
2170   while ( ! mapEl_setLi.empty() ) {
2171     // Look for the start element:
2172     // the element having the least nb of shared links
2173     const SMDS_MeshElement* startElem = 0;
2174     int minNbLinks = 4;
2175     for ( itEL = mapEl_setLi.begin(); itEL != mapEl_setLi.end(); itEL++ ) {
2176       int nbLinks = (*itEL).second.size();
2177       if ( nbLinks < minNbLinks ) {
2178         startElem = (*itEL).first;
2179         minNbLinks = nbLinks;
2180         if ( minNbLinks == 1 )
2181           break;
2182       }
2183     }
2184
2185     // search elements to fuse starting from startElem or links of elements
2186     // fused earlyer - startLinks
2187     list< SMESH_TLink > startLinks;
2188     while ( startElem || !startLinks.empty() ) {
2189       while ( !startElem && !startLinks.empty() ) {
2190         // Get an element to start, by a link
2191         SMESH_TLink linkId = startLinks.front();
2192         startLinks.pop_front();
2193         itLE = mapLi_listEl.find( linkId );
2194         if ( itLE != mapLi_listEl.end() ) {
2195           list< const SMDS_MeshElement* > & listElem = (*itLE).second;
2196           list< const SMDS_MeshElement* >::iterator itE = listElem.begin();
2197           for ( ; itE != listElem.end() ; itE++ )
2198             if ( mapEl_setLi.find( (*itE) ) != mapEl_setLi.end() )
2199               startElem = (*itE);
2200           mapLi_listEl.erase( itLE );
2201         }
2202       }
2203
2204       if ( startElem ) {
2205         // Get candidates to be fused
2206         const SMDS_MeshElement *tr1 = startElem, *tr2 = 0, *tr3 = 0;
2207         const SMESH_TLink *link12, *link13;
2208         startElem = 0;
2209         ASSERT( mapEl_setLi.find( tr1 ) != mapEl_setLi.end() );
2210         set< SMESH_TLink >& setLi = mapEl_setLi[ tr1 ];
2211         ASSERT( !setLi.empty() );
2212         set< SMESH_TLink >::iterator itLi;
2213         for ( itLi = setLi.begin(); itLi != setLi.end(); itLi++ )
2214         {
2215           const SMESH_TLink & link = (*itLi);
2216           itLE = mapLi_listEl.find( link );
2217           if ( itLE == mapLi_listEl.end() )
2218             continue;
2219
2220           const SMDS_MeshElement* elem = (*itLE).second.front();
2221           if ( elem == tr1 )
2222             elem = (*itLE).second.back();
2223           mapLi_listEl.erase( itLE );
2224           if ( mapEl_setLi.find( elem ) == mapEl_setLi.end())
2225             continue;
2226           if ( tr2 ) {
2227             tr3 = elem;
2228             link13 = &link;
2229           }
2230           else {
2231             tr2 = elem;
2232             link12 = &link;
2233           }
2234
2235           // add other links of elem to list of links to re-start from
2236           set< SMESH_TLink >& links = mapEl_setLi[ elem ];
2237           set< SMESH_TLink >::iterator it;
2238           for ( it = links.begin(); it != links.end(); it++ ) {
2239             const SMESH_TLink& link2 = (*it);
2240             if ( link2 != link )
2241               startLinks.push_back( link2 );
2242           }
2243         }
2244
2245         // Get nodes of possible quadrangles
2246         const SMDS_MeshNode *n12 [4], *n13 [4];
2247         bool Ok12 = false, Ok13 = false;
2248         const SMDS_MeshNode *linkNode1, *linkNode2;
2249         if(tr2) {
2250           linkNode1 = link12->first;
2251           linkNode2 = link12->second;
2252           if ( tr2 && getQuadrangleNodes( n12, linkNode1, linkNode2, tr1, tr2 ))
2253             Ok12 = true;
2254         }
2255         if(tr3) {
2256           linkNode1 = link13->first;
2257           linkNode2 = link13->second;
2258           if ( tr3 && getQuadrangleNodes( n13, linkNode1, linkNode2, tr1, tr3 ))
2259             Ok13 = true;
2260         }
2261
2262         // Choose a pair to fuse
2263         if ( Ok12 && Ok13 ) {
2264           SMDS_FaceOfNodes quad12 ( n12[ 0 ], n12[ 1 ], n12[ 2 ], n12[ 3 ] );
2265           SMDS_FaceOfNodes quad13 ( n13[ 0 ], n13[ 1 ], n13[ 2 ], n13[ 3 ] );
2266           double aBadRate12 = getBadRate( &quad12, theCrit );
2267           double aBadRate13 = getBadRate( &quad13, theCrit );
2268           if (  aBadRate13 < aBadRate12 )
2269             Ok12 = false;
2270           else
2271             Ok13 = false;
2272         }
2273
2274         // Make quadrangles
2275         // and remove fused elems and removed links from the maps
2276         mapEl_setLi.erase( tr1 );
2277         if ( Ok12 ) {
2278           mapEl_setLi.erase( tr2 );
2279           mapLi_listEl.erase( *link12 );
2280           if(tr1->NbNodes()==3) {
2281             const SMDS_MeshElement* newElem = 0;
2282             newElem = aMesh->AddFace(n12[0], n12[1], n12[2], n12[3] );
2283             myLastCreatedElems.Append(newElem);
2284             AddToSameGroups( newElem, tr1, aMesh );
2285             int aShapeId = tr1->getshapeId();
2286             if ( aShapeId )
2287               {
2288                 aMesh->SetMeshElementOnShape( newElem, aShapeId );
2289               }
2290             aMesh->RemoveElement( tr1 );
2291             aMesh->RemoveElement( tr2 );
2292           }
2293           else {
2294             const SMDS_MeshNode* N1 [6];
2295             const SMDS_MeshNode* N2 [6];
2296             GetNodesFromTwoTria(tr1,tr2,N1,N2);
2297             // now we receive following N1 and N2 (using numeration as above image)
2298             // tria1 : (1 2 4 5 9 7)  and  tria2 : (3 4 2 8 9 6)
2299             // i.e. first nodes from both arrays determ new diagonal
2300             const SMDS_MeshNode* aNodes[8];
2301             aNodes[0] = N1[0];
2302             aNodes[1] = N1[1];
2303             aNodes[2] = N2[0];
2304             aNodes[3] = N2[1];
2305             aNodes[4] = N1[3];
2306             aNodes[5] = N2[5];
2307             aNodes[6] = N2[3];
2308             aNodes[7] = N1[5];
2309             const SMDS_MeshElement* newElem = 0;
2310             newElem = aMesh->AddFace(aNodes[0], aNodes[1], aNodes[2], aNodes[3],
2311                                      aNodes[4], aNodes[5], aNodes[6], aNodes[7]);
2312             myLastCreatedElems.Append(newElem);
2313             AddToSameGroups( newElem, tr1, aMesh );
2314             int aShapeId = tr1->getshapeId();
2315             if ( aShapeId )
2316               {
2317                 aMesh->SetMeshElementOnShape( newElem, aShapeId );
2318               }
2319             aMesh->RemoveElement( tr1 );
2320             aMesh->RemoveElement( tr2 );
2321             // remove middle node (9)
2322             GetMeshDS()->RemoveNode( N1[4] );
2323           }
2324         }
2325         else if ( Ok13 ) {
2326           mapEl_setLi.erase( tr3 );
2327           mapLi_listEl.erase( *link13 );
2328           if(tr1->NbNodes()==3) {
2329             const SMDS_MeshElement* newElem = 0;
2330             newElem = aMesh->AddFace(n13[0], n13[1], n13[2], n13[3] );
2331             myLastCreatedElems.Append(newElem);
2332             AddToSameGroups( newElem, tr1, aMesh );
2333             int aShapeId = tr1->getshapeId();
2334             if ( aShapeId )
2335               {
2336                 aMesh->SetMeshElementOnShape( newElem, aShapeId );
2337               }
2338             aMesh->RemoveElement( tr1 );
2339             aMesh->RemoveElement( tr3 );
2340           }
2341           else {
2342             const SMDS_MeshNode* N1 [6];
2343             const SMDS_MeshNode* N2 [6];
2344             GetNodesFromTwoTria(tr1,tr3,N1,N2);
2345             // now we receive following N1 and N2 (using numeration as above image)
2346             // tria1 : (1 2 4 5 9 7)  and  tria2 : (3 4 2 8 9 6)
2347             // i.e. first nodes from both arrays determ new diagonal
2348             const SMDS_MeshNode* aNodes[8];
2349             aNodes[0] = N1[0];
2350             aNodes[1] = N1[1];
2351             aNodes[2] = N2[0];
2352             aNodes[3] = N2[1];
2353             aNodes[4] = N1[3];
2354             aNodes[5] = N2[5];
2355             aNodes[6] = N2[3];
2356             aNodes[7] = N1[5];
2357             const SMDS_MeshElement* newElem = 0;
2358             newElem = aMesh->AddFace(aNodes[0], aNodes[1], aNodes[2], aNodes[3],
2359                                      aNodes[4], aNodes[5], aNodes[6], aNodes[7]);
2360             myLastCreatedElems.Append(newElem);
2361             AddToSameGroups( newElem, tr1, aMesh );
2362             int aShapeId = tr1->getshapeId();
2363             if ( aShapeId )
2364               {
2365                 aMesh->SetMeshElementOnShape( newElem, aShapeId );
2366               }
2367             aMesh->RemoveElement( tr1 );
2368             aMesh->RemoveElement( tr3 );
2369             // remove middle node (9)
2370             GetMeshDS()->RemoveNode( N1[4] );
2371           }
2372         }
2373
2374         // Next element to fuse: the rejected one
2375         if ( tr3 )
2376           startElem = Ok12 ? tr3 : tr2;
2377
2378       } // if ( startElem )
2379     } // while ( startElem || !startLinks.empty() )
2380   } // while ( ! mapEl_setLi.empty() )
2381
2382   return true;
2383 }
2384
2385
2386 /*#define DUMPSO(txt) \
2387 //  cout << txt << endl;
2388 //=============================================================================
2389 //
2390 //
2391 //
2392 //=============================================================================
2393 static void swap( int i1, int i2, int idNodes[], gp_Pnt P[] )
2394 {
2395 if ( i1 == i2 )
2396 return;
2397 int tmp = idNodes[ i1 ];
2398 idNodes[ i1 ] = idNodes[ i2 ];
2399 idNodes[ i2 ] = tmp;
2400 gp_Pnt Ptmp = P[ i1 ];
2401 P[ i1 ] = P[ i2 ];
2402 P[ i2 ] = Ptmp;
2403 DUMPSO( i1 << "(" << idNodes[ i2 ] << ") <-> " << i2 << "(" << idNodes[ i1 ] << ")");
2404 }
2405
2406 //=======================================================================
2407 //function : SortQuadNodes
2408 //purpose  : Set 4 nodes of a quadrangle face in a good order.
2409 //           Swap 1<->2 or 2<->3 nodes and correspondingly return
2410 //           1 or 2 else 0.
2411 //=======================================================================
2412
2413 int SMESH_MeshEditor::SortQuadNodes (const SMDS_Mesh * theMesh,
2414 int               idNodes[] )
2415 {
2416   gp_Pnt P[4];
2417   int i;
2418   for ( i = 0; i < 4; i++ ) {
2419     const SMDS_MeshNode *n = theMesh->FindNode( idNodes[i] );
2420     if ( !n ) return 0;
2421     P[ i ].SetCoord( n->X(), n->Y(), n->Z() );
2422   }
2423
2424   gp_Vec V1(P[0], P[1]);
2425   gp_Vec V2(P[0], P[2]);
2426   gp_Vec V3(P[0], P[3]);
2427
2428   gp_Vec Cross1 = V1 ^ V2;
2429   gp_Vec Cross2 = V2 ^ V3;
2430
2431   i = 0;
2432   if (Cross1.Dot(Cross2) < 0)
2433   {
2434     Cross1 = V2 ^ V1;
2435     Cross2 = V1 ^ V3;
2436
2437     if (Cross1.Dot(Cross2) < 0)
2438       i = 2;
2439     else
2440       i = 1;
2441     swap ( i, i + 1, idNodes, P );
2442
2443     //     for ( int ii = 0; ii < 4; ii++ ) {
2444     //       const SMDS_MeshNode *n = theMesh->FindNode( idNodes[ii] );
2445     //       DUMPSO( ii << "(" << idNodes[ii] <<") : "<<n->X()<<" "<<n->Y()<<" "<<n->Z());
2446     //     }
2447   }
2448   return i;
2449 }
2450
2451 //=======================================================================
2452 //function : SortHexaNodes
2453 //purpose  : Set 8 nodes of a hexahedron in a good order.
2454 //           Return success status
2455 //=======================================================================
2456
2457 bool SMESH_MeshEditor::SortHexaNodes (const SMDS_Mesh * theMesh,
2458                                       int               idNodes[] )
2459 {
2460   gp_Pnt P[8];
2461   int i;
2462   DUMPSO( "INPUT: ========================================");
2463   for ( i = 0; i < 8; i++ ) {
2464     const SMDS_MeshNode *n = theMesh->FindNode( idNodes[i] );
2465     if ( !n ) return false;
2466     P[ i ].SetCoord( n->X(), n->Y(), n->Z() );
2467     DUMPSO( i << "(" << idNodes[i] <<") : "<<n->X()<<" "<<n->Y()<<" "<<n->Z());
2468   }
2469   DUMPSO( "========================================");
2470
2471
2472   set<int> faceNodes;  // ids of bottom face nodes, to be found
2473   set<int> checkedId1; // ids of tried 2-nd nodes
2474   Standard_Real leastDist = DBL_MAX; // dist of the 4-th node from 123 plane
2475   const Standard_Real tol = 1.e-6;   // tolerance to find nodes in plane
2476   int iMin, iLoop1 = 0;
2477
2478   // Loop to try the 2-nd nodes
2479
2480   while ( leastDist > DBL_MIN && ++iLoop1 < 8 )
2481   {
2482     // Find not checked 2-nd node
2483     for ( i = 1; i < 8; i++ )
2484       if ( checkedId1.find( idNodes[i] ) == checkedId1.end() ) {
2485         int id1 = idNodes[i];
2486         swap ( 1, i, idNodes, P );
2487         checkedId1.insert ( id1 );
2488         break;
2489       }
2490
2491     // Find the 3-d node so that 1-2-3 triangle to be on a hexa face,
2492     // ie that all but meybe one (id3 which is on the same face) nodes
2493     // lay on the same side from the triangle plane.
2494
2495     bool manyInPlane = false; // more than 4 nodes lay in plane
2496     int iLoop2 = 0;
2497     while ( ++iLoop2 < 6 ) {
2498
2499       // get 1-2-3 plane coeffs
2500       Standard_Real A, B, C, D;
2501       gp_Vec N = gp_Vec (P[0], P[1]).Crossed( gp_Vec (P[0], P[2]) );
2502       if ( N.SquareMagnitude() > gp::Resolution() )
2503       {
2504         gp_Pln pln ( P[0], N );
2505         pln.Coefficients( A, B, C, D );
2506
2507         // find the node (iMin) closest to pln
2508         Standard_Real dist[ 8 ], minDist = DBL_MAX;
2509         set<int> idInPln;
2510         for ( i = 3; i < 8; i++ ) {
2511           dist[i] = A * P[i].X() + B * P[i].Y() + C * P[i].Z() + D;
2512           if ( fabs( dist[i] ) < minDist ) {
2513             minDist = fabs( dist[i] );
2514             iMin = i;
2515           }
2516           if ( fabs( dist[i] ) <= tol )
2517             idInPln.insert( idNodes[i] );
2518         }
2519
2520         // there should not be more than 4 nodes in bottom plane
2521         if ( idInPln.size() > 1 )
2522         {
2523           DUMPSO( "### idInPln.size() = " << idInPln.size());
2524           // idInPlane does not contain the first 3 nodes
2525           if ( manyInPlane || idInPln.size() == 5)
2526             return false; // all nodes in one plane
2527           manyInPlane = true;
2528
2529           // set the 1-st node to be not in plane
2530           for ( i = 3; i < 8; i++ ) {
2531             if ( idInPln.find( idNodes[ i ] ) == idInPln.end() ) {
2532               DUMPSO( "### Reset 0-th node");
2533               swap( 0, i, idNodes, P );
2534               break;
2535             }
2536           }
2537
2538           // reset to re-check second nodes
2539           leastDist = DBL_MAX;
2540           faceNodes.clear();
2541           checkedId1.clear();
2542           iLoop1 = 0;
2543           break; // from iLoop2;
2544         }
2545
2546         // check that the other 4 nodes are on the same side
2547         bool sameSide = true;
2548         bool isNeg = dist[ iMin == 3 ? 4 : 3 ] <= 0.;
2549         for ( i = 3; sameSide && i < 8; i++ ) {
2550           if ( i != iMin )
2551             sameSide = ( isNeg == dist[i] <= 0.);
2552         }
2553
2554         // keep best solution
2555         if ( sameSide && minDist < leastDist ) {
2556           leastDist = minDist;
2557           faceNodes.clear();
2558           faceNodes.insert( idNodes[ 1 ] );
2559           faceNodes.insert( idNodes[ 2 ] );
2560           faceNodes.insert( idNodes[ iMin ] );
2561           DUMPSO( "loop " << iLoop2 << " id2 " << idNodes[ 1 ] << " id3 " << idNodes[ 2 ]
2562                   << " leastDist = " << leastDist);
2563           if ( leastDist <= DBL_MIN )
2564             break;
2565         }
2566       }
2567
2568       // set next 3-d node to check
2569       int iNext = 2 + iLoop2;
2570       if ( iNext < 8 ) {
2571         DUMPSO( "Try 2-nd");
2572         swap ( 2, iNext, idNodes, P );
2573       }
2574     } // while ( iLoop2 < 6 )
2575   } // iLoop1
2576
2577   if ( faceNodes.empty() ) return false;
2578
2579   // Put the faceNodes in proper places
2580   for ( i = 4; i < 8; i++ ) {
2581     if ( faceNodes.find( idNodes[ i ] ) != faceNodes.end() ) {
2582       // find a place to put
2583       int iTo = 1;
2584       while ( faceNodes.find( idNodes[ iTo ] ) != faceNodes.end() )
2585         iTo++;
2586       DUMPSO( "Set faceNodes");
2587       swap ( iTo, i, idNodes, P );
2588     }
2589   }
2590
2591
2592   // Set nodes of the found bottom face in good order
2593   DUMPSO( " Found bottom face: ");
2594   i = SortQuadNodes( theMesh, idNodes );
2595   if ( i ) {
2596     gp_Pnt Ptmp = P[ i ];
2597     P[ i ] = P[ i+1 ];
2598     P[ i+1 ] = Ptmp;
2599   }
2600   //   else
2601   //     for ( int ii = 0; ii < 4; ii++ ) {
2602   //       const SMDS_MeshNode *n = theMesh->FindNode( idNodes[ii] );
2603   //       DUMPSO( ii << "(" << idNodes[ii] <<") : "<<n->X()<<" "<<n->Y()<<" "<<n->Z());
2604   //    }
2605
2606   // Gravity center of the top and bottom faces
2607   gp_Pnt aGCb = ( P[0].XYZ() + P[1].XYZ() + P[2].XYZ() + P[3].XYZ() ) / 4.;
2608   gp_Pnt aGCt = ( P[4].XYZ() + P[5].XYZ() + P[6].XYZ() + P[7].XYZ() ) / 4.;
2609
2610   // Get direction from the bottom to the top face
2611   gp_Vec upDir ( aGCb, aGCt );
2612   Standard_Real upDirSize = upDir.Magnitude();
2613   if ( upDirSize <= gp::Resolution() ) return false;
2614   upDir / upDirSize;
2615
2616   // Assure that the bottom face normal points up
2617   gp_Vec Nb = gp_Vec (P[0], P[1]).Crossed( gp_Vec (P[0], P[2]) );
2618   Nb += gp_Vec (P[0], P[2]).Crossed( gp_Vec (P[0], P[3]) );
2619   if ( Nb.Dot( upDir ) < 0 ) {
2620     DUMPSO( "Reverse bottom face");
2621     swap( 1, 3, idNodes, P );
2622   }
2623
2624   // Find 5-th node - the one closest to the 1-st among the last 4 nodes.
2625   Standard_Real minDist = DBL_MAX;
2626   for ( i = 4; i < 8; i++ ) {
2627     // projection of P[i] to the plane defined by P[0] and upDir
2628     gp_Pnt Pp = P[i].Translated( upDir * ( upDir.Dot( gp_Vec( P[i], P[0] ))));
2629     Standard_Real sqDist = P[0].SquareDistance( Pp );
2630     if ( sqDist < minDist ) {
2631       minDist = sqDist;
2632       iMin = i;
2633     }
2634   }
2635   DUMPSO( "Set 4-th");
2636   swap ( 4, iMin, idNodes, P );
2637
2638   // Set nodes of the top face in good order
2639   DUMPSO( "Sort top face");
2640   i = SortQuadNodes( theMesh, &idNodes[4] );
2641   if ( i ) {
2642     i += 4;
2643     gp_Pnt Ptmp = P[ i ];
2644     P[ i ] = P[ i+1 ];
2645     P[ i+1 ] = Ptmp;
2646   }
2647
2648   // Assure that direction of the top face normal is from the bottom face
2649   gp_Vec Nt = gp_Vec (P[4], P[5]).Crossed( gp_Vec (P[4], P[6]) );
2650   Nt += gp_Vec (P[4], P[6]).Crossed( gp_Vec (P[4], P[7]) );
2651   if ( Nt.Dot( upDir ) < 0 ) {
2652     DUMPSO( "Reverse top face");
2653     swap( 5, 7, idNodes, P );
2654   }
2655
2656   //   DUMPSO( "OUTPUT: ========================================");
2657   //   for ( i = 0; i < 8; i++ ) {
2658   //     float *p = ugrid->GetPoint(idNodes[i]);
2659   //     DUMPSO( i << "(" << idNodes[i] << ") : " << p[0] << " " << p[1] << " " << p[2]);
2660   //   }
2661
2662   return true;
2663 }*/
2664
2665 //================================================================================
2666 /*!
2667  * \brief Return nodes linked to the given one
2668  * \param theNode - the node
2669  * \param linkedNodes - the found nodes
2670  * \param type - the type of elements to check
2671  *
2672  * Medium nodes are ignored
2673  */
2674 //================================================================================
2675
2676 void SMESH_MeshEditor::GetLinkedNodes( const SMDS_MeshNode* theNode,
2677                                        TIDSortedElemSet &   linkedNodes,
2678                                        SMDSAbs_ElementType  type )
2679 {
2680   SMDS_ElemIteratorPtr elemIt = theNode->GetInverseElementIterator(type);
2681   while ( elemIt->more() )
2682   {
2683     const SMDS_MeshElement* elem = elemIt->next();
2684     SMDS_ElemIteratorPtr nodeIt = elem->nodesIterator();
2685     if ( elem->GetType() == SMDSAbs_Volume )
2686     {
2687       SMDS_VolumeTool vol( elem );
2688       while ( nodeIt->more() ) {
2689         const SMDS_MeshNode* n = cast2Node( nodeIt->next() );
2690         if ( theNode != n && vol.IsLinked( theNode, n ))
2691           linkedNodes.insert( n );
2692       }
2693     }
2694     else
2695     {
2696       for ( int i = 0; nodeIt->more(); ++i ) {
2697         const SMDS_MeshNode* n = cast2Node( nodeIt->next() );
2698         if ( n == theNode ) {
2699           int iBefore = i - 1;
2700           int iAfter  = i + 1;
2701           if ( elem->IsQuadratic() ) {
2702             int nb = elem->NbNodes() / 2;
2703             iAfter  = SMESH_MesherHelper::WrapIndex( iAfter, nb );
2704             iBefore = SMESH_MesherHelper::WrapIndex( iBefore, nb );
2705           }
2706           linkedNodes.insert( elem->GetNodeWrap( iAfter ));
2707           linkedNodes.insert( elem->GetNodeWrap( iBefore ));
2708         }
2709       }
2710     }
2711   }
2712 }
2713
2714 //=======================================================================
2715 //function : laplacianSmooth
2716 //purpose  : pulls theNode toward the center of surrounding nodes directly
2717 //           connected to that node along an element edge
2718 //=======================================================================
2719
2720 void laplacianSmooth(const SMDS_MeshNode*                 theNode,
2721                      const Handle(Geom_Surface)&          theSurface,
2722                      map< const SMDS_MeshNode*, gp_XY* >& theUVMap)
2723 {
2724   // find surrounding nodes
2725
2726   TIDSortedElemSet nodeSet;
2727   SMESH_MeshEditor::GetLinkedNodes( theNode, nodeSet, SMDSAbs_Face );
2728
2729   // compute new coodrs
2730
2731   double coord[] = { 0., 0., 0. };
2732   TIDSortedElemSet::iterator nodeSetIt = nodeSet.begin();
2733   for ( ; nodeSetIt != nodeSet.end(); nodeSetIt++ ) {
2734     const SMDS_MeshNode* node = cast2Node(*nodeSetIt);
2735     if ( theSurface.IsNull() ) { // smooth in 3D
2736       coord[0] += node->X();
2737       coord[1] += node->Y();
2738       coord[2] += node->Z();
2739     }
2740     else { // smooth in 2D
2741       ASSERT( theUVMap.find( node ) != theUVMap.end() );
2742       gp_XY* uv = theUVMap[ node ];
2743       coord[0] += uv->X();
2744       coord[1] += uv->Y();
2745     }
2746   }
2747   int nbNodes = nodeSet.size();
2748   if ( !nbNodes )
2749     return;
2750   coord[0] /= nbNodes;
2751   coord[1] /= nbNodes;
2752
2753   if ( !theSurface.IsNull() ) {
2754     ASSERT( theUVMap.find( theNode ) != theUVMap.end() );
2755     theUVMap[ theNode ]->SetCoord( coord[0], coord[1] );
2756     gp_Pnt p3d = theSurface->Value( coord[0], coord[1] );
2757     coord[0] = p3d.X();
2758     coord[1] = p3d.Y();
2759     coord[2] = p3d.Z();
2760   }
2761   else
2762     coord[2] /= nbNodes;
2763
2764   // move node
2765
2766   const_cast< SMDS_MeshNode* >( theNode )->setXYZ(coord[0],coord[1],coord[2]);
2767 }
2768
2769 //=======================================================================
2770 //function : centroidalSmooth
2771 //purpose  : pulls theNode toward the element-area-weighted centroid of the
2772 //           surrounding elements
2773 //=======================================================================
2774
2775 void centroidalSmooth(const SMDS_MeshNode*                 theNode,
2776                       const Handle(Geom_Surface)&          theSurface,
2777                       map< const SMDS_MeshNode*, gp_XY* >& theUVMap)
2778 {
2779   gp_XYZ aNewXYZ(0.,0.,0.);
2780   SMESH::Controls::Area anAreaFunc;
2781   double totalArea = 0.;
2782   int nbElems = 0;
2783
2784   // compute new XYZ
2785
2786   SMDS_ElemIteratorPtr elemIt = theNode->GetInverseElementIterator(SMDSAbs_Face);
2787   while ( elemIt->more() )
2788   {
2789     const SMDS_MeshElement* elem = elemIt->next();
2790     nbElems++;
2791
2792     gp_XYZ elemCenter(0.,0.,0.);
2793     SMESH::Controls::TSequenceOfXYZ aNodePoints;
2794     SMDS_ElemIteratorPtr itN = elem->nodesIterator();
2795     int nn = elem->NbNodes();
2796     if(elem->IsQuadratic()) nn = nn/2;
2797     int i=0;
2798     //while ( itN->more() ) {
2799     while ( i<nn ) {
2800       const SMDS_MeshNode* aNode = static_cast<const SMDS_MeshNode*>( itN->next() );
2801       i++;
2802       gp_XYZ aP( aNode->X(), aNode->Y(), aNode->Z() );
2803       aNodePoints.push_back( aP );
2804       if ( !theSurface.IsNull() ) { // smooth in 2D
2805         ASSERT( theUVMap.find( aNode ) != theUVMap.end() );
2806         gp_XY* uv = theUVMap[ aNode ];
2807         aP.SetCoord( uv->X(), uv->Y(), 0. );
2808       }
2809       elemCenter += aP;
2810     }
2811     double elemArea = anAreaFunc.GetValue( aNodePoints );
2812     totalArea += elemArea;
2813     elemCenter /= nn;
2814     aNewXYZ += elemCenter * elemArea;
2815   }
2816   aNewXYZ /= totalArea;
2817   if ( !theSurface.IsNull() ) {
2818     theUVMap[ theNode ]->SetCoord( aNewXYZ.X(), aNewXYZ.Y() );
2819     aNewXYZ = theSurface->Value( aNewXYZ.X(), aNewXYZ.Y() ).XYZ();
2820   }
2821
2822   // move node
2823
2824   const_cast< SMDS_MeshNode* >( theNode )->setXYZ(aNewXYZ.X(),aNewXYZ.Y(),aNewXYZ.Z());
2825 }
2826
2827 //=======================================================================
2828 //function : getClosestUV
2829 //purpose  : return UV of closest projection
2830 //=======================================================================
2831
2832 static bool getClosestUV (Extrema_GenExtPS& projector,
2833                           const gp_Pnt&     point,
2834                           gp_XY &           result)
2835 {
2836   projector.Perform( point );
2837   if ( projector.IsDone() ) {
2838     double u, v, minVal = DBL_MAX;
2839     for ( int i = projector.NbExt(); i > 0; i-- )
2840       if ( projector.Value( i ) < minVal ) {
2841         minVal = projector.Value( i );
2842         projector.Point( i ).Parameter( u, v );
2843       }
2844     result.SetCoord( u, v );
2845     return true;
2846   }
2847   return false;
2848 }
2849
2850 //=======================================================================
2851 //function : Smooth
2852 //purpose  : Smooth theElements during theNbIterations or until a worst
2853 //           element has aspect ratio <= theTgtAspectRatio.
2854 //           Aspect Ratio varies in range [1.0, inf].
2855 //           If theElements is empty, the whole mesh is smoothed.
2856 //           theFixedNodes contains additionally fixed nodes. Nodes built
2857 //           on edges and boundary nodes are always fixed.
2858 //=======================================================================
2859
2860 void SMESH_MeshEditor::Smooth (TIDSortedElemSet &          theElems,
2861                                set<const SMDS_MeshNode*> & theFixedNodes,
2862                                const SmoothMethod          theSmoothMethod,
2863                                const int                   theNbIterations,
2864                                double                      theTgtAspectRatio,
2865                                const bool                  the2D)
2866 {
2867   myLastCreatedElems.Clear();
2868   myLastCreatedNodes.Clear();
2869
2870   MESSAGE((theSmoothMethod==LAPLACIAN ? "LAPLACIAN" : "CENTROIDAL") << "--::Smooth()");
2871
2872   if ( theTgtAspectRatio < 1.0 )
2873     theTgtAspectRatio = 1.0;
2874
2875   const double disttol = 1.e-16;
2876
2877   SMESH::Controls::AspectRatio aQualityFunc;
2878
2879   SMESHDS_Mesh* aMesh = GetMeshDS();
2880
2881   if ( theElems.empty() ) {
2882     // add all faces to theElems
2883     SMDS_FaceIteratorPtr fIt = aMesh->facesIterator();
2884     while ( fIt->more() ) {
2885       const SMDS_MeshElement* face = fIt->next();
2886       theElems.insert( face );
2887     }
2888   }
2889   // get all face ids theElems are on
2890   set< int > faceIdSet;
2891   TIDSortedElemSet::iterator itElem;
2892   if ( the2D )
2893     for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
2894       int fId = FindShape( *itElem );
2895       // check that corresponding submesh exists and a shape is face
2896       if (fId &&
2897           faceIdSet.find( fId ) == faceIdSet.end() &&
2898           aMesh->MeshElements( fId )) {
2899         TopoDS_Shape F = aMesh->IndexToShape( fId );
2900         if ( !F.IsNull() && F.ShapeType() == TopAbs_FACE )
2901           faceIdSet.insert( fId );
2902       }
2903     }
2904   faceIdSet.insert( 0 ); // to smooth elements that are not on any TopoDS_Face
2905
2906   // ===============================================
2907   // smooth elements on each TopoDS_Face separately
2908   // ===============================================
2909
2910   set< int >::reverse_iterator fId = faceIdSet.rbegin(); // treate 0 fId at the end
2911   for ( ; fId != faceIdSet.rend(); ++fId ) {
2912     // get face surface and submesh
2913     Handle(Geom_Surface) surface;
2914     SMESHDS_SubMesh* faceSubMesh = 0;
2915     TopoDS_Face face;
2916     double fToler2 = 0, vPeriod = 0., uPeriod = 0., f,l;
2917     double u1 = 0, u2 = 0, v1 = 0, v2 = 0;
2918     bool isUPeriodic = false, isVPeriodic = false;
2919     if ( *fId ) {
2920       face = TopoDS::Face( aMesh->IndexToShape( *fId ));
2921       surface = BRep_Tool::Surface( face );
2922       faceSubMesh = aMesh->MeshElements( *fId );
2923       fToler2 = BRep_Tool::Tolerance( face );
2924       fToler2 *= fToler2 * 10.;
2925       isUPeriodic = surface->IsUPeriodic();
2926       if ( isUPeriodic )
2927         vPeriod = surface->UPeriod();
2928       isVPeriodic = surface->IsVPeriodic();
2929       if ( isVPeriodic )
2930         uPeriod = surface->VPeriod();
2931       surface->Bounds( u1, u2, v1, v2 );
2932     }
2933     // ---------------------------------------------------------
2934     // for elements on a face, find movable and fixed nodes and
2935     // compute UV for them
2936     // ---------------------------------------------------------
2937     bool checkBoundaryNodes = false;
2938     bool isQuadratic = false;
2939     set<const SMDS_MeshNode*> setMovableNodes;
2940     map< const SMDS_MeshNode*, gp_XY* > uvMap, uvMap2;
2941     list< gp_XY > listUV; // uvs the 2 uvMaps refer to
2942     list< const SMDS_MeshElement* > elemsOnFace;
2943
2944     Extrema_GenExtPS projector;
2945     GeomAdaptor_Surface surfAdaptor;
2946     if ( !surface.IsNull() ) {
2947       surfAdaptor.Load( surface );
2948       projector.Initialize( surfAdaptor, 20,20, 1e-5,1e-5 );
2949     }
2950     int nbElemOnFace = 0;
2951     itElem = theElems.begin();
2952     // loop on not yet smoothed elements: look for elems on a face
2953     while ( itElem != theElems.end() ) {
2954       if ( faceSubMesh && nbElemOnFace == faceSubMesh->NbElements() )
2955         break; // all elements found
2956
2957       const SMDS_MeshElement* elem = *itElem;
2958       if ( !elem || elem->GetType() != SMDSAbs_Face || elem->NbNodes() < 3 ||
2959            ( faceSubMesh && !faceSubMesh->Contains( elem ))) {
2960         ++itElem;
2961         continue;
2962       }
2963       elemsOnFace.push_back( elem );
2964       theElems.erase( itElem++ );
2965       nbElemOnFace++;
2966
2967       if ( !isQuadratic )
2968         isQuadratic = elem->IsQuadratic();
2969
2970       // get movable nodes of elem
2971       const SMDS_MeshNode* node;
2972       SMDS_TypeOfPosition posType;
2973       SMDS_ElemIteratorPtr itN = elem->nodesIterator();
2974       int nn = 0, nbn =  elem->NbNodes();
2975       if(elem->IsQuadratic())
2976         nbn = nbn/2;
2977       while ( nn++ < nbn ) {
2978         node = static_cast<const SMDS_MeshNode*>( itN->next() );
2979         const SMDS_PositionPtr& pos = node->GetPosition();
2980         posType = pos ? pos->GetTypeOfPosition() : SMDS_TOP_3DSPACE;
2981         if (posType != SMDS_TOP_EDGE &&
2982             posType != SMDS_TOP_VERTEX &&
2983             theFixedNodes.find( node ) == theFixedNodes.end())
2984         {
2985           // check if all faces around the node are on faceSubMesh
2986           // because a node on edge may be bound to face
2987           SMDS_ElemIteratorPtr eIt = node->GetInverseElementIterator(SMDSAbs_Face);
2988           bool all = true;
2989           if ( faceSubMesh ) {
2990             while ( eIt->more() && all ) {
2991               const SMDS_MeshElement* e = eIt->next();
2992               all = faceSubMesh->Contains( e );
2993             }
2994           }
2995           if ( all )
2996             setMovableNodes.insert( node );
2997           else
2998             checkBoundaryNodes = true;
2999         }
3000         if ( posType == SMDS_TOP_3DSPACE )
3001           checkBoundaryNodes = true;
3002       }
3003
3004       if ( surface.IsNull() )
3005         continue;
3006
3007       // get nodes to check UV
3008       list< const SMDS_MeshNode* > uvCheckNodes;
3009       itN = elem->nodesIterator();
3010       nn = 0; nbn =  elem->NbNodes();
3011       if(elem->IsQuadratic())
3012         nbn = nbn/2;
3013       while ( nn++ < nbn ) {
3014         node = static_cast<const SMDS_MeshNode*>( itN->next() );
3015         if ( uvMap.find( node ) == uvMap.end() )
3016           uvCheckNodes.push_back( node );
3017         // add nodes of elems sharing node
3018         //         SMDS_ElemIteratorPtr eIt = node->GetInverseElementIterator(SMDSAbs_Face);
3019         //         while ( eIt->more() ) {
3020         //           const SMDS_MeshElement* e = eIt->next();
3021         //           if ( e != elem ) {
3022         //             SMDS_ElemIteratorPtr nIt = e->nodesIterator();
3023         //             while ( nIt->more() ) {
3024         //               const SMDS_MeshNode* n =
3025         //                 static_cast<const SMDS_MeshNode*>( nIt->next() );
3026         //               if ( uvMap.find( n ) == uvMap.end() )
3027         //                 uvCheckNodes.push_back( n );
3028         //             }
3029         //           }
3030         //         }
3031       }
3032       // check UV on face
3033       list< const SMDS_MeshNode* >::iterator n = uvCheckNodes.begin();
3034       for ( ; n != uvCheckNodes.end(); ++n ) {
3035         node = *n;
3036         gp_XY uv( 0, 0 );
3037         const SMDS_PositionPtr& pos = node->GetPosition();
3038         posType = pos ? pos->GetTypeOfPosition() : SMDS_TOP_3DSPACE;
3039         // get existing UV
3040         switch ( posType ) {
3041         case SMDS_TOP_FACE: {
3042           SMDS_FacePosition* fPos = ( SMDS_FacePosition* ) pos;
3043           uv.SetCoord( fPos->GetUParameter(), fPos->GetVParameter() );
3044           break;
3045         }
3046         case SMDS_TOP_EDGE: {
3047           TopoDS_Shape S = aMesh->IndexToShape( node->getshapeId() );
3048           Handle(Geom2d_Curve) pcurve;
3049           if ( !S.IsNull() && S.ShapeType() == TopAbs_EDGE )
3050             pcurve = BRep_Tool::CurveOnSurface( TopoDS::Edge( S ), face, f,l );
3051           if ( !pcurve.IsNull() ) {
3052             double u = (( SMDS_EdgePosition* ) pos )->GetUParameter();
3053             uv = pcurve->Value( u ).XY();
3054           }
3055           break;
3056         }
3057         case SMDS_TOP_VERTEX: {
3058           TopoDS_Shape S = aMesh->IndexToShape( node->getshapeId() );
3059           if ( !S.IsNull() && S.ShapeType() == TopAbs_VERTEX )
3060             uv = BRep_Tool::Parameters( TopoDS::Vertex( S ), face ).XY();
3061           break;
3062         }
3063         default:;
3064         }
3065         // check existing UV
3066         bool project = true;
3067         gp_Pnt pNode ( node->X(), node->Y(), node->Z() );
3068         double dist1 = DBL_MAX, dist2 = 0;
3069         if ( posType != SMDS_TOP_3DSPACE ) {
3070           dist1 = pNode.SquareDistance( surface->Value( uv.X(), uv.Y() ));
3071           project = dist1 > fToler2;
3072         }
3073         if ( project ) { // compute new UV
3074           gp_XY newUV;
3075           if ( !getClosestUV( projector, pNode, newUV )) {
3076             MESSAGE("Node Projection Failed " << node);
3077           }
3078           else {
3079             if ( isUPeriodic )
3080               newUV.SetX( ElCLib::InPeriod( newUV.X(), u1, u2 ));
3081             if ( isVPeriodic )
3082               newUV.SetY( ElCLib::InPeriod( newUV.Y(), v1, v2 ));
3083             // check new UV
3084             if ( posType != SMDS_TOP_3DSPACE )
3085               dist2 = pNode.SquareDistance( surface->Value( newUV.X(), newUV.Y() ));
3086             if ( dist2 < dist1 )
3087               uv = newUV;
3088           }
3089         }
3090         // store UV in the map
3091         listUV.push_back( uv );
3092         uvMap.insert( make_pair( node, &listUV.back() ));
3093       }
3094     } // loop on not yet smoothed elements
3095
3096     if ( !faceSubMesh || nbElemOnFace != faceSubMesh->NbElements() )
3097       checkBoundaryNodes = true;
3098
3099     // fix nodes on mesh boundary
3100
3101     if ( checkBoundaryNodes ) {
3102       map< NLink, int > linkNbMap; // how many times a link encounters in elemsOnFace
3103       map< NLink, int >::iterator link_nb;
3104       // put all elements links to linkNbMap
3105       list< const SMDS_MeshElement* >::iterator elemIt = elemsOnFace.begin();
3106       for ( ; elemIt != elemsOnFace.end(); ++elemIt ) {
3107         const SMDS_MeshElement* elem = (*elemIt);
3108         int nbn =  elem->NbNodes();
3109         if(elem->IsQuadratic())
3110           nbn = nbn/2;
3111         // loop on elem links: insert them in linkNbMap
3112         const SMDS_MeshNode* curNode, *prevNode = elem->GetNodeWrap( nbn );
3113         for ( int iN = 0; iN < nbn; ++iN ) {
3114           curNode = elem->GetNode( iN );
3115           NLink link;
3116           if ( curNode < prevNode ) link = make_pair( curNode , prevNode );
3117           else                      link = make_pair( prevNode , curNode );
3118           prevNode = curNode;
3119           link_nb = linkNbMap.find( link );
3120           if ( link_nb == linkNbMap.end() )
3121             linkNbMap.insert( make_pair ( link, 1 ));
3122           else
3123             link_nb->second++;
3124         }
3125       }
3126       // remove nodes that are in links encountered only once from setMovableNodes
3127       for ( link_nb = linkNbMap.begin(); link_nb != linkNbMap.end(); ++link_nb ) {
3128         if ( link_nb->second == 1 ) {
3129           setMovableNodes.erase( link_nb->first.first );
3130           setMovableNodes.erase( link_nb->first.second );
3131         }
3132       }
3133     }
3134
3135     // -----------------------------------------------------
3136     // for nodes on seam edge, compute one more UV ( uvMap2 );
3137     // find movable nodes linked to nodes on seam and which
3138     // are to be smoothed using the second UV ( uvMap2 )
3139     // -----------------------------------------------------
3140
3141     set<const SMDS_MeshNode*> nodesNearSeam; // to smooth using uvMap2
3142     if ( !surface.IsNull() ) {
3143       TopExp_Explorer eExp( face, TopAbs_EDGE );
3144       for ( ; eExp.More(); eExp.Next() ) {
3145         TopoDS_Edge edge = TopoDS::Edge( eExp.Current() );
3146         if ( !BRep_Tool::IsClosed( edge, face ))
3147           continue;
3148         SMESHDS_SubMesh* sm = aMesh->MeshElements( edge );
3149         if ( !sm ) continue;
3150         // find out which parameter varies for a node on seam
3151         double f,l;
3152         gp_Pnt2d uv1, uv2;
3153         Handle(Geom2d_Curve) pcurve = BRep_Tool::CurveOnSurface( edge, face, f, l );
3154         if ( pcurve.IsNull() ) continue;
3155         uv1 = pcurve->Value( f );
3156         edge.Reverse();
3157         pcurve = BRep_Tool::CurveOnSurface( edge, face, f, l );
3158         if ( pcurve.IsNull() ) continue;
3159         uv2 = pcurve->Value( f );
3160         int iPar = Abs( uv1.X() - uv2.X() ) > Abs( uv1.Y() - uv2.Y() ) ? 1 : 2;
3161         // assure uv1 < uv2
3162         if ( uv1.Coord( iPar ) > uv2.Coord( iPar )) {
3163           gp_Pnt2d tmp = uv1; uv1 = uv2; uv2 = tmp;
3164         }
3165         // get nodes on seam and its vertices
3166         list< const SMDS_MeshNode* > seamNodes;
3167         SMDS_NodeIteratorPtr nSeamIt = sm->GetNodes();
3168         while ( nSeamIt->more() ) {
3169           const SMDS_MeshNode* node = nSeamIt->next();
3170           if ( !isQuadratic || !IsMedium( node ))
3171             seamNodes.push_back( node );
3172         }
3173         TopExp_Explorer vExp( edge, TopAbs_VERTEX );
3174         for ( ; vExp.More(); vExp.Next() ) {
3175           sm = aMesh->MeshElements( vExp.Current() );
3176           if ( sm ) {
3177             nSeamIt = sm->GetNodes();
3178             while ( nSeamIt->more() )
3179               seamNodes.push_back( nSeamIt->next() );
3180           }
3181         }
3182         // loop on nodes on seam
3183         list< const SMDS_MeshNode* >::iterator noSeIt = seamNodes.begin();
3184         for ( ; noSeIt != seamNodes.end(); ++noSeIt ) {
3185           const SMDS_MeshNode* nSeam = *noSeIt;
3186           map< const SMDS_MeshNode*, gp_XY* >::iterator n_uv = uvMap.find( nSeam );
3187           if ( n_uv == uvMap.end() )
3188             continue;
3189           // set the first UV
3190           n_uv->second->SetCoord( iPar, uv1.Coord( iPar ));
3191           // set the second UV
3192           listUV.push_back( *n_uv->second );
3193           listUV.back().SetCoord( iPar, uv2.Coord( iPar ));
3194           if ( uvMap2.empty() )
3195             uvMap2 = uvMap; // copy the uvMap contents
3196           uvMap2[ nSeam ] = &listUV.back();
3197
3198           // collect movable nodes linked to ones on seam in nodesNearSeam
3199           SMDS_ElemIteratorPtr eIt = nSeam->GetInverseElementIterator(SMDSAbs_Face);
3200           while ( eIt->more() ) {
3201             const SMDS_MeshElement* e = eIt->next();
3202             int nbUseMap1 = 0, nbUseMap2 = 0;
3203             SMDS_ElemIteratorPtr nIt = e->nodesIterator();
3204             int nn = 0, nbn =  e->NbNodes();
3205             if(e->IsQuadratic()) nbn = nbn/2;
3206             while ( nn++ < nbn )
3207             {
3208               const SMDS_MeshNode* n =
3209                 static_cast<const SMDS_MeshNode*>( nIt->next() );
3210               if (n == nSeam ||
3211                   setMovableNodes.find( n ) == setMovableNodes.end() )
3212                 continue;
3213               // add only nodes being closer to uv2 than to uv1
3214               gp_Pnt pMid (0.5 * ( n->X() + nSeam->X() ),
3215                            0.5 * ( n->Y() + nSeam->Y() ),
3216                            0.5 * ( n->Z() + nSeam->Z() ));
3217               gp_XY uv;
3218               getClosestUV( projector, pMid, uv );
3219               if ( uv.Coord( iPar ) > uvMap[ n ]->Coord( iPar ) ) {
3220                 nodesNearSeam.insert( n );
3221                 nbUseMap2++;
3222               }
3223               else
3224                 nbUseMap1++;
3225             }
3226             // for centroidalSmooth all element nodes must
3227             // be on one side of a seam
3228             if ( theSmoothMethod == CENTROIDAL && nbUseMap1 && nbUseMap2 ) {
3229               SMDS_ElemIteratorPtr nIt = e->nodesIterator();
3230               nn = 0;
3231               while ( nn++ < nbn ) {
3232                 const SMDS_MeshNode* n =
3233                   static_cast<const SMDS_MeshNode*>( nIt->next() );
3234                 setMovableNodes.erase( n );
3235               }
3236             }
3237           }
3238         } // loop on nodes on seam
3239       } // loop on edge of a face
3240     } // if ( !face.IsNull() )
3241
3242     if ( setMovableNodes.empty() ) {
3243       MESSAGE( "Face id : " << *fId << " - NO SMOOTHING: no nodes to move!!!");
3244       continue; // goto next face
3245     }
3246
3247     // -------------
3248     // SMOOTHING //
3249     // -------------
3250
3251     int it = -1;
3252     double maxRatio = -1., maxDisplacement = -1.;
3253     set<const SMDS_MeshNode*>::iterator nodeToMove;
3254     for ( it = 0; it < theNbIterations; it++ ) {
3255       maxDisplacement = 0.;
3256       nodeToMove = setMovableNodes.begin();
3257       for ( ; nodeToMove != setMovableNodes.end(); nodeToMove++ ) {
3258         const SMDS_MeshNode* node = (*nodeToMove);
3259         gp_XYZ aPrevPos ( node->X(), node->Y(), node->Z() );
3260
3261         // smooth
3262         bool map2 = ( nodesNearSeam.find( node ) != nodesNearSeam.end() );
3263         if ( theSmoothMethod == LAPLACIAN )
3264           laplacianSmooth( node, surface, map2 ? uvMap2 : uvMap );
3265         else
3266           centroidalSmooth( node, surface, map2 ? uvMap2 : uvMap );
3267
3268         // node displacement
3269         gp_XYZ aNewPos ( node->X(), node->Y(), node->Z() );
3270         Standard_Real aDispl = (aPrevPos - aNewPos).SquareModulus();
3271         if ( aDispl > maxDisplacement )
3272           maxDisplacement = aDispl;
3273       }
3274       // no node movement => exit
3275       //if ( maxDisplacement < 1.e-16 ) {
3276       if ( maxDisplacement < disttol ) {
3277         MESSAGE("-- no node movement --");
3278         break;
3279       }
3280
3281       // check elements quality
3282       maxRatio  = 0;
3283       list< const SMDS_MeshElement* >::iterator elemIt = elemsOnFace.begin();
3284       for ( ; elemIt != elemsOnFace.end(); ++elemIt ) {
3285         const SMDS_MeshElement* elem = (*elemIt);
3286         if ( !elem || elem->GetType() != SMDSAbs_Face )
3287           continue;
3288         SMESH::Controls::TSequenceOfXYZ aPoints;
3289         if ( aQualityFunc.GetPoints( elem, aPoints )) {
3290           double aValue = aQualityFunc.GetValue( aPoints );
3291           if ( aValue > maxRatio )
3292             maxRatio = aValue;
3293         }
3294       }
3295       if ( maxRatio <= theTgtAspectRatio ) {
3296         MESSAGE("-- quality achived --");
3297         break;
3298       }
3299       if (it+1 == theNbIterations) {
3300         MESSAGE("-- Iteration limit exceeded --");
3301       }
3302     } // smoothing iterations
3303
3304     MESSAGE(" Face id: " << *fId <<
3305             " Nb iterstions: " << it <<
3306             " Displacement: " << maxDisplacement <<
3307             " Aspect Ratio " << maxRatio);
3308
3309     // ---------------------------------------
3310     // new nodes positions are computed,
3311     // record movement in DS and set new UV
3312     // ---------------------------------------
3313     nodeToMove = setMovableNodes.begin();
3314     for ( ; nodeToMove != setMovableNodes.end(); nodeToMove++ ) {
3315       SMDS_MeshNode* node = const_cast< SMDS_MeshNode* > (*nodeToMove);
3316       aMesh->MoveNode( node, node->X(), node->Y(), node->Z() );
3317       map< const SMDS_MeshNode*, gp_XY* >::iterator node_uv = uvMap.find( node );
3318       if ( node_uv != uvMap.end() ) {
3319         gp_XY* uv = node_uv->second;
3320         node->SetPosition
3321           ( SMDS_PositionPtr( new SMDS_FacePosition( uv->X(), uv->Y() )));
3322       }
3323     }
3324
3325     // move medium nodes of quadratic elements
3326     if ( isQuadratic )
3327     {
3328       SMESH_MesherHelper helper( *GetMesh() );
3329       if ( !face.IsNull() )
3330         helper.SetSubShape( face );
3331       list< const SMDS_MeshElement* >::iterator elemIt = elemsOnFace.begin();
3332       for ( ; elemIt != elemsOnFace.end(); ++elemIt ) {
3333         const SMDS_VtkFace* QF =
3334           dynamic_cast<const SMDS_VtkFace*> (*elemIt);
3335         if(QF && QF->IsQuadratic()) {
3336           vector<const SMDS_MeshNode*> Ns;
3337           Ns.reserve(QF->NbNodes()+1);
3338           SMDS_ElemIteratorPtr anIter = QF->interlacedNodesElemIterator();
3339           while ( anIter->more() )
3340             Ns.push_back( cast2Node(anIter->next()) );
3341           Ns.push_back( Ns[0] );
3342           double x, y, z;
3343           for(int i=0; i<QF->NbNodes(); i=i+2) {
3344             if ( !surface.IsNull() ) {
3345               gp_XY uv1 = helper.GetNodeUV( face, Ns[i], Ns[i+2] );
3346               gp_XY uv2 = helper.GetNodeUV( face, Ns[i+2], Ns[i] );
3347               gp_XY uv = ( uv1 + uv2 ) / 2.;
3348               gp_Pnt xyz = surface->Value( uv.X(), uv.Y() );
3349               x = xyz.X(); y = xyz.Y(); z = xyz.Z();
3350             }
3351             else {
3352               x = (Ns[i]->X() + Ns[i+2]->X())/2;
3353               y = (Ns[i]->Y() + Ns[i+2]->Y())/2;
3354               z = (Ns[i]->Z() + Ns[i+2]->Z())/2;
3355             }
3356             if( fabs( Ns[i+1]->X() - x ) > disttol ||
3357                 fabs( Ns[i+1]->Y() - y ) > disttol ||
3358                 fabs( Ns[i+1]->Z() - z ) > disttol ) {
3359               // we have to move i+1 node
3360               aMesh->MoveNode( Ns[i+1], x, y, z );
3361             }
3362           }
3363         }
3364       }
3365     }
3366
3367   } // loop on face ids
3368
3369 }
3370
3371 //=======================================================================
3372 //function : isReverse
3373 //purpose  : Return true if normal of prevNodes is not co-directied with
3374 //           gp_Vec(prevNodes[iNotSame],nextNodes[iNotSame]).
3375 //           iNotSame is where prevNodes and nextNodes are different
3376 //=======================================================================
3377
3378 static bool isReverse(vector<const SMDS_MeshNode*> prevNodes,
3379                       vector<const SMDS_MeshNode*> nextNodes,
3380                       const int            nbNodes,
3381                       const int            iNotSame)
3382 {
3383   int iBeforeNotSame = ( iNotSame == 0 ? nbNodes - 1 : iNotSame - 1 );
3384   int iAfterNotSame  = ( iNotSame + 1 == nbNodes ? 0 : iNotSame + 1 );
3385
3386   const SMDS_MeshNode* nB = prevNodes[ iBeforeNotSame ];
3387   const SMDS_MeshNode* nA = prevNodes[ iAfterNotSame ];
3388   const SMDS_MeshNode* nP = prevNodes[ iNotSame ];
3389   const SMDS_MeshNode* nN = nextNodes[ iNotSame ];
3390
3391   gp_Pnt pB ( nB->X(), nB->Y(), nB->Z() );
3392   gp_Pnt pA ( nA->X(), nA->Y(), nA->Z() );
3393   gp_Pnt pP ( nP->X(), nP->Y(), nP->Z() );
3394   gp_Pnt pN ( nN->X(), nN->Y(), nN->Z() );
3395
3396   gp_Vec vB ( pP, pB ), vA ( pP, pA ), vN ( pP, pN );
3397
3398   return (vA ^ vB) * vN < 0.0;
3399 }
3400
3401 //=======================================================================
3402 /*!
3403  * \brief Create elements by sweeping an element
3404  * \param elem - element to sweep
3405  * \param newNodesItVec - nodes generated from each node of the element
3406  * \param newElems - generated elements
3407  * \param nbSteps - number of sweeping steps
3408  * \param srcElements - to append elem for each generated element
3409  */
3410 //=======================================================================
3411
3412 void SMESH_MeshEditor::sweepElement(const SMDS_MeshElement*               elem,
3413                                     const vector<TNodeOfNodeListMapItr> & newNodesItVec,
3414                                     list<const SMDS_MeshElement*>&        newElems,
3415                                     const int                             nbSteps,
3416                                     SMESH_SequenceOfElemPtr&              srcElements)
3417 {
3418   //MESSAGE("sweepElement " << nbSteps);
3419   SMESHDS_Mesh* aMesh = GetMeshDS();
3420
3421   // Loop on elem nodes:
3422   // find new nodes and detect same nodes indices
3423   int nbNodes = elem->NbNodes();
3424   vector < list< const SMDS_MeshNode* >::const_iterator > itNN( nbNodes );
3425   vector<const SMDS_MeshNode*> prevNod( nbNodes );
3426   vector<const SMDS_MeshNode*> nextNod( nbNodes );
3427   vector<const SMDS_MeshNode*> midlNod( nbNodes );
3428
3429   int iNode, nbSame = 0, iNotSameNode = 0, iSameNode = 0;
3430   vector<int> sames(nbNodes);
3431   vector<bool> issimple(nbNodes);
3432
3433   for ( iNode = 0; iNode < nbNodes; iNode++ ) {
3434     TNodeOfNodeListMapItr nnIt = newNodesItVec[ iNode ];
3435     const SMDS_MeshNode*                 node         = nnIt->first;
3436     const list< const SMDS_MeshNode* > & listNewNodes = nnIt->second;
3437     if ( listNewNodes.empty() ) {
3438       return;
3439     }
3440
3441     issimple[iNode] = (listNewNodes.size()==nbSteps); // is node medium
3442
3443     itNN[ iNode ] = listNewNodes.begin();
3444     prevNod[ iNode ] = node;
3445     nextNod[ iNode ] = listNewNodes.front();
3446     if( !elem->IsQuadratic() || !issimple[iNode] ) {
3447       if ( prevNod[ iNode ] != nextNod [ iNode ])
3448         iNotSameNode = iNode;
3449       else {
3450         iSameNode = iNode;
3451         //nbSame++;
3452         sames[nbSame++] = iNode;
3453       }
3454     }
3455   }
3456
3457   //cerr<<"  nbSame = "<<nbSame<<endl;
3458   if ( nbSame == nbNodes || nbSame > 2) {
3459     MESSAGE( " Too many same nodes of element " << elem->GetID() );
3460     //INFOS( " Too many same nodes of element " << elem->GetID() );
3461     return;
3462   }
3463
3464   //  if( elem->IsQuadratic() && nbSame>0 ) {
3465   //    MESSAGE( "Can not rotate quadratic element " << elem->GetID() );
3466   //    return;
3467   //  }
3468
3469   int iBeforeSame = 0, iAfterSame = 0, iOpposSame = 0;
3470   int nbBaseNodes = ( elem->IsQuadratic() ? nbNodes/2 : nbNodes );
3471   if ( nbSame > 0 ) {
3472     iBeforeSame = ( iSameNode == 0 ? nbBaseNodes - 1 : iSameNode - 1 );
3473     iAfterSame  = ( iSameNode + 1 == nbBaseNodes ? 0 : iSameNode + 1 );
3474     iOpposSame  = ( iSameNode - 2 < 0  ? iSameNode + 2 : iSameNode - 2 );
3475   }
3476
3477   //if(nbNodes==8)
3478   //cout<<" prevNod[0]="<< prevNod[0]<<" prevNod[1]="<< prevNod[1]
3479   //    <<" prevNod[2]="<< prevNod[2]<<" prevNod[3]="<< prevNod[4]
3480   //    <<" prevNod[4]="<< prevNod[4]<<" prevNod[5]="<< prevNod[5]
3481   //    <<" prevNod[6]="<< prevNod[6]<<" prevNod[7]="<< prevNod[7]<<endl;
3482
3483   // check element orientation
3484   int i0 = 0, i2 = 2;
3485   if ( nbNodes > 2 && !isReverse( prevNod, nextNod, nbNodes, iNotSameNode )) {
3486     //MESSAGE("Reversed elem " << elem );
3487     i0 = 2;
3488     i2 = 0;
3489     if ( nbSame > 0 )
3490       std::swap( iBeforeSame, iAfterSame );
3491   }
3492
3493   // make new elements
3494   const SMDS_MeshElement* lastElem = elem;
3495   for (int iStep = 0; iStep < nbSteps; iStep++ ) {
3496     // get next nodes
3497     for ( iNode = 0; iNode < nbNodes; iNode++ ) {
3498       if(issimple[iNode]) {
3499         nextNod[ iNode ] = *itNN[ iNode ];
3500         itNN[ iNode ]++;
3501       }
3502       else {
3503         if( elem->GetType()==SMDSAbs_Node ) {
3504           // we have to use two nodes
3505           midlNod[ iNode ] = *itNN[ iNode ];
3506           itNN[ iNode ]++;
3507           nextNod[ iNode ] = *itNN[ iNode ];
3508           itNN[ iNode ]++;
3509         }
3510         else if(!elem->IsQuadratic() || lastElem->IsMediumNode(prevNod[iNode]) ) {
3511           // we have to use each second node
3512           //itNN[ iNode ]++;
3513           nextNod[ iNode ] = *itNN[ iNode ];
3514           itNN[ iNode ]++;
3515         }
3516         else {
3517           // we have to use two nodes
3518           midlNod[ iNode ] = *itNN[ iNode ];
3519           itNN[ iNode ]++;
3520           nextNod[ iNode ] = *itNN[ iNode ];
3521           itNN[ iNode ]++;
3522         }
3523       }
3524     }
3525     SMDS_MeshElement* aNewElem = 0;
3526     if(!elem->IsPoly()) {
3527       switch ( nbNodes ) {
3528       case 0:
3529         return;
3530       case 1: { // NODE
3531         if ( nbSame == 0 ) {
3532           if(issimple[0])
3533             aNewElem = aMesh->AddEdge( prevNod[ 0 ], nextNod[ 0 ] );
3534           else
3535             aNewElem = aMesh->AddEdge( prevNod[ 0 ], nextNod[ 0 ], midlNod[ 0 ] );
3536         }
3537         break;
3538       }
3539       case 2: { // EDGE
3540         if ( nbSame == 0 )
3541           aNewElem = aMesh->AddFace(prevNod[ 0 ], prevNod[ 1 ],
3542                                     nextNod[ 1 ], nextNod[ 0 ] );
3543         else
3544           aNewElem = aMesh->AddFace(prevNod[ 0 ], prevNod[ 1 ],
3545                                     nextNod[ iNotSameNode ] );
3546         break;
3547       }
3548
3549       case 3: { // TRIANGLE or quadratic edge
3550         if(elem->GetType() == SMDSAbs_Face) { // TRIANGLE
3551
3552           if ( nbSame == 0 )       // --- pentahedron
3553             aNewElem = aMesh->AddVolume (prevNod[ i0 ], prevNod[ 1 ], prevNod[ i2 ],
3554                                          nextNod[ i0 ], nextNod[ 1 ], nextNod[ i2 ] );
3555
3556           else if ( nbSame == 1 )  // --- pyramid
3557             aNewElem = aMesh->AddVolume (prevNod[ iBeforeSame ],  prevNod[ iAfterSame ],
3558                                          nextNod[ iAfterSame ], nextNod[ iBeforeSame ],
3559                                          nextNod[ iSameNode ]);
3560
3561           else // 2 same nodes:      --- tetrahedron
3562             aNewElem = aMesh->AddVolume (prevNod[ i0 ], prevNod[ 1 ], prevNod[ i2 ],
3563                                          nextNod[ iNotSameNode ]);
3564         }
3565         else { // quadratic edge
3566           if(nbSame==0) {     // quadratic quadrangle
3567             aNewElem = aMesh->AddFace(prevNod[0], nextNod[0], nextNod[1], prevNod[1],
3568                                       midlNod[0], nextNod[2], midlNod[1], prevNod[2]);
3569           }
3570           else if(nbSame==1) { // quadratic triangle
3571             if(sames[0]==2) {
3572               return; // medium node on axis
3573             }
3574             else if(sames[0]==0) {
3575               aNewElem = aMesh->AddFace(prevNod[0], nextNod[1], prevNod[1],
3576                                         nextNod[2], midlNod[1], prevNod[2]);
3577             }
3578             else { // sames[0]==1
3579               aNewElem = aMesh->AddFace(prevNod[0], nextNod[0], prevNod[1],
3580                                         midlNod[0], nextNod[2], prevNod[2]);
3581             }
3582           }
3583           else {
3584             return;
3585           }
3586         }
3587         break;
3588       }
3589       case 4: { // QUADRANGLE
3590
3591         if ( nbSame == 0 )       // --- hexahedron
3592           aNewElem = aMesh->AddVolume (prevNod[ i0 ], prevNod[ 1 ], prevNod[ i2 ], prevNod[ 3 ],
3593                                        nextNod[ i0 ], nextNod[ 1 ], nextNod[ i2 ], nextNod[ 3 ]);
3594
3595         else if ( nbSame == 1 ) { // --- pyramid + pentahedron
3596           aNewElem = aMesh->AddVolume (prevNod[ iBeforeSame ],  prevNod[ iAfterSame ],
3597                                        nextNod[ iAfterSame ], nextNod[ iBeforeSame ],
3598                                        nextNod[ iSameNode ]);
3599           newElems.push_back( aNewElem );
3600           aNewElem = aMesh->AddVolume (prevNod[ iAfterSame ], prevNod[ iOpposSame ],
3601                                        prevNod[ iBeforeSame ],  nextNod[ iAfterSame ],
3602                                        nextNod[ iOpposSame ],  nextNod[ iBeforeSame ] );
3603         }
3604         else if ( nbSame == 2 ) { // pentahedron
3605           if ( prevNod[ iBeforeSame ] == nextNod[ iBeforeSame ] )
3606             // iBeforeSame is same too
3607             aNewElem = aMesh->AddVolume (prevNod[ iBeforeSame ], prevNod[ iOpposSame ],
3608                                          nextNod[ iOpposSame ], prevNod[ iSameNode ],
3609                                          prevNod[ iAfterSame ],  nextNod[ iAfterSame ]);
3610           else
3611             // iAfterSame is same too
3612             aNewElem = aMesh->AddVolume (prevNod[ iSameNode ], prevNod[ iBeforeSame ],
3613                                          nextNod[ iBeforeSame ], prevNod[ iAfterSame ],
3614                                          prevNod[ iOpposSame ],  nextNod[ iOpposSame ]);
3615         }
3616         break;
3617       }
3618       case 6: { // quadratic triangle
3619         // create pentahedron with 15 nodes
3620         if(nbSame==0) {
3621           if(i0>0) { // reversed case
3622             aNewElem = aMesh->AddVolume (prevNod[0], prevNod[2], prevNod[1],
3623                                          nextNod[0], nextNod[2], nextNod[1],
3624                                          prevNod[5], prevNod[4], prevNod[3],
3625                                          nextNod[5], nextNod[4], nextNod[3],
3626                                          midlNod[0], midlNod[2], midlNod[1]);
3627           }
3628           else { // not reversed case
3629             aNewElem = aMesh->AddVolume (prevNod[0], prevNod[1], prevNod[2],
3630                                          nextNod[0], nextNod[1], nextNod[2],
3631                                          prevNod[3], prevNod[4], prevNod[5],
3632                                          nextNod[3], nextNod[4], nextNod[5],
3633                                          midlNod[0], midlNod[1], midlNod[2]);
3634           }
3635         }
3636         else if(nbSame==1) {
3637           // 2d order pyramid of 13 nodes
3638           //SMDS_MeshVolume* AddVolumeWithID(int n1, int n2, int n3, int n4, int n5,
3639           //                                 int n12,int n23,int n34,int n41,
3640           //                                 int n15,int n25,int n35,int n45, int ID);
3641           int n5 = iSameNode;
3642           int n1,n4,n41,n15,n45;
3643           if(i0>0) { // reversed case
3644             n1 = ( n5 + 1 == nbBaseNodes ? 0 : n5 + 1 );
3645             n4 = ( n5 == 0 ? nbBaseNodes - 1 : n5 - 1 );
3646             n41 = n1 + 3;
3647             n15 = n5 + 3;
3648             n45 = n4 + 3;
3649           }
3650           else {
3651             n1 = ( n5 == 0 ? nbBaseNodes - 1 : n5 - 1 );
3652             n4 = ( n5 + 1 == nbBaseNodes ? 0 : n5 + 1 );
3653             n41 = n4 + 3;
3654             n15 = n1 + 3;
3655             n45 = n5 + 3;
3656           }
3657           aNewElem = aMesh->AddVolume(prevNod[n1], nextNod[n1],
3658                                       nextNod[n4], prevNod[n4], prevNod[n5],
3659                                       midlNod[n1], nextNod[n41],
3660                                       midlNod[n4], prevNod[n41],
3661                                       prevNod[n15], nextNod[n15],
3662                                       nextNod[n45], prevNod[n45]);
3663         }
3664         else if(nbSame==2) {
3665           // 2d order tetrahedron of 10 nodes
3666           //SMDS_MeshVolume* AddVolumeWithID(int n1, int n2, int n3, int n4,
3667           //                                 int n12,int n23,int n31,
3668           //                                 int n14,int n24,int n34, int ID);
3669           int n1 = iNotSameNode;
3670           int n2,n3,n12,n23,n31;
3671           if(i0>0) { // reversed case
3672             n2 = ( n1 == 0 ? nbBaseNodes - 1 : n1 - 1 );
3673             n3 = ( n1 + 1 == nbBaseNodes ? 0 : n1 + 1 );
3674             n12 = n2 + 3;
3675             n23 = n3 + 3;
3676             n31 = n1 + 3;
3677           }
3678           else {
3679             n2 = ( n1 + 1 == nbBaseNodes ? 0 : n1 + 1 );
3680             n3 = ( n1 == 0 ? nbBaseNodes - 1 : n1 - 1 );
3681             n12 = n1 + 3;
3682             n23 = n2 + 3;
3683             n31 = n3 + 3;
3684           }
3685           aNewElem = aMesh->AddVolume (prevNod[n1], prevNod[n2], prevNod[n3], nextNod[n1],
3686                                        prevNod[n12], prevNod[n23], prevNod[n31],
3687                                        midlNod[n1], nextNod[n12], nextNod[n31]);
3688         }
3689         break;
3690       }
3691       case 8: { // quadratic quadrangle
3692         if(nbSame==0) {
3693           // create hexahedron with 20 nodes
3694           if(i0>0) { // reversed case
3695             aNewElem = aMesh->AddVolume (prevNod[0], prevNod[3], prevNod[2], prevNod[1],
3696                                          nextNod[0], nextNod[3], nextNod[2], nextNod[1],
3697                                          prevNod[7], prevNod[6], prevNod[5], prevNod[4],
3698                                          nextNod[7], nextNod[6], nextNod[5], nextNod[4],
3699                                          midlNod[0], midlNod[3], midlNod[2], midlNod[1]);
3700           }
3701           else { // not reversed case
3702             aNewElem = aMesh->AddVolume (prevNod[0], prevNod[1], prevNod[2], prevNod[3],
3703                                          nextNod[0], nextNod[1], nextNod[2], nextNod[3],
3704                                          prevNod[4], prevNod[5], prevNod[6], prevNod[7],
3705                                          nextNod[4], nextNod[5], nextNod[6], nextNod[7],
3706                                          midlNod[0], midlNod[1], midlNod[2], midlNod[3]);
3707           }
3708         }
3709         else if(nbSame==1) { 
3710           // --- pyramid + pentahedron - can not be created since it is needed 
3711           // additional middle node ot the center of face
3712           INFOS( " Sweep for face " << elem->GetID() << " can not be created" );
3713           return;
3714         }
3715         else if(nbSame==2) {
3716           // 2d order Pentahedron with 15 nodes
3717           //SMDS_MeshVolume* AddVolumeWithID(int n1, int n2, int n3, int n4, int n5, int n6,
3718           //                                 int n12,int n23,int n31,int n45,int n56,int n64,
3719           //                                 int n14,int n25,int n36, int ID);
3720           int n1,n2,n4,n5;
3721           if ( prevNod[ iBeforeSame ] == nextNod[ iBeforeSame ] ) {
3722             // iBeforeSame is same too
3723             n1 = iBeforeSame;
3724             n2 = iOpposSame;
3725             n4 = iSameNode;
3726             n5 = iAfterSame;
3727           }
3728           else {
3729             // iAfterSame is same too
3730             n1 = iSameNode;
3731             n2 = iBeforeSame;
3732             n4 = iAfterSame;
3733             n5 = iOpposSame;
3734           }
3735           int n12,n45,n14,n25;
3736           if(i0>0) { //reversed case
3737             n12 = n1 + 4;
3738             n45 = n5 + 4;
3739             n14 = n4 + 4;
3740             n25 = n2 + 4;
3741           }
3742           else {
3743             n12 = n2 + 4;
3744             n45 = n4 + 4;
3745             n14 = n1 + 4;
3746             n25 = n5 + 4;
3747           }
3748           aNewElem = aMesh->AddVolume (prevNod[n1], prevNod[n2], nextNod[n2],
3749                                        prevNod[n4], prevNod[n5], nextNod[n5],
3750                                        prevNod[n12], midlNod[n2], nextNod[n12],
3751                                        prevNod[n45], midlNod[n5], nextNod[n45],
3752                                        prevNod[n14], prevNod[n25], nextNod[n25]);
3753         }
3754         break;
3755       }
3756       default: {
3757         // realized for extrusion only
3758         //vector<const SMDS_MeshNode*> polyedre_nodes (nbNodes*2 + 4*nbNodes);
3759         //vector<int> quantities (nbNodes + 2);
3760
3761         //quantities[0] = nbNodes; // bottom of prism
3762         //for (int inode = 0; inode < nbNodes; inode++) {
3763         //  polyedre_nodes[inode] = prevNod[inode];
3764         //}
3765
3766         //quantities[1] = nbNodes; // top of prism
3767         //for (int inode = 0; inode < nbNodes; inode++) {
3768         //  polyedre_nodes[nbNodes + inode] = nextNod[inode];
3769         //}
3770
3771         //for (int iface = 0; iface < nbNodes; iface++) {
3772         //  quantities[iface + 2] = 4;
3773         //  int inextface = (iface == nbNodes - 1) ? 0 : iface + 1;
3774         //  polyedre_nodes[2*nbNodes + 4*iface + 0] = prevNod[iface];
3775         //  polyedre_nodes[2*nbNodes + 4*iface + 1] = prevNod[inextface];
3776         //  polyedre_nodes[2*nbNodes + 4*iface + 2] = nextNod[inextface];
3777         //  polyedre_nodes[2*nbNodes + 4*iface + 3] = nextNod[iface];
3778         //}
3779         //aNewElem = aMesh->AddPolyhedralVolume (polyedre_nodes, quantities);
3780         break;
3781       }
3782       }
3783     }
3784
3785     if(!aNewElem) {
3786       // realized for extrusion only
3787       vector<const SMDS_MeshNode*> polyedre_nodes (nbNodes*2 + 4*nbNodes);
3788       vector<int> quantities (nbNodes + 2);
3789
3790       quantities[0] = nbNodes; // bottom of prism
3791       for (int inode = 0; inode < nbNodes; inode++) {
3792         polyedre_nodes[inode] = prevNod[inode];
3793       }
3794
3795       quantities[1] = nbNodes; // top of prism
3796       for (int inode = 0; inode < nbNodes; inode++) {
3797         polyedre_nodes[nbNodes + inode] = nextNod[inode];
3798       }
3799
3800       for (int iface = 0; iface < nbNodes; iface++) {
3801         quantities[iface + 2] = 4;
3802         int inextface = (iface == nbNodes - 1) ? 0 : iface + 1;
3803         polyedre_nodes[2*nbNodes + 4*iface + 0] = prevNod[iface];
3804         polyedre_nodes[2*nbNodes + 4*iface + 1] = prevNod[inextface];
3805         polyedre_nodes[2*nbNodes + 4*iface + 2] = nextNod[inextface];
3806         polyedre_nodes[2*nbNodes + 4*iface + 3] = nextNod[iface];
3807       }
3808       aNewElem = aMesh->AddPolyhedralVolume (polyedre_nodes, quantities);
3809     }
3810
3811     if ( aNewElem ) {
3812       newElems.push_back( aNewElem );
3813       myLastCreatedElems.Append(aNewElem);
3814       srcElements.Append( elem );
3815       lastElem = aNewElem;
3816     }
3817
3818     // set new prev nodes
3819     for ( iNode = 0; iNode < nbNodes; iNode++ )
3820       prevNod[ iNode ] = nextNod[ iNode ];
3821
3822   } // for steps
3823 }
3824
3825 //=======================================================================
3826 /*!
3827  * \brief Create 1D and 2D elements around swept elements
3828  * \param mapNewNodes - source nodes and ones generated from them
3829  * \param newElemsMap - source elements and ones generated from them
3830  * \param elemNewNodesMap - nodes generated from each node of each element
3831  * \param elemSet - all swept elements
3832  * \param nbSteps - number of sweeping steps
3833  * \param srcElements - to append elem for each generated element
3834  */
3835 //=======================================================================
3836
3837 void SMESH_MeshEditor::makeWalls (TNodeOfNodeListMap &     mapNewNodes,
3838                                   TElemOfElemListMap &     newElemsMap,
3839                                   TElemOfVecOfNnlmiMap &   elemNewNodesMap,
3840                                   TIDSortedElemSet&        elemSet,
3841                                   const int                nbSteps,
3842                                   SMESH_SequenceOfElemPtr& srcElements)
3843 {
3844   MESSAGE("makeWalls");
3845   ASSERT( newElemsMap.size() == elemNewNodesMap.size() );
3846   SMESHDS_Mesh* aMesh = GetMeshDS();
3847
3848   // Find nodes belonging to only one initial element - sweep them to get edges.
3849
3850   TNodeOfNodeListMapItr nList = mapNewNodes.begin();
3851   for ( ; nList != mapNewNodes.end(); nList++ ) {
3852     const SMDS_MeshNode* node =
3853       static_cast<const SMDS_MeshNode*>( nList->first );
3854     SMDS_ElemIteratorPtr eIt = node->GetInverseElementIterator();
3855     int nbInitElems = 0;
3856     const SMDS_MeshElement* el = 0;
3857     SMDSAbs_ElementType highType = SMDSAbs_Edge; // count most complex elements only
3858     while ( eIt->more() && nbInitElems < 2 ) {
3859       el = eIt->next();
3860       SMDSAbs_ElementType type = el->GetType();
3861       if ( type == SMDSAbs_Volume || type < highType ) continue;
3862       if ( type > highType ) {
3863         nbInitElems = 0;
3864         highType = type;
3865       }
3866       if ( elemSet.find(el) != elemSet.end() )
3867         nbInitElems++;
3868     }
3869     if ( nbInitElems < 2 ) {
3870       bool NotCreateEdge = el && el->IsQuadratic() && el->IsMediumNode(node);
3871       if(!NotCreateEdge) {
3872         vector<TNodeOfNodeListMapItr> newNodesItVec( 1, nList );
3873         list<const SMDS_MeshElement*> newEdges;
3874         sweepElement( node, newNodesItVec, newEdges, nbSteps, srcElements );
3875       }
3876     }
3877   }
3878
3879   // Make a ceiling for each element ie an equal element of last new nodes.
3880   // Find free links of faces - make edges and sweep them into faces.
3881
3882   TElemOfElemListMap::iterator   itElem      = newElemsMap.begin();
3883   TElemOfVecOfNnlmiMap::iterator itElemNodes = elemNewNodesMap.begin();
3884   for ( ; itElem != newElemsMap.end(); itElem++, itElemNodes++ ) {
3885     const SMDS_MeshElement* elem = itElem->first;
3886     vector<TNodeOfNodeListMapItr>& vecNewNodes = itElemNodes->second;
3887
3888     if(itElem->second.size()==0) continue;
3889
3890     if ( elem->GetType() == SMDSAbs_Edge ) {
3891       // create a ceiling edge
3892       if (!elem->IsQuadratic()) {
3893         if ( !aMesh->FindEdge( vecNewNodes[ 0 ]->second.back(),
3894                                vecNewNodes[ 1 ]->second.back())) {
3895           myLastCreatedElems.Append(aMesh->AddEdge(vecNewNodes[ 0 ]->second.back(),
3896                                                    vecNewNodes[ 1 ]->second.back()));
3897           srcElements.Append( myLastCreatedElems.Last() );
3898         }
3899       }
3900       else {
3901         if ( !aMesh->FindEdge( vecNewNodes[ 0 ]->second.back(),
3902                                vecNewNodes[ 1 ]->second.back(),
3903                                vecNewNodes[ 2 ]->second.back())) {
3904           myLastCreatedElems.Append(aMesh->AddEdge(vecNewNodes[ 0 ]->second.back(),
3905                                                    vecNewNodes[ 1 ]->second.back(),
3906                                                    vecNewNodes[ 2 ]->second.back()));
3907           srcElements.Append( myLastCreatedElems.Last() );
3908         }
3909       }
3910     }
3911     if ( elem->GetType() != SMDSAbs_Face )
3912       continue;
3913
3914     bool hasFreeLinks = false;
3915
3916     TIDSortedElemSet avoidSet;
3917     avoidSet.insert( elem );
3918
3919     set<const SMDS_MeshNode*> aFaceLastNodes;
3920     int iNode, nbNodes = vecNewNodes.size();
3921     if(!elem->IsQuadratic()) {
3922       // loop on the face nodes
3923       for ( iNode = 0; iNode < nbNodes; iNode++ ) {
3924         aFaceLastNodes.insert( vecNewNodes[ iNode ]->second.back() );
3925         // look for free links of the face
3926         int iNext = ( iNode + 1 == nbNodes ) ? 0 : iNode + 1;
3927         const SMDS_MeshNode* n1 = vecNewNodes[ iNode ]->first;
3928         const SMDS_MeshNode* n2 = vecNewNodes[ iNext ]->first;
3929         // check if a link is free
3930         if ( ! SMESH_MeshEditor::FindFaceInSet ( n1, n2, elemSet, avoidSet )) {
3931           hasFreeLinks = true;
3932           // make an edge and a ceiling for a new edge
3933           if ( !aMesh->FindEdge( n1, n2 )) {
3934             myLastCreatedElems.Append(aMesh->AddEdge( n1, n2 )); // free link edge
3935             srcElements.Append( myLastCreatedElems.Last() );
3936           }
3937           n1 = vecNewNodes[ iNode ]->second.back();
3938           n2 = vecNewNodes[ iNext ]->second.back();
3939           if ( !aMesh->FindEdge( n1, n2 )) {
3940             myLastCreatedElems.Append(aMesh->AddEdge( n1, n2 )); // ceiling edge
3941             srcElements.Append( myLastCreatedElems.Last() );
3942           }
3943         }
3944       }
3945     }
3946     else { // elem is quadratic face
3947       int nbn = nbNodes/2;
3948       for ( iNode = 0; iNode < nbn; iNode++ ) {
3949         aFaceLastNodes.insert( vecNewNodes[ iNode ]->second.back() );
3950         int iNext = ( iNode + 1 == nbn ) ? 0 : iNode + 1;
3951         const SMDS_MeshNode* n1 = vecNewNodes[ iNode ]->first;
3952         const SMDS_MeshNode* n2 = vecNewNodes[ iNext ]->first;
3953         // check if a link is free
3954         if ( ! SMESH_MeshEditor::FindFaceInSet ( n1, n2, elemSet, avoidSet )) {
3955           hasFreeLinks = true;
3956           // make an edge and a ceiling for a new edge
3957           // find medium node
3958           const SMDS_MeshNode* n3 = vecNewNodes[ iNode+nbn ]->first;
3959           if ( !aMesh->FindEdge( n1, n2, n3 )) {
3960             myLastCreatedElems.Append(aMesh->AddEdge( n1, n2, n3 )); // free link edge
3961             srcElements.Append( myLastCreatedElems.Last() );
3962           }
3963           n1 = vecNewNodes[ iNode ]->second.back();
3964           n2 = vecNewNodes[ iNext ]->second.back();
3965           n3 = vecNewNodes[ iNode+nbn ]->second.back();
3966           if ( !aMesh->FindEdge( n1, n2, n3 )) {
3967             myLastCreatedElems.Append(aMesh->AddEdge( n1, n2, n3 )); // ceiling edge
3968             srcElements.Append( myLastCreatedElems.Last() );
3969           }
3970         }
3971       }
3972       for ( iNode = nbn; iNode < 2*nbn; iNode++ ) {
3973         aFaceLastNodes.insert( vecNewNodes[ iNode ]->second.back() );
3974       }
3975     }
3976
3977     // sweep free links into faces
3978
3979     if ( hasFreeLinks )  {
3980       list<const SMDS_MeshElement*> & newVolumes = itElem->second;
3981       int iVol, volNb, nbVolumesByStep = newVolumes.size() / nbSteps;
3982
3983       set<const SMDS_MeshNode*> initNodeSet, topNodeSet, faceNodeSet;
3984       for ( iNode = 0; iNode < nbNodes; iNode++ ) {
3985         initNodeSet.insert( vecNewNodes[ iNode ]->first );
3986         topNodeSet .insert( vecNewNodes[ iNode ]->second.back() );
3987       }
3988       for ( volNb = 0; volNb < nbVolumesByStep; volNb++ ) {
3989         list<const SMDS_MeshElement*>::iterator v = newVolumes.begin();
3990         iVol = 0;
3991         while ( iVol++ < volNb ) v++;
3992         // find indices of free faces of a volume and their source edges
3993         list< int > freeInd;
3994         list< const SMDS_MeshElement* > srcEdges; // source edges of free faces
3995         SMDS_VolumeTool vTool( *v );
3996         int iF, nbF = vTool.NbFaces();
3997         for ( iF = 0; iF < nbF; iF ++ ) {
3998           if (vTool.IsFreeFace( iF ) &&
3999               vTool.GetFaceNodes( iF, faceNodeSet ) &&
4000               initNodeSet != faceNodeSet) // except an initial face
4001           {
4002             if ( nbSteps == 1 && faceNodeSet == topNodeSet )
4003               continue;
4004             freeInd.push_back( iF );
4005             // find source edge of a free face iF
4006             vector<const SMDS_MeshNode*> commonNodes; // shared by the initial and free faces
4007             commonNodes.resize( initNodeSet.size(), NULL ); // avoid spoiling memory
4008             std::set_intersection( faceNodeSet.begin(), faceNodeSet.end(),
4009                                    initNodeSet.begin(), initNodeSet.end(),
4010                                    commonNodes.begin());
4011             if ( (*v)->IsQuadratic() )
4012               srcEdges.push_back(aMesh->FindEdge (commonNodes[0],commonNodes[1],commonNodes[2]));
4013             else
4014               srcEdges.push_back(aMesh->FindEdge (commonNodes[0],commonNodes[1]));
4015 #ifdef _DEBUG_
4016             if ( !srcEdges.back() )
4017             {
4018               cout << "SMESH_MeshEditor::makeWalls(), no source edge found for a free face #"
4019                    << iF << " of volume #" << vTool.ID() << endl;
4020             }
4021 #endif
4022           }
4023         }
4024         if ( freeInd.empty() )
4025           continue;
4026
4027         // create faces for all steps;
4028         // if such a face has been already created by sweep of edge,
4029         // assure that its orientation is OK
4030         for ( int iStep = 0; iStep < nbSteps; iStep++ )  {
4031           vTool.Set( *v );
4032           vTool.SetExternalNormal();
4033           list< int >::iterator ind = freeInd.begin();
4034           list< const SMDS_MeshElement* >::iterator srcEdge = srcEdges.begin();
4035           for ( ; ind != freeInd.end(); ++ind, ++srcEdge ) // loop on free faces
4036           {
4037             const SMDS_MeshNode** nodes = vTool.GetFaceNodes( *ind );
4038             int nbn = vTool.NbFaceNodes( *ind );
4039             switch ( nbn ) {
4040             case 3: { ///// triangle
4041               const SMDS_MeshFace * f = aMesh->FindFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ]);
4042               if ( !f )
4043                 myLastCreatedElems.Append(aMesh->AddFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ] ));
4044               else if ( nodes[ 1 ] != f->GetNodeWrap( f->GetNodeIndex( nodes[ 0 ] ) + 1 ))
4045                 {
4046                   myLastCreatedElems.Append(aMesh->AddFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ] ));
4047                   aMesh->RemoveElement(f);
4048                 }
4049               break;
4050             }
4051             case 4: { ///// quadrangle
4052               const SMDS_MeshFace * f = aMesh->FindFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ], nodes[ 3 ]);
4053               if ( !f )
4054                 myLastCreatedElems.Append(aMesh->AddFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ], nodes[ 3 ] ));
4055               else if ( nodes[ 1 ] != f->GetNodeWrap( f->GetNodeIndex( nodes[ 0 ] ) + 1 ))
4056                 {
4057                   myLastCreatedElems.Append(aMesh->AddFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ], nodes[ 3 ] ));
4058                   aMesh->RemoveElement(f);
4059                 }
4060               break;
4061             }
4062             default:
4063               if( (*v)->IsQuadratic() ) {
4064                 if(nbn==6) { /////// quadratic triangle
4065                   const SMDS_MeshFace * f = aMesh->FindFace( nodes[0], nodes[2], nodes[4],
4066                                                              nodes[1], nodes[3], nodes[5] );
4067                   if ( !f ) {
4068                     myLastCreatedElems.Append(aMesh->AddFace(nodes[0], nodes[2], nodes[4],
4069                                                              nodes[1], nodes[3], nodes[5]));
4070                   }
4071                   else if ( nodes[ 2 ] != f->GetNodeWrap( f->GetNodeIndex( nodes[ 0 ] ) + 1 )) {
4072                     const SMDS_MeshNode** tmpnodes = new const SMDS_MeshNode*[6];
4073                     tmpnodes[0] = nodes[0];
4074                     tmpnodes[1] = nodes[2];
4075                     tmpnodes[2] = nodes[4];
4076                     tmpnodes[3] = nodes[1];
4077                     tmpnodes[4] = nodes[3];
4078                     tmpnodes[5] = nodes[5];
4079                     myLastCreatedElems.Append(aMesh->AddFace(nodes[0], nodes[2], nodes[4],
4080                                                              nodes[1], nodes[3], nodes[5]));
4081                     aMesh->RemoveElement(f);
4082                   }
4083                 }
4084                 else {       /////// quadratic quadrangle
4085                   const SMDS_MeshFace * f = aMesh->FindFace( nodes[0], nodes[2], nodes[4], nodes[6],
4086                                                              nodes[1], nodes[3], nodes[5], nodes[7] );
4087                   if ( !f ) {
4088                     myLastCreatedElems.Append(aMesh->AddFace(nodes[0], nodes[2], nodes[4], nodes[6],
4089                                                              nodes[1], nodes[3], nodes[5], nodes[7]));
4090                   }
4091                   else if ( nodes[ 2 ] != f->GetNodeWrap( f->GetNodeIndex( nodes[ 0 ] ) + 1 )) {
4092                     const SMDS_MeshNode** tmpnodes = new const SMDS_MeshNode*[8];
4093                     tmpnodes[0] = nodes[0];
4094                     tmpnodes[1] = nodes[2];
4095                     tmpnodes[2] = nodes[4];
4096                     tmpnodes[3] = nodes[6];
4097                     tmpnodes[4] = nodes[1];
4098                     tmpnodes[5] = nodes[3];
4099                     tmpnodes[6] = nodes[5];
4100                     tmpnodes[7] = nodes[7];
4101                     myLastCreatedElems.Append(aMesh->AddFace(nodes[0], nodes[2], nodes[4], nodes[6],
4102                                                              nodes[1], nodes[3], nodes[5], nodes[7]));
4103                     aMesh->RemoveElement(f);
4104                   }
4105                 }
4106               }
4107               else { //////// polygon
4108                 vector<const SMDS_MeshNode*> polygon_nodes ( nodes, &nodes[nbn] );
4109                 const SMDS_MeshFace * f = aMesh->FindFace( polygon_nodes );
4110                 if ( !f )
4111                   myLastCreatedElems.Append(aMesh->AddPolygonalFace(polygon_nodes));
4112                 else if ( nodes[ 1 ] != f->GetNodeWrap( f->GetNodeIndex( nodes[ 0 ] ) + 1 ))
4113                   {
4114                   // TODO problem ChangeElementNodes : not the same number of nodes, not the same type
4115                   MESSAGE("ChangeElementNodes");
4116                   aMesh->ChangeElementNodes( f, nodes, nbn );
4117                   }
4118               }
4119             }
4120             while ( srcElements.Length() < myLastCreatedElems.Length() )
4121               srcElements.Append( *srcEdge );
4122
4123           }  // loop on free faces
4124
4125           // go to the next volume
4126           iVol = 0;
4127           while ( iVol++ < nbVolumesByStep ) v++;
4128         }
4129       }
4130     } // sweep free links into faces
4131
4132     // Make a ceiling face with a normal external to a volume
4133
4134     SMDS_VolumeTool lastVol( itElem->second.back() );
4135
4136     int iF = lastVol.GetFaceIndex( aFaceLastNodes );
4137     if ( iF >= 0 ) {
4138       lastVol.SetExternalNormal();
4139       const SMDS_MeshNode** nodes = lastVol.GetFaceNodes( iF );
4140       int nbn = lastVol.NbFaceNodes( iF );
4141       switch ( nbn ) {
4142       case 3:
4143         if (!hasFreeLinks ||
4144             !aMesh->FindFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ]))
4145           myLastCreatedElems.Append(aMesh->AddFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ] ));
4146         break;
4147       case 4:
4148         if (!hasFreeLinks ||
4149             !aMesh->FindFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ], nodes[ 3 ]))
4150           myLastCreatedElems.Append(aMesh->AddFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ], nodes[ 3 ] ));
4151         break;
4152       default:
4153         if(itElem->second.back()->IsQuadratic()) {
4154           if(nbn==6) {
4155             if (!hasFreeLinks ||
4156                 !aMesh->FindFace(nodes[0], nodes[2], nodes[4],
4157                                  nodes[1], nodes[3], nodes[5]) ) {
4158               myLastCreatedElems.Append(aMesh->AddFace(nodes[0], nodes[2], nodes[4],
4159                                                        nodes[1], nodes[3], nodes[5]));
4160             }
4161           }
4162           else { // nbn==8
4163             if (!hasFreeLinks ||
4164                 !aMesh->FindFace(nodes[0], nodes[2], nodes[4], nodes[6],
4165                                  nodes[1], nodes[3], nodes[5], nodes[7]) )
4166               myLastCreatedElems.Append(aMesh->AddFace(nodes[0], nodes[2], nodes[4], nodes[6],
4167                                                        nodes[1], nodes[3], nodes[5], nodes[7]));
4168           }
4169         }
4170         else {
4171           vector<const SMDS_MeshNode*> polygon_nodes ( nodes, &nodes[nbn] );
4172           if (!hasFreeLinks || !aMesh->FindFace(polygon_nodes))
4173             myLastCreatedElems.Append(aMesh->AddPolygonalFace(polygon_nodes));
4174         }
4175       } // switch
4176
4177       while ( srcElements.Length() < myLastCreatedElems.Length() )
4178         srcElements.Append( myLastCreatedElems.Last() );
4179     }
4180   } // loop on swept elements
4181 }
4182
4183 //=======================================================================
4184 //function : RotationSweep
4185 //purpose  :
4186 //=======================================================================
4187
4188 SMESH_MeshEditor::PGroupIDs
4189 SMESH_MeshEditor::RotationSweep(TIDSortedElemSet & theElems,
4190                                 const gp_Ax1&      theAxis,
4191                                 const double       theAngle,
4192                                 const int          theNbSteps,
4193                                 const double       theTol,
4194                                 const bool         theMakeGroups,
4195                                 const bool         theMakeWalls)
4196 {
4197   myLastCreatedElems.Clear();
4198   myLastCreatedNodes.Clear();
4199
4200   // source elements for each generated one
4201   SMESH_SequenceOfElemPtr srcElems, srcNodes;
4202
4203   MESSAGE( "RotationSweep()");
4204   gp_Trsf aTrsf;
4205   aTrsf.SetRotation( theAxis, theAngle );
4206   gp_Trsf aTrsf2;
4207   aTrsf2.SetRotation( theAxis, theAngle/2. );
4208
4209   gp_Lin aLine( theAxis );
4210   double aSqTol = theTol * theTol;
4211
4212   SMESHDS_Mesh* aMesh = GetMeshDS();
4213
4214   TNodeOfNodeListMap mapNewNodes;
4215   TElemOfVecOfNnlmiMap mapElemNewNodes;
4216   TElemOfElemListMap newElemsMap;
4217
4218   // loop on theElems
4219   TIDSortedElemSet::iterator itElem;
4220   for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
4221     const SMDS_MeshElement* elem = *itElem;
4222     if ( !elem || elem->GetType() == SMDSAbs_Volume )
4223       continue;
4224     vector<TNodeOfNodeListMapItr> & newNodesItVec = mapElemNewNodes[ elem ];
4225     newNodesItVec.reserve( elem->NbNodes() );
4226
4227     // loop on elem nodes
4228     SMDS_ElemIteratorPtr itN = elem->nodesIterator();
4229     while ( itN->more() ) {
4230       // check if a node has been already sweeped
4231       const SMDS_MeshNode* node = cast2Node( itN->next() );
4232
4233       gp_XYZ aXYZ( node->X(), node->Y(), node->Z() );
4234       double coord[3];
4235       aXYZ.Coord( coord[0], coord[1], coord[2] );
4236       bool isOnAxis = ( aLine.SquareDistance( aXYZ ) <= aSqTol );
4237
4238       TNodeOfNodeListMapItr nIt = mapNewNodes.find( node );
4239       if ( nIt == mapNewNodes.end() ) {
4240         nIt = mapNewNodes.insert( make_pair( node, list<const SMDS_MeshNode*>() )).first;
4241         list<const SMDS_MeshNode*>& listNewNodes = nIt->second;
4242
4243         // make new nodes
4244         //gp_XYZ aXYZ( node->X(), node->Y(), node->Z() );
4245         //double coord[3];
4246         //aXYZ.Coord( coord[0], coord[1], coord[2] );
4247         //bool isOnAxis = ( aLine.SquareDistance( aXYZ ) <= aSqTol );
4248         const SMDS_MeshNode * newNode = node;
4249         for ( int i = 0; i < theNbSteps; i++ ) {
4250           if ( !isOnAxis ) {
4251             if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
4252               // create two nodes
4253               aTrsf2.Transforms( coord[0], coord[1], coord[2] );
4254               //aTrsf.Transforms( coord[0], coord[1], coord[2] );
4255               newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
4256               myLastCreatedNodes.Append(newNode);
4257               srcNodes.Append( node );
4258               listNewNodes.push_back( newNode );
4259               aTrsf2.Transforms( coord[0], coord[1], coord[2] );
4260               //aTrsf.Transforms( coord[0], coord[1], coord[2] );
4261             }
4262             else {
4263               aTrsf.Transforms( coord[0], coord[1], coord[2] );
4264             }
4265             newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
4266             myLastCreatedNodes.Append(newNode);
4267             srcNodes.Append( node );
4268             listNewNodes.push_back( newNode );
4269           }
4270           else {
4271             listNewNodes.push_back( newNode );
4272             if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
4273               listNewNodes.push_back( newNode );
4274             }
4275           }
4276         }
4277       }
4278       /*
4279         else {
4280         // if current elem is quadratic and current node is not medium
4281         // we have to check - may be it is needed to insert additional nodes
4282         if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
4283         list< const SMDS_MeshNode* > & listNewNodes = nIt->second;
4284         if(listNewNodes.size()==theNbSteps) {
4285         listNewNodes.clear();
4286         // make new nodes
4287         //gp_XYZ aXYZ( node->X(), node->Y(), node->Z() );
4288         //double coord[3];
4289         //aXYZ.Coord( coord[0], coord[1], coord[2] );
4290         const SMDS_MeshNode * newNode = node;
4291         if ( !isOnAxis ) {
4292         for(int i = 0; i<theNbSteps; i++) {
4293         aTrsf2.Transforms( coord[0], coord[1], coord[2] );
4294         newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
4295         cout<<"    3 AddNode:  "<<newNode;
4296         myLastCreatedNodes.Append(newNode);
4297         listNewNodes.push_back( newNode );
4298         srcNodes.Append( node );
4299         aTrsf2.Transforms( coord[0], coord[1], coord[2] );
4300         newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
4301         cout<<"    4 AddNode:  "<<newNode;
4302         myLastCreatedNodes.Append(newNode);
4303         srcNodes.Append( node );
4304         listNewNodes.push_back( newNode );
4305         }
4306         }
4307         else {
4308         listNewNodes.push_back( newNode );
4309         }
4310         }
4311         }
4312         }
4313       */
4314       newNodesItVec.push_back( nIt );
4315     }
4316     // make new elements
4317     sweepElement( elem, newNodesItVec, newElemsMap[elem], theNbSteps, srcElems );
4318   }
4319
4320   if ( theMakeWalls )
4321     makeWalls( mapNewNodes, newElemsMap, mapElemNewNodes, theElems, theNbSteps, srcElems );
4322
4323   PGroupIDs newGroupIDs;
4324   if ( theMakeGroups )
4325     newGroupIDs = generateGroups( srcNodes, srcElems, "rotated");
4326
4327   return newGroupIDs;
4328 }
4329
4330
4331 //=======================================================================
4332 //function : CreateNode
4333 //purpose  :
4334 //=======================================================================
4335 const SMDS_MeshNode* SMESH_MeshEditor::CreateNode(const double x,
4336                                                   const double y,
4337                                                   const double z,
4338                                                   const double tolnode,
4339                                                   SMESH_SequenceOfNode& aNodes)
4340 {
4341   myLastCreatedElems.Clear();
4342   myLastCreatedNodes.Clear();
4343
4344   gp_Pnt P1(x,y,z);
4345   SMESHDS_Mesh * aMesh = myMesh->GetMeshDS();
4346
4347   // try to search in sequence of existing nodes
4348   // if aNodes.Length()>0 we 'nave to use given sequence
4349   // else - use all nodes of mesh
4350   if(aNodes.Length()>0) {
4351     int i;
4352     for(i=1; i<=aNodes.Length(); i++) {
4353       gp_Pnt P2(aNodes.Value(i)->X(),aNodes.Value(i)->Y(),aNodes.Value(i)->Z());
4354       if(P1.Distance(P2)<tolnode)
4355         return aNodes.Value(i);
4356     }
4357   }
4358   else {
4359     SMDS_NodeIteratorPtr itn = aMesh->nodesIterator();
4360     while(itn->more()) {
4361       const SMDS_MeshNode* aN = static_cast<const SMDS_MeshNode*> (itn->next());
4362       gp_Pnt P2(aN->X(),aN->Y(),aN->Z());
4363       if(P1.Distance(P2)<tolnode)
4364         return aN;
4365     }
4366   }
4367
4368   // create new node and return it
4369   const SMDS_MeshNode* NewNode = aMesh->AddNode(x,y,z);
4370   myLastCreatedNodes.Append(NewNode);
4371   return NewNode;
4372 }
4373
4374
4375 //=======================================================================
4376 //function : ExtrusionSweep
4377 //purpose  :
4378 //=======================================================================
4379
4380 SMESH_MeshEditor::PGroupIDs
4381 SMESH_MeshEditor::ExtrusionSweep (TIDSortedElemSet &  theElems,
4382                                   const gp_Vec&       theStep,
4383                                   const int           theNbSteps,
4384                                   TElemOfElemListMap& newElemsMap,
4385                                   const bool          theMakeGroups,
4386                                   const int           theFlags,
4387                                   const double        theTolerance)
4388 {
4389   ExtrusParam aParams;
4390   aParams.myDir = gp_Dir(theStep);
4391   aParams.myNodes.Clear();
4392   aParams.mySteps = new TColStd_HSequenceOfReal;
4393   int i;
4394   for(i=1; i<=theNbSteps; i++)
4395     aParams.mySteps->Append(theStep.Magnitude());
4396
4397   return
4398     ExtrusionSweep(theElems,aParams,newElemsMap,theMakeGroups,theFlags,theTolerance);
4399 }
4400
4401
4402 //=======================================================================
4403 //function : ExtrusionSweep
4404 //purpose  :
4405 //=======================================================================
4406
4407 SMESH_MeshEditor::PGroupIDs
4408 SMESH_MeshEditor::ExtrusionSweep (TIDSortedElemSet &  theElems,
4409                                   ExtrusParam&        theParams,
4410                                   TElemOfElemListMap& newElemsMap,
4411                                   const bool          theMakeGroups,
4412                                   const int           theFlags,
4413                                   const double        theTolerance)
4414 {
4415   MESSAGE("ExtrusionSweep " << theMakeGroups << " " << theFlags << " " << theTolerance);
4416   myLastCreatedElems.Clear();
4417   myLastCreatedNodes.Clear();
4418
4419   // source elements for each generated one
4420   SMESH_SequenceOfElemPtr srcElems, srcNodes;
4421
4422   SMESHDS_Mesh* aMesh = GetMeshDS();
4423
4424   int nbsteps = theParams.mySteps->Length();
4425
4426   TNodeOfNodeListMap mapNewNodes;
4427   //TNodeOfNodeVecMap mapNewNodes;
4428   TElemOfVecOfNnlmiMap mapElemNewNodes;
4429   //TElemOfVecOfMapNodesMap mapElemNewNodes;
4430
4431   // loop on theElems
4432   TIDSortedElemSet::iterator itElem;
4433   for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
4434     // check element type
4435     const SMDS_MeshElement* elem = *itElem;
4436     if ( !elem  || elem->GetType() == SMDSAbs_Volume )
4437       continue;
4438
4439     vector<TNodeOfNodeListMapItr> & newNodesItVec = mapElemNewNodes[ elem ];
4440     //vector<TNodeOfNodeVecMapItr> & newNodesItVec = mapElemNewNodes[ elem ];
4441     newNodesItVec.reserve( elem->NbNodes() );
4442
4443     // loop on elem nodes
4444     SMDS_ElemIteratorPtr itN = elem->nodesIterator();
4445     while ( itN->more() )
4446     {
4447       // check if a node has been already sweeped
4448       const SMDS_MeshNode* node = cast2Node( itN->next() );
4449       TNodeOfNodeListMap::iterator nIt = mapNewNodes.find( node );
4450       //TNodeOfNodeVecMap::iterator nIt = mapNewNodes.find( node );
4451       if ( nIt == mapNewNodes.end() ) {
4452         nIt = mapNewNodes.insert( make_pair( node, list<const SMDS_MeshNode*>() )).first;
4453         //nIt = mapNewNodes.insert( make_pair( node, vector<const SMDS_MeshNode*>() )).first;
4454         list<const SMDS_MeshNode*>& listNewNodes = nIt->second;
4455         //vector<const SMDS_MeshNode*>& vecNewNodes = nIt->second;
4456         //vecNewNodes.reserve(nbsteps);
4457
4458         // make new nodes
4459         double coord[] = { node->X(), node->Y(), node->Z() };
4460         //int nbsteps = theParams.mySteps->Length();
4461         for ( int i = 0; i < nbsteps; i++ ) {
4462           if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
4463             // create additional node
4464             double x = coord[0] + theParams.myDir.X()*theParams.mySteps->Value(i+1)/2.;
4465             double y = coord[1] + theParams.myDir.Y()*theParams.mySteps->Value(i+1)/2.;
4466             double z = coord[2] + theParams.myDir.Z()*theParams.mySteps->Value(i+1)/2.;
4467             if( theFlags & EXTRUSION_FLAG_SEW ) {
4468               const SMDS_MeshNode * newNode = CreateNode(x, y, z,
4469                                                          theTolerance, theParams.myNodes);
4470               listNewNodes.push_back( newNode );
4471             }
4472             else {
4473               const SMDS_MeshNode * newNode = aMesh->AddNode(x, y, z);
4474               myLastCreatedNodes.Append(newNode);
4475               srcNodes.Append( node );
4476               listNewNodes.push_back( newNode );
4477             }
4478           }
4479           //aTrsf.Transforms( coord[0], coord[1], coord[2] );
4480           coord[0] = coord[0] + theParams.myDir.X()*theParams.mySteps->Value(i+1);
4481           coord[1] = coord[1] + theParams.myDir.Y()*theParams.mySteps->Value(i+1);
4482           coord[2] = coord[2] + theParams.myDir.Z()*theParams.mySteps->Value(i+1);
4483           if( theFlags & EXTRUSION_FLAG_SEW ) {
4484             const SMDS_MeshNode * newNode = CreateNode(coord[0], coord[1], coord[2],
4485                                                        theTolerance, theParams.myNodes);
4486             listNewNodes.push_back( newNode );
4487             //vecNewNodes[i]=newNode;
4488           }
4489           else {
4490             const SMDS_MeshNode * newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
4491             myLastCreatedNodes.Append(newNode);
4492             srcNodes.Append( node );
4493             listNewNodes.push_back( newNode );
4494             //vecNewNodes[i]=newNode;
4495           }
4496         }
4497       }
4498       else {
4499         // if current elem is quadratic and current node is not medium
4500         // we have to check - may be it is needed to insert additional nodes
4501         if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
4502           list< const SMDS_MeshNode* > & listNewNodes = nIt->second;
4503           if(listNewNodes.size()==nbsteps) {
4504             listNewNodes.clear();
4505             double coord[] = { node->X(), node->Y(), node->Z() };
4506             for ( int i = 0; i < nbsteps; i++ ) {
4507               double x = coord[0] + theParams.myDir.X()*theParams.mySteps->Value(i+1);
4508               double y = coord[1] + theParams.myDir.Y()*theParams.mySteps->Value(i+1);
4509               double z = coord[2] + theParams.myDir.Z()*theParams.mySteps->Value(i+1);
4510               if( theFlags & EXTRUSION_FLAG_SEW ) {
4511                 const SMDS_MeshNode * newNode = CreateNode(x, y, z,
4512                                                            theTolerance, theParams.myNodes);
4513                 listNewNodes.push_back( newNode );
4514               }
4515               else {
4516                 const SMDS_MeshNode * newNode = aMesh->AddNode(x, y, z);
4517                 myLastCreatedNodes.Append(newNode);
4518                 srcNodes.Append( node );
4519                 listNewNodes.push_back( newNode );
4520               }
4521               coord[0] = coord[0] + theParams.myDir.X()*theParams.mySteps->Value(i+1);
4522               coord[1] = coord[1] + theParams.myDir.Y()*theParams.mySteps->Value(i+1);
4523               coord[2] = coord[2] + theParams.myDir.Z()*theParams.mySteps->Value(i+1);
4524               if( theFlags & EXTRUSION_FLAG_SEW ) {
4525                 const SMDS_MeshNode * newNode = CreateNode(coord[0], coord[1], coord[2],
4526                                                            theTolerance, theParams.myNodes);
4527                 listNewNodes.push_back( newNode );
4528               }
4529               else {
4530                 const SMDS_MeshNode * newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
4531                 myLastCreatedNodes.Append(newNode);
4532                 srcNodes.Append( node );
4533                 listNewNodes.push_back( newNode );
4534               }
4535             }
4536           }
4537         }
4538       }
4539       newNodesItVec.push_back( nIt );
4540     }
4541     // make new elements
4542     sweepElement( elem, newNodesItVec, newElemsMap[elem], nbsteps, srcElems );
4543   }
4544
4545   if( theFlags & EXTRUSION_FLAG_BOUNDARY ) {
4546     makeWalls( mapNewNodes, newElemsMap, mapElemNewNodes, theElems, nbsteps, srcElems );
4547   }
4548   PGroupIDs newGroupIDs;
4549   if ( theMakeGroups )
4550     newGroupIDs = generateGroups( srcNodes, srcElems, "extruded");
4551
4552   return newGroupIDs;
4553 }
4554
4555 /*
4556 //=======================================================================
4557 //class    : SMESH_MeshEditor_PathPoint
4558 //purpose  : auxiliary class
4559 //=======================================================================
4560 class SMESH_MeshEditor_PathPoint {
4561 public:
4562 SMESH_MeshEditor_PathPoint() {
4563 myPnt.SetCoord(99., 99., 99.);
4564 myTgt.SetCoord(1.,0.,0.);
4565 myAngle=0.;
4566 myPrm=0.;
4567 }
4568 void SetPnt(const gp_Pnt& aP3D){
4569 myPnt=aP3D;
4570 }
4571 void SetTangent(const gp_Dir& aTgt){
4572 myTgt=aTgt;
4573 }
4574 void SetAngle(const double& aBeta){
4575 myAngle=aBeta;
4576 }
4577 void SetParameter(const double& aPrm){
4578 myPrm=aPrm;
4579 }
4580 const gp_Pnt& Pnt()const{
4581 return myPnt;
4582 }
4583 const gp_Dir& Tangent()const{
4584 return myTgt;
4585 }
4586 double Angle()const{
4587 return myAngle;
4588 }
4589 double Parameter()const{
4590 return myPrm;
4591 }
4592
4593 protected:
4594 gp_Pnt myPnt;
4595 gp_Dir myTgt;
4596 double myAngle;
4597 double myPrm;
4598 };
4599 */
4600
4601 //=======================================================================
4602 //function : ExtrusionAlongTrack
4603 //purpose  :
4604 //=======================================================================
4605 SMESH_MeshEditor::Extrusion_Error
4606 SMESH_MeshEditor::ExtrusionAlongTrack (TIDSortedElemSet &   theElements,
4607                                        SMESH_subMesh*       theTrack,
4608                                        const SMDS_MeshNode* theN1,
4609                                        const bool           theHasAngles,
4610                                        list<double>&        theAngles,
4611                                        const bool           theLinearVariation,
4612                                        const bool           theHasRefPoint,
4613                                        const gp_Pnt&        theRefPoint,
4614                                        const bool           theMakeGroups)
4615 {
4616   MESSAGE("ExtrusionAlongTrack");
4617   myLastCreatedElems.Clear();
4618   myLastCreatedNodes.Clear();
4619
4620   int aNbE;
4621   std::list<double> aPrms;
4622   TIDSortedElemSet::iterator itElem;
4623
4624   gp_XYZ aGC;
4625   TopoDS_Edge aTrackEdge;
4626   TopoDS_Vertex aV1, aV2;
4627
4628   SMDS_ElemIteratorPtr aItE;
4629   SMDS_NodeIteratorPtr aItN;
4630   SMDSAbs_ElementType aTypeE;
4631
4632   TNodeOfNodeListMap mapNewNodes;
4633
4634   // 1. Check data
4635   aNbE = theElements.size();
4636   // nothing to do
4637   if ( !aNbE )
4638     return EXTR_NO_ELEMENTS;
4639
4640   // 1.1 Track Pattern
4641   ASSERT( theTrack );
4642
4643   SMESHDS_SubMesh* pSubMeshDS = theTrack->GetSubMeshDS();
4644
4645   aItE = pSubMeshDS->GetElements();
4646   while ( aItE->more() ) {
4647     const SMDS_MeshElement* pE = aItE->next();
4648     aTypeE = pE->GetType();
4649     // Pattern must contain links only
4650     if ( aTypeE != SMDSAbs_Edge )
4651       return EXTR_PATH_NOT_EDGE;
4652   }
4653
4654   list<SMESH_MeshEditor_PathPoint> fullList;
4655
4656   const TopoDS_Shape& aS = theTrack->GetSubShape();
4657   // Sub shape for the Pattern must be an Edge or Wire
4658   if( aS.ShapeType() == TopAbs_EDGE ) {
4659     aTrackEdge = TopoDS::Edge( aS );
4660     // the Edge must not be degenerated
4661     if ( BRep_Tool::Degenerated( aTrackEdge ) )
4662       return EXTR_BAD_PATH_SHAPE;
4663     TopExp::Vertices( aTrackEdge, aV1, aV2 );
4664     aItN = theTrack->GetFather()->GetSubMesh( aV1 )->GetSubMeshDS()->GetNodes();
4665     const SMDS_MeshNode* aN1 = aItN->next();
4666     aItN = theTrack->GetFather()->GetSubMesh( aV2 )->GetSubMeshDS()->GetNodes();
4667     const SMDS_MeshNode* aN2 = aItN->next();
4668     // starting node must be aN1 or aN2
4669     if ( !( aN1 == theN1 || aN2 == theN1 ) )
4670       return EXTR_BAD_STARTING_NODE;
4671     aItN = pSubMeshDS->GetNodes();
4672     while ( aItN->more() ) {
4673       const SMDS_MeshNode* pNode = aItN->next();
4674       const SMDS_EdgePosition* pEPos =
4675         static_cast<const SMDS_EdgePosition*>( pNode->GetPosition() );
4676       double aT = pEPos->GetUParameter();
4677       aPrms.push_back( aT );
4678     }
4679     //Extrusion_Error err =
4680     MakeEdgePathPoints(aPrms, aTrackEdge, (aN1==theN1), fullList);
4681   }
4682   else if( aS.ShapeType() == TopAbs_WIRE ) {
4683     list< SMESH_subMesh* > LSM;
4684     TopTools_SequenceOfShape Edges;
4685     SMESH_subMeshIteratorPtr itSM = theTrack->getDependsOnIterator(false,true);
4686     while(itSM->more()) {
4687       SMESH_subMesh* SM = itSM->next();
4688       LSM.push_back(SM);
4689       const TopoDS_Shape& aS = SM->GetSubShape();
4690       Edges.Append(aS);
4691     }
4692     list< list<SMESH_MeshEditor_PathPoint> > LLPPs;
4693     int startNid = theN1->GetID();
4694     TColStd_MapOfInteger UsedNums;
4695     int NbEdges = Edges.Length();
4696     int i = 1;
4697     for(; i<=NbEdges; i++) {
4698       int k = 0;
4699       list< SMESH_subMesh* >::iterator itLSM = LSM.begin();
4700       for(; itLSM!=LSM.end(); itLSM++) {
4701         k++;
4702         if(UsedNums.Contains(k)) continue;
4703         aTrackEdge = TopoDS::Edge( Edges.Value(k) );
4704         SMESH_subMesh* locTrack = *itLSM;
4705         SMESHDS_SubMesh* locMeshDS = locTrack->GetSubMeshDS();
4706         TopExp::Vertices( aTrackEdge, aV1, aV2 );
4707         aItN = locTrack->GetFather()->GetSubMesh(aV1)->GetSubMeshDS()->GetNodes();
4708         const SMDS_MeshNode* aN1 = aItN->next();
4709         aItN = locTrack->GetFather()->GetSubMesh(aV2)->GetSubMeshDS()->GetNodes();
4710         const SMDS_MeshNode* aN2 = aItN->next();
4711         // starting node must be aN1 or aN2
4712         if ( !( aN1->GetID() == startNid || aN2->GetID() == startNid ) ) continue;
4713         // 2. Collect parameters on the track edge
4714         aPrms.clear();
4715         aItN = locMeshDS->GetNodes();
4716         while ( aItN->more() ) {
4717           const SMDS_MeshNode* pNode = aItN->next();
4718           const SMDS_EdgePosition* pEPos =
4719             static_cast<const SMDS_EdgePosition*>( pNode->GetPosition() );
4720           double aT = pEPos->GetUParameter();
4721           aPrms.push_back( aT );
4722         }
4723         list<SMESH_MeshEditor_PathPoint> LPP;
4724         //Extrusion_Error err =
4725         MakeEdgePathPoints(aPrms, aTrackEdge,(aN1->GetID()==startNid), LPP);
4726         LLPPs.push_back(LPP);
4727         UsedNums.Add(k);
4728         // update startN for search following egde
4729         if( aN1->GetID() == startNid ) startNid = aN2->GetID();
4730         else startNid = aN1->GetID();
4731         break;
4732       }
4733     }
4734     list< list<SMESH_MeshEditor_PathPoint> >::iterator itLLPP = LLPPs.begin();
4735     list<SMESH_MeshEditor_PathPoint> firstList = *itLLPP;
4736     list<SMESH_MeshEditor_PathPoint>::iterator itPP = firstList.begin();
4737     for(; itPP!=firstList.end(); itPP++) {
4738       fullList.push_back( *itPP );
4739     }
4740     SMESH_MeshEditor_PathPoint PP1 = fullList.back();
4741     fullList.pop_back();
4742     itLLPP++;
4743     for(; itLLPP!=LLPPs.end(); itLLPP++) {
4744       list<SMESH_MeshEditor_PathPoint> currList = *itLLPP;
4745       itPP = currList.begin();
4746       SMESH_MeshEditor_PathPoint PP2 = currList.front();
4747       gp_Dir D1 = PP1.Tangent();
4748       gp_Dir D2 = PP2.Tangent();
4749       gp_Dir Dnew( gp_Vec( (D1.X()+D2.X())/2, (D1.Y()+D2.Y())/2,
4750                            (D1.Z()+D2.Z())/2 ) );
4751       PP1.SetTangent(Dnew);
4752       fullList.push_back(PP1);
4753       itPP++;
4754       for(; itPP!=firstList.end(); itPP++) {
4755         fullList.push_back( *itPP );
4756       }
4757       PP1 = fullList.back();
4758       fullList.pop_back();
4759     }
4760     // if wire not closed
4761     fullList.push_back(PP1);
4762     // else ???
4763   }
4764   else {
4765     return EXTR_BAD_PATH_SHAPE;
4766   }
4767
4768   return MakeExtrElements(theElements, fullList, theHasAngles, theAngles, theLinearVariation,
4769                           theHasRefPoint, theRefPoint, theMakeGroups);
4770 }
4771
4772
4773 //=======================================================================
4774 //function : ExtrusionAlongTrack
4775 //purpose  :
4776 //=======================================================================
4777 SMESH_MeshEditor::Extrusion_Error
4778 SMESH_MeshEditor::ExtrusionAlongTrack (TIDSortedElemSet &   theElements,
4779                                        SMESH_Mesh*          theTrack,
4780                                        const SMDS_MeshNode* theN1,
4781                                        const bool           theHasAngles,
4782                                        list<double>&        theAngles,
4783                                        const bool           theLinearVariation,
4784                                        const bool           theHasRefPoint,
4785                                        const gp_Pnt&        theRefPoint,
4786                                        const bool           theMakeGroups)
4787 {
4788   myLastCreatedElems.Clear();
4789   myLastCreatedNodes.Clear();
4790
4791   int aNbE;
4792   std::list<double> aPrms;
4793   TIDSortedElemSet::iterator itElem;
4794
4795   gp_XYZ aGC;
4796   TopoDS_Edge aTrackEdge;
4797   TopoDS_Vertex aV1, aV2;
4798
4799   SMDS_ElemIteratorPtr aItE;
4800   SMDS_NodeIteratorPtr aItN;
4801   SMDSAbs_ElementType aTypeE;
4802
4803   TNodeOfNodeListMap mapNewNodes;
4804
4805   // 1. Check data
4806   aNbE = theElements.size();
4807   // nothing to do
4808   if ( !aNbE )
4809     return EXTR_NO_ELEMENTS;
4810
4811   // 1.1 Track Pattern
4812   ASSERT( theTrack );
4813
4814   SMESHDS_Mesh* pMeshDS = theTrack->GetMeshDS();
4815
4816   aItE = pMeshDS->elementsIterator();
4817   while ( aItE->more() ) {
4818     const SMDS_MeshElement* pE = aItE->next();
4819     aTypeE = pE->GetType();
4820     // Pattern must contain links only
4821     if ( aTypeE != SMDSAbs_Edge )
4822       return EXTR_PATH_NOT_EDGE;
4823   }
4824
4825   list<SMESH_MeshEditor_PathPoint> fullList;
4826
4827   const TopoDS_Shape& aS = theTrack->GetShapeToMesh();
4828   // Sub shape for the Pattern must be an Edge or Wire
4829   if( aS.ShapeType() == TopAbs_EDGE ) {
4830     aTrackEdge = TopoDS::Edge( aS );
4831     // the Edge must not be degenerated
4832     if ( BRep_Tool::Degenerated( aTrackEdge ) )
4833       return EXTR_BAD_PATH_SHAPE;
4834     TopExp::Vertices( aTrackEdge, aV1, aV2 );
4835     aItN = theTrack->GetSubMesh( aV1 )->GetSubMeshDS()->GetNodes();
4836     const SMDS_MeshNode* aN1 = aItN->next();
4837     aItN = theTrack->GetSubMesh( aV2 )->GetSubMeshDS()->GetNodes();
4838     const SMDS_MeshNode* aN2 = aItN->next();
4839     // starting node must be aN1 or aN2
4840     if ( !( aN1 == theN1 || aN2 == theN1 ) )
4841       return EXTR_BAD_STARTING_NODE;
4842     aItN = pMeshDS->nodesIterator();
4843     while ( aItN->more() ) {
4844       const SMDS_MeshNode* pNode = aItN->next();
4845       if( pNode==aN1 || pNode==aN2 ) continue;
4846       const SMDS_EdgePosition* pEPos =
4847         static_cast<const SMDS_EdgePosition*>( pNode->GetPosition() );
4848       double aT = pEPos->GetUParameter();
4849       aPrms.push_back( aT );
4850     }
4851     //Extrusion_Error err =
4852     MakeEdgePathPoints(aPrms, aTrackEdge, (aN1==theN1), fullList);
4853   }
4854   else if( aS.ShapeType() == TopAbs_WIRE ) {
4855     list< SMESH_subMesh* > LSM;
4856     TopTools_SequenceOfShape Edges;
4857     TopExp_Explorer eExp(aS, TopAbs_EDGE);
4858     for(; eExp.More(); eExp.Next()) {
4859       TopoDS_Edge E = TopoDS::Edge( eExp.Current() );
4860       if( BRep_Tool::Degenerated(E) ) continue;
4861       SMESH_subMesh* SM = theTrack->GetSubMesh(E);
4862       if(SM) {
4863         LSM.push_back(SM);
4864         Edges.Append(E);
4865       }
4866     }
4867     list< list<SMESH_MeshEditor_PathPoint> > LLPPs;
4868     int startNid = theN1->GetID();
4869     TColStd_MapOfInteger UsedNums;
4870     int NbEdges = Edges.Length();
4871     int i = 1;
4872     for(; i<=NbEdges; i++) {
4873       int k = 0;
4874       list< SMESH_subMesh* >::iterator itLSM = LSM.begin();
4875       for(; itLSM!=LSM.end(); itLSM++) {
4876         k++;
4877         if(UsedNums.Contains(k)) continue;
4878         aTrackEdge = TopoDS::Edge( Edges.Value(k) );
4879         SMESH_subMesh* locTrack = *itLSM;
4880         SMESHDS_SubMesh* locMeshDS = locTrack->GetSubMeshDS();
4881         TopExp::Vertices( aTrackEdge, aV1, aV2 );
4882         aItN = locTrack->GetFather()->GetSubMesh(aV1)->GetSubMeshDS()->GetNodes();
4883         const SMDS_MeshNode* aN1 = aItN->next();
4884         aItN = locTrack->GetFather()->GetSubMesh(aV2)->GetSubMeshDS()->GetNodes();
4885         const SMDS_MeshNode* aN2 = aItN->next();
4886         // starting node must be aN1 or aN2
4887         if ( !( aN1->GetID() == startNid || aN2->GetID() == startNid ) ) continue;
4888         // 2. Collect parameters on the track edge
4889         aPrms.clear();
4890         aItN = locMeshDS->GetNodes();
4891         while ( aItN->more() ) {
4892           const SMDS_MeshNode* pNode = aItN->next();
4893           const SMDS_EdgePosition* pEPos =
4894             static_cast<const SMDS_EdgePosition*>( pNode->GetPosition() );
4895           double aT = pEPos->GetUParameter();
4896           aPrms.push_back( aT );
4897         }
4898         list<SMESH_MeshEditor_PathPoint> LPP;
4899         //Extrusion_Error err =
4900         MakeEdgePathPoints(aPrms, aTrackEdge,(aN1->GetID()==startNid), LPP);
4901         LLPPs.push_back(LPP);
4902         UsedNums.Add(k);
4903         // update startN for search following egde
4904         if( aN1->GetID() == startNid ) startNid = aN2->GetID();
4905         else startNid = aN1->GetID();
4906         break;
4907       }
4908     }
4909     list< list<SMESH_MeshEditor_PathPoint> >::iterator itLLPP = LLPPs.begin();
4910     list<SMESH_MeshEditor_PathPoint> firstList = *itLLPP;
4911     list<SMESH_MeshEditor_PathPoint>::iterator itPP = firstList.begin();
4912     for(; itPP!=firstList.end(); itPP++) {
4913       fullList.push_back( *itPP );
4914     }
4915     SMESH_MeshEditor_PathPoint PP1 = fullList.back();
4916     fullList.pop_back();
4917     itLLPP++;
4918     for(; itLLPP!=LLPPs.end(); itLLPP++) {
4919       list<SMESH_MeshEditor_PathPoint> currList = *itLLPP;
4920       itPP = currList.begin();
4921       SMESH_MeshEditor_PathPoint PP2 = currList.front();
4922       gp_Pnt P1 = PP1.Pnt();
4923       //cout<<"    PP1: Pnt("<<P1.X()<<","<<P1.Y()<<","<<P1.Z()<<")"<<endl;
4924       gp_Pnt P2 = PP2.Pnt();
4925       gp_Dir D1 = PP1.Tangent();
4926       gp_Dir D2 = PP2.Tangent();
4927       gp_Dir Dnew( gp_Vec( (D1.X()+D2.X())/2, (D1.Y()+D2.Y())/2,
4928                            (D1.Z()+D2.Z())/2 ) );
4929       PP1.SetTangent(Dnew);
4930       fullList.push_back(PP1);
4931       itPP++;
4932       for(; itPP!=currList.end(); itPP++) {
4933         fullList.push_back( *itPP );
4934       }
4935       PP1 = fullList.back();
4936       fullList.pop_back();
4937     }
4938     // if wire not closed
4939     fullList.push_back(PP1);
4940     // else ???
4941   }
4942   else {
4943     return EXTR_BAD_PATH_SHAPE;
4944   }
4945
4946   return MakeExtrElements(theElements, fullList, theHasAngles, theAngles, theLinearVariation,
4947                           theHasRefPoint, theRefPoint, theMakeGroups);
4948 }
4949
4950
4951 //=======================================================================
4952 //function : MakeEdgePathPoints
4953 //purpose  : auxilary for ExtrusionAlongTrack
4954 //=======================================================================
4955 SMESH_MeshEditor::Extrusion_Error
4956 SMESH_MeshEditor::MakeEdgePathPoints(std::list<double>& aPrms,
4957                                      const TopoDS_Edge& aTrackEdge,
4958                                      bool FirstIsStart,
4959                                      list<SMESH_MeshEditor_PathPoint>& LPP)
4960 {
4961   Standard_Real aTx1, aTx2, aL2, aTolVec, aTolVec2;
4962   aTolVec=1.e-7;
4963   aTolVec2=aTolVec*aTolVec;
4964   double aT1, aT2;
4965   TopoDS_Vertex aV1, aV2;
4966   TopExp::Vertices( aTrackEdge, aV1, aV2 );
4967   aT1=BRep_Tool::Parameter( aV1, aTrackEdge );
4968   aT2=BRep_Tool::Parameter( aV2, aTrackEdge );
4969   // 2. Collect parameters on the track edge
4970   aPrms.push_front( aT1 );
4971   aPrms.push_back( aT2 );
4972   // sort parameters
4973   aPrms.sort();
4974   if( FirstIsStart ) {
4975     if ( aT1 > aT2 ) {
4976       aPrms.reverse();
4977     }
4978   }
4979   else {
4980     if ( aT2 > aT1 ) {
4981       aPrms.reverse();
4982     }
4983   }
4984   // 3. Path Points
4985   SMESH_MeshEditor_PathPoint aPP;
4986   Handle(Geom_Curve) aC3D = BRep_Tool::Curve( aTrackEdge, aTx1, aTx2 );
4987   std::list<double>::iterator aItD = aPrms.begin();
4988   for(; aItD != aPrms.end(); ++aItD) {
4989     double aT = *aItD;
4990     gp_Pnt aP3D;
4991     gp_Vec aVec;
4992     aC3D->D1( aT, aP3D, aVec );
4993     aL2 = aVec.SquareMagnitude();
4994     if ( aL2 < aTolVec2 )
4995       return EXTR_CANT_GET_TANGENT;
4996     gp_Dir aTgt( aVec );
4997     aPP.SetPnt( aP3D );
4998     aPP.SetTangent( aTgt );
4999     aPP.SetParameter( aT );
5000     LPP.push_back(aPP);
5001   }
5002   return EXTR_OK;
5003 }
5004
5005
5006 //=======================================================================
5007 //function : MakeExtrElements
5008 //purpose  : auxilary for ExtrusionAlongTrack
5009 //=======================================================================
5010 SMESH_MeshEditor::Extrusion_Error
5011 SMESH_MeshEditor::MakeExtrElements(TIDSortedElemSet&  theElements,
5012                                    list<SMESH_MeshEditor_PathPoint>& fullList,
5013                                    const bool theHasAngles,
5014                                    list<double>& theAngles,
5015                                    const bool theLinearVariation,
5016                                    const bool theHasRefPoint,
5017                                    const gp_Pnt& theRefPoint,
5018                                    const bool theMakeGroups)
5019 {
5020   MESSAGE("MakeExtrElements");
5021   //cout<<"MakeExtrElements  fullList.size() = "<<fullList.size()<<endl;
5022   int aNbTP = fullList.size();
5023   vector<SMESH_MeshEditor_PathPoint> aPPs(aNbTP);
5024   // Angles
5025   if( theHasAngles && theAngles.size()>0 && theLinearVariation ) {
5026     LinearAngleVariation(aNbTP-1, theAngles);
5027   }
5028   vector<double> aAngles( aNbTP );
5029   int j = 0;
5030   for(; j<aNbTP; ++j) {
5031     aAngles[j] = 0.;
5032   }
5033   if ( theHasAngles ) {
5034     double anAngle;;
5035     std::list<double>::iterator aItD = theAngles.begin();
5036     for ( j=1; (aItD != theAngles.end()) && (j<aNbTP); ++aItD, ++j ) {
5037       anAngle = *aItD;
5038       aAngles[j] = anAngle;
5039     }
5040   }
5041   // fill vector of path points with angles
5042   //aPPs.resize(fullList.size());
5043   j = -1;
5044   list<SMESH_MeshEditor_PathPoint>::iterator itPP = fullList.begin();
5045   for(; itPP!=fullList.end(); itPP++) {
5046     j++;
5047     SMESH_MeshEditor_PathPoint PP = *itPP;
5048     PP.SetAngle(aAngles[j]);
5049     aPPs[j] = PP;
5050   }
5051
5052   TNodeOfNodeListMap mapNewNodes;
5053   TElemOfVecOfNnlmiMap mapElemNewNodes;
5054   TElemOfElemListMap newElemsMap;
5055   TIDSortedElemSet::iterator itElem;
5056   double aX, aY, aZ;
5057   int aNb;
5058   SMDSAbs_ElementType aTypeE;
5059   // source elements for each generated one
5060   SMESH_SequenceOfElemPtr srcElems, srcNodes;
5061
5062   // 3. Center of rotation aV0
5063   gp_Pnt aV0 = theRefPoint;
5064   gp_XYZ aGC;
5065   if ( !theHasRefPoint ) {
5066     aNb = 0;
5067     aGC.SetCoord( 0.,0.,0. );
5068
5069     itElem = theElements.begin();
5070     for ( ; itElem != theElements.end(); itElem++ ) {
5071       const SMDS_MeshElement* elem = *itElem;
5072
5073       SMDS_ElemIteratorPtr itN = elem->nodesIterator();
5074       while ( itN->more() ) {
5075         const SMDS_MeshNode* node = static_cast<const SMDS_MeshNode*>( itN->next() );
5076         aX = node->X();
5077         aY = node->Y();
5078         aZ = node->Z();
5079
5080         if ( mapNewNodes.find( node ) == mapNewNodes.end() ) {
5081           list<const SMDS_MeshNode*> aLNx;
5082           mapNewNodes[node] = aLNx;
5083           //
5084           gp_XYZ aXYZ( aX, aY, aZ );
5085           aGC += aXYZ;
5086           ++aNb;
5087         }
5088       }
5089     }
5090     aGC /= aNb;
5091     aV0.SetXYZ( aGC );
5092   } // if (!theHasRefPoint) {
5093   mapNewNodes.clear();
5094
5095   // 4. Processing the elements
5096   SMESHDS_Mesh* aMesh = GetMeshDS();
5097
5098   for ( itElem = theElements.begin(); itElem != theElements.end(); itElem++ ) {
5099     // check element type
5100     const SMDS_MeshElement* elem = *itElem;
5101     aTypeE = elem->GetType();
5102     if ( !elem || ( aTypeE != SMDSAbs_Face && aTypeE != SMDSAbs_Edge ) )
5103       continue;
5104
5105     vector<TNodeOfNodeListMapItr> & newNodesItVec = mapElemNewNodes[ elem ];
5106     newNodesItVec.reserve( elem->NbNodes() );
5107
5108     // loop on elem nodes
5109     int nodeIndex = -1;
5110     SMDS_ElemIteratorPtr itN = elem->nodesIterator();
5111     while ( itN->more() )
5112     {
5113       ++nodeIndex;
5114       // check if a node has been already processed
5115       const SMDS_MeshNode* node =
5116         static_cast<const SMDS_MeshNode*>( itN->next() );
5117       TNodeOfNodeListMap::iterator nIt = mapNewNodes.find( node );
5118       if ( nIt == mapNewNodes.end() ) {
5119         nIt = mapNewNodes.insert( make_pair( node, list<const SMDS_MeshNode*>() )).first;
5120         list<const SMDS_MeshNode*>& listNewNodes = nIt->second;
5121
5122         // make new nodes
5123         aX = node->X();  aY = node->Y(); aZ = node->Z();
5124
5125         Standard_Real aAngle1x, aAngleT1T0, aTolAng;
5126         gp_Pnt aP0x, aP1x, aPN0, aPN1, aV0x, aV1x;
5127         gp_Ax1 anAx1, anAxT1T0;
5128         gp_Dir aDT1x, aDT0x, aDT1T0;
5129
5130         aTolAng=1.e-4;
5131
5132         aV0x = aV0;
5133         aPN0.SetCoord(aX, aY, aZ);
5134
5135         const SMESH_MeshEditor_PathPoint& aPP0 = aPPs[0];
5136         aP0x = aPP0.Pnt();
5137         aDT0x= aPP0.Tangent();
5138         //cout<<"j = 0   PP: Pnt("<<aP0x.X()<<","<<aP0x.Y()<<","<<aP0x.Z()<<")"<<endl;
5139
5140         for ( j = 1; j < aNbTP; ++j ) {
5141           const SMESH_MeshEditor_PathPoint& aPP1 = aPPs[j];
5142           aP1x = aPP1.Pnt();
5143           aDT1x = aPP1.Tangent();
5144           aAngle1x = aPP1.Angle();
5145
5146           gp_Trsf aTrsf, aTrsfRot, aTrsfRotT1T0;
5147           // Translation
5148           gp_Vec aV01x( aP0x, aP1x );
5149           aTrsf.SetTranslation( aV01x );
5150
5151           // traslated point
5152           aV1x = aV0x.Transformed( aTrsf );
5153           aPN1 = aPN0.Transformed( aTrsf );
5154
5155           // rotation 1 [ T1,T0 ]
5156           aAngleT1T0=-aDT1x.Angle( aDT0x );
5157           if (fabs(aAngleT1T0) > aTolAng) {
5158             aDT1T0=aDT1x^aDT0x;
5159             anAxT1T0.SetLocation( aV1x );
5160             anAxT1T0.SetDirection( aDT1T0 );
5161             aTrsfRotT1T0.SetRotation( anAxT1T0, aAngleT1T0 );
5162
5163             aPN1 = aPN1.Transformed( aTrsfRotT1T0 );
5164           }
5165
5166           // rotation 2
5167           if ( theHasAngles ) {
5168             anAx1.SetLocation( aV1x );
5169             anAx1.SetDirection( aDT1x );
5170             aTrsfRot.SetRotation( anAx1, aAngle1x );
5171
5172             aPN1 = aPN1.Transformed( aTrsfRot );
5173           }
5174
5175           // make new node
5176           //MESSAGE("elem->IsQuadratic " << elem->IsQuadratic() << " " << elem->IsMediumNode(node));
5177           if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
5178             // create additional node
5179             double x = ( aPN1.X() + aPN0.X() )/2.;
5180             double y = ( aPN1.Y() + aPN0.Y() )/2.;
5181             double z = ( aPN1.Z() + aPN0.Z() )/2.;
5182             const SMDS_MeshNode* newNode = aMesh->AddNode(x,y,z);
5183             myLastCreatedNodes.Append(newNode);
5184             srcNodes.Append( node );
5185             listNewNodes.push_back( newNode );
5186           }
5187           aX = aPN1.X();
5188           aY = aPN1.Y();
5189           aZ = aPN1.Z();
5190           const SMDS_MeshNode* newNode = aMesh->AddNode( aX, aY, aZ );
5191           myLastCreatedNodes.Append(newNode);
5192           srcNodes.Append( node );
5193           listNewNodes.push_back( newNode );
5194
5195           aPN0 = aPN1;
5196           aP0x = aP1x;
5197           aV0x = aV1x;
5198           aDT0x = aDT1x;
5199         }
5200       }
5201
5202       else {
5203         // if current elem is quadratic and current node is not medium
5204         // we have to check - may be it is needed to insert additional nodes
5205         if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
5206           list< const SMDS_MeshNode* > & listNewNodes = nIt->second;
5207           if(listNewNodes.size()==aNbTP-1) {
5208             vector<const SMDS_MeshNode*> aNodes(2*(aNbTP-1));
5209             gp_XYZ P(node->X(), node->Y(), node->Z());
5210             list< const SMDS_MeshNode* >::iterator it = listNewNodes.begin();
5211             int i;
5212             for(i=0; i<aNbTP-1; i++) {
5213               const SMDS_MeshNode* N = *it;
5214               double x = ( N->X() + P.X() )/2.;
5215               double y = ( N->Y() + P.Y() )/2.;
5216               double z = ( N->Z() + P.Z() )/2.;
5217               const SMDS_MeshNode* newN = aMesh->AddNode(x,y,z);
5218               srcNodes.Append( node );
5219               myLastCreatedNodes.Append(newN);
5220               aNodes[2*i] = newN;
5221               aNodes[2*i+1] = N;
5222               P = gp_XYZ(N->X(),N->Y(),N->Z());
5223             }
5224             listNewNodes.clear();
5225             for(i=0; i<2*(aNbTP-1); i++) {
5226               listNewNodes.push_back(aNodes[i]);
5227             }
5228           }
5229         }
5230       }
5231
5232       newNodesItVec.push_back( nIt );
5233     }
5234     // make new elements
5235     //sweepElement( aMesh, elem, newNodesItVec, newElemsMap[elem],
5236     //              newNodesItVec[0]->second.size(), myLastCreatedElems );
5237     sweepElement( elem, newNodesItVec, newElemsMap[elem], aNbTP-1, srcElems );
5238   }
5239
5240   makeWalls( mapNewNodes, newElemsMap, mapElemNewNodes, theElements, aNbTP-1, srcElems );
5241
5242   if ( theMakeGroups )
5243     generateGroups( srcNodes, srcElems, "extruded");
5244
5245   return EXTR_OK;
5246 }
5247
5248
5249 //=======================================================================
5250 //function : LinearAngleVariation
5251 //purpose  : auxilary for ExtrusionAlongTrack
5252 //=======================================================================
5253 void SMESH_MeshEditor::LinearAngleVariation(const int nbSteps,
5254                                             list<double>& Angles)
5255 {
5256   int nbAngles = Angles.size();
5257   if( nbSteps > nbAngles ) {
5258     vector<double> theAngles(nbAngles);
5259     list<double>::iterator it = Angles.begin();
5260     int i = -1;
5261     for(; it!=Angles.end(); it++) {
5262       i++;
5263       theAngles[i] = (*it);
5264     }
5265     list<double> res;
5266     double rAn2St = double( nbAngles ) / double( nbSteps );
5267     double angPrev = 0, angle;
5268     for ( int iSt = 0; iSt < nbSteps; ++iSt ) {
5269       double angCur = rAn2St * ( iSt+1 );
5270       double angCurFloor  = floor( angCur );
5271       double angPrevFloor = floor( angPrev );
5272       if ( angPrevFloor == angCurFloor )
5273         angle = rAn2St * theAngles[ int( angCurFloor ) ];
5274       else {
5275         int iP = int( angPrevFloor );
5276         double angPrevCeil = ceil(angPrev);
5277         angle = ( angPrevCeil - angPrev ) * theAngles[ iP ];
5278
5279         int iC = int( angCurFloor );
5280         if ( iC < nbAngles )
5281           angle += ( angCur - angCurFloor ) * theAngles[ iC ];
5282
5283         iP = int( angPrevCeil );
5284         while ( iC-- > iP )
5285           angle += theAngles[ iC ];
5286       }
5287       res.push_back(angle);
5288       angPrev = angCur;
5289     }
5290     Angles.clear();
5291     it = res.begin();
5292     for(; it!=res.end(); it++)
5293       Angles.push_back( *it );
5294   }
5295 }
5296
5297
5298 //================================================================================
5299 /*!
5300  * \brief Move or copy theElements applying theTrsf to their nodes
5301  *  \param theElems - elements to transform, if theElems is empty then apply to all mesh nodes
5302  *  \param theTrsf - transformation to apply
5303  *  \param theCopy - if true, create translated copies of theElems
5304  *  \param theMakeGroups - if true and theCopy, create translated groups
5305  *  \param theTargetMesh - mesh to copy translated elements into
5306  *  \retval SMESH_MeshEditor::PGroupIDs - list of ids of created groups
5307  */
5308 //================================================================================
5309
5310 SMESH_MeshEditor::PGroupIDs
5311 SMESH_MeshEditor::Transform (TIDSortedElemSet & theElems,
5312                              const gp_Trsf&     theTrsf,
5313                              const bool         theCopy,
5314                              const bool         theMakeGroups,
5315                              SMESH_Mesh*        theTargetMesh)
5316 {
5317   myLastCreatedElems.Clear();
5318   myLastCreatedNodes.Clear();
5319
5320   bool needReverse = false;
5321   string groupPostfix;
5322   switch ( theTrsf.Form() ) {
5323   case gp_PntMirror:
5324     MESSAGE("gp_PntMirror");
5325     needReverse = true;
5326     groupPostfix = "mirrored";
5327     break;
5328   case gp_Ax1Mirror:
5329     MESSAGE("gp_Ax1Mirror");
5330     groupPostfix = "mirrored";
5331     break;
5332   case gp_Ax2Mirror:
5333     MESSAGE("gp_Ax2Mirror");
5334     needReverse = true;
5335     groupPostfix = "mirrored";
5336     break;
5337   case gp_Rotation:
5338     MESSAGE("gp_Rotation");
5339     groupPostfix = "rotated";
5340     break;
5341   case gp_Translation:
5342     MESSAGE("gp_Translation");
5343     groupPostfix = "translated";
5344     break;
5345   case gp_Scale:
5346     MESSAGE("gp_Scale");
5347     groupPostfix = "scaled";
5348     break;
5349   case gp_CompoundTrsf: // different scale by axis
5350     MESSAGE("gp_CompoundTrsf");
5351     groupPostfix = "scaled";
5352     break;
5353   default:
5354     MESSAGE("default");
5355     needReverse = false;
5356     groupPostfix = "transformed";
5357   }
5358
5359   SMESH_MeshEditor targetMeshEditor( theTargetMesh );
5360   SMESHDS_Mesh* aTgtMesh = theTargetMesh ? theTargetMesh->GetMeshDS() : 0;
5361   SMESHDS_Mesh* aMesh    = GetMeshDS();
5362
5363
5364   // map old node to new one
5365   TNodeNodeMap nodeMap;
5366
5367   // elements sharing moved nodes; those of them which have all
5368   // nodes mirrored but are not in theElems are to be reversed
5369   TIDSortedElemSet inverseElemSet;
5370
5371   // source elements for each generated one
5372   SMESH_SequenceOfElemPtr srcElems, srcNodes;
5373
5374   // issue 021015: EDF 1578 SMESH: Free nodes are removed when translating a mesh
5375   TIDSortedElemSet orphanNode;
5376
5377   if ( theElems.empty() ) // transform the whole mesh
5378   {
5379     // add all elements
5380     SMDS_ElemIteratorPtr eIt = aMesh->elementsIterator();
5381     while ( eIt->more() ) theElems.insert( eIt->next() );
5382     // add orphan nodes
5383     SMDS_NodeIteratorPtr nIt = aMesh->nodesIterator();
5384     while ( nIt->more() )
5385     {
5386       const SMDS_MeshNode* node = nIt->next();
5387       if ( node->NbInverseElements() == 0)
5388         orphanNode.insert( node );
5389     }
5390   }
5391
5392   // loop on elements to transform nodes : first orphan nodes then elems
5393   TIDSortedElemSet::iterator itElem;
5394   TIDSortedElemSet *elements[] = {&orphanNode, &theElems };
5395   for (int i=0; i<2; i++)
5396   for ( itElem = elements[i]->begin(); itElem != elements[i]->end(); itElem++ ) {
5397     const SMDS_MeshElement* elem = *itElem;
5398     if ( !elem )
5399       continue;
5400
5401     // loop on elem nodes
5402     SMDS_ElemIteratorPtr itN = elem->nodesIterator();
5403     while ( itN->more() ) {
5404
5405       const SMDS_MeshNode* node = cast2Node( itN->next() );
5406       // check if a node has been already transformed
5407       pair<TNodeNodeMap::iterator,bool> n2n_isnew =
5408         nodeMap.insert( make_pair ( node, node ));
5409       if ( !n2n_isnew.second )
5410         continue;
5411
5412       double coord[3];
5413       coord[0] = node->X();
5414       coord[1] = node->Y();
5415       coord[2] = node->Z();
5416       theTrsf.Transforms( coord[0], coord[1], coord[2] );
5417       if ( theTargetMesh ) {
5418         const SMDS_MeshNode * newNode = aTgtMesh->AddNode( coord[0], coord[1], coord[2] );
5419         n2n_isnew.first->second = newNode;
5420         myLastCreatedNodes.Append(newNode);
5421         srcNodes.Append( node );
5422       }
5423       else if ( theCopy ) {
5424         const SMDS_MeshNode * newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
5425         n2n_isnew.first->second = newNode;
5426         myLastCreatedNodes.Append(newNode);
5427         srcNodes.Append( node );
5428       }
5429       else {
5430         aMesh->MoveNode( node, coord[0], coord[1], coord[2] );
5431         // node position on shape becomes invalid
5432         const_cast< SMDS_MeshNode* > ( node )->SetPosition
5433           ( SMDS_SpacePosition::originSpacePosition() );
5434       }
5435
5436       // keep inverse elements
5437       if ( !theCopy && !theTargetMesh && needReverse ) {
5438         SMDS_ElemIteratorPtr invElemIt = node->GetInverseElementIterator();
5439         while ( invElemIt->more() ) {
5440           const SMDS_MeshElement* iel = invElemIt->next();
5441           inverseElemSet.insert( iel );
5442         }
5443       }
5444     }
5445   }
5446
5447   // either create new elements or reverse mirrored ones
5448   if ( !theCopy && !needReverse && !theTargetMesh )
5449     return PGroupIDs();
5450
5451   TIDSortedElemSet::iterator invElemIt = inverseElemSet.begin();
5452   for ( ; invElemIt != inverseElemSet.end(); invElemIt++ )
5453     theElems.insert( *invElemIt );
5454
5455   // replicate or reverse elements
5456   // TODO revoir ordre reverse vtk
5457   enum {
5458     REV_TETRA   = 0,  //  = nbNodes - 4
5459     REV_PYRAMID = 1,  //  = nbNodes - 4
5460     REV_PENTA   = 2,  //  = nbNodes - 4
5461     REV_FACE    = 3,
5462     REV_HEXA    = 4,  //  = nbNodes - 4
5463     FORWARD     = 5
5464   };
5465   int index[][8] = {
5466     { 2, 1, 0, 3, 4, 0, 0, 0 },  // REV_TETRA
5467     { 2, 1, 0, 3, 4, 0, 0, 0 },  // REV_PYRAMID
5468     { 2, 1, 0, 5, 4, 3, 0, 0 },  // REV_PENTA
5469     { 2, 1, 0, 3, 0, 0, 0, 0 },  // REV_FACE
5470     { 2, 1, 0, 3, 6, 5, 4, 7 },  // REV_HEXA
5471     { 0, 1, 2, 3, 4, 5, 6, 7 }   // FORWARD
5472   };
5473
5474   for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ )
5475   {
5476     const SMDS_MeshElement* elem = *itElem;
5477     if ( !elem || elem->GetType() == SMDSAbs_Node )
5478       continue;
5479
5480     int nbNodes = elem->NbNodes();
5481     int elemType = elem->GetType();
5482
5483     if (elem->IsPoly()) {
5484       // Polygon or Polyhedral Volume
5485       switch ( elemType ) {
5486       case SMDSAbs_Face:
5487         {
5488           vector<const SMDS_MeshNode*> poly_nodes (nbNodes);
5489           int iNode = 0;
5490           SMDS_ElemIteratorPtr itN = elem->nodesIterator();
5491           while (itN->more()) {
5492             const SMDS_MeshNode* node =
5493               static_cast<const SMDS_MeshNode*>(itN->next());
5494             TNodeNodeMap::iterator nodeMapIt = nodeMap.find(node);
5495             if (nodeMapIt == nodeMap.end())
5496               break; // not all nodes transformed
5497             if (needReverse) {
5498               // reverse mirrored faces and volumes
5499               poly_nodes[nbNodes - iNode - 1] = (*nodeMapIt).second;
5500             } else {
5501               poly_nodes[iNode] = (*nodeMapIt).second;
5502             }
5503             iNode++;
5504           }
5505           if ( iNode != nbNodes )
5506             continue; // not all nodes transformed
5507
5508           if ( theTargetMesh ) {
5509             myLastCreatedElems.Append(aTgtMesh->AddPolygonalFace(poly_nodes));
5510             srcElems.Append( elem );
5511           }
5512           else if ( theCopy ) {
5513             myLastCreatedElems.Append(aMesh->AddPolygonalFace(poly_nodes));
5514             srcElems.Append( elem );
5515           }
5516           else {
5517             aMesh->ChangePolygonNodes(elem, poly_nodes);
5518           }
5519         }
5520         break;
5521       case SMDSAbs_Volume:
5522         {
5523           // ATTENTION: Reversing is not yet done!!!
5524           const SMDS_VtkVolume* aPolyedre =
5525             dynamic_cast<const SMDS_VtkVolume*>( elem );
5526           if (!aPolyedre) {
5527             MESSAGE("Warning: bad volumic element");
5528             continue;
5529           }
5530
5531           vector<const SMDS_MeshNode*> poly_nodes;
5532           vector<int> quantities;
5533
5534           bool allTransformed = true;
5535           int nbFaces = aPolyedre->NbFaces();
5536           for (int iface = 1; iface <= nbFaces && allTransformed; iface++) {
5537             int nbFaceNodes = aPolyedre->NbFaceNodes(iface);
5538             for (int inode = 1; inode <= nbFaceNodes && allTransformed; inode++) {
5539               const SMDS_MeshNode* node = aPolyedre->GetFaceNode(iface, inode);
5540               TNodeNodeMap::iterator nodeMapIt = nodeMap.find(node);
5541               if (nodeMapIt == nodeMap.end()) {
5542                 allTransformed = false; // not all nodes transformed
5543               } else {
5544                 poly_nodes.push_back((*nodeMapIt).second);
5545               }
5546             }
5547             quantities.push_back(nbFaceNodes);
5548           }
5549           if ( !allTransformed )
5550             continue; // not all nodes transformed
5551
5552           if ( theTargetMesh ) {
5553             myLastCreatedElems.Append(aTgtMesh->AddPolyhedralVolume(poly_nodes, quantities));
5554             srcElems.Append( elem );
5555           }
5556           else if ( theCopy ) {
5557             myLastCreatedElems.Append(aMesh->AddPolyhedralVolume(poly_nodes, quantities));
5558             srcElems.Append( elem );
5559           }
5560           else {
5561             aMesh->ChangePolyhedronNodes(elem, poly_nodes, quantities);
5562           }
5563         }
5564         break;
5565       default:;
5566       }
5567       continue;
5568     }
5569
5570     // Regular elements
5571     int* i = index[ FORWARD ];
5572     if ( needReverse && nbNodes > 2) {// reverse mirrored faces and volumes
5573       if ( elemType == SMDSAbs_Face )
5574         i = index[ REV_FACE ];
5575       else
5576         i = index[ nbNodes - 4 ];
5577     }
5578     if(elem->IsQuadratic()) {
5579       static int anIds[] = {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19};
5580       i = anIds;
5581       if(needReverse) {
5582         if(nbNodes==3) { // quadratic edge
5583           static int anIds[] = {1,0,2};
5584           i = anIds;
5585         }
5586         else if(nbNodes==6) { // quadratic triangle
5587           static int anIds[] = {0,2,1,5,4,3};
5588           i = anIds;
5589         }
5590         else if(nbNodes==8) { // quadratic quadrangle
5591           static int anIds[] = {0,3,2,1,7,6,5,4};
5592           i = anIds;
5593         }
5594         else if(nbNodes==10) { // quadratic tetrahedron of 10 nodes
5595           static int anIds[] = {0,2,1,3,6,5,4,7,9,8};
5596           i = anIds;
5597         }
5598         else if(nbNodes==13) { // quadratic pyramid of 13 nodes
5599           static int anIds[] = {0,3,2,1,4,8,7,6,5,9,12,11,10};
5600           i = anIds;
5601         }
5602         else if(nbNodes==15) { // quadratic pentahedron with 15 nodes
5603           static int anIds[] = {0,2,1,3,5,4,8,7,6,11,10,9,12,14,13};
5604           i = anIds;
5605         }
5606         else { // nbNodes==20 - quadratic hexahedron with 20 nodes
5607           static int anIds[] = {0,3,2,1,4,7,6,5,11,10,9,8,15,14,13,12,16,19,18,17};
5608           i = anIds;
5609         }
5610       }
5611     }
5612
5613     // find transformed nodes
5614     vector<const SMDS_MeshNode*> nodes(nbNodes);
5615     int iNode = 0;
5616     SMDS_ElemIteratorPtr itN = elem->nodesIterator();
5617     while ( itN->more() ) {
5618       const SMDS_MeshNode* node =
5619         static_cast<const SMDS_MeshNode*>( itN->next() );
5620       TNodeNodeMap::iterator nodeMapIt = nodeMap.find( node );
5621       if ( nodeMapIt == nodeMap.end() )
5622         break; // not all nodes transformed
5623       nodes[ i [ iNode++ ]] = (*nodeMapIt).second;
5624     }
5625     if ( iNode != nbNodes )
5626       continue; // not all nodes transformed
5627
5628     if ( theTargetMesh ) {
5629       if ( SMDS_MeshElement* copy =
5630            targetMeshEditor.AddElement( nodes, elem->GetType(), elem->IsPoly() )) {
5631         myLastCreatedElems.Append( copy );
5632         srcElems.Append( elem );
5633       }
5634     }
5635     else if ( theCopy ) {
5636       if ( AddElement( nodes, elem->GetType(), elem->IsPoly() ))
5637         srcElems.Append( elem );
5638     }
5639     else {
5640       // reverse element as it was reversed by transformation
5641       if ( nbNodes > 2 )
5642         aMesh->ChangeElementNodes( elem, &nodes[0], nbNodes );
5643     }
5644   }
5645
5646   PGroupIDs newGroupIDs;
5647
5648   if ( theMakeGroups && theCopy ||
5649        theMakeGroups && theTargetMesh )
5650     newGroupIDs = generateGroups( srcNodes, srcElems, groupPostfix, theTargetMesh );
5651
5652   return newGroupIDs;
5653 }
5654
5655
5656 ////=======================================================================
5657 ////function : Scale
5658 ////purpose  :
5659 ////=======================================================================
5660 //
5661 //SMESH_MeshEditor::PGroupIDs
5662 //SMESH_MeshEditor::Scale (TIDSortedElemSet & theElems,
5663 //                         const gp_Pnt&            thePoint,
5664 //                         const std::list<double>& theScaleFact,
5665 //                         const bool         theCopy,
5666 //                         const bool         theMakeGroups,
5667 //                         SMESH_Mesh*        theTargetMesh)
5668 //{
5669 //  MESSAGE("Scale");
5670 //  myLastCreatedElems.Clear();
5671 //  myLastCreatedNodes.Clear();
5672 //
5673 //  SMESH_MeshEditor targetMeshEditor( theTargetMesh );
5674 //  SMESHDS_Mesh* aTgtMesh = theTargetMesh ? theTargetMesh->GetMeshDS() : 0;
5675 //  SMESHDS_Mesh* aMesh    = GetMeshDS();
5676 //
5677 //  double scaleX=1.0, scaleY=1.0, scaleZ=1.0;
5678 //  std::list<double>::const_iterator itS = theScaleFact.begin();
5679 //  scaleX = (*itS);
5680 //  if(theScaleFact.size()==1) {
5681 //    scaleY = (*itS);
5682 //    scaleZ= (*itS);
5683 //  }
5684 //  if(theScaleFact.size()==2) {
5685 //    itS++;
5686 //    scaleY = (*itS);
5687 //    scaleZ= (*itS);
5688 //  }
5689 //  if(theScaleFact.size()>2) {
5690 //    itS++;
5691 //    scaleY = (*itS);
5692 //    itS++;
5693 //    scaleZ= (*itS);
5694 //  }
5695 //
5696 //  // map old node to new one
5697 //  TNodeNodeMap nodeMap;
5698 //
5699 //  // elements sharing moved nodes; those of them which have all
5700 //  // nodes mirrored but are not in theElems are to be reversed
5701 //  TIDSortedElemSet inverseElemSet;
5702 //
5703 //  // source elements for each generated one
5704 //  SMESH_SequenceOfElemPtr srcElems, srcNodes;
5705 //
5706 //  // loop on theElems
5707 //  TIDSortedElemSet::iterator itElem;
5708 //  for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
5709 //    const SMDS_MeshElement* elem = *itElem;
5710 //    if ( !elem )
5711 //      continue;
5712 //
5713 //    // loop on elem nodes
5714 //    SMDS_ElemIteratorPtr itN = elem->nodesIterator();
5715 //    while ( itN->more() ) {
5716 //
5717 //      // check if a node has been already transformed
5718 //      const SMDS_MeshNode* node = cast2Node( itN->next() );
5719 //      pair<TNodeNodeMap::iterator,bool> n2n_isnew =
5720 //        nodeMap.insert( make_pair ( node, node ));
5721 //      if ( !n2n_isnew.second )
5722 //        continue;
5723 //
5724 //      //double coord[3];
5725 //      //coord[0] = node->X();
5726 //      //coord[1] = node->Y();
5727 //      //coord[2] = node->Z();
5728 //      //theTrsf.Transforms( coord[0], coord[1], coord[2] );
5729 //      double dx = (node->X() - thePoint.X()) * scaleX;
5730 //      double dy = (node->Y() - thePoint.Y()) * scaleY;
5731 //      double dz = (node->Z() - thePoint.Z()) * scaleZ;
5732 //      if ( theTargetMesh ) {
5733 //        //const SMDS_MeshNode * newNode = aTgtMesh->AddNode( coord[0], coord[1], coord[2] );
5734 //        const SMDS_MeshNode * newNode =
5735 //          aTgtMesh->AddNode( thePoint.X()+dx, thePoint.Y()+dy, thePoint.Z()+dz );
5736 //        n2n_isnew.first->second = newNode;
5737 //        myLastCreatedNodes.Append(newNode);
5738 //        srcNodes.Append( node );
5739 //      }
5740 //      else if ( theCopy ) {
5741 //        //const SMDS_MeshNode * newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
5742 //        const SMDS_MeshNode * newNode =
5743 //          aMesh->AddNode( thePoint.X()+dx, thePoint.Y()+dy, thePoint.Z()+dz );
5744 //        n2n_isnew.first->second = newNode;
5745 //        myLastCreatedNodes.Append(newNode);
5746 //        srcNodes.Append( node );
5747 //      }
5748 //      else {
5749 //        //aMesh->MoveNode( node, coord[0], coord[1], coord[2] );
5750 //        aMesh->MoveNode( node, thePoint.X()+dx, thePoint.Y()+dy, thePoint.Z()+dz );
5751 //        // node position on shape becomes invalid
5752 //        const_cast< SMDS_MeshNode* > ( node )->SetPosition
5753 //          ( SMDS_SpacePosition::originSpacePosition() );
5754 //      }
5755 //
5756 //      // keep inverse elements
5757 //      //if ( !theCopy && !theTargetMesh && needReverse ) {
5758 //      //  SMDS_ElemIteratorPtr invElemIt = node->GetInverseElementIterator();
5759 //      //  while ( invElemIt->more() ) {
5760 //      //    const SMDS_MeshElement* iel = invElemIt->next();
5761 //      //    inverseElemSet.insert( iel );
5762 //      //  }
5763 //      //}
5764 //    }
5765 //  }
5766 //
5767 //  // either create new elements or reverse mirrored ones
5768 //  //if ( !theCopy && !needReverse && !theTargetMesh )
5769 //  if ( !theCopy && !theTargetMesh )
5770 //    return PGroupIDs();
5771 //
5772 //  TIDSortedElemSet::iterator invElemIt = inverseElemSet.begin();
5773 //  for ( ; invElemIt != inverseElemSet.end(); invElemIt++ )
5774 //    theElems.insert( *invElemIt );
5775 //
5776 //  // replicate or reverse elements
5777 //
5778 //  enum {
5779 //    REV_TETRA   = 0,  //  = nbNodes - 4
5780 //    REV_PYRAMID = 1,  //  = nbNodes - 4
5781 //    REV_PENTA   = 2,  //  = nbNodes - 4
5782 //    REV_FACE    = 3,
5783 //    REV_HEXA    = 4,  //  = nbNodes - 4
5784 //    FORWARD     = 5
5785 //  };
5786 //  int index[][8] = {
5787 //    { 2, 1, 0, 3, 4, 0, 0, 0 },  // REV_TETRA
5788 //    { 2, 1, 0, 3, 4, 0, 0, 0 },  // REV_PYRAMID
5789 //    { 2, 1, 0, 5, 4, 3, 0, 0 },  // REV_PENTA
5790 //    { 2, 1, 0, 3, 0, 0, 0, 0 },  // REV_FACE
5791 //    { 2, 1, 0, 3, 6, 5, 4, 7 },  // REV_HEXA
5792 //    { 0, 1, 2, 3, 4, 5, 6, 7 }   // FORWARD
5793 //  };
5794 //
5795 //  for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ )
5796 //  {
5797 //    const SMDS_MeshElement* elem = *itElem;
5798 //    if ( !elem || elem->GetType() == SMDSAbs_Node )
5799 //      continue;
5800 //
5801 //    int nbNodes = elem->NbNodes();
5802 //    int elemType = elem->GetType();
5803 //
5804 //    if (elem->IsPoly()) {
5805 //      // Polygon or Polyhedral Volume
5806 //      switch ( elemType ) {
5807 //      case SMDSAbs_Face:
5808 //        {
5809 //          vector<const SMDS_MeshNode*> poly_nodes (nbNodes);
5810 //          int iNode = 0;
5811 //          SMDS_ElemIteratorPtr itN = elem->nodesIterator();
5812 //          while (itN->more()) {
5813 //            const SMDS_MeshNode* node =
5814 //              static_cast<const SMDS_MeshNode*>(itN->next());
5815 //            TNodeNodeMap::iterator nodeMapIt = nodeMap.find(node);
5816 //            if (nodeMapIt == nodeMap.end())
5817 //              break; // not all nodes transformed
5818 //            //if (needReverse) {
5819 //            //  // reverse mirrored faces and volumes
5820 //            //  poly_nodes[nbNodes - iNode - 1] = (*nodeMapIt).second;
5821 //            //} else {
5822 //            poly_nodes[iNode] = (*nodeMapIt).second;
5823 //            //}
5824 //            iNode++;
5825 //          }
5826 //          if ( iNode != nbNodes )
5827 //            continue; // not all nodes transformed
5828 //
5829 //          if ( theTargetMesh ) {
5830 //            myLastCreatedElems.Append(aTgtMesh->AddPolygonalFace(poly_nodes));
5831 //            srcElems.Append( elem );
5832 //          }
5833 //          else if ( theCopy ) {
5834 //            myLastCreatedElems.Append(aMesh->AddPolygonalFace(poly_nodes));
5835 //            srcElems.Append( elem );
5836 //          }
5837 //          else {
5838 //            aMesh->ChangePolygonNodes(elem, poly_nodes);
5839 //          }
5840 //        }
5841 //        break;
5842 //      case SMDSAbs_Volume:
5843 //        {
5844 //          // ATTENTION: Reversing is not yet done!!!
5845 //          const SMDS_VtkVolume* aPolyedre =
5846 //            dynamic_cast<const SMDS_VtkVolume*>( elem );
5847 //          if (!aPolyedre) {
5848 //            MESSAGE("Warning: bad volumic element");
5849 //            continue;
5850 //          }
5851 //
5852 //          vector<const SMDS_MeshNode*> poly_nodes;
5853 //          vector<int> quantities;
5854 //
5855 //          bool allTransformed = true;
5856 //          int nbFaces = aPolyedre->NbFaces();
5857 //          for (int iface = 1; iface <= nbFaces && allTransformed; iface++) {
5858 //            int nbFaceNodes = aPolyedre->NbFaceNodes(iface);
5859 //            for (int inode = 1; inode <= nbFaceNodes && allTransformed; inode++) {
5860 //              const SMDS_MeshNode* node = aPolyedre->GetFaceNode(iface, inode);
5861 //              TNodeNodeMap::iterator nodeMapIt = nodeMap.find(node);
5862 //              if (nodeMapIt == nodeMap.end()) {
5863 //                allTransformed = false; // not all nodes transformed
5864 //              } else {
5865 //                poly_nodes.push_back((*nodeMapIt).second);
5866 //              }
5867 //            }
5868 //            quantities.push_back(nbFaceNodes);
5869 //          }
5870 //          if ( !allTransformed )
5871 //            continue; // not all nodes transformed
5872 //
5873 //          if ( theTargetMesh ) {
5874 //            myLastCreatedElems.Append(aTgtMesh->AddPolyhedralVolume(poly_nodes, quantities));
5875 //            srcElems.Append( elem );
5876 //          }
5877 //          else if ( theCopy ) {
5878 //            myLastCreatedElems.Append(aMesh->AddPolyhedralVolume(poly_nodes, quantities));
5879 //            srcElems.Append( elem );
5880 //          }
5881 //          else {
5882 //            aMesh->ChangePolyhedronNodes(elem, poly_nodes, quantities);
5883 //          }
5884 //        }
5885 //        break;
5886 //      default:;
5887 //      }
5888 //      continue;
5889 //    }
5890 //
5891 //    // Regular elements
5892 //    int* i = index[ FORWARD ];
5893 //    //if ( needReverse && nbNodes > 2) // reverse mirrored faces and volumes
5894 //    //  if ( elemType == SMDSAbs_Face )
5895 //    //    i = index[ REV_FACE ];
5896 //    //  else
5897 //    //    i = index[ nbNodes - 4 ];
5898 //
5899 //    if(elem->IsQuadratic()) {
5900 //      static int anIds[] = {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19};
5901 //      i = anIds;
5902 //      //if(needReverse) {
5903 //      //  if(nbNodes==3) { // quadratic edge
5904 //      //    static int anIds[] = {1,0,2};
5905 //      //    i = anIds;
5906 //      //  }
5907 //      //  else if(nbNodes==6) { // quadratic triangle
5908 //      //    static int anIds[] = {0,2,1,5,4,3};
5909 //      //    i = anIds;
5910 //      //  }
5911 //      //  else if(nbNodes==8) { // quadratic quadrangle
5912 //      //    static int anIds[] = {0,3,2,1,7,6,5,4};
5913 //      //    i = anIds;
5914 //      //  }
5915 //      //  else if(nbNodes==10) { // quadratic tetrahedron of 10 nodes
5916 //      //    static int anIds[] = {0,2,1,3,6,5,4,7,9,8};
5917 //      //    i = anIds;
5918 //      //  }
5919 //      //  else if(nbNodes==13) { // quadratic pyramid of 13 nodes
5920 //      //    static int anIds[] = {0,3,2,1,4,8,7,6,5,9,12,11,10};
5921 //      //    i = anIds;
5922 //      //  }
5923 //      //  else if(nbNodes==15) { // quadratic pentahedron with 15 nodes
5924 //      //    static int anIds[] = {0,2,1,3,5,4,8,7,6,11,10,9,12,14,13};
5925 //      //    i = anIds;
5926 //      //  }
5927 //      //  else { // nbNodes==20 - quadratic hexahedron with 20 nodes
5928 //      //    static int anIds[] = {0,3,2,1,4,7,6,5,11,10,9,8,15,14,13,12,16,19,18,17};
5929 //      //    i = anIds;
5930 //      //  }
5931 //      //}
5932 //    }
5933 //
5934 //    // find transformed nodes
5935 //    vector<const SMDS_MeshNode*> nodes(nbNodes);
5936 //    int iNode = 0;
5937 //    SMDS_ElemIteratorPtr itN = elem->nodesIterator();
5938 //    while ( itN->more() ) {
5939 //      const SMDS_MeshNode* node =
5940 //        static_cast<const SMDS_MeshNode*>( itN->next() );
5941 //      TNodeNodeMap::iterator nodeMapIt = nodeMap.find( node );
5942 //      if ( nodeMapIt == nodeMap.end() )
5943 //        break; // not all nodes transformed
5944 //      nodes[ i [ iNode++ ]] = (*nodeMapIt).second;
5945 //    }
5946 //    if ( iNode != nbNodes )
5947 //      continue; // not all nodes transformed
5948 //
5949 //    if ( theTargetMesh ) {
5950 //      if ( SMDS_MeshElement* copy =
5951 //           targetMeshEditor.AddElement( nodes, elem->GetType(), elem->IsPoly() )) {
5952 //        myLastCreatedElems.Append( copy );
5953 //        srcElems.Append( elem );
5954 //      }
5955 //    }
5956 //    else if ( theCopy ) {
5957 //      if ( SMDS_MeshElement* copy = AddElement( nodes, elem->GetType(), elem->IsPoly() )) {
5958 //        myLastCreatedElems.Append( copy );
5959 //        srcElems.Append( elem );
5960 //      }
5961 //    }
5962 //    else {
5963 //      // reverse element as it was reversed by transformation
5964 //      if ( nbNodes > 2 )
5965 //        aMesh->ChangeElementNodes( elem, &nodes[0], nbNodes );
5966 //    }
5967 //  }
5968 //
5969 //  PGroupIDs newGroupIDs;
5970 //
5971 //  if ( theMakeGroups && theCopy ||
5972 //       theMakeGroups && theTargetMesh ) {
5973 //    string groupPostfix = "scaled";
5974 //    newGroupIDs = generateGroups( srcNodes, srcElems, groupPostfix, theTargetMesh );
5975 //  }
5976 //
5977 //  return newGroupIDs;
5978 //}
5979
5980
5981 //=======================================================================
5982 /*!
5983  * \brief Create groups of elements made during transformation
5984  * \param nodeGens - nodes making corresponding myLastCreatedNodes
5985  * \param elemGens - elements making corresponding myLastCreatedElems
5986  * \param postfix - to append to names of new groups
5987  */
5988 //=======================================================================
5989
5990 SMESH_MeshEditor::PGroupIDs
5991 SMESH_MeshEditor::generateGroups(const SMESH_SequenceOfElemPtr& nodeGens,
5992                                  const SMESH_SequenceOfElemPtr& elemGens,
5993                                  const std::string&             postfix,
5994                                  SMESH_Mesh*                    targetMesh)
5995 {
5996   PGroupIDs newGroupIDs( new list<int> );
5997   SMESH_Mesh* mesh = targetMesh ? targetMesh : GetMesh();
5998
5999   // Sort existing groups by types and collect their names
6000
6001   // to store an old group and a generated new one
6002   typedef pair< SMESHDS_GroupBase*, SMDS_MeshGroup* > TOldNewGroup;
6003   vector< list< TOldNewGroup > > groupsByType( SMDSAbs_NbElementTypes );
6004   // group names
6005   set< string > groupNames;
6006   //
6007   SMDS_MeshGroup* nullNewGroup = (SMDS_MeshGroup*) 0;
6008   SMESH_Mesh::GroupIteratorPtr groupIt = GetMesh()->GetGroups();
6009   while ( groupIt->more() ) {
6010     SMESH_Group * group = groupIt->next();
6011     if ( !group ) continue;
6012     SMESHDS_GroupBase* groupDS = group->GetGroupDS();
6013     if ( !groupDS || groupDS->IsEmpty() ) continue;
6014     groupNames.insert( group->GetName() );
6015     groupDS->SetStoreName( group->GetName() );
6016     groupsByType[ groupDS->GetType() ].push_back( make_pair( groupDS, nullNewGroup ));
6017   }
6018
6019   // Groups creation
6020
6021   // loop on nodes and elements
6022   for ( int isNodes = 0; isNodes < 2; ++isNodes )
6023   {
6024     const SMESH_SequenceOfElemPtr& gens  = isNodes ? nodeGens : elemGens;
6025     const SMESH_SequenceOfElemPtr& elems = isNodes ? myLastCreatedNodes : myLastCreatedElems;
6026     if ( gens.Length() != elems.Length() )
6027       throw SALOME_Exception(LOCALIZED("invalid args"));
6028
6029     // loop on created elements
6030     for (int iElem = 1; iElem <= elems.Length(); ++iElem )
6031     {
6032       const SMDS_MeshElement* sourceElem = gens( iElem );
6033       if ( !sourceElem ) {
6034         MESSAGE("generateGroups(): NULL source element");
6035         continue;
6036       }
6037       list< TOldNewGroup > & groupsOldNew = groupsByType[ sourceElem->GetType() ];
6038       if ( groupsOldNew.empty() ) {
6039         while ( iElem < gens.Length() && gens( iElem+1 ) == sourceElem )
6040           ++iElem; // skip all elements made by sourceElem
6041         continue;
6042       }
6043       // collect all elements made by sourceElem
6044       list< const SMDS_MeshElement* > resultElems;
6045       if ( const SMDS_MeshElement* resElem = elems( iElem ))
6046         if ( resElem != sourceElem )
6047           resultElems.push_back( resElem );
6048       while ( iElem < gens.Length() && gens( iElem+1 ) == sourceElem )
6049         if ( const SMDS_MeshElement* resElem = elems( ++iElem ))
6050           if ( resElem != sourceElem )
6051             resultElems.push_back( resElem );
6052       // do not generate element groups from node ones
6053       if ( sourceElem->GetType() == SMDSAbs_Node &&
6054            elems( iElem )->GetType() != SMDSAbs_Node )
6055         continue;
6056
6057       // add resultElems to groups made by ones the sourceElem belongs to
6058       list< TOldNewGroup >::iterator gOldNew, gLast = groupsOldNew.end();
6059       for ( gOldNew = groupsOldNew.begin(); gOldNew != gLast; ++gOldNew )
6060       {
6061         SMESHDS_GroupBase* oldGroup = gOldNew->first;
6062         if ( oldGroup->Contains( sourceElem )) // sourceElem in oldGroup
6063         {
6064           SMDS_MeshGroup* & newGroup = gOldNew->second;
6065           if ( !newGroup )// create a new group
6066           {
6067             // make a name
6068             string name = oldGroup->GetStoreName();
6069             if ( !targetMesh ) {
6070               name += "_";
6071               name += postfix;
6072               int nb = 0;
6073               while ( !groupNames.insert( name ).second ) // name exists
6074               {
6075                 if ( nb == 0 ) {
6076                   name += "_1";
6077                 }
6078                 else {
6079                   TCollection_AsciiString nbStr(nb+1);
6080                   name.resize( name.rfind('_')+1 );
6081                   name += nbStr.ToCString();
6082                 }
6083                 ++nb;
6084               }
6085             }
6086             // make a group
6087             int id;
6088             SMESH_Group* group = mesh->AddGroup( resultElems.back()->GetType(),
6089                                                  name.c_str(), id );
6090             SMESHDS_Group* groupDS = static_cast<SMESHDS_Group*>(group->GetGroupDS());
6091             newGroup = & groupDS->SMDSGroup();
6092             newGroupIDs->push_back( id );
6093           }
6094
6095           // fill in a new group
6096           list< const SMDS_MeshElement* >::iterator resLast = resultElems.end(), resElemIt;
6097           for ( resElemIt = resultElems.begin(); resElemIt != resLast; ++resElemIt )
6098             newGroup->Add( *resElemIt );
6099         }
6100       }
6101     } // loop on created elements
6102   }// loop on nodes and elements
6103
6104   return newGroupIDs;
6105 }
6106
6107 //================================================================================
6108 /*!
6109  * \brief Return list of group of nodes close to each other within theTolerance
6110  *        Search among theNodes or in the whole mesh if theNodes is empty using
6111  *        an Octree algorithm
6112  */
6113 //================================================================================
6114
6115 void SMESH_MeshEditor::FindCoincidentNodes (TIDSortedNodeSet &   theNodes,
6116                                             const double         theTolerance,
6117                                             TListOfListOfNodes & theGroupsOfNodes)
6118 {
6119   myLastCreatedElems.Clear();
6120   myLastCreatedNodes.Clear();
6121
6122   if ( theNodes.empty() )
6123   { // get all nodes in the mesh
6124     SMDS_NodeIteratorPtr nIt = GetMeshDS()->nodesIterator(/*idInceasingOrder=*/true);
6125     while ( nIt->more() )
6126       theNodes.insert( theNodes.end(),nIt->next());
6127   }
6128
6129   SMESH_OctreeNode::FindCoincidentNodes ( theNodes, &theGroupsOfNodes, theTolerance);
6130 }
6131
6132
6133 //=======================================================================
6134 /*!
6135  * \brief Implementation of search for the node closest to point
6136  */
6137 //=======================================================================
6138
6139 struct SMESH_NodeSearcherImpl: public SMESH_NodeSearcher
6140 {
6141   //---------------------------------------------------------------------
6142   /*!
6143    * \brief Constructor
6144    */
6145   SMESH_NodeSearcherImpl( const SMESHDS_Mesh* theMesh )
6146   {
6147     myMesh = ( SMESHDS_Mesh* ) theMesh;
6148
6149     TIDSortedNodeSet nodes;
6150     if ( theMesh ) {
6151       SMDS_NodeIteratorPtr nIt = theMesh->nodesIterator(/*idInceasingOrder=*/true);
6152       while ( nIt->more() )
6153         nodes.insert( nodes.end(), nIt->next() );
6154     }
6155     myOctreeNode = new SMESH_OctreeNode(nodes) ;
6156
6157     // get max size of a leaf box
6158     SMESH_OctreeNode* tree = myOctreeNode;
6159     while ( !tree->isLeaf() )
6160     {
6161       SMESH_OctreeNodeIteratorPtr cIt = tree->GetChildrenIterator();
6162       if ( cIt->more() )
6163         tree = cIt->next();
6164     }
6165     myHalfLeafSize = tree->maxSize() / 2.;
6166   }
6167
6168   //---------------------------------------------------------------------
6169   /*!
6170    * \brief Move node and update myOctreeNode accordingly
6171    */
6172   void MoveNode( const SMDS_MeshNode* node, const gp_Pnt& toPnt )
6173   {
6174     myOctreeNode->UpdateByMoveNode( node, toPnt );
6175     myMesh->MoveNode( node, toPnt.X(), toPnt.Y(), toPnt.Z() );
6176   }
6177
6178   //---------------------------------------------------------------------
6179   /*!
6180    * \brief Do it's job
6181    */
6182   const SMDS_MeshNode* FindClosestTo( const gp_Pnt& thePnt )
6183   {
6184     map<double, const SMDS_MeshNode*> dist2Nodes;
6185     myOctreeNode->NodesAround( thePnt.Coord(), dist2Nodes, myHalfLeafSize );
6186     if ( !dist2Nodes.empty() )
6187       return dist2Nodes.begin()->second;
6188     list<const SMDS_MeshNode*> nodes;
6189     //myOctreeNode->NodesAround( &tgtNode, &nodes, myHalfLeafSize );
6190
6191     double minSqDist = DBL_MAX;
6192     if ( nodes.empty() )  // get all nodes of OctreeNode's closest to thePnt
6193     {
6194       // sort leafs by their distance from thePnt
6195       typedef map< double, SMESH_OctreeNode* > TDistTreeMap;
6196       TDistTreeMap treeMap;
6197       list< SMESH_OctreeNode* > treeList;
6198       list< SMESH_OctreeNode* >::iterator trIt;
6199       treeList.push_back( myOctreeNode );
6200
6201       gp_XYZ pointNode( thePnt.X(), thePnt.Y(), thePnt.Z() );
6202       bool pointInside = myOctreeNode->isInside( pointNode, myHalfLeafSize );
6203       for ( trIt = treeList.begin(); trIt != treeList.end(); ++trIt)
6204       {
6205         SMESH_OctreeNode* tree = *trIt;
6206         if ( !tree->isLeaf() ) // put children to the queue
6207         {
6208           if ( pointInside && !tree->isInside( pointNode, myHalfLeafSize )) continue;
6209           SMESH_OctreeNodeIteratorPtr cIt = tree->GetChildrenIterator();
6210           while ( cIt->more() )
6211             treeList.push_back( cIt->next() );
6212         }
6213         else if ( tree->NbNodes() ) // put a tree to the treeMap
6214         {
6215           const Bnd_B3d& box = tree->getBox();
6216           double sqDist = thePnt.SquareDistance( 0.5 * ( box.CornerMin() + box.CornerMax() ));
6217           pair<TDistTreeMap::iterator,bool> it_in = treeMap.insert( make_pair( sqDist, tree ));
6218           if ( !it_in.second ) // not unique distance to box center
6219             treeMap.insert( it_in.first, make_pair( sqDist + 1e-13*treeMap.size(), tree ));
6220         }
6221       }
6222       // find distance after which there is no sense to check tree's
6223       double sqLimit = DBL_MAX;
6224       TDistTreeMap::iterator sqDist_tree = treeMap.begin();
6225       if ( treeMap.size() > 5 ) {
6226         SMESH_OctreeNode* closestTree = sqDist_tree->second;
6227         const Bnd_B3d& box = closestTree->getBox();
6228         double limit = sqrt( sqDist_tree->first ) + sqrt ( box.SquareExtent() );
6229         sqLimit = limit * limit;
6230       }
6231       // get all nodes from trees
6232       for ( ; sqDist_tree != treeMap.end(); ++sqDist_tree) {
6233         if ( sqDist_tree->first > sqLimit )
6234           break;
6235         SMESH_OctreeNode* tree = sqDist_tree->second;
6236         tree->NodesAround( tree->GetNodeIterator()->next(), &nodes );
6237       }
6238     }
6239     // find closest among nodes
6240     minSqDist = DBL_MAX;
6241     const SMDS_MeshNode* closestNode = 0;
6242     list<const SMDS_MeshNode*>::iterator nIt = nodes.begin();
6243     for ( ; nIt != nodes.end(); ++nIt ) {
6244       double sqDist = thePnt.SquareDistance( SMESH_MeshEditor::TNodeXYZ( *nIt ) );
6245       if ( minSqDist > sqDist ) {
6246         closestNode = *nIt;
6247         minSqDist = sqDist;
6248       }
6249     }
6250     return closestNode;
6251   }
6252
6253   //---------------------------------------------------------------------
6254   /*!
6255    * \brief Destructor
6256    */
6257   ~SMESH_NodeSearcherImpl() { delete myOctreeNode; }
6258
6259   //---------------------------------------------------------------------
6260   /*!
6261    * \brief Return the node tree
6262    */
6263   const SMESH_OctreeNode* getTree() const { return myOctreeNode; }
6264
6265 private:
6266   SMESH_OctreeNode* myOctreeNode;
6267   SMESHDS_Mesh*     myMesh;
6268   double            myHalfLeafSize; // max size of a leaf box
6269 };
6270
6271 //=======================================================================
6272 /*!
6273  * \brief Return SMESH_NodeSearcher
6274  */
6275 //=======================================================================
6276
6277 SMESH_NodeSearcher* SMESH_MeshEditor::GetNodeSearcher() 
6278 {
6279   return new SMESH_NodeSearcherImpl( GetMeshDS() );
6280 }
6281
6282 // ========================================================================
6283 namespace // Utils used in SMESH_ElementSearcherImpl::FindElementsByPoint()
6284 {
6285   const int MaxNbElemsInLeaf = 10; // maximal number of elements in a leaf of tree
6286   const int MaxLevel         = 7;  // maximal tree height -> nb terminal boxes: 8^7 = 2097152
6287   const double NodeRadius = 1e-9;  // to enlarge bnd box of element
6288
6289   //=======================================================================
6290   /*!
6291    * \brief Octal tree of bounding boxes of elements
6292    */
6293   //=======================================================================
6294
6295   class ElementBndBoxTree : public SMESH_Octree
6296   {
6297   public:
6298
6299     ElementBndBoxTree(const SMDS_Mesh& mesh, SMDSAbs_ElementType elemType, SMDS_ElemIteratorPtr theElemIt = SMDS_ElemIteratorPtr(), double tolerance = NodeRadius );
6300     void getElementsNearPoint( const gp_Pnt& point, TIDSortedElemSet& foundElems);
6301     void getElementsNearLine ( const gp_Ax1& line, TIDSortedElemSet& foundElems);
6302     ~ElementBndBoxTree();
6303
6304   protected:
6305     ElementBndBoxTree() {}
6306     SMESH_Octree* allocateOctreeChild() const { return new ElementBndBoxTree; }
6307     void buildChildrenData();
6308     Bnd_B3d* buildRootBox();
6309   private:
6310     //!< Bounding box of element
6311     struct ElementBox : public Bnd_B3d
6312     {
6313       const SMDS_MeshElement* _element;
6314       int                     _refCount; // an ElementBox can be included in several tree branches
6315       ElementBox(const SMDS_MeshElement* elem, double tolerance);
6316     };
6317     vector< ElementBox* > _elements;
6318   };
6319
6320   //================================================================================
6321   /*!
6322    * \brief ElementBndBoxTree creation
6323    */
6324   //================================================================================
6325
6326   ElementBndBoxTree::ElementBndBoxTree(const SMDS_Mesh& mesh, SMDSAbs_ElementType elemType, SMDS_ElemIteratorPtr theElemIt, double tolerance)
6327     :SMESH_Octree( new SMESH_Octree::Limit( MaxLevel, /*minSize=*/0. ))
6328   {
6329     int nbElems = mesh.GetMeshInfo().NbElements( elemType );
6330     _elements.reserve( nbElems );
6331
6332     SMDS_ElemIteratorPtr elemIt = theElemIt ? theElemIt : mesh.elementsIterator( elemType );
6333     while ( elemIt->more() )
6334       _elements.push_back( new ElementBox( elemIt->next(),tolerance  ));
6335
6336     if ( _elements.size() > MaxNbElemsInLeaf )
6337       compute();
6338     else
6339       myIsLeaf = true;
6340   }
6341
6342   //================================================================================
6343   /*!
6344    * \brief Destructor
6345    */
6346   //================================================================================
6347
6348   ElementBndBoxTree::~ElementBndBoxTree()
6349   {
6350     for ( int i = 0; i < _elements.size(); ++i )
6351       if ( --_elements[i]->_refCount <= 0 )
6352         delete _elements[i];
6353   }
6354
6355   //================================================================================
6356   /*!
6357    * \brief Return the maximal box
6358    */
6359   //================================================================================
6360
6361   Bnd_B3d* ElementBndBoxTree::buildRootBox()
6362   {
6363     Bnd_B3d* box = new Bnd_B3d;
6364     for ( int i = 0; i < _elements.size(); ++i )
6365       box->Add( *_elements[i] );
6366     return box;
6367   }
6368
6369   //================================================================================
6370   /*!
6371    * \brief Redistrubute element boxes among children
6372    */
6373   //================================================================================
6374
6375   void ElementBndBoxTree::buildChildrenData()
6376   {
6377     for ( int i = 0; i < _elements.size(); ++i )
6378     {
6379       for (int j = 0; j < 8; j++)
6380       {
6381         if ( !_elements[i]->IsOut( myChildren[j]->getBox() ))
6382         {
6383           _elements[i]->_refCount++;
6384           ((ElementBndBoxTree*)myChildren[j])->_elements.push_back( _elements[i]);
6385         }
6386       }
6387       _elements[i]->_refCount--;
6388     }
6389     _elements.clear();
6390
6391     for (int j = 0; j < 8; j++)
6392     {
6393       ElementBndBoxTree* child = static_cast<ElementBndBoxTree*>( myChildren[j]);
6394       if ( child->_elements.size() <= MaxNbElemsInLeaf )
6395         child->myIsLeaf = true;
6396
6397       if ( child->_elements.capacity() - child->_elements.size() > 1000 )
6398         child->_elements.resize( child->_elements.size() ); // compact
6399     }
6400   }
6401
6402   //================================================================================
6403   /*!
6404    * \brief Return elements which can include the point
6405    */
6406   //================================================================================
6407
6408   void ElementBndBoxTree::getElementsNearPoint( const gp_Pnt&     point,
6409                                                 TIDSortedElemSet& foundElems)
6410   {
6411     if ( level() && getBox().IsOut( point.XYZ() ))
6412       return;
6413
6414     if ( isLeaf() )
6415     {
6416       for ( int i = 0; i < _elements.size(); ++i )
6417         if ( !_elements[i]->IsOut( point.XYZ() ))
6418           foundElems.insert( _elements[i]->_element );
6419     }
6420     else
6421     {
6422       for (int i = 0; i < 8; i++)
6423         ((ElementBndBoxTree*) myChildren[i])->getElementsNearPoint( point, foundElems );
6424     }
6425   }
6426
6427   //================================================================================
6428   /*!
6429    * \brief Return elements which can be intersected by the line
6430    */
6431   //================================================================================
6432
6433   void ElementBndBoxTree::getElementsNearLine( const gp_Ax1&     line,
6434                                                TIDSortedElemSet& foundElems)
6435   {
6436     if ( level() && getBox().IsOut( line ))
6437       return;
6438
6439     if ( isLeaf() )
6440     {
6441       for ( int i = 0; i < _elements.size(); ++i )
6442         if ( !_elements[i]->IsOut( line ))
6443           foundElems.insert( _elements[i]->_element );
6444     }
6445     else
6446     {
6447       for (int i = 0; i < 8; i++)
6448         ((ElementBndBoxTree*) myChildren[i])->getElementsNearLine( line, foundElems );
6449     }
6450   }
6451
6452   //================================================================================
6453   /*!
6454    * \brief Construct the element box
6455    */
6456   //================================================================================
6457
6458   ElementBndBoxTree::ElementBox::ElementBox(const SMDS_MeshElement* elem, double tolerance)
6459   {
6460     _element  = elem;
6461     _refCount = 1;
6462     SMDS_ElemIteratorPtr nIt = elem->nodesIterator();
6463     while ( nIt->more() )
6464       Add( SMESH_MeshEditor::TNodeXYZ( cast2Node( nIt->next() )));
6465     Enlarge( tolerance );
6466   }
6467
6468 } // namespace
6469
6470 //=======================================================================
6471 /*!
6472  * \brief Implementation of search for the elements by point and
6473  *        of classification of point in 2D mesh
6474  */
6475 //=======================================================================
6476
6477 struct SMESH_ElementSearcherImpl: public SMESH_ElementSearcher
6478 {
6479   SMESHDS_Mesh*                _mesh;
6480   SMDS_ElemIteratorPtr         _meshPartIt;
6481   ElementBndBoxTree*           _ebbTree;
6482   SMESH_NodeSearcherImpl*      _nodeSearcher;
6483   SMDSAbs_ElementType          _elementType;
6484   double                       _tolerance;
6485   bool                         _outerFacesFound;
6486   set<const SMDS_MeshElement*> _outerFaces; // empty means "no internal faces at all"
6487
6488   SMESH_ElementSearcherImpl( SMESHDS_Mesh& mesh, SMDS_ElemIteratorPtr elemIt=SMDS_ElemIteratorPtr())
6489     : _mesh(&mesh),_meshPartIt(elemIt),_ebbTree(0),_nodeSearcher(0),_tolerance(-1),_outerFacesFound(false) {}
6490   ~SMESH_ElementSearcherImpl()
6491   {
6492     if ( _ebbTree )      delete _ebbTree;      _ebbTree      = 0;
6493     if ( _nodeSearcher ) delete _nodeSearcher; _nodeSearcher = 0;
6494   }
6495   virtual int FindElementsByPoint(const gp_Pnt&                      point,
6496                                   SMDSAbs_ElementType                type,
6497                                   vector< const SMDS_MeshElement* >& foundElements);
6498   virtual TopAbs_State GetPointState(const gp_Pnt& point);
6499
6500   void GetElementsNearLine( const gp_Ax1&                      line,
6501                             SMDSAbs_ElementType                type,
6502                             vector< const SMDS_MeshElement* >& foundElems);
6503   double getTolerance();
6504   bool getIntersParamOnLine(const gp_Lin& line, const SMDS_MeshElement* face,
6505                             const double tolerance, double & param);
6506   void findOuterBoundary(const SMDS_MeshElement* anyOuterFace);
6507   bool isOuterBoundary(const SMDS_MeshElement* face) const
6508   {
6509     return _outerFaces.empty() || _outerFaces.count(face);
6510   }
6511   struct TInters //!< data of intersection of the line and the mesh face (used in GetPointState())
6512   {
6513     const SMDS_MeshElement* _face;
6514     gp_Vec                  _faceNorm;
6515     bool                    _coincides; //!< the line lays in face plane
6516     TInters(const SMDS_MeshElement* face, const gp_Vec& faceNorm, bool coinc=false)
6517       : _face(face), _faceNorm( faceNorm ), _coincides( coinc ) {}
6518   };
6519   struct TFaceLink //!< link and faces sharing it (used in findOuterBoundary())
6520   {
6521     SMESH_TLink      _link;
6522     TIDSortedElemSet _faces;
6523     TFaceLink( const SMDS_MeshNode* n1, const SMDS_MeshNode* n2, const SMDS_MeshElement* face)
6524       : _link( n1, n2 ), _faces( &face, &face + 1) {}
6525   };
6526 };
6527
6528 ostream& operator<< (ostream& out, const SMESH_ElementSearcherImpl::TInters& i)
6529 {
6530   return out << "TInters(face=" << ( i._face ? i._face->GetID() : 0)
6531              << ", _coincides="<<i._coincides << ")";
6532 }
6533
6534 //=======================================================================
6535 /*!
6536  * \brief define tolerance for search
6537  */
6538 //=======================================================================
6539
6540 double SMESH_ElementSearcherImpl::getTolerance()
6541 {
6542   if ( _tolerance < 0 )
6543   {
6544     const SMDS_MeshInfo& meshInfo = _mesh->GetMeshInfo();
6545
6546     _tolerance = 0;
6547     if ( _nodeSearcher && meshInfo.NbNodes() > 1 )
6548     {
6549       double boxSize = _nodeSearcher->getTree()->maxSize();
6550       _tolerance = 1e-8 * boxSize/* / meshInfo.NbNodes()*/;
6551     }
6552     else if ( _ebbTree && meshInfo.NbElements() > 0 )
6553     {
6554       double boxSize = _ebbTree->maxSize();
6555       _tolerance = 1e-8 * boxSize/* / meshInfo.NbElements()*/;
6556     }
6557     if ( _tolerance == 0 )
6558     {
6559       // define tolerance by size of a most complex element
6560       int complexType = SMDSAbs_Volume;
6561       while ( complexType > SMDSAbs_All &&
6562               meshInfo.NbElements( SMDSAbs_ElementType( complexType )) < 1 )
6563         --complexType;
6564       if ( complexType == SMDSAbs_All ) return 0; // empty mesh
6565       double elemSize;
6566       if ( complexType == int( SMDSAbs_Node ))
6567       {
6568         SMDS_NodeIteratorPtr nodeIt = _mesh->nodesIterator();
6569         elemSize = 1;
6570         if ( meshInfo.NbNodes() > 2 )
6571           elemSize = SMESH_MeshEditor::TNodeXYZ( nodeIt->next() ).Distance( nodeIt->next() );
6572       }
6573       else
6574       {
6575         SMDS_ElemIteratorPtr elemIt =
6576             _mesh->elementsIterator( SMDSAbs_ElementType( complexType ));
6577         const SMDS_MeshElement* elem = elemIt->next();
6578         SMDS_ElemIteratorPtr nodeIt = elem->nodesIterator();
6579         SMESH_MeshEditor::TNodeXYZ n1( cast2Node( nodeIt->next() ));
6580         while ( nodeIt->more() )
6581         {
6582           double dist = n1.Distance( cast2Node( nodeIt->next() ));
6583           elemSize = max( dist, elemSize );
6584         }
6585       }
6586       _tolerance = 1e-4 * elemSize;
6587     }
6588   }
6589   return _tolerance;
6590 }
6591
6592 //================================================================================
6593 /*!
6594  * \brief Find intersection of the line and an edge of face and return parameter on line
6595  */
6596 //================================================================================
6597
6598 bool SMESH_ElementSearcherImpl::getIntersParamOnLine(const gp_Lin&           line,
6599                                                      const SMDS_MeshElement* face,
6600                                                      const double            tol,
6601                                                      double &                param)
6602 {
6603   int nbInts = 0;
6604   param = 0;
6605
6606   GeomAPI_ExtremaCurveCurve anExtCC;
6607   Handle(Geom_Curve) lineCurve = new Geom_Line( line );
6608   
6609   int nbNodes = face->IsQuadratic() ? face->NbNodes()/2 : face->NbNodes();
6610   for ( int i = 0; i < nbNodes && nbInts < 2; ++i )
6611   {
6612     GC_MakeSegment edge( SMESH_MeshEditor::TNodeXYZ( face->GetNode( i )),
6613                          SMESH_MeshEditor::TNodeXYZ( face->GetNode( (i+1)%nbNodes) )); 
6614     anExtCC.Init( lineCurve, edge);
6615     if ( anExtCC.NbExtrema() > 0 && anExtCC.LowerDistance() <= tol)
6616     {
6617       Quantity_Parameter pl, pe;
6618       anExtCC.LowerDistanceParameters( pl, pe );
6619       param += pl;
6620       if ( ++nbInts == 2 )
6621         break;
6622     }
6623   }
6624   if ( nbInts > 0 ) param /= nbInts;
6625   return nbInts > 0;
6626 }
6627 //================================================================================
6628 /*!
6629  * \brief Find all faces belonging to the outer boundary of mesh
6630  */
6631 //================================================================================
6632
6633 void SMESH_ElementSearcherImpl::findOuterBoundary(const SMDS_MeshElement* outerFace)
6634 {
6635   if ( _outerFacesFound ) return;
6636
6637   // Collect all outer faces by passing from one outer face to another via their links
6638   // and BTW find out if there are internal faces at all.
6639
6640   // checked links and links where outer boundary meets internal one
6641   set< SMESH_TLink > visitedLinks, seamLinks;
6642
6643   // links to treat with already visited faces sharing them
6644   list < TFaceLink > startLinks;
6645
6646   // load startLinks with the first outerFace
6647   startLinks.push_back( TFaceLink( outerFace->GetNode(0), outerFace->GetNode(1), outerFace));
6648   _outerFaces.insert( outerFace );
6649
6650   TIDSortedElemSet emptySet;
6651   while ( !startLinks.empty() )
6652   {
6653     const SMESH_TLink& link  = startLinks.front()._link;
6654     TIDSortedElemSet&  faces = startLinks.front()._faces;
6655
6656     outerFace = *faces.begin();
6657     // find other faces sharing the link
6658     const SMDS_MeshElement* f;
6659     while (( f = SMESH_MeshEditor::FindFaceInSet(link.node1(), link.node2(), emptySet, faces )))
6660       faces.insert( f );
6661
6662     // select another outer face among the found 
6663     const SMDS_MeshElement* outerFace2 = 0;
6664     if ( faces.size() == 2 )
6665     {
6666       outerFace2 = (outerFace == *faces.begin() ? *faces.rbegin() : *faces.begin());
6667     }
6668     else if ( faces.size() > 2 )
6669     {
6670       seamLinks.insert( link );
6671
6672       // link direction within the outerFace
6673       gp_Vec n1n2( SMESH_MeshEditor::TNodeXYZ( link.node1()),
6674                    SMESH_MeshEditor::TNodeXYZ( link.node2()));
6675       int i1 = outerFace->GetNodeIndex( link.node1() );
6676       int i2 = outerFace->GetNodeIndex( link.node2() );
6677       bool rev = ( abs(i2-i1) == 1 ? i1 > i2 : i2 > i1 );
6678       if ( rev ) n1n2.Reverse();
6679       // outerFace normal
6680       gp_XYZ ofNorm, fNorm;
6681       if ( SMESH_Algo::FaceNormal( outerFace, ofNorm, /*normalized=*/false ))
6682       {
6683         // direction from the link inside outerFace
6684         gp_Vec dirInOF = gp_Vec( ofNorm ) ^ n1n2;
6685         // sort all other faces by angle with the dirInOF
6686         map< double, const SMDS_MeshElement* > angle2Face;
6687         set< const SMDS_MeshElement*, TIDCompare >::const_iterator face = faces.begin();
6688         for ( ; face != faces.end(); ++face )
6689         {
6690           if ( !SMESH_Algo::FaceNormal( *face, fNorm, /*normalized=*/false ))
6691             continue;
6692           gp_Vec dirInF = gp_Vec( fNorm ) ^ n1n2;
6693           double angle = dirInOF.AngleWithRef( dirInF, n1n2 );
6694           if ( angle < 0 ) angle += 2*PI;
6695           angle2Face.insert( make_pair( angle, *face ));
6696         }
6697         if ( !angle2Face.empty() )
6698           outerFace2 = angle2Face.begin()->second;
6699       }
6700     }
6701     // store the found outer face and add its links to continue seaching from
6702     if ( outerFace2 )
6703     {
6704       _outerFaces.insert( outerFace );
6705       int nbNodes = outerFace2->NbNodes()/( outerFace2->IsQuadratic() ? 2 : 1 );
6706       for ( int i = 0; i < nbNodes; ++i )
6707       {
6708         SMESH_TLink link2( outerFace2->GetNode(i), outerFace2->GetNode((i+1)%nbNodes));
6709         if ( visitedLinks.insert( link2 ).second )
6710           startLinks.push_back( TFaceLink( link2.node1(), link2.node2(), outerFace2 ));
6711       }
6712     }
6713     startLinks.pop_front();
6714   }
6715   _outerFacesFound = true;
6716
6717   if ( !seamLinks.empty() )
6718   {
6719     // There are internal boundaries touching the outher one,
6720     // find all faces of internal boundaries in order to find
6721     // faces of boundaries of holes, if any.
6722     
6723   }
6724   else
6725   {
6726     _outerFaces.clear();
6727   }
6728 }
6729
6730 //=======================================================================
6731 /*!
6732  * \brief Find elements of given type where the given point is IN or ON.
6733  *        Returns nb of found elements and elements them-selves.
6734  *
6735  * 'ALL' type means elements of any type excluding nodes and 0D elements
6736  */
6737 //=======================================================================
6738
6739 int SMESH_ElementSearcherImpl::
6740 FindElementsByPoint(const gp_Pnt&                      point,
6741                     SMDSAbs_ElementType                type,
6742                     vector< const SMDS_MeshElement* >& foundElements)
6743 {
6744   foundElements.clear();
6745
6746   double tolerance = getTolerance();
6747
6748   // =================================================================================
6749   if ( type == SMDSAbs_Node || type == SMDSAbs_0DElement )
6750   {
6751     if ( !_nodeSearcher )
6752       _nodeSearcher = new SMESH_NodeSearcherImpl( _mesh );
6753
6754     const SMDS_MeshNode* closeNode = _nodeSearcher->FindClosestTo( point );
6755     if ( !closeNode ) return foundElements.size();
6756
6757     if ( point.Distance( SMESH_MeshEditor::TNodeXYZ( closeNode )) > tolerance )
6758       return foundElements.size(); // to far from any node
6759
6760     if ( type == SMDSAbs_Node )
6761     {
6762       foundElements.push_back( closeNode );
6763     }
6764     else
6765     {
6766       SMDS_ElemIteratorPtr elemIt = closeNode->GetInverseElementIterator( SMDSAbs_0DElement );
6767       while ( elemIt->more() )
6768         foundElements.push_back( elemIt->next() );
6769     }
6770   }
6771   // =================================================================================
6772   else // elements more complex than 0D
6773   {
6774     if ( !_ebbTree || _elementType != type )
6775     {
6776       if ( _ebbTree ) delete _ebbTree;
6777       _ebbTree = new ElementBndBoxTree( *_mesh, _elementType = type, _meshPartIt, tolerance );
6778     }
6779     TIDSortedElemSet suspectElems;
6780     _ebbTree->getElementsNearPoint( point, suspectElems );
6781     TIDSortedElemSet::iterator elem = suspectElems.begin();
6782     for ( ; elem != suspectElems.end(); ++elem )
6783       if ( !SMESH_MeshEditor::isOut( *elem, point, tolerance ))
6784         foundElements.push_back( *elem );
6785   }
6786   return foundElements.size();
6787 }
6788
6789 //================================================================================
6790 /*!
6791  * \brief Classify the given point in the closed 2D mesh
6792  */
6793 //================================================================================
6794
6795 TopAbs_State SMESH_ElementSearcherImpl::GetPointState(const gp_Pnt& point)
6796 {
6797   double tolerance = getTolerance();
6798   if ( !_ebbTree || _elementType != SMDSAbs_Face )
6799   {
6800     if ( _ebbTree ) delete _ebbTree;
6801     _ebbTree = new ElementBndBoxTree( *_mesh, _elementType = SMDSAbs_Face, _meshPartIt );
6802   }
6803   // Algo: analyse transition of a line starting at the point through mesh boundary;
6804   // try three lines parallel to axis of the coordinate system and perform rough
6805   // analysis. If solution is not clear perform thorough analysis.
6806
6807   const int nbAxes = 3;
6808   gp_Dir axisDir[ nbAxes ] = { gp::DX(), gp::DY(), gp::DZ() };
6809   map< double, TInters >   paramOnLine2TInters[ nbAxes ];
6810   list< TInters > tangentInters[ nbAxes ]; // of faces whose plane includes the line
6811   multimap< int, int > nbInt2Axis; // to find the simplest case
6812   for ( int axis = 0; axis < nbAxes; ++axis )
6813   {
6814     gp_Ax1 lineAxis( point, axisDir[axis]);
6815     gp_Lin line    ( lineAxis );
6816
6817     TIDSortedElemSet suspectFaces; // faces possibly intersecting the line
6818     _ebbTree->getElementsNearLine( lineAxis, suspectFaces );
6819
6820     // Intersect faces with the line
6821
6822     map< double, TInters > & u2inters = paramOnLine2TInters[ axis ];
6823     TIDSortedElemSet::iterator face = suspectFaces.begin();
6824     for ( ; face != suspectFaces.end(); ++face )
6825     {
6826       // get face plane
6827       gp_XYZ fNorm;
6828       if ( !SMESH_Algo::FaceNormal( *face, fNorm, /*normalized=*/false)) continue;
6829       gp_Pln facePlane( SMESH_MeshEditor::TNodeXYZ( (*face)->GetNode(0)), fNorm );
6830
6831       // perform intersection
6832       IntAna_IntConicQuad intersection( line, IntAna_Quadric( facePlane ));
6833       if ( !intersection.IsDone() )
6834         continue;
6835       if ( intersection.IsInQuadric() )
6836       {
6837         tangentInters[ axis ].push_back( TInters( *face, fNorm, true ));
6838       }
6839       else if ( ! intersection.IsParallel() && intersection.NbPoints() > 0 )
6840       {
6841         gp_Pnt intersectionPoint = intersection.Point(1);
6842         if ( !SMESH_MeshEditor::isOut( *face, intersectionPoint, tolerance ))
6843           u2inters.insert(make_pair( intersection.ParamOnConic(1), TInters( *face, fNorm )));
6844       }
6845     }
6846     // Analyse intersections roughly
6847
6848     int nbInter = u2inters.size();
6849     if ( nbInter == 0 )
6850       return TopAbs_OUT; 
6851
6852     double f = u2inters.begin()->first, l = u2inters.rbegin()->first;
6853     if ( nbInter == 1 ) // not closed mesh
6854       return fabs( f ) < tolerance ? TopAbs_ON : TopAbs_UNKNOWN;
6855
6856     if ( fabs( f ) < tolerance || fabs( l ) < tolerance )
6857       return TopAbs_ON;
6858
6859     if ( (f<0) == (l<0) )
6860       return TopAbs_OUT;
6861
6862     int nbIntBeforePoint = std::distance( u2inters.begin(), u2inters.lower_bound(0));
6863     int nbIntAfterPoint  = nbInter - nbIntBeforePoint;
6864     if ( nbIntBeforePoint == 1 || nbIntAfterPoint == 1 )
6865       return TopAbs_IN;
6866
6867     nbInt2Axis.insert( make_pair( min( nbIntBeforePoint, nbIntAfterPoint ), axis ));
6868
6869     if ( _outerFacesFound ) break; // pass to thorough analysis
6870
6871   } // three attempts - loop on CS axes
6872
6873   // Analyse intersections thoroughly.
6874   // We make two loops maximum, on the first one we only exclude touching intersections,
6875   // on the second, if situation is still unclear, we gather and use information on
6876   // position of faces (internal or outer). If faces position is already gathered,
6877   // we make the second loop right away.
6878
6879   for ( int hasPositionInfo = _outerFacesFound; hasPositionInfo < 2; ++hasPositionInfo )
6880   {
6881     multimap< int, int >::const_iterator nb_axis = nbInt2Axis.begin();
6882     for ( ; nb_axis != nbInt2Axis.end(); ++nb_axis )
6883     {
6884       int axis = nb_axis->second;
6885       map< double, TInters > & u2inters = paramOnLine2TInters[ axis ];
6886
6887       gp_Ax1 lineAxis( point, axisDir[axis]);
6888       gp_Lin line    ( lineAxis );
6889
6890       // add tangent intersections to u2inters
6891       double param;
6892       list< TInters >::const_iterator tgtInt = tangentInters[ axis ].begin();
6893       for ( ; tgtInt != tangentInters[ axis ].end(); ++tgtInt )
6894         if ( getIntersParamOnLine( line, tgtInt->_face, tolerance, param ))
6895           u2inters.insert(make_pair( param, *tgtInt ));
6896       tangentInters[ axis ].clear();
6897
6898       // Count intersections before and after the point excluding touching ones.
6899       // If hasPositionInfo we count intersections of outer boundary only
6900
6901       int nbIntBeforePoint = 0, nbIntAfterPoint = 0;
6902       double f = numeric_limits<double>::max(), l = -numeric_limits<double>::max();
6903       map< double, TInters >::iterator u_int1 = u2inters.begin(), u_int2 = u_int1;
6904       bool ok = ! u_int1->second._coincides;
6905       while ( ok && u_int1 != u2inters.end() )
6906       {
6907         double u = u_int1->first;
6908         bool touchingInt = false;
6909         if ( ++u_int2 != u2inters.end() )
6910         {
6911           // skip intersections at the same point (if the line passes through edge or node)
6912           int nbSamePnt = 0;
6913           while ( u_int2 != u2inters.end() && fabs( u_int2->first - u ) < tolerance )
6914           {
6915             ++nbSamePnt;
6916             ++u_int2;
6917           }
6918
6919           // skip tangent intersections
6920           int nbTgt = 0;
6921           const SMDS_MeshElement* prevFace = u_int1->second._face;
6922           while ( ok && u_int2->second._coincides )
6923           {
6924             if ( SMESH_Algo::GetCommonNodes(prevFace , u_int2->second._face).empty() )
6925               ok = false;
6926             else
6927             {
6928               nbTgt++;
6929               u_int2++;
6930               ok = ( u_int2 != u2inters.end() );
6931             }
6932           }
6933           if ( !ok ) break;
6934
6935           // skip intersections at the same point after tangent intersections
6936           if ( nbTgt > 0 )
6937           {
6938             double u2 = u_int2->first;
6939             ++u_int2;
6940             while ( u_int2 != u2inters.end() && fabs( u_int2->first - u2 ) < tolerance )
6941             {
6942               ++nbSamePnt;
6943               ++u_int2;
6944             }
6945           }
6946           // decide if we skipped a touching intersection
6947           if ( nbSamePnt + nbTgt > 0 )
6948           {
6949             double minDot = numeric_limits<double>::max(), maxDot = -numeric_limits<double>::max();
6950             map< double, TInters >::iterator u_int = u_int1;
6951             for ( ; u_int != u_int2; ++u_int )
6952             {
6953               if ( u_int->second._coincides ) continue;
6954               double dot = u_int->second._faceNorm * line.Direction();
6955               if ( dot > maxDot ) maxDot = dot;
6956               if ( dot < minDot ) minDot = dot;
6957             }
6958             touchingInt = ( minDot*maxDot < 0 );
6959           }
6960         }
6961         if ( !touchingInt )
6962         {
6963           if ( !hasPositionInfo || isOuterBoundary( u_int1->second._face ))
6964           {
6965             if ( u < 0 )
6966               ++nbIntBeforePoint;
6967             else
6968               ++nbIntAfterPoint;
6969           }
6970           if ( u < f ) f = u;
6971           if ( u > l ) l = u;
6972         }
6973
6974         u_int1 = u_int2; // to next intersection
6975
6976       } // loop on intersections with one line
6977
6978       if ( ok )
6979       {
6980         if ( fabs( f ) < tolerance || fabs( l ) < tolerance )
6981           return TopAbs_ON;
6982
6983         if ( nbIntBeforePoint == 0  || nbIntAfterPoint == 0)
6984           return TopAbs_OUT; 
6985
6986         if ( nbIntBeforePoint + nbIntAfterPoint == 1 ) // not closed mesh
6987           return fabs( f ) < tolerance ? TopAbs_ON : TopAbs_UNKNOWN;
6988
6989         if ( nbIntBeforePoint == 1 || nbIntAfterPoint == 1 )
6990           return TopAbs_IN;
6991
6992         if ( (f<0) == (l<0) )
6993           return TopAbs_OUT;
6994
6995         if ( hasPositionInfo )
6996           return nbIntBeforePoint % 2 ? TopAbs_IN : TopAbs_OUT;
6997       }
6998     } // loop on intersections of the tree lines - thorough analysis
6999
7000     if ( !hasPositionInfo )
7001     {
7002       // gather info on faces position - is face in the outer boundary or not
7003       map< double, TInters > & u2inters = paramOnLine2TInters[ 0 ];
7004       findOuterBoundary( u2inters.begin()->second._face );
7005     }
7006
7007   } // two attempts - with and w/o faces position info in the mesh
7008
7009   return TopAbs_UNKNOWN;
7010 }
7011
7012 //=======================================================================
7013 /*!
7014  * \brief Return elements possibly intersecting the line
7015  */
7016 //=======================================================================
7017
7018 void SMESH_ElementSearcherImpl::GetElementsNearLine( const gp_Ax1&                      line,
7019                                                      SMDSAbs_ElementType                type,
7020                                                      vector< const SMDS_MeshElement* >& foundElems)
7021 {
7022   if ( !_ebbTree || _elementType != type )
7023   {
7024     if ( _ebbTree ) delete _ebbTree;
7025     _ebbTree = new ElementBndBoxTree( *_mesh, _elementType = type, _meshPartIt );
7026   }
7027   TIDSortedElemSet suspectFaces; // elements possibly intersecting the line
7028   _ebbTree->getElementsNearLine( line, suspectFaces );
7029   foundElems.assign( suspectFaces.begin(), suspectFaces.end());
7030 }
7031
7032 //=======================================================================
7033 /*!
7034  * \brief Return SMESH_ElementSearcher
7035  */
7036 //=======================================================================
7037
7038 SMESH_ElementSearcher* SMESH_MeshEditor::GetElementSearcher()
7039 {
7040   return new SMESH_ElementSearcherImpl( *GetMeshDS() );
7041 }
7042
7043 //=======================================================================
7044 /*!
7045  * \brief Return SMESH_ElementSearcher
7046  */
7047 //=======================================================================
7048
7049 SMESH_ElementSearcher* SMESH_MeshEditor::GetElementSearcher(SMDS_ElemIteratorPtr elemIt)
7050 {
7051   return new SMESH_ElementSearcherImpl( *GetMeshDS(), elemIt );
7052 }
7053
7054 //=======================================================================
7055 /*!
7056  * \brief Return true if the point is IN or ON of the element
7057  */
7058 //=======================================================================
7059
7060 bool SMESH_MeshEditor::isOut( const SMDS_MeshElement* element, const gp_Pnt& point, double tol )
7061 {
7062   if ( element->GetType() == SMDSAbs_Volume)
7063   {
7064     return SMDS_VolumeTool( element ).IsOut( point.X(), point.Y(), point.Z(), tol );
7065   }
7066
7067   // get ordered nodes
7068
7069   vector< gp_XYZ > xyz;
7070   vector<const SMDS_MeshNode*> nodeList;
7071
7072   SMDS_ElemIteratorPtr nodeIt = element->nodesIterator();
7073   if ( element->IsQuadratic() ) {
7074     if (const SMDS_VtkFace* f=dynamic_cast<const SMDS_VtkFace*>(element))
7075       nodeIt = f->interlacedNodesElemIterator();
7076     else if (const SMDS_VtkEdge*  e =dynamic_cast<const SMDS_VtkEdge*>(element))
7077       nodeIt = e->interlacedNodesElemIterator();
7078   }
7079   while ( nodeIt->more() )
7080     {
7081       const SMDS_MeshNode* node = cast2Node( nodeIt->next() );
7082       xyz.push_back( TNodeXYZ(node) );
7083       nodeList.push_back(node);
7084     }
7085
7086   int i, nbNodes = element->NbNodes();
7087
7088   if ( element->GetType() == SMDSAbs_Face ) // --------------------------------------------------
7089   {
7090     // compute face normal
7091     gp_Vec faceNorm(0,0,0);
7092     xyz.push_back( xyz.front() );
7093     nodeList.push_back( nodeList.front() );
7094     for ( i = 0; i < nbNodes; ++i )
7095     {
7096       gp_Vec edge1( xyz[i+1], xyz[i]);
7097       gp_Vec edge2( xyz[i+1], xyz[(i+2)%nbNodes] );
7098       faceNorm += edge1 ^ edge2;
7099     }
7100     double normSize = faceNorm.Magnitude();
7101     if ( normSize <= tol )
7102     {
7103       // degenerated face: point is out if it is out of all face edges
7104       for ( i = 0; i < nbNodes; ++i )
7105       {
7106         SMDS_LinearEdge edge( nodeList[i], nodeList[i+1] );
7107         if ( !isOut( &edge, point, tol ))
7108           return false;
7109       }
7110       return true;
7111     }
7112     faceNorm /= normSize;
7113
7114     // check if the point lays on face plane
7115     gp_Vec n2p( xyz[0], point );
7116     if ( fabs( n2p * faceNorm ) > tol )
7117       return true; // not on face plane
7118
7119     // check if point is out of face boundary:
7120     // define it by closest transition of a ray point->infinity through face boundary
7121     // on the face plane.
7122     // First, find normal of a plane perpendicular to face plane, to be used as a cutting tool
7123     // to find intersections of the ray with the boundary.
7124     gp_Vec ray = n2p;
7125     gp_Vec plnNorm = ray ^ faceNorm;
7126     normSize = plnNorm.Magnitude();
7127     if ( normSize <= tol ) return false; // point coincides with the first node
7128     plnNorm /= normSize;
7129     // for each node of the face, compute its signed distance to the plane
7130     vector<double> dist( nbNodes + 1);
7131     for ( i = 0; i < nbNodes; ++i )
7132     {
7133       gp_Vec n2p( xyz[i], point );
7134       dist[i] = n2p * plnNorm;
7135     }
7136     dist.back() = dist.front();
7137     // find the closest intersection
7138     int    iClosest = -1;
7139     double rClosest, distClosest = 1e100;;
7140     gp_Pnt pClosest;
7141     for ( i = 0; i < nbNodes; ++i )
7142     {
7143       double r;
7144       if ( fabs( dist[i]) < tol )
7145         r = 0.;
7146       else if ( fabs( dist[i+1]) < tol )
7147         r = 1.;
7148       else if ( dist[i] * dist[i+1] < 0 )
7149         r = dist[i] / ( dist[i] - dist[i+1] );
7150       else
7151         continue; // no intersection
7152       gp_Pnt pInt = xyz[i] * (1.-r) + xyz[i+1] * r;
7153       gp_Vec p2int ( point, pInt);
7154       if ( p2int * ray > -tol ) // right half-space
7155       {
7156         double intDist = p2int.SquareMagnitude();
7157         if ( intDist < distClosest )
7158         {
7159           iClosest = i;
7160           rClosest = r;
7161           pClosest = pInt;
7162           distClosest = intDist;
7163         }
7164       }
7165     }
7166     if ( iClosest < 0 )
7167       return true; // no intesections - out
7168
7169     // analyse transition
7170     gp_Vec edge( xyz[iClosest], xyz[iClosest+1] );
7171     gp_Vec edgeNorm = -( edge ^ faceNorm ); // normal to intersected edge pointing out of face
7172     gp_Vec p2int ( point, pClosest );
7173     bool out = (edgeNorm * p2int) < -tol;
7174     if ( rClosest > 0. && rClosest < 1. ) // not node intersection
7175       return out;
7176
7177     // ray pass through a face node; analyze transition through an adjacent edge
7178     gp_Pnt p1 = xyz[ (rClosest == 0.) ? ((iClosest+nbNodes-1) % nbNodes) : (iClosest+1) ];
7179     gp_Pnt p2 = xyz[ (rClosest == 0.) ? iClosest : ((iClosest+2) % nbNodes) ];
7180     gp_Vec edgeAdjacent( p1, p2 );
7181     gp_Vec edgeNorm2 = -( edgeAdjacent ^ faceNorm );
7182     bool out2 = (edgeNorm2 * p2int) < -tol;
7183
7184     bool covexCorner = ( edgeNorm * edgeAdjacent * (rClosest==1. ? 1. : -1.)) < 0;
7185     return covexCorner ? (out || out2) : (out && out2);
7186   }
7187   if ( element->GetType() == SMDSAbs_Edge ) // --------------------------------------------------
7188   {
7189     // point is out of edge if it is NOT ON any straight part of edge
7190     // (we consider quadratic edge as being composed of two straight parts)
7191     for ( i = 1; i < nbNodes; ++i )
7192     {
7193       gp_Vec edge( xyz[i-1], xyz[i]);
7194       gp_Vec n1p ( xyz[i-1], point);
7195       double dist = ( edge ^ n1p ).Magnitude() / edge.Magnitude();
7196       if ( dist > tol )
7197         continue;
7198       gp_Vec n2p( xyz[i], point );
7199       if ( fabs( edge.Magnitude() - n1p.Magnitude() - n2p.Magnitude()) > tol )
7200         continue;
7201       return false; // point is ON this part
7202     }
7203     return true;
7204   }
7205   // Node or 0D element -------------------------------------------------------------------------
7206   {
7207     gp_Vec n2p ( xyz[0], point );
7208     return n2p.Magnitude() <= tol;
7209   }
7210   return true;
7211 }
7212
7213 //=======================================================================
7214 //function : SimplifyFace
7215 //purpose  :
7216 //=======================================================================
7217 int SMESH_MeshEditor::SimplifyFace (const vector<const SMDS_MeshNode *> faceNodes,
7218                                     vector<const SMDS_MeshNode *>&      poly_nodes,
7219                                     vector<int>&                        quantities) const
7220 {
7221   int nbNodes = faceNodes.size();
7222
7223   if (nbNodes < 3)
7224     return 0;
7225
7226   set<const SMDS_MeshNode*> nodeSet;
7227
7228   // get simple seq of nodes
7229   //const SMDS_MeshNode* simpleNodes[ nbNodes ];
7230   vector<const SMDS_MeshNode*> simpleNodes( nbNodes );
7231   int iSimple = 0, nbUnique = 0;
7232
7233   simpleNodes[iSimple++] = faceNodes[0];
7234   nbUnique++;
7235   for (int iCur = 1; iCur < nbNodes; iCur++) {
7236     if (faceNodes[iCur] != simpleNodes[iSimple - 1]) {
7237       simpleNodes[iSimple++] = faceNodes[iCur];
7238       if (nodeSet.insert( faceNodes[iCur] ).second)
7239         nbUnique++;
7240     }
7241   }
7242   int nbSimple = iSimple;
7243   if (simpleNodes[nbSimple - 1] == simpleNodes[0]) {
7244     nbSimple--;
7245     iSimple--;
7246   }
7247
7248   if (nbUnique < 3)
7249     return 0;
7250
7251   // separate loops
7252   int nbNew = 0;
7253   bool foundLoop = (nbSimple > nbUnique);
7254   while (foundLoop) {
7255     foundLoop = false;
7256     set<const SMDS_MeshNode*> loopSet;
7257     for (iSimple = 0; iSimple < nbSimple && !foundLoop; iSimple++) {
7258       const SMDS_MeshNode* n = simpleNodes[iSimple];
7259       if (!loopSet.insert( n ).second) {
7260         foundLoop = true;
7261
7262         // separate loop
7263         int iC = 0, curLast = iSimple;
7264         for (; iC < curLast; iC++) {
7265           if (simpleNodes[iC] == n) break;
7266         }
7267         int loopLen = curLast - iC;
7268         if (loopLen > 2) {
7269           // create sub-element
7270           nbNew++;
7271           quantities.push_back(loopLen);
7272           for (; iC < curLast; iC++) {
7273             poly_nodes.push_back(simpleNodes[iC]);
7274           }
7275         }
7276         // shift the rest nodes (place from the first loop position)
7277         for (iC = curLast + 1; iC < nbSimple; iC++) {
7278           simpleNodes[iC - loopLen] = simpleNodes[iC];
7279         }
7280         nbSimple -= loopLen;
7281         iSimple -= loopLen;
7282       }
7283     } // for (iSimple = 0; iSimple < nbSimple; iSimple++)
7284   } // while (foundLoop)
7285
7286   if (iSimple > 2) {
7287     nbNew++;
7288     quantities.push_back(iSimple);
7289     for (int i = 0; i < iSimple; i++)
7290       poly_nodes.push_back(simpleNodes[i]);
7291   }
7292
7293   return nbNew;
7294 }
7295
7296 //=======================================================================
7297 //function : MergeNodes
7298 //purpose  : In each group, the cdr of nodes are substituted by the first one
7299 //           in all elements.
7300 //=======================================================================
7301
7302 void SMESH_MeshEditor::MergeNodes (TListOfListOfNodes & theGroupsOfNodes)
7303 {
7304   MESSAGE("MergeNodes");
7305   myLastCreatedElems.Clear();
7306   myLastCreatedNodes.Clear();
7307
7308   SMESHDS_Mesh* aMesh = GetMeshDS();
7309
7310   TNodeNodeMap nodeNodeMap; // node to replace - new node
7311   set<const SMDS_MeshElement*> elems; // all elements with changed nodes
7312   list< int > rmElemIds, rmNodeIds;
7313
7314   // Fill nodeNodeMap and elems
7315
7316   TListOfListOfNodes::iterator grIt = theGroupsOfNodes.begin();
7317   for ( ; grIt != theGroupsOfNodes.end(); grIt++ ) {
7318     list<const SMDS_MeshNode*>& nodes = *grIt;
7319     list<const SMDS_MeshNode*>::iterator nIt = nodes.begin();
7320     const SMDS_MeshNode* nToKeep = *nIt;
7321     //MESSAGE("node to keep " << nToKeep->GetID());
7322     for ( ++nIt; nIt != nodes.end(); nIt++ ) {
7323       const SMDS_MeshNode* nToRemove = *nIt;
7324       nodeNodeMap.insert( TNodeNodeMap::value_type( nToRemove, nToKeep ));
7325       if ( nToRemove != nToKeep ) {
7326         //MESSAGE("  node to remove " << nToRemove->GetID());
7327         rmNodeIds.push_back( nToRemove->GetID() );
7328         AddToSameGroups( nToKeep, nToRemove, aMesh );
7329       }
7330
7331       SMDS_ElemIteratorPtr invElemIt = nToRemove->GetInverseElementIterator();
7332       while ( invElemIt->more() ) {
7333         const SMDS_MeshElement* elem = invElemIt->next();
7334         elems.insert(elem);
7335       }
7336     }
7337   }
7338   // Change element nodes or remove an element
7339
7340   set<const SMDS_MeshElement*>::iterator eIt = elems.begin();
7341   for ( ; eIt != elems.end(); eIt++ ) {
7342     const SMDS_MeshElement* elem = *eIt;
7343     //MESSAGE(" ---- inverse elem on node to remove " << elem->GetID());
7344     int nbNodes = elem->NbNodes();
7345     int aShapeId = FindShape( elem );
7346
7347     set<const SMDS_MeshNode*> nodeSet;
7348     vector< const SMDS_MeshNode*> curNodes( nbNodes ), uniqueNodes( nbNodes );
7349     int iUnique = 0, iCur = 0, nbRepl = 0;
7350     vector<int> iRepl( nbNodes );
7351
7352     // get new seq of nodes
7353     SMDS_ElemIteratorPtr itN = elem->nodesIterator();
7354     while ( itN->more() ) {
7355       const SMDS_MeshNode* n =
7356         static_cast<const SMDS_MeshNode*>( itN->next() );
7357
7358       TNodeNodeMap::iterator nnIt = nodeNodeMap.find( n );
7359       if ( nnIt != nodeNodeMap.end() ) { // n sticks
7360         n = (*nnIt).second;
7361         // BUG 0020185: begin
7362         {
7363           bool stopRecur = false;
7364           set<const SMDS_MeshNode*> nodesRecur;
7365           nodesRecur.insert(n);
7366           while (!stopRecur) {
7367             TNodeNodeMap::iterator nnIt_i = nodeNodeMap.find( n );
7368             if ( nnIt_i != nodeNodeMap.end() ) { // n sticks
7369               n = (*nnIt_i).second;
7370               if (!nodesRecur.insert(n).second) {
7371                 // error: recursive dependancy
7372                 stopRecur = true;
7373               }
7374             }
7375             else
7376               stopRecur = true;
7377           }
7378         }
7379         // BUG 0020185: end
7380         iRepl[ nbRepl++ ] = iCur;
7381       }
7382       curNodes[ iCur ] = n;
7383       bool isUnique = nodeSet.insert( n ).second;
7384       if ( isUnique )
7385         uniqueNodes[ iUnique++ ] = n;
7386       iCur++;
7387     }
7388
7389     // Analyse element topology after replacement
7390
7391     bool isOk = true;
7392     int nbUniqueNodes = nodeSet.size();
7393     //MESSAGE("nbNodes nbUniqueNodes " << nbNodes << " " << nbUniqueNodes);
7394     if ( nbNodes != nbUniqueNodes ) { // some nodes stick
7395       // Polygons and Polyhedral volumes
7396       if (elem->IsPoly()) {
7397
7398         if (elem->GetType() == SMDSAbs_Face) {
7399           // Polygon
7400           vector<const SMDS_MeshNode *> face_nodes (nbNodes);
7401           int inode = 0;
7402           for (; inode < nbNodes; inode++) {
7403             face_nodes[inode] = curNodes[inode];
7404           }
7405
7406           vector<const SMDS_MeshNode *> polygons_nodes;
7407           vector<int> quantities;
7408           int nbNew = SimplifyFace(face_nodes, polygons_nodes, quantities);
7409           if (nbNew > 0) {
7410             inode = 0;
7411             for (int iface = 0; iface < nbNew; iface++) {
7412               int nbNodes = quantities[iface];
7413               vector<const SMDS_MeshNode *> poly_nodes (nbNodes);
7414               for (int ii = 0; ii < nbNodes; ii++, inode++) {
7415                 poly_nodes[ii] = polygons_nodes[inode];
7416               }
7417               SMDS_MeshElement* newElem = aMesh->AddPolygonalFace(poly_nodes);
7418               myLastCreatedElems.Append(newElem);
7419               if (aShapeId)
7420                 aMesh->SetMeshElementOnShape(newElem, aShapeId);
7421             }
7422
7423             MESSAGE("ChangeElementNodes MergeNodes Polygon");
7424             //aMesh->ChangeElementNodes(elem, &polygons_nodes[inode], quantities[nbNew - 1]);
7425             vector<const SMDS_MeshNode *> polynodes(polygons_nodes.begin()+inode,polygons_nodes.end());
7426             int quid =0;
7427             if (nbNew > 0) quid = nbNew - 1;
7428             vector<int> newquant(quantities.begin()+quid, quantities.end());
7429             const SMDS_MeshElement* newElem = 0;
7430             newElem = aMesh->AddPolyhedralVolume(polynodes, newquant);
7431             myLastCreatedElems.Append(newElem);
7432             if ( aShapeId && newElem )
7433               aMesh->SetMeshElementOnShape( newElem, aShapeId );
7434             rmElemIds.push_back(elem->GetID());
7435           }
7436           else {
7437             rmElemIds.push_back(elem->GetID());
7438           }
7439
7440         }
7441         else if (elem->GetType() == SMDSAbs_Volume) {
7442           // Polyhedral volume
7443           if (nbUniqueNodes < 4) {
7444             rmElemIds.push_back(elem->GetID());
7445           }
7446           else {
7447             // each face has to be analyzed in order to check volume validity
7448             const SMDS_VtkVolume* aPolyedre =
7449               dynamic_cast<const SMDS_VtkVolume*>( elem );
7450             if (aPolyedre) {
7451               int nbFaces = aPolyedre->NbFaces();
7452
7453               vector<const SMDS_MeshNode *> poly_nodes;
7454               vector<int> quantities;
7455
7456               for (int iface = 1; iface <= nbFaces; iface++) {
7457                 int nbFaceNodes = aPolyedre->NbFaceNodes(iface);
7458                 vector<const SMDS_MeshNode *> faceNodes (nbFaceNodes);
7459
7460                 for (int inode = 1; inode <= nbFaceNodes; inode++) {
7461                   const SMDS_MeshNode * faceNode = aPolyedre->GetFaceNode(iface, inode);
7462                   TNodeNodeMap::iterator nnIt = nodeNodeMap.find(faceNode);
7463                   if (nnIt != nodeNodeMap.end()) { // faceNode sticks
7464                     faceNode = (*nnIt).second;
7465                   }
7466                   faceNodes[inode - 1] = faceNode;
7467                 }
7468
7469                 SimplifyFace(faceNodes, poly_nodes, quantities);
7470               }
7471
7472               if (quantities.size() > 3) {
7473                 // to be done: remove coincident faces
7474               }
7475
7476               if (quantities.size() > 3)
7477                 {
7478                   MESSAGE("ChangeElementNodes MergeNodes Polyhedron");
7479                   //aMesh->ChangePolyhedronNodes(elem, poly_nodes, quantities);
7480                   const SMDS_MeshElement* newElem = 0;
7481                   newElem = aMesh->AddPolyhedralVolume(poly_nodes, quantities);
7482                   myLastCreatedElems.Append(newElem);
7483                   if ( aShapeId && newElem )
7484                     aMesh->SetMeshElementOnShape( newElem, aShapeId );
7485                   rmElemIds.push_back(elem->GetID());
7486                 }
7487             }
7488             else {
7489               rmElemIds.push_back(elem->GetID());
7490             }
7491           }
7492         }
7493         else {
7494         }
7495
7496         continue;
7497       }
7498
7499       // Regular elements
7500       // TODO not all the possible cases are solved. Find something more generic?
7501       switch ( nbNodes ) {
7502       case 2: ///////////////////////////////////// EDGE
7503         isOk = false; break;
7504       case 3: ///////////////////////////////////// TRIANGLE
7505         isOk = false; break;
7506       case 4:
7507         if ( elem->GetType() == SMDSAbs_Volume ) // TETRAHEDRON
7508           isOk = false;
7509         else { //////////////////////////////////// QUADRANGLE
7510           if ( nbUniqueNodes < 3 )
7511             isOk = false;
7512           else if ( nbRepl == 2 && iRepl[ 1 ] - iRepl[ 0 ] == 2 )
7513             isOk = false; // opposite nodes stick
7514           //MESSAGE("isOk " << isOk);
7515         }
7516         break;
7517       case 6: ///////////////////////////////////// PENTAHEDRON
7518         if ( nbUniqueNodes == 4 ) {
7519           // ---------------------------------> tetrahedron
7520           if (nbRepl == 3 &&
7521               iRepl[ 0 ] > 2 && iRepl[ 1 ] > 2 && iRepl[ 2 ] > 2 ) {
7522             // all top nodes stick: reverse a bottom
7523             uniqueNodes[ 0 ] = curNodes [ 1 ];
7524             uniqueNodes[ 1 ] = curNodes [ 0 ];
7525           }
7526           else if (nbRepl == 3 &&
7527                    iRepl[ 0 ] < 3 && iRepl[ 1 ] < 3 && iRepl[ 2 ] < 3 ) {
7528             // all bottom nodes stick: set a top before
7529             uniqueNodes[ 3 ] = uniqueNodes [ 0 ];
7530             uniqueNodes[ 0 ] = curNodes [ 3 ];
7531             uniqueNodes[ 1 ] = curNodes [ 4 ];
7532             uniqueNodes[ 2 ] = curNodes [ 5 ];
7533           }
7534           else if (nbRepl == 4 &&
7535                    iRepl[ 2 ] - iRepl [ 0 ] == 3 && iRepl[ 3 ] - iRepl [ 1 ] == 3 ) {
7536             // a lateral face turns into a line: reverse a bottom
7537             uniqueNodes[ 0 ] = curNodes [ 1 ];
7538             uniqueNodes[ 1 ] = curNodes [ 0 ];
7539           }
7540           else
7541             isOk = false;
7542         }
7543         else if ( nbUniqueNodes == 5 ) {
7544           // PENTAHEDRON --------------------> 2 tetrahedrons
7545           if ( nbRepl == 2 && iRepl[ 1 ] - iRepl [ 0 ] == 3 ) {
7546             // a bottom node sticks with a linked top one
7547             // 1.
7548             SMDS_MeshElement* newElem =
7549               aMesh->AddVolume(curNodes[ 3 ],
7550                                curNodes[ 4 ],
7551                                curNodes[ 5 ],
7552                                curNodes[ iRepl[ 0 ] == 2 ? 1 : 2 ]);
7553             myLastCreatedElems.Append(newElem);
7554             if ( aShapeId )
7555               aMesh->SetMeshElementOnShape( newElem, aShapeId );
7556             // 2. : reverse a bottom
7557             uniqueNodes[ 0 ] = curNodes [ 1 ];
7558             uniqueNodes[ 1 ] = curNodes [ 0 ];
7559             nbUniqueNodes = 4;
7560           }
7561           else
7562             isOk = false;
7563         }
7564         else
7565           isOk = false;
7566         break;
7567       case 8: {
7568         if(elem->IsQuadratic()) { // Quadratic quadrangle
7569           //   1    5    2
7570           //    +---+---+
7571           //    |       |
7572           //    |       |
7573           //   4+       +6
7574           //    |       |
7575           //    |       |
7576           //    +---+---+
7577           //   0    7    3
7578           isOk = false;
7579           if(nbRepl==2) {
7580             MESSAGE("nbRepl=2: " << iRepl[0] << " " << iRepl[1]);
7581           }
7582           if(nbRepl==3) {
7583             MESSAGE("nbRepl=3: " << iRepl[0] << " " << iRepl[1]  << " " << iRepl[2]);
7584             nbUniqueNodes = 6;
7585             if( iRepl[0]==0 && iRepl[1]==1 && iRepl[2]==4 ) {
7586               uniqueNodes[0] = curNodes[0];
7587               uniqueNodes[1] = curNodes[2];
7588               uniqueNodes[2] = curNodes[3];
7589               uniqueNodes[3] = curNodes[5];
7590               uniqueNodes[4] = curNodes[6];
7591               uniqueNodes[5] = curNodes[7];
7592               isOk = true;
7593             }
7594             if( iRepl[0]==0 && iRepl[1]==3 && iRepl[2]==7 ) {
7595               uniqueNodes[0] = curNodes[0];
7596               uniqueNodes[1] = curNodes[1];
7597               uniqueNodes[2] = curNodes[2];
7598               uniqueNodes[3] = curNodes[4];
7599               uniqueNodes[4] = curNodes[5];
7600               uniqueNodes[5] = curNodes[6];
7601               isOk = true;
7602             }
7603             if( iRepl[0]==0 && iRepl[1]==4 && iRepl[2]==7 ) {
7604               uniqueNodes[0] = curNodes[1];
7605               uniqueNodes[1] = curNodes[2];
7606               uniqueNodes[2] = curNodes[3];
7607               uniqueNodes[3] = curNodes[5];
7608               uniqueNodes[4] = curNodes[6];
7609               uniqueNodes[5] = curNodes[0];
7610               isOk = true;
7611             }
7612             if( iRepl[0]==1 && iRepl[1]==2 && iRepl[2]==5 ) {
7613               uniqueNodes[0] = curNodes[0];
7614               uniqueNodes[1] = curNodes[1];
7615               uniqueNodes[2] = curNodes[3];
7616               uniqueNodes[3] = curNodes[4];
7617               uniqueNodes[4] = curNodes[6];
7618               uniqueNodes[5] = curNodes[7];
7619               isOk = true;
7620             }
7621             if( iRepl[0]==1 && iRepl[1]==4 && iRepl[2]==5 ) {
7622               uniqueNodes[0] = curNodes[0];
7623               uniqueNodes[1] = curNodes[2];
7624               uniqueNodes[2] = curNodes[3];
7625               uniqueNodes[3] = curNodes[1];
7626               uniqueNodes[4] = curNodes[6];
7627               uniqueNodes[5] = curNodes[7];
7628               isOk = true;
7629             }
7630             if( iRepl[0]==2 && iRepl[1]==3 && iRepl[2]==6 ) {
7631               uniqueNodes[0] = curNodes[0];
7632               uniqueNodes[1] = curNodes[1];
7633               uniqueNodes[2] = curNodes[2];
7634               uniqueNodes[3] = curNodes[4];
7635               uniqueNodes[4] = curNodes[5];
7636               uniqueNodes[5] = curNodes[7];
7637               isOk = true;
7638             }
7639             if( iRepl[0]==2 && iRepl[1]==5 && iRepl[2]==6 ) {
7640               uniqueNodes[0] = curNodes[0];
7641               uniqueNodes[1] = curNodes[1];
7642               uniqueNodes[2] = curNodes[3];
7643               uniqueNodes[3] = curNodes[4];
7644               uniqueNodes[4] = curNodes[2];
7645               uniqueNodes[5] = curNodes[7];
7646               isOk = true;
7647             }
7648             if( iRepl[0]==3 && iRepl[1]==6 && iRepl[2]==7 ) {
7649               uniqueNodes[0] = curNodes[0];
7650               uniqueNodes[1] = curNodes[1];
7651               uniqueNodes[2] = curNodes[2];
7652               uniqueNodes[3] = curNodes[4];
7653               uniqueNodes[4] = curNodes[5];
7654               uniqueNodes[5] = curNodes[3];
7655               isOk = true;
7656             }
7657           }
7658           if(nbRepl==4) {
7659             MESSAGE("nbRepl=4: " << iRepl[0] << " " << iRepl[1]  << " " << iRepl[2] << " " << iRepl[3]);
7660           }
7661           if(nbRepl==5) {
7662             MESSAGE("nbRepl=5: " << iRepl[0] << " " << iRepl[1]  << " " << iRepl[2] << " " << iRepl[3] << " " << iRepl[4]);
7663           }
7664           break;
7665         }
7666         //////////////////////////////////// HEXAHEDRON
7667         isOk = false;
7668         SMDS_VolumeTool hexa (elem);
7669         hexa.SetExternalNormal();
7670         if ( nbUniqueNodes == 4 && nbRepl == 6 ) {
7671           //////////////////////// ---> tetrahedron
7672           for ( int iFace = 0; iFace < 6; iFace++ ) {
7673             const int *ind = hexa.GetFaceNodesIndices( iFace ); // indices of face nodes
7674             if (curNodes[ind[ 0 ]] == curNodes[ind[ 1 ]] &&
7675                 curNodes[ind[ 0 ]] == curNodes[ind[ 2 ]] &&
7676                 curNodes[ind[ 0 ]] == curNodes[ind[ 3 ]] ) {
7677               // one face turns into a point ...
7678               int iOppFace = hexa.GetOppFaceIndex( iFace );
7679               ind = hexa.GetFaceNodesIndices( iOppFace );
7680               int nbStick = 0;
7681               iUnique = 2; // reverse a tetrahedron bottom
7682               for ( iCur = 0; iCur < 4 && nbStick < 2; iCur++ ) {
7683                 if ( curNodes[ind[ iCur ]] == curNodes[ind[ iCur + 1 ]] )
7684                   nbStick++;
7685                 else if ( iUnique >= 0 )
7686                   uniqueNodes[ iUnique-- ] = curNodes[ind[ iCur ]];
7687               }
7688               if ( nbStick == 1 ) {
7689                 // ... and the opposite one - into a triangle.
7690                 // set a top node
7691                 ind = hexa.GetFaceNodesIndices( iFace );
7692                 uniqueNodes[ 3 ] = curNodes[ind[ 0 ]];
7693                 isOk = true;
7694               }
7695               break;
7696             }
7697           }
7698         }
7699         else if (nbUniqueNodes == 5 && nbRepl == 4 ) {
7700           //////////////////// HEXAHEDRON ---> 2 tetrahedrons
7701           for ( int iFace = 0; iFace < 6; iFace++ ) {
7702             const int *ind = hexa.GetFaceNodesIndices( iFace ); // indices of face nodes
7703             if (curNodes[ind[ 0 ]] == curNodes[ind[ 1 ]] &&
7704                 curNodes[ind[ 0 ]] == curNodes[ind[ 2 ]] &&
7705                 curNodes[ind[ 0 ]] == curNodes[ind[ 3 ]] ) {
7706               // one face turns into a point ...
7707               int iOppFace = hexa.GetOppFaceIndex( iFace );
7708               ind = hexa.GetFaceNodesIndices( iOppFace );
7709               int nbStick = 0;
7710               iUnique = 2;  // reverse a tetrahedron 1 bottom
7711               for ( iCur = 0; iCur < 4 && nbStick == 0; iCur++ ) {
7712                 if ( curNodes[ind[ iCur ]] == curNodes[ind[ iCur + 1 ]] )
7713                   nbStick++;
7714                 else if ( iUnique >= 0 )
7715                   uniqueNodes[ iUnique-- ] = curNodes[ind[ iCur ]];
7716               }
7717               if ( nbStick == 0 ) {
7718                 // ... and the opposite one is a quadrangle
7719                 // set a top node
7720                 const int* indTop = hexa.GetFaceNodesIndices( iFace );
7721                 uniqueNodes[ 3 ] = curNodes[indTop[ 0 ]];
7722                 nbUniqueNodes = 4;
7723                 // tetrahedron 2
7724                 SMDS_MeshElement* newElem =
7725                   aMesh->AddVolume(curNodes[ind[ 0 ]],
7726                                    curNodes[ind[ 3 ]],
7727                                    curNodes[ind[ 2 ]],
7728                                    curNodes[indTop[ 0 ]]);
7729                 myLastCreatedElems.Append(newElem);
7730                 if ( aShapeId )
7731                   aMesh->SetMeshElementOnShape( newElem, aShapeId );
7732                 isOk = true;
7733               }
7734               break;
7735             }
7736           }
7737         }
7738         else if ( nbUniqueNodes == 6 && nbRepl == 4 ) {
7739           ////////////////// HEXAHEDRON ---> 2 tetrahedrons or 1 prism
7740           // find indices of quad and tri faces
7741           int iQuadFace[ 6 ], iTriFace[ 6 ], nbQuad = 0, nbTri = 0, iFace;
7742           for ( iFace = 0; iFace < 6; iFace++ ) {
7743             const int *ind = hexa.GetFaceNodesIndices( iFace ); // indices of face nodes
7744             nodeSet.clear();
7745             for ( iCur = 0; iCur < 4; iCur++ )
7746               nodeSet.insert( curNodes[ind[ iCur ]] );
7747             nbUniqueNodes = nodeSet.size();
7748             if ( nbUniqueNodes == 3 )
7749               iTriFace[ nbTri++ ] = iFace;
7750             else if ( nbUniqueNodes == 4 )
7751               iQuadFace[ nbQuad++ ] = iFace;
7752           }
7753           if (nbQuad == 2 && nbTri == 4 &&
7754               hexa.GetOppFaceIndex( iQuadFace[ 0 ] ) == iQuadFace[ 1 ]) {
7755             // 2 opposite quadrangles stuck with a diagonal;
7756             // sample groups of merged indices: (0-4)(2-6)
7757             // --------------------------------------------> 2 tetrahedrons
7758             const int *ind1 = hexa.GetFaceNodesIndices( iQuadFace[ 0 ]); // indices of quad1 nodes
7759             const int *ind2 = hexa.GetFaceNodesIndices( iQuadFace[ 1 ]);
7760             int i0, i1d, i2, i3d, i0t, i2t; // d-daigonal, t-top
7761             if (curNodes[ind1[ 0 ]] == curNodes[ind2[ 0 ]] &&
7762                 curNodes[ind1[ 2 ]] == curNodes[ind2[ 2 ]]) {
7763               // stuck with 0-2 diagonal
7764               i0  = ind1[ 3 ];
7765               i1d = ind1[ 0 ];
7766               i2  = ind1[ 1 ];
7767               i3d = ind1[ 2 ];
7768               i0t = ind2[ 1 ];
7769               i2t = ind2[ 3 ];
7770             }
7771             else if (curNodes[ind1[ 1 ]] == curNodes[ind2[ 3 ]] &&
7772                      curNodes[ind1[ 3 ]] == curNodes[ind2[ 1 ]]) {
7773               // stuck with 1-3 diagonal
7774               i0  = ind1[ 0 ];
7775               i1d = ind1[ 1 ];
7776               i2  = ind1[ 2 ];
7777               i3d = ind1[ 3 ];
7778               i0t = ind2[ 0 ];
7779               i2t = ind2[ 1 ];
7780             }
7781             else {
7782               ASSERT(0);
7783             }
7784             // tetrahedron 1
7785             uniqueNodes[ 0 ] = curNodes [ i0 ];
7786             uniqueNodes[ 1 ] = curNodes [ i1d ];
7787             uniqueNodes[ 2 ] = curNodes [ i3d ];
7788             uniqueNodes[ 3 ] = curNodes [ i0t ];
7789             nbUniqueNodes = 4;
7790             // tetrahedron 2
7791             SMDS_MeshElement* newElem = aMesh->AddVolume(curNodes[ i1d ],
7792                                                          curNodes[ i2 ],
7793                                                          curNodes[ i3d ],
7794                                                          curNodes[ i2t ]);
7795             myLastCreatedElems.Append(newElem);
7796             if ( aShapeId )
7797               aMesh->SetMeshElementOnShape( newElem, aShapeId );
7798             isOk = true;
7799           }
7800           else if (( nbTri == 2 && nbQuad == 3 ) || // merged (0-4)(1-5)
7801                    ( nbTri == 4 && nbQuad == 2 )) { // merged (7-4)(1-5)
7802             // --------------------------------------------> prism
7803             // find 2 opposite triangles
7804             nbUniqueNodes = 6;
7805             for ( iFace = 0; iFace + 1 < nbTri; iFace++ ) {
7806               if ( hexa.GetOppFaceIndex( iTriFace[ iFace ] ) == iTriFace[ iFace + 1 ]) {
7807                 // find indices of kept and replaced nodes
7808                 // and fill unique nodes of 2 opposite triangles
7809                 const int *ind1 = hexa.GetFaceNodesIndices( iTriFace[ iFace ]);
7810                 const int *ind2 = hexa.GetFaceNodesIndices( iTriFace[ iFace + 1 ]);
7811                 const SMDS_MeshNode** hexanodes = hexa.GetNodes();
7812                 // fill unique nodes
7813                 iUnique = 0;
7814                 isOk = true;
7815                 for ( iCur = 0; iCur < 4 && isOk; iCur++ ) {
7816                   const SMDS_MeshNode* n     = curNodes[ind1[ iCur ]];
7817                   const SMDS_MeshNode* nInit = hexanodes[ind1[ iCur ]];
7818                   if ( n == nInit ) {
7819                     // iCur of a linked node of the opposite face (make normals co-directed):
7820                     int iCurOpp = ( iCur == 1 || iCur == 3 ) ? 4 - iCur : iCur;
7821                     // check that correspondent corners of triangles are linked
7822                     if ( !hexa.IsLinked( ind1[ iCur ], ind2[ iCurOpp ] ))
7823                       isOk = false;
7824                     else {
7825                       uniqueNodes[ iUnique ] = n;
7826                       uniqueNodes[ iUnique + 3 ] = curNodes[ind2[ iCurOpp ]];
7827                       iUnique++;
7828                     }
7829                   }
7830                 }
7831                 break;
7832               }
7833             }
7834           }
7835         } // if ( nbUniqueNodes == 6 && nbRepl == 4 )
7836         break;
7837       } // HEXAHEDRON
7838
7839       default:
7840         isOk = false;
7841       } // switch ( nbNodes )
7842
7843     } // if ( nbNodes != nbUniqueNodes ) // some nodes stick
7844
7845     if ( isOk ) {
7846       if (elem->IsPoly() && elem->GetType() == SMDSAbs_Volume) {
7847         // Change nodes of polyedre
7848         const SMDS_VtkVolume* aPolyedre =
7849           dynamic_cast<const SMDS_VtkVolume*>( elem );
7850         if (aPolyedre) {
7851           int nbFaces = aPolyedre->NbFaces();
7852
7853           vector<const SMDS_MeshNode *> poly_nodes;
7854           vector<int> quantities (nbFaces);
7855
7856           for (int iface = 1; iface <= nbFaces; iface++) {
7857             int inode, nbFaceNodes = aPolyedre->NbFaceNodes(iface);
7858             quantities[iface - 1] = nbFaceNodes;
7859
7860             for (inode = 1; inode <= nbFaceNodes; inode++) {
7861               const SMDS_MeshNode* curNode = aPolyedre->GetFaceNode(iface, inode);
7862
7863               TNodeNodeMap::iterator nnIt = nodeNodeMap.find( curNode );
7864               if (nnIt != nodeNodeMap.end()) { // curNode sticks
7865                 curNode = (*nnIt).second;
7866               }
7867               poly_nodes.push_back(curNode);
7868             }
7869           }
7870           aMesh->ChangePolyhedronNodes( elem, poly_nodes, quantities );
7871         }
7872       }
7873       else {
7874         //int elemId = elem->GetID();
7875         //MESSAGE("Change regular element or polygon " << elemId);
7876         SMDSAbs_ElementType etyp = elem->GetType();
7877         uniqueNodes.resize(nbUniqueNodes);
7878         SMDS_MeshElement* newElem = 0;
7879         if (elem->GetEntityType() == SMDSEntity_Polygon)
7880           newElem = this->AddElement(uniqueNodes, etyp, true);
7881         else
7882           newElem = this->AddElement(uniqueNodes, etyp, false);
7883         if (newElem)
7884           {
7885             myLastCreatedElems.Append(newElem);
7886             if ( aShapeId )
7887               aMesh->SetMeshElementOnShape( newElem, aShapeId );
7888           }
7889         aMesh->RemoveElement(elem);
7890       }
7891     }
7892     else {
7893       // Remove invalid regular element or invalid polygon
7894       //MESSAGE("Remove invalid " << elem->GetID());
7895       rmElemIds.push_back( elem->GetID() );
7896     }
7897
7898   } // loop on elements
7899
7900   // Remove bad elements, then equal nodes (order important)
7901
7902   Remove( rmElemIds, false );
7903   Remove( rmNodeIds, true );
7904
7905 }
7906
7907
7908 // ========================================================
7909 // class   : SortableElement
7910 // purpose : allow sorting elements basing on their nodes
7911 // ========================================================
7912 class SortableElement : public set <const SMDS_MeshElement*>
7913 {
7914 public:
7915
7916   SortableElement( const SMDS_MeshElement* theElem )
7917   {
7918     myElem = theElem;
7919     SMDS_ElemIteratorPtr nodeIt = theElem->nodesIterator();
7920     while ( nodeIt->more() )
7921       this->insert( nodeIt->next() );
7922   }
7923
7924   const SMDS_MeshElement* Get() const
7925   { return myElem; }
7926
7927   void Set(const SMDS_MeshElement* e) const
7928   { myElem = e; }
7929
7930
7931 private:
7932   mutable const SMDS_MeshElement* myElem;
7933 };
7934
7935 //=======================================================================
7936 //function : FindEqualElements
7937 //purpose  : Return list of group of elements built on the same nodes.
7938 //           Search among theElements or in the whole mesh if theElements is empty
7939 //=======================================================================
7940 void SMESH_MeshEditor::FindEqualElements(set<const SMDS_MeshElement*> & theElements,
7941                                          TListOfListOfElementsID &      theGroupsOfElementsID)
7942 {
7943   myLastCreatedElems.Clear();
7944   myLastCreatedNodes.Clear();
7945
7946   typedef set<const SMDS_MeshElement*> TElemsSet;
7947   typedef map< SortableElement, int > TMapOfNodeSet;
7948   typedef list<int> TGroupOfElems;
7949
7950   TElemsSet elems;
7951   if ( theElements.empty() )
7952   { // get all elements in the mesh
7953     SMDS_ElemIteratorPtr eIt = GetMeshDS()->elementsIterator();
7954     while ( eIt->more() )
7955       elems.insert( elems.end(), eIt->next());
7956   }
7957   else
7958     elems = theElements;
7959
7960   vector< TGroupOfElems > arrayOfGroups;
7961   TGroupOfElems groupOfElems;
7962   TMapOfNodeSet mapOfNodeSet;
7963
7964   TElemsSet::iterator elemIt = elems.begin();
7965   for ( int i = 0, j=0; elemIt != elems.end(); ++elemIt, ++j ) {
7966     const SMDS_MeshElement* curElem = *elemIt;
7967     SortableElement SE(curElem);
7968     int ind = -1;
7969     // check uniqueness
7970     pair< TMapOfNodeSet::iterator, bool> pp = mapOfNodeSet.insert(make_pair(SE, i));
7971     if( !(pp.second) ) {
7972       TMapOfNodeSet::iterator& itSE = pp.first;
7973       ind = (*itSE).second;
7974       arrayOfGroups[ind].push_back(curElem->GetID());
7975     }
7976     else {
7977       groupOfElems.clear();
7978       groupOfElems.push_back(curElem->GetID());
7979       arrayOfGroups.push_back(groupOfElems);
7980       i++;
7981     }
7982   }
7983
7984   vector< TGroupOfElems >::iterator groupIt = arrayOfGroups.begin();
7985   for ( ; groupIt != arrayOfGroups.end(); ++groupIt ) {
7986     groupOfElems = *groupIt;
7987     if ( groupOfElems.size() > 1 ) {
7988       groupOfElems.sort();
7989       theGroupsOfElementsID.push_back(groupOfElems);
7990     }
7991   }
7992 }
7993
7994 //=======================================================================
7995 //function : MergeElements
7996 //purpose  : In each given group, substitute all elements by the first one.
7997 //=======================================================================
7998
7999 void SMESH_MeshEditor::MergeElements(TListOfListOfElementsID & theGroupsOfElementsID)
8000 {
8001   myLastCreatedElems.Clear();
8002   myLastCreatedNodes.Clear();
8003
8004   typedef list<int> TListOfIDs;
8005   TListOfIDs rmElemIds; // IDs of elems to remove
8006
8007   SMESHDS_Mesh* aMesh = GetMeshDS();
8008
8009   TListOfListOfElementsID::iterator groupsIt = theGroupsOfElementsID.begin();
8010   while ( groupsIt != theGroupsOfElementsID.end() ) {
8011     TListOfIDs& aGroupOfElemID = *groupsIt;
8012     aGroupOfElemID.sort();
8013     int elemIDToKeep = aGroupOfElemID.front();
8014     const SMDS_MeshElement* elemToKeep = aMesh->FindElement(elemIDToKeep);
8015     aGroupOfElemID.pop_front();
8016     TListOfIDs::iterator idIt = aGroupOfElemID.begin();
8017     while ( idIt != aGroupOfElemID.end() ) {
8018       int elemIDToRemove = *idIt;
8019       const SMDS_MeshElement* elemToRemove = aMesh->FindElement(elemIDToRemove);
8020       // add the kept element in groups of removed one (PAL15188)
8021       AddToSameGroups( elemToKeep, elemToRemove, aMesh );
8022       rmElemIds.push_back( elemIDToRemove );
8023       ++idIt;
8024     }
8025     ++groupsIt;
8026   }
8027
8028   Remove( rmElemIds, false );
8029 }
8030
8031 //=======================================================================
8032 //function : MergeEqualElements
8033 //purpose  : Remove all but one of elements built on the same nodes.
8034 //=======================================================================
8035
8036 void SMESH_MeshEditor::MergeEqualElements()
8037 {
8038   set<const SMDS_MeshElement*> aMeshElements; /* empty input -
8039                                                  to merge equal elements in the whole mesh */
8040   TListOfListOfElementsID aGroupsOfElementsID;
8041   FindEqualElements(aMeshElements, aGroupsOfElementsID);
8042   MergeElements(aGroupsOfElementsID);
8043 }
8044
8045 //=======================================================================
8046 //function : FindFaceInSet
8047 //purpose  : Return a face having linked nodes n1 and n2 and which is
8048 //           - not in avoidSet,
8049 //           - in elemSet provided that !elemSet.empty()
8050 //           i1 and i2 optionally returns indices of n1 and n2
8051 //=======================================================================
8052
8053 const SMDS_MeshElement*
8054 SMESH_MeshEditor::FindFaceInSet(const SMDS_MeshNode*    n1,
8055                                 const SMDS_MeshNode*    n2,
8056                                 const TIDSortedElemSet& elemSet,
8057                                 const TIDSortedElemSet& avoidSet,
8058                                 int*                    n1ind,
8059                                 int*                    n2ind)
8060
8061 {
8062   int i1, i2;
8063   const SMDS_MeshElement* face = 0;
8064
8065   SMDS_ElemIteratorPtr invElemIt = n1->GetInverseElementIterator(SMDSAbs_Face);
8066   //MESSAGE("n1->GetInverseElementIterator(SMDSAbs_Face) " << invElemIt);
8067   while ( invElemIt->more() && !face ) // loop on inverse faces of n1
8068   {
8069     //MESSAGE("in while ( invElemIt->more() && !face )");
8070     const SMDS_MeshElement* elem = invElemIt->next();
8071     if (avoidSet.count( elem ))
8072       continue;
8073     if ( !elemSet.empty() && !elemSet.count( elem ))
8074       continue;
8075     // index of n1
8076     i1 = elem->GetNodeIndex( n1 );
8077     // find a n2 linked to n1
8078     int nbN = elem->IsQuadratic() ? elem->NbNodes()/2 : elem->NbNodes();
8079     for ( int di = -1; di < 2 && !face; di += 2 )
8080     {
8081       i2 = (i1+di+nbN) % nbN;
8082       if ( elem->GetNode( i2 ) == n2 )
8083         face = elem;
8084     }
8085     if ( !face && elem->IsQuadratic())
8086     {
8087       // analysis for quadratic elements using all nodes
8088       const SMDS_VtkFace* F =
8089         dynamic_cast<const SMDS_VtkFace*>(elem);
8090       if (!F) throw SALOME_Exception(LOCALIZED("not an SMDS_VtkFace"));
8091       // use special nodes iterator
8092       SMDS_ElemIteratorPtr anIter = F->interlacedNodesElemIterator();
8093       const SMDS_MeshNode* prevN = cast2Node( anIter->next() );
8094       for ( i1 = -1, i2 = 0; anIter->more() && !face; i1++, i2++ )
8095       {
8096         const SMDS_MeshNode* n = cast2Node( anIter->next() );
8097         if ( n1 == prevN && n2 == n )
8098         {
8099           face = elem;
8100         }
8101         else if ( n2 == prevN && n1 == n )
8102         {
8103           face = elem; swap( i1, i2 );
8104         }
8105         prevN = n;
8106       }
8107     }
8108   }
8109   if ( n1ind ) *n1ind = i1;
8110   if ( n2ind ) *n2ind = i2;
8111   return face;
8112 }
8113
8114 //=======================================================================
8115 //function : findAdjacentFace
8116 //purpose  :
8117 //=======================================================================
8118
8119 static const SMDS_MeshElement* findAdjacentFace(const SMDS_MeshNode* n1,
8120                                                 const SMDS_MeshNode* n2,
8121                                                 const SMDS_MeshElement* elem)
8122 {
8123   TIDSortedElemSet elemSet, avoidSet;
8124   if ( elem )
8125     avoidSet.insert ( elem );
8126   return SMESH_MeshEditor::FindFaceInSet( n1, n2, elemSet, avoidSet );
8127 }
8128
8129 //=======================================================================
8130 //function : FindFreeBorder
8131 //purpose  :
8132 //=======================================================================
8133
8134 #define ControlFreeBorder SMESH::Controls::FreeEdges::IsFreeEdge
8135
8136 bool SMESH_MeshEditor::FindFreeBorder (const SMDS_MeshNode*             theFirstNode,
8137                                        const SMDS_MeshNode*             theSecondNode,
8138                                        const SMDS_MeshNode*             theLastNode,
8139                                        list< const SMDS_MeshNode* > &   theNodes,
8140                                        list< const SMDS_MeshElement* >& theFaces)
8141 {
8142   if ( !theFirstNode || !theSecondNode )
8143     return false;
8144   // find border face between theFirstNode and theSecondNode
8145   const SMDS_MeshElement* curElem = findAdjacentFace( theFirstNode, theSecondNode, 0 );
8146   if ( !curElem )
8147     return false;
8148
8149   theFaces.push_back( curElem );
8150   theNodes.push_back( theFirstNode );
8151   theNodes.push_back( theSecondNode );
8152
8153   //vector<const SMDS_MeshNode*> nodes;
8154   const SMDS_MeshNode *nIgnore = theFirstNode, *nStart = theSecondNode;
8155   TIDSortedElemSet foundElems;
8156   bool needTheLast = ( theLastNode != 0 );
8157
8158   while ( nStart != theLastNode ) {
8159     if ( nStart == theFirstNode )
8160       return !needTheLast;
8161
8162     // find all free border faces sharing form nStart
8163
8164     list< const SMDS_MeshElement* > curElemList;
8165     list< const SMDS_MeshNode* > nStartList;
8166     SMDS_ElemIteratorPtr invElemIt = nStart->GetInverseElementIterator(SMDSAbs_Face);
8167     while ( invElemIt->more() ) {
8168       const SMDS_MeshElement* e = invElemIt->next();
8169       if ( e == curElem || foundElems.insert( e ).second ) {
8170         // get nodes
8171         int iNode = 0, nbNodes = e->NbNodes();
8172         //const SMDS_MeshNode* nodes[nbNodes+1];
8173         vector<const SMDS_MeshNode*> nodes(nbNodes+1);
8174
8175         if(e->IsQuadratic()) {
8176           const SMDS_VtkFace* F =
8177             dynamic_cast<const SMDS_VtkFace*>(e);
8178           if (!F) throw SALOME_Exception(LOCALIZED("not an SMDS_VtkFace"));
8179           // use special nodes iterator
8180           SMDS_ElemIteratorPtr anIter = F->interlacedNodesElemIterator();
8181           while( anIter->more() ) {
8182             nodes[ iNode++ ] = cast2Node(anIter->next());
8183           }
8184         }
8185         else {
8186           SMDS_ElemIteratorPtr nIt = e->nodesIterator();
8187           while ( nIt->more() )
8188             nodes[ iNode++ ] = static_cast<const SMDS_MeshNode*>( nIt->next() );
8189         }
8190         nodes[ iNode ] = nodes[ 0 ];
8191         // check 2 links
8192         for ( iNode = 0; iNode < nbNodes; iNode++ )
8193           if (((nodes[ iNode ] == nStart && nodes[ iNode + 1] != nIgnore ) ||
8194                (nodes[ iNode + 1] == nStart && nodes[ iNode ] != nIgnore )) &&
8195               ControlFreeBorder( &nodes[ iNode ], e->GetID() ))
8196           {
8197             nStartList.push_back( nodes[ iNode + ( nodes[ iNode ] == nStart ? 1 : 0 )]);
8198             curElemList.push_back( e );
8199           }
8200       }
8201     }
8202     // analyse the found
8203
8204     int nbNewBorders = curElemList.size();
8205     if ( nbNewBorders == 0 ) {
8206       // no free border furthermore
8207       return !needTheLast;
8208     }
8209     else if ( nbNewBorders == 1 ) {
8210       // one more element found
8211       nIgnore = nStart;
8212       nStart = nStartList.front();
8213       curElem = curElemList.front();
8214       theFaces.push_back( curElem );
8215       theNodes.push_back( nStart );
8216     }
8217     else {
8218       // several continuations found
8219       list< const SMDS_MeshElement* >::iterator curElemIt;
8220       list< const SMDS_MeshNode* >::iterator nStartIt;
8221       // check if one of them reached the last node
8222       if ( needTheLast ) {
8223         for (curElemIt = curElemList.begin(), nStartIt = nStartList.begin();
8224              curElemIt!= curElemList.end();
8225              curElemIt++, nStartIt++ )
8226           if ( *nStartIt == theLastNode ) {
8227             theFaces.push_back( *curElemIt );
8228             theNodes.push_back( *nStartIt );
8229             return true;
8230           }
8231       }
8232       // find the best free border by the continuations
8233       list<const SMDS_MeshNode*>    contNodes[ 2 ], *cNL;
8234       list<const SMDS_MeshElement*> contFaces[ 2 ], *cFL;
8235       for (curElemIt = curElemList.begin(), nStartIt = nStartList.begin();
8236            curElemIt!= curElemList.end();
8237            curElemIt++, nStartIt++ )
8238       {
8239         cNL = & contNodes[ contNodes[0].empty() ? 0 : 1 ];
8240         cFL = & contFaces[ contFaces[0].empty() ? 0 : 1 ];
8241         // find one more free border
8242         if ( ! FindFreeBorder( nStart, *nStartIt, theLastNode, *cNL, *cFL )) {
8243           cNL->clear();
8244           cFL->clear();
8245         }
8246         else if ( !contNodes[0].empty() && !contNodes[1].empty() ) {
8247           // choice: clear a worse one
8248           int iLongest = ( contNodes[0].size() < contNodes[1].size() ? 1 : 0 );
8249           int iWorse = ( needTheLast ? 1 - iLongest : iLongest );
8250           contNodes[ iWorse ].clear();
8251           contFaces[ iWorse ].clear();
8252         }
8253       }
8254       if ( contNodes[0].empty() && contNodes[1].empty() )
8255         return false;
8256
8257       // append the best free border
8258       cNL = & contNodes[ contNodes[0].empty() ? 1 : 0 ];
8259       cFL = & contFaces[ contFaces[0].empty() ? 1 : 0 ];
8260       theNodes.pop_back(); // remove nIgnore
8261       theNodes.pop_back(); // remove nStart
8262       theFaces.pop_back(); // remove curElem
8263       list< const SMDS_MeshNode* >::iterator nIt = cNL->begin();
8264       list< const SMDS_MeshElement* >::iterator fIt = cFL->begin();
8265       for ( ; nIt != cNL->end(); nIt++ ) theNodes.push_back( *nIt );
8266       for ( ; fIt != cFL->end(); fIt++ ) theFaces.push_back( *fIt );
8267       return true;
8268
8269     } // several continuations found
8270   } // while ( nStart != theLastNode )
8271
8272   return true;
8273 }
8274
8275 //=======================================================================
8276 //function : CheckFreeBorderNodes
8277 //purpose  : Return true if the tree nodes are on a free border
8278 //=======================================================================
8279
8280 bool SMESH_MeshEditor::CheckFreeBorderNodes(const SMDS_MeshNode* theNode1,
8281                                             const SMDS_MeshNode* theNode2,
8282                                             const SMDS_MeshNode* theNode3)
8283 {
8284   list< const SMDS_MeshNode* > nodes;
8285   list< const SMDS_MeshElement* > faces;
8286   return FindFreeBorder( theNode1, theNode2, theNode3, nodes, faces);
8287 }
8288
8289 //=======================================================================
8290 //function : SewFreeBorder
8291 //purpose  :
8292 //=======================================================================
8293
8294 SMESH_MeshEditor::Sew_Error
8295 SMESH_MeshEditor::SewFreeBorder (const SMDS_MeshNode* theBordFirstNode,
8296                                  const SMDS_MeshNode* theBordSecondNode,
8297                                  const SMDS_MeshNode* theBordLastNode,
8298                                  const SMDS_MeshNode* theSideFirstNode,
8299                                  const SMDS_MeshNode* theSideSecondNode,
8300                                  const SMDS_MeshNode* theSideThirdNode,
8301                                  const bool           theSideIsFreeBorder,
8302                                  const bool           toCreatePolygons,
8303                                  const bool           toCreatePolyedrs)
8304 {
8305   myLastCreatedElems.Clear();
8306   myLastCreatedNodes.Clear();
8307
8308   MESSAGE("::SewFreeBorder()");
8309   Sew_Error aResult = SEW_OK;
8310
8311   // ====================================
8312   //    find side nodes and elements
8313   // ====================================
8314
8315   list< const SMDS_MeshNode* > nSide[ 2 ];
8316   list< const SMDS_MeshElement* > eSide[ 2 ];
8317   list< const SMDS_MeshNode* >::iterator nIt[ 2 ];
8318   list< const SMDS_MeshElement* >::iterator eIt[ 2 ];
8319
8320   // Free border 1
8321   // --------------
8322   if (!FindFreeBorder(theBordFirstNode,theBordSecondNode,theBordLastNode,
8323                       nSide[0], eSide[0])) {
8324     MESSAGE(" Free Border 1 not found " );
8325     aResult = SEW_BORDER1_NOT_FOUND;
8326   }
8327   if (theSideIsFreeBorder) {
8328     // Free border 2
8329     // --------------
8330     if (!FindFreeBorder(theSideFirstNode, theSideSecondNode, theSideThirdNode,
8331                         nSide[1], eSide[1])) {
8332       MESSAGE(" Free Border 2 not found " );
8333       aResult = ( aResult != SEW_OK ? SEW_BOTH_BORDERS_NOT_FOUND : SEW_BORDER2_NOT_FOUND );
8334     }
8335   }
8336   if ( aResult != SEW_OK )
8337     return aResult;
8338
8339   if (!theSideIsFreeBorder) {
8340     // Side 2
8341     // --------------
8342
8343     // -------------------------------------------------------------------------
8344     // Algo:
8345     // 1. If nodes to merge are not coincident, move nodes of the free border
8346     //    from the coord sys defined by the direction from the first to last
8347     //    nodes of the border to the correspondent sys of the side 2
8348     // 2. On the side 2, find the links most co-directed with the correspondent
8349     //    links of the free border
8350     // -------------------------------------------------------------------------
8351
8352     // 1. Since sewing may break if there are volumes to split on the side 2,
8353     //    we wont move nodes but just compute new coordinates for them
8354     typedef map<const SMDS_MeshNode*, gp_XYZ> TNodeXYZMap;
8355     TNodeXYZMap nBordXYZ;
8356     list< const SMDS_MeshNode* >& bordNodes = nSide[ 0 ];
8357     list< const SMDS_MeshNode* >::iterator nBordIt;
8358
8359     gp_XYZ Pb1( theBordFirstNode->X(), theBordFirstNode->Y(), theBordFirstNode->Z() );
8360     gp_XYZ Pb2( theBordLastNode->X(), theBordLastNode->Y(), theBordLastNode->Z() );
8361     gp_XYZ Ps1( theSideFirstNode->X(), theSideFirstNode->Y(), theSideFirstNode->Z() );
8362     gp_XYZ Ps2( theSideSecondNode->X(), theSideSecondNode->Y(), theSideSecondNode->Z() );
8363     double tol2 = 1.e-8;
8364     gp_Vec Vbs1( Pb1 - Ps1 ),Vbs2( Pb2 - Ps2 );
8365     if ( Vbs1.SquareMagnitude() > tol2 || Vbs2.SquareMagnitude() > tol2 ) {
8366       // Need node movement.
8367
8368       // find X and Z axes to create trsf
8369       gp_Vec Zb( Pb1 - Pb2 ), Zs( Ps1 - Ps2 );
8370       gp_Vec X = Zs ^ Zb;
8371       if ( X.SquareMagnitude() <= gp::Resolution() * gp::Resolution() )
8372         // Zb || Zs
8373         X = gp_Ax2( gp::Origin(), Zb ).XDirection();
8374
8375       // coord systems
8376       gp_Ax3 toBordAx( Pb1, Zb, X );
8377       gp_Ax3 fromSideAx( Ps1, Zs, X );
8378       gp_Ax3 toGlobalAx( gp::Origin(), gp::DZ(), gp::DX() );
8379       // set trsf
8380       gp_Trsf toBordSys, fromSide2Sys;
8381       toBordSys.SetTransformation( toBordAx );
8382       fromSide2Sys.SetTransformation( fromSideAx, toGlobalAx );
8383       fromSide2Sys.SetScaleFactor( Zs.Magnitude() / Zb.Magnitude() );
8384
8385       // move
8386       for ( nBordIt = bordNodes.begin(); nBordIt != bordNodes.end(); nBordIt++ ) {
8387         const SMDS_MeshNode* n = *nBordIt;
8388         gp_XYZ xyz( n->X(),n->Y(),n->Z() );
8389         toBordSys.Transforms( xyz );
8390         fromSide2Sys.Transforms( xyz );
8391         nBordXYZ.insert( TNodeXYZMap::value_type( n, xyz ));
8392       }
8393     }
8394     else {
8395       // just insert nodes XYZ in the nBordXYZ map
8396       for ( nBordIt = bordNodes.begin(); nBordIt != bordNodes.end(); nBordIt++ ) {
8397         const SMDS_MeshNode* n = *nBordIt;
8398         nBordXYZ.insert( TNodeXYZMap::value_type( n, gp_XYZ( n->X(),n->Y(),n->Z() )));
8399       }
8400     }
8401
8402     // 2. On the side 2, find the links most co-directed with the correspondent
8403     //    links of the free border
8404
8405     list< const SMDS_MeshElement* >& sideElems = eSide[ 1 ];
8406     list< const SMDS_MeshNode* >& sideNodes = nSide[ 1 ];
8407     sideNodes.push_back( theSideFirstNode );
8408
8409     bool hasVolumes = false;
8410     LinkID_Gen aLinkID_Gen( GetMeshDS() );
8411     set<long> foundSideLinkIDs, checkedLinkIDs;
8412     SMDS_VolumeTool volume;
8413     //const SMDS_MeshNode* faceNodes[ 4 ];
8414
8415     const SMDS_MeshNode*    sideNode;
8416     const SMDS_MeshElement* sideElem;
8417     const SMDS_MeshNode* prevSideNode = theSideFirstNode;
8418     const SMDS_MeshNode* prevBordNode = theBordFirstNode;
8419     nBordIt = bordNodes.begin();
8420     nBordIt++;
8421     // border node position and border link direction to compare with
8422     gp_XYZ bordPos = nBordXYZ[ *nBordIt ];
8423     gp_XYZ bordDir = bordPos - nBordXYZ[ prevBordNode ];
8424     // choose next side node by link direction or by closeness to
8425     // the current border node:
8426     bool searchByDir = ( *nBordIt != theBordLastNode );
8427     do {
8428       // find the next node on the Side 2
8429       sideNode = 0;
8430       double maxDot = -DBL_MAX, minDist = DBL_MAX;
8431       long linkID;
8432       checkedLinkIDs.clear();
8433       gp_XYZ prevXYZ( prevSideNode->X(), prevSideNode->Y(), prevSideNode->Z() );
8434
8435       // loop on inverse elements of current node (prevSideNode) on the Side 2
8436       SMDS_ElemIteratorPtr invElemIt = prevSideNode->GetInverseElementIterator();
8437       while ( invElemIt->more() )
8438       {
8439         const SMDS_MeshElement* elem = invElemIt->next();
8440         // prepare data for a loop on links coming to prevSideNode, of a face or a volume
8441         int iPrevNode, iNode = 0, nbNodes = elem->NbNodes();
8442         vector< const SMDS_MeshNode* > faceNodes( nbNodes, (const SMDS_MeshNode*)0 );
8443         bool isVolume = volume.Set( elem );
8444         const SMDS_MeshNode** nodes = isVolume ? volume.GetNodes() : & faceNodes[0];
8445         if ( isVolume ) // --volume
8446           hasVolumes = true;
8447         else if ( elem->GetType()==SMDSAbs_Face ) { // --face
8448           // retrieve all face nodes and find iPrevNode - an index of the prevSideNode
8449           if(elem->IsQuadratic()) {
8450             const SMDS_VtkFace* F =
8451               dynamic_cast<const SMDS_VtkFace*>(elem);
8452             if (!F) throw SALOME_Exception(LOCALIZED("not an SMDS_VtkFace"));
8453             // use special nodes iterator
8454             SMDS_ElemIteratorPtr anIter = F->interlacedNodesElemIterator();
8455             while( anIter->more() ) {
8456               nodes[ iNode ] = cast2Node(anIter->next());
8457               if ( nodes[ iNode++ ] == prevSideNode )
8458                 iPrevNode = iNode - 1;
8459             }
8460           }
8461           else {
8462             SMDS_ElemIteratorPtr nIt = elem->nodesIterator();
8463             while ( nIt->more() ) {
8464               nodes[ iNode ] = cast2Node( nIt->next() );
8465               if ( nodes[ iNode++ ] == prevSideNode )
8466                 iPrevNode = iNode - 1;
8467             }
8468           }
8469           // there are 2 links to check
8470           nbNodes = 2;
8471         }
8472         else // --edge
8473           continue;
8474         // loop on links, to be precise, on the second node of links
8475         for ( iNode = 0; iNode < nbNodes; iNode++ ) {
8476           const SMDS_MeshNode* n = nodes[ iNode ];
8477           if ( isVolume ) {
8478             if ( !volume.IsLinked( n, prevSideNode ))
8479               continue;
8480           }
8481           else {
8482             if ( iNode ) // a node before prevSideNode
8483               n = nodes[ iPrevNode == 0 ? elem->NbNodes() - 1 : iPrevNode - 1 ];
8484             else         // a node after prevSideNode
8485               n = nodes[ iPrevNode + 1 == elem->NbNodes() ? 0 : iPrevNode + 1 ];
8486           }
8487           // check if this link was already used
8488           long iLink = aLinkID_Gen.GetLinkID( prevSideNode, n );
8489           bool isJustChecked = !checkedLinkIDs.insert( iLink ).second;
8490           if (!isJustChecked &&
8491               foundSideLinkIDs.find( iLink ) == foundSideLinkIDs.end() )
8492           {
8493             // test a link geometrically
8494             gp_XYZ nextXYZ ( n->X(), n->Y(), n->Z() );
8495             bool linkIsBetter = false;
8496             double dot = 0.0, dist = 0.0;
8497             if ( searchByDir ) { // choose most co-directed link
8498               dot = bordDir * ( nextXYZ - prevXYZ ).Normalized();
8499               linkIsBetter = ( dot > maxDot );
8500             }
8501             else { // choose link with the node closest to bordPos
8502               dist = ( nextXYZ - bordPos ).SquareModulus();
8503               linkIsBetter = ( dist < minDist );
8504             }
8505             if ( linkIsBetter ) {
8506               maxDot = dot;
8507               minDist = dist;
8508               linkID = iLink;
8509               sideNode = n;
8510               sideElem = elem;
8511             }
8512           }
8513         }
8514       } // loop on inverse elements of prevSideNode
8515
8516       if ( !sideNode ) {
8517         MESSAGE(" Cant find path by links of the Side 2 ");
8518         return SEW_BAD_SIDE_NODES;
8519       }
8520       sideNodes.push_back( sideNode );
8521       sideElems.push_back( sideElem );
8522       foundSideLinkIDs.insert ( linkID );
8523       prevSideNode = sideNode;
8524
8525       if ( *nBordIt == theBordLastNode )
8526         searchByDir = false;
8527       else {
8528         // find the next border link to compare with
8529         gp_XYZ sidePos( sideNode->X(), sideNode->Y(), sideNode->Z() );
8530         searchByDir = ( bordDir * ( sidePos - bordPos ) <= 0 );
8531         // move to next border node if sideNode is before forward border node (bordPos)
8532         while ( *nBordIt != theBordLastNode && !searchByDir ) {
8533           prevBordNode = *nBordIt;
8534           nBordIt++;
8535           bordPos = nBordXYZ[ *nBordIt ];
8536           bordDir = bordPos - nBordXYZ[ prevBordNode ];
8537           searchByDir = ( bordDir * ( sidePos - bordPos ) <= 0 );
8538         }
8539       }
8540     }
8541     while ( sideNode != theSideSecondNode );
8542
8543     if ( hasVolumes && sideNodes.size () != bordNodes.size() && !toCreatePolyedrs) {
8544       MESSAGE("VOLUME SPLITTING IS FORBIDDEN");
8545       return SEW_VOLUMES_TO_SPLIT; // volume splitting is forbidden
8546     }
8547   } // end nodes search on the side 2
8548
8549   // ============================
8550   // sew the border to the side 2
8551   // ============================
8552
8553   int nbNodes[]  = { nSide[0].size(), nSide[1].size() };
8554   int maxNbNodes = Max( nbNodes[0], nbNodes[1] );
8555
8556   TListOfListOfNodes nodeGroupsToMerge;
8557   if ( nbNodes[0] == nbNodes[1] ||
8558        ( theSideIsFreeBorder && !theSideThirdNode)) {
8559
8560     // all nodes are to be merged
8561
8562     for (nIt[0] = nSide[0].begin(), nIt[1] = nSide[1].begin();
8563          nIt[0] != nSide[0].end() && nIt[1] != nSide[1].end();
8564          nIt[0]++, nIt[1]++ )
8565     {
8566       nodeGroupsToMerge.push_back( list<const SMDS_MeshNode*>() );
8567       nodeGroupsToMerge.back().push_back( *nIt[1] ); // to keep
8568       nodeGroupsToMerge.back().push_back( *nIt[0] ); // to remove
8569     }
8570   }
8571   else {
8572
8573     // insert new nodes into the border and the side to get equal nb of segments
8574
8575     // get normalized parameters of nodes on the borders
8576     //double param[ 2 ][ maxNbNodes ];
8577     double* param[ 2 ];
8578     param[0] = new double [ maxNbNodes ];
8579     param[1] = new double [ maxNbNodes ];
8580     int iNode, iBord;
8581     for ( iBord = 0; iBord < 2; iBord++ ) { // loop on 2 borders
8582       list< const SMDS_MeshNode* >& nodes = nSide[ iBord ];
8583       list< const SMDS_MeshNode* >::iterator nIt = nodes.begin();
8584       const SMDS_MeshNode* nPrev = *nIt;
8585       double bordLength = 0;
8586       for ( iNode = 0; nIt != nodes.end(); nIt++, iNode++ ) { // loop on border nodes
8587         const SMDS_MeshNode* nCur = *nIt;
8588         gp_XYZ segment (nCur->X() - nPrev->X(),
8589                         nCur->Y() - nPrev->Y(),
8590                         nCur->Z() - nPrev->Z());
8591         double segmentLen = segment.Modulus();
8592         bordLength += segmentLen;
8593         param[ iBord ][ iNode ] = bordLength;
8594         nPrev = nCur;
8595       }
8596       // normalize within [0,1]
8597       for ( iNode = 0; iNode < nbNodes[ iBord ]; iNode++ ) {
8598         param[ iBord ][ iNode ] /= bordLength;
8599       }
8600     }
8601
8602     // loop on border segments
8603     const SMDS_MeshNode *nPrev[ 2 ] = { 0, 0 };
8604     int i[ 2 ] = { 0, 0 };
8605     nIt[0] = nSide[0].begin(); eIt[0] = eSide[0].begin();
8606     nIt[1] = nSide[1].begin(); eIt[1] = eSide[1].begin();
8607
8608     TElemOfNodeListMap insertMap;
8609     TElemOfNodeListMap::iterator insertMapIt;
8610     // insertMap is
8611     // key:   elem to insert nodes into
8612     // value: 2 nodes to insert between + nodes to be inserted
8613     do {
8614       bool next[ 2 ] = { false, false };
8615
8616       // find min adjacent segment length after sewing
8617       double nextParam = 10., prevParam = 0;
8618       for ( iBord = 0; iBord < 2; iBord++ ) { // loop on 2 borders
8619         if ( i[ iBord ] + 1 < nbNodes[ iBord ])
8620           nextParam = Min( nextParam, param[iBord][ i[iBord] + 1 ]);
8621         if ( i[ iBord ] > 0 )
8622           prevParam = Max( prevParam, param[iBord][ i[iBord] - 1 ]);
8623       }
8624       double minParam = Min( param[ 0 ][ i[0] ], param[ 1 ][ i[1] ]);
8625       double maxParam = Max( param[ 0 ][ i[0] ], param[ 1 ][ i[1] ]);
8626       double minSegLen = Min( nextParam - minParam, maxParam - prevParam );
8627
8628       // choose to insert or to merge nodes
8629       double du = param[ 1 ][ i[1] ] - param[ 0 ][ i[0] ];
8630       if ( Abs( du ) <= minSegLen * 0.2 ) {
8631         // merge
8632         // ------
8633         nodeGroupsToMerge.push_back( list<const SMDS_MeshNode*>() );
8634         const SMDS_MeshNode* n0 = *nIt[0];
8635         const SMDS_MeshNode* n1 = *nIt[1];
8636         nodeGroupsToMerge.back().push_back( n1 );
8637         nodeGroupsToMerge.back().push_back( n0 );
8638         // position of node of the border changes due to merge
8639         param[ 0 ][ i[0] ] += du;
8640         // move n1 for the sake of elem shape evaluation during insertion.
8641         // n1 will be removed by MergeNodes() anyway
8642         const_cast<SMDS_MeshNode*>( n0 )->setXYZ( n1->X(), n1->Y(), n1->Z() );
8643         next[0] = next[1] = true;
8644       }
8645       else {
8646         // insert
8647         // ------
8648         int intoBord = ( du < 0 ) ? 0 : 1;
8649         const SMDS_MeshElement* elem = *eIt[ intoBord ];
8650         const SMDS_MeshNode*    n1   = nPrev[ intoBord ];
8651         const SMDS_MeshNode*    n2   = *nIt[ intoBord ];
8652         const SMDS_MeshNode*    nIns = *nIt[ 1 - intoBord ];
8653         if ( intoBord == 1 ) {
8654           // move node of the border to be on a link of elem of the side
8655           gp_XYZ p1 (n1->X(), n1->Y(), n1->Z());
8656           gp_XYZ p2 (n2->X(), n2->Y(), n2->Z());
8657           double ratio = du / ( param[ 1 ][ i[1] ] - param[ 1 ][ i[1]-1 ]);
8658           gp_XYZ p = p2 * ( 1 - ratio ) + p1 * ratio;
8659           GetMeshDS()->MoveNode( nIns, p.X(), p.Y(), p.Z() );
8660         }
8661         insertMapIt = insertMap.find( elem );
8662         bool notFound = ( insertMapIt == insertMap.end() );
8663         bool otherLink = ( !notFound && (*insertMapIt).second.front() != n1 );
8664         if ( otherLink ) {
8665           // insert into another link of the same element:
8666           // 1. perform insertion into the other link of the elem
8667           list<const SMDS_MeshNode*> & nodeList = (*insertMapIt).second;
8668           const SMDS_MeshNode* n12 = nodeList.front(); nodeList.pop_front();
8669           const SMDS_MeshNode* n22 = nodeList.front(); nodeList.pop_front();
8670           InsertNodesIntoLink( elem, n12, n22, nodeList, toCreatePolygons );
8671           // 2. perform insertion into the link of adjacent faces
8672           while (true) {
8673             const SMDS_MeshElement* adjElem = findAdjacentFace( n12, n22, elem );
8674             if ( adjElem )
8675               InsertNodesIntoLink( adjElem, n12, n22, nodeList, toCreatePolygons );
8676             else
8677               break;
8678           }
8679           if (toCreatePolyedrs) {
8680             // perform insertion into the links of adjacent volumes
8681             UpdateVolumes(n12, n22, nodeList);
8682           }
8683           // 3. find an element appeared on n1 and n2 after the insertion
8684           insertMap.erase( elem );
8685           elem = findAdjacentFace( n1, n2, 0 );
8686         }
8687         if ( notFound || otherLink ) {
8688           // add element and nodes of the side into the insertMap
8689           insertMapIt = insertMap.insert
8690             ( TElemOfNodeListMap::value_type( elem, list<const SMDS_MeshNode*>() )).first;
8691           (*insertMapIt).second.push_back( n1 );
8692           (*insertMapIt).second.push_back( n2 );
8693         }
8694         // add node to be inserted into elem
8695         (*insertMapIt).second.push_back( nIns );
8696         next[ 1 - intoBord ] = true;
8697       }
8698
8699       // go to the next segment
8700       for ( iBord = 0; iBord < 2; iBord++ ) { // loop on 2 borders
8701         if ( next[ iBord ] ) {
8702           if ( i[ iBord ] != 0 && eIt[ iBord ] != eSide[ iBord ].end())
8703             eIt[ iBord ]++;
8704           nPrev[ iBord ] = *nIt[ iBord ];
8705           nIt[ iBord ]++; i[ iBord ]++;
8706         }
8707       }
8708     }
8709     while ( nIt[0] != nSide[0].end() && nIt[1] != nSide[1].end());
8710
8711     // perform insertion of nodes into elements
8712
8713     for (insertMapIt = insertMap.begin();
8714          insertMapIt != insertMap.end();
8715          insertMapIt++ )
8716     {
8717       const SMDS_MeshElement* elem = (*insertMapIt).first;
8718       list<const SMDS_MeshNode*> & nodeList = (*insertMapIt).second;
8719       const SMDS_MeshNode* n1 = nodeList.front(); nodeList.pop_front();
8720       const SMDS_MeshNode* n2 = nodeList.front(); nodeList.pop_front();
8721
8722       InsertNodesIntoLink( elem, n1, n2, nodeList, toCreatePolygons );
8723
8724       if ( !theSideIsFreeBorder ) {
8725         // look for and insert nodes into the faces adjacent to elem
8726         while (true) {
8727           const SMDS_MeshElement* adjElem = findAdjacentFace( n1, n2, elem );
8728           if ( adjElem )
8729             InsertNodesIntoLink( adjElem, n1, n2, nodeList, toCreatePolygons );
8730           else
8731             break;
8732         }
8733       }
8734       if (toCreatePolyedrs) {
8735         // perform insertion into the links of adjacent volumes
8736         UpdateVolumes(n1, n2, nodeList);
8737       }
8738     }
8739
8740     delete param[0];
8741     delete param[1];
8742   } // end: insert new nodes
8743
8744   MergeNodes ( nodeGroupsToMerge );
8745
8746   return aResult;
8747 }
8748
8749 //=======================================================================
8750 //function : InsertNodesIntoLink
8751 //purpose  : insert theNodesToInsert into theFace between theBetweenNode1
8752 //           and theBetweenNode2 and split theElement
8753 //=======================================================================
8754
8755 void SMESH_MeshEditor::InsertNodesIntoLink(const SMDS_MeshElement*     theFace,
8756                                            const SMDS_MeshNode*        theBetweenNode1,
8757                                            const SMDS_MeshNode*        theBetweenNode2,
8758                                            list<const SMDS_MeshNode*>& theNodesToInsert,
8759                                            const bool                  toCreatePoly)
8760 {
8761   if ( theFace->GetType() != SMDSAbs_Face ) return;
8762
8763   // find indices of 2 link nodes and of the rest nodes
8764   int iNode = 0, il1, il2, i3, i4;
8765   il1 = il2 = i3 = i4 = -1;
8766   //const SMDS_MeshNode* nodes[ theFace->NbNodes() ];
8767   vector<const SMDS_MeshNode*> nodes( theFace->NbNodes() );
8768
8769   if(theFace->IsQuadratic()) {
8770     const SMDS_VtkFace* F =
8771       dynamic_cast<const SMDS_VtkFace*>(theFace);
8772     if (!F) throw SALOME_Exception(LOCALIZED("not an SMDS_VtkFace"));
8773     // use special nodes iterator
8774     SMDS_ElemIteratorPtr anIter = F->interlacedNodesElemIterator();
8775     while( anIter->more() ) {
8776       const SMDS_MeshNode* n = cast2Node(anIter->next());
8777       if ( n == theBetweenNode1 )
8778         il1 = iNode;
8779       else if ( n == theBetweenNode2 )
8780         il2 = iNode;
8781       else if ( i3 < 0 )
8782         i3 = iNode;
8783       else
8784         i4 = iNode;
8785       nodes[ iNode++ ] = n;
8786     }
8787   }
8788   else {
8789     SMDS_ElemIteratorPtr nodeIt = theFace->nodesIterator();
8790     while ( nodeIt->more() ) {
8791       const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
8792       if ( n == theBetweenNode1 )
8793         il1 = iNode;
8794       else if ( n == theBetweenNode2 )
8795         il2 = iNode;
8796       else if ( i3 < 0 )
8797         i3 = iNode;
8798       else
8799         i4 = iNode;
8800       nodes[ iNode++ ] = n;
8801     }
8802   }
8803   if ( il1 < 0 || il2 < 0 || i3 < 0 )
8804     return ;
8805
8806   // arrange link nodes to go one after another regarding the face orientation
8807   bool reverse = ( Abs( il2 - il1 ) == 1 ? il2 < il1 : il1 < il2 );
8808   list<const SMDS_MeshNode *> aNodesToInsert = theNodesToInsert;
8809   if ( reverse ) {
8810     iNode = il1;
8811     il1 = il2;
8812     il2 = iNode;
8813     aNodesToInsert.reverse();
8814   }
8815   // check that not link nodes of a quadrangles are in good order
8816   int nbFaceNodes = theFace->NbNodes();
8817   if ( nbFaceNodes == 4 && i4 - i3 != 1 ) {
8818     iNode = i3;
8819     i3 = i4;
8820     i4 = iNode;
8821   }
8822
8823   if (toCreatePoly || theFace->IsPoly()) {
8824
8825     iNode = 0;
8826     vector<const SMDS_MeshNode *> poly_nodes (nbFaceNodes + aNodesToInsert.size());
8827
8828     // add nodes of face up to first node of link
8829     bool isFLN = false;
8830
8831     if(theFace->IsQuadratic()) {
8832       const SMDS_VtkFace* F =
8833         dynamic_cast<const SMDS_VtkFace*>(theFace);
8834       if (!F) throw SALOME_Exception(LOCALIZED("not an SMDS_VtkFace"));
8835       // use special nodes iterator
8836       SMDS_ElemIteratorPtr anIter = F->interlacedNodesElemIterator();
8837       while( anIter->more()  && !isFLN ) {
8838         const SMDS_MeshNode* n = cast2Node(anIter->next());
8839         poly_nodes[iNode++] = n;
8840         if (n == nodes[il1]) {
8841           isFLN = true;
8842         }
8843       }
8844       // add nodes to insert
8845       list<const SMDS_MeshNode*>::iterator nIt = aNodesToInsert.begin();
8846       for (; nIt != aNodesToInsert.end(); nIt++) {
8847         poly_nodes[iNode++] = *nIt;
8848       }
8849       // add nodes of face starting from last node of link
8850       while ( anIter->more() ) {
8851         poly_nodes[iNode++] = cast2Node(anIter->next());
8852       }
8853     }
8854     else {
8855       SMDS_ElemIteratorPtr nodeIt = theFace->nodesIterator();
8856       while ( nodeIt->more() && !isFLN ) {
8857         const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
8858         poly_nodes[iNode++] = n;
8859         if (n == nodes[il1]) {
8860           isFLN = true;
8861         }
8862       }
8863       // add nodes to insert
8864       list<const SMDS_MeshNode*>::iterator nIt = aNodesToInsert.begin();
8865       for (; nIt != aNodesToInsert.end(); nIt++) {
8866         poly_nodes[iNode++] = *nIt;
8867       }
8868       // add nodes of face starting from last node of link
8869       while ( nodeIt->more() ) {
8870         const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
8871         poly_nodes[iNode++] = n;
8872       }
8873     }
8874
8875     // edit or replace the face
8876     SMESHDS_Mesh *aMesh = GetMeshDS();
8877
8878     if (theFace->IsPoly()) {
8879       aMesh->ChangePolygonNodes(theFace, poly_nodes);
8880     }
8881     else {
8882       int aShapeId = FindShape( theFace );
8883
8884       SMDS_MeshElement* newElem = aMesh->AddPolygonalFace(poly_nodes);
8885       myLastCreatedElems.Append(newElem);
8886       if ( aShapeId && newElem )
8887         aMesh->SetMeshElementOnShape( newElem, aShapeId );
8888
8889       aMesh->RemoveElement(theFace);
8890     }
8891     return;
8892   }
8893
8894   SMESHDS_Mesh *aMesh = GetMeshDS();
8895   if( !theFace->IsQuadratic() ) {
8896
8897     // put aNodesToInsert between theBetweenNode1 and theBetweenNode2
8898     int nbLinkNodes = 2 + aNodesToInsert.size();
8899     //const SMDS_MeshNode* linkNodes[ nbLinkNodes ];
8900     vector<const SMDS_MeshNode*> linkNodes( nbLinkNodes );
8901     linkNodes[ 0 ] = nodes[ il1 ];
8902     linkNodes[ nbLinkNodes - 1 ] = nodes[ il2 ];
8903     list<const SMDS_MeshNode*>::iterator nIt = aNodesToInsert.begin();
8904     for ( iNode = 1; nIt != aNodesToInsert.end(); nIt++ ) {
8905       linkNodes[ iNode++ ] = *nIt;
8906     }
8907     // decide how to split a quadrangle: compare possible variants
8908     // and choose which of splits to be a quadrangle
8909     int i1, i2, iSplit, nbSplits = nbLinkNodes - 1, iBestQuad;
8910     if ( nbFaceNodes == 3 ) {
8911       iBestQuad = nbSplits;
8912       i4 = i3;
8913     }
8914     else if ( nbFaceNodes == 4 ) {
8915       SMESH::Controls::NumericalFunctorPtr aCrit( new SMESH::Controls::AspectRatio);
8916       double aBestRate = DBL_MAX;
8917       for ( int iQuad = 0; iQuad < nbSplits; iQuad++ ) {
8918         i1 = 0; i2 = 1;
8919         double aBadRate = 0;
8920         // evaluate elements quality
8921         for ( iSplit = 0; iSplit < nbSplits; iSplit++ ) {
8922           if ( iSplit == iQuad ) {
8923             SMDS_FaceOfNodes quad (linkNodes[ i1++ ],
8924                                    linkNodes[ i2++ ],
8925                                    nodes[ i3 ],
8926                                    nodes[ i4 ]);
8927             aBadRate += getBadRate( &quad, aCrit );
8928           }
8929           else {
8930             SMDS_FaceOfNodes tria (linkNodes[ i1++ ],
8931                                    linkNodes[ i2++ ],
8932                                    nodes[ iSplit < iQuad ? i4 : i3 ]);
8933             aBadRate += getBadRate( &tria, aCrit );
8934           }
8935         }
8936         // choice
8937         if ( aBadRate < aBestRate ) {
8938           iBestQuad = iQuad;
8939           aBestRate = aBadRate;
8940         }
8941       }
8942     }
8943
8944     // create new elements
8945     int aShapeId = FindShape( theFace );
8946
8947     i1 = 0; i2 = 1;
8948     for ( iSplit = 0; iSplit < nbSplits - 1; iSplit++ ) {
8949       SMDS_MeshElement* newElem = 0;
8950       if ( iSplit == iBestQuad )
8951         newElem = aMesh->AddFace (linkNodes[ i1++ ],
8952                                   linkNodes[ i2++ ],
8953                                   nodes[ i3 ],
8954                                   nodes[ i4 ]);
8955       else
8956         newElem = aMesh->AddFace (linkNodes[ i1++ ],
8957                                   linkNodes[ i2++ ],
8958                                   nodes[ iSplit < iBestQuad ? i4 : i3 ]);
8959       myLastCreatedElems.Append(newElem);
8960       if ( aShapeId && newElem )
8961         aMesh->SetMeshElementOnShape( newElem, aShapeId );
8962     }
8963
8964     // change nodes of theFace
8965     const SMDS_MeshNode* newNodes[ 4 ];
8966     newNodes[ 0 ] = linkNodes[ i1 ];
8967     newNodes[ 1 ] = linkNodes[ i2 ];
8968     newNodes[ 2 ] = nodes[ iSplit >= iBestQuad ? i3 : i4 ];
8969     newNodes[ 3 ] = nodes[ i4 ];
8970     //aMesh->ChangeElementNodes( theFace, newNodes, iSplit == iBestQuad ? 4 : 3 );
8971     const SMDS_MeshElement* newElem = 0;
8972     if (iSplit == iBestQuad)
8973       newElem = aMesh->AddFace( newNodes[0], newNodes[1], newNodes[2], newNodes[3] );
8974     else
8975       newElem = aMesh->AddFace( newNodes[0], newNodes[1], newNodes[2] );
8976     myLastCreatedElems.Append(newElem);
8977     if ( aShapeId && newElem )
8978       aMesh->SetMeshElementOnShape( newElem, aShapeId );
8979 } // end if(!theFace->IsQuadratic())
8980   else { // theFace is quadratic
8981     // we have to split theFace on simple triangles and one simple quadrangle
8982     int tmp = il1/2;
8983     int nbshift = tmp*2;
8984     // shift nodes in nodes[] by nbshift
8985     int i,j;
8986     for(i=0; i<nbshift; i++) {
8987       const SMDS_MeshNode* n = nodes[0];
8988       for(j=0; j<nbFaceNodes-1; j++) {
8989         nodes[j] = nodes[j+1];
8990       }
8991       nodes[nbFaceNodes-1] = n;
8992     }
8993     il1 = il1 - nbshift;
8994     // now have to insert nodes between n0 and n1 or n1 and n2 (see below)
8995     //   n0      n1     n2    n0      n1     n2
8996     //     +-----+-----+        +-----+-----+
8997     //      \         /         |           |
8998     //       \       /          |           |
8999     //      n5+     +n3       n7+           +n3
9000     //         \   /            |           |
9001     //          \ /             |           |
9002     //           +              +-----+-----+
9003     //           n4           n6      n5     n4
9004
9005     // create new elements
9006     int aShapeId = FindShape( theFace );
9007
9008     int n1,n2,n3;
9009     if(nbFaceNodes==6) { // quadratic triangle
9010       SMDS_MeshElement* newElem =
9011         aMesh->AddFace(nodes[3],nodes[4],nodes[5]);
9012       myLastCreatedElems.Append(newElem);
9013       if ( aShapeId && newElem )
9014         aMesh->SetMeshElementOnShape( newElem, aShapeId );
9015       if(theFace->IsMediumNode(nodes[il1])) {
9016         // create quadrangle
9017         newElem = aMesh->AddFace(nodes[0],nodes[1],nodes[3],nodes[5]);
9018         myLastCreatedElems.Append(newElem);
9019         if ( aShapeId && newElem )
9020           aMesh->SetMeshElementOnShape( newElem, aShapeId );
9021         n1 = 1;
9022         n2 = 2;
9023         n3 = 3;
9024       }
9025       else {
9026         // create quadrangle
9027         newElem = aMesh->AddFace(nodes[1],nodes[2],nodes[3],nodes[5]);
9028         myLastCreatedElems.Append(newElem);
9029         if ( aShapeId && newElem )
9030           aMesh->SetMeshElementOnShape( newElem, aShapeId );
9031         n1 = 0;
9032         n2 = 1;
9033         n3 = 5;
9034       }
9035     }
9036     else { // nbFaceNodes==8 - quadratic quadrangle
9037       SMDS_MeshElement* newElem =
9038         aMesh->AddFace(nodes[3],nodes[4],nodes[5]);
9039       myLastCreatedElems.Append(newElem);
9040       if ( aShapeId && newElem )
9041         aMesh->SetMeshElementOnShape( newElem, aShapeId );
9042       newElem = aMesh->AddFace(nodes[5],nodes[6],nodes[7]);
9043       myLastCreatedElems.Append(newElem);
9044       if ( aShapeId && newElem )
9045         aMesh->SetMeshElementOnShape( newElem, aShapeId );
9046       newElem = aMesh->AddFace(nodes[5],nodes[7],nodes[3]);
9047       myLastCreatedElems.Append(newElem);
9048       if ( aShapeId && newElem )
9049         aMesh->SetMeshElementOnShape( newElem, aShapeId );
9050       if(theFace->IsMediumNode(nodes[il1])) {
9051         // create quadrangle
9052         newElem = aMesh->AddFace(nodes[0],nodes[1],nodes[3],nodes[7]);
9053         myLastCreatedElems.Append(newElem);
9054         if ( aShapeId && newElem )
9055           aMesh->SetMeshElementOnShape( newElem, aShapeId );
9056         n1 = 1;
9057         n2 = 2;
9058         n3 = 3;
9059       }
9060       else {
9061         // create quadrangle
9062         newElem = aMesh->AddFace(nodes[1],nodes[2],nodes[3],nodes[7]);
9063         myLastCreatedElems.Append(newElem);
9064         if ( aShapeId && newElem )
9065           aMesh->SetMeshElementOnShape( newElem, aShapeId );
9066         n1 = 0;
9067         n2 = 1;
9068         n3 = 7;
9069       }
9070     }
9071     // create needed triangles using n1,n2,n3 and inserted nodes
9072     int nbn = 2 + aNodesToInsert.size();
9073     //const SMDS_MeshNode* aNodes[nbn];
9074     vector<const SMDS_MeshNode*> aNodes(nbn);
9075     aNodes[0] = nodes[n1];
9076     aNodes[nbn-1] = nodes[n2];
9077     list<const SMDS_MeshNode*>::iterator nIt = aNodesToInsert.begin();
9078     for ( iNode = 1; nIt != aNodesToInsert.end(); nIt++ ) {
9079       aNodes[iNode++] = *nIt;
9080     }
9081     for(i=1; i<nbn; i++) {
9082       SMDS_MeshElement* newElem =
9083         aMesh->AddFace(aNodes[i-1],aNodes[i],nodes[n3]);
9084       myLastCreatedElems.Append(newElem);
9085       if ( aShapeId && newElem )
9086         aMesh->SetMeshElementOnShape( newElem, aShapeId );
9087     }
9088   }
9089   // remove old face
9090   aMesh->RemoveElement(theFace);
9091 }
9092
9093 //=======================================================================
9094 //function : UpdateVolumes
9095 //purpose  :
9096 //=======================================================================
9097 void SMESH_MeshEditor::UpdateVolumes (const SMDS_MeshNode*        theBetweenNode1,
9098                                       const SMDS_MeshNode*        theBetweenNode2,
9099                                       list<const SMDS_MeshNode*>& theNodesToInsert)
9100 {
9101   myLastCreatedElems.Clear();
9102   myLastCreatedNodes.Clear();
9103
9104   SMDS_ElemIteratorPtr invElemIt = theBetweenNode1->GetInverseElementIterator(SMDSAbs_Volume);
9105   while (invElemIt->more()) { // loop on inverse elements of theBetweenNode1
9106     const SMDS_MeshElement* elem = invElemIt->next();
9107
9108     // check, if current volume has link theBetweenNode1 - theBetweenNode2
9109     SMDS_VolumeTool aVolume (elem);
9110     if (!aVolume.IsLinked(theBetweenNode1, theBetweenNode2))
9111       continue;
9112
9113     // insert new nodes in all faces of the volume, sharing link theBetweenNode1 - theBetweenNode2
9114     int iface, nbFaces = aVolume.NbFaces();
9115     vector<const SMDS_MeshNode *> poly_nodes;
9116     vector<int> quantities (nbFaces);
9117
9118     for (iface = 0; iface < nbFaces; iface++) {
9119       int nbFaceNodes = aVolume.NbFaceNodes(iface), nbInserted = 0;
9120       // faceNodes will contain (nbFaceNodes + 1) nodes, last = first
9121       const SMDS_MeshNode** faceNodes = aVolume.GetFaceNodes(iface);
9122
9123       for (int inode = 0; inode < nbFaceNodes; inode++) {
9124         poly_nodes.push_back(faceNodes[inode]);
9125
9126         if (nbInserted == 0) {
9127           if (faceNodes[inode] == theBetweenNode1) {
9128             if (faceNodes[inode + 1] == theBetweenNode2) {
9129               nbInserted = theNodesToInsert.size();
9130
9131               // add nodes to insert
9132               list<const SMDS_MeshNode*>::iterator nIt = theNodesToInsert.begin();
9133               for (; nIt != theNodesToInsert.end(); nIt++) {
9134                 poly_nodes.push_back(*nIt);
9135               }
9136             }
9137           }
9138           else if (faceNodes[inode] == theBetweenNode2) {
9139             if (faceNodes[inode + 1] == theBetweenNode1) {
9140               nbInserted = theNodesToInsert.size();
9141
9142               // add nodes to insert in reversed order
9143               list<const SMDS_MeshNode*>::iterator nIt = theNodesToInsert.end();
9144               nIt--;
9145               for (; nIt != theNodesToInsert.begin(); nIt--) {
9146                 poly_nodes.push_back(*nIt);
9147               }
9148               poly_nodes.push_back(*nIt);
9149             }
9150           }
9151           else {
9152           }
9153         }
9154       }
9155       quantities[iface] = nbFaceNodes + nbInserted;
9156     }
9157
9158     // Replace or update the volume
9159     SMESHDS_Mesh *aMesh = GetMeshDS();
9160
9161     if (elem->IsPoly()) {
9162       aMesh->ChangePolyhedronNodes(elem, poly_nodes, quantities);
9163
9164     }
9165     else {
9166       int aShapeId = FindShape( elem );
9167
9168       SMDS_MeshElement* newElem =
9169         aMesh->AddPolyhedralVolume(poly_nodes, quantities);
9170       myLastCreatedElems.Append(newElem);
9171       if (aShapeId && newElem)
9172         aMesh->SetMeshElementOnShape(newElem, aShapeId);
9173
9174       aMesh->RemoveElement(elem);
9175     }
9176   }
9177 }
9178
9179 //=======================================================================
9180 /*!
9181  * \brief Convert elements contained in a submesh to quadratic
9182  * \retval int - nb of checked elements
9183  */
9184 //=======================================================================
9185
9186 int SMESH_MeshEditor::convertElemToQuadratic(SMESHDS_SubMesh *   theSm,
9187                                              SMESH_MesherHelper& theHelper,
9188                                              const bool          theForce3d)
9189 {
9190   int nbElem = 0;
9191   if( !theSm ) return nbElem;
9192
9193   vector<int> nbNodeInFaces;
9194   SMDS_ElemIteratorPtr ElemItr = theSm->GetElements();
9195   while(ElemItr->more())
9196   {
9197     nbElem++;
9198     const SMDS_MeshElement* elem = ElemItr->next();
9199     if( !elem || elem->IsQuadratic() ) continue;
9200
9201     int id = elem->GetID();
9202     //MESSAGE("elem " << id);
9203     id = 0; // get a free number for new elements
9204     int nbNodes = elem->NbNodes();
9205     SMDSAbs_ElementType aType = elem->GetType();
9206
9207     vector<const SMDS_MeshNode *> nodes (elem->begin_nodes(), elem->end_nodes());
9208     if ( elem->GetEntityType() == SMDSEntity_Polyhedra )
9209       nbNodeInFaces = static_cast<const SMDS_VtkVolume* >( elem )->GetQuantities();
9210
9211     const SMDS_MeshElement* NewElem = 0;
9212
9213     switch( aType )
9214     {
9215     case SMDSAbs_Edge :
9216       {
9217         NewElem = theHelper.AddEdge(nodes[0], nodes[1], id, theForce3d);
9218         break;
9219       }
9220     case SMDSAbs_Face :
9221       {
9222         switch(nbNodes)
9223         {
9224         case 3:
9225           NewElem = theHelper.AddFace(nodes[0], nodes[1], nodes[2], id, theForce3d);
9226           break;
9227         case 4:
9228           NewElem = theHelper.AddFace(nodes[0], nodes[1], nodes[2], nodes[3], id, theForce3d);
9229           break;
9230         default:
9231           NewElem = theHelper.AddPolygonalFace(nodes, id, theForce3d);
9232           continue;
9233         }
9234         break;
9235       }
9236     case SMDSAbs_Volume :
9237       {
9238         switch(nbNodes)
9239         {
9240         case 4:
9241           NewElem = theHelper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3], id, theForce3d);
9242           break;
9243         case 5:
9244           NewElem = theHelper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3], nodes[4], id, theForce3d);
9245           break;
9246         case 6:
9247           NewElem = theHelper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3], nodes[4], nodes[5], id, theForce3d);
9248           break;
9249         case 8:
9250           NewElem = theHelper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3],
9251                                         nodes[4], nodes[5], nodes[6], nodes[7], id, theForce3d);
9252           break;
9253         default:
9254           NewElem = theHelper.AddPolyhedralVolume(nodes, nbNodeInFaces, id, theForce3d);
9255         }
9256         break;
9257       }
9258     default :
9259       continue;
9260     }
9261     ReplaceElemInGroups( elem, NewElem, GetMeshDS());
9262     if( NewElem )
9263       theSm->AddElement( NewElem );
9264
9265     GetMeshDS()->RemoveFreeElement(elem, theSm, /*fromGroups=*/false);
9266   }
9267 //  if (!GetMeshDS()->isCompacted())
9268 //    GetMeshDS()->compactMesh();
9269   return nbElem;
9270 }
9271
9272 //=======================================================================
9273 //function : ConvertToQuadratic
9274 //purpose  :
9275 //=======================================================================
9276 void SMESH_MeshEditor::ConvertToQuadratic(const bool theForce3d)
9277 {
9278   SMESHDS_Mesh* meshDS = GetMeshDS();
9279
9280   SMESH_MesherHelper aHelper(*myMesh);
9281   aHelper.SetIsQuadratic( true );
9282
9283   int nbCheckedElems = 0;
9284   if ( myMesh->HasShapeToMesh() )
9285   {
9286     if ( SMESH_subMesh *aSubMesh = myMesh->GetSubMeshContaining(myMesh->GetShapeToMesh()))
9287     {
9288       SMESH_subMeshIteratorPtr smIt = aSubMesh->getDependsOnIterator(true,false);
9289       while ( smIt->more() ) {
9290         SMESH_subMesh* sm = smIt->next();
9291         if ( SMESHDS_SubMesh *smDS = sm->GetSubMeshDS() ) {
9292           aHelper.SetSubShape( sm->GetSubShape() );
9293           nbCheckedElems += convertElemToQuadratic(smDS, aHelper, theForce3d);
9294         }
9295       }
9296     }
9297   }
9298   int totalNbElems = meshDS->NbEdges() + meshDS->NbFaces() + meshDS->NbVolumes();
9299   if ( nbCheckedElems < totalNbElems ) // not all elements are in submeshes
9300   {
9301     SMESHDS_SubMesh *smDS = 0;
9302     SMDS_EdgeIteratorPtr aEdgeItr = meshDS->edgesIterator();
9303     while(aEdgeItr->more())
9304     {
9305       const SMDS_MeshEdge* edge = aEdgeItr->next();
9306       if(edge && !edge->IsQuadratic())
9307       {
9308         int id = edge->GetID();
9309         //MESSAGE("edge->GetID() " << id);
9310         const SMDS_MeshNode* n1 = edge->GetNode(0);
9311         const SMDS_MeshNode* n2 = edge->GetNode(1);
9312
9313         meshDS->RemoveFreeElement(edge, smDS, /*fromGroups=*/false);
9314
9315         const SMDS_MeshEdge* NewEdge = aHelper.AddEdge(n1, n2, id, theForce3d);
9316         ReplaceElemInGroups( edge, NewEdge, GetMeshDS());
9317       }
9318     }
9319     SMDS_FaceIteratorPtr aFaceItr = meshDS->facesIterator();
9320     while(aFaceItr->more())
9321     {
9322       const SMDS_MeshFace* face = aFaceItr->next();
9323       if(!face || face->IsQuadratic() ) continue;
9324
9325       int id = face->GetID();
9326       int nbNodes = face->NbNodes();
9327       vector<const SMDS_MeshNode *> nodes ( face->begin_nodes(), face->end_nodes());
9328
9329       meshDS->RemoveFreeElement(face, smDS, /*fromGroups=*/false);
9330
9331       SMDS_MeshFace * NewFace = 0;
9332       switch(nbNodes)
9333       {
9334       case 3:
9335         NewFace = aHelper.AddFace(nodes[0], nodes[1], nodes[2], id, theForce3d);
9336         break;
9337       case 4:
9338         NewFace = aHelper.AddFace(nodes[0], nodes[1], nodes[2], nodes[3], id, theForce3d);
9339         break;
9340       default:
9341         NewFace = aHelper.AddPolygonalFace(nodes, id, theForce3d);
9342       }
9343       ReplaceElemInGroups( face, NewFace, GetMeshDS());
9344     }
9345     vector<int> nbNodeInFaces;
9346     SMDS_VolumeIteratorPtr aVolumeItr = meshDS->volumesIterator();
9347     while(aVolumeItr->more())
9348     {
9349       const SMDS_MeshVolume* volume = aVolumeItr->next();
9350       if(!volume || volume->IsQuadratic() ) continue;
9351
9352       int id = volume->GetID();
9353       int nbNodes = volume->NbNodes();
9354       vector<const SMDS_MeshNode *> nodes (volume->begin_nodes(), volume->end_nodes());
9355       if ( volume->GetEntityType() == SMDSEntity_Polyhedra )
9356         nbNodeInFaces = static_cast<const SMDS_VtkVolume* >(volume)->GetQuantities();
9357
9358       meshDS->RemoveFreeElement(volume, smDS, /*fromGroups=*/false);
9359
9360       SMDS_MeshVolume * NewVolume = 0;
9361       switch(nbNodes)
9362       {
9363       case 4:
9364         NewVolume = aHelper.AddVolume(nodes[0], nodes[1], nodes[2],
9365                                       nodes[3], id, theForce3d );
9366         break;
9367       case 5:
9368         NewVolume = aHelper.AddVolume(nodes[0], nodes[1], nodes[2],
9369                                       nodes[3], nodes[4], id, theForce3d);
9370         break;
9371       case 6:
9372         NewVolume = aHelper.AddVolume(nodes[0], nodes[1], nodes[2],
9373                                       nodes[3], nodes[4], nodes[5], id, theForce3d);
9374         break;
9375       case 8:
9376         NewVolume = aHelper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3],
9377                                       nodes[4], nodes[5], nodes[6], nodes[7], id, theForce3d);
9378         break;
9379       default:
9380         NewVolume = aHelper.AddPolyhedralVolume(nodes, nbNodeInFaces, id, theForce3d);
9381       }
9382       ReplaceElemInGroups(volume, NewVolume, meshDS);
9383     }
9384   }
9385
9386   if ( !theForce3d  && !getenv("NO_FixQuadraticElements"))
9387   { // setenv NO_FixQuadraticElements to know if FixQuadraticElements() is guilty of bad conversion
9388     aHelper.SetSubShape(0); // apply FixQuadraticElements() to the whole mesh
9389     aHelper.FixQuadraticElements();
9390   }
9391   if (!GetMeshDS()->isCompacted())
9392     GetMeshDS()->compactMesh();
9393 }
9394
9395 //=======================================================================
9396 /*!
9397  * \brief Convert quadratic elements to linear ones and remove quadratic nodes
9398  * \retval int - nb of checked elements
9399  */
9400 //=======================================================================
9401
9402 int SMESH_MeshEditor::removeQuadElem(SMESHDS_SubMesh *    theSm,
9403                                      SMDS_ElemIteratorPtr theItr,
9404                                      const int            theShapeID)
9405 {
9406   int nbElem = 0;
9407   SMESHDS_Mesh* meshDS = GetMeshDS();
9408   const bool notFromGroups = false;
9409
9410   while( theItr->more() )
9411   {
9412     const SMDS_MeshElement* elem = theItr->next();
9413     nbElem++;
9414     if( elem && elem->IsQuadratic())
9415     {
9416       int id = elem->GetID();
9417       int nbNodes = elem->NbNodes();
9418       vector<const SMDS_MeshNode *> nodes, mediumNodes;
9419       nodes.reserve( nbNodes );
9420       mediumNodes.reserve( nbNodes );
9421
9422       for(int i = 0; i < nbNodes; i++)
9423       {
9424         const SMDS_MeshNode* n = elem->GetNode(i);
9425
9426         if( elem->IsMediumNode( n ) )
9427           mediumNodes.push_back( n );
9428         else
9429           nodes.push_back( n );
9430       }
9431       if( nodes.empty() ) continue;
9432       SMDSAbs_ElementType aType = elem->GetType();
9433
9434       //remove old quadratic element
9435       meshDS->RemoveFreeElement( elem, theSm, notFromGroups );
9436
9437       SMDS_MeshElement * NewElem = AddElement( nodes, aType, false, id );
9438       ReplaceElemInGroups(elem, NewElem, meshDS);
9439       if( theSm && NewElem )
9440         theSm->AddElement( NewElem );
9441
9442       // remove medium nodes
9443       vector<const SMDS_MeshNode*>::iterator nIt = mediumNodes.begin();
9444       for ( ; nIt != mediumNodes.end(); ++nIt ) {
9445         const SMDS_MeshNode* n = *nIt;
9446         if ( n->NbInverseElements() == 0 ) {
9447           if ( n->getshapeId() != theShapeID )
9448             meshDS->RemoveFreeNode( n, meshDS->MeshElements
9449                                     ( n->getshapeId() ));
9450           else
9451             meshDS->RemoveFreeNode( n, theSm );
9452         }
9453       }
9454     }
9455   }
9456   return nbElem;
9457 }
9458
9459 //=======================================================================
9460 //function : ConvertFromQuadratic
9461 //purpose  :
9462 //=======================================================================
9463 bool  SMESH_MeshEditor::ConvertFromQuadratic()
9464 {
9465   int nbCheckedElems = 0;
9466   if ( myMesh->HasShapeToMesh() )
9467   {
9468     if ( SMESH_subMesh *aSubMesh = myMesh->GetSubMeshContaining(myMesh->GetShapeToMesh()))
9469     {
9470       SMESH_subMeshIteratorPtr smIt = aSubMesh->getDependsOnIterator(true,false);
9471       while ( smIt->more() ) {
9472         SMESH_subMesh* sm = smIt->next();
9473         if ( SMESHDS_SubMesh *smDS = sm->GetSubMeshDS() )
9474           nbCheckedElems += removeQuadElem( smDS, smDS->GetElements(), sm->GetId() );
9475       }
9476     }
9477   }
9478
9479   int totalNbElems =
9480     GetMeshDS()->NbEdges() + GetMeshDS()->NbFaces() + GetMeshDS()->NbVolumes();
9481   if ( nbCheckedElems < totalNbElems ) // not all elements are in submeshes
9482   {
9483     SMESHDS_SubMesh *aSM = 0;
9484     removeQuadElem( aSM, GetMeshDS()->elementsIterator(), 0 );
9485   }
9486
9487   return true;
9488 }
9489
9490 //=======================================================================
9491 //function : SewSideElements
9492 //purpose  :
9493 //=======================================================================
9494
9495 SMESH_MeshEditor::Sew_Error
9496 SMESH_MeshEditor::SewSideElements (TIDSortedElemSet&    theSide1,
9497                                    TIDSortedElemSet&    theSide2,
9498                                    const SMDS_MeshNode* theFirstNode1,
9499                                    const SMDS_MeshNode* theFirstNode2,
9500                                    const SMDS_MeshNode* theSecondNode1,
9501                                    const SMDS_MeshNode* theSecondNode2)
9502 {
9503   myLastCreatedElems.Clear();
9504   myLastCreatedNodes.Clear();
9505
9506   MESSAGE ("::::SewSideElements()");
9507   if ( theSide1.size() != theSide2.size() )
9508     return SEW_DIFF_NB_OF_ELEMENTS;
9509
9510   Sew_Error aResult = SEW_OK;
9511   // Algo:
9512   // 1. Build set of faces representing each side
9513   // 2. Find which nodes of the side 1 to merge with ones on the side 2
9514   // 3. Replace nodes in elements of the side 1 and remove replaced nodes
9515
9516   // =======================================================================
9517   // 1. Build set of faces representing each side:
9518   // =======================================================================
9519   // a. build set of nodes belonging to faces
9520   // b. complete set of faces: find missing faces whose nodes are in set of nodes
9521   // c. create temporary faces representing side of volumes if correspondent
9522   //    face does not exist
9523
9524   SMESHDS_Mesh* aMesh = GetMeshDS();
9525   // TODO algoritm not OK with vtkUnstructuredGrid: 2 meshes can't share nodes
9526   //SMDS_Mesh aTmpFacesMesh; // try to use the same mesh
9527   set<const SMDS_MeshElement*> faceSet1, faceSet2;
9528   set<const SMDS_MeshElement*> volSet1,  volSet2;
9529   set<const SMDS_MeshNode*>    nodeSet1, nodeSet2;
9530   set<const SMDS_MeshElement*> * faceSetPtr[] = { &faceSet1, &faceSet2 };
9531   set<const SMDS_MeshElement*>  * volSetPtr[] = { &volSet1,  &volSet2  };
9532   set<const SMDS_MeshNode*>    * nodeSetPtr[] = { &nodeSet1, &nodeSet2 };
9533   TIDSortedElemSet * elemSetPtr[] = { &theSide1, &theSide2 };
9534   int iSide, iFace, iNode;
9535
9536   list<const SMDS_MeshElement* > tempFaceList;
9537   for ( iSide = 0; iSide < 2; iSide++ ) {
9538     set<const SMDS_MeshNode*>    * nodeSet = nodeSetPtr[ iSide ];
9539     TIDSortedElemSet * elemSet = elemSetPtr[ iSide ];
9540     set<const SMDS_MeshElement*> * faceSet = faceSetPtr[ iSide ];
9541     set<const SMDS_MeshElement*> * volSet  = volSetPtr [ iSide ];
9542     set<const SMDS_MeshElement*>::iterator vIt;
9543     TIDSortedElemSet::iterator eIt;
9544     set<const SMDS_MeshNode*>::iterator    nIt;
9545
9546     // check that given nodes belong to given elements
9547     const SMDS_MeshNode* n1 = ( iSide == 0 ) ? theFirstNode1 : theFirstNode2;
9548     const SMDS_MeshNode* n2 = ( iSide == 0 ) ? theSecondNode1 : theSecondNode2;
9549     int firstIndex = -1, secondIndex = -1;
9550     for (eIt = elemSet->begin(); eIt != elemSet->end(); eIt++ ) {
9551       const SMDS_MeshElement* elem = *eIt;
9552       if ( firstIndex  < 0 ) firstIndex  = elem->GetNodeIndex( n1 );
9553       if ( secondIndex < 0 ) secondIndex = elem->GetNodeIndex( n2 );
9554       if ( firstIndex > -1 && secondIndex > -1 ) break;
9555     }
9556     if ( firstIndex < 0 || secondIndex < 0 ) {
9557       // we can simply return until temporary faces created
9558       return (iSide == 0 ) ? SEW_BAD_SIDE1_NODES : SEW_BAD_SIDE2_NODES;
9559     }
9560
9561     // -----------------------------------------------------------
9562     // 1a. Collect nodes of existing faces
9563     //     and build set of face nodes in order to detect missing
9564     //     faces corresponding to sides of volumes
9565     // -----------------------------------------------------------
9566
9567     set< set <const SMDS_MeshNode*> > setOfFaceNodeSet;
9568
9569     // loop on the given element of a side
9570     for (eIt = elemSet->begin(); eIt != elemSet->end(); eIt++ ) {
9571       //const SMDS_MeshElement* elem = *eIt;
9572       const SMDS_MeshElement* elem = *eIt;
9573       if ( elem->GetType() == SMDSAbs_Face ) {
9574         faceSet->insert( elem );
9575         set <const SMDS_MeshNode*> faceNodeSet;
9576         SMDS_ElemIteratorPtr nodeIt = elem->nodesIterator();
9577         while ( nodeIt->more() ) {
9578           const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
9579           nodeSet->insert( n );
9580           faceNodeSet.insert( n );
9581         }
9582         setOfFaceNodeSet.insert( faceNodeSet );
9583       }
9584       else if ( elem->GetType() == SMDSAbs_Volume )
9585         volSet->insert( elem );
9586     }
9587     // ------------------------------------------------------------------------------
9588     // 1b. Complete set of faces: find missing faces whose nodes are in set of nodes
9589     // ------------------------------------------------------------------------------
9590
9591     for ( nIt = nodeSet->begin(); nIt != nodeSet->end(); nIt++ ) { // loop on nodes of iSide
9592       SMDS_ElemIteratorPtr fIt = (*nIt)->GetInverseElementIterator(SMDSAbs_Face);
9593       while ( fIt->more() ) { // loop on faces sharing a node
9594         const SMDS_MeshElement* f = fIt->next();
9595         if ( faceSet->find( f ) == faceSet->end() ) {
9596           // check if all nodes are in nodeSet and
9597           // complete setOfFaceNodeSet if they are
9598           set <const SMDS_MeshNode*> faceNodeSet;
9599           SMDS_ElemIteratorPtr nodeIt = f->nodesIterator();
9600           bool allInSet = true;
9601           while ( nodeIt->more() && allInSet ) { // loop on nodes of a face
9602             const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
9603             if ( nodeSet->find( n ) == nodeSet->end() )
9604               allInSet = false;
9605             else
9606               faceNodeSet.insert( n );
9607           }
9608           if ( allInSet ) {
9609             faceSet->insert( f );
9610             setOfFaceNodeSet.insert( faceNodeSet );
9611           }
9612         }
9613       }
9614     }
9615
9616     // -------------------------------------------------------------------------
9617     // 1c. Create temporary faces representing sides of volumes if correspondent
9618     //     face does not exist
9619     // -------------------------------------------------------------------------
9620
9621     if ( !volSet->empty() ) {
9622       //int nodeSetSize = nodeSet->size();
9623
9624       // loop on given volumes
9625       for ( vIt = volSet->begin(); vIt != volSet->end(); vIt++ ) {
9626         SMDS_VolumeTool vol (*vIt);
9627         // loop on volume faces: find free faces
9628         // --------------------------------------
9629         list<const SMDS_MeshElement* > freeFaceList;
9630         for ( iFace = 0; iFace < vol.NbFaces(); iFace++ ) {
9631           if ( !vol.IsFreeFace( iFace ))
9632             continue;
9633           // check if there is already a face with same nodes in a face set
9634           const SMDS_MeshElement* aFreeFace = 0;
9635           const SMDS_MeshNode** fNodes = vol.GetFaceNodes( iFace );
9636           int nbNodes = vol.NbFaceNodes( iFace );
9637           set <const SMDS_MeshNode*> faceNodeSet;
9638           vol.GetFaceNodes( iFace, faceNodeSet );
9639           bool isNewFace = setOfFaceNodeSet.insert( faceNodeSet ).second;
9640           if ( isNewFace ) {
9641             // no such a face is given but it still can exist, check it
9642             if ( nbNodes == 3 ) {
9643               aFreeFace = aMesh->FindFace( fNodes[0],fNodes[1],fNodes[2] );
9644             }
9645             else if ( nbNodes == 4 ) {
9646               aFreeFace = aMesh->FindFace( fNodes[0],fNodes[1],fNodes[2],fNodes[3] );
9647             }
9648             else {
9649               vector<const SMDS_MeshNode *> poly_nodes ( fNodes, & fNodes[nbNodes]);
9650               aFreeFace = aMesh->FindFace(poly_nodes);
9651             }
9652           }
9653           if ( !aFreeFace ) {
9654             // create a temporary face
9655             if ( nbNodes == 3 ) {
9656               //aFreeFace = aTmpFacesMesh.AddFace( fNodes[0],fNodes[1],fNodes[2] );
9657               aFreeFace = aMesh->AddFace( fNodes[0],fNodes[1],fNodes[2] );
9658             }
9659             else if ( nbNodes == 4 ) {
9660               //aFreeFace = aTmpFacesMesh.AddFace( fNodes[0],fNodes[1],fNodes[2],fNodes[3] );
9661               aFreeFace = aMesh->AddFace( fNodes[0],fNodes[1],fNodes[2],fNodes[3] );
9662             }
9663             else {
9664               vector<const SMDS_MeshNode *> poly_nodes ( fNodes, & fNodes[nbNodes]);
9665               //aFreeFace = aTmpFacesMesh.AddPolygonalFace(poly_nodes);
9666               aFreeFace = aMesh->AddPolygonalFace(poly_nodes);
9667             }
9668           }
9669           if ( aFreeFace ) {
9670             freeFaceList.push_back( aFreeFace );
9671             tempFaceList.push_back( aFreeFace );
9672           }
9673
9674         } // loop on faces of a volume
9675
9676         // choose one of several free faces
9677         // --------------------------------------
9678         if ( freeFaceList.size() > 1 ) {
9679           // choose a face having max nb of nodes shared by other elems of a side
9680           int maxNbNodes = -1/*, nbExcludedFaces = 0*/;
9681           list<const SMDS_MeshElement* >::iterator fIt = freeFaceList.begin();
9682           while ( fIt != freeFaceList.end() ) { // loop on free faces
9683             int nbSharedNodes = 0;
9684             SMDS_ElemIteratorPtr nodeIt = (*fIt)->nodesIterator();
9685             while ( nodeIt->more() ) { // loop on free face nodes
9686               const SMDS_MeshNode* n =
9687                 static_cast<const SMDS_MeshNode*>( nodeIt->next() );
9688               SMDS_ElemIteratorPtr invElemIt = n->GetInverseElementIterator();
9689               while ( invElemIt->more() ) {
9690                 const SMDS_MeshElement* e = invElemIt->next();
9691                 if ( faceSet->find( e ) != faceSet->end() )
9692                   nbSharedNodes++;
9693                 if ( elemSet->find( e ) != elemSet->end() )
9694                   nbSharedNodes++;
9695               }
9696             }
9697             if ( nbSharedNodes >= maxNbNodes ) {
9698               maxNbNodes = nbSharedNodes;
9699               fIt++;
9700             }
9701             else
9702               freeFaceList.erase( fIt++ ); // here fIt++ occurs before erase
9703           }
9704           if ( freeFaceList.size() > 1 )
9705           {
9706             // could not choose one face, use another way
9707             // choose a face most close to the bary center of the opposite side
9708             gp_XYZ aBC( 0., 0., 0. );
9709             set <const SMDS_MeshNode*> addedNodes;
9710             TIDSortedElemSet * elemSet2 = elemSetPtr[ 1 - iSide ];
9711             eIt = elemSet2->begin();
9712             for ( eIt = elemSet2->begin(); eIt != elemSet2->end(); eIt++ ) {
9713               SMDS_ElemIteratorPtr nodeIt = (*eIt)->nodesIterator();
9714               while ( nodeIt->more() ) { // loop on free face nodes
9715                 const SMDS_MeshNode* n =
9716                   static_cast<const SMDS_MeshNode*>( nodeIt->next() );
9717                 if ( addedNodes.insert( n ).second )
9718                   aBC += gp_XYZ( n->X(),n->Y(),n->Z() );
9719               }
9720             }
9721             aBC /= addedNodes.size();
9722             double minDist = DBL_MAX;
9723             fIt = freeFaceList.begin();
9724             while ( fIt != freeFaceList.end() ) { // loop on free faces
9725               double dist = 0;
9726               SMDS_ElemIteratorPtr nodeIt = (*fIt)->nodesIterator();
9727               while ( nodeIt->more() ) { // loop on free face nodes
9728                 const SMDS_MeshNode* n =
9729                   static_cast<const SMDS_MeshNode*>( nodeIt->next() );
9730                 gp_XYZ p( n->X(),n->Y(),n->Z() );
9731                 dist += ( aBC - p ).SquareModulus();
9732               }
9733               if ( dist < minDist ) {
9734                 minDist = dist;
9735                 freeFaceList.erase( freeFaceList.begin(), fIt++ );
9736               }
9737               else
9738                 fIt = freeFaceList.erase( fIt++ );
9739             }
9740           }
9741         } // choose one of several free faces of a volume
9742
9743         if ( freeFaceList.size() == 1 ) {
9744           const SMDS_MeshElement* aFreeFace = freeFaceList.front();
9745           faceSet->insert( aFreeFace );
9746           // complete a node set with nodes of a found free face
9747           //           for ( iNode = 0; iNode < ; iNode++ )
9748           //             nodeSet->insert( fNodes[ iNode ] );
9749         }
9750
9751       } // loop on volumes of a side
9752
9753       //       // complete a set of faces if new nodes in a nodeSet appeared
9754       //       // ----------------------------------------------------------
9755       //       if ( nodeSetSize != nodeSet->size() ) {
9756       //         for ( ; nIt != nodeSet->end(); nIt++ ) { // loop on nodes of iSide
9757       //           SMDS_ElemIteratorPtr fIt = (*nIt)->GetInverseElementIterator(SMDSAbs_Face);
9758       //           while ( fIt->more() ) { // loop on faces sharing a node
9759       //             const SMDS_MeshElement* f = fIt->next();
9760       //             if ( faceSet->find( f ) == faceSet->end() ) {
9761       //               // check if all nodes are in nodeSet and
9762       //               // complete setOfFaceNodeSet if they are
9763       //               set <const SMDS_MeshNode*> faceNodeSet;
9764       //               SMDS_ElemIteratorPtr nodeIt = f->nodesIterator();
9765       //               bool allInSet = true;
9766       //               while ( nodeIt->more() && allInSet ) { // loop on nodes of a face
9767       //                 const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
9768       //                 if ( nodeSet->find( n ) == nodeSet->end() )
9769       //                   allInSet = false;
9770       //                 else
9771       //                   faceNodeSet.insert( n );
9772       //               }
9773       //               if ( allInSet ) {
9774       //                 faceSet->insert( f );
9775       //                 setOfFaceNodeSet.insert( faceNodeSet );
9776       //               }
9777       //             }
9778       //           }
9779       //         }
9780       //       }
9781     } // Create temporary faces, if there are volumes given
9782   } // loop on sides
9783
9784   if ( faceSet1.size() != faceSet2.size() ) {
9785     // delete temporary faces: they are in reverseElements of actual nodes
9786 //    SMDS_FaceIteratorPtr tmpFaceIt = aTmpFacesMesh.facesIterator();
9787 //    while ( tmpFaceIt->more() )
9788 //      aTmpFacesMesh.RemoveElement( tmpFaceIt->next() );
9789 //    list<const SMDS_MeshElement* >::iterator tmpFaceIt = tempFaceList.begin();
9790 //    for (; tmpFaceIt !=tempFaceList.end(); ++tmpFaceIt)
9791 //      aMesh->RemoveElement(*tmpFaceIt);
9792     MESSAGE("Diff nb of faces");
9793     return SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
9794   }
9795
9796   // ============================================================
9797   // 2. Find nodes to merge:
9798   //              bind a node to remove to a node to put instead
9799   // ============================================================
9800
9801   TNodeNodeMap nReplaceMap; // bind a node to remove to a node to put instead
9802   if ( theFirstNode1 != theFirstNode2 )
9803     nReplaceMap.insert( TNodeNodeMap::value_type( theFirstNode1, theFirstNode2 ));
9804   if ( theSecondNode1 != theSecondNode2 )
9805     nReplaceMap.insert( TNodeNodeMap::value_type( theSecondNode1, theSecondNode2 ));
9806
9807   LinkID_Gen aLinkID_Gen( GetMeshDS() );
9808   set< long > linkIdSet; // links to process
9809   linkIdSet.insert( aLinkID_Gen.GetLinkID( theFirstNode1, theSecondNode1 ));
9810
9811   typedef pair< const SMDS_MeshNode*, const SMDS_MeshNode* > NLink;
9812   list< NLink > linkList[2];
9813   linkList[0].push_back( NLink( theFirstNode1, theSecondNode1 ));
9814   linkList[1].push_back( NLink( theFirstNode2, theSecondNode2 ));
9815   // loop on links in linkList; find faces by links and append links
9816   // of the found faces to linkList
9817   list< NLink >::iterator linkIt[] = { linkList[0].begin(), linkList[1].begin() } ;
9818   for ( ; linkIt[0] != linkList[0].end(); linkIt[0]++, linkIt[1]++ ) {
9819     NLink link[] = { *linkIt[0], *linkIt[1] };
9820     long linkID = aLinkID_Gen.GetLinkID( link[0].first, link[0].second );
9821     if ( linkIdSet.find( linkID ) == linkIdSet.end() )
9822       continue;
9823
9824     // by links, find faces in the face sets,
9825     // and find indices of link nodes in the found faces;
9826     // in a face set, there is only one or no face sharing a link
9827     // ---------------------------------------------------------------
9828
9829     const SMDS_MeshElement* face[] = { 0, 0 };
9830     //const SMDS_MeshNode* faceNodes[ 2 ][ 5 ];
9831     vector<const SMDS_MeshNode*> fnodes1(9);
9832     vector<const SMDS_MeshNode*> fnodes2(9);
9833     //const SMDS_MeshNode* notLinkNodes[ 2 ][ 2 ] = {{ 0, 0 },{ 0, 0 }} ;
9834     vector<const SMDS_MeshNode*> notLinkNodes1(6);
9835     vector<const SMDS_MeshNode*> notLinkNodes2(6);
9836     int iLinkNode[2][2];
9837     for ( iSide = 0; iSide < 2; iSide++ ) { // loop on 2 sides
9838       const SMDS_MeshNode* n1 = link[iSide].first;
9839       const SMDS_MeshNode* n2 = link[iSide].second;
9840       set<const SMDS_MeshElement*> * faceSet = faceSetPtr[ iSide ];
9841       set< const SMDS_MeshElement* > fMap;
9842       for ( int i = 0; i < 2; i++ ) { // loop on 2 nodes of a link
9843         const SMDS_MeshNode* n = i ? n1 : n2; // a node of a link
9844         SMDS_ElemIteratorPtr fIt = n->GetInverseElementIterator(SMDSAbs_Face);
9845         while ( fIt->more() ) { // loop on faces sharing a node
9846           const SMDS_MeshElement* f = fIt->next();
9847           if (faceSet->find( f ) != faceSet->end() && // f is in face set
9848               ! fMap.insert( f ).second ) // f encounters twice
9849           {
9850             if ( face[ iSide ] ) {
9851               MESSAGE( "2 faces per link " );
9852               aResult = iSide ? SEW_BAD_SIDE2_NODES : SEW_BAD_SIDE1_NODES;
9853               break;
9854             }
9855             face[ iSide ] = f;
9856             faceSet->erase( f );
9857             // get face nodes and find ones of a link
9858             iNode = 0;
9859             int nbl = -1;
9860             if(f->IsPoly()) {
9861               if(iSide==0) {
9862                 fnodes1.resize(f->NbNodes()+1);
9863                 notLinkNodes1.resize(f->NbNodes()-2);
9864               }
9865               else {
9866                 fnodes2.resize(f->NbNodes()+1);
9867                 notLinkNodes2.resize(f->NbNodes()-2);
9868               }
9869             }
9870             if(!f->IsQuadratic()) {
9871               SMDS_ElemIteratorPtr nIt = f->nodesIterator();
9872               while ( nIt->more() ) {
9873                 const SMDS_MeshNode* n =
9874                   static_cast<const SMDS_MeshNode*>( nIt->next() );
9875                 if ( n == n1 ) {
9876                   iLinkNode[ iSide ][ 0 ] = iNode;
9877                 }
9878                 else if ( n == n2 ) {
9879                   iLinkNode[ iSide ][ 1 ] = iNode;
9880                 }
9881                 //else if ( notLinkNodes[ iSide ][ 0 ] )
9882                 //  notLinkNodes[ iSide ][ 1 ] = n;
9883                 //else
9884                 //  notLinkNodes[ iSide ][ 0 ] = n;
9885                 else {
9886                   nbl++;
9887                   if(iSide==0)
9888                     notLinkNodes1[nbl] = n;
9889                   //notLinkNodes1.push_back(n);
9890                   else
9891                     notLinkNodes2[nbl] = n;
9892                   //notLinkNodes2.push_back(n);
9893                 }
9894                 //faceNodes[ iSide ][ iNode++ ] = n;
9895                 if(iSide==0) {
9896                   fnodes1[iNode++] = n;
9897                 }
9898                 else {
9899                   fnodes2[iNode++] = n;
9900                 }
9901               }
9902             }
9903             else { // f->IsQuadratic()
9904               const SMDS_VtkFace* F =
9905                 dynamic_cast<const SMDS_VtkFace*>(f);
9906               if (!F) throw SALOME_Exception(LOCALIZED("not an SMDS_VtkFace"));
9907               // use special nodes iterator
9908               SMDS_ElemIteratorPtr anIter = F->interlacedNodesElemIterator();
9909               while ( anIter->more() ) {
9910                 const SMDS_MeshNode* n =
9911                   static_cast<const SMDS_MeshNode*>( anIter->next() );
9912                 if ( n == n1 ) {
9913                   iLinkNode[ iSide ][ 0 ] = iNode;
9914                 }
9915                 else if ( n == n2 ) {
9916                   iLinkNode[ iSide ][ 1 ] = iNode;
9917                 }
9918                 else {
9919                   nbl++;
9920                   if(iSide==0) {
9921                     notLinkNodes1[nbl] = n;
9922                   }
9923                   else {
9924                     notLinkNodes2[nbl] = n;
9925                   }
9926                 }
9927                 if(iSide==0) {
9928                   fnodes1[iNode++] = n;
9929                 }
9930                 else {
9931                   fnodes2[iNode++] = n;
9932                 }
9933               }
9934             }
9935             //faceNodes[ iSide ][ iNode ] = faceNodes[ iSide ][ 0 ];
9936             if(iSide==0) {
9937               fnodes1[iNode] = fnodes1[0];
9938             }
9939             else {
9940               fnodes2[iNode] = fnodes1[0];
9941             }
9942           }
9943         }
9944       }
9945     }
9946
9947     // check similarity of elements of the sides
9948     if (aResult == SEW_OK && ( face[0] && !face[1] ) || ( !face[0] && face[1] )) {
9949       MESSAGE("Correspondent face not found on side " << ( face[0] ? 1 : 0 ));
9950       if ( nReplaceMap.size() == 2 ) { // faces on input nodes not found
9951         aResult = ( face[0] ? SEW_BAD_SIDE2_NODES : SEW_BAD_SIDE1_NODES );
9952       }
9953       else {
9954         aResult = SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
9955       }
9956       break; // do not return because it s necessary to remove tmp faces
9957     }
9958
9959     // set nodes to merge
9960     // -------------------
9961
9962     if ( face[0] && face[1] )  {
9963       int nbNodes = face[0]->NbNodes();
9964       if ( nbNodes != face[1]->NbNodes() ) {
9965         MESSAGE("Diff nb of face nodes");
9966         aResult = SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
9967         break; // do not return because it s necessary to remove tmp faces
9968       }
9969       bool reverse[] = { false, false }; // order of notLinkNodes of quadrangle
9970       if ( nbNodes == 3 ) {
9971         //nReplaceMap.insert( TNodeNodeMap::value_type
9972         //                   ( notLinkNodes[0][0], notLinkNodes[1][0] ));
9973         nReplaceMap.insert( TNodeNodeMap::value_type
9974                             ( notLinkNodes1[0], notLinkNodes2[0] ));
9975       }
9976       else {
9977         for ( iSide = 0; iSide < 2; iSide++ ) { // loop on 2 sides
9978           // analyse link orientation in faces
9979           int i1 = iLinkNode[ iSide ][ 0 ];
9980           int i2 = iLinkNode[ iSide ][ 1 ];
9981           reverse[ iSide ] = Abs( i1 - i2 ) == 1 ? i1 > i2 : i2 > i1;
9982           // if notLinkNodes are the first and the last ones, then
9983           // their order does not correspond to the link orientation
9984           if (( i1 == 1 && i2 == 2 ) ||
9985               ( i1 == 2 && i2 == 1 ))
9986             reverse[ iSide ] = !reverse[ iSide ];
9987         }
9988         if ( reverse[0] == reverse[1] ) {
9989           //nReplaceMap.insert( TNodeNodeMap::value_type
9990           //                   ( notLinkNodes[0][0], notLinkNodes[1][0] ));
9991           //nReplaceMap.insert( TNodeNodeMap::value_type
9992           //                   ( notLinkNodes[0][1], notLinkNodes[1][1] ));
9993           for(int nn=0; nn<nbNodes-2; nn++) {
9994             nReplaceMap.insert( TNodeNodeMap::value_type
9995                                 ( notLinkNodes1[nn], notLinkNodes2[nn] ));
9996           }
9997         }
9998         else {
9999           //nReplaceMap.insert( TNodeNodeMap::value_type
10000           //                   ( notLinkNodes[0][0], notLinkNodes[1][1] ));
10001           //nReplaceMap.insert( TNodeNodeMap::value_type
10002           //                   ( notLinkNodes[0][1], notLinkNodes[1][0] ));
10003           for(int nn=0; nn<nbNodes-2; nn++) {
10004             nReplaceMap.insert( TNodeNodeMap::value_type
10005                                 ( notLinkNodes1[nn], notLinkNodes2[nbNodes-3-nn] ));
10006           }
10007         }
10008       }
10009
10010       // add other links of the faces to linkList
10011       // -----------------------------------------
10012
10013       //const SMDS_MeshNode** nodes = faceNodes[ 0 ];
10014       for ( iNode = 0; iNode < nbNodes; iNode++ )  {
10015         //linkID = aLinkID_Gen.GetLinkID( nodes[iNode], nodes[iNode+1] );
10016         linkID = aLinkID_Gen.GetLinkID( fnodes1[iNode], fnodes1[iNode+1] );
10017         pair< set<long>::iterator, bool > iter_isnew = linkIdSet.insert( linkID );
10018         if ( !iter_isnew.second ) { // already in a set: no need to process
10019           linkIdSet.erase( iter_isnew.first );
10020         }
10021         else // new in set == encountered for the first time: add
10022         {
10023           //const SMDS_MeshNode* n1 = nodes[ iNode ];
10024           //const SMDS_MeshNode* n2 = nodes[ iNode + 1];
10025           const SMDS_MeshNode* n1 = fnodes1[ iNode ];
10026           const SMDS_MeshNode* n2 = fnodes1[ iNode + 1];
10027           linkList[0].push_back ( NLink( n1, n2 ));
10028           linkList[1].push_back ( NLink( nReplaceMap[n1], nReplaceMap[n2] ));
10029         }
10030       }
10031     } // 2 faces found
10032   } // loop on link lists
10033
10034   if ( aResult == SEW_OK &&
10035        ( linkIt[0] != linkList[0].end() ||
10036          !faceSetPtr[0]->empty() || !faceSetPtr[1]->empty() )) {
10037     MESSAGE( (linkIt[0] != linkList[0].end()) <<" "<< (faceSetPtr[0]->empty()) <<
10038              " " << (faceSetPtr[1]->empty()));
10039     aResult = SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
10040   }
10041
10042   // ====================================================================
10043   // 3. Replace nodes in elements of the side 1 and remove replaced nodes
10044   // ====================================================================
10045
10046   // delete temporary faces: they are in reverseElements of actual nodes
10047 //  SMDS_FaceIteratorPtr tmpFaceIt = aTmpFacesMesh.facesIterator();
10048 //  while ( tmpFaceIt->more() )
10049 //    aTmpFacesMesh.RemoveElement( tmpFaceIt->next() );
10050 //  list<const SMDS_MeshElement* >::iterator tmpFaceIt = tempFaceList.begin();
10051 //  for (; tmpFaceIt !=tempFaceList.end(); ++tmpFaceIt)
10052 //    aMesh->RemoveElement(*tmpFaceIt);
10053
10054   if ( aResult != SEW_OK)
10055     return aResult;
10056
10057   list< int > nodeIDsToRemove/*, elemIDsToRemove*/;
10058   // loop on nodes replacement map
10059   TNodeNodeMap::iterator nReplaceMapIt = nReplaceMap.begin(), nnIt;
10060   for ( ; nReplaceMapIt != nReplaceMap.end(); nReplaceMapIt++ )
10061     if ( (*nReplaceMapIt).first != (*nReplaceMapIt).second ) {
10062       const SMDS_MeshNode* nToRemove = (*nReplaceMapIt).first;
10063       nodeIDsToRemove.push_back( nToRemove->GetID() );
10064       // loop on elements sharing nToRemove
10065       SMDS_ElemIteratorPtr invElemIt = nToRemove->GetInverseElementIterator();
10066       while ( invElemIt->more() ) {
10067         const SMDS_MeshElement* e = invElemIt->next();
10068         // get a new suite of nodes: make replacement
10069         int nbReplaced = 0, i = 0, nbNodes = e->NbNodes();
10070         vector< const SMDS_MeshNode*> nodes( nbNodes );
10071         SMDS_ElemIteratorPtr nIt = e->nodesIterator();
10072         while ( nIt->more() ) {
10073           const SMDS_MeshNode* n =
10074             static_cast<const SMDS_MeshNode*>( nIt->next() );
10075           nnIt = nReplaceMap.find( n );
10076           if ( nnIt != nReplaceMap.end() ) {
10077             nbReplaced++;
10078             n = (*nnIt).second;
10079           }
10080           nodes[ i++ ] = n;
10081         }
10082         //       if ( nbReplaced == nbNodes && e->GetType() == SMDSAbs_Face )
10083         //         elemIDsToRemove.push_back( e->GetID() );
10084         //       else
10085         if ( nbReplaced )
10086           {
10087             SMDSAbs_ElementType etyp = e->GetType();
10088             SMDS_MeshElement* newElem = this->AddElement(nodes, etyp, false);
10089             if (newElem)
10090               {
10091                 myLastCreatedElems.Append(newElem);
10092                 AddToSameGroups(newElem, e, aMesh);
10093                 int aShapeId = e->getshapeId();
10094                 if ( aShapeId )
10095                   {
10096                     aMesh->SetMeshElementOnShape( newElem, aShapeId );
10097                   }
10098               }
10099             aMesh->RemoveElement(e);
10100           }
10101       }
10102     }
10103
10104   Remove( nodeIDsToRemove, true );
10105
10106   return aResult;
10107 }
10108
10109 //================================================================================
10110 /*!
10111  * \brief Find corresponding nodes in two sets of faces
10112  * \param theSide1 - first face set
10113  * \param theSide2 - second first face
10114  * \param theFirstNode1 - a boundary node of set 1
10115  * \param theFirstNode2 - a node of set 2 corresponding to theFirstNode1
10116  * \param theSecondNode1 - a boundary node of set 1 linked with theFirstNode1
10117  * \param theSecondNode2 - a node of set 2 corresponding to theSecondNode1
10118  * \param nReplaceMap - output map of corresponding nodes
10119  * \retval bool  - is a success or not
10120  */
10121 //================================================================================
10122
10123 #ifdef _DEBUG_
10124 //#define DEBUG_MATCHING_NODES
10125 #endif
10126
10127 SMESH_MeshEditor::Sew_Error
10128 SMESH_MeshEditor::FindMatchingNodes(set<const SMDS_MeshElement*>& theSide1,
10129                                     set<const SMDS_MeshElement*>& theSide2,
10130                                     const SMDS_MeshNode*          theFirstNode1,
10131                                     const SMDS_MeshNode*          theFirstNode2,
10132                                     const SMDS_MeshNode*          theSecondNode1,
10133                                     const SMDS_MeshNode*          theSecondNode2,
10134                                     TNodeNodeMap &                nReplaceMap)
10135 {
10136   set<const SMDS_MeshElement*> * faceSetPtr[] = { &theSide1, &theSide2 };
10137
10138   nReplaceMap.clear();
10139   if ( theFirstNode1 != theFirstNode2 )
10140     nReplaceMap.insert( make_pair( theFirstNode1, theFirstNode2 ));
10141   if ( theSecondNode1 != theSecondNode2 )
10142     nReplaceMap.insert( make_pair( theSecondNode1, theSecondNode2 ));
10143
10144   set< SMESH_TLink > linkSet; // set of nodes where order of nodes is ignored
10145   linkSet.insert( SMESH_TLink( theFirstNode1, theSecondNode1 ));
10146
10147   list< NLink > linkList[2];
10148   linkList[0].push_back( NLink( theFirstNode1, theSecondNode1 ));
10149   linkList[1].push_back( NLink( theFirstNode2, theSecondNode2 ));
10150
10151   // loop on links in linkList; find faces by links and append links
10152   // of the found faces to linkList
10153   list< NLink >::iterator linkIt[] = { linkList[0].begin(), linkList[1].begin() } ;
10154   for ( ; linkIt[0] != linkList[0].end(); linkIt[0]++, linkIt[1]++ ) {
10155     NLink link[] = { *linkIt[0], *linkIt[1] };
10156     if ( linkSet.find( link[0] ) == linkSet.end() )
10157       continue;
10158
10159     // by links, find faces in the face sets,
10160     // and find indices of link nodes in the found faces;
10161     // in a face set, there is only one or no face sharing a link
10162     // ---------------------------------------------------------------
10163
10164     const SMDS_MeshElement* face[] = { 0, 0 };
10165     list<const SMDS_MeshNode*> notLinkNodes[2];
10166     //bool reverse[] = { false, false }; // order of notLinkNodes
10167     int nbNodes[2];
10168     for ( int iSide = 0; iSide < 2; iSide++ ) // loop on 2 sides
10169     {
10170       const SMDS_MeshNode* n1 = link[iSide].first;
10171       const SMDS_MeshNode* n2 = link[iSide].second;
10172       set<const SMDS_MeshElement*> * faceSet = faceSetPtr[ iSide ];
10173       set< const SMDS_MeshElement* > facesOfNode1;
10174       for ( int iNode = 0; iNode < 2; iNode++ ) // loop on 2 nodes of a link
10175       {
10176         // during a loop of the first node, we find all faces around n1,
10177         // during a loop of the second node, we find one face sharing both n1 and n2
10178         const SMDS_MeshNode* n = iNode ? n1 : n2; // a node of a link
10179         SMDS_ElemIteratorPtr fIt = n->GetInverseElementIterator(SMDSAbs_Face);
10180         while ( fIt->more() ) { // loop on faces sharing a node
10181           const SMDS_MeshElement* f = fIt->next();
10182           if (faceSet->find( f ) != faceSet->end() && // f is in face set
10183               ! facesOfNode1.insert( f ).second ) // f encounters twice
10184           {
10185             if ( face[ iSide ] ) {
10186               MESSAGE( "2 faces per link " );
10187               return ( iSide ? SEW_BAD_SIDE2_NODES : SEW_BAD_SIDE1_NODES );
10188             }
10189             face[ iSide ] = f;
10190             faceSet->erase( f );
10191
10192             // get not link nodes
10193             int nbN = f->NbNodes();
10194             if ( f->IsQuadratic() )
10195               nbN /= 2;
10196             nbNodes[ iSide ] = nbN;
10197             list< const SMDS_MeshNode* > & nodes = notLinkNodes[ iSide ];
10198             int i1 = f->GetNodeIndex( n1 );
10199             int i2 = f->GetNodeIndex( n2 );
10200             int iEnd = nbN, iBeg = -1, iDelta = 1;
10201             bool reverse = ( Abs( i1 - i2 ) == 1 ? i1 > i2 : i2 > i1 );
10202             if ( reverse ) {
10203               std::swap( iEnd, iBeg ); iDelta = -1;
10204             }
10205             int i = i2;
10206             while ( true ) {
10207               i += iDelta;
10208               if ( i == iEnd ) i = iBeg + iDelta;
10209               if ( i == i1 ) break;
10210               nodes.push_back ( f->GetNode( i ) );
10211             }
10212           }
10213         }
10214       }
10215     }
10216     // check similarity of elements of the sides
10217     if (( face[0] && !face[1] ) || ( !face[0] && face[1] )) {
10218       MESSAGE("Correspondent face not found on side " << ( face[0] ? 1 : 0 ));
10219       if ( nReplaceMap.size() == 2 ) { // faces on input nodes not found
10220         return ( face[0] ? SEW_BAD_SIDE2_NODES : SEW_BAD_SIDE1_NODES );
10221       }
10222       else {
10223         return SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
10224       }
10225     }
10226
10227     // set nodes to merge
10228     // -------------------
10229
10230     if ( face[0] && face[1] )  {
10231       if ( nbNodes[0] != nbNodes[1] ) {
10232         MESSAGE("Diff nb of face nodes");
10233         return SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
10234       }
10235 #ifdef DEBUG_MATCHING_NODES
10236       MESSAGE ( " Link 1: " << link[0].first->GetID() <<" "<< link[0].second->GetID()
10237                 << " F 1: " << face[0] << "| Link 2: " << link[1].first->GetID() <<" "
10238                 << link[1].second->GetID() << " F 2: " << face[1] << " | Bind: " ) ;
10239 #endif
10240       int nbN = nbNodes[0];
10241       {
10242         list<const SMDS_MeshNode*>::iterator n1 = notLinkNodes[0].begin();
10243         list<const SMDS_MeshNode*>::iterator n2 = notLinkNodes[1].begin();
10244         for ( int i = 0 ; i < nbN - 2; ++i ) {
10245 #ifdef DEBUG_MATCHING_NODES
10246           MESSAGE ( (*n1)->GetID() << " to " << (*n2)->GetID() );
10247 #endif
10248           nReplaceMap.insert( make_pair( *(n1++), *(n2++) ));
10249         }
10250       }
10251
10252       // add other links of the face 1 to linkList
10253       // -----------------------------------------
10254
10255       const SMDS_MeshElement* f0 = face[0];
10256       const SMDS_MeshNode* n1 = f0->GetNode( nbN - 1 );
10257       for ( int i = 0; i < nbN; i++ )
10258       {
10259         const SMDS_MeshNode* n2 = f0->GetNode( i );
10260         pair< set< SMESH_TLink >::iterator, bool > iter_isnew =
10261           linkSet.insert( SMESH_TLink( n1, n2 ));
10262         if ( !iter_isnew.second ) { // already in a set: no need to process
10263           linkSet.erase( iter_isnew.first );
10264         }
10265         else // new in set == encountered for the first time: add
10266         {
10267 #ifdef DEBUG_MATCHING_NODES
10268           MESSAGE ( "Add link 1: " << n1->GetID() << " " << n2->GetID() << " "
10269                     << " | link 2: " << nReplaceMap[n1]->GetID() << " " << nReplaceMap[n2]->GetID() << " " );
10270 #endif
10271           linkList[0].push_back ( NLink( n1, n2 ));
10272           linkList[1].push_back ( NLink( nReplaceMap[n1], nReplaceMap[n2] ));
10273         }
10274         n1 = n2;
10275       }
10276     } // 2 faces found
10277   } // loop on link lists
10278
10279   return SEW_OK;
10280 }
10281
10282 //================================================================================
10283 /*!
10284   \brief Creates a hole in a mesh by doubling the nodes of some particular elements
10285   \param theElems - the list of elements (edges or faces) to be replicated
10286   The nodes for duplication could be found from these elements
10287   \param theNodesNot - list of nodes to NOT replicate
10288   \param theAffectedElems - the list of elements (cells and edges) to which the 
10289   replicated nodes should be associated to.
10290   \return TRUE if operation has been completed successfully, FALSE otherwise
10291 */
10292 //================================================================================
10293
10294 bool SMESH_MeshEditor::DoubleNodes( const TIDSortedElemSet& theElems,
10295                                     const TIDSortedElemSet& theNodesNot,
10296                                     const TIDSortedElemSet& theAffectedElems )
10297 {
10298   myLastCreatedElems.Clear();
10299   myLastCreatedNodes.Clear();
10300
10301   if ( theElems.size() == 0 )
10302     return false;
10303
10304   SMESHDS_Mesh* aMeshDS = GetMeshDS();
10305   if ( !aMeshDS )
10306     return false;
10307
10308   bool res = false;
10309   std::map< const SMDS_MeshNode*, const SMDS_MeshNode* > anOldNodeToNewNode;
10310   // duplicate elements and nodes
10311   res = doubleNodes( aMeshDS, theElems, theNodesNot, anOldNodeToNewNode, true );
10312   // replce nodes by duplications
10313   res = doubleNodes( aMeshDS, theAffectedElems, theNodesNot, anOldNodeToNewNode, false );
10314   return res;
10315 }
10316
10317 //================================================================================
10318 /*!
10319   \brief Creates a hole in a mesh by doubling the nodes of some particular elements
10320   \param theMeshDS - mesh instance
10321   \param theElems - the elements replicated or modified (nodes should be changed)
10322   \param theNodesNot - nodes to NOT replicate
10323   \param theNodeNodeMap - relation of old node to new created node
10324   \param theIsDoubleElem - flag os to replicate element or modify
10325   \return TRUE if operation has been completed successfully, FALSE otherwise
10326 */
10327 //================================================================================
10328
10329 bool SMESH_MeshEditor::doubleNodes( SMESHDS_Mesh*     theMeshDS,
10330                                     const TIDSortedElemSet& theElems,
10331                                     const TIDSortedElemSet& theNodesNot,
10332                                     std::map< const SMDS_MeshNode*,
10333                                     const SMDS_MeshNode* >& theNodeNodeMap,
10334                                     const bool theIsDoubleElem )
10335 {
10336   MESSAGE("doubleNodes");
10337   // iterate on through element and duplicate them (by nodes duplication)
10338   bool res = false;
10339   TIDSortedElemSet::const_iterator elemItr = theElems.begin();
10340   for ( ;  elemItr != theElems.end(); ++elemItr )
10341   {
10342     const SMDS_MeshElement* anElem = *elemItr;
10343     if (!anElem)
10344       continue;
10345
10346     bool isDuplicate = false;
10347     // duplicate nodes to duplicate element
10348     std::vector<const SMDS_MeshNode*> newNodes( anElem->NbNodes() );
10349     SMDS_ElemIteratorPtr anIter = anElem->nodesIterator();
10350     int ind = 0;
10351     while ( anIter->more() ) 
10352     { 
10353
10354       SMDS_MeshNode* aCurrNode = (SMDS_MeshNode*)anIter->next();
10355       SMDS_MeshNode* aNewNode = aCurrNode;
10356       if ( theNodeNodeMap.find( aCurrNode ) != theNodeNodeMap.end() )
10357         aNewNode = (SMDS_MeshNode*)theNodeNodeMap[ aCurrNode ];
10358       else if ( theIsDoubleElem && theNodesNot.find( aCurrNode ) == theNodesNot.end() )
10359       {
10360         // duplicate node
10361         aNewNode = theMeshDS->AddNode( aCurrNode->X(), aCurrNode->Y(), aCurrNode->Z() );
10362         theNodeNodeMap[ aCurrNode ] = aNewNode;
10363         myLastCreatedNodes.Append( aNewNode );
10364       }
10365       isDuplicate |= (aCurrNode != aNewNode);
10366       newNodes[ ind++ ] = aNewNode;
10367     }
10368     if ( !isDuplicate )
10369       continue;
10370
10371     if ( theIsDoubleElem )
10372       AddElement(newNodes, anElem->GetType(), anElem->IsPoly());
10373     else
10374       {
10375       MESSAGE("ChangeElementNodes");
10376       theMeshDS->ChangeElementNodes( anElem, &newNodes[ 0 ], anElem->NbNodes() );
10377       }
10378     res = true;
10379   }
10380   return res;
10381 }
10382
10383 //================================================================================
10384 /*!
10385   \brief Creates a hole in a mesh by doubling the nodes of some particular elements
10386   \param theNodes - identifiers of nodes to be doubled
10387   \param theModifiedElems - identifiers of elements to be updated by the new (doubled) 
10388          nodes. If list of element identifiers is empty then nodes are doubled but 
10389          they not assigned to elements
10390   \return TRUE if operation has been completed successfully, FALSE otherwise
10391 */
10392 //================================================================================
10393
10394 bool SMESH_MeshEditor::DoubleNodes( const std::list< int >& theListOfNodes, 
10395                                     const std::list< int >& theListOfModifiedElems )
10396 {
10397   MESSAGE("DoubleNodes");
10398   myLastCreatedElems.Clear();
10399   myLastCreatedNodes.Clear();
10400
10401   if ( theListOfNodes.size() == 0 )
10402     return false;
10403
10404   SMESHDS_Mesh* aMeshDS = GetMeshDS();
10405   if ( !aMeshDS )
10406     return false;
10407
10408   // iterate through nodes and duplicate them
10409
10410   std::map< const SMDS_MeshNode*, const SMDS_MeshNode* > anOldNodeToNewNode;
10411
10412   std::list< int >::const_iterator aNodeIter;
10413   for ( aNodeIter = theListOfNodes.begin(); aNodeIter != theListOfNodes.end(); ++aNodeIter )
10414   {
10415     int aCurr = *aNodeIter;
10416     SMDS_MeshNode* aNode = (SMDS_MeshNode*)aMeshDS->FindNode( aCurr );
10417     if ( !aNode )
10418       continue;
10419
10420     // duplicate node
10421
10422     const SMDS_MeshNode* aNewNode = aMeshDS->AddNode( aNode->X(), aNode->Y(), aNode->Z() );
10423     if ( aNewNode )
10424     {
10425       anOldNodeToNewNode[ aNode ] = aNewNode;
10426       myLastCreatedNodes.Append( aNewNode );
10427     }
10428   }
10429
10430   // Create map of new nodes for modified elements
10431
10432   std::map< SMDS_MeshElement*, vector<const SMDS_MeshNode*> > anElemToNodes;
10433
10434   std::list< int >::const_iterator anElemIter;
10435   for ( anElemIter = theListOfModifiedElems.begin(); 
10436         anElemIter != theListOfModifiedElems.end(); ++anElemIter )
10437   {
10438     int aCurr = *anElemIter;
10439     SMDS_MeshElement* anElem = (SMDS_MeshElement*)aMeshDS->FindElement( aCurr );
10440     if ( !anElem )
10441       continue;
10442
10443     vector<const SMDS_MeshNode*> aNodeArr( anElem->NbNodes() );
10444
10445     SMDS_ElemIteratorPtr anIter = anElem->nodesIterator();
10446     int ind = 0;
10447     while ( anIter->more() ) 
10448     { 
10449       SMDS_MeshNode* aCurrNode = (SMDS_MeshNode*)anIter->next();
10450       if ( aCurr && anOldNodeToNewNode.find( aCurrNode ) != anOldNodeToNewNode.end() )
10451       {
10452         const SMDS_MeshNode* aNewNode = anOldNodeToNewNode[ aCurrNode ];
10453         aNodeArr[ ind++ ] = aNewNode;
10454       }
10455       else
10456         aNodeArr[ ind++ ] = aCurrNode;
10457     }
10458     anElemToNodes[ anElem ] = aNodeArr;
10459   }
10460
10461   // Change nodes of elements  
10462
10463   std::map< SMDS_MeshElement*, vector<const SMDS_MeshNode*> >::iterator
10464     anElemToNodesIter = anElemToNodes.begin();
10465   for ( ; anElemToNodesIter != anElemToNodes.end(); ++anElemToNodesIter )
10466   {
10467     const SMDS_MeshElement* anElem = anElemToNodesIter->first;
10468     vector<const SMDS_MeshNode*> aNodeArr = anElemToNodesIter->second;
10469     if ( anElem )
10470       {
10471       MESSAGE("ChangeElementNodes");
10472       aMeshDS->ChangeElementNodes( anElem, &aNodeArr[ 0 ], anElem->NbNodes() );
10473       }
10474   }
10475
10476   return true;
10477 }
10478
10479 namespace {
10480
10481   //================================================================================
10482   /*!
10483   \brief Check if element located inside shape
10484   \return TRUE if IN or ON shape, FALSE otherwise
10485   */
10486   //================================================================================
10487
10488   template<class Classifier>
10489   bool isInside(const SMDS_MeshElement* theElem,
10490                 Classifier&             theClassifier,
10491                 const double            theTol)
10492   {
10493     gp_XYZ centerXYZ (0, 0, 0);
10494     SMDS_ElemIteratorPtr aNodeItr = theElem->nodesIterator();
10495     while (aNodeItr->more())
10496       centerXYZ += SMESH_MeshEditor::TNodeXYZ(cast2Node( aNodeItr->next()));
10497
10498     gp_Pnt aPnt = centerXYZ / theElem->NbNodes();
10499     theClassifier.Perform(aPnt, theTol);
10500     TopAbs_State aState = theClassifier.State();
10501     return (aState == TopAbs_IN || aState == TopAbs_ON );
10502   }
10503
10504   //================================================================================
10505   /*!
10506    * \brief Classifier of the 3D point on the TopoDS_Face
10507    *        with interaface suitable for isInside()
10508    */
10509   //================================================================================
10510
10511   struct _FaceClassifier
10512   {
10513     Extrema_ExtPS       _extremum;
10514     BRepAdaptor_Surface _surface;
10515     TopAbs_State        _state;
10516
10517     _FaceClassifier(const TopoDS_Face& face):_extremum(),_surface(face),_state(TopAbs_OUT)
10518     {
10519       _extremum.Initialize( _surface,
10520                             _surface.FirstUParameter(), _surface.LastUParameter(),
10521                             _surface.FirstVParameter(), _surface.LastVParameter(),
10522                             _surface.Tolerance(), _surface.Tolerance() );
10523     }
10524     void Perform(const gp_Pnt& aPnt, double theTol)
10525     {
10526       _state = TopAbs_OUT;
10527       _extremum.Perform(aPnt);
10528       if ( _extremum.IsDone() )
10529         for ( int iSol = 1; iSol <= _extremum.NbExt() && _state == TopAbs_OUT; ++iSol)
10530           _state = ( _extremum.Value(iSol) <= theTol ? TopAbs_IN : TopAbs_OUT );
10531     }
10532     TopAbs_State State() const
10533     {
10534       return _state;
10535     }
10536   };
10537 }
10538
10539 //================================================================================
10540 /*!
10541   \brief Creates a hole in a mesh by doubling the nodes of some particular elements
10542   \param theElems - group of of elements (edges or faces) to be replicated
10543   \param theNodesNot - group of nodes not to replicate
10544   \param theShape - shape to detect affected elements (element which geometric center
10545   located on or inside shape).
10546   The replicated nodes should be associated to affected elements.
10547   \return TRUE if operation has been completed successfully, FALSE otherwise
10548 */
10549 //================================================================================
10550
10551 bool SMESH_MeshEditor::DoubleNodesInRegion( const TIDSortedElemSet& theElems,
10552                                             const TIDSortedElemSet& theNodesNot,
10553                                             const TopoDS_Shape&     theShape )
10554 {
10555   if ( theShape.IsNull() )
10556     return false;
10557
10558   const double aTol = Precision::Confusion();
10559   auto_ptr< BRepClass3d_SolidClassifier> bsc3d;
10560   auto_ptr<_FaceClassifier>              aFaceClassifier;
10561   if ( theShape.ShapeType() == TopAbs_SOLID )
10562   {
10563     bsc3d.reset( new BRepClass3d_SolidClassifier(theShape));;
10564     bsc3d->PerformInfinitePoint(aTol);
10565   }
10566   else if (theShape.ShapeType() == TopAbs_FACE )
10567   {
10568     aFaceClassifier.reset( new _FaceClassifier(TopoDS::Face(theShape)));
10569   }
10570
10571   // iterates on indicated elements and get elements by back references from their nodes
10572   TIDSortedElemSet anAffected;
10573   TIDSortedElemSet::const_iterator elemItr = theElems.begin();
10574   for ( ;  elemItr != theElems.end(); ++elemItr )
10575   {
10576     SMDS_MeshElement* anElem = (SMDS_MeshElement*)*elemItr;
10577     if (!anElem)
10578       continue;
10579
10580     SMDS_ElemIteratorPtr nodeItr = anElem->nodesIterator();
10581     while ( nodeItr->more() )
10582     {
10583       const SMDS_MeshNode* aNode = cast2Node(nodeItr->next());
10584       if ( !aNode || theNodesNot.find(aNode) != theNodesNot.end() )
10585         continue;
10586       SMDS_ElemIteratorPtr backElemItr = aNode->GetInverseElementIterator();
10587       while ( backElemItr->more() )
10588       {
10589         const SMDS_MeshElement* curElem = backElemItr->next();
10590         if ( curElem && theElems.find(curElem) == theElems.end() &&
10591              ( bsc3d.get() ?
10592                isInside( curElem, *bsc3d, aTol ) :
10593                isInside( curElem, *aFaceClassifier, aTol )))
10594           anAffected.insert( curElem );
10595       }
10596     }
10597   }
10598   return DoubleNodes( theElems, theNodesNot, anAffected );
10599 }
10600
10601 /*!
10602  * \brief Double nodes on shared faces between groups of volumes and create flat elements on demand.
10603  * The list of groups must describe a partition of the mesh volumes.
10604  * The nodes of the internal faces at the boundaries of the groups are doubled.
10605  * In option, the internal faces are replaced by flat elements.
10606  * Triangles are transformed in prisms, and quadrangles in hexahedrons.
10607  * @param theElems - list of groups of volumes, where a group of volume is a set of
10608  * SMDS_MeshElements sorted by Id.
10609  * @param createJointElems - if TRUE, create the elements
10610  * @return TRUE if operation has been completed successfully, FALSE otherwise
10611  */
10612 bool SMESH_MeshEditor::DoubleNodesOnGroupBoundaries( const std::vector<TIDSortedElemSet>& theElems,
10613                                                      bool createJointElems)
10614 {
10615   MESSAGE("------------------------------------------------------");
10616   MESSAGE("SMESH_MeshEditor::CreateJointElementsOnGroupBoundaries");
10617   MESSAGE("------------------------------------------------------");
10618
10619   SMESHDS_Mesh *meshDS = this->myMesh->GetMeshDS();
10620   meshDS->BuildDownWardConnectivity(false);
10621   CHRONO(50);
10622   SMDS_UnstructuredGrid *grid = meshDS->getGrid();
10623
10624   // --- build the list of faces shared by 2 domains (group of elements), with their domain and volume indexes
10625   //     build the list of nodes shared by 2 or more domains, with their domain indexes
10626
10627   std::map<DownIdType, std::map<int,int>, DownIdCompare> faceDomains; // 2x(id domain --> id volume)
10628   std::map<int, std::map<int,int> > nodeDomains; //oldId ->  (domainId -> newId)
10629   faceDomains.clear();
10630   nodeDomains.clear();
10631   std::map<int,int> emptyMap;
10632   emptyMap.clear();
10633
10634   for (int idom = 0; idom < theElems.size(); idom++)
10635     {
10636
10637       // --- build a map (face to duplicate --> volume to modify)
10638       //     with all the faces shared by 2 domains (group of elements)
10639       //     and corresponding volume of this domain, for each shared face.
10640       //     a volume has a face shared by 2 domains if it has a neighbor which is not in is domain.
10641
10642       const TIDSortedElemSet& domain = theElems[idom];
10643       TIDSortedElemSet::const_iterator elemItr = domain.begin();
10644       for (; elemItr != domain.end(); ++elemItr)
10645         {
10646           SMDS_MeshElement* anElem = (SMDS_MeshElement*) *elemItr;
10647           if (!anElem)
10648             continue;
10649           int vtkId = anElem->getVtkId();
10650           int neighborsVtkIds[NBMAXNEIGHBORS];
10651           int downIds[NBMAXNEIGHBORS];
10652           unsigned char downTypes[NBMAXNEIGHBORS];
10653           int nbNeighbors = grid->GetNeighbors(neighborsVtkIds, downIds, downTypes, vtkId);
10654           for (int n = 0; n < nbNeighbors; n++)
10655             {
10656               int smdsId = meshDS->fromVtkToSmds(neighborsVtkIds[n]);
10657               const SMDS_MeshElement* elem = meshDS->FindElement(smdsId);
10658               if (! domain.count(elem)) // neighbor is in another domain : face is shared
10659                 {
10660                   DownIdType face(downIds[n], downTypes[n]);
10661                   if (!faceDomains.count(face))
10662                     faceDomains[face] = emptyMap; // create an empty entry for face
10663                   if (!faceDomains[face].count(idom))
10664                     {
10665                       faceDomains[face][idom] = vtkId; // volume associated to face in this domain
10666                     }
10667                 }
10668             }
10669         }
10670     }
10671
10672   MESSAGE("Number of shared faces " << faceDomains.size());
10673
10674   // --- for each shared face, get the nodes
10675   //     for each node, for each domain of the face, create a clone of the node
10676
10677   std::map<DownIdType, std::map<int,int>, DownIdCompare>::iterator itface = faceDomains.begin();
10678   for( ; itface != faceDomains.end();++itface )
10679     {
10680       DownIdType face = itface->first;
10681       std::map<int,int> domvol = itface->second;
10682       std::set<int> oldNodes;
10683       oldNodes.clear();
10684       grid->GetNodeIds(oldNodes, face.cellId, face.cellType);
10685       std::set<int>::iterator itn = oldNodes.begin();
10686       for (;itn != oldNodes.end(); ++itn)
10687         {
10688           int oldId = *itn;
10689           if (!nodeDomains.count(oldId))
10690             nodeDomains[oldId] = emptyMap; // create an empty entry for node
10691           std::map<int,int>::iterator itdom = domvol.begin();
10692           for(; itdom != domvol.end(); ++itdom)
10693             {
10694               int idom = itdom->first;
10695               if ( nodeDomains[oldId].empty() )
10696                 nodeDomains[oldId][idom] = oldId; // keep the old node in the first domain
10697               else
10698                 {
10699                   double *coords = grid->GetPoint(oldId);
10700                   SMDS_MeshNode *newNode = meshDS->AddNode(coords[0], coords[1], coords[2]);
10701                   int newId = newNode->getVtkId();
10702                   nodeDomains[oldId][idom] = newId; // cloned node for other domains
10703                 }
10704             }
10705         }
10706     }
10707
10708   // --- iterate on shared faces (volumes to modify, face to extrude)
10709   //     get node id's of the face (id SMDS = id VTK)
10710   //     create flat element with old and new nodes if requested
10711
10712   if (createJointElems)
10713     {
10714       itface = faceDomains.begin();
10715       for( ; itface != faceDomains.end();++itface )
10716         {
10717           DownIdType face = itface->first;
10718           std::set<int> oldNodes;
10719           std::set<int>::iterator itn;
10720           oldNodes.clear();
10721           grid->GetNodeIds(oldNodes, face.cellId, face.cellType);
10722           std::map<int,int> localClonedNodeIds;
10723
10724           std::map<int,int> domvol = itface->second;
10725           std::map<int,int>::iterator itdom = domvol.begin();
10726           int dom1 = itdom->first;
10727           int vtkVolId = itdom->second;
10728           itdom++;
10729           int dom2 = itdom->first;
10730
10731           localClonedNodeIds.clear();
10732           for (itn = oldNodes.begin(); itn != oldNodes.end(); ++itn)
10733             {
10734               int oldId = *itn;
10735               int refid = oldId;
10736               if (nodeDomains[oldId].count(dom1))
10737                 refid = nodeDomains[oldId][dom1];
10738               else
10739                 MESSAGE("--- problem domain node " << dom1 << " " << oldId);
10740               int newid = oldId;
10741               if (nodeDomains[oldId].count(dom2))
10742                 newid = nodeDomains[oldId][dom2];
10743               else
10744                 MESSAGE("--- problem domain node " << dom2 << " " << oldId);
10745               localClonedNodeIds[oldId] = newid;
10746             }
10747           meshDS->extrudeVolumeFromFace(vtkVolId, localClonedNodeIds);
10748         }
10749     }
10750
10751   // --- iterate on shared faces (volumes to modify, face to extrude)
10752   //     get node id's of the face
10753   //     replace old nodes by new nodes in volumes, and update inverse connectivity
10754
10755   itface = faceDomains.begin();
10756   for( ; itface != faceDomains.end();++itface )
10757     {
10758       DownIdType face = itface->first;
10759       std::set<int> oldNodes;
10760       std::set<int>::iterator itn;
10761       oldNodes.clear();
10762       grid->GetNodeIds(oldNodes, face.cellId, face.cellType);
10763       std::map<int,int> localClonedNodeIds;
10764
10765       std::map<int,int> domvol = itface->second;
10766       std::map<int,int>::iterator itdom = domvol.begin();
10767       for(; itdom != domvol.end(); ++itdom)
10768         {
10769           int idom = itdom->first;
10770           int vtkVolId = itdom->second;
10771           localClonedNodeIds.clear();
10772           for (itn = oldNodes.begin(); itn != oldNodes.end(); ++itn)
10773             {
10774               int oldId = *itn;
10775               if (nodeDomains[oldId].count(idom))
10776                 localClonedNodeIds[oldId] = nodeDomains[oldId][idom];
10777             }
10778           meshDS->ModifyCellNodes(vtkVolId, localClonedNodeIds);
10779         }
10780     }
10781   grid->BuildLinks();
10782
10783   // TODO replace also old nodes by new nodes in faces and edges
10784   CHRONOSTOP(50);
10785   counters::stats();
10786   return true;
10787 }
10788
10789 //================================================================================
10790 /*!
10791  * \brief Generates skin mesh (containing 2D cells) from 3D mesh
10792  * The created 2D mesh elements based on nodes of free faces of boundary volumes
10793  * \return TRUE if operation has been completed successfully, FALSE otherwise
10794  */
10795 //================================================================================
10796
10797 bool SMESH_MeshEditor::Make2DMeshFrom3D()
10798 {
10799   // iterates on volume elements and detect all free faces on them
10800   SMESHDS_Mesh* aMesh = GetMeshDS();
10801   if (!aMesh)
10802     return false;
10803   //bool res = false;
10804   int nbFree = 0, nbExisted = 0, nbCreated = 0;
10805   SMDS_VolumeIteratorPtr vIt = aMesh->volumesIterator();
10806   while(vIt->more())
10807   {
10808     const SMDS_MeshVolume* volume = vIt->next();
10809     SMDS_VolumeTool vTool( volume );
10810     vTool.SetExternalNormal();
10811     const bool isPoly = volume->IsPoly();
10812     const bool isQuad = volume->IsQuadratic();
10813     for ( int iface = 0, n = vTool.NbFaces(); iface < n; iface++ )
10814     {
10815       if (!vTool.IsFreeFace(iface))
10816         continue;
10817       nbFree++;
10818       vector<const SMDS_MeshNode *> nodes;
10819       int nbFaceNodes = vTool.NbFaceNodes(iface);
10820       const SMDS_MeshNode** faceNodes = vTool.GetFaceNodes(iface);
10821       int inode = 0;
10822       for ( ; inode < nbFaceNodes; inode += isQuad ? 2 : 1)
10823         nodes.push_back(faceNodes[inode]);
10824       if (isQuad)
10825         for ( inode = 1; inode < nbFaceNodes; inode += 2)
10826           nodes.push_back(faceNodes[inode]);
10827
10828       // add new face based on volume nodes
10829       if (aMesh->FindFace( nodes ) ) {
10830         nbExisted++;
10831         continue; // face already exsist
10832       }
10833       AddElement(nodes, SMDSAbs_Face, isPoly && iface == 1);
10834       nbCreated++;
10835     }
10836   }
10837   return ( nbFree==(nbExisted+nbCreated) );
10838 }
10839
10840 namespace
10841 {
10842   inline const SMDS_MeshNode* getNodeWithSameID(SMESHDS_Mesh* mesh, const SMDS_MeshNode* node)
10843   {
10844     if ( const SMDS_MeshNode* n = mesh->FindNode( node->GetID() ))
10845       return n;
10846     return mesh->AddNodeWithID( node->X(),node->Y(),node->Z(), node->GetID() );
10847   }
10848 }
10849 //================================================================================
10850 /*!
10851  * \brief Creates missing boundary elements
10852  *  \param elements - elements whose boundary is to be checked
10853  *  \param dimension - defines type of boundary elements to create
10854  *  \param group - a group to store created boundary elements in
10855  *  \param targetMesh - a mesh to store created boundary elements in
10856  *  \param toCopyElements - if true, the checked elements will be copied into the targetMesh
10857  *  \param toCopyExistingBondary - if true, not only new but also pre-existing
10858  *                                boundary elements will be copied into the targetMesh
10859  */
10860 //================================================================================
10861
10862 void SMESH_MeshEditor::MakeBoundaryMesh(const TIDSortedElemSet& elements,
10863                                         Bnd_Dimension           dimension,
10864                                         SMESH_Group*            group/*=0*/,
10865                                         SMESH_Mesh*             targetMesh/*=0*/,
10866                                         bool                    toCopyElements/*=false*/,
10867                                         bool                    toCopyExistingBondary/*=false*/)
10868 {
10869   SMDSAbs_ElementType missType = (dimension == BND_2DFROM3D) ? SMDSAbs_Face : SMDSAbs_Edge;
10870   SMDSAbs_ElementType elemType = (dimension == BND_1DFROM2D) ? SMDSAbs_Face : SMDSAbs_Volume;
10871   // hope that all elements are of the same type, do not check them all
10872   if ( !elements.empty() && (*elements.begin())->GetType() != elemType )
10873     throw SALOME_Exception(LOCALIZED("wrong element type"));
10874
10875   if ( !targetMesh )
10876     toCopyElements = toCopyExistingBondary = false;
10877
10878   SMESH_MeshEditor tgtEditor( targetMesh ? targetMesh : myMesh );
10879   SMESHDS_Mesh* aMesh = GetMeshDS(), *tgtMeshDS = tgtEditor.GetMeshDS();
10880
10881   SMDS_VolumeTool vTool;
10882   TIDSortedElemSet emptySet, avoidSet;
10883   int inode;
10884
10885   typedef vector<const SMDS_MeshNode*> TConnectivity;
10886
10887   SMDS_ElemIteratorPtr eIt;
10888   if (elements.empty())
10889     eIt = aMesh->elementsIterator(elemType);
10890   else
10891     eIt = SMDS_ElemIteratorPtr( new TSetIterator( elements.begin(), elements.end() ));
10892
10893   while (eIt->more())
10894   {
10895     const SMDS_MeshElement* elem = eIt->next();
10896     const int iQuad = elem->IsQuadratic();
10897
10898     // 1. For an elem, get present bnd elements and connectivities of missing bnd elements
10899     vector<const SMDS_MeshElement*> presentBndElems;
10900     vector<TConnectivity>           missingBndElems;
10901     TConnectivity nodes;
10902     if ( vTool.Set(elem) ) // elem is a volume ------------------------------------------
10903     {
10904       vTool.SetExternalNormal();
10905       for ( int iface = 0, n = vTool.NbFaces(); iface < n; iface++ )
10906       {
10907         if (!vTool.IsFreeFace(iface))
10908           continue;
10909         int nbFaceNodes = vTool.NbFaceNodes(iface);
10910         const SMDS_MeshNode** nn = vTool.GetFaceNodes(iface);
10911         if ( missType == SMDSAbs_Edge ) // boundary edges
10912         {
10913           nodes.resize( 2+iQuad );
10914           for ( int i = 0; i < nbFaceNodes; i += 1+iQuad)
10915           {
10916             for ( int j = 0; j < nodes.size(); ++j )
10917               nodes[j] =nn[i+j];
10918             if ( const SMDS_MeshElement* edge =
10919                  aMesh->FindElement(nodes,SMDSAbs_Edge,/*noMedium=*/0))
10920               presentBndElems.push_back( edge );
10921             else
10922               missingBndElems.push_back( nodes );
10923           }
10924         }
10925         else // boundary face
10926         {
10927           nodes.clear();
10928           for ( inode = 0; inode < nbFaceNodes; inode += 1+iQuad)
10929             nodes.push_back( nn[inode] );
10930           if (iQuad)
10931             for ( inode = 1; inode < nbFaceNodes; inode += 2)
10932               nodes.push_back( nn[inode] );
10933
10934           if (const SMDS_MeshFace * f = aMesh->FindFace( nodes ) )
10935             presentBndElems.push_back( f );
10936           else
10937             missingBndElems.push_back( nodes );
10938         }
10939       }
10940     }
10941     else                     // elem is a face ------------------------------------------
10942     {
10943       avoidSet.clear(), avoidSet.insert( elem );
10944       int nbNodes = elem->NbCornerNodes();
10945       nodes.resize( 2 /*+ iQuad*/);
10946       for ( int i = 0; i < nbNodes; i++ )
10947       {
10948         nodes[0] = elem->GetNode(i);
10949         nodes[1] = elem->GetNode((i+1)%nbNodes);
10950         if ( FindFaceInSet( nodes[0], nodes[1], emptySet, avoidSet))
10951           continue; // not free link
10952
10953         //if ( iQuad )
10954         //nodes[2] = elem->GetNode( i + nbNodes );
10955         if ( const SMDS_MeshElement* edge =
10956              aMesh->FindElement(nodes,SMDSAbs_Edge,/*noMedium=*/true))
10957           presentBndElems.push_back( edge );
10958         else
10959           missingBndElems.push_back( nodes );
10960       }
10961     }
10962
10963     // 2. Add missing boundary elements
10964     if ( targetMesh != myMesh )
10965       // instead of making a map of nodes in this mesh and targetMesh,
10966       // we create nodes with same IDs. We can renumber them later, if needed
10967       for ( int i = 0; i < missingBndElems.size(); ++i )
10968       {
10969         TConnectivity& srcNodes = missingBndElems[i];
10970         TConnectivity  nodes( srcNodes.size() );
10971         for ( inode = 0; inode < nodes.size(); ++inode )
10972           nodes[inode] = getNodeWithSameID( tgtMeshDS, srcNodes[inode] );
10973         tgtEditor.AddElement(nodes, missType, elem->IsPoly() && nodes.size()/(iQuad+1)>4);
10974       }
10975     else
10976       for ( int i = 0; i < missingBndElems.size(); ++i )
10977       {
10978         TConnectivity&  nodes = missingBndElems[i];
10979         tgtEditor.AddElement(nodes, missType, elem->IsPoly() && nodes.size()/(iQuad+1)>4);
10980       }
10981
10982     // 3. Copy present boundary elements
10983     if ( toCopyExistingBondary )
10984       for ( int i = 0 ; i < presentBndElems.size(); ++i )
10985       {
10986         const SMDS_MeshElement* e = presentBndElems[i];
10987         TConnectivity nodes( e->NbNodes() );
10988         for ( inode = 0; inode < nodes.size(); ++inode )
10989           nodes[inode] = getNodeWithSameID( tgtMeshDS, e->GetNode(inode) );
10990         tgtEditor.AddElement(nodes, missType, e->IsPoly());
10991         // leave only missing elements in tgtEditor.myLastCreatedElems
10992         tgtEditor.myLastCreatedElems.Remove( tgtEditor.myLastCreatedElems.Size() );
10993       }
10994   } // loop on given elements
10995
10996   // 4. Fill group with missing boundary elements
10997   if ( group )
10998   {
10999     if ( SMESHDS_Group* g = dynamic_cast<SMESHDS_Group*>( group->GetGroupDS() ))
11000       for ( int i = 0; i < tgtEditor.myLastCreatedElems.Size(); ++i )
11001         g->SMDSGroup().Add( tgtEditor.myLastCreatedElems( i+1 ));
11002   }
11003   tgtEditor.myLastCreatedElems.Clear();
11004
11005   // 5. Copy given elements
11006   if ( toCopyElements )
11007   {
11008     if (elements.empty())
11009       eIt = aMesh->elementsIterator(elemType);
11010     else
11011       eIt = SMDS_ElemIteratorPtr( new TSetIterator( elements.begin(), elements.end() ));
11012     while (eIt->more())
11013     {
11014       const SMDS_MeshElement* elem = eIt->next();
11015       TConnectivity nodes( elem->NbNodes() );
11016       for ( inode = 0; inode < nodes.size(); ++inode )
11017         nodes[inode] = getNodeWithSameID( tgtMeshDS, elem->GetNode(inode) );
11018       tgtEditor.AddElement(nodes, elemType, elem->IsPoly());
11019
11020       tgtEditor.myLastCreatedElems.Clear();
11021     }
11022   }
11023   return;
11024 }