Salome HOME
0020801: EDF 1343 SMESH : Segmentation violation during compound od Mesh with 0D...
[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_Algo.hxx"
42 #include "SMESH_ControlsDef.hxx"
43 #include "SMESH_Group.hxx"
44 #include "SMESH_MesherHelper.hxx"
45 #include "SMESH_OctreeNode.hxx"
46 #include "SMESH_subMesh.hxx"
47
48 #include "utilities.h"
49
50 #include <BRepAdaptor_Surface.hxx>
51 #include <BRepClass3d_SolidClassifier.hxx>
52 #include <BRep_Tool.hxx>
53 #include <ElCLib.hxx>
54 #include <Extrema_GenExtPS.hxx>
55 #include <Extrema_POnCurv.hxx>
56 #include <Extrema_POnSurf.hxx>
57 #include <GC_MakeSegment.hxx>
58 #include <Geom2d_Curve.hxx>
59 #include <GeomAPI_ExtremaCurveCurve.hxx>
60 #include <GeomAdaptor_Surface.hxx>
61 #include <Geom_Curve.hxx>
62 #include <Geom_Line.hxx>
63 #include <Geom_Surface.hxx>
64 #include <IntAna_IntConicQuad.hxx>
65 #include <IntAna_Quadric.hxx>
66 #include <Precision.hxx>
67 #include <TColStd_ListOfInteger.hxx>
68 #include <TopAbs_State.hxx>
69 #include <TopExp.hxx>
70 #include <TopExp_Explorer.hxx>
71 #include <TopTools_ListIteratorOfListOfShape.hxx>
72 #include <TopTools_ListOfShape.hxx>
73 #include <TopTools_SequenceOfShape.hxx>
74 #include <TopoDS.hxx>
75 #include <TopoDS_Face.hxx>
76 #include <gp.hxx>
77 #include <gp_Ax1.hxx>
78 #include <gp_Dir.hxx>
79 #include <gp_Lin.hxx>
80 #include <gp_Pln.hxx>
81 #include <gp_Trsf.hxx>
82 #include <gp_Vec.hxx>
83 #include <gp_XY.hxx>
84 #include <gp_XYZ.hxx>
85
86 #include <math.h>
87
88 #include <map>
89 #include <set>
90 #include <numeric>
91 #include <limits>
92
93 #define cast2Node(elem) static_cast<const SMDS_MeshNode*>( elem )
94
95 using namespace std;
96 using namespace SMESH::Controls;
97
98 typedef map<const SMDS_MeshElement*, list<const SMDS_MeshNode*> >    TElemOfNodeListMap;
99 typedef map<const SMDS_MeshElement*, list<const SMDS_MeshElement*> > TElemOfElemListMap;
100
101 //=======================================================================
102 //function : SMESH_MeshEditor
103 //purpose  :
104 //=======================================================================
105
106 SMESH_MeshEditor::SMESH_MeshEditor( SMESH_Mesh* theMesh )
107   :myMesh( theMesh ) // theMesh may be NULL
108 {
109 }
110
111 //=======================================================================
112 /*!
113  * \brief Add element
114  */
115 //=======================================================================
116
117 SMDS_MeshElement*
118 SMESH_MeshEditor::AddElement(const vector<const SMDS_MeshNode*> & node,
119                              const SMDSAbs_ElementType            type,
120                              const bool                           isPoly,
121                              const int                            ID)
122 {
123   SMDS_MeshElement* e = 0;
124   int nbnode = node.size();
125   SMESHDS_Mesh* mesh = GetMeshDS();
126   switch ( type ) {
127   case SMDSAbs_0DElement:
128     if ( nbnode == 1 )
129       if ( ID ) e = mesh->Add0DElementWithID(node[0], ID);
130       else      e = mesh->Add0DElement      (node[0] );
131     break;
132   case SMDSAbs_Edge:
133     if ( nbnode == 2 )
134       if ( ID ) e = mesh->AddEdgeWithID(node[0], node[1], ID);
135       else      e = mesh->AddEdge      (node[0], node[1] );
136     else if ( nbnode == 3 )
137       if ( ID ) e = mesh->AddEdgeWithID(node[0], node[1], node[2], ID);
138       else      e = mesh->AddEdge      (node[0], node[1], node[2] );
139     break;
140   case SMDSAbs_Face:
141     if ( !isPoly ) {
142       if      (nbnode == 3)
143         if ( ID ) e = mesh->AddFaceWithID(node[0], node[1], node[2], ID);
144         else      e = mesh->AddFace      (node[0], node[1], node[2] );
145       else if (nbnode == 4) 
146         if ( ID ) e = mesh->AddFaceWithID(node[0], node[1], node[2], node[3], ID);
147         else      e = mesh->AddFace      (node[0], node[1], node[2], node[3] );
148       else if (nbnode == 6)
149         if ( ID ) e = mesh->AddFaceWithID(node[0], node[1], node[2], node[3],
150                                           node[4], node[5], ID);
151         else      e = mesh->AddFace      (node[0], node[1], node[2], node[3],
152                                           node[4], node[5] );
153       else if (nbnode == 8)
154         if ( ID ) e = mesh->AddFaceWithID(node[0], node[1], node[2], node[3],
155                                           node[4], node[5], node[6], node[7], ID);
156         else      e = mesh->AddFace      (node[0], node[1], node[2], node[3],
157                                           node[4], node[5], node[6], node[7] );
158     } else {
159       if ( ID ) e = mesh->AddPolygonalFaceWithID(node, ID);
160       else      e = mesh->AddPolygonalFace      (node    );
161     }
162     break;
163   case SMDSAbs_Volume:
164     if ( !isPoly ) {
165       if      (nbnode == 4)
166         if ( ID ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3], ID);
167         else      e = mesh->AddVolume      (node[0], node[1], node[2], node[3] );
168       else if (nbnode == 5)
169         if ( ID ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
170                                             node[4], ID);
171         else      e = mesh->AddVolume      (node[0], node[1], node[2], node[3],
172                                             node[4] );
173       else if (nbnode == 6)
174         if ( ID ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
175                                             node[4], node[5], ID);
176         else      e = mesh->AddVolume      (node[0], node[1], node[2], node[3],
177                                             node[4], node[5] );
178       else if (nbnode == 8)
179         if ( ID ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
180                                             node[4], node[5], node[6], node[7], ID);
181         else      e = mesh->AddVolume      (node[0], node[1], node[2], node[3],
182                                             node[4], node[5], node[6], node[7] );
183       else if (nbnode == 10)
184         if ( ID ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
185                                             node[4], node[5], node[6], node[7],
186                                             node[8], node[9], ID);
187         else      e = mesh->AddVolume      (node[0], node[1], node[2], node[3],
188                                             node[4], node[5], node[6], node[7],
189                                             node[8], node[9] );
190       else if (nbnode == 13)
191         if ( ID ) e = mesh->AddVolumeWithID(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],ID);
195         else      e = mesh->AddVolume      (node[0], node[1], node[2], node[3],
196                                             node[4], node[5], node[6], node[7],
197                                             node[8], node[9], node[10],node[11],
198                                             node[12] );
199       else if (nbnode == 15)
200         if ( ID ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
201                                             node[4], node[5], node[6], node[7],
202                                             node[8], node[9], node[10],node[11],
203                                             node[12],node[13],node[14],ID);
204         else      e = mesh->AddVolume      (node[0], node[1], node[2], node[3],
205                                             node[4], node[5], node[6], node[7],
206                                             node[8], node[9], node[10],node[11],
207                                             node[12],node[13],node[14] );
208       else if (nbnode == 20)
209         if ( ID ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
210                                             node[4], node[5], node[6], node[7],
211                                             node[8], node[9], node[10],node[11],
212                                             node[12],node[13],node[14],node[15],
213                                             node[16],node[17],node[18],node[19],ID);
214         else      e = mesh->AddVolume      (node[0], node[1], node[2], node[3],
215                                             node[4], node[5], node[6], node[7],
216                                             node[8], node[9], node[10],node[11],
217                                             node[12],node[13],node[14],node[15],
218                                             node[16],node[17],node[18],node[19] );
219     }
220   }
221   return e;
222 }
223
224 //=======================================================================
225 /*!
226  * \brief Add element
227  */
228 //=======================================================================
229
230 SMDS_MeshElement* SMESH_MeshEditor::AddElement(const vector<int> &       nodeIDs,
231                                                const SMDSAbs_ElementType type,
232                                                const bool                isPoly,
233                                                const int                 ID)
234 {
235   vector<const SMDS_MeshNode*> nodes;
236   nodes.reserve( nodeIDs.size() );
237   vector<int>::const_iterator id = nodeIDs.begin();
238   while ( id != nodeIDs.end() ) {
239     if ( const SMDS_MeshNode* node = GetMeshDS()->FindNode( *id++ ))
240       nodes.push_back( node );
241     else
242       return 0;
243   }
244   return AddElement( nodes, type, isPoly, ID );
245 }
246
247 //=======================================================================
248 //function : Remove
249 //purpose  : Remove a node or an element.
250 //           Modify a compute state of sub-meshes which become empty
251 //=======================================================================
252
253 bool SMESH_MeshEditor::Remove (const list< int >& theIDs,
254                                const bool         isNodes )
255 {
256   myLastCreatedElems.Clear();
257   myLastCreatedNodes.Clear();
258
259   SMESHDS_Mesh* aMesh = GetMeshDS();
260   set< SMESH_subMesh *> smmap;
261
262   list<int>::const_iterator it = theIDs.begin();
263   for ( ; it != theIDs.end(); it++ ) {
264     const SMDS_MeshElement * elem;
265     if ( isNodes )
266       elem = aMesh->FindNode( *it );
267     else
268       elem = aMesh->FindElement( *it );
269     if ( !elem )
270       continue;
271
272     // Notify VERTEX sub-meshes about modification
273     if ( isNodes ) {
274       const SMDS_MeshNode* node = cast2Node( elem );
275       if ( node->GetPosition()->GetTypeOfPosition() == SMDS_TOP_VERTEX )
276         if ( int aShapeID = node->GetPosition()->GetShapeId() )
277           if ( SMESH_subMesh * sm = GetMesh()->GetSubMeshContaining( aShapeID ) )
278             smmap.insert( sm );
279     }
280     // Find sub-meshes to notify about modification
281     //     SMDS_ElemIteratorPtr nodeIt = elem->nodesIterator();
282     //     while ( nodeIt->more() ) {
283     //       const SMDS_MeshNode* node = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
284     //       const SMDS_PositionPtr& aPosition = node->GetPosition();
285     //       if ( aPosition.get() ) {
286     //         if ( int aShapeID = aPosition->GetShapeId() ) {
287     //           if ( SMESH_subMesh * sm = GetMesh()->GetSubMeshContaining( aShapeID ) )
288     //             smmap.insert( sm );
289     //         }
290     //       }
291     //     }
292
293     // Do remove
294     if ( isNodes )
295       aMesh->RemoveNode( static_cast< const SMDS_MeshNode* >( elem ));
296     else
297       aMesh->RemoveElement( elem );
298   }
299
300   // Notify sub-meshes about modification
301   if ( !smmap.empty() ) {
302     set< SMESH_subMesh *>::iterator smIt;
303     for ( smIt = smmap.begin(); smIt != smmap.end(); smIt++ )
304       (*smIt)->ComputeStateEngine( SMESH_subMesh::MESH_ENTITY_REMOVED );
305   }
306
307   //   // Check if the whole mesh becomes empty
308   //   if ( SMESH_subMesh * sm = GetMesh()->GetSubMeshContaining( 1 ) )
309   //     sm->ComputeStateEngine( SMESH_subMesh::CHECK_COMPUTE_STATE );
310
311   return true;
312 }
313
314 //=======================================================================
315 //function : FindShape
316 //purpose  : Return an index of the shape theElem is on
317 //           or zero if a shape not found
318 //=======================================================================
319
320 int SMESH_MeshEditor::FindShape (const SMDS_MeshElement * theElem)
321 {
322   myLastCreatedElems.Clear();
323   myLastCreatedNodes.Clear();
324
325   SMESHDS_Mesh * aMesh = GetMeshDS();
326   if ( aMesh->ShapeToMesh().IsNull() )
327     return 0;
328
329   if ( theElem->GetType() == SMDSAbs_Node ) {
330     const SMDS_PositionPtr& aPosition =
331       static_cast<const SMDS_MeshNode*>( theElem )->GetPosition();
332     if ( aPosition.get() )
333       return aPosition->GetShapeId();
334     else
335       return 0;
336   }
337
338   TopoDS_Shape aShape; // the shape a node is on
339   SMDS_ElemIteratorPtr nodeIt = theElem->nodesIterator();
340   while ( nodeIt->more() ) {
341     const SMDS_MeshNode* node = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
342     const SMDS_PositionPtr& aPosition = node->GetPosition();
343     if ( aPosition.get() ) {
344       int aShapeID = aPosition->GetShapeId();
345       SMESHDS_SubMesh * sm = aMesh->MeshElements( aShapeID );
346       if ( sm ) {
347         if ( sm->Contains( theElem ))
348           return aShapeID;
349         if ( aShape.IsNull() )
350           aShape = aMesh->IndexToShape( aShapeID );
351       }
352       else {
353         //MESSAGE ( "::FindShape() No SubShape for aShapeID " << aShapeID );
354       }
355     }
356   }
357
358   // None of nodes is on a proper shape,
359   // find the shape among ancestors of aShape on which a node is
360   if ( aShape.IsNull() ) {
361     //MESSAGE ("::FindShape() - NONE node is on shape")
362     return 0;
363   }
364   TopTools_ListIteratorOfListOfShape ancIt( GetMesh()->GetAncestors( aShape ));
365   for ( ; ancIt.More(); ancIt.Next() ) {
366     SMESHDS_SubMesh * sm = aMesh->MeshElements( ancIt.Value() );
367     if ( sm && sm->Contains( theElem ))
368       return aMesh->ShapeToIndex( ancIt.Value() );
369   }
370
371   //MESSAGE ("::FindShape() - SHAPE NOT FOUND")
372   return 0;
373 }
374
375 //=======================================================================
376 //function : IsMedium
377 //purpose  :
378 //=======================================================================
379
380 bool SMESH_MeshEditor::IsMedium(const SMDS_MeshNode*      node,
381                                 const SMDSAbs_ElementType typeToCheck)
382 {
383   bool isMedium = false;
384   SMDS_ElemIteratorPtr it = node->GetInverseElementIterator(typeToCheck);
385   while (it->more() && !isMedium ) {
386     const SMDS_MeshElement* elem = it->next();
387     isMedium = elem->IsMediumNode(node);
388   }
389   return isMedium;
390 }
391
392 //=======================================================================
393 //function : ShiftNodesQuadTria
394 //purpose  : auxilary
395 //           Shift nodes in the array corresponded to quadratic triangle
396 //           example: (0,1,2,3,4,5) -> (1,2,0,4,5,3)
397 //=======================================================================
398 static void ShiftNodesQuadTria(const SMDS_MeshNode* aNodes[])
399 {
400   const SMDS_MeshNode* nd1 = aNodes[0];
401   aNodes[0] = aNodes[1];
402   aNodes[1] = aNodes[2];
403   aNodes[2] = nd1;
404   const SMDS_MeshNode* nd2 = aNodes[3];
405   aNodes[3] = aNodes[4];
406   aNodes[4] = aNodes[5];
407   aNodes[5] = nd2;
408 }
409
410 //=======================================================================
411 //function : GetNodesFromTwoTria
412 //purpose  : auxilary
413 //           Shift nodes in the array corresponded to quadratic triangle
414 //           example: (0,1,2,3,4,5) -> (1,2,0,4,5,3)
415 //=======================================================================
416 static bool GetNodesFromTwoTria(const SMDS_MeshElement * theTria1,
417                                 const SMDS_MeshElement * theTria2,
418                                 const SMDS_MeshNode* N1[],
419                                 const SMDS_MeshNode* N2[])
420 {
421   SMDS_ElemIteratorPtr it = theTria1->nodesIterator();
422   int i=0;
423   while(i<6) {
424     N1[i] = static_cast<const SMDS_MeshNode*>( it->next() );
425     i++;
426   }
427   if(it->more()) return false;
428   it = theTria2->nodesIterator();
429   i=0;
430   while(i<6) {
431     N2[i] = static_cast<const SMDS_MeshNode*>( it->next() );
432     i++;
433   }
434   if(it->more()) return false;
435
436   int sames[3] = {-1,-1,-1};
437   int nbsames = 0;
438   int j;
439   for(i=0; i<3; i++) {
440     for(j=0; j<3; j++) {
441       if(N1[i]==N2[j]) {
442         sames[i] = j;
443         nbsames++;
444         break;
445       }
446     }
447   }
448   if(nbsames!=2) return false;
449   if(sames[0]>-1) {
450     ShiftNodesQuadTria(N1);
451     if(sames[1]>-1) {
452       ShiftNodesQuadTria(N1);
453     }
454   }
455   i = sames[0] + sames[1] + sames[2];
456   for(; i<2; i++) {
457     ShiftNodesQuadTria(N2);
458   }
459   // now we receive following N1 and N2 (using numeration as above image)
460   // tria1 : (1 2 4 5 9 7)  and  tria2 : (3 4 2 8 9 6)
461   // i.e. first nodes from both arrays determ new diagonal
462   return true;
463 }
464
465 //=======================================================================
466 //function : InverseDiag
467 //purpose  : Replace two neighbour triangles with ones built on the same 4 nodes
468 //           but having other common link.
469 //           Return False if args are improper
470 //=======================================================================
471
472 bool SMESH_MeshEditor::InverseDiag (const SMDS_MeshElement * theTria1,
473                                     const SMDS_MeshElement * theTria2 )
474 {
475   myLastCreatedElems.Clear();
476   myLastCreatedNodes.Clear();
477
478   if (!theTria1 || !theTria2)
479     return false;
480
481   const SMDS_FaceOfNodes* F1 = dynamic_cast<const SMDS_FaceOfNodes*>( theTria1 );
482   const SMDS_FaceOfNodes* F2 = dynamic_cast<const SMDS_FaceOfNodes*>( theTria2 );
483   if (F1 && F2) {
484
485     //  1 +--+ A  theTria1: ( 1 A B ) A->2 ( 1 2 B ) 1 +--+ A
486     //    | /|    theTria2: ( B A 2 ) B->1 ( 1 A 2 )   |\ |
487     //    |/ |                                         | \|
488     //  B +--+ 2                                     B +--+ 2
489
490     // put nodes in array and find out indices of the same ones
491     const SMDS_MeshNode* aNodes [6];
492     int sameInd [] = { 0, 0, 0, 0, 0, 0 };
493     int i = 0;
494     SMDS_ElemIteratorPtr it = theTria1->nodesIterator();
495     while ( it->more() ) {
496       aNodes[ i ] = static_cast<const SMDS_MeshNode*>( it->next() );
497
498       if ( i > 2 ) // theTria2
499         // find same node of theTria1
500         for ( int j = 0; j < 3; j++ )
501           if ( aNodes[ i ] == aNodes[ j ]) {
502             sameInd[ j ] = i;
503             sameInd[ i ] = j;
504             break;
505           }
506       // next
507       i++;
508       if ( i == 3 ) {
509         if ( it->more() )
510           return false; // theTria1 is not a triangle
511         it = theTria2->nodesIterator();
512       }
513       if ( i == 6 && it->more() )
514         return false; // theTria2 is not a triangle
515     }
516
517     // find indices of 1,2 and of A,B in theTria1
518     int iA = 0, iB = 0, i1 = 0, i2 = 0;
519     for ( i = 0; i < 6; i++ ) {
520       if ( sameInd [ i ] == 0 )
521         if ( i < 3 ) i1 = i;
522         else         i2 = i;
523       else if (i < 3)
524         if ( iA ) iB = i;
525         else      iA = i;
526     }
527     // nodes 1 and 2 should not be the same
528     if ( aNodes[ i1 ] == aNodes[ i2 ] )
529       return false;
530
531     // theTria1: A->2
532     aNodes[ iA ] = aNodes[ i2 ];
533     // theTria2: B->1
534     aNodes[ sameInd[ iB ]] = aNodes[ i1 ];
535
536     //MESSAGE( theTria1 << theTria2 );
537
538     GetMeshDS()->ChangeElementNodes( theTria1, aNodes, 3 );
539     GetMeshDS()->ChangeElementNodes( theTria2, &aNodes[ 3 ], 3 );
540
541     //MESSAGE( theTria1 << theTria2 );
542
543     return true;
544
545   } // end if(F1 && F2)
546
547   // check case of quadratic faces
548   const SMDS_QuadraticFaceOfNodes* QF1 =
549     dynamic_cast<const SMDS_QuadraticFaceOfNodes*> (theTria1);
550   if(!QF1) return false;
551   const SMDS_QuadraticFaceOfNodes* QF2 =
552     dynamic_cast<const SMDS_QuadraticFaceOfNodes*> (theTria2);
553   if(!QF2) return false;
554
555   //       5
556   //  1 +--+--+ 2  theTria1: (1 2 4 5 9 7) or (2 4 1 9 7 5) or (4 1 2 7 5 9)
557   //    |    /|    theTria2: (2 3 4 6 8 9) or (3 4 2 8 9 6) or (4 2 3 9 6 8)
558   //    |   / |
559   //  7 +  +  + 6
560   //    | /9  |
561   //    |/    |
562   //  4 +--+--+ 3
563   //       8
564
565   const SMDS_MeshNode* N1 [6];
566   const SMDS_MeshNode* N2 [6];
567   if(!GetNodesFromTwoTria(theTria1,theTria2,N1,N2))
568     return false;
569   // now we receive following N1 and N2 (using numeration as above image)
570   // tria1 : (1 2 4 5 9 7)  and  tria2 : (3 4 2 8 9 6)
571   // i.e. first nodes from both arrays determ new diagonal
572
573   const SMDS_MeshNode* N1new [6];
574   const SMDS_MeshNode* N2new [6];
575   N1new[0] = N1[0];
576   N1new[1] = N2[0];
577   N1new[2] = N2[1];
578   N1new[3] = N1[4];
579   N1new[4] = N2[3];
580   N1new[5] = N1[5];
581   N2new[0] = N1[0];
582   N2new[1] = N1[1];
583   N2new[2] = N2[0];
584   N2new[3] = N1[3];
585   N2new[4] = N2[5];
586   N2new[5] = N1[4];
587   // replaces nodes in faces
588   GetMeshDS()->ChangeElementNodes( theTria1, N1new, 6 );
589   GetMeshDS()->ChangeElementNodes( theTria2, N2new, 6 );
590
591   return true;
592 }
593
594 //=======================================================================
595 //function : findTriangles
596 //purpose  : find triangles sharing theNode1-theNode2 link
597 //=======================================================================
598
599 static bool findTriangles(const SMDS_MeshNode *    theNode1,
600                           const SMDS_MeshNode *    theNode2,
601                           const SMDS_MeshElement*& theTria1,
602                           const SMDS_MeshElement*& theTria2)
603 {
604   if ( !theNode1 || !theNode2 ) return false;
605
606   theTria1 = theTria2 = 0;
607
608   set< const SMDS_MeshElement* > emap;
609   SMDS_ElemIteratorPtr it = theNode1->GetInverseElementIterator(SMDSAbs_Face);
610   while (it->more()) {
611     const SMDS_MeshElement* elem = it->next();
612     if ( elem->NbNodes() == 3 )
613       emap.insert( elem );
614   }
615   it = theNode2->GetInverseElementIterator(SMDSAbs_Face);
616   while (it->more()) {
617     const SMDS_MeshElement* elem = it->next();
618     if ( emap.find( elem ) != emap.end() )
619       if ( theTria1 ) {
620         // theTria1 must be element with minimum ID
621         if( theTria1->GetID() < elem->GetID() ) {
622           theTria2 = elem;
623         }
624         else {
625           theTria2 = theTria1;
626           theTria1 = elem;
627         }
628         break;
629       }
630       else {
631         theTria1 = elem;
632       }
633   }
634   return ( theTria1 && theTria2 );
635 }
636
637 //=======================================================================
638 //function : InverseDiag
639 //purpose  : Replace two neighbour triangles sharing theNode1-theNode2 link
640 //           with ones built on the same 4 nodes but having other common link.
641 //           Return false if proper faces not found
642 //=======================================================================
643
644 bool SMESH_MeshEditor::InverseDiag (const SMDS_MeshNode * theNode1,
645                                     const SMDS_MeshNode * theNode2)
646 {
647   myLastCreatedElems.Clear();
648   myLastCreatedNodes.Clear();
649
650   MESSAGE( "::InverseDiag()" );
651
652   const SMDS_MeshElement *tr1, *tr2;
653   if ( !findTriangles( theNode1, theNode2, tr1, tr2 ))
654     return false;
655
656   const SMDS_FaceOfNodes* F1 = dynamic_cast<const SMDS_FaceOfNodes*>( tr1 );
657   //if (!F1) return false;
658   const SMDS_FaceOfNodes* F2 = dynamic_cast<const SMDS_FaceOfNodes*>( tr2 );
659   //if (!F2) return false;
660   if (F1 && F2) {
661
662     //  1 +--+ A  tr1: ( 1 A B ) A->2 ( 1 2 B ) 1 +--+ A
663     //    | /|    tr2: ( B A 2 ) B->1 ( 1 A 2 )   |\ |
664     //    |/ |                                    | \|
665     //  B +--+ 2                                B +--+ 2
666
667     // put nodes in array
668     // and find indices of 1,2 and of A in tr1 and of B in tr2
669     int i, iA1 = 0, i1 = 0;
670     const SMDS_MeshNode* aNodes1 [3];
671     SMDS_ElemIteratorPtr it;
672     for (i = 0, it = tr1->nodesIterator(); it->more(); i++ ) {
673       aNodes1[ i ] = static_cast<const SMDS_MeshNode*>( it->next() );
674       if ( aNodes1[ i ] == theNode1 )
675         iA1 = i; // node A in tr1
676       else if ( aNodes1[ i ] != theNode2 )
677         i1 = i;  // node 1
678     }
679     int iB2 = 0, i2 = 0;
680     const SMDS_MeshNode* aNodes2 [3];
681     for (i = 0, it = tr2->nodesIterator(); it->more(); i++ ) {
682       aNodes2[ i ] = static_cast<const SMDS_MeshNode*>( it->next() );
683       if ( aNodes2[ i ] == theNode2 )
684         iB2 = i; // node B in tr2
685       else if ( aNodes2[ i ] != theNode1 )
686         i2 = i;  // node 2
687     }
688
689     // nodes 1 and 2 should not be the same
690     if ( aNodes1[ i1 ] == aNodes2[ i2 ] )
691       return false;
692
693     // tr1: A->2
694     aNodes1[ iA1 ] = aNodes2[ i2 ];
695     // tr2: B->1
696     aNodes2[ iB2 ] = aNodes1[ i1 ];
697
698     //MESSAGE( tr1 << tr2 );
699
700     GetMeshDS()->ChangeElementNodes( tr1, aNodes1, 3 );
701     GetMeshDS()->ChangeElementNodes( tr2, aNodes2, 3 );
702
703     //MESSAGE( tr1 << tr2 );
704
705     return true;
706   }
707
708   // check case of quadratic faces
709   const SMDS_QuadraticFaceOfNodes* QF1 =
710     dynamic_cast<const SMDS_QuadraticFaceOfNodes*> (tr1);
711   if(!QF1) return false;
712   const SMDS_QuadraticFaceOfNodes* QF2 =
713     dynamic_cast<const SMDS_QuadraticFaceOfNodes*> (tr2);
714   if(!QF2) return false;
715   return InverseDiag(tr1,tr2);
716 }
717
718 //=======================================================================
719 //function : getQuadrangleNodes
720 //purpose  : fill theQuadNodes - nodes of a quadrangle resulting from
721 //           fusion of triangles tr1 and tr2 having shared link on
722 //           theNode1 and theNode2
723 //=======================================================================
724
725 bool getQuadrangleNodes(const SMDS_MeshNode *    theQuadNodes [],
726                         const SMDS_MeshNode *    theNode1,
727                         const SMDS_MeshNode *    theNode2,
728                         const SMDS_MeshElement * tr1,
729                         const SMDS_MeshElement * tr2 )
730 {
731   if( tr1->NbNodes() != tr2->NbNodes() )
732     return false;
733   // find the 4-th node to insert into tr1
734   const SMDS_MeshNode* n4 = 0;
735   SMDS_ElemIteratorPtr it = tr2->nodesIterator();
736   int i=0;
737   while ( !n4 && i<3 ) {
738     const SMDS_MeshNode * n = cast2Node( it->next() );
739     i++;
740     bool isDiag = ( n == theNode1 || n == theNode2 );
741     if ( !isDiag )
742       n4 = n;
743   }
744   // Make an array of nodes to be in a quadrangle
745   int iNode = 0, iFirstDiag = -1;
746   it = tr1->nodesIterator();
747   i=0;
748   while ( i<3 ) {
749     const SMDS_MeshNode * n = cast2Node( it->next() );
750     i++;
751     bool isDiag = ( n == theNode1 || n == theNode2 );
752     if ( isDiag ) {
753       if ( iFirstDiag < 0 )
754         iFirstDiag = iNode;
755       else if ( iNode - iFirstDiag == 1 )
756         theQuadNodes[ iNode++ ] = n4; // insert the 4-th node between diagonal nodes
757     }
758     else if ( n == n4 ) {
759       return false; // tr1 and tr2 should not have all the same nodes
760     }
761     theQuadNodes[ iNode++ ] = n;
762   }
763   if ( iNode == 3 ) // diagonal nodes have 0 and 2 indices
764     theQuadNodes[ iNode ] = n4;
765
766   return true;
767 }
768
769 //=======================================================================
770 //function : DeleteDiag
771 //purpose  : Replace two neighbour triangles sharing theNode1-theNode2 link
772 //           with a quadrangle built on the same 4 nodes.
773 //           Return false if proper faces not found
774 //=======================================================================
775
776 bool SMESH_MeshEditor::DeleteDiag (const SMDS_MeshNode * theNode1,
777                                    const SMDS_MeshNode * theNode2)
778 {
779   myLastCreatedElems.Clear();
780   myLastCreatedNodes.Clear();
781
782   MESSAGE( "::DeleteDiag()" );
783
784   const SMDS_MeshElement *tr1, *tr2;
785   if ( !findTriangles( theNode1, theNode2, tr1, tr2 ))
786     return false;
787
788   const SMDS_FaceOfNodes* F1 = dynamic_cast<const SMDS_FaceOfNodes*>( tr1 );
789   //if (!F1) return false;
790   const SMDS_FaceOfNodes* F2 = dynamic_cast<const SMDS_FaceOfNodes*>( tr2 );
791   //if (!F2) return false;
792   if (F1 && F2) {
793
794     const SMDS_MeshNode* aNodes [ 4 ];
795     if ( ! getQuadrangleNodes( aNodes, theNode1, theNode2, tr1, tr2 ))
796       return false;
797
798     //MESSAGE( endl << tr1 << tr2 );
799
800     GetMeshDS()->ChangeElementNodes( tr1, aNodes, 4 );
801     myLastCreatedElems.Append(tr1);
802     GetMeshDS()->RemoveElement( tr2 );
803
804     //MESSAGE( endl << tr1 );
805
806     return true;
807   }
808
809   // check case of quadratic faces
810   const SMDS_QuadraticFaceOfNodes* QF1 =
811     dynamic_cast<const SMDS_QuadraticFaceOfNodes*> (tr1);
812   if(!QF1) return false;
813   const SMDS_QuadraticFaceOfNodes* QF2 =
814     dynamic_cast<const SMDS_QuadraticFaceOfNodes*> (tr2);
815   if(!QF2) return false;
816
817   //       5
818   //  1 +--+--+ 2  tr1: (1 2 4 5 9 7) or (2 4 1 9 7 5) or (4 1 2 7 5 9)
819   //    |    /|    tr2: (2 3 4 6 8 9) or (3 4 2 8 9 6) or (4 2 3 9 6 8)
820   //    |   / |
821   //  7 +  +  + 6
822   //    | /9  |
823   //    |/    |
824   //  4 +--+--+ 3
825   //       8
826
827   const SMDS_MeshNode* N1 [6];
828   const SMDS_MeshNode* N2 [6];
829   if(!GetNodesFromTwoTria(tr1,tr2,N1,N2))
830     return false;
831   // now we receive following N1 and N2 (using numeration as above image)
832   // tria1 : (1 2 4 5 9 7)  and  tria2 : (3 4 2 8 9 6)
833   // i.e. first nodes from both arrays determ new diagonal
834
835   const SMDS_MeshNode* aNodes[8];
836   aNodes[0] = N1[0];
837   aNodes[1] = N1[1];
838   aNodes[2] = N2[0];
839   aNodes[3] = N2[1];
840   aNodes[4] = N1[3];
841   aNodes[5] = N2[5];
842   aNodes[6] = N2[3];
843   aNodes[7] = N1[5];
844
845   GetMeshDS()->ChangeElementNodes( tr1, aNodes, 8 );
846   myLastCreatedElems.Append(tr1);
847   GetMeshDS()->RemoveElement( tr2 );
848
849   // remove middle node (9)
850   GetMeshDS()->RemoveNode( N1[4] );
851
852   return true;
853 }
854
855 //=======================================================================
856 //function : Reorient
857 //purpose  : Reverse theElement orientation
858 //=======================================================================
859
860 bool SMESH_MeshEditor::Reorient (const SMDS_MeshElement * theElem)
861 {
862   myLastCreatedElems.Clear();
863   myLastCreatedNodes.Clear();
864
865   if (!theElem)
866     return false;
867   SMDS_ElemIteratorPtr it = theElem->nodesIterator();
868   if ( !it || !it->more() )
869     return false;
870
871   switch ( theElem->GetType() ) {
872
873   case SMDSAbs_Edge:
874   case SMDSAbs_Face: {
875     if(!theElem->IsQuadratic()) {
876       int i = theElem->NbNodes();
877       vector<const SMDS_MeshNode*> aNodes( i );
878       while ( it->more() )
879         aNodes[ --i ]= static_cast<const SMDS_MeshNode*>( it->next() );
880       return GetMeshDS()->ChangeElementNodes( theElem, &aNodes[0], theElem->NbNodes() );
881     }
882     else {
883       // quadratic elements
884       if(theElem->GetType()==SMDSAbs_Edge) {
885         vector<const SMDS_MeshNode*> aNodes(3);
886         aNodes[1]= static_cast<const SMDS_MeshNode*>( it->next() );
887         aNodes[0]= static_cast<const SMDS_MeshNode*>( it->next() );
888         aNodes[2]= static_cast<const SMDS_MeshNode*>( it->next() );
889         return GetMeshDS()->ChangeElementNodes( theElem, &aNodes[0], 3 );
890       }
891       else {
892         int nbn = theElem->NbNodes();
893         vector<const SMDS_MeshNode*> aNodes(nbn);
894         aNodes[0]= static_cast<const SMDS_MeshNode*>( it->next() );
895         int i=1;
896         for(; i<nbn/2; i++) {
897           aNodes[nbn/2-i]= static_cast<const SMDS_MeshNode*>( it->next() );
898         }
899         for(i=0; i<nbn/2; i++) {
900           aNodes[nbn-i-1]= static_cast<const SMDS_MeshNode*>( it->next() );
901         }
902         return GetMeshDS()->ChangeElementNodes( theElem, &aNodes[0], nbn );
903       }
904     }
905   }
906   case SMDSAbs_Volume: {
907     if (theElem->IsPoly()) {
908       const SMDS_PolyhedralVolumeOfNodes* aPolyedre =
909         static_cast<const SMDS_PolyhedralVolumeOfNodes*>( theElem );
910       if (!aPolyedre) {
911         MESSAGE("Warning: bad volumic element");
912         return false;
913       }
914
915       int nbFaces = aPolyedre->NbFaces();
916       vector<const SMDS_MeshNode *> poly_nodes;
917       vector<int> quantities (nbFaces);
918
919       // reverse each face of the polyedre
920       for (int iface = 1; iface <= nbFaces; iface++) {
921         int inode, nbFaceNodes = aPolyedre->NbFaceNodes(iface);
922         quantities[iface - 1] = nbFaceNodes;
923
924         for (inode = nbFaceNodes; inode >= 1; inode--) {
925           const SMDS_MeshNode* curNode = aPolyedre->GetFaceNode(iface, inode);
926           poly_nodes.push_back(curNode);
927         }
928       }
929
930       return GetMeshDS()->ChangePolyhedronNodes( theElem, poly_nodes, quantities );
931
932     }
933     else {
934       SMDS_VolumeTool vTool;
935       if ( !vTool.Set( theElem ))
936         return false;
937       vTool.Inverse();
938       return GetMeshDS()->ChangeElementNodes( theElem, vTool.GetNodes(), vTool.NbNodes() );
939     }
940   }
941   default:;
942   }
943
944   return false;
945 }
946
947 //=======================================================================
948 //function : getBadRate
949 //purpose  :
950 //=======================================================================
951
952 static double getBadRate (const SMDS_MeshElement*               theElem,
953                           SMESH::Controls::NumericalFunctorPtr& theCrit)
954 {
955   SMESH::Controls::TSequenceOfXYZ P;
956   if ( !theElem || !theCrit->GetPoints( theElem, P ))
957     return 1e100;
958   return theCrit->GetBadRate( theCrit->GetValue( P ), theElem->NbNodes() );
959   //return theCrit->GetBadRate( theCrit->GetValue( theElem->GetID() ), theElem->NbNodes() );
960 }
961
962 //=======================================================================
963 //function : QuadToTri
964 //purpose  : Cut quadrangles into triangles.
965 //           theCrit is used to select a diagonal to cut
966 //=======================================================================
967
968 bool SMESH_MeshEditor::QuadToTri (TIDSortedElemSet &                   theElems,
969                                   SMESH::Controls::NumericalFunctorPtr theCrit)
970 {
971   myLastCreatedElems.Clear();
972   myLastCreatedNodes.Clear();
973
974   MESSAGE( "::QuadToTri()" );
975
976   if ( !theCrit.get() )
977     return false;
978
979   SMESHDS_Mesh * aMesh = GetMeshDS();
980
981   Handle(Geom_Surface) surface;
982   SMESH_MesherHelper   helper( *GetMesh() );
983
984   TIDSortedElemSet::iterator itElem;
985   for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
986     const SMDS_MeshElement* elem = *itElem;
987     if ( !elem || elem->GetType() != SMDSAbs_Face )
988       continue;
989     if ( elem->NbNodes() != ( elem->IsQuadratic() ? 8 : 4 ))
990       continue;
991
992     // retrieve element nodes
993     const SMDS_MeshNode* aNodes [8];
994     SMDS_ElemIteratorPtr itN = elem->nodesIterator();
995     int i = 0;
996     while ( itN->more() )
997       aNodes[ i++ ] = static_cast<const SMDS_MeshNode*>( itN->next() );
998
999     // compare two sets of possible triangles
1000     double aBadRate1, aBadRate2; // to what extent a set is bad
1001     SMDS_FaceOfNodes tr1 ( aNodes[0], aNodes[1], aNodes[2] );
1002     SMDS_FaceOfNodes tr2 ( aNodes[2], aNodes[3], aNodes[0] );
1003     aBadRate1 = getBadRate( &tr1, theCrit ) + getBadRate( &tr2, theCrit );
1004
1005     SMDS_FaceOfNodes tr3 ( aNodes[1], aNodes[2], aNodes[3] );
1006     SMDS_FaceOfNodes tr4 ( aNodes[3], aNodes[0], aNodes[1] );
1007     aBadRate2 = getBadRate( &tr3, theCrit ) + getBadRate( &tr4, theCrit );
1008
1009     int aShapeId = FindShape( elem );
1010     const SMDS_MeshElement* newElem = 0;
1011
1012     if( !elem->IsQuadratic() ) {
1013
1014       // split liner quadrangle
1015
1016       if ( aBadRate1 <= aBadRate2 ) {
1017         // tr1 + tr2 is better
1018         aMesh->ChangeElementNodes( elem, aNodes, 3 );
1019         newElem = aMesh->AddFace( aNodes[2], aNodes[3], aNodes[0] );
1020       }
1021       else {
1022         // tr3 + tr4 is better
1023         aMesh->ChangeElementNodes( elem, &aNodes[1], 3 );
1024         newElem = aMesh->AddFace( aNodes[3], aNodes[0], aNodes[1] );
1025       }
1026     }
1027     else {
1028
1029       // split quadratic quadrangle
1030
1031       // get surface elem is on
1032       if ( aShapeId != helper.GetSubShapeID() ) {
1033         surface.Nullify();
1034         TopoDS_Shape shape;
1035         if ( aShapeId > 0 )
1036           shape = aMesh->IndexToShape( aShapeId );
1037         if ( !shape.IsNull() && shape.ShapeType() == TopAbs_FACE ) {
1038           TopoDS_Face face = TopoDS::Face( shape );
1039           surface = BRep_Tool::Surface( face );
1040           if ( !surface.IsNull() )
1041             helper.SetSubShape( shape );
1042         }
1043       }
1044       // get elem nodes
1045       const SMDS_MeshNode* aNodes [8];
1046       const SMDS_MeshNode* inFaceNode = 0;
1047       SMDS_ElemIteratorPtr itN = elem->nodesIterator();
1048       int i = 0;
1049       while ( itN->more() ) {
1050         aNodes[ i++ ] = static_cast<const SMDS_MeshNode*>( itN->next() );
1051         if ( !inFaceNode && helper.GetNodeUVneedInFaceNode() &&
1052              aNodes[ i-1 ]->GetPosition()->GetTypeOfPosition() == SMDS_TOP_FACE )
1053         {
1054           inFaceNode = aNodes[ i-1 ];
1055         }
1056       }
1057       // find middle point for (0,1,2,3)
1058       // and create a node in this point;
1059       gp_XYZ p( 0,0,0 );
1060       if ( surface.IsNull() ) {
1061         for(i=0; i<4; i++)
1062           p += gp_XYZ(aNodes[i]->X(), aNodes[i]->Y(), aNodes[i]->Z() );
1063         p /= 4;
1064       }
1065       else {
1066         TopoDS_Face face = TopoDS::Face( helper.GetSubShape() );
1067         gp_XY uv( 0,0 );
1068         for(i=0; i<4; i++)
1069           uv += helper.GetNodeUV( face, aNodes[i], inFaceNode );
1070         uv /= 4.;
1071         p = surface->Value( uv.X(), uv.Y() ).XYZ();
1072       }
1073       const SMDS_MeshNode* newN = aMesh->AddNode( p.X(), p.Y(), p.Z() );
1074       myLastCreatedNodes.Append(newN);
1075
1076       // create a new element
1077       const SMDS_MeshNode* N[6];
1078       if ( aBadRate1 <= aBadRate2 ) {
1079         N[0] = aNodes[0];
1080         N[1] = aNodes[1];
1081         N[2] = aNodes[2];
1082         N[3] = aNodes[4];
1083         N[4] = aNodes[5];
1084         N[5] = newN;
1085         newElem = aMesh->AddFace(aNodes[2], aNodes[3], aNodes[0],
1086                                  aNodes[6], aNodes[7], newN );
1087       }
1088       else {
1089         N[0] = aNodes[1];
1090         N[1] = aNodes[2];
1091         N[2] = aNodes[3];
1092         N[3] = aNodes[5];
1093         N[4] = aNodes[6];
1094         N[5] = newN;
1095         newElem = aMesh->AddFace(aNodes[3], aNodes[0], aNodes[1],
1096                                  aNodes[7], aNodes[4], newN );
1097       }
1098       aMesh->ChangeElementNodes( elem, N, 6 );
1099
1100     } // quadratic case
1101
1102     // care of a new element
1103
1104     myLastCreatedElems.Append(newElem);
1105     AddToSameGroups( newElem, elem, aMesh );
1106
1107     // put a new triangle on the same shape
1108     if ( aShapeId )
1109       aMesh->SetMeshElementOnShape( newElem, aShapeId );
1110   }
1111   return true;
1112 }
1113
1114 //=======================================================================
1115 //function : BestSplit
1116 //purpose  : Find better diagonal for cutting.
1117 //=======================================================================
1118
1119 int SMESH_MeshEditor::BestSplit (const SMDS_MeshElement*              theQuad,
1120                                  SMESH::Controls::NumericalFunctorPtr theCrit)
1121 {
1122   myLastCreatedElems.Clear();
1123   myLastCreatedNodes.Clear();
1124
1125   if (!theCrit.get())
1126     return -1;
1127
1128   if (!theQuad || theQuad->GetType() != SMDSAbs_Face )
1129     return -1;
1130
1131   if( theQuad->NbNodes()==4 ||
1132       (theQuad->NbNodes()==8 && theQuad->IsQuadratic()) ) {
1133
1134     // retrieve element nodes
1135     const SMDS_MeshNode* aNodes [4];
1136     SMDS_ElemIteratorPtr itN = theQuad->nodesIterator();
1137     int i = 0;
1138     //while (itN->more())
1139     while (i<4) {
1140       aNodes[ i++ ] = static_cast<const SMDS_MeshNode*>( itN->next() );
1141     }
1142     // compare two sets of possible triangles
1143     double aBadRate1, aBadRate2; // to what extent a set is bad
1144     SMDS_FaceOfNodes tr1 ( aNodes[0], aNodes[1], aNodes[2] );
1145     SMDS_FaceOfNodes tr2 ( aNodes[2], aNodes[3], aNodes[0] );
1146     aBadRate1 = getBadRate( &tr1, theCrit ) + getBadRate( &tr2, theCrit );
1147
1148     SMDS_FaceOfNodes tr3 ( aNodes[1], aNodes[2], aNodes[3] );
1149     SMDS_FaceOfNodes tr4 ( aNodes[3], aNodes[0], aNodes[1] );
1150     aBadRate2 = getBadRate( &tr3, theCrit ) + getBadRate( &tr4, theCrit );
1151
1152     if (aBadRate1 <= aBadRate2) // tr1 + tr2 is better
1153       return 1; // diagonal 1-3
1154
1155     return 2; // diagonal 2-4
1156   }
1157   return -1;
1158 }
1159
1160 namespace
1161 {
1162   // Methods of splitting volumes into tetra
1163
1164   const int theHexTo5[5*4] =
1165     {
1166       0, 1, 5, 2,
1167       0, 4, 5, 7,
1168       0, 3, 7, 2,
1169       5, 6, 7, 2,
1170       0, 2, 5, 7
1171     };
1172   const int theHexTo6[6*4] =
1173     {
1174       0, 1, 5, 2,
1175       0, 4, 5, 7,
1176       0, 3, 7, 2,
1177       5, 6, 7, 2,
1178       0, 2, 5, 7
1179     };
1180   const int thePyraTo2[2*4] =
1181     {
1182       0, 1, 2, 4,
1183       0, 2, 3, 4
1184     };
1185
1186   const int thePentaTo8[8*4] =
1187     {
1188       0, 1, 2, 6,
1189       3, 5, 4, 6,
1190       0, 3, 4, 6,
1191       0, 4, 1, 6,
1192       1, 4, 5, 6,
1193       1, 5, 2, 6,
1194       2, 5, 3, 6,
1195       2, 3, 0, 6
1196     };
1197
1198   struct TSplitMethod
1199   {
1200     int        _nbTetra;
1201     const int* _connectivity;
1202     bool       _addNode; // additional node is to be created
1203     TSplitMethod( int nbTet=0, const int* conn=0, bool addNode=false)
1204       : _nbTetra(nbTet), _connectivity(conn), _addNode(addNode) {}
1205   };
1206
1207   /*!
1208    * \brief return TSplitMethod for the given element
1209    */
1210   TSplitMethod getSplitMethod( const SMDS_MeshElement* vol, const int theMethodFlags)
1211   {
1212     TSplitMethod method;
1213     if ( vol->GetType() == SMDSAbs_Volume && !vol->IsPoly())
1214       switch ( vol->NbNodes() )
1215       {
1216       case 8:
1217       case 20:
1218         if ( theMethodFlags & SMESH_MeshEditor::HEXA_TO_5 )
1219           method = TSplitMethod( 5, theHexTo5 );
1220         else
1221           method = TSplitMethod( 6, theHexTo6 );
1222         break;
1223       case 5:
1224       case 13:
1225         method = TSplitMethod( 2, thePyraTo2 );
1226         break;
1227       case 6:
1228       case 15:
1229         method = TSplitMethod( 8, thePentaTo8, /*addNode=*/true );
1230         break;
1231       default:;
1232       }
1233     return method;
1234   }
1235 }
1236
1237 //=======================================================================
1238 //function : SplitVolumesIntoTetra
1239 //purpose  : Split volumic elements into tetrahedra.
1240 //=======================================================================
1241
1242 // void SMESH_MeshEditor::SplitVolumesIntoTetra (const TIDSortedElemSet & theElems,
1243 //                                               const int                theMethodFlags)
1244 // {
1245 //   // sdt-like iterator on coordinates of nodes of mesh element
1246 //   typedef SMDS_StdIterator< TNodeXYZ, SMDS_ElemIteratorPtr > NXyzIterator;
1247 //   NXyzIterator xyzEnd;
1248
1249 //   SMESH_MesherHelper helper( *GetMesh());
1250
1251 //   TIDSortedElemSet::const_iterator elem = theElems.begin();
1252 //   for ( ; elem != theElems.end(); ++elem )
1253 //   {
1254 //     SMDSAbs_EntityType geomType = (*elem)->GetEntityType();
1255 //     if ( geomType <= SMDSEntity_Quad_Tetra )
1256 //       continue; // tetra or face or edge
1257
1258 //     if ( (*elem)->IsQuadratic() )
1259 //     {
1260 //       // add quadratic links to the helper
1261 //       SMDS_VolumeTool vol( *elem );
1262 //       for ( int iF = 0; iF < vol.NbFaces(); ++iF )
1263 //       {
1264 //         const SMDS_MeshNode** fNodes = vol.GetFaceNodes( iF );
1265 //         for ( int iN = 0; iN < vol.NbFaceNodes( iF ); iN += 2)
1266 //           helper.AddTLinkNode( fNodes[iF], fNodes[iF+2], fNodes[iF+1] );
1267 //       }
1268 //       helper.SetIsQuadratic( true );
1269 //     }
1270 //     else
1271 //     {
1272 //       helper.SetIsQuadratic( false );
1273 //     }
1274
1275 //     vector<const SMDS_MeshElement* > tetras; // splits of a volume
1276
1277 //     if ( geomType == SMDSEntity_Polyhedra )
1278 //     {
1279 //       // Each face of a polyhedron is split into triangles and
1280 //       // each of triangles and a cell barycenter form a tetrahedron.
1281
1282 //       SMDS_VolumeTool vol( *elem );
1283
1284 //       // make a node at barycenter
1285 //       gp_XYZ gc = std::accumulate( NXyzIterator((*elem)->nodesIterator()), xyzEnd,gp_XYZ(0,0,0));
1286 //       gc /= vol.NbNodes();
1287 //       SMDS_MeshNode* gcNode = GetMeshDS()->AddNode( gc.X(), gc.Y(), gc.Z() );
1288
1289 //       for ( int iF = 0; iF < vol.NbFaces(); ++iF )
1290 //       {
1291 //         const SMDS_MeshNode** fNodes = vol.GetFaceNodes( iF );
1292 //         int nbFNodes = vol.NbFaceNodes( iF );
1293 //         int nbTria = nbFNodes - 2;
1294 //         bool extFace =  vol.IsFaceExternal( iF );
1295 //         SMDS_MeshElement* tet;
1296 //         for ( int i = 0; i < nbTria; ++i )
1297 //         {
1298 //           if ( extFace )
1299 //             tet = helper.AddVolume( fNodes[0], fNodes[i+1], fNodes[i+2], gcNode );
1300 //           else
1301 //             tet = helper.AddVolume( fNodes[0], fNodes[i+2], fNodes[i+1], gcNode );
1302 //           tetras.push_back( tet );
1303 //         }
1304 //       }
1305
1306 //     }
1307 //     else
1308 //     {
1309
1310 //       TSplitMethod splitMethod = getSplitMethod( *elem, theMethodFlags );
1311 //       if ( splitMethod._nbTetra < 1 ) continue;
1312
1313 //       vector<const SMDS_MeshNode*> volNodes( (*elem)->begin_nodes(), (*elem)->end_nodes());
1314 //     }
1315 //   }
1316 // }
1317
1318 //=======================================================================
1319 //function : AddToSameGroups
1320 //purpose  : add elemToAdd to the groups the elemInGroups belongs to
1321 //=======================================================================
1322
1323 void SMESH_MeshEditor::AddToSameGroups (const SMDS_MeshElement* elemToAdd,
1324                                         const SMDS_MeshElement* elemInGroups,
1325                                         SMESHDS_Mesh *          aMesh)
1326 {
1327   const set<SMESHDS_GroupBase*>& groups = aMesh->GetGroups();
1328   if (!groups.empty()) {
1329     set<SMESHDS_GroupBase*>::const_iterator grIt = groups.begin();
1330     for ( ; grIt != groups.end(); grIt++ ) {
1331       SMESHDS_Group* group = dynamic_cast<SMESHDS_Group*>( *grIt );
1332       if ( group && group->Contains( elemInGroups ))
1333         group->SMDSGroup().Add( elemToAdd );
1334     }
1335   }
1336 }
1337
1338
1339 //=======================================================================
1340 //function : RemoveElemFromGroups
1341 //purpose  : Remove removeelem to the groups the elemInGroups belongs to
1342 //=======================================================================
1343 void SMESH_MeshEditor::RemoveElemFromGroups (const SMDS_MeshElement* removeelem,
1344                                              SMESHDS_Mesh *          aMesh)
1345 {
1346   const set<SMESHDS_GroupBase*>& groups = aMesh->GetGroups();
1347   if (!groups.empty())
1348   {
1349     set<SMESHDS_GroupBase*>::const_iterator GrIt = groups.begin();
1350     for (; GrIt != groups.end(); GrIt++)
1351     {
1352       SMESHDS_Group* grp = dynamic_cast<SMESHDS_Group*>(*GrIt);
1353       if (!grp || grp->IsEmpty()) continue;
1354       grp->SMDSGroup().Remove(removeelem);
1355     }
1356   }
1357 }
1358
1359 //=======================================================================
1360 //function : ReplaceElemInGroups
1361 //purpose  : replace elemToRm by elemToAdd in the all groups
1362 //=======================================================================
1363
1364 void SMESH_MeshEditor::ReplaceElemInGroups (const SMDS_MeshElement* elemToRm,
1365                                             const SMDS_MeshElement* elemToAdd,
1366                                             SMESHDS_Mesh *          aMesh)
1367 {
1368   const set<SMESHDS_GroupBase*>& groups = aMesh->GetGroups();
1369   if (!groups.empty()) {
1370     set<SMESHDS_GroupBase*>::const_iterator grIt = groups.begin();
1371     for ( ; grIt != groups.end(); grIt++ ) {
1372       SMESHDS_Group* group = dynamic_cast<SMESHDS_Group*>( *grIt );
1373       if ( group && group->SMDSGroup().Remove( elemToRm ) && elemToAdd )
1374         group->SMDSGroup().Add( elemToAdd );
1375     }
1376   }
1377 }
1378
1379 //=======================================================================
1380 //function : QuadToTri
1381 //purpose  : Cut quadrangles into triangles.
1382 //           theCrit is used to select a diagonal to cut
1383 //=======================================================================
1384
1385 bool SMESH_MeshEditor::QuadToTri (TIDSortedElemSet & theElems,
1386                                   const bool         the13Diag)
1387 {
1388   myLastCreatedElems.Clear();
1389   myLastCreatedNodes.Clear();
1390
1391   MESSAGE( "::QuadToTri()" );
1392
1393   SMESHDS_Mesh * aMesh = GetMeshDS();
1394
1395   Handle(Geom_Surface) surface;
1396   SMESH_MesherHelper   helper( *GetMesh() );
1397
1398   TIDSortedElemSet::iterator itElem;
1399   for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
1400     const SMDS_MeshElement* elem = *itElem;
1401     if ( !elem || elem->GetType() != SMDSAbs_Face )
1402       continue;
1403     bool isquad = elem->NbNodes()==4 || elem->NbNodes()==8;
1404     if(!isquad) continue;
1405
1406     if(elem->NbNodes()==4) {
1407       // retrieve element nodes
1408       const SMDS_MeshNode* aNodes [4];
1409       SMDS_ElemIteratorPtr itN = elem->nodesIterator();
1410       int i = 0;
1411       while ( itN->more() )
1412         aNodes[ i++ ] = static_cast<const SMDS_MeshNode*>( itN->next() );
1413
1414       int aShapeId = FindShape( elem );
1415       const SMDS_MeshElement* newElem = 0;
1416       if ( the13Diag ) {
1417         aMesh->ChangeElementNodes( elem, aNodes, 3 );
1418         newElem = aMesh->AddFace( aNodes[2], aNodes[3], aNodes[0] );
1419       }
1420       else {
1421         aMesh->ChangeElementNodes( elem, &aNodes[1], 3 );
1422         newElem = aMesh->AddFace( aNodes[3], aNodes[0], aNodes[1] );
1423       }
1424       myLastCreatedElems.Append(newElem);
1425       // put a new triangle on the same shape and add to the same groups
1426       if ( aShapeId )
1427         aMesh->SetMeshElementOnShape( newElem, aShapeId );
1428       AddToSameGroups( newElem, elem, aMesh );
1429     }
1430
1431     // Quadratic quadrangle
1432
1433     if( elem->NbNodes()==8 && elem->IsQuadratic() ) {
1434
1435       // get surface elem is on
1436       int aShapeId = FindShape( elem );
1437       if ( aShapeId != helper.GetSubShapeID() ) {
1438         surface.Nullify();
1439         TopoDS_Shape shape;
1440         if ( aShapeId > 0 )
1441           shape = aMesh->IndexToShape( aShapeId );
1442         if ( !shape.IsNull() && shape.ShapeType() == TopAbs_FACE ) {
1443           TopoDS_Face face = TopoDS::Face( shape );
1444           surface = BRep_Tool::Surface( face );
1445           if ( !surface.IsNull() )
1446             helper.SetSubShape( shape );
1447         }
1448       }
1449
1450       const SMDS_MeshNode* aNodes [8];
1451       const SMDS_MeshNode* inFaceNode = 0;
1452       SMDS_ElemIteratorPtr itN = elem->nodesIterator();
1453       int i = 0;
1454       while ( itN->more() ) {
1455         aNodes[ i++ ] = static_cast<const SMDS_MeshNode*>( itN->next() );
1456         if ( !inFaceNode && helper.GetNodeUVneedInFaceNode() &&
1457              aNodes[ i-1 ]->GetPosition()->GetTypeOfPosition() == SMDS_TOP_FACE )
1458         {
1459           inFaceNode = aNodes[ i-1 ];
1460         }
1461       }
1462
1463       // find middle point for (0,1,2,3)
1464       // and create a node in this point;
1465       gp_XYZ p( 0,0,0 );
1466       if ( surface.IsNull() ) {
1467         for(i=0; i<4; i++)
1468           p += gp_XYZ(aNodes[i]->X(), aNodes[i]->Y(), aNodes[i]->Z() );
1469         p /= 4;
1470       }
1471       else {
1472         TopoDS_Face geomFace = TopoDS::Face( helper.GetSubShape() );
1473         gp_XY uv( 0,0 );
1474         for(i=0; i<4; i++)
1475           uv += helper.GetNodeUV( geomFace, aNodes[i], inFaceNode );
1476         uv /= 4.;
1477         p = surface->Value( uv.X(), uv.Y() ).XYZ();
1478       }
1479       const SMDS_MeshNode* newN = aMesh->AddNode( p.X(), p.Y(), p.Z() );
1480       myLastCreatedNodes.Append(newN);
1481
1482       // create a new element
1483       const SMDS_MeshElement* newElem = 0;
1484       const SMDS_MeshNode* N[6];
1485       if ( the13Diag ) {
1486         N[0] = aNodes[0];
1487         N[1] = aNodes[1];
1488         N[2] = aNodes[2];
1489         N[3] = aNodes[4];
1490         N[4] = aNodes[5];
1491         N[5] = newN;
1492         newElem = aMesh->AddFace(aNodes[2], aNodes[3], aNodes[0],
1493                                  aNodes[6], aNodes[7], newN );
1494       }
1495       else {
1496         N[0] = aNodes[1];
1497         N[1] = aNodes[2];
1498         N[2] = aNodes[3];
1499         N[3] = aNodes[5];
1500         N[4] = aNodes[6];
1501         N[5] = newN;
1502         newElem = aMesh->AddFace(aNodes[3], aNodes[0], aNodes[1],
1503                                  aNodes[7], aNodes[4], newN );
1504       }
1505       myLastCreatedElems.Append(newElem);
1506       aMesh->ChangeElementNodes( elem, N, 6 );
1507       // put a new triangle on the same shape and add to the same groups
1508       if ( aShapeId )
1509         aMesh->SetMeshElementOnShape( newElem, aShapeId );
1510       AddToSameGroups( newElem, elem, aMesh );
1511     }
1512   }
1513
1514   return true;
1515 }
1516
1517 //=======================================================================
1518 //function : getAngle
1519 //purpose  :
1520 //=======================================================================
1521
1522 double getAngle(const SMDS_MeshElement * tr1,
1523                 const SMDS_MeshElement * tr2,
1524                 const SMDS_MeshNode *    n1,
1525                 const SMDS_MeshNode *    n2)
1526 {
1527   double angle = 2*PI; // bad angle
1528
1529   // get normals
1530   SMESH::Controls::TSequenceOfXYZ P1, P2;
1531   if ( !SMESH::Controls::NumericalFunctor::GetPoints( tr1, P1 ) ||
1532        !SMESH::Controls::NumericalFunctor::GetPoints( tr2, P2 ))
1533     return angle;
1534   gp_Vec N1,N2;
1535   if(!tr1->IsQuadratic())
1536     N1 = gp_Vec( P1(2) - P1(1) ) ^ gp_Vec( P1(3) - P1(1) );
1537   else
1538     N1 = gp_Vec( P1(3) - P1(1) ) ^ gp_Vec( P1(5) - P1(1) );
1539   if ( N1.SquareMagnitude() <= gp::Resolution() )
1540     return angle;
1541   if(!tr2->IsQuadratic())
1542     N2 = gp_Vec( P2(2) - P2(1) ) ^ gp_Vec( P2(3) - P2(1) );
1543   else
1544     N2 = gp_Vec( P2(3) - P2(1) ) ^ gp_Vec( P2(5) - P2(1) );
1545   if ( N2.SquareMagnitude() <= gp::Resolution() )
1546     return angle;
1547
1548   // find the first diagonal node n1 in the triangles:
1549   // take in account a diagonal link orientation
1550   const SMDS_MeshElement *nFirst[2], *tr[] = { tr1, tr2 };
1551   for ( int t = 0; t < 2; t++ ) {
1552     SMDS_ElemIteratorPtr it = tr[ t ]->nodesIterator();
1553     int i = 0, iDiag = -1;
1554     while ( it->more()) {
1555       const SMDS_MeshElement *n = it->next();
1556       if ( n == n1 || n == n2 )
1557         if ( iDiag < 0)
1558           iDiag = i;
1559         else {
1560           if ( i - iDiag == 1 )
1561             nFirst[ t ] = ( n == n1 ? n2 : n1 );
1562           else
1563             nFirst[ t ] = n;
1564           break;
1565         }
1566       i++;
1567     }
1568   }
1569   if ( nFirst[ 0 ] == nFirst[ 1 ] )
1570     N2.Reverse();
1571
1572   angle = N1.Angle( N2 );
1573   //SCRUTE( angle );
1574   return angle;
1575 }
1576
1577 // =================================================
1578 // class generating a unique ID for a pair of nodes
1579 // and able to return nodes by that ID
1580 // =================================================
1581 class LinkID_Gen {
1582 public:
1583
1584   LinkID_Gen( const SMESHDS_Mesh* theMesh )
1585     :myMesh( theMesh ), myMaxID( theMesh->MaxNodeID() + 1)
1586   {}
1587
1588   long GetLinkID (const SMDS_MeshNode * n1,
1589                   const SMDS_MeshNode * n2) const
1590   {
1591     return ( Min(n1->GetID(),n2->GetID()) * myMaxID + Max(n1->GetID(),n2->GetID()));
1592   }
1593
1594   bool GetNodes (const long             theLinkID,
1595                  const SMDS_MeshNode* & theNode1,
1596                  const SMDS_MeshNode* & theNode2) const
1597   {
1598     theNode1 = myMesh->FindNode( theLinkID / myMaxID );
1599     if ( !theNode1 ) return false;
1600     theNode2 = myMesh->FindNode( theLinkID % myMaxID );
1601     if ( !theNode2 ) return false;
1602     return true;
1603   }
1604
1605 private:
1606   LinkID_Gen();
1607   const SMESHDS_Mesh* myMesh;
1608   long                myMaxID;
1609 };
1610
1611
1612 //=======================================================================
1613 //function : TriToQuad
1614 //purpose  : Fuse neighbour triangles into quadrangles.
1615 //           theCrit is used to select a neighbour to fuse with.
1616 //           theMaxAngle is a max angle between element normals at which
1617 //           fusion is still performed.
1618 //=======================================================================
1619
1620 bool SMESH_MeshEditor::TriToQuad (TIDSortedElemSet &                   theElems,
1621                                   SMESH::Controls::NumericalFunctorPtr theCrit,
1622                                   const double                         theMaxAngle)
1623 {
1624   myLastCreatedElems.Clear();
1625   myLastCreatedNodes.Clear();
1626
1627   MESSAGE( "::TriToQuad()" );
1628
1629   if ( !theCrit.get() )
1630     return false;
1631
1632   SMESHDS_Mesh * aMesh = GetMeshDS();
1633
1634   // Prepare data for algo: build
1635   // 1. map of elements with their linkIDs
1636   // 2. map of linkIDs with their elements
1637
1638   map< SMESH_TLink, list< const SMDS_MeshElement* > > mapLi_listEl;
1639   map< SMESH_TLink, list< const SMDS_MeshElement* > >::iterator itLE;
1640   map< const SMDS_MeshElement*, set< SMESH_TLink > >  mapEl_setLi;
1641   map< const SMDS_MeshElement*, set< SMESH_TLink > >::iterator itEL;
1642
1643   TIDSortedElemSet::iterator itElem;
1644   for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
1645     const SMDS_MeshElement* elem = *itElem;
1646     if(!elem || elem->GetType() != SMDSAbs_Face ) continue;
1647     bool IsTria = elem->NbNodes()==3 || (elem->NbNodes()==6 && elem->IsQuadratic());
1648     if(!IsTria) continue;
1649
1650     // retrieve element nodes
1651     const SMDS_MeshNode* aNodes [4];
1652     SMDS_ElemIteratorPtr itN = elem->nodesIterator();
1653     int i = 0;
1654     while ( i<3 )
1655       aNodes[ i++ ] = cast2Node( itN->next() );
1656     aNodes[ 3 ] = aNodes[ 0 ];
1657
1658     // fill maps
1659     for ( i = 0; i < 3; i++ ) {
1660       SMESH_TLink link( aNodes[i], aNodes[i+1] );
1661       // check if elements sharing a link can be fused
1662       itLE = mapLi_listEl.find( link );
1663       if ( itLE != mapLi_listEl.end() ) {
1664         if ((*itLE).second.size() > 1 ) // consider only 2 elems adjacent by a link
1665           continue;
1666         const SMDS_MeshElement* elem2 = (*itLE).second.front();
1667         //if ( FindShape( elem ) != FindShape( elem2 ))
1668         //  continue; // do not fuse triangles laying on different shapes
1669         if ( getAngle( elem, elem2, aNodes[i], aNodes[i+1] ) > theMaxAngle )
1670           continue; // avoid making badly shaped quads
1671         (*itLE).second.push_back( elem );
1672       }
1673       else {
1674         mapLi_listEl[ link ].push_back( elem );
1675       }
1676       mapEl_setLi [ elem ].insert( link );
1677     }
1678   }
1679   // Clean the maps from the links shared by a sole element, ie
1680   // links to which only one element is bound in mapLi_listEl
1681
1682   for ( itLE = mapLi_listEl.begin(); itLE != mapLi_listEl.end(); itLE++ ) {
1683     int nbElems = (*itLE).second.size();
1684     if ( nbElems < 2  ) {
1685       const SMDS_MeshElement* elem = (*itLE).second.front();
1686       SMESH_TLink link = (*itLE).first;
1687       mapEl_setLi[ elem ].erase( link );
1688       if ( mapEl_setLi[ elem ].empty() )
1689         mapEl_setLi.erase( elem );
1690     }
1691   }
1692
1693   // Algo: fuse triangles into quadrangles
1694
1695   while ( ! mapEl_setLi.empty() ) {
1696     // Look for the start element:
1697     // the element having the least nb of shared links
1698     const SMDS_MeshElement* startElem = 0;
1699     int minNbLinks = 4;
1700     for ( itEL = mapEl_setLi.begin(); itEL != mapEl_setLi.end(); itEL++ ) {
1701       int nbLinks = (*itEL).second.size();
1702       if ( nbLinks < minNbLinks ) {
1703         startElem = (*itEL).first;
1704         minNbLinks = nbLinks;
1705         if ( minNbLinks == 1 )
1706           break;
1707       }
1708     }
1709
1710     // search elements to fuse starting from startElem or links of elements
1711     // fused earlyer - startLinks
1712     list< SMESH_TLink > startLinks;
1713     while ( startElem || !startLinks.empty() ) {
1714       while ( !startElem && !startLinks.empty() ) {
1715         // Get an element to start, by a link
1716         SMESH_TLink linkId = startLinks.front();
1717         startLinks.pop_front();
1718         itLE = mapLi_listEl.find( linkId );
1719         if ( itLE != mapLi_listEl.end() ) {
1720           list< const SMDS_MeshElement* > & listElem = (*itLE).second;
1721           list< const SMDS_MeshElement* >::iterator itE = listElem.begin();
1722           for ( ; itE != listElem.end() ; itE++ )
1723             if ( mapEl_setLi.find( (*itE) ) != mapEl_setLi.end() )
1724               startElem = (*itE);
1725           mapLi_listEl.erase( itLE );
1726         }
1727       }
1728
1729       if ( startElem ) {
1730         // Get candidates to be fused
1731         const SMDS_MeshElement *tr1 = startElem, *tr2 = 0, *tr3 = 0;
1732         const SMESH_TLink *link12, *link13;
1733         startElem = 0;
1734         ASSERT( mapEl_setLi.find( tr1 ) != mapEl_setLi.end() );
1735         set< SMESH_TLink >& setLi = mapEl_setLi[ tr1 ];
1736         ASSERT( !setLi.empty() );
1737         set< SMESH_TLink >::iterator itLi;
1738         for ( itLi = setLi.begin(); itLi != setLi.end(); itLi++ )
1739         {
1740           const SMESH_TLink & link = (*itLi);
1741           itLE = mapLi_listEl.find( link );
1742           if ( itLE == mapLi_listEl.end() )
1743             continue;
1744
1745           const SMDS_MeshElement* elem = (*itLE).second.front();
1746           if ( elem == tr1 )
1747             elem = (*itLE).second.back();
1748           mapLi_listEl.erase( itLE );
1749           if ( mapEl_setLi.find( elem ) == mapEl_setLi.end())
1750             continue;
1751           if ( tr2 ) {
1752             tr3 = elem;
1753             link13 = &link;
1754           }
1755           else {
1756             tr2 = elem;
1757             link12 = &link;
1758           }
1759
1760           // add other links of elem to list of links to re-start from
1761           set< SMESH_TLink >& links = mapEl_setLi[ elem ];
1762           set< SMESH_TLink >::iterator it;
1763           for ( it = links.begin(); it != links.end(); it++ ) {
1764             const SMESH_TLink& link2 = (*it);
1765             if ( link2 != link )
1766               startLinks.push_back( link2 );
1767           }
1768         }
1769
1770         // Get nodes of possible quadrangles
1771         const SMDS_MeshNode *n12 [4], *n13 [4];
1772         bool Ok12 = false, Ok13 = false;
1773         const SMDS_MeshNode *linkNode1, *linkNode2;
1774         if(tr2) {
1775           linkNode1 = link12->first;
1776           linkNode2 = link12->second;
1777           if ( tr2 && getQuadrangleNodes( n12, linkNode1, linkNode2, tr1, tr2 ))
1778             Ok12 = true;
1779         }
1780         if(tr3) {
1781           linkNode1 = link13->first;
1782           linkNode2 = link13->second;
1783           if ( tr3 && getQuadrangleNodes( n13, linkNode1, linkNode2, tr1, tr3 ))
1784             Ok13 = true;
1785         }
1786
1787         // Choose a pair to fuse
1788         if ( Ok12 && Ok13 ) {
1789           SMDS_FaceOfNodes quad12 ( n12[ 0 ], n12[ 1 ], n12[ 2 ], n12[ 3 ] );
1790           SMDS_FaceOfNodes quad13 ( n13[ 0 ], n13[ 1 ], n13[ 2 ], n13[ 3 ] );
1791           double aBadRate12 = getBadRate( &quad12, theCrit );
1792           double aBadRate13 = getBadRate( &quad13, theCrit );
1793           if (  aBadRate13 < aBadRate12 )
1794             Ok12 = false;
1795           else
1796             Ok13 = false;
1797         }
1798
1799         // Make quadrangles
1800         // and remove fused elems and removed links from the maps
1801         mapEl_setLi.erase( tr1 );
1802         if ( Ok12 ) {
1803           mapEl_setLi.erase( tr2 );
1804           mapLi_listEl.erase( *link12 );
1805           if(tr1->NbNodes()==3) {
1806             if( tr1->GetID() < tr2->GetID() ) {
1807               aMesh->ChangeElementNodes( tr1, n12, 4 );
1808               myLastCreatedElems.Append(tr1);
1809               aMesh->RemoveElement( tr2 );
1810             }
1811             else {
1812               aMesh->ChangeElementNodes( tr2, n12, 4 );
1813               myLastCreatedElems.Append(tr2);
1814               aMesh->RemoveElement( tr1);
1815             }
1816           }
1817           else {
1818             const SMDS_MeshNode* N1 [6];
1819             const SMDS_MeshNode* N2 [6];
1820             GetNodesFromTwoTria(tr1,tr2,N1,N2);
1821             // now we receive following N1 and N2 (using numeration as above image)
1822             // tria1 : (1 2 4 5 9 7)  and  tria2 : (3 4 2 8 9 6)
1823             // i.e. first nodes from both arrays determ new diagonal
1824             const SMDS_MeshNode* aNodes[8];
1825             aNodes[0] = N1[0];
1826             aNodes[1] = N1[1];
1827             aNodes[2] = N2[0];
1828             aNodes[3] = N2[1];
1829             aNodes[4] = N1[3];
1830             aNodes[5] = N2[5];
1831             aNodes[6] = N2[3];
1832             aNodes[7] = N1[5];
1833             if( tr1->GetID() < tr2->GetID() ) {
1834               GetMeshDS()->ChangeElementNodes( tr1, aNodes, 8 );
1835               myLastCreatedElems.Append(tr1);
1836               GetMeshDS()->RemoveElement( tr2 );
1837             }
1838             else {
1839               GetMeshDS()->ChangeElementNodes( tr2, aNodes, 8 );
1840               myLastCreatedElems.Append(tr2);
1841               GetMeshDS()->RemoveElement( tr1 );
1842             }
1843             // remove middle node (9)
1844             GetMeshDS()->RemoveNode( N1[4] );
1845           }
1846         }
1847         else if ( Ok13 ) {
1848           mapEl_setLi.erase( tr3 );
1849           mapLi_listEl.erase( *link13 );
1850           if(tr1->NbNodes()==3) {
1851             if( tr1->GetID() < tr2->GetID() ) {
1852               aMesh->ChangeElementNodes( tr1, n13, 4 );
1853               myLastCreatedElems.Append(tr1);
1854               aMesh->RemoveElement( tr3 );
1855             }
1856             else {
1857               aMesh->ChangeElementNodes( tr3, n13, 4 );
1858               myLastCreatedElems.Append(tr3);
1859               aMesh->RemoveElement( tr1 );
1860             }
1861           }
1862           else {
1863             const SMDS_MeshNode* N1 [6];
1864             const SMDS_MeshNode* N2 [6];
1865             GetNodesFromTwoTria(tr1,tr3,N1,N2);
1866             // now we receive following N1 and N2 (using numeration as above image)
1867             // tria1 : (1 2 4 5 9 7)  and  tria2 : (3 4 2 8 9 6)
1868             // i.e. first nodes from both arrays determ new diagonal
1869             const SMDS_MeshNode* aNodes[8];
1870             aNodes[0] = N1[0];
1871             aNodes[1] = N1[1];
1872             aNodes[2] = N2[0];
1873             aNodes[3] = N2[1];
1874             aNodes[4] = N1[3];
1875             aNodes[5] = N2[5];
1876             aNodes[6] = N2[3];
1877             aNodes[7] = N1[5];
1878             if( tr1->GetID() < tr2->GetID() ) {
1879               GetMeshDS()->ChangeElementNodes( tr1, aNodes, 8 );
1880               myLastCreatedElems.Append(tr1);
1881               GetMeshDS()->RemoveElement( tr3 );
1882             }
1883             else {
1884               GetMeshDS()->ChangeElementNodes( tr3, aNodes, 8 );
1885               myLastCreatedElems.Append(tr3);
1886               GetMeshDS()->RemoveElement( tr1 );
1887             }
1888             // remove middle node (9)
1889             GetMeshDS()->RemoveNode( N1[4] );
1890           }
1891         }
1892
1893         // Next element to fuse: the rejected one
1894         if ( tr3 )
1895           startElem = Ok12 ? tr3 : tr2;
1896
1897       } // if ( startElem )
1898     } // while ( startElem || !startLinks.empty() )
1899   } // while ( ! mapEl_setLi.empty() )
1900
1901   return true;
1902 }
1903
1904
1905 /*#define DUMPSO(txt) \
1906 //  cout << txt << endl;
1907 //=============================================================================
1908 //
1909 //
1910 //
1911 //=============================================================================
1912 static void swap( int i1, int i2, int idNodes[], gp_Pnt P[] )
1913 {
1914 if ( i1 == i2 )
1915 return;
1916 int tmp = idNodes[ i1 ];
1917 idNodes[ i1 ] = idNodes[ i2 ];
1918 idNodes[ i2 ] = tmp;
1919 gp_Pnt Ptmp = P[ i1 ];
1920 P[ i1 ] = P[ i2 ];
1921 P[ i2 ] = Ptmp;
1922 DUMPSO( i1 << "(" << idNodes[ i2 ] << ") <-> " << i2 << "(" << idNodes[ i1 ] << ")");
1923 }
1924
1925 //=======================================================================
1926 //function : SortQuadNodes
1927 //purpose  : Set 4 nodes of a quadrangle face in a good order.
1928 //           Swap 1<->2 or 2<->3 nodes and correspondingly return
1929 //           1 or 2 else 0.
1930 //=======================================================================
1931
1932 int SMESH_MeshEditor::SortQuadNodes (const SMDS_Mesh * theMesh,
1933 int               idNodes[] )
1934 {
1935   gp_Pnt P[4];
1936   int i;
1937   for ( i = 0; i < 4; i++ ) {
1938     const SMDS_MeshNode *n = theMesh->FindNode( idNodes[i] );
1939     if ( !n ) return 0;
1940     P[ i ].SetCoord( n->X(), n->Y(), n->Z() );
1941   }
1942
1943   gp_Vec V1(P[0], P[1]);
1944   gp_Vec V2(P[0], P[2]);
1945   gp_Vec V3(P[0], P[3]);
1946
1947   gp_Vec Cross1 = V1 ^ V2;
1948   gp_Vec Cross2 = V2 ^ V3;
1949
1950   i = 0;
1951   if (Cross1.Dot(Cross2) < 0)
1952   {
1953     Cross1 = V2 ^ V1;
1954     Cross2 = V1 ^ V3;
1955
1956     if (Cross1.Dot(Cross2) < 0)
1957       i = 2;
1958     else
1959       i = 1;
1960     swap ( i, i + 1, idNodes, P );
1961
1962     //     for ( int ii = 0; ii < 4; ii++ ) {
1963     //       const SMDS_MeshNode *n = theMesh->FindNode( idNodes[ii] );
1964     //       DUMPSO( ii << "(" << idNodes[ii] <<") : "<<n->X()<<" "<<n->Y()<<" "<<n->Z());
1965     //     }
1966   }
1967   return i;
1968 }
1969
1970 //=======================================================================
1971 //function : SortHexaNodes
1972 //purpose  : Set 8 nodes of a hexahedron in a good order.
1973 //           Return success status
1974 //=======================================================================
1975
1976 bool SMESH_MeshEditor::SortHexaNodes (const SMDS_Mesh * theMesh,
1977                                       int               idNodes[] )
1978 {
1979   gp_Pnt P[8];
1980   int i;
1981   DUMPSO( "INPUT: ========================================");
1982   for ( i = 0; i < 8; i++ ) {
1983     const SMDS_MeshNode *n = theMesh->FindNode( idNodes[i] );
1984     if ( !n ) return false;
1985     P[ i ].SetCoord( n->X(), n->Y(), n->Z() );
1986     DUMPSO( i << "(" << idNodes[i] <<") : "<<n->X()<<" "<<n->Y()<<" "<<n->Z());
1987   }
1988   DUMPSO( "========================================");
1989
1990
1991   set<int> faceNodes;  // ids of bottom face nodes, to be found
1992   set<int> checkedId1; // ids of tried 2-nd nodes
1993   Standard_Real leastDist = DBL_MAX; // dist of the 4-th node from 123 plane
1994   const Standard_Real tol = 1.e-6;   // tolerance to find nodes in plane
1995   int iMin, iLoop1 = 0;
1996
1997   // Loop to try the 2-nd nodes
1998
1999   while ( leastDist > DBL_MIN && ++iLoop1 < 8 )
2000   {
2001     // Find not checked 2-nd node
2002     for ( i = 1; i < 8; i++ )
2003       if ( checkedId1.find( idNodes[i] ) == checkedId1.end() ) {
2004         int id1 = idNodes[i];
2005         swap ( 1, i, idNodes, P );
2006         checkedId1.insert ( id1 );
2007         break;
2008       }
2009
2010     // Find the 3-d node so that 1-2-3 triangle to be on a hexa face,
2011     // ie that all but meybe one (id3 which is on the same face) nodes
2012     // lay on the same side from the triangle plane.
2013
2014     bool manyInPlane = false; // more than 4 nodes lay in plane
2015     int iLoop2 = 0;
2016     while ( ++iLoop2 < 6 ) {
2017
2018       // get 1-2-3 plane coeffs
2019       Standard_Real A, B, C, D;
2020       gp_Vec N = gp_Vec (P[0], P[1]).Crossed( gp_Vec (P[0], P[2]) );
2021       if ( N.SquareMagnitude() > gp::Resolution() )
2022       {
2023         gp_Pln pln ( P[0], N );
2024         pln.Coefficients( A, B, C, D );
2025
2026         // find the node (iMin) closest to pln
2027         Standard_Real dist[ 8 ], minDist = DBL_MAX;
2028         set<int> idInPln;
2029         for ( i = 3; i < 8; i++ ) {
2030           dist[i] = A * P[i].X() + B * P[i].Y() + C * P[i].Z() + D;
2031           if ( fabs( dist[i] ) < minDist ) {
2032             minDist = fabs( dist[i] );
2033             iMin = i;
2034           }
2035           if ( fabs( dist[i] ) <= tol )
2036             idInPln.insert( idNodes[i] );
2037         }
2038
2039         // there should not be more than 4 nodes in bottom plane
2040         if ( idInPln.size() > 1 )
2041         {
2042           DUMPSO( "### idInPln.size() = " << idInPln.size());
2043           // idInPlane does not contain the first 3 nodes
2044           if ( manyInPlane || idInPln.size() == 5)
2045             return false; // all nodes in one plane
2046           manyInPlane = true;
2047
2048           // set the 1-st node to be not in plane
2049           for ( i = 3; i < 8; i++ ) {
2050             if ( idInPln.find( idNodes[ i ] ) == idInPln.end() ) {
2051               DUMPSO( "### Reset 0-th node");
2052               swap( 0, i, idNodes, P );
2053               break;
2054             }
2055           }
2056
2057           // reset to re-check second nodes
2058           leastDist = DBL_MAX;
2059           faceNodes.clear();
2060           checkedId1.clear();
2061           iLoop1 = 0;
2062           break; // from iLoop2;
2063         }
2064
2065         // check that the other 4 nodes are on the same side
2066         bool sameSide = true;
2067         bool isNeg = dist[ iMin == 3 ? 4 : 3 ] <= 0.;
2068         for ( i = 3; sameSide && i < 8; i++ ) {
2069           if ( i != iMin )
2070             sameSide = ( isNeg == dist[i] <= 0.);
2071         }
2072
2073         // keep best solution
2074         if ( sameSide && minDist < leastDist ) {
2075           leastDist = minDist;
2076           faceNodes.clear();
2077           faceNodes.insert( idNodes[ 1 ] );
2078           faceNodes.insert( idNodes[ 2 ] );
2079           faceNodes.insert( idNodes[ iMin ] );
2080           DUMPSO( "loop " << iLoop2 << " id2 " << idNodes[ 1 ] << " id3 " << idNodes[ 2 ]
2081                   << " leastDist = " << leastDist);
2082           if ( leastDist <= DBL_MIN )
2083             break;
2084         }
2085       }
2086
2087       // set next 3-d node to check
2088       int iNext = 2 + iLoop2;
2089       if ( iNext < 8 ) {
2090         DUMPSO( "Try 2-nd");
2091         swap ( 2, iNext, idNodes, P );
2092       }
2093     } // while ( iLoop2 < 6 )
2094   } // iLoop1
2095
2096   if ( faceNodes.empty() ) return false;
2097
2098   // Put the faceNodes in proper places
2099   for ( i = 4; i < 8; i++ ) {
2100     if ( faceNodes.find( idNodes[ i ] ) != faceNodes.end() ) {
2101       // find a place to put
2102       int iTo = 1;
2103       while ( faceNodes.find( idNodes[ iTo ] ) != faceNodes.end() )
2104         iTo++;
2105       DUMPSO( "Set faceNodes");
2106       swap ( iTo, i, idNodes, P );
2107     }
2108   }
2109
2110
2111   // Set nodes of the found bottom face in good order
2112   DUMPSO( " Found bottom face: ");
2113   i = SortQuadNodes( theMesh, idNodes );
2114   if ( i ) {
2115     gp_Pnt Ptmp = P[ i ];
2116     P[ i ] = P[ i+1 ];
2117     P[ i+1 ] = Ptmp;
2118   }
2119   //   else
2120   //     for ( int ii = 0; ii < 4; ii++ ) {
2121   //       const SMDS_MeshNode *n = theMesh->FindNode( idNodes[ii] );
2122   //       DUMPSO( ii << "(" << idNodes[ii] <<") : "<<n->X()<<" "<<n->Y()<<" "<<n->Z());
2123   //    }
2124
2125   // Gravity center of the top and bottom faces
2126   gp_Pnt aGCb = ( P[0].XYZ() + P[1].XYZ() + P[2].XYZ() + P[3].XYZ() ) / 4.;
2127   gp_Pnt aGCt = ( P[4].XYZ() + P[5].XYZ() + P[6].XYZ() + P[7].XYZ() ) / 4.;
2128
2129   // Get direction from the bottom to the top face
2130   gp_Vec upDir ( aGCb, aGCt );
2131   Standard_Real upDirSize = upDir.Magnitude();
2132   if ( upDirSize <= gp::Resolution() ) return false;
2133   upDir / upDirSize;
2134
2135   // Assure that the bottom face normal points up
2136   gp_Vec Nb = gp_Vec (P[0], P[1]).Crossed( gp_Vec (P[0], P[2]) );
2137   Nb += gp_Vec (P[0], P[2]).Crossed( gp_Vec (P[0], P[3]) );
2138   if ( Nb.Dot( upDir ) < 0 ) {
2139     DUMPSO( "Reverse bottom face");
2140     swap( 1, 3, idNodes, P );
2141   }
2142
2143   // Find 5-th node - the one closest to the 1-st among the last 4 nodes.
2144   Standard_Real minDist = DBL_MAX;
2145   for ( i = 4; i < 8; i++ ) {
2146     // projection of P[i] to the plane defined by P[0] and upDir
2147     gp_Pnt Pp = P[i].Translated( upDir * ( upDir.Dot( gp_Vec( P[i], P[0] ))));
2148     Standard_Real sqDist = P[0].SquareDistance( Pp );
2149     if ( sqDist < minDist ) {
2150       minDist = sqDist;
2151       iMin = i;
2152     }
2153   }
2154   DUMPSO( "Set 4-th");
2155   swap ( 4, iMin, idNodes, P );
2156
2157   // Set nodes of the top face in good order
2158   DUMPSO( "Sort top face");
2159   i = SortQuadNodes( theMesh, &idNodes[4] );
2160   if ( i ) {
2161     i += 4;
2162     gp_Pnt Ptmp = P[ i ];
2163     P[ i ] = P[ i+1 ];
2164     P[ i+1 ] = Ptmp;
2165   }
2166
2167   // Assure that direction of the top face normal is from the bottom face
2168   gp_Vec Nt = gp_Vec (P[4], P[5]).Crossed( gp_Vec (P[4], P[6]) );
2169   Nt += gp_Vec (P[4], P[6]).Crossed( gp_Vec (P[4], P[7]) );
2170   if ( Nt.Dot( upDir ) < 0 ) {
2171     DUMPSO( "Reverse top face");
2172     swap( 5, 7, idNodes, P );
2173   }
2174
2175   //   DUMPSO( "OUTPUT: ========================================");
2176   //   for ( i = 0; i < 8; i++ ) {
2177   //     float *p = ugrid->GetPoint(idNodes[i]);
2178   //     DUMPSO( i << "(" << idNodes[i] << ") : " << p[0] << " " << p[1] << " " << p[2]);
2179   //   }
2180
2181   return true;
2182 }*/
2183
2184 //================================================================================
2185 /*!
2186  * \brief Return nodes linked to the given one
2187  * \param theNode - the node
2188  * \param linkedNodes - the found nodes
2189  * \param type - the type of elements to check
2190  *
2191  * Medium nodes are ignored
2192  */
2193 //================================================================================
2194
2195 void SMESH_MeshEditor::GetLinkedNodes( const SMDS_MeshNode* theNode,
2196                                        TIDSortedElemSet &   linkedNodes,
2197                                        SMDSAbs_ElementType  type )
2198 {
2199   SMDS_ElemIteratorPtr elemIt = theNode->GetInverseElementIterator(type);
2200   while ( elemIt->more() )
2201   {
2202     const SMDS_MeshElement* elem = elemIt->next();
2203     SMDS_ElemIteratorPtr nodeIt = elem->nodesIterator();
2204     if ( elem->GetType() == SMDSAbs_Volume )
2205     {
2206       SMDS_VolumeTool vol( elem );
2207       while ( nodeIt->more() ) {
2208         const SMDS_MeshNode* n = cast2Node( nodeIt->next() );
2209         if ( theNode != n && vol.IsLinked( theNode, n ))
2210           linkedNodes.insert( n );
2211       }
2212     }
2213     else
2214     {
2215       for ( int i = 0; nodeIt->more(); ++i ) {
2216         const SMDS_MeshNode* n = cast2Node( nodeIt->next() );
2217         if ( n == theNode ) {
2218           int iBefore = i - 1;
2219           int iAfter  = i + 1;
2220           if ( elem->IsQuadratic() ) {
2221             int nb = elem->NbNodes() / 2;
2222             iAfter  = SMESH_MesherHelper::WrapIndex( iAfter, nb );
2223             iBefore = SMESH_MesherHelper::WrapIndex( iBefore, nb );
2224           }
2225           linkedNodes.insert( elem->GetNodeWrap( iAfter ));
2226           linkedNodes.insert( elem->GetNodeWrap( iBefore ));
2227         }
2228       }
2229     }
2230   }
2231 }
2232
2233 //=======================================================================
2234 //function : laplacianSmooth
2235 //purpose  : pulls theNode toward the center of surrounding nodes directly
2236 //           connected to that node along an element edge
2237 //=======================================================================
2238
2239 void laplacianSmooth(const SMDS_MeshNode*                 theNode,
2240                      const Handle(Geom_Surface)&          theSurface,
2241                      map< const SMDS_MeshNode*, gp_XY* >& theUVMap)
2242 {
2243   // find surrounding nodes
2244
2245   TIDSortedElemSet nodeSet;
2246   SMESH_MeshEditor::GetLinkedNodes( theNode, nodeSet, SMDSAbs_Face );
2247
2248   // compute new coodrs
2249
2250   double coord[] = { 0., 0., 0. };
2251   TIDSortedElemSet::iterator nodeSetIt = nodeSet.begin();
2252   for ( ; nodeSetIt != nodeSet.end(); nodeSetIt++ ) {
2253     const SMDS_MeshNode* node = cast2Node(*nodeSetIt);
2254     if ( theSurface.IsNull() ) { // smooth in 3D
2255       coord[0] += node->X();
2256       coord[1] += node->Y();
2257       coord[2] += node->Z();
2258     }
2259     else { // smooth in 2D
2260       ASSERT( theUVMap.find( node ) != theUVMap.end() );
2261       gp_XY* uv = theUVMap[ node ];
2262       coord[0] += uv->X();
2263       coord[1] += uv->Y();
2264     }
2265   }
2266   int nbNodes = nodeSet.size();
2267   if ( !nbNodes )
2268     return;
2269   coord[0] /= nbNodes;
2270   coord[1] /= nbNodes;
2271
2272   if ( !theSurface.IsNull() ) {
2273     ASSERT( theUVMap.find( theNode ) != theUVMap.end() );
2274     theUVMap[ theNode ]->SetCoord( coord[0], coord[1] );
2275     gp_Pnt p3d = theSurface->Value( coord[0], coord[1] );
2276     coord[0] = p3d.X();
2277     coord[1] = p3d.Y();
2278     coord[2] = p3d.Z();
2279   }
2280   else
2281     coord[2] /= nbNodes;
2282
2283   // move node
2284
2285   const_cast< SMDS_MeshNode* >( theNode )->setXYZ(coord[0],coord[1],coord[2]);
2286 }
2287
2288 //=======================================================================
2289 //function : centroidalSmooth
2290 //purpose  : pulls theNode toward the element-area-weighted centroid of the
2291 //           surrounding elements
2292 //=======================================================================
2293
2294 void centroidalSmooth(const SMDS_MeshNode*                 theNode,
2295                       const Handle(Geom_Surface)&          theSurface,
2296                       map< const SMDS_MeshNode*, gp_XY* >& theUVMap)
2297 {
2298   gp_XYZ aNewXYZ(0.,0.,0.);
2299   SMESH::Controls::Area anAreaFunc;
2300   double totalArea = 0.;
2301   int nbElems = 0;
2302
2303   // compute new XYZ
2304
2305   SMDS_ElemIteratorPtr elemIt = theNode->GetInverseElementIterator(SMDSAbs_Face);
2306   while ( elemIt->more() )
2307   {
2308     const SMDS_MeshElement* elem = elemIt->next();
2309     nbElems++;
2310
2311     gp_XYZ elemCenter(0.,0.,0.);
2312     SMESH::Controls::TSequenceOfXYZ aNodePoints;
2313     SMDS_ElemIteratorPtr itN = elem->nodesIterator();
2314     int nn = elem->NbNodes();
2315     if(elem->IsQuadratic()) nn = nn/2;
2316     int i=0;
2317     //while ( itN->more() ) {
2318     while ( i<nn ) {
2319       const SMDS_MeshNode* aNode = static_cast<const SMDS_MeshNode*>( itN->next() );
2320       i++;
2321       gp_XYZ aP( aNode->X(), aNode->Y(), aNode->Z() );
2322       aNodePoints.push_back( aP );
2323       if ( !theSurface.IsNull() ) { // smooth in 2D
2324         ASSERT( theUVMap.find( aNode ) != theUVMap.end() );
2325         gp_XY* uv = theUVMap[ aNode ];
2326         aP.SetCoord( uv->X(), uv->Y(), 0. );
2327       }
2328       elemCenter += aP;
2329     }
2330     double elemArea = anAreaFunc.GetValue( aNodePoints );
2331     totalArea += elemArea;
2332     elemCenter /= nn;
2333     aNewXYZ += elemCenter * elemArea;
2334   }
2335   aNewXYZ /= totalArea;
2336   if ( !theSurface.IsNull() ) {
2337     theUVMap[ theNode ]->SetCoord( aNewXYZ.X(), aNewXYZ.Y() );
2338     aNewXYZ = theSurface->Value( aNewXYZ.X(), aNewXYZ.Y() ).XYZ();
2339   }
2340
2341   // move node
2342
2343   const_cast< SMDS_MeshNode* >( theNode )->setXYZ(aNewXYZ.X(),aNewXYZ.Y(),aNewXYZ.Z());
2344 }
2345
2346 //=======================================================================
2347 //function : getClosestUV
2348 //purpose  : return UV of closest projection
2349 //=======================================================================
2350
2351 static bool getClosestUV (Extrema_GenExtPS& projector,
2352                           const gp_Pnt&     point,
2353                           gp_XY &           result)
2354 {
2355   projector.Perform( point );
2356   if ( projector.IsDone() ) {
2357     double u, v, minVal = DBL_MAX;
2358     for ( int i = projector.NbExt(); i > 0; i-- )
2359       if ( projector.Value( i ) < minVal ) {
2360         minVal = projector.Value( i );
2361         projector.Point( i ).Parameter( u, v );
2362       }
2363     result.SetCoord( u, v );
2364     return true;
2365   }
2366   return false;
2367 }
2368
2369 //=======================================================================
2370 //function : Smooth
2371 //purpose  : Smooth theElements during theNbIterations or until a worst
2372 //           element has aspect ratio <= theTgtAspectRatio.
2373 //           Aspect Ratio varies in range [1.0, inf].
2374 //           If theElements is empty, the whole mesh is smoothed.
2375 //           theFixedNodes contains additionally fixed nodes. Nodes built
2376 //           on edges and boundary nodes are always fixed.
2377 //=======================================================================
2378
2379 void SMESH_MeshEditor::Smooth (TIDSortedElemSet &          theElems,
2380                                set<const SMDS_MeshNode*> & theFixedNodes,
2381                                const SmoothMethod          theSmoothMethod,
2382                                const int                   theNbIterations,
2383                                double                      theTgtAspectRatio,
2384                                const bool                  the2D)
2385 {
2386   myLastCreatedElems.Clear();
2387   myLastCreatedNodes.Clear();
2388
2389   MESSAGE((theSmoothMethod==LAPLACIAN ? "LAPLACIAN" : "CENTROIDAL") << "--::Smooth()");
2390
2391   if ( theTgtAspectRatio < 1.0 )
2392     theTgtAspectRatio = 1.0;
2393
2394   const double disttol = 1.e-16;
2395
2396   SMESH::Controls::AspectRatio aQualityFunc;
2397
2398   SMESHDS_Mesh* aMesh = GetMeshDS();
2399
2400   if ( theElems.empty() ) {
2401     // add all faces to theElems
2402     SMDS_FaceIteratorPtr fIt = aMesh->facesIterator();
2403     while ( fIt->more() ) {
2404       const SMDS_MeshElement* face = fIt->next();
2405       theElems.insert( face );
2406     }
2407   }
2408   // get all face ids theElems are on
2409   set< int > faceIdSet;
2410   TIDSortedElemSet::iterator itElem;
2411   if ( the2D )
2412     for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
2413       int fId = FindShape( *itElem );
2414       // check that corresponding submesh exists and a shape is face
2415       if (fId &&
2416           faceIdSet.find( fId ) == faceIdSet.end() &&
2417           aMesh->MeshElements( fId )) {
2418         TopoDS_Shape F = aMesh->IndexToShape( fId );
2419         if ( !F.IsNull() && F.ShapeType() == TopAbs_FACE )
2420           faceIdSet.insert( fId );
2421       }
2422     }
2423   faceIdSet.insert( 0 ); // to smooth elements that are not on any TopoDS_Face
2424
2425   // ===============================================
2426   // smooth elements on each TopoDS_Face separately
2427   // ===============================================
2428
2429   set< int >::reverse_iterator fId = faceIdSet.rbegin(); // treate 0 fId at the end
2430   for ( ; fId != faceIdSet.rend(); ++fId ) {
2431     // get face surface and submesh
2432     Handle(Geom_Surface) surface;
2433     SMESHDS_SubMesh* faceSubMesh = 0;
2434     TopoDS_Face face;
2435     double fToler2 = 0, vPeriod = 0., uPeriod = 0., f,l;
2436     double u1 = 0, u2 = 0, v1 = 0, v2 = 0;
2437     bool isUPeriodic = false, isVPeriodic = false;
2438     if ( *fId ) {
2439       face = TopoDS::Face( aMesh->IndexToShape( *fId ));
2440       surface = BRep_Tool::Surface( face );
2441       faceSubMesh = aMesh->MeshElements( *fId );
2442       fToler2 = BRep_Tool::Tolerance( face );
2443       fToler2 *= fToler2 * 10.;
2444       isUPeriodic = surface->IsUPeriodic();
2445       if ( isUPeriodic )
2446         vPeriod = surface->UPeriod();
2447       isVPeriodic = surface->IsVPeriodic();
2448       if ( isVPeriodic )
2449         uPeriod = surface->VPeriod();
2450       surface->Bounds( u1, u2, v1, v2 );
2451     }
2452     // ---------------------------------------------------------
2453     // for elements on a face, find movable and fixed nodes and
2454     // compute UV for them
2455     // ---------------------------------------------------------
2456     bool checkBoundaryNodes = false;
2457     bool isQuadratic = false;
2458     set<const SMDS_MeshNode*> setMovableNodes;
2459     map< const SMDS_MeshNode*, gp_XY* > uvMap, uvMap2;
2460     list< gp_XY > listUV; // uvs the 2 uvMaps refer to
2461     list< const SMDS_MeshElement* > elemsOnFace;
2462
2463     Extrema_GenExtPS projector;
2464     GeomAdaptor_Surface surfAdaptor;
2465     if ( !surface.IsNull() ) {
2466       surfAdaptor.Load( surface );
2467       projector.Initialize( surfAdaptor, 20,20, 1e-5,1e-5 );
2468     }
2469     int nbElemOnFace = 0;
2470     itElem = theElems.begin();
2471     // loop on not yet smoothed elements: look for elems on a face
2472     while ( itElem != theElems.end() ) {
2473       if ( faceSubMesh && nbElemOnFace == faceSubMesh->NbElements() )
2474         break; // all elements found
2475
2476       const SMDS_MeshElement* elem = *itElem;
2477       if ( !elem || elem->GetType() != SMDSAbs_Face || elem->NbNodes() < 3 ||
2478            ( faceSubMesh && !faceSubMesh->Contains( elem ))) {
2479         ++itElem;
2480         continue;
2481       }
2482       elemsOnFace.push_back( elem );
2483       theElems.erase( itElem++ );
2484       nbElemOnFace++;
2485
2486       if ( !isQuadratic )
2487         isQuadratic = elem->IsQuadratic();
2488
2489       // get movable nodes of elem
2490       const SMDS_MeshNode* node;
2491       SMDS_TypeOfPosition posType;
2492       SMDS_ElemIteratorPtr itN = elem->nodesIterator();
2493       int nn = 0, nbn =  elem->NbNodes();
2494       if(elem->IsQuadratic())
2495         nbn = nbn/2;
2496       while ( nn++ < nbn ) {
2497         node = static_cast<const SMDS_MeshNode*>( itN->next() );
2498         const SMDS_PositionPtr& pos = node->GetPosition();
2499         posType = pos.get() ? pos->GetTypeOfPosition() : SMDS_TOP_3DSPACE;
2500         if (posType != SMDS_TOP_EDGE &&
2501             posType != SMDS_TOP_VERTEX &&
2502             theFixedNodes.find( node ) == theFixedNodes.end())
2503         {
2504           // check if all faces around the node are on faceSubMesh
2505           // because a node on edge may be bound to face
2506           SMDS_ElemIteratorPtr eIt = node->GetInverseElementIterator(SMDSAbs_Face);
2507           bool all = true;
2508           if ( faceSubMesh ) {
2509             while ( eIt->more() && all ) {
2510               const SMDS_MeshElement* e = eIt->next();
2511               all = faceSubMesh->Contains( e );
2512             }
2513           }
2514           if ( all )
2515             setMovableNodes.insert( node );
2516           else
2517             checkBoundaryNodes = true;
2518         }
2519         if ( posType == SMDS_TOP_3DSPACE )
2520           checkBoundaryNodes = true;
2521       }
2522
2523       if ( surface.IsNull() )
2524         continue;
2525
2526       // get nodes to check UV
2527       list< const SMDS_MeshNode* > uvCheckNodes;
2528       itN = elem->nodesIterator();
2529       nn = 0; nbn =  elem->NbNodes();
2530       if(elem->IsQuadratic())
2531         nbn = nbn/2;
2532       while ( nn++ < nbn ) {
2533         node = static_cast<const SMDS_MeshNode*>( itN->next() );
2534         if ( uvMap.find( node ) == uvMap.end() )
2535           uvCheckNodes.push_back( node );
2536         // add nodes of elems sharing node
2537         //         SMDS_ElemIteratorPtr eIt = node->GetInverseElementIterator(SMDSAbs_Face);
2538         //         while ( eIt->more() ) {
2539         //           const SMDS_MeshElement* e = eIt->next();
2540         //           if ( e != elem ) {
2541         //             SMDS_ElemIteratorPtr nIt = e->nodesIterator();
2542         //             while ( nIt->more() ) {
2543         //               const SMDS_MeshNode* n =
2544         //                 static_cast<const SMDS_MeshNode*>( nIt->next() );
2545         //               if ( uvMap.find( n ) == uvMap.end() )
2546         //                 uvCheckNodes.push_back( n );
2547         //             }
2548         //           }
2549         //         }
2550       }
2551       // check UV on face
2552       list< const SMDS_MeshNode* >::iterator n = uvCheckNodes.begin();
2553       for ( ; n != uvCheckNodes.end(); ++n ) {
2554         node = *n;
2555         gp_XY uv( 0, 0 );
2556         const SMDS_PositionPtr& pos = node->GetPosition();
2557         posType = pos.get() ? pos->GetTypeOfPosition() : SMDS_TOP_3DSPACE;
2558         // get existing UV
2559         switch ( posType ) {
2560         case SMDS_TOP_FACE: {
2561           SMDS_FacePosition* fPos = ( SMDS_FacePosition* ) pos.get();
2562           uv.SetCoord( fPos->GetUParameter(), fPos->GetVParameter() );
2563           break;
2564         }
2565         case SMDS_TOP_EDGE: {
2566           TopoDS_Shape S = aMesh->IndexToShape( pos->GetShapeId() );
2567           Handle(Geom2d_Curve) pcurve;
2568           if ( !S.IsNull() && S.ShapeType() == TopAbs_EDGE )
2569             pcurve = BRep_Tool::CurveOnSurface( TopoDS::Edge( S ), face, f,l );
2570           if ( !pcurve.IsNull() ) {
2571             double u = (( SMDS_EdgePosition* ) pos.get() )->GetUParameter();
2572             uv = pcurve->Value( u ).XY();
2573           }
2574           break;
2575         }
2576         case SMDS_TOP_VERTEX: {
2577           TopoDS_Shape S = aMesh->IndexToShape( pos->GetShapeId() );
2578           if ( !S.IsNull() && S.ShapeType() == TopAbs_VERTEX )
2579             uv = BRep_Tool::Parameters( TopoDS::Vertex( S ), face ).XY();
2580           break;
2581         }
2582         default:;
2583         }
2584         // check existing UV
2585         bool project = true;
2586         gp_Pnt pNode ( node->X(), node->Y(), node->Z() );
2587         double dist1 = DBL_MAX, dist2 = 0;
2588         if ( posType != SMDS_TOP_3DSPACE ) {
2589           dist1 = pNode.SquareDistance( surface->Value( uv.X(), uv.Y() ));
2590           project = dist1 > fToler2;
2591         }
2592         if ( project ) { // compute new UV
2593           gp_XY newUV;
2594           if ( !getClosestUV( projector, pNode, newUV )) {
2595             MESSAGE("Node Projection Failed " << node);
2596           }
2597           else {
2598             if ( isUPeriodic )
2599               newUV.SetX( ElCLib::InPeriod( newUV.X(), u1, u2 ));
2600             if ( isVPeriodic )
2601               newUV.SetY( ElCLib::InPeriod( newUV.Y(), v1, v2 ));
2602             // check new UV
2603             if ( posType != SMDS_TOP_3DSPACE )
2604               dist2 = pNode.SquareDistance( surface->Value( newUV.X(), newUV.Y() ));
2605             if ( dist2 < dist1 )
2606               uv = newUV;
2607           }
2608         }
2609         // store UV in the map
2610         listUV.push_back( uv );
2611         uvMap.insert( make_pair( node, &listUV.back() ));
2612       }
2613     } // loop on not yet smoothed elements
2614
2615     if ( !faceSubMesh || nbElemOnFace != faceSubMesh->NbElements() )
2616       checkBoundaryNodes = true;
2617
2618     // fix nodes on mesh boundary
2619
2620     if ( checkBoundaryNodes ) {
2621       map< NLink, int > linkNbMap; // how many times a link encounters in elemsOnFace
2622       map< NLink, int >::iterator link_nb;
2623       // put all elements links to linkNbMap
2624       list< const SMDS_MeshElement* >::iterator elemIt = elemsOnFace.begin();
2625       for ( ; elemIt != elemsOnFace.end(); ++elemIt ) {
2626         const SMDS_MeshElement* elem = (*elemIt);
2627         int nbn =  elem->NbNodes();
2628         if(elem->IsQuadratic())
2629           nbn = nbn/2;
2630         // loop on elem links: insert them in linkNbMap
2631         const SMDS_MeshNode* curNode, *prevNode = elem->GetNodeWrap( nbn );
2632         for ( int iN = 0; iN < nbn; ++iN ) {
2633           curNode = elem->GetNode( iN );
2634           NLink link;
2635           if ( curNode < prevNode ) link = make_pair( curNode , prevNode );
2636           else                      link = make_pair( prevNode , curNode );
2637           prevNode = curNode;
2638           link_nb = linkNbMap.find( link );
2639           if ( link_nb == linkNbMap.end() )
2640             linkNbMap.insert( make_pair ( link, 1 ));
2641           else
2642             link_nb->second++;
2643         }
2644       }
2645       // remove nodes that are in links encountered only once from setMovableNodes
2646       for ( link_nb = linkNbMap.begin(); link_nb != linkNbMap.end(); ++link_nb ) {
2647         if ( link_nb->second == 1 ) {
2648           setMovableNodes.erase( link_nb->first.first );
2649           setMovableNodes.erase( link_nb->first.second );
2650         }
2651       }
2652     }
2653
2654     // -----------------------------------------------------
2655     // for nodes on seam edge, compute one more UV ( uvMap2 );
2656     // find movable nodes linked to nodes on seam and which
2657     // are to be smoothed using the second UV ( uvMap2 )
2658     // -----------------------------------------------------
2659
2660     set<const SMDS_MeshNode*> nodesNearSeam; // to smooth using uvMap2
2661     if ( !surface.IsNull() ) {
2662       TopExp_Explorer eExp( face, TopAbs_EDGE );
2663       for ( ; eExp.More(); eExp.Next() ) {
2664         TopoDS_Edge edge = TopoDS::Edge( eExp.Current() );
2665         if ( !BRep_Tool::IsClosed( edge, face ))
2666           continue;
2667         SMESHDS_SubMesh* sm = aMesh->MeshElements( edge );
2668         if ( !sm ) continue;
2669         // find out which parameter varies for a node on seam
2670         double f,l;
2671         gp_Pnt2d uv1, uv2;
2672         Handle(Geom2d_Curve) pcurve = BRep_Tool::CurveOnSurface( edge, face, f, l );
2673         if ( pcurve.IsNull() ) continue;
2674         uv1 = pcurve->Value( f );
2675         edge.Reverse();
2676         pcurve = BRep_Tool::CurveOnSurface( edge, face, f, l );
2677         if ( pcurve.IsNull() ) continue;
2678         uv2 = pcurve->Value( f );
2679         int iPar = Abs( uv1.X() - uv2.X() ) > Abs( uv1.Y() - uv2.Y() ) ? 1 : 2;
2680         // assure uv1 < uv2
2681         if ( uv1.Coord( iPar ) > uv2.Coord( iPar )) {
2682           gp_Pnt2d tmp = uv1; uv1 = uv2; uv2 = tmp;
2683         }
2684         // get nodes on seam and its vertices
2685         list< const SMDS_MeshNode* > seamNodes;
2686         SMDS_NodeIteratorPtr nSeamIt = sm->GetNodes();
2687         while ( nSeamIt->more() ) {
2688           const SMDS_MeshNode* node = nSeamIt->next();
2689           if ( !isQuadratic || !IsMedium( node ))
2690             seamNodes.push_back( node );
2691         }
2692         TopExp_Explorer vExp( edge, TopAbs_VERTEX );
2693         for ( ; vExp.More(); vExp.Next() ) {
2694           sm = aMesh->MeshElements( vExp.Current() );
2695           if ( sm ) {
2696             nSeamIt = sm->GetNodes();
2697             while ( nSeamIt->more() )
2698               seamNodes.push_back( nSeamIt->next() );
2699           }
2700         }
2701         // loop on nodes on seam
2702         list< const SMDS_MeshNode* >::iterator noSeIt = seamNodes.begin();
2703         for ( ; noSeIt != seamNodes.end(); ++noSeIt ) {
2704           const SMDS_MeshNode* nSeam = *noSeIt;
2705           map< const SMDS_MeshNode*, gp_XY* >::iterator n_uv = uvMap.find( nSeam );
2706           if ( n_uv == uvMap.end() )
2707             continue;
2708           // set the first UV
2709           n_uv->second->SetCoord( iPar, uv1.Coord( iPar ));
2710           // set the second UV
2711           listUV.push_back( *n_uv->second );
2712           listUV.back().SetCoord( iPar, uv2.Coord( iPar ));
2713           if ( uvMap2.empty() )
2714             uvMap2 = uvMap; // copy the uvMap contents
2715           uvMap2[ nSeam ] = &listUV.back();
2716
2717           // collect movable nodes linked to ones on seam in nodesNearSeam
2718           SMDS_ElemIteratorPtr eIt = nSeam->GetInverseElementIterator(SMDSAbs_Face);
2719           while ( eIt->more() ) {
2720             const SMDS_MeshElement* e = eIt->next();
2721             int nbUseMap1 = 0, nbUseMap2 = 0;
2722             SMDS_ElemIteratorPtr nIt = e->nodesIterator();
2723             int nn = 0, nbn =  e->NbNodes();
2724             if(e->IsQuadratic()) nbn = nbn/2;
2725             while ( nn++ < nbn )
2726             {
2727               const SMDS_MeshNode* n =
2728                 static_cast<const SMDS_MeshNode*>( nIt->next() );
2729               if (n == nSeam ||
2730                   setMovableNodes.find( n ) == setMovableNodes.end() )
2731                 continue;
2732               // add only nodes being closer to uv2 than to uv1
2733               gp_Pnt pMid (0.5 * ( n->X() + nSeam->X() ),
2734                            0.5 * ( n->Y() + nSeam->Y() ),
2735                            0.5 * ( n->Z() + nSeam->Z() ));
2736               gp_XY uv;
2737               getClosestUV( projector, pMid, uv );
2738               if ( uv.Coord( iPar ) > uvMap[ n ]->Coord( iPar ) ) {
2739                 nodesNearSeam.insert( n );
2740                 nbUseMap2++;
2741               }
2742               else
2743                 nbUseMap1++;
2744             }
2745             // for centroidalSmooth all element nodes must
2746             // be on one side of a seam
2747             if ( theSmoothMethod == CENTROIDAL && nbUseMap1 && nbUseMap2 ) {
2748               SMDS_ElemIteratorPtr nIt = e->nodesIterator();
2749               nn = 0;
2750               while ( nn++ < nbn ) {
2751                 const SMDS_MeshNode* n =
2752                   static_cast<const SMDS_MeshNode*>( nIt->next() );
2753                 setMovableNodes.erase( n );
2754               }
2755             }
2756           }
2757         } // loop on nodes on seam
2758       } // loop on edge of a face
2759     } // if ( !face.IsNull() )
2760
2761     if ( setMovableNodes.empty() ) {
2762       MESSAGE( "Face id : " << *fId << " - NO SMOOTHING: no nodes to move!!!");
2763       continue; // goto next face
2764     }
2765
2766     // -------------
2767     // SMOOTHING //
2768     // -------------
2769
2770     int it = -1;
2771     double maxRatio = -1., maxDisplacement = -1.;
2772     set<const SMDS_MeshNode*>::iterator nodeToMove;
2773     for ( it = 0; it < theNbIterations; it++ ) {
2774       maxDisplacement = 0.;
2775       nodeToMove = setMovableNodes.begin();
2776       for ( ; nodeToMove != setMovableNodes.end(); nodeToMove++ ) {
2777         const SMDS_MeshNode* node = (*nodeToMove);
2778         gp_XYZ aPrevPos ( node->X(), node->Y(), node->Z() );
2779
2780         // smooth
2781         bool map2 = ( nodesNearSeam.find( node ) != nodesNearSeam.end() );
2782         if ( theSmoothMethod == LAPLACIAN )
2783           laplacianSmooth( node, surface, map2 ? uvMap2 : uvMap );
2784         else
2785           centroidalSmooth( node, surface, map2 ? uvMap2 : uvMap );
2786
2787         // node displacement
2788         gp_XYZ aNewPos ( node->X(), node->Y(), node->Z() );
2789         Standard_Real aDispl = (aPrevPos - aNewPos).SquareModulus();
2790         if ( aDispl > maxDisplacement )
2791           maxDisplacement = aDispl;
2792       }
2793       // no node movement => exit
2794       //if ( maxDisplacement < 1.e-16 ) {
2795       if ( maxDisplacement < disttol ) {
2796         MESSAGE("-- no node movement --");
2797         break;
2798       }
2799
2800       // check elements quality
2801       maxRatio  = 0;
2802       list< const SMDS_MeshElement* >::iterator elemIt = elemsOnFace.begin();
2803       for ( ; elemIt != elemsOnFace.end(); ++elemIt ) {
2804         const SMDS_MeshElement* elem = (*elemIt);
2805         if ( !elem || elem->GetType() != SMDSAbs_Face )
2806           continue;
2807         SMESH::Controls::TSequenceOfXYZ aPoints;
2808         if ( aQualityFunc.GetPoints( elem, aPoints )) {
2809           double aValue = aQualityFunc.GetValue( aPoints );
2810           if ( aValue > maxRatio )
2811             maxRatio = aValue;
2812         }
2813       }
2814       if ( maxRatio <= theTgtAspectRatio ) {
2815         MESSAGE("-- quality achived --");
2816         break;
2817       }
2818       if (it+1 == theNbIterations) {
2819         MESSAGE("-- Iteration limit exceeded --");
2820       }
2821     } // smoothing iterations
2822
2823     MESSAGE(" Face id: " << *fId <<
2824             " Nb iterstions: " << it <<
2825             " Displacement: " << maxDisplacement <<
2826             " Aspect Ratio " << maxRatio);
2827
2828     // ---------------------------------------
2829     // new nodes positions are computed,
2830     // record movement in DS and set new UV
2831     // ---------------------------------------
2832     nodeToMove = setMovableNodes.begin();
2833     for ( ; nodeToMove != setMovableNodes.end(); nodeToMove++ ) {
2834       SMDS_MeshNode* node = const_cast< SMDS_MeshNode* > (*nodeToMove);
2835       aMesh->MoveNode( node, node->X(), node->Y(), node->Z() );
2836       map< const SMDS_MeshNode*, gp_XY* >::iterator node_uv = uvMap.find( node );
2837       if ( node_uv != uvMap.end() ) {
2838         gp_XY* uv = node_uv->second;
2839         node->SetPosition
2840           ( SMDS_PositionPtr( new SMDS_FacePosition( *fId, uv->X(), uv->Y() )));
2841       }
2842     }
2843
2844     // move medium nodes of quadratic elements
2845     if ( isQuadratic )
2846     {
2847       SMESH_MesherHelper helper( *GetMesh() );
2848       if ( !face.IsNull() )
2849         helper.SetSubShape( face );
2850       list< const SMDS_MeshElement* >::iterator elemIt = elemsOnFace.begin();
2851       for ( ; elemIt != elemsOnFace.end(); ++elemIt ) {
2852         const SMDS_QuadraticFaceOfNodes* QF =
2853           dynamic_cast<const SMDS_QuadraticFaceOfNodes*> (*elemIt);
2854         if(QF) {
2855           vector<const SMDS_MeshNode*> Ns;
2856           Ns.reserve(QF->NbNodes()+1);
2857           SMDS_NodeIteratorPtr anIter = QF->interlacedNodesIterator();
2858           while ( anIter->more() )
2859             Ns.push_back( anIter->next() );
2860           Ns.push_back( Ns[0] );
2861           double x, y, z;
2862           for(int i=0; i<QF->NbNodes(); i=i+2) {
2863             if ( !surface.IsNull() ) {
2864               gp_XY uv1 = helper.GetNodeUV( face, Ns[i], Ns[i+2] );
2865               gp_XY uv2 = helper.GetNodeUV( face, Ns[i+2], Ns[i] );
2866               gp_XY uv = ( uv1 + uv2 ) / 2.;
2867               gp_Pnt xyz = surface->Value( uv.X(), uv.Y() );
2868               x = xyz.X(); y = xyz.Y(); z = xyz.Z();
2869             }
2870             else {
2871               x = (Ns[i]->X() + Ns[i+2]->X())/2;
2872               y = (Ns[i]->Y() + Ns[i+2]->Y())/2;
2873               z = (Ns[i]->Z() + Ns[i+2]->Z())/2;
2874             }
2875             if( fabs( Ns[i+1]->X() - x ) > disttol ||
2876                 fabs( Ns[i+1]->Y() - y ) > disttol ||
2877                 fabs( Ns[i+1]->Z() - z ) > disttol ) {
2878               // we have to move i+1 node
2879               aMesh->MoveNode( Ns[i+1], x, y, z );
2880             }
2881           }
2882         }
2883       }
2884     }
2885
2886   } // loop on face ids
2887
2888 }
2889
2890 //=======================================================================
2891 //function : isReverse
2892 //purpose  : Return true if normal of prevNodes is not co-directied with
2893 //           gp_Vec(prevNodes[iNotSame],nextNodes[iNotSame]).
2894 //           iNotSame is where prevNodes and nextNodes are different
2895 //=======================================================================
2896
2897 static bool isReverse(vector<const SMDS_MeshNode*> prevNodes,
2898                       vector<const SMDS_MeshNode*> nextNodes,
2899                       const int            nbNodes,
2900                       const int            iNotSame)
2901 {
2902   int iBeforeNotSame = ( iNotSame == 0 ? nbNodes - 1 : iNotSame - 1 );
2903   int iAfterNotSame  = ( iNotSame + 1 == nbNodes ? 0 : iNotSame + 1 );
2904
2905   const SMDS_MeshNode* nB = prevNodes[ iBeforeNotSame ];
2906   const SMDS_MeshNode* nA = prevNodes[ iAfterNotSame ];
2907   const SMDS_MeshNode* nP = prevNodes[ iNotSame ];
2908   const SMDS_MeshNode* nN = nextNodes[ iNotSame ];
2909
2910   gp_Pnt pB ( nB->X(), nB->Y(), nB->Z() );
2911   gp_Pnt pA ( nA->X(), nA->Y(), nA->Z() );
2912   gp_Pnt pP ( nP->X(), nP->Y(), nP->Z() );
2913   gp_Pnt pN ( nN->X(), nN->Y(), nN->Z() );
2914
2915   gp_Vec vB ( pP, pB ), vA ( pP, pA ), vN ( pP, pN );
2916
2917   return (vA ^ vB) * vN < 0.0;
2918 }
2919
2920 //=======================================================================
2921 /*!
2922  * \brief Create elements by sweeping an element
2923  * \param elem - element to sweep
2924  * \param newNodesItVec - nodes generated from each node of the element
2925  * \param newElems - generated elements
2926  * \param nbSteps - number of sweeping steps
2927  * \param srcElements - to append elem for each generated element
2928  */
2929 //=======================================================================
2930
2931 void SMESH_MeshEditor::sweepElement(const SMDS_MeshElement*               elem,
2932                                     const vector<TNodeOfNodeListMapItr> & newNodesItVec,
2933                                     list<const SMDS_MeshElement*>&        newElems,
2934                                     const int                             nbSteps,
2935                                     SMESH_SequenceOfElemPtr&              srcElements)
2936 {
2937   SMESHDS_Mesh* aMesh = GetMeshDS();
2938
2939   // Loop on elem nodes:
2940   // find new nodes and detect same nodes indices
2941   int nbNodes = elem->NbNodes();
2942   vector < list< const SMDS_MeshNode* >::const_iterator > itNN( nbNodes );
2943   vector<const SMDS_MeshNode*> prevNod( nbNodes );
2944   vector<const SMDS_MeshNode*> nextNod( nbNodes );
2945   vector<const SMDS_MeshNode*> midlNod( nbNodes );
2946
2947   int iNode, nbSame = 0, iNotSameNode = 0, iSameNode = 0;
2948   vector<int> sames(nbNodes);
2949   vector<bool> issimple(nbNodes);
2950
2951   for ( iNode = 0; iNode < nbNodes; iNode++ ) {
2952     TNodeOfNodeListMapItr nnIt = newNodesItVec[ iNode ];
2953     const SMDS_MeshNode*                 node         = nnIt->first;
2954     const list< const SMDS_MeshNode* > & listNewNodes = nnIt->second;
2955     if ( listNewNodes.empty() ) {
2956       return;
2957     }
2958
2959     issimple[iNode] = (listNewNodes.size()==nbSteps); // is node medium
2960
2961     itNN[ iNode ] = listNewNodes.begin();
2962     prevNod[ iNode ] = node;
2963     nextNod[ iNode ] = listNewNodes.front();
2964     if( !elem->IsQuadratic() || !issimple[iNode] ) {
2965       if ( prevNod[ iNode ] != nextNod [ iNode ])
2966         iNotSameNode = iNode;
2967       else {
2968         iSameNode = iNode;
2969         //nbSame++;
2970         sames[nbSame++] = iNode;
2971       }
2972     }
2973   }
2974
2975   //cout<<"  nbSame = "<<nbSame<<endl;
2976   if ( nbSame == nbNodes || nbSame > 2) {
2977     MESSAGE( " Too many same nodes of element " << elem->GetID() );
2978     //INFOS( " Too many same nodes of element " << elem->GetID() );
2979     return;
2980   }
2981
2982   //  if( elem->IsQuadratic() && nbSame>0 ) {
2983   //    MESSAGE( "Can not rotate quadratic element " << elem->GetID() );
2984   //    return;
2985   //  }
2986
2987   int iBeforeSame = 0, iAfterSame = 0, iOpposSame = 0;
2988   int nbBaseNodes = ( elem->IsQuadratic() ? nbNodes/2 : nbNodes );
2989   if ( nbSame > 0 ) {
2990     iBeforeSame = ( iSameNode == 0 ? nbBaseNodes - 1 : iSameNode - 1 );
2991     iAfterSame  = ( iSameNode + 1 == nbBaseNodes ? 0 : iSameNode + 1 );
2992     iOpposSame  = ( iSameNode - 2 < 0  ? iSameNode + 2 : iSameNode - 2 );
2993   }
2994
2995   //if(nbNodes==8)
2996   //cout<<" prevNod[0]="<< prevNod[0]<<" prevNod[1]="<< prevNod[1]
2997   //    <<" prevNod[2]="<< prevNod[2]<<" prevNod[3]="<< prevNod[4]
2998   //    <<" prevNod[4]="<< prevNod[4]<<" prevNod[5]="<< prevNod[5]
2999   //    <<" prevNod[6]="<< prevNod[6]<<" prevNod[7]="<< prevNod[7]<<endl;
3000
3001   // check element orientation
3002   int i0 = 0, i2 = 2;
3003   if ( nbNodes > 2 && !isReverse( prevNod, nextNod, nbNodes, iNotSameNode )) {
3004     //MESSAGE("Reversed elem " << elem );
3005     i0 = 2;
3006     i2 = 0;
3007     if ( nbSame > 0 )
3008       std::swap( iBeforeSame, iAfterSame );
3009   }
3010
3011   // make new elements
3012   for (int iStep = 0; iStep < nbSteps; iStep++ ) {
3013     // get next nodes
3014     for ( iNode = 0; iNode < nbNodes; iNode++ ) {
3015       if(issimple[iNode]) {
3016         nextNod[ iNode ] = *itNN[ iNode ];
3017         itNN[ iNode ]++;
3018       }
3019       else {
3020         if( elem->GetType()==SMDSAbs_Node ) {
3021           // we have to use two nodes
3022           midlNod[ iNode ] = *itNN[ iNode ];
3023           itNN[ iNode ]++;
3024           nextNod[ iNode ] = *itNN[ iNode ];
3025           itNN[ iNode ]++;
3026         }
3027         else if(!elem->IsQuadratic() || elem->IsMediumNode(prevNod[iNode]) ) {
3028           // we have to use each second node
3029           //itNN[ iNode ]++;
3030           nextNod[ iNode ] = *itNN[ iNode ];
3031           itNN[ iNode ]++;
3032         }
3033         else {
3034           // we have to use two nodes
3035           midlNod[ iNode ] = *itNN[ iNode ];
3036           itNN[ iNode ]++;
3037           nextNod[ iNode ] = *itNN[ iNode ];
3038           itNN[ iNode ]++;
3039         }
3040       }
3041     }
3042     SMDS_MeshElement* aNewElem = 0;
3043     if(!elem->IsPoly()) {
3044       switch ( nbNodes ) {
3045       case 0:
3046         return;
3047       case 1: { // NODE
3048         if ( nbSame == 0 ) {
3049           if(issimple[0])
3050             aNewElem = aMesh->AddEdge( prevNod[ 0 ], nextNod[ 0 ] );
3051           else
3052             aNewElem = aMesh->AddEdge( prevNod[ 0 ], nextNod[ 0 ], midlNod[ 0 ] );
3053         }
3054         break;
3055       }
3056       case 2: { // EDGE
3057         if ( nbSame == 0 )
3058           aNewElem = aMesh->AddFace(prevNod[ 0 ], prevNod[ 1 ],
3059                                     nextNod[ 1 ], nextNod[ 0 ] );
3060         else
3061           aNewElem = aMesh->AddFace(prevNod[ 0 ], prevNod[ 1 ],
3062                                     nextNod[ iNotSameNode ] );
3063         break;
3064       }
3065
3066       case 3: { // TRIANGLE or quadratic edge
3067         if(elem->GetType() == SMDSAbs_Face) { // TRIANGLE
3068
3069           if ( nbSame == 0 )       // --- pentahedron
3070             aNewElem = aMesh->AddVolume (prevNod[ i0 ], prevNod[ 1 ], prevNod[ i2 ],
3071                                          nextNod[ i0 ], nextNod[ 1 ], nextNod[ i2 ] );
3072
3073           else if ( nbSame == 1 )  // --- pyramid
3074             aNewElem = aMesh->AddVolume (prevNod[ iBeforeSame ],  prevNod[ iAfterSame ],
3075                                          nextNod[ iAfterSame ], nextNod[ iBeforeSame ],
3076                                          nextNod[ iSameNode ]);
3077
3078           else // 2 same nodes:      --- tetrahedron
3079             aNewElem = aMesh->AddVolume (prevNod[ i0 ], prevNod[ 1 ], prevNod[ i2 ],
3080                                          nextNod[ iNotSameNode ]);
3081         }
3082         else { // quadratic edge
3083           if(nbSame==0) {     // quadratic quadrangle
3084             aNewElem = aMesh->AddFace(prevNod[0], nextNod[0], nextNod[1], prevNod[1],
3085                                       midlNod[0], nextNod[2], midlNod[1], prevNod[2]);
3086           }
3087           else if(nbSame==1) { // quadratic triangle
3088             if(sames[0]==2) {
3089               return; // medium node on axis
3090             }
3091             else if(sames[0]==0) {
3092               aNewElem = aMesh->AddFace(prevNod[0], nextNod[1], prevNod[1],
3093                                         nextNod[2], midlNod[1], prevNod[2]);
3094             }
3095             else { // sames[0]==1
3096               aNewElem = aMesh->AddFace(prevNod[0], nextNod[0], prevNod[1],
3097                                         midlNod[0], nextNod[2], prevNod[2]);
3098             }
3099           }
3100           else {
3101             return;
3102           }
3103         }
3104         break;
3105       }
3106       case 4: { // QUADRANGLE
3107
3108         if ( nbSame == 0 )       // --- hexahedron
3109           aNewElem = aMesh->AddVolume (prevNod[ i0 ], prevNod[ 1 ], prevNod[ i2 ], prevNod[ 3 ],
3110                                        nextNod[ i0 ], nextNod[ 1 ], nextNod[ i2 ], nextNod[ 3 ]);
3111
3112         else if ( nbSame == 1 ) { // --- pyramid + pentahedron
3113           aNewElem = aMesh->AddVolume (prevNod[ iBeforeSame ],  prevNod[ iAfterSame ],
3114                                        nextNod[ iAfterSame ], nextNod[ iBeforeSame ],
3115                                        nextNod[ iSameNode ]);
3116           newElems.push_back( aNewElem );
3117           aNewElem = aMesh->AddVolume (prevNod[ iAfterSame ], prevNod[ iOpposSame ],
3118                                        prevNod[ iBeforeSame ],  nextNod[ iAfterSame ],
3119                                        nextNod[ iOpposSame ],  nextNod[ iBeforeSame ] );
3120         }
3121         else if ( nbSame == 2 ) { // pentahedron
3122           if ( prevNod[ iBeforeSame ] == nextNod[ iBeforeSame ] )
3123             // iBeforeSame is same too
3124             aNewElem = aMesh->AddVolume (prevNod[ iBeforeSame ], prevNod[ iOpposSame ],
3125                                          nextNod[ iOpposSame ], prevNod[ iSameNode ],
3126                                          prevNod[ iAfterSame ],  nextNod[ iAfterSame ]);
3127           else
3128             // iAfterSame is same too
3129             aNewElem = aMesh->AddVolume (prevNod[ iSameNode ], prevNod[ iBeforeSame ],
3130                                          nextNod[ iBeforeSame ], prevNod[ iAfterSame ],
3131                                          prevNod[ iOpposSame ],  nextNod[ iOpposSame ]);
3132         }
3133         break;
3134       }
3135       case 6: { // quadratic triangle
3136         // create pentahedron with 15 nodes
3137         if(nbSame==0) {
3138           if(i0>0) { // reversed case
3139             aNewElem = aMesh->AddVolume (prevNod[0], prevNod[2], prevNod[1],
3140                                          nextNod[0], nextNod[2], nextNod[1],
3141                                          prevNod[5], prevNod[4], prevNod[3],
3142                                          nextNod[5], nextNod[4], nextNod[3],
3143                                          midlNod[0], midlNod[2], midlNod[1]);
3144           }
3145           else { // not reversed case
3146             aNewElem = aMesh->AddVolume (prevNod[0], prevNod[1], prevNod[2],
3147                                          nextNod[0], nextNod[1], nextNod[2],
3148                                          prevNod[3], prevNod[4], prevNod[5],
3149                                          nextNod[3], nextNod[4], nextNod[5],
3150                                          midlNod[0], midlNod[1], midlNod[2]);
3151           }
3152         }
3153         else if(nbSame==1) {
3154           // 2d order pyramid of 13 nodes
3155           //SMDS_MeshVolume* AddVolumeWithID(int n1, int n2, int n3, int n4, int n5,
3156           //                                 int n12,int n23,int n34,int n41,
3157           //                                 int n15,int n25,int n35,int n45, int ID);
3158           int n5 = iSameNode;
3159           int n1,n4,n41,n15,n45;
3160           if(i0>0) { // reversed case
3161             n1 = ( n5 + 1 == nbBaseNodes ? 0 : n5 + 1 );
3162             n4 = ( n5 == 0 ? nbBaseNodes - 1 : n5 - 1 );
3163             n41 = n1 + 3;
3164             n15 = n5 + 3;
3165             n45 = n4 + 3;
3166           }
3167           else {
3168             n1 = ( n5 == 0 ? nbBaseNodes - 1 : n5 - 1 );
3169             n4 = ( n5 + 1 == nbBaseNodes ? 0 : n5 + 1 );
3170             n41 = n4 + 3;
3171             n15 = n1 + 3;
3172             n45 = n5 + 3;
3173           }
3174           aNewElem = aMesh->AddVolume(prevNod[n1], nextNod[n1],
3175                                       nextNod[n4], prevNod[n4], prevNod[n5],
3176                                       midlNod[n1], nextNod[n41],
3177                                       midlNod[n4], prevNod[n41],
3178                                       prevNod[n15], nextNod[n15],
3179                                       nextNod[n45], prevNod[n45]);
3180         }
3181         else if(nbSame==2) {
3182           // 2d order tetrahedron of 10 nodes
3183           //SMDS_MeshVolume* AddVolumeWithID(int n1, int n2, int n3, int n4,
3184           //                                 int n12,int n23,int n31,
3185           //                                 int n14,int n24,int n34, int ID);
3186           int n1 = iNotSameNode;
3187           int n2,n3,n12,n23,n31;
3188           if(i0>0) { // reversed case
3189             n2 = ( n1 == 0 ? nbBaseNodes - 1 : n1 - 1 );
3190             n3 = ( n1 + 1 == nbBaseNodes ? 0 : n1 + 1 );
3191             n12 = n2 + 3;
3192             n23 = n3 + 3;
3193             n31 = n1 + 3;
3194           }
3195           else {
3196             n2 = ( n1 + 1 == nbBaseNodes ? 0 : n1 + 1 );
3197             n3 = ( n1 == 0 ? nbBaseNodes - 1 : n1 - 1 );
3198             n12 = n1 + 3;
3199             n23 = n2 + 3;
3200             n31 = n3 + 3;
3201           }
3202           aNewElem = aMesh->AddVolume (prevNod[n1], prevNod[n2], prevNod[n3], nextNod[n1],
3203                                        prevNod[n12], prevNod[n23], prevNod[n31],
3204                                        midlNod[n1], nextNod[n12], nextNod[n31]);
3205         }
3206         break;
3207       }
3208       case 8: { // quadratic quadrangle
3209         if(nbSame==0) {
3210           // create hexahedron with 20 nodes
3211           if(i0>0) { // reversed case
3212             aNewElem = aMesh->AddVolume (prevNod[0], prevNod[3], prevNod[2], prevNod[1],
3213                                          nextNod[0], nextNod[3], nextNod[2], nextNod[1],
3214                                          prevNod[7], prevNod[6], prevNod[5], prevNod[4],
3215                                          nextNod[7], nextNod[6], nextNod[5], nextNod[4],
3216                                          midlNod[0], midlNod[3], midlNod[2], midlNod[1]);
3217           }
3218           else { // not reversed case
3219             aNewElem = aMesh->AddVolume (prevNod[0], prevNod[1], prevNod[2], prevNod[3],
3220                                          nextNod[0], nextNod[1], nextNod[2], nextNod[3],
3221                                          prevNod[4], prevNod[5], prevNod[6], prevNod[7],
3222                                          nextNod[4], nextNod[5], nextNod[6], nextNod[7],
3223                                          midlNod[0], midlNod[1], midlNod[2], midlNod[3]);
3224           }
3225         }
3226         else if(nbSame==1) { 
3227           // --- pyramid + pentahedron - can not be created since it is needed 
3228           // additional middle node ot the center of face
3229           INFOS( " Sweep for face " << elem->GetID() << " can not be created" );
3230           return;
3231         }
3232         else if(nbSame==2) {
3233           // 2d order Pentahedron with 15 nodes
3234           //SMDS_MeshVolume* AddVolumeWithID(int n1, int n2, int n3, int n4, int n5, int n6,
3235           //                                 int n12,int n23,int n31,int n45,int n56,int n64,
3236           //                                 int n14,int n25,int n36, int ID);
3237           int n1,n2,n4,n5;
3238           if ( prevNod[ iBeforeSame ] == nextNod[ iBeforeSame ] ) {
3239             // iBeforeSame is same too
3240             n1 = iBeforeSame;
3241             n2 = iOpposSame;
3242             n4 = iSameNode;
3243             n5 = iAfterSame;
3244           }
3245           else {
3246             // iAfterSame is same too
3247             n1 = iSameNode;
3248             n2 = iBeforeSame;
3249             n4 = iAfterSame;
3250             n5 = iOpposSame;
3251           }
3252           int n12,n45,n14,n25;
3253           if(i0>0) { //reversed case
3254             n12 = n1 + 4;
3255             n45 = n5 + 4;
3256             n14 = n4 + 4;
3257             n25 = n2 + 4;
3258           }
3259           else {
3260             n12 = n2 + 4;
3261             n45 = n4 + 4;
3262             n14 = n1 + 4;
3263             n25 = n5 + 4;
3264           }
3265           aNewElem = aMesh->AddVolume (prevNod[n1], prevNod[n2], nextNod[n2],
3266                                        prevNod[n4], prevNod[n5], nextNod[n5],
3267                                        prevNod[n12], midlNod[n2], nextNod[n12],
3268                                        prevNod[n45], midlNod[n5], nextNod[n45],
3269                                        prevNod[n14], prevNod[n25], nextNod[n25]);
3270         }
3271         break;
3272       }
3273       default: {
3274         // realized for extrusion only
3275         //vector<const SMDS_MeshNode*> polyedre_nodes (nbNodes*2 + 4*nbNodes);
3276         //vector<int> quantities (nbNodes + 2);
3277
3278         //quantities[0] = nbNodes; // bottom of prism
3279         //for (int inode = 0; inode < nbNodes; inode++) {
3280         //  polyedre_nodes[inode] = prevNod[inode];
3281         //}
3282
3283         //quantities[1] = nbNodes; // top of prism
3284         //for (int inode = 0; inode < nbNodes; inode++) {
3285         //  polyedre_nodes[nbNodes + inode] = nextNod[inode];
3286         //}
3287
3288         //for (int iface = 0; iface < nbNodes; iface++) {
3289         //  quantities[iface + 2] = 4;
3290         //  int inextface = (iface == nbNodes - 1) ? 0 : iface + 1;
3291         //  polyedre_nodes[2*nbNodes + 4*iface + 0] = prevNod[iface];
3292         //  polyedre_nodes[2*nbNodes + 4*iface + 1] = prevNod[inextface];
3293         //  polyedre_nodes[2*nbNodes + 4*iface + 2] = nextNod[inextface];
3294         //  polyedre_nodes[2*nbNodes + 4*iface + 3] = nextNod[iface];
3295         //}
3296         //aNewElem = aMesh->AddPolyhedralVolume (polyedre_nodes, quantities);
3297         break;
3298       }
3299       }
3300     }
3301
3302     if(!aNewElem) {
3303       // realized for extrusion only
3304       vector<const SMDS_MeshNode*> polyedre_nodes (nbNodes*2 + 4*nbNodes);
3305       vector<int> quantities (nbNodes + 2);
3306
3307       quantities[0] = nbNodes; // bottom of prism
3308       for (int inode = 0; inode < nbNodes; inode++) {
3309         polyedre_nodes[inode] = prevNod[inode];
3310       }
3311
3312       quantities[1] = nbNodes; // top of prism
3313       for (int inode = 0; inode < nbNodes; inode++) {
3314         polyedre_nodes[nbNodes + inode] = nextNod[inode];
3315       }
3316
3317       for (int iface = 0; iface < nbNodes; iface++) {
3318         quantities[iface + 2] = 4;
3319         int inextface = (iface == nbNodes - 1) ? 0 : iface + 1;
3320         polyedre_nodes[2*nbNodes + 4*iface + 0] = prevNod[iface];
3321         polyedre_nodes[2*nbNodes + 4*iface + 1] = prevNod[inextface];
3322         polyedre_nodes[2*nbNodes + 4*iface + 2] = nextNod[inextface];
3323         polyedre_nodes[2*nbNodes + 4*iface + 3] = nextNod[iface];
3324       }
3325       aNewElem = aMesh->AddPolyhedralVolume (polyedre_nodes, quantities);
3326     }
3327
3328     if ( aNewElem ) {
3329       newElems.push_back( aNewElem );
3330       myLastCreatedElems.Append(aNewElem);
3331       srcElements.Append( elem );
3332     }
3333
3334     // set new prev nodes
3335     for ( iNode = 0; iNode < nbNodes; iNode++ )
3336       prevNod[ iNode ] = nextNod[ iNode ];
3337
3338   } // for steps
3339 }
3340
3341 //=======================================================================
3342 /*!
3343  * \brief Create 1D and 2D elements around swept elements
3344  * \param mapNewNodes - source nodes and ones generated from them
3345  * \param newElemsMap - source elements and ones generated from them
3346  * \param elemNewNodesMap - nodes generated from each node of each element
3347  * \param elemSet - all swept elements
3348  * \param nbSteps - number of sweeping steps
3349  * \param srcElements - to append elem for each generated element
3350  */
3351 //=======================================================================
3352
3353 void SMESH_MeshEditor::makeWalls (TNodeOfNodeListMap &     mapNewNodes,
3354                                   TElemOfElemListMap &     newElemsMap,
3355                                   TElemOfVecOfNnlmiMap &   elemNewNodesMap,
3356                                   TIDSortedElemSet&        elemSet,
3357                                   const int                nbSteps,
3358                                   SMESH_SequenceOfElemPtr& srcElements)
3359 {
3360   ASSERT( newElemsMap.size() == elemNewNodesMap.size() );
3361   SMESHDS_Mesh* aMesh = GetMeshDS();
3362
3363   // Find nodes belonging to only one initial element - sweep them to get edges.
3364
3365   TNodeOfNodeListMapItr nList = mapNewNodes.begin();
3366   for ( ; nList != mapNewNodes.end(); nList++ ) {
3367     const SMDS_MeshNode* node =
3368       static_cast<const SMDS_MeshNode*>( nList->first );
3369     SMDS_ElemIteratorPtr eIt = node->GetInverseElementIterator();
3370     int nbInitElems = 0;
3371     const SMDS_MeshElement* el = 0;
3372     SMDSAbs_ElementType highType = SMDSAbs_Edge; // count most complex elements only
3373     while ( eIt->more() && nbInitElems < 2 ) {
3374       el = eIt->next();
3375       SMDSAbs_ElementType type = el->GetType();
3376       if ( type == SMDSAbs_Volume || type < highType ) continue;
3377       if ( type > highType ) {
3378         nbInitElems = 0;
3379         highType = type;
3380       }
3381       if ( elemSet.find(el) != elemSet.end() )
3382         nbInitElems++;
3383     }
3384     if ( nbInitElems < 2 ) {
3385       bool NotCreateEdge = el && el->IsQuadratic() && el->IsMediumNode(node);
3386       if(!NotCreateEdge) {
3387         vector<TNodeOfNodeListMapItr> newNodesItVec( 1, nList );
3388         list<const SMDS_MeshElement*> newEdges;
3389         sweepElement( node, newNodesItVec, newEdges, nbSteps, srcElements );
3390       }
3391     }
3392   }
3393
3394   // Make a ceiling for each element ie an equal element of last new nodes.
3395   // Find free links of faces - make edges and sweep them into faces.
3396
3397   TElemOfElemListMap::iterator   itElem      = newElemsMap.begin();
3398   TElemOfVecOfNnlmiMap::iterator itElemNodes = elemNewNodesMap.begin();
3399   for ( ; itElem != newElemsMap.end(); itElem++, itElemNodes++ ) {
3400     const SMDS_MeshElement* elem = itElem->first;
3401     vector<TNodeOfNodeListMapItr>& vecNewNodes = itElemNodes->second;
3402
3403     if ( elem->GetType() == SMDSAbs_Edge ) {
3404       // create a ceiling edge
3405       if (!elem->IsQuadratic()) {
3406         if ( !aMesh->FindEdge( vecNewNodes[ 0 ]->second.back(),
3407                                vecNewNodes[ 1 ]->second.back())) {
3408           myLastCreatedElems.Append(aMesh->AddEdge(vecNewNodes[ 0 ]->second.back(),
3409                                                    vecNewNodes[ 1 ]->second.back()));
3410           srcElements.Append( myLastCreatedElems.Last() );
3411         }
3412       }
3413       else {
3414         if ( !aMesh->FindEdge( vecNewNodes[ 0 ]->second.back(),
3415                                vecNewNodes[ 1 ]->second.back(),
3416                                vecNewNodes[ 2 ]->second.back())) {
3417           myLastCreatedElems.Append(aMesh->AddEdge(vecNewNodes[ 0 ]->second.back(),
3418                                                    vecNewNodes[ 1 ]->second.back(),
3419                                                    vecNewNodes[ 2 ]->second.back()));
3420           srcElements.Append( myLastCreatedElems.Last() );
3421         }
3422       }
3423     }
3424     if ( elem->GetType() != SMDSAbs_Face )
3425       continue;
3426
3427     if(itElem->second.size()==0) continue;
3428
3429     bool hasFreeLinks = false;
3430
3431     TIDSortedElemSet avoidSet;
3432     avoidSet.insert( elem );
3433
3434     set<const SMDS_MeshNode*> aFaceLastNodes;
3435     int iNode, nbNodes = vecNewNodes.size();
3436     if(!elem->IsQuadratic()) {
3437       // loop on the face nodes
3438       for ( iNode = 0; iNode < nbNodes; iNode++ ) {
3439         aFaceLastNodes.insert( vecNewNodes[ iNode ]->second.back() );
3440         // look for free links of the face
3441         int iNext = ( iNode + 1 == nbNodes ) ? 0 : iNode + 1;
3442         const SMDS_MeshNode* n1 = vecNewNodes[ iNode ]->first;
3443         const SMDS_MeshNode* n2 = vecNewNodes[ iNext ]->first;
3444         // check if a link is free
3445         if ( ! SMESH_MeshEditor::FindFaceInSet ( n1, n2, elemSet, avoidSet )) {
3446           hasFreeLinks = true;
3447           // make an edge and a ceiling for a new edge
3448           if ( !aMesh->FindEdge( n1, n2 )) {
3449             myLastCreatedElems.Append(aMesh->AddEdge( n1, n2 )); // free link edge
3450             srcElements.Append( myLastCreatedElems.Last() );
3451           }
3452           n1 = vecNewNodes[ iNode ]->second.back();
3453           n2 = vecNewNodes[ iNext ]->second.back();
3454           if ( !aMesh->FindEdge( n1, n2 )) {
3455             myLastCreatedElems.Append(aMesh->AddEdge( n1, n2 )); // ceiling edge
3456             srcElements.Append( myLastCreatedElems.Last() );
3457           }
3458         }
3459       }
3460     }
3461     else { // elem is quadratic face
3462       int nbn = nbNodes/2;
3463       for ( iNode = 0; iNode < nbn; iNode++ ) {
3464         aFaceLastNodes.insert( vecNewNodes[ iNode ]->second.back() );
3465         int iNext = ( iNode + 1 == nbn ) ? 0 : iNode + 1;
3466         const SMDS_MeshNode* n1 = vecNewNodes[ iNode ]->first;
3467         const SMDS_MeshNode* n2 = vecNewNodes[ iNext ]->first;
3468         // check if a link is free
3469         if ( ! SMESH_MeshEditor::FindFaceInSet ( n1, n2, elemSet, avoidSet )) {
3470           hasFreeLinks = true;
3471           // make an edge and a ceiling for a new edge
3472           // find medium node
3473           const SMDS_MeshNode* n3 = vecNewNodes[ iNode+nbn ]->first;
3474           if ( !aMesh->FindEdge( n1, n2, n3 )) {
3475             myLastCreatedElems.Append(aMesh->AddEdge( n1, n2, n3 )); // free link edge
3476             srcElements.Append( myLastCreatedElems.Last() );
3477           }
3478           n1 = vecNewNodes[ iNode ]->second.back();
3479           n2 = vecNewNodes[ iNext ]->second.back();
3480           n3 = vecNewNodes[ iNode+nbn ]->second.back();
3481           if ( !aMesh->FindEdge( n1, n2, n3 )) {
3482             myLastCreatedElems.Append(aMesh->AddEdge( n1, n2, n3 )); // ceiling edge
3483             srcElements.Append( myLastCreatedElems.Last() );
3484           }
3485         }
3486       }
3487       for ( iNode = nbn; iNode < 2*nbn; iNode++ ) {
3488         aFaceLastNodes.insert( vecNewNodes[ iNode ]->second.back() );
3489       }
3490     }
3491
3492     // sweep free links into faces
3493
3494     if ( hasFreeLinks )  {
3495       list<const SMDS_MeshElement*> & newVolumes = itElem->second;
3496       int iVol, volNb, nbVolumesByStep = newVolumes.size() / nbSteps;
3497
3498       set<const SMDS_MeshNode*> initNodeSet, topNodeSet, faceNodeSet;
3499       for ( iNode = 0; iNode < nbNodes; iNode++ ) {
3500         initNodeSet.insert( vecNewNodes[ iNode ]->first );
3501         topNodeSet .insert( vecNewNodes[ iNode ]->second.back() );
3502       }
3503       for ( volNb = 0; volNb < nbVolumesByStep; volNb++ ) {
3504         list<const SMDS_MeshElement*>::iterator v = newVolumes.begin();
3505         iVol = 0;
3506         while ( iVol++ < volNb ) v++;
3507         // find indices of free faces of a volume and their source edges
3508         list< int > freeInd;
3509         list< const SMDS_MeshElement* > srcEdges; // source edges of free faces
3510         SMDS_VolumeTool vTool( *v );
3511         int iF, nbF = vTool.NbFaces();
3512         for ( iF = 0; iF < nbF; iF ++ ) {
3513           if (vTool.IsFreeFace( iF ) &&
3514               vTool.GetFaceNodes( iF, faceNodeSet ) &&
3515               initNodeSet != faceNodeSet) // except an initial face
3516           {
3517             if ( nbSteps == 1 && faceNodeSet == topNodeSet )
3518               continue;
3519             freeInd.push_back( iF );
3520             // find source edge of a free face iF
3521             vector<const SMDS_MeshNode*> commonNodes; // shared by the initial and free faces
3522             commonNodes.resize( initNodeSet.size(), NULL ); // avoid spoiling memory
3523             std::set_intersection( faceNodeSet.begin(), faceNodeSet.end(),
3524                                    initNodeSet.begin(), initNodeSet.end(),
3525                                    commonNodes.begin());
3526             if ( (*v)->IsQuadratic() )
3527               srcEdges.push_back(aMesh->FindEdge (commonNodes[0],commonNodes[1],commonNodes[2]));
3528             else
3529               srcEdges.push_back(aMesh->FindEdge (commonNodes[0],commonNodes[1]));
3530 #ifdef _DEBUG_
3531             if ( !srcEdges.back() )
3532             {
3533               cout << "SMESH_MeshEditor::makeWalls(), no source edge found for a free face #"
3534                    << iF << " of volume #" << vTool.ID() << endl;
3535             }
3536 #endif
3537           }
3538         }
3539         if ( freeInd.empty() )
3540           continue;
3541
3542         // create faces for all steps;
3543         // if such a face has been already created by sweep of edge,
3544         // assure that its orientation is OK
3545         for ( int iStep = 0; iStep < nbSteps; iStep++ )  {
3546           vTool.Set( *v );
3547           vTool.SetExternalNormal();
3548           list< int >::iterator ind = freeInd.begin();
3549           list< const SMDS_MeshElement* >::iterator srcEdge = srcEdges.begin();
3550           for ( ; ind != freeInd.end(); ++ind, ++srcEdge ) // loop on free faces
3551           {
3552             const SMDS_MeshNode** nodes = vTool.GetFaceNodes( *ind );
3553             int nbn = vTool.NbFaceNodes( *ind );
3554             switch ( nbn ) {
3555             case 3: { ///// triangle
3556               const SMDS_MeshFace * f = aMesh->FindFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ]);
3557               if ( !f )
3558                 myLastCreatedElems.Append(aMesh->AddFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ] ));
3559               else if ( nodes[ 1 ] != f->GetNodeWrap( f->GetNodeIndex( nodes[ 0 ] ) + 1 ))
3560                 aMesh->ChangeElementNodes( f, nodes, nbn );
3561               break;
3562             }
3563             case 4: { ///// quadrangle
3564               const SMDS_MeshFace * f = aMesh->FindFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ], nodes[ 3 ]);
3565               if ( !f )
3566                 myLastCreatedElems.Append(aMesh->AddFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ], nodes[ 3 ] ));
3567               else if ( nodes[ 1 ] != f->GetNodeWrap( f->GetNodeIndex( nodes[ 0 ] ) + 1 ))
3568                 aMesh->ChangeElementNodes( f, nodes, nbn );
3569               break;
3570             }
3571             default:
3572               if( (*v)->IsQuadratic() ) {
3573                 if(nbn==6) { /////// quadratic triangle
3574                   const SMDS_MeshFace * f = aMesh->FindFace( nodes[0], nodes[2], nodes[4],
3575                                                              nodes[1], nodes[3], nodes[5] );
3576                   if ( !f ) {
3577                     myLastCreatedElems.Append(aMesh->AddFace(nodes[0], nodes[2], nodes[4],
3578                                                              nodes[1], nodes[3], nodes[5]));
3579                   }
3580                   else if ( nodes[ 2 ] != f->GetNodeWrap( f->GetNodeIndex( nodes[ 0 ] ) + 1 )) {
3581                     const SMDS_MeshNode** tmpnodes = new const SMDS_MeshNode*[6];
3582                     tmpnodes[0] = nodes[0];
3583                     tmpnodes[1] = nodes[2];
3584                     tmpnodes[2] = nodes[4];
3585                     tmpnodes[3] = nodes[1];
3586                     tmpnodes[4] = nodes[3];
3587                     tmpnodes[5] = nodes[5];
3588                     aMesh->ChangeElementNodes( f, tmpnodes, nbn );
3589                   }
3590                 }
3591                 else {       /////// quadratic quadrangle
3592                   const SMDS_MeshFace * f = aMesh->FindFace( nodes[0], nodes[2], nodes[4], nodes[6],
3593                                                              nodes[1], nodes[3], nodes[5], nodes[7] );
3594                   if ( !f ) {
3595                     myLastCreatedElems.Append(aMesh->AddFace(nodes[0], nodes[2], nodes[4], nodes[6],
3596                                                              nodes[1], nodes[3], nodes[5], nodes[7]));
3597                   }
3598                   else if ( nodes[ 2 ] != f->GetNodeWrap( f->GetNodeIndex( nodes[ 0 ] ) + 1 )) {
3599                     const SMDS_MeshNode** tmpnodes = new const SMDS_MeshNode*[8];
3600                     tmpnodes[0] = nodes[0];
3601                     tmpnodes[1] = nodes[2];
3602                     tmpnodes[2] = nodes[4];
3603                     tmpnodes[3] = nodes[6];
3604                     tmpnodes[4] = nodes[1];
3605                     tmpnodes[5] = nodes[3];
3606                     tmpnodes[6] = nodes[5];
3607                     tmpnodes[7] = nodes[7];
3608                     aMesh->ChangeElementNodes( f, tmpnodes, nbn );
3609                   }
3610                 }
3611               }
3612               else { //////// polygon
3613                 vector<const SMDS_MeshNode*> polygon_nodes ( nodes, &nodes[nbn] );
3614                 const SMDS_MeshFace * f = aMesh->FindFace( polygon_nodes );
3615                 if ( !f )
3616                   myLastCreatedElems.Append(aMesh->AddPolygonalFace(polygon_nodes));
3617                 else if ( nodes[ 1 ] != f->GetNodeWrap( f->GetNodeIndex( nodes[ 0 ] ) + 1 ))
3618                   aMesh->ChangeElementNodes( f, nodes, nbn );
3619               }
3620             }
3621             while ( srcElements.Length() < myLastCreatedElems.Length() )
3622               srcElements.Append( *srcEdge );
3623
3624           }  // loop on free faces
3625
3626           // go to the next volume
3627           iVol = 0;
3628           while ( iVol++ < nbVolumesByStep ) v++;
3629         }
3630       }
3631     } // sweep free links into faces
3632
3633     // Make a ceiling face with a normal external to a volume
3634
3635     SMDS_VolumeTool lastVol( itElem->second.back() );
3636
3637     int iF = lastVol.GetFaceIndex( aFaceLastNodes );
3638     if ( iF >= 0 ) {
3639       lastVol.SetExternalNormal();
3640       const SMDS_MeshNode** nodes = lastVol.GetFaceNodes( iF );
3641       int nbn = lastVol.NbFaceNodes( iF );
3642       switch ( nbn ) {
3643       case 3:
3644         if (!hasFreeLinks ||
3645             !aMesh->FindFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ]))
3646           myLastCreatedElems.Append(aMesh->AddFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ] ));
3647         break;
3648       case 4:
3649         if (!hasFreeLinks ||
3650             !aMesh->FindFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ], nodes[ 3 ]))
3651           myLastCreatedElems.Append(aMesh->AddFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ], nodes[ 3 ] ));
3652         break;
3653       default:
3654         if(itElem->second.back()->IsQuadratic()) {
3655           if(nbn==6) {
3656             if (!hasFreeLinks ||
3657                 !aMesh->FindFace(nodes[0], nodes[2], nodes[4],
3658                                  nodes[1], nodes[3], nodes[5]) ) {
3659               myLastCreatedElems.Append(aMesh->AddFace(nodes[0], nodes[2], nodes[4],
3660                                                        nodes[1], nodes[3], nodes[5]));
3661             }
3662           }
3663           else { // nbn==8
3664             if (!hasFreeLinks ||
3665                 !aMesh->FindFace(nodes[0], nodes[2], nodes[4], nodes[6],
3666                                  nodes[1], nodes[3], nodes[5], nodes[7]) )
3667               myLastCreatedElems.Append(aMesh->AddFace(nodes[0], nodes[2], nodes[4], nodes[6],
3668                                                        nodes[1], nodes[3], nodes[5], nodes[7]));
3669           }
3670         }
3671         else {
3672           vector<const SMDS_MeshNode*> polygon_nodes ( nodes, &nodes[nbn] );
3673           if (!hasFreeLinks || !aMesh->FindFace(polygon_nodes))
3674             myLastCreatedElems.Append(aMesh->AddPolygonalFace(polygon_nodes));
3675         }
3676       } // switch
3677
3678       while ( srcElements.Length() < myLastCreatedElems.Length() )
3679         srcElements.Append( myLastCreatedElems.Last() );
3680     }
3681   } // loop on swept elements
3682 }
3683
3684 //=======================================================================
3685 //function : RotationSweep
3686 //purpose  :
3687 //=======================================================================
3688
3689 SMESH_MeshEditor::PGroupIDs
3690 SMESH_MeshEditor::RotationSweep(TIDSortedElemSet & theElems,
3691                                 const gp_Ax1&      theAxis,
3692                                 const double       theAngle,
3693                                 const int          theNbSteps,
3694                                 const double       theTol,
3695                                 const bool         theMakeGroups,
3696                                 const bool         theMakeWalls)
3697 {
3698   myLastCreatedElems.Clear();
3699   myLastCreatedNodes.Clear();
3700
3701   // source elements for each generated one
3702   SMESH_SequenceOfElemPtr srcElems, srcNodes;
3703
3704   MESSAGE( "RotationSweep()");
3705   gp_Trsf aTrsf;
3706   aTrsf.SetRotation( theAxis, theAngle );
3707   gp_Trsf aTrsf2;
3708   aTrsf2.SetRotation( theAxis, theAngle/2. );
3709
3710   gp_Lin aLine( theAxis );
3711   double aSqTol = theTol * theTol;
3712
3713   SMESHDS_Mesh* aMesh = GetMeshDS();
3714
3715   TNodeOfNodeListMap mapNewNodes;
3716   TElemOfVecOfNnlmiMap mapElemNewNodes;
3717   TElemOfElemListMap newElemsMap;
3718
3719   // loop on theElems
3720   TIDSortedElemSet::iterator itElem;
3721   for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
3722     const SMDS_MeshElement* elem = *itElem;
3723     if ( !elem || elem->GetType() == SMDSAbs_Volume )
3724       continue;
3725     vector<TNodeOfNodeListMapItr> & newNodesItVec = mapElemNewNodes[ elem ];
3726     newNodesItVec.reserve( elem->NbNodes() );
3727
3728     // loop on elem nodes
3729     SMDS_ElemIteratorPtr itN = elem->nodesIterator();
3730     while ( itN->more() ) {
3731       // check if a node has been already sweeped
3732       const SMDS_MeshNode* node = cast2Node( itN->next() );
3733
3734       gp_XYZ aXYZ( node->X(), node->Y(), node->Z() );
3735       double coord[3];
3736       aXYZ.Coord( coord[0], coord[1], coord[2] );
3737       bool isOnAxis = ( aLine.SquareDistance( aXYZ ) <= aSqTol );
3738
3739       TNodeOfNodeListMapItr nIt = mapNewNodes.find( node );
3740       if ( nIt == mapNewNodes.end() ) {
3741         nIt = mapNewNodes.insert( make_pair( node, list<const SMDS_MeshNode*>() )).first;
3742         list<const SMDS_MeshNode*>& listNewNodes = nIt->second;
3743
3744         // make new nodes
3745         //gp_XYZ aXYZ( node->X(), node->Y(), node->Z() );
3746         //double coord[3];
3747         //aXYZ.Coord( coord[0], coord[1], coord[2] );
3748         //bool isOnAxis = ( aLine.SquareDistance( aXYZ ) <= aSqTol );
3749         const SMDS_MeshNode * newNode = node;
3750         for ( int i = 0; i < theNbSteps; i++ ) {
3751           if ( !isOnAxis ) {
3752             if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
3753               // create two nodes
3754               aTrsf2.Transforms( coord[0], coord[1], coord[2] );
3755               //aTrsf.Transforms( coord[0], coord[1], coord[2] );
3756               newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
3757               myLastCreatedNodes.Append(newNode);
3758               srcNodes.Append( node );
3759               listNewNodes.push_back( newNode );
3760               aTrsf2.Transforms( coord[0], coord[1], coord[2] );
3761               //aTrsf.Transforms( coord[0], coord[1], coord[2] );
3762             }
3763             else {
3764               aTrsf.Transforms( coord[0], coord[1], coord[2] );
3765             }
3766             newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
3767             myLastCreatedNodes.Append(newNode);
3768             srcNodes.Append( node );
3769             listNewNodes.push_back( newNode );
3770           }
3771           else {
3772             listNewNodes.push_back( newNode );
3773             if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
3774               listNewNodes.push_back( newNode );
3775             }
3776           }
3777         }
3778       }
3779       /*
3780         else {
3781         // if current elem is quadratic and current node is not medium
3782         // we have to check - may be it is needed to insert additional nodes
3783         if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
3784         list< const SMDS_MeshNode* > & listNewNodes = nIt->second;
3785         if(listNewNodes.size()==theNbSteps) {
3786         listNewNodes.clear();
3787         // make new nodes
3788         //gp_XYZ aXYZ( node->X(), node->Y(), node->Z() );
3789         //double coord[3];
3790         //aXYZ.Coord( coord[0], coord[1], coord[2] );
3791         const SMDS_MeshNode * newNode = node;
3792         if ( !isOnAxis ) {
3793         for(int i = 0; i<theNbSteps; i++) {
3794         aTrsf2.Transforms( coord[0], coord[1], coord[2] );
3795         newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
3796         cout<<"    3 AddNode:  "<<newNode;
3797         myLastCreatedNodes.Append(newNode);
3798         listNewNodes.push_back( newNode );
3799         srcNodes.Append( node );
3800         aTrsf2.Transforms( coord[0], coord[1], coord[2] );
3801         newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
3802         cout<<"    4 AddNode:  "<<newNode;
3803         myLastCreatedNodes.Append(newNode);
3804         srcNodes.Append( node );
3805         listNewNodes.push_back( newNode );
3806         }
3807         }
3808         else {
3809         listNewNodes.push_back( newNode );
3810         }
3811         }
3812         }
3813         }
3814       */
3815       newNodesItVec.push_back( nIt );
3816     }
3817     // make new elements
3818     sweepElement( elem, newNodesItVec, newElemsMap[elem], theNbSteps, srcElems );
3819   }
3820
3821   if ( theMakeWalls )
3822     makeWalls( mapNewNodes, newElemsMap, mapElemNewNodes, theElems, theNbSteps, srcElems );
3823
3824   PGroupIDs newGroupIDs;
3825   if ( theMakeGroups )
3826     newGroupIDs = generateGroups( srcNodes, srcElems, "rotated");
3827
3828   return newGroupIDs;
3829 }
3830
3831
3832 //=======================================================================
3833 //function : CreateNode
3834 //purpose  :
3835 //=======================================================================
3836 const SMDS_MeshNode* SMESH_MeshEditor::CreateNode(const double x,
3837                                                   const double y,
3838                                                   const double z,
3839                                                   const double tolnode,
3840                                                   SMESH_SequenceOfNode& aNodes)
3841 {
3842   myLastCreatedElems.Clear();
3843   myLastCreatedNodes.Clear();
3844
3845   gp_Pnt P1(x,y,z);
3846   SMESHDS_Mesh * aMesh = myMesh->GetMeshDS();
3847
3848   // try to search in sequence of existing nodes
3849   // if aNodes.Length()>0 we 'nave to use given sequence
3850   // else - use all nodes of mesh
3851   if(aNodes.Length()>0) {
3852     int i;
3853     for(i=1; i<=aNodes.Length(); i++) {
3854       gp_Pnt P2(aNodes.Value(i)->X(),aNodes.Value(i)->Y(),aNodes.Value(i)->Z());
3855       if(P1.Distance(P2)<tolnode)
3856         return aNodes.Value(i);
3857     }
3858   }
3859   else {
3860     SMDS_NodeIteratorPtr itn = aMesh->nodesIterator();
3861     while(itn->more()) {
3862       const SMDS_MeshNode* aN = static_cast<const SMDS_MeshNode*> (itn->next());
3863       gp_Pnt P2(aN->X(),aN->Y(),aN->Z());
3864       if(P1.Distance(P2)<tolnode)
3865         return aN;
3866     }
3867   }
3868
3869   // create new node and return it
3870   const SMDS_MeshNode* NewNode = aMesh->AddNode(x,y,z);
3871   myLastCreatedNodes.Append(NewNode);
3872   return NewNode;
3873 }
3874
3875
3876 //=======================================================================
3877 //function : ExtrusionSweep
3878 //purpose  :
3879 //=======================================================================
3880
3881 SMESH_MeshEditor::PGroupIDs
3882 SMESH_MeshEditor::ExtrusionSweep (TIDSortedElemSet &  theElems,
3883                                   const gp_Vec&       theStep,
3884                                   const int           theNbSteps,
3885                                   TElemOfElemListMap& newElemsMap,
3886                                   const bool          theMakeGroups,
3887                                   const int           theFlags,
3888                                   const double        theTolerance)
3889 {
3890   ExtrusParam aParams;
3891   aParams.myDir = gp_Dir(theStep);
3892   aParams.myNodes.Clear();
3893   aParams.mySteps = new TColStd_HSequenceOfReal;
3894   int i;
3895   for(i=1; i<=theNbSteps; i++)
3896     aParams.mySteps->Append(theStep.Magnitude());
3897
3898   return
3899     ExtrusionSweep(theElems,aParams,newElemsMap,theMakeGroups,theFlags,theTolerance);
3900 }
3901
3902
3903 //=======================================================================
3904 //function : ExtrusionSweep
3905 //purpose  :
3906 //=======================================================================
3907
3908 SMESH_MeshEditor::PGroupIDs
3909 SMESH_MeshEditor::ExtrusionSweep (TIDSortedElemSet &  theElems,
3910                                   ExtrusParam&        theParams,
3911                                   TElemOfElemListMap& newElemsMap,
3912                                   const bool          theMakeGroups,
3913                                   const int           theFlags,
3914                                   const double        theTolerance)
3915 {
3916   myLastCreatedElems.Clear();
3917   myLastCreatedNodes.Clear();
3918
3919   // source elements for each generated one
3920   SMESH_SequenceOfElemPtr srcElems, srcNodes;
3921
3922   SMESHDS_Mesh* aMesh = GetMeshDS();
3923
3924   int nbsteps = theParams.mySteps->Length();
3925
3926   TNodeOfNodeListMap mapNewNodes;
3927   //TNodeOfNodeVecMap mapNewNodes;
3928   TElemOfVecOfNnlmiMap mapElemNewNodes;
3929   //TElemOfVecOfMapNodesMap mapElemNewNodes;
3930
3931   // loop on theElems
3932   TIDSortedElemSet::iterator itElem;
3933   for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
3934     // check element type
3935     const SMDS_MeshElement* elem = *itElem;
3936     if ( !elem  || elem->GetType() == SMDSAbs_Volume )
3937       continue;
3938
3939     vector<TNodeOfNodeListMapItr> & newNodesItVec = mapElemNewNodes[ elem ];
3940     //vector<TNodeOfNodeVecMapItr> & newNodesItVec = mapElemNewNodes[ elem ];
3941     newNodesItVec.reserve( elem->NbNodes() );
3942
3943     // loop on elem nodes
3944     SMDS_ElemIteratorPtr itN = elem->nodesIterator();
3945     while ( itN->more() )
3946     {
3947       // check if a node has been already sweeped
3948       const SMDS_MeshNode* node = cast2Node( itN->next() );
3949       TNodeOfNodeListMap::iterator nIt = mapNewNodes.find( node );
3950       //TNodeOfNodeVecMap::iterator nIt = mapNewNodes.find( node );
3951       if ( nIt == mapNewNodes.end() ) {
3952         nIt = mapNewNodes.insert( make_pair( node, list<const SMDS_MeshNode*>() )).first;
3953         //nIt = mapNewNodes.insert( make_pair( node, vector<const SMDS_MeshNode*>() )).first;
3954         list<const SMDS_MeshNode*>& listNewNodes = nIt->second;
3955         //vector<const SMDS_MeshNode*>& vecNewNodes = nIt->second;
3956         //vecNewNodes.reserve(nbsteps);
3957
3958         // make new nodes
3959         double coord[] = { node->X(), node->Y(), node->Z() };
3960         //int nbsteps = theParams.mySteps->Length();
3961         for ( int i = 0; i < nbsteps; i++ ) {
3962           if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
3963             // create additional node
3964             double x = coord[0] + theParams.myDir.X()*theParams.mySteps->Value(i+1)/2.;
3965             double y = coord[1] + theParams.myDir.Y()*theParams.mySteps->Value(i+1)/2.;
3966             double z = coord[2] + theParams.myDir.Z()*theParams.mySteps->Value(i+1)/2.;
3967             if( theFlags & EXTRUSION_FLAG_SEW ) {
3968               const SMDS_MeshNode * newNode = CreateNode(x, y, z,
3969                                                          theTolerance, theParams.myNodes);
3970               listNewNodes.push_back( newNode );
3971             }
3972             else {
3973               const SMDS_MeshNode * newNode = aMesh->AddNode(x, y, z);
3974               myLastCreatedNodes.Append(newNode);
3975               srcNodes.Append( node );
3976               listNewNodes.push_back( newNode );
3977             }
3978           }
3979           //aTrsf.Transforms( coord[0], coord[1], coord[2] );
3980           coord[0] = coord[0] + theParams.myDir.X()*theParams.mySteps->Value(i+1);
3981           coord[1] = coord[1] + theParams.myDir.Y()*theParams.mySteps->Value(i+1);
3982           coord[2] = coord[2] + theParams.myDir.Z()*theParams.mySteps->Value(i+1);
3983           if( theFlags & EXTRUSION_FLAG_SEW ) {
3984             const SMDS_MeshNode * newNode = CreateNode(coord[0], coord[1], coord[2],
3985                                                        theTolerance, theParams.myNodes);
3986             listNewNodes.push_back( newNode );
3987             //vecNewNodes[i]=newNode;
3988           }
3989           else {
3990             const SMDS_MeshNode * newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
3991             myLastCreatedNodes.Append(newNode);
3992             srcNodes.Append( node );
3993             listNewNodes.push_back( newNode );
3994             //vecNewNodes[i]=newNode;
3995           }
3996         }
3997       }
3998       else {
3999         // if current elem is quadratic and current node is not medium
4000         // we have to check - may be it is needed to insert additional nodes
4001         if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
4002           list< const SMDS_MeshNode* > & listNewNodes = nIt->second;
4003           if(listNewNodes.size()==nbsteps) {
4004             listNewNodes.clear();
4005             double coord[] = { node->X(), node->Y(), node->Z() };
4006             for ( int i = 0; i < nbsteps; i++ ) {
4007               double x = coord[0] + theParams.myDir.X()*theParams.mySteps->Value(i+1);
4008               double y = coord[1] + theParams.myDir.Y()*theParams.mySteps->Value(i+1);
4009               double z = coord[2] + theParams.myDir.Z()*theParams.mySteps->Value(i+1);
4010               if( theFlags & EXTRUSION_FLAG_SEW ) {
4011                 const SMDS_MeshNode * newNode = CreateNode(x, y, z,
4012                                                            theTolerance, theParams.myNodes);
4013                 listNewNodes.push_back( newNode );
4014               }
4015               else {
4016                 const SMDS_MeshNode * newNode = aMesh->AddNode(x, y, z);
4017                 myLastCreatedNodes.Append(newNode);
4018                 srcNodes.Append( node );
4019                 listNewNodes.push_back( newNode );
4020               }
4021               coord[0] = coord[0] + theParams.myDir.X()*theParams.mySteps->Value(i+1);
4022               coord[1] = coord[1] + theParams.myDir.Y()*theParams.mySteps->Value(i+1);
4023               coord[2] = coord[2] + theParams.myDir.Z()*theParams.mySteps->Value(i+1);
4024               if( theFlags & EXTRUSION_FLAG_SEW ) {
4025                 const SMDS_MeshNode * newNode = CreateNode(coord[0], coord[1], coord[2],
4026                                                            theTolerance, theParams.myNodes);
4027                 listNewNodes.push_back( newNode );
4028               }
4029               else {
4030                 const SMDS_MeshNode * newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
4031                 myLastCreatedNodes.Append(newNode);
4032                 srcNodes.Append( node );
4033                 listNewNodes.push_back( newNode );
4034               }
4035             }
4036           }
4037         }
4038       }
4039       newNodesItVec.push_back( nIt );
4040     }
4041     // make new elements
4042     sweepElement( elem, newNodesItVec, newElemsMap[elem], nbsteps, srcElems );
4043   }
4044
4045   if( theFlags & EXTRUSION_FLAG_BOUNDARY ) {
4046     makeWalls( mapNewNodes, newElemsMap, mapElemNewNodes, theElems, nbsteps, srcElems );
4047   }
4048   PGroupIDs newGroupIDs;
4049   if ( theMakeGroups )
4050     newGroupIDs = generateGroups( srcNodes, srcElems, "extruded");
4051
4052   return newGroupIDs;
4053 }
4054
4055 /*
4056 //=======================================================================
4057 //class    : SMESH_MeshEditor_PathPoint
4058 //purpose  : auxiliary class
4059 //=======================================================================
4060 class SMESH_MeshEditor_PathPoint {
4061 public:
4062 SMESH_MeshEditor_PathPoint() {
4063 myPnt.SetCoord(99., 99., 99.);
4064 myTgt.SetCoord(1.,0.,0.);
4065 myAngle=0.;
4066 myPrm=0.;
4067 }
4068 void SetPnt(const gp_Pnt& aP3D){
4069 myPnt=aP3D;
4070 }
4071 void SetTangent(const gp_Dir& aTgt){
4072 myTgt=aTgt;
4073 }
4074 void SetAngle(const double& aBeta){
4075 myAngle=aBeta;
4076 }
4077 void SetParameter(const double& aPrm){
4078 myPrm=aPrm;
4079 }
4080 const gp_Pnt& Pnt()const{
4081 return myPnt;
4082 }
4083 const gp_Dir& Tangent()const{
4084 return myTgt;
4085 }
4086 double Angle()const{
4087 return myAngle;
4088 }
4089 double Parameter()const{
4090 return myPrm;
4091 }
4092
4093 protected:
4094 gp_Pnt myPnt;
4095 gp_Dir myTgt;
4096 double myAngle;
4097 double myPrm;
4098 };
4099 */
4100
4101 //=======================================================================
4102 //function : ExtrusionAlongTrack
4103 //purpose  :
4104 //=======================================================================
4105 SMESH_MeshEditor::Extrusion_Error
4106 SMESH_MeshEditor::ExtrusionAlongTrack (TIDSortedElemSet &   theElements,
4107                                        SMESH_subMesh*       theTrack,
4108                                        const SMDS_MeshNode* theN1,
4109                                        const bool           theHasAngles,
4110                                        list<double>&        theAngles,
4111                                        const bool           theLinearVariation,
4112                                        const bool           theHasRefPoint,
4113                                        const gp_Pnt&        theRefPoint,
4114                                        const bool           theMakeGroups)
4115 {
4116   myLastCreatedElems.Clear();
4117   myLastCreatedNodes.Clear();
4118
4119   int aNbE;
4120   std::list<double> aPrms;
4121   TIDSortedElemSet::iterator itElem;
4122
4123   gp_XYZ aGC;
4124   TopoDS_Edge aTrackEdge;
4125   TopoDS_Vertex aV1, aV2;
4126
4127   SMDS_ElemIteratorPtr aItE;
4128   SMDS_NodeIteratorPtr aItN;
4129   SMDSAbs_ElementType aTypeE;
4130
4131   TNodeOfNodeListMap mapNewNodes;
4132
4133   // 1. Check data
4134   aNbE = theElements.size();
4135   // nothing to do
4136   if ( !aNbE )
4137     return EXTR_NO_ELEMENTS;
4138
4139   // 1.1 Track Pattern
4140   ASSERT( theTrack );
4141
4142   SMESHDS_SubMesh* pSubMeshDS = theTrack->GetSubMeshDS();
4143
4144   aItE = pSubMeshDS->GetElements();
4145   while ( aItE->more() ) {
4146     const SMDS_MeshElement* pE = aItE->next();
4147     aTypeE = pE->GetType();
4148     // Pattern must contain links only
4149     if ( aTypeE != SMDSAbs_Edge )
4150       return EXTR_PATH_NOT_EDGE;
4151   }
4152
4153   list<SMESH_MeshEditor_PathPoint> fullList;
4154
4155   const TopoDS_Shape& aS = theTrack->GetSubShape();
4156   // Sub shape for the Pattern must be an Edge or Wire
4157   if( aS.ShapeType() == TopAbs_EDGE ) {
4158     aTrackEdge = TopoDS::Edge( aS );
4159     // the Edge must not be degenerated
4160     if ( BRep_Tool::Degenerated( aTrackEdge ) )
4161       return EXTR_BAD_PATH_SHAPE;
4162     TopExp::Vertices( aTrackEdge, aV1, aV2 );
4163     aItN = theTrack->GetFather()->GetSubMesh( aV1 )->GetSubMeshDS()->GetNodes();
4164     const SMDS_MeshNode* aN1 = aItN->next();
4165     aItN = theTrack->GetFather()->GetSubMesh( aV2 )->GetSubMeshDS()->GetNodes();
4166     const SMDS_MeshNode* aN2 = aItN->next();
4167     // starting node must be aN1 or aN2
4168     if ( !( aN1 == theN1 || aN2 == theN1 ) )
4169       return EXTR_BAD_STARTING_NODE;
4170     aItN = pSubMeshDS->GetNodes();
4171     while ( aItN->more() ) {
4172       const SMDS_MeshNode* pNode = aItN->next();
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     SMESH_subMeshIteratorPtr itSM = theTrack->getDependsOnIterator(false,true);
4185     while(itSM->more()) {
4186       SMESH_subMesh* SM = itSM->next();
4187       LSM.push_back(SM);
4188       const TopoDS_Shape& aS = SM->GetSubShape();
4189       Edges.Append(aS);
4190     }
4191     list< list<SMESH_MeshEditor_PathPoint> > LLPPs;
4192     int startNid = theN1->GetID();
4193     TColStd_MapOfInteger UsedNums;
4194     int NbEdges = Edges.Length();
4195     int i = 1;
4196     for(; i<=NbEdges; i++) {
4197       int k = 0;
4198       list< SMESH_subMesh* >::iterator itLSM = LSM.begin();
4199       for(; itLSM!=LSM.end(); itLSM++) {
4200         k++;
4201         if(UsedNums.Contains(k)) continue;
4202         aTrackEdge = TopoDS::Edge( Edges.Value(k) );
4203         SMESH_subMesh* locTrack = *itLSM;
4204         SMESHDS_SubMesh* locMeshDS = locTrack->GetSubMeshDS();
4205         TopExp::Vertices( aTrackEdge, aV1, aV2 );
4206         aItN = locTrack->GetFather()->GetSubMesh(aV1)->GetSubMeshDS()->GetNodes();
4207         const SMDS_MeshNode* aN1 = aItN->next();
4208         aItN = locTrack->GetFather()->GetSubMesh(aV2)->GetSubMeshDS()->GetNodes();
4209         const SMDS_MeshNode* aN2 = aItN->next();
4210         // starting node must be aN1 or aN2
4211         if ( !( aN1->GetID() == startNid || aN2->GetID() == startNid ) ) continue;
4212         // 2. Collect parameters on the track edge
4213         aPrms.clear();
4214         aItN = locMeshDS->GetNodes();
4215         while ( aItN->more() ) {
4216           const SMDS_MeshNode* pNode = aItN->next();
4217           const SMDS_EdgePosition* pEPos =
4218             static_cast<const SMDS_EdgePosition*>( pNode->GetPosition().get() );
4219           double aT = pEPos->GetUParameter();
4220           aPrms.push_back( aT );
4221         }
4222         list<SMESH_MeshEditor_PathPoint> LPP;
4223         //Extrusion_Error err =
4224         MakeEdgePathPoints(aPrms, aTrackEdge,(aN1->GetID()==startNid), LPP);
4225         LLPPs.push_back(LPP);
4226         UsedNums.Add(k);
4227         // update startN for search following egde
4228         if( aN1->GetID() == startNid ) startNid = aN2->GetID();
4229         else startNid = aN1->GetID();
4230         break;
4231       }
4232     }
4233     list< list<SMESH_MeshEditor_PathPoint> >::iterator itLLPP = LLPPs.begin();
4234     list<SMESH_MeshEditor_PathPoint> firstList = *itLLPP;
4235     list<SMESH_MeshEditor_PathPoint>::iterator itPP = firstList.begin();
4236     for(; itPP!=firstList.end(); itPP++) {
4237       fullList.push_back( *itPP );
4238     }
4239     SMESH_MeshEditor_PathPoint PP1 = fullList.back();
4240     fullList.pop_back();
4241     itLLPP++;
4242     for(; itLLPP!=LLPPs.end(); itLLPP++) {
4243       list<SMESH_MeshEditor_PathPoint> currList = *itLLPP;
4244       itPP = currList.begin();
4245       SMESH_MeshEditor_PathPoint PP2 = currList.front();
4246       gp_Dir D1 = PP1.Tangent();
4247       gp_Dir D2 = PP2.Tangent();
4248       gp_Dir Dnew( gp_Vec( (D1.X()+D2.X())/2, (D1.Y()+D2.Y())/2,
4249                            (D1.Z()+D2.Z())/2 ) );
4250       PP1.SetTangent(Dnew);
4251       fullList.push_back(PP1);
4252       itPP++;
4253       for(; itPP!=firstList.end(); itPP++) {
4254         fullList.push_back( *itPP );
4255       }
4256       PP1 = fullList.back();
4257       fullList.pop_back();
4258     }
4259     // if wire not closed
4260     fullList.push_back(PP1);
4261     // else ???
4262   }
4263   else {
4264     return EXTR_BAD_PATH_SHAPE;
4265   }
4266
4267   return MakeExtrElements(theElements, fullList, theHasAngles, theAngles, theLinearVariation,
4268                           theHasRefPoint, theRefPoint, theMakeGroups);
4269 }
4270
4271
4272 //=======================================================================
4273 //function : ExtrusionAlongTrack
4274 //purpose  :
4275 //=======================================================================
4276 SMESH_MeshEditor::Extrusion_Error
4277 SMESH_MeshEditor::ExtrusionAlongTrack (TIDSortedElemSet &   theElements,
4278                                        SMESH_Mesh*          theTrack,
4279                                        const SMDS_MeshNode* theN1,
4280                                        const bool           theHasAngles,
4281                                        list<double>&        theAngles,
4282                                        const bool           theLinearVariation,
4283                                        const bool           theHasRefPoint,
4284                                        const gp_Pnt&        theRefPoint,
4285                                        const bool           theMakeGroups)
4286 {
4287   myLastCreatedElems.Clear();
4288   myLastCreatedNodes.Clear();
4289
4290   int aNbE;
4291   std::list<double> aPrms;
4292   TIDSortedElemSet::iterator itElem;
4293
4294   gp_XYZ aGC;
4295   TopoDS_Edge aTrackEdge;
4296   TopoDS_Vertex aV1, aV2;
4297
4298   SMDS_ElemIteratorPtr aItE;
4299   SMDS_NodeIteratorPtr aItN;
4300   SMDSAbs_ElementType aTypeE;
4301
4302   TNodeOfNodeListMap mapNewNodes;
4303
4304   // 1. Check data
4305   aNbE = theElements.size();
4306   // nothing to do
4307   if ( !aNbE )
4308     return EXTR_NO_ELEMENTS;
4309
4310   // 1.1 Track Pattern
4311   ASSERT( theTrack );
4312
4313   SMESHDS_Mesh* pMeshDS = theTrack->GetMeshDS();
4314
4315   aItE = pMeshDS->elementsIterator();
4316   while ( aItE->more() ) {
4317     const SMDS_MeshElement* pE = aItE->next();
4318     aTypeE = pE->GetType();
4319     // Pattern must contain links only
4320     if ( aTypeE != SMDSAbs_Edge )
4321       return EXTR_PATH_NOT_EDGE;
4322   }
4323
4324   list<SMESH_MeshEditor_PathPoint> fullList;
4325
4326   const TopoDS_Shape& aS = theTrack->GetShapeToMesh();
4327   // Sub shape for the Pattern must be an Edge or Wire
4328   if( aS.ShapeType() == TopAbs_EDGE ) {
4329     aTrackEdge = TopoDS::Edge( aS );
4330     // the Edge must not be degenerated
4331     if ( BRep_Tool::Degenerated( aTrackEdge ) )
4332       return EXTR_BAD_PATH_SHAPE;
4333     TopExp::Vertices( aTrackEdge, aV1, aV2 );
4334     aItN = theTrack->GetSubMesh( aV1 )->GetSubMeshDS()->GetNodes();
4335     const SMDS_MeshNode* aN1 = aItN->next();
4336     aItN = theTrack->GetSubMesh( aV2 )->GetSubMeshDS()->GetNodes();
4337     const SMDS_MeshNode* aN2 = aItN->next();
4338     // starting node must be aN1 or aN2
4339     if ( !( aN1 == theN1 || aN2 == theN1 ) )
4340       return EXTR_BAD_STARTING_NODE;
4341     aItN = pMeshDS->nodesIterator();
4342     while ( aItN->more() ) {
4343       const SMDS_MeshNode* pNode = aItN->next();
4344       if( pNode==aN1 || pNode==aN2 ) continue;
4345       const SMDS_EdgePosition* pEPos =
4346         static_cast<const SMDS_EdgePosition*>( pNode->GetPosition().get() );
4347       double aT = pEPos->GetUParameter();
4348       aPrms.push_back( aT );
4349     }
4350     //Extrusion_Error err =
4351     MakeEdgePathPoints(aPrms, aTrackEdge, (aN1==theN1), fullList);
4352   }
4353   else if( aS.ShapeType() == TopAbs_WIRE ) {
4354     list< SMESH_subMesh* > LSM;
4355     TopTools_SequenceOfShape Edges;
4356     TopExp_Explorer eExp(aS, TopAbs_EDGE);
4357     for(; eExp.More(); eExp.Next()) {
4358       TopoDS_Edge E = TopoDS::Edge( eExp.Current() );
4359       if( BRep_Tool::Degenerated(E) ) continue;
4360       SMESH_subMesh* SM = theTrack->GetSubMesh(E);
4361       if(SM) {
4362         LSM.push_back(SM);
4363         Edges.Append(E);
4364       }
4365     }
4366     list< list<SMESH_MeshEditor_PathPoint> > LLPPs;
4367     int startNid = theN1->GetID();
4368     TColStd_MapOfInteger UsedNums;
4369     int NbEdges = Edges.Length();
4370     int i = 1;
4371     for(; i<=NbEdges; i++) {
4372       int k = 0;
4373       list< SMESH_subMesh* >::iterator itLSM = LSM.begin();
4374       for(; itLSM!=LSM.end(); itLSM++) {
4375         k++;
4376         if(UsedNums.Contains(k)) continue;
4377         aTrackEdge = TopoDS::Edge( Edges.Value(k) );
4378         SMESH_subMesh* locTrack = *itLSM;
4379         SMESHDS_SubMesh* locMeshDS = locTrack->GetSubMeshDS();
4380         TopExp::Vertices( aTrackEdge, aV1, aV2 );
4381         aItN = locTrack->GetFather()->GetSubMesh(aV1)->GetSubMeshDS()->GetNodes();
4382         const SMDS_MeshNode* aN1 = aItN->next();
4383         aItN = locTrack->GetFather()->GetSubMesh(aV2)->GetSubMeshDS()->GetNodes();
4384         const SMDS_MeshNode* aN2 = aItN->next();
4385         // starting node must be aN1 or aN2
4386         if ( !( aN1->GetID() == startNid || aN2->GetID() == startNid ) ) continue;
4387         // 2. Collect parameters on the track edge
4388         aPrms.clear();
4389         aItN = locMeshDS->GetNodes();
4390         while ( aItN->more() ) {
4391           const SMDS_MeshNode* pNode = aItN->next();
4392           const SMDS_EdgePosition* pEPos =
4393             static_cast<const SMDS_EdgePosition*>( pNode->GetPosition().get() );
4394           double aT = pEPos->GetUParameter();
4395           aPrms.push_back( aT );
4396         }
4397         list<SMESH_MeshEditor_PathPoint> LPP;
4398         //Extrusion_Error err =
4399         MakeEdgePathPoints(aPrms, aTrackEdge,(aN1->GetID()==startNid), LPP);
4400         LLPPs.push_back(LPP);
4401         UsedNums.Add(k);
4402         // update startN for search following egde
4403         if( aN1->GetID() == startNid ) startNid = aN2->GetID();
4404         else startNid = aN1->GetID();
4405         break;
4406       }
4407     }
4408     list< list<SMESH_MeshEditor_PathPoint> >::iterator itLLPP = LLPPs.begin();
4409     list<SMESH_MeshEditor_PathPoint> firstList = *itLLPP;
4410     list<SMESH_MeshEditor_PathPoint>::iterator itPP = firstList.begin();
4411     for(; itPP!=firstList.end(); itPP++) {
4412       fullList.push_back( *itPP );
4413     }
4414     SMESH_MeshEditor_PathPoint PP1 = fullList.back();
4415     fullList.pop_back();
4416     itLLPP++;
4417     for(; itLLPP!=LLPPs.end(); itLLPP++) {
4418       list<SMESH_MeshEditor_PathPoint> currList = *itLLPP;
4419       itPP = currList.begin();
4420       SMESH_MeshEditor_PathPoint PP2 = currList.front();
4421       gp_Pnt P1 = PP1.Pnt();
4422       //cout<<"    PP1: Pnt("<<P1.X()<<","<<P1.Y()<<","<<P1.Z()<<")"<<endl;
4423       gp_Pnt P2 = PP2.Pnt();
4424       gp_Dir D1 = PP1.Tangent();
4425       gp_Dir D2 = PP2.Tangent();
4426       gp_Dir Dnew( gp_Vec( (D1.X()+D2.X())/2, (D1.Y()+D2.Y())/2,
4427                            (D1.Z()+D2.Z())/2 ) );
4428       PP1.SetTangent(Dnew);
4429       fullList.push_back(PP1);
4430       itPP++;
4431       for(; itPP!=currList.end(); itPP++) {
4432         fullList.push_back( *itPP );
4433       }
4434       PP1 = fullList.back();
4435       fullList.pop_back();
4436     }
4437     // if wire not closed
4438     fullList.push_back(PP1);
4439     // else ???
4440   }
4441   else {
4442     return EXTR_BAD_PATH_SHAPE;
4443   }
4444
4445   return MakeExtrElements(theElements, fullList, theHasAngles, theAngles, theLinearVariation,
4446                           theHasRefPoint, theRefPoint, theMakeGroups);
4447 }
4448
4449
4450 //=======================================================================
4451 //function : MakeEdgePathPoints
4452 //purpose  : auxilary for ExtrusionAlongTrack
4453 //=======================================================================
4454 SMESH_MeshEditor::Extrusion_Error
4455 SMESH_MeshEditor::MakeEdgePathPoints(std::list<double>& aPrms,
4456                                      const TopoDS_Edge& aTrackEdge,
4457                                      bool FirstIsStart,
4458                                      list<SMESH_MeshEditor_PathPoint>& LPP)
4459 {
4460   Standard_Real aTx1, aTx2, aL2, aTolVec, aTolVec2;
4461   aTolVec=1.e-7;
4462   aTolVec2=aTolVec*aTolVec;
4463   double aT1, aT2;
4464   TopoDS_Vertex aV1, aV2;
4465   TopExp::Vertices( aTrackEdge, aV1, aV2 );
4466   aT1=BRep_Tool::Parameter( aV1, aTrackEdge );
4467   aT2=BRep_Tool::Parameter( aV2, aTrackEdge );
4468   // 2. Collect parameters on the track edge
4469   aPrms.push_front( aT1 );
4470   aPrms.push_back( aT2 );
4471   // sort parameters
4472   aPrms.sort();
4473   if( FirstIsStart ) {
4474     if ( aT1 > aT2 ) {
4475       aPrms.reverse();
4476     }
4477   }
4478   else {
4479     if ( aT2 > aT1 ) {
4480       aPrms.reverse();
4481     }
4482   }
4483   // 3. Path Points
4484   SMESH_MeshEditor_PathPoint aPP;
4485   Handle(Geom_Curve) aC3D = BRep_Tool::Curve( aTrackEdge, aTx1, aTx2 );
4486   std::list<double>::iterator aItD = aPrms.begin();
4487   for(; aItD != aPrms.end(); ++aItD) {
4488     double aT = *aItD;
4489     gp_Pnt aP3D;
4490     gp_Vec aVec;
4491     aC3D->D1( aT, aP3D, aVec );
4492     aL2 = aVec.SquareMagnitude();
4493     if ( aL2 < aTolVec2 )
4494       return EXTR_CANT_GET_TANGENT;
4495     gp_Dir aTgt( aVec );
4496     aPP.SetPnt( aP3D );
4497     aPP.SetTangent( aTgt );
4498     aPP.SetParameter( aT );
4499     LPP.push_back(aPP);
4500   }
4501   return EXTR_OK;
4502 }
4503
4504
4505 //=======================================================================
4506 //function : MakeExtrElements
4507 //purpose  : auxilary for ExtrusionAlongTrack
4508 //=======================================================================
4509 SMESH_MeshEditor::Extrusion_Error
4510 SMESH_MeshEditor::MakeExtrElements(TIDSortedElemSet&  theElements,
4511                                    list<SMESH_MeshEditor_PathPoint>& fullList,
4512                                    const bool theHasAngles,
4513                                    list<double>& theAngles,
4514                                    const bool theLinearVariation,
4515                                    const bool theHasRefPoint,
4516                                    const gp_Pnt& theRefPoint,
4517                                    const bool theMakeGroups)
4518 {
4519   //cout<<"MakeExtrElements  fullList.size() = "<<fullList.size()<<endl;
4520   int aNbTP = fullList.size();
4521   vector<SMESH_MeshEditor_PathPoint> aPPs(aNbTP);
4522   // Angles
4523   if( theHasAngles && theAngles.size()>0 && theLinearVariation ) {
4524     LinearAngleVariation(aNbTP-1, theAngles);
4525   }
4526   vector<double> aAngles( aNbTP );
4527   int j = 0;
4528   for(; j<aNbTP; ++j) {
4529     aAngles[j] = 0.;
4530   }
4531   if ( theHasAngles ) {
4532     double anAngle;;
4533     std::list<double>::iterator aItD = theAngles.begin();
4534     for ( j=1; (aItD != theAngles.end()) && (j<aNbTP); ++aItD, ++j ) {
4535       anAngle = *aItD;
4536       aAngles[j] = anAngle;
4537     }
4538   }
4539   // fill vector of path points with angles
4540   //aPPs.resize(fullList.size());
4541   j = -1;
4542   list<SMESH_MeshEditor_PathPoint>::iterator itPP = fullList.begin();
4543   for(; itPP!=fullList.end(); itPP++) {
4544     j++;
4545     SMESH_MeshEditor_PathPoint PP = *itPP;
4546     PP.SetAngle(aAngles[j]);
4547     aPPs[j] = PP;
4548   }
4549
4550   TNodeOfNodeListMap mapNewNodes;
4551   TElemOfVecOfNnlmiMap mapElemNewNodes;
4552   TElemOfElemListMap newElemsMap;
4553   TIDSortedElemSet::iterator itElem;
4554   double aX, aY, aZ;
4555   int aNb;
4556   SMDSAbs_ElementType aTypeE;
4557   // source elements for each generated one
4558   SMESH_SequenceOfElemPtr srcElems, srcNodes;
4559
4560   // 3. Center of rotation aV0
4561   gp_Pnt aV0 = theRefPoint;
4562   gp_XYZ aGC;
4563   if ( !theHasRefPoint ) {
4564     aNb = 0;
4565     aGC.SetCoord( 0.,0.,0. );
4566
4567     itElem = theElements.begin();
4568     for ( ; itElem != theElements.end(); itElem++ ) {
4569       const SMDS_MeshElement* elem = *itElem;
4570
4571       SMDS_ElemIteratorPtr itN = elem->nodesIterator();
4572       while ( itN->more() ) {
4573         const SMDS_MeshNode* node = static_cast<const SMDS_MeshNode*>( itN->next() );
4574         aX = node->X();
4575         aY = node->Y();
4576         aZ = node->Z();
4577
4578         if ( mapNewNodes.find( node ) == mapNewNodes.end() ) {
4579           list<const SMDS_MeshNode*> aLNx;
4580           mapNewNodes[node] = aLNx;
4581           //
4582           gp_XYZ aXYZ( aX, aY, aZ );
4583           aGC += aXYZ;
4584           ++aNb;
4585         }
4586       }
4587     }
4588     aGC /= aNb;
4589     aV0.SetXYZ( aGC );
4590   } // if (!theHasRefPoint) {
4591   mapNewNodes.clear();
4592
4593   // 4. Processing the elements
4594   SMESHDS_Mesh* aMesh = GetMeshDS();
4595
4596   for ( itElem = theElements.begin(); itElem != theElements.end(); itElem++ ) {
4597     // check element type
4598     const SMDS_MeshElement* elem = *itElem;
4599     aTypeE = elem->GetType();
4600     if ( !elem || ( aTypeE != SMDSAbs_Face && aTypeE != SMDSAbs_Edge ) )
4601       continue;
4602
4603     vector<TNodeOfNodeListMapItr> & newNodesItVec = mapElemNewNodes[ elem ];
4604     newNodesItVec.reserve( elem->NbNodes() );
4605
4606     // loop on elem nodes
4607     int nodeIndex = -1;
4608     SMDS_ElemIteratorPtr itN = elem->nodesIterator();
4609     while ( itN->more() )
4610     {
4611       ++nodeIndex;
4612       // check if a node has been already processed
4613       const SMDS_MeshNode* node =
4614         static_cast<const SMDS_MeshNode*>( itN->next() );
4615       TNodeOfNodeListMap::iterator nIt = mapNewNodes.find( node );
4616       if ( nIt == mapNewNodes.end() ) {
4617         nIt = mapNewNodes.insert( make_pair( node, list<const SMDS_MeshNode*>() )).first;
4618         list<const SMDS_MeshNode*>& listNewNodes = nIt->second;
4619
4620         // make new nodes
4621         aX = node->X();  aY = node->Y(); aZ = node->Z();
4622
4623         Standard_Real aAngle1x, aAngleT1T0, aTolAng;
4624         gp_Pnt aP0x, aP1x, aPN0, aPN1, aV0x, aV1x;
4625         gp_Ax1 anAx1, anAxT1T0;
4626         gp_Dir aDT1x, aDT0x, aDT1T0;
4627
4628         aTolAng=1.e-4;
4629
4630         aV0x = aV0;
4631         aPN0.SetCoord(aX, aY, aZ);
4632
4633         const SMESH_MeshEditor_PathPoint& aPP0 = aPPs[0];
4634         aP0x = aPP0.Pnt();
4635         aDT0x= aPP0.Tangent();
4636         //cout<<"j = 0   PP: Pnt("<<aP0x.X()<<","<<aP0x.Y()<<","<<aP0x.Z()<<")"<<endl;
4637
4638         for ( j = 1; j < aNbTP; ++j ) {
4639           const SMESH_MeshEditor_PathPoint& aPP1 = aPPs[j];
4640           aP1x = aPP1.Pnt();
4641           aDT1x = aPP1.Tangent();
4642           aAngle1x = aPP1.Angle();
4643
4644           gp_Trsf aTrsf, aTrsfRot, aTrsfRotT1T0;
4645           // Translation
4646           gp_Vec aV01x( aP0x, aP1x );
4647           aTrsf.SetTranslation( aV01x );
4648
4649           // traslated point
4650           aV1x = aV0x.Transformed( aTrsf );
4651           aPN1 = aPN0.Transformed( aTrsf );
4652
4653           // rotation 1 [ T1,T0 ]
4654           aAngleT1T0=-aDT1x.Angle( aDT0x );
4655           if (fabs(aAngleT1T0) > aTolAng) {
4656             aDT1T0=aDT1x^aDT0x;
4657             anAxT1T0.SetLocation( aV1x );
4658             anAxT1T0.SetDirection( aDT1T0 );
4659             aTrsfRotT1T0.SetRotation( anAxT1T0, aAngleT1T0 );
4660
4661             aPN1 = aPN1.Transformed( aTrsfRotT1T0 );
4662           }
4663
4664           // rotation 2
4665           if ( theHasAngles ) {
4666             anAx1.SetLocation( aV1x );
4667             anAx1.SetDirection( aDT1x );
4668             aTrsfRot.SetRotation( anAx1, aAngle1x );
4669
4670             aPN1 = aPN1.Transformed( aTrsfRot );
4671           }
4672
4673           // make new node
4674           if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
4675             // create additional node
4676             double x = ( aPN1.X() + aPN0.X() )/2.;
4677             double y = ( aPN1.Y() + aPN0.Y() )/2.;
4678             double z = ( aPN1.Z() + aPN0.Z() )/2.;
4679             const SMDS_MeshNode* newNode = aMesh->AddNode(x,y,z);
4680             myLastCreatedNodes.Append(newNode);
4681             srcNodes.Append( node );
4682             listNewNodes.push_back( newNode );
4683           }
4684           aX = aPN1.X();
4685           aY = aPN1.Y();
4686           aZ = aPN1.Z();
4687           const SMDS_MeshNode* newNode = aMesh->AddNode( aX, aY, aZ );
4688           myLastCreatedNodes.Append(newNode);
4689           srcNodes.Append( node );
4690           listNewNodes.push_back( newNode );
4691
4692           aPN0 = aPN1;
4693           aP0x = aP1x;
4694           aV0x = aV1x;
4695           aDT0x = aDT1x;
4696         }
4697       }
4698
4699       else {
4700         // if current elem is quadratic and current node is not medium
4701         // we have to check - may be it is needed to insert additional nodes
4702         if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
4703           list< const SMDS_MeshNode* > & listNewNodes = nIt->second;
4704           if(listNewNodes.size()==aNbTP-1) {
4705             vector<const SMDS_MeshNode*> aNodes(2*(aNbTP-1));
4706             gp_XYZ P(node->X(), node->Y(), node->Z());
4707             list< const SMDS_MeshNode* >::iterator it = listNewNodes.begin();
4708             int i;
4709             for(i=0; i<aNbTP-1; i++) {
4710               const SMDS_MeshNode* N = *it;
4711               double x = ( N->X() + P.X() )/2.;
4712               double y = ( N->Y() + P.Y() )/2.;
4713               double z = ( N->Z() + P.Z() )/2.;
4714               const SMDS_MeshNode* newN = aMesh->AddNode(x,y,z);
4715               srcNodes.Append( node );
4716               myLastCreatedNodes.Append(newN);
4717               aNodes[2*i] = newN;
4718               aNodes[2*i+1] = N;
4719               P = gp_XYZ(N->X(),N->Y(),N->Z());
4720             }
4721             listNewNodes.clear();
4722             for(i=0; i<2*(aNbTP-1); i++) {
4723               listNewNodes.push_back(aNodes[i]);
4724             }
4725           }
4726         }
4727       }
4728
4729       newNodesItVec.push_back( nIt );
4730     }
4731     // make new elements
4732     //sweepElement( aMesh, elem, newNodesItVec, newElemsMap[elem],
4733     //              newNodesItVec[0]->second.size(), myLastCreatedElems );
4734     sweepElement( elem, newNodesItVec, newElemsMap[elem], aNbTP-1, srcElems );
4735   }
4736
4737   makeWalls( mapNewNodes, newElemsMap, mapElemNewNodes, theElements, aNbTP-1, srcElems );
4738
4739   if ( theMakeGroups )
4740     generateGroups( srcNodes, srcElems, "extruded");
4741
4742   return EXTR_OK;
4743 }
4744
4745
4746 //=======================================================================
4747 //function : LinearAngleVariation
4748 //purpose  : auxilary for ExtrusionAlongTrack
4749 //=======================================================================
4750 void SMESH_MeshEditor::LinearAngleVariation(const int nbSteps,
4751                                             list<double>& Angles)
4752 {
4753   int nbAngles = Angles.size();
4754   if( nbSteps > nbAngles ) {
4755     vector<double> theAngles(nbAngles);
4756     list<double>::iterator it = Angles.begin();
4757     int i = -1;
4758     for(; it!=Angles.end(); it++) {
4759       i++;
4760       theAngles[i] = (*it);
4761     }
4762     list<double> res;
4763     double rAn2St = double( nbAngles ) / double( nbSteps );
4764     double angPrev = 0, angle;
4765     for ( int iSt = 0; iSt < nbSteps; ++iSt ) {
4766       double angCur = rAn2St * ( iSt+1 );
4767       double angCurFloor  = floor( angCur );
4768       double angPrevFloor = floor( angPrev );
4769       if ( angPrevFloor == angCurFloor )
4770         angle = rAn2St * theAngles[ int( angCurFloor ) ];
4771       else {
4772         int iP = int( angPrevFloor );
4773         double angPrevCeil = ceil(angPrev);
4774         angle = ( angPrevCeil - angPrev ) * theAngles[ iP ];
4775
4776         int iC = int( angCurFloor );
4777         if ( iC < nbAngles )
4778           angle += ( angCur - angCurFloor ) * theAngles[ iC ];
4779
4780         iP = int( angPrevCeil );
4781         while ( iC-- > iP )
4782           angle += theAngles[ iC ];
4783       }
4784       res.push_back(angle);
4785       angPrev = angCur;
4786     }
4787     Angles.clear();
4788     it = res.begin();
4789     for(; it!=res.end(); it++)
4790       Angles.push_back( *it );
4791   }
4792 }
4793
4794
4795 //=======================================================================
4796 //function : Transform
4797 //purpose  :
4798 //=======================================================================
4799
4800 SMESH_MeshEditor::PGroupIDs
4801 SMESH_MeshEditor::Transform (TIDSortedElemSet & theElems,
4802                              const gp_Trsf&     theTrsf,
4803                              const bool         theCopy,
4804                              const bool         theMakeGroups,
4805                              SMESH_Mesh*        theTargetMesh)
4806 {
4807   myLastCreatedElems.Clear();
4808   myLastCreatedNodes.Clear();
4809
4810   bool needReverse = false;
4811   string groupPostfix;
4812   switch ( theTrsf.Form() ) {
4813   case gp_PntMirror:
4814   case gp_Ax1Mirror:
4815   case gp_Ax2Mirror:
4816     needReverse = true;
4817     groupPostfix = "mirrored";
4818     break;
4819   case gp_Rotation:
4820     groupPostfix = "rotated";
4821     break;
4822   case gp_Translation:
4823     groupPostfix = "translated";
4824     break;
4825   case gp_Scale:
4826     groupPostfix = "scaled";
4827     break;
4828   default:
4829     needReverse = false;
4830     groupPostfix = "transformed";
4831   }
4832
4833   SMESH_MeshEditor targetMeshEditor( theTargetMesh );
4834   SMESHDS_Mesh* aTgtMesh = theTargetMesh ? theTargetMesh->GetMeshDS() : 0;
4835   SMESHDS_Mesh* aMesh    = GetMeshDS();
4836
4837
4838   // map old node to new one
4839   TNodeNodeMap nodeMap;
4840
4841   // elements sharing moved nodes; those of them which have all
4842   // nodes mirrored but are not in theElems are to be reversed
4843   TIDSortedElemSet inverseElemSet;
4844
4845   // source elements for each generated one
4846   SMESH_SequenceOfElemPtr srcElems, srcNodes;
4847
4848   // loop on theElems
4849   TIDSortedElemSet::iterator itElem;
4850   for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
4851     const SMDS_MeshElement* elem = *itElem;
4852     if ( !elem )
4853       continue;
4854
4855     // loop on elem nodes
4856     SMDS_ElemIteratorPtr itN = elem->nodesIterator();
4857     while ( itN->more() ) {
4858
4859       // check if a node has been already transformed
4860       const SMDS_MeshNode* node = cast2Node( itN->next() );
4861       pair<TNodeNodeMap::iterator,bool> n2n_isnew =
4862         nodeMap.insert( make_pair ( node, node ));
4863       if ( !n2n_isnew.second )
4864         continue;
4865
4866       double coord[3];
4867       coord[0] = node->X();
4868       coord[1] = node->Y();
4869       coord[2] = node->Z();
4870       theTrsf.Transforms( coord[0], coord[1], coord[2] );
4871       if ( theTargetMesh ) {
4872         const SMDS_MeshNode * newNode = aTgtMesh->AddNode( coord[0], coord[1], coord[2] );
4873         n2n_isnew.first->second = newNode;
4874         myLastCreatedNodes.Append(newNode);
4875         srcNodes.Append( node );
4876       }
4877       else if ( theCopy ) {
4878         const SMDS_MeshNode * newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
4879         n2n_isnew.first->second = newNode;
4880         myLastCreatedNodes.Append(newNode);
4881         srcNodes.Append( node );
4882       }
4883       else {
4884         aMesh->MoveNode( node, coord[0], coord[1], coord[2] );
4885         // node position on shape becomes invalid
4886         const_cast< SMDS_MeshNode* > ( node )->SetPosition
4887           ( SMDS_SpacePosition::originSpacePosition() );
4888       }
4889
4890       // keep inverse elements
4891       if ( !theCopy && !theTargetMesh && needReverse ) {
4892         SMDS_ElemIteratorPtr invElemIt = node->GetInverseElementIterator();
4893         while ( invElemIt->more() ) {
4894           const SMDS_MeshElement* iel = invElemIt->next();
4895           inverseElemSet.insert( iel );
4896         }
4897       }
4898     }
4899   }
4900
4901   // either create new elements or reverse mirrored ones
4902   if ( !theCopy && !needReverse && !theTargetMesh )
4903     return PGroupIDs();
4904
4905   TIDSortedElemSet::iterator invElemIt = inverseElemSet.begin();
4906   for ( ; invElemIt != inverseElemSet.end(); invElemIt++ )
4907     theElems.insert( *invElemIt );
4908
4909   // replicate or reverse elements
4910
4911   enum {
4912     REV_TETRA   = 0,  //  = nbNodes - 4
4913     REV_PYRAMID = 1,  //  = nbNodes - 4
4914     REV_PENTA   = 2,  //  = nbNodes - 4
4915     REV_FACE    = 3,
4916     REV_HEXA    = 4,  //  = nbNodes - 4
4917     FORWARD     = 5
4918   };
4919   int index[][8] = {
4920     { 2, 1, 0, 3, 4, 0, 0, 0 },  // REV_TETRA
4921     { 2, 1, 0, 3, 4, 0, 0, 0 },  // REV_PYRAMID
4922     { 2, 1, 0, 5, 4, 3, 0, 0 },  // REV_PENTA
4923     { 2, 1, 0, 3, 0, 0, 0, 0 },  // REV_FACE
4924     { 2, 1, 0, 3, 6, 5, 4, 7 },  // REV_HEXA
4925     { 0, 1, 2, 3, 4, 5, 6, 7 }   // FORWARD
4926   };
4927
4928   for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ )
4929   {
4930     const SMDS_MeshElement* elem = *itElem;
4931     if ( !elem || elem->GetType() == SMDSAbs_Node )
4932       continue;
4933
4934     int nbNodes = elem->NbNodes();
4935     int elemType = elem->GetType();
4936
4937     if (elem->IsPoly()) {
4938       // Polygon or Polyhedral Volume
4939       switch ( elemType ) {
4940       case SMDSAbs_Face:
4941         {
4942           vector<const SMDS_MeshNode*> poly_nodes (nbNodes);
4943           int iNode = 0;
4944           SMDS_ElemIteratorPtr itN = elem->nodesIterator();
4945           while (itN->more()) {
4946             const SMDS_MeshNode* node =
4947               static_cast<const SMDS_MeshNode*>(itN->next());
4948             TNodeNodeMap::iterator nodeMapIt = nodeMap.find(node);
4949             if (nodeMapIt == nodeMap.end())
4950               break; // not all nodes transformed
4951             if (needReverse) {
4952               // reverse mirrored faces and volumes
4953               poly_nodes[nbNodes - iNode - 1] = (*nodeMapIt).second;
4954             } else {
4955               poly_nodes[iNode] = (*nodeMapIt).second;
4956             }
4957             iNode++;
4958           }
4959           if ( iNode != nbNodes )
4960             continue; // not all nodes transformed
4961
4962           if ( theTargetMesh ) {
4963             myLastCreatedElems.Append(aTgtMesh->AddPolygonalFace(poly_nodes));
4964             srcElems.Append( elem );
4965           }
4966           else if ( theCopy ) {
4967             myLastCreatedElems.Append(aMesh->AddPolygonalFace(poly_nodes));
4968             srcElems.Append( elem );
4969           }
4970           else {
4971             aMesh->ChangePolygonNodes(elem, poly_nodes);
4972           }
4973         }
4974         break;
4975       case SMDSAbs_Volume:
4976         {
4977           // ATTENTION: Reversing is not yet done!!!
4978           const SMDS_PolyhedralVolumeOfNodes* aPolyedre =
4979             dynamic_cast<const SMDS_PolyhedralVolumeOfNodes*>( elem );
4980           if (!aPolyedre) {
4981             MESSAGE("Warning: bad volumic element");
4982             continue;
4983           }
4984
4985           vector<const SMDS_MeshNode*> poly_nodes;
4986           vector<int> quantities;
4987
4988           bool allTransformed = true;
4989           int nbFaces = aPolyedre->NbFaces();
4990           for (int iface = 1; iface <= nbFaces && allTransformed; iface++) {
4991             int nbFaceNodes = aPolyedre->NbFaceNodes(iface);
4992             for (int inode = 1; inode <= nbFaceNodes && allTransformed; inode++) {
4993               const SMDS_MeshNode* node = aPolyedre->GetFaceNode(iface, inode);
4994               TNodeNodeMap::iterator nodeMapIt = nodeMap.find(node);
4995               if (nodeMapIt == nodeMap.end()) {
4996                 allTransformed = false; // not all nodes transformed
4997               } else {
4998                 poly_nodes.push_back((*nodeMapIt).second);
4999               }
5000             }
5001             quantities.push_back(nbFaceNodes);
5002           }
5003           if ( !allTransformed )
5004             continue; // not all nodes transformed
5005
5006           if ( theTargetMesh ) {
5007             myLastCreatedElems.Append(aTgtMesh->AddPolyhedralVolume(poly_nodes, quantities));
5008             srcElems.Append( elem );
5009           }
5010           else if ( theCopy ) {
5011             myLastCreatedElems.Append(aMesh->AddPolyhedralVolume(poly_nodes, quantities));
5012             srcElems.Append( elem );
5013           }
5014           else {
5015             aMesh->ChangePolyhedronNodes(elem, poly_nodes, quantities);
5016           }
5017         }
5018         break;
5019       default:;
5020       }
5021       continue;
5022     }
5023
5024     // Regular elements
5025     int* i = index[ FORWARD ];
5026     if ( needReverse && nbNodes > 2) // reverse mirrored faces and volumes
5027       if ( elemType == SMDSAbs_Face )
5028         i = index[ REV_FACE ];
5029       else
5030         i = index[ nbNodes - 4 ];
5031
5032     if(elem->IsQuadratic()) {
5033       static int anIds[] = {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19};
5034       i = anIds;
5035       if(needReverse) {
5036         if(nbNodes==3) { // quadratic edge
5037           static int anIds[] = {1,0,2};
5038           i = anIds;
5039         }
5040         else if(nbNodes==6) { // quadratic triangle
5041           static int anIds[] = {0,2,1,5,4,3};
5042           i = anIds;
5043         }
5044         else if(nbNodes==8) { // quadratic quadrangle
5045           static int anIds[] = {0,3,2,1,7,6,5,4};
5046           i = anIds;
5047         }
5048         else if(nbNodes==10) { // quadratic tetrahedron of 10 nodes
5049           static int anIds[] = {0,2,1,3,6,5,4,7,9,8};
5050           i = anIds;
5051         }
5052         else if(nbNodes==13) { // quadratic pyramid of 13 nodes
5053           static int anIds[] = {0,3,2,1,4,8,7,6,5,9,12,11,10};
5054           i = anIds;
5055         }
5056         else if(nbNodes==15) { // quadratic pentahedron with 15 nodes
5057           static int anIds[] = {0,2,1,3,5,4,8,7,6,11,10,9,12,14,13};
5058           i = anIds;
5059         }
5060         else { // nbNodes==20 - quadratic hexahedron with 20 nodes
5061           static int anIds[] = {0,3,2,1,4,7,6,5,11,10,9,8,15,14,13,12,16,19,18,17};
5062           i = anIds;
5063         }
5064       }
5065     }
5066
5067     // find transformed nodes
5068     vector<const SMDS_MeshNode*> nodes(nbNodes);
5069     int iNode = 0;
5070     SMDS_ElemIteratorPtr itN = elem->nodesIterator();
5071     while ( itN->more() ) {
5072       const SMDS_MeshNode* node =
5073         static_cast<const SMDS_MeshNode*>( itN->next() );
5074       TNodeNodeMap::iterator nodeMapIt = nodeMap.find( node );
5075       if ( nodeMapIt == nodeMap.end() )
5076         break; // not all nodes transformed
5077       nodes[ i [ iNode++ ]] = (*nodeMapIt).second;
5078     }
5079     if ( iNode != nbNodes )
5080       continue; // not all nodes transformed
5081
5082     if ( theTargetMesh ) {
5083       if ( SMDS_MeshElement* copy =
5084            targetMeshEditor.AddElement( nodes, elem->GetType(), elem->IsPoly() )) {
5085         myLastCreatedElems.Append( copy );
5086         srcElems.Append( elem );
5087       }
5088     }
5089     else if ( theCopy ) {
5090       if ( SMDS_MeshElement* copy = AddElement( nodes, elem->GetType(), elem->IsPoly() )) {
5091         myLastCreatedElems.Append( copy );
5092         srcElems.Append( elem );
5093       }
5094     }
5095     else {
5096       // reverse element as it was reversed by transformation
5097       if ( nbNodes > 2 )
5098         aMesh->ChangeElementNodes( elem, &nodes[0], nbNodes );
5099     }
5100   }
5101
5102   PGroupIDs newGroupIDs;
5103
5104   if ( theMakeGroups && theCopy ||
5105        theMakeGroups && theTargetMesh )
5106     newGroupIDs = generateGroups( srcNodes, srcElems, groupPostfix, theTargetMesh );
5107
5108   return newGroupIDs;
5109 }
5110
5111
5112 //=======================================================================
5113 //function : Scale
5114 //purpose  :
5115 //=======================================================================
5116
5117 SMESH_MeshEditor::PGroupIDs
5118 SMESH_MeshEditor::Scale (TIDSortedElemSet & theElems,
5119                          const gp_Pnt&            thePoint,
5120                          const std::list<double>& theScaleFact,
5121                          const bool         theCopy,
5122                          const bool         theMakeGroups,
5123                          SMESH_Mesh*        theTargetMesh)
5124 {
5125   myLastCreatedElems.Clear();
5126   myLastCreatedNodes.Clear();
5127
5128   SMESH_MeshEditor targetMeshEditor( theTargetMesh );
5129   SMESHDS_Mesh* aTgtMesh = theTargetMesh ? theTargetMesh->GetMeshDS() : 0;
5130   SMESHDS_Mesh* aMesh    = GetMeshDS();
5131
5132   double scaleX=1.0, scaleY=1.0, scaleZ=1.0;
5133   std::list<double>::const_iterator itS = theScaleFact.begin();
5134   scaleX = (*itS);
5135   if(theScaleFact.size()==1) {
5136     scaleY = (*itS);
5137     scaleZ= (*itS);
5138   }
5139   if(theScaleFact.size()==2) {
5140     itS++;
5141     scaleY = (*itS);
5142     scaleZ= (*itS);
5143   }
5144   if(theScaleFact.size()>2) {
5145     itS++;
5146     scaleY = (*itS);
5147     itS++;
5148     scaleZ= (*itS);
5149   }
5150   
5151   // map old node to new one
5152   TNodeNodeMap nodeMap;
5153
5154   // elements sharing moved nodes; those of them which have all
5155   // nodes mirrored but are not in theElems are to be reversed
5156   TIDSortedElemSet inverseElemSet;
5157
5158   // source elements for each generated one
5159   SMESH_SequenceOfElemPtr srcElems, srcNodes;
5160
5161   // loop on theElems
5162   TIDSortedElemSet::iterator itElem;
5163   for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
5164     const SMDS_MeshElement* elem = *itElem;
5165     if ( !elem )
5166       continue;
5167
5168     // loop on elem nodes
5169     SMDS_ElemIteratorPtr itN = elem->nodesIterator();
5170     while ( itN->more() ) {
5171
5172       // check if a node has been already transformed
5173       const SMDS_MeshNode* node = cast2Node( itN->next() );
5174       pair<TNodeNodeMap::iterator,bool> n2n_isnew =
5175         nodeMap.insert( make_pair ( node, node ));
5176       if ( !n2n_isnew.second )
5177         continue;
5178
5179       //double coord[3];
5180       //coord[0] = node->X();
5181       //coord[1] = node->Y();
5182       //coord[2] = node->Z();
5183       //theTrsf.Transforms( coord[0], coord[1], coord[2] );
5184       double dx = (node->X() - thePoint.X()) * scaleX;
5185       double dy = (node->Y() - thePoint.Y()) * scaleY;
5186       double dz = (node->Z() - thePoint.Z()) * scaleZ;
5187       if ( theTargetMesh ) {
5188         //const SMDS_MeshNode * newNode = aTgtMesh->AddNode( coord[0], coord[1], coord[2] );
5189         const SMDS_MeshNode * newNode =
5190           aTgtMesh->AddNode( thePoint.X()+dx, thePoint.Y()+dy, thePoint.Z()+dz );
5191         n2n_isnew.first->second = newNode;
5192         myLastCreatedNodes.Append(newNode);
5193         srcNodes.Append( node );
5194       }
5195       else if ( theCopy ) {
5196         //const SMDS_MeshNode * newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
5197         const SMDS_MeshNode * newNode =
5198           aMesh->AddNode( thePoint.X()+dx, thePoint.Y()+dy, thePoint.Z()+dz );
5199         n2n_isnew.first->second = newNode;
5200         myLastCreatedNodes.Append(newNode);
5201         srcNodes.Append( node );
5202       }
5203       else {
5204         //aMesh->MoveNode( node, coord[0], coord[1], coord[2] );
5205         aMesh->MoveNode( node, thePoint.X()+dx, thePoint.Y()+dy, thePoint.Z()+dz );
5206         // node position on shape becomes invalid
5207         const_cast< SMDS_MeshNode* > ( node )->SetPosition
5208           ( SMDS_SpacePosition::originSpacePosition() );
5209       }
5210
5211       // keep inverse elements
5212       //if ( !theCopy && !theTargetMesh && needReverse ) {
5213       //  SMDS_ElemIteratorPtr invElemIt = node->GetInverseElementIterator();
5214       //  while ( invElemIt->more() ) {
5215       //    const SMDS_MeshElement* iel = invElemIt->next();
5216       //    inverseElemSet.insert( iel );
5217       //  }
5218       //}
5219     }
5220   }
5221
5222   // either create new elements or reverse mirrored ones
5223   //if ( !theCopy && !needReverse && !theTargetMesh )
5224   if ( !theCopy && !theTargetMesh )
5225     return PGroupIDs();
5226
5227   TIDSortedElemSet::iterator invElemIt = inverseElemSet.begin();
5228   for ( ; invElemIt != inverseElemSet.end(); invElemIt++ )
5229     theElems.insert( *invElemIt );
5230
5231   // replicate or reverse elements
5232
5233   enum {
5234     REV_TETRA   = 0,  //  = nbNodes - 4
5235     REV_PYRAMID = 1,  //  = nbNodes - 4
5236     REV_PENTA   = 2,  //  = nbNodes - 4
5237     REV_FACE    = 3,
5238     REV_HEXA    = 4,  //  = nbNodes - 4
5239     FORWARD     = 5
5240   };
5241   int index[][8] = {
5242     { 2, 1, 0, 3, 4, 0, 0, 0 },  // REV_TETRA
5243     { 2, 1, 0, 3, 4, 0, 0, 0 },  // REV_PYRAMID
5244     { 2, 1, 0, 5, 4, 3, 0, 0 },  // REV_PENTA
5245     { 2, 1, 0, 3, 0, 0, 0, 0 },  // REV_FACE
5246     { 2, 1, 0, 3, 6, 5, 4, 7 },  // REV_HEXA
5247     { 0, 1, 2, 3, 4, 5, 6, 7 }   // FORWARD
5248   };
5249
5250   for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ )
5251   {
5252     const SMDS_MeshElement* elem = *itElem;
5253     if ( !elem || elem->GetType() == SMDSAbs_Node )
5254       continue;
5255
5256     int nbNodes = elem->NbNodes();
5257     int elemType = elem->GetType();
5258
5259     if (elem->IsPoly()) {
5260       // Polygon or Polyhedral Volume
5261       switch ( elemType ) {
5262       case SMDSAbs_Face:
5263         {
5264           vector<const SMDS_MeshNode*> poly_nodes (nbNodes);
5265           int iNode = 0;
5266           SMDS_ElemIteratorPtr itN = elem->nodesIterator();
5267           while (itN->more()) {
5268             const SMDS_MeshNode* node =
5269               static_cast<const SMDS_MeshNode*>(itN->next());
5270             TNodeNodeMap::iterator nodeMapIt = nodeMap.find(node);
5271             if (nodeMapIt == nodeMap.end())
5272               break; // not all nodes transformed
5273             //if (needReverse) {
5274             //  // reverse mirrored faces and volumes
5275             //  poly_nodes[nbNodes - iNode - 1] = (*nodeMapIt).second;
5276             //} else {
5277             poly_nodes[iNode] = (*nodeMapIt).second;
5278             //}
5279             iNode++;
5280           }
5281           if ( iNode != nbNodes )
5282             continue; // not all nodes transformed
5283
5284           if ( theTargetMesh ) {
5285             myLastCreatedElems.Append(aTgtMesh->AddPolygonalFace(poly_nodes));
5286             srcElems.Append( elem );
5287           }
5288           else if ( theCopy ) {
5289             myLastCreatedElems.Append(aMesh->AddPolygonalFace(poly_nodes));
5290             srcElems.Append( elem );
5291           }
5292           else {
5293             aMesh->ChangePolygonNodes(elem, poly_nodes);
5294           }
5295         }
5296         break;
5297       case SMDSAbs_Volume:
5298         {
5299           // ATTENTION: Reversing is not yet done!!!
5300           const SMDS_PolyhedralVolumeOfNodes* aPolyedre =
5301             dynamic_cast<const SMDS_PolyhedralVolumeOfNodes*>( elem );
5302           if (!aPolyedre) {
5303             MESSAGE("Warning: bad volumic element");
5304             continue;
5305           }
5306
5307           vector<const SMDS_MeshNode*> poly_nodes;
5308           vector<int> quantities;
5309
5310           bool allTransformed = true;
5311           int nbFaces = aPolyedre->NbFaces();
5312           for (int iface = 1; iface <= nbFaces && allTransformed; iface++) {
5313             int nbFaceNodes = aPolyedre->NbFaceNodes(iface);
5314             for (int inode = 1; inode <= nbFaceNodes && allTransformed; inode++) {
5315               const SMDS_MeshNode* node = aPolyedre->GetFaceNode(iface, inode);
5316               TNodeNodeMap::iterator nodeMapIt = nodeMap.find(node);
5317               if (nodeMapIt == nodeMap.end()) {
5318                 allTransformed = false; // not all nodes transformed
5319               } else {
5320                 poly_nodes.push_back((*nodeMapIt).second);
5321               }
5322             }
5323             quantities.push_back(nbFaceNodes);
5324           }
5325           if ( !allTransformed )
5326             continue; // not all nodes transformed
5327
5328           if ( theTargetMesh ) {
5329             myLastCreatedElems.Append(aTgtMesh->AddPolyhedralVolume(poly_nodes, quantities));
5330             srcElems.Append( elem );
5331           }
5332           else if ( theCopy ) {
5333             myLastCreatedElems.Append(aMesh->AddPolyhedralVolume(poly_nodes, quantities));
5334             srcElems.Append( elem );
5335           }
5336           else {
5337             aMesh->ChangePolyhedronNodes(elem, poly_nodes, quantities);
5338           }
5339         }
5340         break;
5341       default:;
5342       }
5343       continue;
5344     }
5345
5346     // Regular elements
5347     int* i = index[ FORWARD ];
5348     //if ( needReverse && nbNodes > 2) // reverse mirrored faces and volumes
5349     //  if ( elemType == SMDSAbs_Face )
5350     //    i = index[ REV_FACE ];
5351     //  else
5352     //    i = index[ nbNodes - 4 ];
5353
5354     if(elem->IsQuadratic()) {
5355       static int anIds[] = {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19};
5356       i = anIds;
5357       //if(needReverse) {
5358       //  if(nbNodes==3) { // quadratic edge
5359       //    static int anIds[] = {1,0,2};
5360       //    i = anIds;
5361       //  }
5362       //  else if(nbNodes==6) { // quadratic triangle
5363       //    static int anIds[] = {0,2,1,5,4,3};
5364       //    i = anIds;
5365       //  }
5366       //  else if(nbNodes==8) { // quadratic quadrangle
5367       //    static int anIds[] = {0,3,2,1,7,6,5,4};
5368       //    i = anIds;
5369       //  }
5370       //  else if(nbNodes==10) { // quadratic tetrahedron of 10 nodes
5371       //    static int anIds[] = {0,2,1,3,6,5,4,7,9,8};
5372       //    i = anIds;
5373       //  }
5374       //  else if(nbNodes==13) { // quadratic pyramid of 13 nodes
5375       //    static int anIds[] = {0,3,2,1,4,8,7,6,5,9,12,11,10};
5376       //    i = anIds;
5377       //  }
5378       //  else if(nbNodes==15) { // quadratic pentahedron with 15 nodes
5379       //    static int anIds[] = {0,2,1,3,5,4,8,7,6,11,10,9,12,14,13};
5380       //    i = anIds;
5381       //  }
5382       //  else { // nbNodes==20 - quadratic hexahedron with 20 nodes
5383       //    static int anIds[] = {0,3,2,1,4,7,6,5,11,10,9,8,15,14,13,12,16,19,18,17};
5384       //    i = anIds;
5385       //  }
5386       //}
5387     }
5388
5389     // find transformed nodes
5390     vector<const SMDS_MeshNode*> nodes(nbNodes);
5391     int iNode = 0;
5392     SMDS_ElemIteratorPtr itN = elem->nodesIterator();
5393     while ( itN->more() ) {
5394       const SMDS_MeshNode* node =
5395         static_cast<const SMDS_MeshNode*>( itN->next() );
5396       TNodeNodeMap::iterator nodeMapIt = nodeMap.find( node );
5397       if ( nodeMapIt == nodeMap.end() )
5398         break; // not all nodes transformed
5399       nodes[ i [ iNode++ ]] = (*nodeMapIt).second;
5400     }
5401     if ( iNode != nbNodes )
5402       continue; // not all nodes transformed
5403
5404     if ( theTargetMesh ) {
5405       if ( SMDS_MeshElement* copy =
5406            targetMeshEditor.AddElement( nodes, elem->GetType(), elem->IsPoly() )) {
5407         myLastCreatedElems.Append( copy );
5408         srcElems.Append( elem );
5409       }
5410     }
5411     else if ( theCopy ) {
5412       if ( SMDS_MeshElement* copy = AddElement( nodes, elem->GetType(), elem->IsPoly() )) {
5413         myLastCreatedElems.Append( copy );
5414         srcElems.Append( elem );
5415       }
5416     }
5417     else {
5418       // reverse element as it was reversed by transformation
5419       if ( nbNodes > 2 )
5420         aMesh->ChangeElementNodes( elem, &nodes[0], nbNodes );
5421     }
5422   }
5423
5424   PGroupIDs newGroupIDs;
5425
5426   if ( theMakeGroups && theCopy ||
5427        theMakeGroups && theTargetMesh ) {
5428     string groupPostfix = "scaled";
5429     newGroupIDs = generateGroups( srcNodes, srcElems, groupPostfix, theTargetMesh );
5430   }
5431
5432   return newGroupIDs;
5433 }
5434
5435
5436 //=======================================================================
5437 /*!
5438  * \brief Create groups of elements made during transformation
5439  * \param nodeGens - nodes making corresponding myLastCreatedNodes
5440  * \param elemGens - elements making corresponding myLastCreatedElems
5441  * \param postfix - to append to names of new groups
5442  */
5443 //=======================================================================
5444
5445 SMESH_MeshEditor::PGroupIDs
5446 SMESH_MeshEditor::generateGroups(const SMESH_SequenceOfElemPtr& nodeGens,
5447                                  const SMESH_SequenceOfElemPtr& elemGens,
5448                                  const std::string&             postfix,
5449                                  SMESH_Mesh*                    targetMesh)
5450 {
5451   PGroupIDs newGroupIDs( new list<int> );
5452   SMESH_Mesh* mesh = targetMesh ? targetMesh : GetMesh();
5453
5454   // Sort existing groups by types and collect their names
5455
5456   // to store an old group and a generated new one
5457   typedef pair< SMESHDS_GroupBase*, SMDS_MeshGroup* > TOldNewGroup;
5458   vector< list< TOldNewGroup > > groupsByType( SMDSAbs_NbElementTypes );
5459   // group names
5460   set< string > groupNames;
5461   //
5462   SMDS_MeshGroup* nullNewGroup = (SMDS_MeshGroup*) 0;
5463   SMESH_Mesh::GroupIteratorPtr groupIt = GetMesh()->GetGroups();
5464   while ( groupIt->more() ) {
5465     SMESH_Group * group = groupIt->next();
5466     if ( !group ) continue;
5467     SMESHDS_GroupBase* groupDS = group->GetGroupDS();
5468     if ( !groupDS || groupDS->IsEmpty() ) continue;
5469     groupNames.insert( group->GetName() );
5470     groupDS->SetStoreName( group->GetName() );
5471     groupsByType[ groupDS->GetType() ].push_back( make_pair( groupDS, nullNewGroup ));
5472   }
5473
5474   // Groups creation
5475
5476   // loop on nodes and elements
5477   for ( int isNodes = 0; isNodes < 2; ++isNodes )
5478   {
5479     const SMESH_SequenceOfElemPtr& gens  = isNodes ? nodeGens : elemGens;
5480     const SMESH_SequenceOfElemPtr& elems = isNodes ? myLastCreatedNodes : myLastCreatedElems;
5481     if ( gens.Length() != elems.Length() )
5482       throw SALOME_Exception(LOCALIZED("invalid args"));
5483
5484     // loop on created elements
5485     for (int iElem = 1; iElem <= elems.Length(); ++iElem )
5486     {
5487       const SMDS_MeshElement* sourceElem = gens( iElem );
5488       if ( !sourceElem ) {
5489         MESSAGE("generateGroups(): NULL source element");
5490         continue;
5491       }
5492       list< TOldNewGroup > & groupsOldNew = groupsByType[ sourceElem->GetType() ];
5493       if ( groupsOldNew.empty() ) {
5494         while ( iElem < gens.Length() && gens( iElem+1 ) == sourceElem )
5495           ++iElem; // skip all elements made by sourceElem
5496         continue;
5497       }
5498       // collect all elements made by sourceElem
5499       list< const SMDS_MeshElement* > resultElems;
5500       if ( const SMDS_MeshElement* resElem = elems( iElem ))
5501         if ( resElem != sourceElem )
5502           resultElems.push_back( resElem );
5503       while ( iElem < gens.Length() && gens( iElem+1 ) == sourceElem )
5504         if ( const SMDS_MeshElement* resElem = elems( ++iElem ))
5505           if ( resElem != sourceElem )
5506             resultElems.push_back( resElem );
5507       // do not generate element groups from node ones
5508       if ( sourceElem->GetType() == SMDSAbs_Node &&
5509            elems( iElem )->GetType() != SMDSAbs_Node )
5510         continue;
5511
5512       // add resultElems to groups made by ones the sourceElem belongs to
5513       list< TOldNewGroup >::iterator gOldNew, gLast = groupsOldNew.end();
5514       for ( gOldNew = groupsOldNew.begin(); gOldNew != gLast; ++gOldNew )
5515       {
5516         SMESHDS_GroupBase* oldGroup = gOldNew->first;
5517         if ( oldGroup->Contains( sourceElem )) // sourceElem in oldGroup
5518         {
5519           SMDS_MeshGroup* & newGroup = gOldNew->second;
5520           if ( !newGroup )// create a new group
5521           {
5522             // make a name
5523             string name = oldGroup->GetStoreName();
5524             if ( !targetMesh ) {
5525               name += "_";
5526               name += postfix;
5527               int nb = 0;
5528               while ( !groupNames.insert( name ).second ) // name exists
5529               {
5530                 if ( nb == 0 ) {
5531                   name += "_1";
5532                 }
5533                 else {
5534                   TCollection_AsciiString nbStr(nb+1);
5535                   name.resize( name.rfind('_')+1 );
5536                   name += nbStr.ToCString();
5537                 }
5538                 ++nb;
5539               }
5540             }
5541             // make a group
5542             int id;
5543             SMESH_Group* group = mesh->AddGroup( resultElems.back()->GetType(),
5544                                                  name.c_str(), id );
5545             SMESHDS_Group* groupDS = static_cast<SMESHDS_Group*>(group->GetGroupDS());
5546             newGroup = & groupDS->SMDSGroup();
5547             newGroupIDs->push_back( id );
5548           }
5549
5550           // fill in a new group
5551           list< const SMDS_MeshElement* >::iterator resLast = resultElems.end(), resElemIt;
5552           for ( resElemIt = resultElems.begin(); resElemIt != resLast; ++resElemIt )
5553             newGroup->Add( *resElemIt );
5554         }
5555       }
5556     } // loop on created elements
5557   }// loop on nodes and elements
5558
5559   return newGroupIDs;
5560 }
5561
5562 //================================================================================
5563 /*!
5564  * \brief Return list of group of nodes close to each other within theTolerance
5565  *        Search among theNodes or in the whole mesh if theNodes is empty using
5566  *        an Octree algorithm
5567  */
5568 //================================================================================
5569
5570 void SMESH_MeshEditor::FindCoincidentNodes (set<const SMDS_MeshNode*> & theNodes,
5571                                             const double                theTolerance,
5572                                             TListOfListOfNodes &        theGroupsOfNodes)
5573 {
5574   myLastCreatedElems.Clear();
5575   myLastCreatedNodes.Clear();
5576
5577   set<const SMDS_MeshNode*> nodes;
5578   if ( theNodes.empty() )
5579   { // get all nodes in the mesh
5580     SMDS_NodeIteratorPtr nIt = GetMeshDS()->nodesIterator();
5581     while ( nIt->more() )
5582       nodes.insert( nodes.end(),nIt->next());
5583   }
5584   else
5585     nodes=theNodes;
5586
5587   SMESH_OctreeNode::FindCoincidentNodes ( nodes, &theGroupsOfNodes, theTolerance);
5588 }
5589
5590
5591 //=======================================================================
5592 /*!
5593  * \brief Implementation of search for the node closest to point
5594  */
5595 //=======================================================================
5596
5597 struct SMESH_NodeSearcherImpl: public SMESH_NodeSearcher
5598 {
5599   //---------------------------------------------------------------------
5600   /*!
5601    * \brief Constructor
5602    */
5603   SMESH_NodeSearcherImpl( const SMESHDS_Mesh* theMesh )
5604   {
5605     myMesh = ( SMESHDS_Mesh* ) theMesh;
5606
5607     set<const SMDS_MeshNode*> nodes;
5608     if ( theMesh ) {
5609       SMDS_NodeIteratorPtr nIt = theMesh->nodesIterator();
5610       while ( nIt->more() )
5611         nodes.insert( nodes.end(), nIt->next() );
5612     }
5613     myOctreeNode = new SMESH_OctreeNode(nodes) ;
5614
5615     // get max size of a leaf box
5616     SMESH_OctreeNode* tree = myOctreeNode;
5617     while ( !tree->isLeaf() )
5618     {
5619       SMESH_OctreeNodeIteratorPtr cIt = tree->GetChildrenIterator();
5620       if ( cIt->more() )
5621         tree = cIt->next();
5622     }
5623     myHalfLeafSize = tree->maxSize() / 2.;
5624   }
5625
5626   //---------------------------------------------------------------------
5627   /*!
5628    * \brief Move node and update myOctreeNode accordingly
5629    */
5630   void MoveNode( const SMDS_MeshNode* node, const gp_Pnt& toPnt )
5631   {
5632     myOctreeNode->UpdateByMoveNode( node, toPnt );
5633     myMesh->MoveNode( node, toPnt.X(), toPnt.Y(), toPnt.Z() );
5634   }
5635
5636   //---------------------------------------------------------------------
5637   /*!
5638    * \brief Do it's job
5639    */
5640   const SMDS_MeshNode* FindClosestTo( const gp_Pnt& thePnt )
5641   {
5642     SMDS_MeshNode tgtNode( thePnt.X(), thePnt.Y(), thePnt.Z() );
5643     map<double, const SMDS_MeshNode*> dist2Nodes;
5644     myOctreeNode->NodesAround( &tgtNode, dist2Nodes, myHalfLeafSize );
5645     if ( !dist2Nodes.empty() )
5646       return dist2Nodes.begin()->second;
5647     list<const SMDS_MeshNode*> nodes;
5648     //myOctreeNode->NodesAround( &tgtNode, &nodes, myHalfLeafSize );
5649
5650     double minSqDist = DBL_MAX;
5651     if ( nodes.empty() )  // get all nodes of OctreeNode's closest to thePnt
5652     {
5653       // sort leafs by their distance from thePnt
5654       typedef map< double, SMESH_OctreeNode* > TDistTreeMap;
5655       TDistTreeMap treeMap;
5656       list< SMESH_OctreeNode* > treeList;
5657       list< SMESH_OctreeNode* >::iterator trIt;
5658       treeList.push_back( myOctreeNode );
5659
5660       SMDS_MeshNode pointNode( thePnt.X(), thePnt.Y(), thePnt.Z() );
5661       for ( trIt = treeList.begin(); trIt != treeList.end(); ++trIt)
5662       {
5663         SMESH_OctreeNode* tree = *trIt;
5664         if ( !tree->isLeaf() ) // put children to the queue
5665         {
5666           if ( !tree->isInside( &pointNode, myHalfLeafSize )) continue;
5667           SMESH_OctreeNodeIteratorPtr cIt = tree->GetChildrenIterator();
5668           while ( cIt->more() )
5669             treeList.push_back( cIt->next() );
5670         }
5671         else if ( tree->NbNodes() ) // put a tree to the treeMap
5672         {
5673           const Bnd_B3d& box = tree->getBox();
5674           double sqDist = thePnt.SquareDistance( 0.5 * ( box.CornerMin() + box.CornerMax() ));
5675           pair<TDistTreeMap::iterator,bool> it_in = treeMap.insert( make_pair( sqDist, tree ));
5676           if ( !it_in.second ) // not unique distance to box center
5677             treeMap.insert( it_in.first, make_pair( sqDist + 1e-13*treeMap.size(), tree ));
5678         }
5679       }
5680       // find distance after which there is no sense to check tree's
5681       double sqLimit = DBL_MAX;
5682       TDistTreeMap::iterator sqDist_tree = treeMap.begin();
5683       if ( treeMap.size() > 5 ) {
5684         SMESH_OctreeNode* closestTree = sqDist_tree->second;
5685         const Bnd_B3d& box = closestTree->getBox();
5686         double limit = sqrt( sqDist_tree->first ) + sqrt ( box.SquareExtent() );
5687         sqLimit = limit * limit;
5688       }
5689       // get all nodes from trees
5690       for ( ; sqDist_tree != treeMap.end(); ++sqDist_tree) {
5691         if ( sqDist_tree->first > sqLimit )
5692           break;
5693         SMESH_OctreeNode* tree = sqDist_tree->second;
5694         tree->NodesAround( tree->GetNodeIterator()->next(), &nodes );
5695       }
5696     }
5697     // find closest among nodes
5698     minSqDist = DBL_MAX;
5699     const SMDS_MeshNode* closestNode = 0;
5700     list<const SMDS_MeshNode*>::iterator nIt = nodes.begin();
5701     for ( ; nIt != nodes.end(); ++nIt ) {
5702       double sqDist = thePnt.SquareDistance( SMESH_MeshEditor::TNodeXYZ( *nIt ) );
5703       if ( minSqDist > sqDist ) {
5704         closestNode = *nIt;
5705         minSqDist = sqDist;
5706       }
5707     }
5708     return closestNode;
5709   }
5710
5711   //---------------------------------------------------------------------
5712   /*!
5713    * \brief Destructor
5714    */
5715   ~SMESH_NodeSearcherImpl() { delete myOctreeNode; }
5716
5717   //---------------------------------------------------------------------
5718   /*!
5719    * \brief Return the node tree
5720    */
5721   const SMESH_OctreeNode* getTree() const { return myOctreeNode; }
5722
5723 private:
5724   SMESH_OctreeNode* myOctreeNode;
5725   SMESHDS_Mesh*     myMesh;
5726   double            myHalfLeafSize; // max size of a leaf box
5727 };
5728
5729 //=======================================================================
5730 /*!
5731  * \brief Return SMESH_NodeSearcher
5732  */
5733 //=======================================================================
5734
5735 SMESH_NodeSearcher* SMESH_MeshEditor::GetNodeSearcher() 
5736 {
5737   return new SMESH_NodeSearcherImpl( GetMeshDS() );
5738 }
5739
5740 // ========================================================================
5741 namespace // Utils used in SMESH_ElementSearcherImpl::FindElementsByPoint()
5742 {
5743   const int MaxNbElemsInLeaf = 10; // maximal number of elements in a leaf of tree
5744   const int MaxLevel         = 7;  // maximal tree height -> nb terminal boxes: 8^7 = 2097152
5745   const double NodeRadius = 1e-9;  // to enlarge bnd box of element
5746
5747   //=======================================================================
5748   /*!
5749    * \brief Octal tree of bounding boxes of elements
5750    */
5751   //=======================================================================
5752
5753   class ElementBndBoxTree : public SMESH_Octree
5754   {
5755   public:
5756
5757     ElementBndBoxTree(const SMDS_Mesh& mesh, SMDSAbs_ElementType elemType);
5758     void getElementsNearPoint( const gp_Pnt& point, TIDSortedElemSet& foundElems);
5759     void getElementsNearLine ( const gp_Ax1& line, TIDSortedElemSet& foundElems);
5760     ~ElementBndBoxTree();
5761
5762   protected:
5763     ElementBndBoxTree() {}
5764     SMESH_Octree* allocateOctreeChild() const { return new ElementBndBoxTree; }
5765     void buildChildrenData();
5766     Bnd_B3d* buildRootBox();
5767   private:
5768     //!< Bounding box of element
5769     struct ElementBox : public Bnd_B3d
5770     {
5771       const SMDS_MeshElement* _element;
5772       int                     _refCount; // an ElementBox can be included in several tree branches
5773       ElementBox(const SMDS_MeshElement* elem);
5774     };
5775     vector< ElementBox* > _elements;
5776   };
5777
5778   //================================================================================
5779   /*!
5780    * \brief ElementBndBoxTree creation
5781    */
5782   //================================================================================
5783
5784   ElementBndBoxTree::ElementBndBoxTree(const SMDS_Mesh& mesh, SMDSAbs_ElementType elemType)
5785     :SMESH_Octree( new SMESH_Octree::Limit( MaxLevel, /*minSize=*/0. ))
5786   {
5787     int nbElems = mesh.GetMeshInfo().NbElements( elemType );
5788     _elements.reserve( nbElems );
5789
5790     SMDS_ElemIteratorPtr elemIt = mesh.elementsIterator( elemType );
5791     while ( elemIt->more() )
5792       _elements.push_back( new ElementBox( elemIt->next() ));
5793
5794     if ( _elements.size() > MaxNbElemsInLeaf )
5795       compute();
5796     else
5797       myIsLeaf = true;
5798   }
5799
5800   //================================================================================
5801   /*!
5802    * \brief Destructor
5803    */
5804   //================================================================================
5805
5806   ElementBndBoxTree::~ElementBndBoxTree()
5807   {
5808     for ( int i = 0; i < _elements.size(); ++i )
5809       if ( --_elements[i]->_refCount <= 0 )
5810         delete _elements[i];
5811   }
5812
5813   //================================================================================
5814   /*!
5815    * \brief Return the maximal box
5816    */
5817   //================================================================================
5818
5819   Bnd_B3d* ElementBndBoxTree::buildRootBox()
5820   {
5821     Bnd_B3d* box = new Bnd_B3d;
5822     for ( int i = 0; i < _elements.size(); ++i )
5823       box->Add( *_elements[i] );
5824     return box;
5825   }
5826
5827   //================================================================================
5828   /*!
5829    * \brief Redistrubute element boxes among children
5830    */
5831   //================================================================================
5832
5833   void ElementBndBoxTree::buildChildrenData()
5834   {
5835     for ( int i = 0; i < _elements.size(); ++i )
5836     {
5837       for (int j = 0; j < 8; j++)
5838       {
5839         if ( !_elements[i]->IsOut( myChildren[j]->getBox() ))
5840         {
5841           _elements[i]->_refCount++;
5842           ((ElementBndBoxTree*)myChildren[j])->_elements.push_back( _elements[i]);
5843         }
5844       }
5845       _elements[i]->_refCount--;
5846     }
5847     _elements.clear();
5848
5849     for (int j = 0; j < 8; j++)
5850     {
5851       ElementBndBoxTree* child = static_cast<ElementBndBoxTree*>( myChildren[j]);
5852       if ( child->_elements.size() <= MaxNbElemsInLeaf )
5853         child->myIsLeaf = true;
5854
5855       if ( child->_elements.capacity() - child->_elements.size() > 1000 )
5856         child->_elements.resize( child->_elements.size() ); // compact
5857     }
5858   }
5859
5860   //================================================================================
5861   /*!
5862    * \brief Return elements which can include the point
5863    */
5864   //================================================================================
5865
5866   void ElementBndBoxTree::getElementsNearPoint( const gp_Pnt&     point,
5867                                                 TIDSortedElemSet& foundElems)
5868   {
5869     if ( level() && getBox().IsOut( point.XYZ() ))
5870       return;
5871
5872     if ( isLeaf() )
5873     {
5874       for ( int i = 0; i < _elements.size(); ++i )
5875         if ( !_elements[i]->IsOut( point.XYZ() ))
5876           foundElems.insert( _elements[i]->_element );
5877     }
5878     else
5879     {
5880       for (int i = 0; i < 8; i++)
5881         ((ElementBndBoxTree*) myChildren[i])->getElementsNearPoint( point, foundElems );
5882     }
5883   }
5884
5885   //================================================================================
5886   /*!
5887    * \brief Return elements which can be intersected by the line
5888    */
5889   //================================================================================
5890
5891   void ElementBndBoxTree::getElementsNearLine( const gp_Ax1&     line,
5892                                                TIDSortedElemSet& foundElems)
5893   {
5894     if ( level() && getBox().IsOut( line ))
5895       return;
5896
5897     if ( isLeaf() )
5898     {
5899       for ( int i = 0; i < _elements.size(); ++i )
5900         if ( !_elements[i]->IsOut( line ))
5901           foundElems.insert( _elements[i]->_element );
5902     }
5903     else
5904     {
5905       for (int i = 0; i < 8; i++)
5906         ((ElementBndBoxTree*) myChildren[i])->getElementsNearLine( line, foundElems );
5907     }
5908   }
5909
5910   //================================================================================
5911   /*!
5912    * \brief Construct the element box
5913    */
5914   //================================================================================
5915
5916   ElementBndBoxTree::ElementBox::ElementBox(const SMDS_MeshElement* elem)
5917   {
5918     _element  = elem;
5919     _refCount = 1;
5920     SMDS_ElemIteratorPtr nIt = elem->nodesIterator();
5921     while ( nIt->more() )
5922       Add( SMESH_MeshEditor::TNodeXYZ( cast2Node( nIt->next() )));
5923     Enlarge( NodeRadius );
5924   }
5925
5926 } // namespace
5927
5928 //=======================================================================
5929 /*!
5930  * \brief Implementation of search for the elements by point and
5931  *        of classification of point in 2D mesh
5932  */
5933 //=======================================================================
5934
5935 struct SMESH_ElementSearcherImpl: public SMESH_ElementSearcher
5936 {
5937   SMESHDS_Mesh*                _mesh;
5938   ElementBndBoxTree*           _ebbTree;
5939   SMESH_NodeSearcherImpl*      _nodeSearcher;
5940   SMDSAbs_ElementType          _elementType;
5941   double                       _tolerance;
5942   bool                         _outerFacesFound;
5943   set<const SMDS_MeshElement*> _outerFaces; // empty means "no internal faces at all"
5944
5945   SMESH_ElementSearcherImpl( SMESHDS_Mesh& mesh )
5946     : _mesh(&mesh),_ebbTree(0),_nodeSearcher(0), _tolerance(-1), _outerFacesFound(false) {}
5947   ~SMESH_ElementSearcherImpl()
5948   {
5949     if ( _ebbTree )      delete _ebbTree;      _ebbTree      = 0;
5950     if ( _nodeSearcher ) delete _nodeSearcher; _nodeSearcher = 0;
5951   }
5952   virtual int FindElementsByPoint(const gp_Pnt&                      point,
5953                                   SMDSAbs_ElementType                type,
5954                                   vector< const SMDS_MeshElement* >& foundElements);
5955   virtual TopAbs_State GetPointState(const gp_Pnt& point);
5956
5957   double getTolerance();
5958   bool getIntersParamOnLine(const gp_Lin& line, const SMDS_MeshElement* face,
5959                             const double tolerance, double & param);
5960   void findOuterBoundary(const SMDS_MeshElement* anyOuterFace);
5961   bool isOuterBoundary(const SMDS_MeshElement* face) const
5962   {
5963     return _outerFaces.empty() || _outerFaces.count(face);
5964   }
5965   struct TInters //!< data of intersection of the line and the mesh face used in GetPointState()
5966   {
5967     const SMDS_MeshElement* _face;
5968     gp_Vec                  _faceNorm;
5969     bool                    _coincides; //!< the line lays in face plane
5970     TInters(const SMDS_MeshElement* face, const gp_Vec& faceNorm, bool coinc=false)
5971       : _face(face), _faceNorm( faceNorm ), _coincides( coinc ) {}
5972   };
5973   struct TFaceLink //!< link and faces sharing it (used in findOuterBoundary())
5974   {
5975     SMESH_TLink      _link;
5976     TIDSortedElemSet _faces;
5977     TFaceLink( const SMDS_MeshNode* n1, const SMDS_MeshNode* n2, const SMDS_MeshElement* face)
5978       : _link( n1, n2 ), _faces( &face, &face + 1) {}
5979   };
5980 };
5981
5982 ostream& operator<< (ostream& out, const SMESH_ElementSearcherImpl::TInters& i)
5983 {
5984   return out << "TInters(face=" << ( i._face ? i._face->GetID() : 0)
5985              << ", _coincides="<<i._coincides << ")";
5986 }
5987
5988 //=======================================================================
5989 /*!
5990  * \brief define tolerance for search
5991  */
5992 //=======================================================================
5993
5994 double SMESH_ElementSearcherImpl::getTolerance()
5995 {
5996   if ( _tolerance < 0 )
5997   {
5998     const SMDS_MeshInfo& meshInfo = _mesh->GetMeshInfo();
5999
6000     _tolerance = 0;
6001     if ( _nodeSearcher && meshInfo.NbNodes() > 1 )
6002     {
6003       double boxSize = _nodeSearcher->getTree()->maxSize();
6004       _tolerance = 1e-8 * boxSize/* / meshInfo.NbNodes()*/;
6005     }
6006     else if ( _ebbTree && meshInfo.NbElements() > 0 )
6007     {
6008       double boxSize = _ebbTree->maxSize();
6009       _tolerance = 1e-8 * boxSize/* / meshInfo.NbElements()*/;
6010     }
6011     if ( _tolerance == 0 )
6012     {
6013       // define tolerance by size of a most complex element
6014       int complexType = SMDSAbs_Volume;
6015       while ( complexType > SMDSAbs_All &&
6016               meshInfo.NbElements( SMDSAbs_ElementType( complexType )) < 1 )
6017         --complexType;
6018       if ( complexType == SMDSAbs_All ) return 0; // empty mesh
6019
6020       double elemSize;
6021       if ( complexType == int( SMDSAbs_Node ))
6022       {
6023         SMDS_NodeIteratorPtr nodeIt = _mesh->nodesIterator();
6024         elemSize = 1;
6025         if ( meshInfo.NbNodes() > 2 )
6026           elemSize = SMESH_MeshEditor::TNodeXYZ( nodeIt->next() ).Distance( nodeIt->next() );
6027       }
6028       else
6029       {
6030         const SMDS_MeshElement* elem =
6031           _mesh->elementsIterator( SMDSAbs_ElementType( complexType ))->next();
6032         SMDS_ElemIteratorPtr nodeIt = elem->nodesIterator();
6033         SMESH_MeshEditor::TNodeXYZ n1( cast2Node( nodeIt->next() ));
6034         while ( nodeIt->more() )
6035         {
6036           double dist = n1.Distance( cast2Node( nodeIt->next() ));
6037           elemSize = max( dist, elemSize );
6038         }
6039       }
6040       _tolerance = 1e-6 * elemSize;
6041     }
6042   }
6043   return _tolerance;
6044 }
6045
6046 //================================================================================
6047 /*!
6048  * \brief Find intersection of the line and an edge of face and return parameter on line
6049  */
6050 //================================================================================
6051
6052 bool SMESH_ElementSearcherImpl::getIntersParamOnLine(const gp_Lin&           line,
6053                                                      const SMDS_MeshElement* face,
6054                                                      const double            tol,
6055                                                      double &                param)
6056 {
6057   int nbInts = 0;
6058   param = 0;
6059
6060   GeomAPI_ExtremaCurveCurve anExtCC;
6061   Handle(Geom_Curve) lineCurve = new Geom_Line( line );
6062   
6063   int nbNodes = face->IsQuadratic() ? face->NbNodes()/2 : face->NbNodes();
6064   for ( int i = 0; i < nbNodes && nbInts < 2; ++i )
6065   {
6066     GC_MakeSegment edge( SMESH_MeshEditor::TNodeXYZ( face->GetNode( i )),
6067                          SMESH_MeshEditor::TNodeXYZ( face->GetNode( (i+1)%nbNodes) )); 
6068     anExtCC.Init( lineCurve, edge);
6069     if ( anExtCC.NbExtrema() > 0 && anExtCC.LowerDistance() <= tol)
6070     {
6071       Quantity_Parameter pl, pe;
6072       anExtCC.LowerDistanceParameters( pl, pe );
6073       param += pl;
6074       if ( ++nbInts == 2 )
6075         break;
6076     }
6077   }
6078   if ( nbInts > 0 ) param /= nbInts;
6079   return nbInts > 0;
6080 }
6081 //================================================================================
6082 /*!
6083  * \brief Find all faces belonging to the outer boundary of mesh
6084  */
6085 //================================================================================
6086
6087 void SMESH_ElementSearcherImpl::findOuterBoundary(const SMDS_MeshElement* outerFace)
6088 {
6089   if ( _outerFacesFound ) return;
6090
6091   // Collect all outer faces by passing from one outer face to another via their links
6092   // and BTW find out if there are internal faces at all.
6093
6094   // checked links and links where outer boundary meets internal one
6095   set< SMESH_TLink > visitedLinks, seamLinks;
6096
6097   // links to treat with already visited faces sharing them
6098   list < TFaceLink > startLinks;
6099
6100   // load startLinks with the first outerFace
6101   startLinks.push_back( TFaceLink( outerFace->GetNode(0), outerFace->GetNode(1), outerFace));
6102   _outerFaces.insert( outerFace );
6103
6104   TIDSortedElemSet emptySet;
6105   while ( !startLinks.empty() )
6106   {
6107     const SMESH_TLink& link  = startLinks.front()._link;
6108     TIDSortedElemSet&  faces = startLinks.front()._faces;
6109
6110     outerFace = *faces.begin();
6111     // find other faces sharing the link
6112     const SMDS_MeshElement* f;
6113     while (( f = SMESH_MeshEditor::FindFaceInSet(link.node1(), link.node2(), emptySet, faces )))
6114       faces.insert( f );
6115
6116     // select another outer face among the found 
6117     const SMDS_MeshElement* outerFace2 = 0;
6118     if ( faces.size() == 2 )
6119     {
6120       outerFace2 = (outerFace == *faces.begin() ? *faces.rbegin() : *faces.begin());
6121     }
6122     else if ( faces.size() > 2 )
6123     {
6124       seamLinks.insert( link );
6125
6126       // link direction within the outerFace
6127       gp_Vec n1n2( SMESH_MeshEditor::TNodeXYZ( link.node1()),
6128                    SMESH_MeshEditor::TNodeXYZ( link.node2()));
6129       int i1 = outerFace->GetNodeIndex( link.node1() );
6130       int i2 = outerFace->GetNodeIndex( link.node2() );
6131       bool rev = ( abs(i2-i1) == 1 ? i1 > i2 : i2 > i1 );
6132       if ( rev ) n1n2.Reverse();
6133       // outerFace normal
6134       gp_XYZ ofNorm, fNorm;
6135       if ( SMESH_Algo::FaceNormal( outerFace, ofNorm, /*normalized=*/false ))
6136       {
6137         // direction from the link inside outerFace
6138         gp_Vec dirInOF = gp_Vec( ofNorm ) ^ n1n2;
6139         // sort all other faces by angle with the dirInOF
6140         map< double, const SMDS_MeshElement* > angle2Face;
6141         set< const SMDS_MeshElement*, TIDCompare >::const_iterator face = faces.begin();
6142         for ( ; face != faces.end(); ++face )
6143         {
6144           if ( !SMESH_Algo::FaceNormal( *face, fNorm, /*normalized=*/false ))
6145             continue;
6146           gp_Vec dirInF = gp_Vec( fNorm ) ^ n1n2;
6147           double angle = dirInOF.AngleWithRef( dirInF, n1n2 );
6148           if ( angle < 0 ) angle += 2*PI;
6149           angle2Face.insert( make_pair( angle, *face ));
6150         }
6151         if ( !angle2Face.empty() )
6152           outerFace2 = angle2Face.begin()->second;
6153       }
6154     }
6155     // store the found outer face and add its links to continue seaching from
6156     if ( outerFace2 )
6157     {
6158       _outerFaces.insert( outerFace );
6159       int nbNodes = outerFace2->NbNodes()/( outerFace2->IsQuadratic() ? 2 : 1 );
6160       for ( int i = 0; i < nbNodes; ++i )
6161       {
6162         SMESH_TLink link2( outerFace2->GetNode(i), outerFace2->GetNode((i+1)%nbNodes));
6163         if ( visitedLinks.insert( link2 ).second )
6164           startLinks.push_back( TFaceLink( link2.node1(), link2.node2(), outerFace2 ));
6165       }
6166     }
6167     startLinks.pop_front();
6168   }
6169   _outerFacesFound = true;
6170
6171   if ( !seamLinks.empty() )
6172   {
6173     // There are internal boundaries touching the outher one,
6174     // find all faces of internal boundaries in order to find
6175     // faces of boundaries of holes, if any.
6176     
6177   }
6178   else
6179   {
6180     _outerFaces.clear();
6181   }
6182 }
6183
6184 //=======================================================================
6185 /*!
6186  * \brief Find elements of given type where the given point is IN or ON.
6187  *        Returns nb of found elements and elements them-selves.
6188  *
6189  * 'ALL' type means elements of any type excluding nodes and 0D elements
6190  */
6191 //=======================================================================
6192
6193 int SMESH_ElementSearcherImpl::
6194 FindElementsByPoint(const gp_Pnt&                      point,
6195                     SMDSAbs_ElementType                type,
6196                     vector< const SMDS_MeshElement* >& foundElements)
6197 {
6198   foundElements.clear();
6199
6200   double tolerance = getTolerance();
6201
6202   // =================================================================================
6203   if ( type == SMDSAbs_Node || type == SMDSAbs_0DElement )
6204   {
6205     if ( !_nodeSearcher )
6206       _nodeSearcher = new SMESH_NodeSearcherImpl( _mesh );
6207
6208     const SMDS_MeshNode* closeNode = _nodeSearcher->FindClosestTo( point );
6209     if ( !closeNode ) return foundElements.size();
6210
6211     if ( point.Distance( SMESH_MeshEditor::TNodeXYZ( closeNode )) > tolerance )
6212       return foundElements.size(); // to far from any node
6213
6214     if ( type == SMDSAbs_Node )
6215     {
6216       foundElements.push_back( closeNode );
6217     }
6218     else
6219     {
6220       SMDS_ElemIteratorPtr elemIt = closeNode->GetInverseElementIterator( SMDSAbs_0DElement );
6221       while ( elemIt->more() )
6222         foundElements.push_back( elemIt->next() );
6223     }
6224   }
6225   // =================================================================================
6226   else // elements more complex than 0D
6227   {
6228     if ( !_ebbTree || _elementType != type )
6229     {
6230       if ( _ebbTree ) delete _ebbTree;
6231       _ebbTree = new ElementBndBoxTree( *_mesh, _elementType = type );
6232     }
6233     TIDSortedElemSet suspectElems;
6234     _ebbTree->getElementsNearPoint( point, suspectElems );
6235     TIDSortedElemSet::iterator elem = suspectElems.begin();
6236     for ( ; elem != suspectElems.end(); ++elem )
6237       if ( !SMESH_MeshEditor::isOut( *elem, point, tolerance ))
6238         foundElements.push_back( *elem );
6239   }
6240   return foundElements.size();
6241 }
6242
6243 //================================================================================
6244 /*!
6245  * \brief Classify the given point in the closed 2D mesh
6246  */
6247 //================================================================================
6248
6249 TopAbs_State SMESH_ElementSearcherImpl::GetPointState(const gp_Pnt& point)
6250 {
6251   double tolerance = getTolerance();
6252   if ( !_ebbTree || _elementType != SMDSAbs_Face )
6253   {
6254     if ( _ebbTree ) delete _ebbTree;
6255     _ebbTree = new ElementBndBoxTree( *_mesh, _elementType = SMDSAbs_Face );
6256   }
6257   // Algo: analyse transition of a line starting at the point through mesh boundary;
6258   // try three lines parallel to axis of the coordinate system and perform rough
6259   // analysis. If solution is not clear perform thorough analysis.
6260
6261   const int nbAxes = 3;
6262   gp_Dir axisDir[ nbAxes ] = { gp::DX(), gp::DY(), gp::DZ() };
6263   map< double, TInters >   paramOnLine2TInters[ nbAxes ];
6264   list< TInters > tangentInters[ nbAxes ]; // of faces whose plane includes the line
6265   multimap< int, int > nbInt2Axis; // to find the simplest case
6266   for ( int axis = 0; axis < nbAxes; ++axis )
6267   {
6268     gp_Ax1 lineAxis( point, axisDir[axis]);
6269     gp_Lin line    ( lineAxis );
6270
6271     TIDSortedElemSet suspectFaces; // faces possibly intersecting the line
6272     _ebbTree->getElementsNearLine( lineAxis, suspectFaces );
6273
6274     // Intersect faces with the line
6275
6276     map< double, TInters > & u2inters = paramOnLine2TInters[ axis ];
6277     TIDSortedElemSet::iterator face = suspectFaces.begin();
6278     for ( ; face != suspectFaces.end(); ++face )
6279     {
6280       // get face plane
6281       gp_XYZ fNorm;
6282       if ( !SMESH_Algo::FaceNormal( *face, fNorm, /*normalized=*/false)) continue;
6283       gp_Pln facePlane( SMESH_MeshEditor::TNodeXYZ( (*face)->GetNode(0)), fNorm );
6284
6285       // perform intersection
6286       IntAna_IntConicQuad intersection( line, IntAna_Quadric( facePlane ));
6287       if ( !intersection.IsDone() )
6288         continue;
6289       if ( intersection.IsInQuadric() )
6290       {
6291         tangentInters[ axis ].push_back( TInters( *face, fNorm, true ));
6292       }
6293       else if ( ! intersection.IsParallel() && intersection.NbPoints() > 0 )
6294       {
6295         gp_Pnt intersectionPoint = intersection.Point(1);
6296         if ( !SMESH_MeshEditor::isOut( *face, intersectionPoint, tolerance ))
6297           u2inters.insert(make_pair( intersection.ParamOnConic(1), TInters( *face, fNorm )));
6298       }
6299     }
6300     // Analyse intersections roughly
6301
6302     int nbInter = u2inters.size();
6303     if ( nbInter == 0 )
6304       return TopAbs_OUT; 
6305
6306     double f = u2inters.begin()->first, l = u2inters.rbegin()->first;
6307     if ( nbInter == 1 ) // not closed mesh
6308       return fabs( f ) < tolerance ? TopAbs_ON : TopAbs_UNKNOWN;
6309
6310     if ( fabs( f ) < tolerance || fabs( l ) < tolerance )
6311       return TopAbs_ON;
6312
6313     if ( (f<0) == (l<0) )
6314       return TopAbs_OUT;
6315
6316     int nbIntBeforePoint = std::distance( u2inters.begin(), u2inters.lower_bound(0));
6317     int nbIntAfterPoint  = nbInter - nbIntBeforePoint;
6318     if ( nbIntBeforePoint == 1 || nbIntAfterPoint == 1 )
6319       return TopAbs_IN;
6320
6321     nbInt2Axis.insert( make_pair( min( nbIntBeforePoint, nbIntAfterPoint ), axis ));
6322
6323     if ( _outerFacesFound ) break; // pass to thorough analysis
6324
6325   } // three attempts - loop on CS axes
6326
6327   // Analyse intersections thoroughly.
6328   // We make two loops maximum, on the first one we only exclude touching intersections,
6329   // on the second, if situation is still unclear, we gather and use information on
6330   // position of faces (internal or outer). If faces position is already gathered,
6331   // we make the second loop right away.
6332
6333   for ( int hasPositionInfo = _outerFacesFound; hasPositionInfo < 2; ++hasPositionInfo )
6334   {
6335     multimap< int, int >::const_iterator nb_axis = nbInt2Axis.begin();
6336     for ( ; nb_axis != nbInt2Axis.end(); ++nb_axis )
6337     {
6338       int axis = nb_axis->second;
6339       map< double, TInters > & u2inters = paramOnLine2TInters[ axis ];
6340
6341       gp_Ax1 lineAxis( point, axisDir[axis]);
6342       gp_Lin line    ( lineAxis );
6343
6344       // add tangent intersections to u2inters
6345       double param;
6346       list< TInters >::const_iterator tgtInt = tangentInters[ axis ].begin();
6347       for ( ; tgtInt != tangentInters[ axis ].end(); ++tgtInt )
6348         if ( getIntersParamOnLine( line, tgtInt->_face, tolerance, param ))
6349           u2inters.insert(make_pair( param, *tgtInt ));
6350       tangentInters[ axis ].clear();
6351
6352       // Count intersections before and after the point excluding touching ones.
6353       // If hasPositionInfo we count intersections of outer boundary only
6354
6355       int nbIntBeforePoint = 0, nbIntAfterPoint = 0;
6356       double f = numeric_limits<double>::max(), l = -numeric_limits<double>::max();
6357       map< double, TInters >::iterator u_int1 = u2inters.begin(), u_int2 = u_int1;
6358       bool ok = ! u_int1->second._coincides;
6359       while ( ok && u_int1 != u2inters.end() )
6360       {
6361         double u = u_int1->first;
6362         bool touchingInt = false;
6363         if ( ++u_int2 != u2inters.end() )
6364         {
6365           // skip intersections at the same point (if the line passes through edge or node)
6366           int nbSamePnt = 0;
6367           while ( u_int2 != u2inters.end() && fabs( u_int2->first - u ) < tolerance )
6368           {
6369             ++nbSamePnt;
6370             ++u_int2;
6371           }
6372
6373           // skip tangent intersections
6374           int nbTgt = 0;
6375           const SMDS_MeshElement* prevFace = u_int1->second._face;
6376           while ( ok && u_int2->second._coincides )
6377           {
6378             if ( SMESH_Algo::GetCommonNodes(prevFace , u_int2->second._face).empty() )
6379               ok = false;
6380             else
6381             {
6382               nbTgt++;
6383               u_int2++;
6384               ok = ( u_int2 != u2inters.end() );
6385             }
6386           }
6387           if ( !ok ) break;
6388
6389           // skip intersections at the same point after tangent intersections
6390           if ( nbTgt > 0 )
6391           {
6392             double u2 = u_int2->first;
6393             ++u_int2;
6394             while ( u_int2 != u2inters.end() && fabs( u_int2->first - u2 ) < tolerance )
6395             {
6396               ++nbSamePnt;
6397               ++u_int2;
6398             }
6399           }
6400           // decide if we skipped a touching intersection
6401           if ( nbSamePnt + nbTgt > 0 )
6402           {
6403             double minDot = numeric_limits<double>::max(), maxDot = -numeric_limits<double>::max();
6404             map< double, TInters >::iterator u_int = u_int1;
6405             for ( ; u_int != u_int2; ++u_int )
6406             {
6407               if ( u_int->second._coincides ) continue;
6408               double dot = u_int->second._faceNorm * line.Direction();
6409               if ( dot > maxDot ) maxDot = dot;
6410               if ( dot < minDot ) minDot = dot;
6411             }
6412             touchingInt = ( minDot*maxDot < 0 );
6413           }
6414         }
6415         if ( !touchingInt )
6416         {
6417           if ( !hasPositionInfo || isOuterBoundary( u_int1->second._face ))
6418           {
6419             if ( u < 0 )
6420               ++nbIntBeforePoint;
6421             else
6422               ++nbIntAfterPoint;
6423           }
6424           if ( u < f ) f = u;
6425           if ( u > l ) l = u;
6426         }
6427
6428         u_int1 = u_int2; // to next intersection
6429
6430       } // loop on intersections with one line
6431
6432       if ( ok )
6433       {
6434         if ( fabs( f ) < tolerance || fabs( l ) < tolerance )
6435           return TopAbs_ON;
6436
6437         if ( nbIntBeforePoint == 0  || nbIntAfterPoint == 0)
6438           return TopAbs_OUT; 
6439
6440         if ( nbIntBeforePoint + nbIntAfterPoint == 1 ) // not closed mesh
6441           return fabs( f ) < tolerance ? TopAbs_ON : TopAbs_UNKNOWN;
6442
6443         if ( nbIntBeforePoint == 1 || nbIntAfterPoint == 1 )
6444           return TopAbs_IN;
6445
6446         if ( (f<0) == (l<0) )
6447           return TopAbs_OUT;
6448
6449         if ( hasPositionInfo )
6450           return nbIntBeforePoint % 2 ? TopAbs_IN : TopAbs_OUT;
6451       }
6452     } // loop on intersections of the tree lines - thorough analysis
6453
6454     if ( !hasPositionInfo )
6455     {
6456       // gather info on faces position - is face in the outer boundary or not
6457       map< double, TInters > & u2inters = paramOnLine2TInters[ 0 ];
6458       findOuterBoundary( u2inters.begin()->second._face );
6459     }
6460
6461   } // two attempts - with and w/o faces position info in the mesh
6462
6463   return TopAbs_UNKNOWN;
6464 }
6465
6466 //=======================================================================
6467 /*!
6468  * \brief Return SMESH_ElementSearcher
6469  */
6470 //=======================================================================
6471
6472 SMESH_ElementSearcher* SMESH_MeshEditor::GetElementSearcher()
6473 {
6474   return new SMESH_ElementSearcherImpl( *GetMeshDS() );
6475 }
6476
6477 //=======================================================================
6478 /*!
6479  * \brief Return true if the point is IN or ON of the element
6480  */
6481 //=======================================================================
6482
6483 bool SMESH_MeshEditor::isOut( const SMDS_MeshElement* element, const gp_Pnt& point, double tol )
6484 {
6485   if ( element->GetType() == SMDSAbs_Volume)
6486   {
6487     return SMDS_VolumeTool( element ).IsOut( point.X(), point.Y(), point.Z(), tol );
6488   }
6489
6490   // get ordered nodes
6491
6492   vector< gp_XYZ > xyz;
6493
6494   SMDS_ElemIteratorPtr nodeIt = element->nodesIterator();
6495   if ( element->IsQuadratic() )
6496     if (const SMDS_QuadraticFaceOfNodes* f=dynamic_cast<const SMDS_QuadraticFaceOfNodes*>(element))
6497       nodeIt = f->interlacedNodesElemIterator();
6498     else if (const SMDS_QuadraticEdge*  e =dynamic_cast<const SMDS_QuadraticEdge*>(element))
6499       nodeIt = e->interlacedNodesElemIterator();
6500
6501   while ( nodeIt->more() )
6502     xyz.push_back( TNodeXYZ( cast2Node( nodeIt->next() )));
6503
6504   int i, nbNodes = element->NbNodes();
6505
6506   if ( element->GetType() == SMDSAbs_Face ) // --------------------------------------------------
6507   {
6508     // compute face normal
6509     gp_Vec faceNorm(0,0,0);
6510     xyz.push_back( xyz.front() );
6511     for ( i = 0; i < nbNodes; ++i )
6512     {
6513       gp_Vec edge1( xyz[i+1], xyz[i]);
6514       gp_Vec edge2( xyz[i+1], xyz[(i+2)%nbNodes] );
6515       faceNorm += edge1 ^ edge2;
6516     }
6517     double normSize = faceNorm.Magnitude();
6518     if ( normSize <= tol )
6519     {
6520       // degenerated face: point is out if it is out of all face edges
6521       for ( i = 0; i < nbNodes; ++i )
6522       {
6523         SMDS_MeshNode n1( xyz[i].X(),   xyz[i].Y(),   xyz[i].Z() );
6524         SMDS_MeshNode n2( xyz[i+1].X(), xyz[i+1].Y(), xyz[i+1].Z() );
6525         SMDS_MeshEdge edge( &n1, &n2 );
6526         if ( !isOut( &edge, point, tol ))
6527           return false;
6528       }
6529       return true;
6530     }
6531     faceNorm /= normSize;
6532
6533     // check if the point lays on face plane
6534     gp_Vec n2p( xyz[0], point );
6535     if ( fabs( n2p * faceNorm ) > tol )
6536       return true; // not on face plane
6537
6538     // check if point is out of face boundary:
6539     // define it by closest transition of a ray point->infinity through face boundary
6540     // on the face plane.
6541     // First, find normal of a plane perpendicular to face plane, to be used as a cutting tool
6542     // to find intersections of the ray with the boundary.
6543     gp_Vec ray = n2p;
6544     gp_Vec plnNorm = ray ^ faceNorm;
6545     normSize = plnNorm.Magnitude();
6546     if ( normSize <= tol ) return false; // point coincides with the first node
6547     plnNorm /= normSize;
6548     // for each node of the face, compute its signed distance to the plane
6549     vector<double> dist( nbNodes + 1);
6550     for ( i = 0; i < nbNodes; ++i )
6551     {
6552       gp_Vec n2p( xyz[i], point );
6553       dist[i] = n2p * plnNorm;
6554     }
6555     dist.back() = dist.front();
6556     // find the closest intersection
6557     int    iClosest = -1;
6558     double rClosest, distClosest = 1e100;;
6559     gp_Pnt pClosest;
6560     for ( i = 0; i < nbNodes; ++i )
6561     {
6562       double r;
6563       if ( fabs( dist[i]) < tol )
6564         r = 0.;
6565       else if ( fabs( dist[i+1]) < tol )
6566         r = 1.;
6567       else if ( dist[i] * dist[i+1] < 0 )
6568         r = dist[i] / ( dist[i] - dist[i+1] );
6569       else
6570         continue; // no intersection
6571       gp_Pnt pInt = xyz[i] * (1.-r) + xyz[i+1] * r;
6572       gp_Vec p2int ( point, pInt);
6573       if ( p2int * ray > -tol ) // right half-space
6574       {
6575         double intDist = p2int.SquareMagnitude();
6576         if ( intDist < distClosest )
6577         {
6578           iClosest = i;
6579           rClosest = r;
6580           pClosest = pInt;
6581           distClosest = intDist;
6582         }
6583       }
6584     }
6585     if ( iClosest < 0 )
6586       return true; // no intesections - out
6587
6588     // analyse transition
6589     gp_Vec edge( xyz[iClosest], xyz[iClosest+1] );
6590     gp_Vec edgeNorm = -( edge ^ faceNorm ); // normal to intersected edge pointing out of face
6591     gp_Vec p2int ( point, pClosest );
6592     bool out = (edgeNorm * p2int) < -tol;
6593     if ( rClosest > 0. && rClosest < 1. ) // not node intersection
6594       return out;
6595
6596     // ray pass through a face node; analyze transition through an adjacent edge
6597     gp_Pnt p1 = xyz[ (rClosest == 0.) ? ((iClosest+nbNodes-1) % nbNodes) : (iClosest+1) ];
6598     gp_Pnt p2 = xyz[ (rClosest == 0.) ? iClosest : ((iClosest+2) % nbNodes) ];
6599     gp_Vec edgeAdjacent( p1, p2 );
6600     gp_Vec edgeNorm2 = -( edgeAdjacent ^ faceNorm );
6601     bool out2 = (edgeNorm2 * p2int) < -tol;
6602
6603     bool covexCorner = ( edgeNorm * edgeAdjacent * (rClosest==1. ? 1. : -1.)) < 0;
6604     return covexCorner ? (out || out2) : (out && out2);
6605   }
6606   if ( element->GetType() == SMDSAbs_Edge ) // --------------------------------------------------
6607   {
6608     // point is out of edge if it is NOT ON any straight part of edge
6609     // (we consider quadratic edge as being composed of two straight parts)
6610     for ( i = 1; i < nbNodes; ++i )
6611     {
6612       gp_Vec edge( xyz[i-1], xyz[i]);
6613       gp_Vec n1p ( xyz[i-1], point);
6614       double dist = ( edge ^ n1p ).Magnitude() / edge.Magnitude();
6615       if ( dist > tol )
6616         continue;
6617       gp_Vec n2p( xyz[i], point );
6618       if ( fabs( edge.Magnitude() - n1p.Magnitude() - n2p.Magnitude()) > tol )
6619         continue;
6620       return false; // point is ON this part
6621     }
6622     return true;
6623   }
6624   // Node or 0D element -------------------------------------------------------------------------
6625   {
6626     gp_Vec n2p ( xyz[0], point );
6627     return n2p.Magnitude() <= tol;
6628   }
6629   return true;
6630 }
6631
6632 //=======================================================================
6633 //function : SimplifyFace
6634 //purpose  :
6635 //=======================================================================
6636 int SMESH_MeshEditor::SimplifyFace (const vector<const SMDS_MeshNode *> faceNodes,
6637                                     vector<const SMDS_MeshNode *>&      poly_nodes,
6638                                     vector<int>&                        quantities) const
6639 {
6640   int nbNodes = faceNodes.size();
6641
6642   if (nbNodes < 3)
6643     return 0;
6644
6645   set<const SMDS_MeshNode*> nodeSet;
6646
6647   // get simple seq of nodes
6648   //const SMDS_MeshNode* simpleNodes[ nbNodes ];
6649   vector<const SMDS_MeshNode*> simpleNodes( nbNodes );
6650   int iSimple = 0, nbUnique = 0;
6651
6652   simpleNodes[iSimple++] = faceNodes[0];
6653   nbUnique++;
6654   for (int iCur = 1; iCur < nbNodes; iCur++) {
6655     if (faceNodes[iCur] != simpleNodes[iSimple - 1]) {
6656       simpleNodes[iSimple++] = faceNodes[iCur];
6657       if (nodeSet.insert( faceNodes[iCur] ).second)
6658         nbUnique++;
6659     }
6660   }
6661   int nbSimple = iSimple;
6662   if (simpleNodes[nbSimple - 1] == simpleNodes[0]) {
6663     nbSimple--;
6664     iSimple--;
6665   }
6666
6667   if (nbUnique < 3)
6668     return 0;
6669
6670   // separate loops
6671   int nbNew = 0;
6672   bool foundLoop = (nbSimple > nbUnique);
6673   while (foundLoop) {
6674     foundLoop = false;
6675     set<const SMDS_MeshNode*> loopSet;
6676     for (iSimple = 0; iSimple < nbSimple && !foundLoop; iSimple++) {
6677       const SMDS_MeshNode* n = simpleNodes[iSimple];
6678       if (!loopSet.insert( n ).second) {
6679         foundLoop = true;
6680
6681         // separate loop
6682         int iC = 0, curLast = iSimple;
6683         for (; iC < curLast; iC++) {
6684           if (simpleNodes[iC] == n) break;
6685         }
6686         int loopLen = curLast - iC;
6687         if (loopLen > 2) {
6688           // create sub-element
6689           nbNew++;
6690           quantities.push_back(loopLen);
6691           for (; iC < curLast; iC++) {
6692             poly_nodes.push_back(simpleNodes[iC]);
6693           }
6694         }
6695         // shift the rest nodes (place from the first loop position)
6696         for (iC = curLast + 1; iC < nbSimple; iC++) {
6697           simpleNodes[iC - loopLen] = simpleNodes[iC];
6698         }
6699         nbSimple -= loopLen;
6700         iSimple -= loopLen;
6701       }
6702     } // for (iSimple = 0; iSimple < nbSimple; iSimple++)
6703   } // while (foundLoop)
6704
6705   if (iSimple > 2) {
6706     nbNew++;
6707     quantities.push_back(iSimple);
6708     for (int i = 0; i < iSimple; i++)
6709       poly_nodes.push_back(simpleNodes[i]);
6710   }
6711
6712   return nbNew;
6713 }
6714
6715 //=======================================================================
6716 //function : MergeNodes
6717 //purpose  : In each group, the cdr of nodes are substituted by the first one
6718 //           in all elements.
6719 //=======================================================================
6720
6721 void SMESH_MeshEditor::MergeNodes (TListOfListOfNodes & theGroupsOfNodes)
6722 {
6723   myLastCreatedElems.Clear();
6724   myLastCreatedNodes.Clear();
6725
6726   SMESHDS_Mesh* aMesh = GetMeshDS();
6727
6728   TNodeNodeMap nodeNodeMap; // node to replace - new node
6729   set<const SMDS_MeshElement*> elems; // all elements with changed nodes
6730   list< int > rmElemIds, rmNodeIds;
6731
6732   // Fill nodeNodeMap and elems
6733
6734   TListOfListOfNodes::iterator grIt = theGroupsOfNodes.begin();
6735   for ( ; grIt != theGroupsOfNodes.end(); grIt++ ) {
6736     list<const SMDS_MeshNode*>& nodes = *grIt;
6737     list<const SMDS_MeshNode*>::iterator nIt = nodes.begin();
6738     const SMDS_MeshNode* nToKeep = *nIt;
6739     for ( ++nIt; nIt != nodes.end(); nIt++ ) {
6740       const SMDS_MeshNode* nToRemove = *nIt;
6741       nodeNodeMap.insert( TNodeNodeMap::value_type( nToRemove, nToKeep ));
6742       if ( nToRemove != nToKeep ) {
6743         rmNodeIds.push_back( nToRemove->GetID() );
6744         AddToSameGroups( nToKeep, nToRemove, aMesh );
6745       }
6746
6747       SMDS_ElemIteratorPtr invElemIt = nToRemove->GetInverseElementIterator();
6748       while ( invElemIt->more() ) {
6749         const SMDS_MeshElement* elem = invElemIt->next();
6750         elems.insert(elem);
6751       }
6752     }
6753   }
6754   // Change element nodes or remove an element
6755
6756   set<const SMDS_MeshElement*>::iterator eIt = elems.begin();
6757   for ( ; eIt != elems.end(); eIt++ ) {
6758     const SMDS_MeshElement* elem = *eIt;
6759     int nbNodes = elem->NbNodes();
6760     int aShapeId = FindShape( elem );
6761
6762     set<const SMDS_MeshNode*> nodeSet;
6763     vector< const SMDS_MeshNode*> curNodes( nbNodes ), uniqueNodes( nbNodes );
6764     int iUnique = 0, iCur = 0, nbRepl = 0;
6765     vector<int> iRepl( nbNodes );
6766
6767     // get new seq of nodes
6768     SMDS_ElemIteratorPtr itN = elem->nodesIterator();
6769     while ( itN->more() ) {
6770       const SMDS_MeshNode* n =
6771         static_cast<const SMDS_MeshNode*>( itN->next() );
6772
6773       TNodeNodeMap::iterator nnIt = nodeNodeMap.find( n );
6774       if ( nnIt != nodeNodeMap.end() ) { // n sticks
6775         n = (*nnIt).second;
6776         // BUG 0020185: begin
6777         {
6778           bool stopRecur = false;
6779           set<const SMDS_MeshNode*> nodesRecur;
6780           nodesRecur.insert(n);
6781           while (!stopRecur) {
6782             TNodeNodeMap::iterator nnIt_i = nodeNodeMap.find( n );
6783             if ( nnIt_i != nodeNodeMap.end() ) { // n sticks
6784               n = (*nnIt_i).second;
6785               if (!nodesRecur.insert(n).second) {
6786                 // error: recursive dependancy
6787                 stopRecur = true;
6788               }
6789             }
6790             else
6791               stopRecur = true;
6792           }
6793         }
6794         // BUG 0020185: end
6795         iRepl[ nbRepl++ ] = iCur;
6796       }
6797       curNodes[ iCur ] = n;
6798       bool isUnique = nodeSet.insert( n ).second;
6799       if ( isUnique )
6800         uniqueNodes[ iUnique++ ] = n;
6801       iCur++;
6802     }
6803
6804     // Analyse element topology after replacement
6805
6806     bool isOk = true;
6807     int nbUniqueNodes = nodeSet.size();
6808     if ( nbNodes != nbUniqueNodes ) { // some nodes stick
6809       // Polygons and Polyhedral volumes
6810       if (elem->IsPoly()) {
6811
6812         if (elem->GetType() == SMDSAbs_Face) {
6813           // Polygon
6814           vector<const SMDS_MeshNode *> face_nodes (nbNodes);
6815           int inode = 0;
6816           for (; inode < nbNodes; inode++) {
6817             face_nodes[inode] = curNodes[inode];
6818           }
6819
6820           vector<const SMDS_MeshNode *> polygons_nodes;
6821           vector<int> quantities;
6822           int nbNew = SimplifyFace(face_nodes, polygons_nodes, quantities);
6823
6824           if (nbNew > 0) {
6825             inode = 0;
6826             for (int iface = 0; iface < nbNew - 1; iface++) {
6827               int nbNodes = quantities[iface];
6828               vector<const SMDS_MeshNode *> poly_nodes (nbNodes);
6829               for (int ii = 0; ii < nbNodes; ii++, inode++) {
6830                 poly_nodes[ii] = polygons_nodes[inode];
6831               }
6832               SMDS_MeshElement* newElem = aMesh->AddPolygonalFace(poly_nodes);
6833               myLastCreatedElems.Append(newElem);
6834               if (aShapeId)
6835                 aMesh->SetMeshElementOnShape(newElem, aShapeId);
6836             }
6837             aMesh->ChangeElementNodes(elem, &polygons_nodes[inode], quantities[nbNew - 1]);
6838           }
6839           else {
6840             rmElemIds.push_back(elem->GetID());
6841           }
6842
6843         }
6844         else if (elem->GetType() == SMDSAbs_Volume) {
6845           // Polyhedral volume
6846           if (nbUniqueNodes < 4) {
6847             rmElemIds.push_back(elem->GetID());
6848           }
6849           else {
6850             // each face has to be analized in order to check volume validity
6851             const SMDS_PolyhedralVolumeOfNodes* aPolyedre =
6852               static_cast<const SMDS_PolyhedralVolumeOfNodes*>( elem );
6853             if (aPolyedre) {
6854               int nbFaces = aPolyedre->NbFaces();
6855
6856               vector<const SMDS_MeshNode *> poly_nodes;
6857               vector<int> quantities;
6858
6859               for (int iface = 1; iface <= nbFaces; iface++) {
6860                 int nbFaceNodes = aPolyedre->NbFaceNodes(iface);
6861                 vector<const SMDS_MeshNode *> faceNodes (nbFaceNodes);
6862
6863                 for (int inode = 1; inode <= nbFaceNodes; inode++) {
6864                   const SMDS_MeshNode * faceNode = aPolyedre->GetFaceNode(iface, inode);
6865                   TNodeNodeMap::iterator nnIt = nodeNodeMap.find(faceNode);
6866                   if (nnIt != nodeNodeMap.end()) { // faceNode sticks
6867                     faceNode = (*nnIt).second;
6868                   }
6869                   faceNodes[inode - 1] = faceNode;
6870                 }
6871
6872                 SimplifyFace(faceNodes, poly_nodes, quantities);
6873               }
6874
6875               if (quantities.size() > 3) {
6876                 // to be done: remove coincident faces
6877               }
6878
6879               if (quantities.size() > 3)
6880                 aMesh->ChangePolyhedronNodes(elem, poly_nodes, quantities);
6881               else
6882                 rmElemIds.push_back(elem->GetID());
6883
6884             }
6885             else {
6886               rmElemIds.push_back(elem->GetID());
6887             }
6888           }
6889         }
6890         else {
6891         }
6892
6893         continue;
6894       }
6895
6896       // Regular elements
6897       switch ( nbNodes ) {
6898       case 2: ///////////////////////////////////// EDGE
6899         isOk = false; break;
6900       case 3: ///////////////////////////////////// TRIANGLE
6901         isOk = false; break;
6902       case 4:
6903         if ( elem->GetType() == SMDSAbs_Volume ) // TETRAHEDRON
6904           isOk = false;
6905         else { //////////////////////////////////// QUADRANGLE
6906           if ( nbUniqueNodes < 3 )
6907             isOk = false;
6908           else if ( nbRepl == 2 && iRepl[ 1 ] - iRepl[ 0 ] == 2 )
6909             isOk = false; // opposite nodes stick
6910         }
6911         break;
6912       case 6: ///////////////////////////////////// PENTAHEDRON
6913         if ( nbUniqueNodes == 4 ) {
6914           // ---------------------------------> tetrahedron
6915           if (nbRepl == 3 &&
6916               iRepl[ 0 ] > 2 && iRepl[ 1 ] > 2 && iRepl[ 2 ] > 2 ) {
6917             // all top nodes stick: reverse a bottom
6918             uniqueNodes[ 0 ] = curNodes [ 1 ];
6919             uniqueNodes[ 1 ] = curNodes [ 0 ];
6920           }
6921           else if (nbRepl == 3 &&
6922                    iRepl[ 0 ] < 3 && iRepl[ 1 ] < 3 && iRepl[ 2 ] < 3 ) {
6923             // all bottom nodes stick: set a top before
6924             uniqueNodes[ 3 ] = uniqueNodes [ 0 ];
6925             uniqueNodes[ 0 ] = curNodes [ 3 ];
6926             uniqueNodes[ 1 ] = curNodes [ 4 ];
6927             uniqueNodes[ 2 ] = curNodes [ 5 ];
6928           }
6929           else if (nbRepl == 4 &&
6930                    iRepl[ 2 ] - iRepl [ 0 ] == 3 && iRepl[ 3 ] - iRepl [ 1 ] == 3 ) {
6931             // a lateral face turns into a line: reverse a bottom
6932             uniqueNodes[ 0 ] = curNodes [ 1 ];
6933             uniqueNodes[ 1 ] = curNodes [ 0 ];
6934           }
6935           else
6936             isOk = false;
6937         }
6938         else if ( nbUniqueNodes == 5 ) {
6939           // PENTAHEDRON --------------------> 2 tetrahedrons
6940           if ( nbRepl == 2 && iRepl[ 1 ] - iRepl [ 0 ] == 3 ) {
6941             // a bottom node sticks with a linked top one
6942             // 1.
6943             SMDS_MeshElement* newElem =
6944               aMesh->AddVolume(curNodes[ 3 ],
6945                                curNodes[ 4 ],
6946                                curNodes[ 5 ],
6947                                curNodes[ iRepl[ 0 ] == 2 ? 1 : 2 ]);
6948             myLastCreatedElems.Append(newElem);
6949             if ( aShapeId )
6950               aMesh->SetMeshElementOnShape( newElem, aShapeId );
6951             // 2. : reverse a bottom
6952             uniqueNodes[ 0 ] = curNodes [ 1 ];
6953             uniqueNodes[ 1 ] = curNodes [ 0 ];
6954             nbUniqueNodes = 4;
6955           }
6956           else
6957             isOk = false;
6958         }
6959         else
6960           isOk = false;
6961         break;
6962       case 8: {
6963         if(elem->IsQuadratic()) { // Quadratic quadrangle
6964           //   1    5    2
6965           //    +---+---+
6966           //    |       |
6967           //    |       |
6968           //   4+       +6
6969           //    |       |
6970           //    |       |
6971           //    +---+---+
6972           //   0    7    3
6973           isOk = false;
6974           if(nbRepl==3) {
6975             nbUniqueNodes = 6;
6976             if( iRepl[0]==0 && iRepl[1]==1 && iRepl[2]==4 ) {
6977               uniqueNodes[0] = curNodes[0];
6978               uniqueNodes[1] = curNodes[2];
6979               uniqueNodes[2] = curNodes[3];
6980               uniqueNodes[3] = curNodes[5];
6981               uniqueNodes[4] = curNodes[6];
6982               uniqueNodes[5] = curNodes[7];
6983               isOk = true;
6984             }
6985             if( iRepl[0]==0 && iRepl[1]==3 && iRepl[2]==7 ) {
6986               uniqueNodes[0] = curNodes[0];
6987               uniqueNodes[1] = curNodes[1];
6988               uniqueNodes[2] = curNodes[2];
6989               uniqueNodes[3] = curNodes[4];
6990               uniqueNodes[4] = curNodes[5];
6991               uniqueNodes[5] = curNodes[6];
6992               isOk = true;
6993             }
6994             if( iRepl[0]==0 && iRepl[1]==4 && iRepl[2]==7 ) {
6995               uniqueNodes[0] = curNodes[1];
6996               uniqueNodes[1] = curNodes[2];
6997               uniqueNodes[2] = curNodes[3];
6998               uniqueNodes[3] = curNodes[5];
6999               uniqueNodes[4] = curNodes[6];
7000               uniqueNodes[5] = curNodes[0];
7001               isOk = true;
7002             }
7003             if( iRepl[0]==1 && iRepl[1]==2 && iRepl[2]==5 ) {
7004               uniqueNodes[0] = curNodes[0];
7005               uniqueNodes[1] = curNodes[1];
7006               uniqueNodes[2] = curNodes[3];
7007               uniqueNodes[3] = curNodes[4];
7008               uniqueNodes[4] = curNodes[6];
7009               uniqueNodes[5] = curNodes[7];
7010               isOk = true;
7011             }
7012             if( iRepl[0]==1 && iRepl[1]==4 && iRepl[2]==5 ) {
7013               uniqueNodes[0] = curNodes[0];
7014               uniqueNodes[1] = curNodes[2];
7015               uniqueNodes[2] = curNodes[3];
7016               uniqueNodes[3] = curNodes[1];
7017               uniqueNodes[4] = curNodes[6];
7018               uniqueNodes[5] = curNodes[7];
7019               isOk = true;
7020             }
7021             if( iRepl[0]==2 && iRepl[1]==3 && iRepl[2]==6 ) {
7022               uniqueNodes[0] = curNodes[0];
7023               uniqueNodes[1] = curNodes[1];
7024               uniqueNodes[2] = curNodes[2];
7025               uniqueNodes[3] = curNodes[4];
7026               uniqueNodes[4] = curNodes[5];
7027               uniqueNodes[5] = curNodes[7];
7028               isOk = true;
7029             }
7030             if( iRepl[0]==2 && iRepl[1]==5 && iRepl[2]==6 ) {
7031               uniqueNodes[0] = curNodes[0];
7032               uniqueNodes[1] = curNodes[1];
7033               uniqueNodes[2] = curNodes[3];
7034               uniqueNodes[3] = curNodes[4];
7035               uniqueNodes[4] = curNodes[2];
7036               uniqueNodes[5] = curNodes[7];
7037               isOk = true;
7038             }
7039             if( iRepl[0]==3 && iRepl[1]==6 && iRepl[2]==7 ) {
7040               uniqueNodes[0] = curNodes[0];
7041               uniqueNodes[1] = curNodes[1];
7042               uniqueNodes[2] = curNodes[2];
7043               uniqueNodes[3] = curNodes[4];
7044               uniqueNodes[4] = curNodes[5];
7045               uniqueNodes[5] = curNodes[3];
7046               isOk = true;
7047             }
7048           }
7049           break;
7050         }
7051         //////////////////////////////////// HEXAHEDRON
7052         isOk = false;
7053         SMDS_VolumeTool hexa (elem);
7054         hexa.SetExternalNormal();
7055         if ( nbUniqueNodes == 4 && nbRepl == 6 ) {
7056           //////////////////////// ---> tetrahedron
7057           for ( int iFace = 0; iFace < 6; iFace++ ) {
7058             const int *ind = hexa.GetFaceNodesIndices( iFace ); // indices of face nodes
7059             if (curNodes[ind[ 0 ]] == curNodes[ind[ 1 ]] &&
7060                 curNodes[ind[ 0 ]] == curNodes[ind[ 2 ]] &&
7061                 curNodes[ind[ 0 ]] == curNodes[ind[ 3 ]] ) {
7062               // one face turns into a point ...
7063               int iOppFace = hexa.GetOppFaceIndex( iFace );
7064               ind = hexa.GetFaceNodesIndices( iOppFace );
7065               int nbStick = 0;
7066               iUnique = 2; // reverse a tetrahedron bottom
7067               for ( iCur = 0; iCur < 4 && nbStick < 2; iCur++ ) {
7068                 if ( curNodes[ind[ iCur ]] == curNodes[ind[ iCur + 1 ]] )
7069                   nbStick++;
7070                 else if ( iUnique >= 0 )
7071                   uniqueNodes[ iUnique-- ] = curNodes[ind[ iCur ]];
7072               }
7073               if ( nbStick == 1 ) {
7074                 // ... and the opposite one - into a triangle.
7075                 // set a top node
7076                 ind = hexa.GetFaceNodesIndices( iFace );
7077                 uniqueNodes[ 3 ] = curNodes[ind[ 0 ]];
7078                 isOk = true;
7079               }
7080               break;
7081             }
7082           }
7083         }
7084         else if (nbUniqueNodes == 5 && nbRepl == 4 ) {
7085           //////////////////// HEXAHEDRON ---> 2 tetrahedrons
7086           for ( int iFace = 0; iFace < 6; iFace++ ) {
7087             const int *ind = hexa.GetFaceNodesIndices( iFace ); // indices of face nodes
7088             if (curNodes[ind[ 0 ]] == curNodes[ind[ 1 ]] &&
7089                 curNodes[ind[ 0 ]] == curNodes[ind[ 2 ]] &&
7090                 curNodes[ind[ 0 ]] == curNodes[ind[ 3 ]] ) {
7091               // one face turns into a point ...
7092               int iOppFace = hexa.GetOppFaceIndex( iFace );
7093               ind = hexa.GetFaceNodesIndices( iOppFace );
7094               int nbStick = 0;
7095               iUnique = 2;  // reverse a tetrahedron 1 bottom
7096               for ( iCur = 0; iCur < 4 && nbStick == 0; iCur++ ) {
7097                 if ( curNodes[ind[ iCur ]] == curNodes[ind[ iCur + 1 ]] )
7098                   nbStick++;
7099                 else if ( iUnique >= 0 )
7100                   uniqueNodes[ iUnique-- ] = curNodes[ind[ iCur ]];
7101               }
7102               if ( nbStick == 0 ) {
7103                 // ... and the opposite one is a quadrangle
7104                 // set a top node
7105                 const int* indTop = hexa.GetFaceNodesIndices( iFace );
7106                 uniqueNodes[ 3 ] = curNodes[indTop[ 0 ]];
7107                 nbUniqueNodes = 4;
7108                 // tetrahedron 2
7109                 SMDS_MeshElement* newElem =
7110                   aMesh->AddVolume(curNodes[ind[ 0 ]],
7111                                    curNodes[ind[ 3 ]],
7112                                    curNodes[ind[ 2 ]],
7113                                    curNodes[indTop[ 0 ]]);
7114                 myLastCreatedElems.Append(newElem);
7115                 if ( aShapeId )
7116                   aMesh->SetMeshElementOnShape( newElem, aShapeId );
7117                 isOk = true;
7118               }
7119               break;
7120             }
7121           }
7122         }
7123         else if ( nbUniqueNodes == 6 && nbRepl == 4 ) {
7124           ////////////////// HEXAHEDRON ---> 2 tetrahedrons or 1 prism
7125           // find indices of quad and tri faces
7126           int iQuadFace[ 6 ], iTriFace[ 6 ], nbQuad = 0, nbTri = 0, iFace;
7127           for ( iFace = 0; iFace < 6; iFace++ ) {
7128             const int *ind = hexa.GetFaceNodesIndices( iFace ); // indices of face nodes
7129             nodeSet.clear();
7130             for ( iCur = 0; iCur < 4; iCur++ )
7131               nodeSet.insert( curNodes[ind[ iCur ]] );
7132             nbUniqueNodes = nodeSet.size();
7133             if ( nbUniqueNodes == 3 )
7134               iTriFace[ nbTri++ ] = iFace;
7135             else if ( nbUniqueNodes == 4 )
7136               iQuadFace[ nbQuad++ ] = iFace;
7137           }
7138           if (nbQuad == 2 && nbTri == 4 &&
7139               hexa.GetOppFaceIndex( iQuadFace[ 0 ] ) == iQuadFace[ 1 ]) {
7140             // 2 opposite quadrangles stuck with a diagonal;
7141             // sample groups of merged indices: (0-4)(2-6)
7142             // --------------------------------------------> 2 tetrahedrons
7143             const int *ind1 = hexa.GetFaceNodesIndices( iQuadFace[ 0 ]); // indices of quad1 nodes
7144             const int *ind2 = hexa.GetFaceNodesIndices( iQuadFace[ 1 ]);
7145             int i0, i1d, i2, i3d, i0t, i2t; // d-daigonal, t-top
7146             if (curNodes[ind1[ 0 ]] == curNodes[ind2[ 0 ]] &&
7147                 curNodes[ind1[ 2 ]] == curNodes[ind2[ 2 ]]) {
7148               // stuck with 0-2 diagonal
7149               i0  = ind1[ 3 ];
7150               i1d = ind1[ 0 ];
7151               i2  = ind1[ 1 ];
7152               i3d = ind1[ 2 ];
7153               i0t = ind2[ 1 ];
7154               i2t = ind2[ 3 ];
7155             }
7156             else if (curNodes[ind1[ 1 ]] == curNodes[ind2[ 3 ]] &&
7157                      curNodes[ind1[ 3 ]] == curNodes[ind2[ 1 ]]) {
7158               // stuck with 1-3 diagonal
7159               i0  = ind1[ 0 ];
7160               i1d = ind1[ 1 ];
7161               i2  = ind1[ 2 ];
7162               i3d = ind1[ 3 ];
7163               i0t = ind2[ 0 ];
7164               i2t = ind2[ 1 ];
7165             }
7166             else {
7167               ASSERT(0);
7168             }
7169             // tetrahedron 1
7170             uniqueNodes[ 0 ] = curNodes [ i0 ];
7171             uniqueNodes[ 1 ] = curNodes [ i1d ];
7172             uniqueNodes[ 2 ] = curNodes [ i3d ];
7173             uniqueNodes[ 3 ] = curNodes [ i0t ];
7174             nbUniqueNodes = 4;
7175             // tetrahedron 2
7176             SMDS_MeshElement* newElem = aMesh->AddVolume(curNodes[ i1d ],
7177                                                          curNodes[ i2 ],
7178                                                          curNodes[ i3d ],
7179                                                          curNodes[ i2t ]);
7180             myLastCreatedElems.Append(newElem);
7181             if ( aShapeId )
7182               aMesh->SetMeshElementOnShape( newElem, aShapeId );
7183             isOk = true;
7184           }
7185           else if (( nbTri == 2 && nbQuad == 3 ) || // merged (0-4)(1-5)
7186                    ( nbTri == 4 && nbQuad == 2 )) { // merged (7-4)(1-5)
7187             // --------------------------------------------> prism
7188             // find 2 opposite triangles
7189             nbUniqueNodes = 6;
7190             for ( iFace = 0; iFace + 1 < nbTri; iFace++ ) {
7191               if ( hexa.GetOppFaceIndex( iTriFace[ iFace ] ) == iTriFace[ iFace + 1 ]) {
7192                 // find indices of kept and replaced nodes
7193                 // and fill unique nodes of 2 opposite triangles
7194                 const int *ind1 = hexa.GetFaceNodesIndices( iTriFace[ iFace ]);
7195                 const int *ind2 = hexa.GetFaceNodesIndices( iTriFace[ iFace + 1 ]);
7196                 const SMDS_MeshNode** hexanodes = hexa.GetNodes();
7197                 // fill unique nodes
7198                 iUnique = 0;
7199                 isOk = true;
7200                 for ( iCur = 0; iCur < 4 && isOk; iCur++ ) {
7201                   const SMDS_MeshNode* n     = curNodes[ind1[ iCur ]];
7202                   const SMDS_MeshNode* nInit = hexanodes[ind1[ iCur ]];
7203                   if ( n == nInit ) {
7204                     // iCur of a linked node of the opposite face (make normals co-directed):
7205                     int iCurOpp = ( iCur == 1 || iCur == 3 ) ? 4 - iCur : iCur;
7206                     // check that correspondent corners of triangles are linked
7207                     if ( !hexa.IsLinked( ind1[ iCur ], ind2[ iCurOpp ] ))
7208                       isOk = false;
7209                     else {
7210                       uniqueNodes[ iUnique ] = n;
7211                       uniqueNodes[ iUnique + 3 ] = curNodes[ind2[ iCurOpp ]];
7212                       iUnique++;
7213                     }
7214                   }
7215                 }
7216                 break;
7217               }
7218             }
7219           }
7220         } // if ( nbUniqueNodes == 6 && nbRepl == 4 )
7221         break;
7222       } // HEXAHEDRON
7223
7224       default:
7225         isOk = false;
7226       } // switch ( nbNodes )
7227
7228     } // if ( nbNodes != nbUniqueNodes ) // some nodes stick
7229
7230     if ( isOk ) {
7231       if (elem->IsPoly() && elem->GetType() == SMDSAbs_Volume) {
7232         // Change nodes of polyedre
7233         const SMDS_PolyhedralVolumeOfNodes* aPolyedre =
7234           static_cast<const SMDS_PolyhedralVolumeOfNodes*>( elem );
7235         if (aPolyedre) {
7236           int nbFaces = aPolyedre->NbFaces();
7237
7238           vector<const SMDS_MeshNode *> poly_nodes;
7239           vector<int> quantities (nbFaces);
7240
7241           for (int iface = 1; iface <= nbFaces; iface++) {
7242             int inode, nbFaceNodes = aPolyedre->NbFaceNodes(iface);
7243             quantities[iface - 1] = nbFaceNodes;
7244
7245             for (inode = 1; inode <= nbFaceNodes; inode++) {
7246               const SMDS_MeshNode* curNode = aPolyedre->GetFaceNode(iface, inode);
7247
7248               TNodeNodeMap::iterator nnIt = nodeNodeMap.find( curNode );
7249               if (nnIt != nodeNodeMap.end()) { // curNode sticks
7250                 curNode = (*nnIt).second;
7251               }
7252               poly_nodes.push_back(curNode);
7253             }
7254           }
7255           aMesh->ChangePolyhedronNodes( elem, poly_nodes, quantities );
7256         }
7257       }
7258       else {
7259         // Change regular element or polygon
7260         aMesh->ChangeElementNodes( elem, & uniqueNodes[0], nbUniqueNodes );
7261       }
7262     }
7263     else {
7264       // Remove invalid regular element or invalid polygon
7265       rmElemIds.push_back( elem->GetID() );
7266     }
7267
7268   } // loop on elements
7269
7270   // Remove equal nodes and bad elements
7271
7272   Remove( rmNodeIds, true );
7273   Remove( rmElemIds, false );
7274
7275 }
7276
7277
7278 // ========================================================
7279 // class   : SortableElement
7280 // purpose : allow sorting elements basing on their nodes
7281 // ========================================================
7282 class SortableElement : public set <const SMDS_MeshElement*>
7283 {
7284 public:
7285
7286   SortableElement( const SMDS_MeshElement* theElem )
7287   {
7288     myElem = theElem;
7289     SMDS_ElemIteratorPtr nodeIt = theElem->nodesIterator();
7290     while ( nodeIt->more() )
7291       this->insert( nodeIt->next() );
7292   }
7293
7294   const SMDS_MeshElement* Get() const
7295   { return myElem; }
7296
7297   void Set(const SMDS_MeshElement* e) const
7298   { myElem = e; }
7299
7300
7301 private:
7302   mutable const SMDS_MeshElement* myElem;
7303 };
7304
7305 //=======================================================================
7306 //function : FindEqualElements
7307 //purpose  : Return list of group of elements built on the same nodes.
7308 //           Search among theElements or in the whole mesh if theElements is empty
7309 //=======================================================================
7310 void SMESH_MeshEditor::FindEqualElements(set<const SMDS_MeshElement*> & theElements,
7311                                          TListOfListOfElementsID &      theGroupsOfElementsID)
7312 {
7313   myLastCreatedElems.Clear();
7314   myLastCreatedNodes.Clear();
7315
7316   typedef set<const SMDS_MeshElement*> TElemsSet;
7317   typedef map< SortableElement, int > TMapOfNodeSet;
7318   typedef list<int> TGroupOfElems;
7319
7320   TElemsSet elems;
7321   if ( theElements.empty() )
7322   { // get all elements in the mesh
7323     SMDS_ElemIteratorPtr eIt = GetMeshDS()->elementsIterator();
7324     while ( eIt->more() )
7325       elems.insert( elems.end(), eIt->next());
7326   }
7327   else
7328     elems = theElements;
7329
7330   vector< TGroupOfElems > arrayOfGroups;
7331   TGroupOfElems groupOfElems;
7332   TMapOfNodeSet mapOfNodeSet;
7333
7334   TElemsSet::iterator elemIt = elems.begin();
7335   for ( int i = 0, j=0; elemIt != elems.end(); ++elemIt, ++j ) {
7336     const SMDS_MeshElement* curElem = *elemIt;
7337     SortableElement SE(curElem);
7338     int ind = -1;
7339     // check uniqueness
7340     pair< TMapOfNodeSet::iterator, bool> pp = mapOfNodeSet.insert(make_pair(SE, i));
7341     if( !(pp.second) ) {
7342       TMapOfNodeSet::iterator& itSE = pp.first;
7343       ind = (*itSE).second;
7344       arrayOfGroups[ind].push_back(curElem->GetID());
7345     }
7346     else {
7347       groupOfElems.clear();
7348       groupOfElems.push_back(curElem->GetID());
7349       arrayOfGroups.push_back(groupOfElems);
7350       i++;
7351     }
7352   }
7353
7354   vector< TGroupOfElems >::iterator groupIt = arrayOfGroups.begin();
7355   for ( ; groupIt != arrayOfGroups.end(); ++groupIt ) {
7356     groupOfElems = *groupIt;
7357     if ( groupOfElems.size() > 1 ) {
7358       groupOfElems.sort();
7359       theGroupsOfElementsID.push_back(groupOfElems);
7360     }
7361   }
7362 }
7363
7364 //=======================================================================
7365 //function : MergeElements
7366 //purpose  : In each given group, substitute all elements by the first one.
7367 //=======================================================================
7368
7369 void SMESH_MeshEditor::MergeElements(TListOfListOfElementsID & theGroupsOfElementsID)
7370 {
7371   myLastCreatedElems.Clear();
7372   myLastCreatedNodes.Clear();
7373
7374   typedef list<int> TListOfIDs;
7375   TListOfIDs rmElemIds; // IDs of elems to remove
7376
7377   SMESHDS_Mesh* aMesh = GetMeshDS();
7378
7379   TListOfListOfElementsID::iterator groupsIt = theGroupsOfElementsID.begin();
7380   while ( groupsIt != theGroupsOfElementsID.end() ) {
7381     TListOfIDs& aGroupOfElemID = *groupsIt;
7382     aGroupOfElemID.sort();
7383     int elemIDToKeep = aGroupOfElemID.front();
7384     const SMDS_MeshElement* elemToKeep = aMesh->FindElement(elemIDToKeep);
7385     aGroupOfElemID.pop_front();
7386     TListOfIDs::iterator idIt = aGroupOfElemID.begin();
7387     while ( idIt != aGroupOfElemID.end() ) {
7388       int elemIDToRemove = *idIt;
7389       const SMDS_MeshElement* elemToRemove = aMesh->FindElement(elemIDToRemove);
7390       // add the kept element in groups of removed one (PAL15188)
7391       AddToSameGroups( elemToKeep, elemToRemove, aMesh );
7392       rmElemIds.push_back( elemIDToRemove );
7393       ++idIt;
7394     }
7395     ++groupsIt;
7396   }
7397
7398   Remove( rmElemIds, false );
7399 }
7400
7401 //=======================================================================
7402 //function : MergeEqualElements
7403 //purpose  : Remove all but one of elements built on the same nodes.
7404 //=======================================================================
7405
7406 void SMESH_MeshEditor::MergeEqualElements()
7407 {
7408   set<const SMDS_MeshElement*> aMeshElements; /* empty input -
7409                                                  to merge equal elements in the whole mesh */
7410   TListOfListOfElementsID aGroupsOfElementsID;
7411   FindEqualElements(aMeshElements, aGroupsOfElementsID);
7412   MergeElements(aGroupsOfElementsID);
7413 }
7414
7415 //=======================================================================
7416 //function : FindFaceInSet
7417 //purpose  : Return a face having linked nodes n1 and n2 and which is
7418 //           - not in avoidSet,
7419 //           - in elemSet provided that !elemSet.empty()
7420 //           i1 and i2 optionally returns indices of n1 and n2
7421 //=======================================================================
7422
7423 const SMDS_MeshElement*
7424 SMESH_MeshEditor::FindFaceInSet(const SMDS_MeshNode*    n1,
7425                                 const SMDS_MeshNode*    n2,
7426                                 const TIDSortedElemSet& elemSet,
7427                                 const TIDSortedElemSet& avoidSet,
7428                                 int*                    n1ind,
7429                                 int*                    n2ind)
7430
7431 {
7432   int i1, i2;
7433   const SMDS_MeshElement* face = 0;
7434
7435   SMDS_ElemIteratorPtr invElemIt = n1->GetInverseElementIterator(SMDSAbs_Face);
7436   while ( invElemIt->more() && !face ) // loop on inverse faces of n1
7437   {
7438     const SMDS_MeshElement* elem = invElemIt->next();
7439     if (avoidSet.count( elem ))
7440       continue;
7441     if ( !elemSet.empty() && !elemSet.count( elem ))
7442       continue;
7443     // index of n1
7444     i1 = elem->GetNodeIndex( n1 );
7445     // find a n2 linked to n1
7446     int nbN = elem->IsQuadratic() ? elem->NbNodes()/2 : elem->NbNodes();
7447     for ( int di = -1; di < 2 && !face; di += 2 )
7448     {
7449       i2 = (i1+di+nbN) % nbN;
7450       if ( elem->GetNode( i2 ) == n2 )
7451         face = elem;
7452     }
7453     if ( !face && elem->IsQuadratic())
7454     {
7455       // analysis for quadratic elements using all nodes
7456       const SMDS_QuadraticFaceOfNodes* F =
7457         static_cast<const SMDS_QuadraticFaceOfNodes*>(elem);
7458       // use special nodes iterator
7459       SMDS_NodeIteratorPtr anIter = F->interlacedNodesIterator();
7460       const SMDS_MeshNode* prevN = cast2Node( anIter->next() );
7461       for ( i1 = -1, i2 = 0; anIter->more() && !face; i1++, i2++ )
7462       {
7463         const SMDS_MeshNode* n = cast2Node( anIter->next() );
7464         if ( n1 == prevN && n2 == n )
7465         {
7466           face = elem;
7467         }
7468         else if ( n2 == prevN && n1 == n )
7469         {
7470           face = elem; swap( i1, i2 );
7471         }
7472         prevN = n;
7473       }
7474     }
7475   }
7476   if ( n1ind ) *n1ind = i1;
7477   if ( n2ind ) *n2ind = i2;
7478   return face;
7479 }
7480
7481 //=======================================================================
7482 //function : findAdjacentFace
7483 //purpose  :
7484 //=======================================================================
7485
7486 static const SMDS_MeshElement* findAdjacentFace(const SMDS_MeshNode* n1,
7487                                                 const SMDS_MeshNode* n2,
7488                                                 const SMDS_MeshElement* elem)
7489 {
7490   TIDSortedElemSet elemSet, avoidSet;
7491   if ( elem )
7492     avoidSet.insert ( elem );
7493   return SMESH_MeshEditor::FindFaceInSet( n1, n2, elemSet, avoidSet );
7494 }
7495
7496 //=======================================================================
7497 //function : FindFreeBorder
7498 //purpose  :
7499 //=======================================================================
7500
7501 #define ControlFreeBorder SMESH::Controls::FreeEdges::IsFreeEdge
7502
7503 bool SMESH_MeshEditor::FindFreeBorder (const SMDS_MeshNode*             theFirstNode,
7504                                        const SMDS_MeshNode*             theSecondNode,
7505                                        const SMDS_MeshNode*             theLastNode,
7506                                        list< const SMDS_MeshNode* > &   theNodes,
7507                                        list< const SMDS_MeshElement* >& theFaces)
7508 {
7509   if ( !theFirstNode || !theSecondNode )
7510     return false;
7511   // find border face between theFirstNode and theSecondNode
7512   const SMDS_MeshElement* curElem = findAdjacentFace( theFirstNode, theSecondNode, 0 );
7513   if ( !curElem )
7514     return false;
7515
7516   theFaces.push_back( curElem );
7517   theNodes.push_back( theFirstNode );
7518   theNodes.push_back( theSecondNode );
7519
7520   //vector<const SMDS_MeshNode*> nodes;
7521   const SMDS_MeshNode *nIgnore = theFirstNode, *nStart = theSecondNode;
7522   TIDSortedElemSet foundElems;
7523   bool needTheLast = ( theLastNode != 0 );
7524
7525   while ( nStart != theLastNode ) {
7526     if ( nStart == theFirstNode )
7527       return !needTheLast;
7528
7529     // find all free border faces sharing form nStart
7530
7531     list< const SMDS_MeshElement* > curElemList;
7532     list< const SMDS_MeshNode* > nStartList;
7533     SMDS_ElemIteratorPtr invElemIt = nStart->GetInverseElementIterator(SMDSAbs_Face);
7534     while ( invElemIt->more() ) {
7535       const SMDS_MeshElement* e = invElemIt->next();
7536       if ( e == curElem || foundElems.insert( e ).second ) {
7537         // get nodes
7538         int iNode = 0, nbNodes = e->NbNodes();
7539         //const SMDS_MeshNode* nodes[nbNodes+1];
7540         vector<const SMDS_MeshNode*> nodes(nbNodes+1);
7541
7542         if(e->IsQuadratic()) {
7543           const SMDS_QuadraticFaceOfNodes* F =
7544             static_cast<const SMDS_QuadraticFaceOfNodes*>(e);
7545           // use special nodes iterator
7546           SMDS_NodeIteratorPtr anIter = F->interlacedNodesIterator();
7547           while( anIter->more() ) {
7548             nodes[ iNode++ ] = anIter->next();
7549           }
7550         }
7551         else {
7552           SMDS_ElemIteratorPtr nIt = e->nodesIterator();
7553           while ( nIt->more() )
7554             nodes[ iNode++ ] = static_cast<const SMDS_MeshNode*>( nIt->next() );
7555         }
7556         nodes[ iNode ] = nodes[ 0 ];
7557         // check 2 links
7558         for ( iNode = 0; iNode < nbNodes; iNode++ )
7559           if (((nodes[ iNode ] == nStart && nodes[ iNode + 1] != nIgnore ) ||
7560                (nodes[ iNode + 1] == nStart && nodes[ iNode ] != nIgnore )) &&
7561               ControlFreeBorder( &nodes[ iNode ], e->GetID() ))
7562           {
7563             nStartList.push_back( nodes[ iNode + ( nodes[ iNode ] == nStart ? 1 : 0 )]);
7564             curElemList.push_back( e );
7565           }
7566       }
7567     }
7568     // analyse the found
7569
7570     int nbNewBorders = curElemList.size();
7571     if ( nbNewBorders == 0 ) {
7572       // no free border furthermore
7573       return !needTheLast;
7574     }
7575     else if ( nbNewBorders == 1 ) {
7576       // one more element found
7577       nIgnore = nStart;
7578       nStart = nStartList.front();
7579       curElem = curElemList.front();
7580       theFaces.push_back( curElem );
7581       theNodes.push_back( nStart );
7582     }
7583     else {
7584       // several continuations found
7585       list< const SMDS_MeshElement* >::iterator curElemIt;
7586       list< const SMDS_MeshNode* >::iterator nStartIt;
7587       // check if one of them reached the last node
7588       if ( needTheLast ) {
7589         for (curElemIt = curElemList.begin(), nStartIt = nStartList.begin();
7590              curElemIt!= curElemList.end();
7591              curElemIt++, nStartIt++ )
7592           if ( *nStartIt == theLastNode ) {
7593             theFaces.push_back( *curElemIt );
7594             theNodes.push_back( *nStartIt );
7595             return true;
7596           }
7597       }
7598       // find the best free border by the continuations
7599       list<const SMDS_MeshNode*>    contNodes[ 2 ], *cNL;
7600       list<const SMDS_MeshElement*> contFaces[ 2 ], *cFL;
7601       for (curElemIt = curElemList.begin(), nStartIt = nStartList.begin();
7602            curElemIt!= curElemList.end();
7603            curElemIt++, nStartIt++ )
7604       {
7605         cNL = & contNodes[ contNodes[0].empty() ? 0 : 1 ];
7606         cFL = & contFaces[ contFaces[0].empty() ? 0 : 1 ];
7607         // find one more free border
7608         if ( ! FindFreeBorder( nStart, *nStartIt, theLastNode, *cNL, *cFL )) {
7609           cNL->clear();
7610           cFL->clear();
7611         }
7612         else if ( !contNodes[0].empty() && !contNodes[1].empty() ) {
7613           // choice: clear a worse one
7614           int iLongest = ( contNodes[0].size() < contNodes[1].size() ? 1 : 0 );
7615           int iWorse = ( needTheLast ? 1 - iLongest : iLongest );
7616           contNodes[ iWorse ].clear();
7617           contFaces[ iWorse ].clear();
7618         }
7619       }
7620       if ( contNodes[0].empty() && contNodes[1].empty() )
7621         return false;
7622
7623       // append the best free border
7624       cNL = & contNodes[ contNodes[0].empty() ? 1 : 0 ];
7625       cFL = & contFaces[ contFaces[0].empty() ? 1 : 0 ];
7626       theNodes.pop_back(); // remove nIgnore
7627       theNodes.pop_back(); // remove nStart
7628       theFaces.pop_back(); // remove curElem
7629       list< const SMDS_MeshNode* >::iterator nIt = cNL->begin();
7630       list< const SMDS_MeshElement* >::iterator fIt = cFL->begin();
7631       for ( ; nIt != cNL->end(); nIt++ ) theNodes.push_back( *nIt );
7632       for ( ; fIt != cFL->end(); fIt++ ) theFaces.push_back( *fIt );
7633       return true;
7634
7635     } // several continuations found
7636   } // while ( nStart != theLastNode )
7637
7638   return true;
7639 }
7640
7641 //=======================================================================
7642 //function : CheckFreeBorderNodes
7643 //purpose  : Return true if the tree nodes are on a free border
7644 //=======================================================================
7645
7646 bool SMESH_MeshEditor::CheckFreeBorderNodes(const SMDS_MeshNode* theNode1,
7647                                             const SMDS_MeshNode* theNode2,
7648                                             const SMDS_MeshNode* theNode3)
7649 {
7650   list< const SMDS_MeshNode* > nodes;
7651   list< const SMDS_MeshElement* > faces;
7652   return FindFreeBorder( theNode1, theNode2, theNode3, nodes, faces);
7653 }
7654
7655 //=======================================================================
7656 //function : SewFreeBorder
7657 //purpose  :
7658 //=======================================================================
7659
7660 SMESH_MeshEditor::Sew_Error
7661 SMESH_MeshEditor::SewFreeBorder (const SMDS_MeshNode* theBordFirstNode,
7662                                  const SMDS_MeshNode* theBordSecondNode,
7663                                  const SMDS_MeshNode* theBordLastNode,
7664                                  const SMDS_MeshNode* theSideFirstNode,
7665                                  const SMDS_MeshNode* theSideSecondNode,
7666                                  const SMDS_MeshNode* theSideThirdNode,
7667                                  const bool           theSideIsFreeBorder,
7668                                  const bool           toCreatePolygons,
7669                                  const bool           toCreatePolyedrs)
7670 {
7671   myLastCreatedElems.Clear();
7672   myLastCreatedNodes.Clear();
7673
7674   MESSAGE("::SewFreeBorder()");
7675   Sew_Error aResult = SEW_OK;
7676
7677   // ====================================
7678   //    find side nodes and elements
7679   // ====================================
7680
7681   list< const SMDS_MeshNode* > nSide[ 2 ];
7682   list< const SMDS_MeshElement* > eSide[ 2 ];
7683   list< const SMDS_MeshNode* >::iterator nIt[ 2 ];
7684   list< const SMDS_MeshElement* >::iterator eIt[ 2 ];
7685
7686   // Free border 1
7687   // --------------
7688   if (!FindFreeBorder(theBordFirstNode,theBordSecondNode,theBordLastNode,
7689                       nSide[0], eSide[0])) {
7690     MESSAGE(" Free Border 1 not found " );
7691     aResult = SEW_BORDER1_NOT_FOUND;
7692   }
7693   if (theSideIsFreeBorder) {
7694     // Free border 2
7695     // --------------
7696     if (!FindFreeBorder(theSideFirstNode, theSideSecondNode, theSideThirdNode,
7697                         nSide[1], eSide[1])) {
7698       MESSAGE(" Free Border 2 not found " );
7699       aResult = ( aResult != SEW_OK ? SEW_BOTH_BORDERS_NOT_FOUND : SEW_BORDER2_NOT_FOUND );
7700     }
7701   }
7702   if ( aResult != SEW_OK )
7703     return aResult;
7704
7705   if (!theSideIsFreeBorder) {
7706     // Side 2
7707     // --------------
7708
7709     // -------------------------------------------------------------------------
7710     // Algo:
7711     // 1. If nodes to merge are not coincident, move nodes of the free border
7712     //    from the coord sys defined by the direction from the first to last
7713     //    nodes of the border to the correspondent sys of the side 2
7714     // 2. On the side 2, find the links most co-directed with the correspondent
7715     //    links of the free border
7716     // -------------------------------------------------------------------------
7717
7718     // 1. Since sewing may brake if there are volumes to split on the side 2,
7719     //    we wont move nodes but just compute new coordinates for them
7720     typedef map<const SMDS_MeshNode*, gp_XYZ> TNodeXYZMap;
7721     TNodeXYZMap nBordXYZ;
7722     list< const SMDS_MeshNode* >& bordNodes = nSide[ 0 ];
7723     list< const SMDS_MeshNode* >::iterator nBordIt;
7724
7725     gp_XYZ Pb1( theBordFirstNode->X(), theBordFirstNode->Y(), theBordFirstNode->Z() );
7726     gp_XYZ Pb2( theBordLastNode->X(), theBordLastNode->Y(), theBordLastNode->Z() );
7727     gp_XYZ Ps1( theSideFirstNode->X(), theSideFirstNode->Y(), theSideFirstNode->Z() );
7728     gp_XYZ Ps2( theSideSecondNode->X(), theSideSecondNode->Y(), theSideSecondNode->Z() );
7729     double tol2 = 1.e-8;
7730     gp_Vec Vbs1( Pb1 - Ps1 ),Vbs2( Pb2 - Ps2 );
7731     if ( Vbs1.SquareMagnitude() > tol2 || Vbs2.SquareMagnitude() > tol2 ) {
7732       // Need node movement.
7733
7734       // find X and Z axes to create trsf
7735       gp_Vec Zb( Pb1 - Pb2 ), Zs( Ps1 - Ps2 );
7736       gp_Vec X = Zs ^ Zb;
7737       if ( X.SquareMagnitude() <= gp::Resolution() * gp::Resolution() )
7738         // Zb || Zs
7739         X = gp_Ax2( gp::Origin(), Zb ).XDirection();
7740
7741       // coord systems
7742       gp_Ax3 toBordAx( Pb1, Zb, X );
7743       gp_Ax3 fromSideAx( Ps1, Zs, X );
7744       gp_Ax3 toGlobalAx( gp::Origin(), gp::DZ(), gp::DX() );
7745       // set trsf
7746       gp_Trsf toBordSys, fromSide2Sys;
7747       toBordSys.SetTransformation( toBordAx );
7748       fromSide2Sys.SetTransformation( fromSideAx, toGlobalAx );
7749       fromSide2Sys.SetScaleFactor( Zs.Magnitude() / Zb.Magnitude() );
7750
7751       // move
7752       for ( nBordIt = bordNodes.begin(); nBordIt != bordNodes.end(); nBordIt++ ) {
7753         const SMDS_MeshNode* n = *nBordIt;
7754         gp_XYZ xyz( n->X(),n->Y(),n->Z() );
7755         toBordSys.Transforms( xyz );
7756         fromSide2Sys.Transforms( xyz );
7757         nBordXYZ.insert( TNodeXYZMap::value_type( n, xyz ));
7758       }
7759     }
7760     else {
7761       // just insert nodes XYZ in the nBordXYZ map
7762       for ( nBordIt = bordNodes.begin(); nBordIt != bordNodes.end(); nBordIt++ ) {
7763         const SMDS_MeshNode* n = *nBordIt;
7764         nBordXYZ.insert( TNodeXYZMap::value_type( n, gp_XYZ( n->X(),n->Y(),n->Z() )));
7765       }
7766     }
7767
7768     // 2. On the side 2, find the links most co-directed with the correspondent
7769     //    links of the free border
7770
7771     list< const SMDS_MeshElement* >& sideElems = eSide[ 1 ];
7772     list< const SMDS_MeshNode* >& sideNodes = nSide[ 1 ];
7773     sideNodes.push_back( theSideFirstNode );
7774
7775     bool hasVolumes = false;
7776     LinkID_Gen aLinkID_Gen( GetMeshDS() );
7777     set<long> foundSideLinkIDs, checkedLinkIDs;
7778     SMDS_VolumeTool volume;
7779     //const SMDS_MeshNode* faceNodes[ 4 ];
7780
7781     const SMDS_MeshNode*    sideNode;
7782     const SMDS_MeshElement* sideElem;
7783     const SMDS_MeshNode* prevSideNode = theSideFirstNode;
7784     const SMDS_MeshNode* prevBordNode = theBordFirstNode;
7785     nBordIt = bordNodes.begin();
7786     nBordIt++;
7787     // border node position and border link direction to compare with
7788     gp_XYZ bordPos = nBordXYZ[ *nBordIt ];
7789     gp_XYZ bordDir = bordPos - nBordXYZ[ prevBordNode ];
7790     // choose next side node by link direction or by closeness to
7791     // the current border node:
7792     bool searchByDir = ( *nBordIt != theBordLastNode );
7793     do {
7794       // find the next node on the Side 2
7795       sideNode = 0;
7796       double maxDot = -DBL_MAX, minDist = DBL_MAX;
7797       long linkID;
7798       checkedLinkIDs.clear();
7799       gp_XYZ prevXYZ( prevSideNode->X(), prevSideNode->Y(), prevSideNode->Z() );
7800
7801       // loop on inverse elements of current node (prevSideNode) on the Side 2
7802       SMDS_ElemIteratorPtr invElemIt = prevSideNode->GetInverseElementIterator();
7803       while ( invElemIt->more() )
7804       {
7805         const SMDS_MeshElement* elem = invElemIt->next();
7806         // prepare data for a loop on links coming to prevSideNode, of a face or a volume
7807         int iPrevNode, iNode = 0, nbNodes = elem->NbNodes();
7808         vector< const SMDS_MeshNode* > faceNodes( nbNodes, (const SMDS_MeshNode*)0 );
7809         bool isVolume = volume.Set( elem );
7810         const SMDS_MeshNode** nodes = isVolume ? volume.GetNodes() : & faceNodes[0];
7811         if ( isVolume ) // --volume
7812           hasVolumes = true;
7813         else if ( elem->GetType()==SMDSAbs_Face ) { // --face
7814           // retrieve all face nodes and find iPrevNode - an index of the prevSideNode
7815           if(elem->IsQuadratic()) {
7816             const SMDS_QuadraticFaceOfNodes* F =
7817               static_cast<const SMDS_QuadraticFaceOfNodes*>(elem);
7818             // use special nodes iterator
7819             SMDS_NodeIteratorPtr anIter = F->interlacedNodesIterator();
7820             while( anIter->more() ) {
7821               nodes[ iNode ] = anIter->next();
7822               if ( nodes[ iNode++ ] == prevSideNode )
7823                 iPrevNode = iNode - 1;
7824             }
7825           }
7826           else {
7827             SMDS_ElemIteratorPtr nIt = elem->nodesIterator();
7828             while ( nIt->more() ) {
7829               nodes[ iNode ] = cast2Node( nIt->next() );
7830               if ( nodes[ iNode++ ] == prevSideNode )
7831                 iPrevNode = iNode - 1;
7832             }
7833           }
7834           // there are 2 links to check
7835           nbNodes = 2;
7836         }
7837         else // --edge
7838           continue;
7839         // loop on links, to be precise, on the second node of links
7840         for ( iNode = 0; iNode < nbNodes; iNode++ ) {
7841           const SMDS_MeshNode* n = nodes[ iNode ];
7842           if ( isVolume ) {
7843             if ( !volume.IsLinked( n, prevSideNode ))
7844               continue;
7845           }
7846           else {
7847             if ( iNode ) // a node before prevSideNode
7848               n = nodes[ iPrevNode == 0 ? elem->NbNodes() - 1 : iPrevNode - 1 ];
7849             else         // a node after prevSideNode
7850               n = nodes[ iPrevNode + 1 == elem->NbNodes() ? 0 : iPrevNode + 1 ];
7851           }
7852           // check if this link was already used
7853           long iLink = aLinkID_Gen.GetLinkID( prevSideNode, n );
7854           bool isJustChecked = !checkedLinkIDs.insert( iLink ).second;
7855           if (!isJustChecked &&
7856               foundSideLinkIDs.find( iLink ) == foundSideLinkIDs.end() )
7857           {
7858             // test a link geometrically
7859             gp_XYZ nextXYZ ( n->X(), n->Y(), n->Z() );
7860             bool linkIsBetter = false;
7861             double dot = 0.0, dist = 0.0;
7862             if ( searchByDir ) { // choose most co-directed link
7863               dot = bordDir * ( nextXYZ - prevXYZ ).Normalized();
7864               linkIsBetter = ( dot > maxDot );
7865             }
7866             else { // choose link with the node closest to bordPos
7867               dist = ( nextXYZ - bordPos ).SquareModulus();
7868               linkIsBetter = ( dist < minDist );
7869             }
7870             if ( linkIsBetter ) {
7871               maxDot = dot;
7872               minDist = dist;
7873               linkID = iLink;
7874               sideNode = n;
7875               sideElem = elem;
7876             }
7877           }
7878         }
7879       } // loop on inverse elements of prevSideNode
7880
7881       if ( !sideNode ) {
7882         MESSAGE(" Cant find path by links of the Side 2 ");
7883         return SEW_BAD_SIDE_NODES;
7884       }
7885       sideNodes.push_back( sideNode );
7886       sideElems.push_back( sideElem );
7887       foundSideLinkIDs.insert ( linkID );
7888       prevSideNode = sideNode;
7889
7890       if ( *nBordIt == theBordLastNode )
7891         searchByDir = false;
7892       else {
7893         // find the next border link to compare with
7894         gp_XYZ sidePos( sideNode->X(), sideNode->Y(), sideNode->Z() );
7895         searchByDir = ( bordDir * ( sidePos - bordPos ) <= 0 );
7896         // move to next border node if sideNode is before forward border node (bordPos)
7897         while ( *nBordIt != theBordLastNode && !searchByDir ) {
7898           prevBordNode = *nBordIt;
7899           nBordIt++;
7900           bordPos = nBordXYZ[ *nBordIt ];
7901           bordDir = bordPos - nBordXYZ[ prevBordNode ];
7902           searchByDir = ( bordDir * ( sidePos - bordPos ) <= 0 );
7903         }
7904       }
7905     }
7906     while ( sideNode != theSideSecondNode );
7907
7908     if ( hasVolumes && sideNodes.size () != bordNodes.size() && !toCreatePolyedrs) {
7909       MESSAGE("VOLUME SPLITTING IS FORBIDDEN");
7910       return SEW_VOLUMES_TO_SPLIT; // volume splitting is forbidden
7911     }
7912   } // end nodes search on the side 2
7913
7914   // ============================
7915   // sew the border to the side 2
7916   // ============================
7917
7918   int nbNodes[]  = { nSide[0].size(), nSide[1].size() };
7919   int maxNbNodes = Max( nbNodes[0], nbNodes[1] );
7920
7921   TListOfListOfNodes nodeGroupsToMerge;
7922   if ( nbNodes[0] == nbNodes[1] ||
7923        ( theSideIsFreeBorder && !theSideThirdNode)) {
7924
7925     // all nodes are to be merged
7926
7927     for (nIt[0] = nSide[0].begin(), nIt[1] = nSide[1].begin();
7928          nIt[0] != nSide[0].end() && nIt[1] != nSide[1].end();
7929          nIt[0]++, nIt[1]++ )
7930     {
7931       nodeGroupsToMerge.push_back( list<const SMDS_MeshNode*>() );
7932       nodeGroupsToMerge.back().push_back( *nIt[1] ); // to keep
7933       nodeGroupsToMerge.back().push_back( *nIt[0] ); // to remove
7934     }
7935   }
7936   else {
7937
7938     // insert new nodes into the border and the side to get equal nb of segments
7939
7940     // get normalized parameters of nodes on the borders
7941     //double param[ 2 ][ maxNbNodes ];
7942     double* param[ 2 ];
7943     param[0] = new double [ maxNbNodes ];
7944     param[1] = new double [ maxNbNodes ];
7945     int iNode, iBord;
7946     for ( iBord = 0; iBord < 2; iBord++ ) { // loop on 2 borders
7947       list< const SMDS_MeshNode* >& nodes = nSide[ iBord ];
7948       list< const SMDS_MeshNode* >::iterator nIt = nodes.begin();
7949       const SMDS_MeshNode* nPrev = *nIt;
7950       double bordLength = 0;
7951       for ( iNode = 0; nIt != nodes.end(); nIt++, iNode++ ) { // loop on border nodes
7952         const SMDS_MeshNode* nCur = *nIt;
7953         gp_XYZ segment (nCur->X() - nPrev->X(),
7954                         nCur->Y() - nPrev->Y(),
7955                         nCur->Z() - nPrev->Z());
7956         double segmentLen = segment.Modulus();
7957         bordLength += segmentLen;
7958         param[ iBord ][ iNode ] = bordLength;
7959         nPrev = nCur;
7960       }
7961       // normalize within [0,1]
7962       for ( iNode = 0; iNode < nbNodes[ iBord ]; iNode++ ) {
7963         param[ iBord ][ iNode ] /= bordLength;
7964       }
7965     }
7966
7967     // loop on border segments
7968     const SMDS_MeshNode *nPrev[ 2 ] = { 0, 0 };
7969     int i[ 2 ] = { 0, 0 };
7970     nIt[0] = nSide[0].begin(); eIt[0] = eSide[0].begin();
7971     nIt[1] = nSide[1].begin(); eIt[1] = eSide[1].begin();
7972
7973     TElemOfNodeListMap insertMap;
7974     TElemOfNodeListMap::iterator insertMapIt;
7975     // insertMap is
7976     // key:   elem to insert nodes into
7977     // value: 2 nodes to insert between + nodes to be inserted
7978     do {
7979       bool next[ 2 ] = { false, false };
7980
7981       // find min adjacent segment length after sewing
7982       double nextParam = 10., prevParam = 0;
7983       for ( iBord = 0; iBord < 2; iBord++ ) { // loop on 2 borders
7984         if ( i[ iBord ] + 1 < nbNodes[ iBord ])
7985           nextParam = Min( nextParam, param[iBord][ i[iBord] + 1 ]);
7986         if ( i[ iBord ] > 0 )
7987           prevParam = Max( prevParam, param[iBord][ i[iBord] - 1 ]);
7988       }
7989       double minParam = Min( param[ 0 ][ i[0] ], param[ 1 ][ i[1] ]);
7990       double maxParam = Max( param[ 0 ][ i[0] ], param[ 1 ][ i[1] ]);
7991       double minSegLen = Min( nextParam - minParam, maxParam - prevParam );
7992
7993       // choose to insert or to merge nodes
7994       double du = param[ 1 ][ i[1] ] - param[ 0 ][ i[0] ];
7995       if ( Abs( du ) <= minSegLen * 0.2 ) {
7996         // merge
7997         // ------
7998         nodeGroupsToMerge.push_back( list<const SMDS_MeshNode*>() );
7999         const SMDS_MeshNode* n0 = *nIt[0];
8000         const SMDS_MeshNode* n1 = *nIt[1];
8001         nodeGroupsToMerge.back().push_back( n1 );
8002         nodeGroupsToMerge.back().push_back( n0 );
8003         // position of node of the border changes due to merge
8004         param[ 0 ][ i[0] ] += du;
8005         // move n1 for the sake of elem shape evaluation during insertion.
8006         // n1 will be removed by MergeNodes() anyway
8007         const_cast<SMDS_MeshNode*>( n0 )->setXYZ( n1->X(), n1->Y(), n1->Z() );
8008         next[0] = next[1] = true;
8009       }
8010       else {
8011         // insert
8012         // ------
8013         int intoBord = ( du < 0 ) ? 0 : 1;
8014         const SMDS_MeshElement* elem = *eIt[ intoBord ];
8015         const SMDS_MeshNode*    n1   = nPrev[ intoBord ];
8016         const SMDS_MeshNode*    n2   = *nIt[ intoBord ];
8017         const SMDS_MeshNode*    nIns = *nIt[ 1 - intoBord ];
8018         if ( intoBord == 1 ) {
8019           // move node of the border to be on a link of elem of the side
8020           gp_XYZ p1 (n1->X(), n1->Y(), n1->Z());
8021           gp_XYZ p2 (n2->X(), n2->Y(), n2->Z());
8022           double ratio = du / ( param[ 1 ][ i[1] ] - param[ 1 ][ i[1]-1 ]);
8023           gp_XYZ p = p2 * ( 1 - ratio ) + p1 * ratio;
8024           GetMeshDS()->MoveNode( nIns, p.X(), p.Y(), p.Z() );
8025         }
8026         insertMapIt = insertMap.find( elem );
8027         bool notFound = ( insertMapIt == insertMap.end() );
8028         bool otherLink = ( !notFound && (*insertMapIt).second.front() != n1 );
8029         if ( otherLink ) {
8030           // insert into another link of the same element:
8031           // 1. perform insertion into the other link of the elem
8032           list<const SMDS_MeshNode*> & nodeList = (*insertMapIt).second;
8033           const SMDS_MeshNode* n12 = nodeList.front(); nodeList.pop_front();
8034           const SMDS_MeshNode* n22 = nodeList.front(); nodeList.pop_front();
8035           InsertNodesIntoLink( elem, n12, n22, nodeList, toCreatePolygons );
8036           // 2. perform insertion into the link of adjacent faces
8037           while (true) {
8038             const SMDS_MeshElement* adjElem = findAdjacentFace( n12, n22, elem );
8039             if ( adjElem )
8040               InsertNodesIntoLink( adjElem, n12, n22, nodeList, toCreatePolygons );
8041             else
8042               break;
8043           }
8044           if (toCreatePolyedrs) {
8045             // perform insertion into the links of adjacent volumes
8046             UpdateVolumes(n12, n22, nodeList);
8047           }
8048           // 3. find an element appeared on n1 and n2 after the insertion
8049           insertMap.erase( elem );
8050           elem = findAdjacentFace( n1, n2, 0 );
8051         }
8052         if ( notFound || otherLink ) {
8053           // add element and nodes of the side into the insertMap
8054           insertMapIt = insertMap.insert
8055             ( TElemOfNodeListMap::value_type( elem, list<const SMDS_MeshNode*>() )).first;
8056           (*insertMapIt).second.push_back( n1 );
8057           (*insertMapIt).second.push_back( n2 );
8058         }
8059         // add node to be inserted into elem
8060         (*insertMapIt).second.push_back( nIns );
8061         next[ 1 - intoBord ] = true;
8062       }
8063
8064       // go to the next segment
8065       for ( iBord = 0; iBord < 2; iBord++ ) { // loop on 2 borders
8066         if ( next[ iBord ] ) {
8067           if ( i[ iBord ] != 0 && eIt[ iBord ] != eSide[ iBord ].end())
8068             eIt[ iBord ]++;
8069           nPrev[ iBord ] = *nIt[ iBord ];
8070           nIt[ iBord ]++; i[ iBord ]++;
8071         }
8072       }
8073     }
8074     while ( nIt[0] != nSide[0].end() && nIt[1] != nSide[1].end());
8075
8076     // perform insertion of nodes into elements
8077
8078     for (insertMapIt = insertMap.begin();
8079          insertMapIt != insertMap.end();
8080          insertMapIt++ )
8081     {
8082       const SMDS_MeshElement* elem = (*insertMapIt).first;
8083       list<const SMDS_MeshNode*> & nodeList = (*insertMapIt).second;
8084       const SMDS_MeshNode* n1 = nodeList.front(); nodeList.pop_front();
8085       const SMDS_MeshNode* n2 = nodeList.front(); nodeList.pop_front();
8086
8087       InsertNodesIntoLink( elem, n1, n2, nodeList, toCreatePolygons );
8088
8089       if ( !theSideIsFreeBorder ) {
8090         // look for and insert nodes into the faces adjacent to elem
8091         while (true) {
8092           const SMDS_MeshElement* adjElem = findAdjacentFace( n1, n2, elem );
8093           if ( adjElem )
8094             InsertNodesIntoLink( adjElem, n1, n2, nodeList, toCreatePolygons );
8095           else
8096             break;
8097         }
8098       }
8099       if (toCreatePolyedrs) {
8100         // perform insertion into the links of adjacent volumes
8101         UpdateVolumes(n1, n2, nodeList);
8102       }
8103     }
8104
8105     delete param[0];
8106     delete param[1];
8107   } // end: insert new nodes
8108
8109   MergeNodes ( nodeGroupsToMerge );
8110
8111   return aResult;
8112 }
8113
8114 //=======================================================================
8115 //function : InsertNodesIntoLink
8116 //purpose  : insert theNodesToInsert into theFace between theBetweenNode1
8117 //           and theBetweenNode2 and split theElement
8118 //=======================================================================
8119
8120 void SMESH_MeshEditor::InsertNodesIntoLink(const SMDS_MeshElement*     theFace,
8121                                            const SMDS_MeshNode*        theBetweenNode1,
8122                                            const SMDS_MeshNode*        theBetweenNode2,
8123                                            list<const SMDS_MeshNode*>& theNodesToInsert,
8124                                            const bool                  toCreatePoly)
8125 {
8126   if ( theFace->GetType() != SMDSAbs_Face ) return;
8127
8128   // find indices of 2 link nodes and of the rest nodes
8129   int iNode = 0, il1, il2, i3, i4;
8130   il1 = il2 = i3 = i4 = -1;
8131   //const SMDS_MeshNode* nodes[ theFace->NbNodes() ];
8132   vector<const SMDS_MeshNode*> nodes( theFace->NbNodes() );
8133
8134   if(theFace->IsQuadratic()) {
8135     const SMDS_QuadraticFaceOfNodes* F =
8136       static_cast<const SMDS_QuadraticFaceOfNodes*>(theFace);
8137     // use special nodes iterator
8138     SMDS_NodeIteratorPtr anIter = F->interlacedNodesIterator();
8139     while( anIter->more() ) {
8140       const SMDS_MeshNode* n = anIter->next();
8141       if ( n == theBetweenNode1 )
8142         il1 = iNode;
8143       else if ( n == theBetweenNode2 )
8144         il2 = iNode;
8145       else if ( i3 < 0 )
8146         i3 = iNode;
8147       else
8148         i4 = iNode;
8149       nodes[ iNode++ ] = n;
8150     }
8151   }
8152   else {
8153     SMDS_ElemIteratorPtr nodeIt = theFace->nodesIterator();
8154     while ( nodeIt->more() ) {
8155       const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
8156       if ( n == theBetweenNode1 )
8157         il1 = iNode;
8158       else if ( n == theBetweenNode2 )
8159         il2 = iNode;
8160       else if ( i3 < 0 )
8161         i3 = iNode;
8162       else
8163         i4 = iNode;
8164       nodes[ iNode++ ] = n;
8165     }
8166   }
8167   if ( il1 < 0 || il2 < 0 || i3 < 0 )
8168     return ;
8169
8170   // arrange link nodes to go one after another regarding the face orientation
8171   bool reverse = ( Abs( il2 - il1 ) == 1 ? il2 < il1 : il1 < il2 );
8172   list<const SMDS_MeshNode *> aNodesToInsert = theNodesToInsert;
8173   if ( reverse ) {
8174     iNode = il1;
8175     il1 = il2;
8176     il2 = iNode;
8177     aNodesToInsert.reverse();
8178   }
8179   // check that not link nodes of a quadrangles are in good order
8180   int nbFaceNodes = theFace->NbNodes();
8181   if ( nbFaceNodes == 4 && i4 - i3 != 1 ) {
8182     iNode = i3;
8183     i3 = i4;
8184     i4 = iNode;
8185   }
8186
8187   if (toCreatePoly || theFace->IsPoly()) {
8188
8189     iNode = 0;
8190     vector<const SMDS_MeshNode *> poly_nodes (nbFaceNodes + aNodesToInsert.size());
8191
8192     // add nodes of face up to first node of link
8193     bool isFLN = false;
8194
8195     if(theFace->IsQuadratic()) {
8196       const SMDS_QuadraticFaceOfNodes* F =
8197         static_cast<const SMDS_QuadraticFaceOfNodes*>(theFace);
8198       // use special nodes iterator
8199       SMDS_NodeIteratorPtr anIter = F->interlacedNodesIterator();
8200       while( anIter->more()  && !isFLN ) {
8201         const SMDS_MeshNode* n = anIter->next();
8202         poly_nodes[iNode++] = n;
8203         if (n == nodes[il1]) {
8204           isFLN = true;
8205         }
8206       }
8207       // add nodes to insert
8208       list<const SMDS_MeshNode*>::iterator nIt = aNodesToInsert.begin();
8209       for (; nIt != aNodesToInsert.end(); nIt++) {
8210         poly_nodes[iNode++] = *nIt;
8211       }
8212       // add nodes of face starting from last node of link
8213       while ( anIter->more() ) {
8214         poly_nodes[iNode++] = anIter->next();
8215       }
8216     }
8217     else {
8218       SMDS_ElemIteratorPtr nodeIt = theFace->nodesIterator();
8219       while ( nodeIt->more() && !isFLN ) {
8220         const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
8221         poly_nodes[iNode++] = n;
8222         if (n == nodes[il1]) {
8223           isFLN = true;
8224         }
8225       }
8226       // add nodes to insert
8227       list<const SMDS_MeshNode*>::iterator nIt = aNodesToInsert.begin();
8228       for (; nIt != aNodesToInsert.end(); nIt++) {
8229         poly_nodes[iNode++] = *nIt;
8230       }
8231       // add nodes of face starting from last node of link
8232       while ( nodeIt->more() ) {
8233         const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
8234         poly_nodes[iNode++] = n;
8235       }
8236     }
8237
8238     // edit or replace the face
8239     SMESHDS_Mesh *aMesh = GetMeshDS();
8240
8241     if (theFace->IsPoly()) {
8242       aMesh->ChangePolygonNodes(theFace, poly_nodes);
8243     }
8244     else {
8245       int aShapeId = FindShape( theFace );
8246
8247       SMDS_MeshElement* newElem = aMesh->AddPolygonalFace(poly_nodes);
8248       myLastCreatedElems.Append(newElem);
8249       if ( aShapeId && newElem )
8250         aMesh->SetMeshElementOnShape( newElem, aShapeId );
8251
8252       aMesh->RemoveElement(theFace);
8253     }
8254     return;
8255   }
8256
8257   if( !theFace->IsQuadratic() ) {
8258
8259     // put aNodesToInsert between theBetweenNode1 and theBetweenNode2
8260     int nbLinkNodes = 2 + aNodesToInsert.size();
8261     //const SMDS_MeshNode* linkNodes[ nbLinkNodes ];
8262     vector<const SMDS_MeshNode*> linkNodes( nbLinkNodes );
8263     linkNodes[ 0 ] = nodes[ il1 ];
8264     linkNodes[ nbLinkNodes - 1 ] = nodes[ il2 ];
8265     list<const SMDS_MeshNode*>::iterator nIt = aNodesToInsert.begin();
8266     for ( iNode = 1; nIt != aNodesToInsert.end(); nIt++ ) {
8267       linkNodes[ iNode++ ] = *nIt;
8268     }
8269     // decide how to split a quadrangle: compare possible variants
8270     // and choose which of splits to be a quadrangle
8271     int i1, i2, iSplit, nbSplits = nbLinkNodes - 1, iBestQuad;
8272     if ( nbFaceNodes == 3 ) {
8273       iBestQuad = nbSplits;
8274       i4 = i3;
8275     }
8276     else if ( nbFaceNodes == 4 ) {
8277       SMESH::Controls::NumericalFunctorPtr aCrit( new SMESH::Controls::AspectRatio);
8278       double aBestRate = DBL_MAX;
8279       for ( int iQuad = 0; iQuad < nbSplits; iQuad++ ) {
8280         i1 = 0; i2 = 1;
8281         double aBadRate = 0;
8282         // evaluate elements quality
8283         for ( iSplit = 0; iSplit < nbSplits; iSplit++ ) {
8284           if ( iSplit == iQuad ) {
8285             SMDS_FaceOfNodes quad (linkNodes[ i1++ ],
8286                                    linkNodes[ i2++ ],
8287                                    nodes[ i3 ],
8288                                    nodes[ i4 ]);
8289             aBadRate += getBadRate( &quad, aCrit );
8290           }
8291           else {
8292             SMDS_FaceOfNodes tria (linkNodes[ i1++ ],
8293                                    linkNodes[ i2++ ],
8294                                    nodes[ iSplit < iQuad ? i4 : i3 ]);
8295             aBadRate += getBadRate( &tria, aCrit );
8296           }
8297         }
8298         // choice
8299         if ( aBadRate < aBestRate ) {
8300           iBestQuad = iQuad;
8301           aBestRate = aBadRate;
8302         }
8303       }
8304     }
8305
8306     // create new elements
8307     SMESHDS_Mesh *aMesh = GetMeshDS();
8308     int aShapeId = FindShape( theFace );
8309
8310     i1 = 0; i2 = 1;
8311     for ( iSplit = 0; iSplit < nbSplits - 1; iSplit++ ) {
8312       SMDS_MeshElement* newElem = 0;
8313       if ( iSplit == iBestQuad )
8314         newElem = aMesh->AddFace (linkNodes[ i1++ ],
8315                                   linkNodes[ i2++ ],
8316                                   nodes[ i3 ],
8317                                   nodes[ i4 ]);
8318       else
8319         newElem = aMesh->AddFace (linkNodes[ i1++ ],
8320                                   linkNodes[ i2++ ],
8321                                   nodes[ iSplit < iBestQuad ? i4 : i3 ]);
8322       myLastCreatedElems.Append(newElem);
8323       if ( aShapeId && newElem )
8324         aMesh->SetMeshElementOnShape( newElem, aShapeId );
8325     }
8326
8327     // change nodes of theFace
8328     const SMDS_MeshNode* newNodes[ 4 ];
8329     newNodes[ 0 ] = linkNodes[ i1 ];
8330     newNodes[ 1 ] = linkNodes[ i2 ];
8331     newNodes[ 2 ] = nodes[ iSplit >= iBestQuad ? i3 : i4 ];
8332     newNodes[ 3 ] = nodes[ i4 ];
8333     aMesh->ChangeElementNodes( theFace, newNodes, iSplit == iBestQuad ? 4 : 3 );
8334   } // end if(!theFace->IsQuadratic())
8335   else { // theFace is quadratic
8336     // we have to split theFace on simple triangles and one simple quadrangle
8337     int tmp = il1/2;
8338     int nbshift = tmp*2;
8339     // shift nodes in nodes[] by nbshift
8340     int i,j;
8341     for(i=0; i<nbshift; i++) {
8342       const SMDS_MeshNode* n = nodes[0];
8343       for(j=0; j<nbFaceNodes-1; j++) {
8344         nodes[j] = nodes[j+1];
8345       }
8346       nodes[nbFaceNodes-1] = n;
8347     }
8348     il1 = il1 - nbshift;
8349     // now have to insert nodes between n0 and n1 or n1 and n2 (see below)
8350     //   n0      n1     n2    n0      n1     n2
8351     //     +-----+-----+        +-----+-----+
8352     //      \         /         |           |
8353     //       \       /          |           |
8354     //      n5+     +n3       n7+           +n3
8355     //         \   /            |           |
8356     //          \ /             |           |
8357     //           +              +-----+-----+
8358     //           n4           n6      n5     n4
8359
8360     // create new elements
8361     SMESHDS_Mesh *aMesh = GetMeshDS();
8362     int aShapeId = FindShape( theFace );
8363
8364     int n1,n2,n3;
8365     if(nbFaceNodes==6) { // quadratic triangle
8366       SMDS_MeshElement* newElem =
8367         aMesh->AddFace(nodes[3],nodes[4],nodes[5]);
8368       myLastCreatedElems.Append(newElem);
8369       if ( aShapeId && newElem )
8370         aMesh->SetMeshElementOnShape( newElem, aShapeId );
8371       if(theFace->IsMediumNode(nodes[il1])) {
8372         // create quadrangle
8373         newElem = aMesh->AddFace(nodes[0],nodes[1],nodes[3],nodes[5]);
8374         myLastCreatedElems.Append(newElem);
8375         if ( aShapeId && newElem )
8376           aMesh->SetMeshElementOnShape( newElem, aShapeId );
8377         n1 = 1;
8378         n2 = 2;
8379         n3 = 3;
8380       }
8381       else {
8382         // create quadrangle
8383         newElem = aMesh->AddFace(nodes[1],nodes[2],nodes[3],nodes[5]);
8384         myLastCreatedElems.Append(newElem);
8385         if ( aShapeId && newElem )
8386           aMesh->SetMeshElementOnShape( newElem, aShapeId );
8387         n1 = 0;
8388         n2 = 1;
8389         n3 = 5;
8390       }
8391     }
8392     else { // nbFaceNodes==8 - quadratic quadrangle
8393       SMDS_MeshElement* newElem =
8394         aMesh->AddFace(nodes[3],nodes[4],nodes[5]);
8395       myLastCreatedElems.Append(newElem);
8396       if ( aShapeId && newElem )
8397         aMesh->SetMeshElementOnShape( newElem, aShapeId );
8398       newElem = aMesh->AddFace(nodes[5],nodes[6],nodes[7]);
8399       myLastCreatedElems.Append(newElem);
8400       if ( aShapeId && newElem )
8401         aMesh->SetMeshElementOnShape( newElem, aShapeId );
8402       newElem = aMesh->AddFace(nodes[5],nodes[7],nodes[3]);
8403       myLastCreatedElems.Append(newElem);
8404       if ( aShapeId && newElem )
8405         aMesh->SetMeshElementOnShape( newElem, aShapeId );
8406       if(theFace->IsMediumNode(nodes[il1])) {
8407         // create quadrangle
8408         newElem = aMesh->AddFace(nodes[0],nodes[1],nodes[3],nodes[7]);
8409         myLastCreatedElems.Append(newElem);
8410         if ( aShapeId && newElem )
8411           aMesh->SetMeshElementOnShape( newElem, aShapeId );
8412         n1 = 1;
8413         n2 = 2;
8414         n3 = 3;
8415       }
8416       else {
8417         // create quadrangle
8418         newElem = aMesh->AddFace(nodes[1],nodes[2],nodes[3],nodes[7]);
8419         myLastCreatedElems.Append(newElem);
8420         if ( aShapeId && newElem )
8421           aMesh->SetMeshElementOnShape( newElem, aShapeId );
8422         n1 = 0;
8423         n2 = 1;
8424         n3 = 7;
8425       }
8426     }
8427     // create needed triangles using n1,n2,n3 and inserted nodes
8428     int nbn = 2 + aNodesToInsert.size();
8429     //const SMDS_MeshNode* aNodes[nbn];
8430     vector<const SMDS_MeshNode*> aNodes(nbn);
8431     aNodes[0] = nodes[n1];
8432     aNodes[nbn-1] = nodes[n2];
8433     list<const SMDS_MeshNode*>::iterator nIt = aNodesToInsert.begin();
8434     for ( iNode = 1; nIt != aNodesToInsert.end(); nIt++ ) {
8435       aNodes[iNode++] = *nIt;
8436     }
8437     for(i=1; i<nbn; i++) {
8438       SMDS_MeshElement* newElem =
8439         aMesh->AddFace(aNodes[i-1],aNodes[i],nodes[n3]);
8440       myLastCreatedElems.Append(newElem);
8441       if ( aShapeId && newElem )
8442         aMesh->SetMeshElementOnShape( newElem, aShapeId );
8443     }
8444     // remove old quadratic face
8445     aMesh->RemoveElement(theFace);
8446   }
8447 }
8448
8449 //=======================================================================
8450 //function : UpdateVolumes
8451 //purpose  :
8452 //=======================================================================
8453 void SMESH_MeshEditor::UpdateVolumes (const SMDS_MeshNode*        theBetweenNode1,
8454                                       const SMDS_MeshNode*        theBetweenNode2,
8455                                       list<const SMDS_MeshNode*>& theNodesToInsert)
8456 {
8457   myLastCreatedElems.Clear();
8458   myLastCreatedNodes.Clear();
8459
8460   SMDS_ElemIteratorPtr invElemIt = theBetweenNode1->GetInverseElementIterator(SMDSAbs_Volume);
8461   while (invElemIt->more()) { // loop on inverse elements of theBetweenNode1
8462     const SMDS_MeshElement* elem = invElemIt->next();
8463
8464     // check, if current volume has link theBetweenNode1 - theBetweenNode2
8465     SMDS_VolumeTool aVolume (elem);
8466     if (!aVolume.IsLinked(theBetweenNode1, theBetweenNode2))
8467       continue;
8468
8469     // insert new nodes in all faces of the volume, sharing link theBetweenNode1 - theBetweenNode2
8470     int iface, nbFaces = aVolume.NbFaces();
8471     vector<const SMDS_MeshNode *> poly_nodes;
8472     vector<int> quantities (nbFaces);
8473
8474     for (iface = 0; iface < nbFaces; iface++) {
8475       int nbFaceNodes = aVolume.NbFaceNodes(iface), nbInserted = 0;
8476       // faceNodes will contain (nbFaceNodes + 1) nodes, last = first
8477       const SMDS_MeshNode** faceNodes = aVolume.GetFaceNodes(iface);
8478
8479       for (int inode = 0; inode < nbFaceNodes; inode++) {
8480         poly_nodes.push_back(faceNodes[inode]);
8481
8482         if (nbInserted == 0) {
8483           if (faceNodes[inode] == theBetweenNode1) {
8484             if (faceNodes[inode + 1] == theBetweenNode2) {
8485               nbInserted = theNodesToInsert.size();
8486
8487               // add nodes to insert
8488               list<const SMDS_MeshNode*>::iterator nIt = theNodesToInsert.begin();
8489               for (; nIt != theNodesToInsert.end(); nIt++) {
8490                 poly_nodes.push_back(*nIt);
8491               }
8492             }
8493           }
8494           else if (faceNodes[inode] == theBetweenNode2) {
8495             if (faceNodes[inode + 1] == theBetweenNode1) {
8496               nbInserted = theNodesToInsert.size();
8497
8498               // add nodes to insert in reversed order
8499               list<const SMDS_MeshNode*>::iterator nIt = theNodesToInsert.end();
8500               nIt--;
8501               for (; nIt != theNodesToInsert.begin(); nIt--) {
8502                 poly_nodes.push_back(*nIt);
8503               }
8504               poly_nodes.push_back(*nIt);
8505             }
8506           }
8507           else {
8508           }
8509         }
8510       }
8511       quantities[iface] = nbFaceNodes + nbInserted;
8512     }
8513
8514     // Replace or update the volume
8515     SMESHDS_Mesh *aMesh = GetMeshDS();
8516
8517     if (elem->IsPoly()) {
8518       aMesh->ChangePolyhedronNodes(elem, poly_nodes, quantities);
8519
8520     }
8521     else {
8522       int aShapeId = FindShape( elem );
8523
8524       SMDS_MeshElement* newElem =
8525         aMesh->AddPolyhedralVolume(poly_nodes, quantities);
8526       myLastCreatedElems.Append(newElem);
8527       if (aShapeId && newElem)
8528         aMesh->SetMeshElementOnShape(newElem, aShapeId);
8529
8530       aMesh->RemoveElement(elem);
8531     }
8532   }
8533 }
8534
8535 //=======================================================================
8536 /*!
8537  * \brief Convert elements contained in a submesh to quadratic
8538  * \retval int - nb of checked elements
8539  */
8540 //=======================================================================
8541
8542 int SMESH_MeshEditor::convertElemToQuadratic(SMESHDS_SubMesh *   theSm,
8543                                              SMESH_MesherHelper& theHelper,
8544                                              const bool          theForce3d)
8545 {
8546   int nbElem = 0;
8547   if( !theSm ) return nbElem;
8548
8549   const bool notFromGroups = false;
8550   SMDS_ElemIteratorPtr ElemItr = theSm->GetElements();
8551   while(ElemItr->more())
8552   {
8553     nbElem++;
8554     const SMDS_MeshElement* elem = ElemItr->next();
8555     if( !elem || elem->IsQuadratic() ) continue;
8556
8557     int id = elem->GetID();
8558     int nbNodes = elem->NbNodes();
8559     vector<const SMDS_MeshNode *> aNds (nbNodes);
8560
8561     for(int i = 0; i < nbNodes; i++)
8562     {
8563       aNds[i] = elem->GetNode(i);
8564     }
8565     SMDSAbs_ElementType aType = elem->GetType();
8566
8567     GetMeshDS()->RemoveFreeElement(elem, theSm, notFromGroups);
8568
8569     const SMDS_MeshElement* NewElem = 0;
8570
8571     switch( aType )
8572     {
8573     case SMDSAbs_Edge :
8574       {
8575         NewElem = theHelper.AddEdge(aNds[0], aNds[1], id, theForce3d);
8576         break;
8577       }
8578     case SMDSAbs_Face :
8579       {
8580         switch(nbNodes)
8581         {
8582         case 3:
8583           NewElem = theHelper.AddFace(aNds[0], aNds[1], aNds[2], id, theForce3d);
8584           break;
8585         case 4:
8586           NewElem = theHelper.AddFace(aNds[0], aNds[1], aNds[2], aNds[3], id, theForce3d);
8587           break;
8588         default:
8589           continue;
8590         }
8591         break;
8592       }
8593     case SMDSAbs_Volume :
8594       {
8595         switch(nbNodes)
8596         {
8597         case 4:
8598           NewElem = theHelper.AddVolume(aNds[0], aNds[1], aNds[2], aNds[3], id, theForce3d);
8599           break;
8600         case 5:
8601           NewElem = theHelper.AddVolume(aNds[0], aNds[1], aNds[2], aNds[3], aNds[4], id, theForce3d);
8602           break;
8603         case 6:
8604           NewElem = theHelper.AddVolume(aNds[0], aNds[1], aNds[2], aNds[3], aNds[4], aNds[5], id, theForce3d);
8605           break;
8606         case 8:
8607           NewElem = theHelper.AddVolume(aNds[0], aNds[1], aNds[2], aNds[3],
8608                                         aNds[4], aNds[5], aNds[6], aNds[7], id, theForce3d);
8609           break;
8610         default:
8611           continue;
8612         }
8613         break;
8614       }
8615     default :
8616       continue;
8617     }
8618     ReplaceElemInGroups( elem, NewElem, GetMeshDS());
8619     if( NewElem )
8620       theSm->AddElement( NewElem );
8621   }
8622   return nbElem;
8623 }
8624
8625 //=======================================================================
8626 //function : ConvertToQuadratic
8627 //purpose  :
8628 //=======================================================================
8629 void SMESH_MeshEditor::ConvertToQuadratic(const bool theForce3d)
8630 {
8631   SMESHDS_Mesh* meshDS = GetMeshDS();
8632
8633   SMESH_MesherHelper aHelper(*myMesh);
8634   aHelper.SetIsQuadratic( true );
8635   const bool notFromGroups = false;
8636
8637   int nbCheckedElems = 0;
8638   if ( myMesh->HasShapeToMesh() )
8639   {
8640     if ( SMESH_subMesh *aSubMesh = myMesh->GetSubMeshContaining(myMesh->GetShapeToMesh()))
8641     {
8642       SMESH_subMeshIteratorPtr smIt = aSubMesh->getDependsOnIterator(true,false);
8643       while ( smIt->more() ) {
8644         SMESH_subMesh* sm = smIt->next();
8645         if ( SMESHDS_SubMesh *smDS = sm->GetSubMeshDS() ) {
8646           aHelper.SetSubShape( sm->GetSubShape() );
8647           nbCheckedElems += convertElemToQuadratic(smDS, aHelper, theForce3d);
8648         }
8649       }
8650     }
8651   }
8652   int totalNbElems = meshDS->NbEdges() + meshDS->NbFaces() + meshDS->NbVolumes();
8653   if ( nbCheckedElems < totalNbElems ) // not all elements are in submeshes
8654   {
8655     SMESHDS_SubMesh *smDS = 0;
8656     SMDS_EdgeIteratorPtr aEdgeItr = meshDS->edgesIterator();
8657     while(aEdgeItr->more())
8658     {
8659       const SMDS_MeshEdge* edge = aEdgeItr->next();
8660       if(edge && !edge->IsQuadratic())
8661       {
8662         int id = edge->GetID();
8663         const SMDS_MeshNode* n1 = edge->GetNode(0);
8664         const SMDS_MeshNode* n2 = edge->GetNode(1);
8665
8666         meshDS->RemoveFreeElement(edge, smDS, notFromGroups);
8667
8668         const SMDS_MeshEdge* NewEdge = aHelper.AddEdge(n1, n2, id, theForce3d);
8669         ReplaceElemInGroups( edge, NewEdge, GetMeshDS());
8670       }
8671     }
8672     SMDS_FaceIteratorPtr aFaceItr = meshDS->facesIterator();
8673     while(aFaceItr->more())
8674     {
8675       const SMDS_MeshFace* face = aFaceItr->next();
8676       if(!face || face->IsQuadratic() ) continue;
8677
8678       int id = face->GetID();
8679       int nbNodes = face->NbNodes();
8680       vector<const SMDS_MeshNode *> aNds (nbNodes);
8681
8682       for(int i = 0; i < nbNodes; i++)
8683       {
8684         aNds[i] = face->GetNode(i);
8685       }
8686
8687       meshDS->RemoveFreeElement(face, smDS, notFromGroups);
8688
8689       SMDS_MeshFace * NewFace = 0;
8690       switch(nbNodes)
8691       {
8692       case 3:
8693         NewFace = aHelper.AddFace(aNds[0], aNds[1], aNds[2], id, theForce3d);
8694         break;
8695       case 4:
8696         NewFace = aHelper.AddFace(aNds[0], aNds[1], aNds[2], aNds[3], id, theForce3d);
8697         break;
8698       default:
8699         continue;
8700       }
8701       ReplaceElemInGroups( face, NewFace, GetMeshDS());
8702     }
8703     SMDS_VolumeIteratorPtr aVolumeItr = meshDS->volumesIterator();
8704     while(aVolumeItr->more())
8705     {
8706       const SMDS_MeshVolume* volume = aVolumeItr->next();
8707       if(!volume || volume->IsQuadratic() ) continue;
8708
8709       int id = volume->GetID();
8710       int nbNodes = volume->NbNodes();
8711       vector<const SMDS_MeshNode *> aNds (nbNodes);
8712
8713       for(int i = 0; i < nbNodes; i++)
8714       {
8715         aNds[i] = volume->GetNode(i);
8716       }
8717
8718       meshDS->RemoveFreeElement(volume, smDS, notFromGroups);
8719
8720       SMDS_MeshVolume * NewVolume = 0;
8721       switch(nbNodes)
8722       {
8723       case 4:
8724         NewVolume = aHelper.AddVolume(aNds[0], aNds[1], aNds[2],
8725                                       aNds[3], id, theForce3d );
8726         break;
8727       case 5:
8728         NewVolume = aHelper.AddVolume(aNds[0], aNds[1], aNds[2],
8729                                       aNds[3], aNds[4], id, theForce3d);
8730         break;
8731       case 6:
8732         NewVolume = aHelper.AddVolume(aNds[0], aNds[1], aNds[2],
8733                                       aNds[3], aNds[4], aNds[5], id, theForce3d);
8734         break;
8735       case 8:
8736         NewVolume = aHelper.AddVolume(aNds[0], aNds[1], aNds[2], aNds[3],
8737                                       aNds[4], aNds[5], aNds[6], aNds[7], id, theForce3d);
8738         break;
8739       default:
8740         continue;
8741       }
8742       ReplaceElemInGroups(volume, NewVolume, meshDS);
8743     }
8744   }
8745   if ( !theForce3d ) {
8746     aHelper.SetSubShape(0); // apply to the whole mesh
8747     aHelper.FixQuadraticElements();
8748   }
8749 }
8750
8751 //=======================================================================
8752 /*!
8753  * \brief Convert quadratic elements to linear ones and remove quadratic nodes
8754  * \retval int - nb of checked elements
8755  */
8756 //=======================================================================
8757
8758 int SMESH_MeshEditor::removeQuadElem(SMESHDS_SubMesh *    theSm,
8759                                      SMDS_ElemIteratorPtr theItr,
8760                                      const int            theShapeID)
8761 {
8762   int nbElem = 0;
8763   SMESHDS_Mesh* meshDS = GetMeshDS();
8764   const bool notFromGroups = false;
8765
8766   while( theItr->more() )
8767   {
8768     const SMDS_MeshElement* elem = theItr->next();
8769     nbElem++;
8770     if( elem && elem->IsQuadratic())
8771     {
8772       int id = elem->GetID();
8773       int nbNodes = elem->NbNodes();
8774       vector<const SMDS_MeshNode *> aNds, mediumNodes;
8775       aNds.reserve( nbNodes );
8776       mediumNodes.reserve( nbNodes );
8777
8778       for(int i = 0; i < nbNodes; i++)
8779       {
8780         const SMDS_MeshNode* n = elem->GetNode(i);
8781
8782         if( elem->IsMediumNode( n ) )
8783           mediumNodes.push_back( n );
8784         else
8785           aNds.push_back( n );
8786       }
8787       if( aNds.empty() ) continue;
8788       SMDSAbs_ElementType aType = elem->GetType();
8789
8790       //remove old quadratic element
8791       meshDS->RemoveFreeElement( elem, theSm, notFromGroups );
8792
8793       SMDS_MeshElement * NewElem = AddElement( aNds, aType, false, id );
8794       ReplaceElemInGroups(elem, NewElem, meshDS);
8795       if( theSm && NewElem )
8796         theSm->AddElement( NewElem );
8797
8798       // remove medium nodes
8799       vector<const SMDS_MeshNode*>::iterator nIt = mediumNodes.begin();
8800       for ( ; nIt != mediumNodes.end(); ++nIt ) {
8801         const SMDS_MeshNode* n = *nIt;
8802         if ( n->NbInverseElements() == 0 ) {
8803           if ( n->GetPosition()->GetShapeId() != theShapeID )
8804             meshDS->RemoveFreeNode( n, meshDS->MeshElements
8805                                     ( n->GetPosition()->GetShapeId() ));
8806           else
8807             meshDS->RemoveFreeNode( n, theSm );
8808         }
8809       }
8810     }
8811   }
8812   return nbElem;
8813 }
8814
8815 //=======================================================================
8816 //function : ConvertFromQuadratic
8817 //purpose  :
8818 //=======================================================================
8819 bool  SMESH_MeshEditor::ConvertFromQuadratic()
8820 {
8821   int nbCheckedElems = 0;
8822   if ( myMesh->HasShapeToMesh() )
8823   {
8824     if ( SMESH_subMesh *aSubMesh = myMesh->GetSubMeshContaining(myMesh->GetShapeToMesh()))
8825     {
8826       SMESH_subMeshIteratorPtr smIt = aSubMesh->getDependsOnIterator(true,false);
8827       while ( smIt->more() ) {
8828         SMESH_subMesh* sm = smIt->next();
8829         if ( SMESHDS_SubMesh *smDS = sm->GetSubMeshDS() )
8830           nbCheckedElems += removeQuadElem( smDS, smDS->GetElements(), sm->GetId() );
8831       }
8832     }
8833   }
8834
8835   int totalNbElems =
8836     GetMeshDS()->NbEdges() + GetMeshDS()->NbFaces() + GetMeshDS()->NbVolumes();
8837   if ( nbCheckedElems < totalNbElems ) // not all elements are in submeshes
8838   {
8839     SMESHDS_SubMesh *aSM = 0;
8840     removeQuadElem( aSM, GetMeshDS()->elementsIterator(), 0 );
8841   }
8842
8843   return true;
8844 }
8845
8846 //=======================================================================
8847 //function : SewSideElements
8848 //purpose  :
8849 //=======================================================================
8850
8851 SMESH_MeshEditor::Sew_Error
8852 SMESH_MeshEditor::SewSideElements (TIDSortedElemSet&    theSide1,
8853                                    TIDSortedElemSet&    theSide2,
8854                                    const SMDS_MeshNode* theFirstNode1,
8855                                    const SMDS_MeshNode* theFirstNode2,
8856                                    const SMDS_MeshNode* theSecondNode1,
8857                                    const SMDS_MeshNode* theSecondNode2)
8858 {
8859   myLastCreatedElems.Clear();
8860   myLastCreatedNodes.Clear();
8861
8862   MESSAGE ("::::SewSideElements()");
8863   if ( theSide1.size() != theSide2.size() )
8864     return SEW_DIFF_NB_OF_ELEMENTS;
8865
8866   Sew_Error aResult = SEW_OK;
8867   // Algo:
8868   // 1. Build set of faces representing each side
8869   // 2. Find which nodes of the side 1 to merge with ones on the side 2
8870   // 3. Replace nodes in elements of the side 1 and remove replaced nodes
8871
8872   // =======================================================================
8873   // 1. Build set of faces representing each side:
8874   // =======================================================================
8875   // a. build set of nodes belonging to faces
8876   // b. complete set of faces: find missing fices whose nodes are in set of nodes
8877   // c. create temporary faces representing side of volumes if correspondent
8878   //    face does not exist
8879
8880   SMESHDS_Mesh* aMesh = GetMeshDS();
8881   SMDS_Mesh aTmpFacesMesh;
8882   set<const SMDS_MeshElement*> faceSet1, faceSet2;
8883   set<const SMDS_MeshElement*> volSet1,  volSet2;
8884   set<const SMDS_MeshNode*>    nodeSet1, nodeSet2;
8885   set<const SMDS_MeshElement*> * faceSetPtr[] = { &faceSet1, &faceSet2 };
8886   set<const SMDS_MeshElement*>  * volSetPtr[] = { &volSet1,  &volSet2  };
8887   set<const SMDS_MeshNode*>    * nodeSetPtr[] = { &nodeSet1, &nodeSet2 };
8888   TIDSortedElemSet * elemSetPtr[] = { &theSide1, &theSide2 };
8889   int iSide, iFace, iNode;
8890
8891   for ( iSide = 0; iSide < 2; iSide++ ) {
8892     set<const SMDS_MeshNode*>    * nodeSet = nodeSetPtr[ iSide ];
8893     TIDSortedElemSet * elemSet = elemSetPtr[ iSide ];
8894     set<const SMDS_MeshElement*> * faceSet = faceSetPtr[ iSide ];
8895     set<const SMDS_MeshElement*> * volSet  = volSetPtr [ iSide ];
8896     set<const SMDS_MeshElement*>::iterator vIt;
8897     TIDSortedElemSet::iterator eIt;
8898     set<const SMDS_MeshNode*>::iterator    nIt;
8899
8900     // check that given nodes belong to given elements
8901     const SMDS_MeshNode* n1 = ( iSide == 0 ) ? theFirstNode1 : theFirstNode2;
8902     const SMDS_MeshNode* n2 = ( iSide == 0 ) ? theSecondNode1 : theSecondNode2;
8903     int firstIndex = -1, secondIndex = -1;
8904     for (eIt = elemSet->begin(); eIt != elemSet->end(); eIt++ ) {
8905       const SMDS_MeshElement* elem = *eIt;
8906       if ( firstIndex  < 0 ) firstIndex  = elem->GetNodeIndex( n1 );
8907       if ( secondIndex < 0 ) secondIndex = elem->GetNodeIndex( n2 );
8908       if ( firstIndex > -1 && secondIndex > -1 ) break;
8909     }
8910     if ( firstIndex < 0 || secondIndex < 0 ) {
8911       // we can simply return until temporary faces created
8912       return (iSide == 0 ) ? SEW_BAD_SIDE1_NODES : SEW_BAD_SIDE2_NODES;
8913     }
8914
8915     // -----------------------------------------------------------
8916     // 1a. Collect nodes of existing faces
8917     //     and build set of face nodes in order to detect missing
8918     //     faces corresponing to sides of volumes
8919     // -----------------------------------------------------------
8920
8921     set< set <const SMDS_MeshNode*> > setOfFaceNodeSet;
8922
8923     // loop on the given element of a side
8924     for (eIt = elemSet->begin(); eIt != elemSet->end(); eIt++ ) {
8925       //const SMDS_MeshElement* elem = *eIt;
8926       const SMDS_MeshElement* elem = *eIt;
8927       if ( elem->GetType() == SMDSAbs_Face ) {
8928         faceSet->insert( elem );
8929         set <const SMDS_MeshNode*> faceNodeSet;
8930         SMDS_ElemIteratorPtr nodeIt = elem->nodesIterator();
8931         while ( nodeIt->more() ) {
8932           const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
8933           nodeSet->insert( n );
8934           faceNodeSet.insert( n );
8935         }
8936         setOfFaceNodeSet.insert( faceNodeSet );
8937       }
8938       else if ( elem->GetType() == SMDSAbs_Volume )
8939         volSet->insert( elem );
8940     }
8941     // ------------------------------------------------------------------------------
8942     // 1b. Complete set of faces: find missing fices whose nodes are in set of nodes
8943     // ------------------------------------------------------------------------------
8944
8945     for ( nIt = nodeSet->begin(); nIt != nodeSet->end(); nIt++ ) { // loop on nodes of iSide
8946       SMDS_ElemIteratorPtr fIt = (*nIt)->GetInverseElementIterator(SMDSAbs_Face);
8947       while ( fIt->more() ) { // loop on faces sharing a node
8948         const SMDS_MeshElement* f = fIt->next();
8949         if ( faceSet->find( f ) == faceSet->end() ) {
8950           // check if all nodes are in nodeSet and
8951           // complete setOfFaceNodeSet if they are
8952           set <const SMDS_MeshNode*> faceNodeSet;
8953           SMDS_ElemIteratorPtr nodeIt = f->nodesIterator();
8954           bool allInSet = true;
8955           while ( nodeIt->more() && allInSet ) { // loop on nodes of a face
8956             const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
8957             if ( nodeSet->find( n ) == nodeSet->end() )
8958               allInSet = false;
8959             else
8960               faceNodeSet.insert( n );
8961           }
8962           if ( allInSet ) {
8963             faceSet->insert( f );
8964             setOfFaceNodeSet.insert( faceNodeSet );
8965           }
8966         }
8967       }
8968     }
8969
8970     // -------------------------------------------------------------------------
8971     // 1c. Create temporary faces representing sides of volumes if correspondent
8972     //     face does not exist
8973     // -------------------------------------------------------------------------
8974
8975     if ( !volSet->empty() ) {
8976       //int nodeSetSize = nodeSet->size();
8977
8978       // loop on given volumes
8979       for ( vIt = volSet->begin(); vIt != volSet->end(); vIt++ ) {
8980         SMDS_VolumeTool vol (*vIt);
8981         // loop on volume faces: find free faces
8982         // --------------------------------------
8983         list<const SMDS_MeshElement* > freeFaceList;
8984         for ( iFace = 0; iFace < vol.NbFaces(); iFace++ ) {
8985           if ( !vol.IsFreeFace( iFace ))
8986             continue;
8987           // check if there is already a face with same nodes in a face set
8988           const SMDS_MeshElement* aFreeFace = 0;
8989           const SMDS_MeshNode** fNodes = vol.GetFaceNodes( iFace );
8990           int nbNodes = vol.NbFaceNodes( iFace );
8991           set <const SMDS_MeshNode*> faceNodeSet;
8992           vol.GetFaceNodes( iFace, faceNodeSet );
8993           bool isNewFace = setOfFaceNodeSet.insert( faceNodeSet ).second;
8994           if ( isNewFace ) {
8995             // no such a face is given but it still can exist, check it
8996             if ( nbNodes == 3 ) {
8997               aFreeFace = aMesh->FindFace( fNodes[0],fNodes[1],fNodes[2] );
8998             }
8999             else if ( nbNodes == 4 ) {
9000               aFreeFace = aMesh->FindFace( fNodes[0],fNodes[1],fNodes[2],fNodes[3] );
9001             }
9002             else {
9003               vector<const SMDS_MeshNode *> poly_nodes ( fNodes, & fNodes[nbNodes]);
9004               aFreeFace = aMesh->FindFace(poly_nodes);
9005             }
9006           }
9007           if ( !aFreeFace ) {
9008             // create a temporary face
9009             if ( nbNodes == 3 ) {
9010               aFreeFace = aTmpFacesMesh.AddFace( fNodes[0],fNodes[1],fNodes[2] );
9011             }
9012             else if ( nbNodes == 4 ) {
9013               aFreeFace = aTmpFacesMesh.AddFace( fNodes[0],fNodes[1],fNodes[2],fNodes[3] );
9014             }
9015             else {
9016               vector<const SMDS_MeshNode *> poly_nodes ( fNodes, & fNodes[nbNodes]);
9017               aFreeFace = aTmpFacesMesh.AddPolygonalFace(poly_nodes);
9018             }
9019           }
9020           if ( aFreeFace )
9021             freeFaceList.push_back( aFreeFace );
9022
9023         } // loop on faces of a volume
9024
9025         // choose one of several free faces
9026         // --------------------------------------
9027         if ( freeFaceList.size() > 1 ) {
9028           // choose a face having max nb of nodes shared by other elems of a side
9029           int maxNbNodes = -1/*, nbExcludedFaces = 0*/;
9030           list<const SMDS_MeshElement* >::iterator fIt = freeFaceList.begin();
9031           while ( fIt != freeFaceList.end() ) { // loop on free faces
9032             int nbSharedNodes = 0;
9033             SMDS_ElemIteratorPtr nodeIt = (*fIt)->nodesIterator();
9034             while ( nodeIt->more() ) { // loop on free face nodes
9035               const SMDS_MeshNode* n =
9036                 static_cast<const SMDS_MeshNode*>( nodeIt->next() );
9037               SMDS_ElemIteratorPtr invElemIt = n->GetInverseElementIterator();
9038               while ( invElemIt->more() ) {
9039                 const SMDS_MeshElement* e = invElemIt->next();
9040                 if ( faceSet->find( e ) != faceSet->end() )
9041                   nbSharedNodes++;
9042                 if ( elemSet->find( e ) != elemSet->end() )
9043                   nbSharedNodes++;
9044               }
9045             }
9046             if ( nbSharedNodes >= maxNbNodes ) {
9047               maxNbNodes = nbSharedNodes;
9048               fIt++;
9049             }
9050             else
9051               freeFaceList.erase( fIt++ ); // here fIt++ occures before erase
9052           }
9053           if ( freeFaceList.size() > 1 )
9054           {
9055             // could not choose one face, use another way
9056             // choose a face most close to the bary center of the opposite side
9057             gp_XYZ aBC( 0., 0., 0. );
9058             set <const SMDS_MeshNode*> addedNodes;
9059             TIDSortedElemSet * elemSet2 = elemSetPtr[ 1 - iSide ];
9060             eIt = elemSet2->begin();
9061             for ( eIt = elemSet2->begin(); eIt != elemSet2->end(); eIt++ ) {
9062               SMDS_ElemIteratorPtr nodeIt = (*eIt)->nodesIterator();
9063               while ( nodeIt->more() ) { // loop on free face nodes
9064                 const SMDS_MeshNode* n =
9065                   static_cast<const SMDS_MeshNode*>( nodeIt->next() );
9066                 if ( addedNodes.insert( n ).second )
9067                   aBC += gp_XYZ( n->X(),n->Y(),n->Z() );
9068               }
9069             }
9070             aBC /= addedNodes.size();
9071             double minDist = DBL_MAX;
9072             fIt = freeFaceList.begin();
9073             while ( fIt != freeFaceList.end() ) { // loop on free faces
9074               double dist = 0;
9075               SMDS_ElemIteratorPtr nodeIt = (*fIt)->nodesIterator();
9076               while ( nodeIt->more() ) { // loop on free face nodes
9077                 const SMDS_MeshNode* n =
9078                   static_cast<const SMDS_MeshNode*>( nodeIt->next() );
9079                 gp_XYZ p( n->X(),n->Y(),n->Z() );
9080                 dist += ( aBC - p ).SquareModulus();
9081               }
9082               if ( dist < minDist ) {
9083                 minDist = dist;
9084                 freeFaceList.erase( freeFaceList.begin(), fIt++ );
9085               }
9086               else
9087                 fIt = freeFaceList.erase( fIt++ );
9088             }
9089           }
9090         } // choose one of several free faces of a volume
9091
9092         if ( freeFaceList.size() == 1 ) {
9093           const SMDS_MeshElement* aFreeFace = freeFaceList.front();
9094           faceSet->insert( aFreeFace );
9095           // complete a node set with nodes of a found free face
9096           //           for ( iNode = 0; iNode < ; iNode++ )
9097           //             nodeSet->insert( fNodes[ iNode ] );
9098         }
9099
9100       } // loop on volumes of a side
9101
9102       //       // complete a set of faces if new nodes in a nodeSet appeared
9103       //       // ----------------------------------------------------------
9104       //       if ( nodeSetSize != nodeSet->size() ) {
9105       //         for ( ; nIt != nodeSet->end(); nIt++ ) { // loop on nodes of iSide
9106       //           SMDS_ElemIteratorPtr fIt = (*nIt)->GetInverseElementIterator(SMDSAbs_Face);
9107       //           while ( fIt->more() ) { // loop on faces sharing a node
9108       //             const SMDS_MeshElement* f = fIt->next();
9109       //             if ( faceSet->find( f ) == faceSet->end() ) {
9110       //               // check if all nodes are in nodeSet and
9111       //               // complete setOfFaceNodeSet if they are
9112       //               set <const SMDS_MeshNode*> faceNodeSet;
9113       //               SMDS_ElemIteratorPtr nodeIt = f->nodesIterator();
9114       //               bool allInSet = true;
9115       //               while ( nodeIt->more() && allInSet ) { // loop on nodes of a face
9116       //                 const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
9117       //                 if ( nodeSet->find( n ) == nodeSet->end() )
9118       //                   allInSet = false;
9119       //                 else
9120       //                   faceNodeSet.insert( n );
9121       //               }
9122       //               if ( allInSet ) {
9123       //                 faceSet->insert( f );
9124       //                 setOfFaceNodeSet.insert( faceNodeSet );
9125       //               }
9126       //             }
9127       //           }
9128       //         }
9129       //       }
9130     } // Create temporary faces, if there are volumes given
9131   } // loop on sides
9132
9133   if ( faceSet1.size() != faceSet2.size() ) {
9134     // delete temporary faces: they are in reverseElements of actual nodes
9135     SMDS_FaceIteratorPtr tmpFaceIt = aTmpFacesMesh.facesIterator();
9136     while ( tmpFaceIt->more() )
9137       aTmpFacesMesh.RemoveElement( tmpFaceIt->next() );
9138     MESSAGE("Diff nb of faces");
9139     return SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
9140   }
9141
9142   // ============================================================
9143   // 2. Find nodes to merge:
9144   //              bind a node to remove to a node to put instead
9145   // ============================================================
9146
9147   TNodeNodeMap nReplaceMap; // bind a node to remove to a node to put instead
9148   if ( theFirstNode1 != theFirstNode2 )
9149     nReplaceMap.insert( TNodeNodeMap::value_type( theFirstNode1, theFirstNode2 ));
9150   if ( theSecondNode1 != theSecondNode2 )
9151     nReplaceMap.insert( TNodeNodeMap::value_type( theSecondNode1, theSecondNode2 ));
9152
9153   LinkID_Gen aLinkID_Gen( GetMeshDS() );
9154   set< long > linkIdSet; // links to process
9155   linkIdSet.insert( aLinkID_Gen.GetLinkID( theFirstNode1, theSecondNode1 ));
9156
9157   typedef pair< const SMDS_MeshNode*, const SMDS_MeshNode* > NLink;
9158   list< NLink > linkList[2];
9159   linkList[0].push_back( NLink( theFirstNode1, theSecondNode1 ));
9160   linkList[1].push_back( NLink( theFirstNode2, theSecondNode2 ));
9161   // loop on links in linkList; find faces by links and append links
9162   // of the found faces to linkList
9163   list< NLink >::iterator linkIt[] = { linkList[0].begin(), linkList[1].begin() } ;
9164   for ( ; linkIt[0] != linkList[0].end(); linkIt[0]++, linkIt[1]++ ) {
9165     NLink link[] = { *linkIt[0], *linkIt[1] };
9166     long linkID = aLinkID_Gen.GetLinkID( link[0].first, link[0].second );
9167     if ( linkIdSet.find( linkID ) == linkIdSet.end() )
9168       continue;
9169
9170     // by links, find faces in the face sets,
9171     // and find indices of link nodes in the found faces;
9172     // in a face set, there is only one or no face sharing a link
9173     // ---------------------------------------------------------------
9174
9175     const SMDS_MeshElement* face[] = { 0, 0 };
9176     //const SMDS_MeshNode* faceNodes[ 2 ][ 5 ];
9177     vector<const SMDS_MeshNode*> fnodes1(9);
9178     vector<const SMDS_MeshNode*> fnodes2(9);
9179     //const SMDS_MeshNode* notLinkNodes[ 2 ][ 2 ] = {{ 0, 0 },{ 0, 0 }} ;
9180     vector<const SMDS_MeshNode*> notLinkNodes1(6);
9181     vector<const SMDS_MeshNode*> notLinkNodes2(6);
9182     int iLinkNode[2][2];
9183     for ( iSide = 0; iSide < 2; iSide++ ) { // loop on 2 sides
9184       const SMDS_MeshNode* n1 = link[iSide].first;
9185       const SMDS_MeshNode* n2 = link[iSide].second;
9186       set<const SMDS_MeshElement*> * faceSet = faceSetPtr[ iSide ];
9187       set< const SMDS_MeshElement* > fMap;
9188       for ( int i = 0; i < 2; i++ ) { // loop on 2 nodes of a link
9189         const SMDS_MeshNode* n = i ? n1 : n2; // a node of a link
9190         SMDS_ElemIteratorPtr fIt = n->GetInverseElementIterator(SMDSAbs_Face);
9191         while ( fIt->more() ) { // loop on faces sharing a node
9192           const SMDS_MeshElement* f = fIt->next();
9193           if (faceSet->find( f ) != faceSet->end() && // f is in face set
9194               ! fMap.insert( f ).second ) // f encounters twice
9195           {
9196             if ( face[ iSide ] ) {
9197               MESSAGE( "2 faces per link " );
9198               aResult = iSide ? SEW_BAD_SIDE2_NODES : SEW_BAD_SIDE1_NODES;
9199               break;
9200             }
9201             face[ iSide ] = f;
9202             faceSet->erase( f );
9203             // get face nodes and find ones of a link
9204             iNode = 0;
9205             int nbl = -1;
9206             if(f->IsPoly()) {
9207               if(iSide==0) {
9208                 fnodes1.resize(f->NbNodes()+1);
9209                 notLinkNodes1.resize(f->NbNodes()-2);
9210               }
9211               else {
9212                 fnodes2.resize(f->NbNodes()+1);
9213                 notLinkNodes2.resize(f->NbNodes()-2);
9214               }
9215             }
9216             if(!f->IsQuadratic()) {
9217               SMDS_ElemIteratorPtr nIt = f->nodesIterator();
9218               while ( nIt->more() ) {
9219                 const SMDS_MeshNode* n =
9220                   static_cast<const SMDS_MeshNode*>( nIt->next() );
9221                 if ( n == n1 ) {
9222                   iLinkNode[ iSide ][ 0 ] = iNode;
9223                 }
9224                 else if ( n == n2 ) {
9225                   iLinkNode[ iSide ][ 1 ] = iNode;
9226                 }
9227                 //else if ( notLinkNodes[ iSide ][ 0 ] )
9228                 //  notLinkNodes[ iSide ][ 1 ] = n;
9229                 //else
9230                 //  notLinkNodes[ iSide ][ 0 ] = n;
9231                 else {
9232                   nbl++;
9233                   if(iSide==0)
9234                     notLinkNodes1[nbl] = n;
9235                   //notLinkNodes1.push_back(n);
9236                   else
9237                     notLinkNodes2[nbl] = n;
9238                   //notLinkNodes2.push_back(n);
9239                 }
9240                 //faceNodes[ iSide ][ iNode++ ] = n;
9241                 if(iSide==0) {
9242                   fnodes1[iNode++] = n;
9243                 }
9244                 else {
9245                   fnodes2[iNode++] = n;
9246                 }
9247               }
9248             }
9249             else { // f->IsQuadratic()
9250               const SMDS_QuadraticFaceOfNodes* F =
9251                 static_cast<const SMDS_QuadraticFaceOfNodes*>(f);
9252               // use special nodes iterator
9253               SMDS_NodeIteratorPtr anIter = F->interlacedNodesIterator();
9254               while ( anIter->more() ) {
9255                 const SMDS_MeshNode* n =
9256                   static_cast<const SMDS_MeshNode*>( anIter->next() );
9257                 if ( n == n1 ) {
9258                   iLinkNode[ iSide ][ 0 ] = iNode;
9259                 }
9260                 else if ( n == n2 ) {
9261                   iLinkNode[ iSide ][ 1 ] = iNode;
9262                 }
9263                 else {
9264                   nbl++;
9265                   if(iSide==0) {
9266                     notLinkNodes1[nbl] = n;
9267                   }
9268                   else {
9269                     notLinkNodes2[nbl] = n;
9270                   }
9271                 }
9272                 if(iSide==0) {
9273                   fnodes1[iNode++] = n;
9274                 }
9275                 else {
9276                   fnodes2[iNode++] = n;
9277                 }
9278               }
9279             }
9280             //faceNodes[ iSide ][ iNode ] = faceNodes[ iSide ][ 0 ];
9281             if(iSide==0) {
9282               fnodes1[iNode] = fnodes1[0];
9283             }
9284             else {
9285               fnodes2[iNode] = fnodes1[0];
9286             }
9287           }
9288         }
9289       }
9290     }
9291
9292     // check similarity of elements of the sides
9293     if (aResult == SEW_OK && ( face[0] && !face[1] ) || ( !face[0] && face[1] )) {
9294       MESSAGE("Correspondent face not found on side " << ( face[0] ? 1 : 0 ));
9295       if ( nReplaceMap.size() == 2 ) { // faces on input nodes not found
9296         aResult = ( face[0] ? SEW_BAD_SIDE2_NODES : SEW_BAD_SIDE1_NODES );
9297       }
9298       else {
9299         aResult = SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
9300       }
9301       break; // do not return because it s necessary to remove tmp faces
9302     }
9303
9304     // set nodes to merge
9305     // -------------------
9306
9307     if ( face[0] && face[1] )  {
9308       int nbNodes = face[0]->NbNodes();
9309       if ( nbNodes != face[1]->NbNodes() ) {
9310         MESSAGE("Diff nb of face nodes");
9311         aResult = SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
9312         break; // do not return because it s necessary to remove tmp faces
9313       }
9314       bool reverse[] = { false, false }; // order of notLinkNodes of quadrangle
9315       if ( nbNodes == 3 ) {
9316         //nReplaceMap.insert( TNodeNodeMap::value_type
9317         //                   ( notLinkNodes[0][0], notLinkNodes[1][0] ));
9318         nReplaceMap.insert( TNodeNodeMap::value_type
9319                             ( notLinkNodes1[0], notLinkNodes2[0] ));
9320       }
9321       else {
9322         for ( iSide = 0; iSide < 2; iSide++ ) { // loop on 2 sides
9323           // analyse link orientation in faces
9324           int i1 = iLinkNode[ iSide ][ 0 ];
9325           int i2 = iLinkNode[ iSide ][ 1 ];
9326           reverse[ iSide ] = Abs( i1 - i2 ) == 1 ? i1 > i2 : i2 > i1;
9327           // if notLinkNodes are the first and the last ones, then
9328           // their order does not correspond to the link orientation
9329           if (( i1 == 1 && i2 == 2 ) ||
9330               ( i1 == 2 && i2 == 1 ))
9331             reverse[ iSide ] = !reverse[ iSide ];
9332         }
9333         if ( reverse[0] == reverse[1] ) {
9334           //nReplaceMap.insert( TNodeNodeMap::value_type
9335           //                   ( notLinkNodes[0][0], notLinkNodes[1][0] ));
9336           //nReplaceMap.insert( TNodeNodeMap::value_type
9337           //                   ( notLinkNodes[0][1], notLinkNodes[1][1] ));
9338           for(int nn=0; nn<nbNodes-2; nn++) {
9339             nReplaceMap.insert( TNodeNodeMap::value_type
9340                                 ( notLinkNodes1[nn], notLinkNodes2[nn] ));
9341           }
9342         }
9343         else {
9344           //nReplaceMap.insert( TNodeNodeMap::value_type
9345           //                   ( notLinkNodes[0][0], notLinkNodes[1][1] ));
9346           //nReplaceMap.insert( TNodeNodeMap::value_type
9347           //                   ( notLinkNodes[0][1], notLinkNodes[1][0] ));
9348           for(int nn=0; nn<nbNodes-2; nn++) {
9349             nReplaceMap.insert( TNodeNodeMap::value_type
9350                                 ( notLinkNodes1[nn], notLinkNodes2[nbNodes-3-nn] ));
9351           }
9352         }
9353       }
9354
9355       // add other links of the faces to linkList
9356       // -----------------------------------------
9357
9358       //const SMDS_MeshNode** nodes = faceNodes[ 0 ];
9359       for ( iNode = 0; iNode < nbNodes; iNode++ )  {
9360         //linkID = aLinkID_Gen.GetLinkID( nodes[iNode], nodes[iNode+1] );
9361         linkID = aLinkID_Gen.GetLinkID( fnodes1[iNode], fnodes1[iNode+1] );
9362         pair< set<long>::iterator, bool > iter_isnew = linkIdSet.insert( linkID );
9363         if ( !iter_isnew.second ) { // already in a set: no need to process
9364           linkIdSet.erase( iter_isnew.first );
9365         }
9366         else // new in set == encountered for the first time: add
9367         {
9368           //const SMDS_MeshNode* n1 = nodes[ iNode ];
9369           //const SMDS_MeshNode* n2 = nodes[ iNode + 1];
9370           const SMDS_MeshNode* n1 = fnodes1[ iNode ];
9371           const SMDS_MeshNode* n2 = fnodes1[ iNode + 1];
9372           linkList[0].push_back ( NLink( n1, n2 ));
9373           linkList[1].push_back ( NLink( nReplaceMap[n1], nReplaceMap[n2] ));
9374         }
9375       }
9376     } // 2 faces found
9377   } // loop on link lists
9378
9379   if ( aResult == SEW_OK &&
9380        ( linkIt[0] != linkList[0].end() ||
9381          !faceSetPtr[0]->empty() || !faceSetPtr[1]->empty() )) {
9382     MESSAGE( (linkIt[0] != linkList[0].end()) <<" "<< (faceSetPtr[0]->empty()) <<
9383              " " << (faceSetPtr[1]->empty()));
9384     aResult = SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
9385   }
9386
9387   // ====================================================================
9388   // 3. Replace nodes in elements of the side 1 and remove replaced nodes
9389   // ====================================================================
9390
9391   // delete temporary faces: they are in reverseElements of actual nodes
9392   SMDS_FaceIteratorPtr tmpFaceIt = aTmpFacesMesh.facesIterator();
9393   while ( tmpFaceIt->more() )
9394     aTmpFacesMesh.RemoveElement( tmpFaceIt->next() );
9395
9396   if ( aResult != SEW_OK)
9397     return aResult;
9398
9399   list< int > nodeIDsToRemove/*, elemIDsToRemove*/;
9400   // loop on nodes replacement map
9401   TNodeNodeMap::iterator nReplaceMapIt = nReplaceMap.begin(), nnIt;
9402   for ( ; nReplaceMapIt != nReplaceMap.end(); nReplaceMapIt++ )
9403     if ( (*nReplaceMapIt).first != (*nReplaceMapIt).second ) {
9404       const SMDS_MeshNode* nToRemove = (*nReplaceMapIt).first;
9405       nodeIDsToRemove.push_back( nToRemove->GetID() );
9406       // loop on elements sharing nToRemove
9407       SMDS_ElemIteratorPtr invElemIt = nToRemove->GetInverseElementIterator();
9408       while ( invElemIt->more() ) {
9409         const SMDS_MeshElement* e = invElemIt->next();
9410         // get a new suite of nodes: make replacement
9411         int nbReplaced = 0, i = 0, nbNodes = e->NbNodes();
9412         vector< const SMDS_MeshNode*> nodes( nbNodes );
9413         SMDS_ElemIteratorPtr nIt = e->nodesIterator();
9414         while ( nIt->more() ) {
9415           const SMDS_MeshNode* n =
9416             static_cast<const SMDS_MeshNode*>( nIt->next() );
9417           nnIt = nReplaceMap.find( n );
9418           if ( nnIt != nReplaceMap.end() ) {
9419             nbReplaced++;
9420             n = (*nnIt).second;
9421           }
9422           nodes[ i++ ] = n;
9423         }
9424         //       if ( nbReplaced == nbNodes && e->GetType() == SMDSAbs_Face )
9425         //         elemIDsToRemove.push_back( e->GetID() );
9426         //       else
9427         if ( nbReplaced )
9428           aMesh->ChangeElementNodes( e, & nodes[0], nbNodes );
9429       }
9430     }
9431
9432   Remove( nodeIDsToRemove, true );
9433
9434   return aResult;
9435 }
9436
9437 //================================================================================
9438 /*!
9439  * \brief Find corresponding nodes in two sets of faces
9440  * \param theSide1 - first face set
9441  * \param theSide2 - second first face
9442  * \param theFirstNode1 - a boundary node of set 1
9443  * \param theFirstNode2 - a node of set 2 corresponding to theFirstNode1
9444  * \param theSecondNode1 - a boundary node of set 1 linked with theFirstNode1
9445  * \param theSecondNode2 - a node of set 2 corresponding to theSecondNode1
9446  * \param nReplaceMap - output map of corresponding nodes
9447  * \retval bool  - is a success or not
9448  */
9449 //================================================================================
9450
9451 #ifdef _DEBUG_
9452 //#define DEBUG_MATCHING_NODES
9453 #endif
9454
9455 SMESH_MeshEditor::Sew_Error
9456 SMESH_MeshEditor::FindMatchingNodes(set<const SMDS_MeshElement*>& theSide1,
9457                                     set<const SMDS_MeshElement*>& theSide2,
9458                                     const SMDS_MeshNode*          theFirstNode1,
9459                                     const SMDS_MeshNode*          theFirstNode2,
9460                                     const SMDS_MeshNode*          theSecondNode1,
9461                                     const SMDS_MeshNode*          theSecondNode2,
9462                                     TNodeNodeMap &                nReplaceMap)
9463 {
9464   set<const SMDS_MeshElement*> * faceSetPtr[] = { &theSide1, &theSide2 };
9465
9466   nReplaceMap.clear();
9467   if ( theFirstNode1 != theFirstNode2 )
9468     nReplaceMap.insert( make_pair( theFirstNode1, theFirstNode2 ));
9469   if ( theSecondNode1 != theSecondNode2 )
9470     nReplaceMap.insert( make_pair( theSecondNode1, theSecondNode2 ));
9471
9472   set< SMESH_TLink > linkSet; // set of nodes where order of nodes is ignored
9473   linkSet.insert( SMESH_TLink( theFirstNode1, theSecondNode1 ));
9474
9475   list< NLink > linkList[2];
9476   linkList[0].push_back( NLink( theFirstNode1, theSecondNode1 ));
9477   linkList[1].push_back( NLink( theFirstNode2, theSecondNode2 ));
9478
9479   // loop on links in linkList; find faces by links and append links
9480   // of the found faces to linkList
9481   list< NLink >::iterator linkIt[] = { linkList[0].begin(), linkList[1].begin() } ;
9482   for ( ; linkIt[0] != linkList[0].end(); linkIt[0]++, linkIt[1]++ ) {
9483     NLink link[] = { *linkIt[0], *linkIt[1] };
9484     if ( linkSet.find( link[0] ) == linkSet.end() )
9485       continue;
9486
9487     // by links, find faces in the face sets,
9488     // and find indices of link nodes in the found faces;
9489     // in a face set, there is only one or no face sharing a link
9490     // ---------------------------------------------------------------
9491
9492     const SMDS_MeshElement* face[] = { 0, 0 };
9493     list<const SMDS_MeshNode*> notLinkNodes[2];
9494     //bool reverse[] = { false, false }; // order of notLinkNodes
9495     int nbNodes[2];
9496     for ( int iSide = 0; iSide < 2; iSide++ ) // loop on 2 sides
9497     {
9498       const SMDS_MeshNode* n1 = link[iSide].first;
9499       const SMDS_MeshNode* n2 = link[iSide].second;
9500       set<const SMDS_MeshElement*> * faceSet = faceSetPtr[ iSide ];
9501       set< const SMDS_MeshElement* > facesOfNode1;
9502       for ( int iNode = 0; iNode < 2; iNode++ ) // loop on 2 nodes of a link
9503       {
9504         // during a loop of the first node, we find all faces around n1,
9505         // during a loop of the second node, we find one face sharing both n1 and n2
9506         const SMDS_MeshNode* n = iNode ? n1 : n2; // a node of a link
9507         SMDS_ElemIteratorPtr fIt = n->GetInverseElementIterator(SMDSAbs_Face);
9508         while ( fIt->more() ) { // loop on faces sharing a node
9509           const SMDS_MeshElement* f = fIt->next();
9510           if (faceSet->find( f ) != faceSet->end() && // f is in face set
9511               ! facesOfNode1.insert( f ).second ) // f encounters twice
9512           {
9513             if ( face[ iSide ] ) {
9514               MESSAGE( "2 faces per link " );
9515               return ( iSide ? SEW_BAD_SIDE2_NODES : SEW_BAD_SIDE1_NODES );
9516             }
9517             face[ iSide ] = f;
9518             faceSet->erase( f );
9519
9520             // get not link nodes
9521             int nbN = f->NbNodes();
9522             if ( f->IsQuadratic() )
9523               nbN /= 2;
9524             nbNodes[ iSide ] = nbN;
9525             list< const SMDS_MeshNode* > & nodes = notLinkNodes[ iSide ];
9526             int i1 = f->GetNodeIndex( n1 );
9527             int i2 = f->GetNodeIndex( n2 );
9528             int iEnd = nbN, iBeg = -1, iDelta = 1;
9529             bool reverse = ( Abs( i1 - i2 ) == 1 ? i1 > i2 : i2 > i1 );
9530             if ( reverse ) {
9531               std::swap( iEnd, iBeg ); iDelta = -1;
9532             }
9533             int i = i2;
9534             while ( true ) {
9535               i += iDelta;
9536               if ( i == iEnd ) i = iBeg + iDelta;
9537               if ( i == i1 ) break;
9538               nodes.push_back ( f->GetNode( i ) );
9539             }
9540           }
9541         }
9542       }
9543     }
9544     // check similarity of elements of the sides
9545     if (( face[0] && !face[1] ) || ( !face[0] && face[1] )) {
9546       MESSAGE("Correspondent face not found on side " << ( face[0] ? 1 : 0 ));
9547       if ( nReplaceMap.size() == 2 ) { // faces on input nodes not found
9548         return ( face[0] ? SEW_BAD_SIDE2_NODES : SEW_BAD_SIDE1_NODES );
9549       }
9550       else {
9551         return SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
9552       }
9553     }
9554
9555     // set nodes to merge
9556     // -------------------
9557
9558     if ( face[0] && face[1] )  {
9559       if ( nbNodes[0] != nbNodes[1] ) {
9560         MESSAGE("Diff nb of face nodes");
9561         return SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
9562       }
9563 #ifdef DEBUG_MATCHING_NODES
9564       MESSAGE ( " Link 1: " << link[0].first->GetID() <<" "<< link[0].second->GetID()
9565                 << " F 1: " << face[0] << "| Link 2: " << link[1].first->GetID() <<" "
9566                 << link[1].second->GetID() << " F 2: " << face[1] << " | Bind: " ) ;
9567 #endif
9568       int nbN = nbNodes[0];
9569       {
9570         list<const SMDS_MeshNode*>::iterator n1 = notLinkNodes[0].begin();
9571         list<const SMDS_MeshNode*>::iterator n2 = notLinkNodes[1].begin();
9572         for ( int i = 0 ; i < nbN - 2; ++i ) {
9573 #ifdef DEBUG_MATCHING_NODES
9574           MESSAGE ( (*n1)->GetID() << " to " << (*n2)->GetID() );
9575 #endif
9576           nReplaceMap.insert( make_pair( *(n1++), *(n2++) ));
9577         }
9578       }
9579
9580       // add other links of the face 1 to linkList
9581       // -----------------------------------------
9582
9583       const SMDS_MeshElement* f0 = face[0];
9584       const SMDS_MeshNode* n1 = f0->GetNode( nbN - 1 );
9585       for ( int i = 0; i < nbN; i++ )
9586       {
9587         const SMDS_MeshNode* n2 = f0->GetNode( i );
9588         pair< set< SMESH_TLink >::iterator, bool > iter_isnew =
9589           linkSet.insert( SMESH_TLink( n1, n2 ));
9590         if ( !iter_isnew.second ) { // already in a set: no need to process
9591           linkSet.erase( iter_isnew.first );
9592         }
9593         else // new in set == encountered for the first time: add
9594         {
9595 #ifdef DEBUG_MATCHING_NODES
9596           MESSAGE ( "Add link 1: " << n1->GetID() << " " << n2->GetID() << " "
9597                     << " | link 2: " << nReplaceMap[n1]->GetID() << " " << nReplaceMap[n2]->GetID() << " " );
9598 #endif
9599           linkList[0].push_back ( NLink( n1, n2 ));
9600           linkList[1].push_back ( NLink( nReplaceMap[n1], nReplaceMap[n2] ));
9601         }
9602         n1 = n2;
9603       }
9604     } // 2 faces found
9605   } // loop on link lists
9606
9607   return SEW_OK;
9608 }
9609
9610 //================================================================================
9611 /*!
9612   \brief Creates a hole in a mesh by doubling the nodes of some particular elements
9613   \param theElems - the list of elements (edges or faces) to be replicated
9614   The nodes for duplication could be found from these elements
9615   \param theNodesNot - list of nodes to NOT replicate
9616   \param theAffectedElems - the list of elements (cells and edges) to which the 
9617   replicated nodes should be associated to.
9618   \return TRUE if operation has been completed successfully, FALSE otherwise
9619 */
9620 //================================================================================
9621
9622 bool SMESH_MeshEditor::DoubleNodes( const TIDSortedElemSet& theElems,
9623                                     const TIDSortedElemSet& theNodesNot,
9624                                     const TIDSortedElemSet& theAffectedElems )
9625 {
9626   myLastCreatedElems.Clear();
9627   myLastCreatedNodes.Clear();
9628
9629   if ( theElems.size() == 0 )
9630     return false;
9631
9632   SMESHDS_Mesh* aMeshDS = GetMeshDS();
9633   if ( !aMeshDS )
9634     return false;
9635
9636   bool res = false;
9637   std::map< const SMDS_MeshNode*, const SMDS_MeshNode* > anOldNodeToNewNode;
9638   // duplicate elements and nodes
9639   res = doubleNodes( aMeshDS, theElems, theNodesNot, anOldNodeToNewNode, true );
9640   // replce nodes by duplications
9641   res = doubleNodes( aMeshDS, theAffectedElems, theNodesNot, anOldNodeToNewNode, false );
9642   return res;
9643 }
9644
9645 //================================================================================
9646 /*!
9647   \brief Creates a hole in a mesh by doubling the nodes of some particular elements
9648   \param theMeshDS - mesh instance
9649   \param theElems - the elements replicated or modified (nodes should be changed)
9650   \param theNodesNot - nodes to NOT replicate
9651   \param theNodeNodeMap - relation of old node to new created node
9652   \param theIsDoubleElem - flag os to replicate element or modify
9653   \return TRUE if operation has been completed successfully, FALSE otherwise
9654 */
9655 //================================================================================
9656
9657 bool SMESH_MeshEditor::doubleNodes( SMESHDS_Mesh*     theMeshDS,
9658                                     const TIDSortedElemSet& theElems,
9659                                     const TIDSortedElemSet& theNodesNot,
9660                                     std::map< const SMDS_MeshNode*,
9661                                     const SMDS_MeshNode* >& theNodeNodeMap,
9662                                     const bool theIsDoubleElem )
9663 {
9664   // iterate on through element and duplicate them (by nodes duplication)
9665   bool res = false;
9666   TIDSortedElemSet::const_iterator elemItr = theElems.begin();
9667   for ( ;  elemItr != theElems.end(); ++elemItr )
9668   {
9669     const SMDS_MeshElement* anElem = *elemItr;
9670     if (!anElem)
9671       continue;
9672
9673     bool isDuplicate = false;
9674     // duplicate nodes to duplicate element
9675     std::vector<const SMDS_MeshNode*> newNodes( anElem->NbNodes() );
9676     SMDS_ElemIteratorPtr anIter = anElem->nodesIterator();
9677     int ind = 0;
9678     while ( anIter->more() ) 
9679     { 
9680
9681       SMDS_MeshNode* aCurrNode = (SMDS_MeshNode*)anIter->next();
9682       SMDS_MeshNode* aNewNode = aCurrNode;
9683       if ( theNodeNodeMap.find( aCurrNode ) != theNodeNodeMap.end() )
9684         aNewNode = (SMDS_MeshNode*)theNodeNodeMap[ aCurrNode ];
9685       else if ( theIsDoubleElem && theNodesNot.find( aCurrNode ) == theNodesNot.end() )
9686       {
9687         // duplicate node
9688         aNewNode = theMeshDS->AddNode( aCurrNode->X(), aCurrNode->Y(), aCurrNode->Z() );
9689         theNodeNodeMap[ aCurrNode ] = aNewNode;
9690         myLastCreatedNodes.Append( aNewNode );
9691       }
9692       isDuplicate |= (aCurrNode != aNewNode);
9693       newNodes[ ind++ ] = aNewNode;
9694     }
9695     if ( !isDuplicate )
9696       continue;
9697
9698     if ( theIsDoubleElem )
9699       myLastCreatedElems.Append( AddElement(newNodes, anElem->GetType(), anElem->IsPoly()) );
9700     else
9701       theMeshDS->ChangeElementNodes( anElem, &newNodes[ 0 ], anElem->NbNodes() );
9702
9703     res = true;
9704   }
9705   return res;
9706 }
9707
9708 //================================================================================
9709 /*!
9710   \brief Creates a hole in a mesh by doubling the nodes of some particular elements
9711   \param theNodes - identifiers of nodes to be doubled
9712   \param theModifiedElems - identifiers of elements to be updated by the new (doubled) 
9713          nodes. If list of element identifiers is empty then nodes are doubled but 
9714          they not assigned to elements
9715   \return TRUE if operation has been completed successfully, FALSE otherwise
9716 */
9717 //================================================================================
9718
9719 bool SMESH_MeshEditor::DoubleNodes( const std::list< int >& theListOfNodes, 
9720                                     const std::list< int >& theListOfModifiedElems )
9721 {
9722   myLastCreatedElems.Clear();
9723   myLastCreatedNodes.Clear();
9724
9725   if ( theListOfNodes.size() == 0 )
9726     return false;
9727
9728   SMESHDS_Mesh* aMeshDS = GetMeshDS();
9729   if ( !aMeshDS )
9730     return false;
9731
9732   // iterate through nodes and duplicate them
9733
9734   std::map< const SMDS_MeshNode*, const SMDS_MeshNode* > anOldNodeToNewNode;
9735
9736   std::list< int >::const_iterator aNodeIter;
9737   for ( aNodeIter = theListOfNodes.begin(); aNodeIter != theListOfNodes.end(); ++aNodeIter )
9738   {
9739     int aCurr = *aNodeIter;
9740     SMDS_MeshNode* aNode = (SMDS_MeshNode*)aMeshDS->FindNode( aCurr );
9741     if ( !aNode )
9742       continue;
9743
9744     // duplicate node
9745
9746     const SMDS_MeshNode* aNewNode = aMeshDS->AddNode( aNode->X(), aNode->Y(), aNode->Z() );
9747     if ( aNewNode )
9748     {
9749       anOldNodeToNewNode[ aNode ] = aNewNode;
9750       myLastCreatedNodes.Append( aNewNode );
9751     }
9752   }
9753
9754   // Create map of new nodes for modified elements
9755
9756   std::map< SMDS_MeshElement*, vector<const SMDS_MeshNode*> > anElemToNodes;
9757
9758   std::list< int >::const_iterator anElemIter;
9759   for ( anElemIter = theListOfModifiedElems.begin(); 
9760         anElemIter != theListOfModifiedElems.end(); ++anElemIter )
9761   {
9762     int aCurr = *anElemIter;
9763     SMDS_MeshElement* anElem = (SMDS_MeshElement*)aMeshDS->FindElement( aCurr );
9764     if ( !anElem )
9765       continue;
9766
9767     vector<const SMDS_MeshNode*> aNodeArr( anElem->NbNodes() );
9768
9769     SMDS_ElemIteratorPtr anIter = anElem->nodesIterator();
9770     int ind = 0;
9771     while ( anIter->more() ) 
9772     { 
9773       SMDS_MeshNode* aCurrNode = (SMDS_MeshNode*)anIter->next();
9774       if ( aCurr && anOldNodeToNewNode.find( aCurrNode ) != anOldNodeToNewNode.end() )
9775       {
9776         const SMDS_MeshNode* aNewNode = anOldNodeToNewNode[ aCurrNode ];
9777         aNodeArr[ ind++ ] = aNewNode;
9778       }
9779       else
9780         aNodeArr[ ind++ ] = aCurrNode;
9781     }
9782     anElemToNodes[ anElem ] = aNodeArr;
9783   }
9784
9785   // Change nodes of elements  
9786
9787   std::map< SMDS_MeshElement*, vector<const SMDS_MeshNode*> >::iterator
9788     anElemToNodesIter = anElemToNodes.begin();
9789   for ( ; anElemToNodesIter != anElemToNodes.end(); ++anElemToNodesIter )
9790   {
9791     const SMDS_MeshElement* anElem = anElemToNodesIter->first;
9792     vector<const SMDS_MeshNode*> aNodeArr = anElemToNodesIter->second;
9793     if ( anElem )
9794       aMeshDS->ChangeElementNodes( anElem, &aNodeArr[ 0 ], anElem->NbNodes() );
9795   }
9796
9797   return true;
9798 }
9799
9800 namespace {
9801
9802   //================================================================================
9803   /*!
9804   \brief Check if element located inside shape
9805   \return TRUE if IN or ON shape, FALSE otherwise
9806   */
9807   //================================================================================
9808
9809   template<class Classifier>
9810   bool isInside(const SMDS_MeshElement* theElem,
9811                 Classifier&             theClassifier,
9812                 const double            theTol)
9813   {
9814     gp_XYZ centerXYZ (0, 0, 0);
9815     SMDS_ElemIteratorPtr aNodeItr = theElem->nodesIterator();
9816     while (aNodeItr->more())
9817       centerXYZ += SMESH_MeshEditor::TNodeXYZ(cast2Node( aNodeItr->next()));
9818
9819     gp_Pnt aPnt = centerXYZ / theElem->NbNodes();
9820     theClassifier.Perform(aPnt, theTol);
9821     TopAbs_State aState = theClassifier.State();
9822     return (aState == TopAbs_IN || aState == TopAbs_ON );
9823   }
9824
9825   //================================================================================
9826   /*!
9827    * \brief Classifier of the 3D point on the TopoDS_Face
9828    *        with interaface suitable for isInside()
9829    */
9830   //================================================================================
9831
9832   struct _FaceClassifier
9833   {
9834     Extrema_ExtPS       _extremum;
9835     BRepAdaptor_Surface _surface;
9836     TopAbs_State        _state;
9837
9838     _FaceClassifier(const TopoDS_Face& face):_extremum(),_surface(face),_state(TopAbs_OUT)
9839     {
9840       _extremum.Initialize( _surface,
9841                             _surface.FirstUParameter(), _surface.LastUParameter(),
9842                             _surface.FirstVParameter(), _surface.LastVParameter(),
9843                             _surface.Tolerance(), _surface.Tolerance() );
9844     }
9845     void Perform(const gp_Pnt& aPnt, double theTol)
9846     {
9847       _state = TopAbs_OUT;
9848       _extremum.Perform(aPnt);
9849       if ( _extremum.IsDone() )
9850         for ( int iSol = 1; iSol <= _extremum.NbExt() && _state == TopAbs_OUT; ++iSol)
9851           _state = ( _extremum.Value(iSol) <= theTol ? TopAbs_IN : TopAbs_OUT );
9852     }
9853     TopAbs_State State() const
9854     {
9855       return _state;
9856     }
9857   };
9858 }
9859
9860 //================================================================================
9861 /*!
9862   \brief Creates a hole in a mesh by doubling the nodes of some particular elements
9863   \param theElems - group of of elements (edges or faces) to be replicated
9864   \param theNodesNot - group of nodes not to replicate
9865   \param theShape - shape to detect affected elements (element which geometric center
9866   located on or inside shape).
9867   The replicated nodes should be associated to affected elements.
9868   \return TRUE if operation has been completed successfully, FALSE otherwise
9869 */
9870 //================================================================================
9871
9872 bool SMESH_MeshEditor::DoubleNodesInRegion( const TIDSortedElemSet& theElems,
9873                                             const TIDSortedElemSet& theNodesNot,
9874                                             const TopoDS_Shape&     theShape )
9875 {
9876   if ( theShape.IsNull() )
9877     return false;
9878
9879   const double aTol = Precision::Confusion();
9880   auto_ptr< BRepClass3d_SolidClassifier> bsc3d;
9881   auto_ptr<_FaceClassifier>              aFaceClassifier;
9882   if ( theShape.ShapeType() == TopAbs_SOLID )
9883   {
9884     bsc3d.reset( new BRepClass3d_SolidClassifier(theShape));;
9885     bsc3d->PerformInfinitePoint(aTol);
9886   }
9887   else if (theShape.ShapeType() == TopAbs_FACE )
9888   {
9889     aFaceClassifier.reset( new _FaceClassifier(TopoDS::Face(theShape)));
9890   }
9891
9892   // iterates on indicated elements and get elements by back references from their nodes
9893   TIDSortedElemSet anAffected;
9894   TIDSortedElemSet::const_iterator elemItr = theElems.begin();
9895   for ( ;  elemItr != theElems.end(); ++elemItr )
9896   {
9897     SMDS_MeshElement* anElem = (SMDS_MeshElement*)*elemItr;
9898     if (!anElem)
9899       continue;
9900
9901     SMDS_ElemIteratorPtr nodeItr = anElem->nodesIterator();
9902     while ( nodeItr->more() )
9903     {
9904       const SMDS_MeshNode* aNode = cast2Node(nodeItr->next());
9905       if ( !aNode || theNodesNot.find(aNode) != theNodesNot.end() )
9906         continue;
9907       SMDS_ElemIteratorPtr backElemItr = aNode->GetInverseElementIterator();
9908       while ( backElemItr->more() )
9909       {
9910         const SMDS_MeshElement* curElem = backElemItr->next();
9911         if ( curElem && theElems.find(curElem) == theElems.end() &&
9912              ( bsc3d.get() ?
9913                isInside( curElem, *bsc3d, aTol ) :
9914                isInside( curElem, *aFaceClassifier, aTol )))
9915           anAffected.insert( curElem );
9916       }
9917     }
9918   }
9919   return DoubleNodes( theElems, theNodesNot, anAffected );
9920 }
9921
9922 //================================================================================
9923 /*!
9924  * \brief Generated skin mesh (containing 2D cells) from 3D mesh
9925  * The created 2D mesh elements based on nodes of free faces of boundary volumes
9926  * \return TRUE if operation has been completed successfully, FALSE otherwise
9927  */
9928 //================================================================================
9929
9930 bool SMESH_MeshEditor::Make2DMeshFrom3D()
9931 {
9932   // iterates on volume elements and detect all free faces on them
9933   SMESHDS_Mesh* aMesh = GetMeshDS();
9934   if (!aMesh)
9935     return false;
9936   //bool res = false;
9937   int nbFree = 0, nbExisted = 0, nbCreated = 0;
9938   SMDS_VolumeIteratorPtr vIt = aMesh->volumesIterator();
9939   while(vIt->more())
9940   {
9941     const SMDS_MeshVolume* volume = vIt->next();
9942     SMDS_VolumeTool vTool( volume );
9943     vTool.SetExternalNormal();
9944     const bool isPoly = volume->IsPoly();
9945     const bool isQuad = volume->IsQuadratic();
9946     for ( int iface = 0, n = vTool.NbFaces(); iface < n; iface++ )
9947     {
9948       if (!vTool.IsFreeFace(iface))
9949         continue;
9950       nbFree++;
9951       vector<const SMDS_MeshNode *> nodes;
9952       int nbFaceNodes = vTool.NbFaceNodes(iface);
9953       const SMDS_MeshNode** faceNodes = vTool.GetFaceNodes(iface);
9954       int inode = 0;
9955       for ( ; inode < nbFaceNodes; inode += isQuad ? 2 : 1)
9956         nodes.push_back(faceNodes[inode]);
9957       if (isQuad)
9958         for ( inode = 1; inode < nbFaceNodes; inode += 2)
9959           nodes.push_back(faceNodes[inode]);
9960
9961       // add new face based on volume nodes
9962       if (aMesh->FindFace( nodes ) ) {
9963         nbExisted++;
9964         continue; // face already exsist
9965       }
9966       myLastCreatedElems.Append( AddElement(nodes, SMDSAbs_Face, isPoly && iface == 1) );
9967       nbCreated++;
9968     }
9969   }
9970   return ( nbFree==(nbExisted+nbCreated) );
9971 }