Salome HOME
not initialized value
[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         elemSize = 0;
6581         while ( nodeIt->more() )
6582         {
6583           double dist = n1.Distance( cast2Node( nodeIt->next() ));
6584           elemSize = max( dist, elemSize );
6585         }
6586       }
6587       _tolerance = 1e-4 * elemSize;
6588     }
6589   }
6590   return _tolerance;
6591 }
6592
6593 //================================================================================
6594 /*!
6595  * \brief Find intersection of the line and an edge of face and return parameter on line
6596  */
6597 //================================================================================
6598
6599 bool SMESH_ElementSearcherImpl::getIntersParamOnLine(const gp_Lin&           line,
6600                                                      const SMDS_MeshElement* face,
6601                                                      const double            tol,
6602                                                      double &                param)
6603 {
6604   int nbInts = 0;
6605   param = 0;
6606
6607   GeomAPI_ExtremaCurveCurve anExtCC;
6608   Handle(Geom_Curve) lineCurve = new Geom_Line( line );
6609   
6610   int nbNodes = face->IsQuadratic() ? face->NbNodes()/2 : face->NbNodes();
6611   for ( int i = 0; i < nbNodes && nbInts < 2; ++i )
6612   {
6613     GC_MakeSegment edge( SMESH_MeshEditor::TNodeXYZ( face->GetNode( i )),
6614                          SMESH_MeshEditor::TNodeXYZ( face->GetNode( (i+1)%nbNodes) )); 
6615     anExtCC.Init( lineCurve, edge);
6616     if ( anExtCC.NbExtrema() > 0 && anExtCC.LowerDistance() <= tol)
6617     {
6618       Quantity_Parameter pl, pe;
6619       anExtCC.LowerDistanceParameters( pl, pe );
6620       param += pl;
6621       if ( ++nbInts == 2 )
6622         break;
6623     }
6624   }
6625   if ( nbInts > 0 ) param /= nbInts;
6626   return nbInts > 0;
6627 }
6628 //================================================================================
6629 /*!
6630  * \brief Find all faces belonging to the outer boundary of mesh
6631  */
6632 //================================================================================
6633
6634 void SMESH_ElementSearcherImpl::findOuterBoundary(const SMDS_MeshElement* outerFace)
6635 {
6636   if ( _outerFacesFound ) return;
6637
6638   // Collect all outer faces by passing from one outer face to another via their links
6639   // and BTW find out if there are internal faces at all.
6640
6641   // checked links and links where outer boundary meets internal one
6642   set< SMESH_TLink > visitedLinks, seamLinks;
6643
6644   // links to treat with already visited faces sharing them
6645   list < TFaceLink > startLinks;
6646
6647   // load startLinks with the first outerFace
6648   startLinks.push_back( TFaceLink( outerFace->GetNode(0), outerFace->GetNode(1), outerFace));
6649   _outerFaces.insert( outerFace );
6650
6651   TIDSortedElemSet emptySet;
6652   while ( !startLinks.empty() )
6653   {
6654     const SMESH_TLink& link  = startLinks.front()._link;
6655     TIDSortedElemSet&  faces = startLinks.front()._faces;
6656
6657     outerFace = *faces.begin();
6658     // find other faces sharing the link
6659     const SMDS_MeshElement* f;
6660     while (( f = SMESH_MeshEditor::FindFaceInSet(link.node1(), link.node2(), emptySet, faces )))
6661       faces.insert( f );
6662
6663     // select another outer face among the found 
6664     const SMDS_MeshElement* outerFace2 = 0;
6665     if ( faces.size() == 2 )
6666     {
6667       outerFace2 = (outerFace == *faces.begin() ? *faces.rbegin() : *faces.begin());
6668     }
6669     else if ( faces.size() > 2 )
6670     {
6671       seamLinks.insert( link );
6672
6673       // link direction within the outerFace
6674       gp_Vec n1n2( SMESH_MeshEditor::TNodeXYZ( link.node1()),
6675                    SMESH_MeshEditor::TNodeXYZ( link.node2()));
6676       int i1 = outerFace->GetNodeIndex( link.node1() );
6677       int i2 = outerFace->GetNodeIndex( link.node2() );
6678       bool rev = ( abs(i2-i1) == 1 ? i1 > i2 : i2 > i1 );
6679       if ( rev ) n1n2.Reverse();
6680       // outerFace normal
6681       gp_XYZ ofNorm, fNorm;
6682       if ( SMESH_Algo::FaceNormal( outerFace, ofNorm, /*normalized=*/false ))
6683       {
6684         // direction from the link inside outerFace
6685         gp_Vec dirInOF = gp_Vec( ofNorm ) ^ n1n2;
6686         // sort all other faces by angle with the dirInOF
6687         map< double, const SMDS_MeshElement* > angle2Face;
6688         set< const SMDS_MeshElement*, TIDCompare >::const_iterator face = faces.begin();
6689         for ( ; face != faces.end(); ++face )
6690         {
6691           if ( !SMESH_Algo::FaceNormal( *face, fNorm, /*normalized=*/false ))
6692             continue;
6693           gp_Vec dirInF = gp_Vec( fNorm ) ^ n1n2;
6694           double angle = dirInOF.AngleWithRef( dirInF, n1n2 );
6695           if ( angle < 0 ) angle += 2*PI;
6696           angle2Face.insert( make_pair( angle, *face ));
6697         }
6698         if ( !angle2Face.empty() )
6699           outerFace2 = angle2Face.begin()->second;
6700       }
6701     }
6702     // store the found outer face and add its links to continue seaching from
6703     if ( outerFace2 )
6704     {
6705       _outerFaces.insert( outerFace );
6706       int nbNodes = outerFace2->NbNodes()/( outerFace2->IsQuadratic() ? 2 : 1 );
6707       for ( int i = 0; i < nbNodes; ++i )
6708       {
6709         SMESH_TLink link2( outerFace2->GetNode(i), outerFace2->GetNode((i+1)%nbNodes));
6710         if ( visitedLinks.insert( link2 ).second )
6711           startLinks.push_back( TFaceLink( link2.node1(), link2.node2(), outerFace2 ));
6712       }
6713     }
6714     startLinks.pop_front();
6715   }
6716   _outerFacesFound = true;
6717
6718   if ( !seamLinks.empty() )
6719   {
6720     // There are internal boundaries touching the outher one,
6721     // find all faces of internal boundaries in order to find
6722     // faces of boundaries of holes, if any.
6723     
6724   }
6725   else
6726   {
6727     _outerFaces.clear();
6728   }
6729 }
6730
6731 //=======================================================================
6732 /*!
6733  * \brief Find elements of given type where the given point is IN or ON.
6734  *        Returns nb of found elements and elements them-selves.
6735  *
6736  * 'ALL' type means elements of any type excluding nodes and 0D elements
6737  */
6738 //=======================================================================
6739
6740 int SMESH_ElementSearcherImpl::
6741 FindElementsByPoint(const gp_Pnt&                      point,
6742                     SMDSAbs_ElementType                type,
6743                     vector< const SMDS_MeshElement* >& foundElements)
6744 {
6745   foundElements.clear();
6746
6747   double tolerance = getTolerance();
6748
6749   // =================================================================================
6750   if ( type == SMDSAbs_Node || type == SMDSAbs_0DElement )
6751   {
6752     if ( !_nodeSearcher )
6753       _nodeSearcher = new SMESH_NodeSearcherImpl( _mesh );
6754
6755     const SMDS_MeshNode* closeNode = _nodeSearcher->FindClosestTo( point );
6756     if ( !closeNode ) return foundElements.size();
6757
6758     if ( point.Distance( SMESH_MeshEditor::TNodeXYZ( closeNode )) > tolerance )
6759       return foundElements.size(); // to far from any node
6760
6761     if ( type == SMDSAbs_Node )
6762     {
6763       foundElements.push_back( closeNode );
6764     }
6765     else
6766     {
6767       SMDS_ElemIteratorPtr elemIt = closeNode->GetInverseElementIterator( SMDSAbs_0DElement );
6768       while ( elemIt->more() )
6769         foundElements.push_back( elemIt->next() );
6770     }
6771   }
6772   // =================================================================================
6773   else // elements more complex than 0D
6774   {
6775     if ( !_ebbTree || _elementType != type )
6776     {
6777       if ( _ebbTree ) delete _ebbTree;
6778       _ebbTree = new ElementBndBoxTree( *_mesh, _elementType = type, _meshPartIt, tolerance );
6779     }
6780     TIDSortedElemSet suspectElems;
6781     _ebbTree->getElementsNearPoint( point, suspectElems );
6782     TIDSortedElemSet::iterator elem = suspectElems.begin();
6783     for ( ; elem != suspectElems.end(); ++elem )
6784       if ( !SMESH_MeshEditor::isOut( *elem, point, tolerance ))
6785         foundElements.push_back( *elem );
6786   }
6787   return foundElements.size();
6788 }
6789
6790 //================================================================================
6791 /*!
6792  * \brief Classify the given point in the closed 2D mesh
6793  */
6794 //================================================================================
6795
6796 TopAbs_State SMESH_ElementSearcherImpl::GetPointState(const gp_Pnt& point)
6797 {
6798   double tolerance = getTolerance();
6799   if ( !_ebbTree || _elementType != SMDSAbs_Face )
6800   {
6801     if ( _ebbTree ) delete _ebbTree;
6802     _ebbTree = new ElementBndBoxTree( *_mesh, _elementType = SMDSAbs_Face, _meshPartIt );
6803   }
6804   // Algo: analyse transition of a line starting at the point through mesh boundary;
6805   // try three lines parallel to axis of the coordinate system and perform rough
6806   // analysis. If solution is not clear perform thorough analysis.
6807
6808   const int nbAxes = 3;
6809   gp_Dir axisDir[ nbAxes ] = { gp::DX(), gp::DY(), gp::DZ() };
6810   map< double, TInters >   paramOnLine2TInters[ nbAxes ];
6811   list< TInters > tangentInters[ nbAxes ]; // of faces whose plane includes the line
6812   multimap< int, int > nbInt2Axis; // to find the simplest case
6813   for ( int axis = 0; axis < nbAxes; ++axis )
6814   {
6815     gp_Ax1 lineAxis( point, axisDir[axis]);
6816     gp_Lin line    ( lineAxis );
6817
6818     TIDSortedElemSet suspectFaces; // faces possibly intersecting the line
6819     _ebbTree->getElementsNearLine( lineAxis, suspectFaces );
6820
6821     // Intersect faces with the line
6822
6823     map< double, TInters > & u2inters = paramOnLine2TInters[ axis ];
6824     TIDSortedElemSet::iterator face = suspectFaces.begin();
6825     for ( ; face != suspectFaces.end(); ++face )
6826     {
6827       // get face plane
6828       gp_XYZ fNorm;
6829       if ( !SMESH_Algo::FaceNormal( *face, fNorm, /*normalized=*/false)) continue;
6830       gp_Pln facePlane( SMESH_MeshEditor::TNodeXYZ( (*face)->GetNode(0)), fNorm );
6831
6832       // perform intersection
6833       IntAna_IntConicQuad intersection( line, IntAna_Quadric( facePlane ));
6834       if ( !intersection.IsDone() )
6835         continue;
6836       if ( intersection.IsInQuadric() )
6837       {
6838         tangentInters[ axis ].push_back( TInters( *face, fNorm, true ));
6839       }
6840       else if ( ! intersection.IsParallel() && intersection.NbPoints() > 0 )
6841       {
6842         gp_Pnt intersectionPoint = intersection.Point(1);
6843         if ( !SMESH_MeshEditor::isOut( *face, intersectionPoint, tolerance ))
6844           u2inters.insert(make_pair( intersection.ParamOnConic(1), TInters( *face, fNorm )));
6845       }
6846     }
6847     // Analyse intersections roughly
6848
6849     int nbInter = u2inters.size();
6850     if ( nbInter == 0 )
6851       return TopAbs_OUT; 
6852
6853     double f = u2inters.begin()->first, l = u2inters.rbegin()->first;
6854     if ( nbInter == 1 ) // not closed mesh
6855       return fabs( f ) < tolerance ? TopAbs_ON : TopAbs_UNKNOWN;
6856
6857     if ( fabs( f ) < tolerance || fabs( l ) < tolerance )
6858       return TopAbs_ON;
6859
6860     if ( (f<0) == (l<0) )
6861       return TopAbs_OUT;
6862
6863     int nbIntBeforePoint = std::distance( u2inters.begin(), u2inters.lower_bound(0));
6864     int nbIntAfterPoint  = nbInter - nbIntBeforePoint;
6865     if ( nbIntBeforePoint == 1 || nbIntAfterPoint == 1 )
6866       return TopAbs_IN;
6867
6868     nbInt2Axis.insert( make_pair( min( nbIntBeforePoint, nbIntAfterPoint ), axis ));
6869
6870     if ( _outerFacesFound ) break; // pass to thorough analysis
6871
6872   } // three attempts - loop on CS axes
6873
6874   // Analyse intersections thoroughly.
6875   // We make two loops maximum, on the first one we only exclude touching intersections,
6876   // on the second, if situation is still unclear, we gather and use information on
6877   // position of faces (internal or outer). If faces position is already gathered,
6878   // we make the second loop right away.
6879
6880   for ( int hasPositionInfo = _outerFacesFound; hasPositionInfo < 2; ++hasPositionInfo )
6881   {
6882     multimap< int, int >::const_iterator nb_axis = nbInt2Axis.begin();
6883     for ( ; nb_axis != nbInt2Axis.end(); ++nb_axis )
6884     {
6885       int axis = nb_axis->second;
6886       map< double, TInters > & u2inters = paramOnLine2TInters[ axis ];
6887
6888       gp_Ax1 lineAxis( point, axisDir[axis]);
6889       gp_Lin line    ( lineAxis );
6890
6891       // add tangent intersections to u2inters
6892       double param;
6893       list< TInters >::const_iterator tgtInt = tangentInters[ axis ].begin();
6894       for ( ; tgtInt != tangentInters[ axis ].end(); ++tgtInt )
6895         if ( getIntersParamOnLine( line, tgtInt->_face, tolerance, param ))
6896           u2inters.insert(make_pair( param, *tgtInt ));
6897       tangentInters[ axis ].clear();
6898
6899       // Count intersections before and after the point excluding touching ones.
6900       // If hasPositionInfo we count intersections of outer boundary only
6901
6902       int nbIntBeforePoint = 0, nbIntAfterPoint = 0;
6903       double f = numeric_limits<double>::max(), l = -numeric_limits<double>::max();
6904       map< double, TInters >::iterator u_int1 = u2inters.begin(), u_int2 = u_int1;
6905       bool ok = ! u_int1->second._coincides;
6906       while ( ok && u_int1 != u2inters.end() )
6907       {
6908         double u = u_int1->first;
6909         bool touchingInt = false;
6910         if ( ++u_int2 != u2inters.end() )
6911         {
6912           // skip intersections at the same point (if the line passes through edge or node)
6913           int nbSamePnt = 0;
6914           while ( u_int2 != u2inters.end() && fabs( u_int2->first - u ) < tolerance )
6915           {
6916             ++nbSamePnt;
6917             ++u_int2;
6918           }
6919
6920           // skip tangent intersections
6921           int nbTgt = 0;
6922           const SMDS_MeshElement* prevFace = u_int1->second._face;
6923           while ( ok && u_int2->second._coincides )
6924           {
6925             if ( SMESH_Algo::GetCommonNodes(prevFace , u_int2->second._face).empty() )
6926               ok = false;
6927             else
6928             {
6929               nbTgt++;
6930               u_int2++;
6931               ok = ( u_int2 != u2inters.end() );
6932             }
6933           }
6934           if ( !ok ) break;
6935
6936           // skip intersections at the same point after tangent intersections
6937           if ( nbTgt > 0 )
6938           {
6939             double u2 = u_int2->first;
6940             ++u_int2;
6941             while ( u_int2 != u2inters.end() && fabs( u_int2->first - u2 ) < tolerance )
6942             {
6943               ++nbSamePnt;
6944               ++u_int2;
6945             }
6946           }
6947           // decide if we skipped a touching intersection
6948           if ( nbSamePnt + nbTgt > 0 )
6949           {
6950             double minDot = numeric_limits<double>::max(), maxDot = -numeric_limits<double>::max();
6951             map< double, TInters >::iterator u_int = u_int1;
6952             for ( ; u_int != u_int2; ++u_int )
6953             {
6954               if ( u_int->second._coincides ) continue;
6955               double dot = u_int->second._faceNorm * line.Direction();
6956               if ( dot > maxDot ) maxDot = dot;
6957               if ( dot < minDot ) minDot = dot;
6958             }
6959             touchingInt = ( minDot*maxDot < 0 );
6960           }
6961         }
6962         if ( !touchingInt )
6963         {
6964           if ( !hasPositionInfo || isOuterBoundary( u_int1->second._face ))
6965           {
6966             if ( u < 0 )
6967               ++nbIntBeforePoint;
6968             else
6969               ++nbIntAfterPoint;
6970           }
6971           if ( u < f ) f = u;
6972           if ( u > l ) l = u;
6973         }
6974
6975         u_int1 = u_int2; // to next intersection
6976
6977       } // loop on intersections with one line
6978
6979       if ( ok )
6980       {
6981         if ( fabs( f ) < tolerance || fabs( l ) < tolerance )
6982           return TopAbs_ON;
6983
6984         if ( nbIntBeforePoint == 0  || nbIntAfterPoint == 0)
6985           return TopAbs_OUT; 
6986
6987         if ( nbIntBeforePoint + nbIntAfterPoint == 1 ) // not closed mesh
6988           return fabs( f ) < tolerance ? TopAbs_ON : TopAbs_UNKNOWN;
6989
6990         if ( nbIntBeforePoint == 1 || nbIntAfterPoint == 1 )
6991           return TopAbs_IN;
6992
6993         if ( (f<0) == (l<0) )
6994           return TopAbs_OUT;
6995
6996         if ( hasPositionInfo )
6997           return nbIntBeforePoint % 2 ? TopAbs_IN : TopAbs_OUT;
6998       }
6999     } // loop on intersections of the tree lines - thorough analysis
7000
7001     if ( !hasPositionInfo )
7002     {
7003       // gather info on faces position - is face in the outer boundary or not
7004       map< double, TInters > & u2inters = paramOnLine2TInters[ 0 ];
7005       findOuterBoundary( u2inters.begin()->second._face );
7006     }
7007
7008   } // two attempts - with and w/o faces position info in the mesh
7009
7010   return TopAbs_UNKNOWN;
7011 }
7012
7013 //=======================================================================
7014 /*!
7015  * \brief Return elements possibly intersecting the line
7016  */
7017 //=======================================================================
7018
7019 void SMESH_ElementSearcherImpl::GetElementsNearLine( const gp_Ax1&                      line,
7020                                                      SMDSAbs_ElementType                type,
7021                                                      vector< const SMDS_MeshElement* >& foundElems)
7022 {
7023   if ( !_ebbTree || _elementType != type )
7024   {
7025     if ( _ebbTree ) delete _ebbTree;
7026     _ebbTree = new ElementBndBoxTree( *_mesh, _elementType = type, _meshPartIt );
7027   }
7028   TIDSortedElemSet suspectFaces; // elements possibly intersecting the line
7029   _ebbTree->getElementsNearLine( line, suspectFaces );
7030   foundElems.assign( suspectFaces.begin(), suspectFaces.end());
7031 }
7032
7033 //=======================================================================
7034 /*!
7035  * \brief Return SMESH_ElementSearcher
7036  */
7037 //=======================================================================
7038
7039 SMESH_ElementSearcher* SMESH_MeshEditor::GetElementSearcher()
7040 {
7041   return new SMESH_ElementSearcherImpl( *GetMeshDS() );
7042 }
7043
7044 //=======================================================================
7045 /*!
7046  * \brief Return SMESH_ElementSearcher
7047  */
7048 //=======================================================================
7049
7050 SMESH_ElementSearcher* SMESH_MeshEditor::GetElementSearcher(SMDS_ElemIteratorPtr elemIt)
7051 {
7052   return new SMESH_ElementSearcherImpl( *GetMeshDS(), elemIt );
7053 }
7054
7055 //=======================================================================
7056 /*!
7057  * \brief Return true if the point is IN or ON of the element
7058  */
7059 //=======================================================================
7060
7061 bool SMESH_MeshEditor::isOut( const SMDS_MeshElement* element, const gp_Pnt& point, double tol )
7062 {
7063   if ( element->GetType() == SMDSAbs_Volume)
7064   {
7065     return SMDS_VolumeTool( element ).IsOut( point.X(), point.Y(), point.Z(), tol );
7066   }
7067
7068   // get ordered nodes
7069
7070   vector< gp_XYZ > xyz;
7071   vector<const SMDS_MeshNode*> nodeList;
7072
7073   SMDS_ElemIteratorPtr nodeIt = element->nodesIterator();
7074   if ( element->IsQuadratic() ) {
7075     if (const SMDS_VtkFace* f=dynamic_cast<const SMDS_VtkFace*>(element))
7076       nodeIt = f->interlacedNodesElemIterator();
7077     else if (const SMDS_VtkEdge*  e =dynamic_cast<const SMDS_VtkEdge*>(element))
7078       nodeIt = e->interlacedNodesElemIterator();
7079   }
7080   while ( nodeIt->more() )
7081     {
7082       const SMDS_MeshNode* node = cast2Node( nodeIt->next() );
7083       xyz.push_back( TNodeXYZ(node) );
7084       nodeList.push_back(node);
7085     }
7086
7087   int i, nbNodes = element->NbNodes();
7088
7089   if ( element->GetType() == SMDSAbs_Face ) // --------------------------------------------------
7090   {
7091     // compute face normal
7092     gp_Vec faceNorm(0,0,0);
7093     xyz.push_back( xyz.front() );
7094     nodeList.push_back( nodeList.front() );
7095     for ( i = 0; i < nbNodes; ++i )
7096     {
7097       gp_Vec edge1( xyz[i+1], xyz[i]);
7098       gp_Vec edge2( xyz[i+1], xyz[(i+2)%nbNodes] );
7099       faceNorm += edge1 ^ edge2;
7100     }
7101     double normSize = faceNorm.Magnitude();
7102     if ( normSize <= tol )
7103     {
7104       // degenerated face: point is out if it is out of all face edges
7105       for ( i = 0; i < nbNodes; ++i )
7106       {
7107         SMDS_LinearEdge edge( nodeList[i], nodeList[i+1] );
7108         if ( !isOut( &edge, point, tol ))
7109           return false;
7110       }
7111       return true;
7112     }
7113     faceNorm /= normSize;
7114
7115     // check if the point lays on face plane
7116     gp_Vec n2p( xyz[0], point );
7117     if ( fabs( n2p * faceNorm ) > tol )
7118       return true; // not on face plane
7119
7120     // check if point is out of face boundary:
7121     // define it by closest transition of a ray point->infinity through face boundary
7122     // on the face plane.
7123     // First, find normal of a plane perpendicular to face plane, to be used as a cutting tool
7124     // to find intersections of the ray with the boundary.
7125     gp_Vec ray = n2p;
7126     gp_Vec plnNorm = ray ^ faceNorm;
7127     normSize = plnNorm.Magnitude();
7128     if ( normSize <= tol ) return false; // point coincides with the first node
7129     plnNorm /= normSize;
7130     // for each node of the face, compute its signed distance to the plane
7131     vector<double> dist( nbNodes + 1);
7132     for ( i = 0; i < nbNodes; ++i )
7133     {
7134       gp_Vec n2p( xyz[i], point );
7135       dist[i] = n2p * plnNorm;
7136     }
7137     dist.back() = dist.front();
7138     // find the closest intersection
7139     int    iClosest = -1;
7140     double rClosest, distClosest = 1e100;;
7141     gp_Pnt pClosest;
7142     for ( i = 0; i < nbNodes; ++i )
7143     {
7144       double r;
7145       if ( fabs( dist[i]) < tol )
7146         r = 0.;
7147       else if ( fabs( dist[i+1]) < tol )
7148         r = 1.;
7149       else if ( dist[i] * dist[i+1] < 0 )
7150         r = dist[i] / ( dist[i] - dist[i+1] );
7151       else
7152         continue; // no intersection
7153       gp_Pnt pInt = xyz[i] * (1.-r) + xyz[i+1] * r;
7154       gp_Vec p2int ( point, pInt);
7155       if ( p2int * ray > -tol ) // right half-space
7156       {
7157         double intDist = p2int.SquareMagnitude();
7158         if ( intDist < distClosest )
7159         {
7160           iClosest = i;
7161           rClosest = r;
7162           pClosest = pInt;
7163           distClosest = intDist;
7164         }
7165       }
7166     }
7167     if ( iClosest < 0 )
7168       return true; // no intesections - out
7169
7170     // analyse transition
7171     gp_Vec edge( xyz[iClosest], xyz[iClosest+1] );
7172     gp_Vec edgeNorm = -( edge ^ faceNorm ); // normal to intersected edge pointing out of face
7173     gp_Vec p2int ( point, pClosest );
7174     bool out = (edgeNorm * p2int) < -tol;
7175     if ( rClosest > 0. && rClosest < 1. ) // not node intersection
7176       return out;
7177
7178     // ray pass through a face node; analyze transition through an adjacent edge
7179     gp_Pnt p1 = xyz[ (rClosest == 0.) ? ((iClosest+nbNodes-1) % nbNodes) : (iClosest+1) ];
7180     gp_Pnt p2 = xyz[ (rClosest == 0.) ? iClosest : ((iClosest+2) % nbNodes) ];
7181     gp_Vec edgeAdjacent( p1, p2 );
7182     gp_Vec edgeNorm2 = -( edgeAdjacent ^ faceNorm );
7183     bool out2 = (edgeNorm2 * p2int) < -tol;
7184
7185     bool covexCorner = ( edgeNorm * edgeAdjacent * (rClosest==1. ? 1. : -1.)) < 0;
7186     return covexCorner ? (out || out2) : (out && out2);
7187   }
7188   if ( element->GetType() == SMDSAbs_Edge ) // --------------------------------------------------
7189   {
7190     // point is out of edge if it is NOT ON any straight part of edge
7191     // (we consider quadratic edge as being composed of two straight parts)
7192     for ( i = 1; i < nbNodes; ++i )
7193     {
7194       gp_Vec edge( xyz[i-1], xyz[i]);
7195       gp_Vec n1p ( xyz[i-1], point);
7196       double dist = ( edge ^ n1p ).Magnitude() / edge.Magnitude();
7197       if ( dist > tol )
7198         continue;
7199       gp_Vec n2p( xyz[i], point );
7200       if ( fabs( edge.Magnitude() - n1p.Magnitude() - n2p.Magnitude()) > tol )
7201         continue;
7202       return false; // point is ON this part
7203     }
7204     return true;
7205   }
7206   // Node or 0D element -------------------------------------------------------------------------
7207   {
7208     gp_Vec n2p ( xyz[0], point );
7209     return n2p.Magnitude() <= tol;
7210   }
7211   return true;
7212 }
7213
7214 //=======================================================================
7215 //function : SimplifyFace
7216 //purpose  :
7217 //=======================================================================
7218 int SMESH_MeshEditor::SimplifyFace (const vector<const SMDS_MeshNode *> faceNodes,
7219                                     vector<const SMDS_MeshNode *>&      poly_nodes,
7220                                     vector<int>&                        quantities) const
7221 {
7222   int nbNodes = faceNodes.size();
7223
7224   if (nbNodes < 3)
7225     return 0;
7226
7227   set<const SMDS_MeshNode*> nodeSet;
7228
7229   // get simple seq of nodes
7230   //const SMDS_MeshNode* simpleNodes[ nbNodes ];
7231   vector<const SMDS_MeshNode*> simpleNodes( nbNodes );
7232   int iSimple = 0, nbUnique = 0;
7233
7234   simpleNodes[iSimple++] = faceNodes[0];
7235   nbUnique++;
7236   for (int iCur = 1; iCur < nbNodes; iCur++) {
7237     if (faceNodes[iCur] != simpleNodes[iSimple - 1]) {
7238       simpleNodes[iSimple++] = faceNodes[iCur];
7239       if (nodeSet.insert( faceNodes[iCur] ).second)
7240         nbUnique++;
7241     }
7242   }
7243   int nbSimple = iSimple;
7244   if (simpleNodes[nbSimple - 1] == simpleNodes[0]) {
7245     nbSimple--;
7246     iSimple--;
7247   }
7248
7249   if (nbUnique < 3)
7250     return 0;
7251
7252   // separate loops
7253   int nbNew = 0;
7254   bool foundLoop = (nbSimple > nbUnique);
7255   while (foundLoop) {
7256     foundLoop = false;
7257     set<const SMDS_MeshNode*> loopSet;
7258     for (iSimple = 0; iSimple < nbSimple && !foundLoop; iSimple++) {
7259       const SMDS_MeshNode* n = simpleNodes[iSimple];
7260       if (!loopSet.insert( n ).second) {
7261         foundLoop = true;
7262
7263         // separate loop
7264         int iC = 0, curLast = iSimple;
7265         for (; iC < curLast; iC++) {
7266           if (simpleNodes[iC] == n) break;
7267         }
7268         int loopLen = curLast - iC;
7269         if (loopLen > 2) {
7270           // create sub-element
7271           nbNew++;
7272           quantities.push_back(loopLen);
7273           for (; iC < curLast; iC++) {
7274             poly_nodes.push_back(simpleNodes[iC]);
7275           }
7276         }
7277         // shift the rest nodes (place from the first loop position)
7278         for (iC = curLast + 1; iC < nbSimple; iC++) {
7279           simpleNodes[iC - loopLen] = simpleNodes[iC];
7280         }
7281         nbSimple -= loopLen;
7282         iSimple -= loopLen;
7283       }
7284     } // for (iSimple = 0; iSimple < nbSimple; iSimple++)
7285   } // while (foundLoop)
7286
7287   if (iSimple > 2) {
7288     nbNew++;
7289     quantities.push_back(iSimple);
7290     for (int i = 0; i < iSimple; i++)
7291       poly_nodes.push_back(simpleNodes[i]);
7292   }
7293
7294   return nbNew;
7295 }
7296
7297 //=======================================================================
7298 //function : MergeNodes
7299 //purpose  : In each group, the cdr of nodes are substituted by the first one
7300 //           in all elements.
7301 //=======================================================================
7302
7303 void SMESH_MeshEditor::MergeNodes (TListOfListOfNodes & theGroupsOfNodes)
7304 {
7305   MESSAGE("MergeNodes");
7306   myLastCreatedElems.Clear();
7307   myLastCreatedNodes.Clear();
7308
7309   SMESHDS_Mesh* aMesh = GetMeshDS();
7310
7311   TNodeNodeMap nodeNodeMap; // node to replace - new node
7312   set<const SMDS_MeshElement*> elems; // all elements with changed nodes
7313   list< int > rmElemIds, rmNodeIds;
7314
7315   // Fill nodeNodeMap and elems
7316
7317   TListOfListOfNodes::iterator grIt = theGroupsOfNodes.begin();
7318   for ( ; grIt != theGroupsOfNodes.end(); grIt++ ) {
7319     list<const SMDS_MeshNode*>& nodes = *grIt;
7320     list<const SMDS_MeshNode*>::iterator nIt = nodes.begin();
7321     const SMDS_MeshNode* nToKeep = *nIt;
7322     //MESSAGE("node to keep " << nToKeep->GetID());
7323     for ( ++nIt; nIt != nodes.end(); nIt++ ) {
7324       const SMDS_MeshNode* nToRemove = *nIt;
7325       nodeNodeMap.insert( TNodeNodeMap::value_type( nToRemove, nToKeep ));
7326       if ( nToRemove != nToKeep ) {
7327         //MESSAGE("  node to remove " << nToRemove->GetID());
7328         rmNodeIds.push_back( nToRemove->GetID() );
7329         AddToSameGroups( nToKeep, nToRemove, aMesh );
7330       }
7331
7332       SMDS_ElemIteratorPtr invElemIt = nToRemove->GetInverseElementIterator();
7333       while ( invElemIt->more() ) {
7334         const SMDS_MeshElement* elem = invElemIt->next();
7335         elems.insert(elem);
7336       }
7337     }
7338   }
7339   // Change element nodes or remove an element
7340
7341   set<const SMDS_MeshElement*>::iterator eIt = elems.begin();
7342   for ( ; eIt != elems.end(); eIt++ ) {
7343     const SMDS_MeshElement* elem = *eIt;
7344     //MESSAGE(" ---- inverse elem on node to remove " << elem->GetID());
7345     int nbNodes = elem->NbNodes();
7346     int aShapeId = FindShape( elem );
7347
7348     set<const SMDS_MeshNode*> nodeSet;
7349     vector< const SMDS_MeshNode*> curNodes( nbNodes ), uniqueNodes( nbNodes );
7350     int iUnique = 0, iCur = 0, nbRepl = 0;
7351     vector<int> iRepl( nbNodes );
7352
7353     // get new seq of nodes
7354     SMDS_ElemIteratorPtr itN = elem->nodesIterator();
7355     while ( itN->more() ) {
7356       const SMDS_MeshNode* n =
7357         static_cast<const SMDS_MeshNode*>( itN->next() );
7358
7359       TNodeNodeMap::iterator nnIt = nodeNodeMap.find( n );
7360       if ( nnIt != nodeNodeMap.end() ) { // n sticks
7361         n = (*nnIt).second;
7362         // BUG 0020185: begin
7363         {
7364           bool stopRecur = false;
7365           set<const SMDS_MeshNode*> nodesRecur;
7366           nodesRecur.insert(n);
7367           while (!stopRecur) {
7368             TNodeNodeMap::iterator nnIt_i = nodeNodeMap.find( n );
7369             if ( nnIt_i != nodeNodeMap.end() ) { // n sticks
7370               n = (*nnIt_i).second;
7371               if (!nodesRecur.insert(n).second) {
7372                 // error: recursive dependancy
7373                 stopRecur = true;
7374               }
7375             }
7376             else
7377               stopRecur = true;
7378           }
7379         }
7380         // BUG 0020185: end
7381         iRepl[ nbRepl++ ] = iCur;
7382       }
7383       curNodes[ iCur ] = n;
7384       bool isUnique = nodeSet.insert( n ).second;
7385       if ( isUnique )
7386         uniqueNodes[ iUnique++ ] = n;
7387       iCur++;
7388     }
7389
7390     // Analyse element topology after replacement
7391
7392     bool isOk = true;
7393     int nbUniqueNodes = nodeSet.size();
7394     //MESSAGE("nbNodes nbUniqueNodes " << nbNodes << " " << nbUniqueNodes);
7395     if ( nbNodes != nbUniqueNodes ) { // some nodes stick
7396       // Polygons and Polyhedral volumes
7397       if (elem->IsPoly()) {
7398
7399         if (elem->GetType() == SMDSAbs_Face) {
7400           // Polygon
7401           vector<const SMDS_MeshNode *> face_nodes (nbNodes);
7402           int inode = 0;
7403           for (; inode < nbNodes; inode++) {
7404             face_nodes[inode] = curNodes[inode];
7405           }
7406
7407           vector<const SMDS_MeshNode *> polygons_nodes;
7408           vector<int> quantities;
7409           int nbNew = SimplifyFace(face_nodes, polygons_nodes, quantities);
7410           if (nbNew > 0) {
7411             inode = 0;
7412             for (int iface = 0; iface < nbNew; iface++) {
7413               int nbNodes = quantities[iface];
7414               vector<const SMDS_MeshNode *> poly_nodes (nbNodes);
7415               for (int ii = 0; ii < nbNodes; ii++, inode++) {
7416                 poly_nodes[ii] = polygons_nodes[inode];
7417               }
7418               SMDS_MeshElement* newElem = aMesh->AddPolygonalFace(poly_nodes);
7419               myLastCreatedElems.Append(newElem);
7420               if (aShapeId)
7421                 aMesh->SetMeshElementOnShape(newElem, aShapeId);
7422             }
7423
7424             MESSAGE("ChangeElementNodes MergeNodes Polygon");
7425             //aMesh->ChangeElementNodes(elem, &polygons_nodes[inode], quantities[nbNew - 1]);
7426             vector<const SMDS_MeshNode *> polynodes(polygons_nodes.begin()+inode,polygons_nodes.end());
7427             int quid =0;
7428             if (nbNew > 0) quid = nbNew - 1;
7429             vector<int> newquant(quantities.begin()+quid, quantities.end());
7430             const SMDS_MeshElement* newElem = 0;
7431             newElem = aMesh->AddPolyhedralVolume(polynodes, newquant);
7432             myLastCreatedElems.Append(newElem);
7433             if ( aShapeId && newElem )
7434               aMesh->SetMeshElementOnShape( newElem, aShapeId );
7435             rmElemIds.push_back(elem->GetID());
7436           }
7437           else {
7438             rmElemIds.push_back(elem->GetID());
7439           }
7440
7441         }
7442         else if (elem->GetType() == SMDSAbs_Volume) {
7443           // Polyhedral volume
7444           if (nbUniqueNodes < 4) {
7445             rmElemIds.push_back(elem->GetID());
7446           }
7447           else {
7448             // each face has to be analyzed in order to check volume validity
7449             const SMDS_VtkVolume* aPolyedre =
7450               dynamic_cast<const SMDS_VtkVolume*>( elem );
7451             if (aPolyedre) {
7452               int nbFaces = aPolyedre->NbFaces();
7453
7454               vector<const SMDS_MeshNode *> poly_nodes;
7455               vector<int> quantities;
7456
7457               for (int iface = 1; iface <= nbFaces; iface++) {
7458                 int nbFaceNodes = aPolyedre->NbFaceNodes(iface);
7459                 vector<const SMDS_MeshNode *> faceNodes (nbFaceNodes);
7460
7461                 for (int inode = 1; inode <= nbFaceNodes; inode++) {
7462                   const SMDS_MeshNode * faceNode = aPolyedre->GetFaceNode(iface, inode);
7463                   TNodeNodeMap::iterator nnIt = nodeNodeMap.find(faceNode);
7464                   if (nnIt != nodeNodeMap.end()) { // faceNode sticks
7465                     faceNode = (*nnIt).second;
7466                   }
7467                   faceNodes[inode - 1] = faceNode;
7468                 }
7469
7470                 SimplifyFace(faceNodes, poly_nodes, quantities);
7471               }
7472
7473               if (quantities.size() > 3) {
7474                 // to be done: remove coincident faces
7475               }
7476
7477               if (quantities.size() > 3)
7478                 {
7479                   MESSAGE("ChangeElementNodes MergeNodes Polyhedron");
7480                   //aMesh->ChangePolyhedronNodes(elem, poly_nodes, quantities);
7481                   const SMDS_MeshElement* newElem = 0;
7482                   newElem = aMesh->AddPolyhedralVolume(poly_nodes, quantities);
7483                   myLastCreatedElems.Append(newElem);
7484                   if ( aShapeId && newElem )
7485                     aMesh->SetMeshElementOnShape( newElem, aShapeId );
7486                   rmElemIds.push_back(elem->GetID());
7487                 }
7488             }
7489             else {
7490               rmElemIds.push_back(elem->GetID());
7491             }
7492           }
7493         }
7494         else {
7495         }
7496
7497         continue;
7498       }
7499
7500       // Regular elements
7501       // TODO not all the possible cases are solved. Find something more generic?
7502       switch ( nbNodes ) {
7503       case 2: ///////////////////////////////////// EDGE
7504         isOk = false; break;
7505       case 3: ///////////////////////////////////// TRIANGLE
7506         isOk = false; break;
7507       case 4:
7508         if ( elem->GetType() == SMDSAbs_Volume ) // TETRAHEDRON
7509           isOk = false;
7510         else { //////////////////////////////////// QUADRANGLE
7511           if ( nbUniqueNodes < 3 )
7512             isOk = false;
7513           else if ( nbRepl == 2 && iRepl[ 1 ] - iRepl[ 0 ] == 2 )
7514             isOk = false; // opposite nodes stick
7515           //MESSAGE("isOk " << isOk);
7516         }
7517         break;
7518       case 6: ///////////////////////////////////// PENTAHEDRON
7519         if ( nbUniqueNodes == 4 ) {
7520           // ---------------------------------> tetrahedron
7521           if (nbRepl == 3 &&
7522               iRepl[ 0 ] > 2 && iRepl[ 1 ] > 2 && iRepl[ 2 ] > 2 ) {
7523             // all top nodes stick: reverse a bottom
7524             uniqueNodes[ 0 ] = curNodes [ 1 ];
7525             uniqueNodes[ 1 ] = curNodes [ 0 ];
7526           }
7527           else if (nbRepl == 3 &&
7528                    iRepl[ 0 ] < 3 && iRepl[ 1 ] < 3 && iRepl[ 2 ] < 3 ) {
7529             // all bottom nodes stick: set a top before
7530             uniqueNodes[ 3 ] = uniqueNodes [ 0 ];
7531             uniqueNodes[ 0 ] = curNodes [ 3 ];
7532             uniqueNodes[ 1 ] = curNodes [ 4 ];
7533             uniqueNodes[ 2 ] = curNodes [ 5 ];
7534           }
7535           else if (nbRepl == 4 &&
7536                    iRepl[ 2 ] - iRepl [ 0 ] == 3 && iRepl[ 3 ] - iRepl [ 1 ] == 3 ) {
7537             // a lateral face turns into a line: reverse a bottom
7538             uniqueNodes[ 0 ] = curNodes [ 1 ];
7539             uniqueNodes[ 1 ] = curNodes [ 0 ];
7540           }
7541           else
7542             isOk = false;
7543         }
7544         else if ( nbUniqueNodes == 5 ) {
7545           // PENTAHEDRON --------------------> 2 tetrahedrons
7546           if ( nbRepl == 2 && iRepl[ 1 ] - iRepl [ 0 ] == 3 ) {
7547             // a bottom node sticks with a linked top one
7548             // 1.
7549             SMDS_MeshElement* newElem =
7550               aMesh->AddVolume(curNodes[ 3 ],
7551                                curNodes[ 4 ],
7552                                curNodes[ 5 ],
7553                                curNodes[ iRepl[ 0 ] == 2 ? 1 : 2 ]);
7554             myLastCreatedElems.Append(newElem);
7555             if ( aShapeId )
7556               aMesh->SetMeshElementOnShape( newElem, aShapeId );
7557             // 2. : reverse a bottom
7558             uniqueNodes[ 0 ] = curNodes [ 1 ];
7559             uniqueNodes[ 1 ] = curNodes [ 0 ];
7560             nbUniqueNodes = 4;
7561           }
7562           else
7563             isOk = false;
7564         }
7565         else
7566           isOk = false;
7567         break;
7568       case 8: {
7569         if(elem->IsQuadratic()) { // Quadratic quadrangle
7570           //   1    5    2
7571           //    +---+---+
7572           //    |       |
7573           //    |       |
7574           //   4+       +6
7575           //    |       |
7576           //    |       |
7577           //    +---+---+
7578           //   0    7    3
7579           isOk = false;
7580           if(nbRepl==2) {
7581             MESSAGE("nbRepl=2: " << iRepl[0] << " " << iRepl[1]);
7582           }
7583           if(nbRepl==3) {
7584             MESSAGE("nbRepl=3: " << iRepl[0] << " " << iRepl[1]  << " " << iRepl[2]);
7585             nbUniqueNodes = 6;
7586             if( iRepl[0]==0 && iRepl[1]==1 && iRepl[2]==4 ) {
7587               uniqueNodes[0] = curNodes[0];
7588               uniqueNodes[1] = curNodes[2];
7589               uniqueNodes[2] = curNodes[3];
7590               uniqueNodes[3] = curNodes[5];
7591               uniqueNodes[4] = curNodes[6];
7592               uniqueNodes[5] = curNodes[7];
7593               isOk = true;
7594             }
7595             if( iRepl[0]==0 && iRepl[1]==3 && iRepl[2]==7 ) {
7596               uniqueNodes[0] = curNodes[0];
7597               uniqueNodes[1] = curNodes[1];
7598               uniqueNodes[2] = curNodes[2];
7599               uniqueNodes[3] = curNodes[4];
7600               uniqueNodes[4] = curNodes[5];
7601               uniqueNodes[5] = curNodes[6];
7602               isOk = true;
7603             }
7604             if( iRepl[0]==0 && iRepl[1]==4 && iRepl[2]==7 ) {
7605               uniqueNodes[0] = curNodes[1];
7606               uniqueNodes[1] = curNodes[2];
7607               uniqueNodes[2] = curNodes[3];
7608               uniqueNodes[3] = curNodes[5];
7609               uniqueNodes[4] = curNodes[6];
7610               uniqueNodes[5] = curNodes[0];
7611               isOk = true;
7612             }
7613             if( iRepl[0]==1 && iRepl[1]==2 && iRepl[2]==5 ) {
7614               uniqueNodes[0] = curNodes[0];
7615               uniqueNodes[1] = curNodes[1];
7616               uniqueNodes[2] = curNodes[3];
7617               uniqueNodes[3] = curNodes[4];
7618               uniqueNodes[4] = curNodes[6];
7619               uniqueNodes[5] = curNodes[7];
7620               isOk = true;
7621             }
7622             if( iRepl[0]==1 && iRepl[1]==4 && iRepl[2]==5 ) {
7623               uniqueNodes[0] = curNodes[0];
7624               uniqueNodes[1] = curNodes[2];
7625               uniqueNodes[2] = curNodes[3];
7626               uniqueNodes[3] = curNodes[1];
7627               uniqueNodes[4] = curNodes[6];
7628               uniqueNodes[5] = curNodes[7];
7629               isOk = true;
7630             }
7631             if( iRepl[0]==2 && iRepl[1]==3 && iRepl[2]==6 ) {
7632               uniqueNodes[0] = curNodes[0];
7633               uniqueNodes[1] = curNodes[1];
7634               uniqueNodes[2] = curNodes[2];
7635               uniqueNodes[3] = curNodes[4];
7636               uniqueNodes[4] = curNodes[5];
7637               uniqueNodes[5] = curNodes[7];
7638               isOk = true;
7639             }
7640             if( iRepl[0]==2 && iRepl[1]==5 && iRepl[2]==6 ) {
7641               uniqueNodes[0] = curNodes[0];
7642               uniqueNodes[1] = curNodes[1];
7643               uniqueNodes[2] = curNodes[3];
7644               uniqueNodes[3] = curNodes[4];
7645               uniqueNodes[4] = curNodes[2];
7646               uniqueNodes[5] = curNodes[7];
7647               isOk = true;
7648             }
7649             if( iRepl[0]==3 && iRepl[1]==6 && iRepl[2]==7 ) {
7650               uniqueNodes[0] = curNodes[0];
7651               uniqueNodes[1] = curNodes[1];
7652               uniqueNodes[2] = curNodes[2];
7653               uniqueNodes[3] = curNodes[4];
7654               uniqueNodes[4] = curNodes[5];
7655               uniqueNodes[5] = curNodes[3];
7656               isOk = true;
7657             }
7658           }
7659           if(nbRepl==4) {
7660             MESSAGE("nbRepl=4: " << iRepl[0] << " " << iRepl[1]  << " " << iRepl[2] << " " << iRepl[3]);
7661           }
7662           if(nbRepl==5) {
7663             MESSAGE("nbRepl=5: " << iRepl[0] << " " << iRepl[1]  << " " << iRepl[2] << " " << iRepl[3] << " " << iRepl[4]);
7664           }
7665           break;
7666         }
7667         //////////////////////////////////// HEXAHEDRON
7668         isOk = false;
7669         SMDS_VolumeTool hexa (elem);
7670         hexa.SetExternalNormal();
7671         if ( nbUniqueNodes == 4 && nbRepl == 6 ) {
7672           //////////////////////// ---> tetrahedron
7673           for ( int iFace = 0; iFace < 6; iFace++ ) {
7674             const int *ind = hexa.GetFaceNodesIndices( iFace ); // indices of face nodes
7675             if (curNodes[ind[ 0 ]] == curNodes[ind[ 1 ]] &&
7676                 curNodes[ind[ 0 ]] == curNodes[ind[ 2 ]] &&
7677                 curNodes[ind[ 0 ]] == curNodes[ind[ 3 ]] ) {
7678               // one face turns into a point ...
7679               int iOppFace = hexa.GetOppFaceIndex( iFace );
7680               ind = hexa.GetFaceNodesIndices( iOppFace );
7681               int nbStick = 0;
7682               iUnique = 2; // reverse a tetrahedron bottom
7683               for ( iCur = 0; iCur < 4 && nbStick < 2; iCur++ ) {
7684                 if ( curNodes[ind[ iCur ]] == curNodes[ind[ iCur + 1 ]] )
7685                   nbStick++;
7686                 else if ( iUnique >= 0 )
7687                   uniqueNodes[ iUnique-- ] = curNodes[ind[ iCur ]];
7688               }
7689               if ( nbStick == 1 ) {
7690                 // ... and the opposite one - into a triangle.
7691                 // set a top node
7692                 ind = hexa.GetFaceNodesIndices( iFace );
7693                 uniqueNodes[ 3 ] = curNodes[ind[ 0 ]];
7694                 isOk = true;
7695               }
7696               break;
7697             }
7698           }
7699         }
7700         else if (nbUniqueNodes == 5 && nbRepl == 4 ) {
7701           //////////////////// HEXAHEDRON ---> 2 tetrahedrons
7702           for ( int iFace = 0; iFace < 6; iFace++ ) {
7703             const int *ind = hexa.GetFaceNodesIndices( iFace ); // indices of face nodes
7704             if (curNodes[ind[ 0 ]] == curNodes[ind[ 1 ]] &&
7705                 curNodes[ind[ 0 ]] == curNodes[ind[ 2 ]] &&
7706                 curNodes[ind[ 0 ]] == curNodes[ind[ 3 ]] ) {
7707               // one face turns into a point ...
7708               int iOppFace = hexa.GetOppFaceIndex( iFace );
7709               ind = hexa.GetFaceNodesIndices( iOppFace );
7710               int nbStick = 0;
7711               iUnique = 2;  // reverse a tetrahedron 1 bottom
7712               for ( iCur = 0; iCur < 4 && nbStick == 0; iCur++ ) {
7713                 if ( curNodes[ind[ iCur ]] == curNodes[ind[ iCur + 1 ]] )
7714                   nbStick++;
7715                 else if ( iUnique >= 0 )
7716                   uniqueNodes[ iUnique-- ] = curNodes[ind[ iCur ]];
7717               }
7718               if ( nbStick == 0 ) {
7719                 // ... and the opposite one is a quadrangle
7720                 // set a top node
7721                 const int* indTop = hexa.GetFaceNodesIndices( iFace );
7722                 uniqueNodes[ 3 ] = curNodes[indTop[ 0 ]];
7723                 nbUniqueNodes = 4;
7724                 // tetrahedron 2
7725                 SMDS_MeshElement* newElem =
7726                   aMesh->AddVolume(curNodes[ind[ 0 ]],
7727                                    curNodes[ind[ 3 ]],
7728                                    curNodes[ind[ 2 ]],
7729                                    curNodes[indTop[ 0 ]]);
7730                 myLastCreatedElems.Append(newElem);
7731                 if ( aShapeId )
7732                   aMesh->SetMeshElementOnShape( newElem, aShapeId );
7733                 isOk = true;
7734               }
7735               break;
7736             }
7737           }
7738         }
7739         else if ( nbUniqueNodes == 6 && nbRepl == 4 ) {
7740           ////////////////// HEXAHEDRON ---> 2 tetrahedrons or 1 prism
7741           // find indices of quad and tri faces
7742           int iQuadFace[ 6 ], iTriFace[ 6 ], nbQuad = 0, nbTri = 0, iFace;
7743           for ( iFace = 0; iFace < 6; iFace++ ) {
7744             const int *ind = hexa.GetFaceNodesIndices( iFace ); // indices of face nodes
7745             nodeSet.clear();
7746             for ( iCur = 0; iCur < 4; iCur++ )
7747               nodeSet.insert( curNodes[ind[ iCur ]] );
7748             nbUniqueNodes = nodeSet.size();
7749             if ( nbUniqueNodes == 3 )
7750               iTriFace[ nbTri++ ] = iFace;
7751             else if ( nbUniqueNodes == 4 )
7752               iQuadFace[ nbQuad++ ] = iFace;
7753           }
7754           if (nbQuad == 2 && nbTri == 4 &&
7755               hexa.GetOppFaceIndex( iQuadFace[ 0 ] ) == iQuadFace[ 1 ]) {
7756             // 2 opposite quadrangles stuck with a diagonal;
7757             // sample groups of merged indices: (0-4)(2-6)
7758             // --------------------------------------------> 2 tetrahedrons
7759             const int *ind1 = hexa.GetFaceNodesIndices( iQuadFace[ 0 ]); // indices of quad1 nodes
7760             const int *ind2 = hexa.GetFaceNodesIndices( iQuadFace[ 1 ]);
7761             int i0, i1d, i2, i3d, i0t, i2t; // d-daigonal, t-top
7762             if (curNodes[ind1[ 0 ]] == curNodes[ind2[ 0 ]] &&
7763                 curNodes[ind1[ 2 ]] == curNodes[ind2[ 2 ]]) {
7764               // stuck with 0-2 diagonal
7765               i0  = ind1[ 3 ];
7766               i1d = ind1[ 0 ];
7767               i2  = ind1[ 1 ];
7768               i3d = ind1[ 2 ];
7769               i0t = ind2[ 1 ];
7770               i2t = ind2[ 3 ];
7771             }
7772             else if (curNodes[ind1[ 1 ]] == curNodes[ind2[ 3 ]] &&
7773                      curNodes[ind1[ 3 ]] == curNodes[ind2[ 1 ]]) {
7774               // stuck with 1-3 diagonal
7775               i0  = ind1[ 0 ];
7776               i1d = ind1[ 1 ];
7777               i2  = ind1[ 2 ];
7778               i3d = ind1[ 3 ];
7779               i0t = ind2[ 0 ];
7780               i2t = ind2[ 1 ];
7781             }
7782             else {
7783               ASSERT(0);
7784             }
7785             // tetrahedron 1
7786             uniqueNodes[ 0 ] = curNodes [ i0 ];
7787             uniqueNodes[ 1 ] = curNodes [ i1d ];
7788             uniqueNodes[ 2 ] = curNodes [ i3d ];
7789             uniqueNodes[ 3 ] = curNodes [ i0t ];
7790             nbUniqueNodes = 4;
7791             // tetrahedron 2
7792             SMDS_MeshElement* newElem = aMesh->AddVolume(curNodes[ i1d ],
7793                                                          curNodes[ i2 ],
7794                                                          curNodes[ i3d ],
7795                                                          curNodes[ i2t ]);
7796             myLastCreatedElems.Append(newElem);
7797             if ( aShapeId )
7798               aMesh->SetMeshElementOnShape( newElem, aShapeId );
7799             isOk = true;
7800           }
7801           else if (( nbTri == 2 && nbQuad == 3 ) || // merged (0-4)(1-5)
7802                    ( nbTri == 4 && nbQuad == 2 )) { // merged (7-4)(1-5)
7803             // --------------------------------------------> prism
7804             // find 2 opposite triangles
7805             nbUniqueNodes = 6;
7806             for ( iFace = 0; iFace + 1 < nbTri; iFace++ ) {
7807               if ( hexa.GetOppFaceIndex( iTriFace[ iFace ] ) == iTriFace[ iFace + 1 ]) {
7808                 // find indices of kept and replaced nodes
7809                 // and fill unique nodes of 2 opposite triangles
7810                 const int *ind1 = hexa.GetFaceNodesIndices( iTriFace[ iFace ]);
7811                 const int *ind2 = hexa.GetFaceNodesIndices( iTriFace[ iFace + 1 ]);
7812                 const SMDS_MeshNode** hexanodes = hexa.GetNodes();
7813                 // fill unique nodes
7814                 iUnique = 0;
7815                 isOk = true;
7816                 for ( iCur = 0; iCur < 4 && isOk; iCur++ ) {
7817                   const SMDS_MeshNode* n     = curNodes[ind1[ iCur ]];
7818                   const SMDS_MeshNode* nInit = hexanodes[ind1[ iCur ]];
7819                   if ( n == nInit ) {
7820                     // iCur of a linked node of the opposite face (make normals co-directed):
7821                     int iCurOpp = ( iCur == 1 || iCur == 3 ) ? 4 - iCur : iCur;
7822                     // check that correspondent corners of triangles are linked
7823                     if ( !hexa.IsLinked( ind1[ iCur ], ind2[ iCurOpp ] ))
7824                       isOk = false;
7825                     else {
7826                       uniqueNodes[ iUnique ] = n;
7827                       uniqueNodes[ iUnique + 3 ] = curNodes[ind2[ iCurOpp ]];
7828                       iUnique++;
7829                     }
7830                   }
7831                 }
7832                 break;
7833               }
7834             }
7835           }
7836         } // if ( nbUniqueNodes == 6 && nbRepl == 4 )
7837         break;
7838       } // HEXAHEDRON
7839
7840       default:
7841         isOk = false;
7842       } // switch ( nbNodes )
7843
7844     } // if ( nbNodes != nbUniqueNodes ) // some nodes stick
7845
7846     if ( isOk ) {
7847       if (elem->IsPoly() && elem->GetType() == SMDSAbs_Volume) {
7848         // Change nodes of polyedre
7849         const SMDS_VtkVolume* aPolyedre =
7850           dynamic_cast<const SMDS_VtkVolume*>( elem );
7851         if (aPolyedre) {
7852           int nbFaces = aPolyedre->NbFaces();
7853
7854           vector<const SMDS_MeshNode *> poly_nodes;
7855           vector<int> quantities (nbFaces);
7856
7857           for (int iface = 1; iface <= nbFaces; iface++) {
7858             int inode, nbFaceNodes = aPolyedre->NbFaceNodes(iface);
7859             quantities[iface - 1] = nbFaceNodes;
7860
7861             for (inode = 1; inode <= nbFaceNodes; inode++) {
7862               const SMDS_MeshNode* curNode = aPolyedre->GetFaceNode(iface, inode);
7863
7864               TNodeNodeMap::iterator nnIt = nodeNodeMap.find( curNode );
7865               if (nnIt != nodeNodeMap.end()) { // curNode sticks
7866                 curNode = (*nnIt).second;
7867               }
7868               poly_nodes.push_back(curNode);
7869             }
7870           }
7871           aMesh->ChangePolyhedronNodes( elem, poly_nodes, quantities );
7872         }
7873       }
7874       else {
7875         //int elemId = elem->GetID();
7876         //MESSAGE("Change regular element or polygon " << elemId);
7877         SMDSAbs_ElementType etyp = elem->GetType();
7878         uniqueNodes.resize(nbUniqueNodes);
7879         SMDS_MeshElement* newElem = 0;
7880         if (elem->GetEntityType() == SMDSEntity_Polygon)
7881           newElem = this->AddElement(uniqueNodes, etyp, true);
7882         else
7883           newElem = this->AddElement(uniqueNodes, etyp, false);
7884         if (newElem)
7885           {
7886             myLastCreatedElems.Append(newElem);
7887             if ( aShapeId )
7888               aMesh->SetMeshElementOnShape( newElem, aShapeId );
7889           }
7890         aMesh->RemoveElement(elem);
7891       }
7892     }
7893     else {
7894       // Remove invalid regular element or invalid polygon
7895       //MESSAGE("Remove invalid " << elem->GetID());
7896       rmElemIds.push_back( elem->GetID() );
7897     }
7898
7899   } // loop on elements
7900
7901   // Remove bad elements, then equal nodes (order important)
7902
7903   Remove( rmElemIds, false );
7904   Remove( rmNodeIds, true );
7905
7906 }
7907
7908
7909 // ========================================================
7910 // class   : SortableElement
7911 // purpose : allow sorting elements basing on their nodes
7912 // ========================================================
7913 class SortableElement : public set <const SMDS_MeshElement*>
7914 {
7915 public:
7916
7917   SortableElement( const SMDS_MeshElement* theElem )
7918   {
7919     myElem = theElem;
7920     SMDS_ElemIteratorPtr nodeIt = theElem->nodesIterator();
7921     while ( nodeIt->more() )
7922       this->insert( nodeIt->next() );
7923   }
7924
7925   const SMDS_MeshElement* Get() const
7926   { return myElem; }
7927
7928   void Set(const SMDS_MeshElement* e) const
7929   { myElem = e; }
7930
7931
7932 private:
7933   mutable const SMDS_MeshElement* myElem;
7934 };
7935
7936 //=======================================================================
7937 //function : FindEqualElements
7938 //purpose  : Return list of group of elements built on the same nodes.
7939 //           Search among theElements or in the whole mesh if theElements is empty
7940 //=======================================================================
7941 void SMESH_MeshEditor::FindEqualElements(set<const SMDS_MeshElement*> & theElements,
7942                                          TListOfListOfElementsID &      theGroupsOfElementsID)
7943 {
7944   myLastCreatedElems.Clear();
7945   myLastCreatedNodes.Clear();
7946
7947   typedef set<const SMDS_MeshElement*> TElemsSet;
7948   typedef map< SortableElement, int > TMapOfNodeSet;
7949   typedef list<int> TGroupOfElems;
7950
7951   TElemsSet elems;
7952   if ( theElements.empty() )
7953   { // get all elements in the mesh
7954     SMDS_ElemIteratorPtr eIt = GetMeshDS()->elementsIterator();
7955     while ( eIt->more() )
7956       elems.insert( elems.end(), eIt->next());
7957   }
7958   else
7959     elems = theElements;
7960
7961   vector< TGroupOfElems > arrayOfGroups;
7962   TGroupOfElems groupOfElems;
7963   TMapOfNodeSet mapOfNodeSet;
7964
7965   TElemsSet::iterator elemIt = elems.begin();
7966   for ( int i = 0, j=0; elemIt != elems.end(); ++elemIt, ++j ) {
7967     const SMDS_MeshElement* curElem = *elemIt;
7968     SortableElement SE(curElem);
7969     int ind = -1;
7970     // check uniqueness
7971     pair< TMapOfNodeSet::iterator, bool> pp = mapOfNodeSet.insert(make_pair(SE, i));
7972     if( !(pp.second) ) {
7973       TMapOfNodeSet::iterator& itSE = pp.first;
7974       ind = (*itSE).second;
7975       arrayOfGroups[ind].push_back(curElem->GetID());
7976     }
7977     else {
7978       groupOfElems.clear();
7979       groupOfElems.push_back(curElem->GetID());
7980       arrayOfGroups.push_back(groupOfElems);
7981       i++;
7982     }
7983   }
7984
7985   vector< TGroupOfElems >::iterator groupIt = arrayOfGroups.begin();
7986   for ( ; groupIt != arrayOfGroups.end(); ++groupIt ) {
7987     groupOfElems = *groupIt;
7988     if ( groupOfElems.size() > 1 ) {
7989       groupOfElems.sort();
7990       theGroupsOfElementsID.push_back(groupOfElems);
7991     }
7992   }
7993 }
7994
7995 //=======================================================================
7996 //function : MergeElements
7997 //purpose  : In each given group, substitute all elements by the first one.
7998 //=======================================================================
7999
8000 void SMESH_MeshEditor::MergeElements(TListOfListOfElementsID & theGroupsOfElementsID)
8001 {
8002   myLastCreatedElems.Clear();
8003   myLastCreatedNodes.Clear();
8004
8005   typedef list<int> TListOfIDs;
8006   TListOfIDs rmElemIds; // IDs of elems to remove
8007
8008   SMESHDS_Mesh* aMesh = GetMeshDS();
8009
8010   TListOfListOfElementsID::iterator groupsIt = theGroupsOfElementsID.begin();
8011   while ( groupsIt != theGroupsOfElementsID.end() ) {
8012     TListOfIDs& aGroupOfElemID = *groupsIt;
8013     aGroupOfElemID.sort();
8014     int elemIDToKeep = aGroupOfElemID.front();
8015     const SMDS_MeshElement* elemToKeep = aMesh->FindElement(elemIDToKeep);
8016     aGroupOfElemID.pop_front();
8017     TListOfIDs::iterator idIt = aGroupOfElemID.begin();
8018     while ( idIt != aGroupOfElemID.end() ) {
8019       int elemIDToRemove = *idIt;
8020       const SMDS_MeshElement* elemToRemove = aMesh->FindElement(elemIDToRemove);
8021       // add the kept element in groups of removed one (PAL15188)
8022       AddToSameGroups( elemToKeep, elemToRemove, aMesh );
8023       rmElemIds.push_back( elemIDToRemove );
8024       ++idIt;
8025     }
8026     ++groupsIt;
8027   }
8028
8029   Remove( rmElemIds, false );
8030 }
8031
8032 //=======================================================================
8033 //function : MergeEqualElements
8034 //purpose  : Remove all but one of elements built on the same nodes.
8035 //=======================================================================
8036
8037 void SMESH_MeshEditor::MergeEqualElements()
8038 {
8039   set<const SMDS_MeshElement*> aMeshElements; /* empty input -
8040                                                  to merge equal elements in the whole mesh */
8041   TListOfListOfElementsID aGroupsOfElementsID;
8042   FindEqualElements(aMeshElements, aGroupsOfElementsID);
8043   MergeElements(aGroupsOfElementsID);
8044 }
8045
8046 //=======================================================================
8047 //function : FindFaceInSet
8048 //purpose  : Return a face having linked nodes n1 and n2 and which is
8049 //           - not in avoidSet,
8050 //           - in elemSet provided that !elemSet.empty()
8051 //           i1 and i2 optionally returns indices of n1 and n2
8052 //=======================================================================
8053
8054 const SMDS_MeshElement*
8055 SMESH_MeshEditor::FindFaceInSet(const SMDS_MeshNode*    n1,
8056                                 const SMDS_MeshNode*    n2,
8057                                 const TIDSortedElemSet& elemSet,
8058                                 const TIDSortedElemSet& avoidSet,
8059                                 int*                    n1ind,
8060                                 int*                    n2ind)
8061
8062 {
8063   int i1, i2;
8064   const SMDS_MeshElement* face = 0;
8065
8066   SMDS_ElemIteratorPtr invElemIt = n1->GetInverseElementIterator(SMDSAbs_Face);
8067   //MESSAGE("n1->GetInverseElementIterator(SMDSAbs_Face) " << invElemIt);
8068   while ( invElemIt->more() && !face ) // loop on inverse faces of n1
8069   {
8070     //MESSAGE("in while ( invElemIt->more() && !face )");
8071     const SMDS_MeshElement* elem = invElemIt->next();
8072     if (avoidSet.count( elem ))
8073       continue;
8074     if ( !elemSet.empty() && !elemSet.count( elem ))
8075       continue;
8076     // index of n1
8077     i1 = elem->GetNodeIndex( n1 );
8078     // find a n2 linked to n1
8079     int nbN = elem->IsQuadratic() ? elem->NbNodes()/2 : elem->NbNodes();
8080     for ( int di = -1; di < 2 && !face; di += 2 )
8081     {
8082       i2 = (i1+di+nbN) % nbN;
8083       if ( elem->GetNode( i2 ) == n2 )
8084         face = elem;
8085     }
8086     if ( !face && elem->IsQuadratic())
8087     {
8088       // analysis for quadratic elements using all nodes
8089       const SMDS_VtkFace* F =
8090         dynamic_cast<const SMDS_VtkFace*>(elem);
8091       if (!F) throw SALOME_Exception(LOCALIZED("not an SMDS_VtkFace"));
8092       // use special nodes iterator
8093       SMDS_ElemIteratorPtr anIter = F->interlacedNodesElemIterator();
8094       const SMDS_MeshNode* prevN = cast2Node( anIter->next() );
8095       for ( i1 = -1, i2 = 0; anIter->more() && !face; i1++, i2++ )
8096       {
8097         const SMDS_MeshNode* n = cast2Node( anIter->next() );
8098         if ( n1 == prevN && n2 == n )
8099         {
8100           face = elem;
8101         }
8102         else if ( n2 == prevN && n1 == n )
8103         {
8104           face = elem; swap( i1, i2 );
8105         }
8106         prevN = n;
8107       }
8108     }
8109   }
8110   if ( n1ind ) *n1ind = i1;
8111   if ( n2ind ) *n2ind = i2;
8112   return face;
8113 }
8114
8115 //=======================================================================
8116 //function : findAdjacentFace
8117 //purpose  :
8118 //=======================================================================
8119
8120 static const SMDS_MeshElement* findAdjacentFace(const SMDS_MeshNode* n1,
8121                                                 const SMDS_MeshNode* n2,
8122                                                 const SMDS_MeshElement* elem)
8123 {
8124   TIDSortedElemSet elemSet, avoidSet;
8125   if ( elem )
8126     avoidSet.insert ( elem );
8127   return SMESH_MeshEditor::FindFaceInSet( n1, n2, elemSet, avoidSet );
8128 }
8129
8130 //=======================================================================
8131 //function : FindFreeBorder
8132 //purpose  :
8133 //=======================================================================
8134
8135 #define ControlFreeBorder SMESH::Controls::FreeEdges::IsFreeEdge
8136
8137 bool SMESH_MeshEditor::FindFreeBorder (const SMDS_MeshNode*             theFirstNode,
8138                                        const SMDS_MeshNode*             theSecondNode,
8139                                        const SMDS_MeshNode*             theLastNode,
8140                                        list< const SMDS_MeshNode* > &   theNodes,
8141                                        list< const SMDS_MeshElement* >& theFaces)
8142 {
8143   if ( !theFirstNode || !theSecondNode )
8144     return false;
8145   // find border face between theFirstNode and theSecondNode
8146   const SMDS_MeshElement* curElem = findAdjacentFace( theFirstNode, theSecondNode, 0 );
8147   if ( !curElem )
8148     return false;
8149
8150   theFaces.push_back( curElem );
8151   theNodes.push_back( theFirstNode );
8152   theNodes.push_back( theSecondNode );
8153
8154   //vector<const SMDS_MeshNode*> nodes;
8155   const SMDS_MeshNode *nIgnore = theFirstNode, *nStart = theSecondNode;
8156   TIDSortedElemSet foundElems;
8157   bool needTheLast = ( theLastNode != 0 );
8158
8159   while ( nStart != theLastNode ) {
8160     if ( nStart == theFirstNode )
8161       return !needTheLast;
8162
8163     // find all free border faces sharing form nStart
8164
8165     list< const SMDS_MeshElement* > curElemList;
8166     list< const SMDS_MeshNode* > nStartList;
8167     SMDS_ElemIteratorPtr invElemIt = nStart->GetInverseElementIterator(SMDSAbs_Face);
8168     while ( invElemIt->more() ) {
8169       const SMDS_MeshElement* e = invElemIt->next();
8170       if ( e == curElem || foundElems.insert( e ).second ) {
8171         // get nodes
8172         int iNode = 0, nbNodes = e->NbNodes();
8173         //const SMDS_MeshNode* nodes[nbNodes+1];
8174         vector<const SMDS_MeshNode*> nodes(nbNodes+1);
8175
8176         if(e->IsQuadratic()) {
8177           const SMDS_VtkFace* F =
8178             dynamic_cast<const SMDS_VtkFace*>(e);
8179           if (!F) throw SALOME_Exception(LOCALIZED("not an SMDS_VtkFace"));
8180           // use special nodes iterator
8181           SMDS_ElemIteratorPtr anIter = F->interlacedNodesElemIterator();
8182           while( anIter->more() ) {
8183             nodes[ iNode++ ] = cast2Node(anIter->next());
8184           }
8185         }
8186         else {
8187           SMDS_ElemIteratorPtr nIt = e->nodesIterator();
8188           while ( nIt->more() )
8189             nodes[ iNode++ ] = static_cast<const SMDS_MeshNode*>( nIt->next() );
8190         }
8191         nodes[ iNode ] = nodes[ 0 ];
8192         // check 2 links
8193         for ( iNode = 0; iNode < nbNodes; iNode++ )
8194           if (((nodes[ iNode ] == nStart && nodes[ iNode + 1] != nIgnore ) ||
8195                (nodes[ iNode + 1] == nStart && nodes[ iNode ] != nIgnore )) &&
8196               ControlFreeBorder( &nodes[ iNode ], e->GetID() ))
8197           {
8198             nStartList.push_back( nodes[ iNode + ( nodes[ iNode ] == nStart ? 1 : 0 )]);
8199             curElemList.push_back( e );
8200           }
8201       }
8202     }
8203     // analyse the found
8204
8205     int nbNewBorders = curElemList.size();
8206     if ( nbNewBorders == 0 ) {
8207       // no free border furthermore
8208       return !needTheLast;
8209     }
8210     else if ( nbNewBorders == 1 ) {
8211       // one more element found
8212       nIgnore = nStart;
8213       nStart = nStartList.front();
8214       curElem = curElemList.front();
8215       theFaces.push_back( curElem );
8216       theNodes.push_back( nStart );
8217     }
8218     else {
8219       // several continuations found
8220       list< const SMDS_MeshElement* >::iterator curElemIt;
8221       list< const SMDS_MeshNode* >::iterator nStartIt;
8222       // check if one of them reached the last node
8223       if ( needTheLast ) {
8224         for (curElemIt = curElemList.begin(), nStartIt = nStartList.begin();
8225              curElemIt!= curElemList.end();
8226              curElemIt++, nStartIt++ )
8227           if ( *nStartIt == theLastNode ) {
8228             theFaces.push_back( *curElemIt );
8229             theNodes.push_back( *nStartIt );
8230             return true;
8231           }
8232       }
8233       // find the best free border by the continuations
8234       list<const SMDS_MeshNode*>    contNodes[ 2 ], *cNL;
8235       list<const SMDS_MeshElement*> contFaces[ 2 ], *cFL;
8236       for (curElemIt = curElemList.begin(), nStartIt = nStartList.begin();
8237            curElemIt!= curElemList.end();
8238            curElemIt++, nStartIt++ )
8239       {
8240         cNL = & contNodes[ contNodes[0].empty() ? 0 : 1 ];
8241         cFL = & contFaces[ contFaces[0].empty() ? 0 : 1 ];
8242         // find one more free border
8243         if ( ! FindFreeBorder( nStart, *nStartIt, theLastNode, *cNL, *cFL )) {
8244           cNL->clear();
8245           cFL->clear();
8246         }
8247         else if ( !contNodes[0].empty() && !contNodes[1].empty() ) {
8248           // choice: clear a worse one
8249           int iLongest = ( contNodes[0].size() < contNodes[1].size() ? 1 : 0 );
8250           int iWorse = ( needTheLast ? 1 - iLongest : iLongest );
8251           contNodes[ iWorse ].clear();
8252           contFaces[ iWorse ].clear();
8253         }
8254       }
8255       if ( contNodes[0].empty() && contNodes[1].empty() )
8256         return false;
8257
8258       // append the best free border
8259       cNL = & contNodes[ contNodes[0].empty() ? 1 : 0 ];
8260       cFL = & contFaces[ contFaces[0].empty() ? 1 : 0 ];
8261       theNodes.pop_back(); // remove nIgnore
8262       theNodes.pop_back(); // remove nStart
8263       theFaces.pop_back(); // remove curElem
8264       list< const SMDS_MeshNode* >::iterator nIt = cNL->begin();
8265       list< const SMDS_MeshElement* >::iterator fIt = cFL->begin();
8266       for ( ; nIt != cNL->end(); nIt++ ) theNodes.push_back( *nIt );
8267       for ( ; fIt != cFL->end(); fIt++ ) theFaces.push_back( *fIt );
8268       return true;
8269
8270     } // several continuations found
8271   } // while ( nStart != theLastNode )
8272
8273   return true;
8274 }
8275
8276 //=======================================================================
8277 //function : CheckFreeBorderNodes
8278 //purpose  : Return true if the tree nodes are on a free border
8279 //=======================================================================
8280
8281 bool SMESH_MeshEditor::CheckFreeBorderNodes(const SMDS_MeshNode* theNode1,
8282                                             const SMDS_MeshNode* theNode2,
8283                                             const SMDS_MeshNode* theNode3)
8284 {
8285   list< const SMDS_MeshNode* > nodes;
8286   list< const SMDS_MeshElement* > faces;
8287   return FindFreeBorder( theNode1, theNode2, theNode3, nodes, faces);
8288 }
8289
8290 //=======================================================================
8291 //function : SewFreeBorder
8292 //purpose  :
8293 //=======================================================================
8294
8295 SMESH_MeshEditor::Sew_Error
8296 SMESH_MeshEditor::SewFreeBorder (const SMDS_MeshNode* theBordFirstNode,
8297                                  const SMDS_MeshNode* theBordSecondNode,
8298                                  const SMDS_MeshNode* theBordLastNode,
8299                                  const SMDS_MeshNode* theSideFirstNode,
8300                                  const SMDS_MeshNode* theSideSecondNode,
8301                                  const SMDS_MeshNode* theSideThirdNode,
8302                                  const bool           theSideIsFreeBorder,
8303                                  const bool           toCreatePolygons,
8304                                  const bool           toCreatePolyedrs)
8305 {
8306   myLastCreatedElems.Clear();
8307   myLastCreatedNodes.Clear();
8308
8309   MESSAGE("::SewFreeBorder()");
8310   Sew_Error aResult = SEW_OK;
8311
8312   // ====================================
8313   //    find side nodes and elements
8314   // ====================================
8315
8316   list< const SMDS_MeshNode* > nSide[ 2 ];
8317   list< const SMDS_MeshElement* > eSide[ 2 ];
8318   list< const SMDS_MeshNode* >::iterator nIt[ 2 ];
8319   list< const SMDS_MeshElement* >::iterator eIt[ 2 ];
8320
8321   // Free border 1
8322   // --------------
8323   if (!FindFreeBorder(theBordFirstNode,theBordSecondNode,theBordLastNode,
8324                       nSide[0], eSide[0])) {
8325     MESSAGE(" Free Border 1 not found " );
8326     aResult = SEW_BORDER1_NOT_FOUND;
8327   }
8328   if (theSideIsFreeBorder) {
8329     // Free border 2
8330     // --------------
8331     if (!FindFreeBorder(theSideFirstNode, theSideSecondNode, theSideThirdNode,
8332                         nSide[1], eSide[1])) {
8333       MESSAGE(" Free Border 2 not found " );
8334       aResult = ( aResult != SEW_OK ? SEW_BOTH_BORDERS_NOT_FOUND : SEW_BORDER2_NOT_FOUND );
8335     }
8336   }
8337   if ( aResult != SEW_OK )
8338     return aResult;
8339
8340   if (!theSideIsFreeBorder) {
8341     // Side 2
8342     // --------------
8343
8344     // -------------------------------------------------------------------------
8345     // Algo:
8346     // 1. If nodes to merge are not coincident, move nodes of the free border
8347     //    from the coord sys defined by the direction from the first to last
8348     //    nodes of the border to the correspondent sys of the side 2
8349     // 2. On the side 2, find the links most co-directed with the correspondent
8350     //    links of the free border
8351     // -------------------------------------------------------------------------
8352
8353     // 1. Since sewing may break if there are volumes to split on the side 2,
8354     //    we wont move nodes but just compute new coordinates for them
8355     typedef map<const SMDS_MeshNode*, gp_XYZ> TNodeXYZMap;
8356     TNodeXYZMap nBordXYZ;
8357     list< const SMDS_MeshNode* >& bordNodes = nSide[ 0 ];
8358     list< const SMDS_MeshNode* >::iterator nBordIt;
8359
8360     gp_XYZ Pb1( theBordFirstNode->X(), theBordFirstNode->Y(), theBordFirstNode->Z() );
8361     gp_XYZ Pb2( theBordLastNode->X(), theBordLastNode->Y(), theBordLastNode->Z() );
8362     gp_XYZ Ps1( theSideFirstNode->X(), theSideFirstNode->Y(), theSideFirstNode->Z() );
8363     gp_XYZ Ps2( theSideSecondNode->X(), theSideSecondNode->Y(), theSideSecondNode->Z() );
8364     double tol2 = 1.e-8;
8365     gp_Vec Vbs1( Pb1 - Ps1 ),Vbs2( Pb2 - Ps2 );
8366     if ( Vbs1.SquareMagnitude() > tol2 || Vbs2.SquareMagnitude() > tol2 ) {
8367       // Need node movement.
8368
8369       // find X and Z axes to create trsf
8370       gp_Vec Zb( Pb1 - Pb2 ), Zs( Ps1 - Ps2 );
8371       gp_Vec X = Zs ^ Zb;
8372       if ( X.SquareMagnitude() <= gp::Resolution() * gp::Resolution() )
8373         // Zb || Zs
8374         X = gp_Ax2( gp::Origin(), Zb ).XDirection();
8375
8376       // coord systems
8377       gp_Ax3 toBordAx( Pb1, Zb, X );
8378       gp_Ax3 fromSideAx( Ps1, Zs, X );
8379       gp_Ax3 toGlobalAx( gp::Origin(), gp::DZ(), gp::DX() );
8380       // set trsf
8381       gp_Trsf toBordSys, fromSide2Sys;
8382       toBordSys.SetTransformation( toBordAx );
8383       fromSide2Sys.SetTransformation( fromSideAx, toGlobalAx );
8384       fromSide2Sys.SetScaleFactor( Zs.Magnitude() / Zb.Magnitude() );
8385
8386       // move
8387       for ( nBordIt = bordNodes.begin(); nBordIt != bordNodes.end(); nBordIt++ ) {
8388         const SMDS_MeshNode* n = *nBordIt;
8389         gp_XYZ xyz( n->X(),n->Y(),n->Z() );
8390         toBordSys.Transforms( xyz );
8391         fromSide2Sys.Transforms( xyz );
8392         nBordXYZ.insert( TNodeXYZMap::value_type( n, xyz ));
8393       }
8394     }
8395     else {
8396       // just insert nodes XYZ in the nBordXYZ map
8397       for ( nBordIt = bordNodes.begin(); nBordIt != bordNodes.end(); nBordIt++ ) {
8398         const SMDS_MeshNode* n = *nBordIt;
8399         nBordXYZ.insert( TNodeXYZMap::value_type( n, gp_XYZ( n->X(),n->Y(),n->Z() )));
8400       }
8401     }
8402
8403     // 2. On the side 2, find the links most co-directed with the correspondent
8404     //    links of the free border
8405
8406     list< const SMDS_MeshElement* >& sideElems = eSide[ 1 ];
8407     list< const SMDS_MeshNode* >& sideNodes = nSide[ 1 ];
8408     sideNodes.push_back( theSideFirstNode );
8409
8410     bool hasVolumes = false;
8411     LinkID_Gen aLinkID_Gen( GetMeshDS() );
8412     set<long> foundSideLinkIDs, checkedLinkIDs;
8413     SMDS_VolumeTool volume;
8414     //const SMDS_MeshNode* faceNodes[ 4 ];
8415
8416     const SMDS_MeshNode*    sideNode;
8417     const SMDS_MeshElement* sideElem;
8418     const SMDS_MeshNode* prevSideNode = theSideFirstNode;
8419     const SMDS_MeshNode* prevBordNode = theBordFirstNode;
8420     nBordIt = bordNodes.begin();
8421     nBordIt++;
8422     // border node position and border link direction to compare with
8423     gp_XYZ bordPos = nBordXYZ[ *nBordIt ];
8424     gp_XYZ bordDir = bordPos - nBordXYZ[ prevBordNode ];
8425     // choose next side node by link direction or by closeness to
8426     // the current border node:
8427     bool searchByDir = ( *nBordIt != theBordLastNode );
8428     do {
8429       // find the next node on the Side 2
8430       sideNode = 0;
8431       double maxDot = -DBL_MAX, minDist = DBL_MAX;
8432       long linkID;
8433       checkedLinkIDs.clear();
8434       gp_XYZ prevXYZ( prevSideNode->X(), prevSideNode->Y(), prevSideNode->Z() );
8435
8436       // loop on inverse elements of current node (prevSideNode) on the Side 2
8437       SMDS_ElemIteratorPtr invElemIt = prevSideNode->GetInverseElementIterator();
8438       while ( invElemIt->more() )
8439       {
8440         const SMDS_MeshElement* elem = invElemIt->next();
8441         // prepare data for a loop on links coming to prevSideNode, of a face or a volume
8442         int iPrevNode, iNode = 0, nbNodes = elem->NbNodes();
8443         vector< const SMDS_MeshNode* > faceNodes( nbNodes, (const SMDS_MeshNode*)0 );
8444         bool isVolume = volume.Set( elem );
8445         const SMDS_MeshNode** nodes = isVolume ? volume.GetNodes() : & faceNodes[0];
8446         if ( isVolume ) // --volume
8447           hasVolumes = true;
8448         else if ( elem->GetType()==SMDSAbs_Face ) { // --face
8449           // retrieve all face nodes and find iPrevNode - an index of the prevSideNode
8450           if(elem->IsQuadratic()) {
8451             const SMDS_VtkFace* F =
8452               dynamic_cast<const SMDS_VtkFace*>(elem);
8453             if (!F) throw SALOME_Exception(LOCALIZED("not an SMDS_VtkFace"));
8454             // use special nodes iterator
8455             SMDS_ElemIteratorPtr anIter = F->interlacedNodesElemIterator();
8456             while( anIter->more() ) {
8457               nodes[ iNode ] = cast2Node(anIter->next());
8458               if ( nodes[ iNode++ ] == prevSideNode )
8459                 iPrevNode = iNode - 1;
8460             }
8461           }
8462           else {
8463             SMDS_ElemIteratorPtr nIt = elem->nodesIterator();
8464             while ( nIt->more() ) {
8465               nodes[ iNode ] = cast2Node( nIt->next() );
8466               if ( nodes[ iNode++ ] == prevSideNode )
8467                 iPrevNode = iNode - 1;
8468             }
8469           }
8470           // there are 2 links to check
8471           nbNodes = 2;
8472         }
8473         else // --edge
8474           continue;
8475         // loop on links, to be precise, on the second node of links
8476         for ( iNode = 0; iNode < nbNodes; iNode++ ) {
8477           const SMDS_MeshNode* n = nodes[ iNode ];
8478           if ( isVolume ) {
8479             if ( !volume.IsLinked( n, prevSideNode ))
8480               continue;
8481           }
8482           else {
8483             if ( iNode ) // a node before prevSideNode
8484               n = nodes[ iPrevNode == 0 ? elem->NbNodes() - 1 : iPrevNode - 1 ];
8485             else         // a node after prevSideNode
8486               n = nodes[ iPrevNode + 1 == elem->NbNodes() ? 0 : iPrevNode + 1 ];
8487           }
8488           // check if this link was already used
8489           long iLink = aLinkID_Gen.GetLinkID( prevSideNode, n );
8490           bool isJustChecked = !checkedLinkIDs.insert( iLink ).second;
8491           if (!isJustChecked &&
8492               foundSideLinkIDs.find( iLink ) == foundSideLinkIDs.end() )
8493           {
8494             // test a link geometrically
8495             gp_XYZ nextXYZ ( n->X(), n->Y(), n->Z() );
8496             bool linkIsBetter = false;
8497             double dot = 0.0, dist = 0.0;
8498             if ( searchByDir ) { // choose most co-directed link
8499               dot = bordDir * ( nextXYZ - prevXYZ ).Normalized();
8500               linkIsBetter = ( dot > maxDot );
8501             }
8502             else { // choose link with the node closest to bordPos
8503               dist = ( nextXYZ - bordPos ).SquareModulus();
8504               linkIsBetter = ( dist < minDist );
8505             }
8506             if ( linkIsBetter ) {
8507               maxDot = dot;
8508               minDist = dist;
8509               linkID = iLink;
8510               sideNode = n;
8511               sideElem = elem;
8512             }
8513           }
8514         }
8515       } // loop on inverse elements of prevSideNode
8516
8517       if ( !sideNode ) {
8518         MESSAGE(" Cant find path by links of the Side 2 ");
8519         return SEW_BAD_SIDE_NODES;
8520       }
8521       sideNodes.push_back( sideNode );
8522       sideElems.push_back( sideElem );
8523       foundSideLinkIDs.insert ( linkID );
8524       prevSideNode = sideNode;
8525
8526       if ( *nBordIt == theBordLastNode )
8527         searchByDir = false;
8528       else {
8529         // find the next border link to compare with
8530         gp_XYZ sidePos( sideNode->X(), sideNode->Y(), sideNode->Z() );
8531         searchByDir = ( bordDir * ( sidePos - bordPos ) <= 0 );
8532         // move to next border node if sideNode is before forward border node (bordPos)
8533         while ( *nBordIt != theBordLastNode && !searchByDir ) {
8534           prevBordNode = *nBordIt;
8535           nBordIt++;
8536           bordPos = nBordXYZ[ *nBordIt ];
8537           bordDir = bordPos - nBordXYZ[ prevBordNode ];
8538           searchByDir = ( bordDir * ( sidePos - bordPos ) <= 0 );
8539         }
8540       }
8541     }
8542     while ( sideNode != theSideSecondNode );
8543
8544     if ( hasVolumes && sideNodes.size () != bordNodes.size() && !toCreatePolyedrs) {
8545       MESSAGE("VOLUME SPLITTING IS FORBIDDEN");
8546       return SEW_VOLUMES_TO_SPLIT; // volume splitting is forbidden
8547     }
8548   } // end nodes search on the side 2
8549
8550   // ============================
8551   // sew the border to the side 2
8552   // ============================
8553
8554   int nbNodes[]  = { nSide[0].size(), nSide[1].size() };
8555   int maxNbNodes = Max( nbNodes[0], nbNodes[1] );
8556
8557   TListOfListOfNodes nodeGroupsToMerge;
8558   if ( nbNodes[0] == nbNodes[1] ||
8559        ( theSideIsFreeBorder && !theSideThirdNode)) {
8560
8561     // all nodes are to be merged
8562
8563     for (nIt[0] = nSide[0].begin(), nIt[1] = nSide[1].begin();
8564          nIt[0] != nSide[0].end() && nIt[1] != nSide[1].end();
8565          nIt[0]++, nIt[1]++ )
8566     {
8567       nodeGroupsToMerge.push_back( list<const SMDS_MeshNode*>() );
8568       nodeGroupsToMerge.back().push_back( *nIt[1] ); // to keep
8569       nodeGroupsToMerge.back().push_back( *nIt[0] ); // to remove
8570     }
8571   }
8572   else {
8573
8574     // insert new nodes into the border and the side to get equal nb of segments
8575
8576     // get normalized parameters of nodes on the borders
8577     //double param[ 2 ][ maxNbNodes ];
8578     double* param[ 2 ];
8579     param[0] = new double [ maxNbNodes ];
8580     param[1] = new double [ maxNbNodes ];
8581     int iNode, iBord;
8582     for ( iBord = 0; iBord < 2; iBord++ ) { // loop on 2 borders
8583       list< const SMDS_MeshNode* >& nodes = nSide[ iBord ];
8584       list< const SMDS_MeshNode* >::iterator nIt = nodes.begin();
8585       const SMDS_MeshNode* nPrev = *nIt;
8586       double bordLength = 0;
8587       for ( iNode = 0; nIt != nodes.end(); nIt++, iNode++ ) { // loop on border nodes
8588         const SMDS_MeshNode* nCur = *nIt;
8589         gp_XYZ segment (nCur->X() - nPrev->X(),
8590                         nCur->Y() - nPrev->Y(),
8591                         nCur->Z() - nPrev->Z());
8592         double segmentLen = segment.Modulus();
8593         bordLength += segmentLen;
8594         param[ iBord ][ iNode ] = bordLength;
8595         nPrev = nCur;
8596       }
8597       // normalize within [0,1]
8598       for ( iNode = 0; iNode < nbNodes[ iBord ]; iNode++ ) {
8599         param[ iBord ][ iNode ] /= bordLength;
8600       }
8601     }
8602
8603     // loop on border segments
8604     const SMDS_MeshNode *nPrev[ 2 ] = { 0, 0 };
8605     int i[ 2 ] = { 0, 0 };
8606     nIt[0] = nSide[0].begin(); eIt[0] = eSide[0].begin();
8607     nIt[1] = nSide[1].begin(); eIt[1] = eSide[1].begin();
8608
8609     TElemOfNodeListMap insertMap;
8610     TElemOfNodeListMap::iterator insertMapIt;
8611     // insertMap is
8612     // key:   elem to insert nodes into
8613     // value: 2 nodes to insert between + nodes to be inserted
8614     do {
8615       bool next[ 2 ] = { false, false };
8616
8617       // find min adjacent segment length after sewing
8618       double nextParam = 10., prevParam = 0;
8619       for ( iBord = 0; iBord < 2; iBord++ ) { // loop on 2 borders
8620         if ( i[ iBord ] + 1 < nbNodes[ iBord ])
8621           nextParam = Min( nextParam, param[iBord][ i[iBord] + 1 ]);
8622         if ( i[ iBord ] > 0 )
8623           prevParam = Max( prevParam, param[iBord][ i[iBord] - 1 ]);
8624       }
8625       double minParam = Min( param[ 0 ][ i[0] ], param[ 1 ][ i[1] ]);
8626       double maxParam = Max( param[ 0 ][ i[0] ], param[ 1 ][ i[1] ]);
8627       double minSegLen = Min( nextParam - minParam, maxParam - prevParam );
8628
8629       // choose to insert or to merge nodes
8630       double du = param[ 1 ][ i[1] ] - param[ 0 ][ i[0] ];
8631       if ( Abs( du ) <= minSegLen * 0.2 ) {
8632         // merge
8633         // ------
8634         nodeGroupsToMerge.push_back( list<const SMDS_MeshNode*>() );
8635         const SMDS_MeshNode* n0 = *nIt[0];
8636         const SMDS_MeshNode* n1 = *nIt[1];
8637         nodeGroupsToMerge.back().push_back( n1 );
8638         nodeGroupsToMerge.back().push_back( n0 );
8639         // position of node of the border changes due to merge
8640         param[ 0 ][ i[0] ] += du;
8641         // move n1 for the sake of elem shape evaluation during insertion.
8642         // n1 will be removed by MergeNodes() anyway
8643         const_cast<SMDS_MeshNode*>( n0 )->setXYZ( n1->X(), n1->Y(), n1->Z() );
8644         next[0] = next[1] = true;
8645       }
8646       else {
8647         // insert
8648         // ------
8649         int intoBord = ( du < 0 ) ? 0 : 1;
8650         const SMDS_MeshElement* elem = *eIt[ intoBord ];
8651         const SMDS_MeshNode*    n1   = nPrev[ intoBord ];
8652         const SMDS_MeshNode*    n2   = *nIt[ intoBord ];
8653         const SMDS_MeshNode*    nIns = *nIt[ 1 - intoBord ];
8654         if ( intoBord == 1 ) {
8655           // move node of the border to be on a link of elem of the side
8656           gp_XYZ p1 (n1->X(), n1->Y(), n1->Z());
8657           gp_XYZ p2 (n2->X(), n2->Y(), n2->Z());
8658           double ratio = du / ( param[ 1 ][ i[1] ] - param[ 1 ][ i[1]-1 ]);
8659           gp_XYZ p = p2 * ( 1 - ratio ) + p1 * ratio;
8660           GetMeshDS()->MoveNode( nIns, p.X(), p.Y(), p.Z() );
8661         }
8662         insertMapIt = insertMap.find( elem );
8663         bool notFound = ( insertMapIt == insertMap.end() );
8664         bool otherLink = ( !notFound && (*insertMapIt).second.front() != n1 );
8665         if ( otherLink ) {
8666           // insert into another link of the same element:
8667           // 1. perform insertion into the other link of the elem
8668           list<const SMDS_MeshNode*> & nodeList = (*insertMapIt).second;
8669           const SMDS_MeshNode* n12 = nodeList.front(); nodeList.pop_front();
8670           const SMDS_MeshNode* n22 = nodeList.front(); nodeList.pop_front();
8671           InsertNodesIntoLink( elem, n12, n22, nodeList, toCreatePolygons );
8672           // 2. perform insertion into the link of adjacent faces
8673           while (true) {
8674             const SMDS_MeshElement* adjElem = findAdjacentFace( n12, n22, elem );
8675             if ( adjElem )
8676               InsertNodesIntoLink( adjElem, n12, n22, nodeList, toCreatePolygons );
8677             else
8678               break;
8679           }
8680           if (toCreatePolyedrs) {
8681             // perform insertion into the links of adjacent volumes
8682             UpdateVolumes(n12, n22, nodeList);
8683           }
8684           // 3. find an element appeared on n1 and n2 after the insertion
8685           insertMap.erase( elem );
8686           elem = findAdjacentFace( n1, n2, 0 );
8687         }
8688         if ( notFound || otherLink ) {
8689           // add element and nodes of the side into the insertMap
8690           insertMapIt = insertMap.insert
8691             ( TElemOfNodeListMap::value_type( elem, list<const SMDS_MeshNode*>() )).first;
8692           (*insertMapIt).second.push_back( n1 );
8693           (*insertMapIt).second.push_back( n2 );
8694         }
8695         // add node to be inserted into elem
8696         (*insertMapIt).second.push_back( nIns );
8697         next[ 1 - intoBord ] = true;
8698       }
8699
8700       // go to the next segment
8701       for ( iBord = 0; iBord < 2; iBord++ ) { // loop on 2 borders
8702         if ( next[ iBord ] ) {
8703           if ( i[ iBord ] != 0 && eIt[ iBord ] != eSide[ iBord ].end())
8704             eIt[ iBord ]++;
8705           nPrev[ iBord ] = *nIt[ iBord ];
8706           nIt[ iBord ]++; i[ iBord ]++;
8707         }
8708       }
8709     }
8710     while ( nIt[0] != nSide[0].end() && nIt[1] != nSide[1].end());
8711
8712     // perform insertion of nodes into elements
8713
8714     for (insertMapIt = insertMap.begin();
8715          insertMapIt != insertMap.end();
8716          insertMapIt++ )
8717     {
8718       const SMDS_MeshElement* elem = (*insertMapIt).first;
8719       list<const SMDS_MeshNode*> & nodeList = (*insertMapIt).second;
8720       const SMDS_MeshNode* n1 = nodeList.front(); nodeList.pop_front();
8721       const SMDS_MeshNode* n2 = nodeList.front(); nodeList.pop_front();
8722
8723       InsertNodesIntoLink( elem, n1, n2, nodeList, toCreatePolygons );
8724
8725       if ( !theSideIsFreeBorder ) {
8726         // look for and insert nodes into the faces adjacent to elem
8727         while (true) {
8728           const SMDS_MeshElement* adjElem = findAdjacentFace( n1, n2, elem );
8729           if ( adjElem )
8730             InsertNodesIntoLink( adjElem, n1, n2, nodeList, toCreatePolygons );
8731           else
8732             break;
8733         }
8734       }
8735       if (toCreatePolyedrs) {
8736         // perform insertion into the links of adjacent volumes
8737         UpdateVolumes(n1, n2, nodeList);
8738       }
8739     }
8740
8741     delete param[0];
8742     delete param[1];
8743   } // end: insert new nodes
8744
8745   MergeNodes ( nodeGroupsToMerge );
8746
8747   return aResult;
8748 }
8749
8750 //=======================================================================
8751 //function : InsertNodesIntoLink
8752 //purpose  : insert theNodesToInsert into theFace between theBetweenNode1
8753 //           and theBetweenNode2 and split theElement
8754 //=======================================================================
8755
8756 void SMESH_MeshEditor::InsertNodesIntoLink(const SMDS_MeshElement*     theFace,
8757                                            const SMDS_MeshNode*        theBetweenNode1,
8758                                            const SMDS_MeshNode*        theBetweenNode2,
8759                                            list<const SMDS_MeshNode*>& theNodesToInsert,
8760                                            const bool                  toCreatePoly)
8761 {
8762   if ( theFace->GetType() != SMDSAbs_Face ) return;
8763
8764   // find indices of 2 link nodes and of the rest nodes
8765   int iNode = 0, il1, il2, i3, i4;
8766   il1 = il2 = i3 = i4 = -1;
8767   //const SMDS_MeshNode* nodes[ theFace->NbNodes() ];
8768   vector<const SMDS_MeshNode*> nodes( theFace->NbNodes() );
8769
8770   if(theFace->IsQuadratic()) {
8771     const SMDS_VtkFace* F =
8772       dynamic_cast<const SMDS_VtkFace*>(theFace);
8773     if (!F) throw SALOME_Exception(LOCALIZED("not an SMDS_VtkFace"));
8774     // use special nodes iterator
8775     SMDS_ElemIteratorPtr anIter = F->interlacedNodesElemIterator();
8776     while( anIter->more() ) {
8777       const SMDS_MeshNode* n = cast2Node(anIter->next());
8778       if ( n == theBetweenNode1 )
8779         il1 = iNode;
8780       else if ( n == theBetweenNode2 )
8781         il2 = iNode;
8782       else if ( i3 < 0 )
8783         i3 = iNode;
8784       else
8785         i4 = iNode;
8786       nodes[ iNode++ ] = n;
8787     }
8788   }
8789   else {
8790     SMDS_ElemIteratorPtr nodeIt = theFace->nodesIterator();
8791     while ( nodeIt->more() ) {
8792       const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
8793       if ( n == theBetweenNode1 )
8794         il1 = iNode;
8795       else if ( n == theBetweenNode2 )
8796         il2 = iNode;
8797       else if ( i3 < 0 )
8798         i3 = iNode;
8799       else
8800         i4 = iNode;
8801       nodes[ iNode++ ] = n;
8802     }
8803   }
8804   if ( il1 < 0 || il2 < 0 || i3 < 0 )
8805     return ;
8806
8807   // arrange link nodes to go one after another regarding the face orientation
8808   bool reverse = ( Abs( il2 - il1 ) == 1 ? il2 < il1 : il1 < il2 );
8809   list<const SMDS_MeshNode *> aNodesToInsert = theNodesToInsert;
8810   if ( reverse ) {
8811     iNode = il1;
8812     il1 = il2;
8813     il2 = iNode;
8814     aNodesToInsert.reverse();
8815   }
8816   // check that not link nodes of a quadrangles are in good order
8817   int nbFaceNodes = theFace->NbNodes();
8818   if ( nbFaceNodes == 4 && i4 - i3 != 1 ) {
8819     iNode = i3;
8820     i3 = i4;
8821     i4 = iNode;
8822   }
8823
8824   if (toCreatePoly || theFace->IsPoly()) {
8825
8826     iNode = 0;
8827     vector<const SMDS_MeshNode *> poly_nodes (nbFaceNodes + aNodesToInsert.size());
8828
8829     // add nodes of face up to first node of link
8830     bool isFLN = false;
8831
8832     if(theFace->IsQuadratic()) {
8833       const SMDS_VtkFace* F =
8834         dynamic_cast<const SMDS_VtkFace*>(theFace);
8835       if (!F) throw SALOME_Exception(LOCALIZED("not an SMDS_VtkFace"));
8836       // use special nodes iterator
8837       SMDS_ElemIteratorPtr anIter = F->interlacedNodesElemIterator();
8838       while( anIter->more()  && !isFLN ) {
8839         const SMDS_MeshNode* n = cast2Node(anIter->next());
8840         poly_nodes[iNode++] = n;
8841         if (n == nodes[il1]) {
8842           isFLN = true;
8843         }
8844       }
8845       // add nodes to insert
8846       list<const SMDS_MeshNode*>::iterator nIt = aNodesToInsert.begin();
8847       for (; nIt != aNodesToInsert.end(); nIt++) {
8848         poly_nodes[iNode++] = *nIt;
8849       }
8850       // add nodes of face starting from last node of link
8851       while ( anIter->more() ) {
8852         poly_nodes[iNode++] = cast2Node(anIter->next());
8853       }
8854     }
8855     else {
8856       SMDS_ElemIteratorPtr nodeIt = theFace->nodesIterator();
8857       while ( nodeIt->more() && !isFLN ) {
8858         const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
8859         poly_nodes[iNode++] = n;
8860         if (n == nodes[il1]) {
8861           isFLN = true;
8862         }
8863       }
8864       // add nodes to insert
8865       list<const SMDS_MeshNode*>::iterator nIt = aNodesToInsert.begin();
8866       for (; nIt != aNodesToInsert.end(); nIt++) {
8867         poly_nodes[iNode++] = *nIt;
8868       }
8869       // add nodes of face starting from last node of link
8870       while ( nodeIt->more() ) {
8871         const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
8872         poly_nodes[iNode++] = n;
8873       }
8874     }
8875
8876     // edit or replace the face
8877     SMESHDS_Mesh *aMesh = GetMeshDS();
8878
8879     if (theFace->IsPoly()) {
8880       aMesh->ChangePolygonNodes(theFace, poly_nodes);
8881     }
8882     else {
8883       int aShapeId = FindShape( theFace );
8884
8885       SMDS_MeshElement* newElem = aMesh->AddPolygonalFace(poly_nodes);
8886       myLastCreatedElems.Append(newElem);
8887       if ( aShapeId && newElem )
8888         aMesh->SetMeshElementOnShape( newElem, aShapeId );
8889
8890       aMesh->RemoveElement(theFace);
8891     }
8892     return;
8893   }
8894
8895   SMESHDS_Mesh *aMesh = GetMeshDS();
8896   if( !theFace->IsQuadratic() ) {
8897
8898     // put aNodesToInsert between theBetweenNode1 and theBetweenNode2
8899     int nbLinkNodes = 2 + aNodesToInsert.size();
8900     //const SMDS_MeshNode* linkNodes[ nbLinkNodes ];
8901     vector<const SMDS_MeshNode*> linkNodes( nbLinkNodes );
8902     linkNodes[ 0 ] = nodes[ il1 ];
8903     linkNodes[ nbLinkNodes - 1 ] = nodes[ il2 ];
8904     list<const SMDS_MeshNode*>::iterator nIt = aNodesToInsert.begin();
8905     for ( iNode = 1; nIt != aNodesToInsert.end(); nIt++ ) {
8906       linkNodes[ iNode++ ] = *nIt;
8907     }
8908     // decide how to split a quadrangle: compare possible variants
8909     // and choose which of splits to be a quadrangle
8910     int i1, i2, iSplit, nbSplits = nbLinkNodes - 1, iBestQuad;
8911     if ( nbFaceNodes == 3 ) {
8912       iBestQuad = nbSplits;
8913       i4 = i3;
8914     }
8915     else if ( nbFaceNodes == 4 ) {
8916       SMESH::Controls::NumericalFunctorPtr aCrit( new SMESH::Controls::AspectRatio);
8917       double aBestRate = DBL_MAX;
8918       for ( int iQuad = 0; iQuad < nbSplits; iQuad++ ) {
8919         i1 = 0; i2 = 1;
8920         double aBadRate = 0;
8921         // evaluate elements quality
8922         for ( iSplit = 0; iSplit < nbSplits; iSplit++ ) {
8923           if ( iSplit == iQuad ) {
8924             SMDS_FaceOfNodes quad (linkNodes[ i1++ ],
8925                                    linkNodes[ i2++ ],
8926                                    nodes[ i3 ],
8927                                    nodes[ i4 ]);
8928             aBadRate += getBadRate( &quad, aCrit );
8929           }
8930           else {
8931             SMDS_FaceOfNodes tria (linkNodes[ i1++ ],
8932                                    linkNodes[ i2++ ],
8933                                    nodes[ iSplit < iQuad ? i4 : i3 ]);
8934             aBadRate += getBadRate( &tria, aCrit );
8935           }
8936         }
8937         // choice
8938         if ( aBadRate < aBestRate ) {
8939           iBestQuad = iQuad;
8940           aBestRate = aBadRate;
8941         }
8942       }
8943     }
8944
8945     // create new elements
8946     int aShapeId = FindShape( theFace );
8947
8948     i1 = 0; i2 = 1;
8949     for ( iSplit = 0; iSplit < nbSplits - 1; iSplit++ ) {
8950       SMDS_MeshElement* newElem = 0;
8951       if ( iSplit == iBestQuad )
8952         newElem = aMesh->AddFace (linkNodes[ i1++ ],
8953                                   linkNodes[ i2++ ],
8954                                   nodes[ i3 ],
8955                                   nodes[ i4 ]);
8956       else
8957         newElem = aMesh->AddFace (linkNodes[ i1++ ],
8958                                   linkNodes[ i2++ ],
8959                                   nodes[ iSplit < iBestQuad ? i4 : i3 ]);
8960       myLastCreatedElems.Append(newElem);
8961       if ( aShapeId && newElem )
8962         aMesh->SetMeshElementOnShape( newElem, aShapeId );
8963     }
8964
8965     // change nodes of theFace
8966     const SMDS_MeshNode* newNodes[ 4 ];
8967     newNodes[ 0 ] = linkNodes[ i1 ];
8968     newNodes[ 1 ] = linkNodes[ i2 ];
8969     newNodes[ 2 ] = nodes[ iSplit >= iBestQuad ? i3 : i4 ];
8970     newNodes[ 3 ] = nodes[ i4 ];
8971     //aMesh->ChangeElementNodes( theFace, newNodes, iSplit == iBestQuad ? 4 : 3 );
8972     const SMDS_MeshElement* newElem = 0;
8973     if (iSplit == iBestQuad)
8974       newElem = aMesh->AddFace( newNodes[0], newNodes[1], newNodes[2], newNodes[3] );
8975     else
8976       newElem = aMesh->AddFace( newNodes[0], newNodes[1], newNodes[2] );
8977     myLastCreatedElems.Append(newElem);
8978     if ( aShapeId && newElem )
8979       aMesh->SetMeshElementOnShape( newElem, aShapeId );
8980 } // end if(!theFace->IsQuadratic())
8981   else { // theFace is quadratic
8982     // we have to split theFace on simple triangles and one simple quadrangle
8983     int tmp = il1/2;
8984     int nbshift = tmp*2;
8985     // shift nodes in nodes[] by nbshift
8986     int i,j;
8987     for(i=0; i<nbshift; i++) {
8988       const SMDS_MeshNode* n = nodes[0];
8989       for(j=0; j<nbFaceNodes-1; j++) {
8990         nodes[j] = nodes[j+1];
8991       }
8992       nodes[nbFaceNodes-1] = n;
8993     }
8994     il1 = il1 - nbshift;
8995     // now have to insert nodes between n0 and n1 or n1 and n2 (see below)
8996     //   n0      n1     n2    n0      n1     n2
8997     //     +-----+-----+        +-----+-----+
8998     //      \         /         |           |
8999     //       \       /          |           |
9000     //      n5+     +n3       n7+           +n3
9001     //         \   /            |           |
9002     //          \ /             |           |
9003     //           +              +-----+-----+
9004     //           n4           n6      n5     n4
9005
9006     // create new elements
9007     int aShapeId = FindShape( theFace );
9008
9009     int n1,n2,n3;
9010     if(nbFaceNodes==6) { // quadratic triangle
9011       SMDS_MeshElement* newElem =
9012         aMesh->AddFace(nodes[3],nodes[4],nodes[5]);
9013       myLastCreatedElems.Append(newElem);
9014       if ( aShapeId && newElem )
9015         aMesh->SetMeshElementOnShape( newElem, aShapeId );
9016       if(theFace->IsMediumNode(nodes[il1])) {
9017         // create quadrangle
9018         newElem = aMesh->AddFace(nodes[0],nodes[1],nodes[3],nodes[5]);
9019         myLastCreatedElems.Append(newElem);
9020         if ( aShapeId && newElem )
9021           aMesh->SetMeshElementOnShape( newElem, aShapeId );
9022         n1 = 1;
9023         n2 = 2;
9024         n3 = 3;
9025       }
9026       else {
9027         // create quadrangle
9028         newElem = aMesh->AddFace(nodes[1],nodes[2],nodes[3],nodes[5]);
9029         myLastCreatedElems.Append(newElem);
9030         if ( aShapeId && newElem )
9031           aMesh->SetMeshElementOnShape( newElem, aShapeId );
9032         n1 = 0;
9033         n2 = 1;
9034         n3 = 5;
9035       }
9036     }
9037     else { // nbFaceNodes==8 - quadratic quadrangle
9038       SMDS_MeshElement* newElem =
9039         aMesh->AddFace(nodes[3],nodes[4],nodes[5]);
9040       myLastCreatedElems.Append(newElem);
9041       if ( aShapeId && newElem )
9042         aMesh->SetMeshElementOnShape( newElem, aShapeId );
9043       newElem = aMesh->AddFace(nodes[5],nodes[6],nodes[7]);
9044       myLastCreatedElems.Append(newElem);
9045       if ( aShapeId && newElem )
9046         aMesh->SetMeshElementOnShape( newElem, aShapeId );
9047       newElem = aMesh->AddFace(nodes[5],nodes[7],nodes[3]);
9048       myLastCreatedElems.Append(newElem);
9049       if ( aShapeId && newElem )
9050         aMesh->SetMeshElementOnShape( newElem, aShapeId );
9051       if(theFace->IsMediumNode(nodes[il1])) {
9052         // create quadrangle
9053         newElem = aMesh->AddFace(nodes[0],nodes[1],nodes[3],nodes[7]);
9054         myLastCreatedElems.Append(newElem);
9055         if ( aShapeId && newElem )
9056           aMesh->SetMeshElementOnShape( newElem, aShapeId );
9057         n1 = 1;
9058         n2 = 2;
9059         n3 = 3;
9060       }
9061       else {
9062         // create quadrangle
9063         newElem = aMesh->AddFace(nodes[1],nodes[2],nodes[3],nodes[7]);
9064         myLastCreatedElems.Append(newElem);
9065         if ( aShapeId && newElem )
9066           aMesh->SetMeshElementOnShape( newElem, aShapeId );
9067         n1 = 0;
9068         n2 = 1;
9069         n3 = 7;
9070       }
9071     }
9072     // create needed triangles using n1,n2,n3 and inserted nodes
9073     int nbn = 2 + aNodesToInsert.size();
9074     //const SMDS_MeshNode* aNodes[nbn];
9075     vector<const SMDS_MeshNode*> aNodes(nbn);
9076     aNodes[0] = nodes[n1];
9077     aNodes[nbn-1] = nodes[n2];
9078     list<const SMDS_MeshNode*>::iterator nIt = aNodesToInsert.begin();
9079     for ( iNode = 1; nIt != aNodesToInsert.end(); nIt++ ) {
9080       aNodes[iNode++] = *nIt;
9081     }
9082     for(i=1; i<nbn; i++) {
9083       SMDS_MeshElement* newElem =
9084         aMesh->AddFace(aNodes[i-1],aNodes[i],nodes[n3]);
9085       myLastCreatedElems.Append(newElem);
9086       if ( aShapeId && newElem )
9087         aMesh->SetMeshElementOnShape( newElem, aShapeId );
9088     }
9089   }
9090   // remove old face
9091   aMesh->RemoveElement(theFace);
9092 }
9093
9094 //=======================================================================
9095 //function : UpdateVolumes
9096 //purpose  :
9097 //=======================================================================
9098 void SMESH_MeshEditor::UpdateVolumes (const SMDS_MeshNode*        theBetweenNode1,
9099                                       const SMDS_MeshNode*        theBetweenNode2,
9100                                       list<const SMDS_MeshNode*>& theNodesToInsert)
9101 {
9102   myLastCreatedElems.Clear();
9103   myLastCreatedNodes.Clear();
9104
9105   SMDS_ElemIteratorPtr invElemIt = theBetweenNode1->GetInverseElementIterator(SMDSAbs_Volume);
9106   while (invElemIt->more()) { // loop on inverse elements of theBetweenNode1
9107     const SMDS_MeshElement* elem = invElemIt->next();
9108
9109     // check, if current volume has link theBetweenNode1 - theBetweenNode2
9110     SMDS_VolumeTool aVolume (elem);
9111     if (!aVolume.IsLinked(theBetweenNode1, theBetweenNode2))
9112       continue;
9113
9114     // insert new nodes in all faces of the volume, sharing link theBetweenNode1 - theBetweenNode2
9115     int iface, nbFaces = aVolume.NbFaces();
9116     vector<const SMDS_MeshNode *> poly_nodes;
9117     vector<int> quantities (nbFaces);
9118
9119     for (iface = 0; iface < nbFaces; iface++) {
9120       int nbFaceNodes = aVolume.NbFaceNodes(iface), nbInserted = 0;
9121       // faceNodes will contain (nbFaceNodes + 1) nodes, last = first
9122       const SMDS_MeshNode** faceNodes = aVolume.GetFaceNodes(iface);
9123
9124       for (int inode = 0; inode < nbFaceNodes; inode++) {
9125         poly_nodes.push_back(faceNodes[inode]);
9126
9127         if (nbInserted == 0) {
9128           if (faceNodes[inode] == theBetweenNode1) {
9129             if (faceNodes[inode + 1] == theBetweenNode2) {
9130               nbInserted = theNodesToInsert.size();
9131
9132               // add nodes to insert
9133               list<const SMDS_MeshNode*>::iterator nIt = theNodesToInsert.begin();
9134               for (; nIt != theNodesToInsert.end(); nIt++) {
9135                 poly_nodes.push_back(*nIt);
9136               }
9137             }
9138           }
9139           else if (faceNodes[inode] == theBetweenNode2) {
9140             if (faceNodes[inode + 1] == theBetweenNode1) {
9141               nbInserted = theNodesToInsert.size();
9142
9143               // add nodes to insert in reversed order
9144               list<const SMDS_MeshNode*>::iterator nIt = theNodesToInsert.end();
9145               nIt--;
9146               for (; nIt != theNodesToInsert.begin(); nIt--) {
9147                 poly_nodes.push_back(*nIt);
9148               }
9149               poly_nodes.push_back(*nIt);
9150             }
9151           }
9152           else {
9153           }
9154         }
9155       }
9156       quantities[iface] = nbFaceNodes + nbInserted;
9157     }
9158
9159     // Replace or update the volume
9160     SMESHDS_Mesh *aMesh = GetMeshDS();
9161
9162     if (elem->IsPoly()) {
9163       aMesh->ChangePolyhedronNodes(elem, poly_nodes, quantities);
9164
9165     }
9166     else {
9167       int aShapeId = FindShape( elem );
9168
9169       SMDS_MeshElement* newElem =
9170         aMesh->AddPolyhedralVolume(poly_nodes, quantities);
9171       myLastCreatedElems.Append(newElem);
9172       if (aShapeId && newElem)
9173         aMesh->SetMeshElementOnShape(newElem, aShapeId);
9174
9175       aMesh->RemoveElement(elem);
9176     }
9177   }
9178 }
9179
9180 //=======================================================================
9181 /*!
9182  * \brief Convert elements contained in a submesh to quadratic
9183  * \retval int - nb of checked elements
9184  */
9185 //=======================================================================
9186
9187 int SMESH_MeshEditor::convertElemToQuadratic(SMESHDS_SubMesh *   theSm,
9188                                              SMESH_MesherHelper& theHelper,
9189                                              const bool          theForce3d)
9190 {
9191   int nbElem = 0;
9192   if( !theSm ) return nbElem;
9193
9194   vector<int> nbNodeInFaces;
9195   SMDS_ElemIteratorPtr ElemItr = theSm->GetElements();
9196   while(ElemItr->more())
9197   {
9198     nbElem++;
9199     const SMDS_MeshElement* elem = ElemItr->next();
9200     if( !elem || elem->IsQuadratic() ) continue;
9201
9202     int id = elem->GetID();
9203     //MESSAGE("elem " << id);
9204     id = 0; // get a free number for new elements
9205     int nbNodes = elem->NbNodes();
9206     SMDSAbs_ElementType aType = elem->GetType();
9207
9208     vector<const SMDS_MeshNode *> nodes (elem->begin_nodes(), elem->end_nodes());
9209     if ( elem->GetEntityType() == SMDSEntity_Polyhedra )
9210       nbNodeInFaces = static_cast<const SMDS_VtkVolume* >( elem )->GetQuantities();
9211
9212     const SMDS_MeshElement* NewElem = 0;
9213
9214     switch( aType )
9215     {
9216     case SMDSAbs_Edge :
9217       {
9218         NewElem = theHelper.AddEdge(nodes[0], nodes[1], id, theForce3d);
9219         break;
9220       }
9221     case SMDSAbs_Face :
9222       {
9223         switch(nbNodes)
9224         {
9225         case 3:
9226           NewElem = theHelper.AddFace(nodes[0], nodes[1], nodes[2], id, theForce3d);
9227           break;
9228         case 4:
9229           NewElem = theHelper.AddFace(nodes[0], nodes[1], nodes[2], nodes[3], id, theForce3d);
9230           break;
9231         default:
9232           NewElem = theHelper.AddPolygonalFace(nodes, id, theForce3d);
9233           continue;
9234         }
9235         break;
9236       }
9237     case SMDSAbs_Volume :
9238       {
9239         switch(nbNodes)
9240         {
9241         case 4:
9242           NewElem = theHelper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3], id, theForce3d);
9243           break;
9244         case 5:
9245           NewElem = theHelper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3], nodes[4], id, theForce3d);
9246           break;
9247         case 6:
9248           NewElem = theHelper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3], nodes[4], nodes[5], id, theForce3d);
9249           break;
9250         case 8:
9251           NewElem = theHelper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3],
9252                                         nodes[4], nodes[5], nodes[6], nodes[7], id, theForce3d);
9253           break;
9254         default:
9255           NewElem = theHelper.AddPolyhedralVolume(nodes, nbNodeInFaces, id, theForce3d);
9256         }
9257         break;
9258       }
9259     default :
9260       continue;
9261     }
9262     ReplaceElemInGroups( elem, NewElem, GetMeshDS());
9263     if( NewElem )
9264       theSm->AddElement( NewElem );
9265
9266     GetMeshDS()->RemoveFreeElement(elem, theSm, /*fromGroups=*/false);
9267   }
9268 //  if (!GetMeshDS()->isCompacted())
9269 //    GetMeshDS()->compactMesh();
9270   return nbElem;
9271 }
9272
9273 //=======================================================================
9274 //function : ConvertToQuadratic
9275 //purpose  :
9276 //=======================================================================
9277 void SMESH_MeshEditor::ConvertToQuadratic(const bool theForce3d)
9278 {
9279   SMESHDS_Mesh* meshDS = GetMeshDS();
9280
9281   SMESH_MesherHelper aHelper(*myMesh);
9282   aHelper.SetIsQuadratic( true );
9283
9284   int nbCheckedElems = 0;
9285   if ( myMesh->HasShapeToMesh() )
9286   {
9287     if ( SMESH_subMesh *aSubMesh = myMesh->GetSubMeshContaining(myMesh->GetShapeToMesh()))
9288     {
9289       SMESH_subMeshIteratorPtr smIt = aSubMesh->getDependsOnIterator(true,false);
9290       while ( smIt->more() ) {
9291         SMESH_subMesh* sm = smIt->next();
9292         if ( SMESHDS_SubMesh *smDS = sm->GetSubMeshDS() ) {
9293           aHelper.SetSubShape( sm->GetSubShape() );
9294           nbCheckedElems += convertElemToQuadratic(smDS, aHelper, theForce3d);
9295         }
9296       }
9297     }
9298   }
9299   int totalNbElems = meshDS->NbEdges() + meshDS->NbFaces() + meshDS->NbVolumes();
9300   if ( nbCheckedElems < totalNbElems ) // not all elements are in submeshes
9301   {
9302     SMESHDS_SubMesh *smDS = 0;
9303     SMDS_EdgeIteratorPtr aEdgeItr = meshDS->edgesIterator();
9304     while(aEdgeItr->more())
9305     {
9306       const SMDS_MeshEdge* edge = aEdgeItr->next();
9307       if(edge && !edge->IsQuadratic())
9308       {
9309         int id = edge->GetID();
9310         //MESSAGE("edge->GetID() " << id);
9311         const SMDS_MeshNode* n1 = edge->GetNode(0);
9312         const SMDS_MeshNode* n2 = edge->GetNode(1);
9313
9314         meshDS->RemoveFreeElement(edge, smDS, /*fromGroups=*/false);
9315
9316         const SMDS_MeshEdge* NewEdge = aHelper.AddEdge(n1, n2, id, theForce3d);
9317         ReplaceElemInGroups( edge, NewEdge, GetMeshDS());
9318       }
9319     }
9320     SMDS_FaceIteratorPtr aFaceItr = meshDS->facesIterator();
9321     while(aFaceItr->more())
9322     {
9323       const SMDS_MeshFace* face = aFaceItr->next();
9324       if(!face || face->IsQuadratic() ) continue;
9325
9326       int id = face->GetID();
9327       int nbNodes = face->NbNodes();
9328       vector<const SMDS_MeshNode *> nodes ( face->begin_nodes(), face->end_nodes());
9329
9330       meshDS->RemoveFreeElement(face, smDS, /*fromGroups=*/false);
9331
9332       SMDS_MeshFace * NewFace = 0;
9333       switch(nbNodes)
9334       {
9335       case 3:
9336         NewFace = aHelper.AddFace(nodes[0], nodes[1], nodes[2], id, theForce3d);
9337         break;
9338       case 4:
9339         NewFace = aHelper.AddFace(nodes[0], nodes[1], nodes[2], nodes[3], id, theForce3d);
9340         break;
9341       default:
9342         NewFace = aHelper.AddPolygonalFace(nodes, id, theForce3d);
9343       }
9344       ReplaceElemInGroups( face, NewFace, GetMeshDS());
9345     }
9346     vector<int> nbNodeInFaces;
9347     SMDS_VolumeIteratorPtr aVolumeItr = meshDS->volumesIterator();
9348     while(aVolumeItr->more())
9349     {
9350       const SMDS_MeshVolume* volume = aVolumeItr->next();
9351       if(!volume || volume->IsQuadratic() ) continue;
9352
9353       int id = volume->GetID();
9354       int nbNodes = volume->NbNodes();
9355       vector<const SMDS_MeshNode *> nodes (volume->begin_nodes(), volume->end_nodes());
9356       if ( volume->GetEntityType() == SMDSEntity_Polyhedra )
9357         nbNodeInFaces = static_cast<const SMDS_VtkVolume* >(volume)->GetQuantities();
9358
9359       meshDS->RemoveFreeElement(volume, smDS, /*fromGroups=*/false);
9360
9361       SMDS_MeshVolume * NewVolume = 0;
9362       switch(nbNodes)
9363       {
9364       case 4:
9365         NewVolume = aHelper.AddVolume(nodes[0], nodes[1], nodes[2],
9366                                       nodes[3], id, theForce3d );
9367         break;
9368       case 5:
9369         NewVolume = aHelper.AddVolume(nodes[0], nodes[1], nodes[2],
9370                                       nodes[3], nodes[4], id, theForce3d);
9371         break;
9372       case 6:
9373         NewVolume = aHelper.AddVolume(nodes[0], nodes[1], nodes[2],
9374                                       nodes[3], nodes[4], nodes[5], id, theForce3d);
9375         break;
9376       case 8:
9377         NewVolume = aHelper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3],
9378                                       nodes[4], nodes[5], nodes[6], nodes[7], id, theForce3d);
9379         break;
9380       default:
9381         NewVolume = aHelper.AddPolyhedralVolume(nodes, nbNodeInFaces, id, theForce3d);
9382       }
9383       ReplaceElemInGroups(volume, NewVolume, meshDS);
9384     }
9385   }
9386
9387   if ( !theForce3d  && !getenv("NO_FixQuadraticElements"))
9388   { // setenv NO_FixQuadraticElements to know if FixQuadraticElements() is guilty of bad conversion
9389     aHelper.SetSubShape(0); // apply FixQuadraticElements() to the whole mesh
9390     aHelper.FixQuadraticElements();
9391   }
9392   if (!GetMeshDS()->isCompacted())
9393     GetMeshDS()->compactMesh();
9394 }
9395
9396 //=======================================================================
9397 /*!
9398  * \brief Convert quadratic elements to linear ones and remove quadratic nodes
9399  * \retval int - nb of checked elements
9400  */
9401 //=======================================================================
9402
9403 int SMESH_MeshEditor::removeQuadElem(SMESHDS_SubMesh *    theSm,
9404                                      SMDS_ElemIteratorPtr theItr,
9405                                      const int            theShapeID)
9406 {
9407   int nbElem = 0;
9408   SMESHDS_Mesh* meshDS = GetMeshDS();
9409   const bool notFromGroups = false;
9410
9411   while( theItr->more() )
9412   {
9413     const SMDS_MeshElement* elem = theItr->next();
9414     nbElem++;
9415     if( elem && elem->IsQuadratic())
9416     {
9417       int id = elem->GetID();
9418       int nbNodes = elem->NbNodes();
9419       vector<const SMDS_MeshNode *> nodes, mediumNodes;
9420       nodes.reserve( nbNodes );
9421       mediumNodes.reserve( nbNodes );
9422
9423       for(int i = 0; i < nbNodes; i++)
9424       {
9425         const SMDS_MeshNode* n = elem->GetNode(i);
9426
9427         if( elem->IsMediumNode( n ) )
9428           mediumNodes.push_back( n );
9429         else
9430           nodes.push_back( n );
9431       }
9432       if( nodes.empty() ) continue;
9433       SMDSAbs_ElementType aType = elem->GetType();
9434
9435       //remove old quadratic element
9436       meshDS->RemoveFreeElement( elem, theSm, notFromGroups );
9437
9438       SMDS_MeshElement * NewElem = AddElement( nodes, aType, false, id );
9439       ReplaceElemInGroups(elem, NewElem, meshDS);
9440       if( theSm && NewElem )
9441         theSm->AddElement( NewElem );
9442
9443       // remove medium nodes
9444       vector<const SMDS_MeshNode*>::iterator nIt = mediumNodes.begin();
9445       for ( ; nIt != mediumNodes.end(); ++nIt ) {
9446         const SMDS_MeshNode* n = *nIt;
9447         if ( n->NbInverseElements() == 0 ) {
9448           if ( n->getshapeId() != theShapeID )
9449             meshDS->RemoveFreeNode( n, meshDS->MeshElements
9450                                     ( n->getshapeId() ));
9451           else
9452             meshDS->RemoveFreeNode( n, theSm );
9453         }
9454       }
9455     }
9456   }
9457   return nbElem;
9458 }
9459
9460 //=======================================================================
9461 //function : ConvertFromQuadratic
9462 //purpose  :
9463 //=======================================================================
9464 bool  SMESH_MeshEditor::ConvertFromQuadratic()
9465 {
9466   int nbCheckedElems = 0;
9467   if ( myMesh->HasShapeToMesh() )
9468   {
9469     if ( SMESH_subMesh *aSubMesh = myMesh->GetSubMeshContaining(myMesh->GetShapeToMesh()))
9470     {
9471       SMESH_subMeshIteratorPtr smIt = aSubMesh->getDependsOnIterator(true,false);
9472       while ( smIt->more() ) {
9473         SMESH_subMesh* sm = smIt->next();
9474         if ( SMESHDS_SubMesh *smDS = sm->GetSubMeshDS() )
9475           nbCheckedElems += removeQuadElem( smDS, smDS->GetElements(), sm->GetId() );
9476       }
9477     }
9478   }
9479
9480   int totalNbElems =
9481     GetMeshDS()->NbEdges() + GetMeshDS()->NbFaces() + GetMeshDS()->NbVolumes();
9482   if ( nbCheckedElems < totalNbElems ) // not all elements are in submeshes
9483   {
9484     SMESHDS_SubMesh *aSM = 0;
9485     removeQuadElem( aSM, GetMeshDS()->elementsIterator(), 0 );
9486   }
9487
9488   return true;
9489 }
9490
9491 //=======================================================================
9492 //function : SewSideElements
9493 //purpose  :
9494 //=======================================================================
9495
9496 SMESH_MeshEditor::Sew_Error
9497 SMESH_MeshEditor::SewSideElements (TIDSortedElemSet&    theSide1,
9498                                    TIDSortedElemSet&    theSide2,
9499                                    const SMDS_MeshNode* theFirstNode1,
9500                                    const SMDS_MeshNode* theFirstNode2,
9501                                    const SMDS_MeshNode* theSecondNode1,
9502                                    const SMDS_MeshNode* theSecondNode2)
9503 {
9504   myLastCreatedElems.Clear();
9505   myLastCreatedNodes.Clear();
9506
9507   MESSAGE ("::::SewSideElements()");
9508   if ( theSide1.size() != theSide2.size() )
9509     return SEW_DIFF_NB_OF_ELEMENTS;
9510
9511   Sew_Error aResult = SEW_OK;
9512   // Algo:
9513   // 1. Build set of faces representing each side
9514   // 2. Find which nodes of the side 1 to merge with ones on the side 2
9515   // 3. Replace nodes in elements of the side 1 and remove replaced nodes
9516
9517   // =======================================================================
9518   // 1. Build set of faces representing each side:
9519   // =======================================================================
9520   // a. build set of nodes belonging to faces
9521   // b. complete set of faces: find missing faces whose nodes are in set of nodes
9522   // c. create temporary faces representing side of volumes if correspondent
9523   //    face does not exist
9524
9525   SMESHDS_Mesh* aMesh = GetMeshDS();
9526   // TODO algoritm not OK with vtkUnstructuredGrid: 2 meshes can't share nodes
9527   //SMDS_Mesh aTmpFacesMesh; // try to use the same mesh
9528   set<const SMDS_MeshElement*> faceSet1, faceSet2;
9529   set<const SMDS_MeshElement*> volSet1,  volSet2;
9530   set<const SMDS_MeshNode*>    nodeSet1, nodeSet2;
9531   set<const SMDS_MeshElement*> * faceSetPtr[] = { &faceSet1, &faceSet2 };
9532   set<const SMDS_MeshElement*>  * volSetPtr[] = { &volSet1,  &volSet2  };
9533   set<const SMDS_MeshNode*>    * nodeSetPtr[] = { &nodeSet1, &nodeSet2 };
9534   TIDSortedElemSet * elemSetPtr[] = { &theSide1, &theSide2 };
9535   int iSide, iFace, iNode;
9536
9537   list<const SMDS_MeshElement* > tempFaceList;
9538   for ( iSide = 0; iSide < 2; iSide++ ) {
9539     set<const SMDS_MeshNode*>    * nodeSet = nodeSetPtr[ iSide ];
9540     TIDSortedElemSet * elemSet = elemSetPtr[ iSide ];
9541     set<const SMDS_MeshElement*> * faceSet = faceSetPtr[ iSide ];
9542     set<const SMDS_MeshElement*> * volSet  = volSetPtr [ iSide ];
9543     set<const SMDS_MeshElement*>::iterator vIt;
9544     TIDSortedElemSet::iterator eIt;
9545     set<const SMDS_MeshNode*>::iterator    nIt;
9546
9547     // check that given nodes belong to given elements
9548     const SMDS_MeshNode* n1 = ( iSide == 0 ) ? theFirstNode1 : theFirstNode2;
9549     const SMDS_MeshNode* n2 = ( iSide == 0 ) ? theSecondNode1 : theSecondNode2;
9550     int firstIndex = -1, secondIndex = -1;
9551     for (eIt = elemSet->begin(); eIt != elemSet->end(); eIt++ ) {
9552       const SMDS_MeshElement* elem = *eIt;
9553       if ( firstIndex  < 0 ) firstIndex  = elem->GetNodeIndex( n1 );
9554       if ( secondIndex < 0 ) secondIndex = elem->GetNodeIndex( n2 );
9555       if ( firstIndex > -1 && secondIndex > -1 ) break;
9556     }
9557     if ( firstIndex < 0 || secondIndex < 0 ) {
9558       // we can simply return until temporary faces created
9559       return (iSide == 0 ) ? SEW_BAD_SIDE1_NODES : SEW_BAD_SIDE2_NODES;
9560     }
9561
9562     // -----------------------------------------------------------
9563     // 1a. Collect nodes of existing faces
9564     //     and build set of face nodes in order to detect missing
9565     //     faces corresponding to sides of volumes
9566     // -----------------------------------------------------------
9567
9568     set< set <const SMDS_MeshNode*> > setOfFaceNodeSet;
9569
9570     // loop on the given element of a side
9571     for (eIt = elemSet->begin(); eIt != elemSet->end(); eIt++ ) {
9572       //const SMDS_MeshElement* elem = *eIt;
9573       const SMDS_MeshElement* elem = *eIt;
9574       if ( elem->GetType() == SMDSAbs_Face ) {
9575         faceSet->insert( elem );
9576         set <const SMDS_MeshNode*> faceNodeSet;
9577         SMDS_ElemIteratorPtr nodeIt = elem->nodesIterator();
9578         while ( nodeIt->more() ) {
9579           const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
9580           nodeSet->insert( n );
9581           faceNodeSet.insert( n );
9582         }
9583         setOfFaceNodeSet.insert( faceNodeSet );
9584       }
9585       else if ( elem->GetType() == SMDSAbs_Volume )
9586         volSet->insert( elem );
9587     }
9588     // ------------------------------------------------------------------------------
9589     // 1b. Complete set of faces: find missing faces whose nodes are in set of nodes
9590     // ------------------------------------------------------------------------------
9591
9592     for ( nIt = nodeSet->begin(); nIt != nodeSet->end(); nIt++ ) { // loop on nodes of iSide
9593       SMDS_ElemIteratorPtr fIt = (*nIt)->GetInverseElementIterator(SMDSAbs_Face);
9594       while ( fIt->more() ) { // loop on faces sharing a node
9595         const SMDS_MeshElement* f = fIt->next();
9596         if ( faceSet->find( f ) == faceSet->end() ) {
9597           // check if all nodes are in nodeSet and
9598           // complete setOfFaceNodeSet if they are
9599           set <const SMDS_MeshNode*> faceNodeSet;
9600           SMDS_ElemIteratorPtr nodeIt = f->nodesIterator();
9601           bool allInSet = true;
9602           while ( nodeIt->more() && allInSet ) { // loop on nodes of a face
9603             const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
9604             if ( nodeSet->find( n ) == nodeSet->end() )
9605               allInSet = false;
9606             else
9607               faceNodeSet.insert( n );
9608           }
9609           if ( allInSet ) {
9610             faceSet->insert( f );
9611             setOfFaceNodeSet.insert( faceNodeSet );
9612           }
9613         }
9614       }
9615     }
9616
9617     // -------------------------------------------------------------------------
9618     // 1c. Create temporary faces representing sides of volumes if correspondent
9619     //     face does not exist
9620     // -------------------------------------------------------------------------
9621
9622     if ( !volSet->empty() ) {
9623       //int nodeSetSize = nodeSet->size();
9624
9625       // loop on given volumes
9626       for ( vIt = volSet->begin(); vIt != volSet->end(); vIt++ ) {
9627         SMDS_VolumeTool vol (*vIt);
9628         // loop on volume faces: find free faces
9629         // --------------------------------------
9630         list<const SMDS_MeshElement* > freeFaceList;
9631         for ( iFace = 0; iFace < vol.NbFaces(); iFace++ ) {
9632           if ( !vol.IsFreeFace( iFace ))
9633             continue;
9634           // check if there is already a face with same nodes in a face set
9635           const SMDS_MeshElement* aFreeFace = 0;
9636           const SMDS_MeshNode** fNodes = vol.GetFaceNodes( iFace );
9637           int nbNodes = vol.NbFaceNodes( iFace );
9638           set <const SMDS_MeshNode*> faceNodeSet;
9639           vol.GetFaceNodes( iFace, faceNodeSet );
9640           bool isNewFace = setOfFaceNodeSet.insert( faceNodeSet ).second;
9641           if ( isNewFace ) {
9642             // no such a face is given but it still can exist, check it
9643             if ( nbNodes == 3 ) {
9644               aFreeFace = aMesh->FindFace( fNodes[0],fNodes[1],fNodes[2] );
9645             }
9646             else if ( nbNodes == 4 ) {
9647               aFreeFace = aMesh->FindFace( fNodes[0],fNodes[1],fNodes[2],fNodes[3] );
9648             }
9649             else {
9650               vector<const SMDS_MeshNode *> poly_nodes ( fNodes, & fNodes[nbNodes]);
9651               aFreeFace = aMesh->FindFace(poly_nodes);
9652             }
9653           }
9654           if ( !aFreeFace ) {
9655             // create a temporary face
9656             if ( nbNodes == 3 ) {
9657               //aFreeFace = aTmpFacesMesh.AddFace( fNodes[0],fNodes[1],fNodes[2] );
9658               aFreeFace = aMesh->AddFace( fNodes[0],fNodes[1],fNodes[2] );
9659             }
9660             else if ( nbNodes == 4 ) {
9661               //aFreeFace = aTmpFacesMesh.AddFace( fNodes[0],fNodes[1],fNodes[2],fNodes[3] );
9662               aFreeFace = aMesh->AddFace( fNodes[0],fNodes[1],fNodes[2],fNodes[3] );
9663             }
9664             else {
9665               vector<const SMDS_MeshNode *> poly_nodes ( fNodes, & fNodes[nbNodes]);
9666               //aFreeFace = aTmpFacesMesh.AddPolygonalFace(poly_nodes);
9667               aFreeFace = aMesh->AddPolygonalFace(poly_nodes);
9668             }
9669           }
9670           if ( aFreeFace ) {
9671             freeFaceList.push_back( aFreeFace );
9672             tempFaceList.push_back( aFreeFace );
9673           }
9674
9675         } // loop on faces of a volume
9676
9677         // choose one of several free faces
9678         // --------------------------------------
9679         if ( freeFaceList.size() > 1 ) {
9680           // choose a face having max nb of nodes shared by other elems of a side
9681           int maxNbNodes = -1/*, nbExcludedFaces = 0*/;
9682           list<const SMDS_MeshElement* >::iterator fIt = freeFaceList.begin();
9683           while ( fIt != freeFaceList.end() ) { // loop on free faces
9684             int nbSharedNodes = 0;
9685             SMDS_ElemIteratorPtr nodeIt = (*fIt)->nodesIterator();
9686             while ( nodeIt->more() ) { // loop on free face nodes
9687               const SMDS_MeshNode* n =
9688                 static_cast<const SMDS_MeshNode*>( nodeIt->next() );
9689               SMDS_ElemIteratorPtr invElemIt = n->GetInverseElementIterator();
9690               while ( invElemIt->more() ) {
9691                 const SMDS_MeshElement* e = invElemIt->next();
9692                 if ( faceSet->find( e ) != faceSet->end() )
9693                   nbSharedNodes++;
9694                 if ( elemSet->find( e ) != elemSet->end() )
9695                   nbSharedNodes++;
9696               }
9697             }
9698             if ( nbSharedNodes >= maxNbNodes ) {
9699               maxNbNodes = nbSharedNodes;
9700               fIt++;
9701             }
9702             else
9703               freeFaceList.erase( fIt++ ); // here fIt++ occurs before erase
9704           }
9705           if ( freeFaceList.size() > 1 )
9706           {
9707             // could not choose one face, use another way
9708             // choose a face most close to the bary center of the opposite side
9709             gp_XYZ aBC( 0., 0., 0. );
9710             set <const SMDS_MeshNode*> addedNodes;
9711             TIDSortedElemSet * elemSet2 = elemSetPtr[ 1 - iSide ];
9712             eIt = elemSet2->begin();
9713             for ( eIt = elemSet2->begin(); eIt != elemSet2->end(); eIt++ ) {
9714               SMDS_ElemIteratorPtr nodeIt = (*eIt)->nodesIterator();
9715               while ( nodeIt->more() ) { // loop on free face nodes
9716                 const SMDS_MeshNode* n =
9717                   static_cast<const SMDS_MeshNode*>( nodeIt->next() );
9718                 if ( addedNodes.insert( n ).second )
9719                   aBC += gp_XYZ( n->X(),n->Y(),n->Z() );
9720               }
9721             }
9722             aBC /= addedNodes.size();
9723             double minDist = DBL_MAX;
9724             fIt = freeFaceList.begin();
9725             while ( fIt != freeFaceList.end() ) { // loop on free faces
9726               double dist = 0;
9727               SMDS_ElemIteratorPtr nodeIt = (*fIt)->nodesIterator();
9728               while ( nodeIt->more() ) { // loop on free face nodes
9729                 const SMDS_MeshNode* n =
9730                   static_cast<const SMDS_MeshNode*>( nodeIt->next() );
9731                 gp_XYZ p( n->X(),n->Y(),n->Z() );
9732                 dist += ( aBC - p ).SquareModulus();
9733               }
9734               if ( dist < minDist ) {
9735                 minDist = dist;
9736                 freeFaceList.erase( freeFaceList.begin(), fIt++ );
9737               }
9738               else
9739                 fIt = freeFaceList.erase( fIt++ );
9740             }
9741           }
9742         } // choose one of several free faces of a volume
9743
9744         if ( freeFaceList.size() == 1 ) {
9745           const SMDS_MeshElement* aFreeFace = freeFaceList.front();
9746           faceSet->insert( aFreeFace );
9747           // complete a node set with nodes of a found free face
9748           //           for ( iNode = 0; iNode < ; iNode++ )
9749           //             nodeSet->insert( fNodes[ iNode ] );
9750         }
9751
9752       } // loop on volumes of a side
9753
9754       //       // complete a set of faces if new nodes in a nodeSet appeared
9755       //       // ----------------------------------------------------------
9756       //       if ( nodeSetSize != nodeSet->size() ) {
9757       //         for ( ; nIt != nodeSet->end(); nIt++ ) { // loop on nodes of iSide
9758       //           SMDS_ElemIteratorPtr fIt = (*nIt)->GetInverseElementIterator(SMDSAbs_Face);
9759       //           while ( fIt->more() ) { // loop on faces sharing a node
9760       //             const SMDS_MeshElement* f = fIt->next();
9761       //             if ( faceSet->find( f ) == faceSet->end() ) {
9762       //               // check if all nodes are in nodeSet and
9763       //               // complete setOfFaceNodeSet if they are
9764       //               set <const SMDS_MeshNode*> faceNodeSet;
9765       //               SMDS_ElemIteratorPtr nodeIt = f->nodesIterator();
9766       //               bool allInSet = true;
9767       //               while ( nodeIt->more() && allInSet ) { // loop on nodes of a face
9768       //                 const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
9769       //                 if ( nodeSet->find( n ) == nodeSet->end() )
9770       //                   allInSet = false;
9771       //                 else
9772       //                   faceNodeSet.insert( n );
9773       //               }
9774       //               if ( allInSet ) {
9775       //                 faceSet->insert( f );
9776       //                 setOfFaceNodeSet.insert( faceNodeSet );
9777       //               }
9778       //             }
9779       //           }
9780       //         }
9781       //       }
9782     } // Create temporary faces, if there are volumes given
9783   } // loop on sides
9784
9785   if ( faceSet1.size() != faceSet2.size() ) {
9786     // delete temporary faces: they are in reverseElements of actual nodes
9787 //    SMDS_FaceIteratorPtr tmpFaceIt = aTmpFacesMesh.facesIterator();
9788 //    while ( tmpFaceIt->more() )
9789 //      aTmpFacesMesh.RemoveElement( tmpFaceIt->next() );
9790 //    list<const SMDS_MeshElement* >::iterator tmpFaceIt = tempFaceList.begin();
9791 //    for (; tmpFaceIt !=tempFaceList.end(); ++tmpFaceIt)
9792 //      aMesh->RemoveElement(*tmpFaceIt);
9793     MESSAGE("Diff nb of faces");
9794     return SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
9795   }
9796
9797   // ============================================================
9798   // 2. Find nodes to merge:
9799   //              bind a node to remove to a node to put instead
9800   // ============================================================
9801
9802   TNodeNodeMap nReplaceMap; // bind a node to remove to a node to put instead
9803   if ( theFirstNode1 != theFirstNode2 )
9804     nReplaceMap.insert( TNodeNodeMap::value_type( theFirstNode1, theFirstNode2 ));
9805   if ( theSecondNode1 != theSecondNode2 )
9806     nReplaceMap.insert( TNodeNodeMap::value_type( theSecondNode1, theSecondNode2 ));
9807
9808   LinkID_Gen aLinkID_Gen( GetMeshDS() );
9809   set< long > linkIdSet; // links to process
9810   linkIdSet.insert( aLinkID_Gen.GetLinkID( theFirstNode1, theSecondNode1 ));
9811
9812   typedef pair< const SMDS_MeshNode*, const SMDS_MeshNode* > NLink;
9813   list< NLink > linkList[2];
9814   linkList[0].push_back( NLink( theFirstNode1, theSecondNode1 ));
9815   linkList[1].push_back( NLink( theFirstNode2, theSecondNode2 ));
9816   // loop on links in linkList; find faces by links and append links
9817   // of the found faces to linkList
9818   list< NLink >::iterator linkIt[] = { linkList[0].begin(), linkList[1].begin() } ;
9819   for ( ; linkIt[0] != linkList[0].end(); linkIt[0]++, linkIt[1]++ ) {
9820     NLink link[] = { *linkIt[0], *linkIt[1] };
9821     long linkID = aLinkID_Gen.GetLinkID( link[0].first, link[0].second );
9822     if ( linkIdSet.find( linkID ) == linkIdSet.end() )
9823       continue;
9824
9825     // by links, find faces in the face sets,
9826     // and find indices of link nodes in the found faces;
9827     // in a face set, there is only one or no face sharing a link
9828     // ---------------------------------------------------------------
9829
9830     const SMDS_MeshElement* face[] = { 0, 0 };
9831     //const SMDS_MeshNode* faceNodes[ 2 ][ 5 ];
9832     vector<const SMDS_MeshNode*> fnodes1(9);
9833     vector<const SMDS_MeshNode*> fnodes2(9);
9834     //const SMDS_MeshNode* notLinkNodes[ 2 ][ 2 ] = {{ 0, 0 },{ 0, 0 }} ;
9835     vector<const SMDS_MeshNode*> notLinkNodes1(6);
9836     vector<const SMDS_MeshNode*> notLinkNodes2(6);
9837     int iLinkNode[2][2];
9838     for ( iSide = 0; iSide < 2; iSide++ ) { // loop on 2 sides
9839       const SMDS_MeshNode* n1 = link[iSide].first;
9840       const SMDS_MeshNode* n2 = link[iSide].second;
9841       set<const SMDS_MeshElement*> * faceSet = faceSetPtr[ iSide ];
9842       set< const SMDS_MeshElement* > fMap;
9843       for ( int i = 0; i < 2; i++ ) { // loop on 2 nodes of a link
9844         const SMDS_MeshNode* n = i ? n1 : n2; // a node of a link
9845         SMDS_ElemIteratorPtr fIt = n->GetInverseElementIterator(SMDSAbs_Face);
9846         while ( fIt->more() ) { // loop on faces sharing a node
9847           const SMDS_MeshElement* f = fIt->next();
9848           if (faceSet->find( f ) != faceSet->end() && // f is in face set
9849               ! fMap.insert( f ).second ) // f encounters twice
9850           {
9851             if ( face[ iSide ] ) {
9852               MESSAGE( "2 faces per link " );
9853               aResult = iSide ? SEW_BAD_SIDE2_NODES : SEW_BAD_SIDE1_NODES;
9854               break;
9855             }
9856             face[ iSide ] = f;
9857             faceSet->erase( f );
9858             // get face nodes and find ones of a link
9859             iNode = 0;
9860             int nbl = -1;
9861             if(f->IsPoly()) {
9862               if(iSide==0) {
9863                 fnodes1.resize(f->NbNodes()+1);
9864                 notLinkNodes1.resize(f->NbNodes()-2);
9865               }
9866               else {
9867                 fnodes2.resize(f->NbNodes()+1);
9868                 notLinkNodes2.resize(f->NbNodes()-2);
9869               }
9870             }
9871             if(!f->IsQuadratic()) {
9872               SMDS_ElemIteratorPtr nIt = f->nodesIterator();
9873               while ( nIt->more() ) {
9874                 const SMDS_MeshNode* n =
9875                   static_cast<const SMDS_MeshNode*>( nIt->next() );
9876                 if ( n == n1 ) {
9877                   iLinkNode[ iSide ][ 0 ] = iNode;
9878                 }
9879                 else if ( n == n2 ) {
9880                   iLinkNode[ iSide ][ 1 ] = iNode;
9881                 }
9882                 //else if ( notLinkNodes[ iSide ][ 0 ] )
9883                 //  notLinkNodes[ iSide ][ 1 ] = n;
9884                 //else
9885                 //  notLinkNodes[ iSide ][ 0 ] = n;
9886                 else {
9887                   nbl++;
9888                   if(iSide==0)
9889                     notLinkNodes1[nbl] = n;
9890                   //notLinkNodes1.push_back(n);
9891                   else
9892                     notLinkNodes2[nbl] = n;
9893                   //notLinkNodes2.push_back(n);
9894                 }
9895                 //faceNodes[ iSide ][ iNode++ ] = n;
9896                 if(iSide==0) {
9897                   fnodes1[iNode++] = n;
9898                 }
9899                 else {
9900                   fnodes2[iNode++] = n;
9901                 }
9902               }
9903             }
9904             else { // f->IsQuadratic()
9905               const SMDS_VtkFace* F =
9906                 dynamic_cast<const SMDS_VtkFace*>(f);
9907               if (!F) throw SALOME_Exception(LOCALIZED("not an SMDS_VtkFace"));
9908               // use special nodes iterator
9909               SMDS_ElemIteratorPtr anIter = F->interlacedNodesElemIterator();
9910               while ( anIter->more() ) {
9911                 const SMDS_MeshNode* n =
9912                   static_cast<const SMDS_MeshNode*>( anIter->next() );
9913                 if ( n == n1 ) {
9914                   iLinkNode[ iSide ][ 0 ] = iNode;
9915                 }
9916                 else if ( n == n2 ) {
9917                   iLinkNode[ iSide ][ 1 ] = iNode;
9918                 }
9919                 else {
9920                   nbl++;
9921                   if(iSide==0) {
9922                     notLinkNodes1[nbl] = n;
9923                   }
9924                   else {
9925                     notLinkNodes2[nbl] = n;
9926                   }
9927                 }
9928                 if(iSide==0) {
9929                   fnodes1[iNode++] = n;
9930                 }
9931                 else {
9932                   fnodes2[iNode++] = n;
9933                 }
9934               }
9935             }
9936             //faceNodes[ iSide ][ iNode ] = faceNodes[ iSide ][ 0 ];
9937             if(iSide==0) {
9938               fnodes1[iNode] = fnodes1[0];
9939             }
9940             else {
9941               fnodes2[iNode] = fnodes1[0];
9942             }
9943           }
9944         }
9945       }
9946     }
9947
9948     // check similarity of elements of the sides
9949     if (aResult == SEW_OK && ( face[0] && !face[1] ) || ( !face[0] && face[1] )) {
9950       MESSAGE("Correspondent face not found on side " << ( face[0] ? 1 : 0 ));
9951       if ( nReplaceMap.size() == 2 ) { // faces on input nodes not found
9952         aResult = ( face[0] ? SEW_BAD_SIDE2_NODES : SEW_BAD_SIDE1_NODES );
9953       }
9954       else {
9955         aResult = SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
9956       }
9957       break; // do not return because it s necessary to remove tmp faces
9958     }
9959
9960     // set nodes to merge
9961     // -------------------
9962
9963     if ( face[0] && face[1] )  {
9964       int nbNodes = face[0]->NbNodes();
9965       if ( nbNodes != face[1]->NbNodes() ) {
9966         MESSAGE("Diff nb of face nodes");
9967         aResult = SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
9968         break; // do not return because it s necessary to remove tmp faces
9969       }
9970       bool reverse[] = { false, false }; // order of notLinkNodes of quadrangle
9971       if ( nbNodes == 3 ) {
9972         //nReplaceMap.insert( TNodeNodeMap::value_type
9973         //                   ( notLinkNodes[0][0], notLinkNodes[1][0] ));
9974         nReplaceMap.insert( TNodeNodeMap::value_type
9975                             ( notLinkNodes1[0], notLinkNodes2[0] ));
9976       }
9977       else {
9978         for ( iSide = 0; iSide < 2; iSide++ ) { // loop on 2 sides
9979           // analyse link orientation in faces
9980           int i1 = iLinkNode[ iSide ][ 0 ];
9981           int i2 = iLinkNode[ iSide ][ 1 ];
9982           reverse[ iSide ] = Abs( i1 - i2 ) == 1 ? i1 > i2 : i2 > i1;
9983           // if notLinkNodes are the first and the last ones, then
9984           // their order does not correspond to the link orientation
9985           if (( i1 == 1 && i2 == 2 ) ||
9986               ( i1 == 2 && i2 == 1 ))
9987             reverse[ iSide ] = !reverse[ iSide ];
9988         }
9989         if ( reverse[0] == reverse[1] ) {
9990           //nReplaceMap.insert( TNodeNodeMap::value_type
9991           //                   ( notLinkNodes[0][0], notLinkNodes[1][0] ));
9992           //nReplaceMap.insert( TNodeNodeMap::value_type
9993           //                   ( notLinkNodes[0][1], notLinkNodes[1][1] ));
9994           for(int nn=0; nn<nbNodes-2; nn++) {
9995             nReplaceMap.insert( TNodeNodeMap::value_type
9996                                 ( notLinkNodes1[nn], notLinkNodes2[nn] ));
9997           }
9998         }
9999         else {
10000           //nReplaceMap.insert( TNodeNodeMap::value_type
10001           //                   ( notLinkNodes[0][0], notLinkNodes[1][1] ));
10002           //nReplaceMap.insert( TNodeNodeMap::value_type
10003           //                   ( notLinkNodes[0][1], notLinkNodes[1][0] ));
10004           for(int nn=0; nn<nbNodes-2; nn++) {
10005             nReplaceMap.insert( TNodeNodeMap::value_type
10006                                 ( notLinkNodes1[nn], notLinkNodes2[nbNodes-3-nn] ));
10007           }
10008         }
10009       }
10010
10011       // add other links of the faces to linkList
10012       // -----------------------------------------
10013
10014       //const SMDS_MeshNode** nodes = faceNodes[ 0 ];
10015       for ( iNode = 0; iNode < nbNodes; iNode++ )  {
10016         //linkID = aLinkID_Gen.GetLinkID( nodes[iNode], nodes[iNode+1] );
10017         linkID = aLinkID_Gen.GetLinkID( fnodes1[iNode], fnodes1[iNode+1] );
10018         pair< set<long>::iterator, bool > iter_isnew = linkIdSet.insert( linkID );
10019         if ( !iter_isnew.second ) { // already in a set: no need to process
10020           linkIdSet.erase( iter_isnew.first );
10021         }
10022         else // new in set == encountered for the first time: add
10023         {
10024           //const SMDS_MeshNode* n1 = nodes[ iNode ];
10025           //const SMDS_MeshNode* n2 = nodes[ iNode + 1];
10026           const SMDS_MeshNode* n1 = fnodes1[ iNode ];
10027           const SMDS_MeshNode* n2 = fnodes1[ iNode + 1];
10028           linkList[0].push_back ( NLink( n1, n2 ));
10029           linkList[1].push_back ( NLink( nReplaceMap[n1], nReplaceMap[n2] ));
10030         }
10031       }
10032     } // 2 faces found
10033   } // loop on link lists
10034
10035   if ( aResult == SEW_OK &&
10036        ( linkIt[0] != linkList[0].end() ||
10037          !faceSetPtr[0]->empty() || !faceSetPtr[1]->empty() )) {
10038     MESSAGE( (linkIt[0] != linkList[0].end()) <<" "<< (faceSetPtr[0]->empty()) <<
10039              " " << (faceSetPtr[1]->empty()));
10040     aResult = SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
10041   }
10042
10043   // ====================================================================
10044   // 3. Replace nodes in elements of the side 1 and remove replaced nodes
10045   // ====================================================================
10046
10047   // delete temporary faces: they are in reverseElements of actual nodes
10048 //  SMDS_FaceIteratorPtr tmpFaceIt = aTmpFacesMesh.facesIterator();
10049 //  while ( tmpFaceIt->more() )
10050 //    aTmpFacesMesh.RemoveElement( tmpFaceIt->next() );
10051 //  list<const SMDS_MeshElement* >::iterator tmpFaceIt = tempFaceList.begin();
10052 //  for (; tmpFaceIt !=tempFaceList.end(); ++tmpFaceIt)
10053 //    aMesh->RemoveElement(*tmpFaceIt);
10054
10055   if ( aResult != SEW_OK)
10056     return aResult;
10057
10058   list< int > nodeIDsToRemove/*, elemIDsToRemove*/;
10059   // loop on nodes replacement map
10060   TNodeNodeMap::iterator nReplaceMapIt = nReplaceMap.begin(), nnIt;
10061   for ( ; nReplaceMapIt != nReplaceMap.end(); nReplaceMapIt++ )
10062     if ( (*nReplaceMapIt).first != (*nReplaceMapIt).second ) {
10063       const SMDS_MeshNode* nToRemove = (*nReplaceMapIt).first;
10064       nodeIDsToRemove.push_back( nToRemove->GetID() );
10065       // loop on elements sharing nToRemove
10066       SMDS_ElemIteratorPtr invElemIt = nToRemove->GetInverseElementIterator();
10067       while ( invElemIt->more() ) {
10068         const SMDS_MeshElement* e = invElemIt->next();
10069         // get a new suite of nodes: make replacement
10070         int nbReplaced = 0, i = 0, nbNodes = e->NbNodes();
10071         vector< const SMDS_MeshNode*> nodes( nbNodes );
10072         SMDS_ElemIteratorPtr nIt = e->nodesIterator();
10073         while ( nIt->more() ) {
10074           const SMDS_MeshNode* n =
10075             static_cast<const SMDS_MeshNode*>( nIt->next() );
10076           nnIt = nReplaceMap.find( n );
10077           if ( nnIt != nReplaceMap.end() ) {
10078             nbReplaced++;
10079             n = (*nnIt).second;
10080           }
10081           nodes[ i++ ] = n;
10082         }
10083         //       if ( nbReplaced == nbNodes && e->GetType() == SMDSAbs_Face )
10084         //         elemIDsToRemove.push_back( e->GetID() );
10085         //       else
10086         if ( nbReplaced )
10087           {
10088             SMDSAbs_ElementType etyp = e->GetType();
10089             SMDS_MeshElement* newElem = this->AddElement(nodes, etyp, false);
10090             if (newElem)
10091               {
10092                 myLastCreatedElems.Append(newElem);
10093                 AddToSameGroups(newElem, e, aMesh);
10094                 int aShapeId = e->getshapeId();
10095                 if ( aShapeId )
10096                   {
10097                     aMesh->SetMeshElementOnShape( newElem, aShapeId );
10098                   }
10099               }
10100             aMesh->RemoveElement(e);
10101           }
10102       }
10103     }
10104
10105   Remove( nodeIDsToRemove, true );
10106
10107   return aResult;
10108 }
10109
10110 //================================================================================
10111 /*!
10112  * \brief Find corresponding nodes in two sets of faces
10113  * \param theSide1 - first face set
10114  * \param theSide2 - second first face
10115  * \param theFirstNode1 - a boundary node of set 1
10116  * \param theFirstNode2 - a node of set 2 corresponding to theFirstNode1
10117  * \param theSecondNode1 - a boundary node of set 1 linked with theFirstNode1
10118  * \param theSecondNode2 - a node of set 2 corresponding to theSecondNode1
10119  * \param nReplaceMap - output map of corresponding nodes
10120  * \retval bool  - is a success or not
10121  */
10122 //================================================================================
10123
10124 #ifdef _DEBUG_
10125 //#define DEBUG_MATCHING_NODES
10126 #endif
10127
10128 SMESH_MeshEditor::Sew_Error
10129 SMESH_MeshEditor::FindMatchingNodes(set<const SMDS_MeshElement*>& theSide1,
10130                                     set<const SMDS_MeshElement*>& theSide2,
10131                                     const SMDS_MeshNode*          theFirstNode1,
10132                                     const SMDS_MeshNode*          theFirstNode2,
10133                                     const SMDS_MeshNode*          theSecondNode1,
10134                                     const SMDS_MeshNode*          theSecondNode2,
10135                                     TNodeNodeMap &                nReplaceMap)
10136 {
10137   set<const SMDS_MeshElement*> * faceSetPtr[] = { &theSide1, &theSide2 };
10138
10139   nReplaceMap.clear();
10140   if ( theFirstNode1 != theFirstNode2 )
10141     nReplaceMap.insert( make_pair( theFirstNode1, theFirstNode2 ));
10142   if ( theSecondNode1 != theSecondNode2 )
10143     nReplaceMap.insert( make_pair( theSecondNode1, theSecondNode2 ));
10144
10145   set< SMESH_TLink > linkSet; // set of nodes where order of nodes is ignored
10146   linkSet.insert( SMESH_TLink( theFirstNode1, theSecondNode1 ));
10147
10148   list< NLink > linkList[2];
10149   linkList[0].push_back( NLink( theFirstNode1, theSecondNode1 ));
10150   linkList[1].push_back( NLink( theFirstNode2, theSecondNode2 ));
10151
10152   // loop on links in linkList; find faces by links and append links
10153   // of the found faces to linkList
10154   list< NLink >::iterator linkIt[] = { linkList[0].begin(), linkList[1].begin() } ;
10155   for ( ; linkIt[0] != linkList[0].end(); linkIt[0]++, linkIt[1]++ ) {
10156     NLink link[] = { *linkIt[0], *linkIt[1] };
10157     if ( linkSet.find( link[0] ) == linkSet.end() )
10158       continue;
10159
10160     // by links, find faces in the face sets,
10161     // and find indices of link nodes in the found faces;
10162     // in a face set, there is only one or no face sharing a link
10163     // ---------------------------------------------------------------
10164
10165     const SMDS_MeshElement* face[] = { 0, 0 };
10166     list<const SMDS_MeshNode*> notLinkNodes[2];
10167     //bool reverse[] = { false, false }; // order of notLinkNodes
10168     int nbNodes[2];
10169     for ( int iSide = 0; iSide < 2; iSide++ ) // loop on 2 sides
10170     {
10171       const SMDS_MeshNode* n1 = link[iSide].first;
10172       const SMDS_MeshNode* n2 = link[iSide].second;
10173       set<const SMDS_MeshElement*> * faceSet = faceSetPtr[ iSide ];
10174       set< const SMDS_MeshElement* > facesOfNode1;
10175       for ( int iNode = 0; iNode < 2; iNode++ ) // loop on 2 nodes of a link
10176       {
10177         // during a loop of the first node, we find all faces around n1,
10178         // during a loop of the second node, we find one face sharing both n1 and n2
10179         const SMDS_MeshNode* n = iNode ? n1 : n2; // a node of a link
10180         SMDS_ElemIteratorPtr fIt = n->GetInverseElementIterator(SMDSAbs_Face);
10181         while ( fIt->more() ) { // loop on faces sharing a node
10182           const SMDS_MeshElement* f = fIt->next();
10183           if (faceSet->find( f ) != faceSet->end() && // f is in face set
10184               ! facesOfNode1.insert( f ).second ) // f encounters twice
10185           {
10186             if ( face[ iSide ] ) {
10187               MESSAGE( "2 faces per link " );
10188               return ( iSide ? SEW_BAD_SIDE2_NODES : SEW_BAD_SIDE1_NODES );
10189             }
10190             face[ iSide ] = f;
10191             faceSet->erase( f );
10192
10193             // get not link nodes
10194             int nbN = f->NbNodes();
10195             if ( f->IsQuadratic() )
10196               nbN /= 2;
10197             nbNodes[ iSide ] = nbN;
10198             list< const SMDS_MeshNode* > & nodes = notLinkNodes[ iSide ];
10199             int i1 = f->GetNodeIndex( n1 );
10200             int i2 = f->GetNodeIndex( n2 );
10201             int iEnd = nbN, iBeg = -1, iDelta = 1;
10202             bool reverse = ( Abs( i1 - i2 ) == 1 ? i1 > i2 : i2 > i1 );
10203             if ( reverse ) {
10204               std::swap( iEnd, iBeg ); iDelta = -1;
10205             }
10206             int i = i2;
10207             while ( true ) {
10208               i += iDelta;
10209               if ( i == iEnd ) i = iBeg + iDelta;
10210               if ( i == i1 ) break;
10211               nodes.push_back ( f->GetNode( i ) );
10212             }
10213           }
10214         }
10215       }
10216     }
10217     // check similarity of elements of the sides
10218     if (( face[0] && !face[1] ) || ( !face[0] && face[1] )) {
10219       MESSAGE("Correspondent face not found on side " << ( face[0] ? 1 : 0 ));
10220       if ( nReplaceMap.size() == 2 ) { // faces on input nodes not found
10221         return ( face[0] ? SEW_BAD_SIDE2_NODES : SEW_BAD_SIDE1_NODES );
10222       }
10223       else {
10224         return SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
10225       }
10226     }
10227
10228     // set nodes to merge
10229     // -------------------
10230
10231     if ( face[0] && face[1] )  {
10232       if ( nbNodes[0] != nbNodes[1] ) {
10233         MESSAGE("Diff nb of face nodes");
10234         return SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
10235       }
10236 #ifdef DEBUG_MATCHING_NODES
10237       MESSAGE ( " Link 1: " << link[0].first->GetID() <<" "<< link[0].second->GetID()
10238                 << " F 1: " << face[0] << "| Link 2: " << link[1].first->GetID() <<" "
10239                 << link[1].second->GetID() << " F 2: " << face[1] << " | Bind: " ) ;
10240 #endif
10241       int nbN = nbNodes[0];
10242       {
10243         list<const SMDS_MeshNode*>::iterator n1 = notLinkNodes[0].begin();
10244         list<const SMDS_MeshNode*>::iterator n2 = notLinkNodes[1].begin();
10245         for ( int i = 0 ; i < nbN - 2; ++i ) {
10246 #ifdef DEBUG_MATCHING_NODES
10247           MESSAGE ( (*n1)->GetID() << " to " << (*n2)->GetID() );
10248 #endif
10249           nReplaceMap.insert( make_pair( *(n1++), *(n2++) ));
10250         }
10251       }
10252
10253       // add other links of the face 1 to linkList
10254       // -----------------------------------------
10255
10256       const SMDS_MeshElement* f0 = face[0];
10257       const SMDS_MeshNode* n1 = f0->GetNode( nbN - 1 );
10258       for ( int i = 0; i < nbN; i++ )
10259       {
10260         const SMDS_MeshNode* n2 = f0->GetNode( i );
10261         pair< set< SMESH_TLink >::iterator, bool > iter_isnew =
10262           linkSet.insert( SMESH_TLink( n1, n2 ));
10263         if ( !iter_isnew.second ) { // already in a set: no need to process
10264           linkSet.erase( iter_isnew.first );
10265         }
10266         else // new in set == encountered for the first time: add
10267         {
10268 #ifdef DEBUG_MATCHING_NODES
10269           MESSAGE ( "Add link 1: " << n1->GetID() << " " << n2->GetID() << " "
10270                     << " | link 2: " << nReplaceMap[n1]->GetID() << " " << nReplaceMap[n2]->GetID() << " " );
10271 #endif
10272           linkList[0].push_back ( NLink( n1, n2 ));
10273           linkList[1].push_back ( NLink( nReplaceMap[n1], nReplaceMap[n2] ));
10274         }
10275         n1 = n2;
10276       }
10277     } // 2 faces found
10278   } // loop on link lists
10279
10280   return SEW_OK;
10281 }
10282
10283 //================================================================================
10284 /*!
10285   \brief Creates a hole in a mesh by doubling the nodes of some particular elements
10286   \param theElems - the list of elements (edges or faces) to be replicated
10287   The nodes for duplication could be found from these elements
10288   \param theNodesNot - list of nodes to NOT replicate
10289   \param theAffectedElems - the list of elements (cells and edges) to which the 
10290   replicated nodes should be associated to.
10291   \return TRUE if operation has been completed successfully, FALSE otherwise
10292 */
10293 //================================================================================
10294
10295 bool SMESH_MeshEditor::DoubleNodes( const TIDSortedElemSet& theElems,
10296                                     const TIDSortedElemSet& theNodesNot,
10297                                     const TIDSortedElemSet& theAffectedElems )
10298 {
10299   myLastCreatedElems.Clear();
10300   myLastCreatedNodes.Clear();
10301
10302   if ( theElems.size() == 0 )
10303     return false;
10304
10305   SMESHDS_Mesh* aMeshDS = GetMeshDS();
10306   if ( !aMeshDS )
10307     return false;
10308
10309   bool res = false;
10310   std::map< const SMDS_MeshNode*, const SMDS_MeshNode* > anOldNodeToNewNode;
10311   // duplicate elements and nodes
10312   res = doubleNodes( aMeshDS, theElems, theNodesNot, anOldNodeToNewNode, true );
10313   // replce nodes by duplications
10314   res = doubleNodes( aMeshDS, theAffectedElems, theNodesNot, anOldNodeToNewNode, false );
10315   return res;
10316 }
10317
10318 //================================================================================
10319 /*!
10320   \brief Creates a hole in a mesh by doubling the nodes of some particular elements
10321   \param theMeshDS - mesh instance
10322   \param theElems - the elements replicated or modified (nodes should be changed)
10323   \param theNodesNot - nodes to NOT replicate
10324   \param theNodeNodeMap - relation of old node to new created node
10325   \param theIsDoubleElem - flag os to replicate element or modify
10326   \return TRUE if operation has been completed successfully, FALSE otherwise
10327 */
10328 //================================================================================
10329
10330 bool SMESH_MeshEditor::doubleNodes( SMESHDS_Mesh*     theMeshDS,
10331                                     const TIDSortedElemSet& theElems,
10332                                     const TIDSortedElemSet& theNodesNot,
10333                                     std::map< const SMDS_MeshNode*,
10334                                     const SMDS_MeshNode* >& theNodeNodeMap,
10335                                     const bool theIsDoubleElem )
10336 {
10337   MESSAGE("doubleNodes");
10338   // iterate on through element and duplicate them (by nodes duplication)
10339   bool res = false;
10340   TIDSortedElemSet::const_iterator elemItr = theElems.begin();
10341   for ( ;  elemItr != theElems.end(); ++elemItr )
10342   {
10343     const SMDS_MeshElement* anElem = *elemItr;
10344     if (!anElem)
10345       continue;
10346
10347     bool isDuplicate = false;
10348     // duplicate nodes to duplicate element
10349     std::vector<const SMDS_MeshNode*> newNodes( anElem->NbNodes() );
10350     SMDS_ElemIteratorPtr anIter = anElem->nodesIterator();
10351     int ind = 0;
10352     while ( anIter->more() ) 
10353     { 
10354
10355       SMDS_MeshNode* aCurrNode = (SMDS_MeshNode*)anIter->next();
10356       SMDS_MeshNode* aNewNode = aCurrNode;
10357       if ( theNodeNodeMap.find( aCurrNode ) != theNodeNodeMap.end() )
10358         aNewNode = (SMDS_MeshNode*)theNodeNodeMap[ aCurrNode ];
10359       else if ( theIsDoubleElem && theNodesNot.find( aCurrNode ) == theNodesNot.end() )
10360       {
10361         // duplicate node
10362         aNewNode = theMeshDS->AddNode( aCurrNode->X(), aCurrNode->Y(), aCurrNode->Z() );
10363         theNodeNodeMap[ aCurrNode ] = aNewNode;
10364         myLastCreatedNodes.Append( aNewNode );
10365       }
10366       isDuplicate |= (aCurrNode != aNewNode);
10367       newNodes[ ind++ ] = aNewNode;
10368     }
10369     if ( !isDuplicate )
10370       continue;
10371
10372     if ( theIsDoubleElem )
10373       AddElement(newNodes, anElem->GetType(), anElem->IsPoly());
10374     else
10375       {
10376       MESSAGE("ChangeElementNodes");
10377       theMeshDS->ChangeElementNodes( anElem, &newNodes[ 0 ], anElem->NbNodes() );
10378       }
10379     res = true;
10380   }
10381   return res;
10382 }
10383
10384 //================================================================================
10385 /*!
10386   \brief Creates a hole in a mesh by doubling the nodes of some particular elements
10387   \param theNodes - identifiers of nodes to be doubled
10388   \param theModifiedElems - identifiers of elements to be updated by the new (doubled) 
10389          nodes. If list of element identifiers is empty then nodes are doubled but 
10390          they not assigned to elements
10391   \return TRUE if operation has been completed successfully, FALSE otherwise
10392 */
10393 //================================================================================
10394
10395 bool SMESH_MeshEditor::DoubleNodes( const std::list< int >& theListOfNodes, 
10396                                     const std::list< int >& theListOfModifiedElems )
10397 {
10398   MESSAGE("DoubleNodes");
10399   myLastCreatedElems.Clear();
10400   myLastCreatedNodes.Clear();
10401
10402   if ( theListOfNodes.size() == 0 )
10403     return false;
10404
10405   SMESHDS_Mesh* aMeshDS = GetMeshDS();
10406   if ( !aMeshDS )
10407     return false;
10408
10409   // iterate through nodes and duplicate them
10410
10411   std::map< const SMDS_MeshNode*, const SMDS_MeshNode* > anOldNodeToNewNode;
10412
10413   std::list< int >::const_iterator aNodeIter;
10414   for ( aNodeIter = theListOfNodes.begin(); aNodeIter != theListOfNodes.end(); ++aNodeIter )
10415   {
10416     int aCurr = *aNodeIter;
10417     SMDS_MeshNode* aNode = (SMDS_MeshNode*)aMeshDS->FindNode( aCurr );
10418     if ( !aNode )
10419       continue;
10420
10421     // duplicate node
10422
10423     const SMDS_MeshNode* aNewNode = aMeshDS->AddNode( aNode->X(), aNode->Y(), aNode->Z() );
10424     if ( aNewNode )
10425     {
10426       anOldNodeToNewNode[ aNode ] = aNewNode;
10427       myLastCreatedNodes.Append( aNewNode );
10428     }
10429   }
10430
10431   // Create map of new nodes for modified elements
10432
10433   std::map< SMDS_MeshElement*, vector<const SMDS_MeshNode*> > anElemToNodes;
10434
10435   std::list< int >::const_iterator anElemIter;
10436   for ( anElemIter = theListOfModifiedElems.begin(); 
10437         anElemIter != theListOfModifiedElems.end(); ++anElemIter )
10438   {
10439     int aCurr = *anElemIter;
10440     SMDS_MeshElement* anElem = (SMDS_MeshElement*)aMeshDS->FindElement( aCurr );
10441     if ( !anElem )
10442       continue;
10443
10444     vector<const SMDS_MeshNode*> aNodeArr( anElem->NbNodes() );
10445
10446     SMDS_ElemIteratorPtr anIter = anElem->nodesIterator();
10447     int ind = 0;
10448     while ( anIter->more() ) 
10449     { 
10450       SMDS_MeshNode* aCurrNode = (SMDS_MeshNode*)anIter->next();
10451       if ( aCurr && anOldNodeToNewNode.find( aCurrNode ) != anOldNodeToNewNode.end() )
10452       {
10453         const SMDS_MeshNode* aNewNode = anOldNodeToNewNode[ aCurrNode ];
10454         aNodeArr[ ind++ ] = aNewNode;
10455       }
10456       else
10457         aNodeArr[ ind++ ] = aCurrNode;
10458     }
10459     anElemToNodes[ anElem ] = aNodeArr;
10460   }
10461
10462   // Change nodes of elements  
10463
10464   std::map< SMDS_MeshElement*, vector<const SMDS_MeshNode*> >::iterator
10465     anElemToNodesIter = anElemToNodes.begin();
10466   for ( ; anElemToNodesIter != anElemToNodes.end(); ++anElemToNodesIter )
10467   {
10468     const SMDS_MeshElement* anElem = anElemToNodesIter->first;
10469     vector<const SMDS_MeshNode*> aNodeArr = anElemToNodesIter->second;
10470     if ( anElem )
10471       {
10472       MESSAGE("ChangeElementNodes");
10473       aMeshDS->ChangeElementNodes( anElem, &aNodeArr[ 0 ], anElem->NbNodes() );
10474       }
10475   }
10476
10477   return true;
10478 }
10479
10480 namespace {
10481
10482   //================================================================================
10483   /*!
10484   \brief Check if element located inside shape
10485   \return TRUE if IN or ON shape, FALSE otherwise
10486   */
10487   //================================================================================
10488
10489   template<class Classifier>
10490   bool isInside(const SMDS_MeshElement* theElem,
10491                 Classifier&             theClassifier,
10492                 const double            theTol)
10493   {
10494     gp_XYZ centerXYZ (0, 0, 0);
10495     SMDS_ElemIteratorPtr aNodeItr = theElem->nodesIterator();
10496     while (aNodeItr->more())
10497       centerXYZ += SMESH_MeshEditor::TNodeXYZ(cast2Node( aNodeItr->next()));
10498
10499     gp_Pnt aPnt = centerXYZ / theElem->NbNodes();
10500     theClassifier.Perform(aPnt, theTol);
10501     TopAbs_State aState = theClassifier.State();
10502     return (aState == TopAbs_IN || aState == TopAbs_ON );
10503   }
10504
10505   //================================================================================
10506   /*!
10507    * \brief Classifier of the 3D point on the TopoDS_Face
10508    *        with interaface suitable for isInside()
10509    */
10510   //================================================================================
10511
10512   struct _FaceClassifier
10513   {
10514     Extrema_ExtPS       _extremum;
10515     BRepAdaptor_Surface _surface;
10516     TopAbs_State        _state;
10517
10518     _FaceClassifier(const TopoDS_Face& face):_extremum(),_surface(face),_state(TopAbs_OUT)
10519     {
10520       _extremum.Initialize( _surface,
10521                             _surface.FirstUParameter(), _surface.LastUParameter(),
10522                             _surface.FirstVParameter(), _surface.LastVParameter(),
10523                             _surface.Tolerance(), _surface.Tolerance() );
10524     }
10525     void Perform(const gp_Pnt& aPnt, double theTol)
10526     {
10527       _state = TopAbs_OUT;
10528       _extremum.Perform(aPnt);
10529       if ( _extremum.IsDone() )
10530         for ( int iSol = 1; iSol <= _extremum.NbExt() && _state == TopAbs_OUT; ++iSol)
10531           _state = ( _extremum.Value(iSol) <= theTol ? TopAbs_IN : TopAbs_OUT );
10532     }
10533     TopAbs_State State() const
10534     {
10535       return _state;
10536     }
10537   };
10538 }
10539
10540 //================================================================================
10541 /*!
10542   \brief Creates a hole in a mesh by doubling the nodes of some particular elements
10543   \param theElems - group of of elements (edges or faces) to be replicated
10544   \param theNodesNot - group of nodes not to replicate
10545   \param theShape - shape to detect affected elements (element which geometric center
10546   located on or inside shape).
10547   The replicated nodes should be associated to affected elements.
10548   \return TRUE if operation has been completed successfully, FALSE otherwise
10549 */
10550 //================================================================================
10551
10552 bool SMESH_MeshEditor::DoubleNodesInRegion( const TIDSortedElemSet& theElems,
10553                                             const TIDSortedElemSet& theNodesNot,
10554                                             const TopoDS_Shape&     theShape )
10555 {
10556   if ( theShape.IsNull() )
10557     return false;
10558
10559   const double aTol = Precision::Confusion();
10560   auto_ptr< BRepClass3d_SolidClassifier> bsc3d;
10561   auto_ptr<_FaceClassifier>              aFaceClassifier;
10562   if ( theShape.ShapeType() == TopAbs_SOLID )
10563   {
10564     bsc3d.reset( new BRepClass3d_SolidClassifier(theShape));;
10565     bsc3d->PerformInfinitePoint(aTol);
10566   }
10567   else if (theShape.ShapeType() == TopAbs_FACE )
10568   {
10569     aFaceClassifier.reset( new _FaceClassifier(TopoDS::Face(theShape)));
10570   }
10571
10572   // iterates on indicated elements and get elements by back references from their nodes
10573   TIDSortedElemSet anAffected;
10574   TIDSortedElemSet::const_iterator elemItr = theElems.begin();
10575   for ( ;  elemItr != theElems.end(); ++elemItr )
10576   {
10577     SMDS_MeshElement* anElem = (SMDS_MeshElement*)*elemItr;
10578     if (!anElem)
10579       continue;
10580
10581     SMDS_ElemIteratorPtr nodeItr = anElem->nodesIterator();
10582     while ( nodeItr->more() )
10583     {
10584       const SMDS_MeshNode* aNode = cast2Node(nodeItr->next());
10585       if ( !aNode || theNodesNot.find(aNode) != theNodesNot.end() )
10586         continue;
10587       SMDS_ElemIteratorPtr backElemItr = aNode->GetInverseElementIterator();
10588       while ( backElemItr->more() )
10589       {
10590         const SMDS_MeshElement* curElem = backElemItr->next();
10591         if ( curElem && theElems.find(curElem) == theElems.end() &&
10592              ( bsc3d.get() ?
10593                isInside( curElem, *bsc3d, aTol ) :
10594                isInside( curElem, *aFaceClassifier, aTol )))
10595           anAffected.insert( curElem );
10596       }
10597     }
10598   }
10599   return DoubleNodes( theElems, theNodesNot, anAffected );
10600 }
10601
10602 /*!
10603  * \brief Double nodes on shared faces between groups of volumes and create flat elements on demand.
10604  * The list of groups must describe a partition of the mesh volumes.
10605  * The nodes of the internal faces at the boundaries of the groups are doubled.
10606  * In option, the internal faces are replaced by flat elements.
10607  * Triangles are transformed in prisms, and quadrangles in hexahedrons.
10608  * @param theElems - list of groups of volumes, where a group of volume is a set of
10609  * SMDS_MeshElements sorted by Id.
10610  * @param createJointElems - if TRUE, create the elements
10611  * @return TRUE if operation has been completed successfully, FALSE otherwise
10612  */
10613 bool SMESH_MeshEditor::DoubleNodesOnGroupBoundaries( const std::vector<TIDSortedElemSet>& theElems,
10614                                                      bool createJointElems)
10615 {
10616   MESSAGE("------------------------------------------------------");
10617   MESSAGE("SMESH_MeshEditor::CreateJointElementsOnGroupBoundaries");
10618   MESSAGE("------------------------------------------------------");
10619
10620   SMESHDS_Mesh *meshDS = this->myMesh->GetMeshDS();
10621   meshDS->BuildDownWardConnectivity(false);
10622   CHRONO(50);
10623   SMDS_UnstructuredGrid *grid = meshDS->getGrid();
10624
10625   // --- build the list of faces shared by 2 domains (group of elements), with their domain and volume indexes
10626   //     build the list of nodes shared by 2 or more domains, with their domain indexes
10627
10628   std::map<DownIdType, std::map<int,int>, DownIdCompare> faceDomains; // 2x(id domain --> id volume)
10629   std::map<int, std::map<int,int> > nodeDomains; //oldId ->  (domainId -> newId)
10630   faceDomains.clear();
10631   nodeDomains.clear();
10632   std::map<int,int> emptyMap;
10633   emptyMap.clear();
10634
10635   for (int idom = 0; idom < theElems.size(); idom++)
10636     {
10637
10638       // --- build a map (face to duplicate --> volume to modify)
10639       //     with all the faces shared by 2 domains (group of elements)
10640       //     and corresponding volume of this domain, for each shared face.
10641       //     a volume has a face shared by 2 domains if it has a neighbor which is not in is domain.
10642
10643       const TIDSortedElemSet& domain = theElems[idom];
10644       TIDSortedElemSet::const_iterator elemItr = domain.begin();
10645       for (; elemItr != domain.end(); ++elemItr)
10646         {
10647           SMDS_MeshElement* anElem = (SMDS_MeshElement*) *elemItr;
10648           if (!anElem)
10649             continue;
10650           int vtkId = anElem->getVtkId();
10651           int neighborsVtkIds[NBMAXNEIGHBORS];
10652           int downIds[NBMAXNEIGHBORS];
10653           unsigned char downTypes[NBMAXNEIGHBORS];
10654           int nbNeighbors = grid->GetNeighbors(neighborsVtkIds, downIds, downTypes, vtkId);
10655           for (int n = 0; n < nbNeighbors; n++)
10656             {
10657               int smdsId = meshDS->fromVtkToSmds(neighborsVtkIds[n]);
10658               const SMDS_MeshElement* elem = meshDS->FindElement(smdsId);
10659               if (! domain.count(elem)) // neighbor is in another domain : face is shared
10660                 {
10661                   DownIdType face(downIds[n], downTypes[n]);
10662                   if (!faceDomains.count(face))
10663                     faceDomains[face] = emptyMap; // create an empty entry for face
10664                   if (!faceDomains[face].count(idom))
10665                     {
10666                       faceDomains[face][idom] = vtkId; // volume associated to face in this domain
10667                     }
10668                 }
10669             }
10670         }
10671     }
10672
10673   MESSAGE("Number of shared faces " << faceDomains.size());
10674
10675   // --- for each shared face, get the nodes
10676   //     for each node, for each domain of the face, create a clone of the node
10677
10678   std::map<DownIdType, std::map<int,int>, DownIdCompare>::iterator itface = faceDomains.begin();
10679   for( ; itface != faceDomains.end();++itface )
10680     {
10681       DownIdType face = itface->first;
10682       std::map<int,int> domvol = itface->second;
10683       std::set<int> oldNodes;
10684       oldNodes.clear();
10685       grid->GetNodeIds(oldNodes, face.cellId, face.cellType);
10686       std::set<int>::iterator itn = oldNodes.begin();
10687       for (;itn != oldNodes.end(); ++itn)
10688         {
10689           int oldId = *itn;
10690           if (!nodeDomains.count(oldId))
10691             nodeDomains[oldId] = emptyMap; // create an empty entry for node
10692           std::map<int,int>::iterator itdom = domvol.begin();
10693           for(; itdom != domvol.end(); ++itdom)
10694             {
10695               int idom = itdom->first;
10696               if ( nodeDomains[oldId].empty() )
10697                 nodeDomains[oldId][idom] = oldId; // keep the old node in the first domain
10698               else
10699                 {
10700                   double *coords = grid->GetPoint(oldId);
10701                   SMDS_MeshNode *newNode = meshDS->AddNode(coords[0], coords[1], coords[2]);
10702                   int newId = newNode->getVtkId();
10703                   nodeDomains[oldId][idom] = newId; // cloned node for other domains
10704                 }
10705             }
10706         }
10707     }
10708
10709   // --- iterate on shared faces (volumes to modify, face to extrude)
10710   //     get node id's of the face (id SMDS = id VTK)
10711   //     create flat element with old and new nodes if requested
10712
10713   if (createJointElems)
10714     {
10715       itface = faceDomains.begin();
10716       for( ; itface != faceDomains.end();++itface )
10717         {
10718           DownIdType face = itface->first;
10719           std::set<int> oldNodes;
10720           std::set<int>::iterator itn;
10721           oldNodes.clear();
10722           grid->GetNodeIds(oldNodes, face.cellId, face.cellType);
10723           std::map<int,int> localClonedNodeIds;
10724
10725           std::map<int,int> domvol = itface->second;
10726           std::map<int,int>::iterator itdom = domvol.begin();
10727           int dom1 = itdom->first;
10728           int vtkVolId = itdom->second;
10729           itdom++;
10730           int dom2 = itdom->first;
10731
10732           localClonedNodeIds.clear();
10733           for (itn = oldNodes.begin(); itn != oldNodes.end(); ++itn)
10734             {
10735               int oldId = *itn;
10736               int refid = oldId;
10737               if (nodeDomains[oldId].count(dom1))
10738                 refid = nodeDomains[oldId][dom1];
10739               else
10740                 MESSAGE("--- problem domain node " << dom1 << " " << oldId);
10741               int newid = oldId;
10742               if (nodeDomains[oldId].count(dom2))
10743                 newid = nodeDomains[oldId][dom2];
10744               else
10745                 MESSAGE("--- problem domain node " << dom2 << " " << oldId);
10746               localClonedNodeIds[oldId] = newid;
10747             }
10748           meshDS->extrudeVolumeFromFace(vtkVolId, localClonedNodeIds);
10749         }
10750     }
10751
10752   // --- iterate on shared faces (volumes to modify, face to extrude)
10753   //     get node id's of the face
10754   //     replace old nodes by new nodes in volumes, and update inverse connectivity
10755
10756   itface = faceDomains.begin();
10757   for( ; itface != faceDomains.end();++itface )
10758     {
10759       DownIdType face = itface->first;
10760       std::set<int> oldNodes;
10761       std::set<int>::iterator itn;
10762       oldNodes.clear();
10763       grid->GetNodeIds(oldNodes, face.cellId, face.cellType);
10764       std::map<int,int> localClonedNodeIds;
10765
10766       std::map<int,int> domvol = itface->second;
10767       std::map<int,int>::iterator itdom = domvol.begin();
10768       for(; itdom != domvol.end(); ++itdom)
10769         {
10770           int idom = itdom->first;
10771           int vtkVolId = itdom->second;
10772           localClonedNodeIds.clear();
10773           for (itn = oldNodes.begin(); itn != oldNodes.end(); ++itn)
10774             {
10775               int oldId = *itn;
10776               if (nodeDomains[oldId].count(idom))
10777                 localClonedNodeIds[oldId] = nodeDomains[oldId][idom];
10778             }
10779           meshDS->ModifyCellNodes(vtkVolId, localClonedNodeIds);
10780         }
10781     }
10782   grid->BuildLinks();
10783
10784   // TODO replace also old nodes by new nodes in faces and edges
10785   CHRONOSTOP(50);
10786   counters::stats();
10787   return true;
10788 }
10789
10790 //================================================================================
10791 /*!
10792  * \brief Generates skin mesh (containing 2D cells) from 3D mesh
10793  * The created 2D mesh elements based on nodes of free faces of boundary volumes
10794  * \return TRUE if operation has been completed successfully, FALSE otherwise
10795  */
10796 //================================================================================
10797
10798 bool SMESH_MeshEditor::Make2DMeshFrom3D()
10799 {
10800   // iterates on volume elements and detect all free faces on them
10801   SMESHDS_Mesh* aMesh = GetMeshDS();
10802   if (!aMesh)
10803     return false;
10804   //bool res = false;
10805   int nbFree = 0, nbExisted = 0, nbCreated = 0;
10806   SMDS_VolumeIteratorPtr vIt = aMesh->volumesIterator();
10807   while(vIt->more())
10808   {
10809     const SMDS_MeshVolume* volume = vIt->next();
10810     SMDS_VolumeTool vTool( volume );
10811     vTool.SetExternalNormal();
10812     const bool isPoly = volume->IsPoly();
10813     const bool isQuad = volume->IsQuadratic();
10814     for ( int iface = 0, n = vTool.NbFaces(); iface < n; iface++ )
10815     {
10816       if (!vTool.IsFreeFace(iface))
10817         continue;
10818       nbFree++;
10819       vector<const SMDS_MeshNode *> nodes;
10820       int nbFaceNodes = vTool.NbFaceNodes(iface);
10821       const SMDS_MeshNode** faceNodes = vTool.GetFaceNodes(iface);
10822       int inode = 0;
10823       for ( ; inode < nbFaceNodes; inode += isQuad ? 2 : 1)
10824         nodes.push_back(faceNodes[inode]);
10825       if (isQuad)
10826         for ( inode = 1; inode < nbFaceNodes; inode += 2)
10827           nodes.push_back(faceNodes[inode]);
10828
10829       // add new face based on volume nodes
10830       if (aMesh->FindFace( nodes ) ) {
10831         nbExisted++;
10832         continue; // face already exsist
10833       }
10834       AddElement(nodes, SMDSAbs_Face, isPoly && iface == 1);
10835       nbCreated++;
10836     }
10837   }
10838   return ( nbFree==(nbExisted+nbCreated) );
10839 }
10840
10841 namespace
10842 {
10843   inline const SMDS_MeshNode* getNodeWithSameID(SMESHDS_Mesh* mesh, const SMDS_MeshNode* node)
10844   {
10845     if ( const SMDS_MeshNode* n = mesh->FindNode( node->GetID() ))
10846       return n;
10847     return mesh->AddNodeWithID( node->X(),node->Y(),node->Z(), node->GetID() );
10848   }
10849 }
10850 //================================================================================
10851 /*!
10852  * \brief Creates missing boundary elements
10853  *  \param elements - elements whose boundary is to be checked
10854  *  \param dimension - defines type of boundary elements to create
10855  *  \param group - a group to store created boundary elements in
10856  *  \param targetMesh - a mesh to store created boundary elements in
10857  *  \param toCopyElements - if true, the checked elements will be copied into the targetMesh
10858  *  \param toCopyExistingBondary - if true, not only new but also pre-existing
10859  *                                boundary elements will be copied into the targetMesh
10860  */
10861 //================================================================================
10862
10863 void SMESH_MeshEditor::MakeBoundaryMesh(const TIDSortedElemSet& elements,
10864                                         Bnd_Dimension           dimension,
10865                                         SMESH_Group*            group/*=0*/,
10866                                         SMESH_Mesh*             targetMesh/*=0*/,
10867                                         bool                    toCopyElements/*=false*/,
10868                                         bool                    toCopyExistingBondary/*=false*/)
10869 {
10870   SMDSAbs_ElementType missType = (dimension == BND_2DFROM3D) ? SMDSAbs_Face : SMDSAbs_Edge;
10871   SMDSAbs_ElementType elemType = (dimension == BND_1DFROM2D) ? SMDSAbs_Face : SMDSAbs_Volume;
10872   // hope that all elements are of the same type, do not check them all
10873   if ( !elements.empty() && (*elements.begin())->GetType() != elemType )
10874     throw SALOME_Exception(LOCALIZED("wrong element type"));
10875
10876   if ( !targetMesh )
10877     toCopyElements = toCopyExistingBondary = false;
10878
10879   SMESH_MeshEditor tgtEditor( targetMesh ? targetMesh : myMesh );
10880   SMESHDS_Mesh* aMesh = GetMeshDS(), *tgtMeshDS = tgtEditor.GetMeshDS();
10881
10882   SMDS_VolumeTool vTool;
10883   TIDSortedElemSet emptySet, avoidSet;
10884   int inode;
10885
10886   typedef vector<const SMDS_MeshNode*> TConnectivity;
10887
10888   SMDS_ElemIteratorPtr eIt;
10889   if (elements.empty())
10890     eIt = aMesh->elementsIterator(elemType);
10891   else
10892     eIt = SMDS_ElemIteratorPtr( new TSetIterator( elements.begin(), elements.end() ));
10893
10894   while (eIt->more())
10895   {
10896     const SMDS_MeshElement* elem = eIt->next();
10897     const int iQuad = elem->IsQuadratic();
10898
10899     // 1. For an elem, get present bnd elements and connectivities of missing bnd elements
10900     vector<const SMDS_MeshElement*> presentBndElems;
10901     vector<TConnectivity>           missingBndElems;
10902     TConnectivity nodes;
10903     if ( vTool.Set(elem) ) // elem is a volume ------------------------------------------
10904     {
10905       vTool.SetExternalNormal();
10906       for ( int iface = 0, n = vTool.NbFaces(); iface < n; iface++ )
10907       {
10908         if (!vTool.IsFreeFace(iface))
10909           continue;
10910         int nbFaceNodes = vTool.NbFaceNodes(iface);
10911         const SMDS_MeshNode** nn = vTool.GetFaceNodes(iface);
10912         if ( missType == SMDSAbs_Edge ) // boundary edges
10913         {
10914           nodes.resize( 2+iQuad );
10915           for ( int i = 0; i < nbFaceNodes; i += 1+iQuad)
10916           {
10917             for ( int j = 0; j < nodes.size(); ++j )
10918               nodes[j] =nn[i+j];
10919             if ( const SMDS_MeshElement* edge =
10920                  aMesh->FindElement(nodes,SMDSAbs_Edge,/*noMedium=*/0))
10921               presentBndElems.push_back( edge );
10922             else
10923               missingBndElems.push_back( nodes );
10924           }
10925         }
10926         else // boundary face
10927         {
10928           nodes.clear();
10929           for ( inode = 0; inode < nbFaceNodes; inode += 1+iQuad)
10930             nodes.push_back( nn[inode] );
10931           if (iQuad)
10932             for ( inode = 1; inode < nbFaceNodes; inode += 2)
10933               nodes.push_back( nn[inode] );
10934
10935           if (const SMDS_MeshFace * f = aMesh->FindFace( nodes ) )
10936             presentBndElems.push_back( f );
10937           else
10938             missingBndElems.push_back( nodes );
10939         }
10940       }
10941     }
10942     else                     // elem is a face ------------------------------------------
10943     {
10944       avoidSet.clear(), avoidSet.insert( elem );
10945       int nbNodes = elem->NbCornerNodes();
10946       nodes.resize( 2 /*+ iQuad*/);
10947       for ( int i = 0; i < nbNodes; i++ )
10948       {
10949         nodes[0] = elem->GetNode(i);
10950         nodes[1] = elem->GetNode((i+1)%nbNodes);
10951         if ( FindFaceInSet( nodes[0], nodes[1], emptySet, avoidSet))
10952           continue; // not free link
10953
10954         //if ( iQuad )
10955         //nodes[2] = elem->GetNode( i + nbNodes );
10956         if ( const SMDS_MeshElement* edge =
10957              aMesh->FindElement(nodes,SMDSAbs_Edge,/*noMedium=*/true))
10958           presentBndElems.push_back( edge );
10959         else
10960           missingBndElems.push_back( nodes );
10961       }
10962     }
10963
10964     // 2. Add missing boundary elements
10965     if ( targetMesh != myMesh )
10966       // instead of making a map of nodes in this mesh and targetMesh,
10967       // we create nodes with same IDs. We can renumber them later, if needed
10968       for ( int i = 0; i < missingBndElems.size(); ++i )
10969       {
10970         TConnectivity& srcNodes = missingBndElems[i];
10971         TConnectivity  nodes( srcNodes.size() );
10972         for ( inode = 0; inode < nodes.size(); ++inode )
10973           nodes[inode] = getNodeWithSameID( tgtMeshDS, srcNodes[inode] );
10974         tgtEditor.AddElement(nodes, missType, elem->IsPoly() && nodes.size()/(iQuad+1)>4);
10975       }
10976     else
10977       for ( int i = 0; i < missingBndElems.size(); ++i )
10978       {
10979         TConnectivity&  nodes = missingBndElems[i];
10980         tgtEditor.AddElement(nodes, missType, elem->IsPoly() && nodes.size()/(iQuad+1)>4);
10981       }
10982
10983     // 3. Copy present boundary elements
10984     if ( toCopyExistingBondary )
10985       for ( int i = 0 ; i < presentBndElems.size(); ++i )
10986       {
10987         const SMDS_MeshElement* e = presentBndElems[i];
10988         TConnectivity nodes( e->NbNodes() );
10989         for ( inode = 0; inode < nodes.size(); ++inode )
10990           nodes[inode] = getNodeWithSameID( tgtMeshDS, e->GetNode(inode) );
10991         tgtEditor.AddElement(nodes, missType, e->IsPoly());
10992         // leave only missing elements in tgtEditor.myLastCreatedElems
10993         tgtEditor.myLastCreatedElems.Remove( tgtEditor.myLastCreatedElems.Size() );
10994       }
10995   } // loop on given elements
10996
10997   // 4. Fill group with missing boundary elements
10998   if ( group )
10999   {
11000     if ( SMESHDS_Group* g = dynamic_cast<SMESHDS_Group*>( group->GetGroupDS() ))
11001       for ( int i = 0; i < tgtEditor.myLastCreatedElems.Size(); ++i )
11002         g->SMDSGroup().Add( tgtEditor.myLastCreatedElems( i+1 ));
11003   }
11004   tgtEditor.myLastCreatedElems.Clear();
11005
11006   // 5. Copy given elements
11007   if ( toCopyElements )
11008   {
11009     if (elements.empty())
11010       eIt = aMesh->elementsIterator(elemType);
11011     else
11012       eIt = SMDS_ElemIteratorPtr( new TSetIterator( elements.begin(), elements.end() ));
11013     while (eIt->more())
11014     {
11015       const SMDS_MeshElement* elem = eIt->next();
11016       TConnectivity nodes( elem->NbNodes() );
11017       for ( inode = 0; inode < nodes.size(); ++inode )
11018         nodes[inode] = getNodeWithSameID( tgtMeshDS, elem->GetNode(inode) );
11019       tgtEditor.AddElement(nodes, elemType, elem->IsPoly());
11020
11021       tgtEditor.myLastCreatedElems.Clear();
11022     }
11023   }
11024   return;
11025 }