]> SALOME platform Git repositories - modules/smesh.git/blob - src/SMESH/SMESH_MeshEditor.cxx
Salome HOME
Rever incorrect integration!!! from 13.09.2009 into the V5_1_main
[modules/smesh.git] / src / SMESH / SMESH_MeshEditor.cxx
1 //  Copyright (C) 2007-2010  CEA/DEN, EDF R&D, OPEN CASCADE
2 //
3 //  Copyright (C) 2003-2007  OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN,
4 //  CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS
5 //
6 //  This library is free software; you can redistribute it and/or
7 //  modify it under the terms of the GNU Lesser General Public
8 //  License as published by the Free Software Foundation; either
9 //  version 2.1 of the License.
10 //
11 //  This library is distributed in the hope that it will be useful,
12 //  but WITHOUT ANY WARRANTY; without even the implied warranty of
13 //  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14 //  Lesser General Public License for more details.
15 //
16 //  You should have received a copy of the GNU Lesser General Public
17 //  License along with this library; if not, write to the Free Software
18 //  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
19 //
20 //  See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
21 //
22
23 //  SMESH SMESH : idl implementation based on 'SMESH' unit's classes
24 // File      : SMESH_MeshEditor.cxx
25 // Created   : Mon Apr 12 16:10:22 2004
26 // Author    : Edward AGAPOV (eap)
27 //
28 #include "SMESH_MeshEditor.hxx"
29
30 #include "SMDS_FaceOfNodes.hxx"
31 #include "SMDS_VolumeTool.hxx"
32 #include "SMDS_EdgePosition.hxx"
33 #include "SMDS_PolyhedralVolumeOfNodes.hxx"
34 #include "SMDS_FacePosition.hxx"
35 #include "SMDS_SpacePosition.hxx"
36 #include "SMDS_QuadraticFaceOfNodes.hxx"
37 #include "SMDS_MeshGroup.hxx"
38 #include "SMDS_SetIterator.hxx"
39
40 #include "SMESHDS_Group.hxx"
41 #include "SMESHDS_Mesh.hxx"
42
43 #include "SMESH_Algo.hxx"
44 #include "SMESH_ControlsDef.hxx"
45 #include "SMESH_Group.hxx"
46 #include "SMESH_MesherHelper.hxx"
47 #include "SMESH_OctreeNode.hxx"
48 #include "SMESH_subMesh.hxx"
49
50 #include "utilities.h"
51
52 #include <BRepAdaptor_Surface.hxx>
53 #include <BRepClass3d_SolidClassifier.hxx>
54 #include <BRep_Tool.hxx>
55 #include <ElCLib.hxx>
56 #include <Extrema_GenExtPS.hxx>
57 #include <Extrema_POnCurv.hxx>
58 #include <Extrema_POnSurf.hxx>
59 #include <GC_MakeSegment.hxx>
60 #include <Geom2d_Curve.hxx>
61 #include <GeomAPI_ExtremaCurveCurve.hxx>
62 #include <GeomAdaptor_Surface.hxx>
63 #include <Geom_Curve.hxx>
64 #include <Geom_Line.hxx>
65 #include <Geom_Surface.hxx>
66 #include <IntAna_IntConicQuad.hxx>
67 #include <IntAna_Quadric.hxx>
68 #include <Precision.hxx>
69 #include <TColStd_ListOfInteger.hxx>
70 #include <TopAbs_State.hxx>
71 #include <TopExp.hxx>
72 #include <TopExp_Explorer.hxx>
73 #include <TopTools_ListIteratorOfListOfShape.hxx>
74 #include <TopTools_ListOfShape.hxx>
75 #include <TopTools_SequenceOfShape.hxx>
76 #include <TopoDS.hxx>
77 #include <TopoDS_Face.hxx>
78 #include <gp.hxx>
79 #include <gp_Ax1.hxx>
80 #include <gp_Dir.hxx>
81 #include <gp_Lin.hxx>
82 #include <gp_Pln.hxx>
83 #include <gp_Trsf.hxx>
84 #include <gp_Vec.hxx>
85 #include <gp_XY.hxx>
86 #include <gp_XYZ.hxx>
87
88 #include <math.h>
89
90 #include <map>
91 #include <set>
92 #include <numeric>
93 #include <limits>
94
95 #define cast2Node(elem) static_cast<const SMDS_MeshNode*>( elem )
96
97 using namespace std;
98 using namespace SMESH::Controls;
99
100 typedef map<const SMDS_MeshElement*, list<const SMDS_MeshNode*> >    TElemOfNodeListMap;
101 typedef map<const SMDS_MeshElement*, list<const SMDS_MeshElement*> > TElemOfElemListMap;
102
103 typedef SMDS_SetIterator< SMDS_pElement, TIDSortedElemSet::const_iterator> TSetIterator;
104
105 //=======================================================================
106 //function : SMESH_MeshEditor
107 //purpose  :
108 //=======================================================================
109
110 SMESH_MeshEditor::SMESH_MeshEditor( SMESH_Mesh* theMesh )
111   :myMesh( theMesh ) // theMesh may be NULL
112 {
113 }
114
115 //=======================================================================
116 /*!
117  * \brief Add element
118  */
119 //=======================================================================
120
121 SMDS_MeshElement*
122 SMESH_MeshEditor::AddElement(const vector<const SMDS_MeshNode*> & node,
123                              const SMDSAbs_ElementType            type,
124                              const bool                           isPoly,
125                              const int                            ID)
126 {
127   SMDS_MeshElement* e = 0;
128   int nbnode = node.size();
129   SMESHDS_Mesh* mesh = GetMeshDS();
130   switch ( type ) {
131   case SMDSAbs_0DElement:
132     if ( nbnode == 1 )
133       if ( ID ) e = mesh->Add0DElementWithID(node[0], ID);
134       else      e = mesh->Add0DElement      (node[0] );
135     break;
136   case SMDSAbs_Edge:
137     if ( nbnode == 2 )
138       if ( ID ) e = mesh->AddEdgeWithID(node[0], node[1], ID);
139       else      e = mesh->AddEdge      (node[0], node[1] );
140     else if ( nbnode == 3 )
141       if ( ID ) e = mesh->AddEdgeWithID(node[0], node[1], node[2], ID);
142       else      e = mesh->AddEdge      (node[0], node[1], node[2] );
143     break;
144   case SMDSAbs_Face:
145     if ( !isPoly ) {
146       if      (nbnode == 3)
147         if ( ID ) e = mesh->AddFaceWithID(node[0], node[1], node[2], ID);
148         else      e = mesh->AddFace      (node[0], node[1], node[2] );
149       else if (nbnode == 4) 
150         if ( ID ) e = mesh->AddFaceWithID(node[0], node[1], node[2], node[3], ID);
151         else      e = mesh->AddFace      (node[0], node[1], node[2], node[3] );
152       else if (nbnode == 6)
153         if ( ID ) e = mesh->AddFaceWithID(node[0], node[1], node[2], node[3],
154                                           node[4], node[5], ID);
155         else      e = mesh->AddFace      (node[0], node[1], node[2], node[3],
156                                           node[4], node[5] );
157       else if (nbnode == 8)
158         if ( ID ) e = mesh->AddFaceWithID(node[0], node[1], node[2], node[3],
159                                           node[4], node[5], node[6], node[7], ID);
160         else      e = mesh->AddFace      (node[0], node[1], node[2], node[3],
161                                           node[4], node[5], node[6], node[7] );
162     } else {
163       if ( ID ) e = mesh->AddPolygonalFaceWithID(node, ID);
164       else      e = mesh->AddPolygonalFace      (node    );
165     }
166     break;
167   case SMDSAbs_Volume:
168     if ( !isPoly ) {
169       if      (nbnode == 4)
170         if ( ID ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3], ID);
171         else      e = mesh->AddVolume      (node[0], node[1], node[2], node[3] );
172       else if (nbnode == 5)
173         if ( ID ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
174                                             node[4], ID);
175         else      e = mesh->AddVolume      (node[0], node[1], node[2], node[3],
176                                             node[4] );
177       else if (nbnode == 6)
178         if ( ID ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
179                                             node[4], node[5], ID);
180         else      e = mesh->AddVolume      (node[0], node[1], node[2], node[3],
181                                             node[4], node[5] );
182       else if (nbnode == 8)
183         if ( ID ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
184                                             node[4], node[5], node[6], node[7], ID);
185         else      e = mesh->AddVolume      (node[0], node[1], node[2], node[3],
186                                             node[4], node[5], node[6], node[7] );
187       else if (nbnode == 10)
188         if ( ID ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
189                                             node[4], node[5], node[6], node[7],
190                                             node[8], node[9], ID);
191         else      e = mesh->AddVolume      (node[0], node[1], node[2], node[3],
192                                             node[4], node[5], node[6], node[7],
193                                             node[8], node[9] );
194       else if (nbnode == 13)
195         if ( ID ) e = mesh->AddVolumeWithID(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],ID);
199         else      e = mesh->AddVolume      (node[0], node[1], node[2], node[3],
200                                             node[4], node[5], node[6], node[7],
201                                             node[8], node[9], node[10],node[11],
202                                             node[12] );
203       else if (nbnode == 15)
204         if ( ID ) e = mesh->AddVolumeWithID(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],ID);
208         else      e = mesh->AddVolume      (node[0], node[1], node[2], node[3],
209                                             node[4], node[5], node[6], node[7],
210                                             node[8], node[9], node[10],node[11],
211                                             node[12],node[13],node[14] );
212       else if (nbnode == 20)
213         if ( ID ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
214                                             node[4], node[5], node[6], node[7],
215                                             node[8], node[9], node[10],node[11],
216                                             node[12],node[13],node[14],node[15],
217                                             node[16],node[17],node[18],node[19],ID);
218         else      e = mesh->AddVolume      (node[0], node[1], node[2], node[3],
219                                             node[4], node[5], node[6], node[7],
220                                             node[8], node[9], node[10],node[11],
221                                             node[12],node[13],node[14],node[15],
222                                             node[16],node[17],node[18],node[19] );
223     }
224   }
225   if ( e ) myLastCreatedElems.Append( e );
226   return e;
227 }
228
229 //=======================================================================
230 /*!
231  * \brief Add element
232  */
233 //=======================================================================
234
235 SMDS_MeshElement* SMESH_MeshEditor::AddElement(const vector<int> &       nodeIDs,
236                                                const SMDSAbs_ElementType type,
237                                                const bool                isPoly,
238                                                const int                 ID)
239 {
240   vector<const SMDS_MeshNode*> nodes;
241   nodes.reserve( nodeIDs.size() );
242   vector<int>::const_iterator id = nodeIDs.begin();
243   while ( id != nodeIDs.end() ) {
244     if ( const SMDS_MeshNode* node = GetMeshDS()->FindNode( *id++ ))
245       nodes.push_back( node );
246     else
247       return 0;
248   }
249   return AddElement( nodes, type, isPoly, ID );
250 }
251
252 //=======================================================================
253 //function : Remove
254 //purpose  : Remove a node or an element.
255 //           Modify a compute state of sub-meshes which become empty
256 //=======================================================================
257
258 int SMESH_MeshEditor::Remove (const list< int >& theIDs,
259                               const bool         isNodes )
260 {
261   myLastCreatedElems.Clear();
262   myLastCreatedNodes.Clear();
263
264   SMESHDS_Mesh* aMesh = GetMeshDS();
265   set< SMESH_subMesh *> smmap;
266
267   int removed = 0;
268   list<int>::const_iterator it = theIDs.begin();
269   for ( ; it != theIDs.end(); it++ ) {
270     const SMDS_MeshElement * elem;
271     if ( isNodes )
272       elem = aMesh->FindNode( *it );
273     else
274       elem = aMesh->FindElement( *it );
275     if ( !elem )
276       continue;
277
278     // Notify VERTEX sub-meshes about modification
279     if ( isNodes ) {
280       const SMDS_MeshNode* node = cast2Node( elem );
281       if ( node->GetPosition()->GetTypeOfPosition() == SMDS_TOP_VERTEX )
282         if ( int aShapeID = node->GetPosition()->GetShapeId() )
283           if ( SMESH_subMesh * sm = GetMesh()->GetSubMeshContaining( aShapeID ) )
284             smmap.insert( sm );
285     }
286     // Find sub-meshes to notify about modification
287     //     SMDS_ElemIteratorPtr nodeIt = elem->nodesIterator();
288     //     while ( nodeIt->more() ) {
289     //       const SMDS_MeshNode* node = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
290     //       const SMDS_PositionPtr& aPosition = node->GetPosition();
291     //       if ( aPosition.get() ) {
292     //         if ( int aShapeID = aPosition->GetShapeId() ) {
293     //           if ( SMESH_subMesh * sm = GetMesh()->GetSubMeshContaining( aShapeID ) )
294     //             smmap.insert( sm );
295     //         }
296     //       }
297     //     }
298
299     // Do remove
300     if ( isNodes )
301       aMesh->RemoveNode( static_cast< const SMDS_MeshNode* >( elem ));
302     else
303       aMesh->RemoveElement( elem );
304     removed++;
305   }
306
307   // Notify sub-meshes about modification
308   if ( !smmap.empty() ) {
309     set< SMESH_subMesh *>::iterator smIt;
310     for ( smIt = smmap.begin(); smIt != smmap.end(); smIt++ )
311       (*smIt)->ComputeStateEngine( SMESH_subMesh::MESH_ENTITY_REMOVED );
312   }
313
314   //   // Check if the whole mesh becomes empty
315   //   if ( SMESH_subMesh * sm = GetMesh()->GetSubMeshContaining( 1 ) )
316   //     sm->ComputeStateEngine( SMESH_subMesh::CHECK_COMPUTE_STATE );
317
318   return removed;
319 }
320
321 //=======================================================================
322 //function : FindShape
323 //purpose  : Return an index of the shape theElem is on
324 //           or zero if a shape not found
325 //=======================================================================
326
327 int SMESH_MeshEditor::FindShape (const SMDS_MeshElement * theElem)
328 {
329   myLastCreatedElems.Clear();
330   myLastCreatedNodes.Clear();
331
332   SMESHDS_Mesh * aMesh = GetMeshDS();
333   if ( aMesh->ShapeToMesh().IsNull() )
334     return 0;
335
336   if ( theElem->GetType() == SMDSAbs_Node ) {
337     const SMDS_PositionPtr& aPosition =
338       static_cast<const SMDS_MeshNode*>( theElem )->GetPosition();
339     if ( aPosition.get() )
340       return aPosition->GetShapeId();
341     else
342       return 0;
343   }
344
345   TopoDS_Shape aShape; // the shape a node is on
346   SMDS_ElemIteratorPtr nodeIt = theElem->nodesIterator();
347   while ( nodeIt->more() ) {
348     const SMDS_MeshNode* node = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
349     const SMDS_PositionPtr& aPosition = node->GetPosition();
350     if ( aPosition.get() ) {
351       int aShapeID = aPosition->GetShapeId();
352       SMESHDS_SubMesh * sm = aMesh->MeshElements( aShapeID );
353       if ( sm ) {
354         if ( sm->Contains( theElem ))
355           return aShapeID;
356         if ( aShape.IsNull() )
357           aShape = aMesh->IndexToShape( aShapeID );
358       }
359       else {
360         //MESSAGE ( "::FindShape() No SubShape for aShapeID " << aShapeID );
361       }
362     }
363   }
364
365   // None of nodes is on a proper shape,
366   // find the shape among ancestors of aShape on which a node is
367   if ( aShape.IsNull() ) {
368     //MESSAGE ("::FindShape() - NONE node is on shape")
369     return 0;
370   }
371   TopTools_ListIteratorOfListOfShape ancIt( GetMesh()->GetAncestors( aShape ));
372   for ( ; ancIt.More(); ancIt.Next() ) {
373     SMESHDS_SubMesh * sm = aMesh->MeshElements( ancIt.Value() );
374     if ( sm && sm->Contains( theElem ))
375       return aMesh->ShapeToIndex( ancIt.Value() );
376   }
377
378   //MESSAGE ("::FindShape() - SHAPE NOT FOUND")
379   return 0;
380 }
381
382 //=======================================================================
383 //function : IsMedium
384 //purpose  :
385 //=======================================================================
386
387 bool SMESH_MeshEditor::IsMedium(const SMDS_MeshNode*      node,
388                                 const SMDSAbs_ElementType typeToCheck)
389 {
390   bool isMedium = false;
391   SMDS_ElemIteratorPtr it = node->GetInverseElementIterator(typeToCheck);
392   while (it->more() && !isMedium ) {
393     const SMDS_MeshElement* elem = it->next();
394     isMedium = elem->IsMediumNode(node);
395   }
396   return isMedium;
397 }
398
399 //=======================================================================
400 //function : ShiftNodesQuadTria
401 //purpose  : auxilary
402 //           Shift nodes in the array corresponded to quadratic triangle
403 //           example: (0,1,2,3,4,5) -> (1,2,0,4,5,3)
404 //=======================================================================
405 static void ShiftNodesQuadTria(const SMDS_MeshNode* aNodes[])
406 {
407   const SMDS_MeshNode* nd1 = aNodes[0];
408   aNodes[0] = aNodes[1];
409   aNodes[1] = aNodes[2];
410   aNodes[2] = nd1;
411   const SMDS_MeshNode* nd2 = aNodes[3];
412   aNodes[3] = aNodes[4];
413   aNodes[4] = aNodes[5];
414   aNodes[5] = nd2;
415 }
416
417 //=======================================================================
418 //function : GetNodesFromTwoTria
419 //purpose  : auxilary
420 //           Shift nodes in the array corresponded to quadratic triangle
421 //           example: (0,1,2,3,4,5) -> (1,2,0,4,5,3)
422 //=======================================================================
423 static bool GetNodesFromTwoTria(const SMDS_MeshElement * theTria1,
424                                 const SMDS_MeshElement * theTria2,
425                                 const SMDS_MeshNode* N1[],
426                                 const SMDS_MeshNode* N2[])
427 {
428   SMDS_ElemIteratorPtr it = theTria1->nodesIterator();
429   int i=0;
430   while(i<6) {
431     N1[i] = static_cast<const SMDS_MeshNode*>( it->next() );
432     i++;
433   }
434   if(it->more()) return false;
435   it = theTria2->nodesIterator();
436   i=0;
437   while(i<6) {
438     N2[i] = static_cast<const SMDS_MeshNode*>( it->next() );
439     i++;
440   }
441   if(it->more()) return false;
442
443   int sames[3] = {-1,-1,-1};
444   int nbsames = 0;
445   int j;
446   for(i=0; i<3; i++) {
447     for(j=0; j<3; j++) {
448       if(N1[i]==N2[j]) {
449         sames[i] = j;
450         nbsames++;
451         break;
452       }
453     }
454   }
455   if(nbsames!=2) return false;
456   if(sames[0]>-1) {
457     ShiftNodesQuadTria(N1);
458     if(sames[1]>-1) {
459       ShiftNodesQuadTria(N1);
460     }
461   }
462   i = sames[0] + sames[1] + sames[2];
463   for(; i<2; i++) {
464     ShiftNodesQuadTria(N2);
465   }
466   // now we receive following N1 and N2 (using numeration as above image)
467   // tria1 : (1 2 4 5 9 7)  and  tria2 : (3 4 2 8 9 6)
468   // i.e. first nodes from both arrays determ new diagonal
469   return true;
470 }
471
472 //=======================================================================
473 //function : InverseDiag
474 //purpose  : Replace two neighbour triangles with ones built on the same 4 nodes
475 //           but having other common link.
476 //           Return False if args are improper
477 //=======================================================================
478
479 bool SMESH_MeshEditor::InverseDiag (const SMDS_MeshElement * theTria1,
480                                     const SMDS_MeshElement * theTria2 )
481 {
482   myLastCreatedElems.Clear();
483   myLastCreatedNodes.Clear();
484
485   if (!theTria1 || !theTria2)
486     return false;
487
488   const SMDS_FaceOfNodes* F1 = dynamic_cast<const SMDS_FaceOfNodes*>( theTria1 );
489   const SMDS_FaceOfNodes* F2 = dynamic_cast<const SMDS_FaceOfNodes*>( theTria2 );
490   if (F1 && F2) {
491
492     //  1 +--+ A  theTria1: ( 1 A B ) A->2 ( 1 2 B ) 1 +--+ A
493     //    | /|    theTria2: ( B A 2 ) B->1 ( 1 A 2 )   |\ |
494     //    |/ |                                         | \|
495     //  B +--+ 2                                     B +--+ 2
496
497     // put nodes in array and find out indices of the same ones
498     const SMDS_MeshNode* aNodes [6];
499     int sameInd [] = { 0, 0, 0, 0, 0, 0 };
500     int i = 0;
501     SMDS_ElemIteratorPtr it = theTria1->nodesIterator();
502     while ( it->more() ) {
503       aNodes[ i ] = static_cast<const SMDS_MeshNode*>( it->next() );
504
505       if ( i > 2 ) // theTria2
506         // find same node of theTria1
507         for ( int j = 0; j < 3; j++ )
508           if ( aNodes[ i ] == aNodes[ j ]) {
509             sameInd[ j ] = i;
510             sameInd[ i ] = j;
511             break;
512           }
513       // next
514       i++;
515       if ( i == 3 ) {
516         if ( it->more() )
517           return false; // theTria1 is not a triangle
518         it = theTria2->nodesIterator();
519       }
520       if ( i == 6 && it->more() )
521         return false; // theTria2 is not a triangle
522     }
523
524     // find indices of 1,2 and of A,B in theTria1
525     int iA = 0, iB = 0, i1 = 0, i2 = 0;
526     for ( i = 0; i < 6; i++ ) {
527       if ( sameInd [ i ] == 0 )
528         if ( i < 3 ) i1 = i;
529         else         i2 = i;
530       else if (i < 3)
531         if ( iA ) iB = i;
532         else      iA = i;
533     }
534     // nodes 1 and 2 should not be the same
535     if ( aNodes[ i1 ] == aNodes[ i2 ] )
536       return false;
537
538     // theTria1: A->2
539     aNodes[ iA ] = aNodes[ i2 ];
540     // theTria2: B->1
541     aNodes[ sameInd[ iB ]] = aNodes[ i1 ];
542
543     //MESSAGE( theTria1 << theTria2 );
544
545     GetMeshDS()->ChangeElementNodes( theTria1, aNodes, 3 );
546     GetMeshDS()->ChangeElementNodes( theTria2, &aNodes[ 3 ], 3 );
547
548     //MESSAGE( theTria1 << theTria2 );
549
550     return true;
551
552   } // end if(F1 && F2)
553
554   // check case of quadratic faces
555   const SMDS_QuadraticFaceOfNodes* QF1 =
556     dynamic_cast<const SMDS_QuadraticFaceOfNodes*> (theTria1);
557   if(!QF1) return false;
558   const SMDS_QuadraticFaceOfNodes* QF2 =
559     dynamic_cast<const SMDS_QuadraticFaceOfNodes*> (theTria2);
560   if(!QF2) return false;
561
562   //       5
563   //  1 +--+--+ 2  theTria1: (1 2 4 5 9 7) or (2 4 1 9 7 5) or (4 1 2 7 5 9)
564   //    |    /|    theTria2: (2 3 4 6 8 9) or (3 4 2 8 9 6) or (4 2 3 9 6 8)
565   //    |   / |
566   //  7 +  +  + 6
567   //    | /9  |
568   //    |/    |
569   //  4 +--+--+ 3
570   //       8
571
572   const SMDS_MeshNode* N1 [6];
573   const SMDS_MeshNode* N2 [6];
574   if(!GetNodesFromTwoTria(theTria1,theTria2,N1,N2))
575     return false;
576   // now we receive following N1 and N2 (using numeration as above image)
577   // tria1 : (1 2 4 5 9 7)  and  tria2 : (3 4 2 8 9 6)
578   // i.e. first nodes from both arrays determ new diagonal
579
580   const SMDS_MeshNode* N1new [6];
581   const SMDS_MeshNode* N2new [6];
582   N1new[0] = N1[0];
583   N1new[1] = N2[0];
584   N1new[2] = N2[1];
585   N1new[3] = N1[4];
586   N1new[4] = N2[3];
587   N1new[5] = N1[5];
588   N2new[0] = N1[0];
589   N2new[1] = N1[1];
590   N2new[2] = N2[0];
591   N2new[3] = N1[3];
592   N2new[4] = N2[5];
593   N2new[5] = N1[4];
594   // replaces nodes in faces
595   GetMeshDS()->ChangeElementNodes( theTria1, N1new, 6 );
596   GetMeshDS()->ChangeElementNodes( theTria2, N2new, 6 );
597
598   return true;
599 }
600
601 //=======================================================================
602 //function : findTriangles
603 //purpose  : find triangles sharing theNode1-theNode2 link
604 //=======================================================================
605
606 static bool findTriangles(const SMDS_MeshNode *    theNode1,
607                           const SMDS_MeshNode *    theNode2,
608                           const SMDS_MeshElement*& theTria1,
609                           const SMDS_MeshElement*& theTria2)
610 {
611   if ( !theNode1 || !theNode2 ) return false;
612
613   theTria1 = theTria2 = 0;
614
615   set< const SMDS_MeshElement* > emap;
616   SMDS_ElemIteratorPtr it = theNode1->GetInverseElementIterator(SMDSAbs_Face);
617   while (it->more()) {
618     const SMDS_MeshElement* elem = it->next();
619     if ( elem->NbNodes() == 3 )
620       emap.insert( elem );
621   }
622   it = theNode2->GetInverseElementIterator(SMDSAbs_Face);
623   while (it->more()) {
624     const SMDS_MeshElement* elem = it->next();
625     if ( emap.find( elem ) != emap.end() )
626       if ( theTria1 ) {
627         // theTria1 must be element with minimum ID
628         if( theTria1->GetID() < elem->GetID() ) {
629           theTria2 = elem;
630         }
631         else {
632           theTria2 = theTria1;
633           theTria1 = elem;
634         }
635         break;
636       }
637       else {
638         theTria1 = elem;
639       }
640   }
641   return ( theTria1 && theTria2 );
642 }
643
644 //=======================================================================
645 //function : InverseDiag
646 //purpose  : Replace two neighbour triangles sharing theNode1-theNode2 link
647 //           with ones built on the same 4 nodes but having other common link.
648 //           Return false if proper faces not found
649 //=======================================================================
650
651 bool SMESH_MeshEditor::InverseDiag (const SMDS_MeshNode * theNode1,
652                                     const SMDS_MeshNode * theNode2)
653 {
654   myLastCreatedElems.Clear();
655   myLastCreatedNodes.Clear();
656
657   MESSAGE( "::InverseDiag()" );
658
659   const SMDS_MeshElement *tr1, *tr2;
660   if ( !findTriangles( theNode1, theNode2, tr1, tr2 ))
661     return false;
662
663   const SMDS_FaceOfNodes* F1 = dynamic_cast<const SMDS_FaceOfNodes*>( tr1 );
664   //if (!F1) return false;
665   const SMDS_FaceOfNodes* F2 = dynamic_cast<const SMDS_FaceOfNodes*>( tr2 );
666   //if (!F2) return false;
667   if (F1 && F2) {
668
669     //  1 +--+ A  tr1: ( 1 A B ) A->2 ( 1 2 B ) 1 +--+ A
670     //    | /|    tr2: ( B A 2 ) B->1 ( 1 A 2 )   |\ |
671     //    |/ |                                    | \|
672     //  B +--+ 2                                B +--+ 2
673
674     // put nodes in array
675     // and find indices of 1,2 and of A in tr1 and of B in tr2
676     int i, iA1 = 0, i1 = 0;
677     const SMDS_MeshNode* aNodes1 [3];
678     SMDS_ElemIteratorPtr it;
679     for (i = 0, it = tr1->nodesIterator(); it->more(); i++ ) {
680       aNodes1[ i ] = static_cast<const SMDS_MeshNode*>( it->next() );
681       if ( aNodes1[ i ] == theNode1 )
682         iA1 = i; // node A in tr1
683       else if ( aNodes1[ i ] != theNode2 )
684         i1 = i;  // node 1
685     }
686     int iB2 = 0, i2 = 0;
687     const SMDS_MeshNode* aNodes2 [3];
688     for (i = 0, it = tr2->nodesIterator(); it->more(); i++ ) {
689       aNodes2[ i ] = static_cast<const SMDS_MeshNode*>( it->next() );
690       if ( aNodes2[ i ] == theNode2 )
691         iB2 = i; // node B in tr2
692       else if ( aNodes2[ i ] != theNode1 )
693         i2 = i;  // node 2
694     }
695
696     // nodes 1 and 2 should not be the same
697     if ( aNodes1[ i1 ] == aNodes2[ i2 ] )
698       return false;
699
700     // tr1: A->2
701     aNodes1[ iA1 ] = aNodes2[ i2 ];
702     // tr2: B->1
703     aNodes2[ iB2 ] = aNodes1[ i1 ];
704
705     //MESSAGE( tr1 << tr2 );
706
707     GetMeshDS()->ChangeElementNodes( tr1, aNodes1, 3 );
708     GetMeshDS()->ChangeElementNodes( tr2, aNodes2, 3 );
709
710     //MESSAGE( tr1 << tr2 );
711
712     return true;
713   }
714
715   // check case of quadratic faces
716   const SMDS_QuadraticFaceOfNodes* QF1 =
717     dynamic_cast<const SMDS_QuadraticFaceOfNodes*> (tr1);
718   if(!QF1) return false;
719   const SMDS_QuadraticFaceOfNodes* QF2 =
720     dynamic_cast<const SMDS_QuadraticFaceOfNodes*> (tr2);
721   if(!QF2) return false;
722   return InverseDiag(tr1,tr2);
723 }
724
725 //=======================================================================
726 //function : getQuadrangleNodes
727 //purpose  : fill theQuadNodes - nodes of a quadrangle resulting from
728 //           fusion of triangles tr1 and tr2 having shared link on
729 //           theNode1 and theNode2
730 //=======================================================================
731
732 bool getQuadrangleNodes(const SMDS_MeshNode *    theQuadNodes [],
733                         const SMDS_MeshNode *    theNode1,
734                         const SMDS_MeshNode *    theNode2,
735                         const SMDS_MeshElement * tr1,
736                         const SMDS_MeshElement * tr2 )
737 {
738   if( tr1->NbNodes() != tr2->NbNodes() )
739     return false;
740   // find the 4-th node to insert into tr1
741   const SMDS_MeshNode* n4 = 0;
742   SMDS_ElemIteratorPtr it = tr2->nodesIterator();
743   int i=0;
744   while ( !n4 && i<3 ) {
745     const SMDS_MeshNode * n = cast2Node( it->next() );
746     i++;
747     bool isDiag = ( n == theNode1 || n == theNode2 );
748     if ( !isDiag )
749       n4 = n;
750   }
751   // Make an array of nodes to be in a quadrangle
752   int iNode = 0, iFirstDiag = -1;
753   it = tr1->nodesIterator();
754   i=0;
755   while ( i<3 ) {
756     const SMDS_MeshNode * n = cast2Node( it->next() );
757     i++;
758     bool isDiag = ( n == theNode1 || n == theNode2 );
759     if ( isDiag ) {
760       if ( iFirstDiag < 0 )
761         iFirstDiag = iNode;
762       else if ( iNode - iFirstDiag == 1 )
763         theQuadNodes[ iNode++ ] = n4; // insert the 4-th node between diagonal nodes
764     }
765     else if ( n == n4 ) {
766       return false; // tr1 and tr2 should not have all the same nodes
767     }
768     theQuadNodes[ iNode++ ] = n;
769   }
770   if ( iNode == 3 ) // diagonal nodes have 0 and 2 indices
771     theQuadNodes[ iNode ] = n4;
772
773   return true;
774 }
775
776 //=======================================================================
777 //function : DeleteDiag
778 //purpose  : Replace two neighbour triangles sharing theNode1-theNode2 link
779 //           with a quadrangle built on the same 4 nodes.
780 //           Return false if proper faces not found
781 //=======================================================================
782
783 bool SMESH_MeshEditor::DeleteDiag (const SMDS_MeshNode * theNode1,
784                                    const SMDS_MeshNode * theNode2)
785 {
786   myLastCreatedElems.Clear();
787   myLastCreatedNodes.Clear();
788
789   MESSAGE( "::DeleteDiag()" );
790
791   const SMDS_MeshElement *tr1, *tr2;
792   if ( !findTriangles( theNode1, theNode2, tr1, tr2 ))
793     return false;
794
795   const SMDS_FaceOfNodes* F1 = dynamic_cast<const SMDS_FaceOfNodes*>( tr1 );
796   //if (!F1) return false;
797   const SMDS_FaceOfNodes* F2 = dynamic_cast<const SMDS_FaceOfNodes*>( tr2 );
798   //if (!F2) return false;
799   if (F1 && F2) {
800
801     const SMDS_MeshNode* aNodes [ 4 ];
802     if ( ! getQuadrangleNodes( aNodes, theNode1, theNode2, tr1, tr2 ))
803       return false;
804
805     //MESSAGE( endl << tr1 << tr2 );
806
807     GetMeshDS()->ChangeElementNodes( tr1, aNodes, 4 );
808     myLastCreatedElems.Append(tr1);
809     GetMeshDS()->RemoveElement( tr2 );
810
811     //MESSAGE( endl << tr1 );
812
813     return true;
814   }
815
816   // check case of quadratic faces
817   const SMDS_QuadraticFaceOfNodes* QF1 =
818     dynamic_cast<const SMDS_QuadraticFaceOfNodes*> (tr1);
819   if(!QF1) return false;
820   const SMDS_QuadraticFaceOfNodes* QF2 =
821     dynamic_cast<const SMDS_QuadraticFaceOfNodes*> (tr2);
822   if(!QF2) return false;
823
824   //       5
825   //  1 +--+--+ 2  tr1: (1 2 4 5 9 7) or (2 4 1 9 7 5) or (4 1 2 7 5 9)
826   //    |    /|    tr2: (2 3 4 6 8 9) or (3 4 2 8 9 6) or (4 2 3 9 6 8)
827   //    |   / |
828   //  7 +  +  + 6
829   //    | /9  |
830   //    |/    |
831   //  4 +--+--+ 3
832   //       8
833
834   const SMDS_MeshNode* N1 [6];
835   const SMDS_MeshNode* N2 [6];
836   if(!GetNodesFromTwoTria(tr1,tr2,N1,N2))
837     return false;
838   // now we receive following N1 and N2 (using numeration as above image)
839   // tria1 : (1 2 4 5 9 7)  and  tria2 : (3 4 2 8 9 6)
840   // i.e. first nodes from both arrays determ new diagonal
841
842   const SMDS_MeshNode* aNodes[8];
843   aNodes[0] = N1[0];
844   aNodes[1] = N1[1];
845   aNodes[2] = N2[0];
846   aNodes[3] = N2[1];
847   aNodes[4] = N1[3];
848   aNodes[5] = N2[5];
849   aNodes[6] = N2[3];
850   aNodes[7] = N1[5];
851
852   GetMeshDS()->ChangeElementNodes( tr1, aNodes, 8 );
853   myLastCreatedElems.Append(tr1);
854   GetMeshDS()->RemoveElement( tr2 );
855
856   // remove middle node (9)
857   GetMeshDS()->RemoveNode( N1[4] );
858
859   return true;
860 }
861
862 //=======================================================================
863 //function : Reorient
864 //purpose  : Reverse theElement orientation
865 //=======================================================================
866
867 bool SMESH_MeshEditor::Reorient (const SMDS_MeshElement * theElem)
868 {
869   myLastCreatedElems.Clear();
870   myLastCreatedNodes.Clear();
871
872   if (!theElem)
873     return false;
874   SMDS_ElemIteratorPtr it = theElem->nodesIterator();
875   if ( !it || !it->more() )
876     return false;
877
878   switch ( theElem->GetType() ) {
879
880   case SMDSAbs_Edge:
881   case SMDSAbs_Face: {
882     if(!theElem->IsQuadratic()) {
883       int i = theElem->NbNodes();
884       vector<const SMDS_MeshNode*> aNodes( i );
885       while ( it->more() )
886         aNodes[ --i ]= static_cast<const SMDS_MeshNode*>( it->next() );
887       return GetMeshDS()->ChangeElementNodes( theElem, &aNodes[0], theElem->NbNodes() );
888     }
889     else {
890       // quadratic elements
891       if(theElem->GetType()==SMDSAbs_Edge) {
892         vector<const SMDS_MeshNode*> aNodes(3);
893         aNodes[1]= static_cast<const SMDS_MeshNode*>( it->next() );
894         aNodes[0]= static_cast<const SMDS_MeshNode*>( it->next() );
895         aNodes[2]= static_cast<const SMDS_MeshNode*>( it->next() );
896         return GetMeshDS()->ChangeElementNodes( theElem, &aNodes[0], 3 );
897       }
898       else {
899         int nbn = theElem->NbNodes();
900         vector<const SMDS_MeshNode*> aNodes(nbn);
901         aNodes[0]= static_cast<const SMDS_MeshNode*>( it->next() );
902         int i=1;
903         for(; i<nbn/2; i++) {
904           aNodes[nbn/2-i]= static_cast<const SMDS_MeshNode*>( it->next() );
905         }
906         for(i=0; i<nbn/2; i++) {
907           aNodes[nbn-i-1]= static_cast<const SMDS_MeshNode*>( it->next() );
908         }
909         return GetMeshDS()->ChangeElementNodes( theElem, &aNodes[0], nbn );
910       }
911     }
912   }
913   case SMDSAbs_Volume: {
914     if (theElem->IsPoly()) {
915       const SMDS_PolyhedralVolumeOfNodes* aPolyedre =
916         static_cast<const SMDS_PolyhedralVolumeOfNodes*>( theElem );
917       if (!aPolyedre) {
918         MESSAGE("Warning: bad volumic element");
919         return false;
920       }
921
922       int nbFaces = aPolyedre->NbFaces();
923       vector<const SMDS_MeshNode *> poly_nodes;
924       vector<int> quantities (nbFaces);
925
926       // reverse each face of the polyedre
927       for (int iface = 1; iface <= nbFaces; iface++) {
928         int inode, nbFaceNodes = aPolyedre->NbFaceNodes(iface);
929         quantities[iface - 1] = nbFaceNodes;
930
931         for (inode = nbFaceNodes; inode >= 1; inode--) {
932           const SMDS_MeshNode* curNode = aPolyedre->GetFaceNode(iface, inode);
933           poly_nodes.push_back(curNode);
934         }
935       }
936
937       return GetMeshDS()->ChangePolyhedronNodes( theElem, poly_nodes, quantities );
938
939     }
940     else {
941       SMDS_VolumeTool vTool;
942       if ( !vTool.Set( theElem ))
943         return false;
944       vTool.Inverse();
945       return GetMeshDS()->ChangeElementNodes( theElem, vTool.GetNodes(), vTool.NbNodes() );
946     }
947   }
948   default:;
949   }
950
951   return false;
952 }
953
954 //=======================================================================
955 //function : getBadRate
956 //purpose  :
957 //=======================================================================
958
959 static double getBadRate (const SMDS_MeshElement*               theElem,
960                           SMESH::Controls::NumericalFunctorPtr& theCrit)
961 {
962   SMESH::Controls::TSequenceOfXYZ P;
963   if ( !theElem || !theCrit->GetPoints( theElem, P ))
964     return 1e100;
965   return theCrit->GetBadRate( theCrit->GetValue( P ), theElem->NbNodes() );
966   //return theCrit->GetBadRate( theCrit->GetValue( theElem->GetID() ), theElem->NbNodes() );
967 }
968
969 //=======================================================================
970 //function : QuadToTri
971 //purpose  : Cut quadrangles into triangles.
972 //           theCrit is used to select a diagonal to cut
973 //=======================================================================
974
975 bool SMESH_MeshEditor::QuadToTri (TIDSortedElemSet &                   theElems,
976                                   SMESH::Controls::NumericalFunctorPtr theCrit)
977 {
978   myLastCreatedElems.Clear();
979   myLastCreatedNodes.Clear();
980
981   MESSAGE( "::QuadToTri()" );
982
983   if ( !theCrit.get() )
984     return false;
985
986   SMESHDS_Mesh * aMesh = GetMeshDS();
987
988   Handle(Geom_Surface) surface;
989   SMESH_MesherHelper   helper( *GetMesh() );
990
991   TIDSortedElemSet::iterator itElem;
992   for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
993     const SMDS_MeshElement* elem = *itElem;
994     if ( !elem || elem->GetType() != SMDSAbs_Face )
995       continue;
996     if ( elem->NbNodes() != ( elem->IsQuadratic() ? 8 : 4 ))
997       continue;
998
999     // retrieve element nodes
1000     const SMDS_MeshNode* aNodes [8];
1001     SMDS_ElemIteratorPtr itN = elem->nodesIterator();
1002     int i = 0;
1003     while ( itN->more() )
1004       aNodes[ i++ ] = static_cast<const SMDS_MeshNode*>( itN->next() );
1005
1006     // compare two sets of possible triangles
1007     double aBadRate1, aBadRate2; // to what extent a set is bad
1008     SMDS_FaceOfNodes tr1 ( aNodes[0], aNodes[1], aNodes[2] );
1009     SMDS_FaceOfNodes tr2 ( aNodes[2], aNodes[3], aNodes[0] );
1010     aBadRate1 = getBadRate( &tr1, theCrit ) + getBadRate( &tr2, theCrit );
1011
1012     SMDS_FaceOfNodes tr3 ( aNodes[1], aNodes[2], aNodes[3] );
1013     SMDS_FaceOfNodes tr4 ( aNodes[3], aNodes[0], aNodes[1] );
1014     aBadRate2 = getBadRate( &tr3, theCrit ) + getBadRate( &tr4, theCrit );
1015
1016     int aShapeId = FindShape( elem );
1017     const SMDS_MeshElement* newElem = 0;
1018
1019     if( !elem->IsQuadratic() ) {
1020
1021       // split liner quadrangle
1022
1023       if ( aBadRate1 <= aBadRate2 ) {
1024         // tr1 + tr2 is better
1025         aMesh->ChangeElementNodes( elem, aNodes, 3 );
1026         newElem = aMesh->AddFace( aNodes[2], aNodes[3], aNodes[0] );
1027       }
1028       else {
1029         // tr3 + tr4 is better
1030         aMesh->ChangeElementNodes( elem, &aNodes[1], 3 );
1031         newElem = aMesh->AddFace( aNodes[3], aNodes[0], aNodes[1] );
1032       }
1033     }
1034     else {
1035
1036       // split quadratic quadrangle
1037
1038       // get surface elem is on
1039       if ( aShapeId != helper.GetSubShapeID() ) {
1040         surface.Nullify();
1041         TopoDS_Shape shape;
1042         if ( aShapeId > 0 )
1043           shape = aMesh->IndexToShape( aShapeId );
1044         if ( !shape.IsNull() && shape.ShapeType() == TopAbs_FACE ) {
1045           TopoDS_Face face = TopoDS::Face( shape );
1046           surface = BRep_Tool::Surface( face );
1047           if ( !surface.IsNull() )
1048             helper.SetSubShape( shape );
1049         }
1050       }
1051       // get elem nodes
1052       const SMDS_MeshNode* aNodes [8];
1053       const SMDS_MeshNode* inFaceNode = 0;
1054       SMDS_ElemIteratorPtr itN = elem->nodesIterator();
1055       int i = 0;
1056       while ( itN->more() ) {
1057         aNodes[ i++ ] = static_cast<const SMDS_MeshNode*>( itN->next() );
1058         if ( !inFaceNode && helper.GetNodeUVneedInFaceNode() &&
1059              aNodes[ i-1 ]->GetPosition()->GetTypeOfPosition() == SMDS_TOP_FACE )
1060         {
1061           inFaceNode = aNodes[ i-1 ];
1062         }
1063       }
1064       // find middle point for (0,1,2,3)
1065       // and create a node in this point;
1066       gp_XYZ p( 0,0,0 );
1067       if ( surface.IsNull() ) {
1068         for(i=0; i<4; i++)
1069           p += gp_XYZ(aNodes[i]->X(), aNodes[i]->Y(), aNodes[i]->Z() );
1070         p /= 4;
1071       }
1072       else {
1073         TopoDS_Face face = TopoDS::Face( helper.GetSubShape() );
1074         gp_XY uv( 0,0 );
1075         for(i=0; i<4; i++)
1076           uv += helper.GetNodeUV( face, aNodes[i], inFaceNode );
1077         uv /= 4.;
1078         p = surface->Value( uv.X(), uv.Y() ).XYZ();
1079       }
1080       const SMDS_MeshNode* newN = aMesh->AddNode( p.X(), p.Y(), p.Z() );
1081       myLastCreatedNodes.Append(newN);
1082
1083       // create a new element
1084       const SMDS_MeshNode* N[6];
1085       if ( aBadRate1 <= aBadRate2 ) {
1086         N[0] = aNodes[0];
1087         N[1] = aNodes[1];
1088         N[2] = aNodes[2];
1089         N[3] = aNodes[4];
1090         N[4] = aNodes[5];
1091         N[5] = newN;
1092         newElem = aMesh->AddFace(aNodes[2], aNodes[3], aNodes[0],
1093                                  aNodes[6], aNodes[7], newN );
1094       }
1095       else {
1096         N[0] = aNodes[1];
1097         N[1] = aNodes[2];
1098         N[2] = aNodes[3];
1099         N[3] = aNodes[5];
1100         N[4] = aNodes[6];
1101         N[5] = newN;
1102         newElem = aMesh->AddFace(aNodes[3], aNodes[0], aNodes[1],
1103                                  aNodes[7], aNodes[4], newN );
1104       }
1105       aMesh->ChangeElementNodes( elem, N, 6 );
1106
1107     } // quadratic case
1108
1109     // care of a new element
1110
1111     myLastCreatedElems.Append(newElem);
1112     AddToSameGroups( newElem, elem, aMesh );
1113
1114     // put a new triangle on the same shape
1115     if ( aShapeId )
1116       aMesh->SetMeshElementOnShape( newElem, aShapeId );
1117   }
1118   return true;
1119 }
1120
1121 //=======================================================================
1122 //function : BestSplit
1123 //purpose  : Find better diagonal for cutting.
1124 //=======================================================================
1125
1126 int SMESH_MeshEditor::BestSplit (const SMDS_MeshElement*              theQuad,
1127                                  SMESH::Controls::NumericalFunctorPtr theCrit)
1128 {
1129   myLastCreatedElems.Clear();
1130   myLastCreatedNodes.Clear();
1131
1132   if (!theCrit.get())
1133     return -1;
1134
1135   if (!theQuad || theQuad->GetType() != SMDSAbs_Face )
1136     return -1;
1137
1138   if( theQuad->NbNodes()==4 ||
1139       (theQuad->NbNodes()==8 && theQuad->IsQuadratic()) ) {
1140
1141     // retrieve element nodes
1142     const SMDS_MeshNode* aNodes [4];
1143     SMDS_ElemIteratorPtr itN = theQuad->nodesIterator();
1144     int i = 0;
1145     //while (itN->more())
1146     while (i<4) {
1147       aNodes[ i++ ] = static_cast<const SMDS_MeshNode*>( itN->next() );
1148     }
1149     // compare two sets of possible triangles
1150     double aBadRate1, aBadRate2; // to what extent a set is bad
1151     SMDS_FaceOfNodes tr1 ( aNodes[0], aNodes[1], aNodes[2] );
1152     SMDS_FaceOfNodes tr2 ( aNodes[2], aNodes[3], aNodes[0] );
1153     aBadRate1 = getBadRate( &tr1, theCrit ) + getBadRate( &tr2, theCrit );
1154
1155     SMDS_FaceOfNodes tr3 ( aNodes[1], aNodes[2], aNodes[3] );
1156     SMDS_FaceOfNodes tr4 ( aNodes[3], aNodes[0], aNodes[1] );
1157     aBadRate2 = getBadRate( &tr3, theCrit ) + getBadRate( &tr4, theCrit );
1158
1159     if (aBadRate1 <= aBadRate2) // tr1 + tr2 is better
1160       return 1; // diagonal 1-3
1161
1162     return 2; // diagonal 2-4
1163   }
1164   return -1;
1165 }
1166
1167 namespace
1168 {
1169   // Methods of splitting volumes into tetra
1170
1171   const int theHexTo5_1[5*4+1] =
1172     {
1173       0, 1, 2, 5,    0, 4, 5, 7,     0, 2, 3, 7,    2, 5, 6, 7,     0, 5, 2, 7,   -1
1174     };
1175   const int theHexTo5_2[5*4+1] =
1176     {
1177       1, 2, 3, 6,    1, 4, 5, 6,     0, 1, 3, 4,    3, 4, 6, 7,     1, 3, 4, 6,   -1
1178     };
1179   const int* theHexTo5[2] = { theHexTo5_1, theHexTo5_2 };
1180
1181   const int theHexTo6_1[6*4+1] =
1182     {
1183       1, 5, 6, 0,    0, 1, 2, 6,     0, 4, 5, 6,    0, 4, 6, 7,     0, 2, 3, 6,   0, 3, 7, 6,  -1
1184     };
1185   const int theHexTo6_2[6*4+1] =
1186     {
1187       2, 6, 7, 1,    1, 2, 3, 7,     1, 5, 6, 7,    1, 5, 7, 4,     1, 3, 0, 7,   1, 0, 4, 7,  -1
1188     };
1189   const int theHexTo6_3[6*4+1] =
1190     {
1191       3, 7, 4, 2,    2, 3, 0, 4,     2, 6, 7, 4,    2, 6, 4, 5,     2, 0, 1, 4,   2, 1, 5, 4,  -1
1192     };
1193   const int theHexTo6_4[6*4+1] =
1194     {
1195       0, 4, 5, 3,    3, 0, 1, 5,     3, 7, 4, 5,    3, 7, 5, 6,     3, 1, 2, 5,   3, 2, 6, 5,  -1
1196     };
1197   const int* theHexTo6[4] = { theHexTo6_1, theHexTo6_2, theHexTo6_3, theHexTo6_4 };
1198
1199   const int thePyraTo2_1[2*4+1] =
1200     {
1201       0, 1, 2, 4,    0, 2, 3, 4,   -1
1202     };
1203   const int thePyraTo2_2[2*4+1] =
1204     {
1205       1, 2, 3, 4,    1, 3, 0, 4,   -1
1206     };
1207   const int* thePyraTo2[2] = { thePyraTo2_1, thePyraTo2_2 };
1208
1209   const int thePentaTo3_1[3*4+1] =
1210     {
1211       0, 1, 2, 3,    1, 3, 4, 2,     2, 3, 4, 5,    -1
1212     };
1213   const int thePentaTo3_2[3*4+1] =
1214     {
1215       1, 2, 0, 4,    2, 4, 5, 0,     0, 4, 5, 3,    -1
1216     };
1217   const int thePentaTo3_3[3*4+1] =
1218     {
1219       2, 0, 1, 5,    0, 5, 3, 1,     1, 5, 3, 4,    -1
1220     };
1221   const int thePentaTo3_4[3*4+1] =
1222     {
1223       0, 1, 2, 3,    1, 3, 4, 5,     2, 3, 1, 5,    -1
1224     };
1225   const int thePentaTo3_5[3*4+1] =
1226     {
1227       1, 2, 0, 4,    2, 4, 5, 3,     0, 4, 2, 3,    -1
1228     };
1229   const int thePentaTo3_6[3*4+1] =
1230     {
1231       2, 0, 1, 5,    0, 5, 3, 4,     1, 5, 0, 4,    -1
1232     };
1233   const int* thePentaTo3[6] = { thePentaTo3_1, thePentaTo3_2, thePentaTo3_3,
1234                                 thePentaTo3_4, thePentaTo3_5, thePentaTo3_6 };
1235
1236   struct TTriangleFacet //!< stores indices of three nodes of tetra facet
1237   {
1238     int _n1, _n2, _n3;
1239     TTriangleFacet(int n1, int n2, int n3): _n1(n1), _n2(n2), _n3(n3) {}
1240     bool contains(int n) const { return ( n == _n1 || n == _n2 || n == _n3 ); }
1241     bool hasAdjacentTetra( const SMDS_MeshElement* elem ) const;
1242   };
1243   struct TSplitMethod
1244   {
1245     int        _nbTetra;
1246     const int* _connectivity; //!< foursomes of tetra connectivy finished by -1
1247     bool       _baryNode;     //!< additional node is to be created at cell barycenter
1248     bool       _ownConn;      //!< to delete _connectivity in destructor
1249     map<int, const SMDS_MeshNode*> _faceBaryNode; //!< map face index to node at BC of face
1250
1251     TSplitMethod( int nbTet=0, const int* conn=0, bool addNode=false)
1252       : _nbTetra(nbTet), _connectivity(conn), _baryNode(addNode), _ownConn(false) {}
1253     ~TSplitMethod() { if ( _ownConn ) delete [] _connectivity; _connectivity = 0; }
1254     bool hasFacet( const TTriangleFacet& facet ) const
1255     {
1256       const int* tetConn = _connectivity;
1257       for ( ; tetConn[0] >= 0; tetConn += 4 )
1258         if (( facet.contains( tetConn[0] ) +
1259               facet.contains( tetConn[1] ) +
1260               facet.contains( tetConn[2] ) +
1261               facet.contains( tetConn[3] )) == 3 )
1262           return true;
1263       return false;
1264     }
1265   };
1266
1267   //=======================================================================
1268   /*!
1269    * \brief return TSplitMethod for the given element
1270    */
1271   //=======================================================================
1272
1273   TSplitMethod getSplitMethod( SMDS_VolumeTool& vol, const int theMethodFlags)
1274   {
1275     const int iQ = vol.Element()->IsQuadratic() ? 2 : 1;
1276
1277     // at HEXA_TO_24 method, each face of volume is split into triangles each based on
1278     // an edge and a face barycenter; tertaherdons are based on triangles and
1279     // a volume barycenter
1280     const bool is24TetMode = ( theMethodFlags == SMESH_MeshEditor::HEXA_TO_24 );
1281
1282     // Find out how adjacent volumes are split
1283
1284     vector < list< TTriangleFacet > > triaSplitsByFace( vol.NbFaces() ); // splits of each side
1285     int hasAdjacentSplits = 0, maxTetConnSize = 0;
1286     for ( int iF = 0; iF < vol.NbFaces(); ++iF )
1287     {
1288       int nbNodes = vol.NbFaceNodes( iF ) / iQ;
1289       maxTetConnSize += 4 * ( nbNodes - (is24TetMode ? 0 : 2));
1290       if ( nbNodes < 4 ) continue;
1291
1292       list< TTriangleFacet >& triaSplits = triaSplitsByFace[ iF ];
1293       const int* nInd = vol.GetFaceNodesIndices( iF );
1294       if ( nbNodes == 4 )
1295       {
1296         TTriangleFacet t012( nInd[0*iQ], nInd[1*iQ], nInd[2*iQ] );
1297         TTriangleFacet t123( nInd[1*iQ], nInd[2*iQ], nInd[3*iQ] );
1298         if      ( t012.hasAdjacentTetra( vol.Element() )) triaSplits.push_back( t012 );
1299         else if ( t123.hasAdjacentTetra( vol.Element() )) triaSplits.push_back( t123 );
1300       }
1301       else
1302       {
1303         int iCom = 0; // common node of triangle faces to split into
1304         for ( int iVar = 0; iVar < nbNodes; ++iVar, ++iCom )
1305         {
1306           TTriangleFacet t012( nInd[ iQ * ( iCom             )],
1307                                nInd[ iQ * ( (iCom+1)%nbNodes )],
1308                                nInd[ iQ * ( (iCom+2)%nbNodes )]);
1309           TTriangleFacet t023( nInd[ iQ * ( iCom             )],
1310                                nInd[ iQ * ( (iCom+2)%nbNodes )],
1311                                nInd[ iQ * ( (iCom+3)%nbNodes )]);
1312           if ( t012.hasAdjacentTetra( vol.Element() ) && t023.hasAdjacentTetra( vol.Element() ))
1313           {
1314             triaSplits.push_back( t012 );
1315             triaSplits.push_back( t023 );
1316             break;
1317           }
1318         }
1319       }
1320       if ( !triaSplits.empty() )
1321         hasAdjacentSplits = true;
1322     }
1323
1324     // Among variants of split method select one compliant with adjacent volumes
1325
1326     TSplitMethod method;
1327     if ( !vol.Element()->IsPoly() && !is24TetMode )
1328     {
1329       int nbVariants = 2, nbTet = 0;
1330       const int** connVariants = 0;
1331       switch ( vol.Element()->GetEntityType() )
1332       {
1333       case SMDSEntity_Hexa:
1334       case SMDSEntity_Quad_Hexa:
1335         if ( theMethodFlags == SMESH_MeshEditor::HEXA_TO_5 )
1336           connVariants = theHexTo5, nbTet = 5;
1337         else
1338           connVariants = theHexTo6, nbTet = 6, nbVariants = 4;
1339         break;
1340       case SMDSEntity_Pyramid:
1341       case SMDSEntity_Quad_Pyramid:
1342         connVariants = thePyraTo2;  nbTet = 2;
1343         break;
1344       case SMDSEntity_Penta:
1345       case SMDSEntity_Quad_Penta:
1346         connVariants = thePentaTo3; nbTet = 3; nbVariants = 6;
1347         break;
1348       default:
1349         nbVariants = 0;
1350       }
1351       for ( int variant = 0; variant < nbVariants && method._nbTetra == 0; ++variant )
1352       {
1353         // check method compliancy with adjacent tetras,
1354         // all found splits must be among facets of tetras described by this method
1355         method = TSplitMethod( nbTet, connVariants[variant] );
1356         if ( hasAdjacentSplits && method._nbTetra > 0 )
1357         {
1358           bool facetCreated = true;
1359           for ( int iF = 0; facetCreated && iF < triaSplitsByFace.size(); ++iF )
1360           {
1361             list< TTriangleFacet >::const_iterator facet = triaSplitsByFace[iF].begin();
1362             for ( ; facetCreated && facet != triaSplitsByFace[iF].end(); ++facet )
1363               facetCreated = method.hasFacet( *facet );
1364           }
1365           if ( !facetCreated )
1366             method = TSplitMethod(0); // incompatible method
1367         }
1368       }
1369     }
1370     if ( method._nbTetra < 1 )
1371     {
1372       // No standard method is applicable, use a generic solution:
1373       // each facet of a volume is split into triangles and
1374       // each of triangles and a volume barycenter form a tetrahedron.
1375
1376       int* connectivity = new int[ maxTetConnSize + 1 ];
1377       method._connectivity = connectivity;
1378       method._ownConn = true;
1379       method._baryNode = true;
1380
1381       int connSize = 0;
1382       int baryCenInd = vol.NbNodes();
1383       for ( int iF = 0; iF < vol.NbFaces(); ++iF )
1384       {
1385         const int nbNodes = vol.NbFaceNodes( iF ) / iQ;
1386         const int*   nInd = vol.GetFaceNodesIndices( iF );
1387         // find common node of triangle facets of tetra to create
1388         int iCommon = 0; // index in linear numeration
1389         const list< TTriangleFacet >& triaSplits = triaSplitsByFace[ iF ];
1390         if ( !triaSplits.empty() )
1391         {
1392           // by found facets
1393           const TTriangleFacet* facet = &triaSplits.front();
1394           for ( ; iCommon < nbNodes-1 ; ++iCommon )
1395             if ( facet->contains( nInd[ iQ * iCommon ]) &&
1396                  facet->contains( nInd[ iQ * ((iCommon+2)%nbNodes) ]))
1397               break;
1398         }
1399         else if ( nbNodes > 3 && !is24TetMode )
1400         {
1401           // find the best method of splitting into triangles by aspect ratio
1402           SMESH::Controls::NumericalFunctorPtr aspectRatio( new SMESH::Controls::AspectRatio);
1403           map< double, int > badness2iCommon;
1404           const SMDS_MeshNode** nodes = vol.GetFaceNodes( iF );
1405           int nbVariants = ( nbNodes == 4 ? 2 : nbNodes );
1406           for ( int iVar = 0; iVar < nbVariants; ++iVar, ++iCommon )
1407             for ( int iLast = iCommon+2; iLast < iCommon+nbNodes; ++iLast )
1408             {
1409               SMDS_FaceOfNodes tria ( nodes[ iQ*( iCommon         )],
1410                                       nodes[ iQ*((iLast-1)%nbNodes)],
1411                                       nodes[ iQ*((iLast  )%nbNodes)]);
1412               double badness = getBadRate( &tria, aspectRatio );
1413               badness2iCommon.insert( make_pair( badness, iCommon ));
1414             }
1415           // use iCommon with lowest badness
1416           iCommon = badness2iCommon.begin()->second;
1417         }
1418         if ( iCommon >= nbNodes )
1419           iCommon = 0; // something wrong
1420
1421         // fill connectivity of tetrahedra based on a current face
1422         int nbTet = nbNodes - 2;
1423         if ( is24TetMode && nbNodes > 3 && triaSplits.empty())
1424         {
1425           method._faceBaryNode.insert( make_pair( iF, (const SMDS_MeshNode*)0 ));
1426           int faceBaryCenInd = baryCenInd + method._faceBaryNode.size();
1427           nbTet = nbNodes;
1428           for ( int i = 0; i < nbTet; ++i )
1429           {
1430             int i1 = i, i2 = (i+1) % nbNodes;
1431             if ( !vol.IsFaceExternal( iF )) swap( i1, i2 );
1432             connectivity[ connSize++ ] = nInd[ iQ * i1 ];
1433             connectivity[ connSize++ ] = nInd[ iQ * i2 ];
1434             connectivity[ connSize++ ] = faceBaryCenInd;
1435             connectivity[ connSize++ ] = baryCenInd;
1436           }
1437         }
1438         else
1439         {
1440           for ( int i = 0; i < nbTet; ++i )
1441           {
1442             int i1 = (iCommon+1+i) % nbNodes, i2 = (iCommon+2+i) % nbNodes;
1443             if ( !vol.IsFaceExternal( iF )) swap( i1, i2 );
1444             connectivity[ connSize++ ] = nInd[ iQ * iCommon ];
1445             connectivity[ connSize++ ] = nInd[ iQ * i1 ];
1446             connectivity[ connSize++ ] = nInd[ iQ * i2 ];
1447             connectivity[ connSize++ ] = baryCenInd;
1448           }
1449         }
1450         method._nbTetra += nbTet;
1451       }
1452       connectivity[ connSize++ ] = -1;
1453     }
1454     return method;
1455   }
1456   //================================================================================
1457   /*!
1458    * \brief Check if there is a tetraherdon adjacent to the given element via this facet
1459    */
1460   //================================================================================
1461
1462   bool TTriangleFacet::hasAdjacentTetra( const SMDS_MeshElement* elem ) const
1463   {
1464     // find the tetrahedron including the three nodes of facet
1465     const SMDS_MeshNode* n1 = elem->GetNode(_n1);
1466     const SMDS_MeshNode* n2 = elem->GetNode(_n2);
1467     const SMDS_MeshNode* n3 = elem->GetNode(_n3);
1468     SMDS_ElemIteratorPtr volIt1 = n1->GetInverseElementIterator(SMDSAbs_Volume);
1469     while ( volIt1->more() )
1470     {
1471       const SMDS_MeshElement* v = volIt1->next();
1472       if ( v->GetEntityType() != ( v->IsQuadratic() ? SMDSEntity_Quad_Tetra : SMDSEntity_Tetra ))
1473         continue;
1474       SMDS_ElemIteratorPtr volIt2 = n2->GetInverseElementIterator(SMDSAbs_Volume);
1475       while ( volIt2->more() )
1476         if ( v != volIt2->next() )
1477           continue;
1478       SMDS_ElemIteratorPtr volIt3 = n3->GetInverseElementIterator(SMDSAbs_Volume);
1479       while ( volIt3->more() )
1480         if ( v == volIt3->next() )
1481           return true;
1482     }
1483     return false;
1484   }
1485
1486   //=======================================================================
1487   /*!
1488    * \brief A key of a face of volume
1489    */
1490   //=======================================================================
1491
1492   struct TVolumeFaceKey: pair< int, pair< int, int> >
1493   {
1494     TVolumeFaceKey( SMDS_VolumeTool& vol, int iF )
1495     {
1496       TIDSortedNodeSet sortedNodes;
1497       const int iQ = vol.Element()->IsQuadratic() ? 2 : 1;
1498       int nbNodes = vol.NbFaceNodes( iF );
1499       const SMDS_MeshNode** fNodes = vol.GetFaceNodes( iF );
1500       for ( int i = 0; i < nbNodes; i += iQ )
1501         sortedNodes.insert( fNodes[i] );
1502       TIDSortedNodeSet::iterator n = sortedNodes.begin();
1503       first = (*(n++))->GetID();
1504       second.first = (*(n++))->GetID();
1505       second.second = (*(n++))->GetID();
1506     }
1507   };
1508 } // namespace
1509
1510 //=======================================================================
1511 //function : SplitVolumesIntoTetra
1512 //purpose  : Split volumic elements into tetrahedra.
1513 //=======================================================================
1514
1515 void SMESH_MeshEditor::SplitVolumesIntoTetra (const TIDSortedElemSet & theElems,
1516                                               const int                theMethodFlags)
1517 {
1518   // std-like iterator on coordinates of nodes of mesh element
1519   typedef SMDS_StdIterator< TNodeXYZ, SMDS_ElemIteratorPtr > NXyzIterator;
1520   NXyzIterator xyzEnd;
1521
1522   SMDS_VolumeTool    volTool;
1523   SMESH_MesherHelper helper( *GetMesh());
1524
1525   SMESHDS_SubMesh* subMesh = GetMeshDS()->MeshElements(1);
1526   SMESHDS_SubMesh* fSubMesh = subMesh;
1527   
1528   SMESH_SequenceOfElemPtr newNodes, newElems;
1529
1530   // map face of volume to it's baricenrtic node
1531   map< TVolumeFaceKey, const SMDS_MeshNode* > volFace2BaryNode;
1532   double bc[3];
1533
1534   TIDSortedElemSet::const_iterator elem = theElems.begin();
1535   for ( ; elem != theElems.end(); ++elem )
1536   {
1537     SMDSAbs_EntityType geomType = (*elem)->GetEntityType();
1538     if ( geomType <= SMDSEntity_Quad_Tetra )
1539       continue; // tetra or face or ...
1540
1541     if ( !volTool.Set( *elem )) continue; // not volume? strange...
1542
1543     TSplitMethod splitMethod = getSplitMethod( volTool, theMethodFlags );
1544     if ( splitMethod._nbTetra < 1 ) continue;
1545
1546     // find submesh to add new tetras to
1547     if ( !subMesh || !subMesh->Contains( *elem ))
1548     {
1549       int shapeID = FindShape( *elem );
1550       helper.SetSubShape( shapeID ); // helper will add tetras to the found submesh
1551       subMesh = GetMeshDS()->MeshElements( shapeID );
1552     }
1553     int iQ;
1554     if ( (*elem)->IsQuadratic() )
1555     {
1556       iQ = 2;
1557       // add quadratic links to the helper
1558       for ( int iF = 0; iF < volTool.NbFaces(); ++iF )
1559       {
1560         const SMDS_MeshNode** fNodes = volTool.GetFaceNodes( iF );
1561         for ( int iN = 0; iN < volTool.NbFaceNodes( iF ); iN += iQ )
1562           helper.AddTLinkNode( fNodes[iF], fNodes[iF+2], fNodes[iF+1] );
1563       }
1564       helper.SetIsQuadratic( true );
1565     }
1566     else
1567     {
1568       iQ = 1;
1569       helper.SetIsQuadratic( false );
1570     }
1571     vector<const SMDS_MeshNode*> nodes( (*elem)->begin_nodes(), (*elem)->end_nodes() );
1572     if ( splitMethod._baryNode )
1573     {
1574       // make a node at barycenter
1575       volTool.GetBaryCenter( bc[0], bc[1], bc[2] );
1576       SMDS_MeshNode* gcNode = helper.AddNode( bc[0], bc[1], bc[2] );
1577       nodes.push_back( gcNode );
1578       newNodes.Append( gcNode );
1579     }
1580     if ( !splitMethod._faceBaryNode.empty() )
1581     {
1582       // make or find baricentric nodes of faces
1583       map<int, const SMDS_MeshNode*>::iterator iF_n = splitMethod._faceBaryNode.begin();
1584       for ( ; iF_n != splitMethod._faceBaryNode.end(); ++iF_n )
1585       {
1586         map< TVolumeFaceKey, const SMDS_MeshNode* >::iterator f_n =
1587           volFace2BaryNode.insert
1588           ( make_pair( TVolumeFaceKey( volTool,iF_n->first ), (const SMDS_MeshNode*)0) ).first;
1589         if ( !f_n->second )
1590         {
1591           volTool.GetFaceBaryCenter( iF_n->first, bc[0], bc[1], bc[2] );
1592           newNodes.Append( f_n->second = helper.AddNode( bc[0], bc[1], bc[2] ));
1593         }
1594         nodes.push_back( iF_n->second = f_n->second );
1595       }
1596     }
1597
1598     // make tetras
1599     helper.SetElementsOnShape( true );
1600     vector<const SMDS_MeshElement* > tetras( splitMethod._nbTetra ); // splits of a volume
1601     const int* tetConn = splitMethod._connectivity;
1602     for ( int i = 0; i < splitMethod._nbTetra; ++i, tetConn += 4 )
1603       newElems.Append( tetras[ i ] = helper.AddVolume( nodes[ tetConn[0] ],
1604                                                        nodes[ tetConn[1] ],
1605                                                        nodes[ tetConn[2] ],
1606                                                        nodes[ tetConn[3] ]));
1607
1608     ReplaceElemInGroups( *elem, tetras, GetMeshDS() );
1609
1610     // Split faces on sides of the split volume
1611
1612     const SMDS_MeshNode** volNodes = volTool.GetNodes();
1613     for ( int iF = 0; iF < volTool.NbFaces(); ++iF )
1614     {
1615       const int nbNodes = volTool.NbFaceNodes( iF ) / iQ;
1616       if ( nbNodes < 4 ) continue;
1617
1618       // find an existing face
1619       vector<const SMDS_MeshNode*> fNodes( volTool.GetFaceNodes( iF ),
1620                                            volTool.GetFaceNodes( iF ) + nbNodes*iQ );
1621       while ( const SMDS_MeshElement* face = GetMeshDS()->FindFace( fNodes ))
1622       {
1623         // make triangles
1624         helper.SetElementsOnShape( false );
1625         vector< const SMDS_MeshElement* > triangles;
1626
1627         map<int, const SMDS_MeshNode*>::iterator iF_n = splitMethod._faceBaryNode.find(iF);
1628         if ( iF_n != splitMethod._faceBaryNode.end() )
1629         {
1630           for ( int iN = 0; iN < nbNodes*iQ; iN += iQ )
1631           {
1632             const SMDS_MeshNode* n1 = fNodes[iN];
1633             const SMDS_MeshNode *n2 = fNodes[(iN+iQ)%nbNodes*iQ];
1634             const SMDS_MeshNode *n3 = iF_n->second;
1635             if ( !volTool.IsFaceExternal( iF ))
1636               swap( n2, n3 );
1637             triangles.push_back( helper.AddFace( n1,n2,n3 ));
1638           }
1639         }
1640         else
1641         {
1642           // among possible triangles create ones discribed by split method
1643           const int* nInd = volTool.GetFaceNodesIndices( iF );
1644           int nbVariants = ( nbNodes == 4 ? 2 : nbNodes );
1645           int iCom = 0; // common node of triangle faces to split into
1646           list< TTriangleFacet > facets;
1647           for ( int iVar = 0; iVar < nbVariants; ++iVar, ++iCom )
1648           {
1649             TTriangleFacet t012( nInd[ iQ * ( iCom                )],
1650                                  nInd[ iQ * ( (iCom+1)%nbNodes )],
1651                                  nInd[ iQ * ( (iCom+2)%nbNodes )]);
1652             TTriangleFacet t023( nInd[ iQ * ( iCom                )],
1653                                  nInd[ iQ * ( (iCom+2)%nbNodes )],
1654                                  nInd[ iQ * ( (iCom+3)%nbNodes )]);
1655             if ( splitMethod.hasFacet( t012 ) && splitMethod.hasFacet( t023 ))
1656             {
1657               facets.push_back( t012 );
1658               facets.push_back( t023 );
1659               for ( int iLast = iCom+4; iLast < iCom+nbNodes; ++iLast )
1660                 facets.push_back( TTriangleFacet( nInd[ iQ * ( iCom             )],
1661                                                   nInd[ iQ * ((iLast-1)%nbNodes )],
1662                                                   nInd[ iQ * ((iLast  )%nbNodes )]));
1663               break;
1664             }
1665           }
1666           list< TTriangleFacet >::iterator facet = facets.begin();
1667           for ( ; facet != facets.end(); ++facet )
1668           {
1669             if ( !volTool.IsFaceExternal( iF ))
1670               swap( facet->_n2, facet->_n3 );
1671             triangles.push_back( helper.AddFace( volNodes[ facet->_n1 ],
1672                                                  volNodes[ facet->_n2 ],
1673                                                  volNodes[ facet->_n3 ]));
1674           }
1675         }
1676         // find submesh to add new triangles in
1677         if ( !fSubMesh || !fSubMesh->Contains( face ))
1678         {
1679           int shapeID = FindShape( face );
1680           fSubMesh = GetMeshDS()->MeshElements( shapeID );
1681         }
1682         for ( int i = 0; i < triangles.size(); ++i )
1683         {
1684           if ( !triangles.back() ) continue;
1685           if ( fSubMesh )
1686             fSubMesh->AddElement( triangles.back());
1687           newElems.Append( triangles.back() );
1688         }
1689         ReplaceElemInGroups( face, triangles, GetMeshDS() );
1690         GetMeshDS()->RemoveFreeElement( face, fSubMesh, /*fromGroups=*/false );
1691       }
1692
1693     } // loop on volume faces to split them into triangles
1694
1695     GetMeshDS()->RemoveFreeElement( *elem, subMesh, /*fromGroups=*/false );
1696
1697   } // loop on volumes to split
1698
1699   myLastCreatedNodes = newNodes;
1700   myLastCreatedElems = newElems;
1701 }
1702
1703 //=======================================================================
1704 //function : AddToSameGroups
1705 //purpose  : add elemToAdd to the groups the elemInGroups belongs to
1706 //=======================================================================
1707
1708 void SMESH_MeshEditor::AddToSameGroups (const SMDS_MeshElement* elemToAdd,
1709                                         const SMDS_MeshElement* elemInGroups,
1710                                         SMESHDS_Mesh *          aMesh)
1711 {
1712   const set<SMESHDS_GroupBase*>& groups = aMesh->GetGroups();
1713   if (!groups.empty()) {
1714     set<SMESHDS_GroupBase*>::const_iterator grIt = groups.begin();
1715     for ( ; grIt != groups.end(); grIt++ ) {
1716       SMESHDS_Group* group = dynamic_cast<SMESHDS_Group*>( *grIt );
1717       if ( group && group->Contains( elemInGroups ))
1718         group->SMDSGroup().Add( elemToAdd );
1719     }
1720   }
1721 }
1722
1723
1724 //=======================================================================
1725 //function : RemoveElemFromGroups
1726 //purpose  : Remove removeelem to the groups the elemInGroups belongs to
1727 //=======================================================================
1728 void SMESH_MeshEditor::RemoveElemFromGroups (const SMDS_MeshElement* removeelem,
1729                                              SMESHDS_Mesh *          aMesh)
1730 {
1731   const set<SMESHDS_GroupBase*>& groups = aMesh->GetGroups();
1732   if (!groups.empty())
1733   {
1734     set<SMESHDS_GroupBase*>::const_iterator GrIt = groups.begin();
1735     for (; GrIt != groups.end(); GrIt++)
1736     {
1737       SMESHDS_Group* grp = dynamic_cast<SMESHDS_Group*>(*GrIt);
1738       if (!grp || grp->IsEmpty()) continue;
1739       grp->SMDSGroup().Remove(removeelem);
1740     }
1741   }
1742 }
1743
1744 //================================================================================
1745 /*!
1746  * \brief Replace elemToRm by elemToAdd in the all groups
1747  */
1748 //================================================================================
1749
1750 void SMESH_MeshEditor::ReplaceElemInGroups (const SMDS_MeshElement* elemToRm,
1751                                             const SMDS_MeshElement* elemToAdd,
1752                                             SMESHDS_Mesh *          aMesh)
1753 {
1754   const set<SMESHDS_GroupBase*>& groups = aMesh->GetGroups();
1755   if (!groups.empty()) {
1756     set<SMESHDS_GroupBase*>::const_iterator grIt = groups.begin();
1757     for ( ; grIt != groups.end(); grIt++ ) {
1758       SMESHDS_Group* group = dynamic_cast<SMESHDS_Group*>( *grIt );
1759       if ( group && group->SMDSGroup().Remove( elemToRm ) && elemToAdd )
1760         group->SMDSGroup().Add( elemToAdd );
1761     }
1762   }
1763 }
1764
1765 //================================================================================
1766 /*!
1767  * \brief Replace elemToRm by elemToAdd in the all groups
1768  */
1769 //================================================================================
1770
1771 void SMESH_MeshEditor::ReplaceElemInGroups (const SMDS_MeshElement*                elemToRm,
1772                                             const vector<const SMDS_MeshElement*>& elemToAdd,
1773                                             SMESHDS_Mesh *                         aMesh)
1774 {
1775   const set<SMESHDS_GroupBase*>& groups = aMesh->GetGroups();
1776   if (!groups.empty())
1777   {
1778     set<SMESHDS_GroupBase*>::const_iterator grIt = groups.begin();
1779     for ( ; grIt != groups.end(); grIt++ ) {
1780       SMESHDS_Group* group = dynamic_cast<SMESHDS_Group*>( *grIt );
1781       if ( group && group->SMDSGroup().Remove( elemToRm ) )
1782         for ( int i = 0; i < elemToAdd.size(); ++i )
1783           group->SMDSGroup().Add( elemToAdd[ i ] );
1784     }
1785   }
1786 }
1787
1788 //=======================================================================
1789 //function : QuadToTri
1790 //purpose  : Cut quadrangles into triangles.
1791 //           theCrit is used to select a diagonal to cut
1792 //=======================================================================
1793
1794 bool SMESH_MeshEditor::QuadToTri (TIDSortedElemSet & theElems,
1795                                   const bool         the13Diag)
1796 {
1797   myLastCreatedElems.Clear();
1798   myLastCreatedNodes.Clear();
1799
1800   MESSAGE( "::QuadToTri()" );
1801
1802   SMESHDS_Mesh * aMesh = GetMeshDS();
1803
1804   Handle(Geom_Surface) surface;
1805   SMESH_MesherHelper   helper( *GetMesh() );
1806
1807   TIDSortedElemSet::iterator itElem;
1808   for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
1809     const SMDS_MeshElement* elem = *itElem;
1810     if ( !elem || elem->GetType() != SMDSAbs_Face )
1811       continue;
1812     bool isquad = elem->NbNodes()==4 || elem->NbNodes()==8;
1813     if(!isquad) continue;
1814
1815     if(elem->NbNodes()==4) {
1816       // retrieve element nodes
1817       const SMDS_MeshNode* aNodes [4];
1818       SMDS_ElemIteratorPtr itN = elem->nodesIterator();
1819       int i = 0;
1820       while ( itN->more() )
1821         aNodes[ i++ ] = static_cast<const SMDS_MeshNode*>( itN->next() );
1822
1823       int aShapeId = FindShape( elem );
1824       const SMDS_MeshElement* newElem = 0;
1825       if ( the13Diag ) {
1826         aMesh->ChangeElementNodes( elem, aNodes, 3 );
1827         newElem = aMesh->AddFace( aNodes[2], aNodes[3], aNodes[0] );
1828       }
1829       else {
1830         aMesh->ChangeElementNodes( elem, &aNodes[1], 3 );
1831         newElem = aMesh->AddFace( aNodes[3], aNodes[0], aNodes[1] );
1832       }
1833       myLastCreatedElems.Append(newElem);
1834       // put a new triangle on the same shape and add to the same groups
1835       if ( aShapeId )
1836         aMesh->SetMeshElementOnShape( newElem, aShapeId );
1837       AddToSameGroups( newElem, elem, aMesh );
1838     }
1839
1840     // Quadratic quadrangle
1841
1842     if( elem->NbNodes()==8 && elem->IsQuadratic() ) {
1843
1844       // get surface elem is on
1845       int aShapeId = FindShape( elem );
1846       if ( aShapeId != helper.GetSubShapeID() ) {
1847         surface.Nullify();
1848         TopoDS_Shape shape;
1849         if ( aShapeId > 0 )
1850           shape = aMesh->IndexToShape( aShapeId );
1851         if ( !shape.IsNull() && shape.ShapeType() == TopAbs_FACE ) {
1852           TopoDS_Face face = TopoDS::Face( shape );
1853           surface = BRep_Tool::Surface( face );
1854           if ( !surface.IsNull() )
1855             helper.SetSubShape( shape );
1856         }
1857       }
1858
1859       const SMDS_MeshNode* aNodes [8];
1860       const SMDS_MeshNode* inFaceNode = 0;
1861       SMDS_ElemIteratorPtr itN = elem->nodesIterator();
1862       int i = 0;
1863       while ( itN->more() ) {
1864         aNodes[ i++ ] = static_cast<const SMDS_MeshNode*>( itN->next() );
1865         if ( !inFaceNode && helper.GetNodeUVneedInFaceNode() &&
1866              aNodes[ i-1 ]->GetPosition()->GetTypeOfPosition() == SMDS_TOP_FACE )
1867         {
1868           inFaceNode = aNodes[ i-1 ];
1869         }
1870       }
1871
1872       // find middle point for (0,1,2,3)
1873       // and create a node in this point;
1874       gp_XYZ p( 0,0,0 );
1875       if ( surface.IsNull() ) {
1876         for(i=0; i<4; i++)
1877           p += gp_XYZ(aNodes[i]->X(), aNodes[i]->Y(), aNodes[i]->Z() );
1878         p /= 4;
1879       }
1880       else {
1881         TopoDS_Face geomFace = TopoDS::Face( helper.GetSubShape() );
1882         gp_XY uv( 0,0 );
1883         for(i=0; i<4; i++)
1884           uv += helper.GetNodeUV( geomFace, aNodes[i], inFaceNode );
1885         uv /= 4.;
1886         p = surface->Value( uv.X(), uv.Y() ).XYZ();
1887       }
1888       const SMDS_MeshNode* newN = aMesh->AddNode( p.X(), p.Y(), p.Z() );
1889       myLastCreatedNodes.Append(newN);
1890
1891       // create a new element
1892       const SMDS_MeshElement* newElem = 0;
1893       const SMDS_MeshNode* N[6];
1894       if ( the13Diag ) {
1895         N[0] = aNodes[0];
1896         N[1] = aNodes[1];
1897         N[2] = aNodes[2];
1898         N[3] = aNodes[4];
1899         N[4] = aNodes[5];
1900         N[5] = newN;
1901         newElem = aMesh->AddFace(aNodes[2], aNodes[3], aNodes[0],
1902                                  aNodes[6], aNodes[7], newN );
1903       }
1904       else {
1905         N[0] = aNodes[1];
1906         N[1] = aNodes[2];
1907         N[2] = aNodes[3];
1908         N[3] = aNodes[5];
1909         N[4] = aNodes[6];
1910         N[5] = newN;
1911         newElem = aMesh->AddFace(aNodes[3], aNodes[0], aNodes[1],
1912                                  aNodes[7], aNodes[4], newN );
1913       }
1914       myLastCreatedElems.Append(newElem);
1915       aMesh->ChangeElementNodes( elem, N, 6 );
1916       // put a new triangle on the same shape and add to the same groups
1917       if ( aShapeId )
1918         aMesh->SetMeshElementOnShape( newElem, aShapeId );
1919       AddToSameGroups( newElem, elem, aMesh );
1920     }
1921   }
1922
1923   return true;
1924 }
1925
1926 //=======================================================================
1927 //function : getAngle
1928 //purpose  :
1929 //=======================================================================
1930
1931 double getAngle(const SMDS_MeshElement * tr1,
1932                 const SMDS_MeshElement * tr2,
1933                 const SMDS_MeshNode *    n1,
1934                 const SMDS_MeshNode *    n2)
1935 {
1936   double angle = 2*PI; // bad angle
1937
1938   // get normals
1939   SMESH::Controls::TSequenceOfXYZ P1, P2;
1940   if ( !SMESH::Controls::NumericalFunctor::GetPoints( tr1, P1 ) ||
1941        !SMESH::Controls::NumericalFunctor::GetPoints( tr2, P2 ))
1942     return angle;
1943   gp_Vec N1,N2;
1944   if(!tr1->IsQuadratic())
1945     N1 = gp_Vec( P1(2) - P1(1) ) ^ gp_Vec( P1(3) - P1(1) );
1946   else
1947     N1 = gp_Vec( P1(3) - P1(1) ) ^ gp_Vec( P1(5) - P1(1) );
1948   if ( N1.SquareMagnitude() <= gp::Resolution() )
1949     return angle;
1950   if(!tr2->IsQuadratic())
1951     N2 = gp_Vec( P2(2) - P2(1) ) ^ gp_Vec( P2(3) - P2(1) );
1952   else
1953     N2 = gp_Vec( P2(3) - P2(1) ) ^ gp_Vec( P2(5) - P2(1) );
1954   if ( N2.SquareMagnitude() <= gp::Resolution() )
1955     return angle;
1956
1957   // find the first diagonal node n1 in the triangles:
1958   // take in account a diagonal link orientation
1959   const SMDS_MeshElement *nFirst[2], *tr[] = { tr1, tr2 };
1960   for ( int t = 0; t < 2; t++ ) {
1961     SMDS_ElemIteratorPtr it = tr[ t ]->nodesIterator();
1962     int i = 0, iDiag = -1;
1963     while ( it->more()) {
1964       const SMDS_MeshElement *n = it->next();
1965       if ( n == n1 || n == n2 )
1966         if ( iDiag < 0)
1967           iDiag = i;
1968         else {
1969           if ( i - iDiag == 1 )
1970             nFirst[ t ] = ( n == n1 ? n2 : n1 );
1971           else
1972             nFirst[ t ] = n;
1973           break;
1974         }
1975       i++;
1976     }
1977   }
1978   if ( nFirst[ 0 ] == nFirst[ 1 ] )
1979     N2.Reverse();
1980
1981   angle = N1.Angle( N2 );
1982   //SCRUTE( angle );
1983   return angle;
1984 }
1985
1986 // =================================================
1987 // class generating a unique ID for a pair of nodes
1988 // and able to return nodes by that ID
1989 // =================================================
1990 class LinkID_Gen {
1991 public:
1992
1993   LinkID_Gen( const SMESHDS_Mesh* theMesh )
1994     :myMesh( theMesh ), myMaxID( theMesh->MaxNodeID() + 1)
1995   {}
1996
1997   long GetLinkID (const SMDS_MeshNode * n1,
1998                   const SMDS_MeshNode * n2) const
1999   {
2000     return ( Min(n1->GetID(),n2->GetID()) * myMaxID + Max(n1->GetID(),n2->GetID()));
2001   }
2002
2003   bool GetNodes (const long             theLinkID,
2004                  const SMDS_MeshNode* & theNode1,
2005                  const SMDS_MeshNode* & theNode2) const
2006   {
2007     theNode1 = myMesh->FindNode( theLinkID / myMaxID );
2008     if ( !theNode1 ) return false;
2009     theNode2 = myMesh->FindNode( theLinkID % myMaxID );
2010     if ( !theNode2 ) return false;
2011     return true;
2012   }
2013
2014 private:
2015   LinkID_Gen();
2016   const SMESHDS_Mesh* myMesh;
2017   long                myMaxID;
2018 };
2019
2020
2021 //=======================================================================
2022 //function : TriToQuad
2023 //purpose  : Fuse neighbour triangles into quadrangles.
2024 //           theCrit is used to select a neighbour to fuse with.
2025 //           theMaxAngle is a max angle between element normals at which
2026 //           fusion is still performed.
2027 //=======================================================================
2028
2029 bool SMESH_MeshEditor::TriToQuad (TIDSortedElemSet &                   theElems,
2030                                   SMESH::Controls::NumericalFunctorPtr theCrit,
2031                                   const double                         theMaxAngle)
2032 {
2033   myLastCreatedElems.Clear();
2034   myLastCreatedNodes.Clear();
2035
2036   MESSAGE( "::TriToQuad()" );
2037
2038   if ( !theCrit.get() )
2039     return false;
2040
2041   SMESHDS_Mesh * aMesh = GetMeshDS();
2042
2043   // Prepare data for algo: build
2044   // 1. map of elements with their linkIDs
2045   // 2. map of linkIDs with their elements
2046
2047   map< SMESH_TLink, list< const SMDS_MeshElement* > > mapLi_listEl;
2048   map< SMESH_TLink, list< const SMDS_MeshElement* > >::iterator itLE;
2049   map< const SMDS_MeshElement*, set< SMESH_TLink > >  mapEl_setLi;
2050   map< const SMDS_MeshElement*, set< SMESH_TLink > >::iterator itEL;
2051
2052   TIDSortedElemSet::iterator itElem;
2053   for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
2054     const SMDS_MeshElement* elem = *itElem;
2055     if(!elem || elem->GetType() != SMDSAbs_Face ) continue;
2056     bool IsTria = elem->NbNodes()==3 || (elem->NbNodes()==6 && elem->IsQuadratic());
2057     if(!IsTria) continue;
2058
2059     // retrieve element nodes
2060     const SMDS_MeshNode* aNodes [4];
2061     SMDS_ElemIteratorPtr itN = elem->nodesIterator();
2062     int i = 0;
2063     while ( i<3 )
2064       aNodes[ i++ ] = cast2Node( itN->next() );
2065     aNodes[ 3 ] = aNodes[ 0 ];
2066
2067     // fill maps
2068     for ( i = 0; i < 3; i++ ) {
2069       SMESH_TLink link( aNodes[i], aNodes[i+1] );
2070       // check if elements sharing a link can be fused
2071       itLE = mapLi_listEl.find( link );
2072       if ( itLE != mapLi_listEl.end() ) {
2073         if ((*itLE).second.size() > 1 ) // consider only 2 elems adjacent by a link
2074           continue;
2075         const SMDS_MeshElement* elem2 = (*itLE).second.front();
2076         //if ( FindShape( elem ) != FindShape( elem2 ))
2077         //  continue; // do not fuse triangles laying on different shapes
2078         if ( getAngle( elem, elem2, aNodes[i], aNodes[i+1] ) > theMaxAngle )
2079           continue; // avoid making badly shaped quads
2080         (*itLE).second.push_back( elem );
2081       }
2082       else {
2083         mapLi_listEl[ link ].push_back( elem );
2084       }
2085       mapEl_setLi [ elem ].insert( link );
2086     }
2087   }
2088   // Clean the maps from the links shared by a sole element, ie
2089   // links to which only one element is bound in mapLi_listEl
2090
2091   for ( itLE = mapLi_listEl.begin(); itLE != mapLi_listEl.end(); itLE++ ) {
2092     int nbElems = (*itLE).second.size();
2093     if ( nbElems < 2  ) {
2094       const SMDS_MeshElement* elem = (*itLE).second.front();
2095       SMESH_TLink link = (*itLE).first;
2096       mapEl_setLi[ elem ].erase( link );
2097       if ( mapEl_setLi[ elem ].empty() )
2098         mapEl_setLi.erase( elem );
2099     }
2100   }
2101
2102   // Algo: fuse triangles into quadrangles
2103
2104   while ( ! mapEl_setLi.empty() ) {
2105     // Look for the start element:
2106     // the element having the least nb of shared links
2107     const SMDS_MeshElement* startElem = 0;
2108     int minNbLinks = 4;
2109     for ( itEL = mapEl_setLi.begin(); itEL != mapEl_setLi.end(); itEL++ ) {
2110       int nbLinks = (*itEL).second.size();
2111       if ( nbLinks < minNbLinks ) {
2112         startElem = (*itEL).first;
2113         minNbLinks = nbLinks;
2114         if ( minNbLinks == 1 )
2115           break;
2116       }
2117     }
2118
2119     // search elements to fuse starting from startElem or links of elements
2120     // fused earlyer - startLinks
2121     list< SMESH_TLink > startLinks;
2122     while ( startElem || !startLinks.empty() ) {
2123       while ( !startElem && !startLinks.empty() ) {
2124         // Get an element to start, by a link
2125         SMESH_TLink linkId = startLinks.front();
2126         startLinks.pop_front();
2127         itLE = mapLi_listEl.find( linkId );
2128         if ( itLE != mapLi_listEl.end() ) {
2129           list< const SMDS_MeshElement* > & listElem = (*itLE).second;
2130           list< const SMDS_MeshElement* >::iterator itE = listElem.begin();
2131           for ( ; itE != listElem.end() ; itE++ )
2132             if ( mapEl_setLi.find( (*itE) ) != mapEl_setLi.end() )
2133               startElem = (*itE);
2134           mapLi_listEl.erase( itLE );
2135         }
2136       }
2137
2138       if ( startElem ) {
2139         // Get candidates to be fused
2140         const SMDS_MeshElement *tr1 = startElem, *tr2 = 0, *tr3 = 0;
2141         const SMESH_TLink *link12, *link13;
2142         startElem = 0;
2143         ASSERT( mapEl_setLi.find( tr1 ) != mapEl_setLi.end() );
2144         set< SMESH_TLink >& setLi = mapEl_setLi[ tr1 ];
2145         ASSERT( !setLi.empty() );
2146         set< SMESH_TLink >::iterator itLi;
2147         for ( itLi = setLi.begin(); itLi != setLi.end(); itLi++ )
2148         {
2149           const SMESH_TLink & link = (*itLi);
2150           itLE = mapLi_listEl.find( link );
2151           if ( itLE == mapLi_listEl.end() )
2152             continue;
2153
2154           const SMDS_MeshElement* elem = (*itLE).second.front();
2155           if ( elem == tr1 )
2156             elem = (*itLE).second.back();
2157           mapLi_listEl.erase( itLE );
2158           if ( mapEl_setLi.find( elem ) == mapEl_setLi.end())
2159             continue;
2160           if ( tr2 ) {
2161             tr3 = elem;
2162             link13 = &link;
2163           }
2164           else {
2165             tr2 = elem;
2166             link12 = &link;
2167           }
2168
2169           // add other links of elem to list of links to re-start from
2170           set< SMESH_TLink >& links = mapEl_setLi[ elem ];
2171           set< SMESH_TLink >::iterator it;
2172           for ( it = links.begin(); it != links.end(); it++ ) {
2173             const SMESH_TLink& link2 = (*it);
2174             if ( link2 != link )
2175               startLinks.push_back( link2 );
2176           }
2177         }
2178
2179         // Get nodes of possible quadrangles
2180         const SMDS_MeshNode *n12 [4], *n13 [4];
2181         bool Ok12 = false, Ok13 = false;
2182         const SMDS_MeshNode *linkNode1, *linkNode2;
2183         if(tr2) {
2184           linkNode1 = link12->first;
2185           linkNode2 = link12->second;
2186           if ( tr2 && getQuadrangleNodes( n12, linkNode1, linkNode2, tr1, tr2 ))
2187             Ok12 = true;
2188         }
2189         if(tr3) {
2190           linkNode1 = link13->first;
2191           linkNode2 = link13->second;
2192           if ( tr3 && getQuadrangleNodes( n13, linkNode1, linkNode2, tr1, tr3 ))
2193             Ok13 = true;
2194         }
2195
2196         // Choose a pair to fuse
2197         if ( Ok12 && Ok13 ) {
2198           SMDS_FaceOfNodes quad12 ( n12[ 0 ], n12[ 1 ], n12[ 2 ], n12[ 3 ] );
2199           SMDS_FaceOfNodes quad13 ( n13[ 0 ], n13[ 1 ], n13[ 2 ], n13[ 3 ] );
2200           double aBadRate12 = getBadRate( &quad12, theCrit );
2201           double aBadRate13 = getBadRate( &quad13, theCrit );
2202           if (  aBadRate13 < aBadRate12 )
2203             Ok12 = false;
2204           else
2205             Ok13 = false;
2206         }
2207
2208         // Make quadrangles
2209         // and remove fused elems and removed links from the maps
2210         mapEl_setLi.erase( tr1 );
2211         if ( Ok12 ) {
2212           mapEl_setLi.erase( tr2 );
2213           mapLi_listEl.erase( *link12 );
2214           if(tr1->NbNodes()==3) {
2215             if( tr1->GetID() < tr2->GetID() ) {
2216               aMesh->ChangeElementNodes( tr1, n12, 4 );
2217               myLastCreatedElems.Append(tr1);
2218               aMesh->RemoveElement( tr2 );
2219             }
2220             else {
2221               aMesh->ChangeElementNodes( tr2, n12, 4 );
2222               myLastCreatedElems.Append(tr2);
2223               aMesh->RemoveElement( tr1);
2224             }
2225           }
2226           else {
2227             const SMDS_MeshNode* N1 [6];
2228             const SMDS_MeshNode* N2 [6];
2229             GetNodesFromTwoTria(tr1,tr2,N1,N2);
2230             // now we receive following N1 and N2 (using numeration as above image)
2231             // tria1 : (1 2 4 5 9 7)  and  tria2 : (3 4 2 8 9 6)
2232             // i.e. first nodes from both arrays determ new diagonal
2233             const SMDS_MeshNode* aNodes[8];
2234             aNodes[0] = N1[0];
2235             aNodes[1] = N1[1];
2236             aNodes[2] = N2[0];
2237             aNodes[3] = N2[1];
2238             aNodes[4] = N1[3];
2239             aNodes[5] = N2[5];
2240             aNodes[6] = N2[3];
2241             aNodes[7] = N1[5];
2242             if( tr1->GetID() < tr2->GetID() ) {
2243               GetMeshDS()->ChangeElementNodes( tr1, aNodes, 8 );
2244               myLastCreatedElems.Append(tr1);
2245               GetMeshDS()->RemoveElement( tr2 );
2246             }
2247             else {
2248               GetMeshDS()->ChangeElementNodes( tr2, aNodes, 8 );
2249               myLastCreatedElems.Append(tr2);
2250               GetMeshDS()->RemoveElement( tr1 );
2251             }
2252             // remove middle node (9)
2253             GetMeshDS()->RemoveNode( N1[4] );
2254           }
2255         }
2256         else if ( Ok13 ) {
2257           mapEl_setLi.erase( tr3 );
2258           mapLi_listEl.erase( *link13 );
2259           if(tr1->NbNodes()==3) {
2260             if( tr1->GetID() < tr2->GetID() ) {
2261               aMesh->ChangeElementNodes( tr1, n13, 4 );
2262               myLastCreatedElems.Append(tr1);
2263               aMesh->RemoveElement( tr3 );
2264             }
2265             else {
2266               aMesh->ChangeElementNodes( tr3, n13, 4 );
2267               myLastCreatedElems.Append(tr3);
2268               aMesh->RemoveElement( tr1 );
2269             }
2270           }
2271           else {
2272             const SMDS_MeshNode* N1 [6];
2273             const SMDS_MeshNode* N2 [6];
2274             GetNodesFromTwoTria(tr1,tr3,N1,N2);
2275             // now we receive following N1 and N2 (using numeration as above image)
2276             // tria1 : (1 2 4 5 9 7)  and  tria2 : (3 4 2 8 9 6)
2277             // i.e. first nodes from both arrays determ new diagonal
2278             const SMDS_MeshNode* aNodes[8];
2279             aNodes[0] = N1[0];
2280             aNodes[1] = N1[1];
2281             aNodes[2] = N2[0];
2282             aNodes[3] = N2[1];
2283             aNodes[4] = N1[3];
2284             aNodes[5] = N2[5];
2285             aNodes[6] = N2[3];
2286             aNodes[7] = N1[5];
2287             if( tr1->GetID() < tr2->GetID() ) {
2288               GetMeshDS()->ChangeElementNodes( tr1, aNodes, 8 );
2289               myLastCreatedElems.Append(tr1);
2290               GetMeshDS()->RemoveElement( tr3 );
2291             }
2292             else {
2293               GetMeshDS()->ChangeElementNodes( tr3, aNodes, 8 );
2294               myLastCreatedElems.Append(tr3);
2295               GetMeshDS()->RemoveElement( tr1 );
2296             }
2297             // remove middle node (9)
2298             GetMeshDS()->RemoveNode( N1[4] );
2299           }
2300         }
2301
2302         // Next element to fuse: the rejected one
2303         if ( tr3 )
2304           startElem = Ok12 ? tr3 : tr2;
2305
2306       } // if ( startElem )
2307     } // while ( startElem || !startLinks.empty() )
2308   } // while ( ! mapEl_setLi.empty() )
2309
2310   return true;
2311 }
2312
2313
2314 /*#define DUMPSO(txt) \
2315 //  cout << txt << endl;
2316 //=============================================================================
2317 //
2318 //
2319 //
2320 //=============================================================================
2321 static void swap( int i1, int i2, int idNodes[], gp_Pnt P[] )
2322 {
2323 if ( i1 == i2 )
2324 return;
2325 int tmp = idNodes[ i1 ];
2326 idNodes[ i1 ] = idNodes[ i2 ];
2327 idNodes[ i2 ] = tmp;
2328 gp_Pnt Ptmp = P[ i1 ];
2329 P[ i1 ] = P[ i2 ];
2330 P[ i2 ] = Ptmp;
2331 DUMPSO( i1 << "(" << idNodes[ i2 ] << ") <-> " << i2 << "(" << idNodes[ i1 ] << ")");
2332 }
2333
2334 //=======================================================================
2335 //function : SortQuadNodes
2336 //purpose  : Set 4 nodes of a quadrangle face in a good order.
2337 //           Swap 1<->2 or 2<->3 nodes and correspondingly return
2338 //           1 or 2 else 0.
2339 //=======================================================================
2340
2341 int SMESH_MeshEditor::SortQuadNodes (const SMDS_Mesh * theMesh,
2342 int               idNodes[] )
2343 {
2344   gp_Pnt P[4];
2345   int i;
2346   for ( i = 0; i < 4; i++ ) {
2347     const SMDS_MeshNode *n = theMesh->FindNode( idNodes[i] );
2348     if ( !n ) return 0;
2349     P[ i ].SetCoord( n->X(), n->Y(), n->Z() );
2350   }
2351
2352   gp_Vec V1(P[0], P[1]);
2353   gp_Vec V2(P[0], P[2]);
2354   gp_Vec V3(P[0], P[3]);
2355
2356   gp_Vec Cross1 = V1 ^ V2;
2357   gp_Vec Cross2 = V2 ^ V3;
2358
2359   i = 0;
2360   if (Cross1.Dot(Cross2) < 0)
2361   {
2362     Cross1 = V2 ^ V1;
2363     Cross2 = V1 ^ V3;
2364
2365     if (Cross1.Dot(Cross2) < 0)
2366       i = 2;
2367     else
2368       i = 1;
2369     swap ( i, i + 1, idNodes, P );
2370
2371     //     for ( int ii = 0; ii < 4; ii++ ) {
2372     //       const SMDS_MeshNode *n = theMesh->FindNode( idNodes[ii] );
2373     //       DUMPSO( ii << "(" << idNodes[ii] <<") : "<<n->X()<<" "<<n->Y()<<" "<<n->Z());
2374     //     }
2375   }
2376   return i;
2377 }
2378
2379 //=======================================================================
2380 //function : SortHexaNodes
2381 //purpose  : Set 8 nodes of a hexahedron in a good order.
2382 //           Return success status
2383 //=======================================================================
2384
2385 bool SMESH_MeshEditor::SortHexaNodes (const SMDS_Mesh * theMesh,
2386                                       int               idNodes[] )
2387 {
2388   gp_Pnt P[8];
2389   int i;
2390   DUMPSO( "INPUT: ========================================");
2391   for ( i = 0; i < 8; i++ ) {
2392     const SMDS_MeshNode *n = theMesh->FindNode( idNodes[i] );
2393     if ( !n ) return false;
2394     P[ i ].SetCoord( n->X(), n->Y(), n->Z() );
2395     DUMPSO( i << "(" << idNodes[i] <<") : "<<n->X()<<" "<<n->Y()<<" "<<n->Z());
2396   }
2397   DUMPSO( "========================================");
2398
2399
2400   set<int> faceNodes;  // ids of bottom face nodes, to be found
2401   set<int> checkedId1; // ids of tried 2-nd nodes
2402   Standard_Real leastDist = DBL_MAX; // dist of the 4-th node from 123 plane
2403   const Standard_Real tol = 1.e-6;   // tolerance to find nodes in plane
2404   int iMin, iLoop1 = 0;
2405
2406   // Loop to try the 2-nd nodes
2407
2408   while ( leastDist > DBL_MIN && ++iLoop1 < 8 )
2409   {
2410     // Find not checked 2-nd node
2411     for ( i = 1; i < 8; i++ )
2412       if ( checkedId1.find( idNodes[i] ) == checkedId1.end() ) {
2413         int id1 = idNodes[i];
2414         swap ( 1, i, idNodes, P );
2415         checkedId1.insert ( id1 );
2416         break;
2417       }
2418
2419     // Find the 3-d node so that 1-2-3 triangle to be on a hexa face,
2420     // ie that all but meybe one (id3 which is on the same face) nodes
2421     // lay on the same side from the triangle plane.
2422
2423     bool manyInPlane = false; // more than 4 nodes lay in plane
2424     int iLoop2 = 0;
2425     while ( ++iLoop2 < 6 ) {
2426
2427       // get 1-2-3 plane coeffs
2428       Standard_Real A, B, C, D;
2429       gp_Vec N = gp_Vec (P[0], P[1]).Crossed( gp_Vec (P[0], P[2]) );
2430       if ( N.SquareMagnitude() > gp::Resolution() )
2431       {
2432         gp_Pln pln ( P[0], N );
2433         pln.Coefficients( A, B, C, D );
2434
2435         // find the node (iMin) closest to pln
2436         Standard_Real dist[ 8 ], minDist = DBL_MAX;
2437         set<int> idInPln;
2438         for ( i = 3; i < 8; i++ ) {
2439           dist[i] = A * P[i].X() + B * P[i].Y() + C * P[i].Z() + D;
2440           if ( fabs( dist[i] ) < minDist ) {
2441             minDist = fabs( dist[i] );
2442             iMin = i;
2443           }
2444           if ( fabs( dist[i] ) <= tol )
2445             idInPln.insert( idNodes[i] );
2446         }
2447
2448         // there should not be more than 4 nodes in bottom plane
2449         if ( idInPln.size() > 1 )
2450         {
2451           DUMPSO( "### idInPln.size() = " << idInPln.size());
2452           // idInPlane does not contain the first 3 nodes
2453           if ( manyInPlane || idInPln.size() == 5)
2454             return false; // all nodes in one plane
2455           manyInPlane = true;
2456
2457           // set the 1-st node to be not in plane
2458           for ( i = 3; i < 8; i++ ) {
2459             if ( idInPln.find( idNodes[ i ] ) == idInPln.end() ) {
2460               DUMPSO( "### Reset 0-th node");
2461               swap( 0, i, idNodes, P );
2462               break;
2463             }
2464           }
2465
2466           // reset to re-check second nodes
2467           leastDist = DBL_MAX;
2468           faceNodes.clear();
2469           checkedId1.clear();
2470           iLoop1 = 0;
2471           break; // from iLoop2;
2472         }
2473
2474         // check that the other 4 nodes are on the same side
2475         bool sameSide = true;
2476         bool isNeg = dist[ iMin == 3 ? 4 : 3 ] <= 0.;
2477         for ( i = 3; sameSide && i < 8; i++ ) {
2478           if ( i != iMin )
2479             sameSide = ( isNeg == dist[i] <= 0.);
2480         }
2481
2482         // keep best solution
2483         if ( sameSide && minDist < leastDist ) {
2484           leastDist = minDist;
2485           faceNodes.clear();
2486           faceNodes.insert( idNodes[ 1 ] );
2487           faceNodes.insert( idNodes[ 2 ] );
2488           faceNodes.insert( idNodes[ iMin ] );
2489           DUMPSO( "loop " << iLoop2 << " id2 " << idNodes[ 1 ] << " id3 " << idNodes[ 2 ]
2490                   << " leastDist = " << leastDist);
2491           if ( leastDist <= DBL_MIN )
2492             break;
2493         }
2494       }
2495
2496       // set next 3-d node to check
2497       int iNext = 2 + iLoop2;
2498       if ( iNext < 8 ) {
2499         DUMPSO( "Try 2-nd");
2500         swap ( 2, iNext, idNodes, P );
2501       }
2502     } // while ( iLoop2 < 6 )
2503   } // iLoop1
2504
2505   if ( faceNodes.empty() ) return false;
2506
2507   // Put the faceNodes in proper places
2508   for ( i = 4; i < 8; i++ ) {
2509     if ( faceNodes.find( idNodes[ i ] ) != faceNodes.end() ) {
2510       // find a place to put
2511       int iTo = 1;
2512       while ( faceNodes.find( idNodes[ iTo ] ) != faceNodes.end() )
2513         iTo++;
2514       DUMPSO( "Set faceNodes");
2515       swap ( iTo, i, idNodes, P );
2516     }
2517   }
2518
2519
2520   // Set nodes of the found bottom face in good order
2521   DUMPSO( " Found bottom face: ");
2522   i = SortQuadNodes( theMesh, idNodes );
2523   if ( i ) {
2524     gp_Pnt Ptmp = P[ i ];
2525     P[ i ] = P[ i+1 ];
2526     P[ i+1 ] = Ptmp;
2527   }
2528   //   else
2529   //     for ( int ii = 0; ii < 4; ii++ ) {
2530   //       const SMDS_MeshNode *n = theMesh->FindNode( idNodes[ii] );
2531   //       DUMPSO( ii << "(" << idNodes[ii] <<") : "<<n->X()<<" "<<n->Y()<<" "<<n->Z());
2532   //    }
2533
2534   // Gravity center of the top and bottom faces
2535   gp_Pnt aGCb = ( P[0].XYZ() + P[1].XYZ() + P[2].XYZ() + P[3].XYZ() ) / 4.;
2536   gp_Pnt aGCt = ( P[4].XYZ() + P[5].XYZ() + P[6].XYZ() + P[7].XYZ() ) / 4.;
2537
2538   // Get direction from the bottom to the top face
2539   gp_Vec upDir ( aGCb, aGCt );
2540   Standard_Real upDirSize = upDir.Magnitude();
2541   if ( upDirSize <= gp::Resolution() ) return false;
2542   upDir / upDirSize;
2543
2544   // Assure that the bottom face normal points up
2545   gp_Vec Nb = gp_Vec (P[0], P[1]).Crossed( gp_Vec (P[0], P[2]) );
2546   Nb += gp_Vec (P[0], P[2]).Crossed( gp_Vec (P[0], P[3]) );
2547   if ( Nb.Dot( upDir ) < 0 ) {
2548     DUMPSO( "Reverse bottom face");
2549     swap( 1, 3, idNodes, P );
2550   }
2551
2552   // Find 5-th node - the one closest to the 1-st among the last 4 nodes.
2553   Standard_Real minDist = DBL_MAX;
2554   for ( i = 4; i < 8; i++ ) {
2555     // projection of P[i] to the plane defined by P[0] and upDir
2556     gp_Pnt Pp = P[i].Translated( upDir * ( upDir.Dot( gp_Vec( P[i], P[0] ))));
2557     Standard_Real sqDist = P[0].SquareDistance( Pp );
2558     if ( sqDist < minDist ) {
2559       minDist = sqDist;
2560       iMin = i;
2561     }
2562   }
2563   DUMPSO( "Set 4-th");
2564   swap ( 4, iMin, idNodes, P );
2565
2566   // Set nodes of the top face in good order
2567   DUMPSO( "Sort top face");
2568   i = SortQuadNodes( theMesh, &idNodes[4] );
2569   if ( i ) {
2570     i += 4;
2571     gp_Pnt Ptmp = P[ i ];
2572     P[ i ] = P[ i+1 ];
2573     P[ i+1 ] = Ptmp;
2574   }
2575
2576   // Assure that direction of the top face normal is from the bottom face
2577   gp_Vec Nt = gp_Vec (P[4], P[5]).Crossed( gp_Vec (P[4], P[6]) );
2578   Nt += gp_Vec (P[4], P[6]).Crossed( gp_Vec (P[4], P[7]) );
2579   if ( Nt.Dot( upDir ) < 0 ) {
2580     DUMPSO( "Reverse top face");
2581     swap( 5, 7, idNodes, P );
2582   }
2583
2584   //   DUMPSO( "OUTPUT: ========================================");
2585   //   for ( i = 0; i < 8; i++ ) {
2586   //     float *p = ugrid->GetPoint(idNodes[i]);
2587   //     DUMPSO( i << "(" << idNodes[i] << ") : " << p[0] << " " << p[1] << " " << p[2]);
2588   //   }
2589
2590   return true;
2591 }*/
2592
2593 //================================================================================
2594 /*!
2595  * \brief Return nodes linked to the given one
2596  * \param theNode - the node
2597  * \param linkedNodes - the found nodes
2598  * \param type - the type of elements to check
2599  *
2600  * Medium nodes are ignored
2601  */
2602 //================================================================================
2603
2604 void SMESH_MeshEditor::GetLinkedNodes( const SMDS_MeshNode* theNode,
2605                                        TIDSortedElemSet &   linkedNodes,
2606                                        SMDSAbs_ElementType  type )
2607 {
2608   SMDS_ElemIteratorPtr elemIt = theNode->GetInverseElementIterator(type);
2609   while ( elemIt->more() )
2610   {
2611     const SMDS_MeshElement* elem = elemIt->next();
2612     SMDS_ElemIteratorPtr nodeIt = elem->nodesIterator();
2613     if ( elem->GetType() == SMDSAbs_Volume )
2614     {
2615       SMDS_VolumeTool vol( elem );
2616       while ( nodeIt->more() ) {
2617         const SMDS_MeshNode* n = cast2Node( nodeIt->next() );
2618         if ( theNode != n && vol.IsLinked( theNode, n ))
2619           linkedNodes.insert( n );
2620       }
2621     }
2622     else
2623     {
2624       for ( int i = 0; nodeIt->more(); ++i ) {
2625         const SMDS_MeshNode* n = cast2Node( nodeIt->next() );
2626         if ( n == theNode ) {
2627           int iBefore = i - 1;
2628           int iAfter  = i + 1;
2629           if ( elem->IsQuadratic() ) {
2630             int nb = elem->NbNodes() / 2;
2631             iAfter  = SMESH_MesherHelper::WrapIndex( iAfter, nb );
2632             iBefore = SMESH_MesherHelper::WrapIndex( iBefore, nb );
2633           }
2634           linkedNodes.insert( elem->GetNodeWrap( iAfter ));
2635           linkedNodes.insert( elem->GetNodeWrap( iBefore ));
2636         }
2637       }
2638     }
2639   }
2640 }
2641
2642 //=======================================================================
2643 //function : laplacianSmooth
2644 //purpose  : pulls theNode toward the center of surrounding nodes directly
2645 //           connected to that node along an element edge
2646 //=======================================================================
2647
2648 void laplacianSmooth(const SMDS_MeshNode*                 theNode,
2649                      const Handle(Geom_Surface)&          theSurface,
2650                      map< const SMDS_MeshNode*, gp_XY* >& theUVMap)
2651 {
2652   // find surrounding nodes
2653
2654   TIDSortedElemSet nodeSet;
2655   SMESH_MeshEditor::GetLinkedNodes( theNode, nodeSet, SMDSAbs_Face );
2656
2657   // compute new coodrs
2658
2659   double coord[] = { 0., 0., 0. };
2660   TIDSortedElemSet::iterator nodeSetIt = nodeSet.begin();
2661   for ( ; nodeSetIt != nodeSet.end(); nodeSetIt++ ) {
2662     const SMDS_MeshNode* node = cast2Node(*nodeSetIt);
2663     if ( theSurface.IsNull() ) { // smooth in 3D
2664       coord[0] += node->X();
2665       coord[1] += node->Y();
2666       coord[2] += node->Z();
2667     }
2668     else { // smooth in 2D
2669       ASSERT( theUVMap.find( node ) != theUVMap.end() );
2670       gp_XY* uv = theUVMap[ node ];
2671       coord[0] += uv->X();
2672       coord[1] += uv->Y();
2673     }
2674   }
2675   int nbNodes = nodeSet.size();
2676   if ( !nbNodes )
2677     return;
2678   coord[0] /= nbNodes;
2679   coord[1] /= nbNodes;
2680
2681   if ( !theSurface.IsNull() ) {
2682     ASSERT( theUVMap.find( theNode ) != theUVMap.end() );
2683     theUVMap[ theNode ]->SetCoord( coord[0], coord[1] );
2684     gp_Pnt p3d = theSurface->Value( coord[0], coord[1] );
2685     coord[0] = p3d.X();
2686     coord[1] = p3d.Y();
2687     coord[2] = p3d.Z();
2688   }
2689   else
2690     coord[2] /= nbNodes;
2691
2692   // move node
2693
2694   const_cast< SMDS_MeshNode* >( theNode )->setXYZ(coord[0],coord[1],coord[2]);
2695 }
2696
2697 //=======================================================================
2698 //function : centroidalSmooth
2699 //purpose  : pulls theNode toward the element-area-weighted centroid of the
2700 //           surrounding elements
2701 //=======================================================================
2702
2703 void centroidalSmooth(const SMDS_MeshNode*                 theNode,
2704                       const Handle(Geom_Surface)&          theSurface,
2705                       map< const SMDS_MeshNode*, gp_XY* >& theUVMap)
2706 {
2707   gp_XYZ aNewXYZ(0.,0.,0.);
2708   SMESH::Controls::Area anAreaFunc;
2709   double totalArea = 0.;
2710   int nbElems = 0;
2711
2712   // compute new XYZ
2713
2714   SMDS_ElemIteratorPtr elemIt = theNode->GetInverseElementIterator(SMDSAbs_Face);
2715   while ( elemIt->more() )
2716   {
2717     const SMDS_MeshElement* elem = elemIt->next();
2718     nbElems++;
2719
2720     gp_XYZ elemCenter(0.,0.,0.);
2721     SMESH::Controls::TSequenceOfXYZ aNodePoints;
2722     SMDS_ElemIteratorPtr itN = elem->nodesIterator();
2723     int nn = elem->NbNodes();
2724     if(elem->IsQuadratic()) nn = nn/2;
2725     int i=0;
2726     //while ( itN->more() ) {
2727     while ( i<nn ) {
2728       const SMDS_MeshNode* aNode = static_cast<const SMDS_MeshNode*>( itN->next() );
2729       i++;
2730       gp_XYZ aP( aNode->X(), aNode->Y(), aNode->Z() );
2731       aNodePoints.push_back( aP );
2732       if ( !theSurface.IsNull() ) { // smooth in 2D
2733         ASSERT( theUVMap.find( aNode ) != theUVMap.end() );
2734         gp_XY* uv = theUVMap[ aNode ];
2735         aP.SetCoord( uv->X(), uv->Y(), 0. );
2736       }
2737       elemCenter += aP;
2738     }
2739     double elemArea = anAreaFunc.GetValue( aNodePoints );
2740     totalArea += elemArea;
2741     elemCenter /= nn;
2742     aNewXYZ += elemCenter * elemArea;
2743   }
2744   aNewXYZ /= totalArea;
2745   if ( !theSurface.IsNull() ) {
2746     theUVMap[ theNode ]->SetCoord( aNewXYZ.X(), aNewXYZ.Y() );
2747     aNewXYZ = theSurface->Value( aNewXYZ.X(), aNewXYZ.Y() ).XYZ();
2748   }
2749
2750   // move node
2751
2752   const_cast< SMDS_MeshNode* >( theNode )->setXYZ(aNewXYZ.X(),aNewXYZ.Y(),aNewXYZ.Z());
2753 }
2754
2755 //=======================================================================
2756 //function : getClosestUV
2757 //purpose  : return UV of closest projection
2758 //=======================================================================
2759
2760 static bool getClosestUV (Extrema_GenExtPS& projector,
2761                           const gp_Pnt&     point,
2762                           gp_XY &           result)
2763 {
2764   projector.Perform( point );
2765   if ( projector.IsDone() ) {
2766     double u, v, minVal = DBL_MAX;
2767     for ( int i = projector.NbExt(); i > 0; i-- )
2768       if ( projector.Value( i ) < minVal ) {
2769         minVal = projector.Value( i );
2770         projector.Point( i ).Parameter( u, v );
2771       }
2772     result.SetCoord( u, v );
2773     return true;
2774   }
2775   return false;
2776 }
2777
2778 //=======================================================================
2779 //function : Smooth
2780 //purpose  : Smooth theElements during theNbIterations or until a worst
2781 //           element has aspect ratio <= theTgtAspectRatio.
2782 //           Aspect Ratio varies in range [1.0, inf].
2783 //           If theElements is empty, the whole mesh is smoothed.
2784 //           theFixedNodes contains additionally fixed nodes. Nodes built
2785 //           on edges and boundary nodes are always fixed.
2786 //=======================================================================
2787
2788 void SMESH_MeshEditor::Smooth (TIDSortedElemSet &          theElems,
2789                                set<const SMDS_MeshNode*> & theFixedNodes,
2790                                const SmoothMethod          theSmoothMethod,
2791                                const int                   theNbIterations,
2792                                double                      theTgtAspectRatio,
2793                                const bool                  the2D)
2794 {
2795   myLastCreatedElems.Clear();
2796   myLastCreatedNodes.Clear();
2797
2798   MESSAGE((theSmoothMethod==LAPLACIAN ? "LAPLACIAN" : "CENTROIDAL") << "--::Smooth()");
2799
2800   if ( theTgtAspectRatio < 1.0 )
2801     theTgtAspectRatio = 1.0;
2802
2803   const double disttol = 1.e-16;
2804
2805   SMESH::Controls::AspectRatio aQualityFunc;
2806
2807   SMESHDS_Mesh* aMesh = GetMeshDS();
2808
2809   if ( theElems.empty() ) {
2810     // add all faces to theElems
2811     SMDS_FaceIteratorPtr fIt = aMesh->facesIterator();
2812     while ( fIt->more() ) {
2813       const SMDS_MeshElement* face = fIt->next();
2814       theElems.insert( face );
2815     }
2816   }
2817   // get all face ids theElems are on
2818   set< int > faceIdSet;
2819   TIDSortedElemSet::iterator itElem;
2820   if ( the2D )
2821     for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
2822       int fId = FindShape( *itElem );
2823       // check that corresponding submesh exists and a shape is face
2824       if (fId &&
2825           faceIdSet.find( fId ) == faceIdSet.end() &&
2826           aMesh->MeshElements( fId )) {
2827         TopoDS_Shape F = aMesh->IndexToShape( fId );
2828         if ( !F.IsNull() && F.ShapeType() == TopAbs_FACE )
2829           faceIdSet.insert( fId );
2830       }
2831     }
2832   faceIdSet.insert( 0 ); // to smooth elements that are not on any TopoDS_Face
2833
2834   // ===============================================
2835   // smooth elements on each TopoDS_Face separately
2836   // ===============================================
2837
2838   set< int >::reverse_iterator fId = faceIdSet.rbegin(); // treate 0 fId at the end
2839   for ( ; fId != faceIdSet.rend(); ++fId ) {
2840     // get face surface and submesh
2841     Handle(Geom_Surface) surface;
2842     SMESHDS_SubMesh* faceSubMesh = 0;
2843     TopoDS_Face face;
2844     double fToler2 = 0, vPeriod = 0., uPeriod = 0., f,l;
2845     double u1 = 0, u2 = 0, v1 = 0, v2 = 0;
2846     bool isUPeriodic = false, isVPeriodic = false;
2847     if ( *fId ) {
2848       face = TopoDS::Face( aMesh->IndexToShape( *fId ));
2849       surface = BRep_Tool::Surface( face );
2850       faceSubMesh = aMesh->MeshElements( *fId );
2851       fToler2 = BRep_Tool::Tolerance( face );
2852       fToler2 *= fToler2 * 10.;
2853       isUPeriodic = surface->IsUPeriodic();
2854       if ( isUPeriodic )
2855         vPeriod = surface->UPeriod();
2856       isVPeriodic = surface->IsVPeriodic();
2857       if ( isVPeriodic )
2858         uPeriod = surface->VPeriod();
2859       surface->Bounds( u1, u2, v1, v2 );
2860     }
2861     // ---------------------------------------------------------
2862     // for elements on a face, find movable and fixed nodes and
2863     // compute UV for them
2864     // ---------------------------------------------------------
2865     bool checkBoundaryNodes = false;
2866     bool isQuadratic = false;
2867     set<const SMDS_MeshNode*> setMovableNodes;
2868     map< const SMDS_MeshNode*, gp_XY* > uvMap, uvMap2;
2869     list< gp_XY > listUV; // uvs the 2 uvMaps refer to
2870     list< const SMDS_MeshElement* > elemsOnFace;
2871
2872     Extrema_GenExtPS projector;
2873     GeomAdaptor_Surface surfAdaptor;
2874     if ( !surface.IsNull() ) {
2875       surfAdaptor.Load( surface );
2876       projector.Initialize( surfAdaptor, 20,20, 1e-5,1e-5 );
2877     }
2878     int nbElemOnFace = 0;
2879     itElem = theElems.begin();
2880     // loop on not yet smoothed elements: look for elems on a face
2881     while ( itElem != theElems.end() ) {
2882       if ( faceSubMesh && nbElemOnFace == faceSubMesh->NbElements() )
2883         break; // all elements found
2884
2885       const SMDS_MeshElement* elem = *itElem;
2886       if ( !elem || elem->GetType() != SMDSAbs_Face || elem->NbNodes() < 3 ||
2887            ( faceSubMesh && !faceSubMesh->Contains( elem ))) {
2888         ++itElem;
2889         continue;
2890       }
2891       elemsOnFace.push_back( elem );
2892       theElems.erase( itElem++ );
2893       nbElemOnFace++;
2894
2895       if ( !isQuadratic )
2896         isQuadratic = elem->IsQuadratic();
2897
2898       // get movable nodes of elem
2899       const SMDS_MeshNode* node;
2900       SMDS_TypeOfPosition posType;
2901       SMDS_ElemIteratorPtr itN = elem->nodesIterator();
2902       int nn = 0, nbn =  elem->NbNodes();
2903       if(elem->IsQuadratic())
2904         nbn = nbn/2;
2905       while ( nn++ < nbn ) {
2906         node = static_cast<const SMDS_MeshNode*>( itN->next() );
2907         const SMDS_PositionPtr& pos = node->GetPosition();
2908         posType = pos.get() ? pos->GetTypeOfPosition() : SMDS_TOP_3DSPACE;
2909         if (posType != SMDS_TOP_EDGE &&
2910             posType != SMDS_TOP_VERTEX &&
2911             theFixedNodes.find( node ) == theFixedNodes.end())
2912         {
2913           // check if all faces around the node are on faceSubMesh
2914           // because a node on edge may be bound to face
2915           SMDS_ElemIteratorPtr eIt = node->GetInverseElementIterator(SMDSAbs_Face);
2916           bool all = true;
2917           if ( faceSubMesh ) {
2918             while ( eIt->more() && all ) {
2919               const SMDS_MeshElement* e = eIt->next();
2920               all = faceSubMesh->Contains( e );
2921             }
2922           }
2923           if ( all )
2924             setMovableNodes.insert( node );
2925           else
2926             checkBoundaryNodes = true;
2927         }
2928         if ( posType == SMDS_TOP_3DSPACE )
2929           checkBoundaryNodes = true;
2930       }
2931
2932       if ( surface.IsNull() )
2933         continue;
2934
2935       // get nodes to check UV
2936       list< const SMDS_MeshNode* > uvCheckNodes;
2937       itN = elem->nodesIterator();
2938       nn = 0; nbn =  elem->NbNodes();
2939       if(elem->IsQuadratic())
2940         nbn = nbn/2;
2941       while ( nn++ < nbn ) {
2942         node = static_cast<const SMDS_MeshNode*>( itN->next() );
2943         if ( uvMap.find( node ) == uvMap.end() )
2944           uvCheckNodes.push_back( node );
2945         // add nodes of elems sharing node
2946         //         SMDS_ElemIteratorPtr eIt = node->GetInverseElementIterator(SMDSAbs_Face);
2947         //         while ( eIt->more() ) {
2948         //           const SMDS_MeshElement* e = eIt->next();
2949         //           if ( e != elem ) {
2950         //             SMDS_ElemIteratorPtr nIt = e->nodesIterator();
2951         //             while ( nIt->more() ) {
2952         //               const SMDS_MeshNode* n =
2953         //                 static_cast<const SMDS_MeshNode*>( nIt->next() );
2954         //               if ( uvMap.find( n ) == uvMap.end() )
2955         //                 uvCheckNodes.push_back( n );
2956         //             }
2957         //           }
2958         //         }
2959       }
2960       // check UV on face
2961       list< const SMDS_MeshNode* >::iterator n = uvCheckNodes.begin();
2962       for ( ; n != uvCheckNodes.end(); ++n ) {
2963         node = *n;
2964         gp_XY uv( 0, 0 );
2965         const SMDS_PositionPtr& pos = node->GetPosition();
2966         posType = pos.get() ? pos->GetTypeOfPosition() : SMDS_TOP_3DSPACE;
2967         // get existing UV
2968         switch ( posType ) {
2969         case SMDS_TOP_FACE: {
2970           SMDS_FacePosition* fPos = ( SMDS_FacePosition* ) pos.get();
2971           uv.SetCoord( fPos->GetUParameter(), fPos->GetVParameter() );
2972           break;
2973         }
2974         case SMDS_TOP_EDGE: {
2975           TopoDS_Shape S = aMesh->IndexToShape( pos->GetShapeId() );
2976           Handle(Geom2d_Curve) pcurve;
2977           if ( !S.IsNull() && S.ShapeType() == TopAbs_EDGE )
2978             pcurve = BRep_Tool::CurveOnSurface( TopoDS::Edge( S ), face, f,l );
2979           if ( !pcurve.IsNull() ) {
2980             double u = (( SMDS_EdgePosition* ) pos.get() )->GetUParameter();
2981             uv = pcurve->Value( u ).XY();
2982           }
2983           break;
2984         }
2985         case SMDS_TOP_VERTEX: {
2986           TopoDS_Shape S = aMesh->IndexToShape( pos->GetShapeId() );
2987           if ( !S.IsNull() && S.ShapeType() == TopAbs_VERTEX )
2988             uv = BRep_Tool::Parameters( TopoDS::Vertex( S ), face ).XY();
2989           break;
2990         }
2991         default:;
2992         }
2993         // check existing UV
2994         bool project = true;
2995         gp_Pnt pNode ( node->X(), node->Y(), node->Z() );
2996         double dist1 = DBL_MAX, dist2 = 0;
2997         if ( posType != SMDS_TOP_3DSPACE ) {
2998           dist1 = pNode.SquareDistance( surface->Value( uv.X(), uv.Y() ));
2999           project = dist1 > fToler2;
3000         }
3001         if ( project ) { // compute new UV
3002           gp_XY newUV;
3003           if ( !getClosestUV( projector, pNode, newUV )) {
3004             MESSAGE("Node Projection Failed " << node);
3005           }
3006           else {
3007             if ( isUPeriodic )
3008               newUV.SetX( ElCLib::InPeriod( newUV.X(), u1, u2 ));
3009             if ( isVPeriodic )
3010               newUV.SetY( ElCLib::InPeriod( newUV.Y(), v1, v2 ));
3011             // check new UV
3012             if ( posType != SMDS_TOP_3DSPACE )
3013               dist2 = pNode.SquareDistance( surface->Value( newUV.X(), newUV.Y() ));
3014             if ( dist2 < dist1 )
3015               uv = newUV;
3016           }
3017         }
3018         // store UV in the map
3019         listUV.push_back( uv );
3020         uvMap.insert( make_pair( node, &listUV.back() ));
3021       }
3022     } // loop on not yet smoothed elements
3023
3024     if ( !faceSubMesh || nbElemOnFace != faceSubMesh->NbElements() )
3025       checkBoundaryNodes = true;
3026
3027     // fix nodes on mesh boundary
3028
3029     if ( checkBoundaryNodes ) {
3030       map< NLink, int > linkNbMap; // how many times a link encounters in elemsOnFace
3031       map< NLink, int >::iterator link_nb;
3032       // put all elements links to linkNbMap
3033       list< const SMDS_MeshElement* >::iterator elemIt = elemsOnFace.begin();
3034       for ( ; elemIt != elemsOnFace.end(); ++elemIt ) {
3035         const SMDS_MeshElement* elem = (*elemIt);
3036         int nbn =  elem->NbNodes();
3037         if(elem->IsQuadratic())
3038           nbn = nbn/2;
3039         // loop on elem links: insert them in linkNbMap
3040         const SMDS_MeshNode* curNode, *prevNode = elem->GetNodeWrap( nbn );
3041         for ( int iN = 0; iN < nbn; ++iN ) {
3042           curNode = elem->GetNode( iN );
3043           NLink link;
3044           if ( curNode < prevNode ) link = make_pair( curNode , prevNode );
3045           else                      link = make_pair( prevNode , curNode );
3046           prevNode = curNode;
3047           link_nb = linkNbMap.find( link );
3048           if ( link_nb == linkNbMap.end() )
3049             linkNbMap.insert( make_pair ( link, 1 ));
3050           else
3051             link_nb->second++;
3052         }
3053       }
3054       // remove nodes that are in links encountered only once from setMovableNodes
3055       for ( link_nb = linkNbMap.begin(); link_nb != linkNbMap.end(); ++link_nb ) {
3056         if ( link_nb->second == 1 ) {
3057           setMovableNodes.erase( link_nb->first.first );
3058           setMovableNodes.erase( link_nb->first.second );
3059         }
3060       }
3061     }
3062
3063     // -----------------------------------------------------
3064     // for nodes on seam edge, compute one more UV ( uvMap2 );
3065     // find movable nodes linked to nodes on seam and which
3066     // are to be smoothed using the second UV ( uvMap2 )
3067     // -----------------------------------------------------
3068
3069     set<const SMDS_MeshNode*> nodesNearSeam; // to smooth using uvMap2
3070     if ( !surface.IsNull() ) {
3071       TopExp_Explorer eExp( face, TopAbs_EDGE );
3072       for ( ; eExp.More(); eExp.Next() ) {
3073         TopoDS_Edge edge = TopoDS::Edge( eExp.Current() );
3074         if ( !BRep_Tool::IsClosed( edge, face ))
3075           continue;
3076         SMESHDS_SubMesh* sm = aMesh->MeshElements( edge );
3077         if ( !sm ) continue;
3078         // find out which parameter varies for a node on seam
3079         double f,l;
3080         gp_Pnt2d uv1, uv2;
3081         Handle(Geom2d_Curve) pcurve = BRep_Tool::CurveOnSurface( edge, face, f, l );
3082         if ( pcurve.IsNull() ) continue;
3083         uv1 = pcurve->Value( f );
3084         edge.Reverse();
3085         pcurve = BRep_Tool::CurveOnSurface( edge, face, f, l );
3086         if ( pcurve.IsNull() ) continue;
3087         uv2 = pcurve->Value( f );
3088         int iPar = Abs( uv1.X() - uv2.X() ) > Abs( uv1.Y() - uv2.Y() ) ? 1 : 2;
3089         // assure uv1 < uv2
3090         if ( uv1.Coord( iPar ) > uv2.Coord( iPar )) {
3091           gp_Pnt2d tmp = uv1; uv1 = uv2; uv2 = tmp;
3092         }
3093         // get nodes on seam and its vertices
3094         list< const SMDS_MeshNode* > seamNodes;
3095         SMDS_NodeIteratorPtr nSeamIt = sm->GetNodes();
3096         while ( nSeamIt->more() ) {
3097           const SMDS_MeshNode* node = nSeamIt->next();
3098           if ( !isQuadratic || !IsMedium( node ))
3099             seamNodes.push_back( node );
3100         }
3101         TopExp_Explorer vExp( edge, TopAbs_VERTEX );
3102         for ( ; vExp.More(); vExp.Next() ) {
3103           sm = aMesh->MeshElements( vExp.Current() );
3104           if ( sm ) {
3105             nSeamIt = sm->GetNodes();
3106             while ( nSeamIt->more() )
3107               seamNodes.push_back( nSeamIt->next() );
3108           }
3109         }
3110         // loop on nodes on seam
3111         list< const SMDS_MeshNode* >::iterator noSeIt = seamNodes.begin();
3112         for ( ; noSeIt != seamNodes.end(); ++noSeIt ) {
3113           const SMDS_MeshNode* nSeam = *noSeIt;
3114           map< const SMDS_MeshNode*, gp_XY* >::iterator n_uv = uvMap.find( nSeam );
3115           if ( n_uv == uvMap.end() )
3116             continue;
3117           // set the first UV
3118           n_uv->second->SetCoord( iPar, uv1.Coord( iPar ));
3119           // set the second UV
3120           listUV.push_back( *n_uv->second );
3121           listUV.back().SetCoord( iPar, uv2.Coord( iPar ));
3122           if ( uvMap2.empty() )
3123             uvMap2 = uvMap; // copy the uvMap contents
3124           uvMap2[ nSeam ] = &listUV.back();
3125
3126           // collect movable nodes linked to ones on seam in nodesNearSeam
3127           SMDS_ElemIteratorPtr eIt = nSeam->GetInverseElementIterator(SMDSAbs_Face);
3128           while ( eIt->more() ) {
3129             const SMDS_MeshElement* e = eIt->next();
3130             int nbUseMap1 = 0, nbUseMap2 = 0;
3131             SMDS_ElemIteratorPtr nIt = e->nodesIterator();
3132             int nn = 0, nbn =  e->NbNodes();
3133             if(e->IsQuadratic()) nbn = nbn/2;
3134             while ( nn++ < nbn )
3135             {
3136               const SMDS_MeshNode* n =
3137                 static_cast<const SMDS_MeshNode*>( nIt->next() );
3138               if (n == nSeam ||
3139                   setMovableNodes.find( n ) == setMovableNodes.end() )
3140                 continue;
3141               // add only nodes being closer to uv2 than to uv1
3142               gp_Pnt pMid (0.5 * ( n->X() + nSeam->X() ),
3143                            0.5 * ( n->Y() + nSeam->Y() ),
3144                            0.5 * ( n->Z() + nSeam->Z() ));
3145               gp_XY uv;
3146               getClosestUV( projector, pMid, uv );
3147               if ( uv.Coord( iPar ) > uvMap[ n ]->Coord( iPar ) ) {
3148                 nodesNearSeam.insert( n );
3149                 nbUseMap2++;
3150               }
3151               else
3152                 nbUseMap1++;
3153             }
3154             // for centroidalSmooth all element nodes must
3155             // be on one side of a seam
3156             if ( theSmoothMethod == CENTROIDAL && nbUseMap1 && nbUseMap2 ) {
3157               SMDS_ElemIteratorPtr nIt = e->nodesIterator();
3158               nn = 0;
3159               while ( nn++ < nbn ) {
3160                 const SMDS_MeshNode* n =
3161                   static_cast<const SMDS_MeshNode*>( nIt->next() );
3162                 setMovableNodes.erase( n );
3163               }
3164             }
3165           }
3166         } // loop on nodes on seam
3167       } // loop on edge of a face
3168     } // if ( !face.IsNull() )
3169
3170     if ( setMovableNodes.empty() ) {
3171       MESSAGE( "Face id : " << *fId << " - NO SMOOTHING: no nodes to move!!!");
3172       continue; // goto next face
3173     }
3174
3175     // -------------
3176     // SMOOTHING //
3177     // -------------
3178
3179     int it = -1;
3180     double maxRatio = -1., maxDisplacement = -1.;
3181     set<const SMDS_MeshNode*>::iterator nodeToMove;
3182     for ( it = 0; it < theNbIterations; it++ ) {
3183       maxDisplacement = 0.;
3184       nodeToMove = setMovableNodes.begin();
3185       for ( ; nodeToMove != setMovableNodes.end(); nodeToMove++ ) {
3186         const SMDS_MeshNode* node = (*nodeToMove);
3187         gp_XYZ aPrevPos ( node->X(), node->Y(), node->Z() );
3188
3189         // smooth
3190         bool map2 = ( nodesNearSeam.find( node ) != nodesNearSeam.end() );
3191         if ( theSmoothMethod == LAPLACIAN )
3192           laplacianSmooth( node, surface, map2 ? uvMap2 : uvMap );
3193         else
3194           centroidalSmooth( node, surface, map2 ? uvMap2 : uvMap );
3195
3196         // node displacement
3197         gp_XYZ aNewPos ( node->X(), node->Y(), node->Z() );
3198         Standard_Real aDispl = (aPrevPos - aNewPos).SquareModulus();
3199         if ( aDispl > maxDisplacement )
3200           maxDisplacement = aDispl;
3201       }
3202       // no node movement => exit
3203       //if ( maxDisplacement < 1.e-16 ) {
3204       if ( maxDisplacement < disttol ) {
3205         MESSAGE("-- no node movement --");
3206         break;
3207       }
3208
3209       // check elements quality
3210       maxRatio  = 0;
3211       list< const SMDS_MeshElement* >::iterator elemIt = elemsOnFace.begin();
3212       for ( ; elemIt != elemsOnFace.end(); ++elemIt ) {
3213         const SMDS_MeshElement* elem = (*elemIt);
3214         if ( !elem || elem->GetType() != SMDSAbs_Face )
3215           continue;
3216         SMESH::Controls::TSequenceOfXYZ aPoints;
3217         if ( aQualityFunc.GetPoints( elem, aPoints )) {
3218           double aValue = aQualityFunc.GetValue( aPoints );
3219           if ( aValue > maxRatio )
3220             maxRatio = aValue;
3221         }
3222       }
3223       if ( maxRatio <= theTgtAspectRatio ) {
3224         MESSAGE("-- quality achived --");
3225         break;
3226       }
3227       if (it+1 == theNbIterations) {
3228         MESSAGE("-- Iteration limit exceeded --");
3229       }
3230     } // smoothing iterations
3231
3232     MESSAGE(" Face id: " << *fId <<
3233             " Nb iterstions: " << it <<
3234             " Displacement: " << maxDisplacement <<
3235             " Aspect Ratio " << maxRatio);
3236
3237     // ---------------------------------------
3238     // new nodes positions are computed,
3239     // record movement in DS and set new UV
3240     // ---------------------------------------
3241     nodeToMove = setMovableNodes.begin();
3242     for ( ; nodeToMove != setMovableNodes.end(); nodeToMove++ ) {
3243       SMDS_MeshNode* node = const_cast< SMDS_MeshNode* > (*nodeToMove);
3244       aMesh->MoveNode( node, node->X(), node->Y(), node->Z() );
3245       map< const SMDS_MeshNode*, gp_XY* >::iterator node_uv = uvMap.find( node );
3246       if ( node_uv != uvMap.end() ) {
3247         gp_XY* uv = node_uv->second;
3248         node->SetPosition
3249           ( SMDS_PositionPtr( new SMDS_FacePosition( *fId, uv->X(), uv->Y() )));
3250       }
3251     }
3252
3253     // move medium nodes of quadratic elements
3254     if ( isQuadratic )
3255     {
3256       SMESH_MesherHelper helper( *GetMesh() );
3257       if ( !face.IsNull() )
3258         helper.SetSubShape( face );
3259       list< const SMDS_MeshElement* >::iterator elemIt = elemsOnFace.begin();
3260       for ( ; elemIt != elemsOnFace.end(); ++elemIt ) {
3261         const SMDS_QuadraticFaceOfNodes* QF =
3262           dynamic_cast<const SMDS_QuadraticFaceOfNodes*> (*elemIt);
3263         if(QF) {
3264           vector<const SMDS_MeshNode*> Ns;
3265           Ns.reserve(QF->NbNodes()+1);
3266           SMDS_NodeIteratorPtr anIter = QF->interlacedNodesIterator();
3267           while ( anIter->more() )
3268             Ns.push_back( anIter->next() );
3269           Ns.push_back( Ns[0] );
3270           double x, y, z;
3271           for(int i=0; i<QF->NbNodes(); i=i+2) {
3272             if ( !surface.IsNull() ) {
3273               gp_XY uv1 = helper.GetNodeUV( face, Ns[i], Ns[i+2] );
3274               gp_XY uv2 = helper.GetNodeUV( face, Ns[i+2], Ns[i] );
3275               gp_XY uv = ( uv1 + uv2 ) / 2.;
3276               gp_Pnt xyz = surface->Value( uv.X(), uv.Y() );
3277               x = xyz.X(); y = xyz.Y(); z = xyz.Z();
3278             }
3279             else {
3280               x = (Ns[i]->X() + Ns[i+2]->X())/2;
3281               y = (Ns[i]->Y() + Ns[i+2]->Y())/2;
3282               z = (Ns[i]->Z() + Ns[i+2]->Z())/2;
3283             }
3284             if( fabs( Ns[i+1]->X() - x ) > disttol ||
3285                 fabs( Ns[i+1]->Y() - y ) > disttol ||
3286                 fabs( Ns[i+1]->Z() - z ) > disttol ) {
3287               // we have to move i+1 node
3288               aMesh->MoveNode( Ns[i+1], x, y, z );
3289             }
3290           }
3291         }
3292       }
3293     }
3294
3295   } // loop on face ids
3296
3297 }
3298
3299 //=======================================================================
3300 //function : isReverse
3301 //purpose  : Return true if normal of prevNodes is not co-directied with
3302 //           gp_Vec(prevNodes[iNotSame],nextNodes[iNotSame]).
3303 //           iNotSame is where prevNodes and nextNodes are different
3304 //=======================================================================
3305
3306 static bool isReverse(vector<const SMDS_MeshNode*> prevNodes,
3307                       vector<const SMDS_MeshNode*> nextNodes,
3308                       const int            nbNodes,
3309                       const int            iNotSame)
3310 {
3311   int iBeforeNotSame = ( iNotSame == 0 ? nbNodes - 1 : iNotSame - 1 );
3312   int iAfterNotSame  = ( iNotSame + 1 == nbNodes ? 0 : iNotSame + 1 );
3313
3314   const SMDS_MeshNode* nB = prevNodes[ iBeforeNotSame ];
3315   const SMDS_MeshNode* nA = prevNodes[ iAfterNotSame ];
3316   const SMDS_MeshNode* nP = prevNodes[ iNotSame ];
3317   const SMDS_MeshNode* nN = nextNodes[ iNotSame ];
3318
3319   gp_Pnt pB ( nB->X(), nB->Y(), nB->Z() );
3320   gp_Pnt pA ( nA->X(), nA->Y(), nA->Z() );
3321   gp_Pnt pP ( nP->X(), nP->Y(), nP->Z() );
3322   gp_Pnt pN ( nN->X(), nN->Y(), nN->Z() );
3323
3324   gp_Vec vB ( pP, pB ), vA ( pP, pA ), vN ( pP, pN );
3325
3326   return (vA ^ vB) * vN < 0.0;
3327 }
3328
3329 //=======================================================================
3330 /*!
3331  * \brief Create elements by sweeping an element
3332  * \param elem - element to sweep
3333  * \param newNodesItVec - nodes generated from each node of the element
3334  * \param newElems - generated elements
3335  * \param nbSteps - number of sweeping steps
3336  * \param srcElements - to append elem for each generated element
3337  */
3338 //=======================================================================
3339
3340 void SMESH_MeshEditor::sweepElement(const SMDS_MeshElement*               elem,
3341                                     const vector<TNodeOfNodeListMapItr> & newNodesItVec,
3342                                     list<const SMDS_MeshElement*>&        newElems,
3343                                     const int                             nbSteps,
3344                                     SMESH_SequenceOfElemPtr&              srcElements)
3345 {
3346   SMESHDS_Mesh* aMesh = GetMeshDS();
3347
3348   // Loop on elem nodes:
3349   // find new nodes and detect same nodes indices
3350   int nbNodes = elem->NbNodes();
3351   vector < list< const SMDS_MeshNode* >::const_iterator > itNN( nbNodes );
3352   vector<const SMDS_MeshNode*> prevNod( nbNodes );
3353   vector<const SMDS_MeshNode*> nextNod( nbNodes );
3354   vector<const SMDS_MeshNode*> midlNod( nbNodes );
3355
3356   int iNode, nbSame = 0, iNotSameNode = 0, iSameNode = 0;
3357   vector<int> sames(nbNodes);
3358   vector<bool> issimple(nbNodes);
3359
3360   for ( iNode = 0; iNode < nbNodes; iNode++ ) {
3361     TNodeOfNodeListMapItr nnIt = newNodesItVec[ iNode ];
3362     const SMDS_MeshNode*                 node         = nnIt->first;
3363     const list< const SMDS_MeshNode* > & listNewNodes = nnIt->second;
3364     if ( listNewNodes.empty() ) {
3365       return;
3366     }
3367
3368     issimple[iNode] = (listNewNodes.size()==nbSteps); // is node medium
3369
3370     itNN[ iNode ] = listNewNodes.begin();
3371     prevNod[ iNode ] = node;
3372     nextNod[ iNode ] = listNewNodes.front();
3373     if( !elem->IsQuadratic() || !issimple[iNode] ) {
3374       if ( prevNod[ iNode ] != nextNod [ iNode ])
3375         iNotSameNode = iNode;
3376       else {
3377         iSameNode = iNode;
3378         //nbSame++;
3379         sames[nbSame++] = iNode;
3380       }
3381     }
3382   }
3383
3384   //cout<<"  nbSame = "<<nbSame<<endl;
3385   if ( nbSame == nbNodes || nbSame > 2) {
3386     MESSAGE( " Too many same nodes of element " << elem->GetID() );
3387     //INFOS( " Too many same nodes of element " << elem->GetID() );
3388     return;
3389   }
3390
3391   //  if( elem->IsQuadratic() && nbSame>0 ) {
3392   //    MESSAGE( "Can not rotate quadratic element " << elem->GetID() );
3393   //    return;
3394   //  }
3395
3396   int iBeforeSame = 0, iAfterSame = 0, iOpposSame = 0;
3397   int nbBaseNodes = ( elem->IsQuadratic() ? nbNodes/2 : nbNodes );
3398   if ( nbSame > 0 ) {
3399     iBeforeSame = ( iSameNode == 0 ? nbBaseNodes - 1 : iSameNode - 1 );
3400     iAfterSame  = ( iSameNode + 1 == nbBaseNodes ? 0 : iSameNode + 1 );
3401     iOpposSame  = ( iSameNode - 2 < 0  ? iSameNode + 2 : iSameNode - 2 );
3402   }
3403
3404   //if(nbNodes==8)
3405   //cout<<" prevNod[0]="<< prevNod[0]<<" prevNod[1]="<< prevNod[1]
3406   //    <<" prevNod[2]="<< prevNod[2]<<" prevNod[3]="<< prevNod[4]
3407   //    <<" prevNod[4]="<< prevNod[4]<<" prevNod[5]="<< prevNod[5]
3408   //    <<" prevNod[6]="<< prevNod[6]<<" prevNod[7]="<< prevNod[7]<<endl;
3409
3410   // check element orientation
3411   int i0 = 0, i2 = 2;
3412   if ( nbNodes > 2 && !isReverse( prevNod, nextNod, nbNodes, iNotSameNode )) {
3413     //MESSAGE("Reversed elem " << elem );
3414     i0 = 2;
3415     i2 = 0;
3416     if ( nbSame > 0 )
3417       std::swap( iBeforeSame, iAfterSame );
3418   }
3419
3420   // make new elements
3421   for (int iStep = 0; iStep < nbSteps; iStep++ ) {
3422     // get next nodes
3423     for ( iNode = 0; iNode < nbNodes; iNode++ ) {
3424       if(issimple[iNode]) {
3425         nextNod[ iNode ] = *itNN[ iNode ];
3426         itNN[ iNode ]++;
3427       }
3428       else {
3429         if( elem->GetType()==SMDSAbs_Node ) {
3430           // we have to use two nodes
3431           midlNod[ iNode ] = *itNN[ iNode ];
3432           itNN[ iNode ]++;
3433           nextNod[ iNode ] = *itNN[ iNode ];
3434           itNN[ iNode ]++;
3435         }
3436         else if(!elem->IsQuadratic() || elem->IsMediumNode(prevNod[iNode]) ) {
3437           // we have to use each second node
3438           //itNN[ iNode ]++;
3439           nextNod[ iNode ] = *itNN[ iNode ];
3440           itNN[ iNode ]++;
3441         }
3442         else {
3443           // we have to use two nodes
3444           midlNod[ iNode ] = *itNN[ iNode ];
3445           itNN[ iNode ]++;
3446           nextNod[ iNode ] = *itNN[ iNode ];
3447           itNN[ iNode ]++;
3448         }
3449       }
3450     }
3451     SMDS_MeshElement* aNewElem = 0;
3452     if(!elem->IsPoly()) {
3453       switch ( nbNodes ) {
3454       case 0:
3455         return;
3456       case 1: { // NODE
3457         if ( nbSame == 0 ) {
3458           if(issimple[0])
3459             aNewElem = aMesh->AddEdge( prevNod[ 0 ], nextNod[ 0 ] );
3460           else
3461             aNewElem = aMesh->AddEdge( prevNod[ 0 ], nextNod[ 0 ], midlNod[ 0 ] );
3462         }
3463         break;
3464       }
3465       case 2: { // EDGE
3466         if ( nbSame == 0 )
3467           aNewElem = aMesh->AddFace(prevNod[ 0 ], prevNod[ 1 ],
3468                                     nextNod[ 1 ], nextNod[ 0 ] );
3469         else
3470           aNewElem = aMesh->AddFace(prevNod[ 0 ], prevNod[ 1 ],
3471                                     nextNod[ iNotSameNode ] );
3472         break;
3473       }
3474
3475       case 3: { // TRIANGLE or quadratic edge
3476         if(elem->GetType() == SMDSAbs_Face) { // TRIANGLE
3477
3478           if ( nbSame == 0 )       // --- pentahedron
3479             aNewElem = aMesh->AddVolume (prevNod[ i0 ], prevNod[ 1 ], prevNod[ i2 ],
3480                                          nextNod[ i0 ], nextNod[ 1 ], nextNod[ i2 ] );
3481
3482           else if ( nbSame == 1 )  // --- pyramid
3483             aNewElem = aMesh->AddVolume (prevNod[ iBeforeSame ],  prevNod[ iAfterSame ],
3484                                          nextNod[ iAfterSame ], nextNod[ iBeforeSame ],
3485                                          nextNod[ iSameNode ]);
3486
3487           else // 2 same nodes:      --- tetrahedron
3488             aNewElem = aMesh->AddVolume (prevNod[ i0 ], prevNod[ 1 ], prevNod[ i2 ],
3489                                          nextNod[ iNotSameNode ]);
3490         }
3491         else { // quadratic edge
3492           if(nbSame==0) {     // quadratic quadrangle
3493             aNewElem = aMesh->AddFace(prevNod[0], nextNod[0], nextNod[1], prevNod[1],
3494                                       midlNod[0], nextNod[2], midlNod[1], prevNod[2]);
3495           }
3496           else if(nbSame==1) { // quadratic triangle
3497             if(sames[0]==2) {
3498               return; // medium node on axis
3499             }
3500             else if(sames[0]==0) {
3501               aNewElem = aMesh->AddFace(prevNod[0], nextNod[1], prevNod[1],
3502                                         nextNod[2], midlNod[1], prevNod[2]);
3503             }
3504             else { // sames[0]==1
3505               aNewElem = aMesh->AddFace(prevNod[0], nextNod[0], prevNod[1],
3506                                         midlNod[0], nextNod[2], prevNod[2]);
3507             }
3508           }
3509           else {
3510             return;
3511           }
3512         }
3513         break;
3514       }
3515       case 4: { // QUADRANGLE
3516
3517         if ( nbSame == 0 )       // --- hexahedron
3518           aNewElem = aMesh->AddVolume (prevNod[ i0 ], prevNod[ 1 ], prevNod[ i2 ], prevNod[ 3 ],
3519                                        nextNod[ i0 ], nextNod[ 1 ], nextNod[ i2 ], nextNod[ 3 ]);
3520
3521         else if ( nbSame == 1 ) { // --- pyramid + pentahedron
3522           aNewElem = aMesh->AddVolume (prevNod[ iBeforeSame ],  prevNod[ iAfterSame ],
3523                                        nextNod[ iAfterSame ], nextNod[ iBeforeSame ],
3524                                        nextNod[ iSameNode ]);
3525           newElems.push_back( aNewElem );
3526           aNewElem = aMesh->AddVolume (prevNod[ iAfterSame ], prevNod[ iOpposSame ],
3527                                        prevNod[ iBeforeSame ],  nextNod[ iAfterSame ],
3528                                        nextNod[ iOpposSame ],  nextNod[ iBeforeSame ] );
3529         }
3530         else if ( nbSame == 2 ) { // pentahedron
3531           if ( prevNod[ iBeforeSame ] == nextNod[ iBeforeSame ] )
3532             // iBeforeSame is same too
3533             aNewElem = aMesh->AddVolume (prevNod[ iBeforeSame ], prevNod[ iOpposSame ],
3534                                          nextNod[ iOpposSame ], prevNod[ iSameNode ],
3535                                          prevNod[ iAfterSame ],  nextNod[ iAfterSame ]);
3536           else
3537             // iAfterSame is same too
3538             aNewElem = aMesh->AddVolume (prevNod[ iSameNode ], prevNod[ iBeforeSame ],
3539                                          nextNod[ iBeforeSame ], prevNod[ iAfterSame ],
3540                                          prevNod[ iOpposSame ],  nextNod[ iOpposSame ]);
3541         }
3542         break;
3543       }
3544       case 6: { // quadratic triangle
3545         // create pentahedron with 15 nodes
3546         if(nbSame==0) {
3547           if(i0>0) { // reversed case
3548             aNewElem = aMesh->AddVolume (prevNod[0], prevNod[2], prevNod[1],
3549                                          nextNod[0], nextNod[2], nextNod[1],
3550                                          prevNod[5], prevNod[4], prevNod[3],
3551                                          nextNod[5], nextNod[4], nextNod[3],
3552                                          midlNod[0], midlNod[2], midlNod[1]);
3553           }
3554           else { // not reversed case
3555             aNewElem = aMesh->AddVolume (prevNod[0], prevNod[1], prevNod[2],
3556                                          nextNod[0], nextNod[1], nextNod[2],
3557                                          prevNod[3], prevNod[4], prevNod[5],
3558                                          nextNod[3], nextNod[4], nextNod[5],
3559                                          midlNod[0], midlNod[1], midlNod[2]);
3560           }
3561         }
3562         else if(nbSame==1) {
3563           // 2d order pyramid of 13 nodes
3564           //SMDS_MeshVolume* AddVolumeWithID(int n1, int n2, int n3, int n4, int n5,
3565           //                                 int n12,int n23,int n34,int n41,
3566           //                                 int n15,int n25,int n35,int n45, int ID);
3567           int n5 = iSameNode;
3568           int n1,n4,n41,n15,n45;
3569           if(i0>0) { // reversed case
3570             n1 = ( n5 + 1 == nbBaseNodes ? 0 : n5 + 1 );
3571             n4 = ( n5 == 0 ? nbBaseNodes - 1 : n5 - 1 );
3572             n41 = n1 + 3;
3573             n15 = n5 + 3;
3574             n45 = n4 + 3;
3575           }
3576           else {
3577             n1 = ( n5 == 0 ? nbBaseNodes - 1 : n5 - 1 );
3578             n4 = ( n5 + 1 == nbBaseNodes ? 0 : n5 + 1 );
3579             n41 = n4 + 3;
3580             n15 = n1 + 3;
3581             n45 = n5 + 3;
3582           }
3583           aNewElem = aMesh->AddVolume(prevNod[n1], nextNod[n1],
3584                                       nextNod[n4], prevNod[n4], prevNod[n5],
3585                                       midlNod[n1], nextNod[n41],
3586                                       midlNod[n4], prevNod[n41],
3587                                       prevNod[n15], nextNod[n15],
3588                                       nextNod[n45], prevNod[n45]);
3589         }
3590         else if(nbSame==2) {
3591           // 2d order tetrahedron of 10 nodes
3592           //SMDS_MeshVolume* AddVolumeWithID(int n1, int n2, int n3, int n4,
3593           //                                 int n12,int n23,int n31,
3594           //                                 int n14,int n24,int n34, int ID);
3595           int n1 = iNotSameNode;
3596           int n2,n3,n12,n23,n31;
3597           if(i0>0) { // reversed case
3598             n2 = ( n1 == 0 ? nbBaseNodes - 1 : n1 - 1 );
3599             n3 = ( n1 + 1 == nbBaseNodes ? 0 : n1 + 1 );
3600             n12 = n2 + 3;
3601             n23 = n3 + 3;
3602             n31 = n1 + 3;
3603           }
3604           else {
3605             n2 = ( n1 + 1 == nbBaseNodes ? 0 : n1 + 1 );
3606             n3 = ( n1 == 0 ? nbBaseNodes - 1 : n1 - 1 );
3607             n12 = n1 + 3;
3608             n23 = n2 + 3;
3609             n31 = n3 + 3;
3610           }
3611           aNewElem = aMesh->AddVolume (prevNod[n1], prevNod[n2], prevNod[n3], nextNod[n1],
3612                                        prevNod[n12], prevNod[n23], prevNod[n31],
3613                                        midlNod[n1], nextNod[n12], nextNod[n31]);
3614         }
3615         break;
3616       }
3617       case 8: { // quadratic quadrangle
3618         if(nbSame==0) {
3619           // create hexahedron with 20 nodes
3620           if(i0>0) { // reversed case
3621             aNewElem = aMesh->AddVolume (prevNod[0], prevNod[3], prevNod[2], prevNod[1],
3622                                          nextNod[0], nextNod[3], nextNod[2], nextNod[1],
3623                                          prevNod[7], prevNod[6], prevNod[5], prevNod[4],
3624                                          nextNod[7], nextNod[6], nextNod[5], nextNod[4],
3625                                          midlNod[0], midlNod[3], midlNod[2], midlNod[1]);
3626           }
3627           else { // not reversed case
3628             aNewElem = aMesh->AddVolume (prevNod[0], prevNod[1], prevNod[2], prevNod[3],
3629                                          nextNod[0], nextNod[1], nextNod[2], nextNod[3],
3630                                          prevNod[4], prevNod[5], prevNod[6], prevNod[7],
3631                                          nextNod[4], nextNod[5], nextNod[6], nextNod[7],
3632                                          midlNod[0], midlNod[1], midlNod[2], midlNod[3]);
3633           }
3634         }
3635         else if(nbSame==1) { 
3636           // --- pyramid + pentahedron - can not be created since it is needed 
3637           // additional middle node ot the center of face
3638           INFOS( " Sweep for face " << elem->GetID() << " can not be created" );
3639           return;
3640         }
3641         else if(nbSame==2) {
3642           // 2d order Pentahedron with 15 nodes
3643           //SMDS_MeshVolume* AddVolumeWithID(int n1, int n2, int n3, int n4, int n5, int n6,
3644           //                                 int n12,int n23,int n31,int n45,int n56,int n64,
3645           //                                 int n14,int n25,int n36, int ID);
3646           int n1,n2,n4,n5;
3647           if ( prevNod[ iBeforeSame ] == nextNod[ iBeforeSame ] ) {
3648             // iBeforeSame is same too
3649             n1 = iBeforeSame;
3650             n2 = iOpposSame;
3651             n4 = iSameNode;
3652             n5 = iAfterSame;
3653           }
3654           else {
3655             // iAfterSame is same too
3656             n1 = iSameNode;
3657             n2 = iBeforeSame;
3658             n4 = iAfterSame;
3659             n5 = iOpposSame;
3660           }
3661           int n12,n45,n14,n25;
3662           if(i0>0) { //reversed case
3663             n12 = n1 + 4;
3664             n45 = n5 + 4;
3665             n14 = n4 + 4;
3666             n25 = n2 + 4;
3667           }
3668           else {
3669             n12 = n2 + 4;
3670             n45 = n4 + 4;
3671             n14 = n1 + 4;
3672             n25 = n5 + 4;
3673           }
3674           aNewElem = aMesh->AddVolume (prevNod[n1], prevNod[n2], nextNod[n2],
3675                                        prevNod[n4], prevNod[n5], nextNod[n5],
3676                                        prevNod[n12], midlNod[n2], nextNod[n12],
3677                                        prevNod[n45], midlNod[n5], nextNod[n45],
3678                                        prevNod[n14], prevNod[n25], nextNod[n25]);
3679         }
3680         break;
3681       }
3682       default: {
3683         // realized for extrusion only
3684         //vector<const SMDS_MeshNode*> polyedre_nodes (nbNodes*2 + 4*nbNodes);
3685         //vector<int> quantities (nbNodes + 2);
3686
3687         //quantities[0] = nbNodes; // bottom of prism
3688         //for (int inode = 0; inode < nbNodes; inode++) {
3689         //  polyedre_nodes[inode] = prevNod[inode];
3690         //}
3691
3692         //quantities[1] = nbNodes; // top of prism
3693         //for (int inode = 0; inode < nbNodes; inode++) {
3694         //  polyedre_nodes[nbNodes + inode] = nextNod[inode];
3695         //}
3696
3697         //for (int iface = 0; iface < nbNodes; iface++) {
3698         //  quantities[iface + 2] = 4;
3699         //  int inextface = (iface == nbNodes - 1) ? 0 : iface + 1;
3700         //  polyedre_nodes[2*nbNodes + 4*iface + 0] = prevNod[iface];
3701         //  polyedre_nodes[2*nbNodes + 4*iface + 1] = prevNod[inextface];
3702         //  polyedre_nodes[2*nbNodes + 4*iface + 2] = nextNod[inextface];
3703         //  polyedre_nodes[2*nbNodes + 4*iface + 3] = nextNod[iface];
3704         //}
3705         //aNewElem = aMesh->AddPolyhedralVolume (polyedre_nodes, quantities);
3706         break;
3707       }
3708       }
3709     }
3710
3711     if(!aNewElem) {
3712       // realized for extrusion only
3713       vector<const SMDS_MeshNode*> polyedre_nodes (nbNodes*2 + 4*nbNodes);
3714       vector<int> quantities (nbNodes + 2);
3715
3716       quantities[0] = nbNodes; // bottom of prism
3717       for (int inode = 0; inode < nbNodes; inode++) {
3718         polyedre_nodes[inode] = prevNod[inode];
3719       }
3720
3721       quantities[1] = nbNodes; // top of prism
3722       for (int inode = 0; inode < nbNodes; inode++) {
3723         polyedre_nodes[nbNodes + inode] = nextNod[inode];
3724       }
3725
3726       for (int iface = 0; iface < nbNodes; iface++) {
3727         quantities[iface + 2] = 4;
3728         int inextface = (iface == nbNodes - 1) ? 0 : iface + 1;
3729         polyedre_nodes[2*nbNodes + 4*iface + 0] = prevNod[iface];
3730         polyedre_nodes[2*nbNodes + 4*iface + 1] = prevNod[inextface];
3731         polyedre_nodes[2*nbNodes + 4*iface + 2] = nextNod[inextface];
3732         polyedre_nodes[2*nbNodes + 4*iface + 3] = nextNod[iface];
3733       }
3734       aNewElem = aMesh->AddPolyhedralVolume (polyedre_nodes, quantities);
3735     }
3736
3737     if ( aNewElem ) {
3738       newElems.push_back( aNewElem );
3739       myLastCreatedElems.Append(aNewElem);
3740       srcElements.Append( elem );
3741     }
3742
3743     // set new prev nodes
3744     for ( iNode = 0; iNode < nbNodes; iNode++ )
3745       prevNod[ iNode ] = nextNod[ iNode ];
3746
3747   } // for steps
3748 }
3749
3750 //=======================================================================
3751 /*!
3752  * \brief Create 1D and 2D elements around swept elements
3753  * \param mapNewNodes - source nodes and ones generated from them
3754  * \param newElemsMap - source elements and ones generated from them
3755  * \param elemNewNodesMap - nodes generated from each node of each element
3756  * \param elemSet - all swept elements
3757  * \param nbSteps - number of sweeping steps
3758  * \param srcElements - to append elem for each generated element
3759  */
3760 //=======================================================================
3761
3762 void SMESH_MeshEditor::makeWalls (TNodeOfNodeListMap &     mapNewNodes,
3763                                   TElemOfElemListMap &     newElemsMap,
3764                                   TElemOfVecOfNnlmiMap &   elemNewNodesMap,
3765                                   TIDSortedElemSet&        elemSet,
3766                                   const int                nbSteps,
3767                                   SMESH_SequenceOfElemPtr& srcElements)
3768 {
3769   ASSERT( newElemsMap.size() == elemNewNodesMap.size() );
3770   SMESHDS_Mesh* aMesh = GetMeshDS();
3771
3772   // Find nodes belonging to only one initial element - sweep them to get edges.
3773
3774   TNodeOfNodeListMapItr nList = mapNewNodes.begin();
3775   for ( ; nList != mapNewNodes.end(); nList++ ) {
3776     const SMDS_MeshNode* node =
3777       static_cast<const SMDS_MeshNode*>( nList->first );
3778     SMDS_ElemIteratorPtr eIt = node->GetInverseElementIterator();
3779     int nbInitElems = 0;
3780     const SMDS_MeshElement* el = 0;
3781     SMDSAbs_ElementType highType = SMDSAbs_Edge; // count most complex elements only
3782     while ( eIt->more() && nbInitElems < 2 ) {
3783       el = eIt->next();
3784       SMDSAbs_ElementType type = el->GetType();
3785       if ( type == SMDSAbs_Volume || type < highType ) continue;
3786       if ( type > highType ) {
3787         nbInitElems = 0;
3788         highType = type;
3789       }
3790       if ( elemSet.find(el) != elemSet.end() )
3791         nbInitElems++;
3792     }
3793     if ( nbInitElems < 2 ) {
3794       bool NotCreateEdge = el && el->IsQuadratic() && el->IsMediumNode(node);
3795       if(!NotCreateEdge) {
3796         vector<TNodeOfNodeListMapItr> newNodesItVec( 1, nList );
3797         list<const SMDS_MeshElement*> newEdges;
3798         sweepElement( node, newNodesItVec, newEdges, nbSteps, srcElements );
3799       }
3800     }
3801   }
3802
3803   // Make a ceiling for each element ie an equal element of last new nodes.
3804   // Find free links of faces - make edges and sweep them into faces.
3805
3806   TElemOfElemListMap::iterator   itElem      = newElemsMap.begin();
3807   TElemOfVecOfNnlmiMap::iterator itElemNodes = elemNewNodesMap.begin();
3808   for ( ; itElem != newElemsMap.end(); itElem++, itElemNodes++ ) {
3809     const SMDS_MeshElement* elem = itElem->first;
3810     vector<TNodeOfNodeListMapItr>& vecNewNodes = itElemNodes->second;
3811
3812     if ( elem->GetType() == SMDSAbs_Edge ) {
3813       // create a ceiling edge
3814       if (!elem->IsQuadratic()) {
3815         if ( !aMesh->FindEdge( vecNewNodes[ 0 ]->second.back(),
3816                                vecNewNodes[ 1 ]->second.back())) {
3817           myLastCreatedElems.Append(aMesh->AddEdge(vecNewNodes[ 0 ]->second.back(),
3818                                                    vecNewNodes[ 1 ]->second.back()));
3819           srcElements.Append( myLastCreatedElems.Last() );
3820         }
3821       }
3822       else {
3823         if ( !aMesh->FindEdge( vecNewNodes[ 0 ]->second.back(),
3824                                vecNewNodes[ 1 ]->second.back(),
3825                                vecNewNodes[ 2 ]->second.back())) {
3826           myLastCreatedElems.Append(aMesh->AddEdge(vecNewNodes[ 0 ]->second.back(),
3827                                                    vecNewNodes[ 1 ]->second.back(),
3828                                                    vecNewNodes[ 2 ]->second.back()));
3829           srcElements.Append( myLastCreatedElems.Last() );
3830         }
3831       }
3832     }
3833     if ( elem->GetType() != SMDSAbs_Face )
3834       continue;
3835
3836     if(itElem->second.size()==0) continue;
3837
3838     bool hasFreeLinks = false;
3839
3840     TIDSortedElemSet avoidSet;
3841     avoidSet.insert( elem );
3842
3843     set<const SMDS_MeshNode*> aFaceLastNodes;
3844     int iNode, nbNodes = vecNewNodes.size();
3845     if(!elem->IsQuadratic()) {
3846       // loop on the face nodes
3847       for ( iNode = 0; iNode < nbNodes; iNode++ ) {
3848         aFaceLastNodes.insert( vecNewNodes[ iNode ]->second.back() );
3849         // look for free links of the face
3850         int iNext = ( iNode + 1 == nbNodes ) ? 0 : iNode + 1;
3851         const SMDS_MeshNode* n1 = vecNewNodes[ iNode ]->first;
3852         const SMDS_MeshNode* n2 = vecNewNodes[ iNext ]->first;
3853         // check if a link is free
3854         if ( ! SMESH_MeshEditor::FindFaceInSet ( n1, n2, elemSet, avoidSet )) {
3855           hasFreeLinks = true;
3856           // make an edge and a ceiling for a new edge
3857           if ( !aMesh->FindEdge( n1, n2 )) {
3858             myLastCreatedElems.Append(aMesh->AddEdge( n1, n2 )); // free link edge
3859             srcElements.Append( myLastCreatedElems.Last() );
3860           }
3861           n1 = vecNewNodes[ iNode ]->second.back();
3862           n2 = vecNewNodes[ iNext ]->second.back();
3863           if ( !aMesh->FindEdge( n1, n2 )) {
3864             myLastCreatedElems.Append(aMesh->AddEdge( n1, n2 )); // ceiling edge
3865             srcElements.Append( myLastCreatedElems.Last() );
3866           }
3867         }
3868       }
3869     }
3870     else { // elem is quadratic face
3871       int nbn = nbNodes/2;
3872       for ( iNode = 0; iNode < nbn; iNode++ ) {
3873         aFaceLastNodes.insert( vecNewNodes[ iNode ]->second.back() );
3874         int iNext = ( iNode + 1 == nbn ) ? 0 : iNode + 1;
3875         const SMDS_MeshNode* n1 = vecNewNodes[ iNode ]->first;
3876         const SMDS_MeshNode* n2 = vecNewNodes[ iNext ]->first;
3877         // check if a link is free
3878         if ( ! SMESH_MeshEditor::FindFaceInSet ( n1, n2, elemSet, avoidSet )) {
3879           hasFreeLinks = true;
3880           // make an edge and a ceiling for a new edge
3881           // find medium node
3882           const SMDS_MeshNode* n3 = vecNewNodes[ iNode+nbn ]->first;
3883           if ( !aMesh->FindEdge( n1, n2, n3 )) {
3884             myLastCreatedElems.Append(aMesh->AddEdge( n1, n2, n3 )); // free link edge
3885             srcElements.Append( myLastCreatedElems.Last() );
3886           }
3887           n1 = vecNewNodes[ iNode ]->second.back();
3888           n2 = vecNewNodes[ iNext ]->second.back();
3889           n3 = vecNewNodes[ iNode+nbn ]->second.back();
3890           if ( !aMesh->FindEdge( n1, n2, n3 )) {
3891             myLastCreatedElems.Append(aMesh->AddEdge( n1, n2, n3 )); // ceiling edge
3892             srcElements.Append( myLastCreatedElems.Last() );
3893           }
3894         }
3895       }
3896       for ( iNode = nbn; iNode < 2*nbn; iNode++ ) {
3897         aFaceLastNodes.insert( vecNewNodes[ iNode ]->second.back() );
3898       }
3899     }
3900
3901     // sweep free links into faces
3902
3903     if ( hasFreeLinks )  {
3904       list<const SMDS_MeshElement*> & newVolumes = itElem->second;
3905       int iVol, volNb, nbVolumesByStep = newVolumes.size() / nbSteps;
3906
3907       set<const SMDS_MeshNode*> initNodeSet, topNodeSet, faceNodeSet;
3908       for ( iNode = 0; iNode < nbNodes; iNode++ ) {
3909         initNodeSet.insert( vecNewNodes[ iNode ]->first );
3910         topNodeSet .insert( vecNewNodes[ iNode ]->second.back() );
3911       }
3912       for ( volNb = 0; volNb < nbVolumesByStep; volNb++ ) {
3913         list<const SMDS_MeshElement*>::iterator v = newVolumes.begin();
3914         iVol = 0;
3915         while ( iVol++ < volNb ) v++;
3916         // find indices of free faces of a volume and their source edges
3917         list< int > freeInd;
3918         list< const SMDS_MeshElement* > srcEdges; // source edges of free faces
3919         SMDS_VolumeTool vTool( *v );
3920         int iF, nbF = vTool.NbFaces();
3921         for ( iF = 0; iF < nbF; iF ++ ) {
3922           if (vTool.IsFreeFace( iF ) &&
3923               vTool.GetFaceNodes( iF, faceNodeSet ) &&
3924               initNodeSet != faceNodeSet) // except an initial face
3925           {
3926             if ( nbSteps == 1 && faceNodeSet == topNodeSet )
3927               continue;
3928             freeInd.push_back( iF );
3929             // find source edge of a free face iF
3930             vector<const SMDS_MeshNode*> commonNodes; // shared by the initial and free faces
3931             commonNodes.resize( initNodeSet.size(), NULL ); // avoid spoiling memory
3932             std::set_intersection( faceNodeSet.begin(), faceNodeSet.end(),
3933                                    initNodeSet.begin(), initNodeSet.end(),
3934                                    commonNodes.begin());
3935             if ( (*v)->IsQuadratic() )
3936               srcEdges.push_back(aMesh->FindEdge (commonNodes[0],commonNodes[1],commonNodes[2]));
3937             else
3938               srcEdges.push_back(aMesh->FindEdge (commonNodes[0],commonNodes[1]));
3939 #ifdef _DEBUG_
3940             if ( !srcEdges.back() )
3941             {
3942               cout << "SMESH_MeshEditor::makeWalls(), no source edge found for a free face #"
3943                    << iF << " of volume #" << vTool.ID() << endl;
3944             }
3945 #endif
3946           }
3947         }
3948         if ( freeInd.empty() )
3949           continue;
3950
3951         // create faces for all steps;
3952         // if such a face has been already created by sweep of edge,
3953         // assure that its orientation is OK
3954         for ( int iStep = 0; iStep < nbSteps; iStep++ )  {
3955           vTool.Set( *v );
3956           vTool.SetExternalNormal();
3957           list< int >::iterator ind = freeInd.begin();
3958           list< const SMDS_MeshElement* >::iterator srcEdge = srcEdges.begin();
3959           for ( ; ind != freeInd.end(); ++ind, ++srcEdge ) // loop on free faces
3960           {
3961             const SMDS_MeshNode** nodes = vTool.GetFaceNodes( *ind );
3962             int nbn = vTool.NbFaceNodes( *ind );
3963             switch ( nbn ) {
3964             case 3: { ///// triangle
3965               const SMDS_MeshFace * f = aMesh->FindFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ]);
3966               if ( !f )
3967                 myLastCreatedElems.Append(aMesh->AddFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ] ));
3968               else if ( nodes[ 1 ] != f->GetNodeWrap( f->GetNodeIndex( nodes[ 0 ] ) + 1 ))
3969                 aMesh->ChangeElementNodes( f, nodes, nbn );
3970               break;
3971             }
3972             case 4: { ///// quadrangle
3973               const SMDS_MeshFace * f = aMesh->FindFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ], nodes[ 3 ]);
3974               if ( !f )
3975                 myLastCreatedElems.Append(aMesh->AddFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ], nodes[ 3 ] ));
3976               else if ( nodes[ 1 ] != f->GetNodeWrap( f->GetNodeIndex( nodes[ 0 ] ) + 1 ))
3977                 aMesh->ChangeElementNodes( f, nodes, nbn );
3978               break;
3979             }
3980             default:
3981               if( (*v)->IsQuadratic() ) {
3982                 if(nbn==6) { /////// quadratic triangle
3983                   const SMDS_MeshFace * f = aMesh->FindFace( nodes[0], nodes[2], nodes[4],
3984                                                              nodes[1], nodes[3], nodes[5] );
3985                   if ( !f ) {
3986                     myLastCreatedElems.Append(aMesh->AddFace(nodes[0], nodes[2], nodes[4],
3987                                                              nodes[1], nodes[3], nodes[5]));
3988                   }
3989                   else if ( nodes[ 2 ] != f->GetNodeWrap( f->GetNodeIndex( nodes[ 0 ] ) + 1 )) {
3990                     const SMDS_MeshNode** tmpnodes = new const SMDS_MeshNode*[6];
3991                     tmpnodes[0] = nodes[0];
3992                     tmpnodes[1] = nodes[2];
3993                     tmpnodes[2] = nodes[4];
3994                     tmpnodes[3] = nodes[1];
3995                     tmpnodes[4] = nodes[3];
3996                     tmpnodes[5] = nodes[5];
3997                     aMesh->ChangeElementNodes( f, tmpnodes, nbn );
3998                   }
3999                 }
4000                 else {       /////// quadratic quadrangle
4001                   const SMDS_MeshFace * f = aMesh->FindFace( nodes[0], nodes[2], nodes[4], nodes[6],
4002                                                              nodes[1], nodes[3], nodes[5], nodes[7] );
4003                   if ( !f ) {
4004                     myLastCreatedElems.Append(aMesh->AddFace(nodes[0], nodes[2], nodes[4], nodes[6],
4005                                                              nodes[1], nodes[3], nodes[5], nodes[7]));
4006                   }
4007                   else if ( nodes[ 2 ] != f->GetNodeWrap( f->GetNodeIndex( nodes[ 0 ] ) + 1 )) {
4008                     const SMDS_MeshNode** tmpnodes = new const SMDS_MeshNode*[8];
4009                     tmpnodes[0] = nodes[0];
4010                     tmpnodes[1] = nodes[2];
4011                     tmpnodes[2] = nodes[4];
4012                     tmpnodes[3] = nodes[6];
4013                     tmpnodes[4] = nodes[1];
4014                     tmpnodes[5] = nodes[3];
4015                     tmpnodes[6] = nodes[5];
4016                     tmpnodes[7] = nodes[7];
4017                     aMesh->ChangeElementNodes( f, tmpnodes, nbn );
4018                   }
4019                 }
4020               }
4021               else { //////// polygon
4022                 vector<const SMDS_MeshNode*> polygon_nodes ( nodes, &nodes[nbn] );
4023                 const SMDS_MeshFace * f = aMesh->FindFace( polygon_nodes );
4024                 if ( !f )
4025                   myLastCreatedElems.Append(aMesh->AddPolygonalFace(polygon_nodes));
4026                 else if ( nodes[ 1 ] != f->GetNodeWrap( f->GetNodeIndex( nodes[ 0 ] ) + 1 ))
4027                   aMesh->ChangeElementNodes( f, nodes, nbn );
4028               }
4029             }
4030             while ( srcElements.Length() < myLastCreatedElems.Length() )
4031               srcElements.Append( *srcEdge );
4032
4033           }  // loop on free faces
4034
4035           // go to the next volume
4036           iVol = 0;
4037           while ( iVol++ < nbVolumesByStep ) v++;
4038         }
4039       }
4040     } // sweep free links into faces
4041
4042     // Make a ceiling face with a normal external to a volume
4043
4044     SMDS_VolumeTool lastVol( itElem->second.back() );
4045
4046     int iF = lastVol.GetFaceIndex( aFaceLastNodes );
4047     if ( iF >= 0 ) {
4048       lastVol.SetExternalNormal();
4049       const SMDS_MeshNode** nodes = lastVol.GetFaceNodes( iF );
4050       int nbn = lastVol.NbFaceNodes( iF );
4051       switch ( nbn ) {
4052       case 3:
4053         if (!hasFreeLinks ||
4054             !aMesh->FindFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ]))
4055           myLastCreatedElems.Append(aMesh->AddFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ] ));
4056         break;
4057       case 4:
4058         if (!hasFreeLinks ||
4059             !aMesh->FindFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ], nodes[ 3 ]))
4060           myLastCreatedElems.Append(aMesh->AddFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ], nodes[ 3 ] ));
4061         break;
4062       default:
4063         if(itElem->second.back()->IsQuadratic()) {
4064           if(nbn==6) {
4065             if (!hasFreeLinks ||
4066                 !aMesh->FindFace(nodes[0], nodes[2], nodes[4],
4067                                  nodes[1], nodes[3], nodes[5]) ) {
4068               myLastCreatedElems.Append(aMesh->AddFace(nodes[0], nodes[2], nodes[4],
4069                                                        nodes[1], nodes[3], nodes[5]));
4070             }
4071           }
4072           else { // nbn==8
4073             if (!hasFreeLinks ||
4074                 !aMesh->FindFace(nodes[0], nodes[2], nodes[4], nodes[6],
4075                                  nodes[1], nodes[3], nodes[5], nodes[7]) )
4076               myLastCreatedElems.Append(aMesh->AddFace(nodes[0], nodes[2], nodes[4], nodes[6],
4077                                                        nodes[1], nodes[3], nodes[5], nodes[7]));
4078           }
4079         }
4080         else {
4081           vector<const SMDS_MeshNode*> polygon_nodes ( nodes, &nodes[nbn] );
4082           if (!hasFreeLinks || !aMesh->FindFace(polygon_nodes))
4083             myLastCreatedElems.Append(aMesh->AddPolygonalFace(polygon_nodes));
4084         }
4085       } // switch
4086
4087       while ( srcElements.Length() < myLastCreatedElems.Length() )
4088         srcElements.Append( myLastCreatedElems.Last() );
4089     }
4090   } // loop on swept elements
4091 }
4092
4093 //=======================================================================
4094 //function : RotationSweep
4095 //purpose  :
4096 //=======================================================================
4097
4098 SMESH_MeshEditor::PGroupIDs
4099 SMESH_MeshEditor::RotationSweep(TIDSortedElemSet & theElems,
4100                                 const gp_Ax1&      theAxis,
4101                                 const double       theAngle,
4102                                 const int          theNbSteps,
4103                                 const double       theTol,
4104                                 const bool         theMakeGroups,
4105                                 const bool         theMakeWalls)
4106 {
4107   myLastCreatedElems.Clear();
4108   myLastCreatedNodes.Clear();
4109
4110   // source elements for each generated one
4111   SMESH_SequenceOfElemPtr srcElems, srcNodes;
4112
4113   MESSAGE( "RotationSweep()");
4114   gp_Trsf aTrsf;
4115   aTrsf.SetRotation( theAxis, theAngle );
4116   gp_Trsf aTrsf2;
4117   aTrsf2.SetRotation( theAxis, theAngle/2. );
4118
4119   gp_Lin aLine( theAxis );
4120   double aSqTol = theTol * theTol;
4121
4122   SMESHDS_Mesh* aMesh = GetMeshDS();
4123
4124   TNodeOfNodeListMap mapNewNodes;
4125   TElemOfVecOfNnlmiMap mapElemNewNodes;
4126   TElemOfElemListMap newElemsMap;
4127
4128   // loop on theElems
4129   TIDSortedElemSet::iterator itElem;
4130   for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
4131     const SMDS_MeshElement* elem = *itElem;
4132     if ( !elem || elem->GetType() == SMDSAbs_Volume )
4133       continue;
4134     vector<TNodeOfNodeListMapItr> & newNodesItVec = mapElemNewNodes[ elem ];
4135     newNodesItVec.reserve( elem->NbNodes() );
4136
4137     // loop on elem nodes
4138     SMDS_ElemIteratorPtr itN = elem->nodesIterator();
4139     while ( itN->more() ) {
4140       // check if a node has been already sweeped
4141       const SMDS_MeshNode* node = cast2Node( itN->next() );
4142
4143       gp_XYZ aXYZ( node->X(), node->Y(), node->Z() );
4144       double coord[3];
4145       aXYZ.Coord( coord[0], coord[1], coord[2] );
4146       bool isOnAxis = ( aLine.SquareDistance( aXYZ ) <= aSqTol );
4147
4148       TNodeOfNodeListMapItr nIt = mapNewNodes.find( node );
4149       if ( nIt == mapNewNodes.end() ) {
4150         nIt = mapNewNodes.insert( make_pair( node, list<const SMDS_MeshNode*>() )).first;
4151         list<const SMDS_MeshNode*>& listNewNodes = nIt->second;
4152
4153         // make new nodes
4154         //gp_XYZ aXYZ( node->X(), node->Y(), node->Z() );
4155         //double coord[3];
4156         //aXYZ.Coord( coord[0], coord[1], coord[2] );
4157         //bool isOnAxis = ( aLine.SquareDistance( aXYZ ) <= aSqTol );
4158         const SMDS_MeshNode * newNode = node;
4159         for ( int i = 0; i < theNbSteps; i++ ) {
4160           if ( !isOnAxis ) {
4161             if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
4162               // create two nodes
4163               aTrsf2.Transforms( coord[0], coord[1], coord[2] );
4164               //aTrsf.Transforms( coord[0], coord[1], coord[2] );
4165               newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
4166               myLastCreatedNodes.Append(newNode);
4167               srcNodes.Append( node );
4168               listNewNodes.push_back( newNode );
4169               aTrsf2.Transforms( coord[0], coord[1], coord[2] );
4170               //aTrsf.Transforms( coord[0], coord[1], coord[2] );
4171             }
4172             else {
4173               aTrsf.Transforms( coord[0], coord[1], coord[2] );
4174             }
4175             newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
4176             myLastCreatedNodes.Append(newNode);
4177             srcNodes.Append( node );
4178             listNewNodes.push_back( newNode );
4179           }
4180           else {
4181             listNewNodes.push_back( newNode );
4182             if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
4183               listNewNodes.push_back( newNode );
4184             }
4185           }
4186         }
4187       }
4188       /*
4189         else {
4190         // if current elem is quadratic and current node is not medium
4191         // we have to check - may be it is needed to insert additional nodes
4192         if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
4193         list< const SMDS_MeshNode* > & listNewNodes = nIt->second;
4194         if(listNewNodes.size()==theNbSteps) {
4195         listNewNodes.clear();
4196         // make new nodes
4197         //gp_XYZ aXYZ( node->X(), node->Y(), node->Z() );
4198         //double coord[3];
4199         //aXYZ.Coord( coord[0], coord[1], coord[2] );
4200         const SMDS_MeshNode * newNode = node;
4201         if ( !isOnAxis ) {
4202         for(int i = 0; i<theNbSteps; i++) {
4203         aTrsf2.Transforms( coord[0], coord[1], coord[2] );
4204         newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
4205         cout<<"    3 AddNode:  "<<newNode;
4206         myLastCreatedNodes.Append(newNode);
4207         listNewNodes.push_back( newNode );
4208         srcNodes.Append( node );
4209         aTrsf2.Transforms( coord[0], coord[1], coord[2] );
4210         newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
4211         cout<<"    4 AddNode:  "<<newNode;
4212         myLastCreatedNodes.Append(newNode);
4213         srcNodes.Append( node );
4214         listNewNodes.push_back( newNode );
4215         }
4216         }
4217         else {
4218         listNewNodes.push_back( newNode );
4219         }
4220         }
4221         }
4222         }
4223       */
4224       newNodesItVec.push_back( nIt );
4225     }
4226     // make new elements
4227     sweepElement( elem, newNodesItVec, newElemsMap[elem], theNbSteps, srcElems );
4228   }
4229
4230   if ( theMakeWalls )
4231     makeWalls( mapNewNodes, newElemsMap, mapElemNewNodes, theElems, theNbSteps, srcElems );
4232
4233   PGroupIDs newGroupIDs;
4234   if ( theMakeGroups )
4235     newGroupIDs = generateGroups( srcNodes, srcElems, "rotated");
4236
4237   return newGroupIDs;
4238 }
4239
4240
4241 //=======================================================================
4242 //function : CreateNode
4243 //purpose  :
4244 //=======================================================================
4245 const SMDS_MeshNode* SMESH_MeshEditor::CreateNode(const double x,
4246                                                   const double y,
4247                                                   const double z,
4248                                                   const double tolnode,
4249                                                   SMESH_SequenceOfNode& aNodes)
4250 {
4251   myLastCreatedElems.Clear();
4252   myLastCreatedNodes.Clear();
4253
4254   gp_Pnt P1(x,y,z);
4255   SMESHDS_Mesh * aMesh = myMesh->GetMeshDS();
4256
4257   // try to search in sequence of existing nodes
4258   // if aNodes.Length()>0 we 'nave to use given sequence
4259   // else - use all nodes of mesh
4260   if(aNodes.Length()>0) {
4261     int i;
4262     for(i=1; i<=aNodes.Length(); i++) {
4263       gp_Pnt P2(aNodes.Value(i)->X(),aNodes.Value(i)->Y(),aNodes.Value(i)->Z());
4264       if(P1.Distance(P2)<tolnode)
4265         return aNodes.Value(i);
4266     }
4267   }
4268   else {
4269     SMDS_NodeIteratorPtr itn = aMesh->nodesIterator();
4270     while(itn->more()) {
4271       const SMDS_MeshNode* aN = static_cast<const SMDS_MeshNode*> (itn->next());
4272       gp_Pnt P2(aN->X(),aN->Y(),aN->Z());
4273       if(P1.Distance(P2)<tolnode)
4274         return aN;
4275     }
4276   }
4277
4278   // create new node and return it
4279   const SMDS_MeshNode* NewNode = aMesh->AddNode(x,y,z);
4280   myLastCreatedNodes.Append(NewNode);
4281   return NewNode;
4282 }
4283
4284
4285 //=======================================================================
4286 //function : ExtrusionSweep
4287 //purpose  :
4288 //=======================================================================
4289
4290 SMESH_MeshEditor::PGroupIDs
4291 SMESH_MeshEditor::ExtrusionSweep (TIDSortedElemSet &  theElems,
4292                                   const gp_Vec&       theStep,
4293                                   const int           theNbSteps,
4294                                   TElemOfElemListMap& newElemsMap,
4295                                   const bool          theMakeGroups,
4296                                   const int           theFlags,
4297                                   const double        theTolerance)
4298 {
4299   ExtrusParam aParams;
4300   aParams.myDir = gp_Dir(theStep);
4301   aParams.myNodes.Clear();
4302   aParams.mySteps = new TColStd_HSequenceOfReal;
4303   int i;
4304   for(i=1; i<=theNbSteps; i++)
4305     aParams.mySteps->Append(theStep.Magnitude());
4306
4307   return
4308     ExtrusionSweep(theElems,aParams,newElemsMap,theMakeGroups,theFlags,theTolerance);
4309 }
4310
4311
4312 //=======================================================================
4313 //function : ExtrusionSweep
4314 //purpose  :
4315 //=======================================================================
4316
4317 SMESH_MeshEditor::PGroupIDs
4318 SMESH_MeshEditor::ExtrusionSweep (TIDSortedElemSet &  theElems,
4319                                   ExtrusParam&        theParams,
4320                                   TElemOfElemListMap& newElemsMap,
4321                                   const bool          theMakeGroups,
4322                                   const int           theFlags,
4323                                   const double        theTolerance)
4324 {
4325   myLastCreatedElems.Clear();
4326   myLastCreatedNodes.Clear();
4327
4328   // source elements for each generated one
4329   SMESH_SequenceOfElemPtr srcElems, srcNodes;
4330
4331   SMESHDS_Mesh* aMesh = GetMeshDS();
4332
4333   int nbsteps = theParams.mySteps->Length();
4334
4335   TNodeOfNodeListMap mapNewNodes;
4336   //TNodeOfNodeVecMap mapNewNodes;
4337   TElemOfVecOfNnlmiMap mapElemNewNodes;
4338   //TElemOfVecOfMapNodesMap mapElemNewNodes;
4339
4340   // loop on theElems
4341   TIDSortedElemSet::iterator itElem;
4342   for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
4343     // check element type
4344     const SMDS_MeshElement* elem = *itElem;
4345     if ( !elem  || elem->GetType() == SMDSAbs_Volume )
4346       continue;
4347
4348     vector<TNodeOfNodeListMapItr> & newNodesItVec = mapElemNewNodes[ elem ];
4349     //vector<TNodeOfNodeVecMapItr> & newNodesItVec = mapElemNewNodes[ elem ];
4350     newNodesItVec.reserve( elem->NbNodes() );
4351
4352     // loop on elem nodes
4353     SMDS_ElemIteratorPtr itN = elem->nodesIterator();
4354     while ( itN->more() )
4355     {
4356       // check if a node has been already sweeped
4357       const SMDS_MeshNode* node = cast2Node( itN->next() );
4358       TNodeOfNodeListMap::iterator nIt = mapNewNodes.find( node );
4359       //TNodeOfNodeVecMap::iterator nIt = mapNewNodes.find( node );
4360       if ( nIt == mapNewNodes.end() ) {
4361         nIt = mapNewNodes.insert( make_pair( node, list<const SMDS_MeshNode*>() )).first;
4362         //nIt = mapNewNodes.insert( make_pair( node, vector<const SMDS_MeshNode*>() )).first;
4363         list<const SMDS_MeshNode*>& listNewNodes = nIt->second;
4364         //vector<const SMDS_MeshNode*>& vecNewNodes = nIt->second;
4365         //vecNewNodes.reserve(nbsteps);
4366
4367         // make new nodes
4368         double coord[] = { node->X(), node->Y(), node->Z() };
4369         //int nbsteps = theParams.mySteps->Length();
4370         for ( int i = 0; i < nbsteps; i++ ) {
4371           if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
4372             // create additional node
4373             double x = coord[0] + theParams.myDir.X()*theParams.mySteps->Value(i+1)/2.;
4374             double y = coord[1] + theParams.myDir.Y()*theParams.mySteps->Value(i+1)/2.;
4375             double z = coord[2] + theParams.myDir.Z()*theParams.mySteps->Value(i+1)/2.;
4376             if( theFlags & EXTRUSION_FLAG_SEW ) {
4377               const SMDS_MeshNode * newNode = CreateNode(x, y, z,
4378                                                          theTolerance, theParams.myNodes);
4379               listNewNodes.push_back( newNode );
4380             }
4381             else {
4382               const SMDS_MeshNode * newNode = aMesh->AddNode(x, y, z);
4383               myLastCreatedNodes.Append(newNode);
4384               srcNodes.Append( node );
4385               listNewNodes.push_back( newNode );
4386             }
4387           }
4388           //aTrsf.Transforms( coord[0], coord[1], coord[2] );
4389           coord[0] = coord[0] + theParams.myDir.X()*theParams.mySteps->Value(i+1);
4390           coord[1] = coord[1] + theParams.myDir.Y()*theParams.mySteps->Value(i+1);
4391           coord[2] = coord[2] + theParams.myDir.Z()*theParams.mySteps->Value(i+1);
4392           if( theFlags & EXTRUSION_FLAG_SEW ) {
4393             const SMDS_MeshNode * newNode = CreateNode(coord[0], coord[1], coord[2],
4394                                                        theTolerance, theParams.myNodes);
4395             listNewNodes.push_back( newNode );
4396             //vecNewNodes[i]=newNode;
4397           }
4398           else {
4399             const SMDS_MeshNode * newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
4400             myLastCreatedNodes.Append(newNode);
4401             srcNodes.Append( node );
4402             listNewNodes.push_back( newNode );
4403             //vecNewNodes[i]=newNode;
4404           }
4405         }
4406       }
4407       else {
4408         // if current elem is quadratic and current node is not medium
4409         // we have to check - may be it is needed to insert additional nodes
4410         if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
4411           list< const SMDS_MeshNode* > & listNewNodes = nIt->second;
4412           if(listNewNodes.size()==nbsteps) {
4413             listNewNodes.clear();
4414             double coord[] = { node->X(), node->Y(), node->Z() };
4415             for ( int i = 0; i < nbsteps; i++ ) {
4416               double x = coord[0] + theParams.myDir.X()*theParams.mySteps->Value(i+1);
4417               double y = coord[1] + theParams.myDir.Y()*theParams.mySteps->Value(i+1);
4418               double z = coord[2] + theParams.myDir.Z()*theParams.mySteps->Value(i+1);
4419               if( theFlags & EXTRUSION_FLAG_SEW ) {
4420                 const SMDS_MeshNode * newNode = CreateNode(x, y, z,
4421                                                            theTolerance, theParams.myNodes);
4422                 listNewNodes.push_back( newNode );
4423               }
4424               else {
4425                 const SMDS_MeshNode * newNode = aMesh->AddNode(x, y, z);
4426                 myLastCreatedNodes.Append(newNode);
4427                 srcNodes.Append( node );
4428                 listNewNodes.push_back( newNode );
4429               }
4430               coord[0] = coord[0] + theParams.myDir.X()*theParams.mySteps->Value(i+1);
4431               coord[1] = coord[1] + theParams.myDir.Y()*theParams.mySteps->Value(i+1);
4432               coord[2] = coord[2] + theParams.myDir.Z()*theParams.mySteps->Value(i+1);
4433               if( theFlags & EXTRUSION_FLAG_SEW ) {
4434                 const SMDS_MeshNode * newNode = CreateNode(coord[0], coord[1], coord[2],
4435                                                            theTolerance, theParams.myNodes);
4436                 listNewNodes.push_back( newNode );
4437               }
4438               else {
4439                 const SMDS_MeshNode * newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
4440                 myLastCreatedNodes.Append(newNode);
4441                 srcNodes.Append( node );
4442                 listNewNodes.push_back( newNode );
4443               }
4444             }
4445           }
4446         }
4447       }
4448       newNodesItVec.push_back( nIt );
4449     }
4450     // make new elements
4451     sweepElement( elem, newNodesItVec, newElemsMap[elem], nbsteps, srcElems );
4452   }
4453
4454   if( theFlags & EXTRUSION_FLAG_BOUNDARY ) {
4455     makeWalls( mapNewNodes, newElemsMap, mapElemNewNodes, theElems, nbsteps, srcElems );
4456   }
4457   PGroupIDs newGroupIDs;
4458   if ( theMakeGroups )
4459     newGroupIDs = generateGroups( srcNodes, srcElems, "extruded");
4460
4461   return newGroupIDs;
4462 }
4463
4464 /*
4465 //=======================================================================
4466 //class    : SMESH_MeshEditor_PathPoint
4467 //purpose  : auxiliary class
4468 //=======================================================================
4469 class SMESH_MeshEditor_PathPoint {
4470 public:
4471 SMESH_MeshEditor_PathPoint() {
4472 myPnt.SetCoord(99., 99., 99.);
4473 myTgt.SetCoord(1.,0.,0.);
4474 myAngle=0.;
4475 myPrm=0.;
4476 }
4477 void SetPnt(const gp_Pnt& aP3D){
4478 myPnt=aP3D;
4479 }
4480 void SetTangent(const gp_Dir& aTgt){
4481 myTgt=aTgt;
4482 }
4483 void SetAngle(const double& aBeta){
4484 myAngle=aBeta;
4485 }
4486 void SetParameter(const double& aPrm){
4487 myPrm=aPrm;
4488 }
4489 const gp_Pnt& Pnt()const{
4490 return myPnt;
4491 }
4492 const gp_Dir& Tangent()const{
4493 return myTgt;
4494 }
4495 double Angle()const{
4496 return myAngle;
4497 }
4498 double Parameter()const{
4499 return myPrm;
4500 }
4501
4502 protected:
4503 gp_Pnt myPnt;
4504 gp_Dir myTgt;
4505 double myAngle;
4506 double myPrm;
4507 };
4508 */
4509
4510 //=======================================================================
4511 //function : ExtrusionAlongTrack
4512 //purpose  :
4513 //=======================================================================
4514 SMESH_MeshEditor::Extrusion_Error
4515 SMESH_MeshEditor::ExtrusionAlongTrack (TIDSortedElemSet &   theElements,
4516                                        SMESH_subMesh*       theTrack,
4517                                        const SMDS_MeshNode* theN1,
4518                                        const bool           theHasAngles,
4519                                        list<double>&        theAngles,
4520                                        const bool           theLinearVariation,
4521                                        const bool           theHasRefPoint,
4522                                        const gp_Pnt&        theRefPoint,
4523                                        const bool           theMakeGroups)
4524 {
4525   myLastCreatedElems.Clear();
4526   myLastCreatedNodes.Clear();
4527
4528   int aNbE;
4529   std::list<double> aPrms;
4530   TIDSortedElemSet::iterator itElem;
4531
4532   gp_XYZ aGC;
4533   TopoDS_Edge aTrackEdge;
4534   TopoDS_Vertex aV1, aV2;
4535
4536   SMDS_ElemIteratorPtr aItE;
4537   SMDS_NodeIteratorPtr aItN;
4538   SMDSAbs_ElementType aTypeE;
4539
4540   TNodeOfNodeListMap mapNewNodes;
4541
4542   // 1. Check data
4543   aNbE = theElements.size();
4544   // nothing to do
4545   if ( !aNbE )
4546     return EXTR_NO_ELEMENTS;
4547
4548   // 1.1 Track Pattern
4549   ASSERT( theTrack );
4550
4551   SMESHDS_SubMesh* pSubMeshDS = theTrack->GetSubMeshDS();
4552
4553   aItE = pSubMeshDS->GetElements();
4554   while ( aItE->more() ) {
4555     const SMDS_MeshElement* pE = aItE->next();
4556     aTypeE = pE->GetType();
4557     // Pattern must contain links only
4558     if ( aTypeE != SMDSAbs_Edge )
4559       return EXTR_PATH_NOT_EDGE;
4560   }
4561
4562   list<SMESH_MeshEditor_PathPoint> fullList;
4563
4564   const TopoDS_Shape& aS = theTrack->GetSubShape();
4565   // Sub shape for the Pattern must be an Edge or Wire
4566   if( aS.ShapeType() == TopAbs_EDGE ) {
4567     aTrackEdge = TopoDS::Edge( aS );
4568     // the Edge must not be degenerated
4569     if ( BRep_Tool::Degenerated( aTrackEdge ) )
4570       return EXTR_BAD_PATH_SHAPE;
4571     TopExp::Vertices( aTrackEdge, aV1, aV2 );
4572     aItN = theTrack->GetFather()->GetSubMesh( aV1 )->GetSubMeshDS()->GetNodes();
4573     const SMDS_MeshNode* aN1 = aItN->next();
4574     aItN = theTrack->GetFather()->GetSubMesh( aV2 )->GetSubMeshDS()->GetNodes();
4575     const SMDS_MeshNode* aN2 = aItN->next();
4576     // starting node must be aN1 or aN2
4577     if ( !( aN1 == theN1 || aN2 == theN1 ) )
4578       return EXTR_BAD_STARTING_NODE;
4579     aItN = pSubMeshDS->GetNodes();
4580     while ( aItN->more() ) {
4581       const SMDS_MeshNode* pNode = aItN->next();
4582       const SMDS_EdgePosition* pEPos =
4583         static_cast<const SMDS_EdgePosition*>( pNode->GetPosition().get() );
4584       double aT = pEPos->GetUParameter();
4585       aPrms.push_back( aT );
4586     }
4587     //Extrusion_Error err =
4588     MakeEdgePathPoints(aPrms, aTrackEdge, (aN1==theN1), fullList);
4589   }
4590   else if( aS.ShapeType() == TopAbs_WIRE ) {
4591     list< SMESH_subMesh* > LSM;
4592     TopTools_SequenceOfShape Edges;
4593     SMESH_subMeshIteratorPtr itSM = theTrack->getDependsOnIterator(false,true);
4594     while(itSM->more()) {
4595       SMESH_subMesh* SM = itSM->next();
4596       LSM.push_back(SM);
4597       const TopoDS_Shape& aS = SM->GetSubShape();
4598       Edges.Append(aS);
4599     }
4600     list< list<SMESH_MeshEditor_PathPoint> > LLPPs;
4601     int startNid = theN1->GetID();
4602     TColStd_MapOfInteger UsedNums;
4603     int NbEdges = Edges.Length();
4604     int i = 1;
4605     for(; i<=NbEdges; i++) {
4606       int k = 0;
4607       list< SMESH_subMesh* >::iterator itLSM = LSM.begin();
4608       for(; itLSM!=LSM.end(); itLSM++) {
4609         k++;
4610         if(UsedNums.Contains(k)) continue;
4611         aTrackEdge = TopoDS::Edge( Edges.Value(k) );
4612         SMESH_subMesh* locTrack = *itLSM;
4613         SMESHDS_SubMesh* locMeshDS = locTrack->GetSubMeshDS();
4614         TopExp::Vertices( aTrackEdge, aV1, aV2 );
4615         aItN = locTrack->GetFather()->GetSubMesh(aV1)->GetSubMeshDS()->GetNodes();
4616         const SMDS_MeshNode* aN1 = aItN->next();
4617         aItN = locTrack->GetFather()->GetSubMesh(aV2)->GetSubMeshDS()->GetNodes();
4618         const SMDS_MeshNode* aN2 = aItN->next();
4619         // starting node must be aN1 or aN2
4620         if ( !( aN1->GetID() == startNid || aN2->GetID() == startNid ) ) continue;
4621         // 2. Collect parameters on the track edge
4622         aPrms.clear();
4623         aItN = locMeshDS->GetNodes();
4624         while ( aItN->more() ) {
4625           const SMDS_MeshNode* pNode = aItN->next();
4626           const SMDS_EdgePosition* pEPos =
4627             static_cast<const SMDS_EdgePosition*>( pNode->GetPosition().get() );
4628           double aT = pEPos->GetUParameter();
4629           aPrms.push_back( aT );
4630         }
4631         list<SMESH_MeshEditor_PathPoint> LPP;
4632         //Extrusion_Error err =
4633         MakeEdgePathPoints(aPrms, aTrackEdge,(aN1->GetID()==startNid), LPP);
4634         LLPPs.push_back(LPP);
4635         UsedNums.Add(k);
4636         // update startN for search following egde
4637         if( aN1->GetID() == startNid ) startNid = aN2->GetID();
4638         else startNid = aN1->GetID();
4639         break;
4640       }
4641     }
4642     list< list<SMESH_MeshEditor_PathPoint> >::iterator itLLPP = LLPPs.begin();
4643     list<SMESH_MeshEditor_PathPoint> firstList = *itLLPP;
4644     list<SMESH_MeshEditor_PathPoint>::iterator itPP = firstList.begin();
4645     for(; itPP!=firstList.end(); itPP++) {
4646       fullList.push_back( *itPP );
4647     }
4648     SMESH_MeshEditor_PathPoint PP1 = fullList.back();
4649     fullList.pop_back();
4650     itLLPP++;
4651     for(; itLLPP!=LLPPs.end(); itLLPP++) {
4652       list<SMESH_MeshEditor_PathPoint> currList = *itLLPP;
4653       itPP = currList.begin();
4654       SMESH_MeshEditor_PathPoint PP2 = currList.front();
4655       gp_Dir D1 = PP1.Tangent();
4656       gp_Dir D2 = PP2.Tangent();
4657       gp_Dir Dnew( gp_Vec( (D1.X()+D2.X())/2, (D1.Y()+D2.Y())/2,
4658                            (D1.Z()+D2.Z())/2 ) );
4659       PP1.SetTangent(Dnew);
4660       fullList.push_back(PP1);
4661       itPP++;
4662       for(; itPP!=firstList.end(); itPP++) {
4663         fullList.push_back( *itPP );
4664       }
4665       PP1 = fullList.back();
4666       fullList.pop_back();
4667     }
4668     // if wire not closed
4669     fullList.push_back(PP1);
4670     // else ???
4671   }
4672   else {
4673     return EXTR_BAD_PATH_SHAPE;
4674   }
4675
4676   return MakeExtrElements(theElements, fullList, theHasAngles, theAngles, theLinearVariation,
4677                           theHasRefPoint, theRefPoint, theMakeGroups);
4678 }
4679
4680
4681 //=======================================================================
4682 //function : ExtrusionAlongTrack
4683 //purpose  :
4684 //=======================================================================
4685 SMESH_MeshEditor::Extrusion_Error
4686 SMESH_MeshEditor::ExtrusionAlongTrack (TIDSortedElemSet &   theElements,
4687                                        SMESH_Mesh*          theTrack,
4688                                        const SMDS_MeshNode* theN1,
4689                                        const bool           theHasAngles,
4690                                        list<double>&        theAngles,
4691                                        const bool           theLinearVariation,
4692                                        const bool           theHasRefPoint,
4693                                        const gp_Pnt&        theRefPoint,
4694                                        const bool           theMakeGroups)
4695 {
4696   myLastCreatedElems.Clear();
4697   myLastCreatedNodes.Clear();
4698
4699   int aNbE;
4700   std::list<double> aPrms;
4701   TIDSortedElemSet::iterator itElem;
4702
4703   gp_XYZ aGC;
4704   TopoDS_Edge aTrackEdge;
4705   TopoDS_Vertex aV1, aV2;
4706
4707   SMDS_ElemIteratorPtr aItE;
4708   SMDS_NodeIteratorPtr aItN;
4709   SMDSAbs_ElementType aTypeE;
4710
4711   TNodeOfNodeListMap mapNewNodes;
4712
4713   // 1. Check data
4714   aNbE = theElements.size();
4715   // nothing to do
4716   if ( !aNbE )
4717     return EXTR_NO_ELEMENTS;
4718
4719   // 1.1 Track Pattern
4720   ASSERT( theTrack );
4721
4722   SMESHDS_Mesh* pMeshDS = theTrack->GetMeshDS();
4723
4724   aItE = pMeshDS->elementsIterator();
4725   while ( aItE->more() ) {
4726     const SMDS_MeshElement* pE = aItE->next();
4727     aTypeE = pE->GetType();
4728     // Pattern must contain links only
4729     if ( aTypeE != SMDSAbs_Edge )
4730       return EXTR_PATH_NOT_EDGE;
4731   }
4732
4733   list<SMESH_MeshEditor_PathPoint> fullList;
4734
4735   const TopoDS_Shape& aS = theTrack->GetShapeToMesh();
4736   // Sub shape for the Pattern must be an Edge or Wire
4737   if( aS.ShapeType() == TopAbs_EDGE ) {
4738     aTrackEdge = TopoDS::Edge( aS );
4739     // the Edge must not be degenerated
4740     if ( BRep_Tool::Degenerated( aTrackEdge ) )
4741       return EXTR_BAD_PATH_SHAPE;
4742     TopExp::Vertices( aTrackEdge, aV1, aV2 );
4743     aItN = theTrack->GetSubMesh( aV1 )->GetSubMeshDS()->GetNodes();
4744     const SMDS_MeshNode* aN1 = aItN->next();
4745     aItN = theTrack->GetSubMesh( aV2 )->GetSubMeshDS()->GetNodes();
4746     const SMDS_MeshNode* aN2 = aItN->next();
4747     // starting node must be aN1 or aN2
4748     if ( !( aN1 == theN1 || aN2 == theN1 ) )
4749       return EXTR_BAD_STARTING_NODE;
4750     aItN = pMeshDS->nodesIterator();
4751     while ( aItN->more() ) {
4752       const SMDS_MeshNode* pNode = aItN->next();
4753       if( pNode==aN1 || pNode==aN2 ) continue;
4754       const SMDS_EdgePosition* pEPos =
4755         static_cast<const SMDS_EdgePosition*>( pNode->GetPosition().get() );
4756       double aT = pEPos->GetUParameter();
4757       aPrms.push_back( aT );
4758     }
4759     //Extrusion_Error err =
4760     MakeEdgePathPoints(aPrms, aTrackEdge, (aN1==theN1), fullList);
4761   }
4762   else if( aS.ShapeType() == TopAbs_WIRE ) {
4763     list< SMESH_subMesh* > LSM;
4764     TopTools_SequenceOfShape Edges;
4765     TopExp_Explorer eExp(aS, TopAbs_EDGE);
4766     for(; eExp.More(); eExp.Next()) {
4767       TopoDS_Edge E = TopoDS::Edge( eExp.Current() );
4768       if( BRep_Tool::Degenerated(E) ) continue;
4769       SMESH_subMesh* SM = theTrack->GetSubMesh(E);
4770       if(SM) {
4771         LSM.push_back(SM);
4772         Edges.Append(E);
4773       }
4774     }
4775     list< list<SMESH_MeshEditor_PathPoint> > LLPPs;
4776     int startNid = theN1->GetID();
4777     TColStd_MapOfInteger UsedNums;
4778     int NbEdges = Edges.Length();
4779     int i = 1;
4780     for(; i<=NbEdges; i++) {
4781       int k = 0;
4782       list< SMESH_subMesh* >::iterator itLSM = LSM.begin();
4783       for(; itLSM!=LSM.end(); itLSM++) {
4784         k++;
4785         if(UsedNums.Contains(k)) continue;
4786         aTrackEdge = TopoDS::Edge( Edges.Value(k) );
4787         SMESH_subMesh* locTrack = *itLSM;
4788         SMESHDS_SubMesh* locMeshDS = locTrack->GetSubMeshDS();
4789         TopExp::Vertices( aTrackEdge, aV1, aV2 );
4790         aItN = locTrack->GetFather()->GetSubMesh(aV1)->GetSubMeshDS()->GetNodes();
4791         const SMDS_MeshNode* aN1 = aItN->next();
4792         aItN = locTrack->GetFather()->GetSubMesh(aV2)->GetSubMeshDS()->GetNodes();
4793         const SMDS_MeshNode* aN2 = aItN->next();
4794         // starting node must be aN1 or aN2
4795         if ( !( aN1->GetID() == startNid || aN2->GetID() == startNid ) ) continue;
4796         // 2. Collect parameters on the track edge
4797         aPrms.clear();
4798         aItN = locMeshDS->GetNodes();
4799         while ( aItN->more() ) {
4800           const SMDS_MeshNode* pNode = aItN->next();
4801           const SMDS_EdgePosition* pEPos =
4802             static_cast<const SMDS_EdgePosition*>( pNode->GetPosition().get() );
4803           double aT = pEPos->GetUParameter();
4804           aPrms.push_back( aT );
4805         }
4806         list<SMESH_MeshEditor_PathPoint> LPP;
4807         //Extrusion_Error err =
4808         MakeEdgePathPoints(aPrms, aTrackEdge,(aN1->GetID()==startNid), LPP);
4809         LLPPs.push_back(LPP);
4810         UsedNums.Add(k);
4811         // update startN for search following egde
4812         if( aN1->GetID() == startNid ) startNid = aN2->GetID();
4813         else startNid = aN1->GetID();
4814         break;
4815       }
4816     }
4817     list< list<SMESH_MeshEditor_PathPoint> >::iterator itLLPP = LLPPs.begin();
4818     list<SMESH_MeshEditor_PathPoint> firstList = *itLLPP;
4819     list<SMESH_MeshEditor_PathPoint>::iterator itPP = firstList.begin();
4820     for(; itPP!=firstList.end(); itPP++) {
4821       fullList.push_back( *itPP );
4822     }
4823     SMESH_MeshEditor_PathPoint PP1 = fullList.back();
4824     fullList.pop_back();
4825     itLLPP++;
4826     for(; itLLPP!=LLPPs.end(); itLLPP++) {
4827       list<SMESH_MeshEditor_PathPoint> currList = *itLLPP;
4828       itPP = currList.begin();
4829       SMESH_MeshEditor_PathPoint PP2 = currList.front();
4830       gp_Pnt P1 = PP1.Pnt();
4831       //cout<<"    PP1: Pnt("<<P1.X()<<","<<P1.Y()<<","<<P1.Z()<<")"<<endl;
4832       gp_Pnt P2 = PP2.Pnt();
4833       gp_Dir D1 = PP1.Tangent();
4834       gp_Dir D2 = PP2.Tangent();
4835       gp_Dir Dnew( gp_Vec( (D1.X()+D2.X())/2, (D1.Y()+D2.Y())/2,
4836                            (D1.Z()+D2.Z())/2 ) );
4837       PP1.SetTangent(Dnew);
4838       fullList.push_back(PP1);
4839       itPP++;
4840       for(; itPP!=currList.end(); itPP++) {
4841         fullList.push_back( *itPP );
4842       }
4843       PP1 = fullList.back();
4844       fullList.pop_back();
4845     }
4846     // if wire not closed
4847     fullList.push_back(PP1);
4848     // else ???
4849   }
4850   else {
4851     return EXTR_BAD_PATH_SHAPE;
4852   }
4853
4854   return MakeExtrElements(theElements, fullList, theHasAngles, theAngles, theLinearVariation,
4855                           theHasRefPoint, theRefPoint, theMakeGroups);
4856 }
4857
4858
4859 //=======================================================================
4860 //function : MakeEdgePathPoints
4861 //purpose  : auxilary for ExtrusionAlongTrack
4862 //=======================================================================
4863 SMESH_MeshEditor::Extrusion_Error
4864 SMESH_MeshEditor::MakeEdgePathPoints(std::list<double>& aPrms,
4865                                      const TopoDS_Edge& aTrackEdge,
4866                                      bool FirstIsStart,
4867                                      list<SMESH_MeshEditor_PathPoint>& LPP)
4868 {
4869   Standard_Real aTx1, aTx2, aL2, aTolVec, aTolVec2;
4870   aTolVec=1.e-7;
4871   aTolVec2=aTolVec*aTolVec;
4872   double aT1, aT2;
4873   TopoDS_Vertex aV1, aV2;
4874   TopExp::Vertices( aTrackEdge, aV1, aV2 );
4875   aT1=BRep_Tool::Parameter( aV1, aTrackEdge );
4876   aT2=BRep_Tool::Parameter( aV2, aTrackEdge );
4877   // 2. Collect parameters on the track edge
4878   aPrms.push_front( aT1 );
4879   aPrms.push_back( aT2 );
4880   // sort parameters
4881   aPrms.sort();
4882   if( FirstIsStart ) {
4883     if ( aT1 > aT2 ) {
4884       aPrms.reverse();
4885     }
4886   }
4887   else {
4888     if ( aT2 > aT1 ) {
4889       aPrms.reverse();
4890     }
4891   }
4892   // 3. Path Points
4893   SMESH_MeshEditor_PathPoint aPP;
4894   Handle(Geom_Curve) aC3D = BRep_Tool::Curve( aTrackEdge, aTx1, aTx2 );
4895   std::list<double>::iterator aItD = aPrms.begin();
4896   for(; aItD != aPrms.end(); ++aItD) {
4897     double aT = *aItD;
4898     gp_Pnt aP3D;
4899     gp_Vec aVec;
4900     aC3D->D1( aT, aP3D, aVec );
4901     aL2 = aVec.SquareMagnitude();
4902     if ( aL2 < aTolVec2 )
4903       return EXTR_CANT_GET_TANGENT;
4904     gp_Dir aTgt( aVec );
4905     aPP.SetPnt( aP3D );
4906     aPP.SetTangent( aTgt );
4907     aPP.SetParameter( aT );
4908     LPP.push_back(aPP);
4909   }
4910   return EXTR_OK;
4911 }
4912
4913
4914 //=======================================================================
4915 //function : MakeExtrElements
4916 //purpose  : auxilary for ExtrusionAlongTrack
4917 //=======================================================================
4918 SMESH_MeshEditor::Extrusion_Error
4919 SMESH_MeshEditor::MakeExtrElements(TIDSortedElemSet&  theElements,
4920                                    list<SMESH_MeshEditor_PathPoint>& fullList,
4921                                    const bool theHasAngles,
4922                                    list<double>& theAngles,
4923                                    const bool theLinearVariation,
4924                                    const bool theHasRefPoint,
4925                                    const gp_Pnt& theRefPoint,
4926                                    const bool theMakeGroups)
4927 {
4928   //cout<<"MakeExtrElements  fullList.size() = "<<fullList.size()<<endl;
4929   int aNbTP = fullList.size();
4930   vector<SMESH_MeshEditor_PathPoint> aPPs(aNbTP);
4931   // Angles
4932   if( theHasAngles && theAngles.size()>0 && theLinearVariation ) {
4933     LinearAngleVariation(aNbTP-1, theAngles);
4934   }
4935   vector<double> aAngles( aNbTP );
4936   int j = 0;
4937   for(; j<aNbTP; ++j) {
4938     aAngles[j] = 0.;
4939   }
4940   if ( theHasAngles ) {
4941     double anAngle;;
4942     std::list<double>::iterator aItD = theAngles.begin();
4943     for ( j=1; (aItD != theAngles.end()) && (j<aNbTP); ++aItD, ++j ) {
4944       anAngle = *aItD;
4945       aAngles[j] = anAngle;
4946     }
4947   }
4948   // fill vector of path points with angles
4949   //aPPs.resize(fullList.size());
4950   j = -1;
4951   list<SMESH_MeshEditor_PathPoint>::iterator itPP = fullList.begin();
4952   for(; itPP!=fullList.end(); itPP++) {
4953     j++;
4954     SMESH_MeshEditor_PathPoint PP = *itPP;
4955     PP.SetAngle(aAngles[j]);
4956     aPPs[j] = PP;
4957   }
4958
4959   TNodeOfNodeListMap mapNewNodes;
4960   TElemOfVecOfNnlmiMap mapElemNewNodes;
4961   TElemOfElemListMap newElemsMap;
4962   TIDSortedElemSet::iterator itElem;
4963   double aX, aY, aZ;
4964   int aNb;
4965   SMDSAbs_ElementType aTypeE;
4966   // source elements for each generated one
4967   SMESH_SequenceOfElemPtr srcElems, srcNodes;
4968
4969   // 3. Center of rotation aV0
4970   gp_Pnt aV0 = theRefPoint;
4971   gp_XYZ aGC;
4972   if ( !theHasRefPoint ) {
4973     aNb = 0;
4974     aGC.SetCoord( 0.,0.,0. );
4975
4976     itElem = theElements.begin();
4977     for ( ; itElem != theElements.end(); itElem++ ) {
4978       const SMDS_MeshElement* elem = *itElem;
4979
4980       SMDS_ElemIteratorPtr itN = elem->nodesIterator();
4981       while ( itN->more() ) {
4982         const SMDS_MeshNode* node = static_cast<const SMDS_MeshNode*>( itN->next() );
4983         aX = node->X();
4984         aY = node->Y();
4985         aZ = node->Z();
4986
4987         if ( mapNewNodes.find( node ) == mapNewNodes.end() ) {
4988           list<const SMDS_MeshNode*> aLNx;
4989           mapNewNodes[node] = aLNx;
4990           //
4991           gp_XYZ aXYZ( aX, aY, aZ );
4992           aGC += aXYZ;
4993           ++aNb;
4994         }
4995       }
4996     }
4997     aGC /= aNb;
4998     aV0.SetXYZ( aGC );
4999   } // if (!theHasRefPoint) {
5000   mapNewNodes.clear();
5001
5002   // 4. Processing the elements
5003   SMESHDS_Mesh* aMesh = GetMeshDS();
5004
5005   for ( itElem = theElements.begin(); itElem != theElements.end(); itElem++ ) {
5006     // check element type
5007     const SMDS_MeshElement* elem = *itElem;
5008     aTypeE = elem->GetType();
5009     if ( !elem || ( aTypeE != SMDSAbs_Face && aTypeE != SMDSAbs_Edge ) )
5010       continue;
5011
5012     vector<TNodeOfNodeListMapItr> & newNodesItVec = mapElemNewNodes[ elem ];
5013     newNodesItVec.reserve( elem->NbNodes() );
5014
5015     // loop on elem nodes
5016     int nodeIndex = -1;
5017     SMDS_ElemIteratorPtr itN = elem->nodesIterator();
5018     while ( itN->more() )
5019     {
5020       ++nodeIndex;
5021       // check if a node has been already processed
5022       const SMDS_MeshNode* node =
5023         static_cast<const SMDS_MeshNode*>( itN->next() );
5024       TNodeOfNodeListMap::iterator nIt = mapNewNodes.find( node );
5025       if ( nIt == mapNewNodes.end() ) {
5026         nIt = mapNewNodes.insert( make_pair( node, list<const SMDS_MeshNode*>() )).first;
5027         list<const SMDS_MeshNode*>& listNewNodes = nIt->second;
5028
5029         // make new nodes
5030         aX = node->X();  aY = node->Y(); aZ = node->Z();
5031
5032         Standard_Real aAngle1x, aAngleT1T0, aTolAng;
5033         gp_Pnt aP0x, aP1x, aPN0, aPN1, aV0x, aV1x;
5034         gp_Ax1 anAx1, anAxT1T0;
5035         gp_Dir aDT1x, aDT0x, aDT1T0;
5036
5037         aTolAng=1.e-4;
5038
5039         aV0x = aV0;
5040         aPN0.SetCoord(aX, aY, aZ);
5041
5042         const SMESH_MeshEditor_PathPoint& aPP0 = aPPs[0];
5043         aP0x = aPP0.Pnt();
5044         aDT0x= aPP0.Tangent();
5045         //cout<<"j = 0   PP: Pnt("<<aP0x.X()<<","<<aP0x.Y()<<","<<aP0x.Z()<<")"<<endl;
5046
5047         for ( j = 1; j < aNbTP; ++j ) {
5048           const SMESH_MeshEditor_PathPoint& aPP1 = aPPs[j];
5049           aP1x = aPP1.Pnt();
5050           aDT1x = aPP1.Tangent();
5051           aAngle1x = aPP1.Angle();
5052
5053           gp_Trsf aTrsf, aTrsfRot, aTrsfRotT1T0;
5054           // Translation
5055           gp_Vec aV01x( aP0x, aP1x );
5056           aTrsf.SetTranslation( aV01x );
5057
5058           // traslated point
5059           aV1x = aV0x.Transformed( aTrsf );
5060           aPN1 = aPN0.Transformed( aTrsf );
5061
5062           // rotation 1 [ T1,T0 ]
5063           aAngleT1T0=-aDT1x.Angle( aDT0x );
5064           if (fabs(aAngleT1T0) > aTolAng) {
5065             aDT1T0=aDT1x^aDT0x;
5066             anAxT1T0.SetLocation( aV1x );
5067             anAxT1T0.SetDirection( aDT1T0 );
5068             aTrsfRotT1T0.SetRotation( anAxT1T0, aAngleT1T0 );
5069
5070             aPN1 = aPN1.Transformed( aTrsfRotT1T0 );
5071           }
5072
5073           // rotation 2
5074           if ( theHasAngles ) {
5075             anAx1.SetLocation( aV1x );
5076             anAx1.SetDirection( aDT1x );
5077             aTrsfRot.SetRotation( anAx1, aAngle1x );
5078
5079             aPN1 = aPN1.Transformed( aTrsfRot );
5080           }
5081
5082           // make new node
5083           if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
5084             // create additional node
5085             double x = ( aPN1.X() + aPN0.X() )/2.;
5086             double y = ( aPN1.Y() + aPN0.Y() )/2.;
5087             double z = ( aPN1.Z() + aPN0.Z() )/2.;
5088             const SMDS_MeshNode* newNode = aMesh->AddNode(x,y,z);
5089             myLastCreatedNodes.Append(newNode);
5090             srcNodes.Append( node );
5091             listNewNodes.push_back( newNode );
5092           }
5093           aX = aPN1.X();
5094           aY = aPN1.Y();
5095           aZ = aPN1.Z();
5096           const SMDS_MeshNode* newNode = aMesh->AddNode( aX, aY, aZ );
5097           myLastCreatedNodes.Append(newNode);
5098           srcNodes.Append( node );
5099           listNewNodes.push_back( newNode );
5100
5101           aPN0 = aPN1;
5102           aP0x = aP1x;
5103           aV0x = aV1x;
5104           aDT0x = aDT1x;
5105         }
5106       }
5107
5108       else {
5109         // if current elem is quadratic and current node is not medium
5110         // we have to check - may be it is needed to insert additional nodes
5111         if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
5112           list< const SMDS_MeshNode* > & listNewNodes = nIt->second;
5113           if(listNewNodes.size()==aNbTP-1) {
5114             vector<const SMDS_MeshNode*> aNodes(2*(aNbTP-1));
5115             gp_XYZ P(node->X(), node->Y(), node->Z());
5116             list< const SMDS_MeshNode* >::iterator it = listNewNodes.begin();
5117             int i;
5118             for(i=0; i<aNbTP-1; i++) {
5119               const SMDS_MeshNode* N = *it;
5120               double x = ( N->X() + P.X() )/2.;
5121               double y = ( N->Y() + P.Y() )/2.;
5122               double z = ( N->Z() + P.Z() )/2.;
5123               const SMDS_MeshNode* newN = aMesh->AddNode(x,y,z);
5124               srcNodes.Append( node );
5125               myLastCreatedNodes.Append(newN);
5126               aNodes[2*i] = newN;
5127               aNodes[2*i+1] = N;
5128               P = gp_XYZ(N->X(),N->Y(),N->Z());
5129             }
5130             listNewNodes.clear();
5131             for(i=0; i<2*(aNbTP-1); i++) {
5132               listNewNodes.push_back(aNodes[i]);
5133             }
5134           }
5135         }
5136       }
5137
5138       newNodesItVec.push_back( nIt );
5139     }
5140     // make new elements
5141     //sweepElement( aMesh, elem, newNodesItVec, newElemsMap[elem],
5142     //              newNodesItVec[0]->second.size(), myLastCreatedElems );
5143     sweepElement( elem, newNodesItVec, newElemsMap[elem], aNbTP-1, srcElems );
5144   }
5145
5146   makeWalls( mapNewNodes, newElemsMap, mapElemNewNodes, theElements, aNbTP-1, srcElems );
5147
5148   if ( theMakeGroups )
5149     generateGroups( srcNodes, srcElems, "extruded");
5150
5151   return EXTR_OK;
5152 }
5153
5154
5155 //=======================================================================
5156 //function : LinearAngleVariation
5157 //purpose  : auxilary for ExtrusionAlongTrack
5158 //=======================================================================
5159 void SMESH_MeshEditor::LinearAngleVariation(const int nbSteps,
5160                                             list<double>& Angles)
5161 {
5162   int nbAngles = Angles.size();
5163   if( nbSteps > nbAngles ) {
5164     vector<double> theAngles(nbAngles);
5165     list<double>::iterator it = Angles.begin();
5166     int i = -1;
5167     for(; it!=Angles.end(); it++) {
5168       i++;
5169       theAngles[i] = (*it);
5170     }
5171     list<double> res;
5172     double rAn2St = double( nbAngles ) / double( nbSteps );
5173     double angPrev = 0, angle;
5174     for ( int iSt = 0; iSt < nbSteps; ++iSt ) {
5175       double angCur = rAn2St * ( iSt+1 );
5176       double angCurFloor  = floor( angCur );
5177       double angPrevFloor = floor( angPrev );
5178       if ( angPrevFloor == angCurFloor )
5179         angle = rAn2St * theAngles[ int( angCurFloor ) ];
5180       else {
5181         int iP = int( angPrevFloor );
5182         double angPrevCeil = ceil(angPrev);
5183         angle = ( angPrevCeil - angPrev ) * theAngles[ iP ];
5184
5185         int iC = int( angCurFloor );
5186         if ( iC < nbAngles )
5187           angle += ( angCur - angCurFloor ) * theAngles[ iC ];
5188
5189         iP = int( angPrevCeil );
5190         while ( iC-- > iP )
5191           angle += theAngles[ iC ];
5192       }
5193       res.push_back(angle);
5194       angPrev = angCur;
5195     }
5196     Angles.clear();
5197     it = res.begin();
5198     for(; it!=res.end(); it++)
5199       Angles.push_back( *it );
5200   }
5201 }
5202
5203
5204 //================================================================================
5205 /*!
5206  * \brief Move or copy theElements applying theTrsf to their nodes
5207  *  \param theElems - elements to transform, if theElems is empty then apply to all mesh nodes
5208  *  \param theTrsf - transformation to apply
5209  *  \param theCopy - if true, create translated copies of theElems
5210  *  \param theMakeGroups - if true and theCopy, create translated groups
5211  *  \param theTargetMesh - mesh to copy translated elements into
5212  *  \retval SMESH_MeshEditor::PGroupIDs - list of ids of created groups
5213  */
5214 //================================================================================
5215
5216 SMESH_MeshEditor::PGroupIDs
5217 SMESH_MeshEditor::Transform (TIDSortedElemSet & theElems,
5218                              const gp_Trsf&     theTrsf,
5219                              const bool         theCopy,
5220                              const bool         theMakeGroups,
5221                              SMESH_Mesh*        theTargetMesh)
5222 {
5223   myLastCreatedElems.Clear();
5224   myLastCreatedNodes.Clear();
5225
5226   bool needReverse = false;
5227   string groupPostfix;
5228   switch ( theTrsf.Form() ) {
5229   case gp_PntMirror:
5230   case gp_Ax1Mirror:
5231   case gp_Ax2Mirror:
5232     needReverse = true;
5233     groupPostfix = "mirrored";
5234     break;
5235   case gp_Rotation:
5236     groupPostfix = "rotated";
5237     break;
5238   case gp_Translation:
5239     groupPostfix = "translated";
5240     break;
5241   case gp_Scale:
5242   case gp_CompoundTrsf: // different scale by axis
5243     groupPostfix = "scaled";
5244     break;
5245   default:
5246     needReverse = false;
5247     groupPostfix = "transformed";
5248   }
5249
5250   SMESH_MeshEditor targetMeshEditor( theTargetMesh );
5251   SMESHDS_Mesh* aTgtMesh = theTargetMesh ? theTargetMesh->GetMeshDS() : 0;
5252   SMESHDS_Mesh* aMesh    = GetMeshDS();
5253
5254
5255   // map old node to new one
5256   TNodeNodeMap nodeMap;
5257
5258   // elements sharing moved nodes; those of them which have all
5259   // nodes mirrored but are not in theElems are to be reversed
5260   TIDSortedElemSet inverseElemSet;
5261
5262   // source elements for each generated one
5263   SMESH_SequenceOfElemPtr srcElems, srcNodes;
5264
5265   // issue 021015: EDF 1578 SMESH: Free nodes are removed when translating a mesh
5266   list<SMDS_MeshNode>          orphanCopy; // copies of orphan nodes
5267   vector<const SMDS_MeshNode*> orphanNode; // original orphan nodes
5268
5269   if ( theElems.empty() ) // transform the whole mesh
5270   {
5271     // add all elements
5272     SMDS_ElemIteratorPtr eIt = aMesh->elementsIterator();
5273     while ( eIt->more() ) theElems.insert( eIt->next() );
5274     // add orphan nodes
5275     SMDS_MeshElementIDFactory idFactory;
5276     SMDS_NodeIteratorPtr nIt = aMesh->nodesIterator();
5277     while ( nIt->more() )
5278     {
5279       const SMDS_MeshNode* node = nIt->next();
5280       if ( node->NbInverseElements() == 0 && !theElems.insert( node ).second )
5281       {
5282         // node was not inserted into theElems because an element with the same ID
5283         // is already there. As a work around we insert a copy of node with
5284         // an ID = -<index in orphanNode>
5285         orphanCopy.push_back( *node ); // copy node
5286         SMDS_MeshNode* nodeCopy = &orphanCopy.back();
5287         int uniqueID = -orphanNode.size();
5288         orphanNode.push_back( node );
5289         idFactory.BindID( uniqueID, nodeCopy );
5290         theElems.insert( nodeCopy );
5291       }
5292     }
5293   }
5294   // loop on theElems to transorm nodes
5295   TIDSortedElemSet::iterator itElem;
5296   for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
5297     const SMDS_MeshElement* elem = *itElem;
5298     if ( !elem )
5299       continue;
5300
5301     // loop on elem nodes
5302     SMDS_ElemIteratorPtr itN = elem->nodesIterator();
5303     while ( itN->more() ) {
5304
5305       const SMDS_MeshNode* node = cast2Node( itN->next() );
5306       if ( node->GetID() < 0 )
5307         node = orphanNode[ -node->GetID() ];
5308       // check if a node has been already transformed
5309       pair<TNodeNodeMap::iterator,bool> n2n_isnew =
5310         nodeMap.insert( make_pair ( node, node ));
5311       if ( !n2n_isnew.second )
5312         continue;
5313
5314       double coord[3];
5315       coord[0] = node->X();
5316       coord[1] = node->Y();
5317       coord[2] = node->Z();
5318       theTrsf.Transforms( coord[0], coord[1], coord[2] );
5319       if ( theTargetMesh ) {
5320         const SMDS_MeshNode * newNode = aTgtMesh->AddNode( coord[0], coord[1], coord[2] );
5321         n2n_isnew.first->second = newNode;
5322         myLastCreatedNodes.Append(newNode);
5323         srcNodes.Append( node );
5324       }
5325       else if ( theCopy ) {
5326         const SMDS_MeshNode * newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
5327         n2n_isnew.first->second = newNode;
5328         myLastCreatedNodes.Append(newNode);
5329         srcNodes.Append( node );
5330       }
5331       else {
5332         aMesh->MoveNode( node, coord[0], coord[1], coord[2] );
5333         // node position on shape becomes invalid
5334         const_cast< SMDS_MeshNode* > ( node )->SetPosition
5335           ( SMDS_SpacePosition::originSpacePosition() );
5336       }
5337
5338       // keep inverse elements
5339       if ( !theCopy && !theTargetMesh && needReverse ) {
5340         SMDS_ElemIteratorPtr invElemIt = node->GetInverseElementIterator();
5341         while ( invElemIt->more() ) {
5342           const SMDS_MeshElement* iel = invElemIt->next();
5343           inverseElemSet.insert( iel );
5344         }
5345       }
5346     }
5347   }
5348
5349   // either create new elements or reverse mirrored ones
5350   if ( !theCopy && !needReverse && !theTargetMesh )
5351     return PGroupIDs();
5352
5353   TIDSortedElemSet::iterator invElemIt = inverseElemSet.begin();
5354   for ( ; invElemIt != inverseElemSet.end(); invElemIt++ )
5355     theElems.insert( *invElemIt );
5356
5357   // replicate or reverse elements
5358
5359   enum {
5360     REV_TETRA   = 0,  //  = nbNodes - 4
5361     REV_PYRAMID = 1,  //  = nbNodes - 4
5362     REV_PENTA   = 2,  //  = nbNodes - 4
5363     REV_FACE    = 3,
5364     REV_HEXA    = 4,  //  = nbNodes - 4
5365     FORWARD     = 5
5366   };
5367   int index[][8] = {
5368     { 2, 1, 0, 3, 4, 0, 0, 0 },  // REV_TETRA
5369     { 2, 1, 0, 3, 4, 0, 0, 0 },  // REV_PYRAMID
5370     { 2, 1, 0, 5, 4, 3, 0, 0 },  // REV_PENTA
5371     { 2, 1, 0, 3, 0, 0, 0, 0 },  // REV_FACE
5372     { 2, 1, 0, 3, 6, 5, 4, 7 },  // REV_HEXA
5373     { 0, 1, 2, 3, 4, 5, 6, 7 }   // FORWARD
5374   };
5375
5376   for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ )
5377   {
5378     const SMDS_MeshElement* elem = *itElem;
5379     if ( !elem || elem->GetType() == SMDSAbs_Node )
5380       continue;
5381
5382     int nbNodes = elem->NbNodes();
5383     int elemType = elem->GetType();
5384
5385     if (elem->IsPoly()) {
5386       // Polygon or Polyhedral Volume
5387       switch ( elemType ) {
5388       case SMDSAbs_Face:
5389         {
5390           vector<const SMDS_MeshNode*> poly_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             if (needReverse) {
5400               // reverse mirrored faces and volumes
5401               poly_nodes[nbNodes - iNode - 1] = (*nodeMapIt).second;
5402             } else {
5403               poly_nodes[iNode] = (*nodeMapIt).second;
5404             }
5405             iNode++;
5406           }
5407           if ( iNode != nbNodes )
5408             continue; // not all nodes transformed
5409
5410           if ( theTargetMesh ) {
5411             myLastCreatedElems.Append(aTgtMesh->AddPolygonalFace(poly_nodes));
5412             srcElems.Append( elem );
5413           }
5414           else if ( theCopy ) {
5415             myLastCreatedElems.Append(aMesh->AddPolygonalFace(poly_nodes));
5416             srcElems.Append( elem );
5417           }
5418           else {
5419             aMesh->ChangePolygonNodes(elem, poly_nodes);
5420           }
5421         }
5422         break;
5423       case SMDSAbs_Volume:
5424         {
5425           // ATTENTION: Reversing is not yet done!!!
5426           const SMDS_PolyhedralVolumeOfNodes* aPolyedre =
5427             dynamic_cast<const SMDS_PolyhedralVolumeOfNodes*>( elem );
5428           if (!aPolyedre) {
5429             MESSAGE("Warning: bad volumic element");
5430             continue;
5431           }
5432
5433           vector<const SMDS_MeshNode*> poly_nodes;
5434           vector<int> quantities;
5435
5436           bool allTransformed = true;
5437           int nbFaces = aPolyedre->NbFaces();
5438           for (int iface = 1; iface <= nbFaces && allTransformed; iface++) {
5439             int nbFaceNodes = aPolyedre->NbFaceNodes(iface);
5440             for (int inode = 1; inode <= nbFaceNodes && allTransformed; inode++) {
5441               const SMDS_MeshNode* node = aPolyedre->GetFaceNode(iface, inode);
5442               TNodeNodeMap::iterator nodeMapIt = nodeMap.find(node);
5443               if (nodeMapIt == nodeMap.end()) {
5444                 allTransformed = false; // not all nodes transformed
5445               } else {
5446                 poly_nodes.push_back((*nodeMapIt).second);
5447               }
5448             }
5449             quantities.push_back(nbFaceNodes);
5450           }
5451           if ( !allTransformed )
5452             continue; // not all nodes transformed
5453
5454           if ( theTargetMesh ) {
5455             myLastCreatedElems.Append(aTgtMesh->AddPolyhedralVolume(poly_nodes, quantities));
5456             srcElems.Append( elem );
5457           }
5458           else if ( theCopy ) {
5459             myLastCreatedElems.Append(aMesh->AddPolyhedralVolume(poly_nodes, quantities));
5460             srcElems.Append( elem );
5461           }
5462           else {
5463             aMesh->ChangePolyhedronNodes(elem, poly_nodes, quantities);
5464           }
5465         }
5466         break;
5467       default:;
5468       }
5469       continue;
5470     }
5471
5472     // Regular elements
5473     int* i = index[ FORWARD ];
5474     if ( needReverse && nbNodes > 2) // reverse mirrored faces and volumes
5475       if ( elemType == SMDSAbs_Face )
5476         i = index[ REV_FACE ];
5477       else
5478         i = index[ nbNodes - 4 ];
5479
5480     if(elem->IsQuadratic()) {
5481       static int anIds[] = {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19};
5482       i = anIds;
5483       if(needReverse) {
5484         if(nbNodes==3) { // quadratic edge
5485           static int anIds[] = {1,0,2};
5486           i = anIds;
5487         }
5488         else if(nbNodes==6) { // quadratic triangle
5489           static int anIds[] = {0,2,1,5,4,3};
5490           i = anIds;
5491         }
5492         else if(nbNodes==8) { // quadratic quadrangle
5493           static int anIds[] = {0,3,2,1,7,6,5,4};
5494           i = anIds;
5495         }
5496         else if(nbNodes==10) { // quadratic tetrahedron of 10 nodes
5497           static int anIds[] = {0,2,1,3,6,5,4,7,9,8};
5498           i = anIds;
5499         }
5500         else if(nbNodes==13) { // quadratic pyramid of 13 nodes
5501           static int anIds[] = {0,3,2,1,4,8,7,6,5,9,12,11,10};
5502           i = anIds;
5503         }
5504         else if(nbNodes==15) { // quadratic pentahedron with 15 nodes
5505           static int anIds[] = {0,2,1,3,5,4,8,7,6,11,10,9,12,14,13};
5506           i = anIds;
5507         }
5508         else { // nbNodes==20 - quadratic hexahedron with 20 nodes
5509           static int anIds[] = {0,3,2,1,4,7,6,5,11,10,9,8,15,14,13,12,16,19,18,17};
5510           i = anIds;
5511         }
5512       }
5513     }
5514
5515     // find transformed nodes
5516     vector<const SMDS_MeshNode*> nodes(nbNodes);
5517     int iNode = 0;
5518     SMDS_ElemIteratorPtr itN = elem->nodesIterator();
5519     while ( itN->more() ) {
5520       const SMDS_MeshNode* node =
5521         static_cast<const SMDS_MeshNode*>( itN->next() );
5522       TNodeNodeMap::iterator nodeMapIt = nodeMap.find( node );
5523       if ( nodeMapIt == nodeMap.end() )
5524         break; // not all nodes transformed
5525       nodes[ i [ iNode++ ]] = (*nodeMapIt).second;
5526     }
5527     if ( iNode != nbNodes )
5528       continue; // not all nodes transformed
5529
5530     if ( theTargetMesh ) {
5531       if ( SMDS_MeshElement* copy =
5532            targetMeshEditor.AddElement( nodes, elem->GetType(), elem->IsPoly() )) {
5533         myLastCreatedElems.Append( copy );
5534         srcElems.Append( elem );
5535       }
5536     }
5537     else if ( theCopy ) {
5538       if ( AddElement( nodes, elem->GetType(), elem->IsPoly() ))
5539         srcElems.Append( elem );
5540     }
5541     else {
5542       // reverse element as it was reversed by transformation
5543       if ( nbNodes > 2 )
5544         aMesh->ChangeElementNodes( elem, &nodes[0], nbNodes );
5545     }
5546   }
5547
5548   PGroupIDs newGroupIDs;
5549
5550   if ( theMakeGroups && theCopy ||
5551        theMakeGroups && theTargetMesh )
5552     newGroupIDs = generateGroups( srcNodes, srcElems, groupPostfix, theTargetMesh );
5553
5554   return newGroupIDs;
5555 }
5556
5557 //=======================================================================
5558 /*!
5559  * \brief Create groups of elements made during transformation
5560  * \param nodeGens - nodes making corresponding myLastCreatedNodes
5561  * \param elemGens - elements making corresponding myLastCreatedElems
5562  * \param postfix - to append to names of new groups
5563  */
5564 //=======================================================================
5565
5566 SMESH_MeshEditor::PGroupIDs
5567 SMESH_MeshEditor::generateGroups(const SMESH_SequenceOfElemPtr& nodeGens,
5568                                  const SMESH_SequenceOfElemPtr& elemGens,
5569                                  const std::string&             postfix,
5570                                  SMESH_Mesh*                    targetMesh)
5571 {
5572   PGroupIDs newGroupIDs( new list<int> );
5573   SMESH_Mesh* mesh = targetMesh ? targetMesh : GetMesh();
5574
5575   // Sort existing groups by types and collect their names
5576
5577   // to store an old group and a generated new one
5578   typedef pair< SMESHDS_GroupBase*, SMDS_MeshGroup* > TOldNewGroup;
5579   vector< list< TOldNewGroup > > groupsByType( SMDSAbs_NbElementTypes );
5580   // group names
5581   set< string > groupNames;
5582   //
5583   SMDS_MeshGroup* nullNewGroup = (SMDS_MeshGroup*) 0;
5584   SMESH_Mesh::GroupIteratorPtr groupIt = GetMesh()->GetGroups();
5585   while ( groupIt->more() ) {
5586     SMESH_Group * group = groupIt->next();
5587     if ( !group ) continue;
5588     SMESHDS_GroupBase* groupDS = group->GetGroupDS();
5589     if ( !groupDS || groupDS->IsEmpty() ) continue;
5590     groupNames.insert( group->GetName() );
5591     groupDS->SetStoreName( group->GetName() );
5592     groupsByType[ groupDS->GetType() ].push_back( make_pair( groupDS, nullNewGroup ));
5593   }
5594
5595   // Groups creation
5596
5597   // loop on nodes and elements
5598   for ( int isNodes = 0; isNodes < 2; ++isNodes )
5599   {
5600     const SMESH_SequenceOfElemPtr& gens  = isNodes ? nodeGens : elemGens;
5601     const SMESH_SequenceOfElemPtr& elems = isNodes ? myLastCreatedNodes : myLastCreatedElems;
5602     if ( gens.Length() != elems.Length() )
5603       throw SALOME_Exception(LOCALIZED("invalid args"));
5604
5605     // loop on created elements
5606     for (int iElem = 1; iElem <= elems.Length(); ++iElem )
5607     {
5608       const SMDS_MeshElement* sourceElem = gens( iElem );
5609       if ( !sourceElem ) {
5610         MESSAGE("generateGroups(): NULL source element");
5611         continue;
5612       }
5613       list< TOldNewGroup > & groupsOldNew = groupsByType[ sourceElem->GetType() ];
5614       if ( groupsOldNew.empty() ) {
5615         while ( iElem < gens.Length() && gens( iElem+1 ) == sourceElem )
5616           ++iElem; // skip all elements made by sourceElem
5617         continue;
5618       }
5619       // collect all elements made by sourceElem
5620       list< const SMDS_MeshElement* > resultElems;
5621       if ( const SMDS_MeshElement* resElem = elems( iElem ))
5622         if ( resElem != sourceElem )
5623           resultElems.push_back( resElem );
5624       while ( iElem < gens.Length() && gens( iElem+1 ) == sourceElem )
5625         if ( const SMDS_MeshElement* resElem = elems( ++iElem ))
5626           if ( resElem != sourceElem )
5627             resultElems.push_back( resElem );
5628       // do not generate element groups from node ones
5629       if ( sourceElem->GetType() == SMDSAbs_Node &&
5630            elems( iElem )->GetType() != SMDSAbs_Node )
5631         continue;
5632
5633       // add resultElems to groups made by ones the sourceElem belongs to
5634       list< TOldNewGroup >::iterator gOldNew, gLast = groupsOldNew.end();
5635       for ( gOldNew = groupsOldNew.begin(); gOldNew != gLast; ++gOldNew )
5636       {
5637         SMESHDS_GroupBase* oldGroup = gOldNew->first;
5638         if ( oldGroup->Contains( sourceElem )) // sourceElem in oldGroup
5639         {
5640           SMDS_MeshGroup* & newGroup = gOldNew->second;
5641           if ( !newGroup )// create a new group
5642           {
5643             // make a name
5644             string name = oldGroup->GetStoreName();
5645             if ( !targetMesh ) {
5646               name += "_";
5647               name += postfix;
5648               int nb = 0;
5649               while ( !groupNames.insert( name ).second ) // name exists
5650               {
5651                 if ( nb == 0 ) {
5652                   name += "_1";
5653                 }
5654                 else {
5655                   TCollection_AsciiString nbStr(nb+1);
5656                   name.resize( name.rfind('_')+1 );
5657                   name += nbStr.ToCString();
5658                 }
5659                 ++nb;
5660               }
5661             }
5662             // make a group
5663             int id;
5664             SMESH_Group* group = mesh->AddGroup( resultElems.back()->GetType(),
5665                                                  name.c_str(), id );
5666             SMESHDS_Group* groupDS = static_cast<SMESHDS_Group*>(group->GetGroupDS());
5667             newGroup = & groupDS->SMDSGroup();
5668             newGroupIDs->push_back( id );
5669           }
5670
5671           // fill in a new group
5672           list< const SMDS_MeshElement* >::iterator resLast = resultElems.end(), resElemIt;
5673           for ( resElemIt = resultElems.begin(); resElemIt != resLast; ++resElemIt )
5674             newGroup->Add( *resElemIt );
5675         }
5676       }
5677     } // loop on created elements
5678   }// loop on nodes and elements
5679
5680   return newGroupIDs;
5681 }
5682
5683 //================================================================================
5684 /*!
5685  * \brief Return list of group of nodes close to each other within theTolerance
5686  *        Search among theNodes or in the whole mesh if theNodes is empty using
5687  *        an Octree algorithm
5688  */
5689 //================================================================================
5690
5691 void SMESH_MeshEditor::FindCoincidentNodes (TIDSortedNodeSet &   theNodes,
5692                                             const double         theTolerance,
5693                                             TListOfListOfNodes & theGroupsOfNodes)
5694 {
5695   myLastCreatedElems.Clear();
5696   myLastCreatedNodes.Clear();
5697
5698   if ( theNodes.empty() )
5699   { // get all nodes in the mesh
5700     SMDS_NodeIteratorPtr nIt = GetMeshDS()->nodesIterator(/*idInceasingOrder=*/true);
5701     while ( nIt->more() )
5702       theNodes.insert( theNodes.end(),nIt->next());
5703   }
5704
5705   SMESH_OctreeNode::FindCoincidentNodes ( theNodes, &theGroupsOfNodes, theTolerance);
5706 }
5707
5708
5709 //=======================================================================
5710 /*!
5711  * \brief Implementation of search for the node closest to point
5712  */
5713 //=======================================================================
5714
5715 struct SMESH_NodeSearcherImpl: public SMESH_NodeSearcher
5716 {
5717   //---------------------------------------------------------------------
5718   /*!
5719    * \brief Constructor
5720    */
5721   SMESH_NodeSearcherImpl( const SMESHDS_Mesh* theMesh )
5722   {
5723     myMesh = ( SMESHDS_Mesh* ) theMesh;
5724
5725     TIDSortedNodeSet nodes;
5726     if ( theMesh ) {
5727       SMDS_NodeIteratorPtr nIt = theMesh->nodesIterator(/*idInceasingOrder=*/true);
5728       while ( nIt->more() )
5729         nodes.insert( nodes.end(), nIt->next() );
5730     }
5731     myOctreeNode = new SMESH_OctreeNode(nodes) ;
5732
5733     // get max size of a leaf box
5734     SMESH_OctreeNode* tree = myOctreeNode;
5735     while ( !tree->isLeaf() )
5736     {
5737       SMESH_OctreeNodeIteratorPtr cIt = tree->GetChildrenIterator();
5738       if ( cIt->more() )
5739         tree = cIt->next();
5740     }
5741     myHalfLeafSize = tree->maxSize() / 2.;
5742   }
5743
5744   //---------------------------------------------------------------------
5745   /*!
5746    * \brief Move node and update myOctreeNode accordingly
5747    */
5748   void MoveNode( const SMDS_MeshNode* node, const gp_Pnt& toPnt )
5749   {
5750     myOctreeNode->UpdateByMoveNode( node, toPnt );
5751     myMesh->MoveNode( node, toPnt.X(), toPnt.Y(), toPnt.Z() );
5752   }
5753
5754   //---------------------------------------------------------------------
5755   /*!
5756    * \brief Do it's job
5757    */
5758   const SMDS_MeshNode* FindClosestTo( const gp_Pnt& thePnt )
5759   {
5760     SMDS_MeshNode tgtNode( thePnt.X(), thePnt.Y(), thePnt.Z() );
5761     map<double, const SMDS_MeshNode*> dist2Nodes;
5762     myOctreeNode->NodesAround( &tgtNode, dist2Nodes, myHalfLeafSize );
5763     if ( !dist2Nodes.empty() )
5764       return dist2Nodes.begin()->second;
5765     list<const SMDS_MeshNode*> nodes;
5766     //myOctreeNode->NodesAround( &tgtNode, &nodes, myHalfLeafSize );
5767
5768     double minSqDist = DBL_MAX;
5769     if ( nodes.empty() )  // get all nodes of OctreeNode's closest to thePnt
5770     {
5771       // sort leafs by their distance from thePnt
5772       typedef map< double, SMESH_OctreeNode* > TDistTreeMap;
5773       TDistTreeMap treeMap;
5774       list< SMESH_OctreeNode* > treeList;
5775       list< SMESH_OctreeNode* >::iterator trIt;
5776       treeList.push_back( myOctreeNode );
5777
5778       SMDS_MeshNode pointNode( thePnt.X(), thePnt.Y(), thePnt.Z() );
5779       bool pointInside = myOctreeNode->isInside( &pointNode, myHalfLeafSize );
5780       for ( trIt = treeList.begin(); trIt != treeList.end(); ++trIt)
5781       {
5782         SMESH_OctreeNode* tree = *trIt;
5783         if ( !tree->isLeaf() ) // put children to the queue
5784         {
5785           if ( pointInside && !tree->isInside( &pointNode, myHalfLeafSize )) continue;
5786           SMESH_OctreeNodeIteratorPtr cIt = tree->GetChildrenIterator();
5787           while ( cIt->more() )
5788             treeList.push_back( cIt->next() );
5789         }
5790         else if ( tree->NbNodes() ) // put a tree to the treeMap
5791         {
5792           const Bnd_B3d& box = tree->getBox();
5793           double sqDist = thePnt.SquareDistance( 0.5 * ( box.CornerMin() + box.CornerMax() ));
5794           pair<TDistTreeMap::iterator,bool> it_in = treeMap.insert( make_pair( sqDist, tree ));
5795           if ( !it_in.second ) // not unique distance to box center
5796             treeMap.insert( it_in.first, make_pair( sqDist + 1e-13*treeMap.size(), tree ));
5797         }
5798       }
5799       // find distance after which there is no sense to check tree's
5800       double sqLimit = DBL_MAX;
5801       TDistTreeMap::iterator sqDist_tree = treeMap.begin();
5802       if ( treeMap.size() > 5 ) {
5803         SMESH_OctreeNode* closestTree = sqDist_tree->second;
5804         const Bnd_B3d& box = closestTree->getBox();
5805         double limit = sqrt( sqDist_tree->first ) + sqrt ( box.SquareExtent() );
5806         sqLimit = limit * limit;
5807       }
5808       // get all nodes from trees
5809       for ( ; sqDist_tree != treeMap.end(); ++sqDist_tree) {
5810         if ( sqDist_tree->first > sqLimit )
5811           break;
5812         SMESH_OctreeNode* tree = sqDist_tree->second;
5813         tree->NodesAround( tree->GetNodeIterator()->next(), &nodes );
5814       }
5815     }
5816     // find closest among nodes
5817     minSqDist = DBL_MAX;
5818     const SMDS_MeshNode* closestNode = 0;
5819     list<const SMDS_MeshNode*>::iterator nIt = nodes.begin();
5820     for ( ; nIt != nodes.end(); ++nIt ) {
5821       double sqDist = thePnt.SquareDistance( SMESH_MeshEditor::TNodeXYZ( *nIt ) );
5822       if ( minSqDist > sqDist ) {
5823         closestNode = *nIt;
5824         minSqDist = sqDist;
5825       }
5826     }
5827     return closestNode;
5828   }
5829
5830   //---------------------------------------------------------------------
5831   /*!
5832    * \brief Destructor
5833    */
5834   ~SMESH_NodeSearcherImpl() { delete myOctreeNode; }
5835
5836   //---------------------------------------------------------------------
5837   /*!
5838    * \brief Return the node tree
5839    */
5840   const SMESH_OctreeNode* getTree() const { return myOctreeNode; }
5841
5842 private:
5843   SMESH_OctreeNode* myOctreeNode;
5844   SMESHDS_Mesh*     myMesh;
5845   double            myHalfLeafSize; // max size of a leaf box
5846 };
5847
5848 //=======================================================================
5849 /*!
5850  * \brief Return SMESH_NodeSearcher
5851  */
5852 //=======================================================================
5853
5854 SMESH_NodeSearcher* SMESH_MeshEditor::GetNodeSearcher() 
5855 {
5856   return new SMESH_NodeSearcherImpl( GetMeshDS() );
5857 }
5858
5859 // ========================================================================
5860 namespace // Utils used in SMESH_ElementSearcherImpl::FindElementsByPoint()
5861 {
5862   const int MaxNbElemsInLeaf = 10; // maximal number of elements in a leaf of tree
5863   const int MaxLevel         = 7;  // maximal tree height -> nb terminal boxes: 8^7 = 2097152
5864   const double NodeRadius = 1e-9;  // to enlarge bnd box of element
5865
5866   //=======================================================================
5867   /*!
5868    * \brief Octal tree of bounding boxes of elements
5869    */
5870   //=======================================================================
5871
5872   class ElementBndBoxTree : public SMESH_Octree
5873   {
5874   public:
5875
5876     ElementBndBoxTree(const SMDS_Mesh& mesh, SMDSAbs_ElementType elemType, double tolerance = NodeRadius );
5877     void getElementsNearPoint( const gp_Pnt& point, TIDSortedElemSet& foundElems);
5878     void getElementsNearLine ( const gp_Ax1& line, TIDSortedElemSet& foundElems);
5879     ~ElementBndBoxTree();
5880
5881   protected:
5882     ElementBndBoxTree() {}
5883     SMESH_Octree* allocateOctreeChild() const { return new ElementBndBoxTree; }
5884     void buildChildrenData();
5885     Bnd_B3d* buildRootBox();
5886   private:
5887     //!< Bounding box of element
5888     struct ElementBox : public Bnd_B3d
5889     {
5890       const SMDS_MeshElement* _element;
5891       int                     _refCount; // an ElementBox can be included in several tree branches
5892       ElementBox(const SMDS_MeshElement* elem, double tolerance);
5893     };
5894     vector< ElementBox* > _elements;
5895   };
5896
5897   //================================================================================
5898   /*!
5899    * \brief ElementBndBoxTree creation
5900    */
5901   //================================================================================
5902
5903   ElementBndBoxTree::ElementBndBoxTree(const SMDS_Mesh& mesh, SMDSAbs_ElementType elemType, double tolerance)
5904     :SMESH_Octree( new SMESH_Octree::Limit( MaxLevel, /*minSize=*/0. ))
5905   {
5906     int nbElems = mesh.GetMeshInfo().NbElements( elemType );
5907     _elements.reserve( nbElems );
5908
5909     SMDS_ElemIteratorPtr elemIt = mesh.elementsIterator( elemType );
5910     while ( elemIt->more() )
5911       _elements.push_back( new ElementBox( elemIt->next(),tolerance  ));
5912
5913     if ( _elements.size() > MaxNbElemsInLeaf )
5914       compute();
5915     else
5916       myIsLeaf = true;
5917   }
5918
5919   //================================================================================
5920   /*!
5921    * \brief Destructor
5922    */
5923   //================================================================================
5924
5925   ElementBndBoxTree::~ElementBndBoxTree()
5926   {
5927     for ( int i = 0; i < _elements.size(); ++i )
5928       if ( --_elements[i]->_refCount <= 0 )
5929         delete _elements[i];
5930   }
5931
5932   //================================================================================
5933   /*!
5934    * \brief Return the maximal box
5935    */
5936   //================================================================================
5937
5938   Bnd_B3d* ElementBndBoxTree::buildRootBox()
5939   {
5940     Bnd_B3d* box = new Bnd_B3d;
5941     for ( int i = 0; i < _elements.size(); ++i )
5942       box->Add( *_elements[i] );
5943     return box;
5944   }
5945
5946   //================================================================================
5947   /*!
5948    * \brief Redistrubute element boxes among children
5949    */
5950   //================================================================================
5951
5952   void ElementBndBoxTree::buildChildrenData()
5953   {
5954     for ( int i = 0; i < _elements.size(); ++i )
5955     {
5956       for (int j = 0; j < 8; j++)
5957       {
5958         if ( !_elements[i]->IsOut( myChildren[j]->getBox() ))
5959         {
5960           _elements[i]->_refCount++;
5961           ((ElementBndBoxTree*)myChildren[j])->_elements.push_back( _elements[i]);
5962         }
5963       }
5964       _elements[i]->_refCount--;
5965     }
5966     _elements.clear();
5967
5968     for (int j = 0; j < 8; j++)
5969     {
5970       ElementBndBoxTree* child = static_cast<ElementBndBoxTree*>( myChildren[j]);
5971       if ( child->_elements.size() <= MaxNbElemsInLeaf )
5972         child->myIsLeaf = true;
5973
5974       if ( child->_elements.capacity() - child->_elements.size() > 1000 )
5975         child->_elements.resize( child->_elements.size() ); // compact
5976     }
5977   }
5978
5979   //================================================================================
5980   /*!
5981    * \brief Return elements which can include the point
5982    */
5983   //================================================================================
5984
5985   void ElementBndBoxTree::getElementsNearPoint( const gp_Pnt&     point,
5986                                                 TIDSortedElemSet& foundElems)
5987   {
5988     if ( level() && getBox().IsOut( point.XYZ() ))
5989       return;
5990
5991     if ( isLeaf() )
5992     {
5993       for ( int i = 0; i < _elements.size(); ++i )
5994         if ( !_elements[i]->IsOut( point.XYZ() ))
5995           foundElems.insert( _elements[i]->_element );
5996     }
5997     else
5998     {
5999       for (int i = 0; i < 8; i++)
6000         ((ElementBndBoxTree*) myChildren[i])->getElementsNearPoint( point, foundElems );
6001     }
6002   }
6003
6004   //================================================================================
6005   /*!
6006    * \brief Return elements which can be intersected by the line
6007    */
6008   //================================================================================
6009
6010   void ElementBndBoxTree::getElementsNearLine( const gp_Ax1&     line,
6011                                                TIDSortedElemSet& foundElems)
6012   {
6013     if ( level() && getBox().IsOut( line ))
6014       return;
6015
6016     if ( isLeaf() )
6017     {
6018       for ( int i = 0; i < _elements.size(); ++i )
6019         if ( !_elements[i]->IsOut( line ))
6020           foundElems.insert( _elements[i]->_element );
6021     }
6022     else
6023     {
6024       for (int i = 0; i < 8; i++)
6025         ((ElementBndBoxTree*) myChildren[i])->getElementsNearLine( line, foundElems );
6026     }
6027   }
6028
6029   //================================================================================
6030   /*!
6031    * \brief Construct the element box
6032    */
6033   //================================================================================
6034
6035   ElementBndBoxTree::ElementBox::ElementBox(const SMDS_MeshElement* elem, double tolerance)
6036   {
6037     _element  = elem;
6038     _refCount = 1;
6039     SMDS_ElemIteratorPtr nIt = elem->nodesIterator();
6040     while ( nIt->more() )
6041       Add( SMESH_MeshEditor::TNodeXYZ( cast2Node( nIt->next() )));
6042     Enlarge( tolerance );
6043   }
6044
6045 } // namespace
6046
6047 //=======================================================================
6048 /*!
6049  * \brief Implementation of search for the elements by point and
6050  *        of classification of point in 2D mesh
6051  */
6052 //=======================================================================
6053
6054 struct SMESH_ElementSearcherImpl: public SMESH_ElementSearcher
6055 {
6056   SMESHDS_Mesh*                _mesh;
6057   ElementBndBoxTree*           _ebbTree;
6058   SMESH_NodeSearcherImpl*      _nodeSearcher;
6059   SMDSAbs_ElementType          _elementType;
6060   double                       _tolerance;
6061   bool                         _outerFacesFound;
6062   set<const SMDS_MeshElement*> _outerFaces; // empty means "no internal faces at all"
6063
6064   SMESH_ElementSearcherImpl( SMESHDS_Mesh& mesh )
6065     : _mesh(&mesh),_ebbTree(0),_nodeSearcher(0), _tolerance(-1), _outerFacesFound(false) {}
6066   ~SMESH_ElementSearcherImpl()
6067   {
6068     if ( _ebbTree )      delete _ebbTree;      _ebbTree      = 0;
6069     if ( _nodeSearcher ) delete _nodeSearcher; _nodeSearcher = 0;
6070   }
6071   virtual int FindElementsByPoint(const gp_Pnt&                      point,
6072                                   SMDSAbs_ElementType                type,
6073                                   vector< const SMDS_MeshElement* >& foundElements);
6074   virtual TopAbs_State GetPointState(const gp_Pnt& point);
6075
6076   void GetElementsNearLine( const gp_Ax1&                      line,
6077                             SMDSAbs_ElementType                type,
6078                             vector< const SMDS_MeshElement* >& foundElems);
6079   double getTolerance();
6080   bool getIntersParamOnLine(const gp_Lin& line, const SMDS_MeshElement* face,
6081                             const double tolerance, double & param);
6082   void findOuterBoundary(const SMDS_MeshElement* anyOuterFace);
6083   bool isOuterBoundary(const SMDS_MeshElement* face) const
6084   {
6085     return _outerFaces.empty() || _outerFaces.count(face);
6086   }
6087   struct TInters //!< data of intersection of the line and the mesh face (used in GetPointState())
6088   {
6089     const SMDS_MeshElement* _face;
6090     gp_Vec                  _faceNorm;
6091     bool                    _coincides; //!< the line lays in face plane
6092     TInters(const SMDS_MeshElement* face, const gp_Vec& faceNorm, bool coinc=false)
6093       : _face(face), _faceNorm( faceNorm ), _coincides( coinc ) {}
6094   };
6095   struct TFaceLink //!< link and faces sharing it (used in findOuterBoundary())
6096   {
6097     SMESH_TLink      _link;
6098     TIDSortedElemSet _faces;
6099     TFaceLink( const SMDS_MeshNode* n1, const SMDS_MeshNode* n2, const SMDS_MeshElement* face)
6100       : _link( n1, n2 ), _faces( &face, &face + 1) {}
6101   };
6102 };
6103
6104 ostream& operator<< (ostream& out, const SMESH_ElementSearcherImpl::TInters& i)
6105 {
6106   return out << "TInters(face=" << ( i._face ? i._face->GetID() : 0)
6107              << ", _coincides="<<i._coincides << ")";
6108 }
6109
6110 //=======================================================================
6111 /*!
6112  * \brief define tolerance for search
6113  */
6114 //=======================================================================
6115
6116 double SMESH_ElementSearcherImpl::getTolerance()
6117 {
6118   if ( _tolerance < 0 )
6119   {
6120     const SMDS_MeshInfo& meshInfo = _mesh->GetMeshInfo();
6121
6122     _tolerance = 0;
6123     if ( _nodeSearcher && meshInfo.NbNodes() > 1 )
6124     {
6125       double boxSize = _nodeSearcher->getTree()->maxSize();
6126       _tolerance = 1e-8 * boxSize/* / meshInfo.NbNodes()*/;
6127     }
6128     else if ( _ebbTree && meshInfo.NbElements() > 0 )
6129     {
6130       double boxSize = _ebbTree->maxSize();
6131       _tolerance = 1e-8 * boxSize/* / meshInfo.NbElements()*/;
6132     }
6133     if ( _tolerance == 0 )
6134     {
6135       // define tolerance by size of a most complex element
6136       int complexType = SMDSAbs_Volume;
6137       while ( complexType > SMDSAbs_All &&
6138               meshInfo.NbElements( SMDSAbs_ElementType( complexType )) < 1 )
6139         --complexType;
6140       if ( complexType == SMDSAbs_All ) return 0; // empty mesh
6141
6142       double elemSize;
6143       if ( complexType == int( SMDSAbs_Node ))
6144       {
6145         SMDS_NodeIteratorPtr nodeIt = _mesh->nodesIterator();
6146         elemSize = 1;
6147         if ( meshInfo.NbNodes() > 2 )
6148           elemSize = SMESH_MeshEditor::TNodeXYZ( nodeIt->next() ).Distance( nodeIt->next() );
6149       }
6150       else
6151       {
6152         const SMDS_MeshElement* elem =
6153           _mesh->elementsIterator( SMDSAbs_ElementType( complexType ))->next();
6154         SMDS_ElemIteratorPtr nodeIt = elem->nodesIterator();
6155         SMESH_MeshEditor::TNodeXYZ n1( cast2Node( nodeIt->next() ));
6156         while ( nodeIt->more() )
6157         {
6158           double dist = n1.Distance( cast2Node( nodeIt->next() ));
6159           elemSize = max( dist, elemSize );
6160         }
6161       }
6162       _tolerance = 1e-4 * elemSize;
6163     }
6164   }
6165   return _tolerance;
6166 }
6167
6168 //================================================================================
6169 /*!
6170  * \brief Find intersection of the line and an edge of face and return parameter on line
6171  */
6172 //================================================================================
6173
6174 bool SMESH_ElementSearcherImpl::getIntersParamOnLine(const gp_Lin&           line,
6175                                                      const SMDS_MeshElement* face,
6176                                                      const double            tol,
6177                                                      double &                param)
6178 {
6179   int nbInts = 0;
6180   param = 0;
6181
6182   GeomAPI_ExtremaCurveCurve anExtCC;
6183   Handle(Geom_Curve) lineCurve = new Geom_Line( line );
6184   
6185   int nbNodes = face->IsQuadratic() ? face->NbNodes()/2 : face->NbNodes();
6186   for ( int i = 0; i < nbNodes && nbInts < 2; ++i )
6187   {
6188     GC_MakeSegment edge( SMESH_MeshEditor::TNodeXYZ( face->GetNode( i )),
6189                          SMESH_MeshEditor::TNodeXYZ( face->GetNode( (i+1)%nbNodes) )); 
6190     anExtCC.Init( lineCurve, edge);
6191     if ( anExtCC.NbExtrema() > 0 && anExtCC.LowerDistance() <= tol)
6192     {
6193       Quantity_Parameter pl, pe;
6194       anExtCC.LowerDistanceParameters( pl, pe );
6195       param += pl;
6196       if ( ++nbInts == 2 )
6197         break;
6198     }
6199   }
6200   if ( nbInts > 0 ) param /= nbInts;
6201   return nbInts > 0;
6202 }
6203 //================================================================================
6204 /*!
6205  * \brief Find all faces belonging to the outer boundary of mesh
6206  */
6207 //================================================================================
6208
6209 void SMESH_ElementSearcherImpl::findOuterBoundary(const SMDS_MeshElement* outerFace)
6210 {
6211   if ( _outerFacesFound ) return;
6212
6213   // Collect all outer faces by passing from one outer face to another via their links
6214   // and BTW find out if there are internal faces at all.
6215
6216   // checked links and links where outer boundary meets internal one
6217   set< SMESH_TLink > visitedLinks, seamLinks;
6218
6219   // links to treat with already visited faces sharing them
6220   list < TFaceLink > startLinks;
6221
6222   // load startLinks with the first outerFace
6223   startLinks.push_back( TFaceLink( outerFace->GetNode(0), outerFace->GetNode(1), outerFace));
6224   _outerFaces.insert( outerFace );
6225
6226   TIDSortedElemSet emptySet;
6227   while ( !startLinks.empty() )
6228   {
6229     const SMESH_TLink& link  = startLinks.front()._link;
6230     TIDSortedElemSet&  faces = startLinks.front()._faces;
6231
6232     outerFace = *faces.begin();
6233     // find other faces sharing the link
6234     const SMDS_MeshElement* f;
6235     while (( f = SMESH_MeshEditor::FindFaceInSet(link.node1(), link.node2(), emptySet, faces )))
6236       faces.insert( f );
6237
6238     // select another outer face among the found 
6239     const SMDS_MeshElement* outerFace2 = 0;
6240     if ( faces.size() == 2 )
6241     {
6242       outerFace2 = (outerFace == *faces.begin() ? *faces.rbegin() : *faces.begin());
6243     }
6244     else if ( faces.size() > 2 )
6245     {
6246       seamLinks.insert( link );
6247
6248       // link direction within the outerFace
6249       gp_Vec n1n2( SMESH_MeshEditor::TNodeXYZ( link.node1()),
6250                    SMESH_MeshEditor::TNodeXYZ( link.node2()));
6251       int i1 = outerFace->GetNodeIndex( link.node1() );
6252       int i2 = outerFace->GetNodeIndex( link.node2() );
6253       bool rev = ( abs(i2-i1) == 1 ? i1 > i2 : i2 > i1 );
6254       if ( rev ) n1n2.Reverse();
6255       // outerFace normal
6256       gp_XYZ ofNorm, fNorm;
6257       if ( SMESH_Algo::FaceNormal( outerFace, ofNorm, /*normalized=*/false ))
6258       {
6259         // direction from the link inside outerFace
6260         gp_Vec dirInOF = gp_Vec( ofNorm ) ^ n1n2;
6261         // sort all other faces by angle with the dirInOF
6262         map< double, const SMDS_MeshElement* > angle2Face;
6263         set< const SMDS_MeshElement*, TIDCompare >::const_iterator face = faces.begin();
6264         for ( ; face != faces.end(); ++face )
6265         {
6266           if ( !SMESH_Algo::FaceNormal( *face, fNorm, /*normalized=*/false ))
6267             continue;
6268           gp_Vec dirInF = gp_Vec( fNorm ) ^ n1n2;
6269           double angle = dirInOF.AngleWithRef( dirInF, n1n2 );
6270           if ( angle < 0 ) angle += 2*PI;
6271           angle2Face.insert( make_pair( angle, *face ));
6272         }
6273         if ( !angle2Face.empty() )
6274           outerFace2 = angle2Face.begin()->second;
6275       }
6276     }
6277     // store the found outer face and add its links to continue seaching from
6278     if ( outerFace2 )
6279     {
6280       _outerFaces.insert( outerFace );
6281       int nbNodes = outerFace2->NbNodes()/( outerFace2->IsQuadratic() ? 2 : 1 );
6282       for ( int i = 0; i < nbNodes; ++i )
6283       {
6284         SMESH_TLink link2( outerFace2->GetNode(i), outerFace2->GetNode((i+1)%nbNodes));
6285         if ( visitedLinks.insert( link2 ).second )
6286           startLinks.push_back( TFaceLink( link2.node1(), link2.node2(), outerFace2 ));
6287       }
6288     }
6289     startLinks.pop_front();
6290   }
6291   _outerFacesFound = true;
6292
6293   if ( !seamLinks.empty() )
6294   {
6295     // There are internal boundaries touching the outher one,
6296     // find all faces of internal boundaries in order to find
6297     // faces of boundaries of holes, if any.
6298     
6299   }
6300   else
6301   {
6302     _outerFaces.clear();
6303   }
6304 }
6305
6306 //=======================================================================
6307 /*!
6308  * \brief Find elements of given type where the given point is IN or ON.
6309  *        Returns nb of found elements and elements them-selves.
6310  *
6311  * 'ALL' type means elements of any type excluding nodes and 0D elements
6312  */
6313 //=======================================================================
6314
6315 int SMESH_ElementSearcherImpl::
6316 FindElementsByPoint(const gp_Pnt&                      point,
6317                     SMDSAbs_ElementType                type,
6318                     vector< const SMDS_MeshElement* >& foundElements)
6319 {
6320   foundElements.clear();
6321
6322   double tolerance = getTolerance();
6323
6324   // =================================================================================
6325   if ( type == SMDSAbs_Node || type == SMDSAbs_0DElement )
6326   {
6327     if ( !_nodeSearcher )
6328       _nodeSearcher = new SMESH_NodeSearcherImpl( _mesh );
6329
6330     const SMDS_MeshNode* closeNode = _nodeSearcher->FindClosestTo( point );
6331     if ( !closeNode ) return foundElements.size();
6332
6333     if ( point.Distance( SMESH_MeshEditor::TNodeXYZ( closeNode )) > tolerance )
6334       return foundElements.size(); // to far from any node
6335
6336     if ( type == SMDSAbs_Node )
6337     {
6338       foundElements.push_back( closeNode );
6339     }
6340     else
6341     {
6342       SMDS_ElemIteratorPtr elemIt = closeNode->GetInverseElementIterator( SMDSAbs_0DElement );
6343       while ( elemIt->more() )
6344         foundElements.push_back( elemIt->next() );
6345     }
6346   }
6347   // =================================================================================
6348   else // elements more complex than 0D
6349   {
6350     if ( !_ebbTree || _elementType != type )
6351     {
6352       if ( _ebbTree ) delete _ebbTree;
6353       _ebbTree = new ElementBndBoxTree( *_mesh, _elementType = type, tolerance );
6354     }
6355     TIDSortedElemSet suspectElems;
6356     _ebbTree->getElementsNearPoint( point, suspectElems );
6357     TIDSortedElemSet::iterator elem = suspectElems.begin();
6358     for ( ; elem != suspectElems.end(); ++elem )
6359       if ( !SMESH_MeshEditor::isOut( *elem, point, tolerance ))
6360         foundElements.push_back( *elem );
6361   }
6362   return foundElements.size();
6363 }
6364
6365 //================================================================================
6366 /*!
6367  * \brief Classify the given point in the closed 2D mesh
6368  */
6369 //================================================================================
6370
6371 TopAbs_State SMESH_ElementSearcherImpl::GetPointState(const gp_Pnt& point)
6372 {
6373   double tolerance = getTolerance();
6374   if ( !_ebbTree || _elementType != SMDSAbs_Face )
6375   {
6376     if ( _ebbTree ) delete _ebbTree;
6377     _ebbTree = new ElementBndBoxTree( *_mesh, _elementType = SMDSAbs_Face );
6378   }
6379   // Algo: analyse transition of a line starting at the point through mesh boundary;
6380   // try three lines parallel to axis of the coordinate system and perform rough
6381   // analysis. If solution is not clear perform thorough analysis.
6382
6383   const int nbAxes = 3;
6384   gp_Dir axisDir[ nbAxes ] = { gp::DX(), gp::DY(), gp::DZ() };
6385   map< double, TInters >   paramOnLine2TInters[ nbAxes ];
6386   list< TInters > tangentInters[ nbAxes ]; // of faces whose plane includes the line
6387   multimap< int, int > nbInt2Axis; // to find the simplest case
6388   for ( int axis = 0; axis < nbAxes; ++axis )
6389   {
6390     gp_Ax1 lineAxis( point, axisDir[axis]);
6391     gp_Lin line    ( lineAxis );
6392
6393     TIDSortedElemSet suspectFaces; // faces possibly intersecting the line
6394     _ebbTree->getElementsNearLine( lineAxis, suspectFaces );
6395
6396     // Intersect faces with the line
6397
6398     map< double, TInters > & u2inters = paramOnLine2TInters[ axis ];
6399     TIDSortedElemSet::iterator face = suspectFaces.begin();
6400     for ( ; face != suspectFaces.end(); ++face )
6401     {
6402       // get face plane
6403       gp_XYZ fNorm;
6404       if ( !SMESH_Algo::FaceNormal( *face, fNorm, /*normalized=*/false)) continue;
6405       gp_Pln facePlane( SMESH_MeshEditor::TNodeXYZ( (*face)->GetNode(0)), fNorm );
6406
6407       // perform intersection
6408       IntAna_IntConicQuad intersection( line, IntAna_Quadric( facePlane ));
6409       if ( !intersection.IsDone() )
6410         continue;
6411       if ( intersection.IsInQuadric() )
6412       {
6413         tangentInters[ axis ].push_back( TInters( *face, fNorm, true ));
6414       }
6415       else if ( ! intersection.IsParallel() && intersection.NbPoints() > 0 )
6416       {
6417         gp_Pnt intersectionPoint = intersection.Point(1);
6418         if ( !SMESH_MeshEditor::isOut( *face, intersectionPoint, tolerance ))
6419           u2inters.insert(make_pair( intersection.ParamOnConic(1), TInters( *face, fNorm )));
6420       }
6421     }
6422     // Analyse intersections roughly
6423
6424     int nbInter = u2inters.size();
6425     if ( nbInter == 0 )
6426       return TopAbs_OUT; 
6427
6428     double f = u2inters.begin()->first, l = u2inters.rbegin()->first;
6429     if ( nbInter == 1 ) // not closed mesh
6430       return fabs( f ) < tolerance ? TopAbs_ON : TopAbs_UNKNOWN;
6431
6432     if ( fabs( f ) < tolerance || fabs( l ) < tolerance )
6433       return TopAbs_ON;
6434
6435     if ( (f<0) == (l<0) )
6436       return TopAbs_OUT;
6437
6438     int nbIntBeforePoint = std::distance( u2inters.begin(), u2inters.lower_bound(0));
6439     int nbIntAfterPoint  = nbInter - nbIntBeforePoint;
6440     if ( nbIntBeforePoint == 1 || nbIntAfterPoint == 1 )
6441       return TopAbs_IN;
6442
6443     nbInt2Axis.insert( make_pair( min( nbIntBeforePoint, nbIntAfterPoint ), axis ));
6444
6445     if ( _outerFacesFound ) break; // pass to thorough analysis
6446
6447   } // three attempts - loop on CS axes
6448
6449   // Analyse intersections thoroughly.
6450   // We make two loops maximum, on the first one we only exclude touching intersections,
6451   // on the second, if situation is still unclear, we gather and use information on
6452   // position of faces (internal or outer). If faces position is already gathered,
6453   // we make the second loop right away.
6454
6455   for ( int hasPositionInfo = _outerFacesFound; hasPositionInfo < 2; ++hasPositionInfo )
6456   {
6457     multimap< int, int >::const_iterator nb_axis = nbInt2Axis.begin();
6458     for ( ; nb_axis != nbInt2Axis.end(); ++nb_axis )
6459     {
6460       int axis = nb_axis->second;
6461       map< double, TInters > & u2inters = paramOnLine2TInters[ axis ];
6462
6463       gp_Ax1 lineAxis( point, axisDir[axis]);
6464       gp_Lin line    ( lineAxis );
6465
6466       // add tangent intersections to u2inters
6467       double param;
6468       list< TInters >::const_iterator tgtInt = tangentInters[ axis ].begin();
6469       for ( ; tgtInt != tangentInters[ axis ].end(); ++tgtInt )
6470         if ( getIntersParamOnLine( line, tgtInt->_face, tolerance, param ))
6471           u2inters.insert(make_pair( param, *tgtInt ));
6472       tangentInters[ axis ].clear();
6473
6474       // Count intersections before and after the point excluding touching ones.
6475       // If hasPositionInfo we count intersections of outer boundary only
6476
6477       int nbIntBeforePoint = 0, nbIntAfterPoint = 0;
6478       double f = numeric_limits<double>::max(), l = -numeric_limits<double>::max();
6479       map< double, TInters >::iterator u_int1 = u2inters.begin(), u_int2 = u_int1;
6480       bool ok = ! u_int1->second._coincides;
6481       while ( ok && u_int1 != u2inters.end() )
6482       {
6483         double u = u_int1->first;
6484         bool touchingInt = false;
6485         if ( ++u_int2 != u2inters.end() )
6486         {
6487           // skip intersections at the same point (if the line passes through edge or node)
6488           int nbSamePnt = 0;
6489           while ( u_int2 != u2inters.end() && fabs( u_int2->first - u ) < tolerance )
6490           {
6491             ++nbSamePnt;
6492             ++u_int2;
6493           }
6494
6495           // skip tangent intersections
6496           int nbTgt = 0;
6497           const SMDS_MeshElement* prevFace = u_int1->second._face;
6498           while ( ok && u_int2->second._coincides )
6499           {
6500             if ( SMESH_Algo::GetCommonNodes(prevFace , u_int2->second._face).empty() )
6501               ok = false;
6502             else
6503             {
6504               nbTgt++;
6505               u_int2++;
6506               ok = ( u_int2 != u2inters.end() );
6507             }
6508           }
6509           if ( !ok ) break;
6510
6511           // skip intersections at the same point after tangent intersections
6512           if ( nbTgt > 0 )
6513           {
6514             double u2 = u_int2->first;
6515             ++u_int2;
6516             while ( u_int2 != u2inters.end() && fabs( u_int2->first - u2 ) < tolerance )
6517             {
6518               ++nbSamePnt;
6519               ++u_int2;
6520             }
6521           }
6522           // decide if we skipped a touching intersection
6523           if ( nbSamePnt + nbTgt > 0 )
6524           {
6525             double minDot = numeric_limits<double>::max(), maxDot = -numeric_limits<double>::max();
6526             map< double, TInters >::iterator u_int = u_int1;
6527             for ( ; u_int != u_int2; ++u_int )
6528             {
6529               if ( u_int->second._coincides ) continue;
6530               double dot = u_int->second._faceNorm * line.Direction();
6531               if ( dot > maxDot ) maxDot = dot;
6532               if ( dot < minDot ) minDot = dot;
6533             }
6534             touchingInt = ( minDot*maxDot < 0 );
6535           }
6536         }
6537         if ( !touchingInt )
6538         {
6539           if ( !hasPositionInfo || isOuterBoundary( u_int1->second._face ))
6540           {
6541             if ( u < 0 )
6542               ++nbIntBeforePoint;
6543             else
6544               ++nbIntAfterPoint;
6545           }
6546           if ( u < f ) f = u;
6547           if ( u > l ) l = u;
6548         }
6549
6550         u_int1 = u_int2; // to next intersection
6551
6552       } // loop on intersections with one line
6553
6554       if ( ok )
6555       {
6556         if ( fabs( f ) < tolerance || fabs( l ) < tolerance )
6557           return TopAbs_ON;
6558
6559         if ( nbIntBeforePoint == 0  || nbIntAfterPoint == 0)
6560           return TopAbs_OUT; 
6561
6562         if ( nbIntBeforePoint + nbIntAfterPoint == 1 ) // not closed mesh
6563           return fabs( f ) < tolerance ? TopAbs_ON : TopAbs_UNKNOWN;
6564
6565         if ( nbIntBeforePoint == 1 || nbIntAfterPoint == 1 )
6566           return TopAbs_IN;
6567
6568         if ( (f<0) == (l<0) )
6569           return TopAbs_OUT;
6570
6571         if ( hasPositionInfo )
6572           return nbIntBeforePoint % 2 ? TopAbs_IN : TopAbs_OUT;
6573       }
6574     } // loop on intersections of the tree lines - thorough analysis
6575
6576     if ( !hasPositionInfo )
6577     {
6578       // gather info on faces position - is face in the outer boundary or not
6579       map< double, TInters > & u2inters = paramOnLine2TInters[ 0 ];
6580       findOuterBoundary( u2inters.begin()->second._face );
6581     }
6582
6583   } // two attempts - with and w/o faces position info in the mesh
6584
6585   return TopAbs_UNKNOWN;
6586 }
6587
6588 //=======================================================================
6589 /*!
6590  * \brief Return elements possibly intersecting the line
6591  */
6592 //=======================================================================
6593
6594 void SMESH_ElementSearcherImpl::GetElementsNearLine( const gp_Ax1&                      line,
6595                                                      SMDSAbs_ElementType                type,
6596                                                      vector< const SMDS_MeshElement* >& foundElems)
6597 {
6598   if ( !_ebbTree || _elementType != type )
6599   {
6600     if ( _ebbTree ) delete _ebbTree;
6601     _ebbTree = new ElementBndBoxTree( *_mesh, _elementType = type );
6602   }
6603   TIDSortedElemSet suspectFaces; // elements possibly intersecting the line
6604   _ebbTree->getElementsNearLine( line, suspectFaces );
6605   foundElems.assign( suspectFaces.begin(), suspectFaces.end());
6606 }
6607
6608 //=======================================================================
6609 /*!
6610  * \brief Return SMESH_ElementSearcher
6611  */
6612 //=======================================================================
6613
6614 SMESH_ElementSearcher* SMESH_MeshEditor::GetElementSearcher()
6615 {
6616   return new SMESH_ElementSearcherImpl( *GetMeshDS() );
6617 }
6618
6619 //=======================================================================
6620 /*!
6621  * \brief Return true if the point is IN or ON of the element
6622  */
6623 //=======================================================================
6624
6625 bool SMESH_MeshEditor::isOut( const SMDS_MeshElement* element, const gp_Pnt& point, double tol )
6626 {
6627   if ( element->GetType() == SMDSAbs_Volume)
6628   {
6629     return SMDS_VolumeTool( element ).IsOut( point.X(), point.Y(), point.Z(), tol );
6630   }
6631
6632   // get ordered nodes
6633
6634   vector< gp_XYZ > xyz;
6635
6636   SMDS_ElemIteratorPtr nodeIt = element->nodesIterator();
6637   if ( element->IsQuadratic() )
6638     if (const SMDS_QuadraticFaceOfNodes* f=dynamic_cast<const SMDS_QuadraticFaceOfNodes*>(element))
6639       nodeIt = f->interlacedNodesElemIterator();
6640     else if (const SMDS_QuadraticEdge*  e =dynamic_cast<const SMDS_QuadraticEdge*>(element))
6641       nodeIt = e->interlacedNodesElemIterator();
6642
6643   while ( nodeIt->more() )
6644     xyz.push_back( TNodeXYZ( cast2Node( nodeIt->next() )));
6645
6646   int i, nbNodes = element->NbNodes();
6647
6648   if ( element->GetType() == SMDSAbs_Face ) // --------------------------------------------------
6649   {
6650     // compute face normal
6651     gp_Vec faceNorm(0,0,0);
6652     xyz.push_back( xyz.front() );
6653     for ( i = 0; i < nbNodes; ++i )
6654     {
6655       gp_Vec edge1( xyz[i+1], xyz[i]);
6656       gp_Vec edge2( xyz[i+1], xyz[(i+2)%nbNodes] );
6657       faceNorm += edge1 ^ edge2;
6658     }
6659     double normSize = faceNorm.Magnitude();
6660     if ( normSize <= tol )
6661     {
6662       // degenerated face: point is out if it is out of all face edges
6663       for ( i = 0; i < nbNodes; ++i )
6664       {
6665         SMDS_MeshNode n1( xyz[i].X(),   xyz[i].Y(),   xyz[i].Z() );
6666         SMDS_MeshNode n2( xyz[i+1].X(), xyz[i+1].Y(), xyz[i+1].Z() );
6667         SMDS_MeshEdge edge( &n1, &n2 );
6668         if ( !isOut( &edge, point, tol ))
6669           return false;
6670       }
6671       return true;
6672     }
6673     faceNorm /= normSize;
6674
6675     // check if the point lays on face plane
6676     gp_Vec n2p( xyz[0], point );
6677     if ( fabs( n2p * faceNorm ) > tol )
6678       return true; // not on face plane
6679
6680     // check if point is out of face boundary:
6681     // define it by closest transition of a ray point->infinity through face boundary
6682     // on the face plane.
6683     // First, find normal of a plane perpendicular to face plane, to be used as a cutting tool
6684     // to find intersections of the ray with the boundary.
6685     gp_Vec ray = n2p;
6686     gp_Vec plnNorm = ray ^ faceNorm;
6687     normSize = plnNorm.Magnitude();
6688     if ( normSize <= tol ) return false; // point coincides with the first node
6689     plnNorm /= normSize;
6690     // for each node of the face, compute its signed distance to the plane
6691     vector<double> dist( nbNodes + 1);
6692     for ( i = 0; i < nbNodes; ++i )
6693     {
6694       gp_Vec n2p( xyz[i], point );
6695       dist[i] = n2p * plnNorm;
6696     }
6697     dist.back() = dist.front();
6698     // find the closest intersection
6699     int    iClosest = -1;
6700     double rClosest, distClosest = 1e100;;
6701     gp_Pnt pClosest;
6702     for ( i = 0; i < nbNodes; ++i )
6703     {
6704       double r;
6705       if ( fabs( dist[i]) < tol )
6706         r = 0.;
6707       else if ( fabs( dist[i+1]) < tol )
6708         r = 1.;
6709       else if ( dist[i] * dist[i+1] < 0 )
6710         r = dist[i] / ( dist[i] - dist[i+1] );
6711       else
6712         continue; // no intersection
6713       gp_Pnt pInt = xyz[i] * (1.-r) + xyz[i+1] * r;
6714       gp_Vec p2int ( point, pInt);
6715       if ( p2int * ray > -tol ) // right half-space
6716       {
6717         double intDist = p2int.SquareMagnitude();
6718         if ( intDist < distClosest )
6719         {
6720           iClosest = i;
6721           rClosest = r;
6722           pClosest = pInt;
6723           distClosest = intDist;
6724         }
6725       }
6726     }
6727     if ( iClosest < 0 )
6728       return true; // no intesections - out
6729
6730     // analyse transition
6731     gp_Vec edge( xyz[iClosest], xyz[iClosest+1] );
6732     gp_Vec edgeNorm = -( edge ^ faceNorm ); // normal to intersected edge pointing out of face
6733     gp_Vec p2int ( point, pClosest );
6734     bool out = (edgeNorm * p2int) < -tol;
6735     if ( rClosest > 0. && rClosest < 1. ) // not node intersection
6736       return out;
6737
6738     // ray pass through a face node; analyze transition through an adjacent edge
6739     gp_Pnt p1 = xyz[ (rClosest == 0.) ? ((iClosest+nbNodes-1) % nbNodes) : (iClosest+1) ];
6740     gp_Pnt p2 = xyz[ (rClosest == 0.) ? iClosest : ((iClosest+2) % nbNodes) ];
6741     gp_Vec edgeAdjacent( p1, p2 );
6742     gp_Vec edgeNorm2 = -( edgeAdjacent ^ faceNorm );
6743     bool out2 = (edgeNorm2 * p2int) < -tol;
6744
6745     bool covexCorner = ( edgeNorm * edgeAdjacent * (rClosest==1. ? 1. : -1.)) < 0;
6746     return covexCorner ? (out || out2) : (out && out2);
6747   }
6748   if ( element->GetType() == SMDSAbs_Edge ) // --------------------------------------------------
6749   {
6750     // point is out of edge if it is NOT ON any straight part of edge
6751     // (we consider quadratic edge as being composed of two straight parts)
6752     for ( i = 1; i < nbNodes; ++i )
6753     {
6754       gp_Vec edge( xyz[i-1], xyz[i]);
6755       gp_Vec n1p ( xyz[i-1], point);
6756       double dist = ( edge ^ n1p ).Magnitude() / edge.Magnitude();
6757       if ( dist > tol )
6758         continue;
6759       gp_Vec n2p( xyz[i], point );
6760       if ( fabs( edge.Magnitude() - n1p.Magnitude() - n2p.Magnitude()) > tol )
6761         continue;
6762       return false; // point is ON this part
6763     }
6764     return true;
6765   }
6766   // Node or 0D element -------------------------------------------------------------------------
6767   {
6768     gp_Vec n2p ( xyz[0], point );
6769     return n2p.Magnitude() <= tol;
6770   }
6771   return true;
6772 }
6773
6774 //=======================================================================
6775 //function : SimplifyFace
6776 //purpose  :
6777 //=======================================================================
6778 int SMESH_MeshEditor::SimplifyFace (const vector<const SMDS_MeshNode *> faceNodes,
6779                                     vector<const SMDS_MeshNode *>&      poly_nodes,
6780                                     vector<int>&                        quantities) const
6781 {
6782   int nbNodes = faceNodes.size();
6783
6784   if (nbNodes < 3)
6785     return 0;
6786
6787   set<const SMDS_MeshNode*> nodeSet;
6788
6789   // get simple seq of nodes
6790   //const SMDS_MeshNode* simpleNodes[ nbNodes ];
6791   vector<const SMDS_MeshNode*> simpleNodes( nbNodes );
6792   int iSimple = 0, nbUnique = 0;
6793
6794   simpleNodes[iSimple++] = faceNodes[0];
6795   nbUnique++;
6796   for (int iCur = 1; iCur < nbNodes; iCur++) {
6797     if (faceNodes[iCur] != simpleNodes[iSimple - 1]) {
6798       simpleNodes[iSimple++] = faceNodes[iCur];
6799       if (nodeSet.insert( faceNodes[iCur] ).second)
6800         nbUnique++;
6801     }
6802   }
6803   int nbSimple = iSimple;
6804   if (simpleNodes[nbSimple - 1] == simpleNodes[0]) {
6805     nbSimple--;
6806     iSimple--;
6807   }
6808
6809   if (nbUnique < 3)
6810     return 0;
6811
6812   // separate loops
6813   int nbNew = 0;
6814   bool foundLoop = (nbSimple > nbUnique);
6815   while (foundLoop) {
6816     foundLoop = false;
6817     set<const SMDS_MeshNode*> loopSet;
6818     for (iSimple = 0; iSimple < nbSimple && !foundLoop; iSimple++) {
6819       const SMDS_MeshNode* n = simpleNodes[iSimple];
6820       if (!loopSet.insert( n ).second) {
6821         foundLoop = true;
6822
6823         // separate loop
6824         int iC = 0, curLast = iSimple;
6825         for (; iC < curLast; iC++) {
6826           if (simpleNodes[iC] == n) break;
6827         }
6828         int loopLen = curLast - iC;
6829         if (loopLen > 2) {
6830           // create sub-element
6831           nbNew++;
6832           quantities.push_back(loopLen);
6833           for (; iC < curLast; iC++) {
6834             poly_nodes.push_back(simpleNodes[iC]);
6835           }
6836         }
6837         // shift the rest nodes (place from the first loop position)
6838         for (iC = curLast + 1; iC < nbSimple; iC++) {
6839           simpleNodes[iC - loopLen] = simpleNodes[iC];
6840         }
6841         nbSimple -= loopLen;
6842         iSimple -= loopLen;
6843       }
6844     } // for (iSimple = 0; iSimple < nbSimple; iSimple++)
6845   } // while (foundLoop)
6846
6847   if (iSimple > 2) {
6848     nbNew++;
6849     quantities.push_back(iSimple);
6850     for (int i = 0; i < iSimple; i++)
6851       poly_nodes.push_back(simpleNodes[i]);
6852   }
6853
6854   return nbNew;
6855 }
6856
6857 //=======================================================================
6858 //function : MergeNodes
6859 //purpose  : In each group, the cdr of nodes are substituted by the first one
6860 //           in all elements.
6861 //=======================================================================
6862
6863 void SMESH_MeshEditor::MergeNodes (TListOfListOfNodes & theGroupsOfNodes)
6864 {
6865   myLastCreatedElems.Clear();
6866   myLastCreatedNodes.Clear();
6867
6868   SMESHDS_Mesh* aMesh = GetMeshDS();
6869
6870   TNodeNodeMap nodeNodeMap; // node to replace - new node
6871   set<const SMDS_MeshElement*> elems; // all elements with changed nodes
6872   list< int > rmElemIds, rmNodeIds;
6873
6874   // Fill nodeNodeMap and elems
6875
6876   TListOfListOfNodes::iterator grIt = theGroupsOfNodes.begin();
6877   for ( ; grIt != theGroupsOfNodes.end(); grIt++ ) {
6878     list<const SMDS_MeshNode*>& nodes = *grIt;
6879     list<const SMDS_MeshNode*>::iterator nIt = nodes.begin();
6880     const SMDS_MeshNode* nToKeep = *nIt;
6881     for ( ++nIt; nIt != nodes.end(); nIt++ ) {
6882       const SMDS_MeshNode* nToRemove = *nIt;
6883       nodeNodeMap.insert( TNodeNodeMap::value_type( nToRemove, nToKeep ));
6884       if ( nToRemove != nToKeep ) {
6885         rmNodeIds.push_back( nToRemove->GetID() );
6886         AddToSameGroups( nToKeep, nToRemove, aMesh );
6887       }
6888
6889       SMDS_ElemIteratorPtr invElemIt = nToRemove->GetInverseElementIterator();
6890       while ( invElemIt->more() ) {
6891         const SMDS_MeshElement* elem = invElemIt->next();
6892         elems.insert(elem);
6893       }
6894     }
6895   }
6896   // Change element nodes or remove an element
6897
6898   set<const SMDS_MeshElement*>::iterator eIt = elems.begin();
6899   for ( ; eIt != elems.end(); eIt++ ) {
6900     const SMDS_MeshElement* elem = *eIt;
6901     int nbNodes = elem->NbNodes();
6902     int aShapeId = FindShape( elem );
6903
6904     set<const SMDS_MeshNode*> nodeSet;
6905     vector< const SMDS_MeshNode*> curNodes( nbNodes ), uniqueNodes( nbNodes );
6906     int iUnique = 0, iCur = 0, nbRepl = 0;
6907     vector<int> iRepl( nbNodes );
6908
6909     // get new seq of nodes
6910     SMDS_ElemIteratorPtr itN = elem->nodesIterator();
6911     while ( itN->more() ) {
6912       const SMDS_MeshNode* n =
6913         static_cast<const SMDS_MeshNode*>( itN->next() );
6914
6915       TNodeNodeMap::iterator nnIt = nodeNodeMap.find( n );
6916       if ( nnIt != nodeNodeMap.end() ) { // n sticks
6917         n = (*nnIt).second;
6918         // BUG 0020185: begin
6919         {
6920           bool stopRecur = false;
6921           set<const SMDS_MeshNode*> nodesRecur;
6922           nodesRecur.insert(n);
6923           while (!stopRecur) {
6924             TNodeNodeMap::iterator nnIt_i = nodeNodeMap.find( n );
6925             if ( nnIt_i != nodeNodeMap.end() ) { // n sticks
6926               n = (*nnIt_i).second;
6927               if (!nodesRecur.insert(n).second) {
6928                 // error: recursive dependancy
6929                 stopRecur = true;
6930               }
6931             }
6932             else
6933               stopRecur = true;
6934           }
6935         }
6936         // BUG 0020185: end
6937         iRepl[ nbRepl++ ] = iCur;
6938       }
6939       curNodes[ iCur ] = n;
6940       bool isUnique = nodeSet.insert( n ).second;
6941       if ( isUnique )
6942         uniqueNodes[ iUnique++ ] = n;
6943       iCur++;
6944     }
6945
6946     // Analyse element topology after replacement
6947
6948     bool isOk = true;
6949     int nbUniqueNodes = nodeSet.size();
6950     if ( nbNodes != nbUniqueNodes ) { // some nodes stick
6951       // Polygons and Polyhedral volumes
6952       if (elem->IsPoly()) {
6953
6954         if (elem->GetType() == SMDSAbs_Face) {
6955           // Polygon
6956           vector<const SMDS_MeshNode *> face_nodes (nbNodes);
6957           int inode = 0;
6958           for (; inode < nbNodes; inode++) {
6959             face_nodes[inode] = curNodes[inode];
6960           }
6961
6962           vector<const SMDS_MeshNode *> polygons_nodes;
6963           vector<int> quantities;
6964           int nbNew = SimplifyFace(face_nodes, polygons_nodes, quantities);
6965
6966           if (nbNew > 0) {
6967             inode = 0;
6968             for (int iface = 0; iface < nbNew - 1; iface++) {
6969               int nbNodes = quantities[iface];
6970               vector<const SMDS_MeshNode *> poly_nodes (nbNodes);
6971               for (int ii = 0; ii < nbNodes; ii++, inode++) {
6972                 poly_nodes[ii] = polygons_nodes[inode];
6973               }
6974               SMDS_MeshElement* newElem = aMesh->AddPolygonalFace(poly_nodes);
6975               myLastCreatedElems.Append(newElem);
6976               if (aShapeId)
6977                 aMesh->SetMeshElementOnShape(newElem, aShapeId);
6978             }
6979             aMesh->ChangeElementNodes(elem, &polygons_nodes[inode], quantities[nbNew - 1]);
6980           }
6981           else {
6982             rmElemIds.push_back(elem->GetID());
6983           }
6984
6985         }
6986         else if (elem->GetType() == SMDSAbs_Volume) {
6987           // Polyhedral volume
6988           if (nbUniqueNodes < 4) {
6989             rmElemIds.push_back(elem->GetID());
6990           }
6991           else {
6992             // each face has to be analized in order to check volume validity
6993             const SMDS_PolyhedralVolumeOfNodes* aPolyedre =
6994               static_cast<const SMDS_PolyhedralVolumeOfNodes*>( elem );
6995             if (aPolyedre) {
6996               int nbFaces = aPolyedre->NbFaces();
6997
6998               vector<const SMDS_MeshNode *> poly_nodes;
6999               vector<int> quantities;
7000
7001               for (int iface = 1; iface <= nbFaces; iface++) {
7002                 int nbFaceNodes = aPolyedre->NbFaceNodes(iface);
7003                 vector<const SMDS_MeshNode *> faceNodes (nbFaceNodes);
7004
7005                 for (int inode = 1; inode <= nbFaceNodes; inode++) {
7006                   const SMDS_MeshNode * faceNode = aPolyedre->GetFaceNode(iface, inode);
7007                   TNodeNodeMap::iterator nnIt = nodeNodeMap.find(faceNode);
7008                   if (nnIt != nodeNodeMap.end()) { // faceNode sticks
7009                     faceNode = (*nnIt).second;
7010                   }
7011                   faceNodes[inode - 1] = faceNode;
7012                 }
7013
7014                 SimplifyFace(faceNodes, poly_nodes, quantities);
7015               }
7016
7017               if (quantities.size() > 3) {
7018                 // to be done: remove coincident faces
7019               }
7020
7021               if (quantities.size() > 3)
7022                 aMesh->ChangePolyhedronNodes(elem, poly_nodes, quantities);
7023               else
7024                 rmElemIds.push_back(elem->GetID());
7025
7026             }
7027             else {
7028               rmElemIds.push_back(elem->GetID());
7029             }
7030           }
7031         }
7032         else {
7033         }
7034
7035         continue;
7036       }
7037
7038       // Regular elements
7039       switch ( nbNodes ) {
7040       case 2: ///////////////////////////////////// EDGE
7041         isOk = false; break;
7042       case 3: ///////////////////////////////////// TRIANGLE
7043         isOk = false; break;
7044       case 4:
7045         if ( elem->GetType() == SMDSAbs_Volume ) // TETRAHEDRON
7046           isOk = false;
7047         else { //////////////////////////////////// QUADRANGLE
7048           if ( nbUniqueNodes < 3 )
7049             isOk = false;
7050           else if ( nbRepl == 2 && iRepl[ 1 ] - iRepl[ 0 ] == 2 )
7051             isOk = false; // opposite nodes stick
7052         }
7053         break;
7054       case 6: ///////////////////////////////////// PENTAHEDRON
7055         if ( nbUniqueNodes == 4 ) {
7056           // ---------------------------------> tetrahedron
7057           if (nbRepl == 3 &&
7058               iRepl[ 0 ] > 2 && iRepl[ 1 ] > 2 && iRepl[ 2 ] > 2 ) {
7059             // all top nodes stick: reverse a bottom
7060             uniqueNodes[ 0 ] = curNodes [ 1 ];
7061             uniqueNodes[ 1 ] = curNodes [ 0 ];
7062           }
7063           else if (nbRepl == 3 &&
7064                    iRepl[ 0 ] < 3 && iRepl[ 1 ] < 3 && iRepl[ 2 ] < 3 ) {
7065             // all bottom nodes stick: set a top before
7066             uniqueNodes[ 3 ] = uniqueNodes [ 0 ];
7067             uniqueNodes[ 0 ] = curNodes [ 3 ];
7068             uniqueNodes[ 1 ] = curNodes [ 4 ];
7069             uniqueNodes[ 2 ] = curNodes [ 5 ];
7070           }
7071           else if (nbRepl == 4 &&
7072                    iRepl[ 2 ] - iRepl [ 0 ] == 3 && iRepl[ 3 ] - iRepl [ 1 ] == 3 ) {
7073             // a lateral face turns into a line: reverse a bottom
7074             uniqueNodes[ 0 ] = curNodes [ 1 ];
7075             uniqueNodes[ 1 ] = curNodes [ 0 ];
7076           }
7077           else
7078             isOk = false;
7079         }
7080         else if ( nbUniqueNodes == 5 ) {
7081           // PENTAHEDRON --------------------> 2 tetrahedrons
7082           if ( nbRepl == 2 && iRepl[ 1 ] - iRepl [ 0 ] == 3 ) {
7083             // a bottom node sticks with a linked top one
7084             // 1.
7085             SMDS_MeshElement* newElem =
7086               aMesh->AddVolume(curNodes[ 3 ],
7087                                curNodes[ 4 ],
7088                                curNodes[ 5 ],
7089                                curNodes[ iRepl[ 0 ] == 2 ? 1 : 2 ]);
7090             myLastCreatedElems.Append(newElem);
7091             if ( aShapeId )
7092               aMesh->SetMeshElementOnShape( newElem, aShapeId );
7093             // 2. : reverse a bottom
7094             uniqueNodes[ 0 ] = curNodes [ 1 ];
7095             uniqueNodes[ 1 ] = curNodes [ 0 ];
7096             nbUniqueNodes = 4;
7097           }
7098           else
7099             isOk = false;
7100         }
7101         else
7102           isOk = false;
7103         break;
7104       case 8: {
7105         if(elem->IsQuadratic()) { // Quadratic quadrangle
7106           //   1    5    2
7107           //    +---+---+
7108           //    |       |
7109           //    |       |
7110           //   4+       +6
7111           //    |       |
7112           //    |       |
7113           //    +---+---+
7114           //   0    7    3
7115           isOk = false;
7116           if(nbRepl==3) {
7117             nbUniqueNodes = 6;
7118             if( iRepl[0]==0 && iRepl[1]==1 && iRepl[2]==4 ) {
7119               uniqueNodes[0] = curNodes[0];
7120               uniqueNodes[1] = curNodes[2];
7121               uniqueNodes[2] = curNodes[3];
7122               uniqueNodes[3] = curNodes[5];
7123               uniqueNodes[4] = curNodes[6];
7124               uniqueNodes[5] = curNodes[7];
7125               isOk = true;
7126             }
7127             if( iRepl[0]==0 && iRepl[1]==3 && iRepl[2]==7 ) {
7128               uniqueNodes[0] = curNodes[0];
7129               uniqueNodes[1] = curNodes[1];
7130               uniqueNodes[2] = curNodes[2];
7131               uniqueNodes[3] = curNodes[4];
7132               uniqueNodes[4] = curNodes[5];
7133               uniqueNodes[5] = curNodes[6];
7134               isOk = true;
7135             }
7136             if( iRepl[0]==0 && iRepl[1]==4 && iRepl[2]==7 ) {
7137               uniqueNodes[0] = curNodes[1];
7138               uniqueNodes[1] = curNodes[2];
7139               uniqueNodes[2] = curNodes[3];
7140               uniqueNodes[3] = curNodes[5];
7141               uniqueNodes[4] = curNodes[6];
7142               uniqueNodes[5] = curNodes[0];
7143               isOk = true;
7144             }
7145             if( iRepl[0]==1 && iRepl[1]==2 && iRepl[2]==5 ) {
7146               uniqueNodes[0] = curNodes[0];
7147               uniqueNodes[1] = curNodes[1];
7148               uniqueNodes[2] = curNodes[3];
7149               uniqueNodes[3] = curNodes[4];
7150               uniqueNodes[4] = curNodes[6];
7151               uniqueNodes[5] = curNodes[7];
7152               isOk = true;
7153             }
7154             if( iRepl[0]==1 && iRepl[1]==4 && iRepl[2]==5 ) {
7155               uniqueNodes[0] = curNodes[0];
7156               uniqueNodes[1] = curNodes[2];
7157               uniqueNodes[2] = curNodes[3];
7158               uniqueNodes[3] = curNodes[1];
7159               uniqueNodes[4] = curNodes[6];
7160               uniqueNodes[5] = curNodes[7];
7161               isOk = true;
7162             }
7163             if( iRepl[0]==2 && iRepl[1]==3 && iRepl[2]==6 ) {
7164               uniqueNodes[0] = curNodes[0];
7165               uniqueNodes[1] = curNodes[1];
7166               uniqueNodes[2] = curNodes[2];
7167               uniqueNodes[3] = curNodes[4];
7168               uniqueNodes[4] = curNodes[5];
7169               uniqueNodes[5] = curNodes[7];
7170               isOk = true;
7171             }
7172             if( iRepl[0]==2 && iRepl[1]==5 && iRepl[2]==6 ) {
7173               uniqueNodes[0] = curNodes[0];
7174               uniqueNodes[1] = curNodes[1];
7175               uniqueNodes[2] = curNodes[3];
7176               uniqueNodes[3] = curNodes[4];
7177               uniqueNodes[4] = curNodes[2];
7178               uniqueNodes[5] = curNodes[7];
7179               isOk = true;
7180             }
7181             if( iRepl[0]==3 && iRepl[1]==6 && iRepl[2]==7 ) {
7182               uniqueNodes[0] = curNodes[0];
7183               uniqueNodes[1] = curNodes[1];
7184               uniqueNodes[2] = curNodes[2];
7185               uniqueNodes[3] = curNodes[4];
7186               uniqueNodes[4] = curNodes[5];
7187               uniqueNodes[5] = curNodes[3];
7188               isOk = true;
7189             }
7190           }
7191           break;
7192         }
7193         //////////////////////////////////// HEXAHEDRON
7194         isOk = false;
7195         SMDS_VolumeTool hexa (elem);
7196         hexa.SetExternalNormal();
7197         if ( nbUniqueNodes == 4 && nbRepl == 6 ) {
7198           //////////////////////// ---> tetrahedron
7199           for ( int iFace = 0; iFace < 6; iFace++ ) {
7200             const int *ind = hexa.GetFaceNodesIndices( iFace ); // indices of face nodes
7201             if (curNodes[ind[ 0 ]] == curNodes[ind[ 1 ]] &&
7202                 curNodes[ind[ 0 ]] == curNodes[ind[ 2 ]] &&
7203                 curNodes[ind[ 0 ]] == curNodes[ind[ 3 ]] ) {
7204               // one face turns into a point ...
7205               int iOppFace = hexa.GetOppFaceIndex( iFace );
7206               ind = hexa.GetFaceNodesIndices( iOppFace );
7207               int nbStick = 0;
7208               iUnique = 2; // reverse a tetrahedron bottom
7209               for ( iCur = 0; iCur < 4 && nbStick < 2; iCur++ ) {
7210                 if ( curNodes[ind[ iCur ]] == curNodes[ind[ iCur + 1 ]] )
7211                   nbStick++;
7212                 else if ( iUnique >= 0 )
7213                   uniqueNodes[ iUnique-- ] = curNodes[ind[ iCur ]];
7214               }
7215               if ( nbStick == 1 ) {
7216                 // ... and the opposite one - into a triangle.
7217                 // set a top node
7218                 ind = hexa.GetFaceNodesIndices( iFace );
7219                 uniqueNodes[ 3 ] = curNodes[ind[ 0 ]];
7220                 isOk = true;
7221               }
7222               break;
7223             }
7224           }
7225         }
7226         else if (nbUniqueNodes == 5 && nbRepl == 4 ) {
7227           //////////////////// HEXAHEDRON ---> 2 tetrahedrons
7228           for ( int iFace = 0; iFace < 6; iFace++ ) {
7229             const int *ind = hexa.GetFaceNodesIndices( iFace ); // indices of face nodes
7230             if (curNodes[ind[ 0 ]] == curNodes[ind[ 1 ]] &&
7231                 curNodes[ind[ 0 ]] == curNodes[ind[ 2 ]] &&
7232                 curNodes[ind[ 0 ]] == curNodes[ind[ 3 ]] ) {
7233               // one face turns into a point ...
7234               int iOppFace = hexa.GetOppFaceIndex( iFace );
7235               ind = hexa.GetFaceNodesIndices( iOppFace );
7236               int nbStick = 0;
7237               iUnique = 2;  // reverse a tetrahedron 1 bottom
7238               for ( iCur = 0; iCur < 4 && nbStick == 0; iCur++ ) {
7239                 if ( curNodes[ind[ iCur ]] == curNodes[ind[ iCur + 1 ]] )
7240                   nbStick++;
7241                 else if ( iUnique >= 0 )
7242                   uniqueNodes[ iUnique-- ] = curNodes[ind[ iCur ]];
7243               }
7244               if ( nbStick == 0 ) {
7245                 // ... and the opposite one is a quadrangle
7246                 // set a top node
7247                 const int* indTop = hexa.GetFaceNodesIndices( iFace );
7248                 uniqueNodes[ 3 ] = curNodes[indTop[ 0 ]];
7249                 nbUniqueNodes = 4;
7250                 // tetrahedron 2
7251                 SMDS_MeshElement* newElem =
7252                   aMesh->AddVolume(curNodes[ind[ 0 ]],
7253                                    curNodes[ind[ 3 ]],
7254                                    curNodes[ind[ 2 ]],
7255                                    curNodes[indTop[ 0 ]]);
7256                 myLastCreatedElems.Append(newElem);
7257                 if ( aShapeId )
7258                   aMesh->SetMeshElementOnShape( newElem, aShapeId );
7259                 isOk = true;
7260               }
7261               break;
7262             }
7263           }
7264         }
7265         else if ( nbUniqueNodes == 6 && nbRepl == 4 ) {
7266           ////////////////// HEXAHEDRON ---> 2 tetrahedrons or 1 prism
7267           // find indices of quad and tri faces
7268           int iQuadFace[ 6 ], iTriFace[ 6 ], nbQuad = 0, nbTri = 0, iFace;
7269           for ( iFace = 0; iFace < 6; iFace++ ) {
7270             const int *ind = hexa.GetFaceNodesIndices( iFace ); // indices of face nodes
7271             nodeSet.clear();
7272             for ( iCur = 0; iCur < 4; iCur++ )
7273               nodeSet.insert( curNodes[ind[ iCur ]] );
7274             nbUniqueNodes = nodeSet.size();
7275             if ( nbUniqueNodes == 3 )
7276               iTriFace[ nbTri++ ] = iFace;
7277             else if ( nbUniqueNodes == 4 )
7278               iQuadFace[ nbQuad++ ] = iFace;
7279           }
7280           if (nbQuad == 2 && nbTri == 4 &&
7281               hexa.GetOppFaceIndex( iQuadFace[ 0 ] ) == iQuadFace[ 1 ]) {
7282             // 2 opposite quadrangles stuck with a diagonal;
7283             // sample groups of merged indices: (0-4)(2-6)
7284             // --------------------------------------------> 2 tetrahedrons
7285             const int *ind1 = hexa.GetFaceNodesIndices( iQuadFace[ 0 ]); // indices of quad1 nodes
7286             const int *ind2 = hexa.GetFaceNodesIndices( iQuadFace[ 1 ]);
7287             int i0, i1d, i2, i3d, i0t, i2t; // d-daigonal, t-top
7288             if (curNodes[ind1[ 0 ]] == curNodes[ind2[ 0 ]] &&
7289                 curNodes[ind1[ 2 ]] == curNodes[ind2[ 2 ]]) {
7290               // stuck with 0-2 diagonal
7291               i0  = ind1[ 3 ];
7292               i1d = ind1[ 0 ];
7293               i2  = ind1[ 1 ];
7294               i3d = ind1[ 2 ];
7295               i0t = ind2[ 1 ];
7296               i2t = ind2[ 3 ];
7297             }
7298             else if (curNodes[ind1[ 1 ]] == curNodes[ind2[ 3 ]] &&
7299                      curNodes[ind1[ 3 ]] == curNodes[ind2[ 1 ]]) {
7300               // stuck with 1-3 diagonal
7301               i0  = ind1[ 0 ];
7302               i1d = ind1[ 1 ];
7303               i2  = ind1[ 2 ];
7304               i3d = ind1[ 3 ];
7305               i0t = ind2[ 0 ];
7306               i2t = ind2[ 1 ];
7307             }
7308             else {
7309               ASSERT(0);
7310             }
7311             // tetrahedron 1
7312             uniqueNodes[ 0 ] = curNodes [ i0 ];
7313             uniqueNodes[ 1 ] = curNodes [ i1d ];
7314             uniqueNodes[ 2 ] = curNodes [ i3d ];
7315             uniqueNodes[ 3 ] = curNodes [ i0t ];
7316             nbUniqueNodes = 4;
7317             // tetrahedron 2
7318             SMDS_MeshElement* newElem = aMesh->AddVolume(curNodes[ i1d ],
7319                                                          curNodes[ i2 ],
7320                                                          curNodes[ i3d ],
7321                                                          curNodes[ i2t ]);
7322             myLastCreatedElems.Append(newElem);
7323             if ( aShapeId )
7324               aMesh->SetMeshElementOnShape( newElem, aShapeId );
7325             isOk = true;
7326           }
7327           else if (( nbTri == 2 && nbQuad == 3 ) || // merged (0-4)(1-5)
7328                    ( nbTri == 4 && nbQuad == 2 )) { // merged (7-4)(1-5)
7329             // --------------------------------------------> prism
7330             // find 2 opposite triangles
7331             nbUniqueNodes = 6;
7332             for ( iFace = 0; iFace + 1 < nbTri; iFace++ ) {
7333               if ( hexa.GetOppFaceIndex( iTriFace[ iFace ] ) == iTriFace[ iFace + 1 ]) {
7334                 // find indices of kept and replaced nodes
7335                 // and fill unique nodes of 2 opposite triangles
7336                 const int *ind1 = hexa.GetFaceNodesIndices( iTriFace[ iFace ]);
7337                 const int *ind2 = hexa.GetFaceNodesIndices( iTriFace[ iFace + 1 ]);
7338                 const SMDS_MeshNode** hexanodes = hexa.GetNodes();
7339                 // fill unique nodes
7340                 iUnique = 0;
7341                 isOk = true;
7342                 for ( iCur = 0; iCur < 4 && isOk; iCur++ ) {
7343                   const SMDS_MeshNode* n     = curNodes[ind1[ iCur ]];
7344                   const SMDS_MeshNode* nInit = hexanodes[ind1[ iCur ]];
7345                   if ( n == nInit ) {
7346                     // iCur of a linked node of the opposite face (make normals co-directed):
7347                     int iCurOpp = ( iCur == 1 || iCur == 3 ) ? 4 - iCur : iCur;
7348                     // check that correspondent corners of triangles are linked
7349                     if ( !hexa.IsLinked( ind1[ iCur ], ind2[ iCurOpp ] ))
7350                       isOk = false;
7351                     else {
7352                       uniqueNodes[ iUnique ] = n;
7353                       uniqueNodes[ iUnique + 3 ] = curNodes[ind2[ iCurOpp ]];
7354                       iUnique++;
7355                     }
7356                   }
7357                 }
7358                 break;
7359               }
7360             }
7361           }
7362         } // if ( nbUniqueNodes == 6 && nbRepl == 4 )
7363         break;
7364       } // HEXAHEDRON
7365
7366       default:
7367         isOk = false;
7368       } // switch ( nbNodes )
7369
7370     } // if ( nbNodes != nbUniqueNodes ) // some nodes stick
7371
7372     if ( isOk ) {
7373       if (elem->IsPoly() && elem->GetType() == SMDSAbs_Volume) {
7374         // Change nodes of polyedre
7375         const SMDS_PolyhedralVolumeOfNodes* aPolyedre =
7376           static_cast<const SMDS_PolyhedralVolumeOfNodes*>( elem );
7377         if (aPolyedre) {
7378           int nbFaces = aPolyedre->NbFaces();
7379
7380           vector<const SMDS_MeshNode *> poly_nodes;
7381           vector<int> quantities (nbFaces);
7382
7383           for (int iface = 1; iface <= nbFaces; iface++) {
7384             int inode, nbFaceNodes = aPolyedre->NbFaceNodes(iface);
7385             quantities[iface - 1] = nbFaceNodes;
7386
7387             for (inode = 1; inode <= nbFaceNodes; inode++) {
7388               const SMDS_MeshNode* curNode = aPolyedre->GetFaceNode(iface, inode);
7389
7390               TNodeNodeMap::iterator nnIt = nodeNodeMap.find( curNode );
7391               if (nnIt != nodeNodeMap.end()) { // curNode sticks
7392                 curNode = (*nnIt).second;
7393               }
7394               poly_nodes.push_back(curNode);
7395             }
7396           }
7397           aMesh->ChangePolyhedronNodes( elem, poly_nodes, quantities );
7398         }
7399       }
7400       else {
7401         // Change regular element or polygon
7402         aMesh->ChangeElementNodes( elem, & uniqueNodes[0], nbUniqueNodes );
7403       }
7404     }
7405     else {
7406       // Remove invalid regular element or invalid polygon
7407       rmElemIds.push_back( elem->GetID() );
7408     }
7409
7410   } // loop on elements
7411
7412   // Remove equal nodes and bad elements
7413
7414   Remove( rmNodeIds, true );
7415   Remove( rmElemIds, false );
7416
7417 }
7418
7419
7420 // ========================================================
7421 // class   : SortableElement
7422 // purpose : allow sorting elements basing on their nodes
7423 // ========================================================
7424 class SortableElement : public set <const SMDS_MeshElement*>
7425 {
7426 public:
7427
7428   SortableElement( const SMDS_MeshElement* theElem )
7429   {
7430     myElem = theElem;
7431     SMDS_ElemIteratorPtr nodeIt = theElem->nodesIterator();
7432     while ( nodeIt->more() )
7433       this->insert( nodeIt->next() );
7434   }
7435
7436   const SMDS_MeshElement* Get() const
7437   { return myElem; }
7438
7439   void Set(const SMDS_MeshElement* e) const
7440   { myElem = e; }
7441
7442
7443 private:
7444   mutable const SMDS_MeshElement* myElem;
7445 };
7446
7447 //=======================================================================
7448 //function : FindEqualElements
7449 //purpose  : Return list of group of elements built on the same nodes.
7450 //           Search among theElements or in the whole mesh if theElements is empty
7451 //=======================================================================
7452 void SMESH_MeshEditor::FindEqualElements(set<const SMDS_MeshElement*> & theElements,
7453                                          TListOfListOfElementsID &      theGroupsOfElementsID)
7454 {
7455   myLastCreatedElems.Clear();
7456   myLastCreatedNodes.Clear();
7457
7458   typedef set<const SMDS_MeshElement*> TElemsSet;
7459   typedef map< SortableElement, int > TMapOfNodeSet;
7460   typedef list<int> TGroupOfElems;
7461
7462   TElemsSet elems;
7463   if ( theElements.empty() )
7464   { // get all elements in the mesh
7465     SMDS_ElemIteratorPtr eIt = GetMeshDS()->elementsIterator();
7466     while ( eIt->more() )
7467       elems.insert( elems.end(), eIt->next());
7468   }
7469   else
7470     elems = theElements;
7471
7472   vector< TGroupOfElems > arrayOfGroups;
7473   TGroupOfElems groupOfElems;
7474   TMapOfNodeSet mapOfNodeSet;
7475
7476   TElemsSet::iterator elemIt = elems.begin();
7477   for ( int i = 0, j=0; elemIt != elems.end(); ++elemIt, ++j ) {
7478     const SMDS_MeshElement* curElem = *elemIt;
7479     SortableElement SE(curElem);
7480     int ind = -1;
7481     // check uniqueness
7482     pair< TMapOfNodeSet::iterator, bool> pp = mapOfNodeSet.insert(make_pair(SE, i));
7483     if( !(pp.second) ) {
7484       TMapOfNodeSet::iterator& itSE = pp.first;
7485       ind = (*itSE).second;
7486       arrayOfGroups[ind].push_back(curElem->GetID());
7487     }
7488     else {
7489       groupOfElems.clear();
7490       groupOfElems.push_back(curElem->GetID());
7491       arrayOfGroups.push_back(groupOfElems);
7492       i++;
7493     }
7494   }
7495
7496   vector< TGroupOfElems >::iterator groupIt = arrayOfGroups.begin();
7497   for ( ; groupIt != arrayOfGroups.end(); ++groupIt ) {
7498     groupOfElems = *groupIt;
7499     if ( groupOfElems.size() > 1 ) {
7500       groupOfElems.sort();
7501       theGroupsOfElementsID.push_back(groupOfElems);
7502     }
7503   }
7504 }
7505
7506 //=======================================================================
7507 //function : MergeElements
7508 //purpose  : In each given group, substitute all elements by the first one.
7509 //=======================================================================
7510
7511 void SMESH_MeshEditor::MergeElements(TListOfListOfElementsID & theGroupsOfElementsID)
7512 {
7513   myLastCreatedElems.Clear();
7514   myLastCreatedNodes.Clear();
7515
7516   typedef list<int> TListOfIDs;
7517   TListOfIDs rmElemIds; // IDs of elems to remove
7518
7519   SMESHDS_Mesh* aMesh = GetMeshDS();
7520
7521   TListOfListOfElementsID::iterator groupsIt = theGroupsOfElementsID.begin();
7522   while ( groupsIt != theGroupsOfElementsID.end() ) {
7523     TListOfIDs& aGroupOfElemID = *groupsIt;
7524     aGroupOfElemID.sort();
7525     int elemIDToKeep = aGroupOfElemID.front();
7526     const SMDS_MeshElement* elemToKeep = aMesh->FindElement(elemIDToKeep);
7527     aGroupOfElemID.pop_front();
7528     TListOfIDs::iterator idIt = aGroupOfElemID.begin();
7529     while ( idIt != aGroupOfElemID.end() ) {
7530       int elemIDToRemove = *idIt;
7531       const SMDS_MeshElement* elemToRemove = aMesh->FindElement(elemIDToRemove);
7532       // add the kept element in groups of removed one (PAL15188)
7533       AddToSameGroups( elemToKeep, elemToRemove, aMesh );
7534       rmElemIds.push_back( elemIDToRemove );
7535       ++idIt;
7536     }
7537     ++groupsIt;
7538   }
7539
7540   Remove( rmElemIds, false );
7541 }
7542
7543 //=======================================================================
7544 //function : MergeEqualElements
7545 //purpose  : Remove all but one of elements built on the same nodes.
7546 //=======================================================================
7547
7548 void SMESH_MeshEditor::MergeEqualElements()
7549 {
7550   set<const SMDS_MeshElement*> aMeshElements; /* empty input -
7551                                                  to merge equal elements in the whole mesh */
7552   TListOfListOfElementsID aGroupsOfElementsID;
7553   FindEqualElements(aMeshElements, aGroupsOfElementsID);
7554   MergeElements(aGroupsOfElementsID);
7555 }
7556
7557 //=======================================================================
7558 //function : FindFaceInSet
7559 //purpose  : Return a face having linked nodes n1 and n2 and which is
7560 //           - not in avoidSet,
7561 //           - in elemSet provided that !elemSet.empty()
7562 //           i1 and i2 optionally returns indices of n1 and n2
7563 //=======================================================================
7564
7565 const SMDS_MeshElement*
7566 SMESH_MeshEditor::FindFaceInSet(const SMDS_MeshNode*    n1,
7567                                 const SMDS_MeshNode*    n2,
7568                                 const TIDSortedElemSet& elemSet,
7569                                 const TIDSortedElemSet& avoidSet,
7570                                 int*                    n1ind,
7571                                 int*                    n2ind)
7572
7573 {
7574   int i1, i2;
7575   const SMDS_MeshElement* face = 0;
7576
7577   SMDS_ElemIteratorPtr invElemIt = n1->GetInverseElementIterator(SMDSAbs_Face);
7578   while ( invElemIt->more() && !face ) // loop on inverse faces of n1
7579   {
7580     const SMDS_MeshElement* elem = invElemIt->next();
7581     if (avoidSet.count( elem ))
7582       continue;
7583     if ( !elemSet.empty() && !elemSet.count( elem ))
7584       continue;
7585     // index of n1
7586     i1 = elem->GetNodeIndex( n1 );
7587     // find a n2 linked to n1
7588     int nbN = elem->IsQuadratic() ? elem->NbNodes()/2 : elem->NbNodes();
7589     for ( int di = -1; di < 2 && !face; di += 2 )
7590     {
7591       i2 = (i1+di+nbN) % nbN;
7592       if ( elem->GetNode( i2 ) == n2 )
7593         face = elem;
7594     }
7595     if ( !face && elem->IsQuadratic())
7596     {
7597       // analysis for quadratic elements using all nodes
7598       const SMDS_QuadraticFaceOfNodes* F =
7599         static_cast<const SMDS_QuadraticFaceOfNodes*>(elem);
7600       // use special nodes iterator
7601       SMDS_NodeIteratorPtr anIter = F->interlacedNodesIterator();
7602       const SMDS_MeshNode* prevN = cast2Node( anIter->next() );
7603       for ( i1 = -1, i2 = 0; anIter->more() && !face; i1++, i2++ )
7604       {
7605         const SMDS_MeshNode* n = cast2Node( anIter->next() );
7606         if ( n1 == prevN && n2 == n )
7607         {
7608           face = elem;
7609         }
7610         else if ( n2 == prevN && n1 == n )
7611         {
7612           face = elem; swap( i1, i2 );
7613         }
7614         prevN = n;
7615       }
7616     }
7617   }
7618   if ( n1ind ) *n1ind = i1;
7619   if ( n2ind ) *n2ind = i2;
7620   return face;
7621 }
7622
7623 //=======================================================================
7624 //function : findAdjacentFace
7625 //purpose  :
7626 //=======================================================================
7627
7628 static const SMDS_MeshElement* findAdjacentFace(const SMDS_MeshNode* n1,
7629                                                 const SMDS_MeshNode* n2,
7630                                                 const SMDS_MeshElement* elem)
7631 {
7632   TIDSortedElemSet elemSet, avoidSet;
7633   if ( elem )
7634     avoidSet.insert ( elem );
7635   return SMESH_MeshEditor::FindFaceInSet( n1, n2, elemSet, avoidSet );
7636 }
7637
7638 //=======================================================================
7639 //function : FindFreeBorder
7640 //purpose  :
7641 //=======================================================================
7642
7643 #define ControlFreeBorder SMESH::Controls::FreeEdges::IsFreeEdge
7644
7645 bool SMESH_MeshEditor::FindFreeBorder (const SMDS_MeshNode*             theFirstNode,
7646                                        const SMDS_MeshNode*             theSecondNode,
7647                                        const SMDS_MeshNode*             theLastNode,
7648                                        list< const SMDS_MeshNode* > &   theNodes,
7649                                        list< const SMDS_MeshElement* >& theFaces)
7650 {
7651   if ( !theFirstNode || !theSecondNode )
7652     return false;
7653   // find border face between theFirstNode and theSecondNode
7654   const SMDS_MeshElement* curElem = findAdjacentFace( theFirstNode, theSecondNode, 0 );
7655   if ( !curElem )
7656     return false;
7657
7658   theFaces.push_back( curElem );
7659   theNodes.push_back( theFirstNode );
7660   theNodes.push_back( theSecondNode );
7661
7662   //vector<const SMDS_MeshNode*> nodes;
7663   const SMDS_MeshNode *nIgnore = theFirstNode, *nStart = theSecondNode;
7664   TIDSortedElemSet foundElems;
7665   bool needTheLast = ( theLastNode != 0 );
7666
7667   while ( nStart != theLastNode ) {
7668     if ( nStart == theFirstNode )
7669       return !needTheLast;
7670
7671     // find all free border faces sharing form nStart
7672
7673     list< const SMDS_MeshElement* > curElemList;
7674     list< const SMDS_MeshNode* > nStartList;
7675     SMDS_ElemIteratorPtr invElemIt = nStart->GetInverseElementIterator(SMDSAbs_Face);
7676     while ( invElemIt->more() ) {
7677       const SMDS_MeshElement* e = invElemIt->next();
7678       if ( e == curElem || foundElems.insert( e ).second ) {
7679         // get nodes
7680         int iNode = 0, nbNodes = e->NbNodes();
7681         //const SMDS_MeshNode* nodes[nbNodes+1];
7682         vector<const SMDS_MeshNode*> nodes(nbNodes+1);
7683
7684         if(e->IsQuadratic()) {
7685           const SMDS_QuadraticFaceOfNodes* F =
7686             static_cast<const SMDS_QuadraticFaceOfNodes*>(e);
7687           // use special nodes iterator
7688           SMDS_NodeIteratorPtr anIter = F->interlacedNodesIterator();
7689           while( anIter->more() ) {
7690             nodes[ iNode++ ] = anIter->next();
7691           }
7692         }
7693         else {
7694           SMDS_ElemIteratorPtr nIt = e->nodesIterator();
7695           while ( nIt->more() )
7696             nodes[ iNode++ ] = static_cast<const SMDS_MeshNode*>( nIt->next() );
7697         }
7698         nodes[ iNode ] = nodes[ 0 ];
7699         // check 2 links
7700         for ( iNode = 0; iNode < nbNodes; iNode++ )
7701           if (((nodes[ iNode ] == nStart && nodes[ iNode + 1] != nIgnore ) ||
7702                (nodes[ iNode + 1] == nStart && nodes[ iNode ] != nIgnore )) &&
7703               ControlFreeBorder( &nodes[ iNode ], e->GetID() ))
7704           {
7705             nStartList.push_back( nodes[ iNode + ( nodes[ iNode ] == nStart ? 1 : 0 )]);
7706             curElemList.push_back( e );
7707           }
7708       }
7709     }
7710     // analyse the found
7711
7712     int nbNewBorders = curElemList.size();
7713     if ( nbNewBorders == 0 ) {
7714       // no free border furthermore
7715       return !needTheLast;
7716     }
7717     else if ( nbNewBorders == 1 ) {
7718       // one more element found
7719       nIgnore = nStart;
7720       nStart = nStartList.front();
7721       curElem = curElemList.front();
7722       theFaces.push_back( curElem );
7723       theNodes.push_back( nStart );
7724     }
7725     else {
7726       // several continuations found
7727       list< const SMDS_MeshElement* >::iterator curElemIt;
7728       list< const SMDS_MeshNode* >::iterator nStartIt;
7729       // check if one of them reached the last node
7730       if ( needTheLast ) {
7731         for (curElemIt = curElemList.begin(), nStartIt = nStartList.begin();
7732              curElemIt!= curElemList.end();
7733              curElemIt++, nStartIt++ )
7734           if ( *nStartIt == theLastNode ) {
7735             theFaces.push_back( *curElemIt );
7736             theNodes.push_back( *nStartIt );
7737             return true;
7738           }
7739       }
7740       // find the best free border by the continuations
7741       list<const SMDS_MeshNode*>    contNodes[ 2 ], *cNL;
7742       list<const SMDS_MeshElement*> contFaces[ 2 ], *cFL;
7743       for (curElemIt = curElemList.begin(), nStartIt = nStartList.begin();
7744            curElemIt!= curElemList.end();
7745            curElemIt++, nStartIt++ )
7746       {
7747         cNL = & contNodes[ contNodes[0].empty() ? 0 : 1 ];
7748         cFL = & contFaces[ contFaces[0].empty() ? 0 : 1 ];
7749         // find one more free border
7750         if ( ! FindFreeBorder( nStart, *nStartIt, theLastNode, *cNL, *cFL )) {
7751           cNL->clear();
7752           cFL->clear();
7753         }
7754         else if ( !contNodes[0].empty() && !contNodes[1].empty() ) {
7755           // choice: clear a worse one
7756           int iLongest = ( contNodes[0].size() < contNodes[1].size() ? 1 : 0 );
7757           int iWorse = ( needTheLast ? 1 - iLongest : iLongest );
7758           contNodes[ iWorse ].clear();
7759           contFaces[ iWorse ].clear();
7760         }
7761       }
7762       if ( contNodes[0].empty() && contNodes[1].empty() )
7763         return false;
7764
7765       // append the best free border
7766       cNL = & contNodes[ contNodes[0].empty() ? 1 : 0 ];
7767       cFL = & contFaces[ contFaces[0].empty() ? 1 : 0 ];
7768       theNodes.pop_back(); // remove nIgnore
7769       theNodes.pop_back(); // remove nStart
7770       theFaces.pop_back(); // remove curElem
7771       list< const SMDS_MeshNode* >::iterator nIt = cNL->begin();
7772       list< const SMDS_MeshElement* >::iterator fIt = cFL->begin();
7773       for ( ; nIt != cNL->end(); nIt++ ) theNodes.push_back( *nIt );
7774       for ( ; fIt != cFL->end(); fIt++ ) theFaces.push_back( *fIt );
7775       return true;
7776
7777     } // several continuations found
7778   } // while ( nStart != theLastNode )
7779
7780   return true;
7781 }
7782
7783 //=======================================================================
7784 //function : CheckFreeBorderNodes
7785 //purpose  : Return true if the tree nodes are on a free border
7786 //=======================================================================
7787
7788 bool SMESH_MeshEditor::CheckFreeBorderNodes(const SMDS_MeshNode* theNode1,
7789                                             const SMDS_MeshNode* theNode2,
7790                                             const SMDS_MeshNode* theNode3)
7791 {
7792   list< const SMDS_MeshNode* > nodes;
7793   list< const SMDS_MeshElement* > faces;
7794   return FindFreeBorder( theNode1, theNode2, theNode3, nodes, faces);
7795 }
7796
7797 //=======================================================================
7798 //function : SewFreeBorder
7799 //purpose  :
7800 //=======================================================================
7801
7802 SMESH_MeshEditor::Sew_Error
7803 SMESH_MeshEditor::SewFreeBorder (const SMDS_MeshNode* theBordFirstNode,
7804                                  const SMDS_MeshNode* theBordSecondNode,
7805                                  const SMDS_MeshNode* theBordLastNode,
7806                                  const SMDS_MeshNode* theSideFirstNode,
7807                                  const SMDS_MeshNode* theSideSecondNode,
7808                                  const SMDS_MeshNode* theSideThirdNode,
7809                                  const bool           theSideIsFreeBorder,
7810                                  const bool           toCreatePolygons,
7811                                  const bool           toCreatePolyedrs)
7812 {
7813   myLastCreatedElems.Clear();
7814   myLastCreatedNodes.Clear();
7815
7816   MESSAGE("::SewFreeBorder()");
7817   Sew_Error aResult = SEW_OK;
7818
7819   // ====================================
7820   //    find side nodes and elements
7821   // ====================================
7822
7823   list< const SMDS_MeshNode* > nSide[ 2 ];
7824   list< const SMDS_MeshElement* > eSide[ 2 ];
7825   list< const SMDS_MeshNode* >::iterator nIt[ 2 ];
7826   list< const SMDS_MeshElement* >::iterator eIt[ 2 ];
7827
7828   // Free border 1
7829   // --------------
7830   if (!FindFreeBorder(theBordFirstNode,theBordSecondNode,theBordLastNode,
7831                       nSide[0], eSide[0])) {
7832     MESSAGE(" Free Border 1 not found " );
7833     aResult = SEW_BORDER1_NOT_FOUND;
7834   }
7835   if (theSideIsFreeBorder) {
7836     // Free border 2
7837     // --------------
7838     if (!FindFreeBorder(theSideFirstNode, theSideSecondNode, theSideThirdNode,
7839                         nSide[1], eSide[1])) {
7840       MESSAGE(" Free Border 2 not found " );
7841       aResult = ( aResult != SEW_OK ? SEW_BOTH_BORDERS_NOT_FOUND : SEW_BORDER2_NOT_FOUND );
7842     }
7843   }
7844   if ( aResult != SEW_OK )
7845     return aResult;
7846
7847   if (!theSideIsFreeBorder) {
7848     // Side 2
7849     // --------------
7850
7851     // -------------------------------------------------------------------------
7852     // Algo:
7853     // 1. If nodes to merge are not coincident, move nodes of the free border
7854     //    from the coord sys defined by the direction from the first to last
7855     //    nodes of the border to the correspondent sys of the side 2
7856     // 2. On the side 2, find the links most co-directed with the correspondent
7857     //    links of the free border
7858     // -------------------------------------------------------------------------
7859
7860     // 1. Since sewing may brake if there are volumes to split on the side 2,
7861     //    we wont move nodes but just compute new coordinates for them
7862     typedef map<const SMDS_MeshNode*, gp_XYZ> TNodeXYZMap;
7863     TNodeXYZMap nBordXYZ;
7864     list< const SMDS_MeshNode* >& bordNodes = nSide[ 0 ];
7865     list< const SMDS_MeshNode* >::iterator nBordIt;
7866
7867     gp_XYZ Pb1( theBordFirstNode->X(), theBordFirstNode->Y(), theBordFirstNode->Z() );
7868     gp_XYZ Pb2( theBordLastNode->X(), theBordLastNode->Y(), theBordLastNode->Z() );
7869     gp_XYZ Ps1( theSideFirstNode->X(), theSideFirstNode->Y(), theSideFirstNode->Z() );
7870     gp_XYZ Ps2( theSideSecondNode->X(), theSideSecondNode->Y(), theSideSecondNode->Z() );
7871     double tol2 = 1.e-8;
7872     gp_Vec Vbs1( Pb1 - Ps1 ),Vbs2( Pb2 - Ps2 );
7873     if ( Vbs1.SquareMagnitude() > tol2 || Vbs2.SquareMagnitude() > tol2 ) {
7874       // Need node movement.
7875
7876       // find X and Z axes to create trsf
7877       gp_Vec Zb( Pb1 - Pb2 ), Zs( Ps1 - Ps2 );
7878       gp_Vec X = Zs ^ Zb;
7879       if ( X.SquareMagnitude() <= gp::Resolution() * gp::Resolution() )
7880         // Zb || Zs
7881         X = gp_Ax2( gp::Origin(), Zb ).XDirection();
7882
7883       // coord systems
7884       gp_Ax3 toBordAx( Pb1, Zb, X );
7885       gp_Ax3 fromSideAx( Ps1, Zs, X );
7886       gp_Ax3 toGlobalAx( gp::Origin(), gp::DZ(), gp::DX() );
7887       // set trsf
7888       gp_Trsf toBordSys, fromSide2Sys;
7889       toBordSys.SetTransformation( toBordAx );
7890       fromSide2Sys.SetTransformation( fromSideAx, toGlobalAx );
7891       fromSide2Sys.SetScaleFactor( Zs.Magnitude() / Zb.Magnitude() );
7892
7893       // move
7894       for ( nBordIt = bordNodes.begin(); nBordIt != bordNodes.end(); nBordIt++ ) {
7895         const SMDS_MeshNode* n = *nBordIt;
7896         gp_XYZ xyz( n->X(),n->Y(),n->Z() );
7897         toBordSys.Transforms( xyz );
7898         fromSide2Sys.Transforms( xyz );
7899         nBordXYZ.insert( TNodeXYZMap::value_type( n, xyz ));
7900       }
7901     }
7902     else {
7903       // just insert nodes XYZ in the nBordXYZ map
7904       for ( nBordIt = bordNodes.begin(); nBordIt != bordNodes.end(); nBordIt++ ) {
7905         const SMDS_MeshNode* n = *nBordIt;
7906         nBordXYZ.insert( TNodeXYZMap::value_type( n, gp_XYZ( n->X(),n->Y(),n->Z() )));
7907       }
7908     }
7909
7910     // 2. On the side 2, find the links most co-directed with the correspondent
7911     //    links of the free border
7912
7913     list< const SMDS_MeshElement* >& sideElems = eSide[ 1 ];
7914     list< const SMDS_MeshNode* >& sideNodes = nSide[ 1 ];
7915     sideNodes.push_back( theSideFirstNode );
7916
7917     bool hasVolumes = false;
7918     LinkID_Gen aLinkID_Gen( GetMeshDS() );
7919     set<long> foundSideLinkIDs, checkedLinkIDs;
7920     SMDS_VolumeTool volume;
7921     //const SMDS_MeshNode* faceNodes[ 4 ];
7922
7923     const SMDS_MeshNode*    sideNode;
7924     const SMDS_MeshElement* sideElem;
7925     const SMDS_MeshNode* prevSideNode = theSideFirstNode;
7926     const SMDS_MeshNode* prevBordNode = theBordFirstNode;
7927     nBordIt = bordNodes.begin();
7928     nBordIt++;
7929     // border node position and border link direction to compare with
7930     gp_XYZ bordPos = nBordXYZ[ *nBordIt ];
7931     gp_XYZ bordDir = bordPos - nBordXYZ[ prevBordNode ];
7932     // choose next side node by link direction or by closeness to
7933     // the current border node:
7934     bool searchByDir = ( *nBordIt != theBordLastNode );
7935     do {
7936       // find the next node on the Side 2
7937       sideNode = 0;
7938       double maxDot = -DBL_MAX, minDist = DBL_MAX;
7939       long linkID;
7940       checkedLinkIDs.clear();
7941       gp_XYZ prevXYZ( prevSideNode->X(), prevSideNode->Y(), prevSideNode->Z() );
7942
7943       // loop on inverse elements of current node (prevSideNode) on the Side 2
7944       SMDS_ElemIteratorPtr invElemIt = prevSideNode->GetInverseElementIterator();
7945       while ( invElemIt->more() )
7946       {
7947         const SMDS_MeshElement* elem = invElemIt->next();
7948         // prepare data for a loop on links coming to prevSideNode, of a face or a volume
7949         int iPrevNode, iNode = 0, nbNodes = elem->NbNodes();
7950         vector< const SMDS_MeshNode* > faceNodes( nbNodes, (const SMDS_MeshNode*)0 );
7951         bool isVolume = volume.Set( elem );
7952         const SMDS_MeshNode** nodes = isVolume ? volume.GetNodes() : & faceNodes[0];
7953         if ( isVolume ) // --volume
7954           hasVolumes = true;
7955         else if ( elem->GetType()==SMDSAbs_Face ) { // --face
7956           // retrieve all face nodes and find iPrevNode - an index of the prevSideNode
7957           if(elem->IsQuadratic()) {
7958             const SMDS_QuadraticFaceOfNodes* F =
7959               static_cast<const SMDS_QuadraticFaceOfNodes*>(elem);
7960             // use special nodes iterator
7961             SMDS_NodeIteratorPtr anIter = F->interlacedNodesIterator();
7962             while( anIter->more() ) {
7963               nodes[ iNode ] = anIter->next();
7964               if ( nodes[ iNode++ ] == prevSideNode )
7965                 iPrevNode = iNode - 1;
7966             }
7967           }
7968           else {
7969             SMDS_ElemIteratorPtr nIt = elem->nodesIterator();
7970             while ( nIt->more() ) {
7971               nodes[ iNode ] = cast2Node( nIt->next() );
7972               if ( nodes[ iNode++ ] == prevSideNode )
7973                 iPrevNode = iNode - 1;
7974             }
7975           }
7976           // there are 2 links to check
7977           nbNodes = 2;
7978         }
7979         else // --edge
7980           continue;
7981         // loop on links, to be precise, on the second node of links
7982         for ( iNode = 0; iNode < nbNodes; iNode++ ) {
7983           const SMDS_MeshNode* n = nodes[ iNode ];
7984           if ( isVolume ) {
7985             if ( !volume.IsLinked( n, prevSideNode ))
7986               continue;
7987           }
7988           else {
7989             if ( iNode ) // a node before prevSideNode
7990               n = nodes[ iPrevNode == 0 ? elem->NbNodes() - 1 : iPrevNode - 1 ];
7991             else         // a node after prevSideNode
7992               n = nodes[ iPrevNode + 1 == elem->NbNodes() ? 0 : iPrevNode + 1 ];
7993           }
7994           // check if this link was already used
7995           long iLink = aLinkID_Gen.GetLinkID( prevSideNode, n );
7996           bool isJustChecked = !checkedLinkIDs.insert( iLink ).second;
7997           if (!isJustChecked &&
7998               foundSideLinkIDs.find( iLink ) == foundSideLinkIDs.end() )
7999           {
8000             // test a link geometrically
8001             gp_XYZ nextXYZ ( n->X(), n->Y(), n->Z() );
8002             bool linkIsBetter = false;
8003             double dot = 0.0, dist = 0.0;
8004             if ( searchByDir ) { // choose most co-directed link
8005               dot = bordDir * ( nextXYZ - prevXYZ ).Normalized();
8006               linkIsBetter = ( dot > maxDot );
8007             }
8008             else { // choose link with the node closest to bordPos
8009               dist = ( nextXYZ - bordPos ).SquareModulus();
8010               linkIsBetter = ( dist < minDist );
8011             }
8012             if ( linkIsBetter ) {
8013               maxDot = dot;
8014               minDist = dist;
8015               linkID = iLink;
8016               sideNode = n;
8017               sideElem = elem;
8018             }
8019           }
8020         }
8021       } // loop on inverse elements of prevSideNode
8022
8023       if ( !sideNode ) {
8024         MESSAGE(" Cant find path by links of the Side 2 ");
8025         return SEW_BAD_SIDE_NODES;
8026       }
8027       sideNodes.push_back( sideNode );
8028       sideElems.push_back( sideElem );
8029       foundSideLinkIDs.insert ( linkID );
8030       prevSideNode = sideNode;
8031
8032       if ( *nBordIt == theBordLastNode )
8033         searchByDir = false;
8034       else {
8035         // find the next border link to compare with
8036         gp_XYZ sidePos( sideNode->X(), sideNode->Y(), sideNode->Z() );
8037         searchByDir = ( bordDir * ( sidePos - bordPos ) <= 0 );
8038         // move to next border node if sideNode is before forward border node (bordPos)
8039         while ( *nBordIt != theBordLastNode && !searchByDir ) {
8040           prevBordNode = *nBordIt;
8041           nBordIt++;
8042           bordPos = nBordXYZ[ *nBordIt ];
8043           bordDir = bordPos - nBordXYZ[ prevBordNode ];
8044           searchByDir = ( bordDir * ( sidePos - bordPos ) <= 0 );
8045         }
8046       }
8047     }
8048     while ( sideNode != theSideSecondNode );
8049
8050     if ( hasVolumes && sideNodes.size () != bordNodes.size() && !toCreatePolyedrs) {
8051       MESSAGE("VOLUME SPLITTING IS FORBIDDEN");
8052       return SEW_VOLUMES_TO_SPLIT; // volume splitting is forbidden
8053     }
8054   } // end nodes search on the side 2
8055
8056   // ============================
8057   // sew the border to the side 2
8058   // ============================
8059
8060   int nbNodes[]  = { nSide[0].size(), nSide[1].size() };
8061   int maxNbNodes = Max( nbNodes[0], nbNodes[1] );
8062
8063   TListOfListOfNodes nodeGroupsToMerge;
8064   if ( nbNodes[0] == nbNodes[1] ||
8065        ( theSideIsFreeBorder && !theSideThirdNode)) {
8066
8067     // all nodes are to be merged
8068
8069     for (nIt[0] = nSide[0].begin(), nIt[1] = nSide[1].begin();
8070          nIt[0] != nSide[0].end() && nIt[1] != nSide[1].end();
8071          nIt[0]++, nIt[1]++ )
8072     {
8073       nodeGroupsToMerge.push_back( list<const SMDS_MeshNode*>() );
8074       nodeGroupsToMerge.back().push_back( *nIt[1] ); // to keep
8075       nodeGroupsToMerge.back().push_back( *nIt[0] ); // to remove
8076     }
8077   }
8078   else {
8079
8080     // insert new nodes into the border and the side to get equal nb of segments
8081
8082     // get normalized parameters of nodes on the borders
8083     //double param[ 2 ][ maxNbNodes ];
8084     double* param[ 2 ];
8085     param[0] = new double [ maxNbNodes ];
8086     param[1] = new double [ maxNbNodes ];
8087     int iNode, iBord;
8088     for ( iBord = 0; iBord < 2; iBord++ ) { // loop on 2 borders
8089       list< const SMDS_MeshNode* >& nodes = nSide[ iBord ];
8090       list< const SMDS_MeshNode* >::iterator nIt = nodes.begin();
8091       const SMDS_MeshNode* nPrev = *nIt;
8092       double bordLength = 0;
8093       for ( iNode = 0; nIt != nodes.end(); nIt++, iNode++ ) { // loop on border nodes
8094         const SMDS_MeshNode* nCur = *nIt;
8095         gp_XYZ segment (nCur->X() - nPrev->X(),
8096                         nCur->Y() - nPrev->Y(),
8097                         nCur->Z() - nPrev->Z());
8098         double segmentLen = segment.Modulus();
8099         bordLength += segmentLen;
8100         param[ iBord ][ iNode ] = bordLength;
8101         nPrev = nCur;
8102       }
8103       // normalize within [0,1]
8104       for ( iNode = 0; iNode < nbNodes[ iBord ]; iNode++ ) {
8105         param[ iBord ][ iNode ] /= bordLength;
8106       }
8107     }
8108
8109     // loop on border segments
8110     const SMDS_MeshNode *nPrev[ 2 ] = { 0, 0 };
8111     int i[ 2 ] = { 0, 0 };
8112     nIt[0] = nSide[0].begin(); eIt[0] = eSide[0].begin();
8113     nIt[1] = nSide[1].begin(); eIt[1] = eSide[1].begin();
8114
8115     TElemOfNodeListMap insertMap;
8116     TElemOfNodeListMap::iterator insertMapIt;
8117     // insertMap is
8118     // key:   elem to insert nodes into
8119     // value: 2 nodes to insert between + nodes to be inserted
8120     do {
8121       bool next[ 2 ] = { false, false };
8122
8123       // find min adjacent segment length after sewing
8124       double nextParam = 10., prevParam = 0;
8125       for ( iBord = 0; iBord < 2; iBord++ ) { // loop on 2 borders
8126         if ( i[ iBord ] + 1 < nbNodes[ iBord ])
8127           nextParam = Min( nextParam, param[iBord][ i[iBord] + 1 ]);
8128         if ( i[ iBord ] > 0 )
8129           prevParam = Max( prevParam, param[iBord][ i[iBord] - 1 ]);
8130       }
8131       double minParam = Min( param[ 0 ][ i[0] ], param[ 1 ][ i[1] ]);
8132       double maxParam = Max( param[ 0 ][ i[0] ], param[ 1 ][ i[1] ]);
8133       double minSegLen = Min( nextParam - minParam, maxParam - prevParam );
8134
8135       // choose to insert or to merge nodes
8136       double du = param[ 1 ][ i[1] ] - param[ 0 ][ i[0] ];
8137       if ( Abs( du ) <= minSegLen * 0.2 ) {
8138         // merge
8139         // ------
8140         nodeGroupsToMerge.push_back( list<const SMDS_MeshNode*>() );
8141         const SMDS_MeshNode* n0 = *nIt[0];
8142         const SMDS_MeshNode* n1 = *nIt[1];
8143         nodeGroupsToMerge.back().push_back( n1 );
8144         nodeGroupsToMerge.back().push_back( n0 );
8145         // position of node of the border changes due to merge
8146         param[ 0 ][ i[0] ] += du;
8147         // move n1 for the sake of elem shape evaluation during insertion.
8148         // n1 will be removed by MergeNodes() anyway
8149         const_cast<SMDS_MeshNode*>( n0 )->setXYZ( n1->X(), n1->Y(), n1->Z() );
8150         next[0] = next[1] = true;
8151       }
8152       else {
8153         // insert
8154         // ------
8155         int intoBord = ( du < 0 ) ? 0 : 1;
8156         const SMDS_MeshElement* elem = *eIt[ intoBord ];
8157         const SMDS_MeshNode*    n1   = nPrev[ intoBord ];
8158         const SMDS_MeshNode*    n2   = *nIt[ intoBord ];
8159         const SMDS_MeshNode*    nIns = *nIt[ 1 - intoBord ];
8160         if ( intoBord == 1 ) {
8161           // move node of the border to be on a link of elem of the side
8162           gp_XYZ p1 (n1->X(), n1->Y(), n1->Z());
8163           gp_XYZ p2 (n2->X(), n2->Y(), n2->Z());
8164           double ratio = du / ( param[ 1 ][ i[1] ] - param[ 1 ][ i[1]-1 ]);
8165           gp_XYZ p = p2 * ( 1 - ratio ) + p1 * ratio;
8166           GetMeshDS()->MoveNode( nIns, p.X(), p.Y(), p.Z() );
8167         }
8168         insertMapIt = insertMap.find( elem );
8169         bool notFound = ( insertMapIt == insertMap.end() );
8170         bool otherLink = ( !notFound && (*insertMapIt).second.front() != n1 );
8171         if ( otherLink ) {
8172           // insert into another link of the same element:
8173           // 1. perform insertion into the other link of the elem
8174           list<const SMDS_MeshNode*> & nodeList = (*insertMapIt).second;
8175           const SMDS_MeshNode* n12 = nodeList.front(); nodeList.pop_front();
8176           const SMDS_MeshNode* n22 = nodeList.front(); nodeList.pop_front();
8177           InsertNodesIntoLink( elem, n12, n22, nodeList, toCreatePolygons );
8178           // 2. perform insertion into the link of adjacent faces
8179           while (true) {
8180             const SMDS_MeshElement* adjElem = findAdjacentFace( n12, n22, elem );
8181             if ( adjElem )
8182               InsertNodesIntoLink( adjElem, n12, n22, nodeList, toCreatePolygons );
8183             else
8184               break;
8185           }
8186           if (toCreatePolyedrs) {
8187             // perform insertion into the links of adjacent volumes
8188             UpdateVolumes(n12, n22, nodeList);
8189           }
8190           // 3. find an element appeared on n1 and n2 after the insertion
8191           insertMap.erase( elem );
8192           elem = findAdjacentFace( n1, n2, 0 );
8193         }
8194         if ( notFound || otherLink ) {
8195           // add element and nodes of the side into the insertMap
8196           insertMapIt = insertMap.insert
8197             ( TElemOfNodeListMap::value_type( elem, list<const SMDS_MeshNode*>() )).first;
8198           (*insertMapIt).second.push_back( n1 );
8199           (*insertMapIt).second.push_back( n2 );
8200         }
8201         // add node to be inserted into elem
8202         (*insertMapIt).second.push_back( nIns );
8203         next[ 1 - intoBord ] = true;
8204       }
8205
8206       // go to the next segment
8207       for ( iBord = 0; iBord < 2; iBord++ ) { // loop on 2 borders
8208         if ( next[ iBord ] ) {
8209           if ( i[ iBord ] != 0 && eIt[ iBord ] != eSide[ iBord ].end())
8210             eIt[ iBord ]++;
8211           nPrev[ iBord ] = *nIt[ iBord ];
8212           nIt[ iBord ]++; i[ iBord ]++;
8213         }
8214       }
8215     }
8216     while ( nIt[0] != nSide[0].end() && nIt[1] != nSide[1].end());
8217
8218     // perform insertion of nodes into elements
8219
8220     for (insertMapIt = insertMap.begin();
8221          insertMapIt != insertMap.end();
8222          insertMapIt++ )
8223     {
8224       const SMDS_MeshElement* elem = (*insertMapIt).first;
8225       list<const SMDS_MeshNode*> & nodeList = (*insertMapIt).second;
8226       const SMDS_MeshNode* n1 = nodeList.front(); nodeList.pop_front();
8227       const SMDS_MeshNode* n2 = nodeList.front(); nodeList.pop_front();
8228
8229       InsertNodesIntoLink( elem, n1, n2, nodeList, toCreatePolygons );
8230
8231       if ( !theSideIsFreeBorder ) {
8232         // look for and insert nodes into the faces adjacent to elem
8233         while (true) {
8234           const SMDS_MeshElement* adjElem = findAdjacentFace( n1, n2, elem );
8235           if ( adjElem )
8236             InsertNodesIntoLink( adjElem, n1, n2, nodeList, toCreatePolygons );
8237           else
8238             break;
8239         }
8240       }
8241       if (toCreatePolyedrs) {
8242         // perform insertion into the links of adjacent volumes
8243         UpdateVolumes(n1, n2, nodeList);
8244       }
8245     }
8246
8247     delete param[0];
8248     delete param[1];
8249   } // end: insert new nodes
8250
8251   MergeNodes ( nodeGroupsToMerge );
8252
8253   return aResult;
8254 }
8255
8256 //=======================================================================
8257 //function : InsertNodesIntoLink
8258 //purpose  : insert theNodesToInsert into theFace between theBetweenNode1
8259 //           and theBetweenNode2 and split theElement
8260 //=======================================================================
8261
8262 void SMESH_MeshEditor::InsertNodesIntoLink(const SMDS_MeshElement*     theFace,
8263                                            const SMDS_MeshNode*        theBetweenNode1,
8264                                            const SMDS_MeshNode*        theBetweenNode2,
8265                                            list<const SMDS_MeshNode*>& theNodesToInsert,
8266                                            const bool                  toCreatePoly)
8267 {
8268   if ( theFace->GetType() != SMDSAbs_Face ) return;
8269
8270   // find indices of 2 link nodes and of the rest nodes
8271   int iNode = 0, il1, il2, i3, i4;
8272   il1 = il2 = i3 = i4 = -1;
8273   //const SMDS_MeshNode* nodes[ theFace->NbNodes() ];
8274   vector<const SMDS_MeshNode*> nodes( theFace->NbNodes() );
8275
8276   if(theFace->IsQuadratic()) {
8277     const SMDS_QuadraticFaceOfNodes* F =
8278       static_cast<const SMDS_QuadraticFaceOfNodes*>(theFace);
8279     // use special nodes iterator
8280     SMDS_NodeIteratorPtr anIter = F->interlacedNodesIterator();
8281     while( anIter->more() ) {
8282       const SMDS_MeshNode* n = anIter->next();
8283       if ( n == theBetweenNode1 )
8284         il1 = iNode;
8285       else if ( n == theBetweenNode2 )
8286         il2 = iNode;
8287       else if ( i3 < 0 )
8288         i3 = iNode;
8289       else
8290         i4 = iNode;
8291       nodes[ iNode++ ] = n;
8292     }
8293   }
8294   else {
8295     SMDS_ElemIteratorPtr nodeIt = theFace->nodesIterator();
8296     while ( nodeIt->more() ) {
8297       const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
8298       if ( n == theBetweenNode1 )
8299         il1 = iNode;
8300       else if ( n == theBetweenNode2 )
8301         il2 = iNode;
8302       else if ( i3 < 0 )
8303         i3 = iNode;
8304       else
8305         i4 = iNode;
8306       nodes[ iNode++ ] = n;
8307     }
8308   }
8309   if ( il1 < 0 || il2 < 0 || i3 < 0 )
8310     return ;
8311
8312   // arrange link nodes to go one after another regarding the face orientation
8313   bool reverse = ( Abs( il2 - il1 ) == 1 ? il2 < il1 : il1 < il2 );
8314   list<const SMDS_MeshNode *> aNodesToInsert = theNodesToInsert;
8315   if ( reverse ) {
8316     iNode = il1;
8317     il1 = il2;
8318     il2 = iNode;
8319     aNodesToInsert.reverse();
8320   }
8321   // check that not link nodes of a quadrangles are in good order
8322   int nbFaceNodes = theFace->NbNodes();
8323   if ( nbFaceNodes == 4 && i4 - i3 != 1 ) {
8324     iNode = i3;
8325     i3 = i4;
8326     i4 = iNode;
8327   }
8328
8329   if (toCreatePoly || theFace->IsPoly()) {
8330
8331     iNode = 0;
8332     vector<const SMDS_MeshNode *> poly_nodes (nbFaceNodes + aNodesToInsert.size());
8333
8334     // add nodes of face up to first node of link
8335     bool isFLN = false;
8336
8337     if(theFace->IsQuadratic()) {
8338       const SMDS_QuadraticFaceOfNodes* F =
8339         static_cast<const SMDS_QuadraticFaceOfNodes*>(theFace);
8340       // use special nodes iterator
8341       SMDS_NodeIteratorPtr anIter = F->interlacedNodesIterator();
8342       while( anIter->more()  && !isFLN ) {
8343         const SMDS_MeshNode* n = anIter->next();
8344         poly_nodes[iNode++] = n;
8345         if (n == nodes[il1]) {
8346           isFLN = true;
8347         }
8348       }
8349       // add nodes to insert
8350       list<const SMDS_MeshNode*>::iterator nIt = aNodesToInsert.begin();
8351       for (; nIt != aNodesToInsert.end(); nIt++) {
8352         poly_nodes[iNode++] = *nIt;
8353       }
8354       // add nodes of face starting from last node of link
8355       while ( anIter->more() ) {
8356         poly_nodes[iNode++] = anIter->next();
8357       }
8358     }
8359     else {
8360       SMDS_ElemIteratorPtr nodeIt = theFace->nodesIterator();
8361       while ( nodeIt->more() && !isFLN ) {
8362         const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
8363         poly_nodes[iNode++] = n;
8364         if (n == nodes[il1]) {
8365           isFLN = true;
8366         }
8367       }
8368       // add nodes to insert
8369       list<const SMDS_MeshNode*>::iterator nIt = aNodesToInsert.begin();
8370       for (; nIt != aNodesToInsert.end(); nIt++) {
8371         poly_nodes[iNode++] = *nIt;
8372       }
8373       // add nodes of face starting from last node of link
8374       while ( nodeIt->more() ) {
8375         const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
8376         poly_nodes[iNode++] = n;
8377       }
8378     }
8379
8380     // edit or replace the face
8381     SMESHDS_Mesh *aMesh = GetMeshDS();
8382
8383     if (theFace->IsPoly()) {
8384       aMesh->ChangePolygonNodes(theFace, poly_nodes);
8385     }
8386     else {
8387       int aShapeId = FindShape( theFace );
8388
8389       SMDS_MeshElement* newElem = aMesh->AddPolygonalFace(poly_nodes);
8390       myLastCreatedElems.Append(newElem);
8391       if ( aShapeId && newElem )
8392         aMesh->SetMeshElementOnShape( newElem, aShapeId );
8393
8394       aMesh->RemoveElement(theFace);
8395     }
8396     return;
8397   }
8398
8399   if( !theFace->IsQuadratic() ) {
8400
8401     // put aNodesToInsert between theBetweenNode1 and theBetweenNode2
8402     int nbLinkNodes = 2 + aNodesToInsert.size();
8403     //const SMDS_MeshNode* linkNodes[ nbLinkNodes ];
8404     vector<const SMDS_MeshNode*> linkNodes( nbLinkNodes );
8405     linkNodes[ 0 ] = nodes[ il1 ];
8406     linkNodes[ nbLinkNodes - 1 ] = nodes[ il2 ];
8407     list<const SMDS_MeshNode*>::iterator nIt = aNodesToInsert.begin();
8408     for ( iNode = 1; nIt != aNodesToInsert.end(); nIt++ ) {
8409       linkNodes[ iNode++ ] = *nIt;
8410     }
8411     // decide how to split a quadrangle: compare possible variants
8412     // and choose which of splits to be a quadrangle
8413     int i1, i2, iSplit, nbSplits = nbLinkNodes - 1, iBestQuad;
8414     if ( nbFaceNodes == 3 ) {
8415       iBestQuad = nbSplits;
8416       i4 = i3;
8417     }
8418     else if ( nbFaceNodes == 4 ) {
8419       SMESH::Controls::NumericalFunctorPtr aCrit( new SMESH::Controls::AspectRatio);
8420       double aBestRate = DBL_MAX;
8421       for ( int iQuad = 0; iQuad < nbSplits; iQuad++ ) {
8422         i1 = 0; i2 = 1;
8423         double aBadRate = 0;
8424         // evaluate elements quality
8425         for ( iSplit = 0; iSplit < nbSplits; iSplit++ ) {
8426           if ( iSplit == iQuad ) {
8427             SMDS_FaceOfNodes quad (linkNodes[ i1++ ],
8428                                    linkNodes[ i2++ ],
8429                                    nodes[ i3 ],
8430                                    nodes[ i4 ]);
8431             aBadRate += getBadRate( &quad, aCrit );
8432           }
8433           else {
8434             SMDS_FaceOfNodes tria (linkNodes[ i1++ ],
8435                                    linkNodes[ i2++ ],
8436                                    nodes[ iSplit < iQuad ? i4 : i3 ]);
8437             aBadRate += getBadRate( &tria, aCrit );
8438           }
8439         }
8440         // choice
8441         if ( aBadRate < aBestRate ) {
8442           iBestQuad = iQuad;
8443           aBestRate = aBadRate;
8444         }
8445       }
8446     }
8447
8448     // create new elements
8449     SMESHDS_Mesh *aMesh = GetMeshDS();
8450     int aShapeId = FindShape( theFace );
8451
8452     i1 = 0; i2 = 1;
8453     for ( iSplit = 0; iSplit < nbSplits - 1; iSplit++ ) {
8454       SMDS_MeshElement* newElem = 0;
8455       if ( iSplit == iBestQuad )
8456         newElem = aMesh->AddFace (linkNodes[ i1++ ],
8457                                   linkNodes[ i2++ ],
8458                                   nodes[ i3 ],
8459                                   nodes[ i4 ]);
8460       else
8461         newElem = aMesh->AddFace (linkNodes[ i1++ ],
8462                                   linkNodes[ i2++ ],
8463                                   nodes[ iSplit < iBestQuad ? i4 : i3 ]);
8464       myLastCreatedElems.Append(newElem);
8465       if ( aShapeId && newElem )
8466         aMesh->SetMeshElementOnShape( newElem, aShapeId );
8467     }
8468
8469     // change nodes of theFace
8470     const SMDS_MeshNode* newNodes[ 4 ];
8471     newNodes[ 0 ] = linkNodes[ i1 ];
8472     newNodes[ 1 ] = linkNodes[ i2 ];
8473     newNodes[ 2 ] = nodes[ iSplit >= iBestQuad ? i3 : i4 ];
8474     newNodes[ 3 ] = nodes[ i4 ];
8475     aMesh->ChangeElementNodes( theFace, newNodes, iSplit == iBestQuad ? 4 : 3 );
8476   } // end if(!theFace->IsQuadratic())
8477   else { // theFace is quadratic
8478     // we have to split theFace on simple triangles and one simple quadrangle
8479     int tmp = il1/2;
8480     int nbshift = tmp*2;
8481     // shift nodes in nodes[] by nbshift
8482     int i,j;
8483     for(i=0; i<nbshift; i++) {
8484       const SMDS_MeshNode* n = nodes[0];
8485       for(j=0; j<nbFaceNodes-1; j++) {
8486         nodes[j] = nodes[j+1];
8487       }
8488       nodes[nbFaceNodes-1] = n;
8489     }
8490     il1 = il1 - nbshift;
8491     // now have to insert nodes between n0 and n1 or n1 and n2 (see below)
8492     //   n0      n1     n2    n0      n1     n2
8493     //     +-----+-----+        +-----+-----+
8494     //      \         /         |           |
8495     //       \       /          |           |
8496     //      n5+     +n3       n7+           +n3
8497     //         \   /            |           |
8498     //          \ /             |           |
8499     //           +              +-----+-----+
8500     //           n4           n6      n5     n4
8501
8502     // create new elements
8503     SMESHDS_Mesh *aMesh = GetMeshDS();
8504     int aShapeId = FindShape( theFace );
8505
8506     int n1,n2,n3;
8507     if(nbFaceNodes==6) { // quadratic triangle
8508       SMDS_MeshElement* newElem =
8509         aMesh->AddFace(nodes[3],nodes[4],nodes[5]);
8510       myLastCreatedElems.Append(newElem);
8511       if ( aShapeId && newElem )
8512         aMesh->SetMeshElementOnShape( newElem, aShapeId );
8513       if(theFace->IsMediumNode(nodes[il1])) {
8514         // create quadrangle
8515         newElem = aMesh->AddFace(nodes[0],nodes[1],nodes[3],nodes[5]);
8516         myLastCreatedElems.Append(newElem);
8517         if ( aShapeId && newElem )
8518           aMesh->SetMeshElementOnShape( newElem, aShapeId );
8519         n1 = 1;
8520         n2 = 2;
8521         n3 = 3;
8522       }
8523       else {
8524         // create quadrangle
8525         newElem = aMesh->AddFace(nodes[1],nodes[2],nodes[3],nodes[5]);
8526         myLastCreatedElems.Append(newElem);
8527         if ( aShapeId && newElem )
8528           aMesh->SetMeshElementOnShape( newElem, aShapeId );
8529         n1 = 0;
8530         n2 = 1;
8531         n3 = 5;
8532       }
8533     }
8534     else { // nbFaceNodes==8 - quadratic quadrangle
8535       SMDS_MeshElement* newElem =
8536         aMesh->AddFace(nodes[3],nodes[4],nodes[5]);
8537       myLastCreatedElems.Append(newElem);
8538       if ( aShapeId && newElem )
8539         aMesh->SetMeshElementOnShape( newElem, aShapeId );
8540       newElem = aMesh->AddFace(nodes[5],nodes[6],nodes[7]);
8541       myLastCreatedElems.Append(newElem);
8542       if ( aShapeId && newElem )
8543         aMesh->SetMeshElementOnShape( newElem, aShapeId );
8544       newElem = aMesh->AddFace(nodes[5],nodes[7],nodes[3]);
8545       myLastCreatedElems.Append(newElem);
8546       if ( aShapeId && newElem )
8547         aMesh->SetMeshElementOnShape( newElem, aShapeId );
8548       if(theFace->IsMediumNode(nodes[il1])) {
8549         // create quadrangle
8550         newElem = aMesh->AddFace(nodes[0],nodes[1],nodes[3],nodes[7]);
8551         myLastCreatedElems.Append(newElem);
8552         if ( aShapeId && newElem )
8553           aMesh->SetMeshElementOnShape( newElem, aShapeId );
8554         n1 = 1;
8555         n2 = 2;
8556         n3 = 3;
8557       }
8558       else {
8559         // create quadrangle
8560         newElem = aMesh->AddFace(nodes[1],nodes[2],nodes[3],nodes[7]);
8561         myLastCreatedElems.Append(newElem);
8562         if ( aShapeId && newElem )
8563           aMesh->SetMeshElementOnShape( newElem, aShapeId );
8564         n1 = 0;
8565         n2 = 1;
8566         n3 = 7;
8567       }
8568     }
8569     // create needed triangles using n1,n2,n3 and inserted nodes
8570     int nbn = 2 + aNodesToInsert.size();
8571     //const SMDS_MeshNode* aNodes[nbn];
8572     vector<const SMDS_MeshNode*> aNodes(nbn);
8573     aNodes[0] = nodes[n1];
8574     aNodes[nbn-1] = nodes[n2];
8575     list<const SMDS_MeshNode*>::iterator nIt = aNodesToInsert.begin();
8576     for ( iNode = 1; nIt != aNodesToInsert.end(); nIt++ ) {
8577       aNodes[iNode++] = *nIt;
8578     }
8579     for(i=1; i<nbn; i++) {
8580       SMDS_MeshElement* newElem =
8581         aMesh->AddFace(aNodes[i-1],aNodes[i],nodes[n3]);
8582       myLastCreatedElems.Append(newElem);
8583       if ( aShapeId && newElem )
8584         aMesh->SetMeshElementOnShape( newElem, aShapeId );
8585     }
8586     // remove old quadratic face
8587     aMesh->RemoveElement(theFace);
8588   }
8589 }
8590
8591 //=======================================================================
8592 //function : UpdateVolumes
8593 //purpose  :
8594 //=======================================================================
8595 void SMESH_MeshEditor::UpdateVolumes (const SMDS_MeshNode*        theBetweenNode1,
8596                                       const SMDS_MeshNode*        theBetweenNode2,
8597                                       list<const SMDS_MeshNode*>& theNodesToInsert)
8598 {
8599   myLastCreatedElems.Clear();
8600   myLastCreatedNodes.Clear();
8601
8602   SMDS_ElemIteratorPtr invElemIt = theBetweenNode1->GetInverseElementIterator(SMDSAbs_Volume);
8603   while (invElemIt->more()) { // loop on inverse elements of theBetweenNode1
8604     const SMDS_MeshElement* elem = invElemIt->next();
8605
8606     // check, if current volume has link theBetweenNode1 - theBetweenNode2
8607     SMDS_VolumeTool aVolume (elem);
8608     if (!aVolume.IsLinked(theBetweenNode1, theBetweenNode2))
8609       continue;
8610
8611     // insert new nodes in all faces of the volume, sharing link theBetweenNode1 - theBetweenNode2
8612     int iface, nbFaces = aVolume.NbFaces();
8613     vector<const SMDS_MeshNode *> poly_nodes;
8614     vector<int> quantities (nbFaces);
8615
8616     for (iface = 0; iface < nbFaces; iface++) {
8617       int nbFaceNodes = aVolume.NbFaceNodes(iface), nbInserted = 0;
8618       // faceNodes will contain (nbFaceNodes + 1) nodes, last = first
8619       const SMDS_MeshNode** faceNodes = aVolume.GetFaceNodes(iface);
8620
8621       for (int inode = 0; inode < nbFaceNodes; inode++) {
8622         poly_nodes.push_back(faceNodes[inode]);
8623
8624         if (nbInserted == 0) {
8625           if (faceNodes[inode] == theBetweenNode1) {
8626             if (faceNodes[inode + 1] == theBetweenNode2) {
8627               nbInserted = theNodesToInsert.size();
8628
8629               // add nodes to insert
8630               list<const SMDS_MeshNode*>::iterator nIt = theNodesToInsert.begin();
8631               for (; nIt != theNodesToInsert.end(); nIt++) {
8632                 poly_nodes.push_back(*nIt);
8633               }
8634             }
8635           }
8636           else if (faceNodes[inode] == theBetweenNode2) {
8637             if (faceNodes[inode + 1] == theBetweenNode1) {
8638               nbInserted = theNodesToInsert.size();
8639
8640               // add nodes to insert in reversed order
8641               list<const SMDS_MeshNode*>::iterator nIt = theNodesToInsert.end();
8642               nIt--;
8643               for (; nIt != theNodesToInsert.begin(); nIt--) {
8644                 poly_nodes.push_back(*nIt);
8645               }
8646               poly_nodes.push_back(*nIt);
8647             }
8648           }
8649           else {
8650           }
8651         }
8652       }
8653       quantities[iface] = nbFaceNodes + nbInserted;
8654     }
8655
8656     // Replace or update the volume
8657     SMESHDS_Mesh *aMesh = GetMeshDS();
8658
8659     if (elem->IsPoly()) {
8660       aMesh->ChangePolyhedronNodes(elem, poly_nodes, quantities);
8661
8662     }
8663     else {
8664       int aShapeId = FindShape( elem );
8665
8666       SMDS_MeshElement* newElem =
8667         aMesh->AddPolyhedralVolume(poly_nodes, quantities);
8668       myLastCreatedElems.Append(newElem);
8669       if (aShapeId && newElem)
8670         aMesh->SetMeshElementOnShape(newElem, aShapeId);
8671
8672       aMesh->RemoveElement(elem);
8673     }
8674   }
8675 }
8676
8677 //=======================================================================
8678 /*!
8679  * \brief Convert elements contained in a submesh to quadratic
8680  * \retval int - nb of checked elements
8681  */
8682 //=======================================================================
8683
8684 int SMESH_MeshEditor::convertElemToQuadratic(SMESHDS_SubMesh *   theSm,
8685                                              SMESH_MesherHelper& theHelper,
8686                                              const bool          theForce3d)
8687 {
8688   int nbElem = 0;
8689   if( !theSm ) return nbElem;
8690
8691   vector<int> nbNodeInFaces;
8692   SMDS_ElemIteratorPtr ElemItr = theSm->GetElements();
8693   while(ElemItr->more())
8694   {
8695     nbElem++;
8696     const SMDS_MeshElement* elem = ElemItr->next();
8697     if( !elem || elem->IsQuadratic() ) continue;
8698
8699     int id = elem->GetID();
8700     int nbNodes = elem->NbNodes();
8701     SMDSAbs_ElementType aType = elem->GetType();
8702
8703     vector<const SMDS_MeshNode *> nodes (elem->begin_nodes(), elem->end_nodes());
8704     if ( elem->GetEntityType() == SMDSEntity_Polyhedra )
8705       nbNodeInFaces = static_cast<const SMDS_PolyhedralVolumeOfNodes* >( elem )->GetQuanities();
8706
8707     GetMeshDS()->RemoveFreeElement(elem, theSm, /*fromGroups=*/false);
8708
8709     const SMDS_MeshElement* NewElem = 0;
8710
8711     switch( aType )
8712     {
8713     case SMDSAbs_Edge :
8714       {
8715         NewElem = theHelper.AddEdge(nodes[0], nodes[1], id, theForce3d);
8716         break;
8717       }
8718     case SMDSAbs_Face :
8719       {
8720         switch(nbNodes)
8721         {
8722         case 3:
8723           NewElem = theHelper.AddFace(nodes[0], nodes[1], nodes[2], id, theForce3d);
8724           break;
8725         case 4:
8726           NewElem = theHelper.AddFace(nodes[0], nodes[1], nodes[2], nodes[3], id, theForce3d);
8727           break;
8728         default:
8729           NewElem = theHelper.AddPolygonalFace(nodes, id, theForce3d);
8730           continue;
8731         }
8732         break;
8733       }
8734     case SMDSAbs_Volume :
8735       {
8736         switch(nbNodes)
8737         {
8738         case 4:
8739           NewElem = theHelper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3], id, theForce3d);
8740           break;
8741         case 5:
8742           NewElem = theHelper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3], nodes[4], id, theForce3d);
8743           break;
8744         case 6:
8745           NewElem = theHelper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3], nodes[4], nodes[5], id, theForce3d);
8746           break;
8747         case 8:
8748           NewElem = theHelper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3],
8749                                         nodes[4], nodes[5], nodes[6], nodes[7], id, theForce3d);
8750           break;
8751         default:
8752           NewElem = theHelper.AddPolyhedralVolume(nodes, nbNodeInFaces, id, theForce3d);
8753         }
8754         break;
8755       }
8756     default :
8757       continue;
8758     }
8759     ReplaceElemInGroups( elem, NewElem, GetMeshDS());
8760     if( NewElem )
8761       theSm->AddElement( NewElem );
8762   }
8763   return nbElem;
8764 }
8765
8766 //=======================================================================
8767 //function : ConvertToQuadratic
8768 //purpose  :
8769 //=======================================================================
8770 void SMESH_MeshEditor::ConvertToQuadratic(const bool theForce3d)
8771 {
8772   SMESHDS_Mesh* meshDS = GetMeshDS();
8773
8774   SMESH_MesherHelper aHelper(*myMesh);
8775   aHelper.SetIsQuadratic( true );
8776
8777   int nbCheckedElems = 0;
8778   if ( myMesh->HasShapeToMesh() )
8779   {
8780     if ( SMESH_subMesh *aSubMesh = myMesh->GetSubMeshContaining(myMesh->GetShapeToMesh()))
8781     {
8782       SMESH_subMeshIteratorPtr smIt = aSubMesh->getDependsOnIterator(true,false);
8783       while ( smIt->more() ) {
8784         SMESH_subMesh* sm = smIt->next();
8785         if ( SMESHDS_SubMesh *smDS = sm->GetSubMeshDS() ) {
8786           aHelper.SetSubShape( sm->GetSubShape() );
8787           nbCheckedElems += convertElemToQuadratic(smDS, aHelper, theForce3d);
8788         }
8789       }
8790     }
8791   }
8792   int totalNbElems = meshDS->NbEdges() + meshDS->NbFaces() + meshDS->NbVolumes();
8793   if ( nbCheckedElems < totalNbElems ) // not all elements are in submeshes
8794   {
8795     SMESHDS_SubMesh *smDS = 0;
8796     SMDS_EdgeIteratorPtr aEdgeItr = meshDS->edgesIterator();
8797     while(aEdgeItr->more())
8798     {
8799       const SMDS_MeshEdge* edge = aEdgeItr->next();
8800       if(edge && !edge->IsQuadratic())
8801       {
8802         int id = edge->GetID();
8803         const SMDS_MeshNode* n1 = edge->GetNode(0);
8804         const SMDS_MeshNode* n2 = edge->GetNode(1);
8805
8806         meshDS->RemoveFreeElement(edge, smDS, /*fromGroups=*/false);
8807
8808         const SMDS_MeshEdge* NewEdge = aHelper.AddEdge(n1, n2, id, theForce3d);
8809         ReplaceElemInGroups( edge, NewEdge, GetMeshDS());
8810       }
8811     }
8812     SMDS_FaceIteratorPtr aFaceItr = meshDS->facesIterator();
8813     while(aFaceItr->more())
8814     {
8815       const SMDS_MeshFace* face = aFaceItr->next();
8816       if(!face || face->IsQuadratic() ) continue;
8817
8818       int id = face->GetID();
8819       int nbNodes = face->NbNodes();
8820       vector<const SMDS_MeshNode *> nodes ( face->begin_nodes(), face->end_nodes());
8821
8822       meshDS->RemoveFreeElement(face, smDS, /*fromGroups=*/false);
8823
8824       SMDS_MeshFace * NewFace = 0;
8825       switch(nbNodes)
8826       {
8827       case 3:
8828         NewFace = aHelper.AddFace(nodes[0], nodes[1], nodes[2], id, theForce3d);
8829         break;
8830       case 4:
8831         NewFace = aHelper.AddFace(nodes[0], nodes[1], nodes[2], nodes[3], id, theForce3d);
8832         break;
8833       default:
8834         NewFace = aHelper.AddPolygonalFace(nodes, id, theForce3d);
8835       }
8836       ReplaceElemInGroups( face, NewFace, GetMeshDS());
8837     }
8838     vector<int> nbNodeInFaces;
8839     SMDS_VolumeIteratorPtr aVolumeItr = meshDS->volumesIterator();
8840     while(aVolumeItr->more())
8841     {
8842       const SMDS_MeshVolume* volume = aVolumeItr->next();
8843       if(!volume || volume->IsQuadratic() ) continue;
8844
8845       int id = volume->GetID();
8846       int nbNodes = volume->NbNodes();
8847       vector<const SMDS_MeshNode *> nodes (volume->begin_nodes(), volume->end_nodes());
8848       if ( volume->GetEntityType() == SMDSEntity_Polyhedra )
8849         nbNodeInFaces = static_cast<const SMDS_PolyhedralVolumeOfNodes* >(volume)->GetQuanities();
8850
8851       meshDS->RemoveFreeElement(volume, smDS, /*fromGroups=*/false);
8852
8853       SMDS_MeshVolume * NewVolume = 0;
8854       switch(nbNodes)
8855       {
8856       case 4:
8857         NewVolume = aHelper.AddVolume(nodes[0], nodes[1], nodes[2],
8858                                       nodes[3], id, theForce3d );
8859         break;
8860       case 5:
8861         NewVolume = aHelper.AddVolume(nodes[0], nodes[1], nodes[2],
8862                                       nodes[3], nodes[4], id, theForce3d);
8863         break;
8864       case 6:
8865         NewVolume = aHelper.AddVolume(nodes[0], nodes[1], nodes[2],
8866                                       nodes[3], nodes[4], nodes[5], id, theForce3d);
8867         break;
8868       case 8:
8869         NewVolume = aHelper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3],
8870                                       nodes[4], nodes[5], nodes[6], nodes[7], id, theForce3d);
8871         break;
8872       default:
8873         NewVolume = aHelper.AddPolyhedralVolume(nodes, nbNodeInFaces, id, theForce3d);
8874       }
8875       ReplaceElemInGroups(volume, NewVolume, meshDS);
8876     }
8877   }
8878
8879   if ( !theForce3d  && !getenv("NO_FixQuadraticElements"))
8880   { // setenv NO_FixQuadraticElements to know if FixQuadraticElements() is guilty of bad conversion
8881     aHelper.SetSubShape(0); // apply FixQuadraticElements() to the whole mesh
8882     aHelper.FixQuadraticElements();
8883   }
8884 }
8885
8886 //=======================================================================
8887 /*!
8888  * \brief Convert quadratic elements to linear ones and remove quadratic nodes
8889  * \retval int - nb of checked elements
8890  */
8891 //=======================================================================
8892
8893 int SMESH_MeshEditor::removeQuadElem(SMESHDS_SubMesh *    theSm,
8894                                      SMDS_ElemIteratorPtr theItr,
8895                                      const int            theShapeID)
8896 {
8897   int nbElem = 0;
8898   SMESHDS_Mesh* meshDS = GetMeshDS();
8899   const bool notFromGroups = false;
8900
8901   while( theItr->more() )
8902   {
8903     const SMDS_MeshElement* elem = theItr->next();
8904     nbElem++;
8905     if( elem && elem->IsQuadratic())
8906     {
8907       int id = elem->GetID();
8908       int nbNodes = elem->NbNodes();
8909       vector<const SMDS_MeshNode *> nodes, mediumNodes;
8910       nodes.reserve( nbNodes );
8911       mediumNodes.reserve( nbNodes );
8912
8913       for(int i = 0; i < nbNodes; i++)
8914       {
8915         const SMDS_MeshNode* n = elem->GetNode(i);
8916
8917         if( elem->IsMediumNode( n ) )
8918           mediumNodes.push_back( n );
8919         else
8920           nodes.push_back( n );
8921       }
8922       if( nodes.empty() ) continue;
8923       SMDSAbs_ElementType aType = elem->GetType();
8924
8925       //remove old quadratic element
8926       meshDS->RemoveFreeElement( elem, theSm, notFromGroups );
8927
8928       SMDS_MeshElement * NewElem = AddElement( nodes, aType, false, id );
8929       ReplaceElemInGroups(elem, NewElem, meshDS);
8930       if( theSm && NewElem )
8931         theSm->AddElement( NewElem );
8932
8933       // remove medium nodes
8934       vector<const SMDS_MeshNode*>::iterator nIt = mediumNodes.begin();
8935       for ( ; nIt != mediumNodes.end(); ++nIt ) {
8936         const SMDS_MeshNode* n = *nIt;
8937         if ( n->NbInverseElements() == 0 ) {
8938           if ( n->GetPosition()->GetShapeId() != theShapeID )
8939             meshDS->RemoveFreeNode( n, meshDS->MeshElements
8940                                     ( n->GetPosition()->GetShapeId() ));
8941           else
8942             meshDS->RemoveFreeNode( n, theSm );
8943         }
8944       }
8945     }
8946   }
8947   return nbElem;
8948 }
8949
8950 //=======================================================================
8951 //function : ConvertFromQuadratic
8952 //purpose  :
8953 //=======================================================================
8954 bool  SMESH_MeshEditor::ConvertFromQuadratic()
8955 {
8956   int nbCheckedElems = 0;
8957   if ( myMesh->HasShapeToMesh() )
8958   {
8959     if ( SMESH_subMesh *aSubMesh = myMesh->GetSubMeshContaining(myMesh->GetShapeToMesh()))
8960     {
8961       SMESH_subMeshIteratorPtr smIt = aSubMesh->getDependsOnIterator(true,false);
8962       while ( smIt->more() ) {
8963         SMESH_subMesh* sm = smIt->next();
8964         if ( SMESHDS_SubMesh *smDS = sm->GetSubMeshDS() )
8965           nbCheckedElems += removeQuadElem( smDS, smDS->GetElements(), sm->GetId() );
8966       }
8967     }
8968   }
8969
8970   int totalNbElems =
8971     GetMeshDS()->NbEdges() + GetMeshDS()->NbFaces() + GetMeshDS()->NbVolumes();
8972   if ( nbCheckedElems < totalNbElems ) // not all elements are in submeshes
8973   {
8974     SMESHDS_SubMesh *aSM = 0;
8975     removeQuadElem( aSM, GetMeshDS()->elementsIterator(), 0 );
8976   }
8977
8978   return true;
8979 }
8980
8981 //=======================================================================
8982 //function : SewSideElements
8983 //purpose  :
8984 //=======================================================================
8985
8986 SMESH_MeshEditor::Sew_Error
8987 SMESH_MeshEditor::SewSideElements (TIDSortedElemSet&    theSide1,
8988                                    TIDSortedElemSet&    theSide2,
8989                                    const SMDS_MeshNode* theFirstNode1,
8990                                    const SMDS_MeshNode* theFirstNode2,
8991                                    const SMDS_MeshNode* theSecondNode1,
8992                                    const SMDS_MeshNode* theSecondNode2)
8993 {
8994   myLastCreatedElems.Clear();
8995   myLastCreatedNodes.Clear();
8996
8997   MESSAGE ("::::SewSideElements()");
8998   if ( theSide1.size() != theSide2.size() )
8999     return SEW_DIFF_NB_OF_ELEMENTS;
9000
9001   Sew_Error aResult = SEW_OK;
9002   // Algo:
9003   // 1. Build set of faces representing each side
9004   // 2. Find which nodes of the side 1 to merge with ones on the side 2
9005   // 3. Replace nodes in elements of the side 1 and remove replaced nodes
9006
9007   // =======================================================================
9008   // 1. Build set of faces representing each side:
9009   // =======================================================================
9010   // a. build set of nodes belonging to faces
9011   // b. complete set of faces: find missing fices whose nodes are in set of nodes
9012   // c. create temporary faces representing side of volumes if correspondent
9013   //    face does not exist
9014
9015   SMESHDS_Mesh* aMesh = GetMeshDS();
9016   SMDS_Mesh aTmpFacesMesh;
9017   set<const SMDS_MeshElement*> faceSet1, faceSet2;
9018   set<const SMDS_MeshElement*> volSet1,  volSet2;
9019   set<const SMDS_MeshNode*>    nodeSet1, nodeSet2;
9020   set<const SMDS_MeshElement*> * faceSetPtr[] = { &faceSet1, &faceSet2 };
9021   set<const SMDS_MeshElement*>  * volSetPtr[] = { &volSet1,  &volSet2  };
9022   set<const SMDS_MeshNode*>    * nodeSetPtr[] = { &nodeSet1, &nodeSet2 };
9023   TIDSortedElemSet * elemSetPtr[] = { &theSide1, &theSide2 };
9024   int iSide, iFace, iNode;
9025
9026   for ( iSide = 0; iSide < 2; iSide++ ) {
9027     set<const SMDS_MeshNode*>    * nodeSet = nodeSetPtr[ iSide ];
9028     TIDSortedElemSet * elemSet = elemSetPtr[ iSide ];
9029     set<const SMDS_MeshElement*> * faceSet = faceSetPtr[ iSide ];
9030     set<const SMDS_MeshElement*> * volSet  = volSetPtr [ iSide ];
9031     set<const SMDS_MeshElement*>::iterator vIt;
9032     TIDSortedElemSet::iterator eIt;
9033     set<const SMDS_MeshNode*>::iterator    nIt;
9034
9035     // check that given nodes belong to given elements
9036     const SMDS_MeshNode* n1 = ( iSide == 0 ) ? theFirstNode1 : theFirstNode2;
9037     const SMDS_MeshNode* n2 = ( iSide == 0 ) ? theSecondNode1 : theSecondNode2;
9038     int firstIndex = -1, secondIndex = -1;
9039     for (eIt = elemSet->begin(); eIt != elemSet->end(); eIt++ ) {
9040       const SMDS_MeshElement* elem = *eIt;
9041       if ( firstIndex  < 0 ) firstIndex  = elem->GetNodeIndex( n1 );
9042       if ( secondIndex < 0 ) secondIndex = elem->GetNodeIndex( n2 );
9043       if ( firstIndex > -1 && secondIndex > -1 ) break;
9044     }
9045     if ( firstIndex < 0 || secondIndex < 0 ) {
9046       // we can simply return until temporary faces created
9047       return (iSide == 0 ) ? SEW_BAD_SIDE1_NODES : SEW_BAD_SIDE2_NODES;
9048     }
9049
9050     // -----------------------------------------------------------
9051     // 1a. Collect nodes of existing faces
9052     //     and build set of face nodes in order to detect missing
9053     //     faces corresponing to sides of volumes
9054     // -----------------------------------------------------------
9055
9056     set< set <const SMDS_MeshNode*> > setOfFaceNodeSet;
9057
9058     // loop on the given element of a side
9059     for (eIt = elemSet->begin(); eIt != elemSet->end(); eIt++ ) {
9060       //const SMDS_MeshElement* elem = *eIt;
9061       const SMDS_MeshElement* elem = *eIt;
9062       if ( elem->GetType() == SMDSAbs_Face ) {
9063         faceSet->insert( elem );
9064         set <const SMDS_MeshNode*> faceNodeSet;
9065         SMDS_ElemIteratorPtr nodeIt = elem->nodesIterator();
9066         while ( nodeIt->more() ) {
9067           const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
9068           nodeSet->insert( n );
9069           faceNodeSet.insert( n );
9070         }
9071         setOfFaceNodeSet.insert( faceNodeSet );
9072       }
9073       else if ( elem->GetType() == SMDSAbs_Volume )
9074         volSet->insert( elem );
9075     }
9076     // ------------------------------------------------------------------------------
9077     // 1b. Complete set of faces: find missing fices whose nodes are in set of nodes
9078     // ------------------------------------------------------------------------------
9079
9080     for ( nIt = nodeSet->begin(); nIt != nodeSet->end(); nIt++ ) { // loop on nodes of iSide
9081       SMDS_ElemIteratorPtr fIt = (*nIt)->GetInverseElementIterator(SMDSAbs_Face);
9082       while ( fIt->more() ) { // loop on faces sharing a node
9083         const SMDS_MeshElement* f = fIt->next();
9084         if ( faceSet->find( f ) == faceSet->end() ) {
9085           // check if all nodes are in nodeSet and
9086           // complete setOfFaceNodeSet if they are
9087           set <const SMDS_MeshNode*> faceNodeSet;
9088           SMDS_ElemIteratorPtr nodeIt = f->nodesIterator();
9089           bool allInSet = true;
9090           while ( nodeIt->more() && allInSet ) { // loop on nodes of a face
9091             const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
9092             if ( nodeSet->find( n ) == nodeSet->end() )
9093               allInSet = false;
9094             else
9095               faceNodeSet.insert( n );
9096           }
9097           if ( allInSet ) {
9098             faceSet->insert( f );
9099             setOfFaceNodeSet.insert( faceNodeSet );
9100           }
9101         }
9102       }
9103     }
9104
9105     // -------------------------------------------------------------------------
9106     // 1c. Create temporary faces representing sides of volumes if correspondent
9107     //     face does not exist
9108     // -------------------------------------------------------------------------
9109
9110     if ( !volSet->empty() ) {
9111       //int nodeSetSize = nodeSet->size();
9112
9113       // loop on given volumes
9114       for ( vIt = volSet->begin(); vIt != volSet->end(); vIt++ ) {
9115         SMDS_VolumeTool vol (*vIt);
9116         // loop on volume faces: find free faces
9117         // --------------------------------------
9118         list<const SMDS_MeshElement* > freeFaceList;
9119         for ( iFace = 0; iFace < vol.NbFaces(); iFace++ ) {
9120           if ( !vol.IsFreeFace( iFace ))
9121             continue;
9122           // check if there is already a face with same nodes in a face set
9123           const SMDS_MeshElement* aFreeFace = 0;
9124           const SMDS_MeshNode** fNodes = vol.GetFaceNodes( iFace );
9125           int nbNodes = vol.NbFaceNodes( iFace );
9126           set <const SMDS_MeshNode*> faceNodeSet;
9127           vol.GetFaceNodes( iFace, faceNodeSet );
9128           bool isNewFace = setOfFaceNodeSet.insert( faceNodeSet ).second;
9129           if ( isNewFace ) {
9130             // no such a face is given but it still can exist, check it
9131             if ( nbNodes == 3 ) {
9132               aFreeFace = aMesh->FindFace( fNodes[0],fNodes[1],fNodes[2] );
9133             }
9134             else if ( nbNodes == 4 ) {
9135               aFreeFace = aMesh->FindFace( fNodes[0],fNodes[1],fNodes[2],fNodes[3] );
9136             }
9137             else {
9138               vector<const SMDS_MeshNode *> poly_nodes ( fNodes, & fNodes[nbNodes]);
9139               aFreeFace = aMesh->FindFace(poly_nodes);
9140             }
9141           }
9142           if ( !aFreeFace ) {
9143             // create a temporary face
9144             if ( nbNodes == 3 ) {
9145               aFreeFace = aTmpFacesMesh.AddFace( fNodes[0],fNodes[1],fNodes[2] );
9146             }
9147             else if ( nbNodes == 4 ) {
9148               aFreeFace = aTmpFacesMesh.AddFace( fNodes[0],fNodes[1],fNodes[2],fNodes[3] );
9149             }
9150             else {
9151               vector<const SMDS_MeshNode *> poly_nodes ( fNodes, & fNodes[nbNodes]);
9152               aFreeFace = aTmpFacesMesh.AddPolygonalFace(poly_nodes);
9153             }
9154           }
9155           if ( aFreeFace )
9156             freeFaceList.push_back( aFreeFace );
9157
9158         } // loop on faces of a volume
9159
9160         // choose one of several free faces
9161         // --------------------------------------
9162         if ( freeFaceList.size() > 1 ) {
9163           // choose a face having max nb of nodes shared by other elems of a side
9164           int maxNbNodes = -1/*, nbExcludedFaces = 0*/;
9165           list<const SMDS_MeshElement* >::iterator fIt = freeFaceList.begin();
9166           while ( fIt != freeFaceList.end() ) { // loop on free faces
9167             int nbSharedNodes = 0;
9168             SMDS_ElemIteratorPtr nodeIt = (*fIt)->nodesIterator();
9169             while ( nodeIt->more() ) { // loop on free face nodes
9170               const SMDS_MeshNode* n =
9171                 static_cast<const SMDS_MeshNode*>( nodeIt->next() );
9172               SMDS_ElemIteratorPtr invElemIt = n->GetInverseElementIterator();
9173               while ( invElemIt->more() ) {
9174                 const SMDS_MeshElement* e = invElemIt->next();
9175                 if ( faceSet->find( e ) != faceSet->end() )
9176                   nbSharedNodes++;
9177                 if ( elemSet->find( e ) != elemSet->end() )
9178                   nbSharedNodes++;
9179               }
9180             }
9181             if ( nbSharedNodes >= maxNbNodes ) {
9182               maxNbNodes = nbSharedNodes;
9183               fIt++;
9184             }
9185             else
9186               freeFaceList.erase( fIt++ ); // here fIt++ occures before erase
9187           }
9188           if ( freeFaceList.size() > 1 )
9189           {
9190             // could not choose one face, use another way
9191             // choose a face most close to the bary center of the opposite side
9192             gp_XYZ aBC( 0., 0., 0. );
9193             set <const SMDS_MeshNode*> addedNodes;
9194             TIDSortedElemSet * elemSet2 = elemSetPtr[ 1 - iSide ];
9195             eIt = elemSet2->begin();
9196             for ( eIt = elemSet2->begin(); eIt != elemSet2->end(); eIt++ ) {
9197               SMDS_ElemIteratorPtr nodeIt = (*eIt)->nodesIterator();
9198               while ( nodeIt->more() ) { // loop on free face nodes
9199                 const SMDS_MeshNode* n =
9200                   static_cast<const SMDS_MeshNode*>( nodeIt->next() );
9201                 if ( addedNodes.insert( n ).second )
9202                   aBC += gp_XYZ( n->X(),n->Y(),n->Z() );
9203               }
9204             }
9205             aBC /= addedNodes.size();
9206             double minDist = DBL_MAX;
9207             fIt = freeFaceList.begin();
9208             while ( fIt != freeFaceList.end() ) { // loop on free faces
9209               double dist = 0;
9210               SMDS_ElemIteratorPtr nodeIt = (*fIt)->nodesIterator();
9211               while ( nodeIt->more() ) { // loop on free face nodes
9212                 const SMDS_MeshNode* n =
9213                   static_cast<const SMDS_MeshNode*>( nodeIt->next() );
9214                 gp_XYZ p( n->X(),n->Y(),n->Z() );
9215                 dist += ( aBC - p ).SquareModulus();
9216               }
9217               if ( dist < minDist ) {
9218                 minDist = dist;
9219                 freeFaceList.erase( freeFaceList.begin(), fIt++ );
9220               }
9221               else
9222                 fIt = freeFaceList.erase( fIt++ );
9223             }
9224           }
9225         } // choose one of several free faces of a volume
9226
9227         if ( freeFaceList.size() == 1 ) {
9228           const SMDS_MeshElement* aFreeFace = freeFaceList.front();
9229           faceSet->insert( aFreeFace );
9230           // complete a node set with nodes of a found free face
9231           //           for ( iNode = 0; iNode < ; iNode++ )
9232           //             nodeSet->insert( fNodes[ iNode ] );
9233         }
9234
9235       } // loop on volumes of a side
9236
9237       //       // complete a set of faces if new nodes in a nodeSet appeared
9238       //       // ----------------------------------------------------------
9239       //       if ( nodeSetSize != nodeSet->size() ) {
9240       //         for ( ; nIt != nodeSet->end(); nIt++ ) { // loop on nodes of iSide
9241       //           SMDS_ElemIteratorPtr fIt = (*nIt)->GetInverseElementIterator(SMDSAbs_Face);
9242       //           while ( fIt->more() ) { // loop on faces sharing a node
9243       //             const SMDS_MeshElement* f = fIt->next();
9244       //             if ( faceSet->find( f ) == faceSet->end() ) {
9245       //               // check if all nodes are in nodeSet and
9246       //               // complete setOfFaceNodeSet if they are
9247       //               set <const SMDS_MeshNode*> faceNodeSet;
9248       //               SMDS_ElemIteratorPtr nodeIt = f->nodesIterator();
9249       //               bool allInSet = true;
9250       //               while ( nodeIt->more() && allInSet ) { // loop on nodes of a face
9251       //                 const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
9252       //                 if ( nodeSet->find( n ) == nodeSet->end() )
9253       //                   allInSet = false;
9254       //                 else
9255       //                   faceNodeSet.insert( n );
9256       //               }
9257       //               if ( allInSet ) {
9258       //                 faceSet->insert( f );
9259       //                 setOfFaceNodeSet.insert( faceNodeSet );
9260       //               }
9261       //             }
9262       //           }
9263       //         }
9264       //       }
9265     } // Create temporary faces, if there are volumes given
9266   } // loop on sides
9267
9268   if ( faceSet1.size() != faceSet2.size() ) {
9269     // delete temporary faces: they are in reverseElements of actual nodes
9270     SMDS_FaceIteratorPtr tmpFaceIt = aTmpFacesMesh.facesIterator();
9271     while ( tmpFaceIt->more() )
9272       aTmpFacesMesh.RemoveElement( tmpFaceIt->next() );
9273     MESSAGE("Diff nb of faces");
9274     return SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
9275   }
9276
9277   // ============================================================
9278   // 2. Find nodes to merge:
9279   //              bind a node to remove to a node to put instead
9280   // ============================================================
9281
9282   TNodeNodeMap nReplaceMap; // bind a node to remove to a node to put instead
9283   if ( theFirstNode1 != theFirstNode2 )
9284     nReplaceMap.insert( TNodeNodeMap::value_type( theFirstNode1, theFirstNode2 ));
9285   if ( theSecondNode1 != theSecondNode2 )
9286     nReplaceMap.insert( TNodeNodeMap::value_type( theSecondNode1, theSecondNode2 ));
9287
9288   LinkID_Gen aLinkID_Gen( GetMeshDS() );
9289   set< long > linkIdSet; // links to process
9290   linkIdSet.insert( aLinkID_Gen.GetLinkID( theFirstNode1, theSecondNode1 ));
9291
9292   typedef pair< const SMDS_MeshNode*, const SMDS_MeshNode* > NLink;
9293   list< NLink > linkList[2];
9294   linkList[0].push_back( NLink( theFirstNode1, theSecondNode1 ));
9295   linkList[1].push_back( NLink( theFirstNode2, theSecondNode2 ));
9296   // loop on links in linkList; find faces by links and append links
9297   // of the found faces to linkList
9298   list< NLink >::iterator linkIt[] = { linkList[0].begin(), linkList[1].begin() } ;
9299   for ( ; linkIt[0] != linkList[0].end(); linkIt[0]++, linkIt[1]++ ) {
9300     NLink link[] = { *linkIt[0], *linkIt[1] };
9301     long linkID = aLinkID_Gen.GetLinkID( link[0].first, link[0].second );
9302     if ( linkIdSet.find( linkID ) == linkIdSet.end() )
9303       continue;
9304
9305     // by links, find faces in the face sets,
9306     // and find indices of link nodes in the found faces;
9307     // in a face set, there is only one or no face sharing a link
9308     // ---------------------------------------------------------------
9309
9310     const SMDS_MeshElement* face[] = { 0, 0 };
9311     //const SMDS_MeshNode* faceNodes[ 2 ][ 5 ];
9312     vector<const SMDS_MeshNode*> fnodes1(9);
9313     vector<const SMDS_MeshNode*> fnodes2(9);
9314     //const SMDS_MeshNode* notLinkNodes[ 2 ][ 2 ] = {{ 0, 0 },{ 0, 0 }} ;
9315     vector<const SMDS_MeshNode*> notLinkNodes1(6);
9316     vector<const SMDS_MeshNode*> notLinkNodes2(6);
9317     int iLinkNode[2][2];
9318     for ( iSide = 0; iSide < 2; iSide++ ) { // loop on 2 sides
9319       const SMDS_MeshNode* n1 = link[iSide].first;
9320       const SMDS_MeshNode* n2 = link[iSide].second;
9321       set<const SMDS_MeshElement*> * faceSet = faceSetPtr[ iSide ];
9322       set< const SMDS_MeshElement* > fMap;
9323       for ( int i = 0; i < 2; i++ ) { // loop on 2 nodes of a link
9324         const SMDS_MeshNode* n = i ? n1 : n2; // a node of a link
9325         SMDS_ElemIteratorPtr fIt = n->GetInverseElementIterator(SMDSAbs_Face);
9326         while ( fIt->more() ) { // loop on faces sharing a node
9327           const SMDS_MeshElement* f = fIt->next();
9328           if (faceSet->find( f ) != faceSet->end() && // f is in face set
9329               ! fMap.insert( f ).second ) // f encounters twice
9330           {
9331             if ( face[ iSide ] ) {
9332               MESSAGE( "2 faces per link " );
9333               aResult = iSide ? SEW_BAD_SIDE2_NODES : SEW_BAD_SIDE1_NODES;
9334               break;
9335             }
9336             face[ iSide ] = f;
9337             faceSet->erase( f );
9338             // get face nodes and find ones of a link
9339             iNode = 0;
9340             int nbl = -1;
9341             if(f->IsPoly()) {
9342               if(iSide==0) {
9343                 fnodes1.resize(f->NbNodes()+1);
9344                 notLinkNodes1.resize(f->NbNodes()-2);
9345               }
9346               else {
9347                 fnodes2.resize(f->NbNodes()+1);
9348                 notLinkNodes2.resize(f->NbNodes()-2);
9349               }
9350             }
9351             if(!f->IsQuadratic()) {
9352               SMDS_ElemIteratorPtr nIt = f->nodesIterator();
9353               while ( nIt->more() ) {
9354                 const SMDS_MeshNode* n =
9355                   static_cast<const SMDS_MeshNode*>( nIt->next() );
9356                 if ( n == n1 ) {
9357                   iLinkNode[ iSide ][ 0 ] = iNode;
9358                 }
9359                 else if ( n == n2 ) {
9360                   iLinkNode[ iSide ][ 1 ] = iNode;
9361                 }
9362                 //else if ( notLinkNodes[ iSide ][ 0 ] )
9363                 //  notLinkNodes[ iSide ][ 1 ] = n;
9364                 //else
9365                 //  notLinkNodes[ iSide ][ 0 ] = n;
9366                 else {
9367                   nbl++;
9368                   if(iSide==0)
9369                     notLinkNodes1[nbl] = n;
9370                   //notLinkNodes1.push_back(n);
9371                   else
9372                     notLinkNodes2[nbl] = n;
9373                   //notLinkNodes2.push_back(n);
9374                 }
9375                 //faceNodes[ iSide ][ iNode++ ] = n;
9376                 if(iSide==0) {
9377                   fnodes1[iNode++] = n;
9378                 }
9379                 else {
9380                   fnodes2[iNode++] = n;
9381                 }
9382               }
9383             }
9384             else { // f->IsQuadratic()
9385               const SMDS_QuadraticFaceOfNodes* F =
9386                 static_cast<const SMDS_QuadraticFaceOfNodes*>(f);
9387               // use special nodes iterator
9388               SMDS_NodeIteratorPtr anIter = F->interlacedNodesIterator();
9389               while ( anIter->more() ) {
9390                 const SMDS_MeshNode* n =
9391                   static_cast<const SMDS_MeshNode*>( anIter->next() );
9392                 if ( n == n1 ) {
9393                   iLinkNode[ iSide ][ 0 ] = iNode;
9394                 }
9395                 else if ( n == n2 ) {
9396                   iLinkNode[ iSide ][ 1 ] = iNode;
9397                 }
9398                 else {
9399                   nbl++;
9400                   if(iSide==0) {
9401                     notLinkNodes1[nbl] = n;
9402                   }
9403                   else {
9404                     notLinkNodes2[nbl] = n;
9405                   }
9406                 }
9407                 if(iSide==0) {
9408                   fnodes1[iNode++] = n;
9409                 }
9410                 else {
9411                   fnodes2[iNode++] = n;
9412                 }
9413               }
9414             }
9415             //faceNodes[ iSide ][ iNode ] = faceNodes[ iSide ][ 0 ];
9416             if(iSide==0) {
9417               fnodes1[iNode] = fnodes1[0];
9418             }
9419             else {
9420               fnodes2[iNode] = fnodes1[0];
9421             }
9422           }
9423         }
9424       }
9425     }
9426
9427     // check similarity of elements of the sides
9428     if (aResult == SEW_OK && ( face[0] && !face[1] ) || ( !face[0] && face[1] )) {
9429       MESSAGE("Correspondent face not found on side " << ( face[0] ? 1 : 0 ));
9430       if ( nReplaceMap.size() == 2 ) { // faces on input nodes not found
9431         aResult = ( face[0] ? SEW_BAD_SIDE2_NODES : SEW_BAD_SIDE1_NODES );
9432       }
9433       else {
9434         aResult = SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
9435       }
9436       break; // do not return because it s necessary to remove tmp faces
9437     }
9438
9439     // set nodes to merge
9440     // -------------------
9441
9442     if ( face[0] && face[1] )  {
9443       int nbNodes = face[0]->NbNodes();
9444       if ( nbNodes != face[1]->NbNodes() ) {
9445         MESSAGE("Diff nb of face nodes");
9446         aResult = SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
9447         break; // do not return because it s necessary to remove tmp faces
9448       }
9449       bool reverse[] = { false, false }; // order of notLinkNodes of quadrangle
9450       if ( nbNodes == 3 ) {
9451         //nReplaceMap.insert( TNodeNodeMap::value_type
9452         //                   ( notLinkNodes[0][0], notLinkNodes[1][0] ));
9453         nReplaceMap.insert( TNodeNodeMap::value_type
9454                             ( notLinkNodes1[0], notLinkNodes2[0] ));
9455       }
9456       else {
9457         for ( iSide = 0; iSide < 2; iSide++ ) { // loop on 2 sides
9458           // analyse link orientation in faces
9459           int i1 = iLinkNode[ iSide ][ 0 ];
9460           int i2 = iLinkNode[ iSide ][ 1 ];
9461           reverse[ iSide ] = Abs( i1 - i2 ) == 1 ? i1 > i2 : i2 > i1;
9462           // if notLinkNodes are the first and the last ones, then
9463           // their order does not correspond to the link orientation
9464           if (( i1 == 1 && i2 == 2 ) ||
9465               ( i1 == 2 && i2 == 1 ))
9466             reverse[ iSide ] = !reverse[ iSide ];
9467         }
9468         if ( reverse[0] == reverse[1] ) {
9469           //nReplaceMap.insert( TNodeNodeMap::value_type
9470           //                   ( notLinkNodes[0][0], notLinkNodes[1][0] ));
9471           //nReplaceMap.insert( TNodeNodeMap::value_type
9472           //                   ( notLinkNodes[0][1], notLinkNodes[1][1] ));
9473           for(int nn=0; nn<nbNodes-2; nn++) {
9474             nReplaceMap.insert( TNodeNodeMap::value_type
9475                                 ( notLinkNodes1[nn], notLinkNodes2[nn] ));
9476           }
9477         }
9478         else {
9479           //nReplaceMap.insert( TNodeNodeMap::value_type
9480           //                   ( notLinkNodes[0][0], notLinkNodes[1][1] ));
9481           //nReplaceMap.insert( TNodeNodeMap::value_type
9482           //                   ( notLinkNodes[0][1], notLinkNodes[1][0] ));
9483           for(int nn=0; nn<nbNodes-2; nn++) {
9484             nReplaceMap.insert( TNodeNodeMap::value_type
9485                                 ( notLinkNodes1[nn], notLinkNodes2[nbNodes-3-nn] ));
9486           }
9487         }
9488       }
9489
9490       // add other links of the faces to linkList
9491       // -----------------------------------------
9492
9493       //const SMDS_MeshNode** nodes = faceNodes[ 0 ];
9494       for ( iNode = 0; iNode < nbNodes; iNode++ )  {
9495         //linkID = aLinkID_Gen.GetLinkID( nodes[iNode], nodes[iNode+1] );
9496         linkID = aLinkID_Gen.GetLinkID( fnodes1[iNode], fnodes1[iNode+1] );
9497         pair< set<long>::iterator, bool > iter_isnew = linkIdSet.insert( linkID );
9498         if ( !iter_isnew.second ) { // already in a set: no need to process
9499           linkIdSet.erase( iter_isnew.first );
9500         }
9501         else // new in set == encountered for the first time: add
9502         {
9503           //const SMDS_MeshNode* n1 = nodes[ iNode ];
9504           //const SMDS_MeshNode* n2 = nodes[ iNode + 1];
9505           const SMDS_MeshNode* n1 = fnodes1[ iNode ];
9506           const SMDS_MeshNode* n2 = fnodes1[ iNode + 1];
9507           linkList[0].push_back ( NLink( n1, n2 ));
9508           linkList[1].push_back ( NLink( nReplaceMap[n1], nReplaceMap[n2] ));
9509         }
9510       }
9511     } // 2 faces found
9512   } // loop on link lists
9513
9514   if ( aResult == SEW_OK &&
9515        ( linkIt[0] != linkList[0].end() ||
9516          !faceSetPtr[0]->empty() || !faceSetPtr[1]->empty() )) {
9517     MESSAGE( (linkIt[0] != linkList[0].end()) <<" "<< (faceSetPtr[0]->empty()) <<
9518              " " << (faceSetPtr[1]->empty()));
9519     aResult = SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
9520   }
9521
9522   // ====================================================================
9523   // 3. Replace nodes in elements of the side 1 and remove replaced nodes
9524   // ====================================================================
9525
9526   // delete temporary faces: they are in reverseElements of actual nodes
9527   SMDS_FaceIteratorPtr tmpFaceIt = aTmpFacesMesh.facesIterator();
9528   while ( tmpFaceIt->more() )
9529     aTmpFacesMesh.RemoveElement( tmpFaceIt->next() );
9530
9531   if ( aResult != SEW_OK)
9532     return aResult;
9533
9534   list< int > nodeIDsToRemove/*, elemIDsToRemove*/;
9535   // loop on nodes replacement map
9536   TNodeNodeMap::iterator nReplaceMapIt = nReplaceMap.begin(), nnIt;
9537   for ( ; nReplaceMapIt != nReplaceMap.end(); nReplaceMapIt++ )
9538     if ( (*nReplaceMapIt).first != (*nReplaceMapIt).second ) {
9539       const SMDS_MeshNode* nToRemove = (*nReplaceMapIt).first;
9540       nodeIDsToRemove.push_back( nToRemove->GetID() );
9541       // loop on elements sharing nToRemove
9542       SMDS_ElemIteratorPtr invElemIt = nToRemove->GetInverseElementIterator();
9543       while ( invElemIt->more() ) {
9544         const SMDS_MeshElement* e = invElemIt->next();
9545         // get a new suite of nodes: make replacement
9546         int nbReplaced = 0, i = 0, nbNodes = e->NbNodes();
9547         vector< const SMDS_MeshNode*> nodes( nbNodes );
9548         SMDS_ElemIteratorPtr nIt = e->nodesIterator();
9549         while ( nIt->more() ) {
9550           const SMDS_MeshNode* n =
9551             static_cast<const SMDS_MeshNode*>( nIt->next() );
9552           nnIt = nReplaceMap.find( n );
9553           if ( nnIt != nReplaceMap.end() ) {
9554             nbReplaced++;
9555             n = (*nnIt).second;
9556           }
9557           nodes[ i++ ] = n;
9558         }
9559         //       if ( nbReplaced == nbNodes && e->GetType() == SMDSAbs_Face )
9560         //         elemIDsToRemove.push_back( e->GetID() );
9561         //       else
9562         if ( nbReplaced )
9563           aMesh->ChangeElementNodes( e, & nodes[0], nbNodes );
9564       }
9565     }
9566
9567   Remove( nodeIDsToRemove, true );
9568
9569   return aResult;
9570 }
9571
9572 //================================================================================
9573 /*!
9574  * \brief Find corresponding nodes in two sets of faces
9575  * \param theSide1 - first face set
9576  * \param theSide2 - second first face
9577  * \param theFirstNode1 - a boundary node of set 1
9578  * \param theFirstNode2 - a node of set 2 corresponding to theFirstNode1
9579  * \param theSecondNode1 - a boundary node of set 1 linked with theFirstNode1
9580  * \param theSecondNode2 - a node of set 2 corresponding to theSecondNode1
9581  * \param nReplaceMap - output map of corresponding nodes
9582  * \retval bool  - is a success or not
9583  */
9584 //================================================================================
9585
9586 #ifdef _DEBUG_
9587 //#define DEBUG_MATCHING_NODES
9588 #endif
9589
9590 SMESH_MeshEditor::Sew_Error
9591 SMESH_MeshEditor::FindMatchingNodes(set<const SMDS_MeshElement*>& theSide1,
9592                                     set<const SMDS_MeshElement*>& theSide2,
9593                                     const SMDS_MeshNode*          theFirstNode1,
9594                                     const SMDS_MeshNode*          theFirstNode2,
9595                                     const SMDS_MeshNode*          theSecondNode1,
9596                                     const SMDS_MeshNode*          theSecondNode2,
9597                                     TNodeNodeMap &                nReplaceMap)
9598 {
9599   set<const SMDS_MeshElement*> * faceSetPtr[] = { &theSide1, &theSide2 };
9600
9601   nReplaceMap.clear();
9602   if ( theFirstNode1 != theFirstNode2 )
9603     nReplaceMap.insert( make_pair( theFirstNode1, theFirstNode2 ));
9604   if ( theSecondNode1 != theSecondNode2 )
9605     nReplaceMap.insert( make_pair( theSecondNode1, theSecondNode2 ));
9606
9607   set< SMESH_TLink > linkSet; // set of nodes where order of nodes is ignored
9608   linkSet.insert( SMESH_TLink( theFirstNode1, theSecondNode1 ));
9609
9610   list< NLink > linkList[2];
9611   linkList[0].push_back( NLink( theFirstNode1, theSecondNode1 ));
9612   linkList[1].push_back( NLink( theFirstNode2, theSecondNode2 ));
9613
9614   // loop on links in linkList; find faces by links and append links
9615   // of the found faces to linkList
9616   list< NLink >::iterator linkIt[] = { linkList[0].begin(), linkList[1].begin() } ;
9617   for ( ; linkIt[0] != linkList[0].end(); linkIt[0]++, linkIt[1]++ ) {
9618     NLink link[] = { *linkIt[0], *linkIt[1] };
9619     if ( linkSet.find( link[0] ) == linkSet.end() )
9620       continue;
9621
9622     // by links, find faces in the face sets,
9623     // and find indices of link nodes in the found faces;
9624     // in a face set, there is only one or no face sharing a link
9625     // ---------------------------------------------------------------
9626
9627     const SMDS_MeshElement* face[] = { 0, 0 };
9628     list<const SMDS_MeshNode*> notLinkNodes[2];
9629     //bool reverse[] = { false, false }; // order of notLinkNodes
9630     int nbNodes[2];
9631     for ( int iSide = 0; iSide < 2; iSide++ ) // loop on 2 sides
9632     {
9633       const SMDS_MeshNode* n1 = link[iSide].first;
9634       const SMDS_MeshNode* n2 = link[iSide].second;
9635       set<const SMDS_MeshElement*> * faceSet = faceSetPtr[ iSide ];
9636       set< const SMDS_MeshElement* > facesOfNode1;
9637       for ( int iNode = 0; iNode < 2; iNode++ ) // loop on 2 nodes of a link
9638       {
9639         // during a loop of the first node, we find all faces around n1,
9640         // during a loop of the second node, we find one face sharing both n1 and n2
9641         const SMDS_MeshNode* n = iNode ? n1 : n2; // a node of a link
9642         SMDS_ElemIteratorPtr fIt = n->GetInverseElementIterator(SMDSAbs_Face);
9643         while ( fIt->more() ) { // loop on faces sharing a node
9644           const SMDS_MeshElement* f = fIt->next();
9645           if (faceSet->find( f ) != faceSet->end() && // f is in face set
9646               ! facesOfNode1.insert( f ).second ) // f encounters twice
9647           {
9648             if ( face[ iSide ] ) {
9649               MESSAGE( "2 faces per link " );
9650               return ( iSide ? SEW_BAD_SIDE2_NODES : SEW_BAD_SIDE1_NODES );
9651             }
9652             face[ iSide ] = f;
9653             faceSet->erase( f );
9654
9655             // get not link nodes
9656             int nbN = f->NbNodes();
9657             if ( f->IsQuadratic() )
9658               nbN /= 2;
9659             nbNodes[ iSide ] = nbN;
9660             list< const SMDS_MeshNode* > & nodes = notLinkNodes[ iSide ];
9661             int i1 = f->GetNodeIndex( n1 );
9662             int i2 = f->GetNodeIndex( n2 );
9663             int iEnd = nbN, iBeg = -1, iDelta = 1;
9664             bool reverse = ( Abs( i1 - i2 ) == 1 ? i1 > i2 : i2 > i1 );
9665             if ( reverse ) {
9666               std::swap( iEnd, iBeg ); iDelta = -1;
9667             }
9668             int i = i2;
9669             while ( true ) {
9670               i += iDelta;
9671               if ( i == iEnd ) i = iBeg + iDelta;
9672               if ( i == i1 ) break;
9673               nodes.push_back ( f->GetNode( i ) );
9674             }
9675           }
9676         }
9677       }
9678     }
9679     // check similarity of elements of the sides
9680     if (( face[0] && !face[1] ) || ( !face[0] && face[1] )) {
9681       MESSAGE("Correspondent face not found on side " << ( face[0] ? 1 : 0 ));
9682       if ( nReplaceMap.size() == 2 ) { // faces on input nodes not found
9683         return ( face[0] ? SEW_BAD_SIDE2_NODES : SEW_BAD_SIDE1_NODES );
9684       }
9685       else {
9686         return SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
9687       }
9688     }
9689
9690     // set nodes to merge
9691     // -------------------
9692
9693     if ( face[0] && face[1] )  {
9694       if ( nbNodes[0] != nbNodes[1] ) {
9695         MESSAGE("Diff nb of face nodes");
9696         return SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
9697       }
9698 #ifdef DEBUG_MATCHING_NODES
9699       MESSAGE ( " Link 1: " << link[0].first->GetID() <<" "<< link[0].second->GetID()
9700                 << " F 1: " << face[0] << "| Link 2: " << link[1].first->GetID() <<" "
9701                 << link[1].second->GetID() << " F 2: " << face[1] << " | Bind: " ) ;
9702 #endif
9703       int nbN = nbNodes[0];
9704       {
9705         list<const SMDS_MeshNode*>::iterator n1 = notLinkNodes[0].begin();
9706         list<const SMDS_MeshNode*>::iterator n2 = notLinkNodes[1].begin();
9707         for ( int i = 0 ; i < nbN - 2; ++i ) {
9708 #ifdef DEBUG_MATCHING_NODES
9709           MESSAGE ( (*n1)->GetID() << " to " << (*n2)->GetID() );
9710 #endif
9711           nReplaceMap.insert( make_pair( *(n1++), *(n2++) ));
9712         }
9713       }
9714
9715       // add other links of the face 1 to linkList
9716       // -----------------------------------------
9717
9718       const SMDS_MeshElement* f0 = face[0];
9719       const SMDS_MeshNode* n1 = f0->GetNode( nbN - 1 );
9720       for ( int i = 0; i < nbN; i++ )
9721       {
9722         const SMDS_MeshNode* n2 = f0->GetNode( i );
9723         pair< set< SMESH_TLink >::iterator, bool > iter_isnew =
9724           linkSet.insert( SMESH_TLink( n1, n2 ));
9725         if ( !iter_isnew.second ) { // already in a set: no need to process
9726           linkSet.erase( iter_isnew.first );
9727         }
9728         else // new in set == encountered for the first time: add
9729         {
9730 #ifdef DEBUG_MATCHING_NODES
9731           MESSAGE ( "Add link 1: " << n1->GetID() << " " << n2->GetID() << " "
9732                     << " | link 2: " << nReplaceMap[n1]->GetID() << " " << nReplaceMap[n2]->GetID() << " " );
9733 #endif
9734           linkList[0].push_back ( NLink( n1, n2 ));
9735           linkList[1].push_back ( NLink( nReplaceMap[n1], nReplaceMap[n2] ));
9736         }
9737         n1 = n2;
9738       }
9739     } // 2 faces found
9740   } // loop on link lists
9741
9742   return SEW_OK;
9743 }
9744
9745 //================================================================================
9746 /*!
9747   \brief Creates a hole in a mesh by doubling the nodes of some particular elements
9748   \param theElems - the list of elements (edges or faces) to be replicated
9749   The nodes for duplication could be found from these elements
9750   \param theNodesNot - list of nodes to NOT replicate
9751   \param theAffectedElems - the list of elements (cells and edges) to which the 
9752   replicated nodes should be associated to.
9753   \return TRUE if operation has been completed successfully, FALSE otherwise
9754 */
9755 //================================================================================
9756
9757 bool SMESH_MeshEditor::DoubleNodes( const TIDSortedElemSet& theElems,
9758                                     const TIDSortedElemSet& theNodesNot,
9759                                     const TIDSortedElemSet& theAffectedElems )
9760 {
9761   myLastCreatedElems.Clear();
9762   myLastCreatedNodes.Clear();
9763
9764   if ( theElems.size() == 0 )
9765     return false;
9766
9767   SMESHDS_Mesh* aMeshDS = GetMeshDS();
9768   if ( !aMeshDS )
9769     return false;
9770
9771   bool res = false;
9772   std::map< const SMDS_MeshNode*, const SMDS_MeshNode* > anOldNodeToNewNode;
9773   // duplicate elements and nodes
9774   res = doubleNodes( aMeshDS, theElems, theNodesNot, anOldNodeToNewNode, true );
9775   // replce nodes by duplications
9776   res = doubleNodes( aMeshDS, theAffectedElems, theNodesNot, anOldNodeToNewNode, false );
9777   return res;
9778 }
9779
9780 //================================================================================
9781 /*!
9782   \brief Creates a hole in a mesh by doubling the nodes of some particular elements
9783   \param theMeshDS - mesh instance
9784   \param theElems - the elements replicated or modified (nodes should be changed)
9785   \param theNodesNot - nodes to NOT replicate
9786   \param theNodeNodeMap - relation of old node to new created node
9787   \param theIsDoubleElem - flag os to replicate element or modify
9788   \return TRUE if operation has been completed successfully, FALSE otherwise
9789 */
9790 //================================================================================
9791
9792 bool SMESH_MeshEditor::doubleNodes( SMESHDS_Mesh*     theMeshDS,
9793                                     const TIDSortedElemSet& theElems,
9794                                     const TIDSortedElemSet& theNodesNot,
9795                                     std::map< const SMDS_MeshNode*,
9796                                     const SMDS_MeshNode* >& theNodeNodeMap,
9797                                     const bool theIsDoubleElem )
9798 {
9799   // iterate on through element and duplicate them (by nodes duplication)
9800   bool res = false;
9801   TIDSortedElemSet::const_iterator elemItr = theElems.begin();
9802   for ( ;  elemItr != theElems.end(); ++elemItr )
9803   {
9804     const SMDS_MeshElement* anElem = *elemItr;
9805     if (!anElem)
9806       continue;
9807
9808     bool isDuplicate = false;
9809     // duplicate nodes to duplicate element
9810     std::vector<const SMDS_MeshNode*> newNodes( anElem->NbNodes() );
9811     SMDS_ElemIteratorPtr anIter = anElem->nodesIterator();
9812     int ind = 0;
9813     while ( anIter->more() ) 
9814     { 
9815
9816       SMDS_MeshNode* aCurrNode = (SMDS_MeshNode*)anIter->next();
9817       SMDS_MeshNode* aNewNode = aCurrNode;
9818       if ( theNodeNodeMap.find( aCurrNode ) != theNodeNodeMap.end() )
9819         aNewNode = (SMDS_MeshNode*)theNodeNodeMap[ aCurrNode ];
9820       else if ( theIsDoubleElem && theNodesNot.find( aCurrNode ) == theNodesNot.end() )
9821       {
9822         // duplicate node
9823         aNewNode = theMeshDS->AddNode( aCurrNode->X(), aCurrNode->Y(), aCurrNode->Z() );
9824         theNodeNodeMap[ aCurrNode ] = aNewNode;
9825         myLastCreatedNodes.Append( aNewNode );
9826       }
9827       isDuplicate |= (aCurrNode != aNewNode);
9828       newNodes[ ind++ ] = aNewNode;
9829     }
9830     if ( !isDuplicate )
9831       continue;
9832
9833     if ( theIsDoubleElem )
9834       AddElement(newNodes, anElem->GetType(), anElem->IsPoly());
9835     else
9836       theMeshDS->ChangeElementNodes( anElem, &newNodes[ 0 ], anElem->NbNodes() );
9837
9838     res = true;
9839   }
9840   return res;
9841 }
9842
9843 //================================================================================
9844 /*!
9845   \brief Creates a hole in a mesh by doubling the nodes of some particular elements
9846   \param theNodes - identifiers of nodes to be doubled
9847   \param theModifiedElems - identifiers of elements to be updated by the new (doubled) 
9848          nodes. If list of element identifiers is empty then nodes are doubled but 
9849          they not assigned to elements
9850   \return TRUE if operation has been completed successfully, FALSE otherwise
9851 */
9852 //================================================================================
9853
9854 bool SMESH_MeshEditor::DoubleNodes( const std::list< int >& theListOfNodes, 
9855                                     const std::list< int >& theListOfModifiedElems )
9856 {
9857   myLastCreatedElems.Clear();
9858   myLastCreatedNodes.Clear();
9859
9860   if ( theListOfNodes.size() == 0 )
9861     return false;
9862
9863   SMESHDS_Mesh* aMeshDS = GetMeshDS();
9864   if ( !aMeshDS )
9865     return false;
9866
9867   // iterate through nodes and duplicate them
9868
9869   std::map< const SMDS_MeshNode*, const SMDS_MeshNode* > anOldNodeToNewNode;
9870
9871   std::list< int >::const_iterator aNodeIter;
9872   for ( aNodeIter = theListOfNodes.begin(); aNodeIter != theListOfNodes.end(); ++aNodeIter )
9873   {
9874     int aCurr = *aNodeIter;
9875     SMDS_MeshNode* aNode = (SMDS_MeshNode*)aMeshDS->FindNode( aCurr );
9876     if ( !aNode )
9877       continue;
9878
9879     // duplicate node
9880
9881     const SMDS_MeshNode* aNewNode = aMeshDS->AddNode( aNode->X(), aNode->Y(), aNode->Z() );
9882     if ( aNewNode )
9883     {
9884       anOldNodeToNewNode[ aNode ] = aNewNode;
9885       myLastCreatedNodes.Append( aNewNode );
9886     }
9887   }
9888
9889   // Create map of new nodes for modified elements
9890
9891   std::map< SMDS_MeshElement*, vector<const SMDS_MeshNode*> > anElemToNodes;
9892
9893   std::list< int >::const_iterator anElemIter;
9894   for ( anElemIter = theListOfModifiedElems.begin(); 
9895         anElemIter != theListOfModifiedElems.end(); ++anElemIter )
9896   {
9897     int aCurr = *anElemIter;
9898     SMDS_MeshElement* anElem = (SMDS_MeshElement*)aMeshDS->FindElement( aCurr );
9899     if ( !anElem )
9900       continue;
9901
9902     vector<const SMDS_MeshNode*> aNodeArr( anElem->NbNodes() );
9903
9904     SMDS_ElemIteratorPtr anIter = anElem->nodesIterator();
9905     int ind = 0;
9906     while ( anIter->more() ) 
9907     { 
9908       SMDS_MeshNode* aCurrNode = (SMDS_MeshNode*)anIter->next();
9909       if ( aCurr && anOldNodeToNewNode.find( aCurrNode ) != anOldNodeToNewNode.end() )
9910       {
9911         const SMDS_MeshNode* aNewNode = anOldNodeToNewNode[ aCurrNode ];
9912         aNodeArr[ ind++ ] = aNewNode;
9913       }
9914       else
9915         aNodeArr[ ind++ ] = aCurrNode;
9916     }
9917     anElemToNodes[ anElem ] = aNodeArr;
9918   }
9919
9920   // Change nodes of elements  
9921
9922   std::map< SMDS_MeshElement*, vector<const SMDS_MeshNode*> >::iterator
9923     anElemToNodesIter = anElemToNodes.begin();
9924   for ( ; anElemToNodesIter != anElemToNodes.end(); ++anElemToNodesIter )
9925   {
9926     const SMDS_MeshElement* anElem = anElemToNodesIter->first;
9927     vector<const SMDS_MeshNode*> aNodeArr = anElemToNodesIter->second;
9928     if ( anElem )
9929       aMeshDS->ChangeElementNodes( anElem, &aNodeArr[ 0 ], anElem->NbNodes() );
9930   }
9931
9932   return true;
9933 }
9934
9935 namespace {
9936
9937   //================================================================================
9938   /*!
9939   \brief Check if element located inside shape
9940   \return TRUE if IN or ON shape, FALSE otherwise
9941   */
9942   //================================================================================
9943
9944   template<class Classifier>
9945   bool isInside(const SMDS_MeshElement* theElem,
9946                 Classifier&             theClassifier,
9947                 const double            theTol)
9948   {
9949     gp_XYZ centerXYZ (0, 0, 0);
9950     SMDS_ElemIteratorPtr aNodeItr = theElem->nodesIterator();
9951     while (aNodeItr->more())
9952       centerXYZ += SMESH_MeshEditor::TNodeXYZ(cast2Node( aNodeItr->next()));
9953
9954     gp_Pnt aPnt = centerXYZ / theElem->NbNodes();
9955     theClassifier.Perform(aPnt, theTol);
9956     TopAbs_State aState = theClassifier.State();
9957     return (aState == TopAbs_IN || aState == TopAbs_ON );
9958   }
9959
9960   //================================================================================
9961   /*!
9962    * \brief Classifier of the 3D point on the TopoDS_Face
9963    *        with interaface suitable for isInside()
9964    */
9965   //================================================================================
9966
9967   struct _FaceClassifier
9968   {
9969     Extrema_ExtPS       _extremum;
9970     BRepAdaptor_Surface _surface;
9971     TopAbs_State        _state;
9972
9973     _FaceClassifier(const TopoDS_Face& face):_extremum(),_surface(face),_state(TopAbs_OUT)
9974     {
9975       _extremum.Initialize( _surface,
9976                             _surface.FirstUParameter(), _surface.LastUParameter(),
9977                             _surface.FirstVParameter(), _surface.LastVParameter(),
9978                             _surface.Tolerance(), _surface.Tolerance() );
9979     }
9980     void Perform(const gp_Pnt& aPnt, double theTol)
9981     {
9982       _state = TopAbs_OUT;
9983       _extremum.Perform(aPnt);
9984       if ( _extremum.IsDone() )
9985         for ( int iSol = 1; iSol <= _extremum.NbExt() && _state == TopAbs_OUT; ++iSol)
9986           _state = ( _extremum.Value(iSol) <= theTol ? TopAbs_IN : TopAbs_OUT );
9987     }
9988     TopAbs_State State() const
9989     {
9990       return _state;
9991     }
9992   };
9993 }
9994
9995 //================================================================================
9996 /*!
9997   \brief Creates a hole in a mesh by doubling the nodes of some particular elements
9998   \param theElems - group of of elements (edges or faces) to be replicated
9999   \param theNodesNot - group of nodes not to replicate
10000   \param theShape - shape to detect affected elements (element which geometric center
10001   located on or inside shape).
10002   The replicated nodes should be associated to affected elements.
10003   \return TRUE if operation has been completed successfully, FALSE otherwise
10004 */
10005 //================================================================================
10006
10007 bool SMESH_MeshEditor::DoubleNodesInRegion( const TIDSortedElemSet& theElems,
10008                                             const TIDSortedElemSet& theNodesNot,
10009                                             const TopoDS_Shape&     theShape )
10010 {
10011   if ( theShape.IsNull() )
10012     return false;
10013
10014   const double aTol = Precision::Confusion();
10015   auto_ptr< BRepClass3d_SolidClassifier> bsc3d;
10016   auto_ptr<_FaceClassifier>              aFaceClassifier;
10017   if ( theShape.ShapeType() == TopAbs_SOLID )
10018   {
10019     bsc3d.reset( new BRepClass3d_SolidClassifier(theShape));;
10020     bsc3d->PerformInfinitePoint(aTol);
10021   }
10022   else if (theShape.ShapeType() == TopAbs_FACE )
10023   {
10024     aFaceClassifier.reset( new _FaceClassifier(TopoDS::Face(theShape)));
10025   }
10026
10027   // iterates on indicated elements and get elements by back references from their nodes
10028   TIDSortedElemSet anAffected;
10029   TIDSortedElemSet::const_iterator elemItr = theElems.begin();
10030   for ( ;  elemItr != theElems.end(); ++elemItr )
10031   {
10032     SMDS_MeshElement* anElem = (SMDS_MeshElement*)*elemItr;
10033     if (!anElem)
10034       continue;
10035
10036     SMDS_ElemIteratorPtr nodeItr = anElem->nodesIterator();
10037     while ( nodeItr->more() )
10038     {
10039       const SMDS_MeshNode* aNode = cast2Node(nodeItr->next());
10040       if ( !aNode || theNodesNot.find(aNode) != theNodesNot.end() )
10041         continue;
10042       SMDS_ElemIteratorPtr backElemItr = aNode->GetInverseElementIterator();
10043       while ( backElemItr->more() )
10044       {
10045         const SMDS_MeshElement* curElem = backElemItr->next();
10046         if ( curElem && theElems.find(curElem) == theElems.end() &&
10047              ( bsc3d.get() ?
10048                isInside( curElem, *bsc3d, aTol ) :
10049                isInside( curElem, *aFaceClassifier, aTol )))
10050           anAffected.insert( curElem );
10051       }
10052     }
10053   }
10054   return DoubleNodes( theElems, theNodesNot, anAffected );
10055 }
10056
10057 //================================================================================
10058 /*!
10059  * \brief Generates skin mesh (containing 2D cells) from 3D mesh
10060  * The created 2D mesh elements based on nodes of free faces of boundary volumes
10061  * \return TRUE if operation has been completed successfully, FALSE otherwise
10062  */
10063 //================================================================================
10064
10065 bool SMESH_MeshEditor::Make2DMeshFrom3D()
10066 {
10067   // iterates on volume elements and detect all free faces on them
10068   SMESHDS_Mesh* aMesh = GetMeshDS();
10069   if (!aMesh)
10070     return false;
10071   //bool res = false;
10072   int nbFree = 0, nbExisted = 0, nbCreated = 0;
10073   SMDS_VolumeIteratorPtr vIt = aMesh->volumesIterator();
10074   while(vIt->more())
10075   {
10076     const SMDS_MeshVolume* volume = vIt->next();
10077     SMDS_VolumeTool vTool( volume );
10078     vTool.SetExternalNormal();
10079     const bool isPoly = volume->IsPoly();
10080     const bool isQuad = volume->IsQuadratic();
10081     for ( int iface = 0, n = vTool.NbFaces(); iface < n; iface++ )
10082     {
10083       if (!vTool.IsFreeFace(iface))
10084         continue;
10085       nbFree++;
10086       vector<const SMDS_MeshNode *> nodes;
10087       int nbFaceNodes = vTool.NbFaceNodes(iface);
10088       const SMDS_MeshNode** faceNodes = vTool.GetFaceNodes(iface);
10089       int inode = 0;
10090       for ( ; inode < nbFaceNodes; inode += isQuad ? 2 : 1)
10091         nodes.push_back(faceNodes[inode]);
10092       if (isQuad)
10093         for ( inode = 1; inode < nbFaceNodes; inode += 2)
10094           nodes.push_back(faceNodes[inode]);
10095
10096       // add new face based on volume nodes
10097       if (aMesh->FindFace( nodes ) ) {
10098         nbExisted++;
10099         continue; // face already exsist
10100       }
10101       AddElement(nodes, SMDSAbs_Face, isPoly && iface == 1);
10102       nbCreated++;
10103     }
10104   }
10105   return ( nbFree==(nbExisted+nbCreated) );
10106 }
10107
10108 namespace
10109 {
10110   inline const SMDS_MeshNode* getNodeWithSameID(SMESHDS_Mesh* mesh, const SMDS_MeshNode* node)
10111   {
10112     if ( const SMDS_MeshNode* n = mesh->FindNode( node->GetID() ))
10113       return n;
10114     return mesh->AddNodeWithID( node->X(),node->Y(),node->Z(), node->GetID() );
10115   }
10116 }
10117 //================================================================================
10118 /*!
10119  * \brief Creates missing boundary elements
10120  *  \param elements - elements whose boundary is to be checked
10121  *  \param dimension - defines type of boundary elements to create
10122  *  \param group - a group to store created boundary elements in
10123  *  \param targetMesh - a mesh to store created boundary elements in
10124  *  \param toCopyElements - if true, the checked elements will be copied into the targetMesh
10125  *  \param toCopyExistingBondary - if true, not only new but also pre-existing 
10126  *                                boundary elements will be copied into the targetMesh
10127  */
10128 //================================================================================
10129
10130 void SMESH_MeshEditor::MakeBoundaryMesh(const TIDSortedElemSet& elements,
10131                                         Bnd_Dimension           dimension,
10132                                         SMESH_Group*            group/*=0*/,
10133                                         SMESH_Mesh*             targetMesh/*=0*/,
10134                                         bool                    toCopyElements/*=false*/,
10135                                         bool                    toCopyExistingBondary/*=false*/)
10136 {
10137   SMDSAbs_ElementType missType = (dimension == BND_2DFROM3D) ? SMDSAbs_Face : SMDSAbs_Edge;
10138   SMDSAbs_ElementType elemType = (dimension == BND_1DFROM2D) ? SMDSAbs_Face : SMDSAbs_Volume;
10139   // hope that all elements are of the same type, do not check them all
10140   if ( !elements.empty() && (*elements.begin())->GetType() != elemType )
10141     throw SALOME_Exception(LOCALIZED("wrong element type"));
10142
10143   if ( !targetMesh )
10144     toCopyElements = toCopyExistingBondary = false;
10145
10146   SMESH_MeshEditor tgtEditor( targetMesh ? targetMesh : myMesh );
10147   SMESHDS_Mesh* aMesh = GetMeshDS(), *tgtMeshDS = tgtEditor.GetMeshDS();
10148
10149   SMDS_VolumeTool vTool;
10150   TIDSortedElemSet emptySet, avoidSet;
10151   int inode;
10152
10153   typedef vector<const SMDS_MeshNode*> TConnectivity;
10154
10155   SMDS_ElemIteratorPtr eIt;
10156   if (elements.empty())
10157     eIt = aMesh->elementsIterator(elemType);
10158   else
10159     eIt = SMDS_ElemIteratorPtr( new TSetIterator( elements.begin(), elements.end() ));
10160
10161   while (eIt->more())
10162   {
10163     const SMDS_MeshElement* elem = eIt->next();
10164     const int iQuad = elem->IsQuadratic();
10165
10166     // 1. For an elem, get present bnd elements and connectivities of missing bnd elements
10167     vector<const SMDS_MeshElement*> presentBndElems;
10168     vector<TConnectivity>           missingBndElems;
10169     TConnectivity nodes;
10170     if ( vTool.Set(elem) ) // elem is a volume ------------------------------------------
10171     { 
10172       vTool.SetExternalNormal();
10173       for ( int iface = 0, n = vTool.NbFaces(); iface < n; iface++ )
10174       {
10175         if (!vTool.IsFreeFace(iface))
10176           continue;
10177         int nbFaceNodes = vTool.NbFaceNodes(iface);
10178         const SMDS_MeshNode** nn = vTool.GetFaceNodes(iface);
10179         if ( missType == SMDSAbs_Edge ) // boundary edges
10180         {
10181           nodes.resize( 2+iQuad );
10182           for ( int i = 0; i < nbFaceNodes; i += 1+iQuad)
10183           {
10184             for ( int j = 0; j < nodes.size(); ++j )
10185               nodes[j] =nn[i+j];
10186             if ( const SMDS_MeshElement* edge =
10187                  aMesh->FindElement(nodes,SMDSAbs_Edge,/*noMedium=*/0))
10188               presentBndElems.push_back( edge );
10189             else
10190               missingBndElems.push_back( nodes );
10191           }
10192         }
10193         else // boundary face
10194         {
10195           nodes.clear();
10196           for ( inode = 0; inode < nbFaceNodes; inode += 1+iQuad)
10197             nodes.push_back( nn[inode] );
10198           if (iQuad)
10199             for ( inode = 1; inode < nbFaceNodes; inode += 2)
10200               nodes.push_back( nn[inode] );
10201
10202           if (const SMDS_MeshFace * f = aMesh->FindFace( nodes ) )
10203             presentBndElems.push_back( f );
10204           else
10205             missingBndElems.push_back( nodes );
10206         }
10207       }
10208     }
10209     else                     // elem is a face ------------------------------------------
10210     {
10211       avoidSet.clear(), avoidSet.insert( elem );
10212       int nbNodes = elem->NbCornerNodes();
10213       nodes.resize( 2 /*+ iQuad*/);
10214       for ( int i = 0; i < nbNodes; i++ )
10215       {
10216         nodes[0] = elem->GetNode(i);
10217         nodes[1] = elem->GetNode((i+1)%nbNodes);
10218         if ( FindFaceInSet( nodes[0], nodes[1], emptySet, avoidSet))
10219           continue; // not free link
10220
10221         //if ( iQuad )
10222         //nodes[2] = elem->GetNode( i + nbNodes );
10223         if ( const SMDS_MeshElement* edge =
10224              aMesh->FindElement(nodes,SMDSAbs_Edge,/*noMedium=*/true))
10225           presentBndElems.push_back( edge );
10226         else
10227           missingBndElems.push_back( nodes );
10228       }
10229     }
10230
10231     // 2. Add missing boundary elements
10232     if ( targetMesh != myMesh )
10233       // instead of making a map of nodes in this mesh and targetMesh,
10234       // we create nodes with same IDs. We can renumber them later, if needed
10235       for ( int i = 0; i < missingBndElems.size(); ++i )
10236       {
10237         TConnectivity& srcNodes = missingBndElems[i];
10238         TConnectivity  nodes( srcNodes.size() );
10239         for ( inode = 0; inode < nodes.size(); ++inode )
10240           nodes[inode] = getNodeWithSameID( tgtMeshDS, srcNodes[inode] );
10241         tgtEditor.AddElement(nodes, missType, elem->IsPoly() && nodes.size()/(iQuad+1)>4);
10242       }
10243     else
10244       for ( int i = 0; i < missingBndElems.size(); ++i )
10245       {
10246         TConnectivity&  nodes = missingBndElems[i];
10247         tgtEditor.AddElement(nodes, missType, elem->IsPoly() && nodes.size()/(iQuad+1)>4);
10248       }
10249
10250     // 3. Copy present boundary elements
10251     if ( toCopyExistingBondary )
10252       for ( int i = 0 ; i < presentBndElems.size(); ++i )
10253       {
10254         const SMDS_MeshElement* e = presentBndElems[i];
10255         TConnectivity nodes( e->NbNodes() );
10256         for ( inode = 0; inode < nodes.size(); ++inode )
10257           nodes[inode] = getNodeWithSameID( tgtMeshDS, e->GetNode(inode) );
10258         tgtEditor.AddElement(nodes, missType, e->IsPoly());
10259         // leave only missing elements in tgtEditor.myLastCreatedElems
10260         tgtEditor.myLastCreatedElems.Remove( tgtEditor.myLastCreatedElems.Size() );
10261       }
10262   } // loop on given elements
10263
10264   // 4. Fill group with missing boundary elements
10265   if ( group )
10266   {
10267     if ( SMESHDS_Group* g = dynamic_cast<SMESHDS_Group*>( group->GetGroupDS() ))
10268       for ( int i = 0; i < tgtEditor.myLastCreatedElems.Size(); ++i )
10269         g->SMDSGroup().Add( tgtEditor.myLastCreatedElems( i+1 ));
10270   }
10271   tgtEditor.myLastCreatedElems.Clear();
10272
10273   // 5. Copy given elements
10274   if ( toCopyElements )
10275   {
10276     if (elements.empty())
10277       eIt = aMesh->elementsIterator(elemType);
10278     else
10279       eIt = SMDS_ElemIteratorPtr( new TSetIterator( elements.begin(), elements.end() ));
10280     while (eIt->more())
10281     {
10282       const SMDS_MeshElement* elem = eIt->next();
10283       TConnectivity nodes( elem->NbNodes() );
10284       for ( inode = 0; inode < nodes.size(); ++inode )
10285         nodes[inode] = getNodeWithSameID( tgtMeshDS, elem->GetNode(inode) );
10286       tgtEditor.AddElement(nodes, elemType, elem->IsPoly());
10287
10288       tgtEditor.myLastCreatedElems.Clear();
10289     }
10290   }
10291   return;
10292 }