Salome HOME
85a8b912c6c5d29a5516cbad5b0448e908577e1a
[modules/smesh.git] / src / SMESH / SMESH_MeshEditor.cxx
1 //  Copyright (C) 2007-2010  CEA/DEN, EDF R&D, OPEN CASCADE
2 //
3 //  Copyright (C) 2003-2007  OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN,
4 //  CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS
5 //
6 //  This library is free software; you can redistribute it and/or
7 //  modify it under the terms of the GNU Lesser General Public
8 //  License as published by the Free Software Foundation; either
9 //  version 2.1 of the License.
10 //
11 //  This library is distributed in the hope that it will be useful,
12 //  but WITHOUT ANY WARRANTY; without even the implied warranty of
13 //  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14 //  Lesser General Public License for more details.
15 //
16 //  You should have received a copy of the GNU Lesser General Public
17 //  License along with this library; if not, write to the Free Software
18 //  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
19 //
20 //  See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
21 //
22
23 //  SMESH SMESH : idl implementation based on 'SMESH' unit's classes
24 // File      : SMESH_MeshEditor.cxx
25 // Created   : Mon Apr 12 16:10:22 2004
26 // Author    : Edward AGAPOV (eap)
27 //
28 #define CHRONODEF
29 #include "SMESH_MeshEditor.hxx"
30
31 #include "SMDS_FaceOfNodes.hxx"
32 #include "SMDS_VolumeTool.hxx"
33 #include "SMDS_EdgePosition.hxx"
34 #include "SMDS_PolyhedralVolumeOfNodes.hxx"
35 #include "SMDS_FacePosition.hxx"
36 #include "SMDS_SpacePosition.hxx"
37 //#include "SMDS_QuadraticFaceOfNodes.hxx"
38 #include "SMDS_MeshGroup.hxx"
39 #include "SMDS_LinearEdge.hxx"
40 #include "SMDS_Downward.hxx"
41 #include "SMDS_SetIterator.hxx"
42
43 #include "SMESHDS_Group.hxx"
44 #include "SMESHDS_Mesh.hxx"
45
46 #include "SMESH_Algo.hxx"
47 #include "SMESH_ControlsDef.hxx"
48 #include "SMESH_Group.hxx"
49 #include "SMESH_MesherHelper.hxx"
50 #include "SMESH_OctreeNode.hxx"
51 #include "SMESH_subMesh.hxx"
52
53 #include "utilities.h"
54
55 #include <BRepAdaptor_Surface.hxx>
56 #include <BRepClass3d_SolidClassifier.hxx>
57 #include <BRep_Tool.hxx>
58 #include <ElCLib.hxx>
59 #include <Extrema_GenExtPS.hxx>
60 #include <Extrema_POnCurv.hxx>
61 #include <Extrema_POnSurf.hxx>
62 #include <GC_MakeSegment.hxx>
63 #include <Geom2d_Curve.hxx>
64 #include <GeomAPI_ExtremaCurveCurve.hxx>
65 #include <GeomAdaptor_Surface.hxx>
66 #include <Geom_Curve.hxx>
67 #include <Geom_Line.hxx>
68 #include <Geom_Surface.hxx>
69 #include <IntAna_IntConicQuad.hxx>
70 #include <IntAna_Quadric.hxx>
71 #include <Precision.hxx>
72 #include <TColStd_ListOfInteger.hxx>
73 #include <TopAbs_State.hxx>
74 #include <TopExp.hxx>
75 #include <TopExp_Explorer.hxx>
76 #include <TopTools_ListIteratorOfListOfShape.hxx>
77 #include <TopTools_ListOfShape.hxx>
78 #include <TopTools_SequenceOfShape.hxx>
79 #include <TopoDS.hxx>
80 #include <TopoDS_Face.hxx>
81 #include <gp.hxx>
82 #include <gp_Ax1.hxx>
83 #include <gp_Dir.hxx>
84 #include <gp_Lin.hxx>
85 #include <gp_Pln.hxx>
86 #include <gp_Trsf.hxx>
87 #include <gp_Vec.hxx>
88 #include <gp_XY.hxx>
89 #include <gp_XYZ.hxx>
90
91 #include <math.h>
92
93 #include <map>
94 #include <set>
95 #include <numeric>
96 #include <limits>
97 #include <algorithm>
98
99 #define cast2Node(elem) static_cast<const SMDS_MeshNode*>( elem )
100
101 using namespace std;
102 using namespace SMESH::Controls;
103
104 typedef map<const SMDS_MeshElement*, list<const SMDS_MeshNode*> >    TElemOfNodeListMap;
105 typedef map<const SMDS_MeshElement*, list<const SMDS_MeshElement*> > TElemOfElemListMap;
106
107 typedef SMDS_SetIterator< SMDS_pElement, TIDSortedElemSet::const_iterator> TSetIterator;
108
109 //=======================================================================
110 //function : SMESH_MeshEditor
111 //purpose  :
112 //=======================================================================
113
114 SMESH_MeshEditor::SMESH_MeshEditor( SMESH_Mesh* theMesh )
115   :myMesh( theMesh ) // theMesh may be NULL
116 {
117 }
118
119 //=======================================================================
120 /*!
121  * \brief Add element
122  */
123 //=======================================================================
124
125 SMDS_MeshElement*
126 SMESH_MeshEditor::AddElement(const vector<const SMDS_MeshNode*> & node,
127                              const SMDSAbs_ElementType            type,
128                              const bool                           isPoly,
129                              const int                            ID)
130 {
131   //MESSAGE("AddElement " <<node.size() << " " << type << " " << isPoly << " " << ID);
132   SMDS_MeshElement* e = 0;
133   int nbnode = node.size();
134   SMESHDS_Mesh* mesh = GetMeshDS();
135   switch ( type ) {
136   case SMDSAbs_Face:
137     if ( !isPoly ) {
138       if      (nbnode == 3) {
139         if ( ID >= 1 ) e = mesh->AddFaceWithID(node[0], node[1], node[2], ID);
140         else           e = mesh->AddFace      (node[0], node[1], node[2] );
141       }
142       else if (nbnode == 4) {
143         if ( ID >= 1 ) e = mesh->AddFaceWithID(node[0], node[1], node[2], node[3], ID);
144         else           e = mesh->AddFace      (node[0], node[1], node[2], node[3] );
145       }
146       else if (nbnode == 6) {
147         if ( ID >= 1 ) e = mesh->AddFaceWithID(node[0], node[1], node[2], node[3],
148                                                node[4], node[5], ID);
149         else           e = mesh->AddFace      (node[0], node[1], node[2], node[3],
150                                                node[4], node[5] );
151       }
152       else if (nbnode == 8) {
153         if ( ID >= 1 ) e = mesh->AddFaceWithID(node[0], node[1], node[2], node[3],
154                                                node[4], node[5], node[6], node[7], ID);
155         else           e = mesh->AddFace      (node[0], node[1], node[2], node[3],
156                                                node[4], node[5], node[6], node[7] );
157       }
158     } else {
159       if ( ID >= 1 ) e = mesh->AddPolygonalFaceWithID(node, ID);
160       else           e = mesh->AddPolygonalFace      (node    );
161     }
162     break;
163
164   case SMDSAbs_Volume:
165     if ( !isPoly ) {
166       if      (nbnode == 4) {
167         if ( ID >= 1 ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3], ID);
168         else           e = mesh->AddVolume      (node[0], node[1], node[2], node[3] );
169       }
170       else if (nbnode == 5) {
171         if ( ID >= 1 ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
172                                                  node[4], ID);
173         else           e = mesh->AddVolume      (node[0], node[1], node[2], node[3],
174                                                  node[4] );
175       }
176       else if (nbnode == 6) {
177         if ( ID >= 1 ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
178                                                  node[4], node[5], ID);
179         else           e = mesh->AddVolume      (node[0], node[1], node[2], node[3],
180                                                  node[4], node[5] );
181       }
182       else if (nbnode == 8) {
183         if ( ID >= 1 ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
184                                                  node[4], node[5], node[6], node[7], ID);
185         else           e = mesh->AddVolume      (node[0], node[1], node[2], node[3],
186                                                  node[4], node[5], node[6], node[7] );
187       }
188       else if (nbnode == 10) {
189         if ( ID >= 1 ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
190                                                  node[4], node[5], node[6], node[7],
191                                                  node[8], node[9], ID);
192         else           e = mesh->AddVolume      (node[0], node[1], node[2], node[3],
193                                                  node[4], node[5], node[6], node[7],
194                                                  node[8], node[9] );
195       }
196       else if (nbnode == 13) {
197         if ( ID >= 1 ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
198                                                  node[4], node[5], node[6], node[7],
199                                                  node[8], node[9], node[10],node[11],
200                                                  node[12],ID);
201         else           e = mesh->AddVolume      (node[0], node[1], node[2], node[3],
202                                                  node[4], node[5], node[6], node[7],
203                                                  node[8], node[9], node[10],node[11],
204                                                  node[12] );
205       }
206       else if (nbnode == 15) {
207         if ( ID >= 1 ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
208                                                  node[4], node[5], node[6], node[7],
209                                                  node[8], node[9], node[10],node[11],
210                                                  node[12],node[13],node[14],ID);
211         else           e = mesh->AddVolume      (node[0], node[1], node[2], node[3],
212                                                  node[4], node[5], node[6], node[7],
213                                                  node[8], node[9], node[10],node[11],
214                                                  node[12],node[13],node[14] );
215       }
216       else if (nbnode == 20) {
217         if ( ID >= 1 ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
218                                                  node[4], node[5], node[6], node[7],
219                                                  node[8], node[9], node[10],node[11],
220                                                  node[12],node[13],node[14],node[15],
221                                                  node[16],node[17],node[18],node[19],ID);
222         else           e = mesh->AddVolume      (node[0], node[1], node[2], node[3],
223                                                  node[4], node[5], node[6], node[7],
224                                                  node[8], node[9], node[10],node[11],
225                                                  node[12],node[13],node[14],node[15],
226                                                  node[16],node[17],node[18],node[19] );
227       }
228     }
229     break;
230
231   case SMDSAbs_Edge:
232     if ( nbnode == 2 ) {
233       if ( ID >= 1 ) e = mesh->AddEdgeWithID(node[0], node[1], ID);
234       else           e = mesh->AddEdge      (node[0], node[1] );
235     }
236     else if ( nbnode == 3 ) {
237       if ( ID >= 1 ) e = mesh->AddEdgeWithID(node[0], node[1], node[2], ID);
238       else           e = mesh->AddEdge      (node[0], node[1], node[2] );
239     }
240     break;
241
242   case SMDSAbs_0DElement:
243     if ( nbnode == 1 ) {
244       if ( ID >= 1 ) e = mesh->Add0DElementWithID(node[0], ID);
245       else           e = mesh->Add0DElement      (node[0] );
246     }
247     break;
248
249   case SMDSAbs_Node:
250     if ( ID >= 1 ) e = mesh->AddNodeWithID(node[0]->X(), node[0]->Y(), node[0]->Z(), ID);
251     else           e = mesh->AddNode      (node[0]->X(), node[0]->Y(), node[0]->Z());
252     break;
253
254   default:;
255   }
256   if ( e ) myLastCreatedElems.Append( e );
257   return e;
258 }
259
260 //=======================================================================
261 /*!
262  * \brief Add element
263  */
264 //=======================================================================
265
266 SMDS_MeshElement* SMESH_MeshEditor::AddElement(const vector<int> &       nodeIDs,
267                                                const SMDSAbs_ElementType type,
268                                                const bool                isPoly,
269                                                const int                 ID)
270 {
271   vector<const SMDS_MeshNode*> nodes;
272   nodes.reserve( nodeIDs.size() );
273   vector<int>::const_iterator id = nodeIDs.begin();
274   while ( id != nodeIDs.end() ) {
275     if ( const SMDS_MeshNode* node = GetMeshDS()->FindNode( *id++ ))
276       nodes.push_back( node );
277     else
278       return 0;
279   }
280   return AddElement( nodes, type, isPoly, ID );
281 }
282
283 //=======================================================================
284 //function : Remove
285 //purpose  : Remove a node or an element.
286 //           Modify a compute state of sub-meshes which become empty
287 //=======================================================================
288
289 int SMESH_MeshEditor::Remove (const list< int >& theIDs,
290                               const bool         isNodes )
291 {
292   myLastCreatedElems.Clear();
293   myLastCreatedNodes.Clear();
294
295   SMESHDS_Mesh* aMesh = GetMeshDS();
296   set< SMESH_subMesh *> smmap;
297
298   int removed = 0;
299   list<int>::const_iterator it = theIDs.begin();
300   for ( ; it != theIDs.end(); it++ ) {
301     const SMDS_MeshElement * elem;
302     if ( isNodes )
303       elem = aMesh->FindNode( *it );
304     else
305       elem = aMesh->FindElement( *it );
306     if ( !elem )
307       continue;
308
309     // Notify VERTEX sub-meshes about modification
310     if ( isNodes ) {
311       const SMDS_MeshNode* node = cast2Node( elem );
312       if ( node->GetPosition()->GetTypeOfPosition() == SMDS_TOP_VERTEX )
313         if ( int aShapeID = node->getshapeId() )
314           if ( SMESH_subMesh * sm = GetMesh()->GetSubMeshContaining( aShapeID ) )
315             smmap.insert( sm );
316     }
317     // Find sub-meshes to notify about modification
318     //     SMDS_ElemIteratorPtr nodeIt = elem->nodesIterator();
319     //     while ( nodeIt->more() ) {
320     //       const SMDS_MeshNode* node = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
321     //       const SMDS_PositionPtr& aPosition = node->GetPosition();
322     //       if ( aPosition.get() ) {
323     //         if ( int aShapeID = aPosition->GetShapeId() ) {
324     //           if ( SMESH_subMesh * sm = GetMesh()->GetSubMeshContaining( aShapeID ) )
325     //             smmap.insert( sm );
326     //         }
327     //       }
328     //     }
329
330     // Do remove
331     if ( isNodes )
332       aMesh->RemoveNode( static_cast< const SMDS_MeshNode* >( elem ));
333     else
334       aMesh->RemoveElement( elem );
335     removed++;
336   }
337
338   // Notify sub-meshes about modification
339   if ( !smmap.empty() ) {
340     set< SMESH_subMesh *>::iterator smIt;
341     for ( smIt = smmap.begin(); smIt != smmap.end(); smIt++ )
342       (*smIt)->ComputeStateEngine( SMESH_subMesh::MESH_ENTITY_REMOVED );
343   }
344
345   //   // Check if the whole mesh becomes empty
346   //   if ( SMESH_subMesh * sm = GetMesh()->GetSubMeshContaining( 1 ) )
347   //     sm->ComputeStateEngine( SMESH_subMesh::CHECK_COMPUTE_STATE );
348
349   return removed;
350 }
351
352 //=======================================================================
353 //function : FindShape
354 //purpose  : Return an index of the shape theElem is on
355 //           or zero if a shape not found
356 //=======================================================================
357
358 int SMESH_MeshEditor::FindShape (const SMDS_MeshElement * theElem)
359 {
360   myLastCreatedElems.Clear();
361   myLastCreatedNodes.Clear();
362
363   SMESHDS_Mesh * aMesh = GetMeshDS();
364   if ( aMesh->ShapeToMesh().IsNull() )
365     return 0;
366
367   if ( theElem->GetType() == SMDSAbs_Node )
368     {
369       int aShapeID = theElem->getshapeId();
370       if (aShapeID <= 0)
371         return 0;
372       else
373         return aShapeID;
374     }
375
376   TopoDS_Shape aShape; // the shape a node is on
377   SMDS_ElemIteratorPtr nodeIt = theElem->nodesIterator();
378   while ( nodeIt->more() ) {
379     const SMDS_MeshNode* node = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
380     int aShapeID = node->getshapeId();
381     if (aShapeID > 0) {
382       SMESHDS_SubMesh * sm = aMesh->MeshElements( aShapeID );
383       if ( sm ) {
384         if ( sm->Contains( theElem ))
385           return aShapeID;
386         if ( aShape.IsNull() )
387           aShape = aMesh->IndexToShape( aShapeID );
388       }
389       else {
390         //MESSAGE ( "::FindShape() No SubShape for aShapeID " << aShapeID );
391       }
392     }
393   }
394
395   // None of nodes is on a proper shape,
396   // find the shape among ancestors of aShape on which a node is
397   if ( aShape.IsNull() ) {
398     //MESSAGE ("::FindShape() - NONE node is on shape")
399     return 0;
400   }
401   TopTools_ListIteratorOfListOfShape ancIt( GetMesh()->GetAncestors( aShape ));
402   for ( ; ancIt.More(); ancIt.Next() ) {
403     SMESHDS_SubMesh * sm = aMesh->MeshElements( ancIt.Value() );
404     if ( sm && sm->Contains( theElem ))
405       return aMesh->ShapeToIndex( ancIt.Value() );
406   }
407
408   //MESSAGE ("::FindShape() - SHAPE NOT FOUND")
409   return 0;
410 }
411
412 //=======================================================================
413 //function : IsMedium
414 //purpose  :
415 //=======================================================================
416
417 bool SMESH_MeshEditor::IsMedium(const SMDS_MeshNode*      node,
418                                 const SMDSAbs_ElementType typeToCheck)
419 {
420   bool isMedium = false;
421   SMDS_ElemIteratorPtr it = node->GetInverseElementIterator(typeToCheck);
422   while (it->more() && !isMedium ) {
423     const SMDS_MeshElement* elem = it->next();
424     isMedium = elem->IsMediumNode(node);
425   }
426   return isMedium;
427 }
428
429 //=======================================================================
430 //function : ShiftNodesQuadTria
431 //purpose  : auxilary
432 //           Shift nodes in the array corresponded to quadratic triangle
433 //           example: (0,1,2,3,4,5) -> (1,2,0,4,5,3)
434 //=======================================================================
435 static void ShiftNodesQuadTria(const SMDS_MeshNode* aNodes[])
436 {
437   const SMDS_MeshNode* nd1 = aNodes[0];
438   aNodes[0] = aNodes[1];
439   aNodes[1] = aNodes[2];
440   aNodes[2] = nd1;
441   const SMDS_MeshNode* nd2 = aNodes[3];
442   aNodes[3] = aNodes[4];
443   aNodes[4] = aNodes[5];
444   aNodes[5] = nd2;
445 }
446
447 //=======================================================================
448 //function : GetNodesFromTwoTria
449 //purpose  : auxilary
450 //           Shift nodes in the array corresponded to quadratic triangle
451 //           example: (0,1,2,3,4,5) -> (1,2,0,4,5,3)
452 //=======================================================================
453 static bool GetNodesFromTwoTria(const SMDS_MeshElement * theTria1,
454                                 const SMDS_MeshElement * theTria2,
455                                 const SMDS_MeshNode* N1[],
456                                 const SMDS_MeshNode* N2[])
457 {
458   SMDS_ElemIteratorPtr it = theTria1->nodesIterator();
459   int i=0;
460   while(i<6) {
461     N1[i] = static_cast<const SMDS_MeshNode*>( it->next() );
462     i++;
463   }
464   if(it->more()) return false;
465   it = theTria2->nodesIterator();
466   i=0;
467   while(i<6) {
468     N2[i] = static_cast<const SMDS_MeshNode*>( it->next() );
469     i++;
470   }
471   if(it->more()) return false;
472
473   int sames[3] = {-1,-1,-1};
474   int nbsames = 0;
475   int j;
476   for(i=0; i<3; i++) {
477     for(j=0; j<3; j++) {
478       if(N1[i]==N2[j]) {
479         sames[i] = j;
480         nbsames++;
481         break;
482       }
483     }
484   }
485   if(nbsames!=2) return false;
486   if(sames[0]>-1) {
487     ShiftNodesQuadTria(N1);
488     if(sames[1]>-1) {
489       ShiftNodesQuadTria(N1);
490     }
491   }
492   i = sames[0] + sames[1] + sames[2];
493   for(; i<2; i++) {
494     ShiftNodesQuadTria(N2);
495   }
496   // now we receive following N1 and N2 (using numeration as above image)
497   // tria1 : (1 2 4 5 9 7)  and  tria2 : (3 4 2 8 9 6)
498   // i.e. first nodes from both arrays determ new diagonal
499   return true;
500 }
501
502 //=======================================================================
503 //function : InverseDiag
504 //purpose  : Replace two neighbour triangles with ones built on the same 4 nodes
505 //           but having other common link.
506 //           Return False if args are improper
507 //=======================================================================
508
509 bool SMESH_MeshEditor::InverseDiag (const SMDS_MeshElement * theTria1,
510                                     const SMDS_MeshElement * theTria2 )
511 {
512   MESSAGE("InverseDiag");
513   myLastCreatedElems.Clear();
514   myLastCreatedNodes.Clear();
515
516   if (!theTria1 || !theTria2)
517     return false;
518
519   const SMDS_VtkFace* F1 = dynamic_cast<const SMDS_VtkFace*>( theTria1 );
520   if (!F1) return false;
521   const SMDS_VtkFace* F2 = dynamic_cast<const SMDS_VtkFace*>( theTria2 );
522   if (!F2) return false;
523   if ((theTria1->GetEntityType() == SMDSEntity_Triangle) &&
524       (theTria2->GetEntityType() == SMDSEntity_Triangle)) {
525
526     //  1 +--+ A  theTria1: ( 1 A B ) A->2 ( 1 2 B ) 1 +--+ A
527     //    | /|    theTria2: ( B A 2 ) B->1 ( 1 A 2 )   |\ |
528     //    |/ |                                         | \|
529     //  B +--+ 2                                     B +--+ 2
530
531     // put nodes in array and find out indices of the same ones
532     const SMDS_MeshNode* aNodes [6];
533     int sameInd [] = { 0, 0, 0, 0, 0, 0 };
534     int i = 0;
535     SMDS_ElemIteratorPtr it = theTria1->nodesIterator();
536     while ( it->more() ) {
537       aNodes[ i ] = static_cast<const SMDS_MeshNode*>( it->next() );
538
539       if ( i > 2 ) // theTria2
540         // find same node of theTria1
541         for ( int j = 0; j < 3; j++ )
542           if ( aNodes[ i ] == aNodes[ j ]) {
543             sameInd[ j ] = i;
544             sameInd[ i ] = j;
545             break;
546           }
547       // next
548       i++;
549       if ( i == 3 ) {
550         if ( it->more() )
551           return false; // theTria1 is not a triangle
552         it = theTria2->nodesIterator();
553       }
554       if ( i == 6 && it->more() )
555         return false; // theTria2 is not a triangle
556     }
557
558     // find indices of 1,2 and of A,B in theTria1
559     int iA = 0, iB = 0, i1 = 0, i2 = 0;
560     for ( i = 0; i < 6; i++ ) {
561       if ( sameInd [ i ] == 0 ) {
562         if ( i < 3 ) i1 = i;
563         else         i2 = i;
564       }
565       else if (i < 3) {
566         if ( iA ) iB = i;
567         else      iA = i;
568       }
569     }
570     // nodes 1 and 2 should not be the same
571     if ( aNodes[ i1 ] == aNodes[ i2 ] )
572       return false;
573
574     // theTria1: A->2
575     aNodes[ iA ] = aNodes[ i2 ];
576     // theTria2: B->1
577     aNodes[ sameInd[ iB ]] = aNodes[ i1 ];
578
579     GetMeshDS()->ChangeElementNodes( theTria1, aNodes, 3 );
580     GetMeshDS()->ChangeElementNodes( theTria2, &aNodes[ 3 ], 3 );
581
582     return true;
583
584   } // end if(F1 && F2)
585
586   // check case of quadratic faces
587   if (theTria1->GetEntityType() != SMDSEntity_Quad_Triangle)
588     return false;
589   if (theTria2->GetEntityType() != SMDSEntity_Quad_Triangle)
590     return false;
591
592   //       5
593   //  1 +--+--+ 2  theTria1: (1 2 4 5 9 7) or (2 4 1 9 7 5) or (4 1 2 7 5 9)
594   //    |    /|    theTria2: (2 3 4 6 8 9) or (3 4 2 8 9 6) or (4 2 3 9 6 8)
595   //    |   / |
596   //  7 +  +  + 6
597   //    | /9  |
598   //    |/    |
599   //  4 +--+--+ 3
600   //       8
601
602   const SMDS_MeshNode* N1 [6];
603   const SMDS_MeshNode* N2 [6];
604   if(!GetNodesFromTwoTria(theTria1,theTria2,N1,N2))
605     return false;
606   // now we receive following N1 and N2 (using numeration as above image)
607   // tria1 : (1 2 4 5 9 7)  and  tria2 : (3 4 2 8 9 6)
608   // i.e. first nodes from both arrays determ new diagonal
609
610   const SMDS_MeshNode* N1new [6];
611   const SMDS_MeshNode* N2new [6];
612   N1new[0] = N1[0];
613   N1new[1] = N2[0];
614   N1new[2] = N2[1];
615   N1new[3] = N1[4];
616   N1new[4] = N2[3];
617   N1new[5] = N1[5];
618   N2new[0] = N1[0];
619   N2new[1] = N1[1];
620   N2new[2] = N2[0];
621   N2new[3] = N1[3];
622   N2new[4] = N2[5];
623   N2new[5] = N1[4];
624   // replaces nodes in faces
625   GetMeshDS()->ChangeElementNodes( theTria1, N1new, 6 );
626   GetMeshDS()->ChangeElementNodes( theTria2, N2new, 6 );
627
628   return true;
629 }
630
631 //=======================================================================
632 //function : findTriangles
633 //purpose  : find triangles sharing theNode1-theNode2 link
634 //=======================================================================
635
636 static bool findTriangles(const SMDS_MeshNode *    theNode1,
637                           const SMDS_MeshNode *    theNode2,
638                           const SMDS_MeshElement*& theTria1,
639                           const SMDS_MeshElement*& theTria2)
640 {
641   if ( !theNode1 || !theNode2 ) return false;
642
643   theTria1 = theTria2 = 0;
644
645   set< const SMDS_MeshElement* > emap;
646   SMDS_ElemIteratorPtr it = theNode1->GetInverseElementIterator(SMDSAbs_Face);
647   while (it->more()) {
648     const SMDS_MeshElement* elem = it->next();
649     if ( elem->NbNodes() == 3 )
650       emap.insert( elem );
651   }
652   it = theNode2->GetInverseElementIterator(SMDSAbs_Face);
653   while (it->more()) {
654     const SMDS_MeshElement* elem = it->next();
655     if ( emap.find( elem ) != emap.end() ) {
656       if ( theTria1 ) {
657         // theTria1 must be element with minimum ID
658         if( theTria1->GetID() < elem->GetID() ) {
659           theTria2 = elem;
660         }
661         else {
662           theTria2 = theTria1;
663           theTria1 = elem;
664         }
665         break;
666       }
667       else {
668         theTria1 = elem;
669       }
670     }
671   }
672   return ( theTria1 && theTria2 );
673 }
674
675 //=======================================================================
676 //function : InverseDiag
677 //purpose  : Replace two neighbour triangles sharing theNode1-theNode2 link
678 //           with ones built on the same 4 nodes but having other common link.
679 //           Return false if proper faces not found
680 //=======================================================================
681
682 bool SMESH_MeshEditor::InverseDiag (const SMDS_MeshNode * theNode1,
683                                     const SMDS_MeshNode * theNode2)
684 {
685   myLastCreatedElems.Clear();
686   myLastCreatedNodes.Clear();
687
688   MESSAGE( "::InverseDiag()" );
689
690   const SMDS_MeshElement *tr1, *tr2;
691   if ( !findTriangles( theNode1, theNode2, tr1, tr2 ))
692     return false;
693
694   const SMDS_VtkFace* F1 = dynamic_cast<const SMDS_VtkFace*>( tr1 );
695   if (!F1) return false;
696   const SMDS_VtkFace* F2 = dynamic_cast<const SMDS_VtkFace*>( tr2 );
697   if (!F2) return false;
698   if ((tr1->GetEntityType() == SMDSEntity_Triangle) &&
699       (tr2->GetEntityType() == SMDSEntity_Triangle)) {
700
701     //  1 +--+ A  tr1: ( 1 A B ) A->2 ( 1 2 B ) 1 +--+ A
702     //    | /|    tr2: ( B A 2 ) B->1 ( 1 A 2 )   |\ |
703     //    |/ |                                    | \|
704     //  B +--+ 2                                B +--+ 2
705
706     // put nodes in array
707     // and find indices of 1,2 and of A in tr1 and of B in tr2
708     int i, iA1 = 0, i1 = 0;
709     const SMDS_MeshNode* aNodes1 [3];
710     SMDS_ElemIteratorPtr it;
711     for (i = 0, it = tr1->nodesIterator(); it->more(); i++ ) {
712       aNodes1[ i ] = static_cast<const SMDS_MeshNode*>( it->next() );
713       if ( aNodes1[ i ] == theNode1 )
714         iA1 = i; // node A in tr1
715       else if ( aNodes1[ i ] != theNode2 )
716         i1 = i;  // node 1
717     }
718     int iB2 = 0, i2 = 0;
719     const SMDS_MeshNode* aNodes2 [3];
720     for (i = 0, it = tr2->nodesIterator(); it->more(); i++ ) {
721       aNodes2[ i ] = static_cast<const SMDS_MeshNode*>( it->next() );
722       if ( aNodes2[ i ] == theNode2 )
723         iB2 = i; // node B in tr2
724       else if ( aNodes2[ i ] != theNode1 )
725         i2 = i;  // node 2
726     }
727
728     // nodes 1 and 2 should not be the same
729     if ( aNodes1[ i1 ] == aNodes2[ i2 ] )
730       return false;
731
732     // tr1: A->2
733     aNodes1[ iA1 ] = aNodes2[ i2 ];
734     // tr2: B->1
735     aNodes2[ iB2 ] = aNodes1[ i1 ];
736
737     GetMeshDS()->ChangeElementNodes( tr1, aNodes1, 3 );
738     GetMeshDS()->ChangeElementNodes( tr2, aNodes2, 3 );
739
740     return true;
741   }
742
743   // check case of quadratic faces
744   return InverseDiag(tr1,tr2);
745 }
746
747 //=======================================================================
748 //function : getQuadrangleNodes
749 //purpose  : fill theQuadNodes - nodes of a quadrangle resulting from
750 //           fusion of triangles tr1 and tr2 having shared link on
751 //           theNode1 and theNode2
752 //=======================================================================
753
754 bool getQuadrangleNodes(const SMDS_MeshNode *    theQuadNodes [],
755                         const SMDS_MeshNode *    theNode1,
756                         const SMDS_MeshNode *    theNode2,
757                         const SMDS_MeshElement * tr1,
758                         const SMDS_MeshElement * tr2 )
759 {
760   if( tr1->NbNodes() != tr2->NbNodes() )
761     return false;
762   // find the 4-th node to insert into tr1
763   const SMDS_MeshNode* n4 = 0;
764   SMDS_ElemIteratorPtr it = tr2->nodesIterator();
765   int i=0;
766   while ( !n4 && i<3 ) {
767     const SMDS_MeshNode * n = cast2Node( it->next() );
768     i++;
769     bool isDiag = ( n == theNode1 || n == theNode2 );
770     if ( !isDiag )
771       n4 = n;
772   }
773   // Make an array of nodes to be in a quadrangle
774   int iNode = 0, iFirstDiag = -1;
775   it = tr1->nodesIterator();
776   i=0;
777   while ( i<3 ) {
778     const SMDS_MeshNode * n = cast2Node( it->next() );
779     i++;
780     bool isDiag = ( n == theNode1 || n == theNode2 );
781     if ( isDiag ) {
782       if ( iFirstDiag < 0 )
783         iFirstDiag = iNode;
784       else if ( iNode - iFirstDiag == 1 )
785         theQuadNodes[ iNode++ ] = n4; // insert the 4-th node between diagonal nodes
786     }
787     else if ( n == n4 ) {
788       return false; // tr1 and tr2 should not have all the same nodes
789     }
790     theQuadNodes[ iNode++ ] = n;
791   }
792   if ( iNode == 3 ) // diagonal nodes have 0 and 2 indices
793     theQuadNodes[ iNode ] = n4;
794
795   return true;
796 }
797
798 //=======================================================================
799 //function : DeleteDiag
800 //purpose  : Replace two neighbour triangles sharing theNode1-theNode2 link
801 //           with a quadrangle built on the same 4 nodes.
802 //           Return false if proper faces not found
803 //=======================================================================
804
805 bool SMESH_MeshEditor::DeleteDiag (const SMDS_MeshNode * theNode1,
806                                    const SMDS_MeshNode * theNode2)
807 {
808   myLastCreatedElems.Clear();
809   myLastCreatedNodes.Clear();
810
811   MESSAGE( "::DeleteDiag()" );
812
813   const SMDS_MeshElement *tr1, *tr2;
814   if ( !findTriangles( theNode1, theNode2, tr1, tr2 ))
815     return false;
816
817   const SMDS_VtkFace* F1 = dynamic_cast<const SMDS_VtkFace*>( tr1 );
818   if (!F1) return false;
819   const SMDS_VtkFace* F2 = dynamic_cast<const SMDS_VtkFace*>( tr2 );
820   if (!F2) return false;
821   SMESHDS_Mesh * aMesh = GetMeshDS();
822
823   if ((tr1->GetEntityType() == SMDSEntity_Triangle) &&
824       (tr2->GetEntityType() == SMDSEntity_Triangle)) {
825
826     const SMDS_MeshNode* aNodes [ 4 ];
827     if ( ! getQuadrangleNodes( aNodes, theNode1, theNode2, tr1, tr2 ))
828       return false;
829
830     const SMDS_MeshElement* newElem = 0;
831     newElem = aMesh->AddFace( aNodes[0], aNodes[1], aNodes[2], aNodes[3] );
832     myLastCreatedElems.Append(newElem);
833     AddToSameGroups( newElem, tr1, aMesh );
834     int aShapeId = tr1->getshapeId();
835     if ( aShapeId )
836       {
837         aMesh->SetMeshElementOnShape( newElem, aShapeId );
838       }
839     aMesh->RemoveElement( tr1 );
840     aMesh->RemoveElement( tr2 );
841
842     return true;
843   }
844
845   // check case of quadratic faces
846   if (tr1->GetEntityType() != SMDSEntity_Quad_Triangle)
847     return false;
848   if (tr2->GetEntityType() != SMDSEntity_Quad_Triangle)
849     return false;
850
851   //       5
852   //  1 +--+--+ 2  tr1: (1 2 4 5 9 7) or (2 4 1 9 7 5) or (4 1 2 7 5 9)
853   //    |    /|    tr2: (2 3 4 6 8 9) or (3 4 2 8 9 6) or (4 2 3 9 6 8)
854   //    |   / |
855   //  7 +  +  + 6
856   //    | /9  |
857   //    |/    |
858   //  4 +--+--+ 3
859   //       8
860
861   const SMDS_MeshNode* N1 [6];
862   const SMDS_MeshNode* N2 [6];
863   if(!GetNodesFromTwoTria(tr1,tr2,N1,N2))
864     return false;
865   // now we receive following N1 and N2 (using numeration as above image)
866   // tria1 : (1 2 4 5 9 7)  and  tria2 : (3 4 2 8 9 6)
867   // i.e. first nodes from both arrays determ new diagonal
868
869   const SMDS_MeshNode* aNodes[8];
870   aNodes[0] = N1[0];
871   aNodes[1] = N1[1];
872   aNodes[2] = N2[0];
873   aNodes[3] = N2[1];
874   aNodes[4] = N1[3];
875   aNodes[5] = N2[5];
876   aNodes[6] = N2[3];
877   aNodes[7] = N1[5];
878
879   const SMDS_MeshElement* newElem = 0;
880   newElem = aMesh->AddFace( aNodes[0], aNodes[1], aNodes[2], aNodes[3],
881                             aNodes[4], aNodes[5], aNodes[6], aNodes[7]);
882   myLastCreatedElems.Append(newElem);
883   AddToSameGroups( newElem, tr1, aMesh );
884   int aShapeId = tr1->getshapeId();
885   if ( aShapeId )
886     {
887       aMesh->SetMeshElementOnShape( newElem, aShapeId );
888     }
889   aMesh->RemoveElement( tr1 );
890   aMesh->RemoveElement( tr2 );
891
892   // remove middle node (9)
893   GetMeshDS()->RemoveNode( N1[4] );
894
895   return true;
896 }
897
898 //=======================================================================
899 //function : Reorient
900 //purpose  : Reverse theElement orientation
901 //=======================================================================
902
903 bool SMESH_MeshEditor::Reorient (const SMDS_MeshElement * theElem)
904 {
905   MESSAGE("Reorient");
906   myLastCreatedElems.Clear();
907   myLastCreatedNodes.Clear();
908
909   if (!theElem)
910     return false;
911   SMDS_ElemIteratorPtr it = theElem->nodesIterator();
912   if ( !it || !it->more() )
913     return false;
914
915   switch ( theElem->GetType() ) {
916
917   case SMDSAbs_Edge:
918   case SMDSAbs_Face: {
919     if(!theElem->IsQuadratic()) {
920       int i = theElem->NbNodes();
921       vector<const SMDS_MeshNode*> aNodes( i );
922       while ( it->more() )
923         aNodes[ --i ]= static_cast<const SMDS_MeshNode*>( it->next() );
924       return GetMeshDS()->ChangeElementNodes( theElem, &aNodes[0], theElem->NbNodes() );
925     }
926     else {
927       // quadratic elements
928       if(theElem->GetType()==SMDSAbs_Edge) {
929         vector<const SMDS_MeshNode*> aNodes(3);
930         aNodes[1]= static_cast<const SMDS_MeshNode*>( it->next() );
931         aNodes[0]= static_cast<const SMDS_MeshNode*>( it->next() );
932         aNodes[2]= static_cast<const SMDS_MeshNode*>( it->next() );
933         return GetMeshDS()->ChangeElementNodes( theElem, &aNodes[0], 3 );
934       }
935       else {
936         int nbn = theElem->NbNodes();
937         vector<const SMDS_MeshNode*> aNodes(nbn);
938         aNodes[0]= static_cast<const SMDS_MeshNode*>( it->next() );
939         int i=1;
940         for(; i<nbn/2; i++) {
941           aNodes[nbn/2-i]= static_cast<const SMDS_MeshNode*>( it->next() );
942         }
943         for(i=0; i<nbn/2; i++) {
944           aNodes[nbn-i-1]= static_cast<const SMDS_MeshNode*>( it->next() );
945         }
946         return GetMeshDS()->ChangeElementNodes( theElem, &aNodes[0], nbn );
947       }
948     }
949   }
950   case SMDSAbs_Volume: {
951     if (theElem->IsPoly()) {
952       // TODO reorient vtk polyhedron
953       MESSAGE("reorient vtk polyhedron ?");
954       const SMDS_VtkVolume* aPolyedre =
955         dynamic_cast<const SMDS_VtkVolume*>( theElem );
956       if (!aPolyedre) {
957         MESSAGE("Warning: bad volumic element");
958         return false;
959       }
960
961       int nbFaces = aPolyedre->NbFaces();
962       vector<const SMDS_MeshNode *> poly_nodes;
963       vector<int> quantities (nbFaces);
964
965       // reverse each face of the polyedre
966       for (int iface = 1; iface <= nbFaces; iface++) {
967         int inode, nbFaceNodes = aPolyedre->NbFaceNodes(iface);
968         quantities[iface - 1] = nbFaceNodes;
969
970         for (inode = nbFaceNodes; inode >= 1; inode--) {
971           const SMDS_MeshNode* curNode = aPolyedre->GetFaceNode(iface, inode);
972           poly_nodes.push_back(curNode);
973         }
974       }
975
976       return GetMeshDS()->ChangePolyhedronNodes( theElem, poly_nodes, quantities );
977
978     }
979     else {
980       SMDS_VolumeTool vTool;
981       if ( !vTool.Set( theElem ))
982         return false;
983       vTool.Inverse();
984       MESSAGE("ChangeElementNodes reorient: check vTool.Inverse");
985       return GetMeshDS()->ChangeElementNodes( theElem, vTool.GetNodes(), vTool.NbNodes() );
986     }
987   }
988   default:;
989   }
990
991   return false;
992 }
993
994 //=======================================================================
995 //function : getBadRate
996 //purpose  :
997 //=======================================================================
998
999 static double getBadRate (const SMDS_MeshElement*               theElem,
1000                           SMESH::Controls::NumericalFunctorPtr& theCrit)
1001 {
1002   SMESH::Controls::TSequenceOfXYZ P;
1003   if ( !theElem || !theCrit->GetPoints( theElem, P ))
1004     return 1e100;
1005   return theCrit->GetBadRate( theCrit->GetValue( P ), theElem->NbNodes() );
1006   //return theCrit->GetBadRate( theCrit->GetValue( theElem->GetID() ), theElem->NbNodes() );
1007 }
1008
1009 //=======================================================================
1010 //function : QuadToTri
1011 //purpose  : Cut quadrangles into triangles.
1012 //           theCrit is used to select a diagonal to cut
1013 //=======================================================================
1014
1015 bool SMESH_MeshEditor::QuadToTri (TIDSortedElemSet &                   theElems,
1016                                   SMESH::Controls::NumericalFunctorPtr theCrit)
1017 {
1018   myLastCreatedElems.Clear();
1019   myLastCreatedNodes.Clear();
1020
1021   MESSAGE( "::QuadToTri()" );
1022
1023   if ( !theCrit.get() )
1024     return false;
1025
1026   SMESHDS_Mesh * aMesh = GetMeshDS();
1027
1028   Handle(Geom_Surface) surface;
1029   SMESH_MesherHelper   helper( *GetMesh() );
1030
1031   TIDSortedElemSet::iterator itElem;
1032   for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
1033     const SMDS_MeshElement* elem = *itElem;
1034     if ( !elem || elem->GetType() != SMDSAbs_Face )
1035       continue;
1036     if ( elem->NbNodes() != ( elem->IsQuadratic() ? 8 : 4 ))
1037       continue;
1038
1039     // retrieve element nodes
1040     const SMDS_MeshNode* aNodes [8];
1041     SMDS_ElemIteratorPtr itN = elem->nodesIterator();
1042     int i = 0;
1043     while ( itN->more() )
1044       aNodes[ i++ ] = static_cast<const SMDS_MeshNode*>( itN->next() );
1045
1046     // compare two sets of possible triangles
1047     double aBadRate1, aBadRate2; // to what extent a set is bad
1048     SMDS_FaceOfNodes tr1 ( aNodes[0], aNodes[1], aNodes[2] );
1049     SMDS_FaceOfNodes tr2 ( aNodes[2], aNodes[3], aNodes[0] );
1050     aBadRate1 = getBadRate( &tr1, theCrit ) + getBadRate( &tr2, theCrit );
1051
1052     SMDS_FaceOfNodes tr3 ( aNodes[1], aNodes[2], aNodes[3] );
1053     SMDS_FaceOfNodes tr4 ( aNodes[3], aNodes[0], aNodes[1] );
1054     aBadRate2 = getBadRate( &tr3, theCrit ) + getBadRate( &tr4, theCrit );
1055
1056     int aShapeId = FindShape( elem );
1057     const SMDS_MeshElement* newElem1 = 0;
1058     const SMDS_MeshElement* newElem2 = 0;
1059
1060     if( !elem->IsQuadratic() ) {
1061
1062       // split liner quadrangle
1063       if ( aBadRate1 <= aBadRate2 ) {
1064         // tr1 + tr2 is better
1065         newElem1 = aMesh->AddFace( aNodes[2], aNodes[3], aNodes[0] );
1066         newElem2 = aMesh->AddFace( aNodes[2], aNodes[0], aNodes[1] );
1067       }
1068       else {
1069         // tr3 + tr4 is better
1070         newElem1 = aMesh->AddFace( aNodes[3], aNodes[0], aNodes[1] );
1071         newElem2 = aMesh->AddFace( aNodes[3], aNodes[1], aNodes[2] );
1072       }
1073     }
1074     else {
1075
1076       // split quadratic quadrangle
1077
1078       // get surface elem is on
1079       if ( aShapeId != helper.GetSubShapeID() ) {
1080         surface.Nullify();
1081         TopoDS_Shape shape;
1082         if ( aShapeId > 0 )
1083           shape = aMesh->IndexToShape( aShapeId );
1084         if ( !shape.IsNull() && shape.ShapeType() == TopAbs_FACE ) {
1085           TopoDS_Face face = TopoDS::Face( shape );
1086           surface = BRep_Tool::Surface( face );
1087           if ( !surface.IsNull() )
1088             helper.SetSubShape( shape );
1089         }
1090       }
1091       // get elem nodes
1092       const SMDS_MeshNode* aNodes [8];
1093       const SMDS_MeshNode* inFaceNode = 0;
1094       SMDS_ElemIteratorPtr itN = elem->nodesIterator();
1095       int i = 0;
1096       while ( itN->more() ) {
1097         aNodes[ i++ ] = static_cast<const SMDS_MeshNode*>( itN->next() );
1098         if ( !inFaceNode && helper.GetNodeUVneedInFaceNode() &&
1099              aNodes[ i-1 ]->GetPosition()->GetTypeOfPosition() == SMDS_TOP_FACE )
1100         {
1101           inFaceNode = aNodes[ i-1 ];
1102         }
1103       }
1104       // find middle point for (0,1,2,3)
1105       // and create a node in this point;
1106       gp_XYZ p( 0,0,0 );
1107       if ( surface.IsNull() ) {
1108         for(i=0; i<4; i++)
1109           p += gp_XYZ(aNodes[i]->X(), aNodes[i]->Y(), aNodes[i]->Z() );
1110         p /= 4;
1111       }
1112       else {
1113         TopoDS_Face face = TopoDS::Face( helper.GetSubShape() );
1114         gp_XY uv( 0,0 );
1115         for(i=0; i<4; i++)
1116           uv += helper.GetNodeUV( face, aNodes[i], inFaceNode );
1117         uv /= 4.;
1118         p = surface->Value( uv.X(), uv.Y() ).XYZ();
1119       }
1120       const SMDS_MeshNode* newN = aMesh->AddNode( p.X(), p.Y(), p.Z() );
1121       myLastCreatedNodes.Append(newN);
1122
1123       // create a new element
1124       const SMDS_MeshNode* N[6];
1125       if ( aBadRate1 <= aBadRate2 ) {
1126         N[0] = aNodes[0];
1127         N[1] = aNodes[1];
1128         N[2] = aNodes[2];
1129         N[3] = aNodes[4];
1130         N[4] = aNodes[5];
1131         N[5] = newN;
1132         newElem1 = aMesh->AddFace(aNodes[2], aNodes[3], aNodes[0],
1133                                   aNodes[6], aNodes[7], newN );
1134         newElem2 = aMesh->AddFace(aNodes[2], aNodes[0], aNodes[1],
1135                                   newN,      aNodes[4], aNodes[5] );
1136       }
1137       else {
1138         N[0] = aNodes[1];
1139         N[1] = aNodes[2];
1140         N[2] = aNodes[3];
1141         N[3] = aNodes[5];
1142         N[4] = aNodes[6];
1143         N[5] = newN;
1144         newElem1 = aMesh->AddFace(aNodes[3], aNodes[0], aNodes[1],
1145                                   aNodes[7], aNodes[4], newN );
1146         newElem2 = aMesh->AddFace(aNodes[3], aNodes[1], aNodes[2],
1147                                   newN,      aNodes[5], aNodes[6] );
1148       }
1149     } // quadratic case
1150
1151     // care of a new element
1152
1153     myLastCreatedElems.Append(newElem1);
1154     myLastCreatedElems.Append(newElem2);
1155     AddToSameGroups( newElem1, elem, aMesh );
1156     AddToSameGroups( newElem2, elem, aMesh );
1157
1158     // put a new triangle on the same shape
1159     if ( aShapeId )
1160       {
1161         aMesh->SetMeshElementOnShape( newElem1, aShapeId );
1162         aMesh->SetMeshElementOnShape( newElem2, aShapeId );
1163       }
1164     aMesh->RemoveElement( elem );
1165   }
1166   return true;
1167 }
1168
1169 //=======================================================================
1170 //function : BestSplit
1171 //purpose  : Find better diagonal for cutting.
1172 //=======================================================================
1173
1174 int SMESH_MeshEditor::BestSplit (const SMDS_MeshElement*              theQuad,
1175                                  SMESH::Controls::NumericalFunctorPtr theCrit)
1176 {
1177   myLastCreatedElems.Clear();
1178   myLastCreatedNodes.Clear();
1179
1180   if (!theCrit.get())
1181     return -1;
1182
1183   if (!theQuad || theQuad->GetType() != SMDSAbs_Face )
1184     return -1;
1185
1186   if( theQuad->NbNodes()==4 ||
1187       (theQuad->NbNodes()==8 && theQuad->IsQuadratic()) ) {
1188
1189     // retrieve element nodes
1190     const SMDS_MeshNode* aNodes [4];
1191     SMDS_ElemIteratorPtr itN = theQuad->nodesIterator();
1192     int i = 0;
1193     //while (itN->more())
1194     while (i<4) {
1195       aNodes[ i++ ] = static_cast<const SMDS_MeshNode*>( itN->next() );
1196     }
1197     // compare two sets of possible triangles
1198     double aBadRate1, aBadRate2; // to what extent a set is bad
1199     SMDS_FaceOfNodes tr1 ( aNodes[0], aNodes[1], aNodes[2] );
1200     SMDS_FaceOfNodes tr2 ( aNodes[2], aNodes[3], aNodes[0] );
1201     aBadRate1 = getBadRate( &tr1, theCrit ) + getBadRate( &tr2, theCrit );
1202
1203     SMDS_FaceOfNodes tr3 ( aNodes[1], aNodes[2], aNodes[3] );
1204     SMDS_FaceOfNodes tr4 ( aNodes[3], aNodes[0], aNodes[1] );
1205     aBadRate2 = getBadRate( &tr3, theCrit ) + getBadRate( &tr4, theCrit );
1206
1207     if (aBadRate1 <= aBadRate2) // tr1 + tr2 is better
1208       return 1; // diagonal 1-3
1209
1210     return 2; // diagonal 2-4
1211   }
1212   return -1;
1213 }
1214
1215 namespace
1216 {
1217   // Methods of splitting volumes into tetra
1218
1219   const int theHexTo5_1[5*4+1] =
1220     {
1221       0, 1, 2, 5,    0, 4, 5, 7,     0, 2, 3, 7,    2, 5, 6, 7,     0, 5, 2, 7,   -1
1222     };
1223   const int theHexTo5_2[5*4+1] =
1224     {
1225       1, 2, 3, 6,    1, 4, 5, 6,     0, 1, 3, 4,    3, 4, 6, 7,     1, 3, 4, 6,   -1
1226     };
1227   const int* theHexTo5[2] = { theHexTo5_1, theHexTo5_2 };
1228
1229   const int theHexTo6_1[6*4+1] =
1230     {
1231       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
1232     };
1233   const int theHexTo6_2[6*4+1] =
1234     {
1235       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
1236     };
1237   const int theHexTo6_3[6*4+1] =
1238     {
1239       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
1240     };
1241   const int theHexTo6_4[6*4+1] =
1242     {
1243       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
1244     };
1245   const int* theHexTo6[4] = { theHexTo6_1, theHexTo6_2, theHexTo6_3, theHexTo6_4 };
1246
1247   const int thePyraTo2_1[2*4+1] =
1248     {
1249       0, 1, 2, 4,    0, 2, 3, 4,   -1
1250     };
1251   const int thePyraTo2_2[2*4+1] =
1252     {
1253       1, 2, 3, 4,    1, 3, 0, 4,   -1
1254     };
1255   const int* thePyraTo2[2] = { thePyraTo2_1, thePyraTo2_2 };
1256
1257   const int thePentaTo3_1[3*4+1] =
1258     {
1259       0, 1, 2, 3,    1, 3, 4, 2,     2, 3, 4, 5,    -1
1260     };
1261   const int thePentaTo3_2[3*4+1] =
1262     {
1263       1, 2, 0, 4,    2, 4, 5, 0,     0, 4, 5, 3,    -1
1264     };
1265   const int thePentaTo3_3[3*4+1] =
1266     {
1267       2, 0, 1, 5,    0, 5, 3, 1,     1, 5, 3, 4,    -1
1268     };
1269   const int thePentaTo3_4[3*4+1] =
1270     {
1271       0, 1, 2, 3,    1, 3, 4, 5,     2, 3, 1, 5,    -1
1272     };
1273   const int thePentaTo3_5[3*4+1] =
1274     {
1275       1, 2, 0, 4,    2, 4, 5, 3,     0, 4, 2, 3,    -1
1276     };
1277   const int thePentaTo3_6[3*4+1] =
1278     {
1279       2, 0, 1, 5,    0, 5, 3, 4,     1, 5, 0, 4,    -1
1280     };
1281   const int* thePentaTo3[6] = { thePentaTo3_1, thePentaTo3_2, thePentaTo3_3,
1282                                 thePentaTo3_4, thePentaTo3_5, thePentaTo3_6 };
1283
1284   struct TTriangleFacet //!< stores indices of three nodes of tetra facet
1285   {
1286     int _n1, _n2, _n3;
1287     TTriangleFacet(int n1, int n2, int n3): _n1(n1), _n2(n2), _n3(n3) {}
1288     bool contains(int n) const { return ( n == _n1 || n == _n2 || n == _n3 ); }
1289     bool hasAdjacentTetra( const SMDS_MeshElement* elem ) const;
1290   };
1291   struct TSplitMethod
1292   {
1293     int        _nbTetra;
1294     const int* _connectivity; //!< foursomes of tetra connectivy finished by -1
1295     bool       _baryNode;     //!< additional node is to be created at cell barycenter
1296     bool       _ownConn;      //!< to delete _connectivity in destructor
1297     map<int, const SMDS_MeshNode*> _faceBaryNode; //!< map face index to node at BC of face
1298
1299     TSplitMethod( int nbTet=0, const int* conn=0, bool addNode=false)
1300       : _nbTetra(nbTet), _connectivity(conn), _baryNode(addNode), _ownConn(false) {}
1301     ~TSplitMethod() { if ( _ownConn ) delete [] _connectivity; _connectivity = 0; }
1302     bool hasFacet( const TTriangleFacet& facet ) const
1303     {
1304       const int* tetConn = _connectivity;
1305       for ( ; tetConn[0] >= 0; tetConn += 4 )
1306         if (( facet.contains( tetConn[0] ) +
1307               facet.contains( tetConn[1] ) +
1308               facet.contains( tetConn[2] ) +
1309               facet.contains( tetConn[3] )) == 3 )
1310           return true;
1311       return false;
1312     }
1313   };
1314
1315   //=======================================================================
1316   /*!
1317    * \brief return TSplitMethod for the given element
1318    */
1319   //=======================================================================
1320
1321   TSplitMethod getSplitMethod( SMDS_VolumeTool& vol, const int theMethodFlags)
1322   {
1323     const int iQ = vol.Element()->IsQuadratic() ? 2 : 1;
1324
1325     // at HEXA_TO_24 method, each face of volume is split into triangles each based on
1326     // an edge and a face barycenter; tertaherdons are based on triangles and
1327     // a volume barycenter
1328     const bool is24TetMode = ( theMethodFlags == SMESH_MeshEditor::HEXA_TO_24 );
1329
1330     // Find out how adjacent volumes are split
1331
1332     vector < list< TTriangleFacet > > triaSplitsByFace( vol.NbFaces() ); // splits of each side
1333     int hasAdjacentSplits = 0, maxTetConnSize = 0;
1334     for ( int iF = 0; iF < vol.NbFaces(); ++iF )
1335     {
1336       int nbNodes = vol.NbFaceNodes( iF ) / iQ;
1337       maxTetConnSize += 4 * ( nbNodes - (is24TetMode ? 0 : 2));
1338       if ( nbNodes < 4 ) continue;
1339
1340       list< TTriangleFacet >& triaSplits = triaSplitsByFace[ iF ];
1341       const int* nInd = vol.GetFaceNodesIndices( iF );
1342       if ( nbNodes == 4 )
1343       {
1344         TTriangleFacet t012( nInd[0*iQ], nInd[1*iQ], nInd[2*iQ] );
1345         TTriangleFacet t123( nInd[1*iQ], nInd[2*iQ], nInd[3*iQ] );
1346         if      ( t012.hasAdjacentTetra( vol.Element() )) triaSplits.push_back( t012 );
1347         else if ( t123.hasAdjacentTetra( vol.Element() )) triaSplits.push_back( t123 );
1348       }
1349       else
1350       {
1351         int iCom = 0; // common node of triangle faces to split into
1352         for ( int iVar = 0; iVar < nbNodes; ++iVar, ++iCom )
1353         {
1354           TTriangleFacet t012( nInd[ iQ * ( iCom             )],
1355                                nInd[ iQ * ( (iCom+1)%nbNodes )],
1356                                nInd[ iQ * ( (iCom+2)%nbNodes )]);
1357           TTriangleFacet t023( nInd[ iQ * ( iCom             )],
1358                                nInd[ iQ * ( (iCom+2)%nbNodes )],
1359                                nInd[ iQ * ( (iCom+3)%nbNodes )]);
1360           if ( t012.hasAdjacentTetra( vol.Element() ) && t023.hasAdjacentTetra( vol.Element() ))
1361           {
1362             triaSplits.push_back( t012 );
1363             triaSplits.push_back( t023 );
1364             break;
1365           }
1366         }
1367       }
1368       if ( !triaSplits.empty() )
1369         hasAdjacentSplits = true;
1370     }
1371
1372     // Among variants of split method select one compliant with adjacent volumes
1373
1374     TSplitMethod method;
1375     if ( !vol.Element()->IsPoly() && !is24TetMode )
1376     {
1377       int nbVariants = 2, nbTet = 0;
1378       const int** connVariants = 0;
1379       switch ( vol.Element()->GetEntityType() )
1380       {
1381       case SMDSEntity_Hexa:
1382       case SMDSEntity_Quad_Hexa:
1383         if ( theMethodFlags == SMESH_MeshEditor::HEXA_TO_5 )
1384           connVariants = theHexTo5, nbTet = 5;
1385         else
1386           connVariants = theHexTo6, nbTet = 6, nbVariants = 4;
1387         break;
1388       case SMDSEntity_Pyramid:
1389       case SMDSEntity_Quad_Pyramid:
1390         connVariants = thePyraTo2;  nbTet = 2;
1391         break;
1392       case SMDSEntity_Penta:
1393       case SMDSEntity_Quad_Penta:
1394         connVariants = thePentaTo3; nbTet = 3; nbVariants = 6;
1395         break;
1396       default:
1397         nbVariants = 0;
1398       }
1399       for ( int variant = 0; variant < nbVariants && method._nbTetra == 0; ++variant )
1400       {
1401         // check method compliancy with adjacent tetras,
1402         // all found splits must be among facets of tetras described by this method
1403         method = TSplitMethod( nbTet, connVariants[variant] );
1404         if ( hasAdjacentSplits && method._nbTetra > 0 )
1405         {
1406           bool facetCreated = true;
1407           for ( int iF = 0; facetCreated && iF < triaSplitsByFace.size(); ++iF )
1408           {
1409             list< TTriangleFacet >::const_iterator facet = triaSplitsByFace[iF].begin();
1410             for ( ; facetCreated && facet != triaSplitsByFace[iF].end(); ++facet )
1411               facetCreated = method.hasFacet( *facet );
1412           }
1413           if ( !facetCreated )
1414             method = TSplitMethod(0); // incompatible method
1415         }
1416       }
1417     }
1418     if ( method._nbTetra < 1 )
1419     {
1420       // No standard method is applicable, use a generic solution:
1421       // each facet of a volume is split into triangles and
1422       // each of triangles and a volume barycenter form a tetrahedron.
1423
1424       int* connectivity = new int[ maxTetConnSize + 1 ];
1425       method._connectivity = connectivity;
1426       method._ownConn = true;
1427       method._baryNode = true;
1428
1429       int connSize = 0;
1430       int baryCenInd = vol.NbNodes();
1431       for ( int iF = 0; iF < vol.NbFaces(); ++iF )
1432       {
1433         const int nbNodes = vol.NbFaceNodes( iF ) / iQ;
1434         const int*   nInd = vol.GetFaceNodesIndices( iF );
1435         // find common node of triangle facets of tetra to create
1436         int iCommon = 0; // index in linear numeration
1437         const list< TTriangleFacet >& triaSplits = triaSplitsByFace[ iF ];
1438         if ( !triaSplits.empty() )
1439         {
1440           // by found facets
1441           const TTriangleFacet* facet = &triaSplits.front();
1442           for ( ; iCommon < nbNodes-1 ; ++iCommon )
1443             if ( facet->contains( nInd[ iQ * iCommon ]) &&
1444                  facet->contains( nInd[ iQ * ((iCommon+2)%nbNodes) ]))
1445               break;
1446         }
1447         else if ( nbNodes > 3 && !is24TetMode )
1448         {
1449           // find the best method of splitting into triangles by aspect ratio
1450           SMESH::Controls::NumericalFunctorPtr aspectRatio( new SMESH::Controls::AspectRatio);
1451           map< double, int > badness2iCommon;
1452           const SMDS_MeshNode** nodes = vol.GetFaceNodes( iF );
1453           int nbVariants = ( nbNodes == 4 ? 2 : nbNodes );
1454           for ( int iVar = 0; iVar < nbVariants; ++iVar, ++iCommon )
1455             for ( int iLast = iCommon+2; iLast < iCommon+nbNodes; ++iLast )
1456             {
1457               SMDS_FaceOfNodes tria ( nodes[ iQ*( iCommon         )],
1458                                       nodes[ iQ*((iLast-1)%nbNodes)],
1459                                       nodes[ iQ*((iLast  )%nbNodes)]);
1460               double badness = getBadRate( &tria, aspectRatio );
1461               badness2iCommon.insert( make_pair( badness, iCommon ));
1462             }
1463           // use iCommon with lowest badness
1464           iCommon = badness2iCommon.begin()->second;
1465         }
1466         if ( iCommon >= nbNodes )
1467           iCommon = 0; // something wrong
1468
1469         // fill connectivity of tetrahedra based on a current face
1470         int nbTet = nbNodes - 2;
1471         if ( is24TetMode && nbNodes > 3 && triaSplits.empty())
1472         {
1473           method._faceBaryNode.insert( make_pair( iF, (const SMDS_MeshNode*)0 ));
1474           int faceBaryCenInd = baryCenInd + method._faceBaryNode.size();
1475           nbTet = nbNodes;
1476           for ( int i = 0; i < nbTet; ++i )
1477           {
1478             int i1 = i, i2 = (i+1) % nbNodes;
1479             if ( !vol.IsFaceExternal( iF )) swap( i1, i2 );
1480             connectivity[ connSize++ ] = nInd[ iQ * i1 ];
1481             connectivity[ connSize++ ] = nInd[ iQ * i2 ];
1482             connectivity[ connSize++ ] = faceBaryCenInd;
1483             connectivity[ connSize++ ] = baryCenInd;
1484           }
1485         }
1486         else
1487         {
1488           for ( int i = 0; i < nbTet; ++i )
1489           {
1490             int i1 = (iCommon+1+i) % nbNodes, i2 = (iCommon+2+i) % nbNodes;
1491             if ( !vol.IsFaceExternal( iF )) swap( i1, i2 );
1492             connectivity[ connSize++ ] = nInd[ iQ * iCommon ];
1493             connectivity[ connSize++ ] = nInd[ iQ * i1 ];
1494             connectivity[ connSize++ ] = nInd[ iQ * i2 ];
1495             connectivity[ connSize++ ] = baryCenInd;
1496           }
1497         }
1498         method._nbTetra += nbTet;
1499       }
1500       connectivity[ connSize++ ] = -1;
1501     }
1502     return method;
1503   }
1504   //================================================================================
1505   /*!
1506    * \brief Check if there is a tetraherdon adjacent to the given element via this facet
1507    */
1508   //================================================================================
1509
1510   bool TTriangleFacet::hasAdjacentTetra( const SMDS_MeshElement* elem ) const
1511   {
1512     // find the tetrahedron including the three nodes of facet
1513     const SMDS_MeshNode* n1 = elem->GetNode(_n1);
1514     const SMDS_MeshNode* n2 = elem->GetNode(_n2);
1515     const SMDS_MeshNode* n3 = elem->GetNode(_n3);
1516     SMDS_ElemIteratorPtr volIt1 = n1->GetInverseElementIterator(SMDSAbs_Volume);
1517     while ( volIt1->more() )
1518     {
1519       const SMDS_MeshElement* v = volIt1->next();
1520       if ( v->GetEntityType() != ( v->IsQuadratic() ? SMDSEntity_Quad_Tetra : SMDSEntity_Tetra ))
1521         continue;
1522       SMDS_ElemIteratorPtr volIt2 = n2->GetInverseElementIterator(SMDSAbs_Volume);
1523       while ( volIt2->more() )
1524         if ( v != volIt2->next() )
1525           continue;
1526       SMDS_ElemIteratorPtr volIt3 = n3->GetInverseElementIterator(SMDSAbs_Volume);
1527       while ( volIt3->more() )
1528         if ( v == volIt3->next() )
1529           return true;
1530     }
1531     return false;
1532   }
1533
1534   //=======================================================================
1535   /*!
1536    * \brief A key of a face of volume
1537    */
1538   //=======================================================================
1539
1540   struct TVolumeFaceKey: pair< int, pair< int, int> >
1541   {
1542     TVolumeFaceKey( SMDS_VolumeTool& vol, int iF )
1543     {
1544       TIDSortedNodeSet sortedNodes;
1545       const int iQ = vol.Element()->IsQuadratic() ? 2 : 1;
1546       int nbNodes = vol.NbFaceNodes( iF );
1547       const SMDS_MeshNode** fNodes = vol.GetFaceNodes( iF );
1548       for ( int i = 0; i < nbNodes; i += iQ )
1549         sortedNodes.insert( fNodes[i] );
1550       TIDSortedNodeSet::iterator n = sortedNodes.begin();
1551       first = (*(n++))->GetID();
1552       second.first = (*(n++))->GetID();
1553       second.second = (*(n++))->GetID();
1554     }
1555   };
1556 } // namespace
1557
1558 //=======================================================================
1559 //function : SplitVolumesIntoTetra
1560 //purpose  : Split volumic elements into tetrahedra.
1561 //=======================================================================
1562
1563 void SMESH_MeshEditor::SplitVolumesIntoTetra (const TIDSortedElemSet & theElems,
1564                                               const int                theMethodFlags)
1565 {
1566   // std-like iterator on coordinates of nodes of mesh element
1567   typedef SMDS_StdIterator< SMESH_TNodeXYZ, SMDS_ElemIteratorPtr > NXyzIterator;
1568   NXyzIterator xyzEnd;
1569
1570   SMDS_VolumeTool    volTool;
1571   SMESH_MesherHelper helper( *GetMesh());
1572
1573   SMESHDS_SubMesh* subMesh = 0;//GetMeshDS()->MeshElements(1);
1574   SMESHDS_SubMesh* fSubMesh = 0;//subMesh;
1575   
1576   SMESH_SequenceOfElemPtr newNodes, newElems;
1577
1578   // map face of volume to it's baricenrtic node
1579   map< TVolumeFaceKey, const SMDS_MeshNode* > volFace2BaryNode;
1580   double bc[3];
1581
1582   TIDSortedElemSet::const_iterator elem = theElems.begin();
1583   for ( ; elem != theElems.end(); ++elem )
1584   {
1585     SMDSAbs_EntityType geomType = (*elem)->GetEntityType();
1586     if ( geomType <= SMDSEntity_Quad_Tetra )
1587       continue; // tetra or face or ...
1588
1589     if ( !volTool.Set( *elem )) continue; // not volume? strange...
1590
1591     TSplitMethod splitMethod = getSplitMethod( volTool, theMethodFlags );
1592     if ( splitMethod._nbTetra < 1 ) continue;
1593
1594     // find submesh to add new tetras to
1595     if ( !subMesh || !subMesh->Contains( *elem ))
1596     {
1597       int shapeID = FindShape( *elem );
1598       helper.SetSubShape( shapeID ); // helper will add tetras to the found submesh
1599       subMesh = GetMeshDS()->MeshElements( shapeID );
1600     }
1601     int iQ;
1602     if ( (*elem)->IsQuadratic() )
1603     {
1604       iQ = 2;
1605       // add quadratic links to the helper
1606       for ( int iF = 0; iF < volTool.NbFaces(); ++iF )
1607       {
1608         const SMDS_MeshNode** fNodes = volTool.GetFaceNodes( iF );
1609         for ( int iN = 0; iN < volTool.NbFaceNodes( iF ); iN += iQ )
1610           helper.AddTLinkNode( fNodes[iF], fNodes[iF+2], fNodes[iF+1] );
1611       }
1612       helper.SetIsQuadratic( true );
1613     }
1614     else
1615     {
1616       iQ = 1;
1617       helper.SetIsQuadratic( false );
1618     }
1619     vector<const SMDS_MeshNode*> nodes( (*elem)->begin_nodes(), (*elem)->end_nodes() );
1620     if ( splitMethod._baryNode )
1621     {
1622       // make a node at barycenter
1623       volTool.GetBaryCenter( bc[0], bc[1], bc[2] );
1624       SMDS_MeshNode* gcNode = helper.AddNode( bc[0], bc[1], bc[2] );
1625       nodes.push_back( gcNode );
1626       newNodes.Append( gcNode );
1627     }
1628     if ( !splitMethod._faceBaryNode.empty() )
1629     {
1630       // make or find baricentric nodes of faces
1631       map<int, const SMDS_MeshNode*>::iterator iF_n = splitMethod._faceBaryNode.begin();
1632       for ( ; iF_n != splitMethod._faceBaryNode.end(); ++iF_n )
1633       {
1634         map< TVolumeFaceKey, const SMDS_MeshNode* >::iterator f_n =
1635           volFace2BaryNode.insert
1636           ( make_pair( TVolumeFaceKey( volTool,iF_n->first ), (const SMDS_MeshNode*)0) ).first;
1637         if ( !f_n->second )
1638         {
1639           volTool.GetFaceBaryCenter( iF_n->first, bc[0], bc[1], bc[2] );
1640           newNodes.Append( f_n->second = helper.AddNode( bc[0], bc[1], bc[2] ));
1641         }
1642         nodes.push_back( iF_n->second = f_n->second );
1643       }
1644     }
1645
1646     // make tetras
1647     helper.SetElementsOnShape( true );
1648     vector<const SMDS_MeshElement* > tetras( splitMethod._nbTetra ); // splits of a volume
1649     const int* tetConn = splitMethod._connectivity;
1650     for ( int i = 0; i < splitMethod._nbTetra; ++i, tetConn += 4 )
1651       newElems.Append( tetras[ i ] = helper.AddVolume( nodes[ tetConn[0] ],
1652                                                        nodes[ tetConn[1] ],
1653                                                        nodes[ tetConn[2] ],
1654                                                        nodes[ tetConn[3] ]));
1655
1656     ReplaceElemInGroups( *elem, tetras, GetMeshDS() );
1657
1658     // Split faces on sides of the split volume
1659
1660     const SMDS_MeshNode** volNodes = volTool.GetNodes();
1661     for ( int iF = 0; iF < volTool.NbFaces(); ++iF )
1662     {
1663       const int nbNodes = volTool.NbFaceNodes( iF ) / iQ;
1664       if ( nbNodes < 4 ) continue;
1665
1666       // find an existing face
1667       vector<const SMDS_MeshNode*> fNodes( volTool.GetFaceNodes( iF ),
1668                                            volTool.GetFaceNodes( iF ) + nbNodes*iQ );
1669       while ( const SMDS_MeshElement* face = GetMeshDS()->FindFace( fNodes ))
1670       {
1671         // make triangles
1672         helper.SetElementsOnShape( false );
1673         vector< const SMDS_MeshElement* > triangles;
1674
1675         map<int, const SMDS_MeshNode*>::iterator iF_n = splitMethod._faceBaryNode.find(iF);
1676         if ( iF_n != splitMethod._faceBaryNode.end() )
1677         {
1678           for ( int iN = 0; iN < nbNodes*iQ; iN += iQ )
1679           {
1680             const SMDS_MeshNode* n1 = fNodes[iN];
1681             const SMDS_MeshNode *n2 = fNodes[(iN+iQ)%nbNodes*iQ];
1682             const SMDS_MeshNode *n3 = iF_n->second;
1683             if ( !volTool.IsFaceExternal( iF ))
1684               swap( n2, n3 );
1685             triangles.push_back( helper.AddFace( n1,n2,n3 ));
1686           }
1687         }
1688         else
1689         {
1690           // among possible triangles create ones discribed by split method
1691           const int* nInd = volTool.GetFaceNodesIndices( iF );
1692           int nbVariants = ( nbNodes == 4 ? 2 : nbNodes );
1693           int iCom = 0; // common node of triangle faces to split into
1694           list< TTriangleFacet > facets;
1695           for ( int iVar = 0; iVar < nbVariants; ++iVar, ++iCom )
1696           {
1697             TTriangleFacet t012( nInd[ iQ * ( iCom                )],
1698                                  nInd[ iQ * ( (iCom+1)%nbNodes )],
1699                                  nInd[ iQ * ( (iCom+2)%nbNodes )]);
1700             TTriangleFacet t023( nInd[ iQ * ( iCom                )],
1701                                  nInd[ iQ * ( (iCom+2)%nbNodes )],
1702                                  nInd[ iQ * ( (iCom+3)%nbNodes )]);
1703             if ( splitMethod.hasFacet( t012 ) && splitMethod.hasFacet( t023 ))
1704             {
1705               facets.push_back( t012 );
1706               facets.push_back( t023 );
1707               for ( int iLast = iCom+4; iLast < iCom+nbNodes; ++iLast )
1708                 facets.push_back( TTriangleFacet( nInd[ iQ * ( iCom             )],
1709                                                   nInd[ iQ * ((iLast-1)%nbNodes )],
1710                                                   nInd[ iQ * ((iLast  )%nbNodes )]));
1711               break;
1712             }
1713           }
1714           list< TTriangleFacet >::iterator facet = facets.begin();
1715           for ( ; facet != facets.end(); ++facet )
1716           {
1717             if ( !volTool.IsFaceExternal( iF ))
1718               swap( facet->_n2, facet->_n3 );
1719             triangles.push_back( helper.AddFace( volNodes[ facet->_n1 ],
1720                                                  volNodes[ facet->_n2 ],
1721                                                  volNodes[ facet->_n3 ]));
1722           }
1723         }
1724         // find submesh to add new triangles in
1725         if ( !fSubMesh || !fSubMesh->Contains( face ))
1726         {
1727           int shapeID = FindShape( face );
1728           fSubMesh = GetMeshDS()->MeshElements( shapeID );
1729         }
1730         for ( int i = 0; i < triangles.size(); ++i )
1731         {
1732           if ( !triangles[i] ) continue;
1733           if ( fSubMesh )
1734             fSubMesh->AddElement( triangles[i]);
1735           newElems.Append( triangles[i] );
1736         }
1737         ReplaceElemInGroups( face, triangles, GetMeshDS() );
1738         GetMeshDS()->RemoveFreeElement( face, fSubMesh, /*fromGroups=*/false );
1739       }
1740
1741     } // loop on volume faces to split them into triangles
1742
1743     GetMeshDS()->RemoveFreeElement( *elem, subMesh, /*fromGroups=*/false );
1744
1745   } // loop on volumes to split
1746
1747   myLastCreatedNodes = newNodes;
1748   myLastCreatedElems = newElems;
1749 }
1750
1751 //=======================================================================
1752 //function : AddToSameGroups
1753 //purpose  : add elemToAdd to the groups the elemInGroups belongs to
1754 //=======================================================================
1755
1756 void SMESH_MeshEditor::AddToSameGroups (const SMDS_MeshElement* elemToAdd,
1757                                         const SMDS_MeshElement* elemInGroups,
1758                                         SMESHDS_Mesh *          aMesh)
1759 {
1760   const set<SMESHDS_GroupBase*>& groups = aMesh->GetGroups();
1761   if (!groups.empty()) {
1762     set<SMESHDS_GroupBase*>::const_iterator grIt = groups.begin();
1763     for ( ; grIt != groups.end(); grIt++ ) {
1764       SMESHDS_Group* group = dynamic_cast<SMESHDS_Group*>( *grIt );
1765       if ( group && group->Contains( elemInGroups ))
1766         group->SMDSGroup().Add( elemToAdd );
1767     }
1768   }
1769 }
1770
1771
1772 //=======================================================================
1773 //function : RemoveElemFromGroups
1774 //purpose  : Remove removeelem to the groups the elemInGroups belongs to
1775 //=======================================================================
1776 void SMESH_MeshEditor::RemoveElemFromGroups (const SMDS_MeshElement* removeelem,
1777                                              SMESHDS_Mesh *          aMesh)
1778 {
1779   const set<SMESHDS_GroupBase*>& groups = aMesh->GetGroups();
1780   if (!groups.empty())
1781   {
1782     set<SMESHDS_GroupBase*>::const_iterator GrIt = groups.begin();
1783     for (; GrIt != groups.end(); GrIt++)
1784     {
1785       SMESHDS_Group* grp = dynamic_cast<SMESHDS_Group*>(*GrIt);
1786       if (!grp || grp->IsEmpty()) continue;
1787       grp->SMDSGroup().Remove(removeelem);
1788     }
1789   }
1790 }
1791
1792 //================================================================================
1793 /*!
1794  * \brief Replace elemToRm by elemToAdd in the all groups
1795  */
1796 //================================================================================
1797
1798 void SMESH_MeshEditor::ReplaceElemInGroups (const SMDS_MeshElement* elemToRm,
1799                                             const SMDS_MeshElement* elemToAdd,
1800                                             SMESHDS_Mesh *          aMesh)
1801 {
1802   const set<SMESHDS_GroupBase*>& groups = aMesh->GetGroups();
1803   if (!groups.empty()) {
1804     set<SMESHDS_GroupBase*>::const_iterator grIt = groups.begin();
1805     for ( ; grIt != groups.end(); grIt++ ) {
1806       SMESHDS_Group* group = dynamic_cast<SMESHDS_Group*>( *grIt );
1807       if ( group && group->SMDSGroup().Remove( elemToRm ) && elemToAdd )
1808         group->SMDSGroup().Add( elemToAdd );
1809     }
1810   }
1811 }
1812
1813 //================================================================================
1814 /*!
1815  * \brief Replace elemToRm by elemToAdd in the all groups
1816  */
1817 //================================================================================
1818
1819 void SMESH_MeshEditor::ReplaceElemInGroups (const SMDS_MeshElement*                elemToRm,
1820                                             const vector<const SMDS_MeshElement*>& elemToAdd,
1821                                             SMESHDS_Mesh *                         aMesh)
1822 {
1823   const set<SMESHDS_GroupBase*>& groups = aMesh->GetGroups();
1824   if (!groups.empty())
1825   {
1826     set<SMESHDS_GroupBase*>::const_iterator grIt = groups.begin();
1827     for ( ; grIt != groups.end(); grIt++ ) {
1828       SMESHDS_Group* group = dynamic_cast<SMESHDS_Group*>( *grIt );
1829       if ( group && group->SMDSGroup().Remove( elemToRm ) )
1830         for ( int i = 0; i < elemToAdd.size(); ++i )
1831           group->SMDSGroup().Add( elemToAdd[ i ] );
1832     }
1833   }
1834 }
1835
1836 //=======================================================================
1837 //function : QuadToTri
1838 //purpose  : Cut quadrangles into triangles.
1839 //           theCrit is used to select a diagonal to cut
1840 //=======================================================================
1841
1842 bool SMESH_MeshEditor::QuadToTri (TIDSortedElemSet & theElems,
1843                                   const bool         the13Diag)
1844 {
1845   myLastCreatedElems.Clear();
1846   myLastCreatedNodes.Clear();
1847
1848   MESSAGE( "::QuadToTri()" );
1849
1850   SMESHDS_Mesh * aMesh = GetMeshDS();
1851
1852   Handle(Geom_Surface) surface;
1853   SMESH_MesherHelper   helper( *GetMesh() );
1854
1855   TIDSortedElemSet::iterator itElem;
1856   for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
1857     const SMDS_MeshElement* elem = *itElem;
1858     if ( !elem || elem->GetType() != SMDSAbs_Face )
1859       continue;
1860     bool isquad = elem->NbNodes()==4 || elem->NbNodes()==8;
1861     if(!isquad) continue;
1862
1863     if(elem->NbNodes()==4) {
1864       // retrieve element nodes
1865       const SMDS_MeshNode* aNodes [4];
1866       SMDS_ElemIteratorPtr itN = elem->nodesIterator();
1867       int i = 0;
1868       while ( itN->more() )
1869         aNodes[ i++ ] = static_cast<const SMDS_MeshNode*>( itN->next() );
1870
1871       int aShapeId = FindShape( elem );
1872       const SMDS_MeshElement* newElem1 = 0;
1873       const SMDS_MeshElement* newElem2 = 0;
1874       if ( the13Diag ) {
1875         newElem1 = aMesh->AddFace( aNodes[2], aNodes[0], aNodes[1] );
1876         newElem2 = aMesh->AddFace( aNodes[2], aNodes[3], aNodes[0] );
1877       }
1878       else {
1879         newElem1 = aMesh->AddFace( aNodes[3], aNodes[0], aNodes[1] );
1880         newElem2 = aMesh->AddFace( aNodes[3], aNodes[1], aNodes[2] );
1881       }
1882       myLastCreatedElems.Append(newElem1);
1883       myLastCreatedElems.Append(newElem2);
1884       // put a new triangle on the same shape and add to the same groups
1885       if ( aShapeId )
1886         {
1887           aMesh->SetMeshElementOnShape( newElem1, aShapeId );
1888           aMesh->SetMeshElementOnShape( newElem2, aShapeId );
1889         }
1890       AddToSameGroups( newElem1, elem, aMesh );
1891       AddToSameGroups( newElem2, elem, aMesh );
1892       //aMesh->RemoveFreeElement(elem, aMesh->MeshElements(aShapeId), true);
1893       aMesh->RemoveElement( elem );
1894     }
1895
1896     // Quadratic quadrangle
1897
1898     if( elem->NbNodes()==8 && elem->IsQuadratic() ) {
1899
1900       // get surface elem is on
1901       int aShapeId = FindShape( elem );
1902       if ( aShapeId != helper.GetSubShapeID() ) {
1903         surface.Nullify();
1904         TopoDS_Shape shape;
1905         if ( aShapeId > 0 )
1906           shape = aMesh->IndexToShape( aShapeId );
1907         if ( !shape.IsNull() && shape.ShapeType() == TopAbs_FACE ) {
1908           TopoDS_Face face = TopoDS::Face( shape );
1909           surface = BRep_Tool::Surface( face );
1910           if ( !surface.IsNull() )
1911             helper.SetSubShape( shape );
1912         }
1913       }
1914
1915       const SMDS_MeshNode* aNodes [8];
1916       const SMDS_MeshNode* inFaceNode = 0;
1917       SMDS_ElemIteratorPtr itN = elem->nodesIterator();
1918       int i = 0;
1919       while ( itN->more() ) {
1920         aNodes[ i++ ] = static_cast<const SMDS_MeshNode*>( itN->next() );
1921         if ( !inFaceNode && helper.GetNodeUVneedInFaceNode() &&
1922              aNodes[ i-1 ]->GetPosition()->GetTypeOfPosition() == SMDS_TOP_FACE )
1923         {
1924           inFaceNode = aNodes[ i-1 ];
1925         }
1926       }
1927
1928       // find middle point for (0,1,2,3)
1929       // and create a node in this point;
1930       gp_XYZ p( 0,0,0 );
1931       if ( surface.IsNull() ) {
1932         for(i=0; i<4; i++)
1933           p += gp_XYZ(aNodes[i]->X(), aNodes[i]->Y(), aNodes[i]->Z() );
1934         p /= 4;
1935       }
1936       else {
1937         TopoDS_Face geomFace = TopoDS::Face( helper.GetSubShape() );
1938         gp_XY uv( 0,0 );
1939         for(i=0; i<4; i++)
1940           uv += helper.GetNodeUV( geomFace, aNodes[i], inFaceNode );
1941         uv /= 4.;
1942         p = surface->Value( uv.X(), uv.Y() ).XYZ();
1943       }
1944       const SMDS_MeshNode* newN = aMesh->AddNode( p.X(), p.Y(), p.Z() );
1945       myLastCreatedNodes.Append(newN);
1946
1947       // create a new element
1948       const SMDS_MeshElement* newElem1 = 0;
1949       const SMDS_MeshElement* newElem2 = 0;
1950       const SMDS_MeshNode* N[6];
1951       if ( the13Diag ) {
1952         N[0] = aNodes[0];
1953         N[1] = aNodes[1];
1954         N[2] = aNodes[2];
1955         N[3] = aNodes[4];
1956         N[4] = aNodes[5];
1957         N[5] = newN;
1958         newElem1 = aMesh->AddFace(aNodes[2], aNodes[3], aNodes[0],
1959                                   aNodes[6], aNodes[7], newN );
1960         newElem2 = aMesh->AddFace(aNodes[2], aNodes[0], aNodes[1],
1961                                   newN,      aNodes[4], aNodes[5] );
1962       }
1963       else {
1964         N[0] = aNodes[1];
1965         N[1] = aNodes[2];
1966         N[2] = aNodes[3];
1967         N[3] = aNodes[5];
1968         N[4] = aNodes[6];
1969         N[5] = newN;
1970         newElem1 = aMesh->AddFace(aNodes[3], aNodes[0], aNodes[1],
1971                                   aNodes[7], aNodes[4], newN );
1972         newElem2 = aMesh->AddFace(aNodes[3], aNodes[1], aNodes[2],
1973                                   newN,      aNodes[5], aNodes[6] );
1974       }
1975       myLastCreatedElems.Append(newElem1);
1976       myLastCreatedElems.Append(newElem2);
1977       // put a new triangle on the same shape and add to the same groups
1978       if ( aShapeId )
1979         {
1980           aMesh->SetMeshElementOnShape( newElem1, aShapeId );
1981           aMesh->SetMeshElementOnShape( newElem2, aShapeId );
1982         }
1983       AddToSameGroups( newElem1, elem, aMesh );
1984       AddToSameGroups( newElem2, elem, aMesh );
1985       aMesh->RemoveElement( elem );
1986     }
1987   }
1988
1989   return true;
1990 }
1991
1992 //=======================================================================
1993 //function : getAngle
1994 //purpose  :
1995 //=======================================================================
1996
1997 double getAngle(const SMDS_MeshElement * tr1,
1998                 const SMDS_MeshElement * tr2,
1999                 const SMDS_MeshNode *    n1,
2000                 const SMDS_MeshNode *    n2)
2001 {
2002   double angle = 2*PI; // bad angle
2003
2004   // get normals
2005   SMESH::Controls::TSequenceOfXYZ P1, P2;
2006   if ( !SMESH::Controls::NumericalFunctor::GetPoints( tr1, P1 ) ||
2007        !SMESH::Controls::NumericalFunctor::GetPoints( tr2, P2 ))
2008     return angle;
2009   gp_Vec N1,N2;
2010   if(!tr1->IsQuadratic())
2011     N1 = gp_Vec( P1(2) - P1(1) ) ^ gp_Vec( P1(3) - P1(1) );
2012   else
2013     N1 = gp_Vec( P1(3) - P1(1) ) ^ gp_Vec( P1(5) - P1(1) );
2014   if ( N1.SquareMagnitude() <= gp::Resolution() )
2015     return angle;
2016   if(!tr2->IsQuadratic())
2017     N2 = gp_Vec( P2(2) - P2(1) ) ^ gp_Vec( P2(3) - P2(1) );
2018   else
2019     N2 = gp_Vec( P2(3) - P2(1) ) ^ gp_Vec( P2(5) - P2(1) );
2020   if ( N2.SquareMagnitude() <= gp::Resolution() )
2021     return angle;
2022
2023   // find the first diagonal node n1 in the triangles:
2024   // take in account a diagonal link orientation
2025   const SMDS_MeshElement *nFirst[2], *tr[] = { tr1, tr2 };
2026   for ( int t = 0; t < 2; t++ ) {
2027     SMDS_ElemIteratorPtr it = tr[ t ]->nodesIterator();
2028     int i = 0, iDiag = -1;
2029     while ( it->more()) {
2030       const SMDS_MeshElement *n = it->next();
2031       if ( n == n1 || n == n2 ) {
2032         if ( iDiag < 0)
2033           iDiag = i;
2034         else {
2035           if ( i - iDiag == 1 )
2036             nFirst[ t ] = ( n == n1 ? n2 : n1 );
2037           else
2038             nFirst[ t ] = n;
2039           break;
2040         }
2041       }
2042       i++;
2043     }
2044   }
2045   if ( nFirst[ 0 ] == nFirst[ 1 ] )
2046     N2.Reverse();
2047
2048   angle = N1.Angle( N2 );
2049   //SCRUTE( angle );
2050   return angle;
2051 }
2052
2053 // =================================================
2054 // class generating a unique ID for a pair of nodes
2055 // and able to return nodes by that ID
2056 // =================================================
2057 class LinkID_Gen {
2058 public:
2059
2060   LinkID_Gen( const SMESHDS_Mesh* theMesh )
2061     :myMesh( theMesh ), myMaxID( theMesh->MaxNodeID() + 1)
2062   {}
2063
2064   long GetLinkID (const SMDS_MeshNode * n1,
2065                   const SMDS_MeshNode * n2) const
2066   {
2067     return ( Min(n1->GetID(),n2->GetID()) * myMaxID + Max(n1->GetID(),n2->GetID()));
2068   }
2069
2070   bool GetNodes (const long             theLinkID,
2071                  const SMDS_MeshNode* & theNode1,
2072                  const SMDS_MeshNode* & theNode2) const
2073   {
2074     theNode1 = myMesh->FindNode( theLinkID / myMaxID );
2075     if ( !theNode1 ) return false;
2076     theNode2 = myMesh->FindNode( theLinkID % myMaxID );
2077     if ( !theNode2 ) return false;
2078     return true;
2079   }
2080
2081 private:
2082   LinkID_Gen();
2083   const SMESHDS_Mesh* myMesh;
2084   long                myMaxID;
2085 };
2086
2087
2088 //=======================================================================
2089 //function : TriToQuad
2090 //purpose  : Fuse neighbour triangles into quadrangles.
2091 //           theCrit is used to select a neighbour to fuse with.
2092 //           theMaxAngle is a max angle between element normals at which
2093 //           fusion is still performed.
2094 //=======================================================================
2095
2096 bool SMESH_MeshEditor::TriToQuad (TIDSortedElemSet &                   theElems,
2097                                   SMESH::Controls::NumericalFunctorPtr theCrit,
2098                                   const double                         theMaxAngle)
2099 {
2100   myLastCreatedElems.Clear();
2101   myLastCreatedNodes.Clear();
2102
2103   MESSAGE( "::TriToQuad()" );
2104
2105   if ( !theCrit.get() )
2106     return false;
2107
2108   SMESHDS_Mesh * aMesh = GetMeshDS();
2109
2110   // Prepare data for algo: build
2111   // 1. map of elements with their linkIDs
2112   // 2. map of linkIDs with their elements
2113
2114   map< SMESH_TLink, list< const SMDS_MeshElement* > > mapLi_listEl;
2115   map< SMESH_TLink, list< const SMDS_MeshElement* > >::iterator itLE;
2116   map< const SMDS_MeshElement*, set< SMESH_TLink > >  mapEl_setLi;
2117   map< const SMDS_MeshElement*, set< SMESH_TLink > >::iterator itEL;
2118
2119   TIDSortedElemSet::iterator itElem;
2120   for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
2121     const SMDS_MeshElement* elem = *itElem;
2122     if(!elem || elem->GetType() != SMDSAbs_Face ) continue;
2123     bool IsTria = elem->NbNodes()==3 || (elem->NbNodes()==6 && elem->IsQuadratic());
2124     if(!IsTria) continue;
2125
2126     // retrieve element nodes
2127     const SMDS_MeshNode* aNodes [4];
2128     SMDS_ElemIteratorPtr itN = elem->nodesIterator();
2129     int i = 0;
2130     while ( i<3 )
2131       aNodes[ i++ ] = cast2Node( itN->next() );
2132     aNodes[ 3 ] = aNodes[ 0 ];
2133
2134     // fill maps
2135     for ( i = 0; i < 3; i++ ) {
2136       SMESH_TLink link( aNodes[i], aNodes[i+1] );
2137       // check if elements sharing a link can be fused
2138       itLE = mapLi_listEl.find( link );
2139       if ( itLE != mapLi_listEl.end() ) {
2140         if ((*itLE).second.size() > 1 ) // consider only 2 elems adjacent by a link
2141           continue;
2142         const SMDS_MeshElement* elem2 = (*itLE).second.front();
2143         //if ( FindShape( elem ) != FindShape( elem2 ))
2144         //  continue; // do not fuse triangles laying on different shapes
2145         if ( getAngle( elem, elem2, aNodes[i], aNodes[i+1] ) > theMaxAngle )
2146           continue; // avoid making badly shaped quads
2147         (*itLE).second.push_back( elem );
2148       }
2149       else {
2150         mapLi_listEl[ link ].push_back( elem );
2151       }
2152       mapEl_setLi [ elem ].insert( link );
2153     }
2154   }
2155   // Clean the maps from the links shared by a sole element, ie
2156   // links to which only one element is bound in mapLi_listEl
2157
2158   for ( itLE = mapLi_listEl.begin(); itLE != mapLi_listEl.end(); itLE++ ) {
2159     int nbElems = (*itLE).second.size();
2160     if ( nbElems < 2  ) {
2161       const SMDS_MeshElement* elem = (*itLE).second.front();
2162       SMESH_TLink link = (*itLE).first;
2163       mapEl_setLi[ elem ].erase( link );
2164       if ( mapEl_setLi[ elem ].empty() )
2165         mapEl_setLi.erase( elem );
2166     }
2167   }
2168
2169   // Algo: fuse triangles into quadrangles
2170
2171   while ( ! mapEl_setLi.empty() ) {
2172     // Look for the start element:
2173     // the element having the least nb of shared links
2174     const SMDS_MeshElement* startElem = 0;
2175     int minNbLinks = 4;
2176     for ( itEL = mapEl_setLi.begin(); itEL != mapEl_setLi.end(); itEL++ ) {
2177       int nbLinks = (*itEL).second.size();
2178       if ( nbLinks < minNbLinks ) {
2179         startElem = (*itEL).first;
2180         minNbLinks = nbLinks;
2181         if ( minNbLinks == 1 )
2182           break;
2183       }
2184     }
2185
2186     // search elements to fuse starting from startElem or links of elements
2187     // fused earlyer - startLinks
2188     list< SMESH_TLink > startLinks;
2189     while ( startElem || !startLinks.empty() ) {
2190       while ( !startElem && !startLinks.empty() ) {
2191         // Get an element to start, by a link
2192         SMESH_TLink linkId = startLinks.front();
2193         startLinks.pop_front();
2194         itLE = mapLi_listEl.find( linkId );
2195         if ( itLE != mapLi_listEl.end() ) {
2196           list< const SMDS_MeshElement* > & listElem = (*itLE).second;
2197           list< const SMDS_MeshElement* >::iterator itE = listElem.begin();
2198           for ( ; itE != listElem.end() ; itE++ )
2199             if ( mapEl_setLi.find( (*itE) ) != mapEl_setLi.end() )
2200               startElem = (*itE);
2201           mapLi_listEl.erase( itLE );
2202         }
2203       }
2204
2205       if ( startElem ) {
2206         // Get candidates to be fused
2207         const SMDS_MeshElement *tr1 = startElem, *tr2 = 0, *tr3 = 0;
2208         const SMESH_TLink *link12, *link13;
2209         startElem = 0;
2210         ASSERT( mapEl_setLi.find( tr1 ) != mapEl_setLi.end() );
2211         set< SMESH_TLink >& setLi = mapEl_setLi[ tr1 ];
2212         ASSERT( !setLi.empty() );
2213         set< SMESH_TLink >::iterator itLi;
2214         for ( itLi = setLi.begin(); itLi != setLi.end(); itLi++ )
2215         {
2216           const SMESH_TLink & link = (*itLi);
2217           itLE = mapLi_listEl.find( link );
2218           if ( itLE == mapLi_listEl.end() )
2219             continue;
2220
2221           const SMDS_MeshElement* elem = (*itLE).second.front();
2222           if ( elem == tr1 )
2223             elem = (*itLE).second.back();
2224           mapLi_listEl.erase( itLE );
2225           if ( mapEl_setLi.find( elem ) == mapEl_setLi.end())
2226             continue;
2227           if ( tr2 ) {
2228             tr3 = elem;
2229             link13 = &link;
2230           }
2231           else {
2232             tr2 = elem;
2233             link12 = &link;
2234           }
2235
2236           // add other links of elem to list of links to re-start from
2237           set< SMESH_TLink >& links = mapEl_setLi[ elem ];
2238           set< SMESH_TLink >::iterator it;
2239           for ( it = links.begin(); it != links.end(); it++ ) {
2240             const SMESH_TLink& link2 = (*it);
2241             if ( link2 != link )
2242               startLinks.push_back( link2 );
2243           }
2244         }
2245
2246         // Get nodes of possible quadrangles
2247         const SMDS_MeshNode *n12 [4], *n13 [4];
2248         bool Ok12 = false, Ok13 = false;
2249         const SMDS_MeshNode *linkNode1, *linkNode2;
2250         if(tr2) {
2251           linkNode1 = link12->first;
2252           linkNode2 = link12->second;
2253           if ( tr2 && getQuadrangleNodes( n12, linkNode1, linkNode2, tr1, tr2 ))
2254             Ok12 = true;
2255         }
2256         if(tr3) {
2257           linkNode1 = link13->first;
2258           linkNode2 = link13->second;
2259           if ( tr3 && getQuadrangleNodes( n13, linkNode1, linkNode2, tr1, tr3 ))
2260             Ok13 = true;
2261         }
2262
2263         // Choose a pair to fuse
2264         if ( Ok12 && Ok13 ) {
2265           SMDS_FaceOfNodes quad12 ( n12[ 0 ], n12[ 1 ], n12[ 2 ], n12[ 3 ] );
2266           SMDS_FaceOfNodes quad13 ( n13[ 0 ], n13[ 1 ], n13[ 2 ], n13[ 3 ] );
2267           double aBadRate12 = getBadRate( &quad12, theCrit );
2268           double aBadRate13 = getBadRate( &quad13, theCrit );
2269           if (  aBadRate13 < aBadRate12 )
2270             Ok12 = false;
2271           else
2272             Ok13 = false;
2273         }
2274
2275         // Make quadrangles
2276         // and remove fused elems and removed links from the maps
2277         mapEl_setLi.erase( tr1 );
2278         if ( Ok12 ) {
2279           mapEl_setLi.erase( tr2 );
2280           mapLi_listEl.erase( *link12 );
2281           if(tr1->NbNodes()==3) {
2282             const SMDS_MeshElement* newElem = 0;
2283             newElem = aMesh->AddFace(n12[0], n12[1], n12[2], n12[3] );
2284             myLastCreatedElems.Append(newElem);
2285             AddToSameGroups( newElem, tr1, aMesh );
2286             int aShapeId = tr1->getshapeId();
2287             if ( aShapeId )
2288               {
2289                 aMesh->SetMeshElementOnShape( newElem, aShapeId );
2290               }
2291             aMesh->RemoveElement( tr1 );
2292             aMesh->RemoveElement( tr2 );
2293           }
2294           else {
2295             const SMDS_MeshNode* N1 [6];
2296             const SMDS_MeshNode* N2 [6];
2297             GetNodesFromTwoTria(tr1,tr2,N1,N2);
2298             // now we receive following N1 and N2 (using numeration as above image)
2299             // tria1 : (1 2 4 5 9 7)  and  tria2 : (3 4 2 8 9 6)
2300             // i.e. first nodes from both arrays determ new diagonal
2301             const SMDS_MeshNode* aNodes[8];
2302             aNodes[0] = N1[0];
2303             aNodes[1] = N1[1];
2304             aNodes[2] = N2[0];
2305             aNodes[3] = N2[1];
2306             aNodes[4] = N1[3];
2307             aNodes[5] = N2[5];
2308             aNodes[6] = N2[3];
2309             aNodes[7] = N1[5];
2310             const SMDS_MeshElement* newElem = 0;
2311             newElem = aMesh->AddFace(aNodes[0], aNodes[1], aNodes[2], aNodes[3],
2312                                      aNodes[4], aNodes[5], aNodes[6], aNodes[7]);
2313             myLastCreatedElems.Append(newElem);
2314             AddToSameGroups( newElem, tr1, aMesh );
2315             int aShapeId = tr1->getshapeId();
2316             if ( aShapeId )
2317               {
2318                 aMesh->SetMeshElementOnShape( newElem, aShapeId );
2319               }
2320             aMesh->RemoveElement( tr1 );
2321             aMesh->RemoveElement( tr2 );
2322             // remove middle node (9)
2323             GetMeshDS()->RemoveNode( N1[4] );
2324           }
2325         }
2326         else if ( Ok13 ) {
2327           mapEl_setLi.erase( tr3 );
2328           mapLi_listEl.erase( *link13 );
2329           if(tr1->NbNodes()==3) {
2330             const SMDS_MeshElement* newElem = 0;
2331             newElem = aMesh->AddFace(n13[0], n13[1], n13[2], n13[3] );
2332             myLastCreatedElems.Append(newElem);
2333             AddToSameGroups( newElem, tr1, aMesh );
2334             int aShapeId = tr1->getshapeId();
2335             if ( aShapeId )
2336               {
2337                 aMesh->SetMeshElementOnShape( newElem, aShapeId );
2338               }
2339             aMesh->RemoveElement( tr1 );
2340             aMesh->RemoveElement( tr3 );
2341           }
2342           else {
2343             const SMDS_MeshNode* N1 [6];
2344             const SMDS_MeshNode* N2 [6];
2345             GetNodesFromTwoTria(tr1,tr3,N1,N2);
2346             // now we receive following N1 and N2 (using numeration as above image)
2347             // tria1 : (1 2 4 5 9 7)  and  tria2 : (3 4 2 8 9 6)
2348             // i.e. first nodes from both arrays determ new diagonal
2349             const SMDS_MeshNode* aNodes[8];
2350             aNodes[0] = N1[0];
2351             aNodes[1] = N1[1];
2352             aNodes[2] = N2[0];
2353             aNodes[3] = N2[1];
2354             aNodes[4] = N1[3];
2355             aNodes[5] = N2[5];
2356             aNodes[6] = N2[3];
2357             aNodes[7] = N1[5];
2358             const SMDS_MeshElement* newElem = 0;
2359             newElem = aMesh->AddFace(aNodes[0], aNodes[1], aNodes[2], aNodes[3],
2360                                      aNodes[4], aNodes[5], aNodes[6], aNodes[7]);
2361             myLastCreatedElems.Append(newElem);
2362             AddToSameGroups( newElem, tr1, aMesh );
2363             int aShapeId = tr1->getshapeId();
2364             if ( aShapeId )
2365               {
2366                 aMesh->SetMeshElementOnShape( newElem, aShapeId );
2367               }
2368             aMesh->RemoveElement( tr1 );
2369             aMesh->RemoveElement( tr3 );
2370             // remove middle node (9)
2371             GetMeshDS()->RemoveNode( N1[4] );
2372           }
2373         }
2374
2375         // Next element to fuse: the rejected one
2376         if ( tr3 )
2377           startElem = Ok12 ? tr3 : tr2;
2378
2379       } // if ( startElem )
2380     } // while ( startElem || !startLinks.empty() )
2381   } // while ( ! mapEl_setLi.empty() )
2382
2383   return true;
2384 }
2385
2386
2387 /*#define DUMPSO(txt) \
2388 //  cout << txt << endl;
2389 //=============================================================================
2390 //
2391 //
2392 //
2393 //=============================================================================
2394 static void swap( int i1, int i2, int idNodes[], gp_Pnt P[] )
2395 {
2396 if ( i1 == i2 )
2397 return;
2398 int tmp = idNodes[ i1 ];
2399 idNodes[ i1 ] = idNodes[ i2 ];
2400 idNodes[ i2 ] = tmp;
2401 gp_Pnt Ptmp = P[ i1 ];
2402 P[ i1 ] = P[ i2 ];
2403 P[ i2 ] = Ptmp;
2404 DUMPSO( i1 << "(" << idNodes[ i2 ] << ") <-> " << i2 << "(" << idNodes[ i1 ] << ")");
2405 }
2406
2407 //=======================================================================
2408 //function : SortQuadNodes
2409 //purpose  : Set 4 nodes of a quadrangle face in a good order.
2410 //           Swap 1<->2 or 2<->3 nodes and correspondingly return
2411 //           1 or 2 else 0.
2412 //=======================================================================
2413
2414 int SMESH_MeshEditor::SortQuadNodes (const SMDS_Mesh * theMesh,
2415 int               idNodes[] )
2416 {
2417   gp_Pnt P[4];
2418   int i;
2419   for ( i = 0; i < 4; i++ ) {
2420     const SMDS_MeshNode *n = theMesh->FindNode( idNodes[i] );
2421     if ( !n ) return 0;
2422     P[ i ].SetCoord( n->X(), n->Y(), n->Z() );
2423   }
2424
2425   gp_Vec V1(P[0], P[1]);
2426   gp_Vec V2(P[0], P[2]);
2427   gp_Vec V3(P[0], P[3]);
2428
2429   gp_Vec Cross1 = V1 ^ V2;
2430   gp_Vec Cross2 = V2 ^ V3;
2431
2432   i = 0;
2433   if (Cross1.Dot(Cross2) < 0)
2434   {
2435     Cross1 = V2 ^ V1;
2436     Cross2 = V1 ^ V3;
2437
2438     if (Cross1.Dot(Cross2) < 0)
2439       i = 2;
2440     else
2441       i = 1;
2442     swap ( i, i + 1, idNodes, P );
2443
2444     //     for ( int ii = 0; ii < 4; ii++ ) {
2445     //       const SMDS_MeshNode *n = theMesh->FindNode( idNodes[ii] );
2446     //       DUMPSO( ii << "(" << idNodes[ii] <<") : "<<n->X()<<" "<<n->Y()<<" "<<n->Z());
2447     //     }
2448   }
2449   return i;
2450 }
2451
2452 //=======================================================================
2453 //function : SortHexaNodes
2454 //purpose  : Set 8 nodes of a hexahedron in a good order.
2455 //           Return success status
2456 //=======================================================================
2457
2458 bool SMESH_MeshEditor::SortHexaNodes (const SMDS_Mesh * theMesh,
2459                                       int               idNodes[] )
2460 {
2461   gp_Pnt P[8];
2462   int i;
2463   DUMPSO( "INPUT: ========================================");
2464   for ( i = 0; i < 8; i++ ) {
2465     const SMDS_MeshNode *n = theMesh->FindNode( idNodes[i] );
2466     if ( !n ) return false;
2467     P[ i ].SetCoord( n->X(), n->Y(), n->Z() );
2468     DUMPSO( i << "(" << idNodes[i] <<") : "<<n->X()<<" "<<n->Y()<<" "<<n->Z());
2469   }
2470   DUMPSO( "========================================");
2471
2472
2473   set<int> faceNodes;  // ids of bottom face nodes, to be found
2474   set<int> checkedId1; // ids of tried 2-nd nodes
2475   Standard_Real leastDist = DBL_MAX; // dist of the 4-th node from 123 plane
2476   const Standard_Real tol = 1.e-6;   // tolerance to find nodes in plane
2477   int iMin, iLoop1 = 0;
2478
2479   // Loop to try the 2-nd nodes
2480
2481   while ( leastDist > DBL_MIN && ++iLoop1 < 8 )
2482   {
2483     // Find not checked 2-nd node
2484     for ( i = 1; i < 8; i++ )
2485       if ( checkedId1.find( idNodes[i] ) == checkedId1.end() ) {
2486         int id1 = idNodes[i];
2487         swap ( 1, i, idNodes, P );
2488         checkedId1.insert ( id1 );
2489         break;
2490       }
2491
2492     // Find the 3-d node so that 1-2-3 triangle to be on a hexa face,
2493     // ie that all but meybe one (id3 which is on the same face) nodes
2494     // lay on the same side from the triangle plane.
2495
2496     bool manyInPlane = false; // more than 4 nodes lay in plane
2497     int iLoop2 = 0;
2498     while ( ++iLoop2 < 6 ) {
2499
2500       // get 1-2-3 plane coeffs
2501       Standard_Real A, B, C, D;
2502       gp_Vec N = gp_Vec (P[0], P[1]).Crossed( gp_Vec (P[0], P[2]) );
2503       if ( N.SquareMagnitude() > gp::Resolution() )
2504       {
2505         gp_Pln pln ( P[0], N );
2506         pln.Coefficients( A, B, C, D );
2507
2508         // find the node (iMin) closest to pln
2509         Standard_Real dist[ 8 ], minDist = DBL_MAX;
2510         set<int> idInPln;
2511         for ( i = 3; i < 8; i++ ) {
2512           dist[i] = A * P[i].X() + B * P[i].Y() + C * P[i].Z() + D;
2513           if ( fabs( dist[i] ) < minDist ) {
2514             minDist = fabs( dist[i] );
2515             iMin = i;
2516           }
2517           if ( fabs( dist[i] ) <= tol )
2518             idInPln.insert( idNodes[i] );
2519         }
2520
2521         // there should not be more than 4 nodes in bottom plane
2522         if ( idInPln.size() > 1 )
2523         {
2524           DUMPSO( "### idInPln.size() = " << idInPln.size());
2525           // idInPlane does not contain the first 3 nodes
2526           if ( manyInPlane || idInPln.size() == 5)
2527             return false; // all nodes in one plane
2528           manyInPlane = true;
2529
2530           // set the 1-st node to be not in plane
2531           for ( i = 3; i < 8; i++ ) {
2532             if ( idInPln.find( idNodes[ i ] ) == idInPln.end() ) {
2533               DUMPSO( "### Reset 0-th node");
2534               swap( 0, i, idNodes, P );
2535               break;
2536             }
2537           }
2538
2539           // reset to re-check second nodes
2540           leastDist = DBL_MAX;
2541           faceNodes.clear();
2542           checkedId1.clear();
2543           iLoop1 = 0;
2544           break; // from iLoop2;
2545         }
2546
2547         // check that the other 4 nodes are on the same side
2548         bool sameSide = true;
2549         bool isNeg = dist[ iMin == 3 ? 4 : 3 ] <= 0.;
2550         for ( i = 3; sameSide && i < 8; i++ ) {
2551           if ( i != iMin )
2552             sameSide = ( isNeg == dist[i] <= 0.);
2553         }
2554
2555         // keep best solution
2556         if ( sameSide && minDist < leastDist ) {
2557           leastDist = minDist;
2558           faceNodes.clear();
2559           faceNodes.insert( idNodes[ 1 ] );
2560           faceNodes.insert( idNodes[ 2 ] );
2561           faceNodes.insert( idNodes[ iMin ] );
2562           DUMPSO( "loop " << iLoop2 << " id2 " << idNodes[ 1 ] << " id3 " << idNodes[ 2 ]
2563                   << " leastDist = " << leastDist);
2564           if ( leastDist <= DBL_MIN )
2565             break;
2566         }
2567       }
2568
2569       // set next 3-d node to check
2570       int iNext = 2 + iLoop2;
2571       if ( iNext < 8 ) {
2572         DUMPSO( "Try 2-nd");
2573         swap ( 2, iNext, idNodes, P );
2574       }
2575     } // while ( iLoop2 < 6 )
2576   } // iLoop1
2577
2578   if ( faceNodes.empty() ) return false;
2579
2580   // Put the faceNodes in proper places
2581   for ( i = 4; i < 8; i++ ) {
2582     if ( faceNodes.find( idNodes[ i ] ) != faceNodes.end() ) {
2583       // find a place to put
2584       int iTo = 1;
2585       while ( faceNodes.find( idNodes[ iTo ] ) != faceNodes.end() )
2586         iTo++;
2587       DUMPSO( "Set faceNodes");
2588       swap ( iTo, i, idNodes, P );
2589     }
2590   }
2591
2592
2593   // Set nodes of the found bottom face in good order
2594   DUMPSO( " Found bottom face: ");
2595   i = SortQuadNodes( theMesh, idNodes );
2596   if ( i ) {
2597     gp_Pnt Ptmp = P[ i ];
2598     P[ i ] = P[ i+1 ];
2599     P[ i+1 ] = Ptmp;
2600   }
2601   //   else
2602   //     for ( int ii = 0; ii < 4; ii++ ) {
2603   //       const SMDS_MeshNode *n = theMesh->FindNode( idNodes[ii] );
2604   //       DUMPSO( ii << "(" << idNodes[ii] <<") : "<<n->X()<<" "<<n->Y()<<" "<<n->Z());
2605   //    }
2606
2607   // Gravity center of the top and bottom faces
2608   gp_Pnt aGCb = ( P[0].XYZ() + P[1].XYZ() + P[2].XYZ() + P[3].XYZ() ) / 4.;
2609   gp_Pnt aGCt = ( P[4].XYZ() + P[5].XYZ() + P[6].XYZ() + P[7].XYZ() ) / 4.;
2610
2611   // Get direction from the bottom to the top face
2612   gp_Vec upDir ( aGCb, aGCt );
2613   Standard_Real upDirSize = upDir.Magnitude();
2614   if ( upDirSize <= gp::Resolution() ) return false;
2615   upDir / upDirSize;
2616
2617   // Assure that the bottom face normal points up
2618   gp_Vec Nb = gp_Vec (P[0], P[1]).Crossed( gp_Vec (P[0], P[2]) );
2619   Nb += gp_Vec (P[0], P[2]).Crossed( gp_Vec (P[0], P[3]) );
2620   if ( Nb.Dot( upDir ) < 0 ) {
2621     DUMPSO( "Reverse bottom face");
2622     swap( 1, 3, idNodes, P );
2623   }
2624
2625   // Find 5-th node - the one closest to the 1-st among the last 4 nodes.
2626   Standard_Real minDist = DBL_MAX;
2627   for ( i = 4; i < 8; i++ ) {
2628     // projection of P[i] to the plane defined by P[0] and upDir
2629     gp_Pnt Pp = P[i].Translated( upDir * ( upDir.Dot( gp_Vec( P[i], P[0] ))));
2630     Standard_Real sqDist = P[0].SquareDistance( Pp );
2631     if ( sqDist < minDist ) {
2632       minDist = sqDist;
2633       iMin = i;
2634     }
2635   }
2636   DUMPSO( "Set 4-th");
2637   swap ( 4, iMin, idNodes, P );
2638
2639   // Set nodes of the top face in good order
2640   DUMPSO( "Sort top face");
2641   i = SortQuadNodes( theMesh, &idNodes[4] );
2642   if ( i ) {
2643     i += 4;
2644     gp_Pnt Ptmp = P[ i ];
2645     P[ i ] = P[ i+1 ];
2646     P[ i+1 ] = Ptmp;
2647   }
2648
2649   // Assure that direction of the top face normal is from the bottom face
2650   gp_Vec Nt = gp_Vec (P[4], P[5]).Crossed( gp_Vec (P[4], P[6]) );
2651   Nt += gp_Vec (P[4], P[6]).Crossed( gp_Vec (P[4], P[7]) );
2652   if ( Nt.Dot( upDir ) < 0 ) {
2653     DUMPSO( "Reverse top face");
2654     swap( 5, 7, idNodes, P );
2655   }
2656
2657   //   DUMPSO( "OUTPUT: ========================================");
2658   //   for ( i = 0; i < 8; i++ ) {
2659   //     float *p = ugrid->GetPoint(idNodes[i]);
2660   //     DUMPSO( i << "(" << idNodes[i] << ") : " << p[0] << " " << p[1] << " " << p[2]);
2661   //   }
2662
2663   return true;
2664 }*/
2665
2666 //================================================================================
2667 /*!
2668  * \brief Return nodes linked to the given one
2669  * \param theNode - the node
2670  * \param linkedNodes - the found nodes
2671  * \param type - the type of elements to check
2672  *
2673  * Medium nodes are ignored
2674  */
2675 //================================================================================
2676
2677 void SMESH_MeshEditor::GetLinkedNodes( const SMDS_MeshNode* theNode,
2678                                        TIDSortedElemSet &   linkedNodes,
2679                                        SMDSAbs_ElementType  type )
2680 {
2681   SMDS_ElemIteratorPtr elemIt = theNode->GetInverseElementIterator(type);
2682   while ( elemIt->more() )
2683   {
2684     const SMDS_MeshElement* elem = elemIt->next();
2685     if(elem->GetType() == SMDSAbs_0DElement)
2686       continue;
2687     
2688     SMDS_ElemIteratorPtr nodeIt = elem->nodesIterator();
2689     if ( elem->GetType() == SMDSAbs_Volume )
2690     {
2691       SMDS_VolumeTool vol( elem );
2692       while ( nodeIt->more() ) {
2693         const SMDS_MeshNode* n = cast2Node( nodeIt->next() );
2694         if ( theNode != n && vol.IsLinked( theNode, n ))
2695           linkedNodes.insert( n );
2696       }
2697     }
2698     else
2699     {
2700       for ( int i = 0; nodeIt->more(); ++i ) {
2701         const SMDS_MeshNode* n = cast2Node( nodeIt->next() );
2702         if ( n == theNode ) {
2703           int iBefore = i - 1;
2704           int iAfter  = i + 1;
2705           if ( elem->IsQuadratic() ) {
2706             int nb = elem->NbNodes() / 2;
2707             iAfter  = SMESH_MesherHelper::WrapIndex( iAfter, nb );
2708             iBefore = SMESH_MesherHelper::WrapIndex( iBefore, nb );
2709           }
2710           linkedNodes.insert( elem->GetNodeWrap( iAfter ));
2711           linkedNodes.insert( elem->GetNodeWrap( iBefore ));
2712         }
2713       }
2714     }
2715   }
2716 }
2717
2718 //=======================================================================
2719 //function : laplacianSmooth
2720 //purpose  : pulls theNode toward the center of surrounding nodes directly
2721 //           connected to that node along an element edge
2722 //=======================================================================
2723
2724 void laplacianSmooth(const SMDS_MeshNode*                 theNode,
2725                      const Handle(Geom_Surface)&          theSurface,
2726                      map< const SMDS_MeshNode*, gp_XY* >& theUVMap)
2727 {
2728   // find surrounding nodes
2729
2730   TIDSortedElemSet nodeSet;
2731   SMESH_MeshEditor::GetLinkedNodes( theNode, nodeSet, SMDSAbs_Face );
2732
2733   // compute new coodrs
2734
2735   double coord[] = { 0., 0., 0. };
2736   TIDSortedElemSet::iterator nodeSetIt = nodeSet.begin();
2737   for ( ; nodeSetIt != nodeSet.end(); nodeSetIt++ ) {
2738     const SMDS_MeshNode* node = cast2Node(*nodeSetIt);
2739     if ( theSurface.IsNull() ) { // smooth in 3D
2740       coord[0] += node->X();
2741       coord[1] += node->Y();
2742       coord[2] += node->Z();
2743     }
2744     else { // smooth in 2D
2745       ASSERT( theUVMap.find( node ) != theUVMap.end() );
2746       gp_XY* uv = theUVMap[ node ];
2747       coord[0] += uv->X();
2748       coord[1] += uv->Y();
2749     }
2750   }
2751   int nbNodes = nodeSet.size();
2752   if ( !nbNodes )
2753     return;
2754   coord[0] /= nbNodes;
2755   coord[1] /= nbNodes;
2756
2757   if ( !theSurface.IsNull() ) {
2758     ASSERT( theUVMap.find( theNode ) != theUVMap.end() );
2759     theUVMap[ theNode ]->SetCoord( coord[0], coord[1] );
2760     gp_Pnt p3d = theSurface->Value( coord[0], coord[1] );
2761     coord[0] = p3d.X();
2762     coord[1] = p3d.Y();
2763     coord[2] = p3d.Z();
2764   }
2765   else
2766     coord[2] /= nbNodes;
2767
2768   // move node
2769
2770   const_cast< SMDS_MeshNode* >( theNode )->setXYZ(coord[0],coord[1],coord[2]);
2771 }
2772
2773 //=======================================================================
2774 //function : centroidalSmooth
2775 //purpose  : pulls theNode toward the element-area-weighted centroid of the
2776 //           surrounding elements
2777 //=======================================================================
2778
2779 void centroidalSmooth(const SMDS_MeshNode*                 theNode,
2780                       const Handle(Geom_Surface)&          theSurface,
2781                       map< const SMDS_MeshNode*, gp_XY* >& theUVMap)
2782 {
2783   gp_XYZ aNewXYZ(0.,0.,0.);
2784   SMESH::Controls::Area anAreaFunc;
2785   double totalArea = 0.;
2786   int nbElems = 0;
2787
2788   // compute new XYZ
2789
2790   SMDS_ElemIteratorPtr elemIt = theNode->GetInverseElementIterator(SMDSAbs_Face);
2791   while ( elemIt->more() )
2792   {
2793     const SMDS_MeshElement* elem = elemIt->next();
2794     nbElems++;
2795
2796     gp_XYZ elemCenter(0.,0.,0.);
2797     SMESH::Controls::TSequenceOfXYZ aNodePoints;
2798     SMDS_ElemIteratorPtr itN = elem->nodesIterator();
2799     int nn = elem->NbNodes();
2800     if(elem->IsQuadratic()) nn = nn/2;
2801     int i=0;
2802     //while ( itN->more() ) {
2803     while ( i<nn ) {
2804       const SMDS_MeshNode* aNode = static_cast<const SMDS_MeshNode*>( itN->next() );
2805       i++;
2806       gp_XYZ aP( aNode->X(), aNode->Y(), aNode->Z() );
2807       aNodePoints.push_back( aP );
2808       if ( !theSurface.IsNull() ) { // smooth in 2D
2809         ASSERT( theUVMap.find( aNode ) != theUVMap.end() );
2810         gp_XY* uv = theUVMap[ aNode ];
2811         aP.SetCoord( uv->X(), uv->Y(), 0. );
2812       }
2813       elemCenter += aP;
2814     }
2815     double elemArea = anAreaFunc.GetValue( aNodePoints );
2816     totalArea += elemArea;
2817     elemCenter /= nn;
2818     aNewXYZ += elemCenter * elemArea;
2819   }
2820   aNewXYZ /= totalArea;
2821   if ( !theSurface.IsNull() ) {
2822     theUVMap[ theNode ]->SetCoord( aNewXYZ.X(), aNewXYZ.Y() );
2823     aNewXYZ = theSurface->Value( aNewXYZ.X(), aNewXYZ.Y() ).XYZ();
2824   }
2825
2826   // move node
2827
2828   const_cast< SMDS_MeshNode* >( theNode )->setXYZ(aNewXYZ.X(),aNewXYZ.Y(),aNewXYZ.Z());
2829 }
2830
2831 //=======================================================================
2832 //function : getClosestUV
2833 //purpose  : return UV of closest projection
2834 //=======================================================================
2835
2836 static bool getClosestUV (Extrema_GenExtPS& projector,
2837                           const gp_Pnt&     point,
2838                           gp_XY &           result)
2839 {
2840   projector.Perform( point );
2841   if ( projector.IsDone() ) {
2842     double u, v, minVal = DBL_MAX;
2843     for ( int i = projector.NbExt(); i > 0; i-- )
2844       if ( projector.Value( i ) < minVal ) {
2845         minVal = projector.Value( i );
2846         projector.Point( i ).Parameter( u, v );
2847       }
2848     result.SetCoord( u, v );
2849     return true;
2850   }
2851   return false;
2852 }
2853
2854 //=======================================================================
2855 //function : Smooth
2856 //purpose  : Smooth theElements during theNbIterations or until a worst
2857 //           element has aspect ratio <= theTgtAspectRatio.
2858 //           Aspect Ratio varies in range [1.0, inf].
2859 //           If theElements is empty, the whole mesh is smoothed.
2860 //           theFixedNodes contains additionally fixed nodes. Nodes built
2861 //           on edges and boundary nodes are always fixed.
2862 //=======================================================================
2863
2864 void SMESH_MeshEditor::Smooth (TIDSortedElemSet &          theElems,
2865                                set<const SMDS_MeshNode*> & theFixedNodes,
2866                                const SmoothMethod          theSmoothMethod,
2867                                const int                   theNbIterations,
2868                                double                      theTgtAspectRatio,
2869                                const bool                  the2D)
2870 {
2871   myLastCreatedElems.Clear();
2872   myLastCreatedNodes.Clear();
2873
2874   MESSAGE((theSmoothMethod==LAPLACIAN ? "LAPLACIAN" : "CENTROIDAL") << "--::Smooth()");
2875
2876   if ( theTgtAspectRatio < 1.0 )
2877     theTgtAspectRatio = 1.0;
2878
2879   const double disttol = 1.e-16;
2880
2881   SMESH::Controls::AspectRatio aQualityFunc;
2882
2883   SMESHDS_Mesh* aMesh = GetMeshDS();
2884
2885   if ( theElems.empty() ) {
2886     // add all faces to theElems
2887     SMDS_FaceIteratorPtr fIt = aMesh->facesIterator();
2888     while ( fIt->more() ) {
2889       const SMDS_MeshElement* face = fIt->next();
2890       theElems.insert( face );
2891     }
2892   }
2893   // get all face ids theElems are on
2894   set< int > faceIdSet;
2895   TIDSortedElemSet::iterator itElem;
2896   if ( the2D )
2897     for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
2898       int fId = FindShape( *itElem );
2899       // check that corresponding submesh exists and a shape is face
2900       if (fId &&
2901           faceIdSet.find( fId ) == faceIdSet.end() &&
2902           aMesh->MeshElements( fId )) {
2903         TopoDS_Shape F = aMesh->IndexToShape( fId );
2904         if ( !F.IsNull() && F.ShapeType() == TopAbs_FACE )
2905           faceIdSet.insert( fId );
2906       }
2907     }
2908   faceIdSet.insert( 0 ); // to smooth elements that are not on any TopoDS_Face
2909
2910   // ===============================================
2911   // smooth elements on each TopoDS_Face separately
2912   // ===============================================
2913
2914   set< int >::reverse_iterator fId = faceIdSet.rbegin(); // treate 0 fId at the end
2915   for ( ; fId != faceIdSet.rend(); ++fId ) {
2916     // get face surface and submesh
2917     Handle(Geom_Surface) surface;
2918     SMESHDS_SubMesh* faceSubMesh = 0;
2919     TopoDS_Face face;
2920     double fToler2 = 0, vPeriod = 0., uPeriod = 0., f,l;
2921     double u1 = 0, u2 = 0, v1 = 0, v2 = 0;
2922     bool isUPeriodic = false, isVPeriodic = false;
2923     if ( *fId ) {
2924       face = TopoDS::Face( aMesh->IndexToShape( *fId ));
2925       surface = BRep_Tool::Surface( face );
2926       faceSubMesh = aMesh->MeshElements( *fId );
2927       fToler2 = BRep_Tool::Tolerance( face );
2928       fToler2 *= fToler2 * 10.;
2929       isUPeriodic = surface->IsUPeriodic();
2930       if ( isUPeriodic )
2931         vPeriod = surface->UPeriod();
2932       isVPeriodic = surface->IsVPeriodic();
2933       if ( isVPeriodic )
2934         uPeriod = surface->VPeriod();
2935       surface->Bounds( u1, u2, v1, v2 );
2936     }
2937     // ---------------------------------------------------------
2938     // for elements on a face, find movable and fixed nodes and
2939     // compute UV for them
2940     // ---------------------------------------------------------
2941     bool checkBoundaryNodes = false;
2942     bool isQuadratic = false;
2943     set<const SMDS_MeshNode*> setMovableNodes;
2944     map< const SMDS_MeshNode*, gp_XY* > uvMap, uvMap2;
2945     list< gp_XY > listUV; // uvs the 2 uvMaps refer to
2946     list< const SMDS_MeshElement* > elemsOnFace;
2947
2948     Extrema_GenExtPS projector;
2949     GeomAdaptor_Surface surfAdaptor;
2950     if ( !surface.IsNull() ) {
2951       surfAdaptor.Load( surface );
2952       projector.Initialize( surfAdaptor, 20,20, 1e-5,1e-5 );
2953     }
2954     int nbElemOnFace = 0;
2955     itElem = theElems.begin();
2956     // loop on not yet smoothed elements: look for elems on a face
2957     while ( itElem != theElems.end() ) {
2958       if ( faceSubMesh && nbElemOnFace == faceSubMesh->NbElements() )
2959         break; // all elements found
2960
2961       const SMDS_MeshElement* elem = *itElem;
2962       if ( !elem || elem->GetType() != SMDSAbs_Face || elem->NbNodes() < 3 ||
2963            ( faceSubMesh && !faceSubMesh->Contains( elem ))) {
2964         ++itElem;
2965         continue;
2966       }
2967       elemsOnFace.push_back( elem );
2968       theElems.erase( itElem++ );
2969       nbElemOnFace++;
2970
2971       if ( !isQuadratic )
2972         isQuadratic = elem->IsQuadratic();
2973
2974       // get movable nodes of elem
2975       const SMDS_MeshNode* node;
2976       SMDS_TypeOfPosition posType;
2977       SMDS_ElemIteratorPtr itN = elem->nodesIterator();
2978       int nn = 0, nbn =  elem->NbNodes();
2979       if(elem->IsQuadratic())
2980         nbn = nbn/2;
2981       while ( nn++ < nbn ) {
2982         node = static_cast<const SMDS_MeshNode*>( itN->next() );
2983         const SMDS_PositionPtr& pos = node->GetPosition();
2984         posType = pos ? pos->GetTypeOfPosition() : SMDS_TOP_3DSPACE;
2985         if (posType != SMDS_TOP_EDGE &&
2986             posType != SMDS_TOP_VERTEX &&
2987             theFixedNodes.find( node ) == theFixedNodes.end())
2988         {
2989           // check if all faces around the node are on faceSubMesh
2990           // because a node on edge may be bound to face
2991           SMDS_ElemIteratorPtr eIt = node->GetInverseElementIterator(SMDSAbs_Face);
2992           bool all = true;
2993           if ( faceSubMesh ) {
2994             while ( eIt->more() && all ) {
2995               const SMDS_MeshElement* e = eIt->next();
2996               all = faceSubMesh->Contains( e );
2997             }
2998           }
2999           if ( all )
3000             setMovableNodes.insert( node );
3001           else
3002             checkBoundaryNodes = true;
3003         }
3004         if ( posType == SMDS_TOP_3DSPACE )
3005           checkBoundaryNodes = true;
3006       }
3007
3008       if ( surface.IsNull() )
3009         continue;
3010
3011       // get nodes to check UV
3012       list< const SMDS_MeshNode* > uvCheckNodes;
3013       itN = elem->nodesIterator();
3014       nn = 0; nbn =  elem->NbNodes();
3015       if(elem->IsQuadratic())
3016         nbn = nbn/2;
3017       while ( nn++ < nbn ) {
3018         node = static_cast<const SMDS_MeshNode*>( itN->next() );
3019         if ( uvMap.find( node ) == uvMap.end() )
3020           uvCheckNodes.push_back( node );
3021         // add nodes of elems sharing node
3022         //         SMDS_ElemIteratorPtr eIt = node->GetInverseElementIterator(SMDSAbs_Face);
3023         //         while ( eIt->more() ) {
3024         //           const SMDS_MeshElement* e = eIt->next();
3025         //           if ( e != elem ) {
3026         //             SMDS_ElemIteratorPtr nIt = e->nodesIterator();
3027         //             while ( nIt->more() ) {
3028         //               const SMDS_MeshNode* n =
3029         //                 static_cast<const SMDS_MeshNode*>( nIt->next() );
3030         //               if ( uvMap.find( n ) == uvMap.end() )
3031         //                 uvCheckNodes.push_back( n );
3032         //             }
3033         //           }
3034         //         }
3035       }
3036       // check UV on face
3037       list< const SMDS_MeshNode* >::iterator n = uvCheckNodes.begin();
3038       for ( ; n != uvCheckNodes.end(); ++n ) {
3039         node = *n;
3040         gp_XY uv( 0, 0 );
3041         const SMDS_PositionPtr& pos = node->GetPosition();
3042         posType = pos ? pos->GetTypeOfPosition() : SMDS_TOP_3DSPACE;
3043         // get existing UV
3044         switch ( posType ) {
3045         case SMDS_TOP_FACE: {
3046           SMDS_FacePosition* fPos = ( SMDS_FacePosition* ) pos;
3047           uv.SetCoord( fPos->GetUParameter(), fPos->GetVParameter() );
3048           break;
3049         }
3050         case SMDS_TOP_EDGE: {
3051           TopoDS_Shape S = aMesh->IndexToShape( node->getshapeId() );
3052           Handle(Geom2d_Curve) pcurve;
3053           if ( !S.IsNull() && S.ShapeType() == TopAbs_EDGE )
3054             pcurve = BRep_Tool::CurveOnSurface( TopoDS::Edge( S ), face, f,l );
3055           if ( !pcurve.IsNull() ) {
3056             double u = (( SMDS_EdgePosition* ) pos )->GetUParameter();
3057             uv = pcurve->Value( u ).XY();
3058           }
3059           break;
3060         }
3061         case SMDS_TOP_VERTEX: {
3062           TopoDS_Shape S = aMesh->IndexToShape( node->getshapeId() );
3063           if ( !S.IsNull() && S.ShapeType() == TopAbs_VERTEX )
3064             uv = BRep_Tool::Parameters( TopoDS::Vertex( S ), face ).XY();
3065           break;
3066         }
3067         default:;
3068         }
3069         // check existing UV
3070         bool project = true;
3071         gp_Pnt pNode ( node->X(), node->Y(), node->Z() );
3072         double dist1 = DBL_MAX, dist2 = 0;
3073         if ( posType != SMDS_TOP_3DSPACE ) {
3074           dist1 = pNode.SquareDistance( surface->Value( uv.X(), uv.Y() ));
3075           project = dist1 > fToler2;
3076         }
3077         if ( project ) { // compute new UV
3078           gp_XY newUV;
3079           if ( !getClosestUV( projector, pNode, newUV )) {
3080             MESSAGE("Node Projection Failed " << node);
3081           }
3082           else {
3083             if ( isUPeriodic )
3084               newUV.SetX( ElCLib::InPeriod( newUV.X(), u1, u2 ));
3085             if ( isVPeriodic )
3086               newUV.SetY( ElCLib::InPeriod( newUV.Y(), v1, v2 ));
3087             // check new UV
3088             if ( posType != SMDS_TOP_3DSPACE )
3089               dist2 = pNode.SquareDistance( surface->Value( newUV.X(), newUV.Y() ));
3090             if ( dist2 < dist1 )
3091               uv = newUV;
3092           }
3093         }
3094         // store UV in the map
3095         listUV.push_back( uv );
3096         uvMap.insert( make_pair( node, &listUV.back() ));
3097       }
3098     } // loop on not yet smoothed elements
3099
3100     if ( !faceSubMesh || nbElemOnFace != faceSubMesh->NbElements() )
3101       checkBoundaryNodes = true;
3102
3103     // fix nodes on mesh boundary
3104
3105     if ( checkBoundaryNodes ) {
3106       map< NLink, int > linkNbMap; // how many times a link encounters in elemsOnFace
3107       map< NLink, int >::iterator link_nb;
3108       // put all elements links to linkNbMap
3109       list< const SMDS_MeshElement* >::iterator elemIt = elemsOnFace.begin();
3110       for ( ; elemIt != elemsOnFace.end(); ++elemIt ) {
3111         const SMDS_MeshElement* elem = (*elemIt);
3112         int nbn =  elem->NbNodes();
3113         if(elem->IsQuadratic())
3114           nbn = nbn/2;
3115         // loop on elem links: insert them in linkNbMap
3116         const SMDS_MeshNode* curNode, *prevNode = elem->GetNodeWrap( nbn );
3117         for ( int iN = 0; iN < nbn; ++iN ) {
3118           curNode = elem->GetNode( iN );
3119           NLink link;
3120           if ( curNode < prevNode ) link = make_pair( curNode , prevNode );
3121           else                      link = make_pair( prevNode , curNode );
3122           prevNode = curNode;
3123           link_nb = linkNbMap.find( link );
3124           if ( link_nb == linkNbMap.end() )
3125             linkNbMap.insert( make_pair ( link, 1 ));
3126           else
3127             link_nb->second++;
3128         }
3129       }
3130       // remove nodes that are in links encountered only once from setMovableNodes
3131       for ( link_nb = linkNbMap.begin(); link_nb != linkNbMap.end(); ++link_nb ) {
3132         if ( link_nb->second == 1 ) {
3133           setMovableNodes.erase( link_nb->first.first );
3134           setMovableNodes.erase( link_nb->first.second );
3135         }
3136       }
3137     }
3138
3139     // -----------------------------------------------------
3140     // for nodes on seam edge, compute one more UV ( uvMap2 );
3141     // find movable nodes linked to nodes on seam and which
3142     // are to be smoothed using the second UV ( uvMap2 )
3143     // -----------------------------------------------------
3144
3145     set<const SMDS_MeshNode*> nodesNearSeam; // to smooth using uvMap2
3146     if ( !surface.IsNull() ) {
3147       TopExp_Explorer eExp( face, TopAbs_EDGE );
3148       for ( ; eExp.More(); eExp.Next() ) {
3149         TopoDS_Edge edge = TopoDS::Edge( eExp.Current() );
3150         if ( !BRep_Tool::IsClosed( edge, face ))
3151           continue;
3152         SMESHDS_SubMesh* sm = aMesh->MeshElements( edge );
3153         if ( !sm ) continue;
3154         // find out which parameter varies for a node on seam
3155         double f,l;
3156         gp_Pnt2d uv1, uv2;
3157         Handle(Geom2d_Curve) pcurve = BRep_Tool::CurveOnSurface( edge, face, f, l );
3158         if ( pcurve.IsNull() ) continue;
3159         uv1 = pcurve->Value( f );
3160         edge.Reverse();
3161         pcurve = BRep_Tool::CurveOnSurface( edge, face, f, l );
3162         if ( pcurve.IsNull() ) continue;
3163         uv2 = pcurve->Value( f );
3164         int iPar = Abs( uv1.X() - uv2.X() ) > Abs( uv1.Y() - uv2.Y() ) ? 1 : 2;
3165         // assure uv1 < uv2
3166         if ( uv1.Coord( iPar ) > uv2.Coord( iPar )) {
3167           gp_Pnt2d tmp = uv1; uv1 = uv2; uv2 = tmp;
3168         }
3169         // get nodes on seam and its vertices
3170         list< const SMDS_MeshNode* > seamNodes;
3171         SMDS_NodeIteratorPtr nSeamIt = sm->GetNodes();
3172         while ( nSeamIt->more() ) {
3173           const SMDS_MeshNode* node = nSeamIt->next();
3174           if ( !isQuadratic || !IsMedium( node ))
3175             seamNodes.push_back( node );
3176         }
3177         TopExp_Explorer vExp( edge, TopAbs_VERTEX );
3178         for ( ; vExp.More(); vExp.Next() ) {
3179           sm = aMesh->MeshElements( vExp.Current() );
3180           if ( sm ) {
3181             nSeamIt = sm->GetNodes();
3182             while ( nSeamIt->more() )
3183               seamNodes.push_back( nSeamIt->next() );
3184           }
3185         }
3186         // loop on nodes on seam
3187         list< const SMDS_MeshNode* >::iterator noSeIt = seamNodes.begin();
3188         for ( ; noSeIt != seamNodes.end(); ++noSeIt ) {
3189           const SMDS_MeshNode* nSeam = *noSeIt;
3190           map< const SMDS_MeshNode*, gp_XY* >::iterator n_uv = uvMap.find( nSeam );
3191           if ( n_uv == uvMap.end() )
3192             continue;
3193           // set the first UV
3194           n_uv->second->SetCoord( iPar, uv1.Coord( iPar ));
3195           // set the second UV
3196           listUV.push_back( *n_uv->second );
3197           listUV.back().SetCoord( iPar, uv2.Coord( iPar ));
3198           if ( uvMap2.empty() )
3199             uvMap2 = uvMap; // copy the uvMap contents
3200           uvMap2[ nSeam ] = &listUV.back();
3201
3202           // collect movable nodes linked to ones on seam in nodesNearSeam
3203           SMDS_ElemIteratorPtr eIt = nSeam->GetInverseElementIterator(SMDSAbs_Face);
3204           while ( eIt->more() ) {
3205             const SMDS_MeshElement* e = eIt->next();
3206             int nbUseMap1 = 0, nbUseMap2 = 0;
3207             SMDS_ElemIteratorPtr nIt = e->nodesIterator();
3208             int nn = 0, nbn =  e->NbNodes();
3209             if(e->IsQuadratic()) nbn = nbn/2;
3210             while ( nn++ < nbn )
3211             {
3212               const SMDS_MeshNode* n =
3213                 static_cast<const SMDS_MeshNode*>( nIt->next() );
3214               if (n == nSeam ||
3215                   setMovableNodes.find( n ) == setMovableNodes.end() )
3216                 continue;
3217               // add only nodes being closer to uv2 than to uv1
3218               gp_Pnt pMid (0.5 * ( n->X() + nSeam->X() ),
3219                            0.5 * ( n->Y() + nSeam->Y() ),
3220                            0.5 * ( n->Z() + nSeam->Z() ));
3221               gp_XY uv;
3222               getClosestUV( projector, pMid, uv );
3223               if ( uv.Coord( iPar ) > uvMap[ n ]->Coord( iPar ) ) {
3224                 nodesNearSeam.insert( n );
3225                 nbUseMap2++;
3226               }
3227               else
3228                 nbUseMap1++;
3229             }
3230             // for centroidalSmooth all element nodes must
3231             // be on one side of a seam
3232             if ( theSmoothMethod == CENTROIDAL && nbUseMap1 && nbUseMap2 ) {
3233               SMDS_ElemIteratorPtr nIt = e->nodesIterator();
3234               nn = 0;
3235               while ( nn++ < nbn ) {
3236                 const SMDS_MeshNode* n =
3237                   static_cast<const SMDS_MeshNode*>( nIt->next() );
3238                 setMovableNodes.erase( n );
3239               }
3240             }
3241           }
3242         } // loop on nodes on seam
3243       } // loop on edge of a face
3244     } // if ( !face.IsNull() )
3245
3246     if ( setMovableNodes.empty() ) {
3247       MESSAGE( "Face id : " << *fId << " - NO SMOOTHING: no nodes to move!!!");
3248       continue; // goto next face
3249     }
3250
3251     // -------------
3252     // SMOOTHING //
3253     // -------------
3254
3255     int it = -1;
3256     double maxRatio = -1., maxDisplacement = -1.;
3257     set<const SMDS_MeshNode*>::iterator nodeToMove;
3258     for ( it = 0; it < theNbIterations; it++ ) {
3259       maxDisplacement = 0.;
3260       nodeToMove = setMovableNodes.begin();
3261       for ( ; nodeToMove != setMovableNodes.end(); nodeToMove++ ) {
3262         const SMDS_MeshNode* node = (*nodeToMove);
3263         gp_XYZ aPrevPos ( node->X(), node->Y(), node->Z() );
3264
3265         // smooth
3266         bool map2 = ( nodesNearSeam.find( node ) != nodesNearSeam.end() );
3267         if ( theSmoothMethod == LAPLACIAN )
3268           laplacianSmooth( node, surface, map2 ? uvMap2 : uvMap );
3269         else
3270           centroidalSmooth( node, surface, map2 ? uvMap2 : uvMap );
3271
3272         // node displacement
3273         gp_XYZ aNewPos ( node->X(), node->Y(), node->Z() );
3274         Standard_Real aDispl = (aPrevPos - aNewPos).SquareModulus();
3275         if ( aDispl > maxDisplacement )
3276           maxDisplacement = aDispl;
3277       }
3278       // no node movement => exit
3279       //if ( maxDisplacement < 1.e-16 ) {
3280       if ( maxDisplacement < disttol ) {
3281         MESSAGE("-- no node movement --");
3282         break;
3283       }
3284
3285       // check elements quality
3286       maxRatio  = 0;
3287       list< const SMDS_MeshElement* >::iterator elemIt = elemsOnFace.begin();
3288       for ( ; elemIt != elemsOnFace.end(); ++elemIt ) {
3289         const SMDS_MeshElement* elem = (*elemIt);
3290         if ( !elem || elem->GetType() != SMDSAbs_Face )
3291           continue;
3292         SMESH::Controls::TSequenceOfXYZ aPoints;
3293         if ( aQualityFunc.GetPoints( elem, aPoints )) {
3294           double aValue = aQualityFunc.GetValue( aPoints );
3295           if ( aValue > maxRatio )
3296             maxRatio = aValue;
3297         }
3298       }
3299       if ( maxRatio <= theTgtAspectRatio ) {
3300         MESSAGE("-- quality achived --");
3301         break;
3302       }
3303       if (it+1 == theNbIterations) {
3304         MESSAGE("-- Iteration limit exceeded --");
3305       }
3306     } // smoothing iterations
3307
3308     MESSAGE(" Face id: " << *fId <<
3309             " Nb iterstions: " << it <<
3310             " Displacement: " << maxDisplacement <<
3311             " Aspect Ratio " << maxRatio);
3312
3313     // ---------------------------------------
3314     // new nodes positions are computed,
3315     // record movement in DS and set new UV
3316     // ---------------------------------------
3317     nodeToMove = setMovableNodes.begin();
3318     for ( ; nodeToMove != setMovableNodes.end(); nodeToMove++ ) {
3319       SMDS_MeshNode* node = const_cast< SMDS_MeshNode* > (*nodeToMove);
3320       aMesh->MoveNode( node, node->X(), node->Y(), node->Z() );
3321       map< const SMDS_MeshNode*, gp_XY* >::iterator node_uv = uvMap.find( node );
3322       if ( node_uv != uvMap.end() ) {
3323         gp_XY* uv = node_uv->second;
3324         node->SetPosition
3325           ( SMDS_PositionPtr( new SMDS_FacePosition( uv->X(), uv->Y() )));
3326       }
3327     }
3328
3329     // move medium nodes of quadratic elements
3330     if ( isQuadratic )
3331     {
3332       SMESH_MesherHelper helper( *GetMesh() );
3333       if ( !face.IsNull() )
3334         helper.SetSubShape( face );
3335       list< const SMDS_MeshElement* >::iterator elemIt = elemsOnFace.begin();
3336       for ( ; elemIt != elemsOnFace.end(); ++elemIt ) {
3337         const SMDS_VtkFace* QF =
3338           dynamic_cast<const SMDS_VtkFace*> (*elemIt);
3339         if(QF && QF->IsQuadratic()) {
3340           vector<const SMDS_MeshNode*> Ns;
3341           Ns.reserve(QF->NbNodes()+1);
3342           SMDS_ElemIteratorPtr anIter = QF->interlacedNodesElemIterator();
3343           while ( anIter->more() )
3344             Ns.push_back( cast2Node(anIter->next()) );
3345           Ns.push_back( Ns[0] );
3346           double x, y, z;
3347           for(int i=0; i<QF->NbNodes(); i=i+2) {
3348             if ( !surface.IsNull() ) {
3349               gp_XY uv1 = helper.GetNodeUV( face, Ns[i], Ns[i+2] );
3350               gp_XY uv2 = helper.GetNodeUV( face, Ns[i+2], Ns[i] );
3351               gp_XY uv = ( uv1 + uv2 ) / 2.;
3352               gp_Pnt xyz = surface->Value( uv.X(), uv.Y() );
3353               x = xyz.X(); y = xyz.Y(); z = xyz.Z();
3354             }
3355             else {
3356               x = (Ns[i]->X() + Ns[i+2]->X())/2;
3357               y = (Ns[i]->Y() + Ns[i+2]->Y())/2;
3358               z = (Ns[i]->Z() + Ns[i+2]->Z())/2;
3359             }
3360             if( fabs( Ns[i+1]->X() - x ) > disttol ||
3361                 fabs( Ns[i+1]->Y() - y ) > disttol ||
3362                 fabs( Ns[i+1]->Z() - z ) > disttol ) {
3363               // we have to move i+1 node
3364               aMesh->MoveNode( Ns[i+1], x, y, z );
3365             }
3366           }
3367         }
3368       }
3369     }
3370
3371   } // loop on face ids
3372
3373 }
3374
3375 //=======================================================================
3376 //function : isReverse
3377 //purpose  : Return true if normal of prevNodes is not co-directied with
3378 //           gp_Vec(prevNodes[iNotSame],nextNodes[iNotSame]).
3379 //           iNotSame is where prevNodes and nextNodes are different
3380 //=======================================================================
3381
3382 static bool isReverse(vector<const SMDS_MeshNode*> prevNodes,
3383                       vector<const SMDS_MeshNode*> nextNodes,
3384                       const int            nbNodes,
3385                       const int            iNotSame)
3386 {
3387   int iBeforeNotSame = ( iNotSame == 0 ? nbNodes - 1 : iNotSame - 1 );
3388   int iAfterNotSame  = ( iNotSame + 1 == nbNodes ? 0 : iNotSame + 1 );
3389
3390   const SMDS_MeshNode* nB = prevNodes[ iBeforeNotSame ];
3391   const SMDS_MeshNode* nA = prevNodes[ iAfterNotSame ];
3392   const SMDS_MeshNode* nP = prevNodes[ iNotSame ];
3393   const SMDS_MeshNode* nN = nextNodes[ iNotSame ];
3394
3395   gp_Pnt pB ( nB->X(), nB->Y(), nB->Z() );
3396   gp_Pnt pA ( nA->X(), nA->Y(), nA->Z() );
3397   gp_Pnt pP ( nP->X(), nP->Y(), nP->Z() );
3398   gp_Pnt pN ( nN->X(), nN->Y(), nN->Z() );
3399
3400   gp_Vec vB ( pP, pB ), vA ( pP, pA ), vN ( pP, pN );
3401
3402   return (vA ^ vB) * vN < 0.0;
3403 }
3404
3405 //=======================================================================
3406 /*!
3407  * \brief Create elements by sweeping an element
3408  * \param elem - element to sweep
3409  * \param newNodesItVec - nodes generated from each node of the element
3410  * \param newElems - generated elements
3411  * \param nbSteps - number of sweeping steps
3412  * \param srcElements - to append elem for each generated element
3413  */
3414 //=======================================================================
3415
3416 void SMESH_MeshEditor::sweepElement(const SMDS_MeshElement*               elem,
3417                                     const vector<TNodeOfNodeListMapItr> & newNodesItVec,
3418                                     list<const SMDS_MeshElement*>&        newElems,
3419                                     const int                             nbSteps,
3420                                     SMESH_SequenceOfElemPtr&              srcElements)
3421 {
3422   //MESSAGE("sweepElement " << nbSteps);
3423   SMESHDS_Mesh* aMesh = GetMeshDS();
3424
3425   // Loop on elem nodes:
3426   // find new nodes and detect same nodes indices
3427   int nbNodes = elem->NbNodes();
3428   vector < list< const SMDS_MeshNode* >::const_iterator > itNN( nbNodes );
3429   vector<const SMDS_MeshNode*> prevNod( nbNodes );
3430   vector<const SMDS_MeshNode*> nextNod( nbNodes );
3431   vector<const SMDS_MeshNode*> midlNod( nbNodes );
3432
3433   int iNode, nbSame = 0, iNotSameNode = 0, iSameNode = 0;
3434   vector<int> sames(nbNodes);
3435   vector<bool> issimple(nbNodes);
3436
3437   for ( iNode = 0; iNode < nbNodes; iNode++ ) {
3438     TNodeOfNodeListMapItr nnIt = newNodesItVec[ iNode ];
3439     const SMDS_MeshNode*                 node         = nnIt->first;
3440     const list< const SMDS_MeshNode* > & listNewNodes = nnIt->second;
3441     if ( listNewNodes.empty() ) {
3442       return;
3443     }
3444
3445     issimple[iNode] = (listNewNodes.size()==nbSteps); // is node medium
3446
3447     itNN[ iNode ] = listNewNodes.begin();
3448     prevNod[ iNode ] = node;
3449     nextNod[ iNode ] = listNewNodes.front();
3450     if( !elem->IsQuadratic() || !issimple[iNode] ) {
3451       if ( prevNod[ iNode ] != nextNod [ iNode ])
3452         iNotSameNode = iNode;
3453       else {
3454         iSameNode = iNode;
3455         //nbSame++;
3456         sames[nbSame++] = iNode;
3457       }
3458     }
3459   }
3460
3461   //cerr<<"  nbSame = "<<nbSame<<endl;
3462   if ( nbSame == nbNodes || nbSame > 2) {
3463     MESSAGE( " Too many same nodes of element " << elem->GetID() );
3464     //INFOS( " Too many same nodes of element " << elem->GetID() );
3465     return;
3466   }
3467
3468   //  if( elem->IsQuadratic() && nbSame>0 ) {
3469   //    MESSAGE( "Can not rotate quadratic element " << elem->GetID() );
3470   //    return;
3471   //  }
3472
3473   int iBeforeSame = 0, iAfterSame = 0, iOpposSame = 0;
3474   int nbBaseNodes = ( elem->IsQuadratic() ? nbNodes/2 : nbNodes );
3475   if ( nbSame > 0 ) {
3476     iBeforeSame = ( iSameNode == 0 ? nbBaseNodes - 1 : iSameNode - 1 );
3477     iAfterSame  = ( iSameNode + 1 == nbBaseNodes ? 0 : iSameNode + 1 );
3478     iOpposSame  = ( iSameNode - 2 < 0  ? iSameNode + 2 : iSameNode - 2 );
3479   }
3480
3481   //if(nbNodes==8)
3482   //cout<<" prevNod[0]="<< prevNod[0]<<" prevNod[1]="<< prevNod[1]
3483   //    <<" prevNod[2]="<< prevNod[2]<<" prevNod[3]="<< prevNod[4]
3484   //    <<" prevNod[4]="<< prevNod[4]<<" prevNod[5]="<< prevNod[5]
3485   //    <<" prevNod[6]="<< prevNod[6]<<" prevNod[7]="<< prevNod[7]<<endl;
3486
3487   // check element orientation
3488   int i0 = 0, i2 = 2;
3489   if ( nbNodes > 2 && !isReverse( prevNod, nextNod, nbNodes, iNotSameNode )) {
3490     //MESSAGE("Reversed elem " << elem );
3491     i0 = 2;
3492     i2 = 0;
3493     if ( nbSame > 0 )
3494       std::swap( iBeforeSame, iAfterSame );
3495   }
3496
3497   // make new elements
3498   const SMDS_MeshElement* lastElem = elem;
3499   for (int iStep = 0; iStep < nbSteps; iStep++ ) {
3500     // get next nodes
3501     for ( iNode = 0; iNode < nbNodes; iNode++ ) {
3502       if(issimple[iNode]) {
3503         nextNod[ iNode ] = *itNN[ iNode ];
3504         itNN[ iNode ]++;
3505       }
3506       else {
3507         if( elem->GetType()==SMDSAbs_Node ) {
3508           // we have to use two nodes
3509           midlNod[ iNode ] = *itNN[ iNode ];
3510           itNN[ iNode ]++;
3511           nextNod[ iNode ] = *itNN[ iNode ];
3512           itNN[ iNode ]++;
3513         }
3514         else if(!elem->IsQuadratic() || lastElem->IsMediumNode(prevNod[iNode]) ) {
3515           // we have to use each second node
3516           //itNN[ iNode ]++;
3517           nextNod[ iNode ] = *itNN[ iNode ];
3518           itNN[ iNode ]++;
3519         }
3520         else {
3521           // we have to use two nodes
3522           midlNod[ iNode ] = *itNN[ iNode ];
3523           itNN[ iNode ]++;
3524           nextNod[ iNode ] = *itNN[ iNode ];
3525           itNN[ iNode ]++;
3526         }
3527       }
3528     }
3529     SMDS_MeshElement* aNewElem = 0;
3530     if(!elem->IsPoly()) {
3531       switch ( nbNodes ) {
3532       case 0:
3533         return;
3534       case 1: { // NODE
3535         if ( nbSame == 0 ) {
3536           if(issimple[0])
3537             aNewElem = aMesh->AddEdge( prevNod[ 0 ], nextNod[ 0 ] );
3538           else
3539             aNewElem = aMesh->AddEdge( prevNod[ 0 ], nextNod[ 0 ], midlNod[ 0 ] );
3540         }
3541         break;
3542       }
3543       case 2: { // EDGE
3544         if ( nbSame == 0 )
3545           aNewElem = aMesh->AddFace(prevNod[ 0 ], prevNod[ 1 ],
3546                                     nextNod[ 1 ], nextNod[ 0 ] );
3547         else
3548           aNewElem = aMesh->AddFace(prevNod[ 0 ], prevNod[ 1 ],
3549                                     nextNod[ iNotSameNode ] );
3550         break;
3551       }
3552
3553       case 3: { // TRIANGLE or quadratic edge
3554         if(elem->GetType() == SMDSAbs_Face) { // TRIANGLE
3555
3556           if ( nbSame == 0 )       // --- pentahedron
3557             aNewElem = aMesh->AddVolume (prevNod[ i0 ], prevNod[ 1 ], prevNod[ i2 ],
3558                                          nextNod[ i0 ], nextNod[ 1 ], nextNod[ i2 ] );
3559
3560           else if ( nbSame == 1 )  // --- pyramid
3561             aNewElem = aMesh->AddVolume (prevNod[ iBeforeSame ],  prevNod[ iAfterSame ],
3562                                          nextNod[ iAfterSame ], nextNod[ iBeforeSame ],
3563                                          nextNod[ iSameNode ]);
3564
3565           else // 2 same nodes:      --- tetrahedron
3566             aNewElem = aMesh->AddVolume (prevNod[ i0 ], prevNod[ 1 ], prevNod[ i2 ],
3567                                          nextNod[ iNotSameNode ]);
3568         }
3569         else { // quadratic edge
3570           if(nbSame==0) {     // quadratic quadrangle
3571             aNewElem = aMesh->AddFace(prevNod[0], nextNod[0], nextNod[1], prevNod[1],
3572                                       midlNod[0], nextNod[2], midlNod[1], prevNod[2]);
3573           }
3574           else if(nbSame==1) { // quadratic triangle
3575             if(sames[0]==2) {
3576               return; // medium node on axis
3577             }
3578             else if(sames[0]==0) {
3579               aNewElem = aMesh->AddFace(prevNod[0], nextNod[1], prevNod[1],
3580                                         nextNod[2], midlNod[1], prevNod[2]);
3581             }
3582             else { // sames[0]==1
3583               aNewElem = aMesh->AddFace(prevNod[0], nextNod[0], prevNod[1],
3584                                         midlNod[0], nextNod[2], prevNod[2]);
3585             }
3586           }
3587           else {
3588             return;
3589           }
3590         }
3591         break;
3592       }
3593       case 4: { // QUADRANGLE
3594
3595         if ( nbSame == 0 )       // --- hexahedron
3596           aNewElem = aMesh->AddVolume (prevNod[ i0 ], prevNod[ 1 ], prevNod[ i2 ], prevNod[ 3 ],
3597                                        nextNod[ i0 ], nextNod[ 1 ], nextNod[ i2 ], nextNod[ 3 ]);
3598
3599         else if ( nbSame == 1 ) { // --- pyramid + pentahedron
3600           aNewElem = aMesh->AddVolume (prevNod[ iBeforeSame ],  prevNod[ iAfterSame ],
3601                                        nextNod[ iAfterSame ], nextNod[ iBeforeSame ],
3602                                        nextNod[ iSameNode ]);
3603           newElems.push_back( aNewElem );
3604           aNewElem = aMesh->AddVolume (prevNod[ iAfterSame ], prevNod[ iOpposSame ],
3605                                        prevNod[ iBeforeSame ],  nextNod[ iAfterSame ],
3606                                        nextNod[ iOpposSame ],  nextNod[ iBeforeSame ] );
3607         }
3608         else if ( nbSame == 2 ) { // pentahedron
3609           if ( prevNod[ iBeforeSame ] == nextNod[ iBeforeSame ] )
3610             // iBeforeSame is same too
3611             aNewElem = aMesh->AddVolume (prevNod[ iBeforeSame ], prevNod[ iOpposSame ],
3612                                          nextNod[ iOpposSame ], prevNod[ iSameNode ],
3613                                          prevNod[ iAfterSame ],  nextNod[ iAfterSame ]);
3614           else
3615             // iAfterSame is same too
3616             aNewElem = aMesh->AddVolume (prevNod[ iSameNode ], prevNod[ iBeforeSame ],
3617                                          nextNod[ iBeforeSame ], prevNod[ iAfterSame ],
3618                                          prevNod[ iOpposSame ],  nextNod[ iOpposSame ]);
3619         }
3620         break;
3621       }
3622       case 6: { // quadratic triangle
3623         // create pentahedron with 15 nodes
3624         if(nbSame==0) {
3625           if(i0>0) { // reversed case
3626             aNewElem = aMesh->AddVolume (prevNod[0], prevNod[2], prevNod[1],
3627                                          nextNod[0], nextNod[2], nextNod[1],
3628                                          prevNod[5], prevNod[4], prevNod[3],
3629                                          nextNod[5], nextNod[4], nextNod[3],
3630                                          midlNod[0], midlNod[2], midlNod[1]);
3631           }
3632           else { // not reversed case
3633             aNewElem = aMesh->AddVolume (prevNod[0], prevNod[1], prevNod[2],
3634                                          nextNod[0], nextNod[1], nextNod[2],
3635                                          prevNod[3], prevNod[4], prevNod[5],
3636                                          nextNod[3], nextNod[4], nextNod[5],
3637                                          midlNod[0], midlNod[1], midlNod[2]);
3638           }
3639         }
3640         else if(nbSame==1) {
3641           // 2d order pyramid of 13 nodes
3642           //SMDS_MeshVolume* AddVolumeWithID(int n1, int n2, int n3, int n4, int n5,
3643           //                                 int n12,int n23,int n34,int n41,
3644           //                                 int n15,int n25,int n35,int n45, int ID);
3645           int n5 = iSameNode;
3646           int n1,n4,n41,n15,n45;
3647           if(i0>0) { // reversed case
3648             n1 = ( n5 + 1 == nbBaseNodes ? 0 : n5 + 1 );
3649             n4 = ( n5 == 0 ? nbBaseNodes - 1 : n5 - 1 );
3650             n41 = n1 + 3;
3651             n15 = n5 + 3;
3652             n45 = n4 + 3;
3653           }
3654           else {
3655             n1 = ( n5 == 0 ? nbBaseNodes - 1 : n5 - 1 );
3656             n4 = ( n5 + 1 == nbBaseNodes ? 0 : n5 + 1 );
3657             n41 = n4 + 3;
3658             n15 = n1 + 3;
3659             n45 = n5 + 3;
3660           }
3661           aNewElem = aMesh->AddVolume(prevNod[n1], nextNod[n1],
3662                                       nextNod[n4], prevNod[n4], prevNod[n5],
3663                                       midlNod[n1], nextNod[n41],
3664                                       midlNod[n4], prevNod[n41],
3665                                       prevNod[n15], nextNod[n15],
3666                                       nextNod[n45], prevNod[n45]);
3667         }
3668         else if(nbSame==2) {
3669           // 2d order tetrahedron of 10 nodes
3670           //SMDS_MeshVolume* AddVolumeWithID(int n1, int n2, int n3, int n4,
3671           //                                 int n12,int n23,int n31,
3672           //                                 int n14,int n24,int n34, int ID);
3673           int n1 = iNotSameNode;
3674           int n2,n3,n12,n23,n31;
3675           if(i0>0) { // reversed case
3676             n2 = ( n1 == 0 ? nbBaseNodes - 1 : n1 - 1 );
3677             n3 = ( n1 + 1 == nbBaseNodes ? 0 : n1 + 1 );
3678             n12 = n2 + 3;
3679             n23 = n3 + 3;
3680             n31 = n1 + 3;
3681           }
3682           else {
3683             n2 = ( n1 + 1 == nbBaseNodes ? 0 : n1 + 1 );
3684             n3 = ( n1 == 0 ? nbBaseNodes - 1 : n1 - 1 );
3685             n12 = n1 + 3;
3686             n23 = n2 + 3;
3687             n31 = n3 + 3;
3688           }
3689           aNewElem = aMesh->AddVolume (prevNod[n1], prevNod[n2], prevNod[n3], nextNod[n1],
3690                                        prevNod[n12], prevNod[n23], prevNod[n31],
3691                                        midlNod[n1], nextNod[n12], nextNod[n31]);
3692         }
3693         break;
3694       }
3695       case 8: { // quadratic quadrangle
3696         if(nbSame==0) {
3697           // create hexahedron with 20 nodes
3698           if(i0>0) { // reversed case
3699             aNewElem = aMesh->AddVolume (prevNod[0], prevNod[3], prevNod[2], prevNod[1],
3700                                          nextNod[0], nextNod[3], nextNod[2], nextNod[1],
3701                                          prevNod[7], prevNod[6], prevNod[5], prevNod[4],
3702                                          nextNod[7], nextNod[6], nextNod[5], nextNod[4],
3703                                          midlNod[0], midlNod[3], midlNod[2], midlNod[1]);
3704           }
3705           else { // not reversed case
3706             aNewElem = aMesh->AddVolume (prevNod[0], prevNod[1], prevNod[2], prevNod[3],
3707                                          nextNod[0], nextNod[1], nextNod[2], nextNod[3],
3708                                          prevNod[4], prevNod[5], prevNod[6], prevNod[7],
3709                                          nextNod[4], nextNod[5], nextNod[6], nextNod[7],
3710                                          midlNod[0], midlNod[1], midlNod[2], midlNod[3]);
3711           }
3712         }
3713         else if(nbSame==1) { 
3714           // --- pyramid + pentahedron - can not be created since it is needed 
3715           // additional middle node ot the center of face
3716           INFOS( " Sweep for face " << elem->GetID() << " can not be created" );
3717           return;
3718         }
3719         else if(nbSame==2) {
3720           // 2d order Pentahedron with 15 nodes
3721           //SMDS_MeshVolume* AddVolumeWithID(int n1, int n2, int n3, int n4, int n5, int n6,
3722           //                                 int n12,int n23,int n31,int n45,int n56,int n64,
3723           //                                 int n14,int n25,int n36, int ID);
3724           int n1,n2,n4,n5;
3725           if ( prevNod[ iBeforeSame ] == nextNod[ iBeforeSame ] ) {
3726             // iBeforeSame is same too
3727             n1 = iBeforeSame;
3728             n2 = iOpposSame;
3729             n4 = iSameNode;
3730             n5 = iAfterSame;
3731           }
3732           else {
3733             // iAfterSame is same too
3734             n1 = iSameNode;
3735             n2 = iBeforeSame;
3736             n4 = iAfterSame;
3737             n5 = iOpposSame;
3738           }
3739           int n12,n45,n14,n25;
3740           if(i0>0) { //reversed case
3741             n12 = n1 + 4;
3742             n45 = n5 + 4;
3743             n14 = n4 + 4;
3744             n25 = n2 + 4;
3745           }
3746           else {
3747             n12 = n2 + 4;
3748             n45 = n4 + 4;
3749             n14 = n1 + 4;
3750             n25 = n5 + 4;
3751           }
3752           aNewElem = aMesh->AddVolume (prevNod[n1], prevNod[n2], nextNod[n2],
3753                                        prevNod[n4], prevNod[n5], nextNod[n5],
3754                                        prevNod[n12], midlNod[n2], nextNod[n12],
3755                                        prevNod[n45], midlNod[n5], nextNod[n45],
3756                                        prevNod[n14], prevNod[n25], nextNod[n25]);
3757         }
3758         break;
3759       }
3760       default: {
3761         // realized for extrusion only
3762         //vector<const SMDS_MeshNode*> polyedre_nodes (nbNodes*2 + 4*nbNodes);
3763         //vector<int> quantities (nbNodes + 2);
3764
3765         //quantities[0] = nbNodes; // bottom of prism
3766         //for (int inode = 0; inode < nbNodes; inode++) {
3767         //  polyedre_nodes[inode] = prevNod[inode];
3768         //}
3769
3770         //quantities[1] = nbNodes; // top of prism
3771         //for (int inode = 0; inode < nbNodes; inode++) {
3772         //  polyedre_nodes[nbNodes + inode] = nextNod[inode];
3773         //}
3774
3775         //for (int iface = 0; iface < nbNodes; iface++) {
3776         //  quantities[iface + 2] = 4;
3777         //  int inextface = (iface == nbNodes - 1) ? 0 : iface + 1;
3778         //  polyedre_nodes[2*nbNodes + 4*iface + 0] = prevNod[iface];
3779         //  polyedre_nodes[2*nbNodes + 4*iface + 1] = prevNod[inextface];
3780         //  polyedre_nodes[2*nbNodes + 4*iface + 2] = nextNod[inextface];
3781         //  polyedre_nodes[2*nbNodes + 4*iface + 3] = nextNod[iface];
3782         //}
3783         //aNewElem = aMesh->AddPolyhedralVolume (polyedre_nodes, quantities);
3784         break;
3785       }
3786       }
3787     }
3788
3789     if(!aNewElem) {
3790       // realized for extrusion only
3791       vector<const SMDS_MeshNode*> polyedre_nodes (nbNodes*2 + 4*nbNodes);
3792       vector<int> quantities (nbNodes + 2);
3793
3794       quantities[0] = nbNodes; // bottom of prism
3795       for (int inode = 0; inode < nbNodes; inode++) {
3796         polyedre_nodes[inode] = prevNod[inode];
3797       }
3798
3799       quantities[1] = nbNodes; // top of prism
3800       for (int inode = 0; inode < nbNodes; inode++) {
3801         polyedre_nodes[nbNodes + inode] = nextNod[inode];
3802       }
3803
3804       for (int iface = 0; iface < nbNodes; iface++) {
3805         quantities[iface + 2] = 4;
3806         int inextface = (iface == nbNodes - 1) ? 0 : iface + 1;
3807         polyedre_nodes[2*nbNodes + 4*iface + 0] = prevNod[iface];
3808         polyedre_nodes[2*nbNodes + 4*iface + 1] = prevNod[inextface];
3809         polyedre_nodes[2*nbNodes + 4*iface + 2] = nextNod[inextface];
3810         polyedre_nodes[2*nbNodes + 4*iface + 3] = nextNod[iface];
3811       }
3812       aNewElem = aMesh->AddPolyhedralVolume (polyedre_nodes, quantities);
3813     }
3814
3815     if ( aNewElem ) {
3816       newElems.push_back( aNewElem );
3817       myLastCreatedElems.Append(aNewElem);
3818       srcElements.Append( elem );
3819       lastElem = aNewElem;
3820     }
3821
3822     // set new prev nodes
3823     for ( iNode = 0; iNode < nbNodes; iNode++ )
3824       prevNod[ iNode ] = nextNod[ iNode ];
3825
3826   } // for steps
3827 }
3828
3829 //=======================================================================
3830 /*!
3831  * \brief Create 1D and 2D elements around swept elements
3832  * \param mapNewNodes - source nodes and ones generated from them
3833  * \param newElemsMap - source elements and ones generated from them
3834  * \param elemNewNodesMap - nodes generated from each node of each element
3835  * \param elemSet - all swept elements
3836  * \param nbSteps - number of sweeping steps
3837  * \param srcElements - to append elem for each generated element
3838  */
3839 //=======================================================================
3840
3841 void SMESH_MeshEditor::makeWalls (TNodeOfNodeListMap &     mapNewNodes,
3842                                   TElemOfElemListMap &     newElemsMap,
3843                                   TElemOfVecOfNnlmiMap &   elemNewNodesMap,
3844                                   TIDSortedElemSet&        elemSet,
3845                                   const int                nbSteps,
3846                                   SMESH_SequenceOfElemPtr& srcElements)
3847 {
3848   MESSAGE("makeWalls");
3849   ASSERT( newElemsMap.size() == elemNewNodesMap.size() );
3850   SMESHDS_Mesh* aMesh = GetMeshDS();
3851
3852   // Find nodes belonging to only one initial element - sweep them to get edges.
3853
3854   TNodeOfNodeListMapItr nList = mapNewNodes.begin();
3855   for ( ; nList != mapNewNodes.end(); nList++ ) {
3856     const SMDS_MeshNode* node =
3857       static_cast<const SMDS_MeshNode*>( nList->first );
3858     SMDS_ElemIteratorPtr eIt = node->GetInverseElementIterator();
3859     int nbInitElems = 0;
3860     const SMDS_MeshElement* el = 0;
3861     SMDSAbs_ElementType highType = SMDSAbs_Edge; // count most complex elements only
3862     while ( eIt->more() && nbInitElems < 2 ) {
3863       el = eIt->next();
3864       SMDSAbs_ElementType type = el->GetType();
3865       if ( type == SMDSAbs_Volume || type < highType ) continue;
3866       if ( type > highType ) {
3867         nbInitElems = 0;
3868         highType = type;
3869       }
3870       if ( elemSet.find(el) != elemSet.end() )
3871         nbInitElems++;
3872     }
3873     if ( nbInitElems < 2 ) {
3874       bool NotCreateEdge = el && el->IsQuadratic() && el->IsMediumNode(node);
3875       if(!NotCreateEdge) {
3876         vector<TNodeOfNodeListMapItr> newNodesItVec( 1, nList );
3877         list<const SMDS_MeshElement*> newEdges;
3878         sweepElement( node, newNodesItVec, newEdges, nbSteps, srcElements );
3879       }
3880     }
3881   }
3882
3883   // Make a ceiling for each element ie an equal element of last new nodes.
3884   // Find free links of faces - make edges and sweep them into faces.
3885
3886   TElemOfElemListMap::iterator   itElem      = newElemsMap.begin();
3887   TElemOfVecOfNnlmiMap::iterator itElemNodes = elemNewNodesMap.begin();
3888   for ( ; itElem != newElemsMap.end(); itElem++, itElemNodes++ ) {
3889     const SMDS_MeshElement* elem = itElem->first;
3890     vector<TNodeOfNodeListMapItr>& vecNewNodes = itElemNodes->second;
3891
3892     if(itElem->second.size()==0) continue;
3893
3894     if ( elem->GetType() == SMDSAbs_Edge ) {
3895       // create a ceiling edge
3896       if (!elem->IsQuadratic()) {
3897         if ( !aMesh->FindEdge( vecNewNodes[ 0 ]->second.back(),
3898                                vecNewNodes[ 1 ]->second.back())) {
3899           myLastCreatedElems.Append(aMesh->AddEdge(vecNewNodes[ 0 ]->second.back(),
3900                                                    vecNewNodes[ 1 ]->second.back()));
3901           srcElements.Append( myLastCreatedElems.Last() );
3902         }
3903       }
3904       else {
3905         if ( !aMesh->FindEdge( vecNewNodes[ 0 ]->second.back(),
3906                                vecNewNodes[ 1 ]->second.back(),
3907                                vecNewNodes[ 2 ]->second.back())) {
3908           myLastCreatedElems.Append(aMesh->AddEdge(vecNewNodes[ 0 ]->second.back(),
3909                                                    vecNewNodes[ 1 ]->second.back(),
3910                                                    vecNewNodes[ 2 ]->second.back()));
3911           srcElements.Append( myLastCreatedElems.Last() );
3912         }
3913       }
3914     }
3915     if ( elem->GetType() != SMDSAbs_Face )
3916       continue;
3917
3918     bool hasFreeLinks = false;
3919
3920     TIDSortedElemSet avoidSet;
3921     avoidSet.insert( elem );
3922
3923     set<const SMDS_MeshNode*> aFaceLastNodes;
3924     int iNode, nbNodes = vecNewNodes.size();
3925     if(!elem->IsQuadratic()) {
3926       // loop on the face nodes
3927       for ( iNode = 0; iNode < nbNodes; iNode++ ) {
3928         aFaceLastNodes.insert( vecNewNodes[ iNode ]->second.back() );
3929         // look for free links of the face
3930         int iNext = ( iNode + 1 == nbNodes ) ? 0 : iNode + 1;
3931         const SMDS_MeshNode* n1 = vecNewNodes[ iNode ]->first;
3932         const SMDS_MeshNode* n2 = vecNewNodes[ iNext ]->first;
3933         // check if a link is free
3934         if ( ! SMESH_MeshEditor::FindFaceInSet ( n1, n2, elemSet, avoidSet )) {
3935           hasFreeLinks = true;
3936           // make an edge and a ceiling for a new edge
3937           if ( !aMesh->FindEdge( n1, n2 )) {
3938             myLastCreatedElems.Append(aMesh->AddEdge( n1, n2 )); // free link edge
3939             srcElements.Append( myLastCreatedElems.Last() );
3940           }
3941           n1 = vecNewNodes[ iNode ]->second.back();
3942           n2 = vecNewNodes[ iNext ]->second.back();
3943           if ( !aMesh->FindEdge( n1, n2 )) {
3944             myLastCreatedElems.Append(aMesh->AddEdge( n1, n2 )); // ceiling edge
3945             srcElements.Append( myLastCreatedElems.Last() );
3946           }
3947         }
3948       }
3949     }
3950     else { // elem is quadratic face
3951       int nbn = nbNodes/2;
3952       for ( iNode = 0; iNode < nbn; iNode++ ) {
3953         aFaceLastNodes.insert( vecNewNodes[ iNode ]->second.back() );
3954         int iNext = ( iNode + 1 == nbn ) ? 0 : iNode + 1;
3955         const SMDS_MeshNode* n1 = vecNewNodes[ iNode ]->first;
3956         const SMDS_MeshNode* n2 = vecNewNodes[ iNext ]->first;
3957         // check if a link is free
3958         if ( ! SMESH_MeshEditor::FindFaceInSet ( n1, n2, elemSet, avoidSet )) {
3959           hasFreeLinks = true;
3960           // make an edge and a ceiling for a new edge
3961           // find medium node
3962           const SMDS_MeshNode* n3 = vecNewNodes[ iNode+nbn ]->first;
3963           if ( !aMesh->FindEdge( n1, n2, n3 )) {
3964             myLastCreatedElems.Append(aMesh->AddEdge( n1, n2, n3 )); // free link edge
3965             srcElements.Append( myLastCreatedElems.Last() );
3966           }
3967           n1 = vecNewNodes[ iNode ]->second.back();
3968           n2 = vecNewNodes[ iNext ]->second.back();
3969           n3 = vecNewNodes[ iNode+nbn ]->second.back();
3970           if ( !aMesh->FindEdge( n1, n2, n3 )) {
3971             myLastCreatedElems.Append(aMesh->AddEdge( n1, n2, n3 )); // ceiling edge
3972             srcElements.Append( myLastCreatedElems.Last() );
3973           }
3974         }
3975       }
3976       for ( iNode = nbn; iNode < 2*nbn; iNode++ ) {
3977         aFaceLastNodes.insert( vecNewNodes[ iNode ]->second.back() );
3978       }
3979     }
3980
3981     // sweep free links into faces
3982
3983     if ( hasFreeLinks )  {
3984       list<const SMDS_MeshElement*> & newVolumes = itElem->second;
3985       int iVol, volNb, nbVolumesByStep = newVolumes.size() / nbSteps;
3986
3987       set<const SMDS_MeshNode*> initNodeSet, topNodeSet, faceNodeSet;
3988       for ( iNode = 0; iNode < nbNodes; iNode++ ) {
3989         initNodeSet.insert( vecNewNodes[ iNode ]->first );
3990         topNodeSet .insert( vecNewNodes[ iNode ]->second.back() );
3991       }
3992       for ( volNb = 0; volNb < nbVolumesByStep; volNb++ ) {
3993         list<const SMDS_MeshElement*>::iterator v = newVolumes.begin();
3994         iVol = 0;
3995         while ( iVol++ < volNb ) v++;
3996         // find indices of free faces of a volume and their source edges
3997         list< int > freeInd;
3998         list< const SMDS_MeshElement* > srcEdges; // source edges of free faces
3999         SMDS_VolumeTool vTool( *v );
4000         int iF, nbF = vTool.NbFaces();
4001         for ( iF = 0; iF < nbF; iF ++ ) {
4002           if (vTool.IsFreeFace( iF ) &&
4003               vTool.GetFaceNodes( iF, faceNodeSet ) &&
4004               initNodeSet != faceNodeSet) // except an initial face
4005           {
4006             if ( nbSteps == 1 && faceNodeSet == topNodeSet )
4007               continue;
4008             freeInd.push_back( iF );
4009             // find source edge of a free face iF
4010             vector<const SMDS_MeshNode*> commonNodes; // shared by the initial and free faces
4011             commonNodes.resize( initNodeSet.size(), NULL ); // avoid spoiling memory
4012             std::set_intersection( faceNodeSet.begin(), faceNodeSet.end(),
4013                                    initNodeSet.begin(), initNodeSet.end(),
4014                                    commonNodes.begin());
4015             if ( (*v)->IsQuadratic() )
4016               srcEdges.push_back(aMesh->FindEdge (commonNodes[0],commonNodes[1],commonNodes[2]));
4017             else
4018               srcEdges.push_back(aMesh->FindEdge (commonNodes[0],commonNodes[1]));
4019 #ifdef _DEBUG_
4020             if ( !srcEdges.back() )
4021             {
4022               cout << "SMESH_MeshEditor::makeWalls(), no source edge found for a free face #"
4023                    << iF << " of volume #" << vTool.ID() << endl;
4024             }
4025 #endif
4026           }
4027         }
4028         if ( freeInd.empty() )
4029           continue;
4030
4031         // create faces for all steps;
4032         // if such a face has been already created by sweep of edge,
4033         // assure that its orientation is OK
4034         for ( int iStep = 0; iStep < nbSteps; iStep++ )  {
4035           vTool.Set( *v );
4036           vTool.SetExternalNormal();
4037           list< int >::iterator ind = freeInd.begin();
4038           list< const SMDS_MeshElement* >::iterator srcEdge = srcEdges.begin();
4039           for ( ; ind != freeInd.end(); ++ind, ++srcEdge ) // loop on free faces
4040           {
4041             const SMDS_MeshNode** nodes = vTool.GetFaceNodes( *ind );
4042             int nbn = vTool.NbFaceNodes( *ind );
4043             switch ( nbn ) {
4044             case 3: { ///// triangle
4045               const SMDS_MeshFace * f = aMesh->FindFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ]);
4046               if ( !f )
4047                 myLastCreatedElems.Append(aMesh->AddFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ] ));
4048               else if ( nodes[ 1 ] != f->GetNodeWrap( f->GetNodeIndex( nodes[ 0 ] ) + 1 ))
4049                 {
4050                   myLastCreatedElems.Append(aMesh->AddFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ] ));
4051                   aMesh->RemoveElement(f);
4052                 }
4053               break;
4054             }
4055             case 4: { ///// quadrangle
4056               const SMDS_MeshFace * f = aMesh->FindFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ], nodes[ 3 ]);
4057               if ( !f )
4058                 myLastCreatedElems.Append(aMesh->AddFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ], nodes[ 3 ] ));
4059               else if ( nodes[ 1 ] != f->GetNodeWrap( f->GetNodeIndex( nodes[ 0 ] ) + 1 ))
4060                 {
4061                   myLastCreatedElems.Append(aMesh->AddFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ], nodes[ 3 ] ));
4062                   aMesh->RemoveElement(f);
4063                 }
4064               break;
4065             }
4066             default:
4067               if( (*v)->IsQuadratic() ) {
4068                 if(nbn==6) { /////// quadratic triangle
4069                   const SMDS_MeshFace * f = aMesh->FindFace( nodes[0], nodes[2], nodes[4],
4070                                                              nodes[1], nodes[3], nodes[5] );
4071                   if ( !f ) {
4072                     myLastCreatedElems.Append(aMesh->AddFace(nodes[0], nodes[2], nodes[4],
4073                                                              nodes[1], nodes[3], nodes[5]));
4074                   }
4075                   else if ( nodes[ 2 ] != f->GetNodeWrap( f->GetNodeIndex( nodes[ 0 ] ) + 1 )) {
4076                     const SMDS_MeshNode** tmpnodes = new const SMDS_MeshNode*[6];
4077                     tmpnodes[0] = nodes[0];
4078                     tmpnodes[1] = nodes[2];
4079                     tmpnodes[2] = nodes[4];
4080                     tmpnodes[3] = nodes[1];
4081                     tmpnodes[4] = nodes[3];
4082                     tmpnodes[5] = nodes[5];
4083                     myLastCreatedElems.Append(aMesh->AddFace(nodes[0], nodes[2], nodes[4],
4084                                                              nodes[1], nodes[3], nodes[5]));
4085                     aMesh->RemoveElement(f);
4086                   }
4087                 }
4088                 else {       /////// quadratic quadrangle
4089                   const SMDS_MeshFace * f = aMesh->FindFace( nodes[0], nodes[2], nodes[4], nodes[6],
4090                                                              nodes[1], nodes[3], nodes[5], nodes[7] );
4091                   if ( !f ) {
4092                     myLastCreatedElems.Append(aMesh->AddFace(nodes[0], nodes[2], nodes[4], nodes[6],
4093                                                              nodes[1], nodes[3], nodes[5], nodes[7]));
4094                   }
4095                   else if ( nodes[ 2 ] != f->GetNodeWrap( f->GetNodeIndex( nodes[ 0 ] ) + 1 )) {
4096                     const SMDS_MeshNode** tmpnodes = new const SMDS_MeshNode*[8];
4097                     tmpnodes[0] = nodes[0];
4098                     tmpnodes[1] = nodes[2];
4099                     tmpnodes[2] = nodes[4];
4100                     tmpnodes[3] = nodes[6];
4101                     tmpnodes[4] = nodes[1];
4102                     tmpnodes[5] = nodes[3];
4103                     tmpnodes[6] = nodes[5];
4104                     tmpnodes[7] = nodes[7];
4105                     myLastCreatedElems.Append(aMesh->AddFace(nodes[0], nodes[2], nodes[4], nodes[6],
4106                                                              nodes[1], nodes[3], nodes[5], nodes[7]));
4107                     aMesh->RemoveElement(f);
4108                   }
4109                 }
4110               }
4111               else { //////// polygon
4112                 vector<const SMDS_MeshNode*> polygon_nodes ( nodes, &nodes[nbn] );
4113                 const SMDS_MeshFace * f = aMesh->FindFace( polygon_nodes );
4114                 if ( !f )
4115                   myLastCreatedElems.Append(aMesh->AddPolygonalFace(polygon_nodes));
4116                 else if ( nodes[ 1 ] != f->GetNodeWrap( f->GetNodeIndex( nodes[ 0 ] ) + 1 ))
4117                   {
4118                   // TODO problem ChangeElementNodes : not the same number of nodes, not the same type
4119                   MESSAGE("ChangeElementNodes");
4120                   aMesh->ChangeElementNodes( f, nodes, nbn );
4121                   }
4122               }
4123             }
4124             while ( srcElements.Length() < myLastCreatedElems.Length() )
4125               srcElements.Append( *srcEdge );
4126
4127           }  // loop on free faces
4128
4129           // go to the next volume
4130           iVol = 0;
4131           while ( iVol++ < nbVolumesByStep ) v++;
4132         }
4133       }
4134     } // sweep free links into faces
4135
4136     // Make a ceiling face with a normal external to a volume
4137
4138     SMDS_VolumeTool lastVol( itElem->second.back() );
4139
4140     int iF = lastVol.GetFaceIndex( aFaceLastNodes );
4141     if ( iF >= 0 ) {
4142       lastVol.SetExternalNormal();
4143       const SMDS_MeshNode** nodes = lastVol.GetFaceNodes( iF );
4144       int nbn = lastVol.NbFaceNodes( iF );
4145       switch ( nbn ) {
4146       case 3:
4147         if (!hasFreeLinks ||
4148             !aMesh->FindFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ]))
4149           myLastCreatedElems.Append(aMesh->AddFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ] ));
4150         break;
4151       case 4:
4152         if (!hasFreeLinks ||
4153             !aMesh->FindFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ], nodes[ 3 ]))
4154           myLastCreatedElems.Append(aMesh->AddFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ], nodes[ 3 ] ));
4155         break;
4156       default:
4157         if(itElem->second.back()->IsQuadratic()) {
4158           if(nbn==6) {
4159             if (!hasFreeLinks ||
4160                 !aMesh->FindFace(nodes[0], nodes[2], nodes[4],
4161                                  nodes[1], nodes[3], nodes[5]) ) {
4162               myLastCreatedElems.Append(aMesh->AddFace(nodes[0], nodes[2], nodes[4],
4163                                                        nodes[1], nodes[3], nodes[5]));
4164             }
4165           }
4166           else { // nbn==8
4167             if (!hasFreeLinks ||
4168                 !aMesh->FindFace(nodes[0], nodes[2], nodes[4], nodes[6],
4169                                  nodes[1], nodes[3], nodes[5], nodes[7]) )
4170               myLastCreatedElems.Append(aMesh->AddFace(nodes[0], nodes[2], nodes[4], nodes[6],
4171                                                        nodes[1], nodes[3], nodes[5], nodes[7]));
4172           }
4173         }
4174         else {
4175           vector<const SMDS_MeshNode*> polygon_nodes ( nodes, &nodes[nbn] );
4176           if (!hasFreeLinks || !aMesh->FindFace(polygon_nodes))
4177             myLastCreatedElems.Append(aMesh->AddPolygonalFace(polygon_nodes));
4178         }
4179       } // switch
4180
4181       while ( srcElements.Length() < myLastCreatedElems.Length() )
4182         srcElements.Append( myLastCreatedElems.Last() );
4183     }
4184   } // loop on swept elements
4185 }
4186
4187 //=======================================================================
4188 //function : RotationSweep
4189 //purpose  :
4190 //=======================================================================
4191
4192 SMESH_MeshEditor::PGroupIDs
4193 SMESH_MeshEditor::RotationSweep(TIDSortedElemSet & theElems,
4194                                 const gp_Ax1&      theAxis,
4195                                 const double       theAngle,
4196                                 const int          theNbSteps,
4197                                 const double       theTol,
4198                                 const bool         theMakeGroups,
4199                                 const bool         theMakeWalls)
4200 {
4201   myLastCreatedElems.Clear();
4202   myLastCreatedNodes.Clear();
4203
4204   // source elements for each generated one
4205   SMESH_SequenceOfElemPtr srcElems, srcNodes;
4206
4207   MESSAGE( "RotationSweep()");
4208   gp_Trsf aTrsf;
4209   aTrsf.SetRotation( theAxis, theAngle );
4210   gp_Trsf aTrsf2;
4211   aTrsf2.SetRotation( theAxis, theAngle/2. );
4212
4213   gp_Lin aLine( theAxis );
4214   double aSqTol = theTol * theTol;
4215
4216   SMESHDS_Mesh* aMesh = GetMeshDS();
4217
4218   TNodeOfNodeListMap mapNewNodes;
4219   TElemOfVecOfNnlmiMap mapElemNewNodes;
4220   TElemOfElemListMap newElemsMap;
4221
4222   // loop on theElems
4223   TIDSortedElemSet::iterator itElem;
4224   for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
4225     const SMDS_MeshElement* elem = *itElem;
4226     if ( !elem || elem->GetType() == SMDSAbs_Volume )
4227       continue;
4228     vector<TNodeOfNodeListMapItr> & newNodesItVec = mapElemNewNodes[ elem ];
4229     newNodesItVec.reserve( elem->NbNodes() );
4230
4231     // loop on elem nodes
4232     SMDS_ElemIteratorPtr itN = elem->nodesIterator();
4233     while ( itN->more() ) {
4234       // check if a node has been already sweeped
4235       const SMDS_MeshNode* node = cast2Node( itN->next() );
4236
4237       gp_XYZ aXYZ( node->X(), node->Y(), node->Z() );
4238       double coord[3];
4239       aXYZ.Coord( coord[0], coord[1], coord[2] );
4240       bool isOnAxis = ( aLine.SquareDistance( aXYZ ) <= aSqTol );
4241
4242       TNodeOfNodeListMapItr nIt = mapNewNodes.find( node );
4243       if ( nIt == mapNewNodes.end() ) {
4244         nIt = mapNewNodes.insert( make_pair( node, list<const SMDS_MeshNode*>() )).first;
4245         list<const SMDS_MeshNode*>& listNewNodes = nIt->second;
4246
4247         // make new nodes
4248         //gp_XYZ aXYZ( node->X(), node->Y(), node->Z() );
4249         //double coord[3];
4250         //aXYZ.Coord( coord[0], coord[1], coord[2] );
4251         //bool isOnAxis = ( aLine.SquareDistance( aXYZ ) <= aSqTol );
4252         const SMDS_MeshNode * newNode = node;
4253         for ( int i = 0; i < theNbSteps; i++ ) {
4254           if ( !isOnAxis ) {
4255             if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
4256               // create two nodes
4257               aTrsf2.Transforms( coord[0], coord[1], coord[2] );
4258               //aTrsf.Transforms( coord[0], coord[1], coord[2] );
4259               newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
4260               myLastCreatedNodes.Append(newNode);
4261               srcNodes.Append( node );
4262               listNewNodes.push_back( newNode );
4263               aTrsf2.Transforms( coord[0], coord[1], coord[2] );
4264               //aTrsf.Transforms( coord[0], coord[1], coord[2] );
4265             }
4266             else {
4267               aTrsf.Transforms( coord[0], coord[1], coord[2] );
4268             }
4269             newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
4270             myLastCreatedNodes.Append(newNode);
4271             srcNodes.Append( node );
4272             listNewNodes.push_back( newNode );
4273           }
4274           else {
4275             listNewNodes.push_back( newNode );
4276             if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
4277               listNewNodes.push_back( newNode );
4278             }
4279           }
4280         }
4281       }
4282       /*
4283         else {
4284         // if current elem is quadratic and current node is not medium
4285         // we have to check - may be it is needed to insert additional nodes
4286         if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
4287         list< const SMDS_MeshNode* > & listNewNodes = nIt->second;
4288         if(listNewNodes.size()==theNbSteps) {
4289         listNewNodes.clear();
4290         // make new nodes
4291         //gp_XYZ aXYZ( node->X(), node->Y(), node->Z() );
4292         //double coord[3];
4293         //aXYZ.Coord( coord[0], coord[1], coord[2] );
4294         const SMDS_MeshNode * newNode = node;
4295         if ( !isOnAxis ) {
4296         for(int i = 0; i<theNbSteps; i++) {
4297         aTrsf2.Transforms( coord[0], coord[1], coord[2] );
4298         newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
4299         cout<<"    3 AddNode:  "<<newNode;
4300         myLastCreatedNodes.Append(newNode);
4301         listNewNodes.push_back( newNode );
4302         srcNodes.Append( node );
4303         aTrsf2.Transforms( coord[0], coord[1], coord[2] );
4304         newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
4305         cout<<"    4 AddNode:  "<<newNode;
4306         myLastCreatedNodes.Append(newNode);
4307         srcNodes.Append( node );
4308         listNewNodes.push_back( newNode );
4309         }
4310         }
4311         else {
4312         listNewNodes.push_back( newNode );
4313         }
4314         }
4315         }
4316         }
4317       */
4318       newNodesItVec.push_back( nIt );
4319     }
4320     // make new elements
4321     sweepElement( elem, newNodesItVec, newElemsMap[elem], theNbSteps, srcElems );
4322   }
4323
4324   if ( theMakeWalls )
4325     makeWalls( mapNewNodes, newElemsMap, mapElemNewNodes, theElems, theNbSteps, srcElems );
4326
4327   PGroupIDs newGroupIDs;
4328   if ( theMakeGroups )
4329     newGroupIDs = generateGroups( srcNodes, srcElems, "rotated");
4330
4331   return newGroupIDs;
4332 }
4333
4334
4335 //=======================================================================
4336 //function : CreateNode
4337 //purpose  :
4338 //=======================================================================
4339 const SMDS_MeshNode* SMESH_MeshEditor::CreateNode(const double x,
4340                                                   const double y,
4341                                                   const double z,
4342                                                   const double tolnode,
4343                                                   SMESH_SequenceOfNode& aNodes)
4344 {
4345   myLastCreatedElems.Clear();
4346   myLastCreatedNodes.Clear();
4347
4348   gp_Pnt P1(x,y,z);
4349   SMESHDS_Mesh * aMesh = myMesh->GetMeshDS();
4350
4351   // try to search in sequence of existing nodes
4352   // if aNodes.Length()>0 we 'nave to use given sequence
4353   // else - use all nodes of mesh
4354   if(aNodes.Length()>0) {
4355     int i;
4356     for(i=1; i<=aNodes.Length(); i++) {
4357       gp_Pnt P2(aNodes.Value(i)->X(),aNodes.Value(i)->Y(),aNodes.Value(i)->Z());
4358       if(P1.Distance(P2)<tolnode)
4359         return aNodes.Value(i);
4360     }
4361   }
4362   else {
4363     SMDS_NodeIteratorPtr itn = aMesh->nodesIterator();
4364     while(itn->more()) {
4365       const SMDS_MeshNode* aN = static_cast<const SMDS_MeshNode*> (itn->next());
4366       gp_Pnt P2(aN->X(),aN->Y(),aN->Z());
4367       if(P1.Distance(P2)<tolnode)
4368         return aN;
4369     }
4370   }
4371
4372   // create new node and return it
4373   const SMDS_MeshNode* NewNode = aMesh->AddNode(x,y,z);
4374   myLastCreatedNodes.Append(NewNode);
4375   return NewNode;
4376 }
4377
4378
4379 //=======================================================================
4380 //function : ExtrusionSweep
4381 //purpose  :
4382 //=======================================================================
4383
4384 SMESH_MeshEditor::PGroupIDs
4385 SMESH_MeshEditor::ExtrusionSweep (TIDSortedElemSet &  theElems,
4386                                   const gp_Vec&       theStep,
4387                                   const int           theNbSteps,
4388                                   TElemOfElemListMap& newElemsMap,
4389                                   const bool          theMakeGroups,
4390                                   const int           theFlags,
4391                                   const double        theTolerance)
4392 {
4393   ExtrusParam aParams;
4394   aParams.myDir = gp_Dir(theStep);
4395   aParams.myNodes.Clear();
4396   aParams.mySteps = new TColStd_HSequenceOfReal;
4397   int i;
4398   for(i=1; i<=theNbSteps; i++)
4399     aParams.mySteps->Append(theStep.Magnitude());
4400
4401   return
4402     ExtrusionSweep(theElems,aParams,newElemsMap,theMakeGroups,theFlags,theTolerance);
4403 }
4404
4405
4406 //=======================================================================
4407 //function : ExtrusionSweep
4408 //purpose  :
4409 //=======================================================================
4410
4411 SMESH_MeshEditor::PGroupIDs
4412 SMESH_MeshEditor::ExtrusionSweep (TIDSortedElemSet &  theElems,
4413                                   ExtrusParam&        theParams,
4414                                   TElemOfElemListMap& newElemsMap,
4415                                   const bool          theMakeGroups,
4416                                   const int           theFlags,
4417                                   const double        theTolerance)
4418 {
4419   MESSAGE("ExtrusionSweep " << theMakeGroups << " " << theFlags << " " << theTolerance);
4420   myLastCreatedElems.Clear();
4421   myLastCreatedNodes.Clear();
4422
4423   // source elements for each generated one
4424   SMESH_SequenceOfElemPtr srcElems, srcNodes;
4425
4426   SMESHDS_Mesh* aMesh = GetMeshDS();
4427
4428   int nbsteps = theParams.mySteps->Length();
4429
4430   TNodeOfNodeListMap mapNewNodes;
4431   //TNodeOfNodeVecMap mapNewNodes;
4432   TElemOfVecOfNnlmiMap mapElemNewNodes;
4433   //TElemOfVecOfMapNodesMap mapElemNewNodes;
4434
4435   // loop on theElems
4436   TIDSortedElemSet::iterator itElem;
4437   for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
4438     // check element type
4439     const SMDS_MeshElement* elem = *itElem;
4440     if ( !elem  || elem->GetType() == SMDSAbs_Volume )
4441       continue;
4442
4443     vector<TNodeOfNodeListMapItr> & newNodesItVec = mapElemNewNodes[ elem ];
4444     //vector<TNodeOfNodeVecMapItr> & newNodesItVec = mapElemNewNodes[ elem ];
4445     newNodesItVec.reserve( elem->NbNodes() );
4446
4447     // loop on elem nodes
4448     SMDS_ElemIteratorPtr itN = elem->nodesIterator();
4449     while ( itN->more() )
4450     {
4451       // check if a node has been already sweeped
4452       const SMDS_MeshNode* node = cast2Node( itN->next() );
4453       TNodeOfNodeListMap::iterator nIt = mapNewNodes.find( node );
4454       //TNodeOfNodeVecMap::iterator nIt = mapNewNodes.find( node );
4455       if ( nIt == mapNewNodes.end() ) {
4456         nIt = mapNewNodes.insert( make_pair( node, list<const SMDS_MeshNode*>() )).first;
4457         //nIt = mapNewNodes.insert( make_pair( node, vector<const SMDS_MeshNode*>() )).first;
4458         list<const SMDS_MeshNode*>& listNewNodes = nIt->second;
4459         //vector<const SMDS_MeshNode*>& vecNewNodes = nIt->second;
4460         //vecNewNodes.reserve(nbsteps);
4461
4462         // make new nodes
4463         double coord[] = { node->X(), node->Y(), node->Z() };
4464         //int nbsteps = theParams.mySteps->Length();
4465         for ( int i = 0; i < nbsteps; i++ ) {
4466           if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
4467             // create additional node
4468             double x = coord[0] + theParams.myDir.X()*theParams.mySteps->Value(i+1)/2.;
4469             double y = coord[1] + theParams.myDir.Y()*theParams.mySteps->Value(i+1)/2.;
4470             double z = coord[2] + theParams.myDir.Z()*theParams.mySteps->Value(i+1)/2.;
4471             if( theFlags & EXTRUSION_FLAG_SEW ) {
4472               const SMDS_MeshNode * newNode = CreateNode(x, y, z,
4473                                                          theTolerance, theParams.myNodes);
4474               listNewNodes.push_back( newNode );
4475             }
4476             else {
4477               const SMDS_MeshNode * newNode = aMesh->AddNode(x, y, z);
4478               myLastCreatedNodes.Append(newNode);
4479               srcNodes.Append( node );
4480               listNewNodes.push_back( newNode );
4481             }
4482           }
4483           //aTrsf.Transforms( coord[0], coord[1], coord[2] );
4484           coord[0] = coord[0] + theParams.myDir.X()*theParams.mySteps->Value(i+1);
4485           coord[1] = coord[1] + theParams.myDir.Y()*theParams.mySteps->Value(i+1);
4486           coord[2] = coord[2] + theParams.myDir.Z()*theParams.mySteps->Value(i+1);
4487           if( theFlags & EXTRUSION_FLAG_SEW ) {
4488             const SMDS_MeshNode * newNode = CreateNode(coord[0], coord[1], coord[2],
4489                                                        theTolerance, theParams.myNodes);
4490             listNewNodes.push_back( newNode );
4491             //vecNewNodes[i]=newNode;
4492           }
4493           else {
4494             const SMDS_MeshNode * newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
4495             myLastCreatedNodes.Append(newNode);
4496             srcNodes.Append( node );
4497             listNewNodes.push_back( newNode );
4498             //vecNewNodes[i]=newNode;
4499           }
4500         }
4501       }
4502       else {
4503         // if current elem is quadratic and current node is not medium
4504         // we have to check - may be it is needed to insert additional nodes
4505         if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
4506           list< const SMDS_MeshNode* > & listNewNodes = nIt->second;
4507           if(listNewNodes.size()==nbsteps) {
4508             listNewNodes.clear();
4509             double coord[] = { node->X(), node->Y(), node->Z() };
4510             for ( int i = 0; i < nbsteps; i++ ) {
4511               double x = coord[0] + theParams.myDir.X()*theParams.mySteps->Value(i+1);
4512               double y = coord[1] + theParams.myDir.Y()*theParams.mySteps->Value(i+1);
4513               double z = coord[2] + theParams.myDir.Z()*theParams.mySteps->Value(i+1);
4514               if( theFlags & EXTRUSION_FLAG_SEW ) {
4515                 const SMDS_MeshNode * newNode = CreateNode(x, y, z,
4516                                                            theTolerance, theParams.myNodes);
4517                 listNewNodes.push_back( newNode );
4518               }
4519               else {
4520                 const SMDS_MeshNode * newNode = aMesh->AddNode(x, y, z);
4521                 myLastCreatedNodes.Append(newNode);
4522                 srcNodes.Append( node );
4523                 listNewNodes.push_back( newNode );
4524               }
4525               coord[0] = coord[0] + theParams.myDir.X()*theParams.mySteps->Value(i+1);
4526               coord[1] = coord[1] + theParams.myDir.Y()*theParams.mySteps->Value(i+1);
4527               coord[2] = coord[2] + theParams.myDir.Z()*theParams.mySteps->Value(i+1);
4528               if( theFlags & EXTRUSION_FLAG_SEW ) {
4529                 const SMDS_MeshNode * newNode = CreateNode(coord[0], coord[1], coord[2],
4530                                                            theTolerance, theParams.myNodes);
4531                 listNewNodes.push_back( newNode );
4532               }
4533               else {
4534                 const SMDS_MeshNode * newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
4535                 myLastCreatedNodes.Append(newNode);
4536                 srcNodes.Append( node );
4537                 listNewNodes.push_back( newNode );
4538               }
4539             }
4540           }
4541         }
4542       }
4543       newNodesItVec.push_back( nIt );
4544     }
4545     // make new elements
4546     sweepElement( elem, newNodesItVec, newElemsMap[elem], nbsteps, srcElems );
4547   }
4548
4549   if( theFlags & EXTRUSION_FLAG_BOUNDARY ) {
4550     makeWalls( mapNewNodes, newElemsMap, mapElemNewNodes, theElems, nbsteps, srcElems );
4551   }
4552   PGroupIDs newGroupIDs;
4553   if ( theMakeGroups )
4554     newGroupIDs = generateGroups( srcNodes, srcElems, "extruded");
4555
4556   return newGroupIDs;
4557 }
4558
4559 /*
4560 //=======================================================================
4561 //class    : SMESH_MeshEditor_PathPoint
4562 //purpose  : auxiliary class
4563 //=======================================================================
4564 class SMESH_MeshEditor_PathPoint {
4565 public:
4566 SMESH_MeshEditor_PathPoint() {
4567 myPnt.SetCoord(99., 99., 99.);
4568 myTgt.SetCoord(1.,0.,0.);
4569 myAngle=0.;
4570 myPrm=0.;
4571 }
4572 void SetPnt(const gp_Pnt& aP3D){
4573 myPnt=aP3D;
4574 }
4575 void SetTangent(const gp_Dir& aTgt){
4576 myTgt=aTgt;
4577 }
4578 void SetAngle(const double& aBeta){
4579 myAngle=aBeta;
4580 }
4581 void SetParameter(const double& aPrm){
4582 myPrm=aPrm;
4583 }
4584 const gp_Pnt& Pnt()const{
4585 return myPnt;
4586 }
4587 const gp_Dir& Tangent()const{
4588 return myTgt;
4589 }
4590 double Angle()const{
4591 return myAngle;
4592 }
4593 double Parameter()const{
4594 return myPrm;
4595 }
4596
4597 protected:
4598 gp_Pnt myPnt;
4599 gp_Dir myTgt;
4600 double myAngle;
4601 double myPrm;
4602 };
4603 */
4604
4605 //=======================================================================
4606 //function : ExtrusionAlongTrack
4607 //purpose  :
4608 //=======================================================================
4609 SMESH_MeshEditor::Extrusion_Error
4610 SMESH_MeshEditor::ExtrusionAlongTrack (TIDSortedElemSet &   theElements,
4611                                        SMESH_subMesh*       theTrack,
4612                                        const SMDS_MeshNode* theN1,
4613                                        const bool           theHasAngles,
4614                                        list<double>&        theAngles,
4615                                        const bool           theLinearVariation,
4616                                        const bool           theHasRefPoint,
4617                                        const gp_Pnt&        theRefPoint,
4618                                        const bool           theMakeGroups)
4619 {
4620   MESSAGE("ExtrusionAlongTrack");
4621   myLastCreatedElems.Clear();
4622   myLastCreatedNodes.Clear();
4623
4624   int aNbE;
4625   std::list<double> aPrms;
4626   TIDSortedElemSet::iterator itElem;
4627
4628   gp_XYZ aGC;
4629   TopoDS_Edge aTrackEdge;
4630   TopoDS_Vertex aV1, aV2;
4631
4632   SMDS_ElemIteratorPtr aItE;
4633   SMDS_NodeIteratorPtr aItN;
4634   SMDSAbs_ElementType aTypeE;
4635
4636   TNodeOfNodeListMap mapNewNodes;
4637
4638   // 1. Check data
4639   aNbE = theElements.size();
4640   // nothing to do
4641   if ( !aNbE )
4642     return EXTR_NO_ELEMENTS;
4643
4644   // 1.1 Track Pattern
4645   ASSERT( theTrack );
4646
4647   SMESHDS_SubMesh* pSubMeshDS = theTrack->GetSubMeshDS();
4648
4649   aItE = pSubMeshDS->GetElements();
4650   while ( aItE->more() ) {
4651     const SMDS_MeshElement* pE = aItE->next();
4652     aTypeE = pE->GetType();
4653     // Pattern must contain links only
4654     if ( aTypeE != SMDSAbs_Edge )
4655       return EXTR_PATH_NOT_EDGE;
4656   }
4657
4658   list<SMESH_MeshEditor_PathPoint> fullList;
4659
4660   const TopoDS_Shape& aS = theTrack->GetSubShape();
4661   // Sub shape for the Pattern must be an Edge or Wire
4662   if( aS.ShapeType() == TopAbs_EDGE ) {
4663     aTrackEdge = TopoDS::Edge( aS );
4664     // the Edge must not be degenerated
4665     if ( BRep_Tool::Degenerated( aTrackEdge ) )
4666       return EXTR_BAD_PATH_SHAPE;
4667     TopExp::Vertices( aTrackEdge, aV1, aV2 );
4668     aItN = theTrack->GetFather()->GetSubMesh( aV1 )->GetSubMeshDS()->GetNodes();
4669     const SMDS_MeshNode* aN1 = aItN->next();
4670     aItN = theTrack->GetFather()->GetSubMesh( aV2 )->GetSubMeshDS()->GetNodes();
4671     const SMDS_MeshNode* aN2 = aItN->next();
4672     // starting node must be aN1 or aN2
4673     if ( !( aN1 == theN1 || aN2 == theN1 ) )
4674       return EXTR_BAD_STARTING_NODE;
4675     aItN = pSubMeshDS->GetNodes();
4676     while ( aItN->more() ) {
4677       const SMDS_MeshNode* pNode = aItN->next();
4678       const SMDS_EdgePosition* pEPos =
4679         static_cast<const SMDS_EdgePosition*>( pNode->GetPosition() );
4680       double aT = pEPos->GetUParameter();
4681       aPrms.push_back( aT );
4682     }
4683     //Extrusion_Error err =
4684     MakeEdgePathPoints(aPrms, aTrackEdge, (aN1==theN1), fullList);
4685   }
4686   else if( aS.ShapeType() == TopAbs_WIRE ) {
4687     list< SMESH_subMesh* > LSM;
4688     TopTools_SequenceOfShape Edges;
4689     SMESH_subMeshIteratorPtr itSM = theTrack->getDependsOnIterator(false,true);
4690     while(itSM->more()) {
4691       SMESH_subMesh* SM = itSM->next();
4692       LSM.push_back(SM);
4693       const TopoDS_Shape& aS = SM->GetSubShape();
4694       Edges.Append(aS);
4695     }
4696     list< list<SMESH_MeshEditor_PathPoint> > LLPPs;
4697     int startNid = theN1->GetID();
4698     TColStd_MapOfInteger UsedNums;
4699     int NbEdges = Edges.Length();
4700     int i = 1;
4701     for(; i<=NbEdges; i++) {
4702       int k = 0;
4703       list< SMESH_subMesh* >::iterator itLSM = LSM.begin();
4704       for(; itLSM!=LSM.end(); itLSM++) {
4705         k++;
4706         if(UsedNums.Contains(k)) continue;
4707         aTrackEdge = TopoDS::Edge( Edges.Value(k) );
4708         SMESH_subMesh* locTrack = *itLSM;
4709         SMESHDS_SubMesh* locMeshDS = locTrack->GetSubMeshDS();
4710         TopExp::Vertices( aTrackEdge, aV1, aV2 );
4711         aItN = locTrack->GetFather()->GetSubMesh(aV1)->GetSubMeshDS()->GetNodes();
4712         const SMDS_MeshNode* aN1 = aItN->next();
4713         aItN = locTrack->GetFather()->GetSubMesh(aV2)->GetSubMeshDS()->GetNodes();
4714         const SMDS_MeshNode* aN2 = aItN->next();
4715         // starting node must be aN1 or aN2
4716         if ( !( aN1->GetID() == startNid || aN2->GetID() == startNid ) ) continue;
4717         // 2. Collect parameters on the track edge
4718         aPrms.clear();
4719         aItN = locMeshDS->GetNodes();
4720         while ( aItN->more() ) {
4721           const SMDS_MeshNode* pNode = aItN->next();
4722           const SMDS_EdgePosition* pEPos =
4723             static_cast<const SMDS_EdgePosition*>( pNode->GetPosition() );
4724           double aT = pEPos->GetUParameter();
4725           aPrms.push_back( aT );
4726         }
4727         list<SMESH_MeshEditor_PathPoint> LPP;
4728         //Extrusion_Error err =
4729         MakeEdgePathPoints(aPrms, aTrackEdge,(aN1->GetID()==startNid), LPP);
4730         LLPPs.push_back(LPP);
4731         UsedNums.Add(k);
4732         // update startN for search following egde
4733         if( aN1->GetID() == startNid ) startNid = aN2->GetID();
4734         else startNid = aN1->GetID();
4735         break;
4736       }
4737     }
4738     list< list<SMESH_MeshEditor_PathPoint> >::iterator itLLPP = LLPPs.begin();
4739     list<SMESH_MeshEditor_PathPoint> firstList = *itLLPP;
4740     list<SMESH_MeshEditor_PathPoint>::iterator itPP = firstList.begin();
4741     for(; itPP!=firstList.end(); itPP++) {
4742       fullList.push_back( *itPP );
4743     }
4744     SMESH_MeshEditor_PathPoint PP1 = fullList.back();
4745     fullList.pop_back();
4746     itLLPP++;
4747     for(; itLLPP!=LLPPs.end(); itLLPP++) {
4748       list<SMESH_MeshEditor_PathPoint> currList = *itLLPP;
4749       itPP = currList.begin();
4750       SMESH_MeshEditor_PathPoint PP2 = currList.front();
4751       gp_Dir D1 = PP1.Tangent();
4752       gp_Dir D2 = PP2.Tangent();
4753       gp_Dir Dnew( gp_Vec( (D1.X()+D2.X())/2, (D1.Y()+D2.Y())/2,
4754                            (D1.Z()+D2.Z())/2 ) );
4755       PP1.SetTangent(Dnew);
4756       fullList.push_back(PP1);
4757       itPP++;
4758       for(; itPP!=firstList.end(); itPP++) {
4759         fullList.push_back( *itPP );
4760       }
4761       PP1 = fullList.back();
4762       fullList.pop_back();
4763     }
4764     // if wire not closed
4765     fullList.push_back(PP1);
4766     // else ???
4767   }
4768   else {
4769     return EXTR_BAD_PATH_SHAPE;
4770   }
4771
4772   return MakeExtrElements(theElements, fullList, theHasAngles, theAngles, theLinearVariation,
4773                           theHasRefPoint, theRefPoint, theMakeGroups);
4774 }
4775
4776
4777 //=======================================================================
4778 //function : ExtrusionAlongTrack
4779 //purpose  :
4780 //=======================================================================
4781 SMESH_MeshEditor::Extrusion_Error
4782 SMESH_MeshEditor::ExtrusionAlongTrack (TIDSortedElemSet &   theElements,
4783                                        SMESH_Mesh*          theTrack,
4784                                        const SMDS_MeshNode* theN1,
4785                                        const bool           theHasAngles,
4786                                        list<double>&        theAngles,
4787                                        const bool           theLinearVariation,
4788                                        const bool           theHasRefPoint,
4789                                        const gp_Pnt&        theRefPoint,
4790                                        const bool           theMakeGroups)
4791 {
4792   myLastCreatedElems.Clear();
4793   myLastCreatedNodes.Clear();
4794
4795   int aNbE;
4796   std::list<double> aPrms;
4797   TIDSortedElemSet::iterator itElem;
4798
4799   gp_XYZ aGC;
4800   TopoDS_Edge aTrackEdge;
4801   TopoDS_Vertex aV1, aV2;
4802
4803   SMDS_ElemIteratorPtr aItE;
4804   SMDS_NodeIteratorPtr aItN;
4805   SMDSAbs_ElementType aTypeE;
4806
4807   TNodeOfNodeListMap mapNewNodes;
4808
4809   // 1. Check data
4810   aNbE = theElements.size();
4811   // nothing to do
4812   if ( !aNbE )
4813     return EXTR_NO_ELEMENTS;
4814
4815   // 1.1 Track Pattern
4816   ASSERT( theTrack );
4817
4818   SMESHDS_Mesh* pMeshDS = theTrack->GetMeshDS();
4819
4820   aItE = pMeshDS->elementsIterator();
4821   while ( aItE->more() ) {
4822     const SMDS_MeshElement* pE = aItE->next();
4823     aTypeE = pE->GetType();
4824     // Pattern must contain links only
4825     if ( aTypeE != SMDSAbs_Edge )
4826       return EXTR_PATH_NOT_EDGE;
4827   }
4828
4829   list<SMESH_MeshEditor_PathPoint> fullList;
4830
4831   const TopoDS_Shape& aS = theTrack->GetShapeToMesh();
4832   // Sub shape for the Pattern must be an Edge or Wire
4833   if( aS.ShapeType() == TopAbs_EDGE ) {
4834     aTrackEdge = TopoDS::Edge( aS );
4835     // the Edge must not be degenerated
4836     if ( BRep_Tool::Degenerated( aTrackEdge ) )
4837       return EXTR_BAD_PATH_SHAPE;
4838     TopExp::Vertices( aTrackEdge, aV1, aV2 );
4839     aItN = theTrack->GetSubMesh( aV1 )->GetSubMeshDS()->GetNodes();
4840     const SMDS_MeshNode* aN1 = aItN->next();
4841     aItN = theTrack->GetSubMesh( aV2 )->GetSubMeshDS()->GetNodes();
4842     const SMDS_MeshNode* aN2 = aItN->next();
4843     // starting node must be aN1 or aN2
4844     if ( !( aN1 == theN1 || aN2 == theN1 ) )
4845       return EXTR_BAD_STARTING_NODE;
4846     aItN = pMeshDS->nodesIterator();
4847     while ( aItN->more() ) {
4848       const SMDS_MeshNode* pNode = aItN->next();
4849       if( pNode==aN1 || pNode==aN2 ) continue;
4850       const SMDS_EdgePosition* pEPos =
4851         static_cast<const SMDS_EdgePosition*>( pNode->GetPosition() );
4852       double aT = pEPos->GetUParameter();
4853       aPrms.push_back( aT );
4854     }
4855     //Extrusion_Error err =
4856     MakeEdgePathPoints(aPrms, aTrackEdge, (aN1==theN1), fullList);
4857   }
4858   else if( aS.ShapeType() == TopAbs_WIRE ) {
4859     list< SMESH_subMesh* > LSM;
4860     TopTools_SequenceOfShape Edges;
4861     TopExp_Explorer eExp(aS, TopAbs_EDGE);
4862     for(; eExp.More(); eExp.Next()) {
4863       TopoDS_Edge E = TopoDS::Edge( eExp.Current() );
4864       if( BRep_Tool::Degenerated(E) ) continue;
4865       SMESH_subMesh* SM = theTrack->GetSubMesh(E);
4866       if(SM) {
4867         LSM.push_back(SM);
4868         Edges.Append(E);
4869       }
4870     }
4871     list< list<SMESH_MeshEditor_PathPoint> > LLPPs;
4872     int startNid = theN1->GetID();
4873     TColStd_MapOfInteger UsedNums;
4874     int NbEdges = Edges.Length();
4875     int i = 1;
4876     for(; i<=NbEdges; i++) {
4877       int k = 0;
4878       list< SMESH_subMesh* >::iterator itLSM = LSM.begin();
4879       for(; itLSM!=LSM.end(); itLSM++) {
4880         k++;
4881         if(UsedNums.Contains(k)) continue;
4882         aTrackEdge = TopoDS::Edge( Edges.Value(k) );
4883         SMESH_subMesh* locTrack = *itLSM;
4884         SMESHDS_SubMesh* locMeshDS = locTrack->GetSubMeshDS();
4885         TopExp::Vertices( aTrackEdge, aV1, aV2 );
4886         aItN = locTrack->GetFather()->GetSubMesh(aV1)->GetSubMeshDS()->GetNodes();
4887         const SMDS_MeshNode* aN1 = aItN->next();
4888         aItN = locTrack->GetFather()->GetSubMesh(aV2)->GetSubMeshDS()->GetNodes();
4889         const SMDS_MeshNode* aN2 = aItN->next();
4890         // starting node must be aN1 or aN2
4891         if ( !( aN1->GetID() == startNid || aN2->GetID() == startNid ) ) continue;
4892         // 2. Collect parameters on the track edge
4893         aPrms.clear();
4894         aItN = locMeshDS->GetNodes();
4895         while ( aItN->more() ) {
4896           const SMDS_MeshNode* pNode = aItN->next();
4897           const SMDS_EdgePosition* pEPos =
4898             static_cast<const SMDS_EdgePosition*>( pNode->GetPosition() );
4899           double aT = pEPos->GetUParameter();
4900           aPrms.push_back( aT );
4901         }
4902         list<SMESH_MeshEditor_PathPoint> LPP;
4903         //Extrusion_Error err =
4904         MakeEdgePathPoints(aPrms, aTrackEdge,(aN1->GetID()==startNid), LPP);
4905         LLPPs.push_back(LPP);
4906         UsedNums.Add(k);
4907         // update startN for search following egde
4908         if( aN1->GetID() == startNid ) startNid = aN2->GetID();
4909         else startNid = aN1->GetID();
4910         break;
4911       }
4912     }
4913     list< list<SMESH_MeshEditor_PathPoint> >::iterator itLLPP = LLPPs.begin();
4914     list<SMESH_MeshEditor_PathPoint> firstList = *itLLPP;
4915     list<SMESH_MeshEditor_PathPoint>::iterator itPP = firstList.begin();
4916     for(; itPP!=firstList.end(); itPP++) {
4917       fullList.push_back( *itPP );
4918     }
4919     SMESH_MeshEditor_PathPoint PP1 = fullList.back();
4920     fullList.pop_back();
4921     itLLPP++;
4922     for(; itLLPP!=LLPPs.end(); itLLPP++) {
4923       list<SMESH_MeshEditor_PathPoint> currList = *itLLPP;
4924       itPP = currList.begin();
4925       SMESH_MeshEditor_PathPoint PP2 = currList.front();
4926       gp_Pnt P1 = PP1.Pnt();
4927       //cout<<"    PP1: Pnt("<<P1.X()<<","<<P1.Y()<<","<<P1.Z()<<")"<<endl;
4928       gp_Pnt P2 = PP2.Pnt();
4929       gp_Dir D1 = PP1.Tangent();
4930       gp_Dir D2 = PP2.Tangent();
4931       gp_Dir Dnew( gp_Vec( (D1.X()+D2.X())/2, (D1.Y()+D2.Y())/2,
4932                            (D1.Z()+D2.Z())/2 ) );
4933       PP1.SetTangent(Dnew);
4934       fullList.push_back(PP1);
4935       itPP++;
4936       for(; itPP!=currList.end(); itPP++) {
4937         fullList.push_back( *itPP );
4938       }
4939       PP1 = fullList.back();
4940       fullList.pop_back();
4941     }
4942     // if wire not closed
4943     fullList.push_back(PP1);
4944     // else ???
4945   }
4946   else {
4947     return EXTR_BAD_PATH_SHAPE;
4948   }
4949
4950   return MakeExtrElements(theElements, fullList, theHasAngles, theAngles, theLinearVariation,
4951                           theHasRefPoint, theRefPoint, theMakeGroups);
4952 }
4953
4954
4955 //=======================================================================
4956 //function : MakeEdgePathPoints
4957 //purpose  : auxilary for ExtrusionAlongTrack
4958 //=======================================================================
4959 SMESH_MeshEditor::Extrusion_Error
4960 SMESH_MeshEditor::MakeEdgePathPoints(std::list<double>& aPrms,
4961                                      const TopoDS_Edge& aTrackEdge,
4962                                      bool FirstIsStart,
4963                                      list<SMESH_MeshEditor_PathPoint>& LPP)
4964 {
4965   Standard_Real aTx1, aTx2, aL2, aTolVec, aTolVec2;
4966   aTolVec=1.e-7;
4967   aTolVec2=aTolVec*aTolVec;
4968   double aT1, aT2;
4969   TopoDS_Vertex aV1, aV2;
4970   TopExp::Vertices( aTrackEdge, aV1, aV2 );
4971   aT1=BRep_Tool::Parameter( aV1, aTrackEdge );
4972   aT2=BRep_Tool::Parameter( aV2, aTrackEdge );
4973   // 2. Collect parameters on the track edge
4974   aPrms.push_front( aT1 );
4975   aPrms.push_back( aT2 );
4976   // sort parameters
4977   aPrms.sort();
4978   if( FirstIsStart ) {
4979     if ( aT1 > aT2 ) {
4980       aPrms.reverse();
4981     }
4982   }
4983   else {
4984     if ( aT2 > aT1 ) {
4985       aPrms.reverse();
4986     }
4987   }
4988   // 3. Path Points
4989   SMESH_MeshEditor_PathPoint aPP;
4990   Handle(Geom_Curve) aC3D = BRep_Tool::Curve( aTrackEdge, aTx1, aTx2 );
4991   std::list<double>::iterator aItD = aPrms.begin();
4992   for(; aItD != aPrms.end(); ++aItD) {
4993     double aT = *aItD;
4994     gp_Pnt aP3D;
4995     gp_Vec aVec;
4996     aC3D->D1( aT, aP3D, aVec );
4997     aL2 = aVec.SquareMagnitude();
4998     if ( aL2 < aTolVec2 )
4999       return EXTR_CANT_GET_TANGENT;
5000     gp_Dir aTgt( aVec );
5001     aPP.SetPnt( aP3D );
5002     aPP.SetTangent( aTgt );
5003     aPP.SetParameter( aT );
5004     LPP.push_back(aPP);
5005   }
5006   return EXTR_OK;
5007 }
5008
5009
5010 //=======================================================================
5011 //function : MakeExtrElements
5012 //purpose  : auxilary for ExtrusionAlongTrack
5013 //=======================================================================
5014 SMESH_MeshEditor::Extrusion_Error
5015 SMESH_MeshEditor::MakeExtrElements(TIDSortedElemSet&  theElements,
5016                                    list<SMESH_MeshEditor_PathPoint>& fullList,
5017                                    const bool theHasAngles,
5018                                    list<double>& theAngles,
5019                                    const bool theLinearVariation,
5020                                    const bool theHasRefPoint,
5021                                    const gp_Pnt& theRefPoint,
5022                                    const bool theMakeGroups)
5023 {
5024   MESSAGE("MakeExtrElements");
5025   //cout<<"MakeExtrElements  fullList.size() = "<<fullList.size()<<endl;
5026   int aNbTP = fullList.size();
5027   vector<SMESH_MeshEditor_PathPoint> aPPs(aNbTP);
5028   // Angles
5029   if( theHasAngles && theAngles.size()>0 && theLinearVariation ) {
5030     LinearAngleVariation(aNbTP-1, theAngles);
5031   }
5032   vector<double> aAngles( aNbTP );
5033   int j = 0;
5034   for(; j<aNbTP; ++j) {
5035     aAngles[j] = 0.;
5036   }
5037   if ( theHasAngles ) {
5038     double anAngle;;
5039     std::list<double>::iterator aItD = theAngles.begin();
5040     for ( j=1; (aItD != theAngles.end()) && (j<aNbTP); ++aItD, ++j ) {
5041       anAngle = *aItD;
5042       aAngles[j] = anAngle;
5043     }
5044   }
5045   // fill vector of path points with angles
5046   //aPPs.resize(fullList.size());
5047   j = -1;
5048   list<SMESH_MeshEditor_PathPoint>::iterator itPP = fullList.begin();
5049   for(; itPP!=fullList.end(); itPP++) {
5050     j++;
5051     SMESH_MeshEditor_PathPoint PP = *itPP;
5052     PP.SetAngle(aAngles[j]);
5053     aPPs[j] = PP;
5054   }
5055
5056   TNodeOfNodeListMap mapNewNodes;
5057   TElemOfVecOfNnlmiMap mapElemNewNodes;
5058   TElemOfElemListMap newElemsMap;
5059   TIDSortedElemSet::iterator itElem;
5060   double aX, aY, aZ;
5061   int aNb;
5062   SMDSAbs_ElementType aTypeE;
5063   // source elements for each generated one
5064   SMESH_SequenceOfElemPtr srcElems, srcNodes;
5065
5066   // 3. Center of rotation aV0
5067   gp_Pnt aV0 = theRefPoint;
5068   gp_XYZ aGC;
5069   if ( !theHasRefPoint ) {
5070     aNb = 0;
5071     aGC.SetCoord( 0.,0.,0. );
5072
5073     itElem = theElements.begin();
5074     for ( ; itElem != theElements.end(); itElem++ ) {
5075       const SMDS_MeshElement* elem = *itElem;
5076
5077       SMDS_ElemIteratorPtr itN = elem->nodesIterator();
5078       while ( itN->more() ) {
5079         const SMDS_MeshNode* node = static_cast<const SMDS_MeshNode*>( itN->next() );
5080         aX = node->X();
5081         aY = node->Y();
5082         aZ = node->Z();
5083
5084         if ( mapNewNodes.find( node ) == mapNewNodes.end() ) {
5085           list<const SMDS_MeshNode*> aLNx;
5086           mapNewNodes[node] = aLNx;
5087           //
5088           gp_XYZ aXYZ( aX, aY, aZ );
5089           aGC += aXYZ;
5090           ++aNb;
5091         }
5092       }
5093     }
5094     aGC /= aNb;
5095     aV0.SetXYZ( aGC );
5096   } // if (!theHasRefPoint) {
5097   mapNewNodes.clear();
5098
5099   // 4. Processing the elements
5100   SMESHDS_Mesh* aMesh = GetMeshDS();
5101
5102   for ( itElem = theElements.begin(); itElem != theElements.end(); itElem++ ) {
5103     // check element type
5104     const SMDS_MeshElement* elem = *itElem;
5105     aTypeE = elem->GetType();
5106     if ( !elem || ( aTypeE != SMDSAbs_Face && aTypeE != SMDSAbs_Edge ) )
5107       continue;
5108
5109     vector<TNodeOfNodeListMapItr> & newNodesItVec = mapElemNewNodes[ elem ];
5110     newNodesItVec.reserve( elem->NbNodes() );
5111
5112     // loop on elem nodes
5113     int nodeIndex = -1;
5114     SMDS_ElemIteratorPtr itN = elem->nodesIterator();
5115     while ( itN->more() )
5116     {
5117       ++nodeIndex;
5118       // check if a node has been already processed
5119       const SMDS_MeshNode* node =
5120         static_cast<const SMDS_MeshNode*>( itN->next() );
5121       TNodeOfNodeListMap::iterator nIt = mapNewNodes.find( node );
5122       if ( nIt == mapNewNodes.end() ) {
5123         nIt = mapNewNodes.insert( make_pair( node, list<const SMDS_MeshNode*>() )).first;
5124         list<const SMDS_MeshNode*>& listNewNodes = nIt->second;
5125
5126         // make new nodes
5127         aX = node->X();  aY = node->Y(); aZ = node->Z();
5128
5129         Standard_Real aAngle1x, aAngleT1T0, aTolAng;
5130         gp_Pnt aP0x, aP1x, aPN0, aPN1, aV0x, aV1x;
5131         gp_Ax1 anAx1, anAxT1T0;
5132         gp_Dir aDT1x, aDT0x, aDT1T0;
5133
5134         aTolAng=1.e-4;
5135
5136         aV0x = aV0;
5137         aPN0.SetCoord(aX, aY, aZ);
5138
5139         const SMESH_MeshEditor_PathPoint& aPP0 = aPPs[0];
5140         aP0x = aPP0.Pnt();
5141         aDT0x= aPP0.Tangent();
5142         //cout<<"j = 0   PP: Pnt("<<aP0x.X()<<","<<aP0x.Y()<<","<<aP0x.Z()<<")"<<endl;
5143
5144         for ( j = 1; j < aNbTP; ++j ) {
5145           const SMESH_MeshEditor_PathPoint& aPP1 = aPPs[j];
5146           aP1x = aPP1.Pnt();
5147           aDT1x = aPP1.Tangent();
5148           aAngle1x = aPP1.Angle();
5149
5150           gp_Trsf aTrsf, aTrsfRot, aTrsfRotT1T0;
5151           // Translation
5152           gp_Vec aV01x( aP0x, aP1x );
5153           aTrsf.SetTranslation( aV01x );
5154
5155           // traslated point
5156           aV1x = aV0x.Transformed( aTrsf );
5157           aPN1 = aPN0.Transformed( aTrsf );
5158
5159           // rotation 1 [ T1,T0 ]
5160           aAngleT1T0=-aDT1x.Angle( aDT0x );
5161           if (fabs(aAngleT1T0) > aTolAng) {
5162             aDT1T0=aDT1x^aDT0x;
5163             anAxT1T0.SetLocation( aV1x );
5164             anAxT1T0.SetDirection( aDT1T0 );
5165             aTrsfRotT1T0.SetRotation( anAxT1T0, aAngleT1T0 );
5166
5167             aPN1 = aPN1.Transformed( aTrsfRotT1T0 );
5168           }
5169
5170           // rotation 2
5171           if ( theHasAngles ) {
5172             anAx1.SetLocation( aV1x );
5173             anAx1.SetDirection( aDT1x );
5174             aTrsfRot.SetRotation( anAx1, aAngle1x );
5175
5176             aPN1 = aPN1.Transformed( aTrsfRot );
5177           }
5178
5179           // make new node
5180           //MESSAGE("elem->IsQuadratic " << elem->IsQuadratic() << " " << elem->IsMediumNode(node));
5181           if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
5182             // create additional node
5183             double x = ( aPN1.X() + aPN0.X() )/2.;
5184             double y = ( aPN1.Y() + aPN0.Y() )/2.;
5185             double z = ( aPN1.Z() + aPN0.Z() )/2.;
5186             const SMDS_MeshNode* newNode = aMesh->AddNode(x,y,z);
5187             myLastCreatedNodes.Append(newNode);
5188             srcNodes.Append( node );
5189             listNewNodes.push_back( newNode );
5190           }
5191           aX = aPN1.X();
5192           aY = aPN1.Y();
5193           aZ = aPN1.Z();
5194           const SMDS_MeshNode* newNode = aMesh->AddNode( aX, aY, aZ );
5195           myLastCreatedNodes.Append(newNode);
5196           srcNodes.Append( node );
5197           listNewNodes.push_back( newNode );
5198
5199           aPN0 = aPN1;
5200           aP0x = aP1x;
5201           aV0x = aV1x;
5202           aDT0x = aDT1x;
5203         }
5204       }
5205
5206       else {
5207         // if current elem is quadratic and current node is not medium
5208         // we have to check - may be it is needed to insert additional nodes
5209         if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
5210           list< const SMDS_MeshNode* > & listNewNodes = nIt->second;
5211           if(listNewNodes.size()==aNbTP-1) {
5212             vector<const SMDS_MeshNode*> aNodes(2*(aNbTP-1));
5213             gp_XYZ P(node->X(), node->Y(), node->Z());
5214             list< const SMDS_MeshNode* >::iterator it = listNewNodes.begin();
5215             int i;
5216             for(i=0; i<aNbTP-1; i++) {
5217               const SMDS_MeshNode* N = *it;
5218               double x = ( N->X() + P.X() )/2.;
5219               double y = ( N->Y() + P.Y() )/2.;
5220               double z = ( N->Z() + P.Z() )/2.;
5221               const SMDS_MeshNode* newN = aMesh->AddNode(x,y,z);
5222               srcNodes.Append( node );
5223               myLastCreatedNodes.Append(newN);
5224               aNodes[2*i] = newN;
5225               aNodes[2*i+1] = N;
5226               P = gp_XYZ(N->X(),N->Y(),N->Z());
5227             }
5228             listNewNodes.clear();
5229             for(i=0; i<2*(aNbTP-1); i++) {
5230               listNewNodes.push_back(aNodes[i]);
5231             }
5232           }
5233         }
5234       }
5235
5236       newNodesItVec.push_back( nIt );
5237     }
5238     // make new elements
5239     //sweepElement( aMesh, elem, newNodesItVec, newElemsMap[elem],
5240     //              newNodesItVec[0]->second.size(), myLastCreatedElems );
5241     sweepElement( elem, newNodesItVec, newElemsMap[elem], aNbTP-1, srcElems );
5242   }
5243
5244   makeWalls( mapNewNodes, newElemsMap, mapElemNewNodes, theElements, aNbTP-1, srcElems );
5245
5246   if ( theMakeGroups )
5247     generateGroups( srcNodes, srcElems, "extruded");
5248
5249   return EXTR_OK;
5250 }
5251
5252
5253 //=======================================================================
5254 //function : LinearAngleVariation
5255 //purpose  : auxilary for ExtrusionAlongTrack
5256 //=======================================================================
5257 void SMESH_MeshEditor::LinearAngleVariation(const int nbSteps,
5258                                             list<double>& Angles)
5259 {
5260   int nbAngles = Angles.size();
5261   if( nbSteps > nbAngles ) {
5262     vector<double> theAngles(nbAngles);
5263     list<double>::iterator it = Angles.begin();
5264     int i = -1;
5265     for(; it!=Angles.end(); it++) {
5266       i++;
5267       theAngles[i] = (*it);
5268     }
5269     list<double> res;
5270     double rAn2St = double( nbAngles ) / double( nbSteps );
5271     double angPrev = 0, angle;
5272     for ( int iSt = 0; iSt < nbSteps; ++iSt ) {
5273       double angCur = rAn2St * ( iSt+1 );
5274       double angCurFloor  = floor( angCur );
5275       double angPrevFloor = floor( angPrev );
5276       if ( angPrevFloor == angCurFloor )
5277         angle = rAn2St * theAngles[ int( angCurFloor ) ];
5278       else {
5279         int iP = int( angPrevFloor );
5280         double angPrevCeil = ceil(angPrev);
5281         angle = ( angPrevCeil - angPrev ) * theAngles[ iP ];
5282
5283         int iC = int( angCurFloor );
5284         if ( iC < nbAngles )
5285           angle += ( angCur - angCurFloor ) * theAngles[ iC ];
5286
5287         iP = int( angPrevCeil );
5288         while ( iC-- > iP )
5289           angle += theAngles[ iC ];
5290       }
5291       res.push_back(angle);
5292       angPrev = angCur;
5293     }
5294     Angles.clear();
5295     it = res.begin();
5296     for(; it!=res.end(); it++)
5297       Angles.push_back( *it );
5298   }
5299 }
5300
5301
5302 //================================================================================
5303 /*!
5304  * \brief Move or copy theElements applying theTrsf to their nodes
5305  *  \param theElems - elements to transform, if theElems is empty then apply to all mesh nodes
5306  *  \param theTrsf - transformation to apply
5307  *  \param theCopy - if true, create translated copies of theElems
5308  *  \param theMakeGroups - if true and theCopy, create translated groups
5309  *  \param theTargetMesh - mesh to copy translated elements into
5310  *  \retval SMESH_MeshEditor::PGroupIDs - list of ids of created groups
5311  */
5312 //================================================================================
5313
5314 SMESH_MeshEditor::PGroupIDs
5315 SMESH_MeshEditor::Transform (TIDSortedElemSet & theElems,
5316                              const gp_Trsf&     theTrsf,
5317                              const bool         theCopy,
5318                              const bool         theMakeGroups,
5319                              SMESH_Mesh*        theTargetMesh)
5320 {
5321   myLastCreatedElems.Clear();
5322   myLastCreatedNodes.Clear();
5323
5324   bool needReverse = false;
5325   string groupPostfix;
5326   switch ( theTrsf.Form() ) {
5327   case gp_PntMirror:
5328     MESSAGE("gp_PntMirror");
5329     needReverse = true;
5330     groupPostfix = "mirrored";
5331     break;
5332   case gp_Ax1Mirror:
5333     MESSAGE("gp_Ax1Mirror");
5334     groupPostfix = "mirrored";
5335     break;
5336   case gp_Ax2Mirror:
5337     MESSAGE("gp_Ax2Mirror");
5338     needReverse = true;
5339     groupPostfix = "mirrored";
5340     break;
5341   case gp_Rotation:
5342     MESSAGE("gp_Rotation");
5343     groupPostfix = "rotated";
5344     break;
5345   case gp_Translation:
5346     MESSAGE("gp_Translation");
5347     groupPostfix = "translated";
5348     break;
5349   case gp_Scale:
5350     MESSAGE("gp_Scale");
5351     groupPostfix = "scaled";
5352     break;
5353   case gp_CompoundTrsf: // different scale by axis
5354     MESSAGE("gp_CompoundTrsf");
5355     groupPostfix = "scaled";
5356     break;
5357   default:
5358     MESSAGE("default");
5359     needReverse = false;
5360     groupPostfix = "transformed";
5361   }
5362
5363   SMESH_MeshEditor targetMeshEditor( theTargetMesh );
5364   SMESHDS_Mesh* aTgtMesh = theTargetMesh ? theTargetMesh->GetMeshDS() : 0;
5365   SMESHDS_Mesh* aMesh    = GetMeshDS();
5366
5367
5368   // map old node to new one
5369   TNodeNodeMap nodeMap;
5370
5371   // elements sharing moved nodes; those of them which have all
5372   // nodes mirrored but are not in theElems are to be reversed
5373   TIDSortedElemSet inverseElemSet;
5374
5375   // source elements for each generated one
5376   SMESH_SequenceOfElemPtr srcElems, srcNodes;
5377
5378   // issue 021015: EDF 1578 SMESH: Free nodes are removed when translating a mesh
5379   TIDSortedElemSet orphanNode;
5380
5381   if ( theElems.empty() ) // transform the whole mesh
5382   {
5383     // add all elements
5384     SMDS_ElemIteratorPtr eIt = aMesh->elementsIterator();
5385     while ( eIt->more() ) theElems.insert( eIt->next() );
5386     // add orphan nodes
5387     SMDS_NodeIteratorPtr nIt = aMesh->nodesIterator();
5388     while ( nIt->more() )
5389     {
5390       const SMDS_MeshNode* node = nIt->next();
5391       if ( node->NbInverseElements() == 0)
5392         orphanNode.insert( node );
5393     }
5394   }
5395
5396   // loop on elements to transform nodes : first orphan nodes then elems
5397   TIDSortedElemSet::iterator itElem;
5398   TIDSortedElemSet *elements[] = {&orphanNode, &theElems };
5399   for (int i=0; i<2; i++)
5400   for ( itElem = elements[i]->begin(); itElem != elements[i]->end(); itElem++ ) {
5401     const SMDS_MeshElement* elem = *itElem;
5402     if ( !elem )
5403       continue;
5404
5405     // loop on elem nodes
5406     SMDS_ElemIteratorPtr itN = elem->nodesIterator();
5407     while ( itN->more() ) {
5408
5409       const SMDS_MeshNode* node = cast2Node( itN->next() );
5410       // check if a node has been already transformed
5411       pair<TNodeNodeMap::iterator,bool> n2n_isnew =
5412         nodeMap.insert( make_pair ( node, node ));
5413       if ( !n2n_isnew.second )
5414         continue;
5415
5416       double coord[3];
5417       coord[0] = node->X();
5418       coord[1] = node->Y();
5419       coord[2] = node->Z();
5420       theTrsf.Transforms( coord[0], coord[1], coord[2] );
5421       if ( theTargetMesh ) {
5422         const SMDS_MeshNode * newNode = aTgtMesh->AddNode( coord[0], coord[1], coord[2] );
5423         n2n_isnew.first->second = newNode;
5424         myLastCreatedNodes.Append(newNode);
5425         srcNodes.Append( node );
5426       }
5427       else if ( theCopy ) {
5428         const SMDS_MeshNode * newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
5429         n2n_isnew.first->second = newNode;
5430         myLastCreatedNodes.Append(newNode);
5431         srcNodes.Append( node );
5432       }
5433       else {
5434         aMesh->MoveNode( node, coord[0], coord[1], coord[2] );
5435         // node position on shape becomes invalid
5436         const_cast< SMDS_MeshNode* > ( node )->SetPosition
5437           ( SMDS_SpacePosition::originSpacePosition() );
5438       }
5439
5440       // keep inverse elements
5441       if ( !theCopy && !theTargetMesh && needReverse ) {
5442         SMDS_ElemIteratorPtr invElemIt = node->GetInverseElementIterator();
5443         while ( invElemIt->more() ) {
5444           const SMDS_MeshElement* iel = invElemIt->next();
5445           inverseElemSet.insert( iel );
5446         }
5447       }
5448     }
5449   }
5450
5451   // either create new elements or reverse mirrored ones
5452   if ( !theCopy && !needReverse && !theTargetMesh )
5453     return PGroupIDs();
5454
5455   TIDSortedElemSet::iterator invElemIt = inverseElemSet.begin();
5456   for ( ; invElemIt != inverseElemSet.end(); invElemIt++ )
5457     theElems.insert( *invElemIt );
5458
5459   // replicate or reverse elements
5460   // TODO revoir ordre reverse vtk
5461   enum {
5462     REV_TETRA   = 0,  //  = nbNodes - 4
5463     REV_PYRAMID = 1,  //  = nbNodes - 4
5464     REV_PENTA   = 2,  //  = nbNodes - 4
5465     REV_FACE    = 3,
5466     REV_HEXA    = 4,  //  = nbNodes - 4
5467     FORWARD     = 5
5468   };
5469   int index[][8] = {
5470     { 2, 1, 0, 3, 4, 0, 0, 0 },  // REV_TETRA
5471     { 2, 1, 0, 3, 4, 0, 0, 0 },  // REV_PYRAMID
5472     { 2, 1, 0, 5, 4, 3, 0, 0 },  // REV_PENTA
5473     { 2, 1, 0, 3, 0, 0, 0, 0 },  // REV_FACE
5474     { 2, 1, 0, 3, 6, 5, 4, 7 },  // REV_HEXA
5475     { 0, 1, 2, 3, 4, 5, 6, 7 }   // FORWARD
5476   };
5477
5478   for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ )
5479   {
5480     const SMDS_MeshElement* elem = *itElem;
5481     if ( !elem || elem->GetType() == SMDSAbs_Node )
5482       continue;
5483
5484     int nbNodes = elem->NbNodes();
5485     int elemType = elem->GetType();
5486
5487     if (elem->IsPoly()) {
5488       // Polygon or Polyhedral Volume
5489       switch ( elemType ) {
5490       case SMDSAbs_Face:
5491         {
5492           vector<const SMDS_MeshNode*> poly_nodes (nbNodes);
5493           int iNode = 0;
5494           SMDS_ElemIteratorPtr itN = elem->nodesIterator();
5495           while (itN->more()) {
5496             const SMDS_MeshNode* node =
5497               static_cast<const SMDS_MeshNode*>(itN->next());
5498             TNodeNodeMap::iterator nodeMapIt = nodeMap.find(node);
5499             if (nodeMapIt == nodeMap.end())
5500               break; // not all nodes transformed
5501             if (needReverse) {
5502               // reverse mirrored faces and volumes
5503               poly_nodes[nbNodes - iNode - 1] = (*nodeMapIt).second;
5504             } else {
5505               poly_nodes[iNode] = (*nodeMapIt).second;
5506             }
5507             iNode++;
5508           }
5509           if ( iNode != nbNodes )
5510             continue; // not all nodes transformed
5511
5512           if ( theTargetMesh ) {
5513             myLastCreatedElems.Append(aTgtMesh->AddPolygonalFace(poly_nodes));
5514             srcElems.Append( elem );
5515           }
5516           else if ( theCopy ) {
5517             myLastCreatedElems.Append(aMesh->AddPolygonalFace(poly_nodes));
5518             srcElems.Append( elem );
5519           }
5520           else {
5521             aMesh->ChangePolygonNodes(elem, poly_nodes);
5522           }
5523         }
5524         break;
5525       case SMDSAbs_Volume:
5526         {
5527           // ATTENTION: Reversing is not yet done!!!
5528           const SMDS_VtkVolume* aPolyedre =
5529             dynamic_cast<const SMDS_VtkVolume*>( elem );
5530           if (!aPolyedre) {
5531             MESSAGE("Warning: bad volumic element");
5532             continue;
5533           }
5534
5535           vector<const SMDS_MeshNode*> poly_nodes;
5536           vector<int> quantities;
5537
5538           bool allTransformed = true;
5539           int nbFaces = aPolyedre->NbFaces();
5540           for (int iface = 1; iface <= nbFaces && allTransformed; iface++) {
5541             int nbFaceNodes = aPolyedre->NbFaceNodes(iface);
5542             for (int inode = 1; inode <= nbFaceNodes && allTransformed; inode++) {
5543               const SMDS_MeshNode* node = aPolyedre->GetFaceNode(iface, inode);
5544               TNodeNodeMap::iterator nodeMapIt = nodeMap.find(node);
5545               if (nodeMapIt == nodeMap.end()) {
5546                 allTransformed = false; // not all nodes transformed
5547               } else {
5548                 poly_nodes.push_back((*nodeMapIt).second);
5549               }
5550             }
5551             quantities.push_back(nbFaceNodes);
5552           }
5553           if ( !allTransformed )
5554             continue; // not all nodes transformed
5555
5556           if ( theTargetMesh ) {
5557             myLastCreatedElems.Append(aTgtMesh->AddPolyhedralVolume(poly_nodes, quantities));
5558             srcElems.Append( elem );
5559           }
5560           else if ( theCopy ) {
5561             myLastCreatedElems.Append(aMesh->AddPolyhedralVolume(poly_nodes, quantities));
5562             srcElems.Append( elem );
5563           }
5564           else {
5565             aMesh->ChangePolyhedronNodes(elem, poly_nodes, quantities);
5566           }
5567         }
5568         break;
5569       default:;
5570       }
5571       continue;
5572     }
5573
5574     // Regular elements
5575     int* i = index[ FORWARD ];
5576     if ( needReverse && nbNodes > 2) {// reverse mirrored faces and volumes
5577       if ( elemType == SMDSAbs_Face )
5578         i = index[ REV_FACE ];
5579       else
5580         i = index[ nbNodes - 4 ];
5581     }
5582     if(elem->IsQuadratic()) {
5583       static int anIds[] = {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19};
5584       i = anIds;
5585       if(needReverse) {
5586         if(nbNodes==3) { // quadratic edge
5587           static int anIds[] = {1,0,2};
5588           i = anIds;
5589         }
5590         else if(nbNodes==6) { // quadratic triangle
5591           static int anIds[] = {0,2,1,5,4,3};
5592           i = anIds;
5593         }
5594         else if(nbNodes==8) { // quadratic quadrangle
5595           static int anIds[] = {0,3,2,1,7,6,5,4};
5596           i = anIds;
5597         }
5598         else if(nbNodes==10) { // quadratic tetrahedron of 10 nodes
5599           static int anIds[] = {0,2,1,3,6,5,4,7,9,8};
5600           i = anIds;
5601         }
5602         else if(nbNodes==13) { // quadratic pyramid of 13 nodes
5603           static int anIds[] = {0,3,2,1,4,8,7,6,5,9,12,11,10};
5604           i = anIds;
5605         }
5606         else if(nbNodes==15) { // quadratic pentahedron with 15 nodes
5607           static int anIds[] = {0,2,1,3,5,4,8,7,6,11,10,9,12,14,13};
5608           i = anIds;
5609         }
5610         else { // nbNodes==20 - quadratic hexahedron with 20 nodes
5611           static int anIds[] = {0,3,2,1,4,7,6,5,11,10,9,8,15,14,13,12,16,19,18,17};
5612           i = anIds;
5613         }
5614       }
5615     }
5616
5617     // find transformed nodes
5618     vector<const SMDS_MeshNode*> nodes(nbNodes);
5619     int iNode = 0;
5620     SMDS_ElemIteratorPtr itN = elem->nodesIterator();
5621     while ( itN->more() ) {
5622       const SMDS_MeshNode* node =
5623         static_cast<const SMDS_MeshNode*>( itN->next() );
5624       TNodeNodeMap::iterator nodeMapIt = nodeMap.find( node );
5625       if ( nodeMapIt == nodeMap.end() )
5626         break; // not all nodes transformed
5627       nodes[ i [ iNode++ ]] = (*nodeMapIt).second;
5628     }
5629     if ( iNode != nbNodes )
5630       continue; // not all nodes transformed
5631
5632     if ( theTargetMesh ) {
5633       if ( SMDS_MeshElement* copy =
5634            targetMeshEditor.AddElement( nodes, elem->GetType(), elem->IsPoly() )) {
5635         myLastCreatedElems.Append( copy );
5636         srcElems.Append( elem );
5637       }
5638     }
5639     else if ( theCopy ) {
5640       if ( AddElement( nodes, elem->GetType(), elem->IsPoly() ))
5641         srcElems.Append( elem );
5642     }
5643     else {
5644       // reverse element as it was reversed by transformation
5645       if ( nbNodes > 2 )
5646         aMesh->ChangeElementNodes( elem, &nodes[0], nbNodes );
5647     }
5648   }
5649
5650   PGroupIDs newGroupIDs;
5651
5652   if ( theMakeGroups && theCopy ||
5653        theMakeGroups && theTargetMesh )
5654     newGroupIDs = generateGroups( srcNodes, srcElems, groupPostfix, theTargetMesh );
5655
5656   return newGroupIDs;
5657 }
5658
5659
5660 ////=======================================================================
5661 ////function : Scale
5662 ////purpose  :
5663 ////=======================================================================
5664 //
5665 //SMESH_MeshEditor::PGroupIDs
5666 //SMESH_MeshEditor::Scale (TIDSortedElemSet & theElems,
5667 //                         const gp_Pnt&            thePoint,
5668 //                         const std::list<double>& theScaleFact,
5669 //                         const bool         theCopy,
5670 //                         const bool         theMakeGroups,
5671 //                         SMESH_Mesh*        theTargetMesh)
5672 //{
5673 //  MESSAGE("Scale");
5674 //  myLastCreatedElems.Clear();
5675 //  myLastCreatedNodes.Clear();
5676 //
5677 //  SMESH_MeshEditor targetMeshEditor( theTargetMesh );
5678 //  SMESHDS_Mesh* aTgtMesh = theTargetMesh ? theTargetMesh->GetMeshDS() : 0;
5679 //  SMESHDS_Mesh* aMesh    = GetMeshDS();
5680 //
5681 //  double scaleX=1.0, scaleY=1.0, scaleZ=1.0;
5682 //  std::list<double>::const_iterator itS = theScaleFact.begin();
5683 //  scaleX = (*itS);
5684 //  if(theScaleFact.size()==1) {
5685 //    scaleY = (*itS);
5686 //    scaleZ= (*itS);
5687 //  }
5688 //  if(theScaleFact.size()==2) {
5689 //    itS++;
5690 //    scaleY = (*itS);
5691 //    scaleZ= (*itS);
5692 //  }
5693 //  if(theScaleFact.size()>2) {
5694 //    itS++;
5695 //    scaleY = (*itS);
5696 //    itS++;
5697 //    scaleZ= (*itS);
5698 //  }
5699 //
5700 //  // map old node to new one
5701 //  TNodeNodeMap nodeMap;
5702 //
5703 //  // elements sharing moved nodes; those of them which have all
5704 //  // nodes mirrored but are not in theElems are to be reversed
5705 //  TIDSortedElemSet inverseElemSet;
5706 //
5707 //  // source elements for each generated one
5708 //  SMESH_SequenceOfElemPtr srcElems, srcNodes;
5709 //
5710 //  // loop on theElems
5711 //  TIDSortedElemSet::iterator itElem;
5712 //  for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
5713 //    const SMDS_MeshElement* elem = *itElem;
5714 //    if ( !elem )
5715 //      continue;
5716 //
5717 //    // loop on elem nodes
5718 //    SMDS_ElemIteratorPtr itN = elem->nodesIterator();
5719 //    while ( itN->more() ) {
5720 //
5721 //      // check if a node has been already transformed
5722 //      const SMDS_MeshNode* node = cast2Node( itN->next() );
5723 //      pair<TNodeNodeMap::iterator,bool> n2n_isnew =
5724 //        nodeMap.insert( make_pair ( node, node ));
5725 //      if ( !n2n_isnew.second )
5726 //        continue;
5727 //
5728 //      //double coord[3];
5729 //      //coord[0] = node->X();
5730 //      //coord[1] = node->Y();
5731 //      //coord[2] = node->Z();
5732 //      //theTrsf.Transforms( coord[0], coord[1], coord[2] );
5733 //      double dx = (node->X() - thePoint.X()) * scaleX;
5734 //      double dy = (node->Y() - thePoint.Y()) * scaleY;
5735 //      double dz = (node->Z() - thePoint.Z()) * scaleZ;
5736 //      if ( theTargetMesh ) {
5737 //        //const SMDS_MeshNode * newNode = aTgtMesh->AddNode( coord[0], coord[1], coord[2] );
5738 //        const SMDS_MeshNode * newNode =
5739 //          aTgtMesh->AddNode( thePoint.X()+dx, thePoint.Y()+dy, thePoint.Z()+dz );
5740 //        n2n_isnew.first->second = newNode;
5741 //        myLastCreatedNodes.Append(newNode);
5742 //        srcNodes.Append( node );
5743 //      }
5744 //      else if ( theCopy ) {
5745 //        //const SMDS_MeshNode * newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
5746 //        const SMDS_MeshNode * newNode =
5747 //          aMesh->AddNode( thePoint.X()+dx, thePoint.Y()+dy, thePoint.Z()+dz );
5748 //        n2n_isnew.first->second = newNode;
5749 //        myLastCreatedNodes.Append(newNode);
5750 //        srcNodes.Append( node );
5751 //      }
5752 //      else {
5753 //        //aMesh->MoveNode( node, coord[0], coord[1], coord[2] );
5754 //        aMesh->MoveNode( node, thePoint.X()+dx, thePoint.Y()+dy, thePoint.Z()+dz );
5755 //        // node position on shape becomes invalid
5756 //        const_cast< SMDS_MeshNode* > ( node )->SetPosition
5757 //          ( SMDS_SpacePosition::originSpacePosition() );
5758 //      }
5759 //
5760 //      // keep inverse elements
5761 //      //if ( !theCopy && !theTargetMesh && needReverse ) {
5762 //      //  SMDS_ElemIteratorPtr invElemIt = node->GetInverseElementIterator();
5763 //      //  while ( invElemIt->more() ) {
5764 //      //    const SMDS_MeshElement* iel = invElemIt->next();
5765 //      //    inverseElemSet.insert( iel );
5766 //      //  }
5767 //      //}
5768 //    }
5769 //  }
5770 //
5771 //  // either create new elements or reverse mirrored ones
5772 //  //if ( !theCopy && !needReverse && !theTargetMesh )
5773 //  if ( !theCopy && !theTargetMesh )
5774 //    return PGroupIDs();
5775 //
5776 //  TIDSortedElemSet::iterator invElemIt = inverseElemSet.begin();
5777 //  for ( ; invElemIt != inverseElemSet.end(); invElemIt++ )
5778 //    theElems.insert( *invElemIt );
5779 //
5780 //  // replicate or reverse elements
5781 //
5782 //  enum {
5783 //    REV_TETRA   = 0,  //  = nbNodes - 4
5784 //    REV_PYRAMID = 1,  //  = nbNodes - 4
5785 //    REV_PENTA   = 2,  //  = nbNodes - 4
5786 //    REV_FACE    = 3,
5787 //    REV_HEXA    = 4,  //  = nbNodes - 4
5788 //    FORWARD     = 5
5789 //  };
5790 //  int index[][8] = {
5791 //    { 2, 1, 0, 3, 4, 0, 0, 0 },  // REV_TETRA
5792 //    { 2, 1, 0, 3, 4, 0, 0, 0 },  // REV_PYRAMID
5793 //    { 2, 1, 0, 5, 4, 3, 0, 0 },  // REV_PENTA
5794 //    { 2, 1, 0, 3, 0, 0, 0, 0 },  // REV_FACE
5795 //    { 2, 1, 0, 3, 6, 5, 4, 7 },  // REV_HEXA
5796 //    { 0, 1, 2, 3, 4, 5, 6, 7 }   // FORWARD
5797 //  };
5798 //
5799 //  for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ )
5800 //  {
5801 //    const SMDS_MeshElement* elem = *itElem;
5802 //    if ( !elem || elem->GetType() == SMDSAbs_Node )
5803 //      continue;
5804 //
5805 //    int nbNodes = elem->NbNodes();
5806 //    int elemType = elem->GetType();
5807 //
5808 //    if (elem->IsPoly()) {
5809 //      // Polygon or Polyhedral Volume
5810 //      switch ( elemType ) {
5811 //      case SMDSAbs_Face:
5812 //        {
5813 //          vector<const SMDS_MeshNode*> poly_nodes (nbNodes);
5814 //          int iNode = 0;
5815 //          SMDS_ElemIteratorPtr itN = elem->nodesIterator();
5816 //          while (itN->more()) {
5817 //            const SMDS_MeshNode* node =
5818 //              static_cast<const SMDS_MeshNode*>(itN->next());
5819 //            TNodeNodeMap::iterator nodeMapIt = nodeMap.find(node);
5820 //            if (nodeMapIt == nodeMap.end())
5821 //              break; // not all nodes transformed
5822 //            //if (needReverse) {
5823 //            //  // reverse mirrored faces and volumes
5824 //            //  poly_nodes[nbNodes - iNode - 1] = (*nodeMapIt).second;
5825 //            //} else {
5826 //            poly_nodes[iNode] = (*nodeMapIt).second;
5827 //            //}
5828 //            iNode++;
5829 //          }
5830 //          if ( iNode != nbNodes )
5831 //            continue; // not all nodes transformed
5832 //
5833 //          if ( theTargetMesh ) {
5834 //            myLastCreatedElems.Append(aTgtMesh->AddPolygonalFace(poly_nodes));
5835 //            srcElems.Append( elem );
5836 //          }
5837 //          else if ( theCopy ) {
5838 //            myLastCreatedElems.Append(aMesh->AddPolygonalFace(poly_nodes));
5839 //            srcElems.Append( elem );
5840 //          }
5841 //          else {
5842 //            aMesh->ChangePolygonNodes(elem, poly_nodes);
5843 //          }
5844 //        }
5845 //        break;
5846 //      case SMDSAbs_Volume:
5847 //        {
5848 //          // ATTENTION: Reversing is not yet done!!!
5849 //          const SMDS_VtkVolume* aPolyedre =
5850 //            dynamic_cast<const SMDS_VtkVolume*>( elem );
5851 //          if (!aPolyedre) {
5852 //            MESSAGE("Warning: bad volumic element");
5853 //            continue;
5854 //          }
5855 //
5856 //          vector<const SMDS_MeshNode*> poly_nodes;
5857 //          vector<int> quantities;
5858 //
5859 //          bool allTransformed = true;
5860 //          int nbFaces = aPolyedre->NbFaces();
5861 //          for (int iface = 1; iface <= nbFaces && allTransformed; iface++) {
5862 //            int nbFaceNodes = aPolyedre->NbFaceNodes(iface);
5863 //            for (int inode = 1; inode <= nbFaceNodes && allTransformed; inode++) {
5864 //              const SMDS_MeshNode* node = aPolyedre->GetFaceNode(iface, inode);
5865 //              TNodeNodeMap::iterator nodeMapIt = nodeMap.find(node);
5866 //              if (nodeMapIt == nodeMap.end()) {
5867 //                allTransformed = false; // not all nodes transformed
5868 //              } else {
5869 //                poly_nodes.push_back((*nodeMapIt).second);
5870 //              }
5871 //            }
5872 //            quantities.push_back(nbFaceNodes);
5873 //          }
5874 //          if ( !allTransformed )
5875 //            continue; // not all nodes transformed
5876 //
5877 //          if ( theTargetMesh ) {
5878 //            myLastCreatedElems.Append(aTgtMesh->AddPolyhedralVolume(poly_nodes, quantities));
5879 //            srcElems.Append( elem );
5880 //          }
5881 //          else if ( theCopy ) {
5882 //            myLastCreatedElems.Append(aMesh->AddPolyhedralVolume(poly_nodes, quantities));
5883 //            srcElems.Append( elem );
5884 //          }
5885 //          else {
5886 //            aMesh->ChangePolyhedronNodes(elem, poly_nodes, quantities);
5887 //          }
5888 //        }
5889 //        break;
5890 //      default:;
5891 //      }
5892 //      continue;
5893 //    }
5894 //
5895 //    // Regular elements
5896 //    int* i = index[ FORWARD ];
5897 //    //if ( needReverse && nbNodes > 2) // reverse mirrored faces and volumes
5898 //    //  if ( elemType == SMDSAbs_Face )
5899 //    //    i = index[ REV_FACE ];
5900 //    //  else
5901 //    //    i = index[ nbNodes - 4 ];
5902 //
5903 //    if(elem->IsQuadratic()) {
5904 //      static int anIds[] = {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19};
5905 //      i = anIds;
5906 //      //if(needReverse) {
5907 //      //  if(nbNodes==3) { // quadratic edge
5908 //      //    static int anIds[] = {1,0,2};
5909 //      //    i = anIds;
5910 //      //  }
5911 //      //  else if(nbNodes==6) { // quadratic triangle
5912 //      //    static int anIds[] = {0,2,1,5,4,3};
5913 //      //    i = anIds;
5914 //      //  }
5915 //      //  else if(nbNodes==8) { // quadratic quadrangle
5916 //      //    static int anIds[] = {0,3,2,1,7,6,5,4};
5917 //      //    i = anIds;
5918 //      //  }
5919 //      //  else if(nbNodes==10) { // quadratic tetrahedron of 10 nodes
5920 //      //    static int anIds[] = {0,2,1,3,6,5,4,7,9,8};
5921 //      //    i = anIds;
5922 //      //  }
5923 //      //  else if(nbNodes==13) { // quadratic pyramid of 13 nodes
5924 //      //    static int anIds[] = {0,3,2,1,4,8,7,6,5,9,12,11,10};
5925 //      //    i = anIds;
5926 //      //  }
5927 //      //  else if(nbNodes==15) { // quadratic pentahedron with 15 nodes
5928 //      //    static int anIds[] = {0,2,1,3,5,4,8,7,6,11,10,9,12,14,13};
5929 //      //    i = anIds;
5930 //      //  }
5931 //      //  else { // nbNodes==20 - quadratic hexahedron with 20 nodes
5932 //      //    static int anIds[] = {0,3,2,1,4,7,6,5,11,10,9,8,15,14,13,12,16,19,18,17};
5933 //      //    i = anIds;
5934 //      //  }
5935 //      //}
5936 //    }
5937 //
5938 //    // find transformed nodes
5939 //    vector<const SMDS_MeshNode*> nodes(nbNodes);
5940 //    int iNode = 0;
5941 //    SMDS_ElemIteratorPtr itN = elem->nodesIterator();
5942 //    while ( itN->more() ) {
5943 //      const SMDS_MeshNode* node =
5944 //        static_cast<const SMDS_MeshNode*>( itN->next() );
5945 //      TNodeNodeMap::iterator nodeMapIt = nodeMap.find( node );
5946 //      if ( nodeMapIt == nodeMap.end() )
5947 //        break; // not all nodes transformed
5948 //      nodes[ i [ iNode++ ]] = (*nodeMapIt).second;
5949 //    }
5950 //    if ( iNode != nbNodes )
5951 //      continue; // not all nodes transformed
5952 //
5953 //    if ( theTargetMesh ) {
5954 //      if ( SMDS_MeshElement* copy =
5955 //           targetMeshEditor.AddElement( nodes, elem->GetType(), elem->IsPoly() )) {
5956 //        myLastCreatedElems.Append( copy );
5957 //        srcElems.Append( elem );
5958 //      }
5959 //    }
5960 //    else if ( theCopy ) {
5961 //      if ( SMDS_MeshElement* copy = AddElement( nodes, elem->GetType(), elem->IsPoly() )) {
5962 //        myLastCreatedElems.Append( copy );
5963 //        srcElems.Append( elem );
5964 //      }
5965 //    }
5966 //    else {
5967 //      // reverse element as it was reversed by transformation
5968 //      if ( nbNodes > 2 )
5969 //        aMesh->ChangeElementNodes( elem, &nodes[0], nbNodes );
5970 //    }
5971 //  }
5972 //
5973 //  PGroupIDs newGroupIDs;
5974 //
5975 //  if ( theMakeGroups && theCopy ||
5976 //       theMakeGroups && theTargetMesh ) {
5977 //    string groupPostfix = "scaled";
5978 //    newGroupIDs = generateGroups( srcNodes, srcElems, groupPostfix, theTargetMesh );
5979 //  }
5980 //
5981 //  return newGroupIDs;
5982 //}
5983
5984
5985 //=======================================================================
5986 /*!
5987  * \brief Create groups of elements made during transformation
5988  * \param nodeGens - nodes making corresponding myLastCreatedNodes
5989  * \param elemGens - elements making corresponding myLastCreatedElems
5990  * \param postfix - to append to names of new groups
5991  */
5992 //=======================================================================
5993
5994 SMESH_MeshEditor::PGroupIDs
5995 SMESH_MeshEditor::generateGroups(const SMESH_SequenceOfElemPtr& nodeGens,
5996                                  const SMESH_SequenceOfElemPtr& elemGens,
5997                                  const std::string&             postfix,
5998                                  SMESH_Mesh*                    targetMesh)
5999 {
6000   PGroupIDs newGroupIDs( new list<int> );
6001   SMESH_Mesh* mesh = targetMesh ? targetMesh : GetMesh();
6002
6003   // Sort existing groups by types and collect their names
6004
6005   // to store an old group and a generated new one
6006   typedef pair< SMESHDS_GroupBase*, SMDS_MeshGroup* > TOldNewGroup;
6007   vector< list< TOldNewGroup > > groupsByType( SMDSAbs_NbElementTypes );
6008   // group names
6009   set< string > groupNames;
6010   //
6011   SMDS_MeshGroup* nullNewGroup = (SMDS_MeshGroup*) 0;
6012   SMESH_Mesh::GroupIteratorPtr groupIt = GetMesh()->GetGroups();
6013   while ( groupIt->more() ) {
6014     SMESH_Group * group = groupIt->next();
6015     if ( !group ) continue;
6016     SMESHDS_GroupBase* groupDS = group->GetGroupDS();
6017     if ( !groupDS || groupDS->IsEmpty() ) continue;
6018     groupNames.insert( group->GetName() );
6019     groupDS->SetStoreName( group->GetName() );
6020     groupsByType[ groupDS->GetType() ].push_back( make_pair( groupDS, nullNewGroup ));
6021   }
6022
6023   // Groups creation
6024
6025   // loop on nodes and elements
6026   for ( int isNodes = 0; isNodes < 2; ++isNodes )
6027   {
6028     const SMESH_SequenceOfElemPtr& gens  = isNodes ? nodeGens : elemGens;
6029     const SMESH_SequenceOfElemPtr& elems = isNodes ? myLastCreatedNodes : myLastCreatedElems;
6030     if ( gens.Length() != elems.Length() )
6031       throw SALOME_Exception(LOCALIZED("invalid args"));
6032
6033     // loop on created elements
6034     for (int iElem = 1; iElem <= elems.Length(); ++iElem )
6035     {
6036       const SMDS_MeshElement* sourceElem = gens( iElem );
6037       if ( !sourceElem ) {
6038         MESSAGE("generateGroups(): NULL source element");
6039         continue;
6040       }
6041       list< TOldNewGroup > & groupsOldNew = groupsByType[ sourceElem->GetType() ];
6042       if ( groupsOldNew.empty() ) {
6043         while ( iElem < gens.Length() && gens( iElem+1 ) == sourceElem )
6044           ++iElem; // skip all elements made by sourceElem
6045         continue;
6046       }
6047       // collect all elements made by sourceElem
6048       list< const SMDS_MeshElement* > resultElems;
6049       if ( const SMDS_MeshElement* resElem = elems( iElem ))
6050         if ( resElem != sourceElem )
6051           resultElems.push_back( resElem );
6052       while ( iElem < gens.Length() && gens( iElem+1 ) == sourceElem )
6053         if ( const SMDS_MeshElement* resElem = elems( ++iElem ))
6054           if ( resElem != sourceElem )
6055             resultElems.push_back( resElem );
6056       // do not generate element groups from node ones
6057       if ( sourceElem->GetType() == SMDSAbs_Node &&
6058            elems( iElem )->GetType() != SMDSAbs_Node )
6059         continue;
6060
6061       // add resultElems to groups made by ones the sourceElem belongs to
6062       list< TOldNewGroup >::iterator gOldNew, gLast = groupsOldNew.end();
6063       for ( gOldNew = groupsOldNew.begin(); gOldNew != gLast; ++gOldNew )
6064       {
6065         SMESHDS_GroupBase* oldGroup = gOldNew->first;
6066         if ( oldGroup->Contains( sourceElem )) // sourceElem in oldGroup
6067         {
6068           SMDS_MeshGroup* & newGroup = gOldNew->second;
6069           if ( !newGroup )// create a new group
6070           {
6071             // make a name
6072             string name = oldGroup->GetStoreName();
6073             if ( !targetMesh ) {
6074               name += "_";
6075               name += postfix;
6076               int nb = 0;
6077               while ( !groupNames.insert( name ).second ) // name exists
6078               {
6079                 if ( nb == 0 ) {
6080                   name += "_1";
6081                 }
6082                 else {
6083                   TCollection_AsciiString nbStr(nb+1);
6084                   name.resize( name.rfind('_')+1 );
6085                   name += nbStr.ToCString();
6086                 }
6087                 ++nb;
6088               }
6089             }
6090             // make a group
6091             int id;
6092             SMESH_Group* group = mesh->AddGroup( resultElems.back()->GetType(),
6093                                                  name.c_str(), id );
6094             SMESHDS_Group* groupDS = static_cast<SMESHDS_Group*>(group->GetGroupDS());
6095             newGroup = & groupDS->SMDSGroup();
6096             newGroupIDs->push_back( id );
6097           }
6098
6099           // fill in a new group
6100           list< const SMDS_MeshElement* >::iterator resLast = resultElems.end(), resElemIt;
6101           for ( resElemIt = resultElems.begin(); resElemIt != resLast; ++resElemIt )
6102             newGroup->Add( *resElemIt );
6103         }
6104       }
6105     } // loop on created elements
6106   }// loop on nodes and elements
6107
6108   return newGroupIDs;
6109 }
6110
6111 //================================================================================
6112 /*!
6113  * \brief Return list of group of nodes close to each other within theTolerance
6114  *        Search among theNodes or in the whole mesh if theNodes is empty using
6115  *        an Octree algorithm
6116  */
6117 //================================================================================
6118
6119 void SMESH_MeshEditor::FindCoincidentNodes (TIDSortedNodeSet &   theNodes,
6120                                             const double         theTolerance,
6121                                             TListOfListOfNodes & theGroupsOfNodes)
6122 {
6123   myLastCreatedElems.Clear();
6124   myLastCreatedNodes.Clear();
6125
6126   if ( theNodes.empty() )
6127   { // get all nodes in the mesh
6128     SMDS_NodeIteratorPtr nIt = GetMeshDS()->nodesIterator(/*idInceasingOrder=*/true);
6129     while ( nIt->more() )
6130       theNodes.insert( theNodes.end(),nIt->next());
6131   }
6132
6133   SMESH_OctreeNode::FindCoincidentNodes ( theNodes, &theGroupsOfNodes, theTolerance);
6134 }
6135
6136
6137 //=======================================================================
6138 /*!
6139  * \brief Implementation of search for the node closest to point
6140  */
6141 //=======================================================================
6142
6143 struct SMESH_NodeSearcherImpl: public SMESH_NodeSearcher
6144 {
6145   //---------------------------------------------------------------------
6146   /*!
6147    * \brief Constructor
6148    */
6149   SMESH_NodeSearcherImpl( const SMESHDS_Mesh* theMesh )
6150   {
6151     myMesh = ( SMESHDS_Mesh* ) theMesh;
6152
6153     TIDSortedNodeSet nodes;
6154     if ( theMesh ) {
6155       SMDS_NodeIteratorPtr nIt = theMesh->nodesIterator(/*idInceasingOrder=*/true);
6156       while ( nIt->more() )
6157         nodes.insert( nodes.end(), nIt->next() );
6158     }
6159     myOctreeNode = new SMESH_OctreeNode(nodes) ;
6160
6161     // get max size of a leaf box
6162     SMESH_OctreeNode* tree = myOctreeNode;
6163     while ( !tree->isLeaf() )
6164     {
6165       SMESH_OctreeNodeIteratorPtr cIt = tree->GetChildrenIterator();
6166       if ( cIt->more() )
6167         tree = cIt->next();
6168     }
6169     myHalfLeafSize = tree->maxSize() / 2.;
6170   }
6171
6172   //---------------------------------------------------------------------
6173   /*!
6174    * \brief Move node and update myOctreeNode accordingly
6175    */
6176   void MoveNode( const SMDS_MeshNode* node, const gp_Pnt& toPnt )
6177   {
6178     myOctreeNode->UpdateByMoveNode( node, toPnt );
6179     myMesh->MoveNode( node, toPnt.X(), toPnt.Y(), toPnt.Z() );
6180   }
6181
6182   //---------------------------------------------------------------------
6183   /*!
6184    * \brief Do it's job
6185    */
6186   const SMDS_MeshNode* FindClosestTo( const gp_Pnt& thePnt )
6187   {
6188     map<double, const SMDS_MeshNode*> dist2Nodes;
6189     myOctreeNode->NodesAround( thePnt.Coord(), dist2Nodes, myHalfLeafSize );
6190     if ( !dist2Nodes.empty() )
6191       return dist2Nodes.begin()->second;
6192     list<const SMDS_MeshNode*> nodes;
6193     //myOctreeNode->NodesAround( &tgtNode, &nodes, myHalfLeafSize );
6194
6195     double minSqDist = DBL_MAX;
6196     if ( nodes.empty() )  // get all nodes of OctreeNode's closest to thePnt
6197     {
6198       // sort leafs by their distance from thePnt
6199       typedef map< double, SMESH_OctreeNode* > TDistTreeMap;
6200       TDistTreeMap treeMap;
6201       list< SMESH_OctreeNode* > treeList;
6202       list< SMESH_OctreeNode* >::iterator trIt;
6203       treeList.push_back( myOctreeNode );
6204
6205       gp_XYZ pointNode( thePnt.X(), thePnt.Y(), thePnt.Z() );
6206       bool pointInside = myOctreeNode->isInside( pointNode, myHalfLeafSize );
6207       for ( trIt = treeList.begin(); trIt != treeList.end(); ++trIt)
6208       {
6209         SMESH_OctreeNode* tree = *trIt;
6210         if ( !tree->isLeaf() ) // put children to the queue
6211         {
6212           if ( pointInside && !tree->isInside( pointNode, myHalfLeafSize )) continue;
6213           SMESH_OctreeNodeIteratorPtr cIt = tree->GetChildrenIterator();
6214           while ( cIt->more() )
6215             treeList.push_back( cIt->next() );
6216         }
6217         else if ( tree->NbNodes() ) // put a tree to the treeMap
6218         {
6219           const Bnd_B3d& box = tree->getBox();
6220           double sqDist = thePnt.SquareDistance( 0.5 * ( box.CornerMin() + box.CornerMax() ));
6221           pair<TDistTreeMap::iterator,bool> it_in = treeMap.insert( make_pair( sqDist, tree ));
6222           if ( !it_in.second ) // not unique distance to box center
6223             treeMap.insert( it_in.first, make_pair( sqDist + 1e-13*treeMap.size(), tree ));
6224         }
6225       }
6226       // find distance after which there is no sense to check tree's
6227       double sqLimit = DBL_MAX;
6228       TDistTreeMap::iterator sqDist_tree = treeMap.begin();
6229       if ( treeMap.size() > 5 ) {
6230         SMESH_OctreeNode* closestTree = sqDist_tree->second;
6231         const Bnd_B3d& box = closestTree->getBox();
6232         double limit = sqrt( sqDist_tree->first ) + sqrt ( box.SquareExtent() );
6233         sqLimit = limit * limit;
6234       }
6235       // get all nodes from trees
6236       for ( ; sqDist_tree != treeMap.end(); ++sqDist_tree) {
6237         if ( sqDist_tree->first > sqLimit )
6238           break;
6239         SMESH_OctreeNode* tree = sqDist_tree->second;
6240         tree->NodesAround( tree->GetNodeIterator()->next(), &nodes );
6241       }
6242     }
6243     // find closest among nodes
6244     minSqDist = DBL_MAX;
6245     const SMDS_MeshNode* closestNode = 0;
6246     list<const SMDS_MeshNode*>::iterator nIt = nodes.begin();
6247     for ( ; nIt != nodes.end(); ++nIt ) {
6248       double sqDist = thePnt.SquareDistance( SMESH_TNodeXYZ( *nIt ) );
6249       if ( minSqDist > sqDist ) {
6250         closestNode = *nIt;
6251         minSqDist = sqDist;
6252       }
6253     }
6254     return closestNode;
6255   }
6256
6257   //---------------------------------------------------------------------
6258   /*!
6259    * \brief Destructor
6260    */
6261   ~SMESH_NodeSearcherImpl() { delete myOctreeNode; }
6262
6263   //---------------------------------------------------------------------
6264   /*!
6265    * \brief Return the node tree
6266    */
6267   const SMESH_OctreeNode* getTree() const { return myOctreeNode; }
6268
6269 private:
6270   SMESH_OctreeNode* myOctreeNode;
6271   SMESHDS_Mesh*     myMesh;
6272   double            myHalfLeafSize; // max size of a leaf box
6273 };
6274
6275 //=======================================================================
6276 /*!
6277  * \brief Return SMESH_NodeSearcher
6278  */
6279 //=======================================================================
6280
6281 SMESH_NodeSearcher* SMESH_MeshEditor::GetNodeSearcher() 
6282 {
6283   return new SMESH_NodeSearcherImpl( GetMeshDS() );
6284 }
6285
6286 // ========================================================================
6287 namespace // Utils used in SMESH_ElementSearcherImpl::FindElementsByPoint()
6288 {
6289   const int MaxNbElemsInLeaf = 10; // maximal number of elements in a leaf of tree
6290   const int MaxLevel         = 7;  // maximal tree height -> nb terminal boxes: 8^7 = 2097152
6291   const double NodeRadius = 1e-9;  // to enlarge bnd box of element
6292
6293   //=======================================================================
6294   /*!
6295    * \brief Octal tree of bounding boxes of elements
6296    */
6297   //=======================================================================
6298
6299   class ElementBndBoxTree : public SMESH_Octree
6300   {
6301   public:
6302
6303     ElementBndBoxTree(const SMDS_Mesh& mesh, SMDSAbs_ElementType elemType, SMDS_ElemIteratorPtr theElemIt = SMDS_ElemIteratorPtr(), double tolerance = NodeRadius );
6304     void getElementsNearPoint( const gp_Pnt& point, TIDSortedElemSet& foundElems);
6305     void getElementsNearLine ( const gp_Ax1& line, TIDSortedElemSet& foundElems);
6306     ~ElementBndBoxTree();
6307
6308   protected:
6309     ElementBndBoxTree() {}
6310     SMESH_Octree* allocateOctreeChild() const { return new ElementBndBoxTree; }
6311     void buildChildrenData();
6312     Bnd_B3d* buildRootBox();
6313   private:
6314     //!< Bounding box of element
6315     struct ElementBox : public Bnd_B3d
6316     {
6317       const SMDS_MeshElement* _element;
6318       int                     _refCount; // an ElementBox can be included in several tree branches
6319       ElementBox(const SMDS_MeshElement* elem, double tolerance);
6320     };
6321     vector< ElementBox* > _elements;
6322   };
6323
6324   //================================================================================
6325   /*!
6326    * \brief ElementBndBoxTree creation
6327    */
6328   //================================================================================
6329
6330   ElementBndBoxTree::ElementBndBoxTree(const SMDS_Mesh& mesh, SMDSAbs_ElementType elemType, SMDS_ElemIteratorPtr theElemIt, double tolerance)
6331     :SMESH_Octree( new SMESH_Octree::Limit( MaxLevel, /*minSize=*/0. ))
6332   {
6333     int nbElems = mesh.GetMeshInfo().NbElements( elemType );
6334     _elements.reserve( nbElems );
6335
6336     SMDS_ElemIteratorPtr elemIt = theElemIt ? theElemIt : mesh.elementsIterator( elemType );
6337     while ( elemIt->more() )
6338       _elements.push_back( new ElementBox( elemIt->next(),tolerance  ));
6339
6340     if ( _elements.size() > MaxNbElemsInLeaf )
6341       compute();
6342     else
6343       myIsLeaf = true;
6344   }
6345
6346   //================================================================================
6347   /*!
6348    * \brief Destructor
6349    */
6350   //================================================================================
6351
6352   ElementBndBoxTree::~ElementBndBoxTree()
6353   {
6354     for ( int i = 0; i < _elements.size(); ++i )
6355       if ( --_elements[i]->_refCount <= 0 )
6356         delete _elements[i];
6357   }
6358
6359   //================================================================================
6360   /*!
6361    * \brief Return the maximal box
6362    */
6363   //================================================================================
6364
6365   Bnd_B3d* ElementBndBoxTree::buildRootBox()
6366   {
6367     Bnd_B3d* box = new Bnd_B3d;
6368     for ( int i = 0; i < _elements.size(); ++i )
6369       box->Add( *_elements[i] );
6370     return box;
6371   }
6372
6373   //================================================================================
6374   /*!
6375    * \brief Redistrubute element boxes among children
6376    */
6377   //================================================================================
6378
6379   void ElementBndBoxTree::buildChildrenData()
6380   {
6381     for ( int i = 0; i < _elements.size(); ++i )
6382     {
6383       for (int j = 0; j < 8; j++)
6384       {
6385         if ( !_elements[i]->IsOut( myChildren[j]->getBox() ))
6386         {
6387           _elements[i]->_refCount++;
6388           ((ElementBndBoxTree*)myChildren[j])->_elements.push_back( _elements[i]);
6389         }
6390       }
6391       _elements[i]->_refCount--;
6392     }
6393     _elements.clear();
6394
6395     for (int j = 0; j < 8; j++)
6396     {
6397       ElementBndBoxTree* child = static_cast<ElementBndBoxTree*>( myChildren[j]);
6398       if ( child->_elements.size() <= MaxNbElemsInLeaf )
6399         child->myIsLeaf = true;
6400
6401       if ( child->_elements.capacity() - child->_elements.size() > 1000 )
6402         child->_elements.resize( child->_elements.size() ); // compact
6403     }
6404   }
6405
6406   //================================================================================
6407   /*!
6408    * \brief Return elements which can include the point
6409    */
6410   //================================================================================
6411
6412   void ElementBndBoxTree::getElementsNearPoint( const gp_Pnt&     point,
6413                                                 TIDSortedElemSet& foundElems)
6414   {
6415     if ( level() && getBox().IsOut( point.XYZ() ))
6416       return;
6417
6418     if ( isLeaf() )
6419     {
6420       for ( int i = 0; i < _elements.size(); ++i )
6421         if ( !_elements[i]->IsOut( point.XYZ() ))
6422           foundElems.insert( _elements[i]->_element );
6423     }
6424     else
6425     {
6426       for (int i = 0; i < 8; i++)
6427         ((ElementBndBoxTree*) myChildren[i])->getElementsNearPoint( point, foundElems );
6428     }
6429   }
6430
6431   //================================================================================
6432   /*!
6433    * \brief Return elements which can be intersected by the line
6434    */
6435   //================================================================================
6436
6437   void ElementBndBoxTree::getElementsNearLine( const gp_Ax1&     line,
6438                                                TIDSortedElemSet& foundElems)
6439   {
6440     if ( level() && getBox().IsOut( line ))
6441       return;
6442
6443     if ( isLeaf() )
6444     {
6445       for ( int i = 0; i < _elements.size(); ++i )
6446         if ( !_elements[i]->IsOut( line ))
6447           foundElems.insert( _elements[i]->_element );
6448     }
6449     else
6450     {
6451       for (int i = 0; i < 8; i++)
6452         ((ElementBndBoxTree*) myChildren[i])->getElementsNearLine( line, foundElems );
6453     }
6454   }
6455
6456   //================================================================================
6457   /*!
6458    * \brief Construct the element box
6459    */
6460   //================================================================================
6461
6462   ElementBndBoxTree::ElementBox::ElementBox(const SMDS_MeshElement* elem, double tolerance)
6463   {
6464     _element  = elem;
6465     _refCount = 1;
6466     SMDS_ElemIteratorPtr nIt = elem->nodesIterator();
6467     while ( nIt->more() )
6468       Add( SMESH_TNodeXYZ( cast2Node( nIt->next() )));
6469     Enlarge( tolerance );
6470   }
6471
6472 } // namespace
6473
6474 //=======================================================================
6475 /*!
6476  * \brief Implementation of search for the elements by point and
6477  *        of classification of point in 2D mesh
6478  */
6479 //=======================================================================
6480
6481 struct SMESH_ElementSearcherImpl: public SMESH_ElementSearcher
6482 {
6483   SMESHDS_Mesh*                _mesh;
6484   SMDS_ElemIteratorPtr         _meshPartIt;
6485   ElementBndBoxTree*           _ebbTree;
6486   SMESH_NodeSearcherImpl*      _nodeSearcher;
6487   SMDSAbs_ElementType          _elementType;
6488   double                       _tolerance;
6489   bool                         _outerFacesFound;
6490   set<const SMDS_MeshElement*> _outerFaces; // empty means "no internal faces at all"
6491
6492   SMESH_ElementSearcherImpl( SMESHDS_Mesh& mesh, SMDS_ElemIteratorPtr elemIt=SMDS_ElemIteratorPtr())
6493     : _mesh(&mesh),_meshPartIt(elemIt),_ebbTree(0),_nodeSearcher(0),_tolerance(-1),_outerFacesFound(false) {}
6494   ~SMESH_ElementSearcherImpl()
6495   {
6496     if ( _ebbTree )      delete _ebbTree;      _ebbTree      = 0;
6497     if ( _nodeSearcher ) delete _nodeSearcher; _nodeSearcher = 0;
6498   }
6499   virtual int FindElementsByPoint(const gp_Pnt&                      point,
6500                                   SMDSAbs_ElementType                type,
6501                                   vector< const SMDS_MeshElement* >& foundElements);
6502   virtual TopAbs_State GetPointState(const gp_Pnt& point);
6503
6504   void GetElementsNearLine( const gp_Ax1&                      line,
6505                             SMDSAbs_ElementType                type,
6506                             vector< const SMDS_MeshElement* >& foundElems);
6507   double getTolerance();
6508   bool getIntersParamOnLine(const gp_Lin& line, const SMDS_MeshElement* face,
6509                             const double tolerance, double & param);
6510   void findOuterBoundary(const SMDS_MeshElement* anyOuterFace);
6511   bool isOuterBoundary(const SMDS_MeshElement* face) const
6512   {
6513     return _outerFaces.empty() || _outerFaces.count(face);
6514   }
6515   struct TInters //!< data of intersection of the line and the mesh face (used in GetPointState())
6516   {
6517     const SMDS_MeshElement* _face;
6518     gp_Vec                  _faceNorm;
6519     bool                    _coincides; //!< the line lays in face plane
6520     TInters(const SMDS_MeshElement* face, const gp_Vec& faceNorm, bool coinc=false)
6521       : _face(face), _faceNorm( faceNorm ), _coincides( coinc ) {}
6522   };
6523   struct TFaceLink //!< link and faces sharing it (used in findOuterBoundary())
6524   {
6525     SMESH_TLink      _link;
6526     TIDSortedElemSet _faces;
6527     TFaceLink( const SMDS_MeshNode* n1, const SMDS_MeshNode* n2, const SMDS_MeshElement* face)
6528       : _link( n1, n2 ), _faces( &face, &face + 1) {}
6529   };
6530 };
6531
6532 ostream& operator<< (ostream& out, const SMESH_ElementSearcherImpl::TInters& i)
6533 {
6534   return out << "TInters(face=" << ( i._face ? i._face->GetID() : 0)
6535              << ", _coincides="<<i._coincides << ")";
6536 }
6537
6538 //=======================================================================
6539 /*!
6540  * \brief define tolerance for search
6541  */
6542 //=======================================================================
6543
6544 double SMESH_ElementSearcherImpl::getTolerance()
6545 {
6546   if ( _tolerance < 0 )
6547   {
6548     const SMDS_MeshInfo& meshInfo = _mesh->GetMeshInfo();
6549
6550     _tolerance = 0;
6551     if ( _nodeSearcher && meshInfo.NbNodes() > 1 )
6552     {
6553       double boxSize = _nodeSearcher->getTree()->maxSize();
6554       _tolerance = 1e-8 * boxSize/* / meshInfo.NbNodes()*/;
6555     }
6556     else if ( _ebbTree && meshInfo.NbElements() > 0 )
6557     {
6558       double boxSize = _ebbTree->maxSize();
6559       _tolerance = 1e-8 * boxSize/* / meshInfo.NbElements()*/;
6560     }
6561     if ( _tolerance == 0 )
6562     {
6563       // define tolerance by size of a most complex element
6564       int complexType = SMDSAbs_Volume;
6565       while ( complexType > SMDSAbs_All &&
6566               meshInfo.NbElements( SMDSAbs_ElementType( complexType )) < 1 )
6567         --complexType;
6568       if ( complexType == SMDSAbs_All ) return 0; // empty mesh
6569       double elemSize;
6570       if ( complexType == int( SMDSAbs_Node ))
6571       {
6572         SMDS_NodeIteratorPtr nodeIt = _mesh->nodesIterator();
6573         elemSize = 1;
6574         if ( meshInfo.NbNodes() > 2 )
6575           elemSize = SMESH_TNodeXYZ( nodeIt->next() ).Distance( nodeIt->next() );
6576       }
6577       else
6578       {
6579         SMDS_ElemIteratorPtr elemIt =
6580             _mesh->elementsIterator( SMDSAbs_ElementType( complexType ));
6581         const SMDS_MeshElement* elem = elemIt->next();
6582         SMDS_ElemIteratorPtr nodeIt = elem->nodesIterator();
6583         SMESH_TNodeXYZ n1( cast2Node( nodeIt->next() ));
6584         elemSize = 0;
6585         while ( nodeIt->more() )
6586         {
6587           double dist = n1.Distance( cast2Node( nodeIt->next() ));
6588           elemSize = max( dist, elemSize );
6589         }
6590       }
6591       _tolerance = 1e-4 * elemSize;
6592     }
6593   }
6594   return _tolerance;
6595 }
6596
6597 //================================================================================
6598 /*!
6599  * \brief Find intersection of the line and an edge of face and return parameter on line
6600  */
6601 //================================================================================
6602
6603 bool SMESH_ElementSearcherImpl::getIntersParamOnLine(const gp_Lin&           line,
6604                                                      const SMDS_MeshElement* face,
6605                                                      const double            tol,
6606                                                      double &                param)
6607 {
6608   int nbInts = 0;
6609   param = 0;
6610
6611   GeomAPI_ExtremaCurveCurve anExtCC;
6612   Handle(Geom_Curve) lineCurve = new Geom_Line( line );
6613   
6614   int nbNodes = face->IsQuadratic() ? face->NbNodes()/2 : face->NbNodes();
6615   for ( int i = 0; i < nbNodes && nbInts < 2; ++i )
6616   {
6617     GC_MakeSegment edge( SMESH_TNodeXYZ( face->GetNode( i )),
6618                          SMESH_TNodeXYZ( face->GetNode( (i+1)%nbNodes) )); 
6619     anExtCC.Init( lineCurve, edge);
6620     if ( anExtCC.NbExtrema() > 0 && anExtCC.LowerDistance() <= tol)
6621     {
6622       Quantity_Parameter pl, pe;
6623       anExtCC.LowerDistanceParameters( pl, pe );
6624       param += pl;
6625       if ( ++nbInts == 2 )
6626         break;
6627     }
6628   }
6629   if ( nbInts > 0 ) param /= nbInts;
6630   return nbInts > 0;
6631 }
6632 //================================================================================
6633 /*!
6634  * \brief Find all faces belonging to the outer boundary of mesh
6635  */
6636 //================================================================================
6637
6638 void SMESH_ElementSearcherImpl::findOuterBoundary(const SMDS_MeshElement* outerFace)
6639 {
6640   if ( _outerFacesFound ) return;
6641
6642   // Collect all outer faces by passing from one outer face to another via their links
6643   // and BTW find out if there are internal faces at all.
6644
6645   // checked links and links where outer boundary meets internal one
6646   set< SMESH_TLink > visitedLinks, seamLinks;
6647
6648   // links to treat with already visited faces sharing them
6649   list < TFaceLink > startLinks;
6650
6651   // load startLinks with the first outerFace
6652   startLinks.push_back( TFaceLink( outerFace->GetNode(0), outerFace->GetNode(1), outerFace));
6653   _outerFaces.insert( outerFace );
6654
6655   TIDSortedElemSet emptySet;
6656   while ( !startLinks.empty() )
6657   {
6658     const SMESH_TLink& link  = startLinks.front()._link;
6659     TIDSortedElemSet&  faces = startLinks.front()._faces;
6660
6661     outerFace = *faces.begin();
6662     // find other faces sharing the link
6663     const SMDS_MeshElement* f;
6664     while (( f = SMESH_MeshEditor::FindFaceInSet(link.node1(), link.node2(), emptySet, faces )))
6665       faces.insert( f );
6666
6667     // select another outer face among the found 
6668     const SMDS_MeshElement* outerFace2 = 0;
6669     if ( faces.size() == 2 )
6670     {
6671       outerFace2 = (outerFace == *faces.begin() ? *faces.rbegin() : *faces.begin());
6672     }
6673     else if ( faces.size() > 2 )
6674     {
6675       seamLinks.insert( link );
6676
6677       // link direction within the outerFace
6678       gp_Vec n1n2( SMESH_TNodeXYZ( link.node1()),
6679                    SMESH_TNodeXYZ( link.node2()));
6680       int i1 = outerFace->GetNodeIndex( link.node1() );
6681       int i2 = outerFace->GetNodeIndex( link.node2() );
6682       bool rev = ( abs(i2-i1) == 1 ? i1 > i2 : i2 > i1 );
6683       if ( rev ) n1n2.Reverse();
6684       // outerFace normal
6685       gp_XYZ ofNorm, fNorm;
6686       if ( SMESH_Algo::FaceNormal( outerFace, ofNorm, /*normalized=*/false ))
6687       {
6688         // direction from the link inside outerFace
6689         gp_Vec dirInOF = gp_Vec( ofNorm ) ^ n1n2;
6690         // sort all other faces by angle with the dirInOF
6691         map< double, const SMDS_MeshElement* > angle2Face;
6692         set< const SMDS_MeshElement*, TIDCompare >::const_iterator face = faces.begin();
6693         for ( ; face != faces.end(); ++face )
6694         {
6695           if ( !SMESH_Algo::FaceNormal( *face, fNorm, /*normalized=*/false ))
6696             continue;
6697           gp_Vec dirInF = gp_Vec( fNorm ) ^ n1n2;
6698           double angle = dirInOF.AngleWithRef( dirInF, n1n2 );
6699           if ( angle < 0 ) angle += 2*PI;
6700           angle2Face.insert( make_pair( angle, *face ));
6701         }
6702         if ( !angle2Face.empty() )
6703           outerFace2 = angle2Face.begin()->second;
6704       }
6705     }
6706     // store the found outer face and add its links to continue seaching from
6707     if ( outerFace2 )
6708     {
6709       _outerFaces.insert( outerFace );
6710       int nbNodes = outerFace2->NbNodes()/( outerFace2->IsQuadratic() ? 2 : 1 );
6711       for ( int i = 0; i < nbNodes; ++i )
6712       {
6713         SMESH_TLink link2( outerFace2->GetNode(i), outerFace2->GetNode((i+1)%nbNodes));
6714         if ( visitedLinks.insert( link2 ).second )
6715           startLinks.push_back( TFaceLink( link2.node1(), link2.node2(), outerFace2 ));
6716       }
6717     }
6718     startLinks.pop_front();
6719   }
6720   _outerFacesFound = true;
6721
6722   if ( !seamLinks.empty() )
6723   {
6724     // There are internal boundaries touching the outher one,
6725     // find all faces of internal boundaries in order to find
6726     // faces of boundaries of holes, if any.
6727     
6728   }
6729   else
6730   {
6731     _outerFaces.clear();
6732   }
6733 }
6734
6735 //=======================================================================
6736 /*!
6737  * \brief Find elements of given type where the given point is IN or ON.
6738  *        Returns nb of found elements and elements them-selves.
6739  *
6740  * 'ALL' type means elements of any type excluding nodes and 0D elements
6741  */
6742 //=======================================================================
6743
6744 int SMESH_ElementSearcherImpl::
6745 FindElementsByPoint(const gp_Pnt&                      point,
6746                     SMDSAbs_ElementType                type,
6747                     vector< const SMDS_MeshElement* >& foundElements)
6748 {
6749   foundElements.clear();
6750
6751   double tolerance = getTolerance();
6752
6753   // =================================================================================
6754   if ( type == SMDSAbs_Node || type == SMDSAbs_0DElement )
6755   {
6756     if ( !_nodeSearcher )
6757       _nodeSearcher = new SMESH_NodeSearcherImpl( _mesh );
6758
6759     const SMDS_MeshNode* closeNode = _nodeSearcher->FindClosestTo( point );
6760     if ( !closeNode ) return foundElements.size();
6761
6762     if ( point.Distance( SMESH_TNodeXYZ( closeNode )) > tolerance )
6763       return foundElements.size(); // to far from any node
6764
6765     if ( type == SMDSAbs_Node )
6766     {
6767       foundElements.push_back( closeNode );
6768     }
6769     else
6770     {
6771       SMDS_ElemIteratorPtr elemIt = closeNode->GetInverseElementIterator( SMDSAbs_0DElement );
6772       while ( elemIt->more() )
6773         foundElements.push_back( elemIt->next() );
6774     }
6775   }
6776   // =================================================================================
6777   else // elements more complex than 0D
6778   {
6779     if ( !_ebbTree || _elementType != type )
6780     {
6781       if ( _ebbTree ) delete _ebbTree;
6782       _ebbTree = new ElementBndBoxTree( *_mesh, _elementType = type, _meshPartIt, tolerance );
6783     }
6784     TIDSortedElemSet suspectElems;
6785     _ebbTree->getElementsNearPoint( point, suspectElems );
6786     TIDSortedElemSet::iterator elem = suspectElems.begin();
6787     for ( ; elem != suspectElems.end(); ++elem )
6788       if ( !SMESH_MeshEditor::isOut( *elem, point, tolerance ))
6789         foundElements.push_back( *elem );
6790   }
6791   return foundElements.size();
6792 }
6793
6794 //================================================================================
6795 /*!
6796  * \brief Classify the given point in the closed 2D mesh
6797  */
6798 //================================================================================
6799
6800 TopAbs_State SMESH_ElementSearcherImpl::GetPointState(const gp_Pnt& point)
6801 {
6802   double tolerance = getTolerance();
6803   if ( !_ebbTree || _elementType != SMDSAbs_Face )
6804   {
6805     if ( _ebbTree ) delete _ebbTree;
6806     _ebbTree = new ElementBndBoxTree( *_mesh, _elementType = SMDSAbs_Face, _meshPartIt );
6807   }
6808   // Algo: analyse transition of a line starting at the point through mesh boundary;
6809   // try three lines parallel to axis of the coordinate system and perform rough
6810   // analysis. If solution is not clear perform thorough analysis.
6811
6812   const int nbAxes = 3;
6813   gp_Dir axisDir[ nbAxes ] = { gp::DX(), gp::DY(), gp::DZ() };
6814   map< double, TInters >   paramOnLine2TInters[ nbAxes ];
6815   list< TInters > tangentInters[ nbAxes ]; // of faces whose plane includes the line
6816   multimap< int, int > nbInt2Axis; // to find the simplest case
6817   for ( int axis = 0; axis < nbAxes; ++axis )
6818   {
6819     gp_Ax1 lineAxis( point, axisDir[axis]);
6820     gp_Lin line    ( lineAxis );
6821
6822     TIDSortedElemSet suspectFaces; // faces possibly intersecting the line
6823     _ebbTree->getElementsNearLine( lineAxis, suspectFaces );
6824
6825     // Intersect faces with the line
6826
6827     map< double, TInters > & u2inters = paramOnLine2TInters[ axis ];
6828     TIDSortedElemSet::iterator face = suspectFaces.begin();
6829     for ( ; face != suspectFaces.end(); ++face )
6830     {
6831       // get face plane
6832       gp_XYZ fNorm;
6833       if ( !SMESH_Algo::FaceNormal( *face, fNorm, /*normalized=*/false)) continue;
6834       gp_Pln facePlane( SMESH_TNodeXYZ( (*face)->GetNode(0)), fNorm );
6835
6836       // perform intersection
6837       IntAna_IntConicQuad intersection( line, IntAna_Quadric( facePlane ));
6838       if ( !intersection.IsDone() )
6839         continue;
6840       if ( intersection.IsInQuadric() )
6841       {
6842         tangentInters[ axis ].push_back( TInters( *face, fNorm, true ));
6843       }
6844       else if ( ! intersection.IsParallel() && intersection.NbPoints() > 0 )
6845       {
6846         gp_Pnt intersectionPoint = intersection.Point(1);
6847         if ( !SMESH_MeshEditor::isOut( *face, intersectionPoint, tolerance ))
6848           u2inters.insert(make_pair( intersection.ParamOnConic(1), TInters( *face, fNorm )));
6849       }
6850     }
6851     // Analyse intersections roughly
6852
6853     int nbInter = u2inters.size();
6854     if ( nbInter == 0 )
6855       return TopAbs_OUT; 
6856
6857     double f = u2inters.begin()->first, l = u2inters.rbegin()->first;
6858     if ( nbInter == 1 ) // not closed mesh
6859       return fabs( f ) < tolerance ? TopAbs_ON : TopAbs_UNKNOWN;
6860
6861     if ( fabs( f ) < tolerance || fabs( l ) < tolerance )
6862       return TopAbs_ON;
6863
6864     if ( (f<0) == (l<0) )
6865       return TopAbs_OUT;
6866
6867     int nbIntBeforePoint = std::distance( u2inters.begin(), u2inters.lower_bound(0));
6868     int nbIntAfterPoint  = nbInter - nbIntBeforePoint;
6869     if ( nbIntBeforePoint == 1 || nbIntAfterPoint == 1 )
6870       return TopAbs_IN;
6871
6872     nbInt2Axis.insert( make_pair( min( nbIntBeforePoint, nbIntAfterPoint ), axis ));
6873
6874     if ( _outerFacesFound ) break; // pass to thorough analysis
6875
6876   } // three attempts - loop on CS axes
6877
6878   // Analyse intersections thoroughly.
6879   // We make two loops maximum, on the first one we only exclude touching intersections,
6880   // on the second, if situation is still unclear, we gather and use information on
6881   // position of faces (internal or outer). If faces position is already gathered,
6882   // we make the second loop right away.
6883
6884   for ( int hasPositionInfo = _outerFacesFound; hasPositionInfo < 2; ++hasPositionInfo )
6885   {
6886     multimap< int, int >::const_iterator nb_axis = nbInt2Axis.begin();
6887     for ( ; nb_axis != nbInt2Axis.end(); ++nb_axis )
6888     {
6889       int axis = nb_axis->second;
6890       map< double, TInters > & u2inters = paramOnLine2TInters[ axis ];
6891
6892       gp_Ax1 lineAxis( point, axisDir[axis]);
6893       gp_Lin line    ( lineAxis );
6894
6895       // add tangent intersections to u2inters
6896       double param;
6897       list< TInters >::const_iterator tgtInt = tangentInters[ axis ].begin();
6898       for ( ; tgtInt != tangentInters[ axis ].end(); ++tgtInt )
6899         if ( getIntersParamOnLine( line, tgtInt->_face, tolerance, param ))
6900           u2inters.insert(make_pair( param, *tgtInt ));
6901       tangentInters[ axis ].clear();
6902
6903       // Count intersections before and after the point excluding touching ones.
6904       // If hasPositionInfo we count intersections of outer boundary only
6905
6906       int nbIntBeforePoint = 0, nbIntAfterPoint = 0;
6907       double f = numeric_limits<double>::max(), l = -numeric_limits<double>::max();
6908       map< double, TInters >::iterator u_int1 = u2inters.begin(), u_int2 = u_int1;
6909       bool ok = ! u_int1->second._coincides;
6910       while ( ok && u_int1 != u2inters.end() )
6911       {
6912         double u = u_int1->first;
6913         bool touchingInt = false;
6914         if ( ++u_int2 != u2inters.end() )
6915         {
6916           // skip intersections at the same point (if the line passes through edge or node)
6917           int nbSamePnt = 0;
6918           while ( u_int2 != u2inters.end() && fabs( u_int2->first - u ) < tolerance )
6919           {
6920             ++nbSamePnt;
6921             ++u_int2;
6922           }
6923
6924           // skip tangent intersections
6925           int nbTgt = 0;
6926           const SMDS_MeshElement* prevFace = u_int1->second._face;
6927           while ( ok && u_int2->second._coincides )
6928           {
6929             if ( SMESH_Algo::GetCommonNodes(prevFace , u_int2->second._face).empty() )
6930               ok = false;
6931             else
6932             {
6933               nbTgt++;
6934               u_int2++;
6935               ok = ( u_int2 != u2inters.end() );
6936             }
6937           }
6938           if ( !ok ) break;
6939
6940           // skip intersections at the same point after tangent intersections
6941           if ( nbTgt > 0 )
6942           {
6943             double u2 = u_int2->first;
6944             ++u_int2;
6945             while ( u_int2 != u2inters.end() && fabs( u_int2->first - u2 ) < tolerance )
6946             {
6947               ++nbSamePnt;
6948               ++u_int2;
6949             }
6950           }
6951           // decide if we skipped a touching intersection
6952           if ( nbSamePnt + nbTgt > 0 )
6953           {
6954             double minDot = numeric_limits<double>::max(), maxDot = -numeric_limits<double>::max();
6955             map< double, TInters >::iterator u_int = u_int1;
6956             for ( ; u_int != u_int2; ++u_int )
6957             {
6958               if ( u_int->second._coincides ) continue;
6959               double dot = u_int->second._faceNorm * line.Direction();
6960               if ( dot > maxDot ) maxDot = dot;
6961               if ( dot < minDot ) minDot = dot;
6962             }
6963             touchingInt = ( minDot*maxDot < 0 );
6964           }
6965         }
6966         if ( !touchingInt )
6967         {
6968           if ( !hasPositionInfo || isOuterBoundary( u_int1->second._face ))
6969           {
6970             if ( u < 0 )
6971               ++nbIntBeforePoint;
6972             else
6973               ++nbIntAfterPoint;
6974           }
6975           if ( u < f ) f = u;
6976           if ( u > l ) l = u;
6977         }
6978
6979         u_int1 = u_int2; // to next intersection
6980
6981       } // loop on intersections with one line
6982
6983       if ( ok )
6984       {
6985         if ( fabs( f ) < tolerance || fabs( l ) < tolerance )
6986           return TopAbs_ON;
6987
6988         if ( nbIntBeforePoint == 0  || nbIntAfterPoint == 0)
6989           return TopAbs_OUT; 
6990
6991         if ( nbIntBeforePoint + nbIntAfterPoint == 1 ) // not closed mesh
6992           return fabs( f ) < tolerance ? TopAbs_ON : TopAbs_UNKNOWN;
6993
6994         if ( nbIntBeforePoint == 1 || nbIntAfterPoint == 1 )
6995           return TopAbs_IN;
6996
6997         if ( (f<0) == (l<0) )
6998           return TopAbs_OUT;
6999
7000         if ( hasPositionInfo )
7001           return nbIntBeforePoint % 2 ? TopAbs_IN : TopAbs_OUT;
7002       }
7003     } // loop on intersections of the tree lines - thorough analysis
7004
7005     if ( !hasPositionInfo )
7006     {
7007       // gather info on faces position - is face in the outer boundary or not
7008       map< double, TInters > & u2inters = paramOnLine2TInters[ 0 ];
7009       findOuterBoundary( u2inters.begin()->second._face );
7010     }
7011
7012   } // two attempts - with and w/o faces position info in the mesh
7013
7014   return TopAbs_UNKNOWN;
7015 }
7016
7017 //=======================================================================
7018 /*!
7019  * \brief Return elements possibly intersecting the line
7020  */
7021 //=======================================================================
7022
7023 void SMESH_ElementSearcherImpl::GetElementsNearLine( const gp_Ax1&                      line,
7024                                                      SMDSAbs_ElementType                type,
7025                                                      vector< const SMDS_MeshElement* >& foundElems)
7026 {
7027   if ( !_ebbTree || _elementType != type )
7028   {
7029     if ( _ebbTree ) delete _ebbTree;
7030     _ebbTree = new ElementBndBoxTree( *_mesh, _elementType = type, _meshPartIt );
7031   }
7032   TIDSortedElemSet suspectFaces; // elements possibly intersecting the line
7033   _ebbTree->getElementsNearLine( line, suspectFaces );
7034   foundElems.assign( suspectFaces.begin(), suspectFaces.end());
7035 }
7036
7037 //=======================================================================
7038 /*!
7039  * \brief Return SMESH_ElementSearcher
7040  */
7041 //=======================================================================
7042
7043 SMESH_ElementSearcher* SMESH_MeshEditor::GetElementSearcher()
7044 {
7045   return new SMESH_ElementSearcherImpl( *GetMeshDS() );
7046 }
7047
7048 //=======================================================================
7049 /*!
7050  * \brief Return SMESH_ElementSearcher
7051  */
7052 //=======================================================================
7053
7054 SMESH_ElementSearcher* SMESH_MeshEditor::GetElementSearcher(SMDS_ElemIteratorPtr elemIt)
7055 {
7056   return new SMESH_ElementSearcherImpl( *GetMeshDS(), elemIt );
7057 }
7058
7059 //=======================================================================
7060 /*!
7061  * \brief Return true if the point is IN or ON of the element
7062  */
7063 //=======================================================================
7064
7065 bool SMESH_MeshEditor::isOut( const SMDS_MeshElement* element, const gp_Pnt& point, double tol )
7066 {
7067   if ( element->GetType() == SMDSAbs_Volume)
7068   {
7069     return SMDS_VolumeTool( element ).IsOut( point.X(), point.Y(), point.Z(), tol );
7070   }
7071
7072   // get ordered nodes
7073
7074   vector< gp_XYZ > xyz;
7075   vector<const SMDS_MeshNode*> nodeList;
7076
7077   SMDS_ElemIteratorPtr nodeIt = element->nodesIterator();
7078   if ( element->IsQuadratic() ) {
7079     if (const SMDS_VtkFace* f=dynamic_cast<const SMDS_VtkFace*>(element))
7080       nodeIt = f->interlacedNodesElemIterator();
7081     else if (const SMDS_VtkEdge*  e =dynamic_cast<const SMDS_VtkEdge*>(element))
7082       nodeIt = e->interlacedNodesElemIterator();
7083   }
7084   while ( nodeIt->more() )
7085     {
7086       const SMDS_MeshNode* node = cast2Node( nodeIt->next() );
7087       xyz.push_back( SMESH_TNodeXYZ(node) );
7088       nodeList.push_back(node);
7089     }
7090
7091   int i, nbNodes = element->NbNodes();
7092
7093   if ( element->GetType() == SMDSAbs_Face ) // --------------------------------------------------
7094   {
7095     // compute face normal
7096     gp_Vec faceNorm(0,0,0);
7097     xyz.push_back( xyz.front() );
7098     nodeList.push_back( nodeList.front() );
7099     for ( i = 0; i < nbNodes; ++i )
7100     {
7101       gp_Vec edge1( xyz[i+1], xyz[i]);
7102       gp_Vec edge2( xyz[i+1], xyz[(i+2)%nbNodes] );
7103       faceNorm += edge1 ^ edge2;
7104     }
7105     double normSize = faceNorm.Magnitude();
7106     if ( normSize <= tol )
7107     {
7108       // degenerated face: point is out if it is out of all face edges
7109       for ( i = 0; i < nbNodes; ++i )
7110       {
7111         SMDS_LinearEdge edge( nodeList[i], nodeList[i+1] );
7112         if ( !isOut( &edge, point, tol ))
7113           return false;
7114       }
7115       return true;
7116     }
7117     faceNorm /= normSize;
7118
7119     // check if the point lays on face plane
7120     gp_Vec n2p( xyz[0], point );
7121     if ( fabs( n2p * faceNorm ) > tol )
7122       return true; // not on face plane
7123
7124     // check if point is out of face boundary:
7125     // define it by closest transition of a ray point->infinity through face boundary
7126     // on the face plane.
7127     // First, find normal of a plane perpendicular to face plane, to be used as a cutting tool
7128     // to find intersections of the ray with the boundary.
7129     gp_Vec ray = n2p;
7130     gp_Vec plnNorm = ray ^ faceNorm;
7131     normSize = plnNorm.Magnitude();
7132     if ( normSize <= tol ) return false; // point coincides with the first node
7133     plnNorm /= normSize;
7134     // for each node of the face, compute its signed distance to the plane
7135     vector<double> dist( nbNodes + 1);
7136     for ( i = 0; i < nbNodes; ++i )
7137     {
7138       gp_Vec n2p( xyz[i], point );
7139       dist[i] = n2p * plnNorm;
7140     }
7141     dist.back() = dist.front();
7142     // find the closest intersection
7143     int    iClosest = -1;
7144     double rClosest, distClosest = 1e100;;
7145     gp_Pnt pClosest;
7146     for ( i = 0; i < nbNodes; ++i )
7147     {
7148       double r;
7149       if ( fabs( dist[i]) < tol )
7150         r = 0.;
7151       else if ( fabs( dist[i+1]) < tol )
7152         r = 1.;
7153       else if ( dist[i] * dist[i+1] < 0 )
7154         r = dist[i] / ( dist[i] - dist[i+1] );
7155       else
7156         continue; // no intersection
7157       gp_Pnt pInt = xyz[i] * (1.-r) + xyz[i+1] * r;
7158       gp_Vec p2int ( point, pInt);
7159       if ( p2int * ray > -tol ) // right half-space
7160       {
7161         double intDist = p2int.SquareMagnitude();
7162         if ( intDist < distClosest )
7163         {
7164           iClosest = i;
7165           rClosest = r;
7166           pClosest = pInt;
7167           distClosest = intDist;
7168         }
7169       }
7170     }
7171     if ( iClosest < 0 )
7172       return true; // no intesections - out
7173
7174     // analyse transition
7175     gp_Vec edge( xyz[iClosest], xyz[iClosest+1] );
7176     gp_Vec edgeNorm = -( edge ^ faceNorm ); // normal to intersected edge pointing out of face
7177     gp_Vec p2int ( point, pClosest );
7178     bool out = (edgeNorm * p2int) < -tol;
7179     if ( rClosest > 0. && rClosest < 1. ) // not node intersection
7180       return out;
7181
7182     // ray pass through a face node; analyze transition through an adjacent edge
7183     gp_Pnt p1 = xyz[ (rClosest == 0.) ? ((iClosest+nbNodes-1) % nbNodes) : (iClosest+1) ];
7184     gp_Pnt p2 = xyz[ (rClosest == 0.) ? iClosest : ((iClosest+2) % nbNodes) ];
7185     gp_Vec edgeAdjacent( p1, p2 );
7186     gp_Vec edgeNorm2 = -( edgeAdjacent ^ faceNorm );
7187     bool out2 = (edgeNorm2 * p2int) < -tol;
7188
7189     bool covexCorner = ( edgeNorm * edgeAdjacent * (rClosest==1. ? 1. : -1.)) < 0;
7190     return covexCorner ? (out || out2) : (out && out2);
7191   }
7192   if ( element->GetType() == SMDSAbs_Edge ) // --------------------------------------------------
7193   {
7194     // point is out of edge if it is NOT ON any straight part of edge
7195     // (we consider quadratic edge as being composed of two straight parts)
7196     for ( i = 1; i < nbNodes; ++i )
7197     {
7198       gp_Vec edge( xyz[i-1], xyz[i]);
7199       gp_Vec n1p ( xyz[i-1], point);
7200       double dist = ( edge ^ n1p ).Magnitude() / edge.Magnitude();
7201       if ( dist > tol )
7202         continue;
7203       gp_Vec n2p( xyz[i], point );
7204       if ( fabs( edge.Magnitude() - n1p.Magnitude() - n2p.Magnitude()) > tol )
7205         continue;
7206       return false; // point is ON this part
7207     }
7208     return true;
7209   }
7210   // Node or 0D element -------------------------------------------------------------------------
7211   {
7212     gp_Vec n2p ( xyz[0], point );
7213     return n2p.Magnitude() <= tol;
7214   }
7215   return true;
7216 }
7217
7218 //=======================================================================
7219 //function : SimplifyFace
7220 //purpose  :
7221 //=======================================================================
7222 int SMESH_MeshEditor::SimplifyFace (const vector<const SMDS_MeshNode *> faceNodes,
7223                                     vector<const SMDS_MeshNode *>&      poly_nodes,
7224                                     vector<int>&                        quantities) const
7225 {
7226   int nbNodes = faceNodes.size();
7227
7228   if (nbNodes < 3)
7229     return 0;
7230
7231   set<const SMDS_MeshNode*> nodeSet;
7232
7233   // get simple seq of nodes
7234   //const SMDS_MeshNode* simpleNodes[ nbNodes ];
7235   vector<const SMDS_MeshNode*> simpleNodes( nbNodes );
7236   int iSimple = 0, nbUnique = 0;
7237
7238   simpleNodes[iSimple++] = faceNodes[0];
7239   nbUnique++;
7240   for (int iCur = 1; iCur < nbNodes; iCur++) {
7241     if (faceNodes[iCur] != simpleNodes[iSimple - 1]) {
7242       simpleNodes[iSimple++] = faceNodes[iCur];
7243       if (nodeSet.insert( faceNodes[iCur] ).second)
7244         nbUnique++;
7245     }
7246   }
7247   int nbSimple = iSimple;
7248   if (simpleNodes[nbSimple - 1] == simpleNodes[0]) {
7249     nbSimple--;
7250     iSimple--;
7251   }
7252
7253   if (nbUnique < 3)
7254     return 0;
7255
7256   // separate loops
7257   int nbNew = 0;
7258   bool foundLoop = (nbSimple > nbUnique);
7259   while (foundLoop) {
7260     foundLoop = false;
7261     set<const SMDS_MeshNode*> loopSet;
7262     for (iSimple = 0; iSimple < nbSimple && !foundLoop; iSimple++) {
7263       const SMDS_MeshNode* n = simpleNodes[iSimple];
7264       if (!loopSet.insert( n ).second) {
7265         foundLoop = true;
7266
7267         // separate loop
7268         int iC = 0, curLast = iSimple;
7269         for (; iC < curLast; iC++) {
7270           if (simpleNodes[iC] == n) break;
7271         }
7272         int loopLen = curLast - iC;
7273         if (loopLen > 2) {
7274           // create sub-element
7275           nbNew++;
7276           quantities.push_back(loopLen);
7277           for (; iC < curLast; iC++) {
7278             poly_nodes.push_back(simpleNodes[iC]);
7279           }
7280         }
7281         // shift the rest nodes (place from the first loop position)
7282         for (iC = curLast + 1; iC < nbSimple; iC++) {
7283           simpleNodes[iC - loopLen] = simpleNodes[iC];
7284         }
7285         nbSimple -= loopLen;
7286         iSimple -= loopLen;
7287       }
7288     } // for (iSimple = 0; iSimple < nbSimple; iSimple++)
7289   } // while (foundLoop)
7290
7291   if (iSimple > 2) {
7292     nbNew++;
7293     quantities.push_back(iSimple);
7294     for (int i = 0; i < iSimple; i++)
7295       poly_nodes.push_back(simpleNodes[i]);
7296   }
7297
7298   return nbNew;
7299 }
7300
7301 //=======================================================================
7302 //function : MergeNodes
7303 //purpose  : In each group, the cdr of nodes are substituted by the first one
7304 //           in all elements.
7305 //=======================================================================
7306
7307 void SMESH_MeshEditor::MergeNodes (TListOfListOfNodes & theGroupsOfNodes)
7308 {
7309   MESSAGE("MergeNodes");
7310   myLastCreatedElems.Clear();
7311   myLastCreatedNodes.Clear();
7312
7313   SMESHDS_Mesh* aMesh = GetMeshDS();
7314
7315   TNodeNodeMap nodeNodeMap; // node to replace - new node
7316   set<const SMDS_MeshElement*> elems; // all elements with changed nodes
7317   list< int > rmElemIds, rmNodeIds;
7318
7319   // Fill nodeNodeMap and elems
7320
7321   TListOfListOfNodes::iterator grIt = theGroupsOfNodes.begin();
7322   for ( ; grIt != theGroupsOfNodes.end(); grIt++ ) {
7323     list<const SMDS_MeshNode*>& nodes = *grIt;
7324     list<const SMDS_MeshNode*>::iterator nIt = nodes.begin();
7325     const SMDS_MeshNode* nToKeep = *nIt;
7326     //MESSAGE("node to keep " << nToKeep->GetID());
7327     for ( ++nIt; nIt != nodes.end(); nIt++ ) {
7328       const SMDS_MeshNode* nToRemove = *nIt;
7329       nodeNodeMap.insert( TNodeNodeMap::value_type( nToRemove, nToKeep ));
7330       if ( nToRemove != nToKeep ) {
7331         //MESSAGE("  node to remove " << nToRemove->GetID());
7332         rmNodeIds.push_back( nToRemove->GetID() );
7333         AddToSameGroups( nToKeep, nToRemove, aMesh );
7334       }
7335
7336       SMDS_ElemIteratorPtr invElemIt = nToRemove->GetInverseElementIterator();
7337       while ( invElemIt->more() ) {
7338         const SMDS_MeshElement* elem = invElemIt->next();
7339         elems.insert(elem);
7340       }
7341     }
7342   }
7343   // Change element nodes or remove an element
7344
7345   set<const SMDS_MeshElement*>::iterator eIt = elems.begin();
7346   for ( ; eIt != elems.end(); eIt++ ) {
7347     const SMDS_MeshElement* elem = *eIt;
7348     //MESSAGE(" ---- inverse elem on node to remove " << elem->GetID());
7349     int nbNodes = elem->NbNodes();
7350     int aShapeId = FindShape( elem );
7351
7352     set<const SMDS_MeshNode*> nodeSet;
7353     vector< const SMDS_MeshNode*> curNodes( nbNodes ), uniqueNodes( nbNodes );
7354     int iUnique = 0, iCur = 0, nbRepl = 0;
7355     vector<int> iRepl( nbNodes );
7356
7357     // get new seq of nodes
7358     SMDS_ElemIteratorPtr itN = elem->nodesIterator();
7359     while ( itN->more() ) {
7360       const SMDS_MeshNode* n =
7361         static_cast<const SMDS_MeshNode*>( itN->next() );
7362
7363       TNodeNodeMap::iterator nnIt = nodeNodeMap.find( n );
7364       if ( nnIt != nodeNodeMap.end() ) { // n sticks
7365         n = (*nnIt).second;
7366         // BUG 0020185: begin
7367         {
7368           bool stopRecur = false;
7369           set<const SMDS_MeshNode*> nodesRecur;
7370           nodesRecur.insert(n);
7371           while (!stopRecur) {
7372             TNodeNodeMap::iterator nnIt_i = nodeNodeMap.find( n );
7373             if ( nnIt_i != nodeNodeMap.end() ) { // n sticks
7374               n = (*nnIt_i).second;
7375               if (!nodesRecur.insert(n).second) {
7376                 // error: recursive dependancy
7377                 stopRecur = true;
7378               }
7379             }
7380             else
7381               stopRecur = true;
7382           }
7383         }
7384         // BUG 0020185: end
7385         iRepl[ nbRepl++ ] = iCur;
7386       }
7387       curNodes[ iCur ] = n;
7388       bool isUnique = nodeSet.insert( n ).second;
7389       if ( isUnique )
7390         uniqueNodes[ iUnique++ ] = n;
7391       iCur++;
7392     }
7393
7394     // Analyse element topology after replacement
7395
7396     bool isOk = true;
7397     int nbUniqueNodes = nodeSet.size();
7398     //MESSAGE("nbNodes nbUniqueNodes " << nbNodes << " " << nbUniqueNodes);
7399     if ( nbNodes != nbUniqueNodes ) { // some nodes stick
7400       // Polygons and Polyhedral volumes
7401       if (elem->IsPoly()) {
7402
7403         if (elem->GetType() == SMDSAbs_Face) {
7404           // Polygon
7405           vector<const SMDS_MeshNode *> face_nodes (nbNodes);
7406           int inode = 0;
7407           for (; inode < nbNodes; inode++) {
7408             face_nodes[inode] = curNodes[inode];
7409           }
7410
7411           vector<const SMDS_MeshNode *> polygons_nodes;
7412           vector<int> quantities;
7413           int nbNew = SimplifyFace(face_nodes, polygons_nodes, quantities);
7414           if (nbNew > 0) {
7415             inode = 0;
7416             for (int iface = 0; iface < nbNew; iface++) {
7417               int nbNodes = quantities[iface];
7418               vector<const SMDS_MeshNode *> poly_nodes (nbNodes);
7419               for (int ii = 0; ii < nbNodes; ii++, inode++) {
7420                 poly_nodes[ii] = polygons_nodes[inode];
7421               }
7422               SMDS_MeshElement* newElem = aMesh->AddPolygonalFace(poly_nodes);
7423               myLastCreatedElems.Append(newElem);
7424               if (aShapeId)
7425                 aMesh->SetMeshElementOnShape(newElem, aShapeId);
7426             }
7427
7428             MESSAGE("ChangeElementNodes MergeNodes Polygon");
7429             //aMesh->ChangeElementNodes(elem, &polygons_nodes[inode], quantities[nbNew - 1]);
7430             vector<const SMDS_MeshNode *> polynodes(polygons_nodes.begin()+inode,polygons_nodes.end());
7431             int quid =0;
7432             if (nbNew > 0) quid = nbNew - 1;
7433             vector<int> newquant(quantities.begin()+quid, quantities.end());
7434             const SMDS_MeshElement* newElem = 0;
7435             newElem = aMesh->AddPolyhedralVolume(polynodes, newquant);
7436             myLastCreatedElems.Append(newElem);
7437             if ( aShapeId && newElem )
7438               aMesh->SetMeshElementOnShape( newElem, aShapeId );
7439             rmElemIds.push_back(elem->GetID());
7440           }
7441           else {
7442             rmElemIds.push_back(elem->GetID());
7443           }
7444
7445         }
7446         else if (elem->GetType() == SMDSAbs_Volume) {
7447           // Polyhedral volume
7448           if (nbUniqueNodes < 4) {
7449             rmElemIds.push_back(elem->GetID());
7450           }
7451           else {
7452             // each face has to be analyzed in order to check volume validity
7453             const SMDS_VtkVolume* aPolyedre =
7454               dynamic_cast<const SMDS_VtkVolume*>( elem );
7455             if (aPolyedre) {
7456               int nbFaces = aPolyedre->NbFaces();
7457
7458               vector<const SMDS_MeshNode *> poly_nodes;
7459               vector<int> quantities;
7460
7461               for (int iface = 1; iface <= nbFaces; iface++) {
7462                 int nbFaceNodes = aPolyedre->NbFaceNodes(iface);
7463                 vector<const SMDS_MeshNode *> faceNodes (nbFaceNodes);
7464
7465                 for (int inode = 1; inode <= nbFaceNodes; inode++) {
7466                   const SMDS_MeshNode * faceNode = aPolyedre->GetFaceNode(iface, inode);
7467                   TNodeNodeMap::iterator nnIt = nodeNodeMap.find(faceNode);
7468                   if (nnIt != nodeNodeMap.end()) { // faceNode sticks
7469                     faceNode = (*nnIt).second;
7470                   }
7471                   faceNodes[inode - 1] = faceNode;
7472                 }
7473
7474                 SimplifyFace(faceNodes, poly_nodes, quantities);
7475               }
7476
7477               if (quantities.size() > 3) {
7478                 // to be done: remove coincident faces
7479               }
7480
7481               if (quantities.size() > 3)
7482                 {
7483                   MESSAGE("ChangeElementNodes MergeNodes Polyhedron");
7484                   //aMesh->ChangePolyhedronNodes(elem, poly_nodes, quantities);
7485                   const SMDS_MeshElement* newElem = 0;
7486                   newElem = aMesh->AddPolyhedralVolume(poly_nodes, quantities);
7487                   myLastCreatedElems.Append(newElem);
7488                   if ( aShapeId && newElem )
7489                     aMesh->SetMeshElementOnShape( newElem, aShapeId );
7490                   rmElemIds.push_back(elem->GetID());
7491                 }
7492             }
7493             else {
7494               rmElemIds.push_back(elem->GetID());
7495             }
7496           }
7497         }
7498         else {
7499         }
7500
7501         continue;
7502       }
7503
7504       // Regular elements
7505       // TODO not all the possible cases are solved. Find something more generic?
7506       switch ( nbNodes ) {
7507       case 2: ///////////////////////////////////// EDGE
7508         isOk = false; break;
7509       case 3: ///////////////////////////////////// TRIANGLE
7510         isOk = false; break;
7511       case 4:
7512         if ( elem->GetType() == SMDSAbs_Volume ) // TETRAHEDRON
7513           isOk = false;
7514         else { //////////////////////////////////// QUADRANGLE
7515           if ( nbUniqueNodes < 3 )
7516             isOk = false;
7517           else if ( nbRepl == 2 && iRepl[ 1 ] - iRepl[ 0 ] == 2 )
7518             isOk = false; // opposite nodes stick
7519           //MESSAGE("isOk " << isOk);
7520         }
7521         break;
7522       case 6: ///////////////////////////////////// PENTAHEDRON
7523         if ( nbUniqueNodes == 4 ) {
7524           // ---------------------------------> tetrahedron
7525           if (nbRepl == 3 &&
7526               iRepl[ 0 ] > 2 && iRepl[ 1 ] > 2 && iRepl[ 2 ] > 2 ) {
7527             // all top nodes stick: reverse a bottom
7528             uniqueNodes[ 0 ] = curNodes [ 1 ];
7529             uniqueNodes[ 1 ] = curNodes [ 0 ];
7530           }
7531           else if (nbRepl == 3 &&
7532                    iRepl[ 0 ] < 3 && iRepl[ 1 ] < 3 && iRepl[ 2 ] < 3 ) {
7533             // all bottom nodes stick: set a top before
7534             uniqueNodes[ 3 ] = uniqueNodes [ 0 ];
7535             uniqueNodes[ 0 ] = curNodes [ 3 ];
7536             uniqueNodes[ 1 ] = curNodes [ 4 ];
7537             uniqueNodes[ 2 ] = curNodes [ 5 ];
7538           }
7539           else if (nbRepl == 4 &&
7540                    iRepl[ 2 ] - iRepl [ 0 ] == 3 && iRepl[ 3 ] - iRepl [ 1 ] == 3 ) {
7541             // a lateral face turns into a line: reverse a bottom
7542             uniqueNodes[ 0 ] = curNodes [ 1 ];
7543             uniqueNodes[ 1 ] = curNodes [ 0 ];
7544           }
7545           else
7546             isOk = false;
7547         }
7548         else if ( nbUniqueNodes == 5 ) {
7549           // PENTAHEDRON --------------------> 2 tetrahedrons
7550           if ( nbRepl == 2 && iRepl[ 1 ] - iRepl [ 0 ] == 3 ) {
7551             // a bottom node sticks with a linked top one
7552             // 1.
7553             SMDS_MeshElement* newElem =
7554               aMesh->AddVolume(curNodes[ 3 ],
7555                                curNodes[ 4 ],
7556                                curNodes[ 5 ],
7557                                curNodes[ iRepl[ 0 ] == 2 ? 1 : 2 ]);
7558             myLastCreatedElems.Append(newElem);
7559             if ( aShapeId )
7560               aMesh->SetMeshElementOnShape( newElem, aShapeId );
7561             // 2. : reverse a bottom
7562             uniqueNodes[ 0 ] = curNodes [ 1 ];
7563             uniqueNodes[ 1 ] = curNodes [ 0 ];
7564             nbUniqueNodes = 4;
7565           }
7566           else
7567             isOk = false;
7568         }
7569         else
7570           isOk = false;
7571         break;
7572       case 8: {
7573         if(elem->IsQuadratic()) { // Quadratic quadrangle
7574           //   1    5    2
7575           //    +---+---+
7576           //    |       |
7577           //    |       |
7578           //   4+       +6
7579           //    |       |
7580           //    |       |
7581           //    +---+---+
7582           //   0    7    3
7583           isOk = false;
7584           if(nbRepl==2) {
7585             MESSAGE("nbRepl=2: " << iRepl[0] << " " << iRepl[1]);
7586           }
7587           if(nbRepl==3) {
7588             MESSAGE("nbRepl=3: " << iRepl[0] << " " << iRepl[1]  << " " << iRepl[2]);
7589             nbUniqueNodes = 6;
7590             if( iRepl[0]==0 && iRepl[1]==1 && iRepl[2]==4 ) {
7591               uniqueNodes[0] = curNodes[0];
7592               uniqueNodes[1] = curNodes[2];
7593               uniqueNodes[2] = curNodes[3];
7594               uniqueNodes[3] = curNodes[5];
7595               uniqueNodes[4] = curNodes[6];
7596               uniqueNodes[5] = curNodes[7];
7597               isOk = true;
7598             }
7599             if( iRepl[0]==0 && iRepl[1]==3 && iRepl[2]==7 ) {
7600               uniqueNodes[0] = curNodes[0];
7601               uniqueNodes[1] = curNodes[1];
7602               uniqueNodes[2] = curNodes[2];
7603               uniqueNodes[3] = curNodes[4];
7604               uniqueNodes[4] = curNodes[5];
7605               uniqueNodes[5] = curNodes[6];
7606               isOk = true;
7607             }
7608             if( iRepl[0]==0 && iRepl[1]==4 && iRepl[2]==7 ) {
7609               uniqueNodes[0] = curNodes[1];
7610               uniqueNodes[1] = curNodes[2];
7611               uniqueNodes[2] = curNodes[3];
7612               uniqueNodes[3] = curNodes[5];
7613               uniqueNodes[4] = curNodes[6];
7614               uniqueNodes[5] = curNodes[0];
7615               isOk = true;
7616             }
7617             if( iRepl[0]==1 && iRepl[1]==2 && iRepl[2]==5 ) {
7618               uniqueNodes[0] = curNodes[0];
7619               uniqueNodes[1] = curNodes[1];
7620               uniqueNodes[2] = curNodes[3];
7621               uniqueNodes[3] = curNodes[4];
7622               uniqueNodes[4] = curNodes[6];
7623               uniqueNodes[5] = curNodes[7];
7624               isOk = true;
7625             }
7626             if( iRepl[0]==1 && iRepl[1]==4 && iRepl[2]==5 ) {
7627               uniqueNodes[0] = curNodes[0];
7628               uniqueNodes[1] = curNodes[2];
7629               uniqueNodes[2] = curNodes[3];
7630               uniqueNodes[3] = curNodes[1];
7631               uniqueNodes[4] = curNodes[6];
7632               uniqueNodes[5] = curNodes[7];
7633               isOk = true;
7634             }
7635             if( iRepl[0]==2 && iRepl[1]==3 && iRepl[2]==6 ) {
7636               uniqueNodes[0] = curNodes[0];
7637               uniqueNodes[1] = curNodes[1];
7638               uniqueNodes[2] = curNodes[2];
7639               uniqueNodes[3] = curNodes[4];
7640               uniqueNodes[4] = curNodes[5];
7641               uniqueNodes[5] = curNodes[7];
7642               isOk = true;
7643             }
7644             if( iRepl[0]==2 && iRepl[1]==5 && iRepl[2]==6 ) {
7645               uniqueNodes[0] = curNodes[0];
7646               uniqueNodes[1] = curNodes[1];
7647               uniqueNodes[2] = curNodes[3];
7648               uniqueNodes[3] = curNodes[4];
7649               uniqueNodes[4] = curNodes[2];
7650               uniqueNodes[5] = curNodes[7];
7651               isOk = true;
7652             }
7653             if( iRepl[0]==3 && iRepl[1]==6 && iRepl[2]==7 ) {
7654               uniqueNodes[0] = curNodes[0];
7655               uniqueNodes[1] = curNodes[1];
7656               uniqueNodes[2] = curNodes[2];
7657               uniqueNodes[3] = curNodes[4];
7658               uniqueNodes[4] = curNodes[5];
7659               uniqueNodes[5] = curNodes[3];
7660               isOk = true;
7661             }
7662           }
7663           if(nbRepl==4) {
7664             MESSAGE("nbRepl=4: " << iRepl[0] << " " << iRepl[1]  << " " << iRepl[2] << " " << iRepl[3]);
7665           }
7666           if(nbRepl==5) {
7667             MESSAGE("nbRepl=5: " << iRepl[0] << " " << iRepl[1]  << " " << iRepl[2] << " " << iRepl[3] << " " << iRepl[4]);
7668           }
7669           break;
7670         }
7671         //////////////////////////////////// HEXAHEDRON
7672         isOk = false;
7673         SMDS_VolumeTool hexa (elem);
7674         hexa.SetExternalNormal();
7675         if ( nbUniqueNodes == 4 && nbRepl == 6 ) {
7676           //////////////////////// ---> tetrahedron
7677           for ( int iFace = 0; iFace < 6; iFace++ ) {
7678             const int *ind = hexa.GetFaceNodesIndices( iFace ); // indices of face nodes
7679             if (curNodes[ind[ 0 ]] == curNodes[ind[ 1 ]] &&
7680                 curNodes[ind[ 0 ]] == curNodes[ind[ 2 ]] &&
7681                 curNodes[ind[ 0 ]] == curNodes[ind[ 3 ]] ) {
7682               // one face turns into a point ...
7683               int iOppFace = hexa.GetOppFaceIndex( iFace );
7684               ind = hexa.GetFaceNodesIndices( iOppFace );
7685               int nbStick = 0;
7686               iUnique = 2; // reverse a tetrahedron bottom
7687               for ( iCur = 0; iCur < 4 && nbStick < 2; iCur++ ) {
7688                 if ( curNodes[ind[ iCur ]] == curNodes[ind[ iCur + 1 ]] )
7689                   nbStick++;
7690                 else if ( iUnique >= 0 )
7691                   uniqueNodes[ iUnique-- ] = curNodes[ind[ iCur ]];
7692               }
7693               if ( nbStick == 1 ) {
7694                 // ... and the opposite one - into a triangle.
7695                 // set a top node
7696                 ind = hexa.GetFaceNodesIndices( iFace );
7697                 uniqueNodes[ 3 ] = curNodes[ind[ 0 ]];
7698                 isOk = true;
7699               }
7700               break;
7701             }
7702           }
7703         }
7704         else if (nbUniqueNodes == 5 && nbRepl == 4 ) {
7705           //////////////////// HEXAHEDRON ---> 2 tetrahedrons
7706           for ( int iFace = 0; iFace < 6; iFace++ ) {
7707             const int *ind = hexa.GetFaceNodesIndices( iFace ); // indices of face nodes
7708             if (curNodes[ind[ 0 ]] == curNodes[ind[ 1 ]] &&
7709                 curNodes[ind[ 0 ]] == curNodes[ind[ 2 ]] &&
7710                 curNodes[ind[ 0 ]] == curNodes[ind[ 3 ]] ) {
7711               // one face turns into a point ...
7712               int iOppFace = hexa.GetOppFaceIndex( iFace );
7713               ind = hexa.GetFaceNodesIndices( iOppFace );
7714               int nbStick = 0;
7715               iUnique = 2;  // reverse a tetrahedron 1 bottom
7716               for ( iCur = 0; iCur < 4 && nbStick == 0; iCur++ ) {
7717                 if ( curNodes[ind[ iCur ]] == curNodes[ind[ iCur + 1 ]] )
7718                   nbStick++;
7719                 else if ( iUnique >= 0 )
7720                   uniqueNodes[ iUnique-- ] = curNodes[ind[ iCur ]];
7721               }
7722               if ( nbStick == 0 ) {
7723                 // ... and the opposite one is a quadrangle
7724                 // set a top node
7725                 const int* indTop = hexa.GetFaceNodesIndices( iFace );
7726                 uniqueNodes[ 3 ] = curNodes[indTop[ 0 ]];
7727                 nbUniqueNodes = 4;
7728                 // tetrahedron 2
7729                 SMDS_MeshElement* newElem =
7730                   aMesh->AddVolume(curNodes[ind[ 0 ]],
7731                                    curNodes[ind[ 3 ]],
7732                                    curNodes[ind[ 2 ]],
7733                                    curNodes[indTop[ 0 ]]);
7734                 myLastCreatedElems.Append(newElem);
7735                 if ( aShapeId )
7736                   aMesh->SetMeshElementOnShape( newElem, aShapeId );
7737                 isOk = true;
7738               }
7739               break;
7740             }
7741           }
7742         }
7743         else if ( nbUniqueNodes == 6 && nbRepl == 4 ) {
7744           ////////////////// HEXAHEDRON ---> 2 tetrahedrons or 1 prism
7745           // find indices of quad and tri faces
7746           int iQuadFace[ 6 ], iTriFace[ 6 ], nbQuad = 0, nbTri = 0, iFace;
7747           for ( iFace = 0; iFace < 6; iFace++ ) {
7748             const int *ind = hexa.GetFaceNodesIndices( iFace ); // indices of face nodes
7749             nodeSet.clear();
7750             for ( iCur = 0; iCur < 4; iCur++ )
7751               nodeSet.insert( curNodes[ind[ iCur ]] );
7752             nbUniqueNodes = nodeSet.size();
7753             if ( nbUniqueNodes == 3 )
7754               iTriFace[ nbTri++ ] = iFace;
7755             else if ( nbUniqueNodes == 4 )
7756               iQuadFace[ nbQuad++ ] = iFace;
7757           }
7758           if (nbQuad == 2 && nbTri == 4 &&
7759               hexa.GetOppFaceIndex( iQuadFace[ 0 ] ) == iQuadFace[ 1 ]) {
7760             // 2 opposite quadrangles stuck with a diagonal;
7761             // sample groups of merged indices: (0-4)(2-6)
7762             // --------------------------------------------> 2 tetrahedrons
7763             const int *ind1 = hexa.GetFaceNodesIndices( iQuadFace[ 0 ]); // indices of quad1 nodes
7764             const int *ind2 = hexa.GetFaceNodesIndices( iQuadFace[ 1 ]);
7765             int i0, i1d, i2, i3d, i0t, i2t; // d-daigonal, t-top
7766             if (curNodes[ind1[ 0 ]] == curNodes[ind2[ 0 ]] &&
7767                 curNodes[ind1[ 2 ]] == curNodes[ind2[ 2 ]]) {
7768               // stuck with 0-2 diagonal
7769               i0  = ind1[ 3 ];
7770               i1d = ind1[ 0 ];
7771               i2  = ind1[ 1 ];
7772               i3d = ind1[ 2 ];
7773               i0t = ind2[ 1 ];
7774               i2t = ind2[ 3 ];
7775             }
7776             else if (curNodes[ind1[ 1 ]] == curNodes[ind2[ 3 ]] &&
7777                      curNodes[ind1[ 3 ]] == curNodes[ind2[ 1 ]]) {
7778               // stuck with 1-3 diagonal
7779               i0  = ind1[ 0 ];
7780               i1d = ind1[ 1 ];
7781               i2  = ind1[ 2 ];
7782               i3d = ind1[ 3 ];
7783               i0t = ind2[ 0 ];
7784               i2t = ind2[ 1 ];
7785             }
7786             else {
7787               ASSERT(0);
7788             }
7789             // tetrahedron 1
7790             uniqueNodes[ 0 ] = curNodes [ i0 ];
7791             uniqueNodes[ 1 ] = curNodes [ i1d ];
7792             uniqueNodes[ 2 ] = curNodes [ i3d ];
7793             uniqueNodes[ 3 ] = curNodes [ i0t ];
7794             nbUniqueNodes = 4;
7795             // tetrahedron 2
7796             SMDS_MeshElement* newElem = aMesh->AddVolume(curNodes[ i1d ],
7797                                                          curNodes[ i2 ],
7798                                                          curNodes[ i3d ],
7799                                                          curNodes[ i2t ]);
7800             myLastCreatedElems.Append(newElem);
7801             if ( aShapeId )
7802               aMesh->SetMeshElementOnShape( newElem, aShapeId );
7803             isOk = true;
7804           }
7805           else if (( nbTri == 2 && nbQuad == 3 ) || // merged (0-4)(1-5)
7806                    ( nbTri == 4 && nbQuad == 2 )) { // merged (7-4)(1-5)
7807             // --------------------------------------------> prism
7808             // find 2 opposite triangles
7809             nbUniqueNodes = 6;
7810             for ( iFace = 0; iFace + 1 < nbTri; iFace++ ) {
7811               if ( hexa.GetOppFaceIndex( iTriFace[ iFace ] ) == iTriFace[ iFace + 1 ]) {
7812                 // find indices of kept and replaced nodes
7813                 // and fill unique nodes of 2 opposite triangles
7814                 const int *ind1 = hexa.GetFaceNodesIndices( iTriFace[ iFace ]);
7815                 const int *ind2 = hexa.GetFaceNodesIndices( iTriFace[ iFace + 1 ]);
7816                 const SMDS_MeshNode** hexanodes = hexa.GetNodes();
7817                 // fill unique nodes
7818                 iUnique = 0;
7819                 isOk = true;
7820                 for ( iCur = 0; iCur < 4 && isOk; iCur++ ) {
7821                   const SMDS_MeshNode* n     = curNodes[ind1[ iCur ]];
7822                   const SMDS_MeshNode* nInit = hexanodes[ind1[ iCur ]];
7823                   if ( n == nInit ) {
7824                     // iCur of a linked node of the opposite face (make normals co-directed):
7825                     int iCurOpp = ( iCur == 1 || iCur == 3 ) ? 4 - iCur : iCur;
7826                     // check that correspondent corners of triangles are linked
7827                     if ( !hexa.IsLinked( ind1[ iCur ], ind2[ iCurOpp ] ))
7828                       isOk = false;
7829                     else {
7830                       uniqueNodes[ iUnique ] = n;
7831                       uniqueNodes[ iUnique + 3 ] = curNodes[ind2[ iCurOpp ]];
7832                       iUnique++;
7833                     }
7834                   }
7835                 }
7836                 break;
7837               }
7838             }
7839           }
7840         } // if ( nbUniqueNodes == 6 && nbRepl == 4 )
7841         break;
7842       } // HEXAHEDRON
7843
7844       default:
7845         isOk = false;
7846       } // switch ( nbNodes )
7847
7848     } // if ( nbNodes != nbUniqueNodes ) // some nodes stick
7849
7850     if ( isOk ) {
7851       if (elem->IsPoly() && elem->GetType() == SMDSAbs_Volume) {
7852         // Change nodes of polyedre
7853         const SMDS_VtkVolume* aPolyedre =
7854           dynamic_cast<const SMDS_VtkVolume*>( elem );
7855         if (aPolyedre) {
7856           int nbFaces = aPolyedre->NbFaces();
7857
7858           vector<const SMDS_MeshNode *> poly_nodes;
7859           vector<int> quantities (nbFaces);
7860
7861           for (int iface = 1; iface <= nbFaces; iface++) {
7862             int inode, nbFaceNodes = aPolyedre->NbFaceNodes(iface);
7863             quantities[iface - 1] = nbFaceNodes;
7864
7865             for (inode = 1; inode <= nbFaceNodes; inode++) {
7866               const SMDS_MeshNode* curNode = aPolyedre->GetFaceNode(iface, inode);
7867
7868               TNodeNodeMap::iterator nnIt = nodeNodeMap.find( curNode );
7869               if (nnIt != nodeNodeMap.end()) { // curNode sticks
7870                 curNode = (*nnIt).second;
7871               }
7872               poly_nodes.push_back(curNode);
7873             }
7874           }
7875           aMesh->ChangePolyhedronNodes( elem, poly_nodes, quantities );
7876         }
7877       }
7878       else {
7879         //int elemId = elem->GetID();
7880         //MESSAGE("Change regular element or polygon " << elemId);
7881         SMDSAbs_ElementType etyp = elem->GetType();
7882         uniqueNodes.resize(nbUniqueNodes);
7883         SMDS_MeshElement* newElem = 0;
7884         if (elem->GetEntityType() == SMDSEntity_Polygon)
7885           newElem = this->AddElement(uniqueNodes, etyp, true);
7886         else
7887           newElem = this->AddElement(uniqueNodes, etyp, false);
7888         if (newElem)
7889           {
7890             myLastCreatedElems.Append(newElem);
7891             if ( aShapeId )
7892               aMesh->SetMeshElementOnShape( newElem, aShapeId );
7893           }
7894         aMesh->RemoveElement(elem);
7895       }
7896     }
7897     else {
7898       // Remove invalid regular element or invalid polygon
7899       //MESSAGE("Remove invalid " << elem->GetID());
7900       rmElemIds.push_back( elem->GetID() );
7901     }
7902
7903   } // loop on elements
7904
7905   // Remove bad elements, then equal nodes (order important)
7906
7907   Remove( rmElemIds, false );
7908   Remove( rmNodeIds, true );
7909
7910 }
7911
7912
7913 // ========================================================
7914 // class   : SortableElement
7915 // purpose : allow sorting elements basing on their nodes
7916 // ========================================================
7917 class SortableElement : public set <const SMDS_MeshElement*>
7918 {
7919 public:
7920
7921   SortableElement( const SMDS_MeshElement* theElem )
7922   {
7923     myElem = theElem;
7924     SMDS_ElemIteratorPtr nodeIt = theElem->nodesIterator();
7925     while ( nodeIt->more() )
7926       this->insert( nodeIt->next() );
7927   }
7928
7929   const SMDS_MeshElement* Get() const
7930   { return myElem; }
7931
7932   void Set(const SMDS_MeshElement* e) const
7933   { myElem = e; }
7934
7935
7936 private:
7937   mutable const SMDS_MeshElement* myElem;
7938 };
7939
7940 //=======================================================================
7941 //function : FindEqualElements
7942 //purpose  : Return list of group of elements built on the same nodes.
7943 //           Search among theElements or in the whole mesh if theElements is empty
7944 //=======================================================================
7945 void SMESH_MeshEditor::FindEqualElements(set<const SMDS_MeshElement*> & theElements,
7946                                          TListOfListOfElementsID &      theGroupsOfElementsID)
7947 {
7948   myLastCreatedElems.Clear();
7949   myLastCreatedNodes.Clear();
7950
7951   typedef set<const SMDS_MeshElement*> TElemsSet;
7952   typedef map< SortableElement, int > TMapOfNodeSet;
7953   typedef list<int> TGroupOfElems;
7954
7955   TElemsSet elems;
7956   if ( theElements.empty() )
7957   { // get all elements in the mesh
7958     SMDS_ElemIteratorPtr eIt = GetMeshDS()->elementsIterator();
7959     while ( eIt->more() )
7960       elems.insert( elems.end(), eIt->next());
7961   }
7962   else
7963     elems = theElements;
7964
7965   vector< TGroupOfElems > arrayOfGroups;
7966   TGroupOfElems groupOfElems;
7967   TMapOfNodeSet mapOfNodeSet;
7968
7969   TElemsSet::iterator elemIt = elems.begin();
7970   for ( int i = 0, j=0; elemIt != elems.end(); ++elemIt, ++j ) {
7971     const SMDS_MeshElement* curElem = *elemIt;
7972     SortableElement SE(curElem);
7973     int ind = -1;
7974     // check uniqueness
7975     pair< TMapOfNodeSet::iterator, bool> pp = mapOfNodeSet.insert(make_pair(SE, i));
7976     if( !(pp.second) ) {
7977       TMapOfNodeSet::iterator& itSE = pp.first;
7978       ind = (*itSE).second;
7979       arrayOfGroups[ind].push_back(curElem->GetID());
7980     }
7981     else {
7982       groupOfElems.clear();
7983       groupOfElems.push_back(curElem->GetID());
7984       arrayOfGroups.push_back(groupOfElems);
7985       i++;
7986     }
7987   }
7988
7989   vector< TGroupOfElems >::iterator groupIt = arrayOfGroups.begin();
7990   for ( ; groupIt != arrayOfGroups.end(); ++groupIt ) {
7991     groupOfElems = *groupIt;
7992     if ( groupOfElems.size() > 1 ) {
7993       groupOfElems.sort();
7994       theGroupsOfElementsID.push_back(groupOfElems);
7995     }
7996   }
7997 }
7998
7999 //=======================================================================
8000 //function : MergeElements
8001 //purpose  : In each given group, substitute all elements by the first one.
8002 //=======================================================================
8003
8004 void SMESH_MeshEditor::MergeElements(TListOfListOfElementsID & theGroupsOfElementsID)
8005 {
8006   myLastCreatedElems.Clear();
8007   myLastCreatedNodes.Clear();
8008
8009   typedef list<int> TListOfIDs;
8010   TListOfIDs rmElemIds; // IDs of elems to remove
8011
8012   SMESHDS_Mesh* aMesh = GetMeshDS();
8013
8014   TListOfListOfElementsID::iterator groupsIt = theGroupsOfElementsID.begin();
8015   while ( groupsIt != theGroupsOfElementsID.end() ) {
8016     TListOfIDs& aGroupOfElemID = *groupsIt;
8017     aGroupOfElemID.sort();
8018     int elemIDToKeep = aGroupOfElemID.front();
8019     const SMDS_MeshElement* elemToKeep = aMesh->FindElement(elemIDToKeep);
8020     aGroupOfElemID.pop_front();
8021     TListOfIDs::iterator idIt = aGroupOfElemID.begin();
8022     while ( idIt != aGroupOfElemID.end() ) {
8023       int elemIDToRemove = *idIt;
8024       const SMDS_MeshElement* elemToRemove = aMesh->FindElement(elemIDToRemove);
8025       // add the kept element in groups of removed one (PAL15188)
8026       AddToSameGroups( elemToKeep, elemToRemove, aMesh );
8027       rmElemIds.push_back( elemIDToRemove );
8028       ++idIt;
8029     }
8030     ++groupsIt;
8031   }
8032
8033   Remove( rmElemIds, false );
8034 }
8035
8036 //=======================================================================
8037 //function : MergeEqualElements
8038 //purpose  : Remove all but one of elements built on the same nodes.
8039 //=======================================================================
8040
8041 void SMESH_MeshEditor::MergeEqualElements()
8042 {
8043   set<const SMDS_MeshElement*> aMeshElements; /* empty input -
8044                                                  to merge equal elements in the whole mesh */
8045   TListOfListOfElementsID aGroupsOfElementsID;
8046   FindEqualElements(aMeshElements, aGroupsOfElementsID);
8047   MergeElements(aGroupsOfElementsID);
8048 }
8049
8050 //=======================================================================
8051 //function : FindFaceInSet
8052 //purpose  : Return a face having linked nodes n1 and n2 and which is
8053 //           - not in avoidSet,
8054 //           - in elemSet provided that !elemSet.empty()
8055 //           i1 and i2 optionally returns indices of n1 and n2
8056 //=======================================================================
8057
8058 const SMDS_MeshElement*
8059 SMESH_MeshEditor::FindFaceInSet(const SMDS_MeshNode*    n1,
8060                                 const SMDS_MeshNode*    n2,
8061                                 const TIDSortedElemSet& elemSet,
8062                                 const TIDSortedElemSet& avoidSet,
8063                                 int*                    n1ind,
8064                                 int*                    n2ind)
8065
8066 {
8067   int i1, i2;
8068   const SMDS_MeshElement* face = 0;
8069
8070   SMDS_ElemIteratorPtr invElemIt = n1->GetInverseElementIterator(SMDSAbs_Face);
8071   //MESSAGE("n1->GetInverseElementIterator(SMDSAbs_Face) " << invElemIt);
8072   while ( invElemIt->more() && !face ) // loop on inverse faces of n1
8073   {
8074     //MESSAGE("in while ( invElemIt->more() && !face )");
8075     const SMDS_MeshElement* elem = invElemIt->next();
8076     if (avoidSet.count( elem ))
8077       continue;
8078     if ( !elemSet.empty() && !elemSet.count( elem ))
8079       continue;
8080     // index of n1
8081     i1 = elem->GetNodeIndex( n1 );
8082     // find a n2 linked to n1
8083     int nbN = elem->IsQuadratic() ? elem->NbNodes()/2 : elem->NbNodes();
8084     for ( int di = -1; di < 2 && !face; di += 2 )
8085     {
8086       i2 = (i1+di+nbN) % nbN;
8087       if ( elem->GetNode( i2 ) == n2 )
8088         face = elem;
8089     }
8090     if ( !face && elem->IsQuadratic())
8091     {
8092       // analysis for quadratic elements using all nodes
8093       const SMDS_VtkFace* F =
8094         dynamic_cast<const SMDS_VtkFace*>(elem);
8095       if (!F) throw SALOME_Exception(LOCALIZED("not an SMDS_VtkFace"));
8096       // use special nodes iterator
8097       SMDS_ElemIteratorPtr anIter = F->interlacedNodesElemIterator();
8098       const SMDS_MeshNode* prevN = cast2Node( anIter->next() );
8099       for ( i1 = -1, i2 = 0; anIter->more() && !face; i1++, i2++ )
8100       {
8101         const SMDS_MeshNode* n = cast2Node( anIter->next() );
8102         if ( n1 == prevN && n2 == n )
8103         {
8104           face = elem;
8105         }
8106         else if ( n2 == prevN && n1 == n )
8107         {
8108           face = elem; swap( i1, i2 );
8109         }
8110         prevN = n;
8111       }
8112     }
8113   }
8114   if ( n1ind ) *n1ind = i1;
8115   if ( n2ind ) *n2ind = i2;
8116   return face;
8117 }
8118
8119 //=======================================================================
8120 //function : findAdjacentFace
8121 //purpose  :
8122 //=======================================================================
8123
8124 static const SMDS_MeshElement* findAdjacentFace(const SMDS_MeshNode* n1,
8125                                                 const SMDS_MeshNode* n2,
8126                                                 const SMDS_MeshElement* elem)
8127 {
8128   TIDSortedElemSet elemSet, avoidSet;
8129   if ( elem )
8130     avoidSet.insert ( elem );
8131   return SMESH_MeshEditor::FindFaceInSet( n1, n2, elemSet, avoidSet );
8132 }
8133
8134 //=======================================================================
8135 //function : FindFreeBorder
8136 //purpose  :
8137 //=======================================================================
8138
8139 #define ControlFreeBorder SMESH::Controls::FreeEdges::IsFreeEdge
8140
8141 bool SMESH_MeshEditor::FindFreeBorder (const SMDS_MeshNode*             theFirstNode,
8142                                        const SMDS_MeshNode*             theSecondNode,
8143                                        const SMDS_MeshNode*             theLastNode,
8144                                        list< const SMDS_MeshNode* > &   theNodes,
8145                                        list< const SMDS_MeshElement* >& theFaces)
8146 {
8147   if ( !theFirstNode || !theSecondNode )
8148     return false;
8149   // find border face between theFirstNode and theSecondNode
8150   const SMDS_MeshElement* curElem = findAdjacentFace( theFirstNode, theSecondNode, 0 );
8151   if ( !curElem )
8152     return false;
8153
8154   theFaces.push_back( curElem );
8155   theNodes.push_back( theFirstNode );
8156   theNodes.push_back( theSecondNode );
8157
8158   //vector<const SMDS_MeshNode*> nodes;
8159   const SMDS_MeshNode *nIgnore = theFirstNode, *nStart = theSecondNode;
8160   TIDSortedElemSet foundElems;
8161   bool needTheLast = ( theLastNode != 0 );
8162
8163   while ( nStart != theLastNode ) {
8164     if ( nStart == theFirstNode )
8165       return !needTheLast;
8166
8167     // find all free border faces sharing form nStart
8168
8169     list< const SMDS_MeshElement* > curElemList;
8170     list< const SMDS_MeshNode* > nStartList;
8171     SMDS_ElemIteratorPtr invElemIt = nStart->GetInverseElementIterator(SMDSAbs_Face);
8172     while ( invElemIt->more() ) {
8173       const SMDS_MeshElement* e = invElemIt->next();
8174       if ( e == curElem || foundElems.insert( e ).second ) {
8175         // get nodes
8176         int iNode = 0, nbNodes = e->NbNodes();
8177         //const SMDS_MeshNode* nodes[nbNodes+1];
8178         vector<const SMDS_MeshNode*> nodes(nbNodes+1);
8179
8180         if(e->IsQuadratic()) {
8181           const SMDS_VtkFace* F =
8182             dynamic_cast<const SMDS_VtkFace*>(e);
8183           if (!F) throw SALOME_Exception(LOCALIZED("not an SMDS_VtkFace"));
8184           // use special nodes iterator
8185           SMDS_ElemIteratorPtr anIter = F->interlacedNodesElemIterator();
8186           while( anIter->more() ) {
8187             nodes[ iNode++ ] = cast2Node(anIter->next());
8188           }
8189         }
8190         else {
8191           SMDS_ElemIteratorPtr nIt = e->nodesIterator();
8192           while ( nIt->more() )
8193             nodes[ iNode++ ] = static_cast<const SMDS_MeshNode*>( nIt->next() );
8194         }
8195         nodes[ iNode ] = nodes[ 0 ];
8196         // check 2 links
8197         for ( iNode = 0; iNode < nbNodes; iNode++ )
8198           if (((nodes[ iNode ] == nStart && nodes[ iNode + 1] != nIgnore ) ||
8199                (nodes[ iNode + 1] == nStart && nodes[ iNode ] != nIgnore )) &&
8200               ControlFreeBorder( &nodes[ iNode ], e->GetID() ))
8201           {
8202             nStartList.push_back( nodes[ iNode + ( nodes[ iNode ] == nStart ? 1 : 0 )]);
8203             curElemList.push_back( e );
8204           }
8205       }
8206     }
8207     // analyse the found
8208
8209     int nbNewBorders = curElemList.size();
8210     if ( nbNewBorders == 0 ) {
8211       // no free border furthermore
8212       return !needTheLast;
8213     }
8214     else if ( nbNewBorders == 1 ) {
8215       // one more element found
8216       nIgnore = nStart;
8217       nStart = nStartList.front();
8218       curElem = curElemList.front();
8219       theFaces.push_back( curElem );
8220       theNodes.push_back( nStart );
8221     }
8222     else {
8223       // several continuations found
8224       list< const SMDS_MeshElement* >::iterator curElemIt;
8225       list< const SMDS_MeshNode* >::iterator nStartIt;
8226       // check if one of them reached the last node
8227       if ( needTheLast ) {
8228         for (curElemIt = curElemList.begin(), nStartIt = nStartList.begin();
8229              curElemIt!= curElemList.end();
8230              curElemIt++, nStartIt++ )
8231           if ( *nStartIt == theLastNode ) {
8232             theFaces.push_back( *curElemIt );
8233             theNodes.push_back( *nStartIt );
8234             return true;
8235           }
8236       }
8237       // find the best free border by the continuations
8238       list<const SMDS_MeshNode*>    contNodes[ 2 ], *cNL;
8239       list<const SMDS_MeshElement*> contFaces[ 2 ], *cFL;
8240       for (curElemIt = curElemList.begin(), nStartIt = nStartList.begin();
8241            curElemIt!= curElemList.end();
8242            curElemIt++, nStartIt++ )
8243       {
8244         cNL = & contNodes[ contNodes[0].empty() ? 0 : 1 ];
8245         cFL = & contFaces[ contFaces[0].empty() ? 0 : 1 ];
8246         // find one more free border
8247         if ( ! FindFreeBorder( nStart, *nStartIt, theLastNode, *cNL, *cFL )) {
8248           cNL->clear();
8249           cFL->clear();
8250         }
8251         else if ( !contNodes[0].empty() && !contNodes[1].empty() ) {
8252           // choice: clear a worse one
8253           int iLongest = ( contNodes[0].size() < contNodes[1].size() ? 1 : 0 );
8254           int iWorse = ( needTheLast ? 1 - iLongest : iLongest );
8255           contNodes[ iWorse ].clear();
8256           contFaces[ iWorse ].clear();
8257         }
8258       }
8259       if ( contNodes[0].empty() && contNodes[1].empty() )
8260         return false;
8261
8262       // append the best free border
8263       cNL = & contNodes[ contNodes[0].empty() ? 1 : 0 ];
8264       cFL = & contFaces[ contFaces[0].empty() ? 1 : 0 ];
8265       theNodes.pop_back(); // remove nIgnore
8266       theNodes.pop_back(); // remove nStart
8267       theFaces.pop_back(); // remove curElem
8268       list< const SMDS_MeshNode* >::iterator nIt = cNL->begin();
8269       list< const SMDS_MeshElement* >::iterator fIt = cFL->begin();
8270       for ( ; nIt != cNL->end(); nIt++ ) theNodes.push_back( *nIt );
8271       for ( ; fIt != cFL->end(); fIt++ ) theFaces.push_back( *fIt );
8272       return true;
8273
8274     } // several continuations found
8275   } // while ( nStart != theLastNode )
8276
8277   return true;
8278 }
8279
8280 //=======================================================================
8281 //function : CheckFreeBorderNodes
8282 //purpose  : Return true if the tree nodes are on a free border
8283 //=======================================================================
8284
8285 bool SMESH_MeshEditor::CheckFreeBorderNodes(const SMDS_MeshNode* theNode1,
8286                                             const SMDS_MeshNode* theNode2,
8287                                             const SMDS_MeshNode* theNode3)
8288 {
8289   list< const SMDS_MeshNode* > nodes;
8290   list< const SMDS_MeshElement* > faces;
8291   return FindFreeBorder( theNode1, theNode2, theNode3, nodes, faces);
8292 }
8293
8294 //=======================================================================
8295 //function : SewFreeBorder
8296 //purpose  :
8297 //=======================================================================
8298
8299 SMESH_MeshEditor::Sew_Error
8300 SMESH_MeshEditor::SewFreeBorder (const SMDS_MeshNode* theBordFirstNode,
8301                                  const SMDS_MeshNode* theBordSecondNode,
8302                                  const SMDS_MeshNode* theBordLastNode,
8303                                  const SMDS_MeshNode* theSideFirstNode,
8304                                  const SMDS_MeshNode* theSideSecondNode,
8305                                  const SMDS_MeshNode* theSideThirdNode,
8306                                  const bool           theSideIsFreeBorder,
8307                                  const bool           toCreatePolygons,
8308                                  const bool           toCreatePolyedrs)
8309 {
8310   myLastCreatedElems.Clear();
8311   myLastCreatedNodes.Clear();
8312
8313   MESSAGE("::SewFreeBorder()");
8314   Sew_Error aResult = SEW_OK;
8315
8316   // ====================================
8317   //    find side nodes and elements
8318   // ====================================
8319
8320   list< const SMDS_MeshNode* > nSide[ 2 ];
8321   list< const SMDS_MeshElement* > eSide[ 2 ];
8322   list< const SMDS_MeshNode* >::iterator nIt[ 2 ];
8323   list< const SMDS_MeshElement* >::iterator eIt[ 2 ];
8324
8325   // Free border 1
8326   // --------------
8327   if (!FindFreeBorder(theBordFirstNode,theBordSecondNode,theBordLastNode,
8328                       nSide[0], eSide[0])) {
8329     MESSAGE(" Free Border 1 not found " );
8330     aResult = SEW_BORDER1_NOT_FOUND;
8331   }
8332   if (theSideIsFreeBorder) {
8333     // Free border 2
8334     // --------------
8335     if (!FindFreeBorder(theSideFirstNode, theSideSecondNode, theSideThirdNode,
8336                         nSide[1], eSide[1])) {
8337       MESSAGE(" Free Border 2 not found " );
8338       aResult = ( aResult != SEW_OK ? SEW_BOTH_BORDERS_NOT_FOUND : SEW_BORDER2_NOT_FOUND );
8339     }
8340   }
8341   if ( aResult != SEW_OK )
8342     return aResult;
8343
8344   if (!theSideIsFreeBorder) {
8345     // Side 2
8346     // --------------
8347
8348     // -------------------------------------------------------------------------
8349     // Algo:
8350     // 1. If nodes to merge are not coincident, move nodes of the free border
8351     //    from the coord sys defined by the direction from the first to last
8352     //    nodes of the border to the correspondent sys of the side 2
8353     // 2. On the side 2, find the links most co-directed with the correspondent
8354     //    links of the free border
8355     // -------------------------------------------------------------------------
8356
8357     // 1. Since sewing may break if there are volumes to split on the side 2,
8358     //    we wont move nodes but just compute new coordinates for them
8359     typedef map<const SMDS_MeshNode*, gp_XYZ> TNodeXYZMap;
8360     TNodeXYZMap nBordXYZ;
8361     list< const SMDS_MeshNode* >& bordNodes = nSide[ 0 ];
8362     list< const SMDS_MeshNode* >::iterator nBordIt;
8363
8364     gp_XYZ Pb1( theBordFirstNode->X(), theBordFirstNode->Y(), theBordFirstNode->Z() );
8365     gp_XYZ Pb2( theBordLastNode->X(), theBordLastNode->Y(), theBordLastNode->Z() );
8366     gp_XYZ Ps1( theSideFirstNode->X(), theSideFirstNode->Y(), theSideFirstNode->Z() );
8367     gp_XYZ Ps2( theSideSecondNode->X(), theSideSecondNode->Y(), theSideSecondNode->Z() );
8368     double tol2 = 1.e-8;
8369     gp_Vec Vbs1( Pb1 - Ps1 ),Vbs2( Pb2 - Ps2 );
8370     if ( Vbs1.SquareMagnitude() > tol2 || Vbs2.SquareMagnitude() > tol2 ) {
8371       // Need node movement.
8372
8373       // find X and Z axes to create trsf
8374       gp_Vec Zb( Pb1 - Pb2 ), Zs( Ps1 - Ps2 );
8375       gp_Vec X = Zs ^ Zb;
8376       if ( X.SquareMagnitude() <= gp::Resolution() * gp::Resolution() )
8377         // Zb || Zs
8378         X = gp_Ax2( gp::Origin(), Zb ).XDirection();
8379
8380       // coord systems
8381       gp_Ax3 toBordAx( Pb1, Zb, X );
8382       gp_Ax3 fromSideAx( Ps1, Zs, X );
8383       gp_Ax3 toGlobalAx( gp::Origin(), gp::DZ(), gp::DX() );
8384       // set trsf
8385       gp_Trsf toBordSys, fromSide2Sys;
8386       toBordSys.SetTransformation( toBordAx );
8387       fromSide2Sys.SetTransformation( fromSideAx, toGlobalAx );
8388       fromSide2Sys.SetScaleFactor( Zs.Magnitude() / Zb.Magnitude() );
8389
8390       // move
8391       for ( nBordIt = bordNodes.begin(); nBordIt != bordNodes.end(); nBordIt++ ) {
8392         const SMDS_MeshNode* n = *nBordIt;
8393         gp_XYZ xyz( n->X(),n->Y(),n->Z() );
8394         toBordSys.Transforms( xyz );
8395         fromSide2Sys.Transforms( xyz );
8396         nBordXYZ.insert( TNodeXYZMap::value_type( n, xyz ));
8397       }
8398     }
8399     else {
8400       // just insert nodes XYZ in the nBordXYZ map
8401       for ( nBordIt = bordNodes.begin(); nBordIt != bordNodes.end(); nBordIt++ ) {
8402         const SMDS_MeshNode* n = *nBordIt;
8403         nBordXYZ.insert( TNodeXYZMap::value_type( n, gp_XYZ( n->X(),n->Y(),n->Z() )));
8404       }
8405     }
8406
8407     // 2. On the side 2, find the links most co-directed with the correspondent
8408     //    links of the free border
8409
8410     list< const SMDS_MeshElement* >& sideElems = eSide[ 1 ];
8411     list< const SMDS_MeshNode* >& sideNodes = nSide[ 1 ];
8412     sideNodes.push_back( theSideFirstNode );
8413
8414     bool hasVolumes = false;
8415     LinkID_Gen aLinkID_Gen( GetMeshDS() );
8416     set<long> foundSideLinkIDs, checkedLinkIDs;
8417     SMDS_VolumeTool volume;
8418     //const SMDS_MeshNode* faceNodes[ 4 ];
8419
8420     const SMDS_MeshNode*    sideNode;
8421     const SMDS_MeshElement* sideElem;
8422     const SMDS_MeshNode* prevSideNode = theSideFirstNode;
8423     const SMDS_MeshNode* prevBordNode = theBordFirstNode;
8424     nBordIt = bordNodes.begin();
8425     nBordIt++;
8426     // border node position and border link direction to compare with
8427     gp_XYZ bordPos = nBordXYZ[ *nBordIt ];
8428     gp_XYZ bordDir = bordPos - nBordXYZ[ prevBordNode ];
8429     // choose next side node by link direction or by closeness to
8430     // the current border node:
8431     bool searchByDir = ( *nBordIt != theBordLastNode );
8432     do {
8433       // find the next node on the Side 2
8434       sideNode = 0;
8435       double maxDot = -DBL_MAX, minDist = DBL_MAX;
8436       long linkID;
8437       checkedLinkIDs.clear();
8438       gp_XYZ prevXYZ( prevSideNode->X(), prevSideNode->Y(), prevSideNode->Z() );
8439
8440       // loop on inverse elements of current node (prevSideNode) on the Side 2
8441       SMDS_ElemIteratorPtr invElemIt = prevSideNode->GetInverseElementIterator();
8442       while ( invElemIt->more() )
8443       {
8444         const SMDS_MeshElement* elem = invElemIt->next();
8445         // prepare data for a loop on links coming to prevSideNode, of a face or a volume
8446         int iPrevNode, iNode = 0, nbNodes = elem->NbNodes();
8447         vector< const SMDS_MeshNode* > faceNodes( nbNodes, (const SMDS_MeshNode*)0 );
8448         bool isVolume = volume.Set( elem );
8449         const SMDS_MeshNode** nodes = isVolume ? volume.GetNodes() : & faceNodes[0];
8450         if ( isVolume ) // --volume
8451           hasVolumes = true;
8452         else if ( elem->GetType()==SMDSAbs_Face ) { // --face
8453           // retrieve all face nodes and find iPrevNode - an index of the prevSideNode
8454           if(elem->IsQuadratic()) {
8455             const SMDS_VtkFace* F =
8456               dynamic_cast<const SMDS_VtkFace*>(elem);
8457             if (!F) throw SALOME_Exception(LOCALIZED("not an SMDS_VtkFace"));
8458             // use special nodes iterator
8459             SMDS_ElemIteratorPtr anIter = F->interlacedNodesElemIterator();
8460             while( anIter->more() ) {
8461               nodes[ iNode ] = cast2Node(anIter->next());
8462               if ( nodes[ iNode++ ] == prevSideNode )
8463                 iPrevNode = iNode - 1;
8464             }
8465           }
8466           else {
8467             SMDS_ElemIteratorPtr nIt = elem->nodesIterator();
8468             while ( nIt->more() ) {
8469               nodes[ iNode ] = cast2Node( nIt->next() );
8470               if ( nodes[ iNode++ ] == prevSideNode )
8471                 iPrevNode = iNode - 1;
8472             }
8473           }
8474           // there are 2 links to check
8475           nbNodes = 2;
8476         }
8477         else // --edge
8478           continue;
8479         // loop on links, to be precise, on the second node of links
8480         for ( iNode = 0; iNode < nbNodes; iNode++ ) {
8481           const SMDS_MeshNode* n = nodes[ iNode ];
8482           if ( isVolume ) {
8483             if ( !volume.IsLinked( n, prevSideNode ))
8484               continue;
8485           }
8486           else {
8487             if ( iNode ) // a node before prevSideNode
8488               n = nodes[ iPrevNode == 0 ? elem->NbNodes() - 1 : iPrevNode - 1 ];
8489             else         // a node after prevSideNode
8490               n = nodes[ iPrevNode + 1 == elem->NbNodes() ? 0 : iPrevNode + 1 ];
8491           }
8492           // check if this link was already used
8493           long iLink = aLinkID_Gen.GetLinkID( prevSideNode, n );
8494           bool isJustChecked = !checkedLinkIDs.insert( iLink ).second;
8495           if (!isJustChecked &&
8496               foundSideLinkIDs.find( iLink ) == foundSideLinkIDs.end() )
8497           {
8498             // test a link geometrically
8499             gp_XYZ nextXYZ ( n->X(), n->Y(), n->Z() );
8500             bool linkIsBetter = false;
8501             double dot = 0.0, dist = 0.0;
8502             if ( searchByDir ) { // choose most co-directed link
8503               dot = bordDir * ( nextXYZ - prevXYZ ).Normalized();
8504               linkIsBetter = ( dot > maxDot );
8505             }
8506             else { // choose link with the node closest to bordPos
8507               dist = ( nextXYZ - bordPos ).SquareModulus();
8508               linkIsBetter = ( dist < minDist );
8509             }
8510             if ( linkIsBetter ) {
8511               maxDot = dot;
8512               minDist = dist;
8513               linkID = iLink;
8514               sideNode = n;
8515               sideElem = elem;
8516             }
8517           }
8518         }
8519       } // loop on inverse elements of prevSideNode
8520
8521       if ( !sideNode ) {
8522         MESSAGE(" Cant find path by links of the Side 2 ");
8523         return SEW_BAD_SIDE_NODES;
8524       }
8525       sideNodes.push_back( sideNode );
8526       sideElems.push_back( sideElem );
8527       foundSideLinkIDs.insert ( linkID );
8528       prevSideNode = sideNode;
8529
8530       if ( *nBordIt == theBordLastNode )
8531         searchByDir = false;
8532       else {
8533         // find the next border link to compare with
8534         gp_XYZ sidePos( sideNode->X(), sideNode->Y(), sideNode->Z() );
8535         searchByDir = ( bordDir * ( sidePos - bordPos ) <= 0 );
8536         // move to next border node if sideNode is before forward border node (bordPos)
8537         while ( *nBordIt != theBordLastNode && !searchByDir ) {
8538           prevBordNode = *nBordIt;
8539           nBordIt++;
8540           bordPos = nBordXYZ[ *nBordIt ];
8541           bordDir = bordPos - nBordXYZ[ prevBordNode ];
8542           searchByDir = ( bordDir * ( sidePos - bordPos ) <= 0 );
8543         }
8544       }
8545     }
8546     while ( sideNode != theSideSecondNode );
8547
8548     if ( hasVolumes && sideNodes.size () != bordNodes.size() && !toCreatePolyedrs) {
8549       MESSAGE("VOLUME SPLITTING IS FORBIDDEN");
8550       return SEW_VOLUMES_TO_SPLIT; // volume splitting is forbidden
8551     }
8552   } // end nodes search on the side 2
8553
8554   // ============================
8555   // sew the border to the side 2
8556   // ============================
8557
8558   int nbNodes[]  = { nSide[0].size(), nSide[1].size() };
8559   int maxNbNodes = Max( nbNodes[0], nbNodes[1] );
8560
8561   TListOfListOfNodes nodeGroupsToMerge;
8562   if ( nbNodes[0] == nbNodes[1] ||
8563        ( theSideIsFreeBorder && !theSideThirdNode)) {
8564
8565     // all nodes are to be merged
8566
8567     for (nIt[0] = nSide[0].begin(), nIt[1] = nSide[1].begin();
8568          nIt[0] != nSide[0].end() && nIt[1] != nSide[1].end();
8569          nIt[0]++, nIt[1]++ )
8570     {
8571       nodeGroupsToMerge.push_back( list<const SMDS_MeshNode*>() );
8572       nodeGroupsToMerge.back().push_back( *nIt[1] ); // to keep
8573       nodeGroupsToMerge.back().push_back( *nIt[0] ); // to remove
8574     }
8575   }
8576   else {
8577
8578     // insert new nodes into the border and the side to get equal nb of segments
8579
8580     // get normalized parameters of nodes on the borders
8581     //double param[ 2 ][ maxNbNodes ];
8582     double* param[ 2 ];
8583     param[0] = new double [ maxNbNodes ];
8584     param[1] = new double [ maxNbNodes ];
8585     int iNode, iBord;
8586     for ( iBord = 0; iBord < 2; iBord++ ) { // loop on 2 borders
8587       list< const SMDS_MeshNode* >& nodes = nSide[ iBord ];
8588       list< const SMDS_MeshNode* >::iterator nIt = nodes.begin();
8589       const SMDS_MeshNode* nPrev = *nIt;
8590       double bordLength = 0;
8591       for ( iNode = 0; nIt != nodes.end(); nIt++, iNode++ ) { // loop on border nodes
8592         const SMDS_MeshNode* nCur = *nIt;
8593         gp_XYZ segment (nCur->X() - nPrev->X(),
8594                         nCur->Y() - nPrev->Y(),
8595                         nCur->Z() - nPrev->Z());
8596         double segmentLen = segment.Modulus();
8597         bordLength += segmentLen;
8598         param[ iBord ][ iNode ] = bordLength;
8599         nPrev = nCur;
8600       }
8601       // normalize within [0,1]
8602       for ( iNode = 0; iNode < nbNodes[ iBord ]; iNode++ ) {
8603         param[ iBord ][ iNode ] /= bordLength;
8604       }
8605     }
8606
8607     // loop on border segments
8608     const SMDS_MeshNode *nPrev[ 2 ] = { 0, 0 };
8609     int i[ 2 ] = { 0, 0 };
8610     nIt[0] = nSide[0].begin(); eIt[0] = eSide[0].begin();
8611     nIt[1] = nSide[1].begin(); eIt[1] = eSide[1].begin();
8612
8613     TElemOfNodeListMap insertMap;
8614     TElemOfNodeListMap::iterator insertMapIt;
8615     // insertMap is
8616     // key:   elem to insert nodes into
8617     // value: 2 nodes to insert between + nodes to be inserted
8618     do {
8619       bool next[ 2 ] = { false, false };
8620
8621       // find min adjacent segment length after sewing
8622       double nextParam = 10., prevParam = 0;
8623       for ( iBord = 0; iBord < 2; iBord++ ) { // loop on 2 borders
8624         if ( i[ iBord ] + 1 < nbNodes[ iBord ])
8625           nextParam = Min( nextParam, param[iBord][ i[iBord] + 1 ]);
8626         if ( i[ iBord ] > 0 )
8627           prevParam = Max( prevParam, param[iBord][ i[iBord] - 1 ]);
8628       }
8629       double minParam = Min( param[ 0 ][ i[0] ], param[ 1 ][ i[1] ]);
8630       double maxParam = Max( param[ 0 ][ i[0] ], param[ 1 ][ i[1] ]);
8631       double minSegLen = Min( nextParam - minParam, maxParam - prevParam );
8632
8633       // choose to insert or to merge nodes
8634       double du = param[ 1 ][ i[1] ] - param[ 0 ][ i[0] ];
8635       if ( Abs( du ) <= minSegLen * 0.2 ) {
8636         // merge
8637         // ------
8638         nodeGroupsToMerge.push_back( list<const SMDS_MeshNode*>() );
8639         const SMDS_MeshNode* n0 = *nIt[0];
8640         const SMDS_MeshNode* n1 = *nIt[1];
8641         nodeGroupsToMerge.back().push_back( n1 );
8642         nodeGroupsToMerge.back().push_back( n0 );
8643         // position of node of the border changes due to merge
8644         param[ 0 ][ i[0] ] += du;
8645         // move n1 for the sake of elem shape evaluation during insertion.
8646         // n1 will be removed by MergeNodes() anyway
8647         const_cast<SMDS_MeshNode*>( n0 )->setXYZ( n1->X(), n1->Y(), n1->Z() );
8648         next[0] = next[1] = true;
8649       }
8650       else {
8651         // insert
8652         // ------
8653         int intoBord = ( du < 0 ) ? 0 : 1;
8654         const SMDS_MeshElement* elem = *eIt[ intoBord ];
8655         const SMDS_MeshNode*    n1   = nPrev[ intoBord ];
8656         const SMDS_MeshNode*    n2   = *nIt[ intoBord ];
8657         const SMDS_MeshNode*    nIns = *nIt[ 1 - intoBord ];
8658         if ( intoBord == 1 ) {
8659           // move node of the border to be on a link of elem of the side
8660           gp_XYZ p1 (n1->X(), n1->Y(), n1->Z());
8661           gp_XYZ p2 (n2->X(), n2->Y(), n2->Z());
8662           double ratio = du / ( param[ 1 ][ i[1] ] - param[ 1 ][ i[1]-1 ]);
8663           gp_XYZ p = p2 * ( 1 - ratio ) + p1 * ratio;
8664           GetMeshDS()->MoveNode( nIns, p.X(), p.Y(), p.Z() );
8665         }
8666         insertMapIt = insertMap.find( elem );
8667         bool notFound = ( insertMapIt == insertMap.end() );
8668         bool otherLink = ( !notFound && (*insertMapIt).second.front() != n1 );
8669         if ( otherLink ) {
8670           // insert into another link of the same element:
8671           // 1. perform insertion into the other link of the elem
8672           list<const SMDS_MeshNode*> & nodeList = (*insertMapIt).second;
8673           const SMDS_MeshNode* n12 = nodeList.front(); nodeList.pop_front();
8674           const SMDS_MeshNode* n22 = nodeList.front(); nodeList.pop_front();
8675           InsertNodesIntoLink( elem, n12, n22, nodeList, toCreatePolygons );
8676           // 2. perform insertion into the link of adjacent faces
8677           while (true) {
8678             const SMDS_MeshElement* adjElem = findAdjacentFace( n12, n22, elem );
8679             if ( adjElem )
8680               InsertNodesIntoLink( adjElem, n12, n22, nodeList, toCreatePolygons );
8681             else
8682               break;
8683           }
8684           if (toCreatePolyedrs) {
8685             // perform insertion into the links of adjacent volumes
8686             UpdateVolumes(n12, n22, nodeList);
8687           }
8688           // 3. find an element appeared on n1 and n2 after the insertion
8689           insertMap.erase( elem );
8690           elem = findAdjacentFace( n1, n2, 0 );
8691         }
8692         if ( notFound || otherLink ) {
8693           // add element and nodes of the side into the insertMap
8694           insertMapIt = insertMap.insert
8695             ( TElemOfNodeListMap::value_type( elem, list<const SMDS_MeshNode*>() )).first;
8696           (*insertMapIt).second.push_back( n1 );
8697           (*insertMapIt).second.push_back( n2 );
8698         }
8699         // add node to be inserted into elem
8700         (*insertMapIt).second.push_back( nIns );
8701         next[ 1 - intoBord ] = true;
8702       }
8703
8704       // go to the next segment
8705       for ( iBord = 0; iBord < 2; iBord++ ) { // loop on 2 borders
8706         if ( next[ iBord ] ) {
8707           if ( i[ iBord ] != 0 && eIt[ iBord ] != eSide[ iBord ].end())
8708             eIt[ iBord ]++;
8709           nPrev[ iBord ] = *nIt[ iBord ];
8710           nIt[ iBord ]++; i[ iBord ]++;
8711         }
8712       }
8713     }
8714     while ( nIt[0] != nSide[0].end() && nIt[1] != nSide[1].end());
8715
8716     // perform insertion of nodes into elements
8717
8718     for (insertMapIt = insertMap.begin();
8719          insertMapIt != insertMap.end();
8720          insertMapIt++ )
8721     {
8722       const SMDS_MeshElement* elem = (*insertMapIt).first;
8723       list<const SMDS_MeshNode*> & nodeList = (*insertMapIt).second;
8724       const SMDS_MeshNode* n1 = nodeList.front(); nodeList.pop_front();
8725       const SMDS_MeshNode* n2 = nodeList.front(); nodeList.pop_front();
8726
8727       InsertNodesIntoLink( elem, n1, n2, nodeList, toCreatePolygons );
8728
8729       if ( !theSideIsFreeBorder ) {
8730         // look for and insert nodes into the faces adjacent to elem
8731         while (true) {
8732           const SMDS_MeshElement* adjElem = findAdjacentFace( n1, n2, elem );
8733           if ( adjElem )
8734             InsertNodesIntoLink( adjElem, n1, n2, nodeList, toCreatePolygons );
8735           else
8736             break;
8737         }
8738       }
8739       if (toCreatePolyedrs) {
8740         // perform insertion into the links of adjacent volumes
8741         UpdateVolumes(n1, n2, nodeList);
8742       }
8743     }
8744
8745     delete param[0];
8746     delete param[1];
8747   } // end: insert new nodes
8748
8749   MergeNodes ( nodeGroupsToMerge );
8750
8751   return aResult;
8752 }
8753
8754 //=======================================================================
8755 //function : InsertNodesIntoLink
8756 //purpose  : insert theNodesToInsert into theFace between theBetweenNode1
8757 //           and theBetweenNode2 and split theElement
8758 //=======================================================================
8759
8760 void SMESH_MeshEditor::InsertNodesIntoLink(const SMDS_MeshElement*     theFace,
8761                                            const SMDS_MeshNode*        theBetweenNode1,
8762                                            const SMDS_MeshNode*        theBetweenNode2,
8763                                            list<const SMDS_MeshNode*>& theNodesToInsert,
8764                                            const bool                  toCreatePoly)
8765 {
8766   if ( theFace->GetType() != SMDSAbs_Face ) return;
8767
8768   // find indices of 2 link nodes and of the rest nodes
8769   int iNode = 0, il1, il2, i3, i4;
8770   il1 = il2 = i3 = i4 = -1;
8771   //const SMDS_MeshNode* nodes[ theFace->NbNodes() ];
8772   vector<const SMDS_MeshNode*> nodes( theFace->NbNodes() );
8773
8774   if(theFace->IsQuadratic()) {
8775     const SMDS_VtkFace* F =
8776       dynamic_cast<const SMDS_VtkFace*>(theFace);
8777     if (!F) throw SALOME_Exception(LOCALIZED("not an SMDS_VtkFace"));
8778     // use special nodes iterator
8779     SMDS_ElemIteratorPtr anIter = F->interlacedNodesElemIterator();
8780     while( anIter->more() ) {
8781       const SMDS_MeshNode* n = cast2Node(anIter->next());
8782       if ( n == theBetweenNode1 )
8783         il1 = iNode;
8784       else if ( n == theBetweenNode2 )
8785         il2 = iNode;
8786       else if ( i3 < 0 )
8787         i3 = iNode;
8788       else
8789         i4 = iNode;
8790       nodes[ iNode++ ] = n;
8791     }
8792   }
8793   else {
8794     SMDS_ElemIteratorPtr nodeIt = theFace->nodesIterator();
8795     while ( nodeIt->more() ) {
8796       const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
8797       if ( n == theBetweenNode1 )
8798         il1 = iNode;
8799       else if ( n == theBetweenNode2 )
8800         il2 = iNode;
8801       else if ( i3 < 0 )
8802         i3 = iNode;
8803       else
8804         i4 = iNode;
8805       nodes[ iNode++ ] = n;
8806     }
8807   }
8808   if ( il1 < 0 || il2 < 0 || i3 < 0 )
8809     return ;
8810
8811   // arrange link nodes to go one after another regarding the face orientation
8812   bool reverse = ( Abs( il2 - il1 ) == 1 ? il2 < il1 : il1 < il2 );
8813   list<const SMDS_MeshNode *> aNodesToInsert = theNodesToInsert;
8814   if ( reverse ) {
8815     iNode = il1;
8816     il1 = il2;
8817     il2 = iNode;
8818     aNodesToInsert.reverse();
8819   }
8820   // check that not link nodes of a quadrangles are in good order
8821   int nbFaceNodes = theFace->NbNodes();
8822   if ( nbFaceNodes == 4 && i4 - i3 != 1 ) {
8823     iNode = i3;
8824     i3 = i4;
8825     i4 = iNode;
8826   }
8827
8828   if (toCreatePoly || theFace->IsPoly()) {
8829
8830     iNode = 0;
8831     vector<const SMDS_MeshNode *> poly_nodes (nbFaceNodes + aNodesToInsert.size());
8832
8833     // add nodes of face up to first node of link
8834     bool isFLN = false;
8835
8836     if(theFace->IsQuadratic()) {
8837       const SMDS_VtkFace* F =
8838         dynamic_cast<const SMDS_VtkFace*>(theFace);
8839       if (!F) throw SALOME_Exception(LOCALIZED("not an SMDS_VtkFace"));
8840       // use special nodes iterator
8841       SMDS_ElemIteratorPtr anIter = F->interlacedNodesElemIterator();
8842       while( anIter->more()  && !isFLN ) {
8843         const SMDS_MeshNode* n = cast2Node(anIter->next());
8844         poly_nodes[iNode++] = n;
8845         if (n == nodes[il1]) {
8846           isFLN = true;
8847         }
8848       }
8849       // add nodes to insert
8850       list<const SMDS_MeshNode*>::iterator nIt = aNodesToInsert.begin();
8851       for (; nIt != aNodesToInsert.end(); nIt++) {
8852         poly_nodes[iNode++] = *nIt;
8853       }
8854       // add nodes of face starting from last node of link
8855       while ( anIter->more() ) {
8856         poly_nodes[iNode++] = cast2Node(anIter->next());
8857       }
8858     }
8859     else {
8860       SMDS_ElemIteratorPtr nodeIt = theFace->nodesIterator();
8861       while ( nodeIt->more() && !isFLN ) {
8862         const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
8863         poly_nodes[iNode++] = n;
8864         if (n == nodes[il1]) {
8865           isFLN = true;
8866         }
8867       }
8868       // add nodes to insert
8869       list<const SMDS_MeshNode*>::iterator nIt = aNodesToInsert.begin();
8870       for (; nIt != aNodesToInsert.end(); nIt++) {
8871         poly_nodes[iNode++] = *nIt;
8872       }
8873       // add nodes of face starting from last node of link
8874       while ( nodeIt->more() ) {
8875         const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
8876         poly_nodes[iNode++] = n;
8877       }
8878     }
8879
8880     // edit or replace the face
8881     SMESHDS_Mesh *aMesh = GetMeshDS();
8882
8883     if (theFace->IsPoly()) {
8884       aMesh->ChangePolygonNodes(theFace, poly_nodes);
8885     }
8886     else {
8887       int aShapeId = FindShape( theFace );
8888
8889       SMDS_MeshElement* newElem = aMesh->AddPolygonalFace(poly_nodes);
8890       myLastCreatedElems.Append(newElem);
8891       if ( aShapeId && newElem )
8892         aMesh->SetMeshElementOnShape( newElem, aShapeId );
8893
8894       aMesh->RemoveElement(theFace);
8895     }
8896     return;
8897   }
8898
8899   SMESHDS_Mesh *aMesh = GetMeshDS();
8900   if( !theFace->IsQuadratic() ) {
8901
8902     // put aNodesToInsert between theBetweenNode1 and theBetweenNode2
8903     int nbLinkNodes = 2 + aNodesToInsert.size();
8904     //const SMDS_MeshNode* linkNodes[ nbLinkNodes ];
8905     vector<const SMDS_MeshNode*> linkNodes( nbLinkNodes );
8906     linkNodes[ 0 ] = nodes[ il1 ];
8907     linkNodes[ nbLinkNodes - 1 ] = nodes[ il2 ];
8908     list<const SMDS_MeshNode*>::iterator nIt = aNodesToInsert.begin();
8909     for ( iNode = 1; nIt != aNodesToInsert.end(); nIt++ ) {
8910       linkNodes[ iNode++ ] = *nIt;
8911     }
8912     // decide how to split a quadrangle: compare possible variants
8913     // and choose which of splits to be a quadrangle
8914     int i1, i2, iSplit, nbSplits = nbLinkNodes - 1, iBestQuad;
8915     if ( nbFaceNodes == 3 ) {
8916       iBestQuad = nbSplits;
8917       i4 = i3;
8918     }
8919     else if ( nbFaceNodes == 4 ) {
8920       SMESH::Controls::NumericalFunctorPtr aCrit( new SMESH::Controls::AspectRatio);
8921       double aBestRate = DBL_MAX;
8922       for ( int iQuad = 0; iQuad < nbSplits; iQuad++ ) {
8923         i1 = 0; i2 = 1;
8924         double aBadRate = 0;
8925         // evaluate elements quality
8926         for ( iSplit = 0; iSplit < nbSplits; iSplit++ ) {
8927           if ( iSplit == iQuad ) {
8928             SMDS_FaceOfNodes quad (linkNodes[ i1++ ],
8929                                    linkNodes[ i2++ ],
8930                                    nodes[ i3 ],
8931                                    nodes[ i4 ]);
8932             aBadRate += getBadRate( &quad, aCrit );
8933           }
8934           else {
8935             SMDS_FaceOfNodes tria (linkNodes[ i1++ ],
8936                                    linkNodes[ i2++ ],
8937                                    nodes[ iSplit < iQuad ? i4 : i3 ]);
8938             aBadRate += getBadRate( &tria, aCrit );
8939           }
8940         }
8941         // choice
8942         if ( aBadRate < aBestRate ) {
8943           iBestQuad = iQuad;
8944           aBestRate = aBadRate;
8945         }
8946       }
8947     }
8948
8949     // create new elements
8950     int aShapeId = FindShape( theFace );
8951
8952     i1 = 0; i2 = 1;
8953     for ( iSplit = 0; iSplit < nbSplits - 1; iSplit++ ) {
8954       SMDS_MeshElement* newElem = 0;
8955       if ( iSplit == iBestQuad )
8956         newElem = aMesh->AddFace (linkNodes[ i1++ ],
8957                                   linkNodes[ i2++ ],
8958                                   nodes[ i3 ],
8959                                   nodes[ i4 ]);
8960       else
8961         newElem = aMesh->AddFace (linkNodes[ i1++ ],
8962                                   linkNodes[ i2++ ],
8963                                   nodes[ iSplit < iBestQuad ? i4 : i3 ]);
8964       myLastCreatedElems.Append(newElem);
8965       if ( aShapeId && newElem )
8966         aMesh->SetMeshElementOnShape( newElem, aShapeId );
8967     }
8968
8969     // change nodes of theFace
8970     const SMDS_MeshNode* newNodes[ 4 ];
8971     newNodes[ 0 ] = linkNodes[ i1 ];
8972     newNodes[ 1 ] = linkNodes[ i2 ];
8973     newNodes[ 2 ] = nodes[ iSplit >= iBestQuad ? i3 : i4 ];
8974     newNodes[ 3 ] = nodes[ i4 ];
8975     //aMesh->ChangeElementNodes( theFace, newNodes, iSplit == iBestQuad ? 4 : 3 );
8976     const SMDS_MeshElement* newElem = 0;
8977     if (iSplit == iBestQuad)
8978       newElem = aMesh->AddFace( newNodes[0], newNodes[1], newNodes[2], newNodes[3] );
8979     else
8980       newElem = aMesh->AddFace( newNodes[0], newNodes[1], newNodes[2] );
8981     myLastCreatedElems.Append(newElem);
8982     if ( aShapeId && newElem )
8983       aMesh->SetMeshElementOnShape( newElem, aShapeId );
8984 } // end if(!theFace->IsQuadratic())
8985   else { // theFace is quadratic
8986     // we have to split theFace on simple triangles and one simple quadrangle
8987     int tmp = il1/2;
8988     int nbshift = tmp*2;
8989     // shift nodes in nodes[] by nbshift
8990     int i,j;
8991     for(i=0; i<nbshift; i++) {
8992       const SMDS_MeshNode* n = nodes[0];
8993       for(j=0; j<nbFaceNodes-1; j++) {
8994         nodes[j] = nodes[j+1];
8995       }
8996       nodes[nbFaceNodes-1] = n;
8997     }
8998     il1 = il1 - nbshift;
8999     // now have to insert nodes between n0 and n1 or n1 and n2 (see below)
9000     //   n0      n1     n2    n0      n1     n2
9001     //     +-----+-----+        +-----+-----+
9002     //      \         /         |           |
9003     //       \       /          |           |
9004     //      n5+     +n3       n7+           +n3
9005     //         \   /            |           |
9006     //          \ /             |           |
9007     //           +              +-----+-----+
9008     //           n4           n6      n5     n4
9009
9010     // create new elements
9011     int aShapeId = FindShape( theFace );
9012
9013     int n1,n2,n3;
9014     if(nbFaceNodes==6) { // quadratic triangle
9015       SMDS_MeshElement* newElem =
9016         aMesh->AddFace(nodes[3],nodes[4],nodes[5]);
9017       myLastCreatedElems.Append(newElem);
9018       if ( aShapeId && newElem )
9019         aMesh->SetMeshElementOnShape( newElem, aShapeId );
9020       if(theFace->IsMediumNode(nodes[il1])) {
9021         // create quadrangle
9022         newElem = aMesh->AddFace(nodes[0],nodes[1],nodes[3],nodes[5]);
9023         myLastCreatedElems.Append(newElem);
9024         if ( aShapeId && newElem )
9025           aMesh->SetMeshElementOnShape( newElem, aShapeId );
9026         n1 = 1;
9027         n2 = 2;
9028         n3 = 3;
9029       }
9030       else {
9031         // create quadrangle
9032         newElem = aMesh->AddFace(nodes[1],nodes[2],nodes[3],nodes[5]);
9033         myLastCreatedElems.Append(newElem);
9034         if ( aShapeId && newElem )
9035           aMesh->SetMeshElementOnShape( newElem, aShapeId );
9036         n1 = 0;
9037         n2 = 1;
9038         n3 = 5;
9039       }
9040     }
9041     else { // nbFaceNodes==8 - quadratic quadrangle
9042       SMDS_MeshElement* newElem =
9043         aMesh->AddFace(nodes[3],nodes[4],nodes[5]);
9044       myLastCreatedElems.Append(newElem);
9045       if ( aShapeId && newElem )
9046         aMesh->SetMeshElementOnShape( newElem, aShapeId );
9047       newElem = aMesh->AddFace(nodes[5],nodes[6],nodes[7]);
9048       myLastCreatedElems.Append(newElem);
9049       if ( aShapeId && newElem )
9050         aMesh->SetMeshElementOnShape( newElem, aShapeId );
9051       newElem = aMesh->AddFace(nodes[5],nodes[7],nodes[3]);
9052       myLastCreatedElems.Append(newElem);
9053       if ( aShapeId && newElem )
9054         aMesh->SetMeshElementOnShape( newElem, aShapeId );
9055       if(theFace->IsMediumNode(nodes[il1])) {
9056         // create quadrangle
9057         newElem = aMesh->AddFace(nodes[0],nodes[1],nodes[3],nodes[7]);
9058         myLastCreatedElems.Append(newElem);
9059         if ( aShapeId && newElem )
9060           aMesh->SetMeshElementOnShape( newElem, aShapeId );
9061         n1 = 1;
9062         n2 = 2;
9063         n3 = 3;
9064       }
9065       else {
9066         // create quadrangle
9067         newElem = aMesh->AddFace(nodes[1],nodes[2],nodes[3],nodes[7]);
9068         myLastCreatedElems.Append(newElem);
9069         if ( aShapeId && newElem )
9070           aMesh->SetMeshElementOnShape( newElem, aShapeId );
9071         n1 = 0;
9072         n2 = 1;
9073         n3 = 7;
9074       }
9075     }
9076     // create needed triangles using n1,n2,n3 and inserted nodes
9077     int nbn = 2 + aNodesToInsert.size();
9078     //const SMDS_MeshNode* aNodes[nbn];
9079     vector<const SMDS_MeshNode*> aNodes(nbn);
9080     aNodes[0] = nodes[n1];
9081     aNodes[nbn-1] = nodes[n2];
9082     list<const SMDS_MeshNode*>::iterator nIt = aNodesToInsert.begin();
9083     for ( iNode = 1; nIt != aNodesToInsert.end(); nIt++ ) {
9084       aNodes[iNode++] = *nIt;
9085     }
9086     for(i=1; i<nbn; i++) {
9087       SMDS_MeshElement* newElem =
9088         aMesh->AddFace(aNodes[i-1],aNodes[i],nodes[n3]);
9089       myLastCreatedElems.Append(newElem);
9090       if ( aShapeId && newElem )
9091         aMesh->SetMeshElementOnShape( newElem, aShapeId );
9092     }
9093   }
9094   // remove old face
9095   aMesh->RemoveElement(theFace);
9096 }
9097
9098 //=======================================================================
9099 //function : UpdateVolumes
9100 //purpose  :
9101 //=======================================================================
9102 void SMESH_MeshEditor::UpdateVolumes (const SMDS_MeshNode*        theBetweenNode1,
9103                                       const SMDS_MeshNode*        theBetweenNode2,
9104                                       list<const SMDS_MeshNode*>& theNodesToInsert)
9105 {
9106   myLastCreatedElems.Clear();
9107   myLastCreatedNodes.Clear();
9108
9109   SMDS_ElemIteratorPtr invElemIt = theBetweenNode1->GetInverseElementIterator(SMDSAbs_Volume);
9110   while (invElemIt->more()) { // loop on inverse elements of theBetweenNode1
9111     const SMDS_MeshElement* elem = invElemIt->next();
9112
9113     // check, if current volume has link theBetweenNode1 - theBetweenNode2
9114     SMDS_VolumeTool aVolume (elem);
9115     if (!aVolume.IsLinked(theBetweenNode1, theBetweenNode2))
9116       continue;
9117
9118     // insert new nodes in all faces of the volume, sharing link theBetweenNode1 - theBetweenNode2
9119     int iface, nbFaces = aVolume.NbFaces();
9120     vector<const SMDS_MeshNode *> poly_nodes;
9121     vector<int> quantities (nbFaces);
9122
9123     for (iface = 0; iface < nbFaces; iface++) {
9124       int nbFaceNodes = aVolume.NbFaceNodes(iface), nbInserted = 0;
9125       // faceNodes will contain (nbFaceNodes + 1) nodes, last = first
9126       const SMDS_MeshNode** faceNodes = aVolume.GetFaceNodes(iface);
9127
9128       for (int inode = 0; inode < nbFaceNodes; inode++) {
9129         poly_nodes.push_back(faceNodes[inode]);
9130
9131         if (nbInserted == 0) {
9132           if (faceNodes[inode] == theBetweenNode1) {
9133             if (faceNodes[inode + 1] == theBetweenNode2) {
9134               nbInserted = theNodesToInsert.size();
9135
9136               // add nodes to insert
9137               list<const SMDS_MeshNode*>::iterator nIt = theNodesToInsert.begin();
9138               for (; nIt != theNodesToInsert.end(); nIt++) {
9139                 poly_nodes.push_back(*nIt);
9140               }
9141             }
9142           }
9143           else if (faceNodes[inode] == theBetweenNode2) {
9144             if (faceNodes[inode + 1] == theBetweenNode1) {
9145               nbInserted = theNodesToInsert.size();
9146
9147               // add nodes to insert in reversed order
9148               list<const SMDS_MeshNode*>::iterator nIt = theNodesToInsert.end();
9149               nIt--;
9150               for (; nIt != theNodesToInsert.begin(); nIt--) {
9151                 poly_nodes.push_back(*nIt);
9152               }
9153               poly_nodes.push_back(*nIt);
9154             }
9155           }
9156           else {
9157           }
9158         }
9159       }
9160       quantities[iface] = nbFaceNodes + nbInserted;
9161     }
9162
9163     // Replace or update the volume
9164     SMESHDS_Mesh *aMesh = GetMeshDS();
9165
9166     if (elem->IsPoly()) {
9167       aMesh->ChangePolyhedronNodes(elem, poly_nodes, quantities);
9168
9169     }
9170     else {
9171       int aShapeId = FindShape( elem );
9172
9173       SMDS_MeshElement* newElem =
9174         aMesh->AddPolyhedralVolume(poly_nodes, quantities);
9175       myLastCreatedElems.Append(newElem);
9176       if (aShapeId && newElem)
9177         aMesh->SetMeshElementOnShape(newElem, aShapeId);
9178
9179       aMesh->RemoveElement(elem);
9180     }
9181   }
9182 }
9183
9184 //=======================================================================
9185 /*!
9186  * \brief Convert elements contained in a submesh to quadratic
9187  * \retval int - nb of checked elements
9188  */
9189 //=======================================================================
9190
9191 int SMESH_MeshEditor::convertElemToQuadratic(SMESHDS_SubMesh *   theSm,
9192                                              SMESH_MesherHelper& theHelper,
9193                                              const bool          theForce3d)
9194 {
9195   int nbElem = 0;
9196   if( !theSm ) return nbElem;
9197
9198   vector<int> nbNodeInFaces;
9199   SMDS_ElemIteratorPtr ElemItr = theSm->GetElements();
9200   while(ElemItr->more())
9201   {
9202     nbElem++;
9203     const SMDS_MeshElement* elem = ElemItr->next();
9204     if( !elem || elem->IsQuadratic() ) continue;
9205
9206     int id = elem->GetID();
9207     int nbNodes = elem->NbNodes();
9208     SMDSAbs_ElementType aType = elem->GetType();
9209
9210     vector<const SMDS_MeshNode *> nodes (elem->begin_nodes(), elem->end_nodes());
9211     if ( elem->GetEntityType() == SMDSEntity_Polyhedra )
9212       nbNodeInFaces = static_cast<const SMDS_VtkVolume* >( elem )->GetQuantities();
9213
9214     GetMeshDS()->RemoveFreeElement(elem, theSm, /*fromGroups=*/false);
9215
9216     const SMDS_MeshElement* NewElem = 0;
9217
9218     switch( aType )
9219     {
9220     case SMDSAbs_Edge :
9221       {
9222         NewElem = theHelper.AddEdge(nodes[0], nodes[1], id, theForce3d);
9223         break;
9224       }
9225     case SMDSAbs_Face :
9226       {
9227         switch(nbNodes)
9228         {
9229         case 3:
9230           NewElem = theHelper.AddFace(nodes[0], nodes[1], nodes[2], id, theForce3d);
9231           break;
9232         case 4:
9233           NewElem = theHelper.AddFace(nodes[0], nodes[1], nodes[2], nodes[3], id, theForce3d);
9234           break;
9235         default:
9236           NewElem = theHelper.AddPolygonalFace(nodes, id, theForce3d);
9237           continue;
9238         }
9239         break;
9240       }
9241     case SMDSAbs_Volume :
9242       {
9243         switch(nbNodes)
9244         {
9245         case 4:
9246           NewElem = theHelper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3], id, theForce3d);
9247           break;
9248         case 5:
9249           NewElem = theHelper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3], nodes[4], id, theForce3d);
9250           break;
9251         case 6:
9252           NewElem = theHelper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3], nodes[4], nodes[5], id, theForce3d);
9253           break;
9254         case 8:
9255           NewElem = theHelper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3],
9256                                         nodes[4], nodes[5], nodes[6], nodes[7], id, theForce3d);
9257           break;
9258         default:
9259           NewElem = theHelper.AddPolyhedralVolume(nodes, nbNodeInFaces, id, theForce3d);
9260         }
9261         break;
9262       }
9263     default :
9264       continue;
9265     }
9266     ReplaceElemInGroups( elem, NewElem, GetMeshDS());
9267     if( NewElem )
9268       theSm->AddElement( NewElem );
9269   }
9270 //  if (!GetMeshDS()->isCompacted())
9271 //    GetMeshDS()->compactMesh();
9272   return nbElem;
9273 }
9274
9275 //=======================================================================
9276 //function : ConvertToQuadratic
9277 //purpose  :
9278 //=======================================================================
9279 void SMESH_MeshEditor::ConvertToQuadratic(const bool theForce3d)
9280 {
9281   SMESHDS_Mesh* meshDS = GetMeshDS();
9282
9283   SMESH_MesherHelper aHelper(*myMesh);
9284   aHelper.SetIsQuadratic( true );
9285
9286   int nbCheckedElems = 0;
9287   if ( myMesh->HasShapeToMesh() )
9288   {
9289     if ( SMESH_subMesh *aSubMesh = myMesh->GetSubMeshContaining(myMesh->GetShapeToMesh()))
9290     {
9291       SMESH_subMeshIteratorPtr smIt = aSubMesh->getDependsOnIterator(true,false);
9292       while ( smIt->more() ) {
9293         SMESH_subMesh* sm = smIt->next();
9294         if ( SMESHDS_SubMesh *smDS = sm->GetSubMeshDS() ) {
9295           aHelper.SetSubShape( sm->GetSubShape() );
9296           nbCheckedElems += convertElemToQuadratic(smDS, aHelper, theForce3d);
9297         }
9298       }
9299     }
9300   }
9301   int totalNbElems = meshDS->NbEdges() + meshDS->NbFaces() + meshDS->NbVolumes();
9302   if ( nbCheckedElems < totalNbElems ) // not all elements are in submeshes
9303   {
9304     SMESHDS_SubMesh *smDS = 0;
9305     SMDS_EdgeIteratorPtr aEdgeItr = meshDS->edgesIterator();
9306     while(aEdgeItr->more())
9307     {
9308       const SMDS_MeshEdge* edge = aEdgeItr->next();
9309       if(edge && !edge->IsQuadratic())
9310       {
9311         int id = edge->GetID();
9312         //MESSAGE("edge->GetID() " << id);
9313         const SMDS_MeshNode* n1 = edge->GetNode(0);
9314         const SMDS_MeshNode* n2 = edge->GetNode(1);
9315
9316         meshDS->RemoveFreeElement(edge, smDS, /*fromGroups=*/false);
9317
9318         const SMDS_MeshEdge* NewEdge = aHelper.AddEdge(n1, n2, id, theForce3d);
9319         ReplaceElemInGroups( edge, NewEdge, GetMeshDS());
9320       }
9321     }
9322     SMDS_FaceIteratorPtr aFaceItr = meshDS->facesIterator();
9323     while(aFaceItr->more())
9324     {
9325       const SMDS_MeshFace* face = aFaceItr->next();
9326       if(!face || face->IsQuadratic() ) continue;
9327
9328       int id = face->GetID();
9329       int nbNodes = face->NbNodes();
9330       vector<const SMDS_MeshNode *> nodes ( face->begin_nodes(), face->end_nodes());
9331
9332       meshDS->RemoveFreeElement(face, smDS, /*fromGroups=*/false);
9333
9334       SMDS_MeshFace * NewFace = 0;
9335       switch(nbNodes)
9336       {
9337       case 3:
9338         NewFace = aHelper.AddFace(nodes[0], nodes[1], nodes[2], id, theForce3d);
9339         break;
9340       case 4:
9341         NewFace = aHelper.AddFace(nodes[0], nodes[1], nodes[2], nodes[3], id, theForce3d);
9342         break;
9343       default:
9344         NewFace = aHelper.AddPolygonalFace(nodes, id, theForce3d);
9345       }
9346       ReplaceElemInGroups( face, NewFace, GetMeshDS());
9347     }
9348     vector<int> nbNodeInFaces;
9349     SMDS_VolumeIteratorPtr aVolumeItr = meshDS->volumesIterator();
9350     while(aVolumeItr->more())
9351     {
9352       const SMDS_MeshVolume* volume = aVolumeItr->next();
9353       if(!volume || volume->IsQuadratic() ) continue;
9354
9355       int id = volume->GetID();
9356       int nbNodes = volume->NbNodes();
9357       vector<const SMDS_MeshNode *> nodes (volume->begin_nodes(), volume->end_nodes());
9358       if ( volume->GetEntityType() == SMDSEntity_Polyhedra )
9359         nbNodeInFaces = static_cast<const SMDS_VtkVolume* >(volume)->GetQuantities();
9360
9361       meshDS->RemoveFreeElement(volume, smDS, /*fromGroups=*/false);
9362
9363       SMDS_MeshVolume * NewVolume = 0;
9364       switch(nbNodes)
9365       {
9366       case 4:
9367         NewVolume = aHelper.AddVolume(nodes[0], nodes[1], nodes[2],
9368                                       nodes[3], id, theForce3d );
9369         break;
9370       case 5:
9371         NewVolume = aHelper.AddVolume(nodes[0], nodes[1], nodes[2],
9372                                       nodes[3], nodes[4], id, theForce3d);
9373         break;
9374       case 6:
9375         NewVolume = aHelper.AddVolume(nodes[0], nodes[1], nodes[2],
9376                                       nodes[3], nodes[4], nodes[5], id, theForce3d);
9377         break;
9378       case 8:
9379         NewVolume = aHelper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3],
9380                                       nodes[4], nodes[5], nodes[6], nodes[7], id, theForce3d);
9381         break;
9382       default:
9383         NewVolume = aHelper.AddPolyhedralVolume(nodes, nbNodeInFaces, id, theForce3d);
9384       }
9385       ReplaceElemInGroups(volume, NewVolume, meshDS);
9386     }
9387   }
9388
9389   if ( !theForce3d  && !getenv("NO_FixQuadraticElements"))
9390   { // setenv NO_FixQuadraticElements to know if FixQuadraticElements() is guilty of bad conversion
9391     aHelper.SetSubShape(0); // apply FixQuadraticElements() to the whole mesh
9392     aHelper.FixQuadraticElements();
9393   }
9394 }
9395
9396 //================================================================================
9397 /*!
9398  * \brief Makes given elements quadratic
9399  *  \param theForce3d - if true, the medium nodes will be placed in the middle of link
9400  *  \param theElements - elements to make quadratic 
9401  */
9402 //================================================================================
9403
9404 void SMESH_MeshEditor::ConvertToQuadratic(const bool        theForce3d,
9405                                           TIDSortedElemSet& theElements)
9406 {
9407   if ( theElements.empty() ) return;
9408
9409   // we believe that all theElements are of the same type
9410   SMDSAbs_ElementType elemType = (*theElements.begin())->GetType();
9411   
9412   // get all nodes shared by theElements
9413   TIDSortedNodeSet allNodes;
9414   TIDSortedElemSet::iterator eIt = theElements.begin();
9415   for ( ; eIt != theElements.end(); ++eIt )
9416     allNodes.insert( (*eIt)->begin_nodes(), (*eIt)->end_nodes() );
9417
9418   // complete theElements with elements of lower dim whose all nodes are in allNodes
9419
9420   TIDSortedElemSet quadAdjacentElems    [ SMDSAbs_NbElementTypes ]; // quadratic adjacent elements
9421   TIDSortedElemSet checkedAdjacentElems [ SMDSAbs_NbElementTypes ];
9422   TIDSortedNodeSet::iterator nIt = allNodes.begin();
9423   for ( ; nIt != allNodes.end(); ++nIt )
9424   {
9425     const SMDS_MeshNode* n = *nIt;
9426     SMDS_ElemIteratorPtr invIt = n->GetInverseElementIterator();
9427     while ( invIt->more() )
9428     {
9429       const SMDS_MeshElement* e = invIt->next();
9430       if ( e->IsQuadratic() )
9431       {
9432         quadAdjacentElems[ e->GetType() ].insert( e );
9433         continue;
9434       }
9435       if ( e->GetType() >= elemType )
9436       {
9437         continue; // same type of more complex linear element
9438       }
9439
9440       if ( !checkedAdjacentElems[ e->GetType() ].insert( e ).second )
9441         continue; // e is already checked
9442
9443       // check nodes
9444       bool allIn = true;
9445       SMDS_ElemIteratorPtr nodeIt = e->nodesIterator();
9446       while ( nodeIt->more() && allIn )
9447         allIn = allNodes.count( cast2Node( nodeIt->next() ));
9448       if ( allIn )
9449         theElements.insert(e );
9450     }
9451   }
9452
9453   SMESH_MesherHelper helper(*myMesh);
9454   helper.SetIsQuadratic( true );
9455
9456   // add links of quadratic adjacent elements to the helper
9457
9458   if ( !quadAdjacentElems[SMDSAbs_Edge].empty() )
9459     for ( eIt  = quadAdjacentElems[SMDSAbs_Edge].begin();
9460           eIt != quadAdjacentElems[SMDSAbs_Edge].end(); ++eIt )
9461     {
9462       helper.AddTLinks( static_cast< const SMDS_MeshEdge*> (*eIt) );
9463     }
9464   if ( !quadAdjacentElems[SMDSAbs_Face].empty() )
9465     for ( eIt  = quadAdjacentElems[SMDSAbs_Face].begin();
9466           eIt != quadAdjacentElems[SMDSAbs_Face].end(); ++eIt )
9467     {
9468       helper.AddTLinks( static_cast< const SMDS_MeshFace*> (*eIt) );
9469     }
9470   if ( !quadAdjacentElems[SMDSAbs_Volume].empty() )
9471     for ( eIt  = quadAdjacentElems[SMDSAbs_Volume].begin();
9472           eIt != quadAdjacentElems[SMDSAbs_Volume].end(); ++eIt )
9473     {
9474       helper.AddTLinks( static_cast< const SMDS_MeshVolume*> (*eIt) );
9475     }
9476
9477   // make quadratic elements instead of linear ones
9478
9479   SMESHDS_Mesh* meshDS = GetMeshDS();
9480   SMESHDS_SubMesh* smDS = 0;
9481   for ( eIt = theElements.begin(); eIt != theElements.end(); ++eIt )
9482   {
9483     const SMDS_MeshElement* elem = *eIt;
9484     if( elem->IsQuadratic() || elem->NbNodes() < 2 || elem->IsPoly() )
9485       continue;
9486
9487     int id = elem->GetID();
9488     SMDSAbs_ElementType type = elem->GetType();
9489     vector<const SMDS_MeshNode *> nodes ( elem->begin_nodes(), elem->end_nodes());
9490
9491     if ( !smDS || !smDS->Contains( elem ))
9492       smDS = meshDS->MeshElements( elem->getshapeId() );
9493     meshDS->RemoveFreeElement(elem, smDS, /*fromGroups=*/false);
9494
9495     SMDS_MeshElement * newElem = 0;
9496     switch( nodes.size() )
9497     {
9498     case 4: // cases for most multiple element types go first (for optimization)
9499       if ( type == SMDSAbs_Volume )
9500         newElem = helper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3], id, theForce3d);
9501       else
9502         newElem = helper.AddFace  (nodes[0], nodes[1], nodes[2], nodes[3], id, theForce3d);
9503       break;
9504     case 8:
9505       newElem = helper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3],
9506                                  nodes[4], nodes[5], nodes[6], nodes[7], id, theForce3d);
9507       break;
9508     case 3:
9509       newElem = helper.AddFace  (nodes[0], nodes[1], nodes[2], id, theForce3d);
9510       break;
9511     case 2:
9512       newElem = helper.AddEdge(nodes[0], nodes[1], id, theForce3d);
9513       break;
9514     case 5:
9515       newElem = helper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3],
9516                                  nodes[4], id, theForce3d);
9517       break;
9518     case 6:
9519       newElem = helper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3],
9520                                  nodes[4], nodes[5], id, theForce3d);
9521       break;
9522     default:;
9523     }
9524     ReplaceElemInGroups( elem, newElem, meshDS);
9525     if( newElem && smDS )
9526       smDS->AddElement( newElem );
9527   }
9528
9529   if ( !theForce3d  && !getenv("NO_FixQuadraticElements"))
9530   { // setenv NO_FixQuadraticElements to know if FixQuadraticElements() is guilty of bad conversion
9531     helper.SetSubShape(0); // apply FixQuadraticElements() to the whole mesh
9532     helper.FixQuadraticElements();
9533   }
9534 }
9535
9536 //=======================================================================
9537 /*!
9538  * \brief Convert quadratic elements to linear ones and remove quadratic nodes
9539  * \retval int - nb of checked elements
9540  */
9541 //=======================================================================
9542
9543 int SMESH_MeshEditor::removeQuadElem(SMESHDS_SubMesh *    theSm,
9544                                      SMDS_ElemIteratorPtr theItr,
9545                                      const int            theShapeID)
9546 {
9547   int nbElem = 0;
9548   SMESHDS_Mesh* meshDS = GetMeshDS();
9549
9550   while( theItr->more() )
9551   {
9552     const SMDS_MeshElement* elem = theItr->next();
9553     nbElem++;
9554     if( elem && elem->IsQuadratic())
9555     {
9556       int id                    = elem->GetID();
9557       int nbCornerNodes         = elem->NbCornerNodes();
9558       SMDSAbs_ElementType aType = elem->GetType();
9559
9560       vector<const SMDS_MeshNode *> nodes( elem->begin_nodes(), elem->end_nodes() );
9561
9562       //remove a quadratic element
9563       if ( !theSm || !theSm->Contains( elem ))
9564         theSm = meshDS->MeshElements( elem->getshapeId() );
9565       meshDS->RemoveFreeElement( elem, theSm, /*fromGroups=*/false );
9566
9567       // remove medium nodes
9568       for ( unsigned i = nbCornerNodes; i < nodes.size(); ++i )
9569         if ( nodes[i]->NbInverseElements() == 0 )
9570           meshDS->RemoveFreeNode( nodes[i], theSm );
9571
9572       // add a linear element
9573       nodes.resize( nbCornerNodes );
9574       SMDS_MeshElement * newElem = AddElement( nodes, aType, false, id );
9575       ReplaceElemInGroups(elem, newElem, meshDS);
9576       if( theSm && newElem )
9577         theSm->AddElement( newElem );
9578     }
9579   }
9580   return nbElem;
9581 }
9582
9583 //=======================================================================
9584 //function : ConvertFromQuadratic
9585 //purpose  :
9586 //=======================================================================
9587
9588 bool SMESH_MeshEditor::ConvertFromQuadratic()
9589 {
9590   int nbCheckedElems = 0;
9591   if ( myMesh->HasShapeToMesh() )
9592   {
9593     if ( SMESH_subMesh *aSubMesh = myMesh->GetSubMeshContaining(myMesh->GetShapeToMesh()))
9594     {
9595       SMESH_subMeshIteratorPtr smIt = aSubMesh->getDependsOnIterator(true,false);
9596       while ( smIt->more() ) {
9597         SMESH_subMesh* sm = smIt->next();
9598         if ( SMESHDS_SubMesh *smDS = sm->GetSubMeshDS() )
9599           nbCheckedElems += removeQuadElem( smDS, smDS->GetElements(), sm->GetId() );
9600       }
9601     }
9602   }
9603
9604   int totalNbElems =
9605     GetMeshDS()->NbEdges() + GetMeshDS()->NbFaces() + GetMeshDS()->NbVolumes();
9606   if ( nbCheckedElems < totalNbElems ) // not all elements are in submeshes
9607   {
9608     SMESHDS_SubMesh *aSM = 0;
9609     removeQuadElem( aSM, GetMeshDS()->elementsIterator(), 0 );
9610   }
9611
9612   return true;
9613 }
9614
9615 namespace
9616 {
9617   //================================================================================
9618   /*!
9619    * \brief Return true if all medium nodes of the element are in the node set
9620    */
9621   //================================================================================
9622
9623   bool allMediumNodesIn(const SMDS_MeshElement* elem, TIDSortedNodeSet& nodeSet )
9624   {
9625     for ( int i = elem->NbCornerNodes(); i < elem->NbNodes(); ++i )
9626       if ( !nodeSet.count( elem->GetNode(i) ))
9627         return false;
9628     return true;
9629   }
9630 }
9631
9632 //================================================================================
9633 /*!
9634  * \brief Makes given elements linear
9635  */
9636 //================================================================================
9637
9638 void SMESH_MeshEditor::ConvertFromQuadratic(TIDSortedElemSet& theElements)
9639 {
9640   if ( theElements.empty() ) return;
9641
9642   // collect IDs of medium nodes of theElements; some of these nodes will be removed
9643   set<int> mediumNodeIDs;
9644   TIDSortedElemSet::iterator eIt = theElements.begin();
9645   for ( ; eIt != theElements.end(); ++eIt )
9646   {
9647     const SMDS_MeshElement* e = *eIt;
9648     for ( int i = e->NbCornerNodes(); i < e->NbNodes(); ++i )
9649       mediumNodeIDs.insert( e->GetNode(i)->GetID() );
9650   }
9651
9652   // replace given elements by linear ones
9653   typedef SMDS_SetIterator<const SMDS_MeshElement*, TIDSortedElemSet::iterator> TSetIterator;
9654   SMDS_ElemIteratorPtr elemIt( new TSetIterator( theElements.begin(), theElements.end() ));
9655   removeQuadElem( /*theSm=*/0, elemIt, /*theShapeID=*/0 );
9656
9657   // we need to convert remaining elements whose all medium nodes are in mediumNodeIDs
9658   // except those elements sharing medium nodes of quadratic element whose medium nodes
9659   // are not all in mediumNodeIDs
9660
9661   // get remaining medium nodes
9662   TIDSortedNodeSet mediumNodes;
9663   set<int>::iterator nIdsIt = mediumNodeIDs.begin();
9664   for ( ; nIdsIt != mediumNodeIDs.end(); ++nIdsIt )
9665     if ( const SMDS_MeshNode* n = GetMeshDS()->FindNode( *nIdsIt ))
9666       mediumNodes.insert( mediumNodes.end(), n );
9667
9668   // find more quadratic elements to convert
9669   TIDSortedElemSet moreElemsToConvert;
9670   TIDSortedNodeSet::iterator nIt = mediumNodes.begin();
9671   for ( ; nIt != mediumNodes.end(); ++nIt )
9672   {
9673     SMDS_ElemIteratorPtr invIt = (*nIt)->GetInverseElementIterator();
9674     while ( invIt->more() )
9675     {
9676       const SMDS_MeshElement* e = invIt->next();
9677       if ( e->IsQuadratic() && allMediumNodesIn( e, mediumNodes ))
9678       {
9679         // find a more complex element including e and
9680         // whose medium nodes are not in mediumNodes
9681         bool complexFound = false;
9682         for ( int type = e->GetType() + 1; type < SMDSAbs_0DElement; ++type )
9683         {
9684           SMDS_ElemIteratorPtr invIt2 =
9685             (*nIt)->GetInverseElementIterator( SMDSAbs_ElementType( type ));
9686           while ( invIt2->more() )
9687           {
9688             const SMDS_MeshElement* eComplex = invIt2->next();
9689             if ( eComplex->IsQuadratic() && !allMediumNodesIn( eComplex, mediumNodes))
9690             {
9691               int nbCommonNodes = SMESH_Algo::GetCommonNodes( e, eComplex ).size();
9692               if ( nbCommonNodes == e->NbNodes())
9693               {
9694                 complexFound = true;
9695                 type = SMDSAbs_NbElementTypes; // to quit from the outer loop
9696                 break;
9697               }
9698             }
9699           }
9700         }
9701         if ( !complexFound )
9702           moreElemsToConvert.insert( e );
9703       }
9704     }
9705   }
9706   elemIt = SMDS_ElemIteratorPtr
9707     (new TSetIterator( moreElemsToConvert.begin(), moreElemsToConvert.end() ));
9708   removeQuadElem( /*theSm=*/0, elemIt, /*theShapeID=*/0 );
9709 }
9710
9711 //=======================================================================
9712 //function : SewSideElements
9713 //purpose  :
9714 //=======================================================================
9715
9716 SMESH_MeshEditor::Sew_Error
9717 SMESH_MeshEditor::SewSideElements (TIDSortedElemSet&    theSide1,
9718                                    TIDSortedElemSet&    theSide2,
9719                                    const SMDS_MeshNode* theFirstNode1,
9720                                    const SMDS_MeshNode* theFirstNode2,
9721                                    const SMDS_MeshNode* theSecondNode1,
9722                                    const SMDS_MeshNode* theSecondNode2)
9723 {
9724   myLastCreatedElems.Clear();
9725   myLastCreatedNodes.Clear();
9726
9727   MESSAGE ("::::SewSideElements()");
9728   if ( theSide1.size() != theSide2.size() )
9729     return SEW_DIFF_NB_OF_ELEMENTS;
9730
9731   Sew_Error aResult = SEW_OK;
9732   // Algo:
9733   // 1. Build set of faces representing each side
9734   // 2. Find which nodes of the side 1 to merge with ones on the side 2
9735   // 3. Replace nodes in elements of the side 1 and remove replaced nodes
9736
9737   // =======================================================================
9738   // 1. Build set of faces representing each side:
9739   // =======================================================================
9740   // a. build set of nodes belonging to faces
9741   // b. complete set of faces: find missing faces whose nodes are in set of nodes
9742   // c. create temporary faces representing side of volumes if correspondent
9743   //    face does not exist
9744
9745   SMESHDS_Mesh* aMesh = GetMeshDS();
9746   // TODO algoritm not OK with vtkUnstructuredGrid: 2 meshes can't share nodes
9747   //SMDS_Mesh aTmpFacesMesh; // try to use the same mesh
9748   set<const SMDS_MeshElement*> faceSet1, faceSet2;
9749   set<const SMDS_MeshElement*> volSet1,  volSet2;
9750   set<const SMDS_MeshNode*>    nodeSet1, nodeSet2;
9751   set<const SMDS_MeshElement*> * faceSetPtr[] = { &faceSet1, &faceSet2 };
9752   set<const SMDS_MeshElement*>  * volSetPtr[] = { &volSet1,  &volSet2  };
9753   set<const SMDS_MeshNode*>    * nodeSetPtr[] = { &nodeSet1, &nodeSet2 };
9754   TIDSortedElemSet * elemSetPtr[] = { &theSide1, &theSide2 };
9755   int iSide, iFace, iNode;
9756
9757   list<const SMDS_MeshElement* > tempFaceList;
9758   for ( iSide = 0; iSide < 2; iSide++ ) {
9759     set<const SMDS_MeshNode*>    * nodeSet = nodeSetPtr[ iSide ];
9760     TIDSortedElemSet * elemSet = elemSetPtr[ iSide ];
9761     set<const SMDS_MeshElement*> * faceSet = faceSetPtr[ iSide ];
9762     set<const SMDS_MeshElement*> * volSet  = volSetPtr [ iSide ];
9763     set<const SMDS_MeshElement*>::iterator vIt;
9764     TIDSortedElemSet::iterator eIt;
9765     set<const SMDS_MeshNode*>::iterator    nIt;
9766
9767     // check that given nodes belong to given elements
9768     const SMDS_MeshNode* n1 = ( iSide == 0 ) ? theFirstNode1 : theFirstNode2;
9769     const SMDS_MeshNode* n2 = ( iSide == 0 ) ? theSecondNode1 : theSecondNode2;
9770     int firstIndex = -1, secondIndex = -1;
9771     for (eIt = elemSet->begin(); eIt != elemSet->end(); eIt++ ) {
9772       const SMDS_MeshElement* elem = *eIt;
9773       if ( firstIndex  < 0 ) firstIndex  = elem->GetNodeIndex( n1 );
9774       if ( secondIndex < 0 ) secondIndex = elem->GetNodeIndex( n2 );
9775       if ( firstIndex > -1 && secondIndex > -1 ) break;
9776     }
9777     if ( firstIndex < 0 || secondIndex < 0 ) {
9778       // we can simply return until temporary faces created
9779       return (iSide == 0 ) ? SEW_BAD_SIDE1_NODES : SEW_BAD_SIDE2_NODES;
9780     }
9781
9782     // -----------------------------------------------------------
9783     // 1a. Collect nodes of existing faces
9784     //     and build set of face nodes in order to detect missing
9785     //     faces corresponding to sides of volumes
9786     // -----------------------------------------------------------
9787
9788     set< set <const SMDS_MeshNode*> > setOfFaceNodeSet;
9789
9790     // loop on the given element of a side
9791     for (eIt = elemSet->begin(); eIt != elemSet->end(); eIt++ ) {
9792       //const SMDS_MeshElement* elem = *eIt;
9793       const SMDS_MeshElement* elem = *eIt;
9794       if ( elem->GetType() == SMDSAbs_Face ) {
9795         faceSet->insert( elem );
9796         set <const SMDS_MeshNode*> faceNodeSet;
9797         SMDS_ElemIteratorPtr nodeIt = elem->nodesIterator();
9798         while ( nodeIt->more() ) {
9799           const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
9800           nodeSet->insert( n );
9801           faceNodeSet.insert( n );
9802         }
9803         setOfFaceNodeSet.insert( faceNodeSet );
9804       }
9805       else if ( elem->GetType() == SMDSAbs_Volume )
9806         volSet->insert( elem );
9807     }
9808     // ------------------------------------------------------------------------------
9809     // 1b. Complete set of faces: find missing faces whose nodes are in set of nodes
9810     // ------------------------------------------------------------------------------
9811
9812     for ( nIt = nodeSet->begin(); nIt != nodeSet->end(); nIt++ ) { // loop on nodes of iSide
9813       SMDS_ElemIteratorPtr fIt = (*nIt)->GetInverseElementIterator(SMDSAbs_Face);
9814       while ( fIt->more() ) { // loop on faces sharing a node
9815         const SMDS_MeshElement* f = fIt->next();
9816         if ( faceSet->find( f ) == faceSet->end() ) {
9817           // check if all nodes are in nodeSet and
9818           // complete setOfFaceNodeSet if they are
9819           set <const SMDS_MeshNode*> faceNodeSet;
9820           SMDS_ElemIteratorPtr nodeIt = f->nodesIterator();
9821           bool allInSet = true;
9822           while ( nodeIt->more() && allInSet ) { // loop on nodes of a face
9823             const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
9824             if ( nodeSet->find( n ) == nodeSet->end() )
9825               allInSet = false;
9826             else
9827               faceNodeSet.insert( n );
9828           }
9829           if ( allInSet ) {
9830             faceSet->insert( f );
9831             setOfFaceNodeSet.insert( faceNodeSet );
9832           }
9833         }
9834       }
9835     }
9836
9837     // -------------------------------------------------------------------------
9838     // 1c. Create temporary faces representing sides of volumes if correspondent
9839     //     face does not exist
9840     // -------------------------------------------------------------------------
9841
9842     if ( !volSet->empty() ) {
9843       //int nodeSetSize = nodeSet->size();
9844
9845       // loop on given volumes
9846       for ( vIt = volSet->begin(); vIt != volSet->end(); vIt++ ) {
9847         SMDS_VolumeTool vol (*vIt);
9848         // loop on volume faces: find free faces
9849         // --------------------------------------
9850         list<const SMDS_MeshElement* > freeFaceList;
9851         for ( iFace = 0; iFace < vol.NbFaces(); iFace++ ) {
9852           if ( !vol.IsFreeFace( iFace ))
9853             continue;
9854           // check if there is already a face with same nodes in a face set
9855           const SMDS_MeshElement* aFreeFace = 0;
9856           const SMDS_MeshNode** fNodes = vol.GetFaceNodes( iFace );
9857           int nbNodes = vol.NbFaceNodes( iFace );
9858           set <const SMDS_MeshNode*> faceNodeSet;
9859           vol.GetFaceNodes( iFace, faceNodeSet );
9860           bool isNewFace = setOfFaceNodeSet.insert( faceNodeSet ).second;
9861           if ( isNewFace ) {
9862             // no such a face is given but it still can exist, check it
9863             if ( nbNodes == 3 ) {
9864               aFreeFace = aMesh->FindFace( fNodes[0],fNodes[1],fNodes[2] );
9865             }
9866             else if ( nbNodes == 4 ) {
9867               aFreeFace = aMesh->FindFace( fNodes[0],fNodes[1],fNodes[2],fNodes[3] );
9868             }
9869             else {
9870               vector<const SMDS_MeshNode *> poly_nodes ( fNodes, & fNodes[nbNodes]);
9871               aFreeFace = aMesh->FindFace(poly_nodes);
9872             }
9873           }
9874           if ( !aFreeFace ) {
9875             // create a temporary face
9876             if ( nbNodes == 3 ) {
9877               //aFreeFace = aTmpFacesMesh.AddFace( fNodes[0],fNodes[1],fNodes[2] );
9878               aFreeFace = aMesh->AddFace( fNodes[0],fNodes[1],fNodes[2] );
9879             }
9880             else if ( nbNodes == 4 ) {
9881               //aFreeFace = aTmpFacesMesh.AddFace( fNodes[0],fNodes[1],fNodes[2],fNodes[3] );
9882               aFreeFace = aMesh->AddFace( fNodes[0],fNodes[1],fNodes[2],fNodes[3] );
9883             }
9884             else {
9885               vector<const SMDS_MeshNode *> poly_nodes ( fNodes, & fNodes[nbNodes]);
9886               //aFreeFace = aTmpFacesMesh.AddPolygonalFace(poly_nodes);
9887               aFreeFace = aMesh->AddPolygonalFace(poly_nodes);
9888             }
9889           }
9890           if ( aFreeFace ) {
9891             freeFaceList.push_back( aFreeFace );
9892             tempFaceList.push_back( aFreeFace );
9893           }
9894
9895         } // loop on faces of a volume
9896
9897         // choose one of several free faces
9898         // --------------------------------------
9899         if ( freeFaceList.size() > 1 ) {
9900           // choose a face having max nb of nodes shared by other elems of a side
9901           int maxNbNodes = -1/*, nbExcludedFaces = 0*/;
9902           list<const SMDS_MeshElement* >::iterator fIt = freeFaceList.begin();
9903           while ( fIt != freeFaceList.end() ) { // loop on free faces
9904             int nbSharedNodes = 0;
9905             SMDS_ElemIteratorPtr nodeIt = (*fIt)->nodesIterator();
9906             while ( nodeIt->more() ) { // loop on free face nodes
9907               const SMDS_MeshNode* n =
9908                 static_cast<const SMDS_MeshNode*>( nodeIt->next() );
9909               SMDS_ElemIteratorPtr invElemIt = n->GetInverseElementIterator();
9910               while ( invElemIt->more() ) {
9911                 const SMDS_MeshElement* e = invElemIt->next();
9912                 if ( faceSet->find( e ) != faceSet->end() )
9913                   nbSharedNodes++;
9914                 if ( elemSet->find( e ) != elemSet->end() )
9915                   nbSharedNodes++;
9916               }
9917             }
9918             if ( nbSharedNodes >= maxNbNodes ) {
9919               maxNbNodes = nbSharedNodes;
9920               fIt++;
9921             }
9922             else
9923               freeFaceList.erase( fIt++ ); // here fIt++ occurs before erase
9924           }
9925           if ( freeFaceList.size() > 1 )
9926           {
9927             // could not choose one face, use another way
9928             // choose a face most close to the bary center of the opposite side
9929             gp_XYZ aBC( 0., 0., 0. );
9930             set <const SMDS_MeshNode*> addedNodes;
9931             TIDSortedElemSet * elemSet2 = elemSetPtr[ 1 - iSide ];
9932             eIt = elemSet2->begin();
9933             for ( eIt = elemSet2->begin(); eIt != elemSet2->end(); eIt++ ) {
9934               SMDS_ElemIteratorPtr nodeIt = (*eIt)->nodesIterator();
9935               while ( nodeIt->more() ) { // loop on free face nodes
9936                 const SMDS_MeshNode* n =
9937                   static_cast<const SMDS_MeshNode*>( nodeIt->next() );
9938                 if ( addedNodes.insert( n ).second )
9939                   aBC += gp_XYZ( n->X(),n->Y(),n->Z() );
9940               }
9941             }
9942             aBC /= addedNodes.size();
9943             double minDist = DBL_MAX;
9944             fIt = freeFaceList.begin();
9945             while ( fIt != freeFaceList.end() ) { // loop on free faces
9946               double dist = 0;
9947               SMDS_ElemIteratorPtr nodeIt = (*fIt)->nodesIterator();
9948               while ( nodeIt->more() ) { // loop on free face nodes
9949                 const SMDS_MeshNode* n =
9950                   static_cast<const SMDS_MeshNode*>( nodeIt->next() );
9951                 gp_XYZ p( n->X(),n->Y(),n->Z() );
9952                 dist += ( aBC - p ).SquareModulus();
9953               }
9954               if ( dist < minDist ) {
9955                 minDist = dist;
9956                 freeFaceList.erase( freeFaceList.begin(), fIt++ );
9957               }
9958               else
9959                 fIt = freeFaceList.erase( fIt++ );
9960             }
9961           }
9962         } // choose one of several free faces of a volume
9963
9964         if ( freeFaceList.size() == 1 ) {
9965           const SMDS_MeshElement* aFreeFace = freeFaceList.front();
9966           faceSet->insert( aFreeFace );
9967           // complete a node set with nodes of a found free face
9968           //           for ( iNode = 0; iNode < ; iNode++ )
9969           //             nodeSet->insert( fNodes[ iNode ] );
9970         }
9971
9972       } // loop on volumes of a side
9973
9974       //       // complete a set of faces if new nodes in a nodeSet appeared
9975       //       // ----------------------------------------------------------
9976       //       if ( nodeSetSize != nodeSet->size() ) {
9977       //         for ( ; nIt != nodeSet->end(); nIt++ ) { // loop on nodes of iSide
9978       //           SMDS_ElemIteratorPtr fIt = (*nIt)->GetInverseElementIterator(SMDSAbs_Face);
9979       //           while ( fIt->more() ) { // loop on faces sharing a node
9980       //             const SMDS_MeshElement* f = fIt->next();
9981       //             if ( faceSet->find( f ) == faceSet->end() ) {
9982       //               // check if all nodes are in nodeSet and
9983       //               // complete setOfFaceNodeSet if they are
9984       //               set <const SMDS_MeshNode*> faceNodeSet;
9985       //               SMDS_ElemIteratorPtr nodeIt = f->nodesIterator();
9986       //               bool allInSet = true;
9987       //               while ( nodeIt->more() && allInSet ) { // loop on nodes of a face
9988       //                 const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
9989       //                 if ( nodeSet->find( n ) == nodeSet->end() )
9990       //                   allInSet = false;
9991       //                 else
9992       //                   faceNodeSet.insert( n );
9993       //               }
9994       //               if ( allInSet ) {
9995       //                 faceSet->insert( f );
9996       //                 setOfFaceNodeSet.insert( faceNodeSet );
9997       //               }
9998       //             }
9999       //           }
10000       //         }
10001       //       }
10002     } // Create temporary faces, if there are volumes given
10003   } // loop on sides
10004
10005   if ( faceSet1.size() != faceSet2.size() ) {
10006     // delete temporary faces: they are in reverseElements of actual nodes
10007 //    SMDS_FaceIteratorPtr tmpFaceIt = aTmpFacesMesh.facesIterator();
10008 //    while ( tmpFaceIt->more() )
10009 //      aTmpFacesMesh.RemoveElement( tmpFaceIt->next() );
10010 //    list<const SMDS_MeshElement* >::iterator tmpFaceIt = tempFaceList.begin();
10011 //    for (; tmpFaceIt !=tempFaceList.end(); ++tmpFaceIt)
10012 //      aMesh->RemoveElement(*tmpFaceIt);
10013     MESSAGE("Diff nb of faces");
10014     return SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
10015   }
10016
10017   // ============================================================
10018   // 2. Find nodes to merge:
10019   //              bind a node to remove to a node to put instead
10020   // ============================================================
10021
10022   TNodeNodeMap nReplaceMap; // bind a node to remove to a node to put instead
10023   if ( theFirstNode1 != theFirstNode2 )
10024     nReplaceMap.insert( TNodeNodeMap::value_type( theFirstNode1, theFirstNode2 ));
10025   if ( theSecondNode1 != theSecondNode2 )
10026     nReplaceMap.insert( TNodeNodeMap::value_type( theSecondNode1, theSecondNode2 ));
10027
10028   LinkID_Gen aLinkID_Gen( GetMeshDS() );
10029   set< long > linkIdSet; // links to process
10030   linkIdSet.insert( aLinkID_Gen.GetLinkID( theFirstNode1, theSecondNode1 ));
10031
10032   typedef pair< const SMDS_MeshNode*, const SMDS_MeshNode* > NLink;
10033   list< NLink > linkList[2];
10034   linkList[0].push_back( NLink( theFirstNode1, theSecondNode1 ));
10035   linkList[1].push_back( NLink( theFirstNode2, theSecondNode2 ));
10036   // loop on links in linkList; find faces by links and append links
10037   // of the found faces to linkList
10038   list< NLink >::iterator linkIt[] = { linkList[0].begin(), linkList[1].begin() } ;
10039   for ( ; linkIt[0] != linkList[0].end(); linkIt[0]++, linkIt[1]++ ) {
10040     NLink link[] = { *linkIt[0], *linkIt[1] };
10041     long linkID = aLinkID_Gen.GetLinkID( link[0].first, link[0].second );
10042     if ( linkIdSet.find( linkID ) == linkIdSet.end() )
10043       continue;
10044
10045     // by links, find faces in the face sets,
10046     // and find indices of link nodes in the found faces;
10047     // in a face set, there is only one or no face sharing a link
10048     // ---------------------------------------------------------------
10049
10050     const SMDS_MeshElement* face[] = { 0, 0 };
10051     //const SMDS_MeshNode* faceNodes[ 2 ][ 5 ];
10052     vector<const SMDS_MeshNode*> fnodes1(9);
10053     vector<const SMDS_MeshNode*> fnodes2(9);
10054     //const SMDS_MeshNode* notLinkNodes[ 2 ][ 2 ] = {{ 0, 0 },{ 0, 0 }} ;
10055     vector<const SMDS_MeshNode*> notLinkNodes1(6);
10056     vector<const SMDS_MeshNode*> notLinkNodes2(6);
10057     int iLinkNode[2][2];
10058     for ( iSide = 0; iSide < 2; iSide++ ) { // loop on 2 sides
10059       const SMDS_MeshNode* n1 = link[iSide].first;
10060       const SMDS_MeshNode* n2 = link[iSide].second;
10061       set<const SMDS_MeshElement*> * faceSet = faceSetPtr[ iSide ];
10062       set< const SMDS_MeshElement* > fMap;
10063       for ( int i = 0; i < 2; i++ ) { // loop on 2 nodes of a link
10064         const SMDS_MeshNode* n = i ? n1 : n2; // a node of a link
10065         SMDS_ElemIteratorPtr fIt = n->GetInverseElementIterator(SMDSAbs_Face);
10066         while ( fIt->more() ) { // loop on faces sharing a node
10067           const SMDS_MeshElement* f = fIt->next();
10068           if (faceSet->find( f ) != faceSet->end() && // f is in face set
10069               ! fMap.insert( f ).second ) // f encounters twice
10070           {
10071             if ( face[ iSide ] ) {
10072               MESSAGE( "2 faces per link " );
10073               aResult = iSide ? SEW_BAD_SIDE2_NODES : SEW_BAD_SIDE1_NODES;
10074               break;
10075             }
10076             face[ iSide ] = f;
10077             faceSet->erase( f );
10078             // get face nodes and find ones of a link
10079             iNode = 0;
10080             int nbl = -1;
10081             if(f->IsPoly()) {
10082               if(iSide==0) {
10083                 fnodes1.resize(f->NbNodes()+1);
10084                 notLinkNodes1.resize(f->NbNodes()-2);
10085               }
10086               else {
10087                 fnodes2.resize(f->NbNodes()+1);
10088                 notLinkNodes2.resize(f->NbNodes()-2);
10089               }
10090             }
10091             if(!f->IsQuadratic()) {
10092               SMDS_ElemIteratorPtr nIt = f->nodesIterator();
10093               while ( nIt->more() ) {
10094                 const SMDS_MeshNode* n =
10095                   static_cast<const SMDS_MeshNode*>( nIt->next() );
10096                 if ( n == n1 ) {
10097                   iLinkNode[ iSide ][ 0 ] = iNode;
10098                 }
10099                 else if ( n == n2 ) {
10100                   iLinkNode[ iSide ][ 1 ] = iNode;
10101                 }
10102                 //else if ( notLinkNodes[ iSide ][ 0 ] )
10103                 //  notLinkNodes[ iSide ][ 1 ] = n;
10104                 //else
10105                 //  notLinkNodes[ iSide ][ 0 ] = n;
10106                 else {
10107                   nbl++;
10108                   if(iSide==0)
10109                     notLinkNodes1[nbl] = n;
10110                   //notLinkNodes1.push_back(n);
10111                   else
10112                     notLinkNodes2[nbl] = n;
10113                   //notLinkNodes2.push_back(n);
10114                 }
10115                 //faceNodes[ iSide ][ iNode++ ] = n;
10116                 if(iSide==0) {
10117                   fnodes1[iNode++] = n;
10118                 }
10119                 else {
10120                   fnodes2[iNode++] = n;
10121                 }
10122               }
10123             }
10124             else { // f->IsQuadratic()
10125               const SMDS_VtkFace* F =
10126                 dynamic_cast<const SMDS_VtkFace*>(f);
10127               if (!F) throw SALOME_Exception(LOCALIZED("not an SMDS_VtkFace"));
10128               // use special nodes iterator
10129               SMDS_ElemIteratorPtr anIter = F->interlacedNodesElemIterator();
10130               while ( anIter->more() ) {
10131                 const SMDS_MeshNode* n =
10132                   static_cast<const SMDS_MeshNode*>( anIter->next() );
10133                 if ( n == n1 ) {
10134                   iLinkNode[ iSide ][ 0 ] = iNode;
10135                 }
10136                 else if ( n == n2 ) {
10137                   iLinkNode[ iSide ][ 1 ] = iNode;
10138                 }
10139                 else {
10140                   nbl++;
10141                   if(iSide==0) {
10142                     notLinkNodes1[nbl] = n;
10143                   }
10144                   else {
10145                     notLinkNodes2[nbl] = n;
10146                   }
10147                 }
10148                 if(iSide==0) {
10149                   fnodes1[iNode++] = n;
10150                 }
10151                 else {
10152                   fnodes2[iNode++] = n;
10153                 }
10154               }
10155             }
10156             //faceNodes[ iSide ][ iNode ] = faceNodes[ iSide ][ 0 ];
10157             if(iSide==0) {
10158               fnodes1[iNode] = fnodes1[0];
10159             }
10160             else {
10161               fnodes2[iNode] = fnodes1[0];
10162             }
10163           }
10164         }
10165       }
10166     }
10167
10168     // check similarity of elements of the sides
10169     if (aResult == SEW_OK && ( face[0] && !face[1] ) || ( !face[0] && face[1] )) {
10170       MESSAGE("Correspondent face not found on side " << ( face[0] ? 1 : 0 ));
10171       if ( nReplaceMap.size() == 2 ) { // faces on input nodes not found
10172         aResult = ( face[0] ? SEW_BAD_SIDE2_NODES : SEW_BAD_SIDE1_NODES );
10173       }
10174       else {
10175         aResult = SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
10176       }
10177       break; // do not return because it s necessary to remove tmp faces
10178     }
10179
10180     // set nodes to merge
10181     // -------------------
10182
10183     if ( face[0] && face[1] )  {
10184       int nbNodes = face[0]->NbNodes();
10185       if ( nbNodes != face[1]->NbNodes() ) {
10186         MESSAGE("Diff nb of face nodes");
10187         aResult = SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
10188         break; // do not return because it s necessary to remove tmp faces
10189       }
10190       bool reverse[] = { false, false }; // order of notLinkNodes of quadrangle
10191       if ( nbNodes == 3 ) {
10192         //nReplaceMap.insert( TNodeNodeMap::value_type
10193         //                   ( notLinkNodes[0][0], notLinkNodes[1][0] ));
10194         nReplaceMap.insert( TNodeNodeMap::value_type
10195                             ( notLinkNodes1[0], notLinkNodes2[0] ));
10196       }
10197       else {
10198         for ( iSide = 0; iSide < 2; iSide++ ) { // loop on 2 sides
10199           // analyse link orientation in faces
10200           int i1 = iLinkNode[ iSide ][ 0 ];
10201           int i2 = iLinkNode[ iSide ][ 1 ];
10202           reverse[ iSide ] = Abs( i1 - i2 ) == 1 ? i1 > i2 : i2 > i1;
10203           // if notLinkNodes are the first and the last ones, then
10204           // their order does not correspond to the link orientation
10205           if (( i1 == 1 && i2 == 2 ) ||
10206               ( i1 == 2 && i2 == 1 ))
10207             reverse[ iSide ] = !reverse[ iSide ];
10208         }
10209         if ( reverse[0] == reverse[1] ) {
10210           //nReplaceMap.insert( TNodeNodeMap::value_type
10211           //                   ( notLinkNodes[0][0], notLinkNodes[1][0] ));
10212           //nReplaceMap.insert( TNodeNodeMap::value_type
10213           //                   ( notLinkNodes[0][1], notLinkNodes[1][1] ));
10214           for(int nn=0; nn<nbNodes-2; nn++) {
10215             nReplaceMap.insert( TNodeNodeMap::value_type
10216                                 ( notLinkNodes1[nn], notLinkNodes2[nn] ));
10217           }
10218         }
10219         else {
10220           //nReplaceMap.insert( TNodeNodeMap::value_type
10221           //                   ( notLinkNodes[0][0], notLinkNodes[1][1] ));
10222           //nReplaceMap.insert( TNodeNodeMap::value_type
10223           //                   ( notLinkNodes[0][1], notLinkNodes[1][0] ));
10224           for(int nn=0; nn<nbNodes-2; nn++) {
10225             nReplaceMap.insert( TNodeNodeMap::value_type
10226                                 ( notLinkNodes1[nn], notLinkNodes2[nbNodes-3-nn] ));
10227           }
10228         }
10229       }
10230
10231       // add other links of the faces to linkList
10232       // -----------------------------------------
10233
10234       //const SMDS_MeshNode** nodes = faceNodes[ 0 ];
10235       for ( iNode = 0; iNode < nbNodes; iNode++ )  {
10236         //linkID = aLinkID_Gen.GetLinkID( nodes[iNode], nodes[iNode+1] );
10237         linkID = aLinkID_Gen.GetLinkID( fnodes1[iNode], fnodes1[iNode+1] );
10238         pair< set<long>::iterator, bool > iter_isnew = linkIdSet.insert( linkID );
10239         if ( !iter_isnew.second ) { // already in a set: no need to process
10240           linkIdSet.erase( iter_isnew.first );
10241         }
10242         else // new in set == encountered for the first time: add
10243         {
10244           //const SMDS_MeshNode* n1 = nodes[ iNode ];
10245           //const SMDS_MeshNode* n2 = nodes[ iNode + 1];
10246           const SMDS_MeshNode* n1 = fnodes1[ iNode ];
10247           const SMDS_MeshNode* n2 = fnodes1[ iNode + 1];
10248           linkList[0].push_back ( NLink( n1, n2 ));
10249           linkList[1].push_back ( NLink( nReplaceMap[n1], nReplaceMap[n2] ));
10250         }
10251       }
10252     } // 2 faces found
10253   } // loop on link lists
10254
10255   if ( aResult == SEW_OK &&
10256        ( linkIt[0] != linkList[0].end() ||
10257          !faceSetPtr[0]->empty() || !faceSetPtr[1]->empty() )) {
10258     MESSAGE( (linkIt[0] != linkList[0].end()) <<" "<< (faceSetPtr[0]->empty()) <<
10259              " " << (faceSetPtr[1]->empty()));
10260     aResult = SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
10261   }
10262
10263   // ====================================================================
10264   // 3. Replace nodes in elements of the side 1 and remove replaced nodes
10265   // ====================================================================
10266
10267   // delete temporary faces: they are in reverseElements of actual nodes
10268 //  SMDS_FaceIteratorPtr tmpFaceIt = aTmpFacesMesh.facesIterator();
10269 //  while ( tmpFaceIt->more() )
10270 //    aTmpFacesMesh.RemoveElement( tmpFaceIt->next() );
10271 //  list<const SMDS_MeshElement* >::iterator tmpFaceIt = tempFaceList.begin();
10272 //  for (; tmpFaceIt !=tempFaceList.end(); ++tmpFaceIt)
10273 //    aMesh->RemoveElement(*tmpFaceIt);
10274
10275   if ( aResult != SEW_OK)
10276     return aResult;
10277
10278   list< int > nodeIDsToRemove/*, elemIDsToRemove*/;
10279   // loop on nodes replacement map
10280   TNodeNodeMap::iterator nReplaceMapIt = nReplaceMap.begin(), nnIt;
10281   for ( ; nReplaceMapIt != nReplaceMap.end(); nReplaceMapIt++ )
10282     if ( (*nReplaceMapIt).first != (*nReplaceMapIt).second ) {
10283       const SMDS_MeshNode* nToRemove = (*nReplaceMapIt).first;
10284       nodeIDsToRemove.push_back( nToRemove->GetID() );
10285       // loop on elements sharing nToRemove
10286       SMDS_ElemIteratorPtr invElemIt = nToRemove->GetInverseElementIterator();
10287       while ( invElemIt->more() ) {
10288         const SMDS_MeshElement* e = invElemIt->next();
10289         // get a new suite of nodes: make replacement
10290         int nbReplaced = 0, i = 0, nbNodes = e->NbNodes();
10291         vector< const SMDS_MeshNode*> nodes( nbNodes );
10292         SMDS_ElemIteratorPtr nIt = e->nodesIterator();
10293         while ( nIt->more() ) {
10294           const SMDS_MeshNode* n =
10295             static_cast<const SMDS_MeshNode*>( nIt->next() );
10296           nnIt = nReplaceMap.find( n );
10297           if ( nnIt != nReplaceMap.end() ) {
10298             nbReplaced++;
10299             n = (*nnIt).second;
10300           }
10301           nodes[ i++ ] = n;
10302         }
10303         //       if ( nbReplaced == nbNodes && e->GetType() == SMDSAbs_Face )
10304         //         elemIDsToRemove.push_back( e->GetID() );
10305         //       else
10306         if ( nbReplaced )
10307           {
10308             SMDSAbs_ElementType etyp = e->GetType();
10309             SMDS_MeshElement* newElem = this->AddElement(nodes, etyp, false);
10310             if (newElem)
10311               {
10312                 myLastCreatedElems.Append(newElem);
10313                 AddToSameGroups(newElem, e, aMesh);
10314                 int aShapeId = e->getshapeId();
10315                 if ( aShapeId )
10316                   {
10317                     aMesh->SetMeshElementOnShape( newElem, aShapeId );
10318                   }
10319               }
10320             aMesh->RemoveElement(e);
10321           }
10322       }
10323     }
10324
10325   Remove( nodeIDsToRemove, true );
10326
10327   return aResult;
10328 }
10329
10330 //================================================================================
10331 /*!
10332  * \brief Find corresponding nodes in two sets of faces
10333  * \param theSide1 - first face set
10334  * \param theSide2 - second first face
10335  * \param theFirstNode1 - a boundary node of set 1
10336  * \param theFirstNode2 - a node of set 2 corresponding to theFirstNode1
10337  * \param theSecondNode1 - a boundary node of set 1 linked with theFirstNode1
10338  * \param theSecondNode2 - a node of set 2 corresponding to theSecondNode1
10339  * \param nReplaceMap - output map of corresponding nodes
10340  * \retval bool  - is a success or not
10341  */
10342 //================================================================================
10343
10344 #ifdef _DEBUG_
10345 //#define DEBUG_MATCHING_NODES
10346 #endif
10347
10348 SMESH_MeshEditor::Sew_Error
10349 SMESH_MeshEditor::FindMatchingNodes(set<const SMDS_MeshElement*>& theSide1,
10350                                     set<const SMDS_MeshElement*>& theSide2,
10351                                     const SMDS_MeshNode*          theFirstNode1,
10352                                     const SMDS_MeshNode*          theFirstNode2,
10353                                     const SMDS_MeshNode*          theSecondNode1,
10354                                     const SMDS_MeshNode*          theSecondNode2,
10355                                     TNodeNodeMap &                nReplaceMap)
10356 {
10357   set<const SMDS_MeshElement*> * faceSetPtr[] = { &theSide1, &theSide2 };
10358
10359   nReplaceMap.clear();
10360   if ( theFirstNode1 != theFirstNode2 )
10361     nReplaceMap.insert( make_pair( theFirstNode1, theFirstNode2 ));
10362   if ( theSecondNode1 != theSecondNode2 )
10363     nReplaceMap.insert( make_pair( theSecondNode1, theSecondNode2 ));
10364
10365   set< SMESH_TLink > linkSet; // set of nodes where order of nodes is ignored
10366   linkSet.insert( SMESH_TLink( theFirstNode1, theSecondNode1 ));
10367
10368   list< NLink > linkList[2];
10369   linkList[0].push_back( NLink( theFirstNode1, theSecondNode1 ));
10370   linkList[1].push_back( NLink( theFirstNode2, theSecondNode2 ));
10371
10372   // loop on links in linkList; find faces by links and append links
10373   // of the found faces to linkList
10374   list< NLink >::iterator linkIt[] = { linkList[0].begin(), linkList[1].begin() } ;
10375   for ( ; linkIt[0] != linkList[0].end(); linkIt[0]++, linkIt[1]++ ) {
10376     NLink link[] = { *linkIt[0], *linkIt[1] };
10377     if ( linkSet.find( link[0] ) == linkSet.end() )
10378       continue;
10379
10380     // by links, find faces in the face sets,
10381     // and find indices of link nodes in the found faces;
10382     // in a face set, there is only one or no face sharing a link
10383     // ---------------------------------------------------------------
10384
10385     const SMDS_MeshElement* face[] = { 0, 0 };
10386     list<const SMDS_MeshNode*> notLinkNodes[2];
10387     //bool reverse[] = { false, false }; // order of notLinkNodes
10388     int nbNodes[2];
10389     for ( int iSide = 0; iSide < 2; iSide++ ) // loop on 2 sides
10390     {
10391       const SMDS_MeshNode* n1 = link[iSide].first;
10392       const SMDS_MeshNode* n2 = link[iSide].second;
10393       set<const SMDS_MeshElement*> * faceSet = faceSetPtr[ iSide ];
10394       set< const SMDS_MeshElement* > facesOfNode1;
10395       for ( int iNode = 0; iNode < 2; iNode++ ) // loop on 2 nodes of a link
10396       {
10397         // during a loop of the first node, we find all faces around n1,
10398         // during a loop of the second node, we find one face sharing both n1 and n2
10399         const SMDS_MeshNode* n = iNode ? n1 : n2; // a node of a link
10400         SMDS_ElemIteratorPtr fIt = n->GetInverseElementIterator(SMDSAbs_Face);
10401         while ( fIt->more() ) { // loop on faces sharing a node
10402           const SMDS_MeshElement* f = fIt->next();
10403           if (faceSet->find( f ) != faceSet->end() && // f is in face set
10404               ! facesOfNode1.insert( f ).second ) // f encounters twice
10405           {
10406             if ( face[ iSide ] ) {
10407               MESSAGE( "2 faces per link " );
10408               return ( iSide ? SEW_BAD_SIDE2_NODES : SEW_BAD_SIDE1_NODES );
10409             }
10410             face[ iSide ] = f;
10411             faceSet->erase( f );
10412
10413             // get not link nodes
10414             int nbN = f->NbNodes();
10415             if ( f->IsQuadratic() )
10416               nbN /= 2;
10417             nbNodes[ iSide ] = nbN;
10418             list< const SMDS_MeshNode* > & nodes = notLinkNodes[ iSide ];
10419             int i1 = f->GetNodeIndex( n1 );
10420             int i2 = f->GetNodeIndex( n2 );
10421             int iEnd = nbN, iBeg = -1, iDelta = 1;
10422             bool reverse = ( Abs( i1 - i2 ) == 1 ? i1 > i2 : i2 > i1 );
10423             if ( reverse ) {
10424               std::swap( iEnd, iBeg ); iDelta = -1;
10425             }
10426             int i = i2;
10427             while ( true ) {
10428               i += iDelta;
10429               if ( i == iEnd ) i = iBeg + iDelta;
10430               if ( i == i1 ) break;
10431               nodes.push_back ( f->GetNode( i ) );
10432             }
10433           }
10434         }
10435       }
10436     }
10437     // check similarity of elements of the sides
10438     if (( face[0] && !face[1] ) || ( !face[0] && face[1] )) {
10439       MESSAGE("Correspondent face not found on side " << ( face[0] ? 1 : 0 ));
10440       if ( nReplaceMap.size() == 2 ) { // faces on input nodes not found
10441         return ( face[0] ? SEW_BAD_SIDE2_NODES : SEW_BAD_SIDE1_NODES );
10442       }
10443       else {
10444         return SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
10445       }
10446     }
10447
10448     // set nodes to merge
10449     // -------------------
10450
10451     if ( face[0] && face[1] )  {
10452       if ( nbNodes[0] != nbNodes[1] ) {
10453         MESSAGE("Diff nb of face nodes");
10454         return SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
10455       }
10456 #ifdef DEBUG_MATCHING_NODES
10457       MESSAGE ( " Link 1: " << link[0].first->GetID() <<" "<< link[0].second->GetID()
10458                 << " F 1: " << face[0] << "| Link 2: " << link[1].first->GetID() <<" "
10459                 << link[1].second->GetID() << " F 2: " << face[1] << " | Bind: " ) ;
10460 #endif
10461       int nbN = nbNodes[0];
10462       {
10463         list<const SMDS_MeshNode*>::iterator n1 = notLinkNodes[0].begin();
10464         list<const SMDS_MeshNode*>::iterator n2 = notLinkNodes[1].begin();
10465         for ( int i = 0 ; i < nbN - 2; ++i ) {
10466 #ifdef DEBUG_MATCHING_NODES
10467           MESSAGE ( (*n1)->GetID() << " to " << (*n2)->GetID() );
10468 #endif
10469           nReplaceMap.insert( make_pair( *(n1++), *(n2++) ));
10470         }
10471       }
10472
10473       // add other links of the face 1 to linkList
10474       // -----------------------------------------
10475
10476       const SMDS_MeshElement* f0 = face[0];
10477       const SMDS_MeshNode* n1 = f0->GetNode( nbN - 1 );
10478       for ( int i = 0; i < nbN; i++ )
10479       {
10480         const SMDS_MeshNode* n2 = f0->GetNode( i );
10481         pair< set< SMESH_TLink >::iterator, bool > iter_isnew =
10482           linkSet.insert( SMESH_TLink( n1, n2 ));
10483         if ( !iter_isnew.second ) { // already in a set: no need to process
10484           linkSet.erase( iter_isnew.first );
10485         }
10486         else // new in set == encountered for the first time: add
10487         {
10488 #ifdef DEBUG_MATCHING_NODES
10489           MESSAGE ( "Add link 1: " << n1->GetID() << " " << n2->GetID() << " "
10490                     << " | link 2: " << nReplaceMap[n1]->GetID() << " " << nReplaceMap[n2]->GetID() << " " );
10491 #endif
10492           linkList[0].push_back ( NLink( n1, n2 ));
10493           linkList[1].push_back ( NLink( nReplaceMap[n1], nReplaceMap[n2] ));
10494         }
10495         n1 = n2;
10496       }
10497     } // 2 faces found
10498   } // loop on link lists
10499
10500   return SEW_OK;
10501 }
10502
10503 //================================================================================
10504 /*!
10505   \brief Creates a hole in a mesh by doubling the nodes of some particular elements
10506   \param theElems - the list of elements (edges or faces) to be replicated
10507   The nodes for duplication could be found from these elements
10508   \param theNodesNot - list of nodes to NOT replicate
10509   \param theAffectedElems - the list of elements (cells and edges) to which the 
10510   replicated nodes should be associated to.
10511   \return TRUE if operation has been completed successfully, FALSE otherwise
10512 */
10513 //================================================================================
10514
10515 bool SMESH_MeshEditor::DoubleNodes( const TIDSortedElemSet& theElems,
10516                                     const TIDSortedElemSet& theNodesNot,
10517                                     const TIDSortedElemSet& theAffectedElems )
10518 {
10519   myLastCreatedElems.Clear();
10520   myLastCreatedNodes.Clear();
10521
10522   if ( theElems.size() == 0 )
10523     return false;
10524
10525   SMESHDS_Mesh* aMeshDS = GetMeshDS();
10526   if ( !aMeshDS )
10527     return false;
10528
10529   bool res = false;
10530   std::map< const SMDS_MeshNode*, const SMDS_MeshNode* > anOldNodeToNewNode;
10531   // duplicate elements and nodes
10532   res = doubleNodes( aMeshDS, theElems, theNodesNot, anOldNodeToNewNode, true );
10533   // replce nodes by duplications
10534   res = doubleNodes( aMeshDS, theAffectedElems, theNodesNot, anOldNodeToNewNode, false );
10535   return res;
10536 }
10537
10538 //================================================================================
10539 /*!
10540   \brief Creates a hole in a mesh by doubling the nodes of some particular elements
10541   \param theMeshDS - mesh instance
10542   \param theElems - the elements replicated or modified (nodes should be changed)
10543   \param theNodesNot - nodes to NOT replicate
10544   \param theNodeNodeMap - relation of old node to new created node
10545   \param theIsDoubleElem - flag os to replicate element or modify
10546   \return TRUE if operation has been completed successfully, FALSE otherwise
10547 */
10548 //================================================================================
10549
10550 bool SMESH_MeshEditor::doubleNodes( SMESHDS_Mesh*     theMeshDS,
10551                                     const TIDSortedElemSet& theElems,
10552                                     const TIDSortedElemSet& theNodesNot,
10553                                     std::map< const SMDS_MeshNode*,
10554                                     const SMDS_MeshNode* >& theNodeNodeMap,
10555                                     const bool theIsDoubleElem )
10556 {
10557   MESSAGE("doubleNodes");
10558   // iterate on through element and duplicate them (by nodes duplication)
10559   bool res = false;
10560   TIDSortedElemSet::const_iterator elemItr = theElems.begin();
10561   for ( ;  elemItr != theElems.end(); ++elemItr )
10562   {
10563     const SMDS_MeshElement* anElem = *elemItr;
10564     if (!anElem)
10565       continue;
10566
10567     bool isDuplicate = false;
10568     // duplicate nodes to duplicate element
10569     std::vector<const SMDS_MeshNode*> newNodes( anElem->NbNodes() );
10570     SMDS_ElemIteratorPtr anIter = anElem->nodesIterator();
10571     int ind = 0;
10572     while ( anIter->more() ) 
10573     { 
10574
10575       SMDS_MeshNode* aCurrNode = (SMDS_MeshNode*)anIter->next();
10576       SMDS_MeshNode* aNewNode = aCurrNode;
10577       if ( theNodeNodeMap.find( aCurrNode ) != theNodeNodeMap.end() )
10578         aNewNode = (SMDS_MeshNode*)theNodeNodeMap[ aCurrNode ];
10579       else if ( theIsDoubleElem && theNodesNot.find( aCurrNode ) == theNodesNot.end() )
10580       {
10581         // duplicate node
10582         aNewNode = theMeshDS->AddNode( aCurrNode->X(), aCurrNode->Y(), aCurrNode->Z() );
10583         theNodeNodeMap[ aCurrNode ] = aNewNode;
10584         myLastCreatedNodes.Append( aNewNode );
10585       }
10586       isDuplicate |= (aCurrNode != aNewNode);
10587       newNodes[ ind++ ] = aNewNode;
10588     }
10589     if ( !isDuplicate )
10590       continue;
10591
10592     if ( theIsDoubleElem )
10593       AddElement(newNodes, anElem->GetType(), anElem->IsPoly());
10594     else
10595       {
10596       MESSAGE("ChangeElementNodes");
10597       theMeshDS->ChangeElementNodes( anElem, &newNodes[ 0 ], anElem->NbNodes() );
10598       }
10599     res = true;
10600   }
10601   return res;
10602 }
10603
10604 //================================================================================
10605 /*!
10606   \brief Creates a hole in a mesh by doubling the nodes of some particular elements
10607   \param theNodes - identifiers of nodes to be doubled
10608   \param theModifiedElems - identifiers of elements to be updated by the new (doubled) 
10609          nodes. If list of element identifiers is empty then nodes are doubled but 
10610          they not assigned to elements
10611   \return TRUE if operation has been completed successfully, FALSE otherwise
10612 */
10613 //================================================================================
10614
10615 bool SMESH_MeshEditor::DoubleNodes( const std::list< int >& theListOfNodes, 
10616                                     const std::list< int >& theListOfModifiedElems )
10617 {
10618   MESSAGE("DoubleNodes");
10619   myLastCreatedElems.Clear();
10620   myLastCreatedNodes.Clear();
10621
10622   if ( theListOfNodes.size() == 0 )
10623     return false;
10624
10625   SMESHDS_Mesh* aMeshDS = GetMeshDS();
10626   if ( !aMeshDS )
10627     return false;
10628
10629   // iterate through nodes and duplicate them
10630
10631   std::map< const SMDS_MeshNode*, const SMDS_MeshNode* > anOldNodeToNewNode;
10632
10633   std::list< int >::const_iterator aNodeIter;
10634   for ( aNodeIter = theListOfNodes.begin(); aNodeIter != theListOfNodes.end(); ++aNodeIter )
10635   {
10636     int aCurr = *aNodeIter;
10637     SMDS_MeshNode* aNode = (SMDS_MeshNode*)aMeshDS->FindNode( aCurr );
10638     if ( !aNode )
10639       continue;
10640
10641     // duplicate node
10642
10643     const SMDS_MeshNode* aNewNode = aMeshDS->AddNode( aNode->X(), aNode->Y(), aNode->Z() );
10644     if ( aNewNode )
10645     {
10646       anOldNodeToNewNode[ aNode ] = aNewNode;
10647       myLastCreatedNodes.Append( aNewNode );
10648     }
10649   }
10650
10651   // Create map of new nodes for modified elements
10652
10653   std::map< SMDS_MeshElement*, vector<const SMDS_MeshNode*> > anElemToNodes;
10654
10655   std::list< int >::const_iterator anElemIter;
10656   for ( anElemIter = theListOfModifiedElems.begin(); 
10657         anElemIter != theListOfModifiedElems.end(); ++anElemIter )
10658   {
10659     int aCurr = *anElemIter;
10660     SMDS_MeshElement* anElem = (SMDS_MeshElement*)aMeshDS->FindElement( aCurr );
10661     if ( !anElem )
10662       continue;
10663
10664     vector<const SMDS_MeshNode*> aNodeArr( anElem->NbNodes() );
10665
10666     SMDS_ElemIteratorPtr anIter = anElem->nodesIterator();
10667     int ind = 0;
10668     while ( anIter->more() ) 
10669     { 
10670       SMDS_MeshNode* aCurrNode = (SMDS_MeshNode*)anIter->next();
10671       if ( aCurr && anOldNodeToNewNode.find( aCurrNode ) != anOldNodeToNewNode.end() )
10672       {
10673         const SMDS_MeshNode* aNewNode = anOldNodeToNewNode[ aCurrNode ];
10674         aNodeArr[ ind++ ] = aNewNode;
10675       }
10676       else
10677         aNodeArr[ ind++ ] = aCurrNode;
10678     }
10679     anElemToNodes[ anElem ] = aNodeArr;
10680   }
10681
10682   // Change nodes of elements  
10683
10684   std::map< SMDS_MeshElement*, vector<const SMDS_MeshNode*> >::iterator
10685     anElemToNodesIter = anElemToNodes.begin();
10686   for ( ; anElemToNodesIter != anElemToNodes.end(); ++anElemToNodesIter )
10687   {
10688     const SMDS_MeshElement* anElem = anElemToNodesIter->first;
10689     vector<const SMDS_MeshNode*> aNodeArr = anElemToNodesIter->second;
10690     if ( anElem )
10691       {
10692       MESSAGE("ChangeElementNodes");
10693       aMeshDS->ChangeElementNodes( anElem, &aNodeArr[ 0 ], anElem->NbNodes() );
10694       }
10695   }
10696
10697   return true;
10698 }
10699
10700 namespace {
10701
10702   //================================================================================
10703   /*!
10704   \brief Check if element located inside shape
10705   \return TRUE if IN or ON shape, FALSE otherwise
10706   */
10707   //================================================================================
10708
10709   template<class Classifier>
10710   bool isInside(const SMDS_MeshElement* theElem,
10711                 Classifier&             theClassifier,
10712                 const double            theTol)
10713   {
10714     gp_XYZ centerXYZ (0, 0, 0);
10715     SMDS_ElemIteratorPtr aNodeItr = theElem->nodesIterator();
10716     while (aNodeItr->more())
10717       centerXYZ += SMESH_TNodeXYZ(cast2Node( aNodeItr->next()));
10718
10719     gp_Pnt aPnt = centerXYZ / theElem->NbNodes();
10720     theClassifier.Perform(aPnt, theTol);
10721     TopAbs_State aState = theClassifier.State();
10722     return (aState == TopAbs_IN || aState == TopAbs_ON );
10723   }
10724
10725   //================================================================================
10726   /*!
10727    * \brief Classifier of the 3D point on the TopoDS_Face
10728    *        with interaface suitable for isInside()
10729    */
10730   //================================================================================
10731
10732   struct _FaceClassifier
10733   {
10734     Extrema_ExtPS       _extremum;
10735     BRepAdaptor_Surface _surface;
10736     TopAbs_State        _state;
10737
10738     _FaceClassifier(const TopoDS_Face& face):_extremum(),_surface(face),_state(TopAbs_OUT)
10739     {
10740       _extremum.Initialize( _surface,
10741                             _surface.FirstUParameter(), _surface.LastUParameter(),
10742                             _surface.FirstVParameter(), _surface.LastVParameter(),
10743                             _surface.Tolerance(), _surface.Tolerance() );
10744     }
10745     void Perform(const gp_Pnt& aPnt, double theTol)
10746     {
10747       _state = TopAbs_OUT;
10748       _extremum.Perform(aPnt);
10749       if ( _extremum.IsDone() )
10750         for ( int iSol = 1; iSol <= _extremum.NbExt() && _state == TopAbs_OUT; ++iSol)
10751           _state = ( _extremum.Value(iSol) <= theTol ? TopAbs_IN : TopAbs_OUT );
10752     }
10753     TopAbs_State State() const
10754     {
10755       return _state;
10756     }
10757   };
10758 }
10759
10760 //================================================================================
10761 /*!
10762   \brief Creates a hole in a mesh by doubling the nodes of some particular elements
10763   \param theElems - group of of elements (edges or faces) to be replicated
10764   \param theNodesNot - group of nodes not to replicate
10765   \param theShape - shape to detect affected elements (element which geometric center
10766   located on or inside shape).
10767   The replicated nodes should be associated to affected elements.
10768   \return TRUE if operation has been completed successfully, FALSE otherwise
10769 */
10770 //================================================================================
10771
10772 bool SMESH_MeshEditor::DoubleNodesInRegion( const TIDSortedElemSet& theElems,
10773                                             const TIDSortedElemSet& theNodesNot,
10774                                             const TopoDS_Shape&     theShape )
10775 {
10776   if ( theShape.IsNull() )
10777     return false;
10778
10779   const double aTol = Precision::Confusion();
10780   auto_ptr< BRepClass3d_SolidClassifier> bsc3d;
10781   auto_ptr<_FaceClassifier>              aFaceClassifier;
10782   if ( theShape.ShapeType() == TopAbs_SOLID )
10783   {
10784     bsc3d.reset( new BRepClass3d_SolidClassifier(theShape));;
10785     bsc3d->PerformInfinitePoint(aTol);
10786   }
10787   else if (theShape.ShapeType() == TopAbs_FACE )
10788   {
10789     aFaceClassifier.reset( new _FaceClassifier(TopoDS::Face(theShape)));
10790   }
10791
10792   // iterates on indicated elements and get elements by back references from their nodes
10793   TIDSortedElemSet anAffected;
10794   TIDSortedElemSet::const_iterator elemItr = theElems.begin();
10795   for ( ;  elemItr != theElems.end(); ++elemItr )
10796   {
10797     SMDS_MeshElement* anElem = (SMDS_MeshElement*)*elemItr;
10798     if (!anElem)
10799       continue;
10800
10801     SMDS_ElemIteratorPtr nodeItr = anElem->nodesIterator();
10802     while ( nodeItr->more() )
10803     {
10804       const SMDS_MeshNode* aNode = cast2Node(nodeItr->next());
10805       if ( !aNode || theNodesNot.find(aNode) != theNodesNot.end() )
10806         continue;
10807       SMDS_ElemIteratorPtr backElemItr = aNode->GetInverseElementIterator();
10808       while ( backElemItr->more() )
10809       {
10810         const SMDS_MeshElement* curElem = backElemItr->next();
10811         if ( curElem && theElems.find(curElem) == theElems.end() &&
10812              ( bsc3d.get() ?
10813                isInside( curElem, *bsc3d, aTol ) :
10814                isInside( curElem, *aFaceClassifier, aTol )))
10815           anAffected.insert( curElem );
10816       }
10817     }
10818   }
10819   return DoubleNodes( theElems, theNodesNot, anAffected );
10820 }
10821
10822 /*!
10823  *  \brief compute an oriented angle between two planes defined by four points.
10824  *  The vector (p0,p1) defines the intersection of the 2 planes (p0,p1,g1) and (p0,p1,g2)
10825  *  @param p0 base of the rotation axe
10826  *  @param p1 extremity of the rotation axe
10827  *  @param g1 belongs to the first plane
10828  *  @param g2 belongs to the second plane
10829  */
10830 double SMESH_MeshEditor::OrientedAngle(const gp_Pnt& p0, const gp_Pnt& p1, const gp_Pnt& g1, const gp_Pnt& g2)
10831 {
10832 //  MESSAGE("    p0: " << p0.X() << " " << p0.Y() << " " << p0.Z());
10833 //  MESSAGE("    p1: " << p1.X() << " " << p1.Y() << " " << p1.Z());
10834 //  MESSAGE("    g1: " << g1.X() << " " << g1.Y() << " " << g1.Z());
10835 //  MESSAGE("    g2: " << g2.X() << " " << g2.Y() << " " << g2.Z());
10836   gp_Vec vref(p0, p1);
10837   gp_Vec v1(p0, g1);
10838   gp_Vec v2(p0, g2);
10839   gp_Vec n1 = vref.Crossed(v1);
10840   gp_Vec n2 = vref.Crossed(v2);
10841   return n2.AngleWithRef(n1, vref);
10842 }
10843
10844 /*!
10845  * \brief Double nodes on shared faces between groups of volumes and create flat elements on demand.
10846  * The list of groups must describe a partition of the mesh volumes.
10847  * The nodes of the internal faces at the boundaries of the groups are doubled.
10848  * In option, the internal faces are replaced by flat elements.
10849  * Triangles are transformed in prisms, and quadrangles in hexahedrons.
10850  * @param theElems - list of groups of volumes, where a group of volume is a set of
10851  * SMDS_MeshElements sorted by Id.
10852  * @param createJointElems - if TRUE, create the elements
10853  * @return TRUE if operation has been completed successfully, FALSE otherwise
10854  */
10855 bool SMESH_MeshEditor::DoubleNodesOnGroupBoundaries( const std::vector<TIDSortedElemSet>& theElems,
10856                                                      bool createJointElems)
10857 {
10858   MESSAGE("----------------------------------------------");
10859   MESSAGE("SMESH_MeshEditor::doubleNodesOnGroupBoundaries");
10860   MESSAGE("----------------------------------------------");
10861
10862   SMESHDS_Mesh *meshDS = this->myMesh->GetMeshDS();
10863   meshDS->BuildDownWardConnectivity(false);
10864   CHRONO(50);
10865   SMDS_UnstructuredGrid *grid = meshDS->getGrid();
10866
10867   // --- build the list of faces shared by 2 domains (group of elements), with their domain and volume indexes
10868   //     build the list of cells with only a node or an edge on the border, with their domain and volume indexes
10869   //     build the list of nodes shared by 2 or more domains, with their domain indexes
10870
10871   std::map<DownIdType, std::map<int,int>, DownIdCompare> faceDomains; // face --> (id domain --> id volume)
10872   std::map<int,int>celldom; // cell vtkId --> domain
10873   std::map<DownIdType, std::map<int,int>, DownIdCompare> cellDomains;  // oldNode --> (id domain --> id cell)
10874   std::map<int, std::map<int,int> > nodeDomains; // oldId -->  (domainId --> newId)
10875   faceDomains.clear();
10876   celldom.clear();
10877   cellDomains.clear();
10878   nodeDomains.clear();
10879   std::map<int,int> emptyMap;
10880   std::set<int> emptySet;
10881   emptyMap.clear();
10882
10883   for (int idom = 0; idom < theElems.size(); idom++)
10884     {
10885
10886       // --- build a map (face to duplicate --> volume to modify)
10887       //     with all the faces shared by 2 domains (group of elements)
10888       //     and corresponding volume of this domain, for each shared face.
10889       //     a volume has a face shared by 2 domains if it has a neighbor which is not in is domain.
10890
10891       const TIDSortedElemSet& domain = theElems[idom];
10892       TIDSortedElemSet::const_iterator elemItr = domain.begin();
10893       for (; elemItr != domain.end(); ++elemItr)
10894         {
10895           SMDS_MeshElement* anElem = (SMDS_MeshElement*) *elemItr;
10896           if (!anElem)
10897             continue;
10898           int vtkId = anElem->getVtkId();
10899           int neighborsVtkIds[NBMAXNEIGHBORS];
10900           int downIds[NBMAXNEIGHBORS];
10901           unsigned char downTypes[NBMAXNEIGHBORS];
10902           int nbNeighbors = grid->GetNeighbors(neighborsVtkIds, downIds, downTypes, vtkId);
10903           for (int n = 0; n < nbNeighbors; n++)
10904             {
10905               int smdsId = meshDS->fromVtkToSmds(neighborsVtkIds[n]);
10906               const SMDS_MeshElement* elem = meshDS->FindElement(smdsId);
10907               if (! domain.count(elem)) // neighbor is in another domain : face is shared
10908                 {
10909                   DownIdType face(downIds[n], downTypes[n]);
10910                   if (!faceDomains.count(face))
10911                     faceDomains[face] = emptyMap; // create an empty entry for face
10912                   if (!faceDomains[face].count(idom))
10913                     {
10914                       faceDomains[face][idom] = vtkId; // volume associated to face in this domain
10915                       celldom[vtkId] = idom;
10916                     }
10917                 }
10918             }
10919         }
10920     }
10921
10922   //MESSAGE("Number of shared faces " << faceDomains.size());
10923   std::map<DownIdType, std::map<int, int>, DownIdCompare>::iterator itface;
10924
10925   // --- explore the shared faces domain by domain,
10926   //     explore the nodes of the face and see if they belong to a cell in the domain,
10927   //     which has only a node or an edge on the border (not a shared face)
10928
10929   for (int idomain = 0; idomain < theElems.size(); idomain++)
10930     {
10931       const TIDSortedElemSet& domain = theElems[idomain];
10932       itface = faceDomains.begin();
10933       for (; itface != faceDomains.end(); ++itface)
10934         {
10935           std::map<int, int> domvol = itface->second;
10936           if (!domvol.count(idomain))
10937             continue;
10938           DownIdType face = itface->first;
10939           //MESSAGE(" --- face " << face.cellId);
10940           std::set<int> oldNodes;
10941           oldNodes.clear();
10942           grid->GetNodeIds(oldNodes, face.cellId, face.cellType);
10943           std::set<int>::iterator itn = oldNodes.begin();
10944           for (; itn != oldNodes.end(); ++itn)
10945             {
10946               int oldId = *itn;
10947               //MESSAGE("     node " << oldId);
10948               std::set<int> cells;
10949               cells.clear();
10950               vtkCellLinks::Link l = grid->GetCellLinks()->GetLink(oldId);
10951               for (int i=0; i<l.ncells; i++)
10952                 {
10953                   int vtkId = l.cells[i];
10954                   const SMDS_MeshElement* anElem = GetMeshDS()->FindElement(GetMeshDS()->fromVtkToSmds(vtkId));
10955                   if (!domain.count(anElem))
10956                     continue;
10957                   int vtkType = grid->GetCellType(vtkId);
10958                   int downId = grid->CellIdToDownId(vtkId);
10959                   DownIdType aCell(downId, vtkType);
10960                   if (celldom.count(vtkId))
10961                     continue;
10962                   cellDomains[aCell][idomain] = vtkId;
10963                   celldom[vtkId] = idomain;
10964                 }
10965             }
10966         }
10967     }
10968
10969   // --- explore the shared faces domain by domain, to duplicate the nodes in a coherent way
10970   //     for each shared face, get the nodes
10971   //     for each node, for each domain of the face, create a clone of the node
10972
10973   // --- edges at the intersection of 3 or 4 domains, with the order of domains to build
10974   //     junction elements of type prism or hexa. the key is the pair of nodesId (lower first)
10975   //     the value is the ordered domain ids. (more than 4 domains not taken into account)
10976
10977   std::map<std::vector<int>, std::vector<int> > edgesMultiDomains; // nodes of edge --> ordered domains
10978   std::map<int, std::vector<int> > mutipleNodes; // nodes muti domains with domain order
10979
10980   for (int idomain = 0; idomain < theElems.size(); idomain++)
10981     {
10982       itface = faceDomains.begin();
10983       for (; itface != faceDomains.end(); ++itface)
10984         {
10985           std::map<int, int> domvol = itface->second;
10986           if (!domvol.count(idomain))
10987             continue;
10988           DownIdType face = itface->first;
10989           //MESSAGE(" --- face " << face.cellId);
10990           std::set<int> oldNodes;
10991           oldNodes.clear();
10992           grid->GetNodeIds(oldNodes, face.cellId, face.cellType);
10993           bool isMultipleDetected = false;
10994           std::set<int>::iterator itn = oldNodes.begin();
10995           for (; itn != oldNodes.end(); ++itn)
10996             {
10997               int oldId = *itn;
10998               //MESSAGE("     node " << oldId);
10999               if (!nodeDomains.count(oldId))
11000                 nodeDomains[oldId] = emptyMap; // create an empty entry for node
11001               if (nodeDomains[oldId].empty())
11002                 nodeDomains[oldId][idomain] = oldId; // keep the old node in the first domain
11003               std::map<int, int>::iterator itdom = domvol.begin();
11004               for (; itdom != domvol.end(); ++itdom)
11005                 {
11006                   int idom = itdom->first;
11007                   //MESSAGE("         domain " << idom);
11008                   if (!nodeDomains[oldId].count(idom)) // --- node to clone
11009                     {
11010                       if (nodeDomains[oldId].size() >= 2) // a multiple node
11011                         {
11012                           vector<int> orderedDoms;
11013                           //MESSAGE("multiple node " << oldId);
11014                           isMultipleDetected =true;
11015                           if (mutipleNodes.count(oldId))
11016                             orderedDoms = mutipleNodes[oldId];
11017                           else
11018                             {
11019                               map<int,int>::iterator it = nodeDomains[oldId].begin();
11020                               for (; it != nodeDomains[oldId].end(); ++it)
11021                                 orderedDoms.push_back(it->first);
11022                             }
11023                           orderedDoms.push_back(idom); // TODO order ==> push_front or back
11024                           //stringstream txt;
11025                           //for (int i=0; i<orderedDoms.size(); i++)
11026                           //  txt << orderedDoms[i] << " ";
11027                           //MESSAGE("orderedDoms " << txt.str());
11028                           mutipleNodes[oldId] = orderedDoms;
11029                         }
11030                       double *coords = grid->GetPoint(oldId);
11031                       SMDS_MeshNode *newNode = meshDS->AddNode(coords[0], coords[1], coords[2]);
11032                       int newId = newNode->getVtkId();
11033                       nodeDomains[oldId][idom] = newId; // cloned node for other domains
11034                       //MESSAGE("   newNode " << newId << " oldNode " << oldId << " size=" <<nodeDomains[oldId].size());
11035                     }
11036                 }
11037             }
11038           if (isMultipleDetected) // check if an edge of the face is shared between 3 or more domains
11039             {
11040               //MESSAGE("multiple Nodes detected on a shared face");
11041               int downId = itface->first.cellId;
11042               unsigned char cellType = itface->first.cellType;
11043               int nbEdges = grid->getDownArray(cellType)->getNumberOfDownCells(downId);
11044               const int *downEdgeIds = grid->getDownArray(cellType)->getDownCells(downId);
11045               const unsigned char* edgeType = grid->getDownArray(cellType)->getDownTypes(downId);
11046               for (int ie =0; ie < nbEdges; ie++)
11047                 {
11048                   int nodes[3];
11049                   int nbNodes = grid->getDownArray(edgeType[ie])->getNodes(downEdgeIds[ie], nodes);
11050                   if (mutipleNodes.count(nodes[0]) && mutipleNodes.count(nodes[nbNodes-1]))
11051                     {
11052                       vector<int> vn0 = mutipleNodes[nodes[0]];
11053                       vector<int> vn1 = mutipleNodes[nodes[nbNodes - 1]];
11054                       sort( vn0.begin(), vn0.end() );
11055                       sort( vn1.begin(), vn1.end() );
11056                       if (vn0 == vn1)
11057                         {
11058                           //MESSAGE(" detect edgesMultiDomains " << nodes[0] << " " << nodes[nbNodes - 1]);
11059                           double *coords = grid->GetPoint(nodes[0]);
11060                           gp_Pnt p0(coords[0], coords[1], coords[2]);
11061                           coords = grid->GetPoint(nodes[nbNodes - 1]);
11062                           gp_Pnt p1(coords[0], coords[1], coords[2]);
11063                           gp_Pnt gref;
11064                           int vtkVolIds[1000];  // an edge can belong to a lot of volumes
11065                           map<int, SMDS_VtkVolume*> domvol; // domain --> a volume with the edge
11066                           map<int, double> angleDom; // oriented angles between planes defined by edge and volume centers
11067                           int nbvol = grid->GetParentVolumes(vtkVolIds, downEdgeIds[ie], edgeType[ie]);
11068                           for (int id=0; id < vn0.size(); id++)
11069                             {
11070                               int idom = vn0[id];
11071                               for (int ivol=0; ivol<nbvol; ivol++)
11072                                 {
11073                                   int smdsId = meshDS->fromVtkToSmds(vtkVolIds[ivol]);
11074                                   SMDS_MeshElement* elem = (SMDS_MeshElement*)meshDS->FindElement(smdsId);
11075                                   if (theElems[idom].count(elem))
11076                                     {
11077                                       SMDS_VtkVolume* svol = dynamic_cast<SMDS_VtkVolume*>(elem);
11078                                       domvol[idom] = svol;
11079                                       //MESSAGE("  domain " << idom << " volume " << elem->GetID());
11080                                       double values[3];
11081                                       vtkIdType npts = 0;
11082                                       vtkIdType* pts = 0;
11083                                       grid->GetCellPoints(vtkVolIds[ivol], npts, pts);
11084                                       SMDS_VtkVolume::gravityCenter(grid, pts, npts, values);
11085                                       if (id ==0)
11086                                         {
11087                                           gref.SetXYZ(gp_XYZ(values[0], values[1], values[2]));
11088                                           angleDom[idom] = 0;
11089                                         }
11090                                       else
11091                                         {
11092                                           gp_Pnt g(values[0], values[1], values[2]);
11093                                           angleDom[idom] = OrientedAngle(p0, p1, gref, g); // -pi<angle<+pi
11094                                           //MESSAGE("  angle=" << angleDom[idom]);
11095                                         }
11096                                       break;
11097                                     }
11098                                 }
11099                             }
11100                           map<double, int> sortedDom; // sort domains by angle
11101                           for (map<int, double>::iterator ia = angleDom.begin(); ia != angleDom.end(); ++ia)
11102                             sortedDom[ia->second] = ia->first;
11103                           vector<int> vnodes;
11104                           vector<int> vdom;
11105                           for (map<double, int>::iterator ib = sortedDom.begin(); ib != sortedDom.end(); ++ib)
11106                             {
11107                               vdom.push_back(ib->second);
11108                               //MESSAGE("  ordered domain " << ib->second << "  angle " << ib->first);
11109                             }
11110                           for (int ino = 0; ino < nbNodes; ino++)
11111                             vnodes.push_back(nodes[ino]);
11112                           edgesMultiDomains[vnodes] = vdom; // nodes vector --> ordered domains
11113                         }
11114                     }
11115                 }
11116             }
11117         }
11118     }
11119
11120   // --- iterate on shared faces (volumes to modify, face to extrude)
11121   //     get node id's of the face (id SMDS = id VTK)
11122   //     create flat element with old and new nodes if requested
11123
11124   // --- new quad nodes on flat quad elements: oldId --> ((domain1 X domain2) --> newId)
11125   //     (domain1 X domain2) = domain1 + MAXINT*domain2
11126
11127   std::map<int, std::map<long,int> > nodeQuadDomains;
11128
11129   if (createJointElems)
11130     {
11131       itface = faceDomains.begin();
11132       for( ; itface != faceDomains.end();++itface )
11133         {
11134           DownIdType face = itface->first;
11135           std::set<int> oldNodes;
11136           std::set<int>::iterator itn;
11137           oldNodes.clear();
11138           grid->GetNodeIds(oldNodes, face.cellId, face.cellType);
11139
11140           std::map<int,int> domvol = itface->second;
11141           std::map<int,int>::iterator itdom = domvol.begin();
11142           int dom1 = itdom->first;
11143           int vtkVolId = itdom->second;
11144           itdom++;
11145           int dom2 = itdom->first;
11146           grid->extrudeVolumeFromFace(vtkVolId, dom1, dom2, oldNodes, nodeDomains, nodeQuadDomains);
11147         }
11148     }
11149
11150   // --- create volumes on multiple domain intersection if requested
11151   //     iterate on edgesMultiDomains
11152
11153   if (createJointElems)
11154     {
11155       std::map<std::vector<int>, std::vector<int> >::iterator ite = edgesMultiDomains.begin();
11156       for (; ite != edgesMultiDomains.end(); ++ite)
11157         {
11158           vector<int> nodes = ite->first;
11159           vector<int> orderDom = ite->second;
11160           vector<vtkIdType> orderedNodes;
11161           if (nodes.size() == 2)
11162             {
11163               //MESSAGE(" use edgesMultiDomains " << nodes[0] << " " << nodes[1]);
11164               for (int ino=0; ino < nodes.size(); ino++)
11165                 if (orderDom.size() == 3)
11166                   for (int idom = 0; idom <orderDom.size(); idom++)
11167                     orderedNodes.push_back( nodeDomains[nodes[ino]][orderDom[idom]] );
11168                 else
11169                   for (int idom = orderDom.size()-1; idom >=0; idom--)
11170                     orderedNodes.push_back( nodeDomains[nodes[ino]][orderDom[idom]] );
11171               this->GetMeshDS()->AddVolumeFromVtkIds(orderedNodes);
11172             }
11173           else
11174             {
11175               // TODO quadratic nodes
11176             }
11177         }
11178     }
11179
11180   // --- list the explicit faces and edges of the mesh that need to be modified,
11181   //     i.e. faces and edges built with one or more duplicated nodes.
11182   //     associate these faces or edges to their corresponding domain.
11183   //     only the first domain found is kept when a face or edge is shared
11184
11185   std::map<DownIdType, std::map<int,int>, DownIdCompare> faceOrEdgeDom; // cellToModify --> (id domain --> id cell)
11186   std::map<int,int> feDom; // vtk id of cell to modify --> id domain
11187   faceOrEdgeDom.clear();
11188   feDom.clear();
11189
11190   for (int idomain = 0; idomain < theElems.size(); idomain++)
11191     {
11192       std::map<int, std::map<int, int> >::const_iterator itnod = nodeDomains.begin();
11193       for (; itnod != nodeDomains.end(); ++itnod)
11194         {
11195           int oldId = itnod->first;
11196           //MESSAGE("     node " << oldId);
11197           vtkCellLinks::Link l = grid->GetCellLinks()->GetLink(oldId);
11198           for (int i = 0; i < l.ncells; i++)
11199             {
11200               int vtkId = l.cells[i];
11201               int vtkType = grid->GetCellType(vtkId);
11202               int downId = grid->CellIdToDownId(vtkId);
11203               DownIdType aCell(downId, vtkType);
11204               int volParents[1000];
11205               int nbvol = grid->GetParentVolumes(volParents, vtkId);
11206               for (int j = 0; j < nbvol; j++)
11207                 if (celldom.count(volParents[j]) && (celldom[volParents[j]] == idomain))
11208                   if (!feDom.count(vtkId))
11209                     {
11210                       feDom[vtkId] = idomain;
11211                       faceOrEdgeDom[aCell] = emptyMap;
11212                       faceOrEdgeDom[aCell][idomain] = vtkId; // affect face or edge to the first domain only
11213                       //MESSAGE("affect cell " << this->GetMeshDS()->fromVtkToSmds(vtkId) << " domain " << idomain
11214                       //        << " type " << vtkType << " downId " << downId);
11215                     }
11216             }
11217         }
11218     }
11219
11220   // --- iterate on shared faces (volumes to modify, face to extrude)
11221   //     get node id's of the face
11222   //     replace old nodes by new nodes in volumes, and update inverse connectivity
11223
11224   std::map<DownIdType, std::map<int,int>, DownIdCompare>* maps[3] = {&faceDomains, &cellDomains, &faceOrEdgeDom};
11225   for (int m=0; m<3; m++)
11226     {
11227       std::map<DownIdType, std::map<int,int>, DownIdCompare>* amap = maps[m];
11228       itface = (*amap).begin();
11229       for (; itface != (*amap).end(); ++itface)
11230         {
11231           DownIdType face = itface->first;
11232           std::set<int> oldNodes;
11233           std::set<int>::iterator itn;
11234           oldNodes.clear();
11235           grid->GetNodeIds(oldNodes, face.cellId, face.cellType);
11236           //MESSAGE("examine cell, downId " << face.cellId << " type " << int(face.cellType));
11237           std::map<int, int> localClonedNodeIds;
11238
11239           std::map<int, int> domvol = itface->second;
11240           std::map<int, int>::iterator itdom = domvol.begin();
11241           for (; itdom != domvol.end(); ++itdom)
11242             {
11243               int idom = itdom->first;
11244               int vtkVolId = itdom->second;
11245               //MESSAGE("modify nodes of cell " << this->GetMeshDS()->fromVtkToSmds(vtkVolId) << " domain " << idom);
11246               localClonedNodeIds.clear();
11247               for (itn = oldNodes.begin(); itn != oldNodes.end(); ++itn)
11248                 {
11249                   int oldId = *itn;
11250                   if (nodeDomains[oldId].count(idom))
11251                     {
11252                       localClonedNodeIds[oldId] = nodeDomains[oldId][idom];
11253                       //MESSAGE("     node " << oldId << " --> " << localClonedNodeIds[oldId]);
11254                     }
11255                 }
11256               meshDS->ModifyCellNodes(vtkVolId, localClonedNodeIds);
11257             }
11258         }
11259     }
11260
11261   grid->BuildLinks();
11262
11263   CHRONOSTOP(50);
11264   counters::stats();
11265   return true;
11266 }
11267
11268 //================================================================================
11269 /*!
11270  * \brief Generates skin mesh (containing 2D cells) from 3D mesh
11271  * The created 2D mesh elements based on nodes of free faces of boundary volumes
11272  * \return TRUE if operation has been completed successfully, FALSE otherwise
11273  */
11274 //================================================================================
11275
11276 bool SMESH_MeshEditor::Make2DMeshFrom3D()
11277 {
11278   // iterates on volume elements and detect all free faces on them
11279   SMESHDS_Mesh* aMesh = GetMeshDS();
11280   if (!aMesh)
11281     return false;
11282   //bool res = false;
11283   int nbFree = 0, nbExisted = 0, nbCreated = 0;
11284   SMDS_VolumeIteratorPtr vIt = aMesh->volumesIterator();
11285   while(vIt->more())
11286   {
11287     const SMDS_MeshVolume* volume = vIt->next();
11288     SMDS_VolumeTool vTool( volume );
11289     vTool.SetExternalNormal();
11290     const bool isPoly = volume->IsPoly();
11291     const bool isQuad = volume->IsQuadratic();
11292     for ( int iface = 0, n = vTool.NbFaces(); iface < n; iface++ )
11293     {
11294       if (!vTool.IsFreeFace(iface))
11295         continue;
11296       nbFree++;
11297       vector<const SMDS_MeshNode *> nodes;
11298       int nbFaceNodes = vTool.NbFaceNodes(iface);
11299       const SMDS_MeshNode** faceNodes = vTool.GetFaceNodes(iface);
11300       int inode = 0;
11301       for ( ; inode < nbFaceNodes; inode += isQuad ? 2 : 1)
11302         nodes.push_back(faceNodes[inode]);
11303       if (isQuad)
11304         for ( inode = 1; inode < nbFaceNodes; inode += 2)
11305           nodes.push_back(faceNodes[inode]);
11306
11307       // add new face based on volume nodes
11308       if (aMesh->FindFace( nodes ) ) {
11309         nbExisted++;
11310         continue; // face already exsist
11311       }
11312       AddElement(nodes, SMDSAbs_Face, isPoly && iface == 1);
11313       nbCreated++;
11314     }
11315   }
11316   return ( nbFree==(nbExisted+nbCreated) );
11317 }
11318
11319 namespace
11320 {
11321   inline const SMDS_MeshNode* getNodeWithSameID(SMESHDS_Mesh* mesh, const SMDS_MeshNode* node)
11322   {
11323     if ( const SMDS_MeshNode* n = mesh->FindNode( node->GetID() ))
11324       return n;
11325     return mesh->AddNodeWithID( node->X(),node->Y(),node->Z(), node->GetID() );
11326   }
11327 }
11328 //================================================================================
11329 /*!
11330  * \brief Creates missing boundary elements
11331  *  \param elements - elements whose boundary is to be checked
11332  *  \param dimension - defines type of boundary elements to create
11333  *  \param group - a group to store created boundary elements in
11334  *  \param targetMesh - a mesh to store created boundary elements in
11335  *  \param toCopyElements - if true, the checked elements will be copied into the targetMesh
11336  *  \param toCopyExistingBondary - if true, not only new but also pre-existing
11337  *                                boundary elements will be copied into the targetMesh
11338  *  \param toAddExistingBondary - if true, not only new but also pre-existing
11339  *                                boundary elements will be added into the new group
11340  *  \param aroundElements - if true, elements will be created on boundary of given
11341  *                          elements else, on boundary of the whole mesh. This
11342  *                          option works for 2D elements only.
11343  * \return nb of added boundary elements
11344  */
11345 //================================================================================
11346
11347 int SMESH_MeshEditor::MakeBoundaryMesh(const TIDSortedElemSet& elements,
11348                                        Bnd_Dimension           dimension,
11349                                        SMESH_Group*            group/*=0*/,
11350                                        SMESH_Mesh*             targetMesh/*=0*/,
11351                                        bool                    toCopyElements/*=false*/,
11352                                        bool                    toCopyExistingBondary/*=false*/,
11353                                        bool                    toAddExistingBondary/*= false*/,
11354                                        bool                    aroundElements/*= false*/)
11355 {
11356   SMDSAbs_ElementType missType = (dimension == BND_2DFROM3D) ? SMDSAbs_Face : SMDSAbs_Edge;
11357   SMDSAbs_ElementType elemType = (dimension == BND_1DFROM2D) ? SMDSAbs_Face : SMDSAbs_Volume;
11358   // hope that all elements are of the same type, do not check them all
11359   if ( !elements.empty() && (*elements.begin())->GetType() != elemType )
11360     throw SALOME_Exception(LOCALIZED("wrong element type"));
11361
11362   if ( aroundElements && elemType == SMDSAbs_Volume )
11363     throw SALOME_Exception(LOCALIZED("wrong element type for aroundElements==true"));
11364
11365   if ( !targetMesh )
11366     toCopyElements = toCopyExistingBondary = false;
11367
11368   SMESH_MeshEditor tgtEditor( targetMesh ? targetMesh : myMesh );
11369   SMESHDS_Mesh* aMesh = GetMeshDS(), *tgtMeshDS = tgtEditor.GetMeshDS();
11370   int nbAddedBnd = 0;
11371
11372   // editor adding present bnd elements and optionally holding elements to add to the group
11373   SMESH_MeshEditor* presentEditor;
11374   SMESH_MeshEditor tgtEditor2( tgtEditor.GetMesh() );
11375   presentEditor = toAddExistingBondary ? &tgtEditor : &tgtEditor2;
11376
11377   SMDS_VolumeTool vTool;
11378   TIDSortedElemSet avoidSet;
11379   const TIDSortedElemSet emptySet, *elemSet = aroundElements ? &elements : &emptySet;
11380   int inode;
11381
11382   typedef vector<const SMDS_MeshNode*> TConnectivity;
11383
11384   SMDS_ElemIteratorPtr eIt;
11385   if (elements.empty())
11386     eIt = aMesh->elementsIterator(elemType);
11387   else
11388     eIt = SMDS_ElemIteratorPtr( new TSetIterator( elements.begin(), elements.end() ));
11389
11390   while (eIt->more())
11391   {
11392     const SMDS_MeshElement* elem = eIt->next();
11393     const int iQuad = elem->IsQuadratic();
11394
11395     // ------------------------------------------------------------------------------------
11396     // 1. For an elem, get present bnd elements and connectivities of missing bnd elements
11397     // ------------------------------------------------------------------------------------
11398     vector<const SMDS_MeshElement*> presentBndElems;
11399     vector<TConnectivity>           missingBndElems;
11400     TConnectivity nodes;
11401     if ( vTool.Set(elem) ) // elem is a volume ------------------------------------------
11402     {
11403       vTool.SetExternalNormal();
11404       for ( int iface = 0, n = vTool.NbFaces(); iface < n; iface++ )
11405       {
11406         if (!vTool.IsFreeFace(iface))
11407           continue;
11408         int nbFaceNodes = vTool.NbFaceNodes(iface);
11409         const SMDS_MeshNode** nn = vTool.GetFaceNodes(iface);
11410         if ( missType == SMDSAbs_Edge ) // boundary edges
11411         {
11412           nodes.resize( 2+iQuad );
11413           for ( int i = 0; i < nbFaceNodes; i += 1+iQuad)
11414           {
11415             for ( int j = 0; j < nodes.size(); ++j )
11416               nodes[j] =nn[i+j];
11417             if ( const SMDS_MeshElement* edge =
11418                  aMesh->FindElement(nodes,SMDSAbs_Edge,/*noMedium=*/0))
11419               presentBndElems.push_back( edge );
11420             else
11421               missingBndElems.push_back( nodes );
11422           }
11423         }
11424         else // boundary face
11425         {
11426           nodes.clear();
11427           for ( inode = 0; inode < nbFaceNodes; inode += 1+iQuad)
11428             nodes.push_back( nn[inode] );
11429           if (iQuad)
11430             for ( inode = 1; inode < nbFaceNodes; inode += 2)
11431               nodes.push_back( nn[inode] );
11432
11433           if (const SMDS_MeshFace * f = aMesh->FindFace( nodes ) )
11434             presentBndElems.push_back( f );
11435           else
11436             missingBndElems.push_back( nodes );
11437         }
11438       }
11439     }
11440     else                     // elem is a face ------------------------------------------
11441     {
11442       avoidSet.clear(), avoidSet.insert( elem );
11443       int nbNodes = elem->NbCornerNodes();
11444       nodes.resize( 2 /*+ iQuad*/);
11445       for ( int i = 0; i < nbNodes; i++ )
11446       {
11447         nodes[0] = elem->GetNode(i);
11448         nodes[1] = elem->GetNode((i+1)%nbNodes);
11449         if ( FindFaceInSet( nodes[0], nodes[1], *elemSet, avoidSet))
11450           continue; // not free link
11451
11452         //if ( iQuad )
11453         //nodes[2] = elem->GetNode( i + nbNodes );
11454         if ( const SMDS_MeshElement* edge =
11455              aMesh->FindElement(nodes,SMDSAbs_Edge,/*noMedium=*/true))
11456           presentBndElems.push_back( edge );
11457         else
11458           missingBndElems.push_back( nodes );
11459       }
11460     }
11461
11462     // ---------------------------------
11463     // 2. Add missing boundary elements
11464     // ---------------------------------
11465     if ( targetMesh != myMesh )
11466       // instead of making a map of nodes in this mesh and targetMesh,
11467       // we create nodes with same IDs. We can renumber them later, if needed
11468       for ( int i = 0; i < missingBndElems.size(); ++i )
11469       {
11470         TConnectivity& srcNodes = missingBndElems[i];
11471         TConnectivity  nodes( srcNodes.size() );
11472         for ( inode = 0; inode < nodes.size(); ++inode )
11473           nodes[inode] = getNodeWithSameID( tgtMeshDS, srcNodes[inode] );
11474         if ( aroundElements && tgtEditor.GetMeshDS()->FindElement( nodes,
11475                                                                    missType,
11476                                                                    /*noMedium=*/true))
11477           continue;
11478         tgtEditor.AddElement(nodes, missType, elem->IsPoly() && nodes.size()/(iQuad+1)>4);
11479         ++nbAddedBnd;
11480       }
11481     else
11482       for ( int i = 0; i < missingBndElems.size(); ++i )
11483       {
11484         TConnectivity& nodes = missingBndElems[i];
11485         if ( aroundElements && tgtEditor.GetMeshDS()->FindElement( nodes,
11486                                                                    missType,
11487                                                                    /*noMedium=*/true))
11488           continue;
11489         tgtEditor.AddElement(nodes, missType, elem->IsPoly() && nodes.size()/(iQuad+1)>4);
11490         ++nbAddedBnd;
11491       }
11492
11493     // ----------------------------------
11494     // 3. Copy present boundary elements
11495     // ----------------------------------
11496     if ( toCopyExistingBondary )
11497       for ( int i = 0 ; i < presentBndElems.size(); ++i )
11498       {
11499         const SMDS_MeshElement* e = presentBndElems[i];
11500         TConnectivity nodes( e->NbNodes() );
11501         for ( inode = 0; inode < nodes.size(); ++inode )
11502           nodes[inode] = getNodeWithSameID( tgtMeshDS, e->GetNode(inode) );
11503         presentEditor->AddElement(nodes, missType, e->IsPoly());
11504       }
11505     else // store present elements to add them to a group
11506       for ( int i = 0 ; i < presentBndElems.size(); ++i )
11507       {
11508         presentEditor->myLastCreatedElems.Append(presentBndElems[i]);
11509       }
11510       
11511   } // loop on given elements
11512
11513   // ---------------------------------------------
11514   // 4. Fill group with boundary elements
11515   // ---------------------------------------------
11516   if ( group )
11517   {
11518     if ( SMESHDS_Group* g = dynamic_cast<SMESHDS_Group*>( group->GetGroupDS() ))
11519       for ( int i = 0; i < tgtEditor.myLastCreatedElems.Size(); ++i )
11520         g->SMDSGroup().Add( tgtEditor.myLastCreatedElems( i+1 ));
11521   }
11522   tgtEditor.myLastCreatedElems.Clear();
11523   tgtEditor2.myLastCreatedElems.Clear();
11524
11525   // -----------------------
11526   // 5. Copy given elements
11527   // -----------------------
11528   if ( toCopyElements && targetMesh != myMesh )
11529   {
11530     if (elements.empty())
11531       eIt = aMesh->elementsIterator(elemType);
11532     else
11533       eIt = SMDS_ElemIteratorPtr( new TSetIterator( elements.begin(), elements.end() ));
11534     while (eIt->more())
11535     {
11536       const SMDS_MeshElement* elem = eIt->next();
11537       TConnectivity nodes( elem->NbNodes() );
11538       for ( inode = 0; inode < nodes.size(); ++inode )
11539         nodes[inode] = getNodeWithSameID( tgtMeshDS, elem->GetNode(inode) );
11540       tgtEditor.AddElement(nodes, elemType, elem->IsPoly());
11541
11542       tgtEditor.myLastCreatedElems.Clear();
11543     }
11544   }
11545   return nbAddedBnd;
11546 }