Salome HOME
Make TNodeXYZ public, which together with SMDS_StdIterator allows getting coordinates...
[modules/smesh.git] / src / SMESH / SMESH_MeshEditor.cxx
1 //  Copyright (C) 2007-2008  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 //  SMESH SMESH : idl implementation based on 'SMESH' unit's classes
23 // File      : SMESH_MeshEditor.cxx
24 // Created   : Mon Apr 12 16:10:22 2004
25 // Author    : Edward AGAPOV (eap)
26 //
27 #include "SMESH_MeshEditor.hxx"
28
29 #include "SMDS_FaceOfNodes.hxx"
30 #include "SMDS_VolumeTool.hxx"
31 #include "SMDS_EdgePosition.hxx"
32 #include "SMDS_PolyhedralVolumeOfNodes.hxx"
33 #include "SMDS_FacePosition.hxx"
34 #include "SMDS_SpacePosition.hxx"
35 #include "SMDS_QuadraticFaceOfNodes.hxx"
36 #include "SMDS_MeshGroup.hxx"
37
38 #include "SMESHDS_Group.hxx"
39 #include "SMESHDS_Mesh.hxx"
40
41 #include "SMESH_subMesh.hxx"
42 #include "SMESH_ControlsDef.hxx"
43 #include "SMESH_MesherHelper.hxx"
44 #include "SMESH_OctreeNode.hxx"
45 #include "SMESH_Group.hxx"
46
47 #include "utilities.h"
48
49 #include <BRepAdaptor_Surface.hxx>
50 #include <BRepClass3d_SolidClassifier.hxx>
51 #include <BRep_Tool.hxx>
52 #include <ElCLib.hxx>
53 #include <Extrema_GenExtPS.hxx>
54 #include <Extrema_POnSurf.hxx>
55 #include <Geom2d_Curve.hxx>
56 #include <GeomAdaptor_Surface.hxx>
57 #include <Geom_Curve.hxx>
58 #include <Geom_Surface.hxx>
59 #include <Precision.hxx>
60 #include <TColStd_ListOfInteger.hxx>
61 #include <TopAbs_State.hxx>
62 #include <TopExp.hxx>
63 #include <TopExp_Explorer.hxx>
64 #include <TopTools_ListIteratorOfListOfShape.hxx>
65 #include <TopTools_ListOfShape.hxx>
66 #include <TopTools_SequenceOfShape.hxx>
67 #include <TopoDS.hxx>
68 #include <TopoDS_Face.hxx>
69 #include <gp.hxx>
70 #include <gp_Ax1.hxx>
71 #include <gp_Dir.hxx>
72 #include <gp_Lin.hxx>
73 #include <gp_Pln.hxx>
74 #include <gp_Trsf.hxx>
75 #include <gp_Vec.hxx>
76 #include <gp_XY.hxx>
77 #include <gp_XYZ.hxx>
78 #include <math.h>
79
80 #include <map>
81 #include <set>
82 #include <numeric>
83 #include <limits>
84
85 #define cast2Node(elem) static_cast<const SMDS_MeshNode*>( elem )
86
87 using namespace std;
88 using namespace SMESH::Controls;
89
90 typedef map<const SMDS_MeshElement*, list<const SMDS_MeshNode*> >    TElemOfNodeListMap;
91 typedef map<const SMDS_MeshElement*, list<const SMDS_MeshElement*> > TElemOfElemListMap;
92
93 //=======================================================================
94 //function : SMESH_MeshEditor
95 //purpose  :
96 //=======================================================================
97
98 SMESH_MeshEditor::SMESH_MeshEditor( SMESH_Mesh* theMesh )
99   :myMesh( theMesh ) // theMesh may be NULL
100 {
101 }
102
103 //=======================================================================
104 /*!
105  * \brief Add element
106  */
107 //=======================================================================
108
109 SMDS_MeshElement*
110 SMESH_MeshEditor::AddElement(const vector<const SMDS_MeshNode*> & node,
111                              const SMDSAbs_ElementType            type,
112                              const bool                           isPoly,
113                              const int                            ID)
114 {
115   SMDS_MeshElement* e = 0;
116   int nbnode = node.size();
117   SMESHDS_Mesh* mesh = GetMeshDS();
118   switch ( type ) {
119   case SMDSAbs_Edge:
120     if ( nbnode == 2 )
121       if ( ID ) e = mesh->AddEdgeWithID(node[0], node[1], ID);
122       else      e = mesh->AddEdge      (node[0], node[1] );
123     else if ( nbnode == 3 )
124       if ( ID ) e = mesh->AddEdgeWithID(node[0], node[1], node[2], ID);
125       else      e = mesh->AddEdge      (node[0], node[1], node[2] );
126     break;
127   case SMDSAbs_Face:
128     if ( !isPoly ) {
129       if      (nbnode == 3)
130         if ( ID ) e = mesh->AddFaceWithID(node[0], node[1], node[2], ID);
131         else      e = mesh->AddFace      (node[0], node[1], node[2] );
132       else if (nbnode == 4) 
133         if ( ID ) e = mesh->AddFaceWithID(node[0], node[1], node[2], node[3], ID);
134         else      e = mesh->AddFace      (node[0], node[1], node[2], node[3] );
135       else if (nbnode == 6)
136         if ( ID ) e = mesh->AddFaceWithID(node[0], node[1], node[2], node[3],
137                                           node[4], node[5], ID);
138         else      e = mesh->AddFace      (node[0], node[1], node[2], node[3],
139                                           node[4], node[5] );
140       else if (nbnode == 8)
141         if ( ID ) e = mesh->AddFaceWithID(node[0], node[1], node[2], node[3],
142                                           node[4], node[5], node[6], node[7], ID);
143         else      e = mesh->AddFace      (node[0], node[1], node[2], node[3],
144                                           node[4], node[5], node[6], node[7] );
145     } else {
146       if ( ID ) e = mesh->AddPolygonalFaceWithID(node, ID);
147       else      e = mesh->AddPolygonalFace      (node    );
148     }
149     break;
150   case SMDSAbs_Volume:
151     if ( !isPoly ) {
152       if      (nbnode == 4)
153         if ( ID ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3], ID);
154         else      e = mesh->AddVolume      (node[0], node[1], node[2], node[3] );
155       else if (nbnode == 5)
156         if ( ID ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
157                                             node[4], ID);
158         else      e = mesh->AddVolume      (node[0], node[1], node[2], node[3],
159                                             node[4] );
160       else if (nbnode == 6)
161         if ( ID ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
162                                             node[4], node[5], ID);
163         else      e = mesh->AddVolume      (node[0], node[1], node[2], node[3],
164                                             node[4], node[5] );
165       else if (nbnode == 8)
166         if ( ID ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
167                                             node[4], node[5], node[6], node[7], ID);
168         else      e = mesh->AddVolume      (node[0], node[1], node[2], node[3],
169                                             node[4], node[5], node[6], node[7] );
170       else if (nbnode == 10)
171         if ( ID ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
172                                             node[4], node[5], node[6], node[7],
173                                             node[8], node[9], ID);
174         else      e = mesh->AddVolume      (node[0], node[1], node[2], node[3],
175                                             node[4], node[5], node[6], node[7],
176                                             node[8], node[9] );
177       else if (nbnode == 13)
178         if ( ID ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
179                                             node[4], node[5], node[6], node[7],
180                                             node[8], node[9], node[10],node[11],
181                                             node[12],ID);
182         else      e = mesh->AddVolume      (node[0], node[1], node[2], node[3],
183                                             node[4], node[5], node[6], node[7],
184                                             node[8], node[9], node[10],node[11],
185                                             node[12] );
186       else if (nbnode == 15)
187         if ( ID ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
188                                             node[4], node[5], node[6], node[7],
189                                             node[8], node[9], node[10],node[11],
190                                             node[12],node[13],node[14],ID);
191         else      e = mesh->AddVolume      (node[0], node[1], node[2], node[3],
192                                             node[4], node[5], node[6], node[7],
193                                             node[8], node[9], node[10],node[11],
194                                             node[12],node[13],node[14] );
195       else if (nbnode == 20)
196         if ( ID ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
197                                             node[4], node[5], node[6], node[7],
198                                             node[8], node[9], node[10],node[11],
199                                             node[12],node[13],node[14],node[15],
200                                             node[16],node[17],node[18],node[19],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],node[13],node[14],node[15],
205                                             node[16],node[17],node[18],node[19] );
206     }
207   }
208   return e;
209 }
210
211 //=======================================================================
212 /*!
213  * \brief Add element
214  */
215 //=======================================================================
216
217 SMDS_MeshElement* SMESH_MeshEditor::AddElement(const vector<int> &       nodeIDs,
218                                                const SMDSAbs_ElementType type,
219                                                const bool                isPoly,
220                                                const int                 ID)
221 {
222   vector<const SMDS_MeshNode*> nodes;
223   nodes.reserve( nodeIDs.size() );
224   vector<int>::const_iterator id = nodeIDs.begin();
225   while ( id != nodeIDs.end() ) {
226     if ( const SMDS_MeshNode* node = GetMeshDS()->FindNode( *id++ ))
227       nodes.push_back( node );
228     else
229       return 0;
230   }
231   return AddElement( nodes, type, isPoly, ID );
232 }
233
234 //=======================================================================
235 //function : Remove
236 //purpose  : Remove a node or an element.
237 //           Modify a compute state of sub-meshes which become empty
238 //=======================================================================
239
240 bool SMESH_MeshEditor::Remove (const list< int >& theIDs,
241                                const bool         isNodes )
242 {
243   myLastCreatedElems.Clear();
244   myLastCreatedNodes.Clear();
245
246   SMESHDS_Mesh* aMesh = GetMeshDS();
247   set< SMESH_subMesh *> smmap;
248
249   list<int>::const_iterator it = theIDs.begin();
250   for ( ; it != theIDs.end(); it++ ) {
251     const SMDS_MeshElement * elem;
252     if ( isNodes )
253       elem = aMesh->FindNode( *it );
254     else
255       elem = aMesh->FindElement( *it );
256     if ( !elem )
257       continue;
258
259     // Notify VERTEX sub-meshes about modification
260     if ( isNodes ) {
261       const SMDS_MeshNode* node = cast2Node( elem );
262       if ( node->GetPosition()->GetTypeOfPosition() == SMDS_TOP_VERTEX )
263         if ( int aShapeID = node->GetPosition()->GetShapeId() )
264           if ( SMESH_subMesh * sm = GetMesh()->GetSubMeshContaining( aShapeID ) )
265             smmap.insert( sm );
266     }
267     // Find sub-meshes to notify about modification
268     //     SMDS_ElemIteratorPtr nodeIt = elem->nodesIterator();
269     //     while ( nodeIt->more() ) {
270     //       const SMDS_MeshNode* node = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
271     //       const SMDS_PositionPtr& aPosition = node->GetPosition();
272     //       if ( aPosition.get() ) {
273     //         if ( int aShapeID = aPosition->GetShapeId() ) {
274     //           if ( SMESH_subMesh * sm = GetMesh()->GetSubMeshContaining( aShapeID ) )
275     //             smmap.insert( sm );
276     //         }
277     //       }
278     //     }
279
280     // Do remove
281     if ( isNodes )
282       aMesh->RemoveNode( static_cast< const SMDS_MeshNode* >( elem ));
283     else
284       aMesh->RemoveElement( elem );
285   }
286
287   // Notify sub-meshes about modification
288   if ( !smmap.empty() ) {
289     set< SMESH_subMesh *>::iterator smIt;
290     for ( smIt = smmap.begin(); smIt != smmap.end(); smIt++ )
291       (*smIt)->ComputeStateEngine( SMESH_subMesh::MESH_ENTITY_REMOVED );
292   }
293
294   //   // Check if the whole mesh becomes empty
295   //   if ( SMESH_subMesh * sm = GetMesh()->GetSubMeshContaining( 1 ) )
296   //     sm->ComputeStateEngine( SMESH_subMesh::CHECK_COMPUTE_STATE );
297
298   return true;
299 }
300
301 //=======================================================================
302 //function : FindShape
303 //purpose  : Return an index of the shape theElem is on
304 //           or zero if a shape not found
305 //=======================================================================
306
307 int SMESH_MeshEditor::FindShape (const SMDS_MeshElement * theElem)
308 {
309   myLastCreatedElems.Clear();
310   myLastCreatedNodes.Clear();
311
312   SMESHDS_Mesh * aMesh = GetMeshDS();
313   if ( aMesh->ShapeToMesh().IsNull() )
314     return 0;
315
316   if ( theElem->GetType() == SMDSAbs_Node ) {
317     const SMDS_PositionPtr& aPosition =
318       static_cast<const SMDS_MeshNode*>( theElem )->GetPosition();
319     if ( aPosition.get() )
320       return aPosition->GetShapeId();
321     else
322       return 0;
323   }
324
325   TopoDS_Shape aShape; // the shape a node is on
326   SMDS_ElemIteratorPtr nodeIt = theElem->nodesIterator();
327   while ( nodeIt->more() ) {
328     const SMDS_MeshNode* node = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
329     const SMDS_PositionPtr& aPosition = node->GetPosition();
330     if ( aPosition.get() ) {
331       int aShapeID = aPosition->GetShapeId();
332       SMESHDS_SubMesh * sm = aMesh->MeshElements( aShapeID );
333       if ( sm ) {
334         if ( sm->Contains( theElem ))
335           return aShapeID;
336         if ( aShape.IsNull() )
337           aShape = aMesh->IndexToShape( aShapeID );
338       }
339       else {
340         //MESSAGE ( "::FindShape() No SubShape for aShapeID " << aShapeID );
341       }
342     }
343   }
344
345   // None of nodes is on a proper shape,
346   // find the shape among ancestors of aShape on which a node is
347   if ( aShape.IsNull() ) {
348     //MESSAGE ("::FindShape() - NONE node is on shape")
349     return 0;
350   }
351   TopTools_ListIteratorOfListOfShape ancIt( GetMesh()->GetAncestors( aShape ));
352   for ( ; ancIt.More(); ancIt.Next() ) {
353     SMESHDS_SubMesh * sm = aMesh->MeshElements( ancIt.Value() );
354     if ( sm && sm->Contains( theElem ))
355       return aMesh->ShapeToIndex( ancIt.Value() );
356   }
357
358   //MESSAGE ("::FindShape() - SHAPE NOT FOUND")
359   return 0;
360 }
361
362 //=======================================================================
363 //function : IsMedium
364 //purpose  :
365 //=======================================================================
366
367 bool SMESH_MeshEditor::IsMedium(const SMDS_MeshNode*      node,
368                                 const SMDSAbs_ElementType typeToCheck)
369 {
370   bool isMedium = false;
371   SMDS_ElemIteratorPtr it = node->GetInverseElementIterator(typeToCheck);
372   while (it->more() && !isMedium ) {
373     const SMDS_MeshElement* elem = it->next();
374     isMedium = elem->IsMediumNode(node);
375   }
376   return isMedium;
377 }
378
379 //=======================================================================
380 //function : ShiftNodesQuadTria
381 //purpose  : auxilary
382 //           Shift nodes in the array corresponded to quadratic triangle
383 //           example: (0,1,2,3,4,5) -> (1,2,0,4,5,3)
384 //=======================================================================
385 static void ShiftNodesQuadTria(const SMDS_MeshNode* aNodes[])
386 {
387   const SMDS_MeshNode* nd1 = aNodes[0];
388   aNodes[0] = aNodes[1];
389   aNodes[1] = aNodes[2];
390   aNodes[2] = nd1;
391   const SMDS_MeshNode* nd2 = aNodes[3];
392   aNodes[3] = aNodes[4];
393   aNodes[4] = aNodes[5];
394   aNodes[5] = nd2;
395 }
396
397 //=======================================================================
398 //function : GetNodesFromTwoTria
399 //purpose  : auxilary
400 //           Shift nodes in the array corresponded to quadratic triangle
401 //           example: (0,1,2,3,4,5) -> (1,2,0,4,5,3)
402 //=======================================================================
403 static bool GetNodesFromTwoTria(const SMDS_MeshElement * theTria1,
404                                 const SMDS_MeshElement * theTria2,
405                                 const SMDS_MeshNode* N1[],
406                                 const SMDS_MeshNode* N2[])
407 {
408   SMDS_ElemIteratorPtr it = theTria1->nodesIterator();
409   int i=0;
410   while(i<6) {
411     N1[i] = static_cast<const SMDS_MeshNode*>( it->next() );
412     i++;
413   }
414   if(it->more()) return false;
415   it = theTria2->nodesIterator();
416   i=0;
417   while(i<6) {
418     N2[i] = static_cast<const SMDS_MeshNode*>( it->next() );
419     i++;
420   }
421   if(it->more()) return false;
422
423   int sames[3] = {-1,-1,-1};
424   int nbsames = 0;
425   int j;
426   for(i=0; i<3; i++) {
427     for(j=0; j<3; j++) {
428       if(N1[i]==N2[j]) {
429         sames[i] = j;
430         nbsames++;
431         break;
432       }
433     }
434   }
435   if(nbsames!=2) return false;
436   if(sames[0]>-1) {
437     ShiftNodesQuadTria(N1);
438     if(sames[1]>-1) {
439       ShiftNodesQuadTria(N1);
440     }
441   }
442   i = sames[0] + sames[1] + sames[2];
443   for(; i<2; i++) {
444     ShiftNodesQuadTria(N2);
445   }
446   // now we receive following N1 and N2 (using numeration as above image)
447   // tria1 : (1 2 4 5 9 7)  and  tria2 : (3 4 2 8 9 6)
448   // i.e. first nodes from both arrays determ new diagonal
449   return true;
450 }
451
452 //=======================================================================
453 //function : InverseDiag
454 //purpose  : Replace two neighbour triangles with ones built on the same 4 nodes
455 //           but having other common link.
456 //           Return False if args are improper
457 //=======================================================================
458
459 bool SMESH_MeshEditor::InverseDiag (const SMDS_MeshElement * theTria1,
460                                     const SMDS_MeshElement * theTria2 )
461 {
462   myLastCreatedElems.Clear();
463   myLastCreatedNodes.Clear();
464
465   if (!theTria1 || !theTria2)
466     return false;
467
468   const SMDS_FaceOfNodes* F1 = dynamic_cast<const SMDS_FaceOfNodes*>( theTria1 );
469   const SMDS_FaceOfNodes* F2 = dynamic_cast<const SMDS_FaceOfNodes*>( theTria2 );
470   if (F1 && F2) {
471
472     //  1 +--+ A  theTria1: ( 1 A B ) A->2 ( 1 2 B ) 1 +--+ A
473     //    | /|    theTria2: ( B A 2 ) B->1 ( 1 A 2 )   |\ |
474     //    |/ |                                         | \|
475     //  B +--+ 2                                     B +--+ 2
476
477     // put nodes in array and find out indices of the same ones
478     const SMDS_MeshNode* aNodes [6];
479     int sameInd [] = { 0, 0, 0, 0, 0, 0 };
480     int i = 0;
481     SMDS_ElemIteratorPtr it = theTria1->nodesIterator();
482     while ( it->more() ) {
483       aNodes[ i ] = static_cast<const SMDS_MeshNode*>( it->next() );
484
485       if ( i > 2 ) // theTria2
486         // find same node of theTria1
487         for ( int j = 0; j < 3; j++ )
488           if ( aNodes[ i ] == aNodes[ j ]) {
489             sameInd[ j ] = i;
490             sameInd[ i ] = j;
491             break;
492           }
493       // next
494       i++;
495       if ( i == 3 ) {
496         if ( it->more() )
497           return false; // theTria1 is not a triangle
498         it = theTria2->nodesIterator();
499       }
500       if ( i == 6 && it->more() )
501         return false; // theTria2 is not a triangle
502     }
503
504     // find indices of 1,2 and of A,B in theTria1
505     int iA = 0, iB = 0, i1 = 0, i2 = 0;
506     for ( i = 0; i < 6; i++ ) {
507       if ( sameInd [ i ] == 0 )
508         if ( i < 3 ) i1 = i;
509         else         i2 = i;
510       else if (i < 3)
511         if ( iA ) iB = i;
512         else      iA = i;
513     }
514     // nodes 1 and 2 should not be the same
515     if ( aNodes[ i1 ] == aNodes[ i2 ] )
516       return false;
517
518     // theTria1: A->2
519     aNodes[ iA ] = aNodes[ i2 ];
520     // theTria2: B->1
521     aNodes[ sameInd[ iB ]] = aNodes[ i1 ];
522
523     //MESSAGE( theTria1 << theTria2 );
524
525     GetMeshDS()->ChangeElementNodes( theTria1, aNodes, 3 );
526     GetMeshDS()->ChangeElementNodes( theTria2, &aNodes[ 3 ], 3 );
527
528     //MESSAGE( theTria1 << theTria2 );
529
530     return true;
531
532   } // end if(F1 && F2)
533
534   // check case of quadratic faces
535   const SMDS_QuadraticFaceOfNodes* QF1 =
536     dynamic_cast<const SMDS_QuadraticFaceOfNodes*> (theTria1);
537   if(!QF1) return false;
538   const SMDS_QuadraticFaceOfNodes* QF2 =
539     dynamic_cast<const SMDS_QuadraticFaceOfNodes*> (theTria2);
540   if(!QF2) return false;
541
542   //       5
543   //  1 +--+--+ 2  theTria1: (1 2 4 5 9 7) or (2 4 1 9 7 5) or (4 1 2 7 5 9)
544   //    |    /|    theTria2: (2 3 4 6 8 9) or (3 4 2 8 9 6) or (4 2 3 9 6 8)
545   //    |   / |
546   //  7 +  +  + 6
547   //    | /9  |
548   //    |/    |
549   //  4 +--+--+ 3
550   //       8
551
552   const SMDS_MeshNode* N1 [6];
553   const SMDS_MeshNode* N2 [6];
554   if(!GetNodesFromTwoTria(theTria1,theTria2,N1,N2))
555     return false;
556   // now we receive following N1 and N2 (using numeration as above image)
557   // tria1 : (1 2 4 5 9 7)  and  tria2 : (3 4 2 8 9 6)
558   // i.e. first nodes from both arrays determ new diagonal
559
560   const SMDS_MeshNode* N1new [6];
561   const SMDS_MeshNode* N2new [6];
562   N1new[0] = N1[0];
563   N1new[1] = N2[0];
564   N1new[2] = N2[1];
565   N1new[3] = N1[4];
566   N1new[4] = N2[3];
567   N1new[5] = N1[5];
568   N2new[0] = N1[0];
569   N2new[1] = N1[1];
570   N2new[2] = N2[0];
571   N2new[3] = N1[3];
572   N2new[4] = N2[5];
573   N2new[5] = N1[4];
574   // replaces nodes in faces
575   GetMeshDS()->ChangeElementNodes( theTria1, N1new, 6 );
576   GetMeshDS()->ChangeElementNodes( theTria2, N2new, 6 );
577
578   return true;
579 }
580
581 //=======================================================================
582 //function : findTriangles
583 //purpose  : find triangles sharing theNode1-theNode2 link
584 //=======================================================================
585
586 static bool findTriangles(const SMDS_MeshNode *    theNode1,
587                           const SMDS_MeshNode *    theNode2,
588                           const SMDS_MeshElement*& theTria1,
589                           const SMDS_MeshElement*& theTria2)
590 {
591   if ( !theNode1 || !theNode2 ) return false;
592
593   theTria1 = theTria2 = 0;
594
595   set< const SMDS_MeshElement* > emap;
596   SMDS_ElemIteratorPtr it = theNode1->GetInverseElementIterator(SMDSAbs_Face);
597   while (it->more()) {
598     const SMDS_MeshElement* elem = it->next();
599     if ( elem->NbNodes() == 3 )
600       emap.insert( elem );
601   }
602   it = theNode2->GetInverseElementIterator(SMDSAbs_Face);
603   while (it->more()) {
604     const SMDS_MeshElement* elem = it->next();
605     if ( emap.find( elem ) != emap.end() )
606       if ( theTria1 ) {
607         // theTria1 must be element with minimum ID
608         if( theTria1->GetID() < elem->GetID() ) {
609           theTria2 = elem;
610         }
611         else {
612           theTria2 = theTria1;
613           theTria1 = elem;
614         }
615         break;
616       }
617       else {
618         theTria1 = elem;
619       }
620   }
621   return ( theTria1 && theTria2 );
622 }
623
624 //=======================================================================
625 //function : InverseDiag
626 //purpose  : Replace two neighbour triangles sharing theNode1-theNode2 link
627 //           with ones built on the same 4 nodes but having other common link.
628 //           Return false if proper faces not found
629 //=======================================================================
630
631 bool SMESH_MeshEditor::InverseDiag (const SMDS_MeshNode * theNode1,
632                                     const SMDS_MeshNode * theNode2)
633 {
634   myLastCreatedElems.Clear();
635   myLastCreatedNodes.Clear();
636
637   MESSAGE( "::InverseDiag()" );
638
639   const SMDS_MeshElement *tr1, *tr2;
640   if ( !findTriangles( theNode1, theNode2, tr1, tr2 ))
641     return false;
642
643   const SMDS_FaceOfNodes* F1 = dynamic_cast<const SMDS_FaceOfNodes*>( tr1 );
644   //if (!F1) return false;
645   const SMDS_FaceOfNodes* F2 = dynamic_cast<const SMDS_FaceOfNodes*>( tr2 );
646   //if (!F2) return false;
647   if (F1 && F2) {
648
649     //  1 +--+ A  tr1: ( 1 A B ) A->2 ( 1 2 B ) 1 +--+ A
650     //    | /|    tr2: ( B A 2 ) B->1 ( 1 A 2 )   |\ |
651     //    |/ |                                    | \|
652     //  B +--+ 2                                B +--+ 2
653
654     // put nodes in array
655     // and find indices of 1,2 and of A in tr1 and of B in tr2
656     int i, iA1 = 0, i1 = 0;
657     const SMDS_MeshNode* aNodes1 [3];
658     SMDS_ElemIteratorPtr it;
659     for (i = 0, it = tr1->nodesIterator(); it->more(); i++ ) {
660       aNodes1[ i ] = static_cast<const SMDS_MeshNode*>( it->next() );
661       if ( aNodes1[ i ] == theNode1 )
662         iA1 = i; // node A in tr1
663       else if ( aNodes1[ i ] != theNode2 )
664         i1 = i;  // node 1
665     }
666     int iB2 = 0, i2 = 0;
667     const SMDS_MeshNode* aNodes2 [3];
668     for (i = 0, it = tr2->nodesIterator(); it->more(); i++ ) {
669       aNodes2[ i ] = static_cast<const SMDS_MeshNode*>( it->next() );
670       if ( aNodes2[ i ] == theNode2 )
671         iB2 = i; // node B in tr2
672       else if ( aNodes2[ i ] != theNode1 )
673         i2 = i;  // node 2
674     }
675
676     // nodes 1 and 2 should not be the same
677     if ( aNodes1[ i1 ] == aNodes2[ i2 ] )
678       return false;
679
680     // tr1: A->2
681     aNodes1[ iA1 ] = aNodes2[ i2 ];
682     // tr2: B->1
683     aNodes2[ iB2 ] = aNodes1[ i1 ];
684
685     //MESSAGE( tr1 << tr2 );
686
687     GetMeshDS()->ChangeElementNodes( tr1, aNodes1, 3 );
688     GetMeshDS()->ChangeElementNodes( tr2, aNodes2, 3 );
689
690     //MESSAGE( tr1 << tr2 );
691
692     return true;
693   }
694
695   // check case of quadratic faces
696   const SMDS_QuadraticFaceOfNodes* QF1 =
697     dynamic_cast<const SMDS_QuadraticFaceOfNodes*> (tr1);
698   if(!QF1) return false;
699   const SMDS_QuadraticFaceOfNodes* QF2 =
700     dynamic_cast<const SMDS_QuadraticFaceOfNodes*> (tr2);
701   if(!QF2) return false;
702   return InverseDiag(tr1,tr2);
703 }
704
705 //=======================================================================
706 //function : getQuadrangleNodes
707 //purpose  : fill theQuadNodes - nodes of a quadrangle resulting from
708 //           fusion of triangles tr1 and tr2 having shared link on
709 //           theNode1 and theNode2
710 //=======================================================================
711
712 bool getQuadrangleNodes(const SMDS_MeshNode *    theQuadNodes [],
713                         const SMDS_MeshNode *    theNode1,
714                         const SMDS_MeshNode *    theNode2,
715                         const SMDS_MeshElement * tr1,
716                         const SMDS_MeshElement * tr2 )
717 {
718   if( tr1->NbNodes() != tr2->NbNodes() )
719     return false;
720   // find the 4-th node to insert into tr1
721   const SMDS_MeshNode* n4 = 0;
722   SMDS_ElemIteratorPtr it = tr2->nodesIterator();
723   int i=0;
724   while ( !n4 && i<3 ) {
725     const SMDS_MeshNode * n = cast2Node( it->next() );
726     i++;
727     bool isDiag = ( n == theNode1 || n == theNode2 );
728     if ( !isDiag )
729       n4 = n;
730   }
731   // Make an array of nodes to be in a quadrangle
732   int iNode = 0, iFirstDiag = -1;
733   it = tr1->nodesIterator();
734   i=0;
735   while ( i<3 ) {
736     const SMDS_MeshNode * n = cast2Node( it->next() );
737     i++;
738     bool isDiag = ( n == theNode1 || n == theNode2 );
739     if ( isDiag ) {
740       if ( iFirstDiag < 0 )
741         iFirstDiag = iNode;
742       else if ( iNode - iFirstDiag == 1 )
743         theQuadNodes[ iNode++ ] = n4; // insert the 4-th node between diagonal nodes
744     }
745     else if ( n == n4 ) {
746       return false; // tr1 and tr2 should not have all the same nodes
747     }
748     theQuadNodes[ iNode++ ] = n;
749   }
750   if ( iNode == 3 ) // diagonal nodes have 0 and 2 indices
751     theQuadNodes[ iNode ] = n4;
752
753   return true;
754 }
755
756 //=======================================================================
757 //function : DeleteDiag
758 //purpose  : Replace two neighbour triangles sharing theNode1-theNode2 link
759 //           with a quadrangle built on the same 4 nodes.
760 //           Return false if proper faces not found
761 //=======================================================================
762
763 bool SMESH_MeshEditor::DeleteDiag (const SMDS_MeshNode * theNode1,
764                                    const SMDS_MeshNode * theNode2)
765 {
766   myLastCreatedElems.Clear();
767   myLastCreatedNodes.Clear();
768
769   MESSAGE( "::DeleteDiag()" );
770
771   const SMDS_MeshElement *tr1, *tr2;
772   if ( !findTriangles( theNode1, theNode2, tr1, tr2 ))
773     return false;
774
775   const SMDS_FaceOfNodes* F1 = dynamic_cast<const SMDS_FaceOfNodes*>( tr1 );
776   //if (!F1) return false;
777   const SMDS_FaceOfNodes* F2 = dynamic_cast<const SMDS_FaceOfNodes*>( tr2 );
778   //if (!F2) return false;
779   if (F1 && F2) {
780
781     const SMDS_MeshNode* aNodes [ 4 ];
782     if ( ! getQuadrangleNodes( aNodes, theNode1, theNode2, tr1, tr2 ))
783       return false;
784
785     //MESSAGE( endl << tr1 << tr2 );
786
787     GetMeshDS()->ChangeElementNodes( tr1, aNodes, 4 );
788     myLastCreatedElems.Append(tr1);
789     GetMeshDS()->RemoveElement( tr2 );
790
791     //MESSAGE( endl << tr1 );
792
793     return true;
794   }
795
796   // check case of quadratic faces
797   const SMDS_QuadraticFaceOfNodes* QF1 =
798     dynamic_cast<const SMDS_QuadraticFaceOfNodes*> (tr1);
799   if(!QF1) return false;
800   const SMDS_QuadraticFaceOfNodes* QF2 =
801     dynamic_cast<const SMDS_QuadraticFaceOfNodes*> (tr2);
802   if(!QF2) return false;
803
804   //       5
805   //  1 +--+--+ 2  tr1: (1 2 4 5 9 7) or (2 4 1 9 7 5) or (4 1 2 7 5 9)
806   //    |    /|    tr2: (2 3 4 6 8 9) or (3 4 2 8 9 6) or (4 2 3 9 6 8)
807   //    |   / |
808   //  7 +  +  + 6
809   //    | /9  |
810   //    |/    |
811   //  4 +--+--+ 3
812   //       8
813
814   const SMDS_MeshNode* N1 [6];
815   const SMDS_MeshNode* N2 [6];
816   if(!GetNodesFromTwoTria(tr1,tr2,N1,N2))
817     return false;
818   // now we receive following N1 and N2 (using numeration as above image)
819   // tria1 : (1 2 4 5 9 7)  and  tria2 : (3 4 2 8 9 6)
820   // i.e. first nodes from both arrays determ new diagonal
821
822   const SMDS_MeshNode* aNodes[8];
823   aNodes[0] = N1[0];
824   aNodes[1] = N1[1];
825   aNodes[2] = N2[0];
826   aNodes[3] = N2[1];
827   aNodes[4] = N1[3];
828   aNodes[5] = N2[5];
829   aNodes[6] = N2[3];
830   aNodes[7] = N1[5];
831
832   GetMeshDS()->ChangeElementNodes( tr1, aNodes, 8 );
833   myLastCreatedElems.Append(tr1);
834   GetMeshDS()->RemoveElement( tr2 );
835
836   // remove middle node (9)
837   GetMeshDS()->RemoveNode( N1[4] );
838
839   return true;
840 }
841
842 //=======================================================================
843 //function : Reorient
844 //purpose  : Reverse theElement orientation
845 //=======================================================================
846
847 bool SMESH_MeshEditor::Reorient (const SMDS_MeshElement * theElem)
848 {
849   myLastCreatedElems.Clear();
850   myLastCreatedNodes.Clear();
851
852   if (!theElem)
853     return false;
854   SMDS_ElemIteratorPtr it = theElem->nodesIterator();
855   if ( !it || !it->more() )
856     return false;
857
858   switch ( theElem->GetType() ) {
859
860   case SMDSAbs_Edge:
861   case SMDSAbs_Face: {
862     if(!theElem->IsQuadratic()) {
863       int i = theElem->NbNodes();
864       vector<const SMDS_MeshNode*> aNodes( i );
865       while ( it->more() )
866         aNodes[ --i ]= static_cast<const SMDS_MeshNode*>( it->next() );
867       return GetMeshDS()->ChangeElementNodes( theElem, &aNodes[0], theElem->NbNodes() );
868     }
869     else {
870       // quadratic elements
871       if(theElem->GetType()==SMDSAbs_Edge) {
872         vector<const SMDS_MeshNode*> aNodes(3);
873         aNodes[1]= static_cast<const SMDS_MeshNode*>( it->next() );
874         aNodes[0]= static_cast<const SMDS_MeshNode*>( it->next() );
875         aNodes[2]= static_cast<const SMDS_MeshNode*>( it->next() );
876         return GetMeshDS()->ChangeElementNodes( theElem, &aNodes[0], 3 );
877       }
878       else {
879         int nbn = theElem->NbNodes();
880         vector<const SMDS_MeshNode*> aNodes(nbn);
881         aNodes[0]= static_cast<const SMDS_MeshNode*>( it->next() );
882         int i=1;
883         for(; i<nbn/2; i++) {
884           aNodes[nbn/2-i]= static_cast<const SMDS_MeshNode*>( it->next() );
885         }
886         for(i=0; i<nbn/2; i++) {
887           aNodes[nbn-i-1]= static_cast<const SMDS_MeshNode*>( it->next() );
888         }
889         return GetMeshDS()->ChangeElementNodes( theElem, &aNodes[0], nbn );
890       }
891     }
892   }
893   case SMDSAbs_Volume: {
894     if (theElem->IsPoly()) {
895       const SMDS_PolyhedralVolumeOfNodes* aPolyedre =
896         static_cast<const SMDS_PolyhedralVolumeOfNodes*>( theElem );
897       if (!aPolyedre) {
898         MESSAGE("Warning: bad volumic element");
899         return false;
900       }
901
902       int nbFaces = aPolyedre->NbFaces();
903       vector<const SMDS_MeshNode *> poly_nodes;
904       vector<int> quantities (nbFaces);
905
906       // reverse each face of the polyedre
907       for (int iface = 1; iface <= nbFaces; iface++) {
908         int inode, nbFaceNodes = aPolyedre->NbFaceNodes(iface);
909         quantities[iface - 1] = nbFaceNodes;
910
911         for (inode = nbFaceNodes; inode >= 1; inode--) {
912           const SMDS_MeshNode* curNode = aPolyedre->GetFaceNode(iface, inode);
913           poly_nodes.push_back(curNode);
914         }
915       }
916
917       return GetMeshDS()->ChangePolyhedronNodes( theElem, poly_nodes, quantities );
918
919     }
920     else {
921       SMDS_VolumeTool vTool;
922       if ( !vTool.Set( theElem ))
923         return false;
924       vTool.Inverse();
925       return GetMeshDS()->ChangeElementNodes( theElem, vTool.GetNodes(), vTool.NbNodes() );
926     }
927   }
928   default:;
929   }
930
931   return false;
932 }
933
934 //=======================================================================
935 //function : getBadRate
936 //purpose  :
937 //=======================================================================
938
939 static double getBadRate (const SMDS_MeshElement*               theElem,
940                           SMESH::Controls::NumericalFunctorPtr& theCrit)
941 {
942   SMESH::Controls::TSequenceOfXYZ P;
943   if ( !theElem || !theCrit->GetPoints( theElem, P ))
944     return 1e100;
945   return theCrit->GetBadRate( theCrit->GetValue( P ), theElem->NbNodes() );
946   //return theCrit->GetBadRate( theCrit->GetValue( theElem->GetID() ), theElem->NbNodes() );
947 }
948
949 //=======================================================================
950 //function : QuadToTri
951 //purpose  : Cut quadrangles into triangles.
952 //           theCrit is used to select a diagonal to cut
953 //=======================================================================
954
955 bool SMESH_MeshEditor::QuadToTri (TIDSortedElemSet &                   theElems,
956                                   SMESH::Controls::NumericalFunctorPtr theCrit)
957 {
958   myLastCreatedElems.Clear();
959   myLastCreatedNodes.Clear();
960
961   MESSAGE( "::QuadToTri()" );
962
963   if ( !theCrit.get() )
964     return false;
965
966   SMESHDS_Mesh * aMesh = GetMeshDS();
967
968   Handle(Geom_Surface) surface;
969   SMESH_MesherHelper   helper( *GetMesh() );
970
971   TIDSortedElemSet::iterator itElem;
972   for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
973     const SMDS_MeshElement* elem = *itElem;
974     if ( !elem || elem->GetType() != SMDSAbs_Face )
975       continue;
976     if ( elem->NbNodes() != ( elem->IsQuadratic() ? 8 : 4 ))
977       continue;
978
979     // retrieve element nodes
980     const SMDS_MeshNode* aNodes [8];
981     SMDS_ElemIteratorPtr itN = elem->nodesIterator();
982     int i = 0;
983     while ( itN->more() )
984       aNodes[ i++ ] = static_cast<const SMDS_MeshNode*>( itN->next() );
985
986     // compare two sets of possible triangles
987     double aBadRate1, aBadRate2; // to what extent a set is bad
988     SMDS_FaceOfNodes tr1 ( aNodes[0], aNodes[1], aNodes[2] );
989     SMDS_FaceOfNodes tr2 ( aNodes[2], aNodes[3], aNodes[0] );
990     aBadRate1 = getBadRate( &tr1, theCrit ) + getBadRate( &tr2, theCrit );
991
992     SMDS_FaceOfNodes tr3 ( aNodes[1], aNodes[2], aNodes[3] );
993     SMDS_FaceOfNodes tr4 ( aNodes[3], aNodes[0], aNodes[1] );
994     aBadRate2 = getBadRate( &tr3, theCrit ) + getBadRate( &tr4, theCrit );
995
996     int aShapeId = FindShape( elem );
997     const SMDS_MeshElement* newElem = 0;
998
999     if( !elem->IsQuadratic() ) {
1000
1001       // split liner quadrangle
1002
1003       if ( aBadRate1 <= aBadRate2 ) {
1004         // tr1 + tr2 is better
1005         aMesh->ChangeElementNodes( elem, aNodes, 3 );
1006         newElem = aMesh->AddFace( aNodes[2], aNodes[3], aNodes[0] );
1007       }
1008       else {
1009         // tr3 + tr4 is better
1010         aMesh->ChangeElementNodes( elem, &aNodes[1], 3 );
1011         newElem = aMesh->AddFace( aNodes[3], aNodes[0], aNodes[1] );
1012       }
1013     }
1014     else {
1015
1016       // split quadratic quadrangle
1017
1018       // get surface elem is on
1019       if ( aShapeId != helper.GetSubShapeID() ) {
1020         surface.Nullify();
1021         TopoDS_Shape shape;
1022         if ( aShapeId > 0 )
1023           shape = aMesh->IndexToShape( aShapeId );
1024         if ( !shape.IsNull() && shape.ShapeType() == TopAbs_FACE ) {
1025           TopoDS_Face face = TopoDS::Face( shape );
1026           surface = BRep_Tool::Surface( face );
1027           if ( !surface.IsNull() )
1028             helper.SetSubShape( shape );
1029         }
1030       }
1031       // get elem nodes
1032       const SMDS_MeshNode* aNodes [8];
1033       const SMDS_MeshNode* inFaceNode = 0;
1034       SMDS_ElemIteratorPtr itN = elem->nodesIterator();
1035       int i = 0;
1036       while ( itN->more() ) {
1037         aNodes[ i++ ] = static_cast<const SMDS_MeshNode*>( itN->next() );
1038         if ( !inFaceNode && helper.GetNodeUVneedInFaceNode() &&
1039              aNodes[ i-1 ]->GetPosition()->GetTypeOfPosition() == SMDS_TOP_FACE )
1040         {
1041           inFaceNode = aNodes[ i-1 ];
1042         }
1043       }
1044       // find middle point for (0,1,2,3)
1045       // and create a node in this point;
1046       gp_XYZ p( 0,0,0 );
1047       if ( surface.IsNull() ) {
1048         for(i=0; i<4; i++)
1049           p += gp_XYZ(aNodes[i]->X(), aNodes[i]->Y(), aNodes[i]->Z() );
1050         p /= 4;
1051       }
1052       else {
1053         TopoDS_Face face = TopoDS::Face( helper.GetSubShape() );
1054         gp_XY uv( 0,0 );
1055         for(i=0; i<4; i++)
1056           uv += helper.GetNodeUV( face, aNodes[i], inFaceNode );
1057         uv /= 4.;
1058         p = surface->Value( uv.X(), uv.Y() ).XYZ();
1059       }
1060       const SMDS_MeshNode* newN = aMesh->AddNode( p.X(), p.Y(), p.Z() );
1061       myLastCreatedNodes.Append(newN);
1062
1063       // create a new element
1064       const SMDS_MeshNode* N[6];
1065       if ( aBadRate1 <= aBadRate2 ) {
1066         N[0] = aNodes[0];
1067         N[1] = aNodes[1];
1068         N[2] = aNodes[2];
1069         N[3] = aNodes[4];
1070         N[4] = aNodes[5];
1071         N[5] = newN;
1072         newElem = aMesh->AddFace(aNodes[2], aNodes[3], aNodes[0],
1073                                  aNodes[6], aNodes[7], newN );
1074       }
1075       else {
1076         N[0] = aNodes[1];
1077         N[1] = aNodes[2];
1078         N[2] = aNodes[3];
1079         N[3] = aNodes[5];
1080         N[4] = aNodes[6];
1081         N[5] = newN;
1082         newElem = aMesh->AddFace(aNodes[3], aNodes[0], aNodes[1],
1083                                  aNodes[7], aNodes[4], newN );
1084       }
1085       aMesh->ChangeElementNodes( elem, N, 6 );
1086
1087     } // quadratic case
1088
1089     // care of a new element
1090
1091     myLastCreatedElems.Append(newElem);
1092     AddToSameGroups( newElem, elem, aMesh );
1093
1094     // put a new triangle on the same shape
1095     if ( aShapeId )
1096       aMesh->SetMeshElementOnShape( newElem, aShapeId );
1097   }
1098   return true;
1099 }
1100
1101 //=======================================================================
1102 //function : BestSplit
1103 //purpose  : Find better diagonal for cutting.
1104 //=======================================================================
1105 int SMESH_MeshEditor::BestSplit (const SMDS_MeshElement*              theQuad,
1106                                  SMESH::Controls::NumericalFunctorPtr theCrit)
1107 {
1108   myLastCreatedElems.Clear();
1109   myLastCreatedNodes.Clear();
1110
1111   if (!theCrit.get())
1112     return -1;
1113
1114   if (!theQuad || theQuad->GetType() != SMDSAbs_Face )
1115     return -1;
1116
1117   if( theQuad->NbNodes()==4 ||
1118       (theQuad->NbNodes()==8 && theQuad->IsQuadratic()) ) {
1119
1120     // retrieve element nodes
1121     const SMDS_MeshNode* aNodes [4];
1122     SMDS_ElemIteratorPtr itN = theQuad->nodesIterator();
1123     int i = 0;
1124     //while (itN->more())
1125     while (i<4) {
1126       aNodes[ i++ ] = static_cast<const SMDS_MeshNode*>( itN->next() );
1127     }
1128     // compare two sets of possible triangles
1129     double aBadRate1, aBadRate2; // to what extent a set is bad
1130     SMDS_FaceOfNodes tr1 ( aNodes[0], aNodes[1], aNodes[2] );
1131     SMDS_FaceOfNodes tr2 ( aNodes[2], aNodes[3], aNodes[0] );
1132     aBadRate1 = getBadRate( &tr1, theCrit ) + getBadRate( &tr2, theCrit );
1133
1134     SMDS_FaceOfNodes tr3 ( aNodes[1], aNodes[2], aNodes[3] );
1135     SMDS_FaceOfNodes tr4 ( aNodes[3], aNodes[0], aNodes[1] );
1136     aBadRate2 = getBadRate( &tr3, theCrit ) + getBadRate( &tr4, theCrit );
1137
1138     if (aBadRate1 <= aBadRate2) // tr1 + tr2 is better
1139       return 1; // diagonal 1-3
1140
1141     return 2; // diagonal 2-4
1142   }
1143   return -1;
1144 }
1145
1146 //=======================================================================
1147 //function : AddToSameGroups
1148 //purpose  : add elemToAdd to the groups the elemInGroups belongs to
1149 //=======================================================================
1150
1151 void SMESH_MeshEditor::AddToSameGroups (const SMDS_MeshElement* elemToAdd,
1152                                         const SMDS_MeshElement* elemInGroups,
1153                                         SMESHDS_Mesh *          aMesh)
1154 {
1155   const set<SMESHDS_GroupBase*>& groups = aMesh->GetGroups();
1156   if (!groups.empty()) {
1157     set<SMESHDS_GroupBase*>::const_iterator grIt = groups.begin();
1158     for ( ; grIt != groups.end(); grIt++ ) {
1159       SMESHDS_Group* group = dynamic_cast<SMESHDS_Group*>( *grIt );
1160       if ( group && group->Contains( elemInGroups ))
1161         group->SMDSGroup().Add( elemToAdd );
1162     }
1163   }
1164 }
1165
1166
1167 //=======================================================================
1168 //function : RemoveElemFromGroups
1169 //purpose  : Remove removeelem to the groups the elemInGroups belongs to
1170 //=======================================================================
1171 void SMESH_MeshEditor::RemoveElemFromGroups (const SMDS_MeshElement* removeelem,
1172                                              SMESHDS_Mesh *          aMesh)
1173 {
1174   const set<SMESHDS_GroupBase*>& groups = aMesh->GetGroups();
1175   if (!groups.empty())
1176   {
1177     set<SMESHDS_GroupBase*>::const_iterator GrIt = groups.begin();
1178     for (; GrIt != groups.end(); GrIt++)
1179     {
1180       SMESHDS_Group* grp = dynamic_cast<SMESHDS_Group*>(*GrIt);
1181       if (!grp || grp->IsEmpty()) continue;
1182       grp->SMDSGroup().Remove(removeelem);
1183     }
1184   }
1185 }
1186
1187 //=======================================================================
1188 //function : ReplaceElemInGroups
1189 //purpose  : replace elemToRm by elemToAdd in the all groups
1190 //=======================================================================
1191
1192 void SMESH_MeshEditor::ReplaceElemInGroups (const SMDS_MeshElement* elemToRm,
1193                                             const SMDS_MeshElement* elemToAdd,
1194                                             SMESHDS_Mesh *          aMesh)
1195 {
1196   const set<SMESHDS_GroupBase*>& groups = aMesh->GetGroups();
1197   if (!groups.empty()) {
1198     set<SMESHDS_GroupBase*>::const_iterator grIt = groups.begin();
1199     for ( ; grIt != groups.end(); grIt++ ) {
1200       SMESHDS_Group* group = dynamic_cast<SMESHDS_Group*>( *grIt );
1201       if ( group && group->SMDSGroup().Remove( elemToRm ) && elemToAdd )
1202         group->SMDSGroup().Add( elemToAdd );
1203     }
1204   }
1205 }
1206
1207 //=======================================================================
1208 //function : QuadToTri
1209 //purpose  : Cut quadrangles into triangles.
1210 //           theCrit is used to select a diagonal to cut
1211 //=======================================================================
1212
1213 bool SMESH_MeshEditor::QuadToTri (TIDSortedElemSet & theElems,
1214                                   const bool         the13Diag)
1215 {
1216   myLastCreatedElems.Clear();
1217   myLastCreatedNodes.Clear();
1218
1219   MESSAGE( "::QuadToTri()" );
1220
1221   SMESHDS_Mesh * aMesh = GetMeshDS();
1222
1223   Handle(Geom_Surface) surface;
1224   SMESH_MesherHelper   helper( *GetMesh() );
1225
1226   TIDSortedElemSet::iterator itElem;
1227   for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
1228     const SMDS_MeshElement* elem = *itElem;
1229     if ( !elem || elem->GetType() != SMDSAbs_Face )
1230       continue;
1231     bool isquad = elem->NbNodes()==4 || elem->NbNodes()==8;
1232     if(!isquad) continue;
1233
1234     if(elem->NbNodes()==4) {
1235       // retrieve element nodes
1236       const SMDS_MeshNode* aNodes [4];
1237       SMDS_ElemIteratorPtr itN = elem->nodesIterator();
1238       int i = 0;
1239       while ( itN->more() )
1240         aNodes[ i++ ] = static_cast<const SMDS_MeshNode*>( itN->next() );
1241
1242       int aShapeId = FindShape( elem );
1243       const SMDS_MeshElement* newElem = 0;
1244       if ( the13Diag ) {
1245         aMesh->ChangeElementNodes( elem, aNodes, 3 );
1246         newElem = aMesh->AddFace( aNodes[2], aNodes[3], aNodes[0] );
1247       }
1248       else {
1249         aMesh->ChangeElementNodes( elem, &aNodes[1], 3 );
1250         newElem = aMesh->AddFace( aNodes[3], aNodes[0], aNodes[1] );
1251       }
1252       myLastCreatedElems.Append(newElem);
1253       // put a new triangle on the same shape and add to the same groups
1254       if ( aShapeId )
1255         aMesh->SetMeshElementOnShape( newElem, aShapeId );
1256       AddToSameGroups( newElem, elem, aMesh );
1257     }
1258
1259     // Quadratic quadrangle
1260
1261     if( elem->NbNodes()==8 && elem->IsQuadratic() ) {
1262
1263       // get surface elem is on
1264       int aShapeId = FindShape( elem );
1265       if ( aShapeId != helper.GetSubShapeID() ) {
1266         surface.Nullify();
1267         TopoDS_Shape shape;
1268         if ( aShapeId > 0 )
1269           shape = aMesh->IndexToShape( aShapeId );
1270         if ( !shape.IsNull() && shape.ShapeType() == TopAbs_FACE ) {
1271           TopoDS_Face face = TopoDS::Face( shape );
1272           surface = BRep_Tool::Surface( face );
1273           if ( !surface.IsNull() )
1274             helper.SetSubShape( shape );
1275         }
1276       }
1277
1278       const SMDS_MeshNode* aNodes [8];
1279       const SMDS_MeshNode* inFaceNode = 0;
1280       SMDS_ElemIteratorPtr itN = elem->nodesIterator();
1281       int i = 0;
1282       while ( itN->more() ) {
1283         aNodes[ i++ ] = static_cast<const SMDS_MeshNode*>( itN->next() );
1284         if ( !inFaceNode && helper.GetNodeUVneedInFaceNode() &&
1285              aNodes[ i-1 ]->GetPosition()->GetTypeOfPosition() == SMDS_TOP_FACE )
1286         {
1287           inFaceNode = aNodes[ i-1 ];
1288         }
1289       }
1290
1291       // find middle point for (0,1,2,3)
1292       // and create a node in this point;
1293       gp_XYZ p( 0,0,0 );
1294       if ( surface.IsNull() ) {
1295         for(i=0; i<4; i++)
1296           p += gp_XYZ(aNodes[i]->X(), aNodes[i]->Y(), aNodes[i]->Z() );
1297         p /= 4;
1298       }
1299       else {
1300         TopoDS_Face geomFace = TopoDS::Face( helper.GetSubShape() );
1301         gp_XY uv( 0,0 );
1302         for(i=0; i<4; i++)
1303           uv += helper.GetNodeUV( geomFace, aNodes[i], inFaceNode );
1304         uv /= 4.;
1305         p = surface->Value( uv.X(), uv.Y() ).XYZ();
1306       }
1307       const SMDS_MeshNode* newN = aMesh->AddNode( p.X(), p.Y(), p.Z() );
1308       myLastCreatedNodes.Append(newN);
1309
1310       // create a new element
1311       const SMDS_MeshElement* newElem = 0;
1312       const SMDS_MeshNode* N[6];
1313       if ( the13Diag ) {
1314         N[0] = aNodes[0];
1315         N[1] = aNodes[1];
1316         N[2] = aNodes[2];
1317         N[3] = aNodes[4];
1318         N[4] = aNodes[5];
1319         N[5] = newN;
1320         newElem = aMesh->AddFace(aNodes[2], aNodes[3], aNodes[0],
1321                                  aNodes[6], aNodes[7], newN );
1322       }
1323       else {
1324         N[0] = aNodes[1];
1325         N[1] = aNodes[2];
1326         N[2] = aNodes[3];
1327         N[3] = aNodes[5];
1328         N[4] = aNodes[6];
1329         N[5] = newN;
1330         newElem = aMesh->AddFace(aNodes[3], aNodes[0], aNodes[1],
1331                                  aNodes[7], aNodes[4], newN );
1332       }
1333       myLastCreatedElems.Append(newElem);
1334       aMesh->ChangeElementNodes( elem, N, 6 );
1335       // put a new triangle on the same shape and add to the same groups
1336       if ( aShapeId )
1337         aMesh->SetMeshElementOnShape( newElem, aShapeId );
1338       AddToSameGroups( newElem, elem, aMesh );
1339     }
1340   }
1341
1342   return true;
1343 }
1344
1345 //=======================================================================
1346 //function : getAngle
1347 //purpose  :
1348 //=======================================================================
1349
1350 double getAngle(const SMDS_MeshElement * tr1,
1351                 const SMDS_MeshElement * tr2,
1352                 const SMDS_MeshNode *    n1,
1353                 const SMDS_MeshNode *    n2)
1354 {
1355   double angle = 2*PI; // bad angle
1356
1357   // get normals
1358   SMESH::Controls::TSequenceOfXYZ P1, P2;
1359   if ( !SMESH::Controls::NumericalFunctor::GetPoints( tr1, P1 ) ||
1360        !SMESH::Controls::NumericalFunctor::GetPoints( tr2, P2 ))
1361     return angle;
1362   gp_Vec N1,N2;
1363   if(!tr1->IsQuadratic())
1364     N1 = gp_Vec( P1(2) - P1(1) ) ^ gp_Vec( P1(3) - P1(1) );
1365   else
1366     N1 = gp_Vec( P1(3) - P1(1) ) ^ gp_Vec( P1(5) - P1(1) );
1367   if ( N1.SquareMagnitude() <= gp::Resolution() )
1368     return angle;
1369   if(!tr2->IsQuadratic())
1370     N2 = gp_Vec( P2(2) - P2(1) ) ^ gp_Vec( P2(3) - P2(1) );
1371   else
1372     N2 = gp_Vec( P2(3) - P2(1) ) ^ gp_Vec( P2(5) - P2(1) );
1373   if ( N2.SquareMagnitude() <= gp::Resolution() )
1374     return angle;
1375
1376   // find the first diagonal node n1 in the triangles:
1377   // take in account a diagonal link orientation
1378   const SMDS_MeshElement *nFirst[2], *tr[] = { tr1, tr2 };
1379   for ( int t = 0; t < 2; t++ ) {
1380     SMDS_ElemIteratorPtr it = tr[ t ]->nodesIterator();
1381     int i = 0, iDiag = -1;
1382     while ( it->more()) {
1383       const SMDS_MeshElement *n = it->next();
1384       if ( n == n1 || n == n2 )
1385         if ( iDiag < 0)
1386           iDiag = i;
1387         else {
1388           if ( i - iDiag == 1 )
1389             nFirst[ t ] = ( n == n1 ? n2 : n1 );
1390           else
1391             nFirst[ t ] = n;
1392           break;
1393         }
1394       i++;
1395     }
1396   }
1397   if ( nFirst[ 0 ] == nFirst[ 1 ] )
1398     N2.Reverse();
1399
1400   angle = N1.Angle( N2 );
1401   //SCRUTE( angle );
1402   return angle;
1403 }
1404
1405 // =================================================
1406 // class generating a unique ID for a pair of nodes
1407 // and able to return nodes by that ID
1408 // =================================================
1409 class LinkID_Gen {
1410 public:
1411
1412   LinkID_Gen( const SMESHDS_Mesh* theMesh )
1413     :myMesh( theMesh ), myMaxID( theMesh->MaxNodeID() + 1)
1414   {}
1415
1416   long GetLinkID (const SMDS_MeshNode * n1,
1417                   const SMDS_MeshNode * n2) const
1418   {
1419     return ( Min(n1->GetID(),n2->GetID()) * myMaxID + Max(n1->GetID(),n2->GetID()));
1420   }
1421
1422   bool GetNodes (const long             theLinkID,
1423                  const SMDS_MeshNode* & theNode1,
1424                  const SMDS_MeshNode* & theNode2) const
1425   {
1426     theNode1 = myMesh->FindNode( theLinkID / myMaxID );
1427     if ( !theNode1 ) return false;
1428     theNode2 = myMesh->FindNode( theLinkID % myMaxID );
1429     if ( !theNode2 ) return false;
1430     return true;
1431   }
1432
1433 private:
1434   LinkID_Gen();
1435   const SMESHDS_Mesh* myMesh;
1436   long                myMaxID;
1437 };
1438
1439
1440 //=======================================================================
1441 //function : TriToQuad
1442 //purpose  : Fuse neighbour triangles into quadrangles.
1443 //           theCrit is used to select a neighbour to fuse with.
1444 //           theMaxAngle is a max angle between element normals at which
1445 //           fusion is still performed.
1446 //=======================================================================
1447
1448 bool SMESH_MeshEditor::TriToQuad (TIDSortedElemSet &                   theElems,
1449                                   SMESH::Controls::NumericalFunctorPtr theCrit,
1450                                   const double                         theMaxAngle)
1451 {
1452   myLastCreatedElems.Clear();
1453   myLastCreatedNodes.Clear();
1454
1455   MESSAGE( "::TriToQuad()" );
1456
1457   if ( !theCrit.get() )
1458     return false;
1459
1460   SMESHDS_Mesh * aMesh = GetMeshDS();
1461
1462   // Prepare data for algo: build
1463   // 1. map of elements with their linkIDs
1464   // 2. map of linkIDs with their elements
1465
1466   map< SMESH_TLink, list< const SMDS_MeshElement* > > mapLi_listEl;
1467   map< SMESH_TLink, list< const SMDS_MeshElement* > >::iterator itLE;
1468   map< const SMDS_MeshElement*, set< SMESH_TLink > >  mapEl_setLi;
1469   map< const SMDS_MeshElement*, set< SMESH_TLink > >::iterator itEL;
1470
1471   TIDSortedElemSet::iterator itElem;
1472   for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
1473     const SMDS_MeshElement* elem = *itElem;
1474     if(!elem || elem->GetType() != SMDSAbs_Face ) continue;
1475     bool IsTria = elem->NbNodes()==3 || (elem->NbNodes()==6 && elem->IsQuadratic());
1476     if(!IsTria) continue;
1477
1478     // retrieve element nodes
1479     const SMDS_MeshNode* aNodes [4];
1480     SMDS_ElemIteratorPtr itN = elem->nodesIterator();
1481     int i = 0;
1482     while ( i<3 )
1483       aNodes[ i++ ] = cast2Node( itN->next() );
1484     aNodes[ 3 ] = aNodes[ 0 ];
1485
1486     // fill maps
1487     for ( i = 0; i < 3; i++ ) {
1488       SMESH_TLink link( aNodes[i], aNodes[i+1] );
1489       // check if elements sharing a link can be fused
1490       itLE = mapLi_listEl.find( link );
1491       if ( itLE != mapLi_listEl.end() ) {
1492         if ((*itLE).second.size() > 1 ) // consider only 2 elems adjacent by a link
1493           continue;
1494         const SMDS_MeshElement* elem2 = (*itLE).second.front();
1495         //if ( FindShape( elem ) != FindShape( elem2 ))
1496         //  continue; // do not fuse triangles laying on different shapes
1497         if ( getAngle( elem, elem2, aNodes[i], aNodes[i+1] ) > theMaxAngle )
1498           continue; // avoid making badly shaped quads
1499         (*itLE).second.push_back( elem );
1500       }
1501       else {
1502         mapLi_listEl[ link ].push_back( elem );
1503       }
1504       mapEl_setLi [ elem ].insert( link );
1505     }
1506   }
1507   // Clean the maps from the links shared by a sole element, ie
1508   // links to which only one element is bound in mapLi_listEl
1509
1510   for ( itLE = mapLi_listEl.begin(); itLE != mapLi_listEl.end(); itLE++ ) {
1511     int nbElems = (*itLE).second.size();
1512     if ( nbElems < 2  ) {
1513       const SMDS_MeshElement* elem = (*itLE).second.front();
1514       SMESH_TLink link = (*itLE).first;
1515       mapEl_setLi[ elem ].erase( link );
1516       if ( mapEl_setLi[ elem ].empty() )
1517         mapEl_setLi.erase( elem );
1518     }
1519   }
1520
1521   // Algo: fuse triangles into quadrangles
1522
1523   while ( ! mapEl_setLi.empty() ) {
1524     // Look for the start element:
1525     // the element having the least nb of shared links
1526     const SMDS_MeshElement* startElem = 0;
1527     int minNbLinks = 4;
1528     for ( itEL = mapEl_setLi.begin(); itEL != mapEl_setLi.end(); itEL++ ) {
1529       int nbLinks = (*itEL).second.size();
1530       if ( nbLinks < minNbLinks ) {
1531         startElem = (*itEL).first;
1532         minNbLinks = nbLinks;
1533         if ( minNbLinks == 1 )
1534           break;
1535       }
1536     }
1537
1538     // search elements to fuse starting from startElem or links of elements
1539     // fused earlyer - startLinks
1540     list< SMESH_TLink > startLinks;
1541     while ( startElem || !startLinks.empty() ) {
1542       while ( !startElem && !startLinks.empty() ) {
1543         // Get an element to start, by a link
1544         SMESH_TLink linkId = startLinks.front();
1545         startLinks.pop_front();
1546         itLE = mapLi_listEl.find( linkId );
1547         if ( itLE != mapLi_listEl.end() ) {
1548           list< const SMDS_MeshElement* > & listElem = (*itLE).second;
1549           list< const SMDS_MeshElement* >::iterator itE = listElem.begin();
1550           for ( ; itE != listElem.end() ; itE++ )
1551             if ( mapEl_setLi.find( (*itE) ) != mapEl_setLi.end() )
1552               startElem = (*itE);
1553           mapLi_listEl.erase( itLE );
1554         }
1555       }
1556
1557       if ( startElem ) {
1558         // Get candidates to be fused
1559         const SMDS_MeshElement *tr1 = startElem, *tr2 = 0, *tr3 = 0;
1560         const SMESH_TLink *link12, *link13;
1561         startElem = 0;
1562         ASSERT( mapEl_setLi.find( tr1 ) != mapEl_setLi.end() );
1563         set< SMESH_TLink >& setLi = mapEl_setLi[ tr1 ];
1564         ASSERT( !setLi.empty() );
1565         set< SMESH_TLink >::iterator itLi;
1566         for ( itLi = setLi.begin(); itLi != setLi.end(); itLi++ )
1567         {
1568           const SMESH_TLink & link = (*itLi);
1569           itLE = mapLi_listEl.find( link );
1570           if ( itLE == mapLi_listEl.end() )
1571             continue;
1572
1573           const SMDS_MeshElement* elem = (*itLE).second.front();
1574           if ( elem == tr1 )
1575             elem = (*itLE).second.back();
1576           mapLi_listEl.erase( itLE );
1577           if ( mapEl_setLi.find( elem ) == mapEl_setLi.end())
1578             continue;
1579           if ( tr2 ) {
1580             tr3 = elem;
1581             link13 = &link;
1582           }
1583           else {
1584             tr2 = elem;
1585             link12 = &link;
1586           }
1587
1588           // add other links of elem to list of links to re-start from
1589           set< SMESH_TLink >& links = mapEl_setLi[ elem ];
1590           set< SMESH_TLink >::iterator it;
1591           for ( it = links.begin(); it != links.end(); it++ ) {
1592             const SMESH_TLink& link2 = (*it);
1593             if ( link2 != link )
1594               startLinks.push_back( link2 );
1595           }
1596         }
1597
1598         // Get nodes of possible quadrangles
1599         const SMDS_MeshNode *n12 [4], *n13 [4];
1600         bool Ok12 = false, Ok13 = false;
1601         const SMDS_MeshNode *linkNode1, *linkNode2;
1602         if(tr2) {
1603           linkNode1 = link12->first;
1604           linkNode2 = link12->second;
1605           if ( tr2 && getQuadrangleNodes( n12, linkNode1, linkNode2, tr1, tr2 ))
1606             Ok12 = true;
1607         }
1608         if(tr3) {
1609           linkNode1 = link13->first;
1610           linkNode2 = link13->second;
1611           if ( tr3 && getQuadrangleNodes( n13, linkNode1, linkNode2, tr1, tr3 ))
1612             Ok13 = true;
1613         }
1614
1615         // Choose a pair to fuse
1616         if ( Ok12 && Ok13 ) {
1617           SMDS_FaceOfNodes quad12 ( n12[ 0 ], n12[ 1 ], n12[ 2 ], n12[ 3 ] );
1618           SMDS_FaceOfNodes quad13 ( n13[ 0 ], n13[ 1 ], n13[ 2 ], n13[ 3 ] );
1619           double aBadRate12 = getBadRate( &quad12, theCrit );
1620           double aBadRate13 = getBadRate( &quad13, theCrit );
1621           if (  aBadRate13 < aBadRate12 )
1622             Ok12 = false;
1623           else
1624             Ok13 = false;
1625         }
1626
1627         // Make quadrangles
1628         // and remove fused elems and removed links from the maps
1629         mapEl_setLi.erase( tr1 );
1630         if ( Ok12 ) {
1631           mapEl_setLi.erase( tr2 );
1632           mapLi_listEl.erase( *link12 );
1633           if(tr1->NbNodes()==3) {
1634             if( tr1->GetID() < tr2->GetID() ) {
1635               aMesh->ChangeElementNodes( tr1, n12, 4 );
1636               myLastCreatedElems.Append(tr1);
1637               aMesh->RemoveElement( tr2 );
1638             }
1639             else {
1640               aMesh->ChangeElementNodes( tr2, n12, 4 );
1641               myLastCreatedElems.Append(tr2);
1642               aMesh->RemoveElement( tr1);
1643             }
1644           }
1645           else {
1646             const SMDS_MeshNode* N1 [6];
1647             const SMDS_MeshNode* N2 [6];
1648             GetNodesFromTwoTria(tr1,tr2,N1,N2);
1649             // now we receive following N1 and N2 (using numeration as above image)
1650             // tria1 : (1 2 4 5 9 7)  and  tria2 : (3 4 2 8 9 6)
1651             // i.e. first nodes from both arrays determ new diagonal
1652             const SMDS_MeshNode* aNodes[8];
1653             aNodes[0] = N1[0];
1654             aNodes[1] = N1[1];
1655             aNodes[2] = N2[0];
1656             aNodes[3] = N2[1];
1657             aNodes[4] = N1[3];
1658             aNodes[5] = N2[5];
1659             aNodes[6] = N2[3];
1660             aNodes[7] = N1[5];
1661             if( tr1->GetID() < tr2->GetID() ) {
1662               GetMeshDS()->ChangeElementNodes( tr1, aNodes, 8 );
1663               myLastCreatedElems.Append(tr1);
1664               GetMeshDS()->RemoveElement( tr2 );
1665             }
1666             else {
1667               GetMeshDS()->ChangeElementNodes( tr2, aNodes, 8 );
1668               myLastCreatedElems.Append(tr2);
1669               GetMeshDS()->RemoveElement( tr1 );
1670             }
1671             // remove middle node (9)
1672             GetMeshDS()->RemoveNode( N1[4] );
1673           }
1674         }
1675         else if ( Ok13 ) {
1676           mapEl_setLi.erase( tr3 );
1677           mapLi_listEl.erase( *link13 );
1678           if(tr1->NbNodes()==3) {
1679             if( tr1->GetID() < tr2->GetID() ) {
1680               aMesh->ChangeElementNodes( tr1, n13, 4 );
1681               myLastCreatedElems.Append(tr1);
1682               aMesh->RemoveElement( tr3 );
1683             }
1684             else {
1685               aMesh->ChangeElementNodes( tr3, n13, 4 );
1686               myLastCreatedElems.Append(tr3);
1687               aMesh->RemoveElement( tr1 );
1688             }
1689           }
1690           else {
1691             const SMDS_MeshNode* N1 [6];
1692             const SMDS_MeshNode* N2 [6];
1693             GetNodesFromTwoTria(tr1,tr3,N1,N2);
1694             // now we receive following N1 and N2 (using numeration as above image)
1695             // tria1 : (1 2 4 5 9 7)  and  tria2 : (3 4 2 8 9 6)
1696             // i.e. first nodes from both arrays determ new diagonal
1697             const SMDS_MeshNode* aNodes[8];
1698             aNodes[0] = N1[0];
1699             aNodes[1] = N1[1];
1700             aNodes[2] = N2[0];
1701             aNodes[3] = N2[1];
1702             aNodes[4] = N1[3];
1703             aNodes[5] = N2[5];
1704             aNodes[6] = N2[3];
1705             aNodes[7] = N1[5];
1706             if( tr1->GetID() < tr2->GetID() ) {
1707               GetMeshDS()->ChangeElementNodes( tr1, aNodes, 8 );
1708               myLastCreatedElems.Append(tr1);
1709               GetMeshDS()->RemoveElement( tr3 );
1710             }
1711             else {
1712               GetMeshDS()->ChangeElementNodes( tr3, aNodes, 8 );
1713               myLastCreatedElems.Append(tr3);
1714               GetMeshDS()->RemoveElement( tr1 );
1715             }
1716             // remove middle node (9)
1717             GetMeshDS()->RemoveNode( N1[4] );
1718           }
1719         }
1720
1721         // Next element to fuse: the rejected one
1722         if ( tr3 )
1723           startElem = Ok12 ? tr3 : tr2;
1724
1725       } // if ( startElem )
1726     } // while ( startElem || !startLinks.empty() )
1727   } // while ( ! mapEl_setLi.empty() )
1728
1729   return true;
1730 }
1731
1732
1733 /*#define DUMPSO(txt) \
1734 //  cout << txt << endl;
1735 //=============================================================================
1736 //
1737 //
1738 //
1739 //=============================================================================
1740 static void swap( int i1, int i2, int idNodes[], gp_Pnt P[] )
1741 {
1742 if ( i1 == i2 )
1743 return;
1744 int tmp = idNodes[ i1 ];
1745 idNodes[ i1 ] = idNodes[ i2 ];
1746 idNodes[ i2 ] = tmp;
1747 gp_Pnt Ptmp = P[ i1 ];
1748 P[ i1 ] = P[ i2 ];
1749 P[ i2 ] = Ptmp;
1750 DUMPSO( i1 << "(" << idNodes[ i2 ] << ") <-> " << i2 << "(" << idNodes[ i1 ] << ")");
1751 }
1752
1753 //=======================================================================
1754 //function : SortQuadNodes
1755 //purpose  : Set 4 nodes of a quadrangle face in a good order.
1756 //           Swap 1<->2 or 2<->3 nodes and correspondingly return
1757 //           1 or 2 else 0.
1758 //=======================================================================
1759
1760 int SMESH_MeshEditor::SortQuadNodes (const SMDS_Mesh * theMesh,
1761 int               idNodes[] )
1762 {
1763   gp_Pnt P[4];
1764   int i;
1765   for ( i = 0; i < 4; i++ ) {
1766     const SMDS_MeshNode *n = theMesh->FindNode( idNodes[i] );
1767     if ( !n ) return 0;
1768     P[ i ].SetCoord( n->X(), n->Y(), n->Z() );
1769   }
1770
1771   gp_Vec V1(P[0], P[1]);
1772   gp_Vec V2(P[0], P[2]);
1773   gp_Vec V3(P[0], P[3]);
1774
1775   gp_Vec Cross1 = V1 ^ V2;
1776   gp_Vec Cross2 = V2 ^ V3;
1777
1778   i = 0;
1779   if (Cross1.Dot(Cross2) < 0)
1780   {
1781     Cross1 = V2 ^ V1;
1782     Cross2 = V1 ^ V3;
1783
1784     if (Cross1.Dot(Cross2) < 0)
1785       i = 2;
1786     else
1787       i = 1;
1788     swap ( i, i + 1, idNodes, P );
1789
1790     //     for ( int ii = 0; ii < 4; ii++ ) {
1791     //       const SMDS_MeshNode *n = theMesh->FindNode( idNodes[ii] );
1792     //       DUMPSO( ii << "(" << idNodes[ii] <<") : "<<n->X()<<" "<<n->Y()<<" "<<n->Z());
1793     //     }
1794   }
1795   return i;
1796 }
1797
1798 //=======================================================================
1799 //function : SortHexaNodes
1800 //purpose  : Set 8 nodes of a hexahedron in a good order.
1801 //           Return success status
1802 //=======================================================================
1803
1804 bool SMESH_MeshEditor::SortHexaNodes (const SMDS_Mesh * theMesh,
1805                                       int               idNodes[] )
1806 {
1807   gp_Pnt P[8];
1808   int i;
1809   DUMPSO( "INPUT: ========================================");
1810   for ( i = 0; i < 8; i++ ) {
1811     const SMDS_MeshNode *n = theMesh->FindNode( idNodes[i] );
1812     if ( !n ) return false;
1813     P[ i ].SetCoord( n->X(), n->Y(), n->Z() );
1814     DUMPSO( i << "(" << idNodes[i] <<") : "<<n->X()<<" "<<n->Y()<<" "<<n->Z());
1815   }
1816   DUMPSO( "========================================");
1817
1818
1819   set<int> faceNodes;  // ids of bottom face nodes, to be found
1820   set<int> checkedId1; // ids of tried 2-nd nodes
1821   Standard_Real leastDist = DBL_MAX; // dist of the 4-th node from 123 plane
1822   const Standard_Real tol = 1.e-6;   // tolerance to find nodes in plane
1823   int iMin, iLoop1 = 0;
1824
1825   // Loop to try the 2-nd nodes
1826
1827   while ( leastDist > DBL_MIN && ++iLoop1 < 8 )
1828   {
1829     // Find not checked 2-nd node
1830     for ( i = 1; i < 8; i++ )
1831       if ( checkedId1.find( idNodes[i] ) == checkedId1.end() ) {
1832         int id1 = idNodes[i];
1833         swap ( 1, i, idNodes, P );
1834         checkedId1.insert ( id1 );
1835         break;
1836       }
1837
1838     // Find the 3-d node so that 1-2-3 triangle to be on a hexa face,
1839     // ie that all but meybe one (id3 which is on the same face) nodes
1840     // lay on the same side from the triangle plane.
1841
1842     bool manyInPlane = false; // more than 4 nodes lay in plane
1843     int iLoop2 = 0;
1844     while ( ++iLoop2 < 6 ) {
1845
1846       // get 1-2-3 plane coeffs
1847       Standard_Real A, B, C, D;
1848       gp_Vec N = gp_Vec (P[0], P[1]).Crossed( gp_Vec (P[0], P[2]) );
1849       if ( N.SquareMagnitude() > gp::Resolution() )
1850       {
1851         gp_Pln pln ( P[0], N );
1852         pln.Coefficients( A, B, C, D );
1853
1854         // find the node (iMin) closest to pln
1855         Standard_Real dist[ 8 ], minDist = DBL_MAX;
1856         set<int> idInPln;
1857         for ( i = 3; i < 8; i++ ) {
1858           dist[i] = A * P[i].X() + B * P[i].Y() + C * P[i].Z() + D;
1859           if ( fabs( dist[i] ) < minDist ) {
1860             minDist = fabs( dist[i] );
1861             iMin = i;
1862           }
1863           if ( fabs( dist[i] ) <= tol )
1864             idInPln.insert( idNodes[i] );
1865         }
1866
1867         // there should not be more than 4 nodes in bottom plane
1868         if ( idInPln.size() > 1 )
1869         {
1870           DUMPSO( "### idInPln.size() = " << idInPln.size());
1871           // idInPlane does not contain the first 3 nodes
1872           if ( manyInPlane || idInPln.size() == 5)
1873             return false; // all nodes in one plane
1874           manyInPlane = true;
1875
1876           // set the 1-st node to be not in plane
1877           for ( i = 3; i < 8; i++ ) {
1878             if ( idInPln.find( idNodes[ i ] ) == idInPln.end() ) {
1879               DUMPSO( "### Reset 0-th node");
1880               swap( 0, i, idNodes, P );
1881               break;
1882             }
1883           }
1884
1885           // reset to re-check second nodes
1886           leastDist = DBL_MAX;
1887           faceNodes.clear();
1888           checkedId1.clear();
1889           iLoop1 = 0;
1890           break; // from iLoop2;
1891         }
1892
1893         // check that the other 4 nodes are on the same side
1894         bool sameSide = true;
1895         bool isNeg = dist[ iMin == 3 ? 4 : 3 ] <= 0.;
1896         for ( i = 3; sameSide && i < 8; i++ ) {
1897           if ( i != iMin )
1898             sameSide = ( isNeg == dist[i] <= 0.);
1899         }
1900
1901         // keep best solution
1902         if ( sameSide && minDist < leastDist ) {
1903           leastDist = minDist;
1904           faceNodes.clear();
1905           faceNodes.insert( idNodes[ 1 ] );
1906           faceNodes.insert( idNodes[ 2 ] );
1907           faceNodes.insert( idNodes[ iMin ] );
1908           DUMPSO( "loop " << iLoop2 << " id2 " << idNodes[ 1 ] << " id3 " << idNodes[ 2 ]
1909                   << " leastDist = " << leastDist);
1910           if ( leastDist <= DBL_MIN )
1911             break;
1912         }
1913       }
1914
1915       // set next 3-d node to check
1916       int iNext = 2 + iLoop2;
1917       if ( iNext < 8 ) {
1918         DUMPSO( "Try 2-nd");
1919         swap ( 2, iNext, idNodes, P );
1920       }
1921     } // while ( iLoop2 < 6 )
1922   } // iLoop1
1923
1924   if ( faceNodes.empty() ) return false;
1925
1926   // Put the faceNodes in proper places
1927   for ( i = 4; i < 8; i++ ) {
1928     if ( faceNodes.find( idNodes[ i ] ) != faceNodes.end() ) {
1929       // find a place to put
1930       int iTo = 1;
1931       while ( faceNodes.find( idNodes[ iTo ] ) != faceNodes.end() )
1932         iTo++;
1933       DUMPSO( "Set faceNodes");
1934       swap ( iTo, i, idNodes, P );
1935     }
1936   }
1937
1938
1939   // Set nodes of the found bottom face in good order
1940   DUMPSO( " Found bottom face: ");
1941   i = SortQuadNodes( theMesh, idNodes );
1942   if ( i ) {
1943     gp_Pnt Ptmp = P[ i ];
1944     P[ i ] = P[ i+1 ];
1945     P[ i+1 ] = Ptmp;
1946   }
1947   //   else
1948   //     for ( int ii = 0; ii < 4; ii++ ) {
1949   //       const SMDS_MeshNode *n = theMesh->FindNode( idNodes[ii] );
1950   //       DUMPSO( ii << "(" << idNodes[ii] <<") : "<<n->X()<<" "<<n->Y()<<" "<<n->Z());
1951   //    }
1952
1953   // Gravity center of the top and bottom faces
1954   gp_Pnt aGCb = ( P[0].XYZ() + P[1].XYZ() + P[2].XYZ() + P[3].XYZ() ) / 4.;
1955   gp_Pnt aGCt = ( P[4].XYZ() + P[5].XYZ() + P[6].XYZ() + P[7].XYZ() ) / 4.;
1956
1957   // Get direction from the bottom to the top face
1958   gp_Vec upDir ( aGCb, aGCt );
1959   Standard_Real upDirSize = upDir.Magnitude();
1960   if ( upDirSize <= gp::Resolution() ) return false;
1961   upDir / upDirSize;
1962
1963   // Assure that the bottom face normal points up
1964   gp_Vec Nb = gp_Vec (P[0], P[1]).Crossed( gp_Vec (P[0], P[2]) );
1965   Nb += gp_Vec (P[0], P[2]).Crossed( gp_Vec (P[0], P[3]) );
1966   if ( Nb.Dot( upDir ) < 0 ) {
1967     DUMPSO( "Reverse bottom face");
1968     swap( 1, 3, idNodes, P );
1969   }
1970
1971   // Find 5-th node - the one closest to the 1-st among the last 4 nodes.
1972   Standard_Real minDist = DBL_MAX;
1973   for ( i = 4; i < 8; i++ ) {
1974     // projection of P[i] to the plane defined by P[0] and upDir
1975     gp_Pnt Pp = P[i].Translated( upDir * ( upDir.Dot( gp_Vec( P[i], P[0] ))));
1976     Standard_Real sqDist = P[0].SquareDistance( Pp );
1977     if ( sqDist < minDist ) {
1978       minDist = sqDist;
1979       iMin = i;
1980     }
1981   }
1982   DUMPSO( "Set 4-th");
1983   swap ( 4, iMin, idNodes, P );
1984
1985   // Set nodes of the top face in good order
1986   DUMPSO( "Sort top face");
1987   i = SortQuadNodes( theMesh, &idNodes[4] );
1988   if ( i ) {
1989     i += 4;
1990     gp_Pnt Ptmp = P[ i ];
1991     P[ i ] = P[ i+1 ];
1992     P[ i+1 ] = Ptmp;
1993   }
1994
1995   // Assure that direction of the top face normal is from the bottom face
1996   gp_Vec Nt = gp_Vec (P[4], P[5]).Crossed( gp_Vec (P[4], P[6]) );
1997   Nt += gp_Vec (P[4], P[6]).Crossed( gp_Vec (P[4], P[7]) );
1998   if ( Nt.Dot( upDir ) < 0 ) {
1999     DUMPSO( "Reverse top face");
2000     swap( 5, 7, idNodes, P );
2001   }
2002
2003   //   DUMPSO( "OUTPUT: ========================================");
2004   //   for ( i = 0; i < 8; i++ ) {
2005   //     float *p = ugrid->GetPoint(idNodes[i]);
2006   //     DUMPSO( i << "(" << idNodes[i] << ") : " << p[0] << " " << p[1] << " " << p[2]);
2007   //   }
2008
2009   return true;
2010 }*/
2011
2012 //================================================================================
2013 /*!
2014  * \brief Return nodes linked to the given one
2015  * \param theNode - the node
2016  * \param linkedNodes - the found nodes
2017  * \param type - the type of elements to check
2018  *
2019  * Medium nodes are ignored
2020  */
2021 //================================================================================
2022
2023 void SMESH_MeshEditor::GetLinkedNodes( const SMDS_MeshNode* theNode,
2024                                        TIDSortedElemSet &   linkedNodes,
2025                                        SMDSAbs_ElementType  type )
2026 {
2027   SMDS_ElemIteratorPtr elemIt = theNode->GetInverseElementIterator(type);
2028   while ( elemIt->more() )
2029   {
2030     const SMDS_MeshElement* elem = elemIt->next();
2031     SMDS_ElemIteratorPtr nodeIt = elem->nodesIterator();
2032     if ( elem->GetType() == SMDSAbs_Volume )
2033     {
2034       SMDS_VolumeTool vol( elem );
2035       while ( nodeIt->more() ) {
2036         const SMDS_MeshNode* n = cast2Node( nodeIt->next() );
2037         if ( theNode != n && vol.IsLinked( theNode, n ))
2038           linkedNodes.insert( n );
2039       }
2040     }
2041     else
2042     {
2043       for ( int i = 0; nodeIt->more(); ++i ) {
2044         const SMDS_MeshNode* n = cast2Node( nodeIt->next() );
2045         if ( n == theNode ) {
2046           int iBefore = i - 1;
2047           int iAfter  = i + 1;
2048           if ( elem->IsQuadratic() ) {
2049             int nb = elem->NbNodes() / 2;
2050             iAfter  = SMESH_MesherHelper::WrapIndex( iAfter, nb );
2051             iBefore = SMESH_MesherHelper::WrapIndex( iBefore, nb );
2052           }
2053           linkedNodes.insert( elem->GetNodeWrap( iAfter ));
2054           linkedNodes.insert( elem->GetNodeWrap( iBefore ));
2055         }
2056       }
2057     }
2058   }
2059 }
2060
2061 //=======================================================================
2062 //function : laplacianSmooth
2063 //purpose  : pulls theNode toward the center of surrounding nodes directly
2064 //           connected to that node along an element edge
2065 //=======================================================================
2066
2067 void laplacianSmooth(const SMDS_MeshNode*                 theNode,
2068                      const Handle(Geom_Surface)&          theSurface,
2069                      map< const SMDS_MeshNode*, gp_XY* >& theUVMap)
2070 {
2071   // find surrounding nodes
2072
2073   TIDSortedElemSet nodeSet;
2074   SMESH_MeshEditor::GetLinkedNodes( theNode, nodeSet, SMDSAbs_Face );
2075
2076   // compute new coodrs
2077
2078   double coord[] = { 0., 0., 0. };
2079   TIDSortedElemSet::iterator nodeSetIt = nodeSet.begin();
2080   for ( ; nodeSetIt != nodeSet.end(); nodeSetIt++ ) {
2081     const SMDS_MeshNode* node = cast2Node(*nodeSetIt);
2082     if ( theSurface.IsNull() ) { // smooth in 3D
2083       coord[0] += node->X();
2084       coord[1] += node->Y();
2085       coord[2] += node->Z();
2086     }
2087     else { // smooth in 2D
2088       ASSERT( theUVMap.find( node ) != theUVMap.end() );
2089       gp_XY* uv = theUVMap[ node ];
2090       coord[0] += uv->X();
2091       coord[1] += uv->Y();
2092     }
2093   }
2094   int nbNodes = nodeSet.size();
2095   if ( !nbNodes )
2096     return;
2097   coord[0] /= nbNodes;
2098   coord[1] /= nbNodes;
2099
2100   if ( !theSurface.IsNull() ) {
2101     ASSERT( theUVMap.find( theNode ) != theUVMap.end() );
2102     theUVMap[ theNode ]->SetCoord( coord[0], coord[1] );
2103     gp_Pnt p3d = theSurface->Value( coord[0], coord[1] );
2104     coord[0] = p3d.X();
2105     coord[1] = p3d.Y();
2106     coord[2] = p3d.Z();
2107   }
2108   else
2109     coord[2] /= nbNodes;
2110
2111   // move node
2112
2113   const_cast< SMDS_MeshNode* >( theNode )->setXYZ(coord[0],coord[1],coord[2]);
2114 }
2115
2116 //=======================================================================
2117 //function : centroidalSmooth
2118 //purpose  : pulls theNode toward the element-area-weighted centroid of the
2119 //           surrounding elements
2120 //=======================================================================
2121
2122 void centroidalSmooth(const SMDS_MeshNode*                 theNode,
2123                       const Handle(Geom_Surface)&          theSurface,
2124                       map< const SMDS_MeshNode*, gp_XY* >& theUVMap)
2125 {
2126   gp_XYZ aNewXYZ(0.,0.,0.);
2127   SMESH::Controls::Area anAreaFunc;
2128   double totalArea = 0.;
2129   int nbElems = 0;
2130
2131   // compute new XYZ
2132
2133   SMDS_ElemIteratorPtr elemIt = theNode->GetInverseElementIterator(SMDSAbs_Face);
2134   while ( elemIt->more() )
2135   {
2136     const SMDS_MeshElement* elem = elemIt->next();
2137     nbElems++;
2138
2139     gp_XYZ elemCenter(0.,0.,0.);
2140     SMESH::Controls::TSequenceOfXYZ aNodePoints;
2141     SMDS_ElemIteratorPtr itN = elem->nodesIterator();
2142     int nn = elem->NbNodes();
2143     if(elem->IsQuadratic()) nn = nn/2;
2144     int i=0;
2145     //while ( itN->more() ) {
2146     while ( i<nn ) {
2147       const SMDS_MeshNode* aNode = static_cast<const SMDS_MeshNode*>( itN->next() );
2148       i++;
2149       gp_XYZ aP( aNode->X(), aNode->Y(), aNode->Z() );
2150       aNodePoints.push_back( aP );
2151       if ( !theSurface.IsNull() ) { // smooth in 2D
2152         ASSERT( theUVMap.find( aNode ) != theUVMap.end() );
2153         gp_XY* uv = theUVMap[ aNode ];
2154         aP.SetCoord( uv->X(), uv->Y(), 0. );
2155       }
2156       elemCenter += aP;
2157     }
2158     double elemArea = anAreaFunc.GetValue( aNodePoints );
2159     totalArea += elemArea;
2160     elemCenter /= nn;
2161     aNewXYZ += elemCenter * elemArea;
2162   }
2163   aNewXYZ /= totalArea;
2164   if ( !theSurface.IsNull() ) {
2165     theUVMap[ theNode ]->SetCoord( aNewXYZ.X(), aNewXYZ.Y() );
2166     aNewXYZ = theSurface->Value( aNewXYZ.X(), aNewXYZ.Y() ).XYZ();
2167   }
2168
2169   // move node
2170
2171   const_cast< SMDS_MeshNode* >( theNode )->setXYZ(aNewXYZ.X(),aNewXYZ.Y(),aNewXYZ.Z());
2172 }
2173
2174 //=======================================================================
2175 //function : getClosestUV
2176 //purpose  : return UV of closest projection
2177 //=======================================================================
2178
2179 static bool getClosestUV (Extrema_GenExtPS& projector,
2180                           const gp_Pnt&     point,
2181                           gp_XY &           result)
2182 {
2183   projector.Perform( point );
2184   if ( projector.IsDone() ) {
2185     double u, v, minVal = DBL_MAX;
2186     for ( int i = projector.NbExt(); i > 0; i-- )
2187       if ( projector.Value( i ) < minVal ) {
2188         minVal = projector.Value( i );
2189         projector.Point( i ).Parameter( u, v );
2190       }
2191     result.SetCoord( u, v );
2192     return true;
2193   }
2194   return false;
2195 }
2196
2197 //=======================================================================
2198 //function : Smooth
2199 //purpose  : Smooth theElements during theNbIterations or until a worst
2200 //           element has aspect ratio <= theTgtAspectRatio.
2201 //           Aspect Ratio varies in range [1.0, inf].
2202 //           If theElements is empty, the whole mesh is smoothed.
2203 //           theFixedNodes contains additionally fixed nodes. Nodes built
2204 //           on edges and boundary nodes are always fixed.
2205 //=======================================================================
2206
2207 void SMESH_MeshEditor::Smooth (TIDSortedElemSet &          theElems,
2208                                set<const SMDS_MeshNode*> & theFixedNodes,
2209                                const SmoothMethod          theSmoothMethod,
2210                                const int                   theNbIterations,
2211                                double                      theTgtAspectRatio,
2212                                const bool                  the2D)
2213 {
2214   myLastCreatedElems.Clear();
2215   myLastCreatedNodes.Clear();
2216
2217   MESSAGE((theSmoothMethod==LAPLACIAN ? "LAPLACIAN" : "CENTROIDAL") << "--::Smooth()");
2218
2219   if ( theTgtAspectRatio < 1.0 )
2220     theTgtAspectRatio = 1.0;
2221
2222   const double disttol = 1.e-16;
2223
2224   SMESH::Controls::AspectRatio aQualityFunc;
2225
2226   SMESHDS_Mesh* aMesh = GetMeshDS();
2227
2228   if ( theElems.empty() ) {
2229     // add all faces to theElems
2230     SMDS_FaceIteratorPtr fIt = aMesh->facesIterator();
2231     while ( fIt->more() ) {
2232       const SMDS_MeshElement* face = fIt->next();
2233       theElems.insert( face );
2234     }
2235   }
2236   // get all face ids theElems are on
2237   set< int > faceIdSet;
2238   TIDSortedElemSet::iterator itElem;
2239   if ( the2D )
2240     for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
2241       int fId = FindShape( *itElem );
2242       // check that corresponding submesh exists and a shape is face
2243       if (fId &&
2244           faceIdSet.find( fId ) == faceIdSet.end() &&
2245           aMesh->MeshElements( fId )) {
2246         TopoDS_Shape F = aMesh->IndexToShape( fId );
2247         if ( !F.IsNull() && F.ShapeType() == TopAbs_FACE )
2248           faceIdSet.insert( fId );
2249       }
2250     }
2251   faceIdSet.insert( 0 ); // to smooth elements that are not on any TopoDS_Face
2252
2253   // ===============================================
2254   // smooth elements on each TopoDS_Face separately
2255   // ===============================================
2256
2257   set< int >::reverse_iterator fId = faceIdSet.rbegin(); // treate 0 fId at the end
2258   for ( ; fId != faceIdSet.rend(); ++fId ) {
2259     // get face surface and submesh
2260     Handle(Geom_Surface) surface;
2261     SMESHDS_SubMesh* faceSubMesh = 0;
2262     TopoDS_Face face;
2263     double fToler2 = 0, vPeriod = 0., uPeriod = 0., f,l;
2264     double u1 = 0, u2 = 0, v1 = 0, v2 = 0;
2265     bool isUPeriodic = false, isVPeriodic = false;
2266     if ( *fId ) {
2267       face = TopoDS::Face( aMesh->IndexToShape( *fId ));
2268       surface = BRep_Tool::Surface( face );
2269       faceSubMesh = aMesh->MeshElements( *fId );
2270       fToler2 = BRep_Tool::Tolerance( face );
2271       fToler2 *= fToler2 * 10.;
2272       isUPeriodic = surface->IsUPeriodic();
2273       if ( isUPeriodic )
2274         vPeriod = surface->UPeriod();
2275       isVPeriodic = surface->IsVPeriodic();
2276       if ( isVPeriodic )
2277         uPeriod = surface->VPeriod();
2278       surface->Bounds( u1, u2, v1, v2 );
2279     }
2280     // ---------------------------------------------------------
2281     // for elements on a face, find movable and fixed nodes and
2282     // compute UV for them
2283     // ---------------------------------------------------------
2284     bool checkBoundaryNodes = false;
2285     bool isQuadratic = false;
2286     set<const SMDS_MeshNode*> setMovableNodes;
2287     map< const SMDS_MeshNode*, gp_XY* > uvMap, uvMap2;
2288     list< gp_XY > listUV; // uvs the 2 uvMaps refer to
2289     list< const SMDS_MeshElement* > elemsOnFace;
2290
2291     Extrema_GenExtPS projector;
2292     GeomAdaptor_Surface surfAdaptor;
2293     if ( !surface.IsNull() ) {
2294       surfAdaptor.Load( surface );
2295       projector.Initialize( surfAdaptor, 20,20, 1e-5,1e-5 );
2296     }
2297     int nbElemOnFace = 0;
2298     itElem = theElems.begin();
2299     // loop on not yet smoothed elements: look for elems on a face
2300     while ( itElem != theElems.end() ) {
2301       if ( faceSubMesh && nbElemOnFace == faceSubMesh->NbElements() )
2302         break; // all elements found
2303
2304       const SMDS_MeshElement* elem = *itElem;
2305       if ( !elem || elem->GetType() != SMDSAbs_Face || elem->NbNodes() < 3 ||
2306            ( faceSubMesh && !faceSubMesh->Contains( elem ))) {
2307         ++itElem;
2308         continue;
2309       }
2310       elemsOnFace.push_back( elem );
2311       theElems.erase( itElem++ );
2312       nbElemOnFace++;
2313
2314       if ( !isQuadratic )
2315         isQuadratic = elem->IsQuadratic();
2316
2317       // get movable nodes of elem
2318       const SMDS_MeshNode* node;
2319       SMDS_TypeOfPosition posType;
2320       SMDS_ElemIteratorPtr itN = elem->nodesIterator();
2321       int nn = 0, nbn =  elem->NbNodes();
2322       if(elem->IsQuadratic())
2323         nbn = nbn/2;
2324       while ( nn++ < nbn ) {
2325         node = static_cast<const SMDS_MeshNode*>( itN->next() );
2326         const SMDS_PositionPtr& pos = node->GetPosition();
2327         posType = pos.get() ? pos->GetTypeOfPosition() : SMDS_TOP_3DSPACE;
2328         if (posType != SMDS_TOP_EDGE &&
2329             posType != SMDS_TOP_VERTEX &&
2330             theFixedNodes.find( node ) == theFixedNodes.end())
2331         {
2332           // check if all faces around the node are on faceSubMesh
2333           // because a node on edge may be bound to face
2334           SMDS_ElemIteratorPtr eIt = node->GetInverseElementIterator(SMDSAbs_Face);
2335           bool all = true;
2336           if ( faceSubMesh ) {
2337             while ( eIt->more() && all ) {
2338               const SMDS_MeshElement* e = eIt->next();
2339               all = faceSubMesh->Contains( e );
2340             }
2341           }
2342           if ( all )
2343             setMovableNodes.insert( node );
2344           else
2345             checkBoundaryNodes = true;
2346         }
2347         if ( posType == SMDS_TOP_3DSPACE )
2348           checkBoundaryNodes = true;
2349       }
2350
2351       if ( surface.IsNull() )
2352         continue;
2353
2354       // get nodes to check UV
2355       list< const SMDS_MeshNode* > uvCheckNodes;
2356       itN = elem->nodesIterator();
2357       nn = 0; nbn =  elem->NbNodes();
2358       if(elem->IsQuadratic())
2359         nbn = nbn/2;
2360       while ( nn++ < nbn ) {
2361         node = static_cast<const SMDS_MeshNode*>( itN->next() );
2362         if ( uvMap.find( node ) == uvMap.end() )
2363           uvCheckNodes.push_back( node );
2364         // add nodes of elems sharing node
2365         //         SMDS_ElemIteratorPtr eIt = node->GetInverseElementIterator(SMDSAbs_Face);
2366         //         while ( eIt->more() ) {
2367         //           const SMDS_MeshElement* e = eIt->next();
2368         //           if ( e != elem ) {
2369         //             SMDS_ElemIteratorPtr nIt = e->nodesIterator();
2370         //             while ( nIt->more() ) {
2371         //               const SMDS_MeshNode* n =
2372         //                 static_cast<const SMDS_MeshNode*>( nIt->next() );
2373         //               if ( uvMap.find( n ) == uvMap.end() )
2374         //                 uvCheckNodes.push_back( n );
2375         //             }
2376         //           }
2377         //         }
2378       }
2379       // check UV on face
2380       list< const SMDS_MeshNode* >::iterator n = uvCheckNodes.begin();
2381       for ( ; n != uvCheckNodes.end(); ++n ) {
2382         node = *n;
2383         gp_XY uv( 0, 0 );
2384         const SMDS_PositionPtr& pos = node->GetPosition();
2385         posType = pos.get() ? pos->GetTypeOfPosition() : SMDS_TOP_3DSPACE;
2386         // get existing UV
2387         switch ( posType ) {
2388         case SMDS_TOP_FACE: {
2389           SMDS_FacePosition* fPos = ( SMDS_FacePosition* ) pos.get();
2390           uv.SetCoord( fPos->GetUParameter(), fPos->GetVParameter() );
2391           break;
2392         }
2393         case SMDS_TOP_EDGE: {
2394           TopoDS_Shape S = aMesh->IndexToShape( pos->GetShapeId() );
2395           Handle(Geom2d_Curve) pcurve;
2396           if ( !S.IsNull() && S.ShapeType() == TopAbs_EDGE )
2397             pcurve = BRep_Tool::CurveOnSurface( TopoDS::Edge( S ), face, f,l );
2398           if ( !pcurve.IsNull() ) {
2399             double u = (( SMDS_EdgePosition* ) pos.get() )->GetUParameter();
2400             uv = pcurve->Value( u ).XY();
2401           }
2402           break;
2403         }
2404         case SMDS_TOP_VERTEX: {
2405           TopoDS_Shape S = aMesh->IndexToShape( pos->GetShapeId() );
2406           if ( !S.IsNull() && S.ShapeType() == TopAbs_VERTEX )
2407             uv = BRep_Tool::Parameters( TopoDS::Vertex( S ), face ).XY();
2408           break;
2409         }
2410         default:;
2411         }
2412         // check existing UV
2413         bool project = true;
2414         gp_Pnt pNode ( node->X(), node->Y(), node->Z() );
2415         double dist1 = DBL_MAX, dist2 = 0;
2416         if ( posType != SMDS_TOP_3DSPACE ) {
2417           dist1 = pNode.SquareDistance( surface->Value( uv.X(), uv.Y() ));
2418           project = dist1 > fToler2;
2419         }
2420         if ( project ) { // compute new UV
2421           gp_XY newUV;
2422           if ( !getClosestUV( projector, pNode, newUV )) {
2423             MESSAGE("Node Projection Failed " << node);
2424           }
2425           else {
2426             if ( isUPeriodic )
2427               newUV.SetX( ElCLib::InPeriod( newUV.X(), u1, u2 ));
2428             if ( isVPeriodic )
2429               newUV.SetY( ElCLib::InPeriod( newUV.Y(), v1, v2 ));
2430             // check new UV
2431             if ( posType != SMDS_TOP_3DSPACE )
2432               dist2 = pNode.SquareDistance( surface->Value( newUV.X(), newUV.Y() ));
2433             if ( dist2 < dist1 )
2434               uv = newUV;
2435           }
2436         }
2437         // store UV in the map
2438         listUV.push_back( uv );
2439         uvMap.insert( make_pair( node, &listUV.back() ));
2440       }
2441     } // loop on not yet smoothed elements
2442
2443     if ( !faceSubMesh || nbElemOnFace != faceSubMesh->NbElements() )
2444       checkBoundaryNodes = true;
2445
2446     // fix nodes on mesh boundary
2447
2448     if ( checkBoundaryNodes ) {
2449       map< NLink, int > linkNbMap; // how many times a link encounters in elemsOnFace
2450       map< NLink, int >::iterator link_nb;
2451       // put all elements links to linkNbMap
2452       list< const SMDS_MeshElement* >::iterator elemIt = elemsOnFace.begin();
2453       for ( ; elemIt != elemsOnFace.end(); ++elemIt ) {
2454         const SMDS_MeshElement* elem = (*elemIt);
2455         int nbn =  elem->NbNodes();
2456         if(elem->IsQuadratic())
2457           nbn = nbn/2;
2458         // loop on elem links: insert them in linkNbMap
2459         const SMDS_MeshNode* curNode, *prevNode = elem->GetNodeWrap( nbn );
2460         for ( int iN = 0; iN < nbn; ++iN ) {
2461           curNode = elem->GetNode( iN );
2462           NLink link;
2463           if ( curNode < prevNode ) link = make_pair( curNode , prevNode );
2464           else                      link = make_pair( prevNode , curNode );
2465           prevNode = curNode;
2466           link_nb = linkNbMap.find( link );
2467           if ( link_nb == linkNbMap.end() )
2468             linkNbMap.insert( make_pair ( link, 1 ));
2469           else
2470             link_nb->second++;
2471         }
2472       }
2473       // remove nodes that are in links encountered only once from setMovableNodes
2474       for ( link_nb = linkNbMap.begin(); link_nb != linkNbMap.end(); ++link_nb ) {
2475         if ( link_nb->second == 1 ) {
2476           setMovableNodes.erase( link_nb->first.first );
2477           setMovableNodes.erase( link_nb->first.second );
2478         }
2479       }
2480     }
2481
2482     // -----------------------------------------------------
2483     // for nodes on seam edge, compute one more UV ( uvMap2 );
2484     // find movable nodes linked to nodes on seam and which
2485     // are to be smoothed using the second UV ( uvMap2 )
2486     // -----------------------------------------------------
2487
2488     set<const SMDS_MeshNode*> nodesNearSeam; // to smooth using uvMap2
2489     if ( !surface.IsNull() ) {
2490       TopExp_Explorer eExp( face, TopAbs_EDGE );
2491       for ( ; eExp.More(); eExp.Next() ) {
2492         TopoDS_Edge edge = TopoDS::Edge( eExp.Current() );
2493         if ( !BRep_Tool::IsClosed( edge, face ))
2494           continue;
2495         SMESHDS_SubMesh* sm = aMesh->MeshElements( edge );
2496         if ( !sm ) continue;
2497         // find out which parameter varies for a node on seam
2498         double f,l;
2499         gp_Pnt2d uv1, uv2;
2500         Handle(Geom2d_Curve) pcurve = BRep_Tool::CurveOnSurface( edge, face, f, l );
2501         if ( pcurve.IsNull() ) continue;
2502         uv1 = pcurve->Value( f );
2503         edge.Reverse();
2504         pcurve = BRep_Tool::CurveOnSurface( edge, face, f, l );
2505         if ( pcurve.IsNull() ) continue;
2506         uv2 = pcurve->Value( f );
2507         int iPar = Abs( uv1.X() - uv2.X() ) > Abs( uv1.Y() - uv2.Y() ) ? 1 : 2;
2508         // assure uv1 < uv2
2509         if ( uv1.Coord( iPar ) > uv2.Coord( iPar )) {
2510           gp_Pnt2d tmp = uv1; uv1 = uv2; uv2 = tmp;
2511         }
2512         // get nodes on seam and its vertices
2513         list< const SMDS_MeshNode* > seamNodes;
2514         SMDS_NodeIteratorPtr nSeamIt = sm->GetNodes();
2515         while ( nSeamIt->more() ) {
2516           const SMDS_MeshNode* node = nSeamIt->next();
2517           if ( !isQuadratic || !IsMedium( node ))
2518             seamNodes.push_back( node );
2519         }
2520         TopExp_Explorer vExp( edge, TopAbs_VERTEX );
2521         for ( ; vExp.More(); vExp.Next() ) {
2522           sm = aMesh->MeshElements( vExp.Current() );
2523           if ( sm ) {
2524             nSeamIt = sm->GetNodes();
2525             while ( nSeamIt->more() )
2526               seamNodes.push_back( nSeamIt->next() );
2527           }
2528         }
2529         // loop on nodes on seam
2530         list< const SMDS_MeshNode* >::iterator noSeIt = seamNodes.begin();
2531         for ( ; noSeIt != seamNodes.end(); ++noSeIt ) {
2532           const SMDS_MeshNode* nSeam = *noSeIt;
2533           map< const SMDS_MeshNode*, gp_XY* >::iterator n_uv = uvMap.find( nSeam );
2534           if ( n_uv == uvMap.end() )
2535             continue;
2536           // set the first UV
2537           n_uv->second->SetCoord( iPar, uv1.Coord( iPar ));
2538           // set the second UV
2539           listUV.push_back( *n_uv->second );
2540           listUV.back().SetCoord( iPar, uv2.Coord( iPar ));
2541           if ( uvMap2.empty() )
2542             uvMap2 = uvMap; // copy the uvMap contents
2543           uvMap2[ nSeam ] = &listUV.back();
2544
2545           // collect movable nodes linked to ones on seam in nodesNearSeam
2546           SMDS_ElemIteratorPtr eIt = nSeam->GetInverseElementIterator(SMDSAbs_Face);
2547           while ( eIt->more() ) {
2548             const SMDS_MeshElement* e = eIt->next();
2549             int nbUseMap1 = 0, nbUseMap2 = 0;
2550             SMDS_ElemIteratorPtr nIt = e->nodesIterator();
2551             int nn = 0, nbn =  e->NbNodes();
2552             if(e->IsQuadratic()) nbn = nbn/2;
2553             while ( nn++ < nbn )
2554             {
2555               const SMDS_MeshNode* n =
2556                 static_cast<const SMDS_MeshNode*>( nIt->next() );
2557               if (n == nSeam ||
2558                   setMovableNodes.find( n ) == setMovableNodes.end() )
2559                 continue;
2560               // add only nodes being closer to uv2 than to uv1
2561               gp_Pnt pMid (0.5 * ( n->X() + nSeam->X() ),
2562                            0.5 * ( n->Y() + nSeam->Y() ),
2563                            0.5 * ( n->Z() + nSeam->Z() ));
2564               gp_XY uv;
2565               getClosestUV( projector, pMid, uv );
2566               if ( uv.Coord( iPar ) > uvMap[ n ]->Coord( iPar ) ) {
2567                 nodesNearSeam.insert( n );
2568                 nbUseMap2++;
2569               }
2570               else
2571                 nbUseMap1++;
2572             }
2573             // for centroidalSmooth all element nodes must
2574             // be on one side of a seam
2575             if ( theSmoothMethod == CENTROIDAL && nbUseMap1 && nbUseMap2 ) {
2576               SMDS_ElemIteratorPtr nIt = e->nodesIterator();
2577               nn = 0;
2578               while ( nn++ < nbn ) {
2579                 const SMDS_MeshNode* n =
2580                   static_cast<const SMDS_MeshNode*>( nIt->next() );
2581                 setMovableNodes.erase( n );
2582               }
2583             }
2584           }
2585         } // loop on nodes on seam
2586       } // loop on edge of a face
2587     } // if ( !face.IsNull() )
2588
2589     if ( setMovableNodes.empty() ) {
2590       MESSAGE( "Face id : " << *fId << " - NO SMOOTHING: no nodes to move!!!");
2591       continue; // goto next face
2592     }
2593
2594     // -------------
2595     // SMOOTHING //
2596     // -------------
2597
2598     int it = -1;
2599     double maxRatio = -1., maxDisplacement = -1.;
2600     set<const SMDS_MeshNode*>::iterator nodeToMove;
2601     for ( it = 0; it < theNbIterations; it++ ) {
2602       maxDisplacement = 0.;
2603       nodeToMove = setMovableNodes.begin();
2604       for ( ; nodeToMove != setMovableNodes.end(); nodeToMove++ ) {
2605         const SMDS_MeshNode* node = (*nodeToMove);
2606         gp_XYZ aPrevPos ( node->X(), node->Y(), node->Z() );
2607
2608         // smooth
2609         bool map2 = ( nodesNearSeam.find( node ) != nodesNearSeam.end() );
2610         if ( theSmoothMethod == LAPLACIAN )
2611           laplacianSmooth( node, surface, map2 ? uvMap2 : uvMap );
2612         else
2613           centroidalSmooth( node, surface, map2 ? uvMap2 : uvMap );
2614
2615         // node displacement
2616         gp_XYZ aNewPos ( node->X(), node->Y(), node->Z() );
2617         Standard_Real aDispl = (aPrevPos - aNewPos).SquareModulus();
2618         if ( aDispl > maxDisplacement )
2619           maxDisplacement = aDispl;
2620       }
2621       // no node movement => exit
2622       //if ( maxDisplacement < 1.e-16 ) {
2623       if ( maxDisplacement < disttol ) {
2624         MESSAGE("-- no node movement --");
2625         break;
2626       }
2627
2628       // check elements quality
2629       maxRatio  = 0;
2630       list< const SMDS_MeshElement* >::iterator elemIt = elemsOnFace.begin();
2631       for ( ; elemIt != elemsOnFace.end(); ++elemIt ) {
2632         const SMDS_MeshElement* elem = (*elemIt);
2633         if ( !elem || elem->GetType() != SMDSAbs_Face )
2634           continue;
2635         SMESH::Controls::TSequenceOfXYZ aPoints;
2636         if ( aQualityFunc.GetPoints( elem, aPoints )) {
2637           double aValue = aQualityFunc.GetValue( aPoints );
2638           if ( aValue > maxRatio )
2639             maxRatio = aValue;
2640         }
2641       }
2642       if ( maxRatio <= theTgtAspectRatio ) {
2643         MESSAGE("-- quality achived --");
2644         break;
2645       }
2646       if (it+1 == theNbIterations) {
2647         MESSAGE("-- Iteration limit exceeded --");
2648       }
2649     } // smoothing iterations
2650
2651     MESSAGE(" Face id: " << *fId <<
2652             " Nb iterstions: " << it <<
2653             " Displacement: " << maxDisplacement <<
2654             " Aspect Ratio " << maxRatio);
2655
2656     // ---------------------------------------
2657     // new nodes positions are computed,
2658     // record movement in DS and set new UV
2659     // ---------------------------------------
2660     nodeToMove = setMovableNodes.begin();
2661     for ( ; nodeToMove != setMovableNodes.end(); nodeToMove++ ) {
2662       SMDS_MeshNode* node = const_cast< SMDS_MeshNode* > (*nodeToMove);
2663       aMesh->MoveNode( node, node->X(), node->Y(), node->Z() );
2664       map< const SMDS_MeshNode*, gp_XY* >::iterator node_uv = uvMap.find( node );
2665       if ( node_uv != uvMap.end() ) {
2666         gp_XY* uv = node_uv->second;
2667         node->SetPosition
2668           ( SMDS_PositionPtr( new SMDS_FacePosition( *fId, uv->X(), uv->Y() )));
2669       }
2670     }
2671
2672     // move medium nodes of quadratic elements
2673     if ( isQuadratic )
2674     {
2675       SMESH_MesherHelper helper( *GetMesh() );
2676       if ( !face.IsNull() )
2677         helper.SetSubShape( face );
2678       list< const SMDS_MeshElement* >::iterator elemIt = elemsOnFace.begin();
2679       for ( ; elemIt != elemsOnFace.end(); ++elemIt ) {
2680         const SMDS_QuadraticFaceOfNodes* QF =
2681           dynamic_cast<const SMDS_QuadraticFaceOfNodes*> (*elemIt);
2682         if(QF) {
2683           vector<const SMDS_MeshNode*> Ns;
2684           Ns.reserve(QF->NbNodes()+1);
2685           SMDS_NodeIteratorPtr anIter = QF->interlacedNodesIterator();
2686           while ( anIter->more() )
2687             Ns.push_back( anIter->next() );
2688           Ns.push_back( Ns[0] );
2689           double x, y, z;
2690           for(int i=0; i<QF->NbNodes(); i=i+2) {
2691             if ( !surface.IsNull() ) {
2692               gp_XY uv1 = helper.GetNodeUV( face, Ns[i], Ns[i+2] );
2693               gp_XY uv2 = helper.GetNodeUV( face, Ns[i+2], Ns[i] );
2694               gp_XY uv = ( uv1 + uv2 ) / 2.;
2695               gp_Pnt xyz = surface->Value( uv.X(), uv.Y() );
2696               x = xyz.X(); y = xyz.Y(); z = xyz.Z();
2697             }
2698             else {
2699               x = (Ns[i]->X() + Ns[i+2]->X())/2;
2700               y = (Ns[i]->Y() + Ns[i+2]->Y())/2;
2701               z = (Ns[i]->Z() + Ns[i+2]->Z())/2;
2702             }
2703             if( fabs( Ns[i+1]->X() - x ) > disttol ||
2704                 fabs( Ns[i+1]->Y() - y ) > disttol ||
2705                 fabs( Ns[i+1]->Z() - z ) > disttol ) {
2706               // we have to move i+1 node
2707               aMesh->MoveNode( Ns[i+1], x, y, z );
2708             }
2709           }
2710         }
2711       }
2712     }
2713
2714   } // loop on face ids
2715
2716 }
2717
2718 //=======================================================================
2719 //function : isReverse
2720 //purpose  : Return true if normal of prevNodes is not co-directied with
2721 //           gp_Vec(prevNodes[iNotSame],nextNodes[iNotSame]).
2722 //           iNotSame is where prevNodes and nextNodes are different
2723 //=======================================================================
2724
2725 static bool isReverse(vector<const SMDS_MeshNode*> prevNodes,
2726                       vector<const SMDS_MeshNode*> nextNodes,
2727                       const int            nbNodes,
2728                       const int            iNotSame)
2729 {
2730   int iBeforeNotSame = ( iNotSame == 0 ? nbNodes - 1 : iNotSame - 1 );
2731   int iAfterNotSame  = ( iNotSame + 1 == nbNodes ? 0 : iNotSame + 1 );
2732
2733   const SMDS_MeshNode* nB = prevNodes[ iBeforeNotSame ];
2734   const SMDS_MeshNode* nA = prevNodes[ iAfterNotSame ];
2735   const SMDS_MeshNode* nP = prevNodes[ iNotSame ];
2736   const SMDS_MeshNode* nN = nextNodes[ iNotSame ];
2737
2738   gp_Pnt pB ( nB->X(), nB->Y(), nB->Z() );
2739   gp_Pnt pA ( nA->X(), nA->Y(), nA->Z() );
2740   gp_Pnt pP ( nP->X(), nP->Y(), nP->Z() );
2741   gp_Pnt pN ( nN->X(), nN->Y(), nN->Z() );
2742
2743   gp_Vec vB ( pP, pB ), vA ( pP, pA ), vN ( pP, pN );
2744
2745   return (vA ^ vB) * vN < 0.0;
2746 }
2747
2748 //=======================================================================
2749 /*!
2750  * \brief Create elements by sweeping an element
2751  * \param elem - element to sweep
2752  * \param newNodesItVec - nodes generated from each node of the element
2753  * \param newElems - generated elements
2754  * \param nbSteps - number of sweeping steps
2755  * \param srcElements - to append elem for each generated element
2756  */
2757 //=======================================================================
2758
2759 void SMESH_MeshEditor::sweepElement(const SMDS_MeshElement*               elem,
2760                                     const vector<TNodeOfNodeListMapItr> & newNodesItVec,
2761                                     list<const SMDS_MeshElement*>&        newElems,
2762                                     const int                             nbSteps,
2763                                     SMESH_SequenceOfElemPtr&              srcElements)
2764 {
2765   SMESHDS_Mesh* aMesh = GetMeshDS();
2766
2767   // Loop on elem nodes:
2768   // find new nodes and detect same nodes indices
2769   int nbNodes = elem->NbNodes();
2770   vector < list< const SMDS_MeshNode* >::const_iterator > itNN( nbNodes );
2771   vector<const SMDS_MeshNode*> prevNod( nbNodes );
2772   vector<const SMDS_MeshNode*> nextNod( nbNodes );
2773   vector<const SMDS_MeshNode*> midlNod( nbNodes );
2774
2775   int iNode, nbSame = 0, iNotSameNode = 0, iSameNode = 0;
2776   vector<int> sames(nbNodes);
2777   vector<bool> issimple(nbNodes);
2778
2779   for ( iNode = 0; iNode < nbNodes; iNode++ ) {
2780     TNodeOfNodeListMapItr nnIt = newNodesItVec[ iNode ];
2781     const SMDS_MeshNode*                 node         = nnIt->first;
2782     const list< const SMDS_MeshNode* > & listNewNodes = nnIt->second;
2783     if ( listNewNodes.empty() ) {
2784       return;
2785     }
2786
2787     issimple[iNode] = (listNewNodes.size()==nbSteps); // is node medium
2788
2789     itNN[ iNode ] = listNewNodes.begin();
2790     prevNod[ iNode ] = node;
2791     nextNod[ iNode ] = listNewNodes.front();
2792     if( !elem->IsQuadratic() || !issimple[iNode] ) {
2793       if ( prevNod[ iNode ] != nextNod [ iNode ])
2794         iNotSameNode = iNode;
2795       else {
2796         iSameNode = iNode;
2797         //nbSame++;
2798         sames[nbSame++] = iNode;
2799       }
2800     }
2801   }
2802
2803   //cout<<"  nbSame = "<<nbSame<<endl;
2804   if ( nbSame == nbNodes || nbSame > 2) {
2805     MESSAGE( " Too many same nodes of element " << elem->GetID() );
2806     //INFOS( " Too many same nodes of element " << elem->GetID() );
2807     return;
2808   }
2809
2810   //  if( elem->IsQuadratic() && nbSame>0 ) {
2811   //    MESSAGE( "Can not rotate quadratic element " << elem->GetID() );
2812   //    return;
2813   //  }
2814
2815   int iBeforeSame = 0, iAfterSame = 0, iOpposSame = 0;
2816   int nbBaseNodes = ( elem->IsQuadratic() ? nbNodes/2 : nbNodes );
2817   if ( nbSame > 0 ) {
2818     iBeforeSame = ( iSameNode == 0 ? nbBaseNodes - 1 : iSameNode - 1 );
2819     iAfterSame  = ( iSameNode + 1 == nbBaseNodes ? 0 : iSameNode + 1 );
2820     iOpposSame  = ( iSameNode - 2 < 0  ? iSameNode + 2 : iSameNode - 2 );
2821   }
2822
2823   //if(nbNodes==8)
2824   //cout<<" prevNod[0]="<< prevNod[0]<<" prevNod[1]="<< prevNod[1]
2825   //    <<" prevNod[2]="<< prevNod[2]<<" prevNod[3]="<< prevNod[4]
2826   //    <<" prevNod[4]="<< prevNod[4]<<" prevNod[5]="<< prevNod[5]
2827   //    <<" prevNod[6]="<< prevNod[6]<<" prevNod[7]="<< prevNod[7]<<endl;
2828
2829   // check element orientation
2830   int i0 = 0, i2 = 2;
2831   if ( nbNodes > 2 && !isReverse( prevNod, nextNod, nbNodes, iNotSameNode )) {
2832     //MESSAGE("Reversed elem " << elem );
2833     i0 = 2;
2834     i2 = 0;
2835     if ( nbSame > 0 )
2836       std::swap( iBeforeSame, iAfterSame );
2837   }
2838
2839   // make new elements
2840   for (int iStep = 0; iStep < nbSteps; iStep++ ) {
2841     // get next nodes
2842     for ( iNode = 0; iNode < nbNodes; iNode++ ) {
2843       if(issimple[iNode]) {
2844         nextNod[ iNode ] = *itNN[ iNode ];
2845         itNN[ iNode ]++;
2846       }
2847       else {
2848         if( elem->GetType()==SMDSAbs_Node ) {
2849           // we have to use two nodes
2850           midlNod[ iNode ] = *itNN[ iNode ];
2851           itNN[ iNode ]++;
2852           nextNod[ iNode ] = *itNN[ iNode ];
2853           itNN[ iNode ]++;
2854         }
2855         else if(!elem->IsQuadratic() || elem->IsMediumNode(prevNod[iNode]) ) {
2856           // we have to use each second node
2857           //itNN[ iNode ]++;
2858           nextNod[ iNode ] = *itNN[ iNode ];
2859           itNN[ iNode ]++;
2860         }
2861         else {
2862           // we have to use two nodes
2863           midlNod[ iNode ] = *itNN[ iNode ];
2864           itNN[ iNode ]++;
2865           nextNod[ iNode ] = *itNN[ iNode ];
2866           itNN[ iNode ]++;
2867         }
2868       }
2869     }
2870     SMDS_MeshElement* aNewElem = 0;
2871     if(!elem->IsPoly()) {
2872       switch ( nbNodes ) {
2873       case 0:
2874         return;
2875       case 1: { // NODE
2876         if ( nbSame == 0 ) {
2877           if(issimple[0])
2878             aNewElem = aMesh->AddEdge( prevNod[ 0 ], nextNod[ 0 ] );
2879           else
2880             aNewElem = aMesh->AddEdge( prevNod[ 0 ], nextNod[ 0 ], midlNod[ 0 ] );
2881         }
2882         break;
2883       }
2884       case 2: { // EDGE
2885         if ( nbSame == 0 )
2886           aNewElem = aMesh->AddFace(prevNod[ 0 ], prevNod[ 1 ],
2887                                     nextNod[ 1 ], nextNod[ 0 ] );
2888         else
2889           aNewElem = aMesh->AddFace(prevNod[ 0 ], prevNod[ 1 ],
2890                                     nextNod[ iNotSameNode ] );
2891         break;
2892       }
2893
2894       case 3: { // TRIANGLE or quadratic edge
2895         if(elem->GetType() == SMDSAbs_Face) { // TRIANGLE
2896
2897           if ( nbSame == 0 )       // --- pentahedron
2898             aNewElem = aMesh->AddVolume (prevNod[ i0 ], prevNod[ 1 ], prevNod[ i2 ],
2899                                          nextNod[ i0 ], nextNod[ 1 ], nextNod[ i2 ] );
2900
2901           else if ( nbSame == 1 )  // --- pyramid
2902             aNewElem = aMesh->AddVolume (prevNod[ iBeforeSame ],  prevNod[ iAfterSame ],
2903                                          nextNod[ iAfterSame ], nextNod[ iBeforeSame ],
2904                                          nextNod[ iSameNode ]);
2905
2906           else // 2 same nodes:      --- tetrahedron
2907             aNewElem = aMesh->AddVolume (prevNod[ i0 ], prevNod[ 1 ], prevNod[ i2 ],
2908                                          nextNod[ iNotSameNode ]);
2909         }
2910         else { // quadratic edge
2911           if(nbSame==0) {     // quadratic quadrangle
2912             aNewElem = aMesh->AddFace(prevNod[0], nextNod[0], nextNod[1], prevNod[1],
2913                                       midlNod[0], nextNod[2], midlNod[1], prevNod[2]);
2914           }
2915           else if(nbSame==1) { // quadratic triangle
2916             if(sames[0]==2) {
2917               return; // medium node on axis
2918             }
2919             else if(sames[0]==0) {
2920               aNewElem = aMesh->AddFace(prevNod[0], nextNod[1], prevNod[1],
2921                                         nextNod[2], midlNod[1], prevNod[2]);
2922             }
2923             else { // sames[0]==1
2924               aNewElem = aMesh->AddFace(prevNod[0], nextNod[0], prevNod[1],
2925                                         midlNod[0], nextNod[2], prevNod[2]);
2926             }
2927           }
2928           else {
2929             return;
2930           }
2931         }
2932         break;
2933       }
2934       case 4: { // QUADRANGLE
2935
2936         if ( nbSame == 0 )       // --- hexahedron
2937           aNewElem = aMesh->AddVolume (prevNod[ i0 ], prevNod[ 1 ], prevNod[ i2 ], prevNod[ 3 ],
2938                                        nextNod[ i0 ], nextNod[ 1 ], nextNod[ i2 ], nextNod[ 3 ]);
2939
2940         else if ( nbSame == 1 ) { // --- pyramid + pentahedron
2941           aNewElem = aMesh->AddVolume (prevNod[ iBeforeSame ],  prevNod[ iAfterSame ],
2942                                        nextNod[ iAfterSame ], nextNod[ iBeforeSame ],
2943                                        nextNod[ iSameNode ]);
2944           newElems.push_back( aNewElem );
2945           aNewElem = aMesh->AddVolume (prevNod[ iAfterSame ], prevNod[ iOpposSame ],
2946                                        prevNod[ iBeforeSame ],  nextNod[ iAfterSame ],
2947                                        nextNod[ iOpposSame ],  nextNod[ iBeforeSame ] );
2948         }
2949         else if ( nbSame == 2 ) { // pentahedron
2950           if ( prevNod[ iBeforeSame ] == nextNod[ iBeforeSame ] )
2951             // iBeforeSame is same too
2952             aNewElem = aMesh->AddVolume (prevNod[ iBeforeSame ], prevNod[ iOpposSame ],
2953                                          nextNod[ iOpposSame ], prevNod[ iSameNode ],
2954                                          prevNod[ iAfterSame ],  nextNod[ iAfterSame ]);
2955           else
2956             // iAfterSame is same too
2957             aNewElem = aMesh->AddVolume (prevNod[ iSameNode ], prevNod[ iBeforeSame ],
2958                                          nextNod[ iBeforeSame ], prevNod[ iAfterSame ],
2959                                          prevNod[ iOpposSame ],  nextNod[ iOpposSame ]);
2960         }
2961         break;
2962       }
2963       case 6: { // quadratic triangle
2964         // create pentahedron with 15 nodes
2965         if(nbSame==0) {
2966           if(i0>0) { // reversed case
2967             aNewElem = aMesh->AddVolume (prevNod[0], prevNod[2], prevNod[1],
2968                                          nextNod[0], nextNod[2], nextNod[1],
2969                                          prevNod[5], prevNod[4], prevNod[3],
2970                                          nextNod[5], nextNod[4], nextNod[3],
2971                                          midlNod[0], midlNod[2], midlNod[1]);
2972           }
2973           else { // not reversed case
2974             aNewElem = aMesh->AddVolume (prevNod[0], prevNod[1], prevNod[2],
2975                                          nextNod[0], nextNod[1], nextNod[2],
2976                                          prevNod[3], prevNod[4], prevNod[5],
2977                                          nextNod[3], nextNod[4], nextNod[5],
2978                                          midlNod[0], midlNod[1], midlNod[2]);
2979           }
2980         }
2981         else if(nbSame==1) {
2982           // 2d order pyramid of 13 nodes
2983           //SMDS_MeshVolume* AddVolumeWithID(int n1, int n2, int n3, int n4, int n5,
2984           //                                 int n12,int n23,int n34,int n41,
2985           //                                 int n15,int n25,int n35,int n45, int ID);
2986           int n5 = iSameNode;
2987           int n1,n4,n41,n15,n45;
2988           if(i0>0) { // reversed case
2989             n1 = ( n5 + 1 == nbBaseNodes ? 0 : n5 + 1 );
2990             n4 = ( n5 == 0 ? nbBaseNodes - 1 : n5 - 1 );
2991             n41 = n1 + 3;
2992             n15 = n5 + 3;
2993             n45 = n4 + 3;
2994           }
2995           else {
2996             n1 = ( n5 == 0 ? nbBaseNodes - 1 : n5 - 1 );
2997             n4 = ( n5 + 1 == nbBaseNodes ? 0 : n5 + 1 );
2998             n41 = n4 + 3;
2999             n15 = n1 + 3;
3000             n45 = n5 + 3;
3001           }
3002           aNewElem = aMesh->AddVolume(prevNod[n1], nextNod[n1],
3003                                       nextNod[n4], prevNod[n4], prevNod[n5],
3004                                       midlNod[n1], nextNod[n41],
3005                                       midlNod[n4], prevNod[n41],
3006                                       prevNod[n15], nextNod[n15],
3007                                       nextNod[n45], prevNod[n45]);
3008         }
3009         else if(nbSame==2) {
3010           // 2d order tetrahedron of 10 nodes
3011           //SMDS_MeshVolume* AddVolumeWithID(int n1, int n2, int n3, int n4,
3012           //                                 int n12,int n23,int n31,
3013           //                                 int n14,int n24,int n34, int ID);
3014           int n1 = iNotSameNode;
3015           int n2,n3,n12,n23,n31;
3016           if(i0>0) { // reversed case
3017             n2 = ( n1 == 0 ? nbBaseNodes - 1 : n1 - 1 );
3018             n3 = ( n1 + 1 == nbBaseNodes ? 0 : n1 + 1 );
3019             n12 = n2 + 3;
3020             n23 = n3 + 3;
3021             n31 = n1 + 3;
3022           }
3023           else {
3024             n2 = ( n1 + 1 == nbBaseNodes ? 0 : n1 + 1 );
3025             n3 = ( n1 == 0 ? nbBaseNodes - 1 : n1 - 1 );
3026             n12 = n1 + 3;
3027             n23 = n2 + 3;
3028             n31 = n3 + 3;
3029           }
3030           aNewElem = aMesh->AddVolume (prevNod[n1], prevNod[n2], prevNod[n3], nextNod[n1],
3031                                        prevNod[n12], prevNod[n23], prevNod[n31],
3032                                        midlNod[n1], nextNod[n12], nextNod[n31]);
3033         }
3034         break;
3035       }
3036       case 8: { // quadratic quadrangle
3037         if(nbSame==0) {
3038           // create hexahedron with 20 nodes
3039           if(i0>0) { // reversed case
3040             aNewElem = aMesh->AddVolume (prevNod[0], prevNod[3], prevNod[2], prevNod[1],
3041                                          nextNod[0], nextNod[3], nextNod[2], nextNod[1],
3042                                          prevNod[7], prevNod[6], prevNod[5], prevNod[4],
3043                                          nextNod[7], nextNod[6], nextNod[5], nextNod[4],
3044                                          midlNod[0], midlNod[3], midlNod[2], midlNod[1]);
3045           }
3046           else { // not reversed case
3047             aNewElem = aMesh->AddVolume (prevNod[0], prevNod[1], prevNod[2], prevNod[3],
3048                                          nextNod[0], nextNod[1], nextNod[2], nextNod[3],
3049                                          prevNod[4], prevNod[5], prevNod[6], prevNod[7],
3050                                          nextNod[4], nextNod[5], nextNod[6], nextNod[7],
3051                                          midlNod[0], midlNod[1], midlNod[2], midlNod[3]);
3052           }
3053         }
3054         else if(nbSame==1) { 
3055           // --- pyramid + pentahedron - can not be created since it is needed 
3056           // additional middle node ot the center of face
3057           INFOS( " Sweep for face " << elem->GetID() << " can not be created" );
3058           return;
3059         }
3060         else if(nbSame==2) {
3061           // 2d order Pentahedron with 15 nodes
3062           //SMDS_MeshVolume* AddVolumeWithID(int n1, int n2, int n3, int n4, int n5, int n6,
3063           //                                 int n12,int n23,int n31,int n45,int n56,int n64,
3064           //                                 int n14,int n25,int n36, int ID);
3065           int n1,n2,n4,n5;
3066           if ( prevNod[ iBeforeSame ] == nextNod[ iBeforeSame ] ) {
3067             // iBeforeSame is same too
3068             n1 = iBeforeSame;
3069             n2 = iOpposSame;
3070             n4 = iSameNode;
3071             n5 = iAfterSame;
3072           }
3073           else {
3074             // iAfterSame is same too
3075             n1 = iSameNode;
3076             n2 = iBeforeSame;
3077             n4 = iAfterSame;
3078             n5 = iOpposSame;
3079           }
3080           int n12,n45,n14,n25;
3081           if(i0>0) { //reversed case
3082             n12 = n1 + 4;
3083             n45 = n5 + 4;
3084             n14 = n4 + 4;
3085             n25 = n2 + 4;
3086           }
3087           else {
3088             n12 = n2 + 4;
3089             n45 = n4 + 4;
3090             n14 = n1 + 4;
3091             n25 = n5 + 4;
3092           }
3093           aNewElem = aMesh->AddVolume (prevNod[n1], prevNod[n2], nextNod[n2],
3094                                        prevNod[n4], prevNod[n5], nextNod[n5],
3095                                        prevNod[n12], midlNod[n2], nextNod[n12],
3096                                        prevNod[n45], midlNod[n5], nextNod[n45],
3097                                        prevNod[n14], prevNod[n25], nextNod[n25]);
3098         }
3099         break;
3100       }
3101       default: {
3102         // realized for extrusion only
3103         //vector<const SMDS_MeshNode*> polyedre_nodes (nbNodes*2 + 4*nbNodes);
3104         //vector<int> quantities (nbNodes + 2);
3105
3106         //quantities[0] = nbNodes; // bottom of prism
3107         //for (int inode = 0; inode < nbNodes; inode++) {
3108         //  polyedre_nodes[inode] = prevNod[inode];
3109         //}
3110
3111         //quantities[1] = nbNodes; // top of prism
3112         //for (int inode = 0; inode < nbNodes; inode++) {
3113         //  polyedre_nodes[nbNodes + inode] = nextNod[inode];
3114         //}
3115
3116         //for (int iface = 0; iface < nbNodes; iface++) {
3117         //  quantities[iface + 2] = 4;
3118         //  int inextface = (iface == nbNodes - 1) ? 0 : iface + 1;
3119         //  polyedre_nodes[2*nbNodes + 4*iface + 0] = prevNod[iface];
3120         //  polyedre_nodes[2*nbNodes + 4*iface + 1] = prevNod[inextface];
3121         //  polyedre_nodes[2*nbNodes + 4*iface + 2] = nextNod[inextface];
3122         //  polyedre_nodes[2*nbNodes + 4*iface + 3] = nextNod[iface];
3123         //}
3124         //aNewElem = aMesh->AddPolyhedralVolume (polyedre_nodes, quantities);
3125         break;
3126       }
3127       }
3128     }
3129
3130     if(!aNewElem) {
3131       // realized for extrusion only
3132       vector<const SMDS_MeshNode*> polyedre_nodes (nbNodes*2 + 4*nbNodes);
3133       vector<int> quantities (nbNodes + 2);
3134
3135       quantities[0] = nbNodes; // bottom of prism
3136       for (int inode = 0; inode < nbNodes; inode++) {
3137         polyedre_nodes[inode] = prevNod[inode];
3138       }
3139
3140       quantities[1] = nbNodes; // top of prism
3141       for (int inode = 0; inode < nbNodes; inode++) {
3142         polyedre_nodes[nbNodes + inode] = nextNod[inode];
3143       }
3144
3145       for (int iface = 0; iface < nbNodes; iface++) {
3146         quantities[iface + 2] = 4;
3147         int inextface = (iface == nbNodes - 1) ? 0 : iface + 1;
3148         polyedre_nodes[2*nbNodes + 4*iface + 0] = prevNod[iface];
3149         polyedre_nodes[2*nbNodes + 4*iface + 1] = prevNod[inextface];
3150         polyedre_nodes[2*nbNodes + 4*iface + 2] = nextNod[inextface];
3151         polyedre_nodes[2*nbNodes + 4*iface + 3] = nextNod[iface];
3152       }
3153       aNewElem = aMesh->AddPolyhedralVolume (polyedre_nodes, quantities);
3154     }
3155
3156     if ( aNewElem ) {
3157       newElems.push_back( aNewElem );
3158       myLastCreatedElems.Append(aNewElem);
3159       srcElements.Append( elem );
3160     }
3161
3162     // set new prev nodes
3163     for ( iNode = 0; iNode < nbNodes; iNode++ )
3164       prevNod[ iNode ] = nextNod[ iNode ];
3165
3166   } // for steps
3167 }
3168
3169 //=======================================================================
3170 /*!
3171  * \brief Create 1D and 2D elements around swept elements
3172  * \param mapNewNodes - source nodes and ones generated from them
3173  * \param newElemsMap - source elements and ones generated from them
3174  * \param elemNewNodesMap - nodes generated from each node of each element
3175  * \param elemSet - all swept elements
3176  * \param nbSteps - number of sweeping steps
3177  * \param srcElements - to append elem for each generated element
3178  */
3179 //=======================================================================
3180
3181 void SMESH_MeshEditor::makeWalls (TNodeOfNodeListMap &     mapNewNodes,
3182                                   TElemOfElemListMap &     newElemsMap,
3183                                   TElemOfVecOfNnlmiMap &   elemNewNodesMap,
3184                                   TIDSortedElemSet&        elemSet,
3185                                   const int                nbSteps,
3186                                   SMESH_SequenceOfElemPtr& srcElements)
3187 {
3188   ASSERT( newElemsMap.size() == elemNewNodesMap.size() );
3189   SMESHDS_Mesh* aMesh = GetMeshDS();
3190
3191   // Find nodes belonging to only one initial element - sweep them to get edges.
3192
3193   TNodeOfNodeListMapItr nList = mapNewNodes.begin();
3194   for ( ; nList != mapNewNodes.end(); nList++ ) {
3195     const SMDS_MeshNode* node =
3196       static_cast<const SMDS_MeshNode*>( nList->first );
3197     SMDS_ElemIteratorPtr eIt = node->GetInverseElementIterator();
3198     int nbInitElems = 0;
3199     const SMDS_MeshElement* el = 0;
3200     SMDSAbs_ElementType highType = SMDSAbs_Edge; // count most complex elements only
3201     while ( eIt->more() && nbInitElems < 2 ) {
3202       el = eIt->next();
3203       SMDSAbs_ElementType type = el->GetType();
3204       if ( type == SMDSAbs_Volume || type < highType ) continue;
3205       if ( type > highType ) {
3206         nbInitElems = 0;
3207         highType = type;
3208       }
3209       if ( elemSet.find(el) != elemSet.end() )
3210         nbInitElems++;
3211     }
3212     if ( nbInitElems < 2 ) {
3213       bool NotCreateEdge = el && el->IsQuadratic() && el->IsMediumNode(node);
3214       if(!NotCreateEdge) {
3215         vector<TNodeOfNodeListMapItr> newNodesItVec( 1, nList );
3216         list<const SMDS_MeshElement*> newEdges;
3217         sweepElement( node, newNodesItVec, newEdges, nbSteps, srcElements );
3218       }
3219     }
3220   }
3221
3222   // Make a ceiling for each element ie an equal element of last new nodes.
3223   // Find free links of faces - make edges and sweep them into faces.
3224
3225   TElemOfElemListMap::iterator   itElem      = newElemsMap.begin();
3226   TElemOfVecOfNnlmiMap::iterator itElemNodes = elemNewNodesMap.begin();
3227   for ( ; itElem != newElemsMap.end(); itElem++, itElemNodes++ ) {
3228     const SMDS_MeshElement* elem = itElem->first;
3229     vector<TNodeOfNodeListMapItr>& vecNewNodes = itElemNodes->second;
3230
3231     if ( elem->GetType() == SMDSAbs_Edge ) {
3232       // create a ceiling edge
3233       if (!elem->IsQuadratic()) {
3234         if ( !aMesh->FindEdge( vecNewNodes[ 0 ]->second.back(),
3235                                vecNewNodes[ 1 ]->second.back())) {
3236           myLastCreatedElems.Append(aMesh->AddEdge(vecNewNodes[ 0 ]->second.back(),
3237                                                    vecNewNodes[ 1 ]->second.back()));
3238           srcElements.Append( myLastCreatedElems.Last() );
3239         }
3240       }
3241       else {
3242         if ( !aMesh->FindEdge( vecNewNodes[ 0 ]->second.back(),
3243                                vecNewNodes[ 1 ]->second.back(),
3244                                vecNewNodes[ 2 ]->second.back())) {
3245           myLastCreatedElems.Append(aMesh->AddEdge(vecNewNodes[ 0 ]->second.back(),
3246                                                    vecNewNodes[ 1 ]->second.back(),
3247                                                    vecNewNodes[ 2 ]->second.back()));
3248           srcElements.Append( myLastCreatedElems.Last() );
3249         }
3250       }
3251     }
3252     if ( elem->GetType() != SMDSAbs_Face )
3253       continue;
3254
3255     if(itElem->second.size()==0) continue;
3256
3257     bool hasFreeLinks = false;
3258
3259     TIDSortedElemSet avoidSet;
3260     avoidSet.insert( elem );
3261
3262     set<const SMDS_MeshNode*> aFaceLastNodes;
3263     int iNode, nbNodes = vecNewNodes.size();
3264     if(!elem->IsQuadratic()) {
3265       // loop on the face nodes
3266       for ( iNode = 0; iNode < nbNodes; iNode++ ) {
3267         aFaceLastNodes.insert( vecNewNodes[ iNode ]->second.back() );
3268         // look for free links of the face
3269         int iNext = ( iNode + 1 == nbNodes ) ? 0 : iNode + 1;
3270         const SMDS_MeshNode* n1 = vecNewNodes[ iNode ]->first;
3271         const SMDS_MeshNode* n2 = vecNewNodes[ iNext ]->first;
3272         // check if a link is free
3273         if ( ! SMESH_MeshEditor::FindFaceInSet ( n1, n2, elemSet, avoidSet )) {
3274           hasFreeLinks = true;
3275           // make an edge and a ceiling for a new edge
3276           if ( !aMesh->FindEdge( n1, n2 )) {
3277             myLastCreatedElems.Append(aMesh->AddEdge( n1, n2 )); // free link edge
3278             srcElements.Append( myLastCreatedElems.Last() );
3279           }
3280           n1 = vecNewNodes[ iNode ]->second.back();
3281           n2 = vecNewNodes[ iNext ]->second.back();
3282           if ( !aMesh->FindEdge( n1, n2 )) {
3283             myLastCreatedElems.Append(aMesh->AddEdge( n1, n2 )); // ceiling edge
3284             srcElements.Append( myLastCreatedElems.Last() );
3285           }
3286         }
3287       }
3288     }
3289     else { // elem is quadratic face
3290       int nbn = nbNodes/2;
3291       for ( iNode = 0; iNode < nbn; iNode++ ) {
3292         aFaceLastNodes.insert( vecNewNodes[ iNode ]->second.back() );
3293         int iNext = ( iNode + 1 == nbn ) ? 0 : iNode + 1;
3294         const SMDS_MeshNode* n1 = vecNewNodes[ iNode ]->first;
3295         const SMDS_MeshNode* n2 = vecNewNodes[ iNext ]->first;
3296         // check if a link is free
3297         if ( ! SMESH_MeshEditor::FindFaceInSet ( n1, n2, elemSet, avoidSet )) {
3298           hasFreeLinks = true;
3299           // make an edge and a ceiling for a new edge
3300           // find medium node
3301           const SMDS_MeshNode* n3 = vecNewNodes[ iNode+nbn ]->first;
3302           if ( !aMesh->FindEdge( n1, n2, n3 )) {
3303             myLastCreatedElems.Append(aMesh->AddEdge( n1, n2, n3 )); // free link edge
3304             srcElements.Append( myLastCreatedElems.Last() );
3305           }
3306           n1 = vecNewNodes[ iNode ]->second.back();
3307           n2 = vecNewNodes[ iNext ]->second.back();
3308           n3 = vecNewNodes[ iNode+nbn ]->second.back();
3309           if ( !aMesh->FindEdge( n1, n2, n3 )) {
3310             myLastCreatedElems.Append(aMesh->AddEdge( n1, n2, n3 )); // ceiling edge
3311             srcElements.Append( myLastCreatedElems.Last() );
3312           }
3313         }
3314       }
3315       for ( iNode = nbn; iNode < 2*nbn; iNode++ ) {
3316         aFaceLastNodes.insert( vecNewNodes[ iNode ]->second.back() );
3317       }
3318     }
3319
3320     // sweep free links into faces
3321
3322     if ( hasFreeLinks )  {
3323       list<const SMDS_MeshElement*> & newVolumes = itElem->second;
3324       int iVol, volNb, nbVolumesByStep = newVolumes.size() / nbSteps;
3325
3326       set<const SMDS_MeshNode*> initNodeSet, topNodeSet, faceNodeSet;
3327       for ( iNode = 0; iNode < nbNodes; iNode++ ) {
3328         initNodeSet.insert( vecNewNodes[ iNode ]->first );
3329         topNodeSet .insert( vecNewNodes[ iNode ]->second.back() );
3330       }
3331       for ( volNb = 0; volNb < nbVolumesByStep; volNb++ ) {
3332         list<const SMDS_MeshElement*>::iterator v = newVolumes.begin();
3333         iVol = 0;
3334         while ( iVol++ < volNb ) v++;
3335         // find indices of free faces of a volume and their source edges
3336         list< int > freeInd;
3337         list< const SMDS_MeshElement* > srcEdges; // source edges of free faces
3338         SMDS_VolumeTool vTool( *v );
3339         int iF, nbF = vTool.NbFaces();
3340         for ( iF = 0; iF < nbF; iF ++ ) {
3341           if (vTool.IsFreeFace( iF ) &&
3342               vTool.GetFaceNodes( iF, faceNodeSet ) &&
3343               initNodeSet != faceNodeSet) // except an initial face
3344           {
3345             if ( nbSteps == 1 && faceNodeSet == topNodeSet )
3346               continue;
3347             freeInd.push_back( iF );
3348             // find source edge of a free face iF
3349             vector<const SMDS_MeshNode*> commonNodes; // shared by the initial and free faces
3350             commonNodes.resize( initNodeSet.size(), NULL ); // avoid spoiling memory
3351             std::set_intersection( faceNodeSet.begin(), faceNodeSet.end(),
3352                                    initNodeSet.begin(), initNodeSet.end(),
3353                                    commonNodes.begin());
3354             if ( (*v)->IsQuadratic() )
3355               srcEdges.push_back(aMesh->FindEdge (commonNodes[0],commonNodes[1],commonNodes[2]));
3356             else
3357               srcEdges.push_back(aMesh->FindEdge (commonNodes[0],commonNodes[1]));
3358 #ifdef _DEBUG_
3359             if ( !srcEdges.back() )
3360             {
3361               cout << "SMESH_MeshEditor::makeWalls(), no source edge found for a free face #"
3362                    << iF << " of volume #" << vTool.ID() << endl;
3363             }
3364 #endif
3365           }
3366         }
3367         if ( freeInd.empty() )
3368           continue;
3369
3370         // create faces for all steps;
3371         // if such a face has been already created by sweep of edge,
3372         // assure that its orientation is OK
3373         for ( int iStep = 0; iStep < nbSteps; iStep++ )  {
3374           vTool.Set( *v );
3375           vTool.SetExternalNormal();
3376           list< int >::iterator ind = freeInd.begin();
3377           list< const SMDS_MeshElement* >::iterator srcEdge = srcEdges.begin();
3378           for ( ; ind != freeInd.end(); ++ind, ++srcEdge ) // loop on free faces
3379           {
3380             const SMDS_MeshNode** nodes = vTool.GetFaceNodes( *ind );
3381             int nbn = vTool.NbFaceNodes( *ind );
3382             switch ( nbn ) {
3383             case 3: { ///// triangle
3384               const SMDS_MeshFace * f = aMesh->FindFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ]);
3385               if ( !f )
3386                 myLastCreatedElems.Append(aMesh->AddFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ] ));
3387               else if ( nodes[ 1 ] != f->GetNodeWrap( f->GetNodeIndex( nodes[ 0 ] ) + 1 ))
3388                 aMesh->ChangeElementNodes( f, nodes, nbn );
3389               break;
3390             }
3391             case 4: { ///// quadrangle
3392               const SMDS_MeshFace * f = aMesh->FindFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ], nodes[ 3 ]);
3393               if ( !f )
3394                 myLastCreatedElems.Append(aMesh->AddFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ], nodes[ 3 ] ));
3395               else if ( nodes[ 1 ] != f->GetNodeWrap( f->GetNodeIndex( nodes[ 0 ] ) + 1 ))
3396                 aMesh->ChangeElementNodes( f, nodes, nbn );
3397               break;
3398             }
3399             default:
3400               if( (*v)->IsQuadratic() ) {
3401                 if(nbn==6) { /////// quadratic triangle
3402                   const SMDS_MeshFace * f = aMesh->FindFace( nodes[0], nodes[2], nodes[4],
3403                                                              nodes[1], nodes[3], nodes[5] );
3404                   if ( !f ) {
3405                     myLastCreatedElems.Append(aMesh->AddFace(nodes[0], nodes[2], nodes[4],
3406                                                              nodes[1], nodes[3], nodes[5]));
3407                   }
3408                   else if ( nodes[ 2 ] != f->GetNodeWrap( f->GetNodeIndex( nodes[ 0 ] ) + 1 )) {
3409                     const SMDS_MeshNode** tmpnodes = new const SMDS_MeshNode*[6];
3410                     tmpnodes[0] = nodes[0];
3411                     tmpnodes[1] = nodes[2];
3412                     tmpnodes[2] = nodes[4];
3413                     tmpnodes[3] = nodes[1];
3414                     tmpnodes[4] = nodes[3];
3415                     tmpnodes[5] = nodes[5];
3416                     aMesh->ChangeElementNodes( f, tmpnodes, nbn );
3417                   }
3418                 }
3419                 else {       /////// quadratic quadrangle
3420                   const SMDS_MeshFace * f = aMesh->FindFace( nodes[0], nodes[2], nodes[4], nodes[6],
3421                                                              nodes[1], nodes[3], nodes[5], nodes[7] );
3422                   if ( !f ) {
3423                     myLastCreatedElems.Append(aMesh->AddFace(nodes[0], nodes[2], nodes[4], nodes[6],
3424                                                              nodes[1], nodes[3], nodes[5], nodes[7]));
3425                   }
3426                   else if ( nodes[ 2 ] != f->GetNodeWrap( f->GetNodeIndex( nodes[ 0 ] ) + 1 )) {
3427                     const SMDS_MeshNode** tmpnodes = new const SMDS_MeshNode*[8];
3428                     tmpnodes[0] = nodes[0];
3429                     tmpnodes[1] = nodes[2];
3430                     tmpnodes[2] = nodes[4];
3431                     tmpnodes[3] = nodes[6];
3432                     tmpnodes[4] = nodes[1];
3433                     tmpnodes[5] = nodes[3];
3434                     tmpnodes[6] = nodes[5];
3435                     tmpnodes[7] = nodes[7];
3436                     aMesh->ChangeElementNodes( f, tmpnodes, nbn );
3437                   }
3438                 }
3439               }
3440               else { //////// polygon
3441                 vector<const SMDS_MeshNode*> polygon_nodes ( nodes, &nodes[nbn] );
3442                 const SMDS_MeshFace * f = aMesh->FindFace( polygon_nodes );
3443                 if ( !f )
3444                   myLastCreatedElems.Append(aMesh->AddPolygonalFace(polygon_nodes));
3445                 else if ( nodes[ 1 ] != f->GetNodeWrap( f->GetNodeIndex( nodes[ 0 ] ) + 1 ))
3446                   aMesh->ChangeElementNodes( f, nodes, nbn );
3447               }
3448             }
3449             while ( srcElements.Length() < myLastCreatedElems.Length() )
3450               srcElements.Append( *srcEdge );
3451
3452           }  // loop on free faces
3453
3454           // go to the next volume
3455           iVol = 0;
3456           while ( iVol++ < nbVolumesByStep ) v++;
3457         }
3458       }
3459     } // sweep free links into faces
3460
3461     // Make a ceiling face with a normal external to a volume
3462
3463     SMDS_VolumeTool lastVol( itElem->second.back() );
3464
3465     int iF = lastVol.GetFaceIndex( aFaceLastNodes );
3466     if ( iF >= 0 ) {
3467       lastVol.SetExternalNormal();
3468       const SMDS_MeshNode** nodes = lastVol.GetFaceNodes( iF );
3469       int nbn = lastVol.NbFaceNodes( iF );
3470       switch ( nbn ) {
3471       case 3:
3472         if (!hasFreeLinks ||
3473             !aMesh->FindFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ]))
3474           myLastCreatedElems.Append(aMesh->AddFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ] ));
3475         break;
3476       case 4:
3477         if (!hasFreeLinks ||
3478             !aMesh->FindFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ], nodes[ 3 ]))
3479           myLastCreatedElems.Append(aMesh->AddFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ], nodes[ 3 ] ));
3480         break;
3481       default:
3482         if(itElem->second.back()->IsQuadratic()) {
3483           if(nbn==6) {
3484             if (!hasFreeLinks ||
3485                 !aMesh->FindFace(nodes[0], nodes[2], nodes[4],
3486                                  nodes[1], nodes[3], nodes[5]) ) {
3487               myLastCreatedElems.Append(aMesh->AddFace(nodes[0], nodes[2], nodes[4],
3488                                                        nodes[1], nodes[3], nodes[5]));
3489             }
3490           }
3491           else { // nbn==8
3492             if (!hasFreeLinks ||
3493                 !aMesh->FindFace(nodes[0], nodes[2], nodes[4], nodes[6],
3494                                  nodes[1], nodes[3], nodes[5], nodes[7]) )
3495               myLastCreatedElems.Append(aMesh->AddFace(nodes[0], nodes[2], nodes[4], nodes[6],
3496                                                        nodes[1], nodes[3], nodes[5], nodes[7]));
3497           }
3498         }
3499         else {
3500           vector<const SMDS_MeshNode*> polygon_nodes ( nodes, &nodes[nbn] );
3501           if (!hasFreeLinks || !aMesh->FindFace(polygon_nodes))
3502             myLastCreatedElems.Append(aMesh->AddPolygonalFace(polygon_nodes));
3503         }
3504       } // switch
3505
3506       while ( srcElements.Length() < myLastCreatedElems.Length() )
3507         srcElements.Append( myLastCreatedElems.Last() );
3508     }
3509   } // loop on swept elements
3510 }
3511
3512 //=======================================================================
3513 //function : RotationSweep
3514 //purpose  :
3515 //=======================================================================
3516
3517 SMESH_MeshEditor::PGroupIDs
3518 SMESH_MeshEditor::RotationSweep(TIDSortedElemSet & theElems,
3519                                 const gp_Ax1&      theAxis,
3520                                 const double       theAngle,
3521                                 const int          theNbSteps,
3522                                 const double       theTol,
3523                                 const bool         theMakeGroups,
3524                                 const bool         theMakeWalls)
3525 {
3526   myLastCreatedElems.Clear();
3527   myLastCreatedNodes.Clear();
3528
3529   // source elements for each generated one
3530   SMESH_SequenceOfElemPtr srcElems, srcNodes;
3531
3532   MESSAGE( "RotationSweep()");
3533   gp_Trsf aTrsf;
3534   aTrsf.SetRotation( theAxis, theAngle );
3535   gp_Trsf aTrsf2;
3536   aTrsf2.SetRotation( theAxis, theAngle/2. );
3537
3538   gp_Lin aLine( theAxis );
3539   double aSqTol = theTol * theTol;
3540
3541   SMESHDS_Mesh* aMesh = GetMeshDS();
3542
3543   TNodeOfNodeListMap mapNewNodes;
3544   TElemOfVecOfNnlmiMap mapElemNewNodes;
3545   TElemOfElemListMap newElemsMap;
3546
3547   // loop on theElems
3548   TIDSortedElemSet::iterator itElem;
3549   for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
3550     const SMDS_MeshElement* elem = *itElem;
3551     if ( !elem || elem->GetType() == SMDSAbs_Volume )
3552       continue;
3553     vector<TNodeOfNodeListMapItr> & newNodesItVec = mapElemNewNodes[ elem ];
3554     newNodesItVec.reserve( elem->NbNodes() );
3555
3556     // loop on elem nodes
3557     SMDS_ElemIteratorPtr itN = elem->nodesIterator();
3558     while ( itN->more() ) {
3559       // check if a node has been already sweeped
3560       const SMDS_MeshNode* node = cast2Node( itN->next() );
3561
3562       gp_XYZ aXYZ( node->X(), node->Y(), node->Z() );
3563       double coord[3];
3564       aXYZ.Coord( coord[0], coord[1], coord[2] );
3565       bool isOnAxis = ( aLine.SquareDistance( aXYZ ) <= aSqTol );
3566
3567       TNodeOfNodeListMapItr nIt = mapNewNodes.find( node );
3568       if ( nIt == mapNewNodes.end() ) {
3569         nIt = mapNewNodes.insert( make_pair( node, list<const SMDS_MeshNode*>() )).first;
3570         list<const SMDS_MeshNode*>& listNewNodes = nIt->second;
3571
3572         // make new nodes
3573         //gp_XYZ aXYZ( node->X(), node->Y(), node->Z() );
3574         //double coord[3];
3575         //aXYZ.Coord( coord[0], coord[1], coord[2] );
3576         //bool isOnAxis = ( aLine.SquareDistance( aXYZ ) <= aSqTol );
3577         const SMDS_MeshNode * newNode = node;
3578         for ( int i = 0; i < theNbSteps; i++ ) {
3579           if ( !isOnAxis ) {
3580             if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
3581               // create two nodes
3582               aTrsf2.Transforms( coord[0], coord[1], coord[2] );
3583               //aTrsf.Transforms( coord[0], coord[1], coord[2] );
3584               newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
3585               myLastCreatedNodes.Append(newNode);
3586               srcNodes.Append( node );
3587               listNewNodes.push_back( newNode );
3588               aTrsf2.Transforms( coord[0], coord[1], coord[2] );
3589               //aTrsf.Transforms( coord[0], coord[1], coord[2] );
3590             }
3591             else {
3592               aTrsf.Transforms( coord[0], coord[1], coord[2] );
3593             }
3594             newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
3595             myLastCreatedNodes.Append(newNode);
3596             srcNodes.Append( node );
3597             listNewNodes.push_back( newNode );
3598           }
3599           else {
3600             listNewNodes.push_back( newNode );
3601             if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
3602               listNewNodes.push_back( newNode );
3603             }
3604           }
3605         }
3606       }
3607       /*
3608         else {
3609         // if current elem is quadratic and current node is not medium
3610         // we have to check - may be it is needed to insert additional nodes
3611         if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
3612         list< const SMDS_MeshNode* > & listNewNodes = nIt->second;
3613         if(listNewNodes.size()==theNbSteps) {
3614         listNewNodes.clear();
3615         // make new nodes
3616         //gp_XYZ aXYZ( node->X(), node->Y(), node->Z() );
3617         //double coord[3];
3618         //aXYZ.Coord( coord[0], coord[1], coord[2] );
3619         const SMDS_MeshNode * newNode = node;
3620         if ( !isOnAxis ) {
3621         for(int i = 0; i<theNbSteps; i++) {
3622         aTrsf2.Transforms( coord[0], coord[1], coord[2] );
3623         newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
3624         cout<<"    3 AddNode:  "<<newNode;
3625         myLastCreatedNodes.Append(newNode);
3626         listNewNodes.push_back( newNode );
3627         srcNodes.Append( node );
3628         aTrsf2.Transforms( coord[0], coord[1], coord[2] );
3629         newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
3630         cout<<"    4 AddNode:  "<<newNode;
3631         myLastCreatedNodes.Append(newNode);
3632         srcNodes.Append( node );
3633         listNewNodes.push_back( newNode );
3634         }
3635         }
3636         else {
3637         listNewNodes.push_back( newNode );
3638         }
3639         }
3640         }
3641         }
3642       */
3643       newNodesItVec.push_back( nIt );
3644     }
3645     // make new elements
3646     sweepElement( elem, newNodesItVec, newElemsMap[elem], theNbSteps, srcElems );
3647   }
3648
3649   if ( theMakeWalls )
3650     makeWalls( mapNewNodes, newElemsMap, mapElemNewNodes, theElems, theNbSteps, srcElems );
3651
3652   PGroupIDs newGroupIDs;
3653   if ( theMakeGroups )
3654     newGroupIDs = generateGroups( srcNodes, srcElems, "rotated");
3655
3656   return newGroupIDs;
3657 }
3658
3659
3660 //=======================================================================
3661 //function : CreateNode
3662 //purpose  :
3663 //=======================================================================
3664 const SMDS_MeshNode* SMESH_MeshEditor::CreateNode(const double x,
3665                                                   const double y,
3666                                                   const double z,
3667                                                   const double tolnode,
3668                                                   SMESH_SequenceOfNode& aNodes)
3669 {
3670   myLastCreatedElems.Clear();
3671   myLastCreatedNodes.Clear();
3672
3673   gp_Pnt P1(x,y,z);
3674   SMESHDS_Mesh * aMesh = myMesh->GetMeshDS();
3675
3676   // try to search in sequence of existing nodes
3677   // if aNodes.Length()>0 we 'nave to use given sequence
3678   // else - use all nodes of mesh
3679   if(aNodes.Length()>0) {
3680     int i;
3681     for(i=1; i<=aNodes.Length(); i++) {
3682       gp_Pnt P2(aNodes.Value(i)->X(),aNodes.Value(i)->Y(),aNodes.Value(i)->Z());
3683       if(P1.Distance(P2)<tolnode)
3684         return aNodes.Value(i);
3685     }
3686   }
3687   else {
3688     SMDS_NodeIteratorPtr itn = aMesh->nodesIterator();
3689     while(itn->more()) {
3690       const SMDS_MeshNode* aN = static_cast<const SMDS_MeshNode*> (itn->next());
3691       gp_Pnt P2(aN->X(),aN->Y(),aN->Z());
3692       if(P1.Distance(P2)<tolnode)
3693         return aN;
3694     }
3695   }
3696
3697   // create new node and return it
3698   const SMDS_MeshNode* NewNode = aMesh->AddNode(x,y,z);
3699   myLastCreatedNodes.Append(NewNode);
3700   return NewNode;
3701 }
3702
3703
3704 //=======================================================================
3705 //function : ExtrusionSweep
3706 //purpose  :
3707 //=======================================================================
3708
3709 SMESH_MeshEditor::PGroupIDs
3710 SMESH_MeshEditor::ExtrusionSweep (TIDSortedElemSet &  theElems,
3711                                   const gp_Vec&       theStep,
3712                                   const int           theNbSteps,
3713                                   TElemOfElemListMap& newElemsMap,
3714                                   const bool          theMakeGroups,
3715                                   const int           theFlags,
3716                                   const double        theTolerance)
3717 {
3718   ExtrusParam aParams;
3719   aParams.myDir = gp_Dir(theStep);
3720   aParams.myNodes.Clear();
3721   aParams.mySteps = new TColStd_HSequenceOfReal;
3722   int i;
3723   for(i=1; i<=theNbSteps; i++)
3724     aParams.mySteps->Append(theStep.Magnitude());
3725
3726   return
3727     ExtrusionSweep(theElems,aParams,newElemsMap,theMakeGroups,theFlags,theTolerance);
3728 }
3729
3730
3731 //=======================================================================
3732 //function : ExtrusionSweep
3733 //purpose  :
3734 //=======================================================================
3735
3736 SMESH_MeshEditor::PGroupIDs
3737 SMESH_MeshEditor::ExtrusionSweep (TIDSortedElemSet &  theElems,
3738                                   ExtrusParam&        theParams,
3739                                   TElemOfElemListMap& newElemsMap,
3740                                   const bool          theMakeGroups,
3741                                   const int           theFlags,
3742                                   const double        theTolerance)
3743 {
3744   myLastCreatedElems.Clear();
3745   myLastCreatedNodes.Clear();
3746
3747   // source elements for each generated one
3748   SMESH_SequenceOfElemPtr srcElems, srcNodes;
3749
3750   SMESHDS_Mesh* aMesh = GetMeshDS();
3751
3752   int nbsteps = theParams.mySteps->Length();
3753
3754   TNodeOfNodeListMap mapNewNodes;
3755   //TNodeOfNodeVecMap mapNewNodes;
3756   TElemOfVecOfNnlmiMap mapElemNewNodes;
3757   //TElemOfVecOfMapNodesMap mapElemNewNodes;
3758
3759   // loop on theElems
3760   TIDSortedElemSet::iterator itElem;
3761   for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
3762     // check element type
3763     const SMDS_MeshElement* elem = *itElem;
3764     if ( !elem  || elem->GetType() == SMDSAbs_Volume )
3765       continue;
3766
3767     vector<TNodeOfNodeListMapItr> & newNodesItVec = mapElemNewNodes[ elem ];
3768     //vector<TNodeOfNodeVecMapItr> & newNodesItVec = mapElemNewNodes[ elem ];
3769     newNodesItVec.reserve( elem->NbNodes() );
3770
3771     // loop on elem nodes
3772     SMDS_ElemIteratorPtr itN = elem->nodesIterator();
3773     while ( itN->more() )
3774     {
3775       // check if a node has been already sweeped
3776       const SMDS_MeshNode* node = cast2Node( itN->next() );
3777       TNodeOfNodeListMap::iterator nIt = mapNewNodes.find( node );
3778       //TNodeOfNodeVecMap::iterator nIt = mapNewNodes.find( node );
3779       if ( nIt == mapNewNodes.end() ) {
3780         nIt = mapNewNodes.insert( make_pair( node, list<const SMDS_MeshNode*>() )).first;
3781         //nIt = mapNewNodes.insert( make_pair( node, vector<const SMDS_MeshNode*>() )).first;
3782         list<const SMDS_MeshNode*>& listNewNodes = nIt->second;
3783         //vector<const SMDS_MeshNode*>& vecNewNodes = nIt->second;
3784         //vecNewNodes.reserve(nbsteps);
3785
3786         // make new nodes
3787         double coord[] = { node->X(), node->Y(), node->Z() };
3788         //int nbsteps = theParams.mySteps->Length();
3789         for ( int i = 0; i < nbsteps; i++ ) {
3790           if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
3791             // create additional node
3792             double x = coord[0] + theParams.myDir.X()*theParams.mySteps->Value(i+1)/2.;
3793             double y = coord[1] + theParams.myDir.Y()*theParams.mySteps->Value(i+1)/2.;
3794             double z = coord[2] + theParams.myDir.Z()*theParams.mySteps->Value(i+1)/2.;
3795             if( theFlags & EXTRUSION_FLAG_SEW ) {
3796               const SMDS_MeshNode * newNode = CreateNode(x, y, z,
3797                                                          theTolerance, theParams.myNodes);
3798               listNewNodes.push_back( newNode );
3799             }
3800             else {
3801               const SMDS_MeshNode * newNode = aMesh->AddNode(x, y, z);
3802               myLastCreatedNodes.Append(newNode);
3803               srcNodes.Append( node );
3804               listNewNodes.push_back( newNode );
3805             }
3806           }
3807           //aTrsf.Transforms( coord[0], coord[1], coord[2] );
3808           coord[0] = coord[0] + theParams.myDir.X()*theParams.mySteps->Value(i+1);
3809           coord[1] = coord[1] + theParams.myDir.Y()*theParams.mySteps->Value(i+1);
3810           coord[2] = coord[2] + theParams.myDir.Z()*theParams.mySteps->Value(i+1);
3811           if( theFlags & EXTRUSION_FLAG_SEW ) {
3812             const SMDS_MeshNode * newNode = CreateNode(coord[0], coord[1], coord[2],
3813                                                        theTolerance, theParams.myNodes);
3814             listNewNodes.push_back( newNode );
3815             //vecNewNodes[i]=newNode;
3816           }
3817           else {
3818             const SMDS_MeshNode * newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
3819             myLastCreatedNodes.Append(newNode);
3820             srcNodes.Append( node );
3821             listNewNodes.push_back( newNode );
3822             //vecNewNodes[i]=newNode;
3823           }
3824         }
3825       }
3826       else {
3827         // if current elem is quadratic and current node is not medium
3828         // we have to check - may be it is needed to insert additional nodes
3829         if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
3830           list< const SMDS_MeshNode* > & listNewNodes = nIt->second;
3831           if(listNewNodes.size()==nbsteps) {
3832             listNewNodes.clear();
3833             double coord[] = { node->X(), node->Y(), node->Z() };
3834             for ( int i = 0; i < nbsteps; i++ ) {
3835               double x = coord[0] + theParams.myDir.X()*theParams.mySteps->Value(i+1);
3836               double y = coord[1] + theParams.myDir.Y()*theParams.mySteps->Value(i+1);
3837               double z = coord[2] + theParams.myDir.Z()*theParams.mySteps->Value(i+1);
3838               if( theFlags & EXTRUSION_FLAG_SEW ) {
3839                 const SMDS_MeshNode * newNode = CreateNode(x, y, z,
3840                                                            theTolerance, theParams.myNodes);
3841                 listNewNodes.push_back( newNode );
3842               }
3843               else {
3844                 const SMDS_MeshNode * newNode = aMesh->AddNode(x, y, z);
3845                 myLastCreatedNodes.Append(newNode);
3846                 srcNodes.Append( node );
3847                 listNewNodes.push_back( newNode );
3848               }
3849               coord[0] = coord[0] + theParams.myDir.X()*theParams.mySteps->Value(i+1);
3850               coord[1] = coord[1] + theParams.myDir.Y()*theParams.mySteps->Value(i+1);
3851               coord[2] = coord[2] + theParams.myDir.Z()*theParams.mySteps->Value(i+1);
3852               if( theFlags & EXTRUSION_FLAG_SEW ) {
3853                 const SMDS_MeshNode * newNode = CreateNode(coord[0], coord[1], coord[2],
3854                                                            theTolerance, theParams.myNodes);
3855                 listNewNodes.push_back( newNode );
3856               }
3857               else {
3858                 const SMDS_MeshNode * newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
3859                 myLastCreatedNodes.Append(newNode);
3860                 srcNodes.Append( node );
3861                 listNewNodes.push_back( newNode );
3862               }
3863             }
3864           }
3865         }
3866       }
3867       newNodesItVec.push_back( nIt );
3868     }
3869     // make new elements
3870     sweepElement( elem, newNodesItVec, newElemsMap[elem], nbsteps, srcElems );
3871   }
3872
3873   if( theFlags & EXTRUSION_FLAG_BOUNDARY ) {
3874     makeWalls( mapNewNodes, newElemsMap, mapElemNewNodes, theElems, nbsteps, srcElems );
3875   }
3876   PGroupIDs newGroupIDs;
3877   if ( theMakeGroups )
3878     newGroupIDs = generateGroups( srcNodes, srcElems, "extruded");
3879
3880   return newGroupIDs;
3881 }
3882
3883 /*
3884 //=======================================================================
3885 //class    : SMESH_MeshEditor_PathPoint
3886 //purpose  : auxiliary class
3887 //=======================================================================
3888 class SMESH_MeshEditor_PathPoint {
3889 public:
3890 SMESH_MeshEditor_PathPoint() {
3891 myPnt.SetCoord(99., 99., 99.);
3892 myTgt.SetCoord(1.,0.,0.);
3893 myAngle=0.;
3894 myPrm=0.;
3895 }
3896 void SetPnt(const gp_Pnt& aP3D){
3897 myPnt=aP3D;
3898 }
3899 void SetTangent(const gp_Dir& aTgt){
3900 myTgt=aTgt;
3901 }
3902 void SetAngle(const double& aBeta){
3903 myAngle=aBeta;
3904 }
3905 void SetParameter(const double& aPrm){
3906 myPrm=aPrm;
3907 }
3908 const gp_Pnt& Pnt()const{
3909 return myPnt;
3910 }
3911 const gp_Dir& Tangent()const{
3912 return myTgt;
3913 }
3914 double Angle()const{
3915 return myAngle;
3916 }
3917 double Parameter()const{
3918 return myPrm;
3919 }
3920
3921 protected:
3922 gp_Pnt myPnt;
3923 gp_Dir myTgt;
3924 double myAngle;
3925 double myPrm;
3926 };
3927 */
3928
3929 //=======================================================================
3930 //function : ExtrusionAlongTrack
3931 //purpose  :
3932 //=======================================================================
3933 SMESH_MeshEditor::Extrusion_Error
3934 SMESH_MeshEditor::ExtrusionAlongTrack (TIDSortedElemSet &   theElements,
3935                                        SMESH_subMesh*       theTrack,
3936                                        const SMDS_MeshNode* theN1,
3937                                        const bool           theHasAngles,
3938                                        list<double>&        theAngles,
3939                                        const bool           theLinearVariation,
3940                                        const bool           theHasRefPoint,
3941                                        const gp_Pnt&        theRefPoint,
3942                                        const bool           theMakeGroups)
3943 {
3944   myLastCreatedElems.Clear();
3945   myLastCreatedNodes.Clear();
3946
3947   int aNbE;
3948   std::list<double> aPrms;
3949   TIDSortedElemSet::iterator itElem;
3950
3951   gp_XYZ aGC;
3952   TopoDS_Edge aTrackEdge;
3953   TopoDS_Vertex aV1, aV2;
3954
3955   SMDS_ElemIteratorPtr aItE;
3956   SMDS_NodeIteratorPtr aItN;
3957   SMDSAbs_ElementType aTypeE;
3958
3959   TNodeOfNodeListMap mapNewNodes;
3960
3961   // 1. Check data
3962   aNbE = theElements.size();
3963   // nothing to do
3964   if ( !aNbE )
3965     return EXTR_NO_ELEMENTS;
3966
3967   // 1.1 Track Pattern
3968   ASSERT( theTrack );
3969
3970   SMESHDS_SubMesh* pSubMeshDS = theTrack->GetSubMeshDS();
3971
3972   aItE = pSubMeshDS->GetElements();
3973   while ( aItE->more() ) {
3974     const SMDS_MeshElement* pE = aItE->next();
3975     aTypeE = pE->GetType();
3976     // Pattern must contain links only
3977     if ( aTypeE != SMDSAbs_Edge )
3978       return EXTR_PATH_NOT_EDGE;
3979   }
3980
3981   list<SMESH_MeshEditor_PathPoint> fullList;
3982
3983   const TopoDS_Shape& aS = theTrack->GetSubShape();
3984   // Sub shape for the Pattern must be an Edge or Wire
3985   if( aS.ShapeType() == TopAbs_EDGE ) {
3986     aTrackEdge = TopoDS::Edge( aS );
3987     // the Edge must not be degenerated
3988     if ( BRep_Tool::Degenerated( aTrackEdge ) )
3989       return EXTR_BAD_PATH_SHAPE;
3990     TopExp::Vertices( aTrackEdge, aV1, aV2 );
3991     aItN = theTrack->GetFather()->GetSubMesh( aV1 )->GetSubMeshDS()->GetNodes();
3992     const SMDS_MeshNode* aN1 = aItN->next();
3993     aItN = theTrack->GetFather()->GetSubMesh( aV2 )->GetSubMeshDS()->GetNodes();
3994     const SMDS_MeshNode* aN2 = aItN->next();
3995     // starting node must be aN1 or aN2
3996     if ( !( aN1 == theN1 || aN2 == theN1 ) )
3997       return EXTR_BAD_STARTING_NODE;
3998     aItN = pSubMeshDS->GetNodes();
3999     while ( aItN->more() ) {
4000       const SMDS_MeshNode* pNode = aItN->next();
4001       const SMDS_EdgePosition* pEPos =
4002         static_cast<const SMDS_EdgePosition*>( pNode->GetPosition().get() );
4003       double aT = pEPos->GetUParameter();
4004       aPrms.push_back( aT );
4005     }
4006     //Extrusion_Error err =
4007     MakeEdgePathPoints(aPrms, aTrackEdge, (aN1==theN1), fullList);
4008   }
4009   else if( aS.ShapeType() == TopAbs_WIRE ) {
4010     list< SMESH_subMesh* > LSM;
4011     TopTools_SequenceOfShape Edges;
4012     SMESH_subMeshIteratorPtr itSM = theTrack->getDependsOnIterator(false,true);
4013     while(itSM->more()) {
4014       SMESH_subMesh* SM = itSM->next();
4015       LSM.push_back(SM);
4016       const TopoDS_Shape& aS = SM->GetSubShape();
4017       Edges.Append(aS);
4018     }
4019     list< list<SMESH_MeshEditor_PathPoint> > LLPPs;
4020     int startNid = theN1->GetID();
4021     TColStd_MapOfInteger UsedNums;
4022     int NbEdges = Edges.Length();
4023     int i = 1;
4024     for(; i<=NbEdges; i++) {
4025       int k = 0;
4026       list< SMESH_subMesh* >::iterator itLSM = LSM.begin();
4027       for(; itLSM!=LSM.end(); itLSM++) {
4028         k++;
4029         if(UsedNums.Contains(k)) continue;
4030         aTrackEdge = TopoDS::Edge( Edges.Value(k) );
4031         SMESH_subMesh* locTrack = *itLSM;
4032         SMESHDS_SubMesh* locMeshDS = locTrack->GetSubMeshDS();
4033         TopExp::Vertices( aTrackEdge, aV1, aV2 );
4034         aItN = locTrack->GetFather()->GetSubMesh(aV1)->GetSubMeshDS()->GetNodes();
4035         const SMDS_MeshNode* aN1 = aItN->next();
4036         aItN = locTrack->GetFather()->GetSubMesh(aV2)->GetSubMeshDS()->GetNodes();
4037         const SMDS_MeshNode* aN2 = aItN->next();
4038         // starting node must be aN1 or aN2
4039         if ( !( aN1->GetID() == startNid || aN2->GetID() == startNid ) ) continue;
4040         // 2. Collect parameters on the track edge
4041         aPrms.clear();
4042         aItN = locMeshDS->GetNodes();
4043         while ( aItN->more() ) {
4044           const SMDS_MeshNode* pNode = aItN->next();
4045           const SMDS_EdgePosition* pEPos =
4046             static_cast<const SMDS_EdgePosition*>( pNode->GetPosition().get() );
4047           double aT = pEPos->GetUParameter();
4048           aPrms.push_back( aT );
4049         }
4050         list<SMESH_MeshEditor_PathPoint> LPP;
4051         //Extrusion_Error err =
4052         MakeEdgePathPoints(aPrms, aTrackEdge,(aN1->GetID()==startNid), LPP);
4053         LLPPs.push_back(LPP);
4054         UsedNums.Add(k);
4055         // update startN for search following egde
4056         if( aN1->GetID() == startNid ) startNid = aN2->GetID();
4057         else startNid = aN1->GetID();
4058         break;
4059       }
4060     }
4061     list< list<SMESH_MeshEditor_PathPoint> >::iterator itLLPP = LLPPs.begin();
4062     list<SMESH_MeshEditor_PathPoint> firstList = *itLLPP;
4063     list<SMESH_MeshEditor_PathPoint>::iterator itPP = firstList.begin();
4064     for(; itPP!=firstList.end(); itPP++) {
4065       fullList.push_back( *itPP );
4066     }
4067     SMESH_MeshEditor_PathPoint PP1 = fullList.back();
4068     fullList.pop_back();
4069     itLLPP++;
4070     for(; itLLPP!=LLPPs.end(); itLLPP++) {
4071       list<SMESH_MeshEditor_PathPoint> currList = *itLLPP;
4072       itPP = currList.begin();
4073       SMESH_MeshEditor_PathPoint PP2 = currList.front();
4074       gp_Dir D1 = PP1.Tangent();
4075       gp_Dir D2 = PP2.Tangent();
4076       gp_Dir Dnew( gp_Vec( (D1.X()+D2.X())/2, (D1.Y()+D2.Y())/2,
4077                            (D1.Z()+D2.Z())/2 ) );
4078       PP1.SetTangent(Dnew);
4079       fullList.push_back(PP1);
4080       itPP++;
4081       for(; itPP!=firstList.end(); itPP++) {
4082         fullList.push_back( *itPP );
4083       }
4084       PP1 = fullList.back();
4085       fullList.pop_back();
4086     }
4087     // if wire not closed
4088     fullList.push_back(PP1);
4089     // else ???
4090   }
4091   else {
4092     return EXTR_BAD_PATH_SHAPE;
4093   }
4094
4095   return MakeExtrElements(theElements, fullList, theHasAngles, theAngles, theLinearVariation,
4096                           theHasRefPoint, theRefPoint, theMakeGroups);
4097 }
4098
4099
4100 //=======================================================================
4101 //function : ExtrusionAlongTrack
4102 //purpose  :
4103 //=======================================================================
4104 SMESH_MeshEditor::Extrusion_Error
4105 SMESH_MeshEditor::ExtrusionAlongTrack (TIDSortedElemSet &   theElements,
4106                                        SMESH_Mesh*          theTrack,
4107                                        const SMDS_MeshNode* theN1,
4108                                        const bool           theHasAngles,
4109                                        list<double>&        theAngles,
4110                                        const bool           theLinearVariation,
4111                                        const bool           theHasRefPoint,
4112                                        const gp_Pnt&        theRefPoint,
4113                                        const bool           theMakeGroups)
4114 {
4115   myLastCreatedElems.Clear();
4116   myLastCreatedNodes.Clear();
4117
4118   int aNbE;
4119   std::list<double> aPrms;
4120   TIDSortedElemSet::iterator itElem;
4121
4122   gp_XYZ aGC;
4123   TopoDS_Edge aTrackEdge;
4124   TopoDS_Vertex aV1, aV2;
4125
4126   SMDS_ElemIteratorPtr aItE;
4127   SMDS_NodeIteratorPtr aItN;
4128   SMDSAbs_ElementType aTypeE;
4129
4130   TNodeOfNodeListMap mapNewNodes;
4131
4132   // 1. Check data
4133   aNbE = theElements.size();
4134   // nothing to do
4135   if ( !aNbE )
4136     return EXTR_NO_ELEMENTS;
4137
4138   // 1.1 Track Pattern
4139   ASSERT( theTrack );
4140
4141   SMESHDS_Mesh* pMeshDS = theTrack->GetMeshDS();
4142
4143   aItE = pMeshDS->elementsIterator();
4144   while ( aItE->more() ) {
4145     const SMDS_MeshElement* pE = aItE->next();
4146     aTypeE = pE->GetType();
4147     // Pattern must contain links only
4148     if ( aTypeE != SMDSAbs_Edge )
4149       return EXTR_PATH_NOT_EDGE;
4150   }
4151
4152   list<SMESH_MeshEditor_PathPoint> fullList;
4153
4154   const TopoDS_Shape& aS = theTrack->GetShapeToMesh();
4155   // Sub shape for the Pattern must be an Edge or Wire
4156   if( aS.ShapeType() == TopAbs_EDGE ) {
4157     aTrackEdge = TopoDS::Edge( aS );
4158     // the Edge must not be degenerated
4159     if ( BRep_Tool::Degenerated( aTrackEdge ) )
4160       return EXTR_BAD_PATH_SHAPE;
4161     TopExp::Vertices( aTrackEdge, aV1, aV2 );
4162     aItN = theTrack->GetSubMesh( aV1 )->GetSubMeshDS()->GetNodes();
4163     const SMDS_MeshNode* aN1 = aItN->next();
4164     aItN = theTrack->GetSubMesh( aV2 )->GetSubMeshDS()->GetNodes();
4165     const SMDS_MeshNode* aN2 = aItN->next();
4166     // starting node must be aN1 or aN2
4167     if ( !( aN1 == theN1 || aN2 == theN1 ) )
4168       return EXTR_BAD_STARTING_NODE;
4169     aItN = pMeshDS->nodesIterator();
4170     while ( aItN->more() ) {
4171       const SMDS_MeshNode* pNode = aItN->next();
4172       if( pNode==aN1 || pNode==aN2 ) continue;
4173       const SMDS_EdgePosition* pEPos =
4174         static_cast<const SMDS_EdgePosition*>( pNode->GetPosition().get() );
4175       double aT = pEPos->GetUParameter();
4176       aPrms.push_back( aT );
4177     }
4178     //Extrusion_Error err =
4179     MakeEdgePathPoints(aPrms, aTrackEdge, (aN1==theN1), fullList);
4180   }
4181   else if( aS.ShapeType() == TopAbs_WIRE ) {
4182     list< SMESH_subMesh* > LSM;
4183     TopTools_SequenceOfShape Edges;
4184     TopExp_Explorer eExp(aS, TopAbs_EDGE);
4185     for(; eExp.More(); eExp.Next()) {
4186       TopoDS_Edge E = TopoDS::Edge( eExp.Current() );
4187       if( BRep_Tool::Degenerated(E) ) continue;
4188       SMESH_subMesh* SM = theTrack->GetSubMesh(E);
4189       if(SM) {
4190         LSM.push_back(SM);
4191         Edges.Append(E);
4192       }
4193     }
4194     list< list<SMESH_MeshEditor_PathPoint> > LLPPs;
4195     int startNid = theN1->GetID();
4196     TColStd_MapOfInteger UsedNums;
4197     int NbEdges = Edges.Length();
4198     int i = 1;
4199     for(; i<=NbEdges; i++) {
4200       int k = 0;
4201       list< SMESH_subMesh* >::iterator itLSM = LSM.begin();
4202       for(; itLSM!=LSM.end(); itLSM++) {
4203         k++;
4204         if(UsedNums.Contains(k)) continue;
4205         aTrackEdge = TopoDS::Edge( Edges.Value(k) );
4206         SMESH_subMesh* locTrack = *itLSM;
4207         SMESHDS_SubMesh* locMeshDS = locTrack->GetSubMeshDS();
4208         TopExp::Vertices( aTrackEdge, aV1, aV2 );
4209         aItN = locTrack->GetFather()->GetSubMesh(aV1)->GetSubMeshDS()->GetNodes();
4210         const SMDS_MeshNode* aN1 = aItN->next();
4211         aItN = locTrack->GetFather()->GetSubMesh(aV2)->GetSubMeshDS()->GetNodes();
4212         const SMDS_MeshNode* aN2 = aItN->next();
4213         // starting node must be aN1 or aN2
4214         if ( !( aN1->GetID() == startNid || aN2->GetID() == startNid ) ) continue;
4215         // 2. Collect parameters on the track edge
4216         aPrms.clear();
4217         aItN = locMeshDS->GetNodes();
4218         while ( aItN->more() ) {
4219           const SMDS_MeshNode* pNode = aItN->next();
4220           const SMDS_EdgePosition* pEPos =
4221             static_cast<const SMDS_EdgePosition*>( pNode->GetPosition().get() );
4222           double aT = pEPos->GetUParameter();
4223           aPrms.push_back( aT );
4224         }
4225         list<SMESH_MeshEditor_PathPoint> LPP;
4226         //Extrusion_Error err =
4227         MakeEdgePathPoints(aPrms, aTrackEdge,(aN1->GetID()==startNid), LPP);
4228         LLPPs.push_back(LPP);
4229         UsedNums.Add(k);
4230         // update startN for search following egde
4231         if( aN1->GetID() == startNid ) startNid = aN2->GetID();
4232         else startNid = aN1->GetID();
4233         break;
4234       }
4235     }
4236     list< list<SMESH_MeshEditor_PathPoint> >::iterator itLLPP = LLPPs.begin();
4237     list<SMESH_MeshEditor_PathPoint> firstList = *itLLPP;
4238     list<SMESH_MeshEditor_PathPoint>::iterator itPP = firstList.begin();
4239     for(; itPP!=firstList.end(); itPP++) {
4240       fullList.push_back( *itPP );
4241     }
4242     SMESH_MeshEditor_PathPoint PP1 = fullList.back();
4243     fullList.pop_back();
4244     itLLPP++;
4245     for(; itLLPP!=LLPPs.end(); itLLPP++) {
4246       list<SMESH_MeshEditor_PathPoint> currList = *itLLPP;
4247       itPP = currList.begin();
4248       SMESH_MeshEditor_PathPoint PP2 = currList.front();
4249       gp_Pnt P1 = PP1.Pnt();
4250       //cout<<"    PP1: Pnt("<<P1.X()<<","<<P1.Y()<<","<<P1.Z()<<")"<<endl;
4251       gp_Pnt P2 = PP2.Pnt();
4252       gp_Dir D1 = PP1.Tangent();
4253       gp_Dir D2 = PP2.Tangent();
4254       gp_Dir Dnew( gp_Vec( (D1.X()+D2.X())/2, (D1.Y()+D2.Y())/2,
4255                            (D1.Z()+D2.Z())/2 ) );
4256       PP1.SetTangent(Dnew);
4257       fullList.push_back(PP1);
4258       itPP++;
4259       for(; itPP!=currList.end(); itPP++) {
4260         fullList.push_back( *itPP );
4261       }
4262       PP1 = fullList.back();
4263       fullList.pop_back();
4264     }
4265     // if wire not closed
4266     fullList.push_back(PP1);
4267     // else ???
4268   }
4269   else {
4270     return EXTR_BAD_PATH_SHAPE;
4271   }
4272
4273   return MakeExtrElements(theElements, fullList, theHasAngles, theAngles, theLinearVariation,
4274                           theHasRefPoint, theRefPoint, theMakeGroups);
4275 }
4276
4277
4278 //=======================================================================
4279 //function : MakeEdgePathPoints
4280 //purpose  : auxilary for ExtrusionAlongTrack
4281 //=======================================================================
4282 SMESH_MeshEditor::Extrusion_Error
4283 SMESH_MeshEditor::MakeEdgePathPoints(std::list<double>& aPrms,
4284                                      const TopoDS_Edge& aTrackEdge,
4285                                      bool FirstIsStart,
4286                                      list<SMESH_MeshEditor_PathPoint>& LPP)
4287 {
4288   Standard_Real aTx1, aTx2, aL2, aTolVec, aTolVec2;
4289   aTolVec=1.e-7;
4290   aTolVec2=aTolVec*aTolVec;
4291   double aT1, aT2;
4292   TopoDS_Vertex aV1, aV2;
4293   TopExp::Vertices( aTrackEdge, aV1, aV2 );
4294   aT1=BRep_Tool::Parameter( aV1, aTrackEdge );
4295   aT2=BRep_Tool::Parameter( aV2, aTrackEdge );
4296   // 2. Collect parameters on the track edge
4297   aPrms.push_front( aT1 );
4298   aPrms.push_back( aT2 );
4299   // sort parameters
4300   aPrms.sort();
4301   if( FirstIsStart ) {
4302     if ( aT1 > aT2 ) {
4303       aPrms.reverse();
4304     }
4305   }
4306   else {
4307     if ( aT2 > aT1 ) {
4308       aPrms.reverse();
4309     }
4310   }
4311   // 3. Path Points
4312   SMESH_MeshEditor_PathPoint aPP;
4313   Handle(Geom_Curve) aC3D = BRep_Tool::Curve( aTrackEdge, aTx1, aTx2 );
4314   std::list<double>::iterator aItD = aPrms.begin();
4315   for(; aItD != aPrms.end(); ++aItD) {
4316     double aT = *aItD;
4317     gp_Pnt aP3D;
4318     gp_Vec aVec;
4319     aC3D->D1( aT, aP3D, aVec );
4320     aL2 = aVec.SquareMagnitude();
4321     if ( aL2 < aTolVec2 )
4322       return EXTR_CANT_GET_TANGENT;
4323     gp_Dir aTgt( aVec );
4324     aPP.SetPnt( aP3D );
4325     aPP.SetTangent( aTgt );
4326     aPP.SetParameter( aT );
4327     LPP.push_back(aPP);
4328   }
4329   return EXTR_OK;
4330 }
4331
4332
4333 //=======================================================================
4334 //function : MakeExtrElements
4335 //purpose  : auxilary for ExtrusionAlongTrack
4336 //=======================================================================
4337 SMESH_MeshEditor::Extrusion_Error
4338 SMESH_MeshEditor::MakeExtrElements(TIDSortedElemSet&  theElements,
4339                                    list<SMESH_MeshEditor_PathPoint>& fullList,
4340                                    const bool theHasAngles,
4341                                    list<double>& theAngles,
4342                                    const bool theLinearVariation,
4343                                    const bool theHasRefPoint,
4344                                    const gp_Pnt& theRefPoint,
4345                                    const bool theMakeGroups)
4346 {
4347   //cout<<"MakeExtrElements  fullList.size() = "<<fullList.size()<<endl;
4348   int aNbTP = fullList.size();
4349   vector<SMESH_MeshEditor_PathPoint> aPPs(aNbTP);
4350   // Angles
4351   if( theHasAngles && theAngles.size()>0 && theLinearVariation ) {
4352     LinearAngleVariation(aNbTP-1, theAngles);
4353   }
4354   vector<double> aAngles( aNbTP );
4355   int j = 0;
4356   for(; j<aNbTP; ++j) {
4357     aAngles[j] = 0.;
4358   }
4359   if ( theHasAngles ) {
4360     double anAngle;;
4361     std::list<double>::iterator aItD = theAngles.begin();
4362     for ( j=1; (aItD != theAngles.end()) && (j<aNbTP); ++aItD, ++j ) {
4363       anAngle = *aItD;
4364       aAngles[j] = anAngle;
4365     }
4366   }
4367   // fill vector of path points with angles
4368   //aPPs.resize(fullList.size());
4369   j = -1;
4370   list<SMESH_MeshEditor_PathPoint>::iterator itPP = fullList.begin();
4371   for(; itPP!=fullList.end(); itPP++) {
4372     j++;
4373     SMESH_MeshEditor_PathPoint PP = *itPP;
4374     PP.SetAngle(aAngles[j]);
4375     aPPs[j] = PP;
4376   }
4377
4378   TNodeOfNodeListMap mapNewNodes;
4379   TElemOfVecOfNnlmiMap mapElemNewNodes;
4380   TElemOfElemListMap newElemsMap;
4381   TIDSortedElemSet::iterator itElem;
4382   double aX, aY, aZ;
4383   int aNb;
4384   SMDSAbs_ElementType aTypeE;
4385   // source elements for each generated one
4386   SMESH_SequenceOfElemPtr srcElems, srcNodes;
4387
4388   // 3. Center of rotation aV0
4389   gp_Pnt aV0 = theRefPoint;
4390   gp_XYZ aGC;
4391   if ( !theHasRefPoint ) {
4392     aNb = 0;
4393     aGC.SetCoord( 0.,0.,0. );
4394
4395     itElem = theElements.begin();
4396     for ( ; itElem != theElements.end(); itElem++ ) {
4397       const SMDS_MeshElement* elem = *itElem;
4398
4399       SMDS_ElemIteratorPtr itN = elem->nodesIterator();
4400       while ( itN->more() ) {
4401         const SMDS_MeshNode* node = static_cast<const SMDS_MeshNode*>( itN->next() );
4402         aX = node->X();
4403         aY = node->Y();
4404         aZ = node->Z();
4405
4406         if ( mapNewNodes.find( node ) == mapNewNodes.end() ) {
4407           list<const SMDS_MeshNode*> aLNx;
4408           mapNewNodes[node] = aLNx;
4409           //
4410           gp_XYZ aXYZ( aX, aY, aZ );
4411           aGC += aXYZ;
4412           ++aNb;
4413         }
4414       }
4415     }
4416     aGC /= aNb;
4417     aV0.SetXYZ( aGC );
4418   } // if (!theHasRefPoint) {
4419   mapNewNodes.clear();
4420
4421   // 4. Processing the elements
4422   SMESHDS_Mesh* aMesh = GetMeshDS();
4423
4424   for ( itElem = theElements.begin(); itElem != theElements.end(); itElem++ ) {
4425     // check element type
4426     const SMDS_MeshElement* elem = *itElem;
4427     aTypeE = elem->GetType();
4428     if ( !elem || ( aTypeE != SMDSAbs_Face && aTypeE != SMDSAbs_Edge ) )
4429       continue;
4430
4431     vector<TNodeOfNodeListMapItr> & newNodesItVec = mapElemNewNodes[ elem ];
4432     newNodesItVec.reserve( elem->NbNodes() );
4433
4434     // loop on elem nodes
4435     int nodeIndex = -1;
4436     SMDS_ElemIteratorPtr itN = elem->nodesIterator();
4437     while ( itN->more() )
4438     {
4439       ++nodeIndex;
4440       // check if a node has been already processed
4441       const SMDS_MeshNode* node =
4442         static_cast<const SMDS_MeshNode*>( itN->next() );
4443       TNodeOfNodeListMap::iterator nIt = mapNewNodes.find( node );
4444       if ( nIt == mapNewNodes.end() ) {
4445         nIt = mapNewNodes.insert( make_pair( node, list<const SMDS_MeshNode*>() )).first;
4446         list<const SMDS_MeshNode*>& listNewNodes = nIt->second;
4447
4448         // make new nodes
4449         aX = node->X();  aY = node->Y(); aZ = node->Z();
4450
4451         Standard_Real aAngle1x, aAngleT1T0, aTolAng;
4452         gp_Pnt aP0x, aP1x, aPN0, aPN1, aV0x, aV1x;
4453         gp_Ax1 anAx1, anAxT1T0;
4454         gp_Dir aDT1x, aDT0x, aDT1T0;
4455
4456         aTolAng=1.e-4;
4457
4458         aV0x = aV0;
4459         aPN0.SetCoord(aX, aY, aZ);
4460
4461         const SMESH_MeshEditor_PathPoint& aPP0 = aPPs[0];
4462         aP0x = aPP0.Pnt();
4463         aDT0x= aPP0.Tangent();
4464         //cout<<"j = 0   PP: Pnt("<<aP0x.X()<<","<<aP0x.Y()<<","<<aP0x.Z()<<")"<<endl;
4465
4466         for ( j = 1; j < aNbTP; ++j ) {
4467           const SMESH_MeshEditor_PathPoint& aPP1 = aPPs[j];
4468           aP1x = aPP1.Pnt();
4469           aDT1x = aPP1.Tangent();
4470           aAngle1x = aPP1.Angle();
4471
4472           gp_Trsf aTrsf, aTrsfRot, aTrsfRotT1T0;
4473           // Translation
4474           gp_Vec aV01x( aP0x, aP1x );
4475           aTrsf.SetTranslation( aV01x );
4476
4477           // traslated point
4478           aV1x = aV0x.Transformed( aTrsf );
4479           aPN1 = aPN0.Transformed( aTrsf );
4480
4481           // rotation 1 [ T1,T0 ]
4482           aAngleT1T0=-aDT1x.Angle( aDT0x );
4483           if (fabs(aAngleT1T0) > aTolAng) {
4484             aDT1T0=aDT1x^aDT0x;
4485             anAxT1T0.SetLocation( aV1x );
4486             anAxT1T0.SetDirection( aDT1T0 );
4487             aTrsfRotT1T0.SetRotation( anAxT1T0, aAngleT1T0 );
4488
4489             aPN1 = aPN1.Transformed( aTrsfRotT1T0 );
4490           }
4491
4492           // rotation 2
4493           if ( theHasAngles ) {
4494             anAx1.SetLocation( aV1x );
4495             anAx1.SetDirection( aDT1x );
4496             aTrsfRot.SetRotation( anAx1, aAngle1x );
4497
4498             aPN1 = aPN1.Transformed( aTrsfRot );
4499           }
4500
4501           // make new node
4502           if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
4503             // create additional node
4504             double x = ( aPN1.X() + aPN0.X() )/2.;
4505             double y = ( aPN1.Y() + aPN0.Y() )/2.;
4506             double z = ( aPN1.Z() + aPN0.Z() )/2.;
4507             const SMDS_MeshNode* newNode = aMesh->AddNode(x,y,z);
4508             myLastCreatedNodes.Append(newNode);
4509             srcNodes.Append( node );
4510             listNewNodes.push_back( newNode );
4511           }
4512           aX = aPN1.X();
4513           aY = aPN1.Y();
4514           aZ = aPN1.Z();
4515           const SMDS_MeshNode* newNode = aMesh->AddNode( aX, aY, aZ );
4516           myLastCreatedNodes.Append(newNode);
4517           srcNodes.Append( node );
4518           listNewNodes.push_back( newNode );
4519
4520           aPN0 = aPN1;
4521           aP0x = aP1x;
4522           aV0x = aV1x;
4523           aDT0x = aDT1x;
4524         }
4525       }
4526
4527       else {
4528         // if current elem is quadratic and current node is not medium
4529         // we have to check - may be it is needed to insert additional nodes
4530         if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
4531           list< const SMDS_MeshNode* > & listNewNodes = nIt->second;
4532           if(listNewNodes.size()==aNbTP-1) {
4533             vector<const SMDS_MeshNode*> aNodes(2*(aNbTP-1));
4534             gp_XYZ P(node->X(), node->Y(), node->Z());
4535             list< const SMDS_MeshNode* >::iterator it = listNewNodes.begin();
4536             int i;
4537             for(i=0; i<aNbTP-1; i++) {
4538               const SMDS_MeshNode* N = *it;
4539               double x = ( N->X() + P.X() )/2.;
4540               double y = ( N->Y() + P.Y() )/2.;
4541               double z = ( N->Z() + P.Z() )/2.;
4542               const SMDS_MeshNode* newN = aMesh->AddNode(x,y,z);
4543               srcNodes.Append( node );
4544               myLastCreatedNodes.Append(newN);
4545               aNodes[2*i] = newN;
4546               aNodes[2*i+1] = N;
4547               P = gp_XYZ(N->X(),N->Y(),N->Z());
4548             }
4549             listNewNodes.clear();
4550             for(i=0; i<2*(aNbTP-1); i++) {
4551               listNewNodes.push_back(aNodes[i]);
4552             }
4553           }
4554         }
4555       }
4556
4557       newNodesItVec.push_back( nIt );
4558     }
4559     // make new elements
4560     //sweepElement( aMesh, elem, newNodesItVec, newElemsMap[elem],
4561     //              newNodesItVec[0]->second.size(), myLastCreatedElems );
4562     sweepElement( elem, newNodesItVec, newElemsMap[elem], aNbTP-1, srcElems );
4563   }
4564
4565   makeWalls( mapNewNodes, newElemsMap, mapElemNewNodes, theElements, aNbTP-1, srcElems );
4566
4567   if ( theMakeGroups )
4568     generateGroups( srcNodes, srcElems, "extruded");
4569
4570   return EXTR_OK;
4571 }
4572
4573
4574 //=======================================================================
4575 //function : LinearAngleVariation
4576 //purpose  : auxilary for ExtrusionAlongTrack
4577 //=======================================================================
4578 void SMESH_MeshEditor::LinearAngleVariation(const int nbSteps,
4579                                             list<double>& Angles)
4580 {
4581   int nbAngles = Angles.size();
4582   if( nbSteps > nbAngles ) {
4583     vector<double> theAngles(nbAngles);
4584     list<double>::iterator it = Angles.begin();
4585     int i = -1;
4586     for(; it!=Angles.end(); it++) {
4587       i++;
4588       theAngles[i] = (*it);
4589     }
4590     list<double> res;
4591     double rAn2St = double( nbAngles ) / double( nbSteps );
4592     double angPrev = 0, angle;
4593     for ( int iSt = 0; iSt < nbSteps; ++iSt ) {
4594       double angCur = rAn2St * ( iSt+1 );
4595       double angCurFloor  = floor( angCur );
4596       double angPrevFloor = floor( angPrev );
4597       if ( angPrevFloor == angCurFloor )
4598         angle = rAn2St * theAngles[ int( angCurFloor ) ];
4599       else {
4600         int iP = int( angPrevFloor );
4601         double angPrevCeil = ceil(angPrev);
4602         angle = ( angPrevCeil - angPrev ) * theAngles[ iP ];
4603
4604         int iC = int( angCurFloor );
4605         if ( iC < nbAngles )
4606           angle += ( angCur - angCurFloor ) * theAngles[ iC ];
4607
4608         iP = int( angPrevCeil );
4609         while ( iC-- > iP )
4610           angle += theAngles[ iC ];
4611       }
4612       res.push_back(angle);
4613       angPrev = angCur;
4614     }
4615     Angles.clear();
4616     it = res.begin();
4617     for(; it!=res.end(); it++)
4618       Angles.push_back( *it );
4619   }
4620 }
4621
4622
4623 //=======================================================================
4624 //function : Transform
4625 //purpose  :
4626 //=======================================================================
4627
4628 SMESH_MeshEditor::PGroupIDs
4629 SMESH_MeshEditor::Transform (TIDSortedElemSet & theElems,
4630                              const gp_Trsf&     theTrsf,
4631                              const bool         theCopy,
4632                              const bool         theMakeGroups,
4633                              SMESH_Mesh*        theTargetMesh)
4634 {
4635   myLastCreatedElems.Clear();
4636   myLastCreatedNodes.Clear();
4637
4638   bool needReverse = false;
4639   string groupPostfix;
4640   switch ( theTrsf.Form() ) {
4641   case gp_PntMirror:
4642   case gp_Ax1Mirror:
4643   case gp_Ax2Mirror:
4644     needReverse = true;
4645     groupPostfix = "mirrored";
4646     break;
4647   case gp_Rotation:
4648     groupPostfix = "rotated";
4649     break;
4650   case gp_Translation:
4651     groupPostfix = "translated";
4652     break;
4653   case gp_Scale:
4654     groupPostfix = "scaled";
4655     break;
4656   default:
4657     needReverse = false;
4658     groupPostfix = "transformed";
4659   }
4660
4661   SMESH_MeshEditor targetMeshEditor( theTargetMesh );
4662   SMESHDS_Mesh* aTgtMesh = theTargetMesh ? theTargetMesh->GetMeshDS() : 0;
4663   SMESHDS_Mesh* aMesh    = GetMeshDS();
4664
4665
4666   // map old node to new one
4667   TNodeNodeMap nodeMap;
4668
4669   // elements sharing moved nodes; those of them which have all
4670   // nodes mirrored but are not in theElems are to be reversed
4671   TIDSortedElemSet inverseElemSet;
4672
4673   // source elements for each generated one
4674   SMESH_SequenceOfElemPtr srcElems, srcNodes;
4675
4676   // loop on theElems
4677   TIDSortedElemSet::iterator itElem;
4678   for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
4679     const SMDS_MeshElement* elem = *itElem;
4680     if ( !elem )
4681       continue;
4682
4683     // loop on elem nodes
4684     SMDS_ElemIteratorPtr itN = elem->nodesIterator();
4685     while ( itN->more() ) {
4686
4687       // check if a node has been already transformed
4688       const SMDS_MeshNode* node = cast2Node( itN->next() );
4689       pair<TNodeNodeMap::iterator,bool> n2n_isnew =
4690         nodeMap.insert( make_pair ( node, node ));
4691       if ( !n2n_isnew.second )
4692         continue;
4693
4694       double coord[3];
4695       coord[0] = node->X();
4696       coord[1] = node->Y();
4697       coord[2] = node->Z();
4698       theTrsf.Transforms( coord[0], coord[1], coord[2] );
4699       if ( theTargetMesh ) {
4700         const SMDS_MeshNode * newNode = aTgtMesh->AddNode( coord[0], coord[1], coord[2] );
4701         n2n_isnew.first->second = newNode;
4702         myLastCreatedNodes.Append(newNode);
4703         srcNodes.Append( node );
4704       }
4705       else if ( theCopy ) {
4706         const SMDS_MeshNode * newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
4707         n2n_isnew.first->second = newNode;
4708         myLastCreatedNodes.Append(newNode);
4709         srcNodes.Append( node );
4710       }
4711       else {
4712         aMesh->MoveNode( node, coord[0], coord[1], coord[2] );
4713         // node position on shape becomes invalid
4714         const_cast< SMDS_MeshNode* > ( node )->SetPosition
4715           ( SMDS_SpacePosition::originSpacePosition() );
4716       }
4717
4718       // keep inverse elements
4719       if ( !theCopy && !theTargetMesh && needReverse ) {
4720         SMDS_ElemIteratorPtr invElemIt = node->GetInverseElementIterator();
4721         while ( invElemIt->more() ) {
4722           const SMDS_MeshElement* iel = invElemIt->next();
4723           inverseElemSet.insert( iel );
4724         }
4725       }
4726     }
4727   }
4728
4729   // either create new elements or reverse mirrored ones
4730   if ( !theCopy && !needReverse && !theTargetMesh )
4731     return PGroupIDs();
4732
4733   TIDSortedElemSet::iterator invElemIt = inverseElemSet.begin();
4734   for ( ; invElemIt != inverseElemSet.end(); invElemIt++ )
4735     theElems.insert( *invElemIt );
4736
4737   // replicate or reverse elements
4738
4739   enum {
4740     REV_TETRA   = 0,  //  = nbNodes - 4
4741     REV_PYRAMID = 1,  //  = nbNodes - 4
4742     REV_PENTA   = 2,  //  = nbNodes - 4
4743     REV_FACE    = 3,
4744     REV_HEXA    = 4,  //  = nbNodes - 4
4745     FORWARD     = 5
4746   };
4747   int index[][8] = {
4748     { 2, 1, 0, 3, 4, 0, 0, 0 },  // REV_TETRA
4749     { 2, 1, 0, 3, 4, 0, 0, 0 },  // REV_PYRAMID
4750     { 2, 1, 0, 5, 4, 3, 0, 0 },  // REV_PENTA
4751     { 2, 1, 0, 3, 0, 0, 0, 0 },  // REV_FACE
4752     { 2, 1, 0, 3, 6, 5, 4, 7 },  // REV_HEXA
4753     { 0, 1, 2, 3, 4, 5, 6, 7 }   // FORWARD
4754   };
4755
4756   for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ )
4757   {
4758     const SMDS_MeshElement* elem = *itElem;
4759     if ( !elem || elem->GetType() == SMDSAbs_Node )
4760       continue;
4761
4762     int nbNodes = elem->NbNodes();
4763     int elemType = elem->GetType();
4764
4765     if (elem->IsPoly()) {
4766       // Polygon or Polyhedral Volume
4767       switch ( elemType ) {
4768       case SMDSAbs_Face:
4769         {
4770           vector<const SMDS_MeshNode*> poly_nodes (nbNodes);
4771           int iNode = 0;
4772           SMDS_ElemIteratorPtr itN = elem->nodesIterator();
4773           while (itN->more()) {
4774             const SMDS_MeshNode* node =
4775               static_cast<const SMDS_MeshNode*>(itN->next());
4776             TNodeNodeMap::iterator nodeMapIt = nodeMap.find(node);
4777             if (nodeMapIt == nodeMap.end())
4778               break; // not all nodes transformed
4779             if (needReverse) {
4780               // reverse mirrored faces and volumes
4781               poly_nodes[nbNodes - iNode - 1] = (*nodeMapIt).second;
4782             } else {
4783               poly_nodes[iNode] = (*nodeMapIt).second;
4784             }
4785             iNode++;
4786           }
4787           if ( iNode != nbNodes )
4788             continue; // not all nodes transformed
4789
4790           if ( theTargetMesh ) {
4791             myLastCreatedElems.Append(aTgtMesh->AddPolygonalFace(poly_nodes));
4792             srcElems.Append( elem );
4793           }
4794           else if ( theCopy ) {
4795             myLastCreatedElems.Append(aMesh->AddPolygonalFace(poly_nodes));
4796             srcElems.Append( elem );
4797           }
4798           else {
4799             aMesh->ChangePolygonNodes(elem, poly_nodes);
4800           }
4801         }
4802         break;
4803       case SMDSAbs_Volume:
4804         {
4805           // ATTENTION: Reversing is not yet done!!!
4806           const SMDS_PolyhedralVolumeOfNodes* aPolyedre =
4807             dynamic_cast<const SMDS_PolyhedralVolumeOfNodes*>( elem );
4808           if (!aPolyedre) {
4809             MESSAGE("Warning: bad volumic element");
4810             continue;
4811           }
4812
4813           vector<const SMDS_MeshNode*> poly_nodes;
4814           vector<int> quantities;
4815
4816           bool allTransformed = true;
4817           int nbFaces = aPolyedre->NbFaces();
4818           for (int iface = 1; iface <= nbFaces && allTransformed; iface++) {
4819             int nbFaceNodes = aPolyedre->NbFaceNodes(iface);
4820             for (int inode = 1; inode <= nbFaceNodes && allTransformed; inode++) {
4821               const SMDS_MeshNode* node = aPolyedre->GetFaceNode(iface, inode);
4822               TNodeNodeMap::iterator nodeMapIt = nodeMap.find(node);
4823               if (nodeMapIt == nodeMap.end()) {
4824                 allTransformed = false; // not all nodes transformed
4825               } else {
4826                 poly_nodes.push_back((*nodeMapIt).second);
4827               }
4828             }
4829             quantities.push_back(nbFaceNodes);
4830           }
4831           if ( !allTransformed )
4832             continue; // not all nodes transformed
4833
4834           if ( theTargetMesh ) {
4835             myLastCreatedElems.Append(aTgtMesh->AddPolyhedralVolume(poly_nodes, quantities));
4836             srcElems.Append( elem );
4837           }
4838           else if ( theCopy ) {
4839             myLastCreatedElems.Append(aMesh->AddPolyhedralVolume(poly_nodes, quantities));
4840             srcElems.Append( elem );
4841           }
4842           else {
4843             aMesh->ChangePolyhedronNodes(elem, poly_nodes, quantities);
4844           }
4845         }
4846         break;
4847       default:;
4848       }
4849       continue;
4850     }
4851
4852     // Regular elements
4853     int* i = index[ FORWARD ];
4854     if ( needReverse && nbNodes > 2) // reverse mirrored faces and volumes
4855       if ( elemType == SMDSAbs_Face )
4856         i = index[ REV_FACE ];
4857       else
4858         i = index[ nbNodes - 4 ];
4859
4860     if(elem->IsQuadratic()) {
4861       static int anIds[] = {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19};
4862       i = anIds;
4863       if(needReverse) {
4864         if(nbNodes==3) { // quadratic edge
4865           static int anIds[] = {1,0,2};
4866           i = anIds;
4867         }
4868         else if(nbNodes==6) { // quadratic triangle
4869           static int anIds[] = {0,2,1,5,4,3};
4870           i = anIds;
4871         }
4872         else if(nbNodes==8) { // quadratic quadrangle
4873           static int anIds[] = {0,3,2,1,7,6,5,4};
4874           i = anIds;
4875         }
4876         else if(nbNodes==10) { // quadratic tetrahedron of 10 nodes
4877           static int anIds[] = {0,2,1,3,6,5,4,7,9,8};
4878           i = anIds;
4879         }
4880         else if(nbNodes==13) { // quadratic pyramid of 13 nodes
4881           static int anIds[] = {0,3,2,1,4,8,7,6,5,9,12,11,10};
4882           i = anIds;
4883         }
4884         else if(nbNodes==15) { // quadratic pentahedron with 15 nodes
4885           static int anIds[] = {0,2,1,3,5,4,8,7,6,11,10,9,12,14,13};
4886           i = anIds;
4887         }
4888         else { // nbNodes==20 - quadratic hexahedron with 20 nodes
4889           static int anIds[] = {0,3,2,1,4,7,6,5,11,10,9,8,15,14,13,12,16,19,18,17};
4890           i = anIds;
4891         }
4892       }
4893     }
4894
4895     // find transformed nodes
4896     vector<const SMDS_MeshNode*> nodes(nbNodes);
4897     int iNode = 0;
4898     SMDS_ElemIteratorPtr itN = elem->nodesIterator();
4899     while ( itN->more() ) {
4900       const SMDS_MeshNode* node =
4901         static_cast<const SMDS_MeshNode*>( itN->next() );
4902       TNodeNodeMap::iterator nodeMapIt = nodeMap.find( node );
4903       if ( nodeMapIt == nodeMap.end() )
4904         break; // not all nodes transformed
4905       nodes[ i [ iNode++ ]] = (*nodeMapIt).second;
4906     }
4907     if ( iNode != nbNodes )
4908       continue; // not all nodes transformed
4909
4910     if ( theTargetMesh ) {
4911       if ( SMDS_MeshElement* copy =
4912            targetMeshEditor.AddElement( nodes, elem->GetType(), elem->IsPoly() )) {
4913         myLastCreatedElems.Append( copy );
4914         srcElems.Append( elem );
4915       }
4916     }
4917     else if ( theCopy ) {
4918       if ( SMDS_MeshElement* copy = AddElement( nodes, elem->GetType(), elem->IsPoly() )) {
4919         myLastCreatedElems.Append( copy );
4920         srcElems.Append( elem );
4921       }
4922     }
4923     else {
4924       // reverse element as it was reversed by transformation
4925       if ( nbNodes > 2 )
4926         aMesh->ChangeElementNodes( elem, &nodes[0], nbNodes );
4927     }
4928   }
4929
4930   PGroupIDs newGroupIDs;
4931
4932   if ( theMakeGroups && theCopy ||
4933        theMakeGroups && theTargetMesh )
4934     newGroupIDs = generateGroups( srcNodes, srcElems, groupPostfix, theTargetMesh );
4935
4936   return newGroupIDs;
4937 }
4938
4939 //=======================================================================
4940 /*!
4941  * \brief Create groups of elements made during transformation
4942  * \param nodeGens - nodes making corresponding myLastCreatedNodes
4943  * \param elemGens - elements making corresponding myLastCreatedElems
4944  * \param postfix - to append to names of new groups
4945  */
4946 //=======================================================================
4947
4948 SMESH_MeshEditor::PGroupIDs
4949 SMESH_MeshEditor::generateGroups(const SMESH_SequenceOfElemPtr& nodeGens,
4950                                  const SMESH_SequenceOfElemPtr& elemGens,
4951                                  const std::string&             postfix,
4952                                  SMESH_Mesh*                    targetMesh)
4953 {
4954   PGroupIDs newGroupIDs( new list<int> );
4955   SMESH_Mesh* mesh = targetMesh ? targetMesh : GetMesh();
4956
4957   // Sort existing groups by types and collect their names
4958
4959   // to store an old group and a generated new one
4960   typedef pair< SMESHDS_GroupBase*, SMDS_MeshGroup* > TOldNewGroup;
4961   vector< list< TOldNewGroup > > groupsByType( SMDSAbs_NbElementTypes );
4962   // group names
4963   set< string > groupNames;
4964   //
4965   SMDS_MeshGroup* nullNewGroup = (SMDS_MeshGroup*) 0;
4966   SMESH_Mesh::GroupIteratorPtr groupIt = GetMesh()->GetGroups();
4967   while ( groupIt->more() ) {
4968     SMESH_Group * group = groupIt->next();
4969     if ( !group ) continue;
4970     SMESHDS_GroupBase* groupDS = group->GetGroupDS();
4971     if ( !groupDS || groupDS->IsEmpty() ) continue;
4972     groupNames.insert( group->GetName() );
4973     groupDS->SetStoreName( group->GetName() );
4974     groupsByType[ groupDS->GetType() ].push_back( make_pair( groupDS, nullNewGroup ));
4975   }
4976
4977   // Groups creation
4978
4979   // loop on nodes and elements
4980   for ( int isNodes = 0; isNodes < 2; ++isNodes )
4981   {
4982     const SMESH_SequenceOfElemPtr& gens  = isNodes ? nodeGens : elemGens;
4983     const SMESH_SequenceOfElemPtr& elems = isNodes ? myLastCreatedNodes : myLastCreatedElems;
4984     if ( gens.Length() != elems.Length() )
4985       throw SALOME_Exception(LOCALIZED("invalid args"));
4986
4987     // loop on created elements
4988     for (int iElem = 1; iElem <= elems.Length(); ++iElem )
4989     {
4990       const SMDS_MeshElement* sourceElem = gens( iElem );
4991       if ( !sourceElem ) {
4992         MESSAGE("generateGroups(): NULL source element");
4993         continue;
4994       }
4995       list< TOldNewGroup > & groupsOldNew = groupsByType[ sourceElem->GetType() ];
4996       if ( groupsOldNew.empty() ) {
4997         while ( iElem < gens.Length() && gens( iElem+1 ) == sourceElem )
4998           ++iElem; // skip all elements made by sourceElem
4999         continue;
5000       }
5001       // collect all elements made by sourceElem
5002       list< const SMDS_MeshElement* > resultElems;
5003       if ( const SMDS_MeshElement* resElem = elems( iElem ))
5004         if ( resElem != sourceElem )
5005           resultElems.push_back( resElem );
5006       while ( iElem < gens.Length() && gens( iElem+1 ) == sourceElem )
5007         if ( const SMDS_MeshElement* resElem = elems( ++iElem ))
5008           if ( resElem != sourceElem )
5009             resultElems.push_back( resElem );
5010       // do not generate element groups from node ones
5011       if ( sourceElem->GetType() == SMDSAbs_Node &&
5012            elems( iElem )->GetType() != SMDSAbs_Node )
5013         continue;
5014
5015       // add resultElems to groups made by ones the sourceElem belongs to
5016       list< TOldNewGroup >::iterator gOldNew, gLast = groupsOldNew.end();
5017       for ( gOldNew = groupsOldNew.begin(); gOldNew != gLast; ++gOldNew )
5018       {
5019         SMESHDS_GroupBase* oldGroup = gOldNew->first;
5020         if ( oldGroup->Contains( sourceElem )) // sourceElem in oldGroup
5021         {
5022           SMDS_MeshGroup* & newGroup = gOldNew->second;
5023           if ( !newGroup )// create a new group
5024           {
5025             // make a name
5026             string name = oldGroup->GetStoreName();
5027             if ( !targetMesh ) {
5028               name += "_";
5029               name += postfix;
5030               int nb = 0;
5031               while ( !groupNames.insert( name ).second ) // name exists
5032               {
5033                 if ( nb == 0 ) {
5034                   name += "_1";
5035                 }
5036                 else {
5037                   TCollection_AsciiString nbStr(nb+1);
5038                   name.resize( name.rfind('_')+1 );
5039                   name += nbStr.ToCString();
5040                 }
5041                 ++nb;
5042               }
5043             }
5044             // make a group
5045             int id;
5046             SMESH_Group* group = mesh->AddGroup( resultElems.back()->GetType(),
5047                                                  name.c_str(), id );
5048             SMESHDS_Group* groupDS = static_cast<SMESHDS_Group*>(group->GetGroupDS());
5049             newGroup = & groupDS->SMDSGroup();
5050             newGroupIDs->push_back( id );
5051           }
5052
5053           // fill in a new group
5054           list< const SMDS_MeshElement* >::iterator resLast = resultElems.end(), resElemIt;
5055           for ( resElemIt = resultElems.begin(); resElemIt != resLast; ++resElemIt )
5056             newGroup->Add( *resElemIt );
5057         }
5058       }
5059     } // loop on created elements
5060   }// loop on nodes and elements
5061
5062   return newGroupIDs;
5063 }
5064
5065 //================================================================================
5066 /*!
5067  * \brief Return list of group of nodes close to each other within theTolerance
5068  *        Search among theNodes or in the whole mesh if theNodes is empty using
5069  *        an Octree algorithm
5070  */
5071 //================================================================================
5072
5073 void SMESH_MeshEditor::FindCoincidentNodes (set<const SMDS_MeshNode*> & theNodes,
5074                                             const double                theTolerance,
5075                                             TListOfListOfNodes &        theGroupsOfNodes)
5076 {
5077   myLastCreatedElems.Clear();
5078   myLastCreatedNodes.Clear();
5079
5080   set<const SMDS_MeshNode*> nodes;
5081   if ( theNodes.empty() )
5082   { // get all nodes in the mesh
5083     SMDS_NodeIteratorPtr nIt = GetMeshDS()->nodesIterator();
5084     while ( nIt->more() )
5085       nodes.insert( nodes.end(),nIt->next());
5086   }
5087   else
5088     nodes=theNodes;
5089
5090   SMESH_OctreeNode::FindCoincidentNodes ( nodes, &theGroupsOfNodes, theTolerance);
5091 }
5092
5093
5094 //=======================================================================
5095 /*!
5096  * \brief Implementation of search for the node closest to point
5097  */
5098 //=======================================================================
5099
5100 struct SMESH_NodeSearcherImpl: public SMESH_NodeSearcher
5101 {
5102   //---------------------------------------------------------------------
5103   /*!
5104    * \brief Constructor
5105    */
5106   SMESH_NodeSearcherImpl( const SMESHDS_Mesh* theMesh )
5107   {
5108     myMesh = ( SMESHDS_Mesh* ) theMesh;
5109
5110     set<const SMDS_MeshNode*> nodes;
5111     if ( theMesh ) {
5112       SMDS_NodeIteratorPtr nIt = theMesh->nodesIterator();
5113       while ( nIt->more() )
5114         nodes.insert( nodes.end(), nIt->next() );
5115     }
5116     myOctreeNode = new SMESH_OctreeNode(nodes) ;
5117
5118     // get max size of a leaf box
5119     SMESH_OctreeNode* tree = myOctreeNode;
5120     while ( !tree->isLeaf() )
5121     {
5122       SMESH_OctreeNodeIteratorPtr cIt = tree->GetChildrenIterator();
5123       if ( cIt->more() )
5124         tree = cIt->next();
5125     }
5126     myHalfLeafSize = tree->maxSize() / 2.;
5127   }
5128
5129   //---------------------------------------------------------------------
5130   /*!
5131    * \brief Move node and update myOctreeNode accordingly
5132    */
5133   void MoveNode( const SMDS_MeshNode* node, const gp_Pnt& toPnt )
5134   {
5135     myOctreeNode->UpdateByMoveNode( node, toPnt );
5136     myMesh->MoveNode( node, toPnt.X(), toPnt.Y(), toPnt.Z() );
5137   }
5138
5139   //---------------------------------------------------------------------
5140   /*!
5141    * \brief Do it's job
5142    */
5143   const SMDS_MeshNode* FindClosestTo( const gp_Pnt& thePnt )
5144   {
5145     SMDS_MeshNode tgtNode( thePnt.X(), thePnt.Y(), thePnt.Z() );
5146     map<double, const SMDS_MeshNode*> dist2Nodes;
5147     myOctreeNode->NodesAround( &tgtNode, dist2Nodes, myHalfLeafSize );
5148     if ( !dist2Nodes.empty() )
5149       return dist2Nodes.begin()->second;
5150     list<const SMDS_MeshNode*> nodes;
5151     //myOctreeNode->NodesAround( &tgtNode, &nodes, myHalfLeafSize );
5152
5153     double minSqDist = DBL_MAX;
5154     if ( nodes.empty() )  // get all nodes of OctreeNode's closest to thePnt
5155     {
5156       // sort leafs by their distance from thePnt
5157       typedef map< double, SMESH_OctreeNode* > TDistTreeMap;
5158       TDistTreeMap treeMap;
5159       list< SMESH_OctreeNode* > treeList;
5160       list< SMESH_OctreeNode* >::iterator trIt;
5161       treeList.push_back( myOctreeNode );
5162
5163       SMDS_MeshNode pointNode( thePnt.X(), thePnt.Y(), thePnt.Z() );
5164       for ( trIt = treeList.begin(); trIt != treeList.end(); ++trIt)
5165       {
5166         SMESH_OctreeNode* tree = *trIt;
5167         if ( !tree->isLeaf() ) // put children to the queue
5168         {
5169           if ( !tree->isInside( &pointNode, myHalfLeafSize )) continue;
5170           SMESH_OctreeNodeIteratorPtr cIt = tree->GetChildrenIterator();
5171           while ( cIt->more() )
5172             treeList.push_back( cIt->next() );
5173         }
5174         else if ( tree->NbNodes() ) // put a tree to the treeMap
5175         {
5176           const Bnd_B3d& box = tree->getBox();
5177           double sqDist = thePnt.SquareDistance( 0.5 * ( box.CornerMin() + box.CornerMax() ));
5178           pair<TDistTreeMap::iterator,bool> it_in = treeMap.insert( make_pair( sqDist, tree ));
5179           if ( !it_in.second ) // not unique distance to box center
5180             treeMap.insert( it_in.first, make_pair( sqDist + 1e-13*treeMap.size(), tree ));
5181         }
5182       }
5183       // find distance after which there is no sense to check tree's
5184       double sqLimit = DBL_MAX;
5185       TDistTreeMap::iterator sqDist_tree = treeMap.begin();
5186       if ( treeMap.size() > 5 ) {
5187         SMESH_OctreeNode* closestTree = sqDist_tree->second;
5188         const Bnd_B3d& box = closestTree->getBox();
5189         double limit = sqrt( sqDist_tree->first ) + sqrt ( box.SquareExtent() );
5190         sqLimit = limit * limit;
5191       }
5192       // get all nodes from trees
5193       for ( ; sqDist_tree != treeMap.end(); ++sqDist_tree) {
5194         if ( sqDist_tree->first > sqLimit )
5195           break;
5196         SMESH_OctreeNode* tree = sqDist_tree->second;
5197         tree->NodesAround( tree->GetNodeIterator()->next(), &nodes );
5198       }
5199     }
5200     // find closest among nodes
5201     minSqDist = DBL_MAX;
5202     const SMDS_MeshNode* closestNode = 0;
5203     list<const SMDS_MeshNode*>::iterator nIt = nodes.begin();
5204     for ( ; nIt != nodes.end(); ++nIt ) {
5205       double sqDist = thePnt.SquareDistance( SMESH_MeshEditor::TNodeXYZ( *nIt ) );
5206       if ( minSqDist > sqDist ) {
5207         closestNode = *nIt;
5208         minSqDist = sqDist;
5209       }
5210     }
5211     return closestNode;
5212   }
5213
5214   //---------------------------------------------------------------------
5215   /*!
5216    * \brief Destructor
5217    */
5218   ~SMESH_NodeSearcherImpl() { delete myOctreeNode; }
5219
5220   //---------------------------------------------------------------------
5221   /*!
5222    * \brief Return the node tree
5223    */
5224   const SMESH_OctreeNode* getTree() const { return myOctreeNode; }
5225
5226 private:
5227   SMESH_OctreeNode* myOctreeNode;
5228   SMESHDS_Mesh*     myMesh;
5229   double            myHalfLeafSize; // max size of a leaf box
5230 };
5231
5232 //=======================================================================
5233 /*!
5234  * \brief Return SMESH_NodeSearcher
5235  */
5236 //=======================================================================
5237
5238 SMESH_NodeSearcher* SMESH_MeshEditor::GetNodeSearcher() 
5239 {
5240   return new SMESH_NodeSearcherImpl( GetMeshDS() );
5241 }
5242
5243 // ========================================================================
5244 namespace // Utils used in SMESH_ElementSearcherImpl::FindElementsByPoint()
5245 {
5246   const int MaxNbElemsInLeaf = 10; // maximal number of elements in a leaf of tree
5247   const int MaxLevel         = 7;  // maximal tree height -> nb terminal boxes: 8^7 = 2097152
5248   const double NodeRadius = 1e-9;  // to enlarge bnd box of element
5249
5250   //=======================================================================
5251   /*!
5252    * \brief Octal tree of bounding boxes of elements
5253    */
5254   //=======================================================================
5255
5256   class ElementBndBoxTree : public SMESH_Octree
5257   {
5258   public:
5259
5260     ElementBndBoxTree(const SMDS_Mesh& mesh, SMDSAbs_ElementType elemType);
5261     void getElementsNearPoint( const gp_Pnt& point, TIDSortedElemSet& foundElems);
5262     ~ElementBndBoxTree();
5263
5264   protected:
5265     ElementBndBoxTree() {}
5266     SMESH_Octree* allocateOctreeChild() const { return new ElementBndBoxTree; }
5267     void buildChildrenData();
5268     Bnd_B3d* buildRootBox();
5269   private:
5270     //!< Bounding box of element
5271     struct ElementBox : public Bnd_B3d
5272     {
5273       const SMDS_MeshElement* _element;
5274       int                     _refCount; // an ElementBox can be included in several tree branches
5275       ElementBox(const SMDS_MeshElement* elem);
5276     };
5277     vector< ElementBox* > _elements;
5278   };
5279
5280   //================================================================================
5281   /*!
5282    * \brief ElementBndBoxTree creation
5283    */
5284   //================================================================================
5285
5286   ElementBndBoxTree::ElementBndBoxTree(const SMDS_Mesh& mesh, SMDSAbs_ElementType elemType)
5287     :SMESH_Octree( new SMESH_Octree::Limit( MaxLevel, /*minSize=*/0. ))
5288   {
5289     int nbElems = mesh.GetMeshInfo().NbElements( elemType );
5290     _elements.reserve( nbElems );
5291
5292     SMDS_ElemIteratorPtr elemIt = mesh.elementsIterator( elemType );
5293     while ( elemIt->more() )
5294       _elements.push_back( new ElementBox( elemIt->next() ));
5295
5296     if ( _elements.size() > MaxNbElemsInLeaf )
5297       compute();
5298     else
5299       myIsLeaf = true;
5300   }
5301
5302   //================================================================================
5303   /*!
5304    * \brief Destructor
5305    */
5306   //================================================================================
5307
5308   ElementBndBoxTree::~ElementBndBoxTree()
5309   {
5310     for ( int i = 0; i < _elements.size(); ++i )
5311       if ( --_elements[i]->_refCount <= 0 )
5312         delete _elements[i];
5313   }
5314
5315   //================================================================================
5316   /*!
5317    * \brief Return the maximal box
5318    */
5319   //================================================================================
5320
5321   Bnd_B3d* ElementBndBoxTree::buildRootBox()
5322   {
5323     Bnd_B3d* box = new Bnd_B3d;
5324     for ( int i = 0; i < _elements.size(); ++i )
5325       box->Add( *_elements[i] );
5326     return box;
5327   }
5328
5329   //================================================================================
5330   /*!
5331    * \brief Redistrubute element boxes among children
5332    */
5333   //================================================================================
5334
5335   void ElementBndBoxTree::buildChildrenData()
5336   {
5337     for ( int i = 0; i < _elements.size(); ++i )
5338     {
5339       for (int j = 0; j < 8; j++)
5340       {
5341         if ( !_elements[i]->IsOut( myChildren[j]->getBox() ))
5342         {
5343           _elements[i]->_refCount++;
5344           ((ElementBndBoxTree*)myChildren[j])->_elements.push_back( _elements[i]);
5345         }
5346       }
5347       _elements[i]->_refCount--;
5348     }
5349     _elements.clear();
5350
5351     for (int j = 0; j < 8; j++)
5352     {
5353       ElementBndBoxTree* child = static_cast<ElementBndBoxTree*>( myChildren[j]);
5354       if ( child->_elements.size() <= MaxNbElemsInLeaf )
5355         child->myIsLeaf = true;
5356
5357       if ( child->_elements.capacity() - child->_elements.size() > 1000 )
5358         child->_elements.resize( child->_elements.size() ); // compact
5359     }
5360   }
5361
5362   //================================================================================
5363   /*!
5364    * \brief Return elements which can include the point
5365    */
5366   //================================================================================
5367
5368   void ElementBndBoxTree::getElementsNearPoint( const gp_Pnt&     point,
5369                                                 TIDSortedElemSet& foundElems)
5370   {
5371     if ( level() && getBox().IsOut( point.XYZ() ))
5372       return;
5373
5374     if ( isLeaf() )
5375     {
5376       for ( int i = 0; i < _elements.size(); ++i )
5377         if ( !_elements[i]->IsOut( point.XYZ() ))
5378           foundElems.insert( _elements[i]->_element );
5379     }
5380     else
5381     {
5382       for (int i = 0; i < 8; i++)
5383         ((ElementBndBoxTree*) myChildren[i])->getElementsNearPoint( point, foundElems );
5384     }
5385   }
5386
5387   //================================================================================
5388   /*!
5389    * \brief Construct the element box
5390    */
5391   //================================================================================
5392
5393   ElementBndBoxTree::ElementBox::ElementBox(const SMDS_MeshElement* elem)
5394   {
5395     _element  = elem;
5396     _refCount = 1;
5397     SMDS_ElemIteratorPtr nIt = elem->nodesIterator();
5398     while ( nIt->more() )
5399       Add( SMESH_MeshEditor::TNodeXYZ( cast2Node( nIt->next() )));
5400     Enlarge( NodeRadius );
5401   }
5402
5403 } // namespace
5404
5405 //=======================================================================
5406 /*!
5407  * \brief Implementation of search for the elements by point
5408  */
5409 //=======================================================================
5410
5411 struct SMESH_ElementSearcherImpl: public SMESH_ElementSearcher
5412 {
5413   SMESHDS_Mesh*           _mesh;
5414   ElementBndBoxTree*      _ebbTree;
5415   SMESH_NodeSearcherImpl* _nodeSearcher;
5416   SMDSAbs_ElementType     _elementType;
5417
5418   SMESH_ElementSearcherImpl( SMESHDS_Mesh& mesh ): _mesh(&mesh),_ebbTree(0),_nodeSearcher(0) {}
5419   ~SMESH_ElementSearcherImpl()
5420   {
5421     if ( _ebbTree )      delete _ebbTree;      _ebbTree      = 0;
5422     if ( _nodeSearcher ) delete _nodeSearcher; _nodeSearcher = 0;
5423   }
5424
5425   /*!
5426    * \brief Find elements of given type where the given point is IN or ON.
5427    *        Returns nb of found elements and elements them-selves.
5428    *
5429    * 'ALL' type means elements of any type excluding nodes and 0D elements
5430    */
5431   int FindElementsByPoint(const gp_Pnt&                      point,
5432                           SMDSAbs_ElementType                type,
5433                           vector< const SMDS_MeshElement* >& foundElements)
5434   {
5435     foundElements.clear();
5436
5437     const SMDS_MeshInfo& meshInfo = _mesh->GetMeshInfo();
5438
5439     // -----------------
5440     // define tolerance
5441     // -----------------
5442     double tolerance = 0;
5443     if ( _nodeSearcher && meshInfo.NbNodes() > 1 )
5444     {
5445       double boxSize = _nodeSearcher->getTree()->maxSize();
5446       tolerance = 1e-8 * boxSize/* / meshInfo.NbNodes()*/;
5447     }
5448     else if ( _ebbTree && meshInfo.NbElements() > 0 )
5449     {
5450       double boxSize = _ebbTree->maxSize();
5451       tolerance = 1e-8 * boxSize/* / meshInfo.NbElements()*/;
5452     }
5453     if ( tolerance == 0 )
5454     {
5455       // define tolerance by size of a most complex element
5456       int complexType = SMDSAbs_Volume;
5457       while ( complexType > SMDSAbs_All &&
5458               meshInfo.NbElements( SMDSAbs_ElementType( complexType )) < 1 )
5459         --complexType;
5460       if ( complexType == SMDSAbs_All ) return foundElements.size(); // empty mesh
5461
5462       double elemSize;
5463       if ( complexType == int( SMDSAbs_Node ))
5464       {
5465         SMDS_NodeIteratorPtr nodeIt = _mesh->nodesIterator();
5466         elemSize = 1;
5467         if ( meshInfo.NbNodes() > 2 )
5468           elemSize = SMESH_MeshEditor::TNodeXYZ( nodeIt->next() ).Distance( nodeIt->next() );
5469       }
5470       else
5471       {
5472         const SMDS_MeshElement* elem =
5473           _mesh->elementsIterator( SMDSAbs_ElementType( complexType ))->next();
5474         SMDS_ElemIteratorPtr nodeIt = elem->nodesIterator();
5475         SMESH_MeshEditor::TNodeXYZ n1( cast2Node( nodeIt->next() ));
5476         while ( nodeIt->more() )
5477         {
5478           double dist = n1.Distance( cast2Node( nodeIt->next() ));
5479           elemSize = max( dist, elemSize );
5480         }
5481       }
5482       tolerance = 1e-6 * elemSize;
5483     }
5484
5485     // =================================================================================
5486     if ( type == SMDSAbs_Node || type == SMDSAbs_0DElement )
5487     {
5488       if ( !_nodeSearcher )
5489         _nodeSearcher = new SMESH_NodeSearcherImpl( _mesh );
5490
5491       const SMDS_MeshNode* closeNode = _nodeSearcher->FindClosestTo( point );
5492       if ( !closeNode ) return foundElements.size();
5493
5494       if ( point.Distance( SMESH_MeshEditor::TNodeXYZ( closeNode )) > tolerance )
5495         return foundElements.size(); // to far from any node
5496
5497       if ( type == SMDSAbs_Node )
5498       {
5499         foundElements.push_back( closeNode );
5500       }
5501       else
5502       {
5503         SMDS_ElemIteratorPtr elemIt = closeNode->GetInverseElementIterator( SMDSAbs_0DElement );
5504         while ( elemIt->more() )
5505           foundElements.push_back( elemIt->next() );
5506       }
5507     }
5508     // =================================================================================
5509     else // elements more complex than 0D
5510     {
5511       if ( !_ebbTree || _elementType != type )
5512       {
5513         if ( _ebbTree ) delete _ebbTree;
5514         _ebbTree = new ElementBndBoxTree( *_mesh, _elementType = type );
5515       }
5516       TIDSortedElemSet suspectElems;
5517       _ebbTree->getElementsNearPoint( point, suspectElems );
5518       TIDSortedElemSet::iterator elem = suspectElems.begin();
5519       for ( ; elem != suspectElems.end(); ++elem )
5520         if ( !SMESH_MeshEditor::isOut( *elem, point, tolerance ))
5521           foundElements.push_back( *elem );
5522     }
5523     return foundElements.size();
5524   }
5525 }; // struct SMESH_ElementSearcherImpl
5526
5527 //=======================================================================
5528 /*!
5529  * \brief Return SMESH_ElementSearcher
5530  */
5531 //=======================================================================
5532
5533 SMESH_ElementSearcher* SMESH_MeshEditor::GetElementSearcher()
5534 {
5535   return new SMESH_ElementSearcherImpl( *GetMeshDS() );
5536 }
5537
5538 //=======================================================================
5539 /*!
5540  * \brief Return true if the point is IN or ON of the element
5541  */
5542 //=======================================================================
5543
5544 bool SMESH_MeshEditor::isOut( const SMDS_MeshElement* element, const gp_Pnt& point, double tol )
5545 {
5546   if ( element->GetType() == SMDSAbs_Volume)
5547   {
5548     return SMDS_VolumeTool( element ).IsOut( point.X(), point.Y(), point.Z(), tol );
5549   }
5550
5551   // get ordered nodes
5552
5553   vector< gp_XYZ > xyz;
5554
5555   SMDS_ElemIteratorPtr nodeIt = element->nodesIterator();
5556   if ( element->IsQuadratic() )
5557     if (const SMDS_QuadraticFaceOfNodes* f=dynamic_cast<const SMDS_QuadraticFaceOfNodes*>(element))
5558       nodeIt = f->interlacedNodesElemIterator();
5559     else if (const SMDS_QuadraticEdge*  e =dynamic_cast<const SMDS_QuadraticEdge*>(element))
5560       nodeIt = e->interlacedNodesElemIterator();
5561
5562   while ( nodeIt->more() )
5563     xyz.push_back( TNodeXYZ( cast2Node( nodeIt->next() )));
5564
5565   int i, nbNodes = element->NbNodes();
5566
5567   if ( element->GetType() == SMDSAbs_Face ) // --------------------------------------------------
5568   {
5569     // compute face normal
5570     gp_Vec faceNorm(0,0,0);
5571     xyz.push_back( xyz.front() );
5572     for ( i = 0; i < nbNodes; ++i )
5573     {
5574       gp_Vec edge1( xyz[i+1], xyz[i]);
5575       gp_Vec edge2( xyz[i+1], xyz[(i+2)%nbNodes] );
5576       faceNorm += edge1 ^ edge2;
5577     }
5578     double normSize = faceNorm.Magnitude();
5579     if ( normSize <= tol )
5580     {
5581       // degenerated face: point is out if it is out of all face edges
5582       for ( i = 0; i < nbNodes; ++i )
5583       {
5584         SMDS_MeshNode n1( xyz[i].X(),   xyz[i].Y(),   xyz[i].Z() );
5585         SMDS_MeshNode n2( xyz[i+1].X(), xyz[i+1].Y(), xyz[i+1].Z() );
5586         SMDS_MeshEdge edge( &n1, &n2 );
5587         if ( !isOut( &edge, point, tol ))
5588           return false;
5589       }
5590       return true;
5591     }
5592     faceNorm /= normSize;
5593
5594     // check if the point lays on face plane
5595     gp_Vec n2p( xyz[0], point );
5596     if ( fabs( n2p * faceNorm ) > tol )
5597       return true; // not on face plane
5598
5599     // check if point is out of face boundary:
5600     // define it by closest transition of a ray point->infinity through face boundary
5601     // on the face plane.
5602     // First, find normal of a plane perpendicular to face plane, to be used as a cutting tool
5603     // to find intersections of the ray with the boundary.
5604     gp_Vec ray = n2p;
5605     gp_Vec plnNorm = ray ^ faceNorm;
5606     normSize = plnNorm.Magnitude();
5607     if ( normSize <= tol ) return false; // point coincides with the first node
5608     plnNorm /= normSize;
5609     // for each node of the face, compute its signed distance to the plane
5610     vector<double> dist( nbNodes + 1);
5611     for ( i = 0; i < nbNodes; ++i )
5612     {
5613       gp_Vec n2p( xyz[i], point );
5614       dist[i] = n2p * plnNorm;
5615     }
5616     dist.back() = dist.front();
5617     // find the closest intersection
5618     int    iClosest = -1;
5619     double rClosest, distClosest = 1e100;;
5620     gp_Pnt pClosest;
5621     for ( i = 0; i < nbNodes; ++i )
5622     {
5623       double r;
5624       if ( fabs( dist[i]) < tol )
5625         r = 0.;
5626       else if ( fabs( dist[i+1]) < tol )
5627         r = 1.;
5628       else if ( dist[i] * dist[i+1] < 0 )
5629         r = dist[i] / ( dist[i] - dist[i+1] );
5630       else
5631         continue; // no intersection
5632       gp_Pnt pInt = xyz[i] * (1.-r) + xyz[i+1] * r;
5633       gp_Vec p2int ( point, pInt);
5634       if ( p2int * ray > -tol ) // right half-space
5635       {
5636         double intDist = p2int.SquareMagnitude();
5637         if ( intDist < distClosest )
5638         {
5639           iClosest = i;
5640           rClosest = r;
5641           pClosest = pInt;
5642           distClosest = intDist;
5643         }
5644       }
5645     }
5646     if ( iClosest < 0 )
5647       return true; // no intesections - out
5648
5649     // analyse transition
5650     gp_Vec edge( xyz[iClosest], xyz[iClosest+1] );
5651     gp_Vec edgeNorm = -( edge ^ faceNorm ); // normal to intersected edge pointing out of face
5652     gp_Vec p2int ( point, pClosest );
5653     bool out = (edgeNorm * p2int) < -tol;
5654     if ( rClosest > 0. && rClosest < 1. ) // not node intersection
5655       return out;
5656
5657     // ray pass through a face node; analyze transition through an adjacent edge
5658     gp_Pnt p1 = xyz[ (rClosest == 0.) ? ((iClosest+nbNodes-1) % nbNodes) : (iClosest+1) ];
5659     gp_Pnt p2 = xyz[ (rClosest == 0.) ? iClosest : ((iClosest+2) % nbNodes) ];
5660     gp_Vec edgeAdjacent( p1, p2 );
5661     gp_Vec edgeNorm2 = -( edgeAdjacent ^ faceNorm );
5662     bool out2 = (edgeNorm2 * p2int) < -tol;
5663
5664     bool covexCorner = ( edgeNorm * edgeAdjacent * (rClosest==1. ? 1. : -1.)) < 0;
5665     return covexCorner ? (out || out2) : (out && out2);
5666   }
5667   if ( element->GetType() == SMDSAbs_Edge ) // --------------------------------------------------
5668   {
5669     // point is out of edge if it is NOT ON any straight part of edge
5670     // (we consider quadratic edge as being composed of two straight parts)
5671     for ( i = 1; i < nbNodes; ++i )
5672     {
5673       gp_Vec edge( xyz[i-1], xyz[i]);
5674       gp_Vec n1p ( xyz[i-1], point);
5675       double dist = ( edge ^ n1p ).Magnitude() / edge.Magnitude();
5676       if ( dist > tol )
5677         continue;
5678       gp_Vec n2p( xyz[i], point );
5679       if ( fabs( edge.Magnitude() - n1p.Magnitude() - n2p.Magnitude()) > tol )
5680         continue;
5681       return false; // point is ON this part
5682     }
5683     return true;
5684   }
5685   // Node or 0D element -------------------------------------------------------------------------
5686   {
5687     gp_Vec n2p ( xyz[0], point );
5688     return n2p.Magnitude() <= tol;
5689   }
5690   return true;
5691 }
5692
5693 //=======================================================================
5694 //function : SimplifyFace
5695 //purpose  :
5696 //=======================================================================
5697 int SMESH_MeshEditor::SimplifyFace (const vector<const SMDS_MeshNode *> faceNodes,
5698                                     vector<const SMDS_MeshNode *>&      poly_nodes,
5699                                     vector<int>&                        quantities) const
5700 {
5701   int nbNodes = faceNodes.size();
5702
5703   if (nbNodes < 3)
5704     return 0;
5705
5706   set<const SMDS_MeshNode*> nodeSet;
5707
5708   // get simple seq of nodes
5709   //const SMDS_MeshNode* simpleNodes[ nbNodes ];
5710   vector<const SMDS_MeshNode*> simpleNodes( nbNodes );
5711   int iSimple = 0, nbUnique = 0;
5712
5713   simpleNodes[iSimple++] = faceNodes[0];
5714   nbUnique++;
5715   for (int iCur = 1; iCur < nbNodes; iCur++) {
5716     if (faceNodes[iCur] != simpleNodes[iSimple - 1]) {
5717       simpleNodes[iSimple++] = faceNodes[iCur];
5718       if (nodeSet.insert( faceNodes[iCur] ).second)
5719         nbUnique++;
5720     }
5721   }
5722   int nbSimple = iSimple;
5723   if (simpleNodes[nbSimple - 1] == simpleNodes[0]) {
5724     nbSimple--;
5725     iSimple--;
5726   }
5727
5728   if (nbUnique < 3)
5729     return 0;
5730
5731   // separate loops
5732   int nbNew = 0;
5733   bool foundLoop = (nbSimple > nbUnique);
5734   while (foundLoop) {
5735     foundLoop = false;
5736     set<const SMDS_MeshNode*> loopSet;
5737     for (iSimple = 0; iSimple < nbSimple && !foundLoop; iSimple++) {
5738       const SMDS_MeshNode* n = simpleNodes[iSimple];
5739       if (!loopSet.insert( n ).second) {
5740         foundLoop = true;
5741
5742         // separate loop
5743         int iC = 0, curLast = iSimple;
5744         for (; iC < curLast; iC++) {
5745           if (simpleNodes[iC] == n) break;
5746         }
5747         int loopLen = curLast - iC;
5748         if (loopLen > 2) {
5749           // create sub-element
5750           nbNew++;
5751           quantities.push_back(loopLen);
5752           for (; iC < curLast; iC++) {
5753             poly_nodes.push_back(simpleNodes[iC]);
5754           }
5755         }
5756         // shift the rest nodes (place from the first loop position)
5757         for (iC = curLast + 1; iC < nbSimple; iC++) {
5758           simpleNodes[iC - loopLen] = simpleNodes[iC];
5759         }
5760         nbSimple -= loopLen;
5761         iSimple -= loopLen;
5762       }
5763     } // for (iSimple = 0; iSimple < nbSimple; iSimple++)
5764   } // while (foundLoop)
5765
5766   if (iSimple > 2) {
5767     nbNew++;
5768     quantities.push_back(iSimple);
5769     for (int i = 0; i < iSimple; i++)
5770       poly_nodes.push_back(simpleNodes[i]);
5771   }
5772
5773   return nbNew;
5774 }
5775
5776 //=======================================================================
5777 //function : MergeNodes
5778 //purpose  : In each group, the cdr of nodes are substituted by the first one
5779 //           in all elements.
5780 //=======================================================================
5781
5782 void SMESH_MeshEditor::MergeNodes (TListOfListOfNodes & theGroupsOfNodes)
5783 {
5784   myLastCreatedElems.Clear();
5785   myLastCreatedNodes.Clear();
5786
5787   SMESHDS_Mesh* aMesh = GetMeshDS();
5788
5789   TNodeNodeMap nodeNodeMap; // node to replace - new node
5790   set<const SMDS_MeshElement*> elems; // all elements with changed nodes
5791   list< int > rmElemIds, rmNodeIds;
5792
5793   // Fill nodeNodeMap and elems
5794
5795   TListOfListOfNodes::iterator grIt = theGroupsOfNodes.begin();
5796   for ( ; grIt != theGroupsOfNodes.end(); grIt++ ) {
5797     list<const SMDS_MeshNode*>& nodes = *grIt;
5798     list<const SMDS_MeshNode*>::iterator nIt = nodes.begin();
5799     const SMDS_MeshNode* nToKeep = *nIt;
5800     for ( ++nIt; nIt != nodes.end(); nIt++ ) {
5801       const SMDS_MeshNode* nToRemove = *nIt;
5802       nodeNodeMap.insert( TNodeNodeMap::value_type( nToRemove, nToKeep ));
5803       if ( nToRemove != nToKeep ) {
5804         rmNodeIds.push_back( nToRemove->GetID() );
5805         AddToSameGroups( nToKeep, nToRemove, aMesh );
5806       }
5807
5808       SMDS_ElemIteratorPtr invElemIt = nToRemove->GetInverseElementIterator();
5809       while ( invElemIt->more() ) {
5810         const SMDS_MeshElement* elem = invElemIt->next();
5811         elems.insert(elem);
5812       }
5813     }
5814   }
5815   // Change element nodes or remove an element
5816
5817   set<const SMDS_MeshElement*>::iterator eIt = elems.begin();
5818   for ( ; eIt != elems.end(); eIt++ ) {
5819     const SMDS_MeshElement* elem = *eIt;
5820     int nbNodes = elem->NbNodes();
5821     int aShapeId = FindShape( elem );
5822
5823     set<const SMDS_MeshNode*> nodeSet;
5824     vector< const SMDS_MeshNode*> curNodes( nbNodes ), uniqueNodes( nbNodes );
5825     int iUnique = 0, iCur = 0, nbRepl = 0;
5826     vector<int> iRepl( nbNodes );
5827
5828     // get new seq of nodes
5829     SMDS_ElemIteratorPtr itN = elem->nodesIterator();
5830     while ( itN->more() ) {
5831       const SMDS_MeshNode* n =
5832         static_cast<const SMDS_MeshNode*>( itN->next() );
5833
5834       TNodeNodeMap::iterator nnIt = nodeNodeMap.find( n );
5835       if ( nnIt != nodeNodeMap.end() ) { // n sticks
5836         n = (*nnIt).second;
5837         // BUG 0020185: begin
5838         {
5839           bool stopRecur = false;
5840           set<const SMDS_MeshNode*> nodesRecur;
5841           nodesRecur.insert(n);
5842           while (!stopRecur) {
5843             TNodeNodeMap::iterator nnIt_i = nodeNodeMap.find( n );
5844             if ( nnIt_i != nodeNodeMap.end() ) { // n sticks
5845               n = (*nnIt_i).second;
5846               if (!nodesRecur.insert(n).second) {
5847                 // error: recursive dependancy
5848                 stopRecur = true;
5849               }
5850             }
5851             else
5852               stopRecur = true;
5853           }
5854         }
5855         // BUG 0020185: end
5856         iRepl[ nbRepl++ ] = iCur;
5857       }
5858       curNodes[ iCur ] = n;
5859       bool isUnique = nodeSet.insert( n ).second;
5860       if ( isUnique )
5861         uniqueNodes[ iUnique++ ] = n;
5862       iCur++;
5863     }
5864
5865     // Analyse element topology after replacement
5866
5867     bool isOk = true;
5868     int nbUniqueNodes = nodeSet.size();
5869     if ( nbNodes != nbUniqueNodes ) { // some nodes stick
5870       // Polygons and Polyhedral volumes
5871       if (elem->IsPoly()) {
5872
5873         if (elem->GetType() == SMDSAbs_Face) {
5874           // Polygon
5875           vector<const SMDS_MeshNode *> face_nodes (nbNodes);
5876           int inode = 0;
5877           for (; inode < nbNodes; inode++) {
5878             face_nodes[inode] = curNodes[inode];
5879           }
5880
5881           vector<const SMDS_MeshNode *> polygons_nodes;
5882           vector<int> quantities;
5883           int nbNew = SimplifyFace(face_nodes, polygons_nodes, quantities);
5884
5885           if (nbNew > 0) {
5886             inode = 0;
5887             for (int iface = 0; iface < nbNew - 1; iface++) {
5888               int nbNodes = quantities[iface];
5889               vector<const SMDS_MeshNode *> poly_nodes (nbNodes);
5890               for (int ii = 0; ii < nbNodes; ii++, inode++) {
5891                 poly_nodes[ii] = polygons_nodes[inode];
5892               }
5893               SMDS_MeshElement* newElem = aMesh->AddPolygonalFace(poly_nodes);
5894               myLastCreatedElems.Append(newElem);
5895               if (aShapeId)
5896                 aMesh->SetMeshElementOnShape(newElem, aShapeId);
5897             }
5898             aMesh->ChangeElementNodes(elem, &polygons_nodes[inode], quantities[nbNew - 1]);
5899           }
5900           else {
5901             rmElemIds.push_back(elem->GetID());
5902           }
5903
5904         }
5905         else if (elem->GetType() == SMDSAbs_Volume) {
5906           // Polyhedral volume
5907           if (nbUniqueNodes < 4) {
5908             rmElemIds.push_back(elem->GetID());
5909           }
5910           else {
5911             // each face has to be analized in order to check volume validity
5912             const SMDS_PolyhedralVolumeOfNodes* aPolyedre =
5913               static_cast<const SMDS_PolyhedralVolumeOfNodes*>( elem );
5914             if (aPolyedre) {
5915               int nbFaces = aPolyedre->NbFaces();
5916
5917               vector<const SMDS_MeshNode *> poly_nodes;
5918               vector<int> quantities;
5919
5920               for (int iface = 1; iface <= nbFaces; iface++) {
5921                 int nbFaceNodes = aPolyedre->NbFaceNodes(iface);
5922                 vector<const SMDS_MeshNode *> faceNodes (nbFaceNodes);
5923
5924                 for (int inode = 1; inode <= nbFaceNodes; inode++) {
5925                   const SMDS_MeshNode * faceNode = aPolyedre->GetFaceNode(iface, inode);
5926                   TNodeNodeMap::iterator nnIt = nodeNodeMap.find(faceNode);
5927                   if (nnIt != nodeNodeMap.end()) { // faceNode sticks
5928                     faceNode = (*nnIt).second;
5929                   }
5930                   faceNodes[inode - 1] = faceNode;
5931                 }
5932
5933                 SimplifyFace(faceNodes, poly_nodes, quantities);
5934               }
5935
5936               if (quantities.size() > 3) {
5937                 // to be done: remove coincident faces
5938               }
5939
5940               if (quantities.size() > 3)
5941                 aMesh->ChangePolyhedronNodes(elem, poly_nodes, quantities);
5942               else
5943                 rmElemIds.push_back(elem->GetID());
5944
5945             }
5946             else {
5947               rmElemIds.push_back(elem->GetID());
5948             }
5949           }
5950         }
5951         else {
5952         }
5953
5954         continue;
5955       }
5956
5957       // Regular elements
5958       switch ( nbNodes ) {
5959       case 2: ///////////////////////////////////// EDGE
5960         isOk = false; break;
5961       case 3: ///////////////////////////////////// TRIANGLE
5962         isOk = false; break;
5963       case 4:
5964         if ( elem->GetType() == SMDSAbs_Volume ) // TETRAHEDRON
5965           isOk = false;
5966         else { //////////////////////////////////// QUADRANGLE
5967           if ( nbUniqueNodes < 3 )
5968             isOk = false;
5969           else if ( nbRepl == 2 && iRepl[ 1 ] - iRepl[ 0 ] == 2 )
5970             isOk = false; // opposite nodes stick
5971         }
5972         break;
5973       case 6: ///////////////////////////////////// PENTAHEDRON
5974         if ( nbUniqueNodes == 4 ) {
5975           // ---------------------------------> tetrahedron
5976           if (nbRepl == 3 &&
5977               iRepl[ 0 ] > 2 && iRepl[ 1 ] > 2 && iRepl[ 2 ] > 2 ) {
5978             // all top nodes stick: reverse a bottom
5979             uniqueNodes[ 0 ] = curNodes [ 1 ];
5980             uniqueNodes[ 1 ] = curNodes [ 0 ];
5981           }
5982           else if (nbRepl == 3 &&
5983                    iRepl[ 0 ] < 3 && iRepl[ 1 ] < 3 && iRepl[ 2 ] < 3 ) {
5984             // all bottom nodes stick: set a top before
5985             uniqueNodes[ 3 ] = uniqueNodes [ 0 ];
5986             uniqueNodes[ 0 ] = curNodes [ 3 ];
5987             uniqueNodes[ 1 ] = curNodes [ 4 ];
5988             uniqueNodes[ 2 ] = curNodes [ 5 ];
5989           }
5990           else if (nbRepl == 4 &&
5991                    iRepl[ 2 ] - iRepl [ 0 ] == 3 && iRepl[ 3 ] - iRepl [ 1 ] == 3 ) {
5992             // a lateral face turns into a line: reverse a bottom
5993             uniqueNodes[ 0 ] = curNodes [ 1 ];
5994             uniqueNodes[ 1 ] = curNodes [ 0 ];
5995           }
5996           else
5997             isOk = false;
5998         }
5999         else if ( nbUniqueNodes == 5 ) {
6000           // PENTAHEDRON --------------------> 2 tetrahedrons
6001           if ( nbRepl == 2 && iRepl[ 1 ] - iRepl [ 0 ] == 3 ) {
6002             // a bottom node sticks with a linked top one
6003             // 1.
6004             SMDS_MeshElement* newElem =
6005               aMesh->AddVolume(curNodes[ 3 ],
6006                                curNodes[ 4 ],
6007                                curNodes[ 5 ],
6008                                curNodes[ iRepl[ 0 ] == 2 ? 1 : 2 ]);
6009             myLastCreatedElems.Append(newElem);
6010             if ( aShapeId )
6011               aMesh->SetMeshElementOnShape( newElem, aShapeId );
6012             // 2. : reverse a bottom
6013             uniqueNodes[ 0 ] = curNodes [ 1 ];
6014             uniqueNodes[ 1 ] = curNodes [ 0 ];
6015             nbUniqueNodes = 4;
6016           }
6017           else
6018             isOk = false;
6019         }
6020         else
6021           isOk = false;
6022         break;
6023       case 8: {
6024         if(elem->IsQuadratic()) { // Quadratic quadrangle
6025           //   1    5    2
6026           //    +---+---+
6027           //    |       |
6028           //    |       |
6029           //   4+       +6
6030           //    |       |
6031           //    |       |
6032           //    +---+---+
6033           //   0    7    3
6034           isOk = false;
6035           if(nbRepl==3) {
6036             nbUniqueNodes = 6;
6037             if( iRepl[0]==0 && iRepl[1]==1 && iRepl[2]==4 ) {
6038               uniqueNodes[0] = curNodes[0];
6039               uniqueNodes[1] = curNodes[2];
6040               uniqueNodes[2] = curNodes[3];
6041               uniqueNodes[3] = curNodes[5];
6042               uniqueNodes[4] = curNodes[6];
6043               uniqueNodes[5] = curNodes[7];
6044               isOk = true;
6045             }
6046             if( iRepl[0]==0 && iRepl[1]==3 && iRepl[2]==7 ) {
6047               uniqueNodes[0] = curNodes[0];
6048               uniqueNodes[1] = curNodes[1];
6049               uniqueNodes[2] = curNodes[2];
6050               uniqueNodes[3] = curNodes[4];
6051               uniqueNodes[4] = curNodes[5];
6052               uniqueNodes[5] = curNodes[6];
6053               isOk = true;
6054             }
6055             if( iRepl[0]==0 && iRepl[1]==4 && iRepl[2]==7 ) {
6056               uniqueNodes[0] = curNodes[1];
6057               uniqueNodes[1] = curNodes[2];
6058               uniqueNodes[2] = curNodes[3];
6059               uniqueNodes[3] = curNodes[5];
6060               uniqueNodes[4] = curNodes[6];
6061               uniqueNodes[5] = curNodes[0];
6062               isOk = true;
6063             }
6064             if( iRepl[0]==1 && iRepl[1]==2 && iRepl[2]==5 ) {
6065               uniqueNodes[0] = curNodes[0];
6066               uniqueNodes[1] = curNodes[1];
6067               uniqueNodes[2] = curNodes[3];
6068               uniqueNodes[3] = curNodes[4];
6069               uniqueNodes[4] = curNodes[6];
6070               uniqueNodes[5] = curNodes[7];
6071               isOk = true;
6072             }
6073             if( iRepl[0]==1 && iRepl[1]==4 && iRepl[2]==5 ) {
6074               uniqueNodes[0] = curNodes[0];
6075               uniqueNodes[1] = curNodes[2];
6076               uniqueNodes[2] = curNodes[3];
6077               uniqueNodes[3] = curNodes[1];
6078               uniqueNodes[4] = curNodes[6];
6079               uniqueNodes[5] = curNodes[7];
6080               isOk = true;
6081             }
6082             if( iRepl[0]==2 && iRepl[1]==3 && iRepl[2]==6 ) {
6083               uniqueNodes[0] = curNodes[0];
6084               uniqueNodes[1] = curNodes[1];
6085               uniqueNodes[2] = curNodes[2];
6086               uniqueNodes[3] = curNodes[4];
6087               uniqueNodes[4] = curNodes[5];
6088               uniqueNodes[5] = curNodes[7];
6089               isOk = true;
6090             }
6091             if( iRepl[0]==2 && iRepl[1]==5 && iRepl[2]==6 ) {
6092               uniqueNodes[0] = curNodes[0];
6093               uniqueNodes[1] = curNodes[1];
6094               uniqueNodes[2] = curNodes[3];
6095               uniqueNodes[3] = curNodes[4];
6096               uniqueNodes[4] = curNodes[2];
6097               uniqueNodes[5] = curNodes[7];
6098               isOk = true;
6099             }
6100             if( iRepl[0]==3 && iRepl[1]==6 && iRepl[2]==7 ) {
6101               uniqueNodes[0] = curNodes[0];
6102               uniqueNodes[1] = curNodes[1];
6103               uniqueNodes[2] = curNodes[2];
6104               uniqueNodes[3] = curNodes[4];
6105               uniqueNodes[4] = curNodes[5];
6106               uniqueNodes[5] = curNodes[3];
6107               isOk = true;
6108             }
6109           }
6110           break;
6111         }
6112         //////////////////////////////////// HEXAHEDRON
6113         isOk = false;
6114         SMDS_VolumeTool hexa (elem);
6115         hexa.SetExternalNormal();
6116         if ( nbUniqueNodes == 4 && nbRepl == 6 ) {
6117           //////////////////////// ---> tetrahedron
6118           for ( int iFace = 0; iFace < 6; iFace++ ) {
6119             const int *ind = hexa.GetFaceNodesIndices( iFace ); // indices of face nodes
6120             if (curNodes[ind[ 0 ]] == curNodes[ind[ 1 ]] &&
6121                 curNodes[ind[ 0 ]] == curNodes[ind[ 2 ]] &&
6122                 curNodes[ind[ 0 ]] == curNodes[ind[ 3 ]] ) {
6123               // one face turns into a point ...
6124               int iOppFace = hexa.GetOppFaceIndex( iFace );
6125               ind = hexa.GetFaceNodesIndices( iOppFace );
6126               int nbStick = 0;
6127               iUnique = 2; // reverse a tetrahedron bottom
6128               for ( iCur = 0; iCur < 4 && nbStick < 2; iCur++ ) {
6129                 if ( curNodes[ind[ iCur ]] == curNodes[ind[ iCur + 1 ]] )
6130                   nbStick++;
6131                 else if ( iUnique >= 0 )
6132                   uniqueNodes[ iUnique-- ] = curNodes[ind[ iCur ]];
6133               }
6134               if ( nbStick == 1 ) {
6135                 // ... and the opposite one - into a triangle.
6136                 // set a top node
6137                 ind = hexa.GetFaceNodesIndices( iFace );
6138                 uniqueNodes[ 3 ] = curNodes[ind[ 0 ]];
6139                 isOk = true;
6140               }
6141               break;
6142             }
6143           }
6144         }
6145         else if (nbUniqueNodes == 5 && nbRepl == 4 ) {
6146           //////////////////// HEXAHEDRON ---> 2 tetrahedrons
6147           for ( int iFace = 0; iFace < 6; iFace++ ) {
6148             const int *ind = hexa.GetFaceNodesIndices( iFace ); // indices of face nodes
6149             if (curNodes[ind[ 0 ]] == curNodes[ind[ 1 ]] &&
6150                 curNodes[ind[ 0 ]] == curNodes[ind[ 2 ]] &&
6151                 curNodes[ind[ 0 ]] == curNodes[ind[ 3 ]] ) {
6152               // one face turns into a point ...
6153               int iOppFace = hexa.GetOppFaceIndex( iFace );
6154               ind = hexa.GetFaceNodesIndices( iOppFace );
6155               int nbStick = 0;
6156               iUnique = 2;  // reverse a tetrahedron 1 bottom
6157               for ( iCur = 0; iCur < 4 && nbStick == 0; iCur++ ) {
6158                 if ( curNodes[ind[ iCur ]] == curNodes[ind[ iCur + 1 ]] )
6159                   nbStick++;
6160                 else if ( iUnique >= 0 )
6161                   uniqueNodes[ iUnique-- ] = curNodes[ind[ iCur ]];
6162               }
6163               if ( nbStick == 0 ) {
6164                 // ... and the opposite one is a quadrangle
6165                 // set a top node
6166                 const int* indTop = hexa.GetFaceNodesIndices( iFace );
6167                 uniqueNodes[ 3 ] = curNodes[indTop[ 0 ]];
6168                 nbUniqueNodes = 4;
6169                 // tetrahedron 2
6170                 SMDS_MeshElement* newElem =
6171                   aMesh->AddVolume(curNodes[ind[ 0 ]],
6172                                    curNodes[ind[ 3 ]],
6173                                    curNodes[ind[ 2 ]],
6174                                    curNodes[indTop[ 0 ]]);
6175                 myLastCreatedElems.Append(newElem);
6176                 if ( aShapeId )
6177                   aMesh->SetMeshElementOnShape( newElem, aShapeId );
6178                 isOk = true;
6179               }
6180               break;
6181             }
6182           }
6183         }
6184         else if ( nbUniqueNodes == 6 && nbRepl == 4 ) {
6185           ////////////////// HEXAHEDRON ---> 2 tetrahedrons or 1 prism
6186           // find indices of quad and tri faces
6187           int iQuadFace[ 6 ], iTriFace[ 6 ], nbQuad = 0, nbTri = 0, iFace;
6188           for ( iFace = 0; iFace < 6; iFace++ ) {
6189             const int *ind = hexa.GetFaceNodesIndices( iFace ); // indices of face nodes
6190             nodeSet.clear();
6191             for ( iCur = 0; iCur < 4; iCur++ )
6192               nodeSet.insert( curNodes[ind[ iCur ]] );
6193             nbUniqueNodes = nodeSet.size();
6194             if ( nbUniqueNodes == 3 )
6195               iTriFace[ nbTri++ ] = iFace;
6196             else if ( nbUniqueNodes == 4 )
6197               iQuadFace[ nbQuad++ ] = iFace;
6198           }
6199           if (nbQuad == 2 && nbTri == 4 &&
6200               hexa.GetOppFaceIndex( iQuadFace[ 0 ] ) == iQuadFace[ 1 ]) {
6201             // 2 opposite quadrangles stuck with a diagonal;
6202             // sample groups of merged indices: (0-4)(2-6)
6203             // --------------------------------------------> 2 tetrahedrons
6204             const int *ind1 = hexa.GetFaceNodesIndices( iQuadFace[ 0 ]); // indices of quad1 nodes
6205             const int *ind2 = hexa.GetFaceNodesIndices( iQuadFace[ 1 ]);
6206             int i0, i1d, i2, i3d, i0t, i2t; // d-daigonal, t-top
6207             if (curNodes[ind1[ 0 ]] == curNodes[ind2[ 0 ]] &&
6208                 curNodes[ind1[ 2 ]] == curNodes[ind2[ 2 ]]) {
6209               // stuck with 0-2 diagonal
6210               i0  = ind1[ 3 ];
6211               i1d = ind1[ 0 ];
6212               i2  = ind1[ 1 ];
6213               i3d = ind1[ 2 ];
6214               i0t = ind2[ 1 ];
6215               i2t = ind2[ 3 ];
6216             }
6217             else if (curNodes[ind1[ 1 ]] == curNodes[ind2[ 3 ]] &&
6218                      curNodes[ind1[ 3 ]] == curNodes[ind2[ 1 ]]) {
6219               // stuck with 1-3 diagonal
6220               i0  = ind1[ 0 ];
6221               i1d = ind1[ 1 ];
6222               i2  = ind1[ 2 ];
6223               i3d = ind1[ 3 ];
6224               i0t = ind2[ 0 ];
6225               i2t = ind2[ 1 ];
6226             }
6227             else {
6228               ASSERT(0);
6229             }
6230             // tetrahedron 1
6231             uniqueNodes[ 0 ] = curNodes [ i0 ];
6232             uniqueNodes[ 1 ] = curNodes [ i1d ];
6233             uniqueNodes[ 2 ] = curNodes [ i3d ];
6234             uniqueNodes[ 3 ] = curNodes [ i0t ];
6235             nbUniqueNodes = 4;
6236             // tetrahedron 2
6237             SMDS_MeshElement* newElem = aMesh->AddVolume(curNodes[ i1d ],
6238                                                          curNodes[ i2 ],
6239                                                          curNodes[ i3d ],
6240                                                          curNodes[ i2t ]);
6241             myLastCreatedElems.Append(newElem);
6242             if ( aShapeId )
6243               aMesh->SetMeshElementOnShape( newElem, aShapeId );
6244             isOk = true;
6245           }
6246           else if (( nbTri == 2 && nbQuad == 3 ) || // merged (0-4)(1-5)
6247                    ( nbTri == 4 && nbQuad == 2 )) { // merged (7-4)(1-5)
6248             // --------------------------------------------> prism
6249             // find 2 opposite triangles
6250             nbUniqueNodes = 6;
6251             for ( iFace = 0; iFace + 1 < nbTri; iFace++ ) {
6252               if ( hexa.GetOppFaceIndex( iTriFace[ iFace ] ) == iTriFace[ iFace + 1 ]) {
6253                 // find indices of kept and replaced nodes
6254                 // and fill unique nodes of 2 opposite triangles
6255                 const int *ind1 = hexa.GetFaceNodesIndices( iTriFace[ iFace ]);
6256                 const int *ind2 = hexa.GetFaceNodesIndices( iTriFace[ iFace + 1 ]);
6257                 const SMDS_MeshNode** hexanodes = hexa.GetNodes();
6258                 // fill unique nodes
6259                 iUnique = 0;
6260                 isOk = true;
6261                 for ( iCur = 0; iCur < 4 && isOk; iCur++ ) {
6262                   const SMDS_MeshNode* n     = curNodes[ind1[ iCur ]];
6263                   const SMDS_MeshNode* nInit = hexanodes[ind1[ iCur ]];
6264                   if ( n == nInit ) {
6265                     // iCur of a linked node of the opposite face (make normals co-directed):
6266                     int iCurOpp = ( iCur == 1 || iCur == 3 ) ? 4 - iCur : iCur;
6267                     // check that correspondent corners of triangles are linked
6268                     if ( !hexa.IsLinked( ind1[ iCur ], ind2[ iCurOpp ] ))
6269                       isOk = false;
6270                     else {
6271                       uniqueNodes[ iUnique ] = n;
6272                       uniqueNodes[ iUnique + 3 ] = curNodes[ind2[ iCurOpp ]];
6273                       iUnique++;
6274                     }
6275                   }
6276                 }
6277                 break;
6278               }
6279             }
6280           }
6281         } // if ( nbUniqueNodes == 6 && nbRepl == 4 )
6282         break;
6283       } // HEXAHEDRON
6284
6285       default:
6286         isOk = false;
6287       } // switch ( nbNodes )
6288
6289     } // if ( nbNodes != nbUniqueNodes ) // some nodes stick
6290
6291     if ( isOk ) {
6292       if (elem->IsPoly() && elem->GetType() == SMDSAbs_Volume) {
6293         // Change nodes of polyedre
6294         const SMDS_PolyhedralVolumeOfNodes* aPolyedre =
6295           static_cast<const SMDS_PolyhedralVolumeOfNodes*>( elem );
6296         if (aPolyedre) {
6297           int nbFaces = aPolyedre->NbFaces();
6298
6299           vector<const SMDS_MeshNode *> poly_nodes;
6300           vector<int> quantities (nbFaces);
6301
6302           for (int iface = 1; iface <= nbFaces; iface++) {
6303             int inode, nbFaceNodes = aPolyedre->NbFaceNodes(iface);
6304             quantities[iface - 1] = nbFaceNodes;
6305
6306             for (inode = 1; inode <= nbFaceNodes; inode++) {
6307               const SMDS_MeshNode* curNode = aPolyedre->GetFaceNode(iface, inode);
6308
6309               TNodeNodeMap::iterator nnIt = nodeNodeMap.find( curNode );
6310               if (nnIt != nodeNodeMap.end()) { // curNode sticks
6311                 curNode = (*nnIt).second;
6312               }
6313               poly_nodes.push_back(curNode);
6314             }
6315           }
6316           aMesh->ChangePolyhedronNodes( elem, poly_nodes, quantities );
6317         }
6318       }
6319       else {
6320         // Change regular element or polygon
6321         aMesh->ChangeElementNodes( elem, & uniqueNodes[0], nbUniqueNodes );
6322       }
6323     }
6324     else {
6325       // Remove invalid regular element or invalid polygon
6326       rmElemIds.push_back( elem->GetID() );
6327     }
6328
6329   } // loop on elements
6330
6331   // Remove equal nodes and bad elements
6332
6333   Remove( rmNodeIds, true );
6334   Remove( rmElemIds, false );
6335
6336 }
6337
6338
6339 // ========================================================
6340 // class   : SortableElement
6341 // purpose : allow sorting elements basing on their nodes
6342 // ========================================================
6343 class SortableElement : public set <const SMDS_MeshElement*>
6344 {
6345 public:
6346
6347   SortableElement( const SMDS_MeshElement* theElem )
6348   {
6349     myElem = theElem;
6350     SMDS_ElemIteratorPtr nodeIt = theElem->nodesIterator();
6351     while ( nodeIt->more() )
6352       this->insert( nodeIt->next() );
6353   }
6354
6355   const SMDS_MeshElement* Get() const
6356   { return myElem; }
6357
6358   void Set(const SMDS_MeshElement* e) const
6359   { myElem = e; }
6360
6361
6362 private:
6363   mutable const SMDS_MeshElement* myElem;
6364 };
6365
6366 //=======================================================================
6367 //function : FindEqualElements
6368 //purpose  : Return list of group of elements built on the same nodes.
6369 //           Search among theElements or in the whole mesh if theElements is empty
6370 //=======================================================================
6371 void SMESH_MeshEditor::FindEqualElements(set<const SMDS_MeshElement*> & theElements,
6372                                          TListOfListOfElementsID &      theGroupsOfElementsID)
6373 {
6374   myLastCreatedElems.Clear();
6375   myLastCreatedNodes.Clear();
6376
6377   typedef set<const SMDS_MeshElement*> TElemsSet;
6378   typedef map< SortableElement, int > TMapOfNodeSet;
6379   typedef list<int> TGroupOfElems;
6380
6381   TElemsSet elems;
6382   if ( theElements.empty() )
6383   { // get all elements in the mesh
6384     SMDS_ElemIteratorPtr eIt = GetMeshDS()->elementsIterator();
6385     while ( eIt->more() )
6386       elems.insert( elems.end(), eIt->next());
6387   }
6388   else
6389     elems = theElements;
6390
6391   vector< TGroupOfElems > arrayOfGroups;
6392   TGroupOfElems groupOfElems;
6393   TMapOfNodeSet mapOfNodeSet;
6394
6395   TElemsSet::iterator elemIt = elems.begin();
6396   for ( int i = 0, j=0; elemIt != elems.end(); ++elemIt, ++j ) {
6397     const SMDS_MeshElement* curElem = *elemIt;
6398     SortableElement SE(curElem);
6399     int ind = -1;
6400     // check uniqueness
6401     pair< TMapOfNodeSet::iterator, bool> pp = mapOfNodeSet.insert(make_pair(SE, i));
6402     if( !(pp.second) ) {
6403       TMapOfNodeSet::iterator& itSE = pp.first;
6404       ind = (*itSE).second;
6405       arrayOfGroups[ind].push_back(curElem->GetID());
6406     }
6407     else {
6408       groupOfElems.clear();
6409       groupOfElems.push_back(curElem->GetID());
6410       arrayOfGroups.push_back(groupOfElems);
6411       i++;
6412     }
6413   }
6414
6415   vector< TGroupOfElems >::iterator groupIt = arrayOfGroups.begin();
6416   for ( ; groupIt != arrayOfGroups.end(); ++groupIt ) {
6417     groupOfElems = *groupIt;
6418     if ( groupOfElems.size() > 1 ) {
6419       groupOfElems.sort();
6420       theGroupsOfElementsID.push_back(groupOfElems);
6421     }
6422   }
6423 }
6424
6425 //=======================================================================
6426 //function : MergeElements
6427 //purpose  : In each given group, substitute all elements by the first one.
6428 //=======================================================================
6429
6430 void SMESH_MeshEditor::MergeElements(TListOfListOfElementsID & theGroupsOfElementsID)
6431 {
6432   myLastCreatedElems.Clear();
6433   myLastCreatedNodes.Clear();
6434
6435   typedef list<int> TListOfIDs;
6436   TListOfIDs rmElemIds; // IDs of elems to remove
6437
6438   SMESHDS_Mesh* aMesh = GetMeshDS();
6439
6440   TListOfListOfElementsID::iterator groupsIt = theGroupsOfElementsID.begin();
6441   while ( groupsIt != theGroupsOfElementsID.end() ) {
6442     TListOfIDs& aGroupOfElemID = *groupsIt;
6443     aGroupOfElemID.sort();
6444     int elemIDToKeep = aGroupOfElemID.front();
6445     const SMDS_MeshElement* elemToKeep = aMesh->FindElement(elemIDToKeep);
6446     aGroupOfElemID.pop_front();
6447     TListOfIDs::iterator idIt = aGroupOfElemID.begin();
6448     while ( idIt != aGroupOfElemID.end() ) {
6449       int elemIDToRemove = *idIt;
6450       const SMDS_MeshElement* elemToRemove = aMesh->FindElement(elemIDToRemove);
6451       // add the kept element in groups of removed one (PAL15188)
6452       AddToSameGroups( elemToKeep, elemToRemove, aMesh );
6453       rmElemIds.push_back( elemIDToRemove );
6454       ++idIt;
6455     }
6456     ++groupsIt;
6457   }
6458
6459   Remove( rmElemIds, false );
6460 }
6461
6462 //=======================================================================
6463 //function : MergeEqualElements
6464 //purpose  : Remove all but one of elements built on the same nodes.
6465 //=======================================================================
6466
6467 void SMESH_MeshEditor::MergeEqualElements()
6468 {
6469   set<const SMDS_MeshElement*> aMeshElements; /* empty input -
6470                                                  to merge equal elements in the whole mesh */
6471   TListOfListOfElementsID aGroupsOfElementsID;
6472   FindEqualElements(aMeshElements, aGroupsOfElementsID);
6473   MergeElements(aGroupsOfElementsID);
6474 }
6475
6476 //=======================================================================
6477 //function : FindFaceInSet
6478 //purpose  : Return a face having linked nodes n1 and n2 and which is
6479 //           - not in avoidSet,
6480 //           - in elemSet provided that !elemSet.empty()
6481 //           i1 and i2 optionally returns indices of n1 and n2
6482 //=======================================================================
6483
6484 const SMDS_MeshElement*
6485 SMESH_MeshEditor::FindFaceInSet(const SMDS_MeshNode*    n1,
6486                                 const SMDS_MeshNode*    n2,
6487                                 const TIDSortedElemSet& elemSet,
6488                                 const TIDSortedElemSet& avoidSet,
6489                                 int*                    n1ind,
6490                                 int*                    n2ind)
6491
6492 {
6493   int i1, i2;
6494   const SMDS_MeshElement* face = 0;
6495
6496   SMDS_ElemIteratorPtr invElemIt = n1->GetInverseElementIterator(SMDSAbs_Face);
6497   while ( invElemIt->more() && !face ) // loop on inverse faces of n1
6498   {
6499     const SMDS_MeshElement* elem = invElemIt->next();
6500     if (avoidSet.count( elem ))
6501       continue;
6502     if ( !elemSet.empty() && !elemSet.count( elem ))
6503       continue;
6504     // index of n1
6505     i1 = elem->GetNodeIndex( n1 );
6506     // find a n2 linked to n1
6507     int nbN = elem->IsQuadratic() ? elem->NbNodes()/2 : elem->NbNodes();
6508     for ( int di = -1; di < 2 && !face; di += 2 )
6509     {
6510       i2 = (i1+di+nbN) % nbN;
6511       if ( elem->GetNode( i2 ) == n2 )
6512         face = elem;
6513     }
6514     if ( !face && elem->IsQuadratic())
6515     {
6516       // analysis for quadratic elements using all nodes
6517       const SMDS_QuadraticFaceOfNodes* F =
6518         static_cast<const SMDS_QuadraticFaceOfNodes*>(elem);
6519       // use special nodes iterator
6520       SMDS_NodeIteratorPtr anIter = F->interlacedNodesIterator();
6521       const SMDS_MeshNode* prevN = cast2Node( anIter->next() );
6522       for ( i1 = -1, i2 = 0; anIter->more() && !face; i1++, i2++ )
6523       {
6524         const SMDS_MeshNode* n = cast2Node( anIter->next() );
6525         if ( n1 == prevN && n2 == n )
6526         {
6527           face = elem;
6528         }
6529         else if ( n2 == prevN && n1 == n )
6530         {
6531           face = elem; swap( i1, i2 );
6532         }
6533         prevN = n;
6534       }
6535     }
6536   }
6537   if ( n1ind ) *n1ind = i1;
6538   if ( n2ind ) *n2ind = i2;
6539   return face;
6540 }
6541
6542 //=======================================================================
6543 //function : findAdjacentFace
6544 //purpose  :
6545 //=======================================================================
6546
6547 static const SMDS_MeshElement* findAdjacentFace(const SMDS_MeshNode* n1,
6548                                                 const SMDS_MeshNode* n2,
6549                                                 const SMDS_MeshElement* elem)
6550 {
6551   TIDSortedElemSet elemSet, avoidSet;
6552   if ( elem )
6553     avoidSet.insert ( elem );
6554   return SMESH_MeshEditor::FindFaceInSet( n1, n2, elemSet, avoidSet );
6555 }
6556
6557 //=======================================================================
6558 //function : FindFreeBorder
6559 //purpose  :
6560 //=======================================================================
6561
6562 #define ControlFreeBorder SMESH::Controls::FreeEdges::IsFreeEdge
6563
6564 bool SMESH_MeshEditor::FindFreeBorder (const SMDS_MeshNode*             theFirstNode,
6565                                        const SMDS_MeshNode*             theSecondNode,
6566                                        const SMDS_MeshNode*             theLastNode,
6567                                        list< const SMDS_MeshNode* > &   theNodes,
6568                                        list< const SMDS_MeshElement* >& theFaces)
6569 {
6570   if ( !theFirstNode || !theSecondNode )
6571     return false;
6572   // find border face between theFirstNode and theSecondNode
6573   const SMDS_MeshElement* curElem = findAdjacentFace( theFirstNode, theSecondNode, 0 );
6574   if ( !curElem )
6575     return false;
6576
6577   theFaces.push_back( curElem );
6578   theNodes.push_back( theFirstNode );
6579   theNodes.push_back( theSecondNode );
6580
6581   //vector<const SMDS_MeshNode*> nodes;
6582   const SMDS_MeshNode *nIgnore = theFirstNode, *nStart = theSecondNode;
6583   TIDSortedElemSet foundElems;
6584   bool needTheLast = ( theLastNode != 0 );
6585
6586   while ( nStart != theLastNode ) {
6587     if ( nStart == theFirstNode )
6588       return !needTheLast;
6589
6590     // find all free border faces sharing form nStart
6591
6592     list< const SMDS_MeshElement* > curElemList;
6593     list< const SMDS_MeshNode* > nStartList;
6594     SMDS_ElemIteratorPtr invElemIt = nStart->GetInverseElementIterator(SMDSAbs_Face);
6595     while ( invElemIt->more() ) {
6596       const SMDS_MeshElement* e = invElemIt->next();
6597       if ( e == curElem || foundElems.insert( e ).second ) {
6598         // get nodes
6599         int iNode = 0, nbNodes = e->NbNodes();
6600         //const SMDS_MeshNode* nodes[nbNodes+1];
6601         vector<const SMDS_MeshNode*> nodes(nbNodes+1);
6602
6603         if(e->IsQuadratic()) {
6604           const SMDS_QuadraticFaceOfNodes* F =
6605             static_cast<const SMDS_QuadraticFaceOfNodes*>(e);
6606           // use special nodes iterator
6607           SMDS_NodeIteratorPtr anIter = F->interlacedNodesIterator();
6608           while( anIter->more() ) {
6609             nodes[ iNode++ ] = anIter->next();
6610           }
6611         }
6612         else {
6613           SMDS_ElemIteratorPtr nIt = e->nodesIterator();
6614           while ( nIt->more() )
6615             nodes[ iNode++ ] = static_cast<const SMDS_MeshNode*>( nIt->next() );
6616         }
6617         nodes[ iNode ] = nodes[ 0 ];
6618         // check 2 links
6619         for ( iNode = 0; iNode < nbNodes; iNode++ )
6620           if (((nodes[ iNode ] == nStart && nodes[ iNode + 1] != nIgnore ) ||
6621                (nodes[ iNode + 1] == nStart && nodes[ iNode ] != nIgnore )) &&
6622               ControlFreeBorder( &nodes[ iNode ], e->GetID() ))
6623           {
6624             nStartList.push_back( nodes[ iNode + ( nodes[ iNode ] == nStart ? 1 : 0 )]);
6625             curElemList.push_back( e );
6626           }
6627       }
6628     }
6629     // analyse the found
6630
6631     int nbNewBorders = curElemList.size();
6632     if ( nbNewBorders == 0 ) {
6633       // no free border furthermore
6634       return !needTheLast;
6635     }
6636     else if ( nbNewBorders == 1 ) {
6637       // one more element found
6638       nIgnore = nStart;
6639       nStart = nStartList.front();
6640       curElem = curElemList.front();
6641       theFaces.push_back( curElem );
6642       theNodes.push_back( nStart );
6643     }
6644     else {
6645       // several continuations found
6646       list< const SMDS_MeshElement* >::iterator curElemIt;
6647       list< const SMDS_MeshNode* >::iterator nStartIt;
6648       // check if one of them reached the last node
6649       if ( needTheLast ) {
6650         for (curElemIt = curElemList.begin(), nStartIt = nStartList.begin();
6651              curElemIt!= curElemList.end();
6652              curElemIt++, nStartIt++ )
6653           if ( *nStartIt == theLastNode ) {
6654             theFaces.push_back( *curElemIt );
6655             theNodes.push_back( *nStartIt );
6656             return true;
6657           }
6658       }
6659       // find the best free border by the continuations
6660       list<const SMDS_MeshNode*>    contNodes[ 2 ], *cNL;
6661       list<const SMDS_MeshElement*> contFaces[ 2 ], *cFL;
6662       for (curElemIt = curElemList.begin(), nStartIt = nStartList.begin();
6663            curElemIt!= curElemList.end();
6664            curElemIt++, nStartIt++ )
6665       {
6666         cNL = & contNodes[ contNodes[0].empty() ? 0 : 1 ];
6667         cFL = & contFaces[ contFaces[0].empty() ? 0 : 1 ];
6668         // find one more free border
6669         if ( ! FindFreeBorder( nStart, *nStartIt, theLastNode, *cNL, *cFL )) {
6670           cNL->clear();
6671           cFL->clear();
6672         }
6673         else if ( !contNodes[0].empty() && !contNodes[1].empty() ) {
6674           // choice: clear a worse one
6675           int iLongest = ( contNodes[0].size() < contNodes[1].size() ? 1 : 0 );
6676           int iWorse = ( needTheLast ? 1 - iLongest : iLongest );
6677           contNodes[ iWorse ].clear();
6678           contFaces[ iWorse ].clear();
6679         }
6680       }
6681       if ( contNodes[0].empty() && contNodes[1].empty() )
6682         return false;
6683
6684       // append the best free border
6685       cNL = & contNodes[ contNodes[0].empty() ? 1 : 0 ];
6686       cFL = & contFaces[ contFaces[0].empty() ? 1 : 0 ];
6687       theNodes.pop_back(); // remove nIgnore
6688       theNodes.pop_back(); // remove nStart
6689       theFaces.pop_back(); // remove curElem
6690       list< const SMDS_MeshNode* >::iterator nIt = cNL->begin();
6691       list< const SMDS_MeshElement* >::iterator fIt = cFL->begin();
6692       for ( ; nIt != cNL->end(); nIt++ ) theNodes.push_back( *nIt );
6693       for ( ; fIt != cFL->end(); fIt++ ) theFaces.push_back( *fIt );
6694       return true;
6695
6696     } // several continuations found
6697   } // while ( nStart != theLastNode )
6698
6699   return true;
6700 }
6701
6702 //=======================================================================
6703 //function : CheckFreeBorderNodes
6704 //purpose  : Return true if the tree nodes are on a free border
6705 //=======================================================================
6706
6707 bool SMESH_MeshEditor::CheckFreeBorderNodes(const SMDS_MeshNode* theNode1,
6708                                             const SMDS_MeshNode* theNode2,
6709                                             const SMDS_MeshNode* theNode3)
6710 {
6711   list< const SMDS_MeshNode* > nodes;
6712   list< const SMDS_MeshElement* > faces;
6713   return FindFreeBorder( theNode1, theNode2, theNode3, nodes, faces);
6714 }
6715
6716 //=======================================================================
6717 //function : SewFreeBorder
6718 //purpose  :
6719 //=======================================================================
6720
6721 SMESH_MeshEditor::Sew_Error
6722 SMESH_MeshEditor::SewFreeBorder (const SMDS_MeshNode* theBordFirstNode,
6723                                  const SMDS_MeshNode* theBordSecondNode,
6724                                  const SMDS_MeshNode* theBordLastNode,
6725                                  const SMDS_MeshNode* theSideFirstNode,
6726                                  const SMDS_MeshNode* theSideSecondNode,
6727                                  const SMDS_MeshNode* theSideThirdNode,
6728                                  const bool           theSideIsFreeBorder,
6729                                  const bool           toCreatePolygons,
6730                                  const bool           toCreatePolyedrs)
6731 {
6732   myLastCreatedElems.Clear();
6733   myLastCreatedNodes.Clear();
6734
6735   MESSAGE("::SewFreeBorder()");
6736   Sew_Error aResult = SEW_OK;
6737
6738   // ====================================
6739   //    find side nodes and elements
6740   // ====================================
6741
6742   list< const SMDS_MeshNode* > nSide[ 2 ];
6743   list< const SMDS_MeshElement* > eSide[ 2 ];
6744   list< const SMDS_MeshNode* >::iterator nIt[ 2 ];
6745   list< const SMDS_MeshElement* >::iterator eIt[ 2 ];
6746
6747   // Free border 1
6748   // --------------
6749   if (!FindFreeBorder(theBordFirstNode,theBordSecondNode,theBordLastNode,
6750                       nSide[0], eSide[0])) {
6751     MESSAGE(" Free Border 1 not found " );
6752     aResult = SEW_BORDER1_NOT_FOUND;
6753   }
6754   if (theSideIsFreeBorder) {
6755     // Free border 2
6756     // --------------
6757     if (!FindFreeBorder(theSideFirstNode, theSideSecondNode, theSideThirdNode,
6758                         nSide[1], eSide[1])) {
6759       MESSAGE(" Free Border 2 not found " );
6760       aResult = ( aResult != SEW_OK ? SEW_BOTH_BORDERS_NOT_FOUND : SEW_BORDER2_NOT_FOUND );
6761     }
6762   }
6763   if ( aResult != SEW_OK )
6764     return aResult;
6765
6766   if (!theSideIsFreeBorder) {
6767     // Side 2
6768     // --------------
6769
6770     // -------------------------------------------------------------------------
6771     // Algo:
6772     // 1. If nodes to merge are not coincident, move nodes of the free border
6773     //    from the coord sys defined by the direction from the first to last
6774     //    nodes of the border to the correspondent sys of the side 2
6775     // 2. On the side 2, find the links most co-directed with the correspondent
6776     //    links of the free border
6777     // -------------------------------------------------------------------------
6778
6779     // 1. Since sewing may brake if there are volumes to split on the side 2,
6780     //    we wont move nodes but just compute new coordinates for them
6781     typedef map<const SMDS_MeshNode*, gp_XYZ> TNodeXYZMap;
6782     TNodeXYZMap nBordXYZ;
6783     list< const SMDS_MeshNode* >& bordNodes = nSide[ 0 ];
6784     list< const SMDS_MeshNode* >::iterator nBordIt;
6785
6786     gp_XYZ Pb1( theBordFirstNode->X(), theBordFirstNode->Y(), theBordFirstNode->Z() );
6787     gp_XYZ Pb2( theBordLastNode->X(), theBordLastNode->Y(), theBordLastNode->Z() );
6788     gp_XYZ Ps1( theSideFirstNode->X(), theSideFirstNode->Y(), theSideFirstNode->Z() );
6789     gp_XYZ Ps2( theSideSecondNode->X(), theSideSecondNode->Y(), theSideSecondNode->Z() );
6790     double tol2 = 1.e-8;
6791     gp_Vec Vbs1( Pb1 - Ps1 ),Vbs2( Pb2 - Ps2 );
6792     if ( Vbs1.SquareMagnitude() > tol2 || Vbs2.SquareMagnitude() > tol2 ) {
6793       // Need node movement.
6794
6795       // find X and Z axes to create trsf
6796       gp_Vec Zb( Pb1 - Pb2 ), Zs( Ps1 - Ps2 );
6797       gp_Vec X = Zs ^ Zb;
6798       if ( X.SquareMagnitude() <= gp::Resolution() * gp::Resolution() )
6799         // Zb || Zs
6800         X = gp_Ax2( gp::Origin(), Zb ).XDirection();
6801
6802       // coord systems
6803       gp_Ax3 toBordAx( Pb1, Zb, X );
6804       gp_Ax3 fromSideAx( Ps1, Zs, X );
6805       gp_Ax3 toGlobalAx( gp::Origin(), gp::DZ(), gp::DX() );
6806       // set trsf
6807       gp_Trsf toBordSys, fromSide2Sys;
6808       toBordSys.SetTransformation( toBordAx );
6809       fromSide2Sys.SetTransformation( fromSideAx, toGlobalAx );
6810       fromSide2Sys.SetScaleFactor( Zs.Magnitude() / Zb.Magnitude() );
6811
6812       // move
6813       for ( nBordIt = bordNodes.begin(); nBordIt != bordNodes.end(); nBordIt++ ) {
6814         const SMDS_MeshNode* n = *nBordIt;
6815         gp_XYZ xyz( n->X(),n->Y(),n->Z() );
6816         toBordSys.Transforms( xyz );
6817         fromSide2Sys.Transforms( xyz );
6818         nBordXYZ.insert( TNodeXYZMap::value_type( n, xyz ));
6819       }
6820     }
6821     else {
6822       // just insert nodes XYZ in the nBordXYZ map
6823       for ( nBordIt = bordNodes.begin(); nBordIt != bordNodes.end(); nBordIt++ ) {
6824         const SMDS_MeshNode* n = *nBordIt;
6825         nBordXYZ.insert( TNodeXYZMap::value_type( n, gp_XYZ( n->X(),n->Y(),n->Z() )));
6826       }
6827     }
6828
6829     // 2. On the side 2, find the links most co-directed with the correspondent
6830     //    links of the free border
6831
6832     list< const SMDS_MeshElement* >& sideElems = eSide[ 1 ];
6833     list< const SMDS_MeshNode* >& sideNodes = nSide[ 1 ];
6834     sideNodes.push_back( theSideFirstNode );
6835
6836     bool hasVolumes = false;
6837     LinkID_Gen aLinkID_Gen( GetMeshDS() );
6838     set<long> foundSideLinkIDs, checkedLinkIDs;
6839     SMDS_VolumeTool volume;
6840     //const SMDS_MeshNode* faceNodes[ 4 ];
6841
6842     const SMDS_MeshNode*    sideNode;
6843     const SMDS_MeshElement* sideElem;
6844     const SMDS_MeshNode* prevSideNode = theSideFirstNode;
6845     const SMDS_MeshNode* prevBordNode = theBordFirstNode;
6846     nBordIt = bordNodes.begin();
6847     nBordIt++;
6848     // border node position and border link direction to compare with
6849     gp_XYZ bordPos = nBordXYZ[ *nBordIt ];
6850     gp_XYZ bordDir = bordPos - nBordXYZ[ prevBordNode ];
6851     // choose next side node by link direction or by closeness to
6852     // the current border node:
6853     bool searchByDir = ( *nBordIt != theBordLastNode );
6854     do {
6855       // find the next node on the Side 2
6856       sideNode = 0;
6857       double maxDot = -DBL_MAX, minDist = DBL_MAX;
6858       long linkID;
6859       checkedLinkIDs.clear();
6860       gp_XYZ prevXYZ( prevSideNode->X(), prevSideNode->Y(), prevSideNode->Z() );
6861
6862       // loop on inverse elements of current node (prevSideNode) on the Side 2
6863       SMDS_ElemIteratorPtr invElemIt = prevSideNode->GetInverseElementIterator();
6864       while ( invElemIt->more() )
6865       {
6866         const SMDS_MeshElement* elem = invElemIt->next();
6867         // prepare data for a loop on links coming to prevSideNode, of a face or a volume
6868         int iPrevNode, iNode = 0, nbNodes = elem->NbNodes();
6869         vector< const SMDS_MeshNode* > faceNodes( nbNodes, (const SMDS_MeshNode*)0 );
6870         bool isVolume = volume.Set( elem );
6871         const SMDS_MeshNode** nodes = isVolume ? volume.GetNodes() : & faceNodes[0];
6872         if ( isVolume ) // --volume
6873           hasVolumes = true;
6874         else if ( elem->GetType()==SMDSAbs_Face ) { // --face
6875           // retrieve all face nodes and find iPrevNode - an index of the prevSideNode
6876           if(elem->IsQuadratic()) {
6877             const SMDS_QuadraticFaceOfNodes* F =
6878               static_cast<const SMDS_QuadraticFaceOfNodes*>(elem);
6879             // use special nodes iterator
6880             SMDS_NodeIteratorPtr anIter = F->interlacedNodesIterator();
6881             while( anIter->more() ) {
6882               nodes[ iNode ] = anIter->next();
6883               if ( nodes[ iNode++ ] == prevSideNode )
6884                 iPrevNode = iNode - 1;
6885             }
6886           }
6887           else {
6888             SMDS_ElemIteratorPtr nIt = elem->nodesIterator();
6889             while ( nIt->more() ) {
6890               nodes[ iNode ] = cast2Node( nIt->next() );
6891               if ( nodes[ iNode++ ] == prevSideNode )
6892                 iPrevNode = iNode - 1;
6893             }
6894           }
6895           // there are 2 links to check
6896           nbNodes = 2;
6897         }
6898         else // --edge
6899           continue;
6900         // loop on links, to be precise, on the second node of links
6901         for ( iNode = 0; iNode < nbNodes; iNode++ ) {
6902           const SMDS_MeshNode* n = nodes[ iNode ];
6903           if ( isVolume ) {
6904             if ( !volume.IsLinked( n, prevSideNode ))
6905               continue;
6906           }
6907           else {
6908             if ( iNode ) // a node before prevSideNode
6909               n = nodes[ iPrevNode == 0 ? elem->NbNodes() - 1 : iPrevNode - 1 ];
6910             else         // a node after prevSideNode
6911               n = nodes[ iPrevNode + 1 == elem->NbNodes() ? 0 : iPrevNode + 1 ];
6912           }
6913           // check if this link was already used
6914           long iLink = aLinkID_Gen.GetLinkID( prevSideNode, n );
6915           bool isJustChecked = !checkedLinkIDs.insert( iLink ).second;
6916           if (!isJustChecked &&
6917               foundSideLinkIDs.find( iLink ) == foundSideLinkIDs.end() )
6918           {
6919             // test a link geometrically
6920             gp_XYZ nextXYZ ( n->X(), n->Y(), n->Z() );
6921             bool linkIsBetter = false;
6922             double dot = 0.0, dist = 0.0;
6923             if ( searchByDir ) { // choose most co-directed link
6924               dot = bordDir * ( nextXYZ - prevXYZ ).Normalized();
6925               linkIsBetter = ( dot > maxDot );
6926             }
6927             else { // choose link with the node closest to bordPos
6928               dist = ( nextXYZ - bordPos ).SquareModulus();
6929               linkIsBetter = ( dist < minDist );
6930             }
6931             if ( linkIsBetter ) {
6932               maxDot = dot;
6933               minDist = dist;
6934               linkID = iLink;
6935               sideNode = n;
6936               sideElem = elem;
6937             }
6938           }
6939         }
6940       } // loop on inverse elements of prevSideNode
6941
6942       if ( !sideNode ) {
6943         MESSAGE(" Cant find path by links of the Side 2 ");
6944         return SEW_BAD_SIDE_NODES;
6945       }
6946       sideNodes.push_back( sideNode );
6947       sideElems.push_back( sideElem );
6948       foundSideLinkIDs.insert ( linkID );
6949       prevSideNode = sideNode;
6950
6951       if ( *nBordIt == theBordLastNode )
6952         searchByDir = false;
6953       else {
6954         // find the next border link to compare with
6955         gp_XYZ sidePos( sideNode->X(), sideNode->Y(), sideNode->Z() );
6956         searchByDir = ( bordDir * ( sidePos - bordPos ) <= 0 );
6957         // move to next border node if sideNode is before forward border node (bordPos)
6958         while ( *nBordIt != theBordLastNode && !searchByDir ) {
6959           prevBordNode = *nBordIt;
6960           nBordIt++;
6961           bordPos = nBordXYZ[ *nBordIt ];
6962           bordDir = bordPos - nBordXYZ[ prevBordNode ];
6963           searchByDir = ( bordDir * ( sidePos - bordPos ) <= 0 );
6964         }
6965       }
6966     }
6967     while ( sideNode != theSideSecondNode );
6968
6969     if ( hasVolumes && sideNodes.size () != bordNodes.size() && !toCreatePolyedrs) {
6970       MESSAGE("VOLUME SPLITTING IS FORBIDDEN");
6971       return SEW_VOLUMES_TO_SPLIT; // volume splitting is forbidden
6972     }
6973   } // end nodes search on the side 2
6974
6975   // ============================
6976   // sew the border to the side 2
6977   // ============================
6978
6979   int nbNodes[]  = { nSide[0].size(), nSide[1].size() };
6980   int maxNbNodes = Max( nbNodes[0], nbNodes[1] );
6981
6982   TListOfListOfNodes nodeGroupsToMerge;
6983   if ( nbNodes[0] == nbNodes[1] ||
6984        ( theSideIsFreeBorder && !theSideThirdNode)) {
6985
6986     // all nodes are to be merged
6987
6988     for (nIt[0] = nSide[0].begin(), nIt[1] = nSide[1].begin();
6989          nIt[0] != nSide[0].end() && nIt[1] != nSide[1].end();
6990          nIt[0]++, nIt[1]++ )
6991     {
6992       nodeGroupsToMerge.push_back( list<const SMDS_MeshNode*>() );
6993       nodeGroupsToMerge.back().push_back( *nIt[1] ); // to keep
6994       nodeGroupsToMerge.back().push_back( *nIt[0] ); // to remove
6995     }
6996   }
6997   else {
6998
6999     // insert new nodes into the border and the side to get equal nb of segments
7000
7001     // get normalized parameters of nodes on the borders
7002     //double param[ 2 ][ maxNbNodes ];
7003     double* param[ 2 ];
7004     param[0] = new double [ maxNbNodes ];
7005     param[1] = new double [ maxNbNodes ];
7006     int iNode, iBord;
7007     for ( iBord = 0; iBord < 2; iBord++ ) { // loop on 2 borders
7008       list< const SMDS_MeshNode* >& nodes = nSide[ iBord ];
7009       list< const SMDS_MeshNode* >::iterator nIt = nodes.begin();
7010       const SMDS_MeshNode* nPrev = *nIt;
7011       double bordLength = 0;
7012       for ( iNode = 0; nIt != nodes.end(); nIt++, iNode++ ) { // loop on border nodes
7013         const SMDS_MeshNode* nCur = *nIt;
7014         gp_XYZ segment (nCur->X() - nPrev->X(),
7015                         nCur->Y() - nPrev->Y(),
7016                         nCur->Z() - nPrev->Z());
7017         double segmentLen = segment.Modulus();
7018         bordLength += segmentLen;
7019         param[ iBord ][ iNode ] = bordLength;
7020         nPrev = nCur;
7021       }
7022       // normalize within [0,1]
7023       for ( iNode = 0; iNode < nbNodes[ iBord ]; iNode++ ) {
7024         param[ iBord ][ iNode ] /= bordLength;
7025       }
7026     }
7027
7028     // loop on border segments
7029     const SMDS_MeshNode *nPrev[ 2 ] = { 0, 0 };
7030     int i[ 2 ] = { 0, 0 };
7031     nIt[0] = nSide[0].begin(); eIt[0] = eSide[0].begin();
7032     nIt[1] = nSide[1].begin(); eIt[1] = eSide[1].begin();
7033
7034     TElemOfNodeListMap insertMap;
7035     TElemOfNodeListMap::iterator insertMapIt;
7036     // insertMap is
7037     // key:   elem to insert nodes into
7038     // value: 2 nodes to insert between + nodes to be inserted
7039     do {
7040       bool next[ 2 ] = { false, false };
7041
7042       // find min adjacent segment length after sewing
7043       double nextParam = 10., prevParam = 0;
7044       for ( iBord = 0; iBord < 2; iBord++ ) { // loop on 2 borders
7045         if ( i[ iBord ] + 1 < nbNodes[ iBord ])
7046           nextParam = Min( nextParam, param[iBord][ i[iBord] + 1 ]);
7047         if ( i[ iBord ] > 0 )
7048           prevParam = Max( prevParam, param[iBord][ i[iBord] - 1 ]);
7049       }
7050       double minParam = Min( param[ 0 ][ i[0] ], param[ 1 ][ i[1] ]);
7051       double maxParam = Max( param[ 0 ][ i[0] ], param[ 1 ][ i[1] ]);
7052       double minSegLen = Min( nextParam - minParam, maxParam - prevParam );
7053
7054       // choose to insert or to merge nodes
7055       double du = param[ 1 ][ i[1] ] - param[ 0 ][ i[0] ];
7056       if ( Abs( du ) <= minSegLen * 0.2 ) {
7057         // merge
7058         // ------
7059         nodeGroupsToMerge.push_back( list<const SMDS_MeshNode*>() );
7060         const SMDS_MeshNode* n0 = *nIt[0];
7061         const SMDS_MeshNode* n1 = *nIt[1];
7062         nodeGroupsToMerge.back().push_back( n1 );
7063         nodeGroupsToMerge.back().push_back( n0 );
7064         // position of node of the border changes due to merge
7065         param[ 0 ][ i[0] ] += du;
7066         // move n1 for the sake of elem shape evaluation during insertion.
7067         // n1 will be removed by MergeNodes() anyway
7068         const_cast<SMDS_MeshNode*>( n0 )->setXYZ( n1->X(), n1->Y(), n1->Z() );
7069         next[0] = next[1] = true;
7070       }
7071       else {
7072         // insert
7073         // ------
7074         int intoBord = ( du < 0 ) ? 0 : 1;
7075         const SMDS_MeshElement* elem = *eIt[ intoBord ];
7076         const SMDS_MeshNode*    n1   = nPrev[ intoBord ];
7077         const SMDS_MeshNode*    n2   = *nIt[ intoBord ];
7078         const SMDS_MeshNode*    nIns = *nIt[ 1 - intoBord ];
7079         if ( intoBord == 1 ) {
7080           // move node of the border to be on a link of elem of the side
7081           gp_XYZ p1 (n1->X(), n1->Y(), n1->Z());
7082           gp_XYZ p2 (n2->X(), n2->Y(), n2->Z());
7083           double ratio = du / ( param[ 1 ][ i[1] ] - param[ 1 ][ i[1]-1 ]);
7084           gp_XYZ p = p2 * ( 1 - ratio ) + p1 * ratio;
7085           GetMeshDS()->MoveNode( nIns, p.X(), p.Y(), p.Z() );
7086         }
7087         insertMapIt = insertMap.find( elem );
7088         bool notFound = ( insertMapIt == insertMap.end() );
7089         bool otherLink = ( !notFound && (*insertMapIt).second.front() != n1 );
7090         if ( otherLink ) {
7091           // insert into another link of the same element:
7092           // 1. perform insertion into the other link of the elem
7093           list<const SMDS_MeshNode*> & nodeList = (*insertMapIt).second;
7094           const SMDS_MeshNode* n12 = nodeList.front(); nodeList.pop_front();
7095           const SMDS_MeshNode* n22 = nodeList.front(); nodeList.pop_front();
7096           InsertNodesIntoLink( elem, n12, n22, nodeList, toCreatePolygons );
7097           // 2. perform insertion into the link of adjacent faces
7098           while (true) {
7099             const SMDS_MeshElement* adjElem = findAdjacentFace( n12, n22, elem );
7100             if ( adjElem )
7101               InsertNodesIntoLink( adjElem, n12, n22, nodeList, toCreatePolygons );
7102             else
7103               break;
7104           }
7105           if (toCreatePolyedrs) {
7106             // perform insertion into the links of adjacent volumes
7107             UpdateVolumes(n12, n22, nodeList);
7108           }
7109           // 3. find an element appeared on n1 and n2 after the insertion
7110           insertMap.erase( elem );
7111           elem = findAdjacentFace( n1, n2, 0 );
7112         }
7113         if ( notFound || otherLink ) {
7114           // add element and nodes of the side into the insertMap
7115           insertMapIt = insertMap.insert
7116             ( TElemOfNodeListMap::value_type( elem, list<const SMDS_MeshNode*>() )).first;
7117           (*insertMapIt).second.push_back( n1 );
7118           (*insertMapIt).second.push_back( n2 );
7119         }
7120         // add node to be inserted into elem
7121         (*insertMapIt).second.push_back( nIns );
7122         next[ 1 - intoBord ] = true;
7123       }
7124
7125       // go to the next segment
7126       for ( iBord = 0; iBord < 2; iBord++ ) { // loop on 2 borders
7127         if ( next[ iBord ] ) {
7128           if ( i[ iBord ] != 0 && eIt[ iBord ] != eSide[ iBord ].end())
7129             eIt[ iBord ]++;
7130           nPrev[ iBord ] = *nIt[ iBord ];
7131           nIt[ iBord ]++; i[ iBord ]++;
7132         }
7133       }
7134     }
7135     while ( nIt[0] != nSide[0].end() && nIt[1] != nSide[1].end());
7136
7137     // perform insertion of nodes into elements
7138
7139     for (insertMapIt = insertMap.begin();
7140          insertMapIt != insertMap.end();
7141          insertMapIt++ )
7142     {
7143       const SMDS_MeshElement* elem = (*insertMapIt).first;
7144       list<const SMDS_MeshNode*> & nodeList = (*insertMapIt).second;
7145       const SMDS_MeshNode* n1 = nodeList.front(); nodeList.pop_front();
7146       const SMDS_MeshNode* n2 = nodeList.front(); nodeList.pop_front();
7147
7148       InsertNodesIntoLink( elem, n1, n2, nodeList, toCreatePolygons );
7149
7150       if ( !theSideIsFreeBorder ) {
7151         // look for and insert nodes into the faces adjacent to elem
7152         while (true) {
7153           const SMDS_MeshElement* adjElem = findAdjacentFace( n1, n2, elem );
7154           if ( adjElem )
7155             InsertNodesIntoLink( adjElem, n1, n2, nodeList, toCreatePolygons );
7156           else
7157             break;
7158         }
7159       }
7160       if (toCreatePolyedrs) {
7161         // perform insertion into the links of adjacent volumes
7162         UpdateVolumes(n1, n2, nodeList);
7163       }
7164     }
7165
7166     delete param[0];
7167     delete param[1];
7168   } // end: insert new nodes
7169
7170   MergeNodes ( nodeGroupsToMerge );
7171
7172   return aResult;
7173 }
7174
7175 //=======================================================================
7176 //function : InsertNodesIntoLink
7177 //purpose  : insert theNodesToInsert into theFace between theBetweenNode1
7178 //           and theBetweenNode2 and split theElement
7179 //=======================================================================
7180
7181 void SMESH_MeshEditor::InsertNodesIntoLink(const SMDS_MeshElement*     theFace,
7182                                            const SMDS_MeshNode*        theBetweenNode1,
7183                                            const SMDS_MeshNode*        theBetweenNode2,
7184                                            list<const SMDS_MeshNode*>& theNodesToInsert,
7185                                            const bool                  toCreatePoly)
7186 {
7187   if ( theFace->GetType() != SMDSAbs_Face ) return;
7188
7189   // find indices of 2 link nodes and of the rest nodes
7190   int iNode = 0, il1, il2, i3, i4;
7191   il1 = il2 = i3 = i4 = -1;
7192   //const SMDS_MeshNode* nodes[ theFace->NbNodes() ];
7193   vector<const SMDS_MeshNode*> nodes( theFace->NbNodes() );
7194
7195   if(theFace->IsQuadratic()) {
7196     const SMDS_QuadraticFaceOfNodes* F =
7197       static_cast<const SMDS_QuadraticFaceOfNodes*>(theFace);
7198     // use special nodes iterator
7199     SMDS_NodeIteratorPtr anIter = F->interlacedNodesIterator();
7200     while( anIter->more() ) {
7201       const SMDS_MeshNode* n = anIter->next();
7202       if ( n == theBetweenNode1 )
7203         il1 = iNode;
7204       else if ( n == theBetweenNode2 )
7205         il2 = iNode;
7206       else if ( i3 < 0 )
7207         i3 = iNode;
7208       else
7209         i4 = iNode;
7210       nodes[ iNode++ ] = n;
7211     }
7212   }
7213   else {
7214     SMDS_ElemIteratorPtr nodeIt = theFace->nodesIterator();
7215     while ( nodeIt->more() ) {
7216       const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
7217       if ( n == theBetweenNode1 )
7218         il1 = iNode;
7219       else if ( n == theBetweenNode2 )
7220         il2 = iNode;
7221       else if ( i3 < 0 )
7222         i3 = iNode;
7223       else
7224         i4 = iNode;
7225       nodes[ iNode++ ] = n;
7226     }
7227   }
7228   if ( il1 < 0 || il2 < 0 || i3 < 0 )
7229     return ;
7230
7231   // arrange link nodes to go one after another regarding the face orientation
7232   bool reverse = ( Abs( il2 - il1 ) == 1 ? il2 < il1 : il1 < il2 );
7233   list<const SMDS_MeshNode *> aNodesToInsert = theNodesToInsert;
7234   if ( reverse ) {
7235     iNode = il1;
7236     il1 = il2;
7237     il2 = iNode;
7238     aNodesToInsert.reverse();
7239   }
7240   // check that not link nodes of a quadrangles are in good order
7241   int nbFaceNodes = theFace->NbNodes();
7242   if ( nbFaceNodes == 4 && i4 - i3 != 1 ) {
7243     iNode = i3;
7244     i3 = i4;
7245     i4 = iNode;
7246   }
7247
7248   if (toCreatePoly || theFace->IsPoly()) {
7249
7250     iNode = 0;
7251     vector<const SMDS_MeshNode *> poly_nodes (nbFaceNodes + aNodesToInsert.size());
7252
7253     // add nodes of face up to first node of link
7254     bool isFLN = false;
7255
7256     if(theFace->IsQuadratic()) {
7257       const SMDS_QuadraticFaceOfNodes* F =
7258         static_cast<const SMDS_QuadraticFaceOfNodes*>(theFace);
7259       // use special nodes iterator
7260       SMDS_NodeIteratorPtr anIter = F->interlacedNodesIterator();
7261       while( anIter->more()  && !isFLN ) {
7262         const SMDS_MeshNode* n = anIter->next();
7263         poly_nodes[iNode++] = n;
7264         if (n == nodes[il1]) {
7265           isFLN = true;
7266         }
7267       }
7268       // add nodes to insert
7269       list<const SMDS_MeshNode*>::iterator nIt = aNodesToInsert.begin();
7270       for (; nIt != aNodesToInsert.end(); nIt++) {
7271         poly_nodes[iNode++] = *nIt;
7272       }
7273       // add nodes of face starting from last node of link
7274       while ( anIter->more() ) {
7275         poly_nodes[iNode++] = anIter->next();
7276       }
7277     }
7278     else {
7279       SMDS_ElemIteratorPtr nodeIt = theFace->nodesIterator();
7280       while ( nodeIt->more() && !isFLN ) {
7281         const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
7282         poly_nodes[iNode++] = n;
7283         if (n == nodes[il1]) {
7284           isFLN = true;
7285         }
7286       }
7287       // add nodes to insert
7288       list<const SMDS_MeshNode*>::iterator nIt = aNodesToInsert.begin();
7289       for (; nIt != aNodesToInsert.end(); nIt++) {
7290         poly_nodes[iNode++] = *nIt;
7291       }
7292       // add nodes of face starting from last node of link
7293       while ( nodeIt->more() ) {
7294         const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
7295         poly_nodes[iNode++] = n;
7296       }
7297     }
7298
7299     // edit or replace the face
7300     SMESHDS_Mesh *aMesh = GetMeshDS();
7301
7302     if (theFace->IsPoly()) {
7303       aMesh->ChangePolygonNodes(theFace, poly_nodes);
7304     }
7305     else {
7306       int aShapeId = FindShape( theFace );
7307
7308       SMDS_MeshElement* newElem = aMesh->AddPolygonalFace(poly_nodes);
7309       myLastCreatedElems.Append(newElem);
7310       if ( aShapeId && newElem )
7311         aMesh->SetMeshElementOnShape( newElem, aShapeId );
7312
7313       aMesh->RemoveElement(theFace);
7314     }
7315     return;
7316   }
7317
7318   if( !theFace->IsQuadratic() ) {
7319
7320     // put aNodesToInsert between theBetweenNode1 and theBetweenNode2
7321     int nbLinkNodes = 2 + aNodesToInsert.size();
7322     //const SMDS_MeshNode* linkNodes[ nbLinkNodes ];
7323     vector<const SMDS_MeshNode*> linkNodes( nbLinkNodes );
7324     linkNodes[ 0 ] = nodes[ il1 ];
7325     linkNodes[ nbLinkNodes - 1 ] = nodes[ il2 ];
7326     list<const SMDS_MeshNode*>::iterator nIt = aNodesToInsert.begin();
7327     for ( iNode = 1; nIt != aNodesToInsert.end(); nIt++ ) {
7328       linkNodes[ iNode++ ] = *nIt;
7329     }
7330     // decide how to split a quadrangle: compare possible variants
7331     // and choose which of splits to be a quadrangle
7332     int i1, i2, iSplit, nbSplits = nbLinkNodes - 1, iBestQuad;
7333     if ( nbFaceNodes == 3 ) {
7334       iBestQuad = nbSplits;
7335       i4 = i3;
7336     }
7337     else if ( nbFaceNodes == 4 ) {
7338       SMESH::Controls::NumericalFunctorPtr aCrit( new SMESH::Controls::AspectRatio);
7339       double aBestRate = DBL_MAX;
7340       for ( int iQuad = 0; iQuad < nbSplits; iQuad++ ) {
7341         i1 = 0; i2 = 1;
7342         double aBadRate = 0;
7343         // evaluate elements quality
7344         for ( iSplit = 0; iSplit < nbSplits; iSplit++ ) {
7345           if ( iSplit == iQuad ) {
7346             SMDS_FaceOfNodes quad (linkNodes[ i1++ ],
7347                                    linkNodes[ i2++ ],
7348                                    nodes[ i3 ],
7349                                    nodes[ i4 ]);
7350             aBadRate += getBadRate( &quad, aCrit );
7351           }
7352           else {
7353             SMDS_FaceOfNodes tria (linkNodes[ i1++ ],
7354                                    linkNodes[ i2++ ],
7355                                    nodes[ iSplit < iQuad ? i4 : i3 ]);
7356             aBadRate += getBadRate( &tria, aCrit );
7357           }
7358         }
7359         // choice
7360         if ( aBadRate < aBestRate ) {
7361           iBestQuad = iQuad;
7362           aBestRate = aBadRate;
7363         }
7364       }
7365     }
7366
7367     // create new elements
7368     SMESHDS_Mesh *aMesh = GetMeshDS();
7369     int aShapeId = FindShape( theFace );
7370
7371     i1 = 0; i2 = 1;
7372     for ( iSplit = 0; iSplit < nbSplits - 1; iSplit++ ) {
7373       SMDS_MeshElement* newElem = 0;
7374       if ( iSplit == iBestQuad )
7375         newElem = aMesh->AddFace (linkNodes[ i1++ ],
7376                                   linkNodes[ i2++ ],
7377                                   nodes[ i3 ],
7378                                   nodes[ i4 ]);
7379       else
7380         newElem = aMesh->AddFace (linkNodes[ i1++ ],
7381                                   linkNodes[ i2++ ],
7382                                   nodes[ iSplit < iBestQuad ? i4 : i3 ]);
7383       myLastCreatedElems.Append(newElem);
7384       if ( aShapeId && newElem )
7385         aMesh->SetMeshElementOnShape( newElem, aShapeId );
7386     }
7387
7388     // change nodes of theFace
7389     const SMDS_MeshNode* newNodes[ 4 ];
7390     newNodes[ 0 ] = linkNodes[ i1 ];
7391     newNodes[ 1 ] = linkNodes[ i2 ];
7392     newNodes[ 2 ] = nodes[ iSplit >= iBestQuad ? i3 : i4 ];
7393     newNodes[ 3 ] = nodes[ i4 ];
7394     aMesh->ChangeElementNodes( theFace, newNodes, iSplit == iBestQuad ? 4 : 3 );
7395   } // end if(!theFace->IsQuadratic())
7396   else { // theFace is quadratic
7397     // we have to split theFace on simple triangles and one simple quadrangle
7398     int tmp = il1/2;
7399     int nbshift = tmp*2;
7400     // shift nodes in nodes[] by nbshift
7401     int i,j;
7402     for(i=0; i<nbshift; i++) {
7403       const SMDS_MeshNode* n = nodes[0];
7404       for(j=0; j<nbFaceNodes-1; j++) {
7405         nodes[j] = nodes[j+1];
7406       }
7407       nodes[nbFaceNodes-1] = n;
7408     }
7409     il1 = il1 - nbshift;
7410     // now have to insert nodes between n0 and n1 or n1 and n2 (see below)
7411     //   n0      n1     n2    n0      n1     n2
7412     //     +-----+-----+        +-----+-----+
7413     //      \         /         |           |
7414     //       \       /          |           |
7415     //      n5+     +n3       n7+           +n3
7416     //         \   /            |           |
7417     //          \ /             |           |
7418     //           +              +-----+-----+
7419     //           n4           n6      n5     n4
7420
7421     // create new elements
7422     SMESHDS_Mesh *aMesh = GetMeshDS();
7423     int aShapeId = FindShape( theFace );
7424
7425     int n1,n2,n3;
7426     if(nbFaceNodes==6) { // quadratic triangle
7427       SMDS_MeshElement* newElem =
7428         aMesh->AddFace(nodes[3],nodes[4],nodes[5]);
7429       myLastCreatedElems.Append(newElem);
7430       if ( aShapeId && newElem )
7431         aMesh->SetMeshElementOnShape( newElem, aShapeId );
7432       if(theFace->IsMediumNode(nodes[il1])) {
7433         // create quadrangle
7434         newElem = aMesh->AddFace(nodes[0],nodes[1],nodes[3],nodes[5]);
7435         myLastCreatedElems.Append(newElem);
7436         if ( aShapeId && newElem )
7437           aMesh->SetMeshElementOnShape( newElem, aShapeId );
7438         n1 = 1;
7439         n2 = 2;
7440         n3 = 3;
7441       }
7442       else {
7443         // create quadrangle
7444         newElem = aMesh->AddFace(nodes[1],nodes[2],nodes[3],nodes[5]);
7445         myLastCreatedElems.Append(newElem);
7446         if ( aShapeId && newElem )
7447           aMesh->SetMeshElementOnShape( newElem, aShapeId );
7448         n1 = 0;
7449         n2 = 1;
7450         n3 = 5;
7451       }
7452     }
7453     else { // nbFaceNodes==8 - quadratic quadrangle
7454       SMDS_MeshElement* newElem =
7455         aMesh->AddFace(nodes[3],nodes[4],nodes[5]);
7456       myLastCreatedElems.Append(newElem);
7457       if ( aShapeId && newElem )
7458         aMesh->SetMeshElementOnShape( newElem, aShapeId );
7459       newElem = aMesh->AddFace(nodes[5],nodes[6],nodes[7]);
7460       myLastCreatedElems.Append(newElem);
7461       if ( aShapeId && newElem )
7462         aMesh->SetMeshElementOnShape( newElem, aShapeId );
7463       newElem = aMesh->AddFace(nodes[5],nodes[7],nodes[3]);
7464       myLastCreatedElems.Append(newElem);
7465       if ( aShapeId && newElem )
7466         aMesh->SetMeshElementOnShape( newElem, aShapeId );
7467       if(theFace->IsMediumNode(nodes[il1])) {
7468         // create quadrangle
7469         newElem = aMesh->AddFace(nodes[0],nodes[1],nodes[3],nodes[7]);
7470         myLastCreatedElems.Append(newElem);
7471         if ( aShapeId && newElem )
7472           aMesh->SetMeshElementOnShape( newElem, aShapeId );
7473         n1 = 1;
7474         n2 = 2;
7475         n3 = 3;
7476       }
7477       else {
7478         // create quadrangle
7479         newElem = aMesh->AddFace(nodes[1],nodes[2],nodes[3],nodes[7]);
7480         myLastCreatedElems.Append(newElem);
7481         if ( aShapeId && newElem )
7482           aMesh->SetMeshElementOnShape( newElem, aShapeId );
7483         n1 = 0;
7484         n2 = 1;
7485         n3 = 7;
7486       }
7487     }
7488     // create needed triangles using n1,n2,n3 and inserted nodes
7489     int nbn = 2 + aNodesToInsert.size();
7490     //const SMDS_MeshNode* aNodes[nbn];
7491     vector<const SMDS_MeshNode*> aNodes(nbn);
7492     aNodes[0] = nodes[n1];
7493     aNodes[nbn-1] = nodes[n2];
7494     list<const SMDS_MeshNode*>::iterator nIt = aNodesToInsert.begin();
7495     for ( iNode = 1; nIt != aNodesToInsert.end(); nIt++ ) {
7496       aNodes[iNode++] = *nIt;
7497     }
7498     for(i=1; i<nbn; i++) {
7499       SMDS_MeshElement* newElem =
7500         aMesh->AddFace(aNodes[i-1],aNodes[i],nodes[n3]);
7501       myLastCreatedElems.Append(newElem);
7502       if ( aShapeId && newElem )
7503         aMesh->SetMeshElementOnShape( newElem, aShapeId );
7504     }
7505     // remove old quadratic face
7506     aMesh->RemoveElement(theFace);
7507   }
7508 }
7509
7510 //=======================================================================
7511 //function : UpdateVolumes
7512 //purpose  :
7513 //=======================================================================
7514 void SMESH_MeshEditor::UpdateVolumes (const SMDS_MeshNode*        theBetweenNode1,
7515                                       const SMDS_MeshNode*        theBetweenNode2,
7516                                       list<const SMDS_MeshNode*>& theNodesToInsert)
7517 {
7518   myLastCreatedElems.Clear();
7519   myLastCreatedNodes.Clear();
7520
7521   SMDS_ElemIteratorPtr invElemIt = theBetweenNode1->GetInverseElementIterator(SMDSAbs_Volume);
7522   while (invElemIt->more()) { // loop on inverse elements of theBetweenNode1
7523     const SMDS_MeshElement* elem = invElemIt->next();
7524
7525     // check, if current volume has link theBetweenNode1 - theBetweenNode2
7526     SMDS_VolumeTool aVolume (elem);
7527     if (!aVolume.IsLinked(theBetweenNode1, theBetweenNode2))
7528       continue;
7529
7530     // insert new nodes in all faces of the volume, sharing link theBetweenNode1 - theBetweenNode2
7531     int iface, nbFaces = aVolume.NbFaces();
7532     vector<const SMDS_MeshNode *> poly_nodes;
7533     vector<int> quantities (nbFaces);
7534
7535     for (iface = 0; iface < nbFaces; iface++) {
7536       int nbFaceNodes = aVolume.NbFaceNodes(iface), nbInserted = 0;
7537       // faceNodes will contain (nbFaceNodes + 1) nodes, last = first
7538       const SMDS_MeshNode** faceNodes = aVolume.GetFaceNodes(iface);
7539
7540       for (int inode = 0; inode < nbFaceNodes; inode++) {
7541         poly_nodes.push_back(faceNodes[inode]);
7542
7543         if (nbInserted == 0) {
7544           if (faceNodes[inode] == theBetweenNode1) {
7545             if (faceNodes[inode + 1] == theBetweenNode2) {
7546               nbInserted = theNodesToInsert.size();
7547
7548               // add nodes to insert
7549               list<const SMDS_MeshNode*>::iterator nIt = theNodesToInsert.begin();
7550               for (; nIt != theNodesToInsert.end(); nIt++) {
7551                 poly_nodes.push_back(*nIt);
7552               }
7553             }
7554           }
7555           else if (faceNodes[inode] == theBetweenNode2) {
7556             if (faceNodes[inode + 1] == theBetweenNode1) {
7557               nbInserted = theNodesToInsert.size();
7558
7559               // add nodes to insert in reversed order
7560               list<const SMDS_MeshNode*>::iterator nIt = theNodesToInsert.end();
7561               nIt--;
7562               for (; nIt != theNodesToInsert.begin(); nIt--) {
7563                 poly_nodes.push_back(*nIt);
7564               }
7565               poly_nodes.push_back(*nIt);
7566             }
7567           }
7568           else {
7569           }
7570         }
7571       }
7572       quantities[iface] = nbFaceNodes + nbInserted;
7573     }
7574
7575     // Replace or update the volume
7576     SMESHDS_Mesh *aMesh = GetMeshDS();
7577
7578     if (elem->IsPoly()) {
7579       aMesh->ChangePolyhedronNodes(elem, poly_nodes, quantities);
7580
7581     }
7582     else {
7583       int aShapeId = FindShape( elem );
7584
7585       SMDS_MeshElement* newElem =
7586         aMesh->AddPolyhedralVolume(poly_nodes, quantities);
7587       myLastCreatedElems.Append(newElem);
7588       if (aShapeId && newElem)
7589         aMesh->SetMeshElementOnShape(newElem, aShapeId);
7590
7591       aMesh->RemoveElement(elem);
7592     }
7593   }
7594 }
7595
7596 //=======================================================================
7597 /*!
7598  * \brief Convert elements contained in a submesh to quadratic
7599  * \retval int - nb of checked elements
7600  */
7601 //=======================================================================
7602
7603 int SMESH_MeshEditor::convertElemToQuadratic(SMESHDS_SubMesh *   theSm,
7604                                              SMESH_MesherHelper& theHelper,
7605                                              const bool          theForce3d)
7606 {
7607   int nbElem = 0;
7608   if( !theSm ) return nbElem;
7609
7610   const bool notFromGroups = false;
7611   SMDS_ElemIteratorPtr ElemItr = theSm->GetElements();
7612   while(ElemItr->more())
7613   {
7614     nbElem++;
7615     const SMDS_MeshElement* elem = ElemItr->next();
7616     if( !elem || elem->IsQuadratic() ) continue;
7617
7618     int id = elem->GetID();
7619     int nbNodes = elem->NbNodes();
7620     vector<const SMDS_MeshNode *> aNds (nbNodes);
7621
7622     for(int i = 0; i < nbNodes; i++)
7623     {
7624       aNds[i] = elem->GetNode(i);
7625     }
7626     SMDSAbs_ElementType aType = elem->GetType();
7627
7628     GetMeshDS()->RemoveFreeElement(elem, theSm, notFromGroups);
7629
7630     const SMDS_MeshElement* NewElem = 0;
7631
7632     switch( aType )
7633     {
7634     case SMDSAbs_Edge :
7635       {
7636         NewElem = theHelper.AddEdge(aNds[0], aNds[1], id, theForce3d);
7637         break;
7638       }
7639     case SMDSAbs_Face :
7640       {
7641         switch(nbNodes)
7642         {
7643         case 3:
7644           NewElem = theHelper.AddFace(aNds[0], aNds[1], aNds[2], id, theForce3d);
7645           break;
7646         case 4:
7647           NewElem = theHelper.AddFace(aNds[0], aNds[1], aNds[2], aNds[3], id, theForce3d);
7648           break;
7649         default:
7650           continue;
7651         }
7652         break;
7653       }
7654     case SMDSAbs_Volume :
7655       {
7656         switch(nbNodes)
7657         {
7658         case 4:
7659           NewElem = theHelper.AddVolume(aNds[0], aNds[1], aNds[2], aNds[3], id, theForce3d);
7660           break;
7661         case 5:
7662           NewElem = theHelper.AddVolume(aNds[0], aNds[1], aNds[2], aNds[3], aNds[4], id, theForce3d);
7663           break;
7664         case 6:
7665           NewElem = theHelper.AddVolume(aNds[0], aNds[1], aNds[2], aNds[3], aNds[4], aNds[5], id, theForce3d);
7666           break;
7667         case 8:
7668           NewElem = theHelper.AddVolume(aNds[0], aNds[1], aNds[2], aNds[3],
7669                                         aNds[4], aNds[5], aNds[6], aNds[7], id, theForce3d);
7670           break;
7671         default:
7672           continue;
7673         }
7674         break;
7675       }
7676     default :
7677       continue;
7678     }
7679     ReplaceElemInGroups( elem, NewElem, GetMeshDS());
7680     if( NewElem )
7681       theSm->AddElement( NewElem );
7682   }
7683   return nbElem;
7684 }
7685
7686 //=======================================================================
7687 //function : ConvertToQuadratic
7688 //purpose  :
7689 //=======================================================================
7690 void SMESH_MeshEditor::ConvertToQuadratic(const bool theForce3d)
7691 {
7692   SMESHDS_Mesh* meshDS = GetMeshDS();
7693
7694   SMESH_MesherHelper aHelper(*myMesh);
7695   aHelper.SetIsQuadratic( true );
7696   const bool notFromGroups = false;
7697
7698   int nbCheckedElems = 0;
7699   if ( myMesh->HasShapeToMesh() )
7700   {
7701     if ( SMESH_subMesh *aSubMesh = myMesh->GetSubMeshContaining(myMesh->GetShapeToMesh()))
7702     {
7703       SMESH_subMeshIteratorPtr smIt = aSubMesh->getDependsOnIterator(true,false);
7704       while ( smIt->more() ) {
7705         SMESH_subMesh* sm = smIt->next();
7706         if ( SMESHDS_SubMesh *smDS = sm->GetSubMeshDS() ) {
7707           aHelper.SetSubShape( sm->GetSubShape() );
7708           nbCheckedElems += convertElemToQuadratic(smDS, aHelper, theForce3d);
7709         }
7710       }
7711     }
7712   }
7713   int totalNbElems = meshDS->NbEdges() + meshDS->NbFaces() + meshDS->NbVolumes();
7714   if ( nbCheckedElems < totalNbElems ) // not all elements are in submeshes
7715   {
7716     SMESHDS_SubMesh *smDS = 0;
7717     SMDS_EdgeIteratorPtr aEdgeItr = meshDS->edgesIterator();
7718     while(aEdgeItr->more())
7719     {
7720       const SMDS_MeshEdge* edge = aEdgeItr->next();
7721       if(edge && !edge->IsQuadratic())
7722       {
7723         int id = edge->GetID();
7724         const SMDS_MeshNode* n1 = edge->GetNode(0);
7725         const SMDS_MeshNode* n2 = edge->GetNode(1);
7726
7727         meshDS->RemoveFreeElement(edge, smDS, notFromGroups);
7728
7729         const SMDS_MeshEdge* NewEdge = aHelper.AddEdge(n1, n2, id, theForce3d);
7730         ReplaceElemInGroups( edge, NewEdge, GetMeshDS());
7731       }
7732     }
7733     SMDS_FaceIteratorPtr aFaceItr = meshDS->facesIterator();
7734     while(aFaceItr->more())
7735     {
7736       const SMDS_MeshFace* face = aFaceItr->next();
7737       if(!face || face->IsQuadratic() ) continue;
7738
7739       int id = face->GetID();
7740       int nbNodes = face->NbNodes();
7741       vector<const SMDS_MeshNode *> aNds (nbNodes);
7742
7743       for(int i = 0; i < nbNodes; i++)
7744       {
7745         aNds[i] = face->GetNode(i);
7746       }
7747
7748       meshDS->RemoveFreeElement(face, smDS, notFromGroups);
7749
7750       SMDS_MeshFace * NewFace = 0;
7751       switch(nbNodes)
7752       {
7753       case 3:
7754         NewFace = aHelper.AddFace(aNds[0], aNds[1], aNds[2], id, theForce3d);
7755         break;
7756       case 4:
7757         NewFace = aHelper.AddFace(aNds[0], aNds[1], aNds[2], aNds[3], id, theForce3d);
7758         break;
7759       default:
7760         continue;
7761       }
7762       ReplaceElemInGroups( face, NewFace, GetMeshDS());
7763     }
7764     SMDS_VolumeIteratorPtr aVolumeItr = meshDS->volumesIterator();
7765     while(aVolumeItr->more())
7766     {
7767       const SMDS_MeshVolume* volume = aVolumeItr->next();
7768       if(!volume || volume->IsQuadratic() ) continue;
7769
7770       int id = volume->GetID();
7771       int nbNodes = volume->NbNodes();
7772       vector<const SMDS_MeshNode *> aNds (nbNodes);
7773
7774       for(int i = 0; i < nbNodes; i++)
7775       {
7776         aNds[i] = volume->GetNode(i);
7777       }
7778
7779       meshDS->RemoveFreeElement(volume, smDS, notFromGroups);
7780
7781       SMDS_MeshVolume * NewVolume = 0;
7782       switch(nbNodes)
7783       {
7784       case 4:
7785         NewVolume = aHelper.AddVolume(aNds[0], aNds[1], aNds[2],
7786                                       aNds[3], id, theForce3d );
7787         break;
7788       case 5:
7789         NewVolume = aHelper.AddVolume(aNds[0], aNds[1], aNds[2],
7790                                       aNds[3], aNds[4], id, theForce3d);
7791         break;
7792       case 6:
7793         NewVolume = aHelper.AddVolume(aNds[0], aNds[1], aNds[2],
7794                                       aNds[3], aNds[4], aNds[5], id, theForce3d);
7795         break;
7796       case 8:
7797         NewVolume = aHelper.AddVolume(aNds[0], aNds[1], aNds[2], aNds[3],
7798                                       aNds[4], aNds[5], aNds[6], aNds[7], id, theForce3d);
7799         break;
7800       default:
7801         continue;
7802       }
7803       ReplaceElemInGroups(volume, NewVolume, meshDS);
7804     }
7805   }
7806   if ( !theForce3d ) {
7807     aHelper.SetSubShape(0); // apply to the whole mesh
7808     aHelper.FixQuadraticElements();
7809   }
7810 }
7811
7812 //=======================================================================
7813 /*!
7814  * \brief Convert quadratic elements to linear ones and remove quadratic nodes
7815  * \retval int - nb of checked elements
7816  */
7817 //=======================================================================
7818
7819 int SMESH_MeshEditor::removeQuadElem(SMESHDS_SubMesh *    theSm,
7820                                      SMDS_ElemIteratorPtr theItr,
7821                                      const int            theShapeID)
7822 {
7823   int nbElem = 0;
7824   SMESHDS_Mesh* meshDS = GetMeshDS();
7825   const bool notFromGroups = false;
7826
7827   while( theItr->more() )
7828   {
7829     const SMDS_MeshElement* elem = theItr->next();
7830     nbElem++;
7831     if( elem && elem->IsQuadratic())
7832     {
7833       int id = elem->GetID();
7834       int nbNodes = elem->NbNodes();
7835       vector<const SMDS_MeshNode *> aNds, mediumNodes;
7836       aNds.reserve( nbNodes );
7837       mediumNodes.reserve( nbNodes );
7838
7839       for(int i = 0; i < nbNodes; i++)
7840       {
7841         const SMDS_MeshNode* n = elem->GetNode(i);
7842
7843         if( elem->IsMediumNode( n ) )
7844           mediumNodes.push_back( n );
7845         else
7846           aNds.push_back( n );
7847       }
7848       if( aNds.empty() ) continue;
7849       SMDSAbs_ElementType aType = elem->GetType();
7850
7851       //remove old quadratic element
7852       meshDS->RemoveFreeElement( elem, theSm, notFromGroups );
7853
7854       SMDS_MeshElement * NewElem = AddElement( aNds, aType, false, id );
7855       ReplaceElemInGroups(elem, NewElem, meshDS);
7856       if( theSm && NewElem )
7857         theSm->AddElement( NewElem );
7858
7859       // remove medium nodes
7860       vector<const SMDS_MeshNode*>::iterator nIt = mediumNodes.begin();
7861       for ( ; nIt != mediumNodes.end(); ++nIt ) {
7862         const SMDS_MeshNode* n = *nIt;
7863         if ( n->NbInverseElements() == 0 ) {
7864           if ( n->GetPosition()->GetShapeId() != theShapeID )
7865             meshDS->RemoveFreeNode( n, meshDS->MeshElements
7866                                     ( n->GetPosition()->GetShapeId() ));
7867           else
7868             meshDS->RemoveFreeNode( n, theSm );
7869         }
7870       }
7871     }
7872   }
7873   return nbElem;
7874 }
7875
7876 //=======================================================================
7877 //function : ConvertFromQuadratic
7878 //purpose  :
7879 //=======================================================================
7880 bool  SMESH_MeshEditor::ConvertFromQuadratic()
7881 {
7882   int nbCheckedElems = 0;
7883   if ( myMesh->HasShapeToMesh() )
7884   {
7885     if ( SMESH_subMesh *aSubMesh = myMesh->GetSubMeshContaining(myMesh->GetShapeToMesh()))
7886     {
7887       SMESH_subMeshIteratorPtr smIt = aSubMesh->getDependsOnIterator(true,false);
7888       while ( smIt->more() ) {
7889         SMESH_subMesh* sm = smIt->next();
7890         if ( SMESHDS_SubMesh *smDS = sm->GetSubMeshDS() )
7891           nbCheckedElems += removeQuadElem( smDS, smDS->GetElements(), sm->GetId() );
7892       }
7893     }
7894   }
7895
7896   int totalNbElems =
7897     GetMeshDS()->NbEdges() + GetMeshDS()->NbFaces() + GetMeshDS()->NbVolumes();
7898   if ( nbCheckedElems < totalNbElems ) // not all elements are in submeshes
7899   {
7900     SMESHDS_SubMesh *aSM = 0;
7901     removeQuadElem( aSM, GetMeshDS()->elementsIterator(), 0 );
7902   }
7903
7904   return true;
7905 }
7906
7907 //=======================================================================
7908 //function : SewSideElements
7909 //purpose  :
7910 //=======================================================================
7911
7912 SMESH_MeshEditor::Sew_Error
7913 SMESH_MeshEditor::SewSideElements (TIDSortedElemSet&    theSide1,
7914                                    TIDSortedElemSet&    theSide2,
7915                                    const SMDS_MeshNode* theFirstNode1,
7916                                    const SMDS_MeshNode* theFirstNode2,
7917                                    const SMDS_MeshNode* theSecondNode1,
7918                                    const SMDS_MeshNode* theSecondNode2)
7919 {
7920   myLastCreatedElems.Clear();
7921   myLastCreatedNodes.Clear();
7922
7923   MESSAGE ("::::SewSideElements()");
7924   if ( theSide1.size() != theSide2.size() )
7925     return SEW_DIFF_NB_OF_ELEMENTS;
7926
7927   Sew_Error aResult = SEW_OK;
7928   // Algo:
7929   // 1. Build set of faces representing each side
7930   // 2. Find which nodes of the side 1 to merge with ones on the side 2
7931   // 3. Replace nodes in elements of the side 1 and remove replaced nodes
7932
7933   // =======================================================================
7934   // 1. Build set of faces representing each side:
7935   // =======================================================================
7936   // a. build set of nodes belonging to faces
7937   // b. complete set of faces: find missing fices whose nodes are in set of nodes
7938   // c. create temporary faces representing side of volumes if correspondent
7939   //    face does not exist
7940
7941   SMESHDS_Mesh* aMesh = GetMeshDS();
7942   SMDS_Mesh aTmpFacesMesh;
7943   set<const SMDS_MeshElement*> faceSet1, faceSet2;
7944   set<const SMDS_MeshElement*> volSet1,  volSet2;
7945   set<const SMDS_MeshNode*>    nodeSet1, nodeSet2;
7946   set<const SMDS_MeshElement*> * faceSetPtr[] = { &faceSet1, &faceSet2 };
7947   set<const SMDS_MeshElement*>  * volSetPtr[] = { &volSet1,  &volSet2  };
7948   set<const SMDS_MeshNode*>    * nodeSetPtr[] = { &nodeSet1, &nodeSet2 };
7949   TIDSortedElemSet * elemSetPtr[] = { &theSide1, &theSide2 };
7950   int iSide, iFace, iNode;
7951
7952   for ( iSide = 0; iSide < 2; iSide++ ) {
7953     set<const SMDS_MeshNode*>    * nodeSet = nodeSetPtr[ iSide ];
7954     TIDSortedElemSet * elemSet = elemSetPtr[ iSide ];
7955     set<const SMDS_MeshElement*> * faceSet = faceSetPtr[ iSide ];
7956     set<const SMDS_MeshElement*> * volSet  = volSetPtr [ iSide ];
7957     set<const SMDS_MeshElement*>::iterator vIt;
7958     TIDSortedElemSet::iterator eIt;
7959     set<const SMDS_MeshNode*>::iterator    nIt;
7960
7961     // check that given nodes belong to given elements
7962     const SMDS_MeshNode* n1 = ( iSide == 0 ) ? theFirstNode1 : theFirstNode2;
7963     const SMDS_MeshNode* n2 = ( iSide == 0 ) ? theSecondNode1 : theSecondNode2;
7964     int firstIndex = -1, secondIndex = -1;
7965     for (eIt = elemSet->begin(); eIt != elemSet->end(); eIt++ ) {
7966       const SMDS_MeshElement* elem = *eIt;
7967       if ( firstIndex  < 0 ) firstIndex  = elem->GetNodeIndex( n1 );
7968       if ( secondIndex < 0 ) secondIndex = elem->GetNodeIndex( n2 );
7969       if ( firstIndex > -1 && secondIndex > -1 ) break;
7970     }
7971     if ( firstIndex < 0 || secondIndex < 0 ) {
7972       // we can simply return until temporary faces created
7973       return (iSide == 0 ) ? SEW_BAD_SIDE1_NODES : SEW_BAD_SIDE2_NODES;
7974     }
7975
7976     // -----------------------------------------------------------
7977     // 1a. Collect nodes of existing faces
7978     //     and build set of face nodes in order to detect missing
7979     //     faces corresponing to sides of volumes
7980     // -----------------------------------------------------------
7981
7982     set< set <const SMDS_MeshNode*> > setOfFaceNodeSet;
7983
7984     // loop on the given element of a side
7985     for (eIt = elemSet->begin(); eIt != elemSet->end(); eIt++ ) {
7986       //const SMDS_MeshElement* elem = *eIt;
7987       const SMDS_MeshElement* elem = *eIt;
7988       if ( elem->GetType() == SMDSAbs_Face ) {
7989         faceSet->insert( elem );
7990         set <const SMDS_MeshNode*> faceNodeSet;
7991         SMDS_ElemIteratorPtr nodeIt = elem->nodesIterator();
7992         while ( nodeIt->more() ) {
7993           const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
7994           nodeSet->insert( n );
7995           faceNodeSet.insert( n );
7996         }
7997         setOfFaceNodeSet.insert( faceNodeSet );
7998       }
7999       else if ( elem->GetType() == SMDSAbs_Volume )
8000         volSet->insert( elem );
8001     }
8002     // ------------------------------------------------------------------------------
8003     // 1b. Complete set of faces: find missing fices whose nodes are in set of nodes
8004     // ------------------------------------------------------------------------------
8005
8006     for ( nIt = nodeSet->begin(); nIt != nodeSet->end(); nIt++ ) { // loop on nodes of iSide
8007       SMDS_ElemIteratorPtr fIt = (*nIt)->GetInverseElementIterator(SMDSAbs_Face);
8008       while ( fIt->more() ) { // loop on faces sharing a node
8009         const SMDS_MeshElement* f = fIt->next();
8010         if ( faceSet->find( f ) == faceSet->end() ) {
8011           // check if all nodes are in nodeSet and
8012           // complete setOfFaceNodeSet if they are
8013           set <const SMDS_MeshNode*> faceNodeSet;
8014           SMDS_ElemIteratorPtr nodeIt = f->nodesIterator();
8015           bool allInSet = true;
8016           while ( nodeIt->more() && allInSet ) { // loop on nodes of a face
8017             const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
8018             if ( nodeSet->find( n ) == nodeSet->end() )
8019               allInSet = false;
8020             else
8021               faceNodeSet.insert( n );
8022           }
8023           if ( allInSet ) {
8024             faceSet->insert( f );
8025             setOfFaceNodeSet.insert( faceNodeSet );
8026           }
8027         }
8028       }
8029     }
8030
8031     // -------------------------------------------------------------------------
8032     // 1c. Create temporary faces representing sides of volumes if correspondent
8033     //     face does not exist
8034     // -------------------------------------------------------------------------
8035
8036     if ( !volSet->empty() ) {
8037       //int nodeSetSize = nodeSet->size();
8038
8039       // loop on given volumes
8040       for ( vIt = volSet->begin(); vIt != volSet->end(); vIt++ ) {
8041         SMDS_VolumeTool vol (*vIt);
8042         // loop on volume faces: find free faces
8043         // --------------------------------------
8044         list<const SMDS_MeshElement* > freeFaceList;
8045         for ( iFace = 0; iFace < vol.NbFaces(); iFace++ ) {
8046           if ( !vol.IsFreeFace( iFace ))
8047             continue;
8048           // check if there is already a face with same nodes in a face set
8049           const SMDS_MeshElement* aFreeFace = 0;
8050           const SMDS_MeshNode** fNodes = vol.GetFaceNodes( iFace );
8051           int nbNodes = vol.NbFaceNodes( iFace );
8052           set <const SMDS_MeshNode*> faceNodeSet;
8053           vol.GetFaceNodes( iFace, faceNodeSet );
8054           bool isNewFace = setOfFaceNodeSet.insert( faceNodeSet ).second;
8055           if ( isNewFace ) {
8056             // no such a face is given but it still can exist, check it
8057             if ( nbNodes == 3 ) {
8058               aFreeFace = aMesh->FindFace( fNodes[0],fNodes[1],fNodes[2] );
8059             }
8060             else if ( nbNodes == 4 ) {
8061               aFreeFace = aMesh->FindFace( fNodes[0],fNodes[1],fNodes[2],fNodes[3] );
8062             }
8063             else {
8064               vector<const SMDS_MeshNode *> poly_nodes ( fNodes, & fNodes[nbNodes]);
8065               aFreeFace = aMesh->FindFace(poly_nodes);
8066             }
8067           }
8068           if ( !aFreeFace ) {
8069             // create a temporary face
8070             if ( nbNodes == 3 ) {
8071               aFreeFace = aTmpFacesMesh.AddFace( fNodes[0],fNodes[1],fNodes[2] );
8072             }
8073             else if ( nbNodes == 4 ) {
8074               aFreeFace = aTmpFacesMesh.AddFace( fNodes[0],fNodes[1],fNodes[2],fNodes[3] );
8075             }
8076             else {
8077               vector<const SMDS_MeshNode *> poly_nodes ( fNodes, & fNodes[nbNodes]);
8078               aFreeFace = aTmpFacesMesh.AddPolygonalFace(poly_nodes);
8079             }
8080           }
8081           if ( aFreeFace )
8082             freeFaceList.push_back( aFreeFace );
8083
8084         } // loop on faces of a volume
8085
8086         // choose one of several free faces
8087         // --------------------------------------
8088         if ( freeFaceList.size() > 1 ) {
8089           // choose a face having max nb of nodes shared by other elems of a side
8090           int maxNbNodes = -1/*, nbExcludedFaces = 0*/;
8091           list<const SMDS_MeshElement* >::iterator fIt = freeFaceList.begin();
8092           while ( fIt != freeFaceList.end() ) { // loop on free faces
8093             int nbSharedNodes = 0;
8094             SMDS_ElemIteratorPtr nodeIt = (*fIt)->nodesIterator();
8095             while ( nodeIt->more() ) { // loop on free face nodes
8096               const SMDS_MeshNode* n =
8097                 static_cast<const SMDS_MeshNode*>( nodeIt->next() );
8098               SMDS_ElemIteratorPtr invElemIt = n->GetInverseElementIterator();
8099               while ( invElemIt->more() ) {
8100                 const SMDS_MeshElement* e = invElemIt->next();
8101                 if ( faceSet->find( e ) != faceSet->end() )
8102                   nbSharedNodes++;
8103                 if ( elemSet->find( e ) != elemSet->end() )
8104                   nbSharedNodes++;
8105               }
8106             }
8107             if ( nbSharedNodes >= maxNbNodes ) {
8108               maxNbNodes = nbSharedNodes;
8109               fIt++;
8110             }
8111             else
8112               freeFaceList.erase( fIt++ ); // here fIt++ occures before erase
8113           }
8114           if ( freeFaceList.size() > 1 )
8115           {
8116             // could not choose one face, use another way
8117             // choose a face most close to the bary center of the opposite side
8118             gp_XYZ aBC( 0., 0., 0. );
8119             set <const SMDS_MeshNode*> addedNodes;
8120             TIDSortedElemSet * elemSet2 = elemSetPtr[ 1 - iSide ];
8121             eIt = elemSet2->begin();
8122             for ( eIt = elemSet2->begin(); eIt != elemSet2->end(); eIt++ ) {
8123               SMDS_ElemIteratorPtr nodeIt = (*eIt)->nodesIterator();
8124               while ( nodeIt->more() ) { // loop on free face nodes
8125                 const SMDS_MeshNode* n =
8126                   static_cast<const SMDS_MeshNode*>( nodeIt->next() );
8127                 if ( addedNodes.insert( n ).second )
8128                   aBC += gp_XYZ( n->X(),n->Y(),n->Z() );
8129               }
8130             }
8131             aBC /= addedNodes.size();
8132             double minDist = DBL_MAX;
8133             fIt = freeFaceList.begin();
8134             while ( fIt != freeFaceList.end() ) { // loop on free faces
8135               double dist = 0;
8136               SMDS_ElemIteratorPtr nodeIt = (*fIt)->nodesIterator();
8137               while ( nodeIt->more() ) { // loop on free face nodes
8138                 const SMDS_MeshNode* n =
8139                   static_cast<const SMDS_MeshNode*>( nodeIt->next() );
8140                 gp_XYZ p( n->X(),n->Y(),n->Z() );
8141                 dist += ( aBC - p ).SquareModulus();
8142               }
8143               if ( dist < minDist ) {
8144                 minDist = dist;
8145                 freeFaceList.erase( freeFaceList.begin(), fIt++ );
8146               }
8147               else
8148                 fIt = freeFaceList.erase( fIt++ );
8149             }
8150           }
8151         } // choose one of several free faces of a volume
8152
8153         if ( freeFaceList.size() == 1 ) {
8154           const SMDS_MeshElement* aFreeFace = freeFaceList.front();
8155           faceSet->insert( aFreeFace );
8156           // complete a node set with nodes of a found free face
8157           //           for ( iNode = 0; iNode < ; iNode++ )
8158           //             nodeSet->insert( fNodes[ iNode ] );
8159         }
8160
8161       } // loop on volumes of a side
8162
8163       //       // complete a set of faces if new nodes in a nodeSet appeared
8164       //       // ----------------------------------------------------------
8165       //       if ( nodeSetSize != nodeSet->size() ) {
8166       //         for ( ; nIt != nodeSet->end(); nIt++ ) { // loop on nodes of iSide
8167       //           SMDS_ElemIteratorPtr fIt = (*nIt)->GetInverseElementIterator(SMDSAbs_Face);
8168       //           while ( fIt->more() ) { // loop on faces sharing a node
8169       //             const SMDS_MeshElement* f = fIt->next();
8170       //             if ( faceSet->find( f ) == faceSet->end() ) {
8171       //               // check if all nodes are in nodeSet and
8172       //               // complete setOfFaceNodeSet if they are
8173       //               set <const SMDS_MeshNode*> faceNodeSet;
8174       //               SMDS_ElemIteratorPtr nodeIt = f->nodesIterator();
8175       //               bool allInSet = true;
8176       //               while ( nodeIt->more() && allInSet ) { // loop on nodes of a face
8177       //                 const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
8178       //                 if ( nodeSet->find( n ) == nodeSet->end() )
8179       //                   allInSet = false;
8180       //                 else
8181       //                   faceNodeSet.insert( n );
8182       //               }
8183       //               if ( allInSet ) {
8184       //                 faceSet->insert( f );
8185       //                 setOfFaceNodeSet.insert( faceNodeSet );
8186       //               }
8187       //             }
8188       //           }
8189       //         }
8190       //       }
8191     } // Create temporary faces, if there are volumes given
8192   } // loop on sides
8193
8194   if ( faceSet1.size() != faceSet2.size() ) {
8195     // delete temporary faces: they are in reverseElements of actual nodes
8196     SMDS_FaceIteratorPtr tmpFaceIt = aTmpFacesMesh.facesIterator();
8197     while ( tmpFaceIt->more() )
8198       aTmpFacesMesh.RemoveElement( tmpFaceIt->next() );
8199     MESSAGE("Diff nb of faces");
8200     return SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
8201   }
8202
8203   // ============================================================
8204   // 2. Find nodes to merge:
8205   //              bind a node to remove to a node to put instead
8206   // ============================================================
8207
8208   TNodeNodeMap nReplaceMap; // bind a node to remove to a node to put instead
8209   if ( theFirstNode1 != theFirstNode2 )
8210     nReplaceMap.insert( TNodeNodeMap::value_type( theFirstNode1, theFirstNode2 ));
8211   if ( theSecondNode1 != theSecondNode2 )
8212     nReplaceMap.insert( TNodeNodeMap::value_type( theSecondNode1, theSecondNode2 ));
8213
8214   LinkID_Gen aLinkID_Gen( GetMeshDS() );
8215   set< long > linkIdSet; // links to process
8216   linkIdSet.insert( aLinkID_Gen.GetLinkID( theFirstNode1, theSecondNode1 ));
8217
8218   typedef pair< const SMDS_MeshNode*, const SMDS_MeshNode* > NLink;
8219   list< NLink > linkList[2];
8220   linkList[0].push_back( NLink( theFirstNode1, theSecondNode1 ));
8221   linkList[1].push_back( NLink( theFirstNode2, theSecondNode2 ));
8222   // loop on links in linkList; find faces by links and append links
8223   // of the found faces to linkList
8224   list< NLink >::iterator linkIt[] = { linkList[0].begin(), linkList[1].begin() } ;
8225   for ( ; linkIt[0] != linkList[0].end(); linkIt[0]++, linkIt[1]++ ) {
8226     NLink link[] = { *linkIt[0], *linkIt[1] };
8227     long linkID = aLinkID_Gen.GetLinkID( link[0].first, link[0].second );
8228     if ( linkIdSet.find( linkID ) == linkIdSet.end() )
8229       continue;
8230
8231     // by links, find faces in the face sets,
8232     // and find indices of link nodes in the found faces;
8233     // in a face set, there is only one or no face sharing a link
8234     // ---------------------------------------------------------------
8235
8236     const SMDS_MeshElement* face[] = { 0, 0 };
8237     //const SMDS_MeshNode* faceNodes[ 2 ][ 5 ];
8238     vector<const SMDS_MeshNode*> fnodes1(9);
8239     vector<const SMDS_MeshNode*> fnodes2(9);
8240     //const SMDS_MeshNode* notLinkNodes[ 2 ][ 2 ] = {{ 0, 0 },{ 0, 0 }} ;
8241     vector<const SMDS_MeshNode*> notLinkNodes1(6);
8242     vector<const SMDS_MeshNode*> notLinkNodes2(6);
8243     int iLinkNode[2][2];
8244     for ( iSide = 0; iSide < 2; iSide++ ) { // loop on 2 sides
8245       const SMDS_MeshNode* n1 = link[iSide].first;
8246       const SMDS_MeshNode* n2 = link[iSide].second;
8247       set<const SMDS_MeshElement*> * faceSet = faceSetPtr[ iSide ];
8248       set< const SMDS_MeshElement* > fMap;
8249       for ( int i = 0; i < 2; i++ ) { // loop on 2 nodes of a link
8250         const SMDS_MeshNode* n = i ? n1 : n2; // a node of a link
8251         SMDS_ElemIteratorPtr fIt = n->GetInverseElementIterator(SMDSAbs_Face);
8252         while ( fIt->more() ) { // loop on faces sharing a node
8253           const SMDS_MeshElement* f = fIt->next();
8254           if (faceSet->find( f ) != faceSet->end() && // f is in face set
8255               ! fMap.insert( f ).second ) // f encounters twice
8256           {
8257             if ( face[ iSide ] ) {
8258               MESSAGE( "2 faces per link " );
8259               aResult = iSide ? SEW_BAD_SIDE2_NODES : SEW_BAD_SIDE1_NODES;
8260               break;
8261             }
8262             face[ iSide ] = f;
8263             faceSet->erase( f );
8264             // get face nodes and find ones of a link
8265             iNode = 0;
8266             int nbl = -1;
8267             if(f->IsPoly()) {
8268               if(iSide==0) {
8269                 fnodes1.resize(f->NbNodes()+1);
8270                 notLinkNodes1.resize(f->NbNodes()-2);
8271               }
8272               else {
8273                 fnodes2.resize(f->NbNodes()+1);
8274                 notLinkNodes2.resize(f->NbNodes()-2);
8275               }
8276             }
8277             if(!f->IsQuadratic()) {
8278               SMDS_ElemIteratorPtr nIt = f->nodesIterator();
8279               while ( nIt->more() ) {
8280                 const SMDS_MeshNode* n =
8281                   static_cast<const SMDS_MeshNode*>( nIt->next() );
8282                 if ( n == n1 ) {
8283                   iLinkNode[ iSide ][ 0 ] = iNode;
8284                 }
8285                 else if ( n == n2 ) {
8286                   iLinkNode[ iSide ][ 1 ] = iNode;
8287                 }
8288                 //else if ( notLinkNodes[ iSide ][ 0 ] )
8289                 //  notLinkNodes[ iSide ][ 1 ] = n;
8290                 //else
8291                 //  notLinkNodes[ iSide ][ 0 ] = n;
8292                 else {
8293                   nbl++;
8294                   if(iSide==0)
8295                     notLinkNodes1[nbl] = n;
8296                   //notLinkNodes1.push_back(n);
8297                   else
8298                     notLinkNodes2[nbl] = n;
8299                   //notLinkNodes2.push_back(n);
8300                 }
8301                 //faceNodes[ iSide ][ iNode++ ] = n;
8302                 if(iSide==0) {
8303                   fnodes1[iNode++] = n;
8304                 }
8305                 else {
8306                   fnodes2[iNode++] = n;
8307                 }
8308               }
8309             }
8310             else { // f->IsQuadratic()
8311               const SMDS_QuadraticFaceOfNodes* F =
8312                 static_cast<const SMDS_QuadraticFaceOfNodes*>(f);
8313               // use special nodes iterator
8314               SMDS_NodeIteratorPtr anIter = F->interlacedNodesIterator();
8315               while ( anIter->more() ) {
8316                 const SMDS_MeshNode* n =
8317                   static_cast<const SMDS_MeshNode*>( anIter->next() );
8318                 if ( n == n1 ) {
8319                   iLinkNode[ iSide ][ 0 ] = iNode;
8320                 }
8321                 else if ( n == n2 ) {
8322                   iLinkNode[ iSide ][ 1 ] = iNode;
8323                 }
8324                 else {
8325                   nbl++;
8326                   if(iSide==0) {
8327                     notLinkNodes1[nbl] = n;
8328                   }
8329                   else {
8330                     notLinkNodes2[nbl] = n;
8331                   }
8332                 }
8333                 if(iSide==0) {
8334                   fnodes1[iNode++] = n;
8335                 }
8336                 else {
8337                   fnodes2[iNode++] = n;
8338                 }
8339               }
8340             }
8341             //faceNodes[ iSide ][ iNode ] = faceNodes[ iSide ][ 0 ];
8342             if(iSide==0) {
8343               fnodes1[iNode] = fnodes1[0];
8344             }
8345             else {
8346               fnodes2[iNode] = fnodes1[0];
8347             }
8348           }
8349         }
8350       }
8351     }
8352
8353     // check similarity of elements of the sides
8354     if (aResult == SEW_OK && ( face[0] && !face[1] ) || ( !face[0] && face[1] )) {
8355       MESSAGE("Correspondent face not found on side " << ( face[0] ? 1 : 0 ));
8356       if ( nReplaceMap.size() == 2 ) { // faces on input nodes not found
8357         aResult = ( face[0] ? SEW_BAD_SIDE2_NODES : SEW_BAD_SIDE1_NODES );
8358       }
8359       else {
8360         aResult = SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
8361       }
8362       break; // do not return because it s necessary to remove tmp faces
8363     }
8364
8365     // set nodes to merge
8366     // -------------------
8367
8368     if ( face[0] && face[1] )  {
8369       int nbNodes = face[0]->NbNodes();
8370       if ( nbNodes != face[1]->NbNodes() ) {
8371         MESSAGE("Diff nb of face nodes");
8372         aResult = SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
8373         break; // do not return because it s necessary to remove tmp faces
8374       }
8375       bool reverse[] = { false, false }; // order of notLinkNodes of quadrangle
8376       if ( nbNodes == 3 ) {
8377         //nReplaceMap.insert( TNodeNodeMap::value_type
8378         //                   ( notLinkNodes[0][0], notLinkNodes[1][0] ));
8379         nReplaceMap.insert( TNodeNodeMap::value_type
8380                             ( notLinkNodes1[0], notLinkNodes2[0] ));
8381       }
8382       else {
8383         for ( iSide = 0; iSide < 2; iSide++ ) { // loop on 2 sides
8384           // analyse link orientation in faces
8385           int i1 = iLinkNode[ iSide ][ 0 ];
8386           int i2 = iLinkNode[ iSide ][ 1 ];
8387           reverse[ iSide ] = Abs( i1 - i2 ) == 1 ? i1 > i2 : i2 > i1;
8388           // if notLinkNodes are the first and the last ones, then
8389           // their order does not correspond to the link orientation
8390           if (( i1 == 1 && i2 == 2 ) ||
8391               ( i1 == 2 && i2 == 1 ))
8392             reverse[ iSide ] = !reverse[ iSide ];
8393         }
8394         if ( reverse[0] == reverse[1] ) {
8395           //nReplaceMap.insert( TNodeNodeMap::value_type
8396           //                   ( notLinkNodes[0][0], notLinkNodes[1][0] ));
8397           //nReplaceMap.insert( TNodeNodeMap::value_type
8398           //                   ( notLinkNodes[0][1], notLinkNodes[1][1] ));
8399           for(int nn=0; nn<nbNodes-2; nn++) {
8400             nReplaceMap.insert( TNodeNodeMap::value_type
8401                                 ( notLinkNodes1[nn], notLinkNodes2[nn] ));
8402           }
8403         }
8404         else {
8405           //nReplaceMap.insert( TNodeNodeMap::value_type
8406           //                   ( notLinkNodes[0][0], notLinkNodes[1][1] ));
8407           //nReplaceMap.insert( TNodeNodeMap::value_type
8408           //                   ( notLinkNodes[0][1], notLinkNodes[1][0] ));
8409           for(int nn=0; nn<nbNodes-2; nn++) {
8410             nReplaceMap.insert( TNodeNodeMap::value_type
8411                                 ( notLinkNodes1[nn], notLinkNodes2[nbNodes-3-nn] ));
8412           }
8413         }
8414       }
8415
8416       // add other links of the faces to linkList
8417       // -----------------------------------------
8418
8419       //const SMDS_MeshNode** nodes = faceNodes[ 0 ];
8420       for ( iNode = 0; iNode < nbNodes; iNode++ )  {
8421         //linkID = aLinkID_Gen.GetLinkID( nodes[iNode], nodes[iNode+1] );
8422         linkID = aLinkID_Gen.GetLinkID( fnodes1[iNode], fnodes1[iNode+1] );
8423         pair< set<long>::iterator, bool > iter_isnew = linkIdSet.insert( linkID );
8424         if ( !iter_isnew.second ) { // already in a set: no need to process
8425           linkIdSet.erase( iter_isnew.first );
8426         }
8427         else // new in set == encountered for the first time: add
8428         {
8429           //const SMDS_MeshNode* n1 = nodes[ iNode ];
8430           //const SMDS_MeshNode* n2 = nodes[ iNode + 1];
8431           const SMDS_MeshNode* n1 = fnodes1[ iNode ];
8432           const SMDS_MeshNode* n2 = fnodes1[ iNode + 1];
8433           linkList[0].push_back ( NLink( n1, n2 ));
8434           linkList[1].push_back ( NLink( nReplaceMap[n1], nReplaceMap[n2] ));
8435         }
8436       }
8437     } // 2 faces found
8438   } // loop on link lists
8439
8440   if ( aResult == SEW_OK &&
8441        ( linkIt[0] != linkList[0].end() ||
8442          !faceSetPtr[0]->empty() || !faceSetPtr[1]->empty() )) {
8443     MESSAGE( (linkIt[0] != linkList[0].end()) <<" "<< (faceSetPtr[0]->empty()) <<
8444              " " << (faceSetPtr[1]->empty()));
8445     aResult = SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
8446   }
8447
8448   // ====================================================================
8449   // 3. Replace nodes in elements of the side 1 and remove replaced nodes
8450   // ====================================================================
8451
8452   // delete temporary faces: they are in reverseElements of actual nodes
8453   SMDS_FaceIteratorPtr tmpFaceIt = aTmpFacesMesh.facesIterator();
8454   while ( tmpFaceIt->more() )
8455     aTmpFacesMesh.RemoveElement( tmpFaceIt->next() );
8456
8457   if ( aResult != SEW_OK)
8458     return aResult;
8459
8460   list< int > nodeIDsToRemove/*, elemIDsToRemove*/;
8461   // loop on nodes replacement map
8462   TNodeNodeMap::iterator nReplaceMapIt = nReplaceMap.begin(), nnIt;
8463   for ( ; nReplaceMapIt != nReplaceMap.end(); nReplaceMapIt++ )
8464     if ( (*nReplaceMapIt).first != (*nReplaceMapIt).second ) {
8465       const SMDS_MeshNode* nToRemove = (*nReplaceMapIt).first;
8466       nodeIDsToRemove.push_back( nToRemove->GetID() );
8467       // loop on elements sharing nToRemove
8468       SMDS_ElemIteratorPtr invElemIt = nToRemove->GetInverseElementIterator();
8469       while ( invElemIt->more() ) {
8470         const SMDS_MeshElement* e = invElemIt->next();
8471         // get a new suite of nodes: make replacement
8472         int nbReplaced = 0, i = 0, nbNodes = e->NbNodes();
8473         vector< const SMDS_MeshNode*> nodes( nbNodes );
8474         SMDS_ElemIteratorPtr nIt = e->nodesIterator();
8475         while ( nIt->more() ) {
8476           const SMDS_MeshNode* n =
8477             static_cast<const SMDS_MeshNode*>( nIt->next() );
8478           nnIt = nReplaceMap.find( n );
8479           if ( nnIt != nReplaceMap.end() ) {
8480             nbReplaced++;
8481             n = (*nnIt).second;
8482           }
8483           nodes[ i++ ] = n;
8484         }
8485         //       if ( nbReplaced == nbNodes && e->GetType() == SMDSAbs_Face )
8486         //         elemIDsToRemove.push_back( e->GetID() );
8487         //       else
8488         if ( nbReplaced )
8489           aMesh->ChangeElementNodes( e, & nodes[0], nbNodes );
8490       }
8491     }
8492
8493   Remove( nodeIDsToRemove, true );
8494
8495   return aResult;
8496 }
8497
8498 //================================================================================
8499 /*!
8500  * \brief Find corresponding nodes in two sets of faces
8501  * \param theSide1 - first face set
8502  * \param theSide2 - second first face
8503  * \param theFirstNode1 - a boundary node of set 1
8504  * \param theFirstNode2 - a node of set 2 corresponding to theFirstNode1
8505  * \param theSecondNode1 - a boundary node of set 1 linked with theFirstNode1
8506  * \param theSecondNode2 - a node of set 2 corresponding to theSecondNode1
8507  * \param nReplaceMap - output map of corresponding nodes
8508  * \retval bool  - is a success or not
8509  */
8510 //================================================================================
8511
8512 #ifdef _DEBUG_
8513 //#define DEBUG_MATCHING_NODES
8514 #endif
8515
8516 SMESH_MeshEditor::Sew_Error
8517 SMESH_MeshEditor::FindMatchingNodes(set<const SMDS_MeshElement*>& theSide1,
8518                                     set<const SMDS_MeshElement*>& theSide2,
8519                                     const SMDS_MeshNode*          theFirstNode1,
8520                                     const SMDS_MeshNode*          theFirstNode2,
8521                                     const SMDS_MeshNode*          theSecondNode1,
8522                                     const SMDS_MeshNode*          theSecondNode2,
8523                                     TNodeNodeMap &                nReplaceMap)
8524 {
8525   set<const SMDS_MeshElement*> * faceSetPtr[] = { &theSide1, &theSide2 };
8526
8527   nReplaceMap.clear();
8528   if ( theFirstNode1 != theFirstNode2 )
8529     nReplaceMap.insert( make_pair( theFirstNode1, theFirstNode2 ));
8530   if ( theSecondNode1 != theSecondNode2 )
8531     nReplaceMap.insert( make_pair( theSecondNode1, theSecondNode2 ));
8532
8533   set< SMESH_TLink > linkSet; // set of nodes where order of nodes is ignored
8534   linkSet.insert( SMESH_TLink( theFirstNode1, theSecondNode1 ));
8535
8536   list< NLink > linkList[2];
8537   linkList[0].push_back( NLink( theFirstNode1, theSecondNode1 ));
8538   linkList[1].push_back( NLink( theFirstNode2, theSecondNode2 ));
8539
8540   // loop on links in linkList; find faces by links and append links
8541   // of the found faces to linkList
8542   list< NLink >::iterator linkIt[] = { linkList[0].begin(), linkList[1].begin() } ;
8543   for ( ; linkIt[0] != linkList[0].end(); linkIt[0]++, linkIt[1]++ ) {
8544     NLink link[] = { *linkIt[0], *linkIt[1] };
8545     if ( linkSet.find( link[0] ) == linkSet.end() )
8546       continue;
8547
8548     // by links, find faces in the face sets,
8549     // and find indices of link nodes in the found faces;
8550     // in a face set, there is only one or no face sharing a link
8551     // ---------------------------------------------------------------
8552
8553     const SMDS_MeshElement* face[] = { 0, 0 };
8554     list<const SMDS_MeshNode*> notLinkNodes[2];
8555     //bool reverse[] = { false, false }; // order of notLinkNodes
8556     int nbNodes[2];
8557     for ( int iSide = 0; iSide < 2; iSide++ ) // loop on 2 sides
8558     {
8559       const SMDS_MeshNode* n1 = link[iSide].first;
8560       const SMDS_MeshNode* n2 = link[iSide].second;
8561       set<const SMDS_MeshElement*> * faceSet = faceSetPtr[ iSide ];
8562       set< const SMDS_MeshElement* > facesOfNode1;
8563       for ( int iNode = 0; iNode < 2; iNode++ ) // loop on 2 nodes of a link
8564       {
8565         // during a loop of the first node, we find all faces around n1,
8566         // during a loop of the second node, we find one face sharing both n1 and n2
8567         const SMDS_MeshNode* n = iNode ? n1 : n2; // a node of a link
8568         SMDS_ElemIteratorPtr fIt = n->GetInverseElementIterator(SMDSAbs_Face);
8569         while ( fIt->more() ) { // loop on faces sharing a node
8570           const SMDS_MeshElement* f = fIt->next();
8571           if (faceSet->find( f ) != faceSet->end() && // f is in face set
8572               ! facesOfNode1.insert( f ).second ) // f encounters twice
8573           {
8574             if ( face[ iSide ] ) {
8575               MESSAGE( "2 faces per link " );
8576               return ( iSide ? SEW_BAD_SIDE2_NODES : SEW_BAD_SIDE1_NODES );
8577             }
8578             face[ iSide ] = f;
8579             faceSet->erase( f );
8580
8581             // get not link nodes
8582             int nbN = f->NbNodes();
8583             if ( f->IsQuadratic() )
8584               nbN /= 2;
8585             nbNodes[ iSide ] = nbN;
8586             list< const SMDS_MeshNode* > & nodes = notLinkNodes[ iSide ];
8587             int i1 = f->GetNodeIndex( n1 );
8588             int i2 = f->GetNodeIndex( n2 );
8589             int iEnd = nbN, iBeg = -1, iDelta = 1;
8590             bool reverse = ( Abs( i1 - i2 ) == 1 ? i1 > i2 : i2 > i1 );
8591             if ( reverse ) {
8592               std::swap( iEnd, iBeg ); iDelta = -1;
8593             }
8594             int i = i2;
8595             while ( true ) {
8596               i += iDelta;
8597               if ( i == iEnd ) i = iBeg + iDelta;
8598               if ( i == i1 ) break;
8599               nodes.push_back ( f->GetNode( i ) );
8600             }
8601           }
8602         }
8603       }
8604     }
8605     // check similarity of elements of the sides
8606     if (( face[0] && !face[1] ) || ( !face[0] && face[1] )) {
8607       MESSAGE("Correspondent face not found on side " << ( face[0] ? 1 : 0 ));
8608       if ( nReplaceMap.size() == 2 ) { // faces on input nodes not found
8609         return ( face[0] ? SEW_BAD_SIDE2_NODES : SEW_BAD_SIDE1_NODES );
8610       }
8611       else {
8612         return SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
8613       }
8614     }
8615
8616     // set nodes to merge
8617     // -------------------
8618
8619     if ( face[0] && face[1] )  {
8620       if ( nbNodes[0] != nbNodes[1] ) {
8621         MESSAGE("Diff nb of face nodes");
8622         return SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
8623       }
8624 #ifdef DEBUG_MATCHING_NODES
8625       MESSAGE ( " Link 1: " << link[0].first->GetID() <<" "<< link[0].second->GetID()
8626                 << " F 1: " << face[0] << "| Link 2: " << link[1].first->GetID() <<" "
8627                 << link[1].second->GetID() << " F 2: " << face[1] << " | Bind: " ) ;
8628 #endif
8629       int nbN = nbNodes[0];
8630       {
8631         list<const SMDS_MeshNode*>::iterator n1 = notLinkNodes[0].begin();
8632         list<const SMDS_MeshNode*>::iterator n2 = notLinkNodes[1].begin();
8633         for ( int i = 0 ; i < nbN - 2; ++i ) {
8634 #ifdef DEBUG_MATCHING_NODES
8635           MESSAGE ( (*n1)->GetID() << " to " << (*n2)->GetID() );
8636 #endif
8637           nReplaceMap.insert( make_pair( *(n1++), *(n2++) ));
8638         }
8639       }
8640
8641       // add other links of the face 1 to linkList
8642       // -----------------------------------------
8643
8644       const SMDS_MeshElement* f0 = face[0];
8645       const SMDS_MeshNode* n1 = f0->GetNode( nbN - 1 );
8646       for ( int i = 0; i < nbN; i++ )
8647       {
8648         const SMDS_MeshNode* n2 = f0->GetNode( i );
8649         pair< set< SMESH_TLink >::iterator, bool > iter_isnew =
8650           linkSet.insert( SMESH_TLink( n1, n2 ));
8651         if ( !iter_isnew.second ) { // already in a set: no need to process
8652           linkSet.erase( iter_isnew.first );
8653         }
8654         else // new in set == encountered for the first time: add
8655         {
8656 #ifdef DEBUG_MATCHING_NODES
8657           MESSAGE ( "Add link 1: " << n1->GetID() << " " << n2->GetID() << " "
8658                     << " | link 2: " << nReplaceMap[n1]->GetID() << " " << nReplaceMap[n2]->GetID() << " " );
8659 #endif
8660           linkList[0].push_back ( NLink( n1, n2 ));
8661           linkList[1].push_back ( NLink( nReplaceMap[n1], nReplaceMap[n2] ));
8662         }
8663         n1 = n2;
8664       }
8665     } // 2 faces found
8666   } // loop on link lists
8667
8668   return SEW_OK;
8669 }
8670
8671 //================================================================================
8672 /*!
8673   \brief Creates a hole in a mesh by doubling the nodes of some particular elements
8674   \param theElems - the list of elements (edges or faces) to be replicated
8675   The nodes for duplication could be found from these elements
8676   \param theNodesNot - list of nodes to NOT replicate
8677   \param theAffectedElems - the list of elements (cells and edges) to which the 
8678   replicated nodes should be associated to.
8679   \return TRUE if operation has been completed successfully, FALSE otherwise
8680 */
8681 //================================================================================
8682
8683 bool SMESH_MeshEditor::DoubleNodes( const TIDSortedElemSet& theElems,
8684                                     const TIDSortedElemSet& theNodesNot,
8685                                     const TIDSortedElemSet& theAffectedElems )
8686 {
8687   myLastCreatedElems.Clear();
8688   myLastCreatedNodes.Clear();
8689
8690   if ( theElems.size() == 0 )
8691     return false;
8692
8693   SMESHDS_Mesh* aMeshDS = GetMeshDS();
8694   if ( !aMeshDS )
8695     return false;
8696
8697   bool res = false;
8698   std::map< const SMDS_MeshNode*, const SMDS_MeshNode* > anOldNodeToNewNode;
8699   // duplicate elements and nodes
8700   res = doubleNodes( aMeshDS, theElems, theNodesNot, anOldNodeToNewNode, true );
8701   // replce nodes by duplications
8702   res = doubleNodes( aMeshDS, theAffectedElems, theNodesNot, anOldNodeToNewNode, false );
8703   return res;
8704 }
8705
8706 //================================================================================
8707 /*!
8708   \brief Creates a hole in a mesh by doubling the nodes of some particular elements
8709   \param theMeshDS - mesh instance
8710   \param theElems - the elements replicated or modified (nodes should be changed)
8711   \param theNodesNot - nodes to NOT replicate
8712   \param theNodeNodeMap - relation of old node to new created node
8713   \param theIsDoubleElem - flag os to replicate element or modify
8714   \return TRUE if operation has been completed successfully, FALSE otherwise
8715 */
8716 //================================================================================
8717
8718 bool SMESH_MeshEditor::doubleNodes( SMESHDS_Mesh*     theMeshDS,
8719                                     const TIDSortedElemSet& theElems,
8720                                     const TIDSortedElemSet& theNodesNot,
8721                                     std::map< const SMDS_MeshNode*,
8722                                     const SMDS_MeshNode* >& theNodeNodeMap,
8723                                     const bool theIsDoubleElem )
8724 {
8725   // iterate on through element and duplicate them (by nodes duplication)
8726   bool res = false;
8727   TIDSortedElemSet::const_iterator elemItr = theElems.begin();
8728   for ( ;  elemItr != theElems.end(); ++elemItr )
8729   {
8730     const SMDS_MeshElement* anElem = *elemItr;
8731     if (!anElem)
8732       continue;
8733
8734     bool isDuplicate = false;
8735     // duplicate nodes to duplicate element
8736     std::vector<const SMDS_MeshNode*> newNodes( anElem->NbNodes() );
8737     SMDS_ElemIteratorPtr anIter = anElem->nodesIterator();
8738     int ind = 0;
8739     while ( anIter->more() ) 
8740     { 
8741
8742       SMDS_MeshNode* aCurrNode = (SMDS_MeshNode*)anIter->next();
8743       SMDS_MeshNode* aNewNode = aCurrNode;
8744       if ( theNodeNodeMap.find( aCurrNode ) != theNodeNodeMap.end() )
8745         aNewNode = (SMDS_MeshNode*)theNodeNodeMap[ aCurrNode ];
8746       else if ( theIsDoubleElem && theNodesNot.find( aCurrNode ) == theNodesNot.end() )
8747       {
8748         // duplicate node
8749         aNewNode = theMeshDS->AddNode( aCurrNode->X(), aCurrNode->Y(), aCurrNode->Z() );
8750         theNodeNodeMap[ aCurrNode ] = aNewNode;
8751         myLastCreatedNodes.Append( aNewNode );
8752       }
8753       isDuplicate |= (aCurrNode != aNewNode);
8754       newNodes[ ind++ ] = aNewNode;
8755     }
8756     if ( !isDuplicate )
8757       continue;
8758
8759     if ( theIsDoubleElem )
8760       myLastCreatedElems.Append( AddElement(newNodes, anElem->GetType(), anElem->IsPoly()) );
8761     else
8762       theMeshDS->ChangeElementNodes( anElem, &newNodes[ 0 ], anElem->NbNodes() );
8763
8764     res = true;
8765   }
8766   return res;
8767 }
8768
8769 //================================================================================
8770 /*!
8771   \brief Creates a hole in a mesh by doubling the nodes of some particular elements
8772   \param theNodes - identifiers of nodes to be doubled
8773   \param theModifiedElems - identifiers of elements to be updated by the new (doubled) 
8774          nodes. If list of element identifiers is empty then nodes are doubled but 
8775          they not assigned to elements
8776   \return TRUE if operation has been completed successfully, FALSE otherwise
8777 */
8778 //================================================================================
8779
8780 bool SMESH_MeshEditor::DoubleNodes( const std::list< int >& theListOfNodes, 
8781                                     const std::list< int >& theListOfModifiedElems )
8782 {
8783   myLastCreatedElems.Clear();
8784   myLastCreatedNodes.Clear();
8785
8786   if ( theListOfNodes.size() == 0 )
8787     return false;
8788
8789   SMESHDS_Mesh* aMeshDS = GetMeshDS();
8790   if ( !aMeshDS )
8791     return false;
8792
8793   // iterate through nodes and duplicate them
8794
8795   std::map< const SMDS_MeshNode*, const SMDS_MeshNode* > anOldNodeToNewNode;
8796
8797   std::list< int >::const_iterator aNodeIter;
8798   for ( aNodeIter = theListOfNodes.begin(); aNodeIter != theListOfNodes.end(); ++aNodeIter )
8799   {
8800     int aCurr = *aNodeIter;
8801     SMDS_MeshNode* aNode = (SMDS_MeshNode*)aMeshDS->FindNode( aCurr );
8802     if ( !aNode )
8803       continue;
8804
8805     // duplicate node
8806
8807     const SMDS_MeshNode* aNewNode = aMeshDS->AddNode( aNode->X(), aNode->Y(), aNode->Z() );
8808     if ( aNewNode )
8809     {
8810       anOldNodeToNewNode[ aNode ] = aNewNode;
8811       myLastCreatedNodes.Append( aNewNode );
8812     }
8813   }
8814
8815   // Create map of new nodes for modified elements
8816
8817   std::map< SMDS_MeshElement*, vector<const SMDS_MeshNode*> > anElemToNodes;
8818
8819   std::list< int >::const_iterator anElemIter;
8820   for ( anElemIter = theListOfModifiedElems.begin(); 
8821         anElemIter != theListOfModifiedElems.end(); ++anElemIter )
8822   {
8823     int aCurr = *anElemIter;
8824     SMDS_MeshElement* anElem = (SMDS_MeshElement*)aMeshDS->FindElement( aCurr );
8825     if ( !anElem )
8826       continue;
8827
8828     vector<const SMDS_MeshNode*> aNodeArr( anElem->NbNodes() );
8829
8830     SMDS_ElemIteratorPtr anIter = anElem->nodesIterator();
8831     int ind = 0;
8832     while ( anIter->more() ) 
8833     { 
8834       SMDS_MeshNode* aCurrNode = (SMDS_MeshNode*)anIter->next();
8835       if ( aCurr && anOldNodeToNewNode.find( aCurrNode ) != anOldNodeToNewNode.end() )
8836       {
8837         const SMDS_MeshNode* aNewNode = anOldNodeToNewNode[ aCurrNode ];
8838         aNodeArr[ ind++ ] = aNewNode;
8839       }
8840       else
8841         aNodeArr[ ind++ ] = aCurrNode;
8842     }
8843     anElemToNodes[ anElem ] = aNodeArr;
8844   }
8845
8846   // Change nodes of elements  
8847
8848   std::map< SMDS_MeshElement*, vector<const SMDS_MeshNode*> >::iterator
8849     anElemToNodesIter = anElemToNodes.begin();
8850   for ( ; anElemToNodesIter != anElemToNodes.end(); ++anElemToNodesIter )
8851   {
8852     const SMDS_MeshElement* anElem = anElemToNodesIter->first;
8853     vector<const SMDS_MeshNode*> aNodeArr = anElemToNodesIter->second;
8854     if ( anElem )
8855       aMeshDS->ChangeElementNodes( anElem, &aNodeArr[ 0 ], anElem->NbNodes() );
8856   }
8857
8858   return true;
8859 }
8860
8861 namespace {
8862
8863   //================================================================================
8864   /*!
8865   \brief Check if element located inside shape
8866   \return TRUE if IN or ON shape, FALSE otherwise
8867   */
8868   //================================================================================
8869
8870   template<class Classifier>
8871   bool isInside(const SMDS_MeshElement* theElem,
8872                 Classifier&             theClassifier,
8873                 const double            theTol)
8874   {
8875     gp_XYZ centerXYZ (0, 0, 0);
8876     SMDS_ElemIteratorPtr aNodeItr = theElem->nodesIterator();
8877     while (aNodeItr->more())
8878       centerXYZ += SMESH_MeshEditor::TNodeXYZ(cast2Node( aNodeItr->next()));
8879
8880     gp_Pnt aPnt = centerXYZ / theElem->NbNodes();
8881     theClassifier.Perform(aPnt, theTol);
8882     TopAbs_State aState = theClassifier.State();
8883     return (aState == TopAbs_IN || aState == TopAbs_ON );
8884   }
8885
8886   //================================================================================
8887   /*!
8888    * \brief Classifier of the 3D point on the TopoDS_Face
8889    *        with interaface suitable for isInside()
8890    */
8891   //================================================================================
8892
8893   struct _FaceClassifier
8894   {
8895     Extrema_ExtPS       _extremum;
8896     BRepAdaptor_Surface _surface;
8897     TopAbs_State        _state;
8898
8899     _FaceClassifier(const TopoDS_Face& face):_extremum(),_surface(face),_state(TopAbs_OUT)
8900     {
8901       _extremum.Initialize( _surface,
8902                             _surface.FirstUParameter(), _surface.LastUParameter(),
8903                             _surface.FirstVParameter(), _surface.LastVParameter(),
8904                             _surface.Tolerance(), _surface.Tolerance() );
8905     }
8906     void Perform(const gp_Pnt& aPnt, double theTol)
8907     {
8908       _state = TopAbs_OUT;
8909       _extremum.Perform(aPnt);
8910       if ( _extremum.IsDone() )
8911         for ( int iSol = 1; iSol <= _extremum.NbExt() && _state == TopAbs_OUT; ++iSol)
8912           _state = ( _extremum.Value(iSol) <= theTol ? TopAbs_IN : TopAbs_OUT );
8913     }
8914     TopAbs_State State() const
8915     {
8916       return _state;
8917     }
8918   };
8919 }
8920
8921 //================================================================================
8922 /*!
8923   \brief Creates a hole in a mesh by doubling the nodes of some particular elements
8924   \param theElems - group of of elements (edges or faces) to be replicated
8925   \param theNodesNot - group of nodes not to replicate
8926   \param theShape - shape to detect affected elements (element which geometric center
8927   located on or inside shape).
8928   The replicated nodes should be associated to affected elements.
8929   \return TRUE if operation has been completed successfully, FALSE otherwise
8930 */
8931 //================================================================================
8932
8933 bool SMESH_MeshEditor::DoubleNodesInRegion( const TIDSortedElemSet& theElems,
8934                                             const TIDSortedElemSet& theNodesNot,
8935                                             const TopoDS_Shape&     theShape )
8936 {
8937   if ( theShape.IsNull() )
8938     return false;
8939
8940   const double aTol = Precision::Confusion();
8941   auto_ptr< BRepClass3d_SolidClassifier> bsc3d;
8942   auto_ptr<_FaceClassifier>              aFaceClassifier;
8943   if ( theShape.ShapeType() == TopAbs_SOLID )
8944   {
8945     bsc3d.reset( new BRepClass3d_SolidClassifier(theShape));;
8946     bsc3d->PerformInfinitePoint(aTol);
8947   }
8948   else if (theShape.ShapeType() == TopAbs_FACE )
8949   {
8950     aFaceClassifier.reset( new _FaceClassifier(TopoDS::Face(theShape)));
8951   }
8952
8953   // iterates on indicated elements and get elements by back references from their nodes
8954   TIDSortedElemSet anAffected;
8955   TIDSortedElemSet::const_iterator elemItr = theElems.begin();
8956   for ( ;  elemItr != theElems.end(); ++elemItr )
8957   {
8958     SMDS_MeshElement* anElem = (SMDS_MeshElement*)*elemItr;
8959     if (!anElem)
8960       continue;
8961
8962     SMDS_ElemIteratorPtr nodeItr = anElem->nodesIterator();
8963     while ( nodeItr->more() )
8964     {
8965       const SMDS_MeshNode* aNode = cast2Node(nodeItr->next());
8966       if ( !aNode || theNodesNot.find(aNode) != theNodesNot.end() )
8967         continue;
8968       SMDS_ElemIteratorPtr backElemItr = aNode->GetInverseElementIterator();
8969       while ( backElemItr->more() )
8970       {
8971         const SMDS_MeshElement* curElem = backElemItr->next();
8972         if ( curElem && theElems.find(curElem) == theElems.end() &&
8973              ( bsc3d.get() ?
8974                isInside( curElem, *bsc3d, aTol ) :
8975                isInside( curElem, *aFaceClassifier, aTol )))
8976           anAffected.insert( curElem );
8977       }
8978     }
8979   }
8980   return DoubleNodes( theElems, theNodesNot, anAffected );
8981 }
8982
8983 //================================================================================
8984 /*!
8985  * \brief Generated skin mesh (containing 2D cells) from 3D mesh
8986  * The created 2D mesh elements based on nodes of free faces of boundary volumes
8987  * \return TRUE if operation has been completed successfully, FALSE otherwise
8988  */
8989 //================================================================================
8990
8991 bool SMESH_MeshEditor::Make2DMeshFrom3D()
8992 {
8993   // iterates on volume elements and detect all free faces on them
8994   SMESHDS_Mesh* aMesh = GetMeshDS();
8995   if (!aMesh)
8996     return false;
8997   bool res = false;
8998   SMDS_VolumeIteratorPtr vIt = aMesh->volumesIterator();
8999   while(vIt->more())
9000   {
9001     const SMDS_MeshVolume* volume = vIt->next();
9002     SMDS_VolumeTool vTool( volume );
9003     vTool.SetExternalNormal();
9004     const bool isPoly = volume->IsPoly();
9005     const bool isQuad = volume->IsQuadratic();
9006     for ( int iface = 0, n = vTool.NbFaces(); iface < n; iface++ )
9007     {
9008       if (!vTool.IsFreeFace(iface))
9009         continue;
9010       vector<const SMDS_MeshNode *> nodes;
9011       int nbFaceNodes = vTool.NbFaceNodes(iface);
9012       const SMDS_MeshNode** faceNodes = vTool.GetFaceNodes(iface);
9013       int inode = 0;
9014       for ( ; inode < nbFaceNodes; inode += isQuad ? 2 : 1)
9015         nodes.push_back(faceNodes[inode]);
9016       if (isQuad)
9017         for ( inode = 1; inode < nbFaceNodes; inode += 2)
9018           nodes.push_back(faceNodes[inode]);
9019
9020       // add new face based on volume nodes
9021       if (aMesh->FindFace( nodes ) )
9022         continue; // face already exsist
9023       myLastCreatedElems.Append( AddElement(nodes, SMDSAbs_Face, isPoly && iface == 1) );
9024       res = true;
9025     }
9026   }
9027   return res;
9028 }