Salome HOME
Merge from V6_main 13/12/2012
[modules/smesh.git] / src / SMESH / SMESH_MeshEditor.cxx
1 // Copyright (C) 2007-2012  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 // File      : SMESH_MeshEditor.cxx
24 // Created   : Mon Apr 12 16:10:22 2004
25 // Author    : Edward AGAPOV (eap)
26
27 #include "SMESH_MeshEditor.hxx"
28
29 #include "SMDS_FaceOfNodes.hxx"
30 #include "SMDS_VolumeTool.hxx"
31 #include "SMDS_EdgePosition.hxx"
32 #include "SMDS_FacePosition.hxx"
33 #include "SMDS_SpacePosition.hxx"
34 #include "SMDS_MeshGroup.hxx"
35 #include "SMDS_LinearEdge.hxx"
36 #include "SMDS_Downward.hxx"
37 #include "SMDS_SetIterator.hxx"
38
39 #include "SMESHDS_Group.hxx"
40 #include "SMESHDS_Mesh.hxx"
41
42 #include "SMESH_Algo.hxx"
43 #include "SMESH_ControlsDef.hxx"
44 #include "SMESH_Group.hxx"
45 #include "SMESH_MesherHelper.hxx"
46 #include "SMESH_OctreeNode.hxx"
47 #include "SMESH_subMesh.hxx"
48
49 #include <Basics_OCCTVersion.hxx>
50
51 #include "utilities.h"
52
53 #include <BRepAdaptor_Surface.hxx>
54 #include <BRepBuilderAPI_MakeEdge.hxx>
55 #include <BRepClass3d_SolidClassifier.hxx>
56 #include <BRep_Tool.hxx>
57 #include <ElCLib.hxx>
58 #include <Extrema_GenExtPS.hxx>
59 #include <Extrema_POnCurv.hxx>
60 #include <Extrema_POnSurf.hxx>
61 #include <GC_MakeSegment.hxx>
62 #include <Geom2d_Curve.hxx>
63 #include <GeomAPI_ExtremaCurveCurve.hxx>
64 #include <GeomAdaptor_Surface.hxx>
65 #include <Geom_Curve.hxx>
66 #include <Geom_Line.hxx>
67 #include <Geom_Surface.hxx>
68 #include <IntAna_IntConicQuad.hxx>
69 #include <IntAna_Quadric.hxx>
70 #include <Precision.hxx>
71 #include <TColStd_ListOfInteger.hxx>
72 #include <TopAbs_State.hxx>
73 #include <TopExp.hxx>
74 #include <TopExp_Explorer.hxx>
75 #include <TopTools_ListIteratorOfListOfShape.hxx>
76 #include <TopTools_ListOfShape.hxx>
77 #include <TopTools_SequenceOfShape.hxx>
78 #include <TopoDS.hxx>
79 #include <TopoDS_Face.hxx>
80 #include <TopoDS_Solid.hxx>
81 #include <gp.hxx>
82 #include <gp_Ax1.hxx>
83 #include <gp_Dir.hxx>
84 #include <gp_Lin.hxx>
85 #include <gp_Pln.hxx>
86 #include <gp_Trsf.hxx>
87 #include <gp_Vec.hxx>
88 #include <gp_XY.hxx>
89 #include <gp_XYZ.hxx>
90
91 #include <cmath>
92
93 #include <map>
94 #include <set>
95 #include <numeric>
96 #include <limits>
97 #include <algorithm>
98 #include <sstream>
99
100 #include <Standard_Failure.hxx>
101 #include <Standard_ErrorHandler.hxx>
102
103 #define cast2Node(elem) static_cast<const SMDS_MeshNode*>( elem )
104
105 using namespace std;
106 using namespace SMESH::Controls;
107
108 typedef map<const SMDS_MeshElement*, list<const SMDS_MeshNode*> >    TElemOfNodeListMap;
109 typedef map<const SMDS_MeshElement*, list<const SMDS_MeshElement*> > TElemOfElemListMap;
110
111 typedef SMDS_SetIterator< SMDS_pElement, TIDSortedElemSet::const_iterator> TSetIterator;
112
113 //=======================================================================
114 //function : SMESH_MeshEditor
115 //purpose  :
116 //=======================================================================
117
118 SMESH_MeshEditor::SMESH_MeshEditor( SMESH_Mesh* theMesh )
119   :myMesh( theMesh ) // theMesh may be NULL
120 {
121 }
122
123 //================================================================================
124 /*!
125  * \brief Clears myLastCreatedNodes and myLastCreatedElems
126  */
127 //================================================================================
128
129 void SMESH_MeshEditor::CrearLastCreated()
130 {
131   myLastCreatedNodes.Clear();
132   myLastCreatedElems.Clear();
133 }
134
135
136 //=======================================================================
137 /*!
138  * \brief Add element
139  */
140 //=======================================================================
141
142 SMDS_MeshElement*
143 SMESH_MeshEditor::AddElement(const vector<const SMDS_MeshNode*> & node,
144                              const SMDSAbs_ElementType            type,
145                              const bool                           isPoly,
146                              const int                            ID,
147                              const double                         ballDiameter)
148 {
149   //MESSAGE("AddElement " <<node.size() << " " << type << " " << isPoly << " " << ID);
150   SMDS_MeshElement* e = 0;
151   int nbnode = node.size();
152   SMESHDS_Mesh* mesh = GetMeshDS();
153   switch ( type ) {
154   case SMDSAbs_Face:
155     if ( !isPoly ) {
156       if      (nbnode == 3) {
157         if ( ID >= 1 ) e = mesh->AddFaceWithID(node[0], node[1], node[2], ID);
158         else           e = mesh->AddFace      (node[0], node[1], node[2] );
159       }
160       else if (nbnode == 4) {
161         if ( ID >= 1 ) e = mesh->AddFaceWithID(node[0], node[1], node[2], node[3], ID);
162         else           e = mesh->AddFace      (node[0], node[1], node[2], node[3] );
163       }
164       else if (nbnode == 6) {
165         if ( ID >= 1 ) e = mesh->AddFaceWithID(node[0], node[1], node[2], node[3],
166                                                node[4], node[5], ID);
167         else           e = mesh->AddFace      (node[0], node[1], node[2], node[3],
168                                                node[4], node[5] );
169       }
170       else if (nbnode == 8) {
171         if ( ID >= 1 ) e = mesh->AddFaceWithID(node[0], node[1], node[2], node[3],
172                                                node[4], node[5], node[6], node[7], ID);
173         else           e = mesh->AddFace      (node[0], node[1], node[2], node[3],
174                                                node[4], node[5], node[6], node[7] );
175       }
176       else if (nbnode == 9) {
177         if ( ID >= 1 ) e = mesh->AddFaceWithID(node[0], node[1], node[2], node[3],
178                                                node[4], node[5], node[6], node[7], node[8], ID);
179         else           e = mesh->AddFace      (node[0], node[1], node[2], node[3],
180                                                node[4], node[5], node[6], node[7], node[8] );
181       }
182     } else {
183       if ( ID >= 1 ) e = mesh->AddPolygonalFaceWithID(node, ID);
184       else           e = mesh->AddPolygonalFace      (node    );
185     }
186     break;
187
188   case SMDSAbs_Volume:
189     if ( !isPoly ) {
190       if      (nbnode == 4) {
191         if ( ID >= 1 ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3], ID);
192         else           e = mesh->AddVolume      (node[0], node[1], node[2], node[3] );
193       }
194       else if (nbnode == 5) {
195         if ( ID >= 1 ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
196                                                  node[4], ID);
197         else           e = mesh->AddVolume      (node[0], node[1], node[2], node[3],
198                                                  node[4] );
199       }
200       else if (nbnode == 6) {
201         if ( ID >= 1 ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
202                                                  node[4], node[5], ID);
203         else           e = mesh->AddVolume      (node[0], node[1], node[2], node[3],
204                                                  node[4], node[5] );
205       }
206       else if (nbnode == 8) {
207         if ( ID >= 1 ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
208                                                  node[4], node[5], node[6], node[7], ID);
209         else           e = mesh->AddVolume      (node[0], node[1], node[2], node[3],
210                                                  node[4], node[5], node[6], node[7] );
211       }
212       else if (nbnode == 10) {
213         if ( ID >= 1 ) 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], ID);
216         else           e = mesh->AddVolume      (node[0], node[1], node[2], node[3],
217                                                  node[4], node[5], node[6], node[7],
218                                                  node[8], node[9] );
219       }
220       else if (nbnode == 12) {
221         if ( ID >= 1 ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
222                                                  node[4], node[5], node[6], node[7],
223                                                  node[8], node[9], node[10], node[11], ID);
224         else           e = mesh->AddVolume      (node[0], node[1], node[2], node[3],
225                                                  node[4], node[5], node[6], node[7],
226                                                  node[8], node[9], node[10], node[11] );
227       }
228       else if (nbnode == 13) {
229         if ( ID >= 1 ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
230                                                  node[4], node[5], node[6], node[7],
231                                                  node[8], node[9], node[10],node[11],
232                                                  node[12],ID);
233         else           e = mesh->AddVolume      (node[0], node[1], node[2], node[3],
234                                                  node[4], node[5], node[6], node[7],
235                                                  node[8], node[9], node[10],node[11],
236                                                  node[12] );
237       }
238       else if (nbnode == 15) {
239         if ( ID >= 1 ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
240                                                  node[4], node[5], node[6], node[7],
241                                                  node[8], node[9], node[10],node[11],
242                                                  node[12],node[13],node[14],ID);
243         else           e = mesh->AddVolume      (node[0], node[1], node[2], node[3],
244                                                  node[4], node[5], node[6], node[7],
245                                                  node[8], node[9], node[10],node[11],
246                                                  node[12],node[13],node[14] );
247       }
248       else if (nbnode == 20) {
249         if ( ID >= 1 ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
250                                                  node[4], node[5], node[6], node[7],
251                                                  node[8], node[9], node[10],node[11],
252                                                  node[12],node[13],node[14],node[15],
253                                                  node[16],node[17],node[18],node[19],ID);
254         else           e = mesh->AddVolume      (node[0], node[1], node[2], node[3],
255                                                  node[4], node[5], node[6], node[7],
256                                                  node[8], node[9], node[10],node[11],
257                                                  node[12],node[13],node[14],node[15],
258                                                  node[16],node[17],node[18],node[19] );
259       }
260       else if (nbnode == 27) {
261         if ( ID >= 1 ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
262                                                  node[4], node[5], node[6], node[7],
263                                                  node[8], node[9], node[10],node[11],
264                                                  node[12],node[13],node[14],node[15],
265                                                  node[16],node[17],node[18],node[19],
266                                                  node[20],node[21],node[22],node[23],
267                                                  node[24],node[25],node[26], ID);
268         else           e = mesh->AddVolume      (node[0], node[1], node[2], node[3],
269                                                  node[4], node[5], node[6], node[7],
270                                                  node[8], node[9], node[10],node[11],
271                                                  node[12],node[13],node[14],node[15],
272                                                  node[16],node[17],node[18],node[19],
273                                                  node[20],node[21],node[22],node[23],
274                                                  node[24],node[25],node[26] );
275       }
276     }
277     break;
278
279   case SMDSAbs_Edge:
280     if ( nbnode == 2 ) {
281       if ( ID >= 1 ) e = mesh->AddEdgeWithID(node[0], node[1], ID);
282       else           e = mesh->AddEdge      (node[0], node[1] );
283     }
284     else if ( nbnode == 3 ) {
285       if ( ID >= 1 ) e = mesh->AddEdgeWithID(node[0], node[1], node[2], ID);
286       else           e = mesh->AddEdge      (node[0], node[1], node[2] );
287     }
288     break;
289
290   case SMDSAbs_0DElement:
291     if ( nbnode == 1 ) {
292       if ( ID >= 1 ) e = mesh->Add0DElementWithID(node[0], ID);
293       else           e = mesh->Add0DElement      (node[0] );
294     }
295     break;
296
297   case SMDSAbs_Node:
298     if ( ID >= 1 ) e = mesh->AddNodeWithID(node[0]->X(), node[0]->Y(), node[0]->Z(), ID);
299     else           e = mesh->AddNode      (node[0]->X(), node[0]->Y(), node[0]->Z());
300     break;
301
302   case SMDSAbs_Ball:
303     if ( ID >= 1 ) e = mesh->AddBallWithID(node[0], ballDiameter, ID);
304     else           e = mesh->AddBall      (node[0], ballDiameter);
305     break;
306
307   default:;
308   }
309   if ( e ) myLastCreatedElems.Append( e );
310   return e;
311 }
312
313 //=======================================================================
314 /*!
315  * \brief Add element
316  */
317 //=======================================================================
318
319 SMDS_MeshElement* SMESH_MeshEditor::AddElement(const vector<int> &       nodeIDs,
320                                                const SMDSAbs_ElementType type,
321                                                const bool                isPoly,
322                                                const int                 ID)
323 {
324   vector<const SMDS_MeshNode*> nodes;
325   nodes.reserve( nodeIDs.size() );
326   vector<int>::const_iterator id = nodeIDs.begin();
327   while ( id != nodeIDs.end() ) {
328     if ( const SMDS_MeshNode* node = GetMeshDS()->FindNode( *id++ ))
329       nodes.push_back( node );
330     else
331       return 0;
332   }
333   return AddElement( nodes, type, isPoly, ID );
334 }
335
336 //=======================================================================
337 //function : Remove
338 //purpose  : Remove a node or an element.
339 //           Modify a compute state of sub-meshes which become empty
340 //=======================================================================
341
342 int SMESH_MeshEditor::Remove (const list< int >& theIDs,
343                               const bool         isNodes )
344 {
345   myLastCreatedElems.Clear();
346   myLastCreatedNodes.Clear();
347
348   SMESHDS_Mesh* aMesh = GetMeshDS();
349   set< SMESH_subMesh *> smmap;
350
351   int removed = 0;
352   list<int>::const_iterator it = theIDs.begin();
353   for ( ; it != theIDs.end(); it++ ) {
354     const SMDS_MeshElement * elem;
355     if ( isNodes )
356       elem = aMesh->FindNode( *it );
357     else
358       elem = aMesh->FindElement( *it );
359     if ( !elem )
360       continue;
361
362     // Notify VERTEX sub-meshes about modification
363     if ( isNodes ) {
364       const SMDS_MeshNode* node = cast2Node( elem );
365       if ( node->GetPosition()->GetTypeOfPosition() == SMDS_TOP_VERTEX )
366         if ( int aShapeID = node->getshapeId() )
367           if ( SMESH_subMesh * sm = GetMesh()->GetSubMeshContaining( aShapeID ) )
368             smmap.insert( sm );
369     }
370     // Find sub-meshes to notify about modification
371     //     SMDS_ElemIteratorPtr nodeIt = elem->nodesIterator();
372     //     while ( nodeIt->more() ) {
373     //       const SMDS_MeshNode* node = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
374     //       const SMDS_PositionPtr& aPosition = node->GetPosition();
375     //       if ( aPosition.get() ) {
376     //         if ( int aShapeID = aPosition->GetShapeId() ) {
377     //           if ( SMESH_subMesh * sm = GetMesh()->GetSubMeshContaining( aShapeID ) )
378     //             smmap.insert( sm );
379     //         }
380     //       }
381     //     }
382
383     // Do remove
384     if ( isNodes )
385       aMesh->RemoveNode( static_cast< const SMDS_MeshNode* >( elem ));
386     else
387       aMesh->RemoveElement( elem );
388     removed++;
389   }
390
391   // Notify sub-meshes about modification
392   if ( !smmap.empty() ) {
393     set< SMESH_subMesh *>::iterator smIt;
394     for ( smIt = smmap.begin(); smIt != smmap.end(); smIt++ )
395       (*smIt)->ComputeStateEngine( SMESH_subMesh::MESH_ENTITY_REMOVED );
396   }
397
398   //   // Check if the whole mesh becomes empty
399   //   if ( SMESH_subMesh * sm = GetMesh()->GetSubMeshContaining( 1 ) )
400   //     sm->ComputeStateEngine( SMESH_subMesh::CHECK_COMPUTE_STATE );
401
402   return removed;
403 }
404
405 //================================================================================
406 /*!
407  * \brief Create 0D elements on all nodes of the given object except those
408  *        nodes on which a 0D element already exists.
409  *  \param elements - Elements on whose nodes to create 0D elements; if empty, 
410  *                    the all mesh is treated
411  *  \param all0DElems - returns all 0D elements found or created on nodes of \a elements
412  */
413 //================================================================================
414
415 void SMESH_MeshEditor::Create0DElementsOnAllNodes( const TIDSortedElemSet& elements,
416                                                    TIDSortedElemSet&       all0DElems )
417 {
418   typedef SMDS_SetIterator<const SMDS_MeshElement*, TIDSortedElemSet::const_iterator> TSetIterator;
419   SMDS_ElemIteratorPtr elemIt;
420   if ( elements.empty() )
421     elemIt = GetMeshDS()->elementsIterator( SMDSAbs_Node );
422   else
423     elemIt = SMDS_ElemIteratorPtr( new TSetIterator( elements.begin(), elements.end() ));
424
425   while ( elemIt->more() )
426   {
427     const SMDS_MeshElement* e = elemIt->next();
428     SMDS_ElemIteratorPtr nodeIt = e->nodesIterator();
429     while ( nodeIt->more() )
430     {
431       const SMDS_MeshNode* n = cast2Node( nodeIt->next() );
432       SMDS_ElemIteratorPtr it0D = n->GetInverseElementIterator( SMDSAbs_0DElement );
433       if ( it0D->more() )
434         all0DElems.insert( it0D->next() );
435       else {
436         myLastCreatedElems.Append( GetMeshDS()->Add0DElement( n ));
437         all0DElems.insert( myLastCreatedElems.Last() );
438       }
439     }
440   }
441 }
442
443 //=======================================================================
444 //function : FindShape
445 //purpose  : Return an index of the shape theElem is on
446 //           or zero if a shape not found
447 //=======================================================================
448
449 int SMESH_MeshEditor::FindShape (const SMDS_MeshElement * theElem)
450 {
451   myLastCreatedElems.Clear();
452   myLastCreatedNodes.Clear();
453
454   SMESHDS_Mesh * aMesh = GetMeshDS();
455   if ( aMesh->ShapeToMesh().IsNull() )
456     return 0;
457
458   int aShapeID = theElem->getshapeId();
459   if ( aShapeID < 1 )
460     return 0;
461
462   if ( SMESHDS_SubMesh * sm = aMesh->MeshElements( aShapeID ))
463     if ( sm->Contains( theElem ))
464       return aShapeID;
465
466   if ( theElem->GetType() == SMDSAbs_Node ) {
467     MESSAGE( ":( Error: invalid myShapeId of node " << theElem->GetID() );
468   }
469   else {
470     MESSAGE( ":( Error: invalid myShapeId of element " << theElem->GetID() );
471   }
472
473   TopoDS_Shape aShape; // the shape a node of theElem is on
474   if ( theElem->GetType() != SMDSAbs_Node )
475   {
476     SMDS_ElemIteratorPtr nodeIt = theElem->nodesIterator();
477     while ( nodeIt->more() ) {
478       const SMDS_MeshNode* node = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
479       if ((aShapeID = node->getshapeId()) > 0) {
480         if ( SMESHDS_SubMesh * sm = aMesh->MeshElements( aShapeID ) ) {
481           if ( sm->Contains( theElem ))
482             return aShapeID;
483           if ( aShape.IsNull() )
484             aShape = aMesh->IndexToShape( aShapeID );
485         }
486       }
487     }
488   }
489
490   // None of nodes is on a proper shape,
491   // find the shape among ancestors of aShape on which a node is
492   if ( !aShape.IsNull() ) {
493     TopTools_ListIteratorOfListOfShape ancIt( GetMesh()->GetAncestors( aShape ));
494     for ( ; ancIt.More(); ancIt.Next() ) {
495       SMESHDS_SubMesh * sm = aMesh->MeshElements( ancIt.Value() );
496       if ( sm && sm->Contains( theElem ))
497         return aMesh->ShapeToIndex( ancIt.Value() );
498     }
499   }
500   else
501   {
502     const map<int,SMESHDS_SubMesh*>& id2sm = GetMeshDS()->SubMeshes();
503     map<int,SMESHDS_SubMesh*>::const_iterator id_sm = id2sm.begin();
504     for ( ; id_sm != id2sm.end(); ++id_sm )
505       if ( id_sm->second->Contains( theElem ))
506         return id_sm->first;
507   }
508
509   //MESSAGE ("::FindShape() - SHAPE NOT FOUND")
510   return 0;
511 }
512
513 //=======================================================================
514 //function : IsMedium
515 //purpose  :
516 //=======================================================================
517
518 bool SMESH_MeshEditor::IsMedium(const SMDS_MeshNode*      node,
519                                 const SMDSAbs_ElementType typeToCheck)
520 {
521   bool isMedium = false;
522   SMDS_ElemIteratorPtr it = node->GetInverseElementIterator(typeToCheck);
523   while (it->more() && !isMedium ) {
524     const SMDS_MeshElement* elem = it->next();
525     isMedium = elem->IsMediumNode(node);
526   }
527   return isMedium;
528 }
529
530 //=======================================================================
531 //function : ShiftNodesQuadTria
532 //purpose  : auxilary
533 //           Shift nodes in the array corresponded to quadratic triangle
534 //           example: (0,1,2,3,4,5) -> (1,2,0,4,5,3)
535 //=======================================================================
536 static void ShiftNodesQuadTria(const SMDS_MeshNode* aNodes[])
537 {
538   const SMDS_MeshNode* nd1 = aNodes[0];
539   aNodes[0] = aNodes[1];
540   aNodes[1] = aNodes[2];
541   aNodes[2] = nd1;
542   const SMDS_MeshNode* nd2 = aNodes[3];
543   aNodes[3] = aNodes[4];
544   aNodes[4] = aNodes[5];
545   aNodes[5] = nd2;
546 }
547
548 //=======================================================================
549 //function : edgeConnectivity
550 //purpose  : auxilary
551 //           return number of the edges connected with the theNode.
552 //           if theEdges has connections with the other type of the
553 //           elements, return -1
554 //=======================================================================
555 static int nbEdgeConnectivity(const SMDS_MeshNode* theNode)
556 {
557   SMDS_ElemIteratorPtr elemIt = theNode->GetInverseElementIterator();
558   int nb=0;
559   while(elemIt->more()) {
560     elemIt->next();
561     nb++;
562   }
563   return nb;
564 }
565
566
567 //=======================================================================
568 //function : GetNodesFromTwoTria
569 //purpose  : auxilary
570 //           Shift nodes in the array corresponded to quadratic triangle
571 //           example: (0,1,2,3,4,5) -> (1,2,0,4,5,3)
572 //=======================================================================
573 static bool GetNodesFromTwoTria(const SMDS_MeshElement * theTria1,
574                                 const SMDS_MeshElement * theTria2,
575                                 const SMDS_MeshNode* N1[],
576                                 const SMDS_MeshNode* N2[])
577 {
578   SMDS_ElemIteratorPtr it = theTria1->nodesIterator();
579   int i=0;
580   while(i<6) {
581     N1[i] = static_cast<const SMDS_MeshNode*>( it->next() );
582     i++;
583   }
584   if(it->more()) return false;
585   it = theTria2->nodesIterator();
586   i=0;
587   while(i<6) {
588     N2[i] = static_cast<const SMDS_MeshNode*>( it->next() );
589     i++;
590   }
591   if(it->more()) return false;
592
593   int sames[3] = {-1,-1,-1};
594   int nbsames = 0;
595   int j;
596   for(i=0; i<3; i++) {
597     for(j=0; j<3; j++) {
598       if(N1[i]==N2[j]) {
599         sames[i] = j;
600         nbsames++;
601         break;
602       }
603     }
604   }
605   if(nbsames!=2) return false;
606   if(sames[0]>-1) {
607     ShiftNodesQuadTria(N1);
608     if(sames[1]>-1) {
609       ShiftNodesQuadTria(N1);
610     }
611   }
612   i = sames[0] + sames[1] + sames[2];
613   for(; i<2; i++) {
614     ShiftNodesQuadTria(N2);
615   }
616   // now we receive following N1 and N2 (using numeration as above image)
617   // tria1 : (1 2 4 5 9 7)  and  tria2 : (3 4 2 8 9 6)
618   // i.e. first nodes from both arrays determ new diagonal
619   return true;
620 }
621
622 //=======================================================================
623 //function : InverseDiag
624 //purpose  : Replace two neighbour triangles with ones built on the same 4 nodes
625 //           but having other common link.
626 //           Return False if args are improper
627 //=======================================================================
628
629 bool SMESH_MeshEditor::InverseDiag (const SMDS_MeshElement * theTria1,
630                                     const SMDS_MeshElement * theTria2 )
631 {
632   MESSAGE("InverseDiag");
633   myLastCreatedElems.Clear();
634   myLastCreatedNodes.Clear();
635
636   if (!theTria1 || !theTria2)
637     return false;
638
639   const SMDS_VtkFace* F1 = dynamic_cast<const SMDS_VtkFace*>( theTria1 );
640   if (!F1) return false;
641   const SMDS_VtkFace* F2 = dynamic_cast<const SMDS_VtkFace*>( theTria2 );
642   if (!F2) return false;
643   if ((theTria1->GetEntityType() == SMDSEntity_Triangle) &&
644       (theTria2->GetEntityType() == SMDSEntity_Triangle)) {
645
646     //  1 +--+ A  theTria1: ( 1 A B ) A->2 ( 1 2 B ) 1 +--+ A
647     //    | /|    theTria2: ( B A 2 ) B->1 ( 1 A 2 )   |\ |
648     //    |/ |                                         | \|
649     //  B +--+ 2                                     B +--+ 2
650
651     // put nodes in array and find out indices of the same ones
652     const SMDS_MeshNode* aNodes [6];
653     int sameInd [] = { 0, 0, 0, 0, 0, 0 };
654     int i = 0;
655     SMDS_ElemIteratorPtr it = theTria1->nodesIterator();
656     while ( it->more() ) {
657       aNodes[ i ] = static_cast<const SMDS_MeshNode*>( it->next() );
658
659       if ( i > 2 ) // theTria2
660         // find same node of theTria1
661         for ( int j = 0; j < 3; j++ )
662           if ( aNodes[ i ] == aNodes[ j ]) {
663             sameInd[ j ] = i;
664             sameInd[ i ] = j;
665             break;
666           }
667       // next
668       i++;
669       if ( i == 3 ) {
670         if ( it->more() )
671           return false; // theTria1 is not a triangle
672         it = theTria2->nodesIterator();
673       }
674       if ( i == 6 && it->more() )
675         return false; // theTria2 is not a triangle
676     }
677
678     // find indices of 1,2 and of A,B in theTria1
679     int iA = 0, iB = 0, i1 = 0, i2 = 0;
680     for ( i = 0; i < 6; i++ ) {
681       if ( sameInd [ i ] == 0 ) {
682         if ( i < 3 ) i1 = i;
683         else         i2 = i;
684       }
685       else if (i < 3) {
686         if ( iA ) iB = i;
687         else      iA = i;
688       }
689     }
690     // nodes 1 and 2 should not be the same
691     if ( aNodes[ i1 ] == aNodes[ i2 ] )
692       return false;
693
694     // theTria1: A->2
695     aNodes[ iA ] = aNodes[ i2 ];
696     // theTria2: B->1
697     aNodes[ sameInd[ iB ]] = aNodes[ i1 ];
698
699     GetMeshDS()->ChangeElementNodes( theTria1, aNodes, 3 );
700     GetMeshDS()->ChangeElementNodes( theTria2, &aNodes[ 3 ], 3 );
701
702     return true;
703
704   } // end if(F1 && F2)
705
706   // check case of quadratic faces
707   if (theTria1->GetEntityType() != SMDSEntity_Quad_Triangle)
708     return false;
709   if (theTria2->GetEntityType() != SMDSEntity_Quad_Triangle)
710     return false;
711
712   //       5
713   //  1 +--+--+ 2  theTria1: (1 2 4 5 9 7) or (2 4 1 9 7 5) or (4 1 2 7 5 9)
714   //    |    /|    theTria2: (2 3 4 6 8 9) or (3 4 2 8 9 6) or (4 2 3 9 6 8)
715   //    |   / |
716   //  7 +  +  + 6
717   //    | /9  |
718   //    |/    |
719   //  4 +--+--+ 3
720   //       8
721
722   const SMDS_MeshNode* N1 [6];
723   const SMDS_MeshNode* N2 [6];
724   if(!GetNodesFromTwoTria(theTria1,theTria2,N1,N2))
725     return false;
726   // now we receive following N1 and N2 (using numeration as above image)
727   // tria1 : (1 2 4 5 9 7)  and  tria2 : (3 4 2 8 9 6)
728   // i.e. first nodes from both arrays determ new diagonal
729
730   const SMDS_MeshNode* N1new [6];
731   const SMDS_MeshNode* N2new [6];
732   N1new[0] = N1[0];
733   N1new[1] = N2[0];
734   N1new[2] = N2[1];
735   N1new[3] = N1[4];
736   N1new[4] = N2[3];
737   N1new[5] = N1[5];
738   N2new[0] = N1[0];
739   N2new[1] = N1[1];
740   N2new[2] = N2[0];
741   N2new[3] = N1[3];
742   N2new[4] = N2[5];
743   N2new[5] = N1[4];
744   // replaces nodes in faces
745   GetMeshDS()->ChangeElementNodes( theTria1, N1new, 6 );
746   GetMeshDS()->ChangeElementNodes( theTria2, N2new, 6 );
747
748   return true;
749 }
750
751 //=======================================================================
752 //function : findTriangles
753 //purpose  : find triangles sharing theNode1-theNode2 link
754 //=======================================================================
755
756 static bool findTriangles(const SMDS_MeshNode *    theNode1,
757                           const SMDS_MeshNode *    theNode2,
758                           const SMDS_MeshElement*& theTria1,
759                           const SMDS_MeshElement*& theTria2)
760 {
761   if ( !theNode1 || !theNode2 ) return false;
762
763   theTria1 = theTria2 = 0;
764
765   set< const SMDS_MeshElement* > emap;
766   SMDS_ElemIteratorPtr it = theNode1->GetInverseElementIterator(SMDSAbs_Face);
767   while (it->more()) {
768     const SMDS_MeshElement* elem = it->next();
769     if ( elem->NbNodes() == 3 )
770       emap.insert( elem );
771   }
772   it = theNode2->GetInverseElementIterator(SMDSAbs_Face);
773   while (it->more()) {
774     const SMDS_MeshElement* elem = it->next();
775     if ( emap.find( elem ) != emap.end() ) {
776       if ( theTria1 ) {
777         // theTria1 must be element with minimum ID
778         if( theTria1->GetID() < elem->GetID() ) {
779           theTria2 = elem;
780         }
781         else {
782           theTria2 = theTria1;
783           theTria1 = elem;
784         }
785         break;
786       }
787       else {
788         theTria1 = elem;
789       }
790     }
791   }
792   return ( theTria1 && theTria2 );
793 }
794
795 //=======================================================================
796 //function : InverseDiag
797 //purpose  : Replace two neighbour triangles sharing theNode1-theNode2 link
798 //           with ones built on the same 4 nodes but having other common link.
799 //           Return false if proper faces not found
800 //=======================================================================
801
802 bool SMESH_MeshEditor::InverseDiag (const SMDS_MeshNode * theNode1,
803                                     const SMDS_MeshNode * theNode2)
804 {
805   myLastCreatedElems.Clear();
806   myLastCreatedNodes.Clear();
807
808   MESSAGE( "::InverseDiag()" );
809
810   const SMDS_MeshElement *tr1, *tr2;
811   if ( !findTriangles( theNode1, theNode2, tr1, tr2 ))
812     return false;
813
814   const SMDS_VtkFace* F1 = dynamic_cast<const SMDS_VtkFace*>( tr1 );
815   if (!F1) return false;
816   const SMDS_VtkFace* F2 = dynamic_cast<const SMDS_VtkFace*>( tr2 );
817   if (!F2) return false;
818   if ((tr1->GetEntityType() == SMDSEntity_Triangle) &&
819       (tr2->GetEntityType() == SMDSEntity_Triangle)) {
820
821     //  1 +--+ A  tr1: ( 1 A B ) A->2 ( 1 2 B ) 1 +--+ A
822     //    | /|    tr2: ( B A 2 ) B->1 ( 1 A 2 )   |\ |
823     //    |/ |                                    | \|
824     //  B +--+ 2                                B +--+ 2
825
826     // put nodes in array
827     // and find indices of 1,2 and of A in tr1 and of B in tr2
828     int i, iA1 = 0, i1 = 0;
829     const SMDS_MeshNode* aNodes1 [3];
830     SMDS_ElemIteratorPtr it;
831     for (i = 0, it = tr1->nodesIterator(); it->more(); i++ ) {
832       aNodes1[ i ] = static_cast<const SMDS_MeshNode*>( it->next() );
833       if ( aNodes1[ i ] == theNode1 )
834         iA1 = i; // node A in tr1
835       else if ( aNodes1[ i ] != theNode2 )
836         i1 = i;  // node 1
837     }
838     int iB2 = 0, i2 = 0;
839     const SMDS_MeshNode* aNodes2 [3];
840     for (i = 0, it = tr2->nodesIterator(); it->more(); i++ ) {
841       aNodes2[ i ] = static_cast<const SMDS_MeshNode*>( it->next() );
842       if ( aNodes2[ i ] == theNode2 )
843         iB2 = i; // node B in tr2
844       else if ( aNodes2[ i ] != theNode1 )
845         i2 = i;  // node 2
846     }
847
848     // nodes 1 and 2 should not be the same
849     if ( aNodes1[ i1 ] == aNodes2[ i2 ] )
850       return false;
851
852     // tr1: A->2
853     aNodes1[ iA1 ] = aNodes2[ i2 ];
854     // tr2: B->1
855     aNodes2[ iB2 ] = aNodes1[ i1 ];
856
857     GetMeshDS()->ChangeElementNodes( tr1, aNodes1, 3 );
858     GetMeshDS()->ChangeElementNodes( tr2, aNodes2, 3 );
859
860     return true;
861   }
862
863   // check case of quadratic faces
864   return InverseDiag(tr1,tr2);
865 }
866
867 //=======================================================================
868 //function : getQuadrangleNodes
869 //purpose  : fill theQuadNodes - nodes of a quadrangle resulting from
870 //           fusion of triangles tr1 and tr2 having shared link on
871 //           theNode1 and theNode2
872 //=======================================================================
873
874 bool getQuadrangleNodes(const SMDS_MeshNode *    theQuadNodes [],
875                         const SMDS_MeshNode *    theNode1,
876                         const SMDS_MeshNode *    theNode2,
877                         const SMDS_MeshElement * tr1,
878                         const SMDS_MeshElement * tr2 )
879 {
880   if( tr1->NbNodes() != tr2->NbNodes() )
881     return false;
882   // find the 4-th node to insert into tr1
883   const SMDS_MeshNode* n4 = 0;
884   SMDS_ElemIteratorPtr it = tr2->nodesIterator();
885   int i=0;
886   while ( !n4 && i<3 ) {
887     const SMDS_MeshNode * n = cast2Node( it->next() );
888     i++;
889     bool isDiag = ( n == theNode1 || n == theNode2 );
890     if ( !isDiag )
891       n4 = n;
892   }
893   // Make an array of nodes to be in a quadrangle
894   int iNode = 0, iFirstDiag = -1;
895   it = tr1->nodesIterator();
896   i=0;
897   while ( i<3 ) {
898     const SMDS_MeshNode * n = cast2Node( it->next() );
899     i++;
900     bool isDiag = ( n == theNode1 || n == theNode2 );
901     if ( isDiag ) {
902       if ( iFirstDiag < 0 )
903         iFirstDiag = iNode;
904       else if ( iNode - iFirstDiag == 1 )
905         theQuadNodes[ iNode++ ] = n4; // insert the 4-th node between diagonal nodes
906     }
907     else if ( n == n4 ) {
908       return false; // tr1 and tr2 should not have all the same nodes
909     }
910     theQuadNodes[ iNode++ ] = n;
911   }
912   if ( iNode == 3 ) // diagonal nodes have 0 and 2 indices
913     theQuadNodes[ iNode ] = n4;
914
915   return true;
916 }
917
918 //=======================================================================
919 //function : DeleteDiag
920 //purpose  : Replace two neighbour triangles sharing theNode1-theNode2 link
921 //           with a quadrangle built on the same 4 nodes.
922 //           Return false if proper faces not found
923 //=======================================================================
924
925 bool SMESH_MeshEditor::DeleteDiag (const SMDS_MeshNode * theNode1,
926                                    const SMDS_MeshNode * theNode2)
927 {
928   myLastCreatedElems.Clear();
929   myLastCreatedNodes.Clear();
930
931   MESSAGE( "::DeleteDiag()" );
932
933   const SMDS_MeshElement *tr1, *tr2;
934   if ( !findTriangles( theNode1, theNode2, tr1, tr2 ))
935     return false;
936
937   const SMDS_VtkFace* F1 = dynamic_cast<const SMDS_VtkFace*>( tr1 );
938   if (!F1) return false;
939   const SMDS_VtkFace* F2 = dynamic_cast<const SMDS_VtkFace*>( tr2 );
940   if (!F2) return false;
941   SMESHDS_Mesh * aMesh = GetMeshDS();
942
943   if ((tr1->GetEntityType() == SMDSEntity_Triangle) &&
944       (tr2->GetEntityType() == SMDSEntity_Triangle)) {
945
946     const SMDS_MeshNode* aNodes [ 4 ];
947     if ( ! getQuadrangleNodes( aNodes, theNode1, theNode2, tr1, tr2 ))
948       return false;
949
950     const SMDS_MeshElement* newElem = 0;
951     newElem = aMesh->AddFace( aNodes[0], aNodes[1], aNodes[2], aNodes[3] );
952     myLastCreatedElems.Append(newElem);
953     AddToSameGroups( newElem, tr1, aMesh );
954     int aShapeId = tr1->getshapeId();
955     if ( aShapeId )
956       {
957         aMesh->SetMeshElementOnShape( newElem, aShapeId );
958       }
959     aMesh->RemoveElement( tr1 );
960     aMesh->RemoveElement( tr2 );
961
962     return true;
963   }
964
965   // check case of quadratic faces
966   if (tr1->GetEntityType() != SMDSEntity_Quad_Triangle)
967     return false;
968   if (tr2->GetEntityType() != SMDSEntity_Quad_Triangle)
969     return false;
970
971   //       5
972   //  1 +--+--+ 2  tr1: (1 2 4 5 9 7) or (2 4 1 9 7 5) or (4 1 2 7 5 9)
973   //    |    /|    tr2: (2 3 4 6 8 9) or (3 4 2 8 9 6) or (4 2 3 9 6 8)
974   //    |   / |
975   //  7 +  +  + 6
976   //    | /9  |
977   //    |/    |
978   //  4 +--+--+ 3
979   //       8
980
981   const SMDS_MeshNode* N1 [6];
982   const SMDS_MeshNode* N2 [6];
983   if(!GetNodesFromTwoTria(tr1,tr2,N1,N2))
984     return false;
985   // now we receive following N1 and N2 (using numeration as above image)
986   // tria1 : (1 2 4 5 9 7)  and  tria2 : (3 4 2 8 9 6)
987   // i.e. first nodes from both arrays determ new diagonal
988
989   const SMDS_MeshNode* aNodes[8];
990   aNodes[0] = N1[0];
991   aNodes[1] = N1[1];
992   aNodes[2] = N2[0];
993   aNodes[3] = N2[1];
994   aNodes[4] = N1[3];
995   aNodes[5] = N2[5];
996   aNodes[6] = N2[3];
997   aNodes[7] = N1[5];
998
999   const SMDS_MeshElement* newElem = 0;
1000   newElem = aMesh->AddFace( aNodes[0], aNodes[1], aNodes[2], aNodes[3],
1001                             aNodes[4], aNodes[5], aNodes[6], aNodes[7]);
1002   myLastCreatedElems.Append(newElem);
1003   AddToSameGroups( newElem, tr1, aMesh );
1004   int aShapeId = tr1->getshapeId();
1005   if ( aShapeId )
1006     {
1007       aMesh->SetMeshElementOnShape( newElem, aShapeId );
1008     }
1009   aMesh->RemoveElement( tr1 );
1010   aMesh->RemoveElement( tr2 );
1011
1012   // remove middle node (9)
1013   GetMeshDS()->RemoveNode( N1[4] );
1014
1015   return true;
1016 }
1017
1018 //=======================================================================
1019 //function : Reorient
1020 //purpose  : Reverse theElement orientation
1021 //=======================================================================
1022
1023 bool SMESH_MeshEditor::Reorient (const SMDS_MeshElement * theElem)
1024 {
1025   MESSAGE("Reorient");
1026   myLastCreatedElems.Clear();
1027   myLastCreatedNodes.Clear();
1028
1029   if (!theElem)
1030     return false;
1031   SMDS_ElemIteratorPtr it = theElem->nodesIterator();
1032   if ( !it || !it->more() )
1033     return false;
1034
1035   switch ( theElem->GetType() ) {
1036
1037   case SMDSAbs_Edge:
1038   case SMDSAbs_Face: {
1039     if(!theElem->IsQuadratic()) {
1040       int i = theElem->NbNodes();
1041       vector<const SMDS_MeshNode*> aNodes( i );
1042       while ( it->more() )
1043         aNodes[ --i ]= static_cast<const SMDS_MeshNode*>( it->next() );
1044       return GetMeshDS()->ChangeElementNodes( theElem, &aNodes[0], theElem->NbNodes() );
1045     }
1046     else {
1047       // quadratic elements
1048       if(theElem->GetType()==SMDSAbs_Edge) {
1049         vector<const SMDS_MeshNode*> aNodes(3);
1050         aNodes[1]= static_cast<const SMDS_MeshNode*>( it->next() );
1051         aNodes[0]= static_cast<const SMDS_MeshNode*>( it->next() );
1052         aNodes[2]= static_cast<const SMDS_MeshNode*>( it->next() );
1053         return GetMeshDS()->ChangeElementNodes( theElem, &aNodes[0], 3 );
1054       }
1055       else {
1056         int nbn = theElem->NbNodes();
1057         vector<const SMDS_MeshNode*> aNodes(nbn);
1058         aNodes[0]= static_cast<const SMDS_MeshNode*>( it->next() );
1059         int i=1;
1060         for(; i<nbn/2; i++) {
1061           aNodes[nbn/2-i]= static_cast<const SMDS_MeshNode*>( it->next() );
1062         }
1063         for(i=0; i<nbn/2; i++) {
1064           aNodes[nbn-i-1]= static_cast<const SMDS_MeshNode*>( it->next() );
1065         }
1066         return GetMeshDS()->ChangeElementNodes( theElem, &aNodes[0], nbn );
1067       }
1068     }
1069   }
1070   case SMDSAbs_Volume: {
1071     if (theElem->IsPoly()) {
1072       // TODO reorient vtk polyhedron
1073       MESSAGE("reorient vtk polyhedron ?");
1074       const SMDS_VtkVolume* aPolyedre =
1075         dynamic_cast<const SMDS_VtkVolume*>( theElem );
1076       if (!aPolyedre) {
1077         MESSAGE("Warning: bad volumic element");
1078         return false;
1079       }
1080
1081       int nbFaces = aPolyedre->NbFaces();
1082       vector<const SMDS_MeshNode *> poly_nodes;
1083       vector<int> quantities (nbFaces);
1084
1085       // reverse each face of the polyedre
1086       for (int iface = 1; iface <= nbFaces; iface++) {
1087         int inode, nbFaceNodes = aPolyedre->NbFaceNodes(iface);
1088         quantities[iface - 1] = nbFaceNodes;
1089
1090         for (inode = nbFaceNodes; inode >= 1; inode--) {
1091           const SMDS_MeshNode* curNode = aPolyedre->GetFaceNode(iface, inode);
1092           poly_nodes.push_back(curNode);
1093         }
1094       }
1095
1096       return GetMeshDS()->ChangePolyhedronNodes( theElem, poly_nodes, quantities );
1097
1098     }
1099     else {
1100       SMDS_VolumeTool vTool;
1101       if ( !vTool.Set( theElem ))
1102         return false;
1103       vTool.Inverse();
1104       MESSAGE("ChangeElementNodes reorient: check vTool.Inverse");
1105       return GetMeshDS()->ChangeElementNodes( theElem, vTool.GetNodes(), vTool.NbNodes() );
1106     }
1107   }
1108   default:;
1109   }
1110
1111   return false;
1112 }
1113
1114 //================================================================================
1115 /*!
1116  * \brief Reorient faces.
1117  * \param theFaces - the faces to reorient. If empty the whole mesh is meant
1118  * \param theDirection - desired direction of normal of \a theFace
1119  * \param theFace - one of \a theFaces that sould be oriented according to
1120  *        \a theDirection and whose orientation defines orientation of other faces
1121  * \return number of reoriented faces.
1122  */
1123 //================================================================================
1124
1125 int SMESH_MeshEditor::Reorient2D (TIDSortedElemSet &       theFaces,
1126                                   const gp_Dir&            theDirection,
1127                                   const SMDS_MeshElement * theFace)
1128 {
1129   int nbReori = 0;
1130   if ( !theFace || theFace->GetType() != SMDSAbs_Face ) return nbReori;
1131
1132   if ( theFaces.empty() )
1133   {
1134     SMDS_FaceIteratorPtr fIt = GetMeshDS()->facesIterator(/*idInceasingOrder=*/true);
1135     while ( fIt->more() )
1136       theFaces.insert( theFaces.end(), fIt->next() );
1137   }
1138
1139   // orient theFace according to theDirection
1140   gp_XYZ normal;
1141   SMESH_Algo::FaceNormal( theFace, normal, /*normalized=*/false );
1142   if ( normal * theDirection.XYZ() < 0 )
1143     nbReori += Reorient( theFace );
1144
1145   // Orient other faces
1146
1147   set< const SMDS_MeshElement* > startFaces, visitedFaces;
1148   TIDSortedElemSet avoidSet;
1149   set< SMESH_TLink > checkedLinks;
1150   pair< set< SMESH_TLink >::iterator, bool > linkIt_isNew;
1151
1152   if ( theFaces.size() > 1 )// leave 1 face to prevent finding not selected faces
1153     theFaces.erase( theFace );
1154   startFaces.insert( theFace );
1155
1156   int nodeInd1, nodeInd2;
1157   const SMDS_MeshElement*           otherFace;
1158   vector< const SMDS_MeshElement* > facesNearLink;
1159   vector< std::pair< int, int > >   nodeIndsOfFace;
1160
1161   set< const SMDS_MeshElement* >::iterator startFace = startFaces.begin();
1162   while ( !startFaces.empty() )
1163   {
1164     startFace = startFaces.begin();
1165     theFace = *startFace;
1166     startFaces.erase( startFace );
1167     if ( !visitedFaces.insert( theFace ).second )
1168       continue;
1169
1170     avoidSet.clear();
1171     avoidSet.insert(theFace);
1172
1173     NLink link( theFace->GetNode( 0 ), 0 );
1174
1175     const int nbNodes = theFace->NbCornerNodes();
1176     for ( int i = 0; i < nbNodes; ++i ) // loop on links of theFace
1177     {
1178       link.second = theFace->GetNode(( i+1 ) % nbNodes );
1179       linkIt_isNew = checkedLinks.insert( link );
1180       if ( !linkIt_isNew.second )
1181       {
1182         // link has already been checked and won't be encountered more
1183         // if the group (theFaces) is manifold
1184         //checkedLinks.erase( linkIt_isNew.first );
1185       }
1186       else
1187       {
1188         facesNearLink.clear();
1189         nodeIndsOfFace.clear();
1190         while (( otherFace = FindFaceInSet( link.first, link.second,
1191                                             theFaces, avoidSet, &nodeInd1, &nodeInd2 )))
1192           if ( otherFace != theFace)
1193           {
1194             facesNearLink.push_back( otherFace );
1195             nodeIndsOfFace.push_back( make_pair( nodeInd1, nodeInd2 ));
1196             avoidSet.insert( otherFace );
1197           }
1198         if ( facesNearLink.size() > 1 )
1199         {
1200           // NON-MANIFOLD mesh shell !
1201           // select a face most co-directed with theFace,
1202           // other faces won't be visited this time
1203           gp_XYZ NF, NOF;
1204           SMESH_Algo::FaceNormal( theFace, NF, /*normalized=*/false );
1205           double proj, maxProj = -1;
1206           for ( size_t i = 0; i < facesNearLink.size(); ++i ) {
1207             SMESH_Algo::FaceNormal( facesNearLink[i], NOF, /*normalized=*/false );
1208             if (( proj = Abs( NF * NOF )) > maxProj ) {
1209               maxProj = proj;
1210               otherFace = facesNearLink[i];
1211               nodeInd1  = nodeIndsOfFace[i].first;
1212               nodeInd2  = nodeIndsOfFace[i].second;
1213             }
1214           }
1215           // not to visit rejected faces
1216           for ( size_t i = 0; i < facesNearLink.size(); ++i )
1217             if ( facesNearLink[i] != otherFace && theFaces.size() > 1 )
1218               visitedFaces.insert( facesNearLink[i] );
1219         }
1220         else if ( facesNearLink.size() == 1 )
1221         {
1222           otherFace = facesNearLink[0];
1223           nodeInd1  = nodeIndsOfFace.back().first;
1224           nodeInd2  = nodeIndsOfFace.back().second;
1225         }
1226         if ( otherFace && otherFace != theFace)
1227         {
1228           // link must be reverse in otherFace if orientation ot otherFace
1229           // is same as that of theFace
1230           if ( abs(nodeInd2-nodeInd1) == 1 ? nodeInd2 > nodeInd1 : nodeInd1 > nodeInd2 )
1231           {
1232             nbReori += Reorient( otherFace );
1233           }
1234           startFaces.insert( otherFace );
1235         }
1236       }
1237       std::swap( link.first, link.second ); // reverse the link
1238     }
1239   }
1240   return nbReori;
1241 }
1242
1243 //=======================================================================
1244 //function : getBadRate
1245 //purpose  :
1246 //=======================================================================
1247
1248 static double getBadRate (const SMDS_MeshElement*               theElem,
1249                           SMESH::Controls::NumericalFunctorPtr& theCrit)
1250 {
1251   SMESH::Controls::TSequenceOfXYZ P;
1252   if ( !theElem || !theCrit->GetPoints( theElem, P ))
1253     return 1e100;
1254   return theCrit->GetBadRate( theCrit->GetValue( P ), theElem->NbNodes() );
1255   //return theCrit->GetBadRate( theCrit->GetValue( theElem->GetID() ), theElem->NbNodes() );
1256 }
1257
1258 //=======================================================================
1259 //function : QuadToTri
1260 //purpose  : Cut quadrangles into triangles.
1261 //           theCrit is used to select a diagonal to cut
1262 //=======================================================================
1263
1264 bool SMESH_MeshEditor::QuadToTri (TIDSortedElemSet &                   theElems,
1265                                   SMESH::Controls::NumericalFunctorPtr theCrit)
1266 {
1267   myLastCreatedElems.Clear();
1268   myLastCreatedNodes.Clear();
1269
1270   MESSAGE( "::QuadToTri()" );
1271
1272   if ( !theCrit.get() )
1273     return false;
1274
1275   SMESHDS_Mesh * aMesh = GetMeshDS();
1276
1277   Handle(Geom_Surface) surface;
1278   SMESH_MesherHelper   helper( *GetMesh() );
1279
1280   TIDSortedElemSet::iterator itElem;
1281   for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
1282     const SMDS_MeshElement* elem = *itElem;
1283     if ( !elem || elem->GetType() != SMDSAbs_Face )
1284       continue;
1285     if ( elem->NbCornerNodes() != 4 )
1286       continue;
1287
1288     // retrieve element nodes
1289     vector< const SMDS_MeshNode* > aNodes( elem->begin_nodes(), elem->end_nodes() );
1290
1291     // compare two sets of possible triangles
1292     double aBadRate1, aBadRate2; // to what extent a set is bad
1293     SMDS_FaceOfNodes tr1 ( aNodes[0], aNodes[1], aNodes[2] );
1294     SMDS_FaceOfNodes tr2 ( aNodes[2], aNodes[3], aNodes[0] );
1295     aBadRate1 = getBadRate( &tr1, theCrit ) + getBadRate( &tr2, theCrit );
1296
1297     SMDS_FaceOfNodes tr3 ( aNodes[1], aNodes[2], aNodes[3] );
1298     SMDS_FaceOfNodes tr4 ( aNodes[3], aNodes[0], aNodes[1] );
1299     aBadRate2 = getBadRate( &tr3, theCrit ) + getBadRate( &tr4, theCrit );
1300
1301     int aShapeId = FindShape( elem );
1302     const SMDS_MeshElement* newElem1 = 0;
1303     const SMDS_MeshElement* newElem2 = 0;
1304
1305     if( !elem->IsQuadratic() ) {
1306
1307       // split liner quadrangle
1308       // for MaxElementLength2D functor we return minimum diagonal for splitting,
1309       // because aBadRate1=2*len(diagonal 1-3); aBadRate2=2*len(diagonal 2-4)
1310       if ( aBadRate1 <= aBadRate2 ) {
1311         // tr1 + tr2 is better
1312         newElem1 = aMesh->AddFace( aNodes[2], aNodes[3], aNodes[0] );
1313         newElem2 = aMesh->AddFace( aNodes[2], aNodes[0], aNodes[1] );
1314       }
1315       else {
1316         // tr3 + tr4 is better
1317         newElem1 = aMesh->AddFace( aNodes[3], aNodes[0], aNodes[1] );
1318         newElem2 = aMesh->AddFace( aNodes[3], aNodes[1], aNodes[2] );
1319       }
1320     }
1321     else {
1322
1323       // split quadratic quadrangle
1324
1325       // get surface elem is on
1326       if ( aShapeId != helper.GetSubShapeID() ) {
1327         surface.Nullify();
1328         TopoDS_Shape shape;
1329         if ( aShapeId > 0 )
1330           shape = aMesh->IndexToShape( aShapeId );
1331         if ( !shape.IsNull() && shape.ShapeType() == TopAbs_FACE ) {
1332           TopoDS_Face face = TopoDS::Face( shape );
1333           surface = BRep_Tool::Surface( face );
1334           if ( !surface.IsNull() )
1335             helper.SetSubShape( shape );
1336         }
1337       }
1338       // find middle point for (0,1,2,3)
1339       // and create a node in this point;
1340       const SMDS_MeshNode* newN = 0;
1341       if ( aNodes.size() == 9 )
1342       {
1343         // SMDSEntity_BiQuad_Quadrangle
1344         newN = aNodes.back();
1345       }
1346       else
1347       {
1348         gp_XYZ p( 0,0,0 );
1349         if ( surface.IsNull() )
1350         {
1351           for ( int i = 0; i < 4; i++ )
1352             p += gp_XYZ(aNodes[i]->X(), aNodes[i]->Y(), aNodes[i]->Z() );
1353           p /= 4;
1354         }
1355         else
1356         {
1357           const SMDS_MeshNode* inFaceNode = 0;
1358           if ( helper.GetNodeUVneedInFaceNode() )
1359             for ( size_t i = 0; i < aNodes.size() && !inFaceNode; ++i )
1360               if ( aNodes[ i ]->GetPosition()->GetTypeOfPosition() == SMDS_TOP_FACE )
1361                 inFaceNode = aNodes[ i ];
1362
1363           TopoDS_Face face = TopoDS::Face( helper.GetSubShape() );
1364           gp_XY uv( 0,0 );
1365           for ( int i = 0; i < 4; i++ )
1366             uv += helper.GetNodeUV( face, aNodes[i], inFaceNode );
1367           uv /= 4.;
1368           p = surface->Value( uv.X(), uv.Y() ).XYZ();
1369         }
1370         newN = aMesh->AddNode( p.X(), p.Y(), p.Z() );
1371         myLastCreatedNodes.Append(newN);
1372       }
1373       // create a new element
1374       if ( aBadRate1 <= aBadRate2 ) {
1375         newElem1 = aMesh->AddFace(aNodes[2], aNodes[3], aNodes[0],
1376                                   aNodes[6], aNodes[7], newN );
1377         newElem2 = aMesh->AddFace(aNodes[2], aNodes[0], aNodes[1],
1378                                   newN,      aNodes[4], aNodes[5] );
1379       }
1380       else {
1381         newElem1 = aMesh->AddFace(aNodes[3], aNodes[0], aNodes[1],
1382                                   aNodes[7], aNodes[4], newN );
1383         newElem2 = aMesh->AddFace(aNodes[3], aNodes[1], aNodes[2],
1384                                   newN,      aNodes[5], aNodes[6] );
1385       }
1386     } // quadratic case
1387
1388     // care of a new element
1389
1390     myLastCreatedElems.Append(newElem1);
1391     myLastCreatedElems.Append(newElem2);
1392     AddToSameGroups( newElem1, elem, aMesh );
1393     AddToSameGroups( newElem2, elem, aMesh );
1394
1395     // put a new triangle on the same shape
1396     if ( aShapeId )
1397       {
1398         aMesh->SetMeshElementOnShape( newElem1, aShapeId );
1399         aMesh->SetMeshElementOnShape( newElem2, aShapeId );
1400       }
1401     aMesh->RemoveElement( elem );
1402   }
1403   return true;
1404 }
1405
1406 //=======================================================================
1407 //function : BestSplit
1408 //purpose  : Find better diagonal for cutting.
1409 //=======================================================================
1410
1411 int SMESH_MeshEditor::BestSplit (const SMDS_MeshElement*              theQuad,
1412                                  SMESH::Controls::NumericalFunctorPtr theCrit)
1413 {
1414   myLastCreatedElems.Clear();
1415   myLastCreatedNodes.Clear();
1416
1417   if (!theCrit.get())
1418     return -1;
1419
1420   if (!theQuad || theQuad->GetType() != SMDSAbs_Face )
1421     return -1;
1422
1423   if( theQuad->NbNodes()==4 ||
1424       (theQuad->NbNodes()==8 && theQuad->IsQuadratic()) ) {
1425
1426     // retrieve element nodes
1427     const SMDS_MeshNode* aNodes [4];
1428     SMDS_ElemIteratorPtr itN = theQuad->nodesIterator();
1429     int i = 0;
1430     //while (itN->more())
1431     while (i<4) {
1432       aNodes[ i++ ] = static_cast<const SMDS_MeshNode*>( itN->next() );
1433     }
1434     // compare two sets of possible triangles
1435     double aBadRate1, aBadRate2; // to what extent a set is bad
1436     SMDS_FaceOfNodes tr1 ( aNodes[0], aNodes[1], aNodes[2] );
1437     SMDS_FaceOfNodes tr2 ( aNodes[2], aNodes[3], aNodes[0] );
1438     aBadRate1 = getBadRate( &tr1, theCrit ) + getBadRate( &tr2, theCrit );
1439
1440     SMDS_FaceOfNodes tr3 ( aNodes[1], aNodes[2], aNodes[3] );
1441     SMDS_FaceOfNodes tr4 ( aNodes[3], aNodes[0], aNodes[1] );
1442     aBadRate2 = getBadRate( &tr3, theCrit ) + getBadRate( &tr4, theCrit );
1443     // for MaxElementLength2D functor we return minimum diagonal for splitting,
1444     // because aBadRate1=2*len(diagonal 1-3); aBadRate2=2*len(diagonal 2-4)
1445     if (aBadRate1 <= aBadRate2) // tr1 + tr2 is better
1446       return 1; // diagonal 1-3
1447
1448     return 2; // diagonal 2-4
1449   }
1450   return -1;
1451 }
1452
1453 namespace
1454 {
1455   // Methods of splitting volumes into tetra
1456
1457   const int theHexTo5_1[5*4+1] =
1458     {
1459       0, 1, 2, 5,    0, 4, 5, 7,     0, 2, 3, 7,    2, 5, 6, 7,     0, 5, 2, 7,   -1
1460     };
1461   const int theHexTo5_2[5*4+1] =
1462     {
1463       1, 2, 3, 6,    1, 4, 5, 6,     0, 1, 3, 4,    3, 4, 6, 7,     1, 3, 4, 6,   -1
1464     };
1465   const int* theHexTo5[2] = { theHexTo5_1, theHexTo5_2 };
1466
1467   const int theHexTo6_1[6*4+1] =
1468     {
1469       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
1470     };
1471   const int theHexTo6_2[6*4+1] =
1472     {
1473       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
1474     };
1475   const int theHexTo6_3[6*4+1] =
1476     {
1477       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
1478     };
1479   const int theHexTo6_4[6*4+1] =
1480     {
1481       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
1482     };
1483   const int* theHexTo6[4] = { theHexTo6_1, theHexTo6_2, theHexTo6_3, theHexTo6_4 };
1484
1485   const int thePyraTo2_1[2*4+1] =
1486     {
1487       0, 1, 2, 4,    0, 2, 3, 4,   -1
1488     };
1489   const int thePyraTo2_2[2*4+1] =
1490     {
1491       1, 2, 3, 4,    1, 3, 0, 4,   -1
1492     };
1493   const int* thePyraTo2[2] = { thePyraTo2_1, thePyraTo2_2 };
1494
1495   const int thePentaTo3_1[3*4+1] =
1496     {
1497       0, 1, 2, 3,    1, 3, 4, 2,     2, 3, 4, 5,    -1
1498     };
1499   const int thePentaTo3_2[3*4+1] =
1500     {
1501       1, 2, 0, 4,    2, 4, 5, 0,     0, 4, 5, 3,    -1
1502     };
1503   const int thePentaTo3_3[3*4+1] =
1504     {
1505       2, 0, 1, 5,    0, 5, 3, 1,     1, 5, 3, 4,    -1
1506     };
1507   const int thePentaTo3_4[3*4+1] =
1508     {
1509       0, 1, 2, 3,    1, 3, 4, 5,     2, 3, 1, 5,    -1
1510     };
1511   const int thePentaTo3_5[3*4+1] =
1512     {
1513       1, 2, 0, 4,    2, 4, 5, 3,     0, 4, 2, 3,    -1
1514     };
1515   const int thePentaTo3_6[3*4+1] =
1516     {
1517       2, 0, 1, 5,    0, 5, 3, 4,     1, 5, 0, 4,    -1
1518     };
1519   const int* thePentaTo3[6] = { thePentaTo3_1, thePentaTo3_2, thePentaTo3_3,
1520                                 thePentaTo3_4, thePentaTo3_5, thePentaTo3_6 };
1521
1522   struct TTriangleFacet //!< stores indices of three nodes of tetra facet
1523   {
1524     int _n1, _n2, _n3;
1525     TTriangleFacet(int n1, int n2, int n3): _n1(n1), _n2(n2), _n3(n3) {}
1526     bool contains(int n) const { return ( n == _n1 || n == _n2 || n == _n3 ); }
1527     bool hasAdjacentTetra( const SMDS_MeshElement* elem ) const;
1528   };
1529   struct TSplitMethod
1530   {
1531     int        _nbTetra;
1532     const int* _connectivity; //!< foursomes of tetra connectivy finished by -1
1533     bool       _baryNode;     //!< additional node is to be created at cell barycenter
1534     bool       _ownConn;      //!< to delete _connectivity in destructor
1535     map<int, const SMDS_MeshNode*> _faceBaryNode; //!< map face index to node at BC of face
1536
1537     TSplitMethod( int nbTet=0, const int* conn=0, bool addNode=false)
1538       : _nbTetra(nbTet), _connectivity(conn), _baryNode(addNode), _ownConn(false) {}
1539     ~TSplitMethod() { if ( _ownConn ) delete [] _connectivity; _connectivity = 0; }
1540     bool hasFacet( const TTriangleFacet& facet ) const
1541     {
1542       const int* tetConn = _connectivity;
1543       for ( ; tetConn[0] >= 0; tetConn += 4 )
1544         if (( facet.contains( tetConn[0] ) +
1545               facet.contains( tetConn[1] ) +
1546               facet.contains( tetConn[2] ) +
1547               facet.contains( tetConn[3] )) == 3 )
1548           return true;
1549       return false;
1550     }
1551   };
1552
1553   //=======================================================================
1554   /*!
1555    * \brief return TSplitMethod for the given element
1556    */
1557   //=======================================================================
1558
1559   TSplitMethod getSplitMethod( SMDS_VolumeTool& vol, const int theMethodFlags)
1560   {
1561     const int iQ = vol.Element()->IsQuadratic() ? 2 : 1;
1562
1563     // at HEXA_TO_24 method, each face of volume is split into triangles each based on
1564     // an edge and a face barycenter; tertaherdons are based on triangles and
1565     // a volume barycenter
1566     const bool is24TetMode = ( theMethodFlags == SMESH_MeshEditor::HEXA_TO_24 );
1567
1568     // Find out how adjacent volumes are split
1569
1570     vector < list< TTriangleFacet > > triaSplitsByFace( vol.NbFaces() ); // splits of each side
1571     int hasAdjacentSplits = 0, maxTetConnSize = 0;
1572     for ( int iF = 0; iF < vol.NbFaces(); ++iF )
1573     {
1574       int nbNodes = vol.NbFaceNodes( iF ) / iQ;
1575       maxTetConnSize += 4 * ( nbNodes - (is24TetMode ? 0 : 2));
1576       if ( nbNodes < 4 ) continue;
1577
1578       list< TTriangleFacet >& triaSplits = triaSplitsByFace[ iF ];
1579       const int* nInd = vol.GetFaceNodesIndices( iF );
1580       if ( nbNodes == 4 )
1581       {
1582         TTriangleFacet t012( nInd[0*iQ], nInd[1*iQ], nInd[2*iQ] );
1583         TTriangleFacet t123( nInd[1*iQ], nInd[2*iQ], nInd[3*iQ] );
1584         if      ( t012.hasAdjacentTetra( vol.Element() )) triaSplits.push_back( t012 );
1585         else if ( t123.hasAdjacentTetra( vol.Element() )) triaSplits.push_back( t123 );
1586       }
1587       else
1588       {
1589         int iCom = 0; // common node of triangle faces to split into
1590         for ( int iVar = 0; iVar < nbNodes; ++iVar, ++iCom )
1591         {
1592           TTriangleFacet t012( nInd[ iQ * ( iCom             )],
1593                                nInd[ iQ * ( (iCom+1)%nbNodes )],
1594                                nInd[ iQ * ( (iCom+2)%nbNodes )]);
1595           TTriangleFacet t023( nInd[ iQ * ( iCom             )],
1596                                nInd[ iQ * ( (iCom+2)%nbNodes )],
1597                                nInd[ iQ * ( (iCom+3)%nbNodes )]);
1598           if ( t012.hasAdjacentTetra( vol.Element() ) && t023.hasAdjacentTetra( vol.Element() ))
1599           {
1600             triaSplits.push_back( t012 );
1601             triaSplits.push_back( t023 );
1602             break;
1603           }
1604         }
1605       }
1606       if ( !triaSplits.empty() )
1607         hasAdjacentSplits = true;
1608     }
1609
1610     // Among variants of split method select one compliant with adjacent volumes
1611
1612     TSplitMethod method;
1613     if ( !vol.Element()->IsPoly() && !is24TetMode )
1614     {
1615       int nbVariants = 2, nbTet = 0;
1616       const int** connVariants = 0;
1617       switch ( vol.Element()->GetEntityType() )
1618       {
1619       case SMDSEntity_Hexa:
1620       case SMDSEntity_Quad_Hexa:
1621       case SMDSEntity_TriQuad_Hexa:
1622         if ( theMethodFlags == SMESH_MeshEditor::HEXA_TO_5 )
1623           connVariants = theHexTo5, nbTet = 5;
1624         else
1625           connVariants = theHexTo6, nbTet = 6, nbVariants = 4;
1626         break;
1627       case SMDSEntity_Pyramid:
1628       case SMDSEntity_Quad_Pyramid:
1629         connVariants = thePyraTo2;  nbTet = 2;
1630         break;
1631       case SMDSEntity_Penta:
1632       case SMDSEntity_Quad_Penta:
1633         connVariants = thePentaTo3; nbTet = 3; nbVariants = 6;
1634         break;
1635       default:
1636         nbVariants = 0;
1637       }
1638       for ( int variant = 0; variant < nbVariants && method._nbTetra == 0; ++variant )
1639       {
1640         // check method compliancy with adjacent tetras,
1641         // all found splits must be among facets of tetras described by this method
1642         method = TSplitMethod( nbTet, connVariants[variant] );
1643         if ( hasAdjacentSplits && method._nbTetra > 0 )
1644         {
1645           bool facetCreated = true;
1646           for ( int iF = 0; facetCreated && iF < triaSplitsByFace.size(); ++iF )
1647           {
1648             list< TTriangleFacet >::const_iterator facet = triaSplitsByFace[iF].begin();
1649             for ( ; facetCreated && facet != triaSplitsByFace[iF].end(); ++facet )
1650               facetCreated = method.hasFacet( *facet );
1651           }
1652           if ( !facetCreated )
1653             method = TSplitMethod(0); // incompatible method
1654         }
1655       }
1656     }
1657     if ( method._nbTetra < 1 )
1658     {
1659       // No standard method is applicable, use a generic solution:
1660       // each facet of a volume is split into triangles and
1661       // each of triangles and a volume barycenter form a tetrahedron.
1662
1663       const bool isHex27 = ( vol.Element()->GetEntityType() == SMDSEntity_TriQuad_Hexa );
1664
1665       int* connectivity = new int[ maxTetConnSize + 1 ];
1666       method._connectivity = connectivity;
1667       method._ownConn = true;
1668       method._baryNode = !isHex27; // to create central node or not
1669
1670       int connSize = 0;
1671       int baryCenInd = vol.NbNodes() - int( isHex27 );
1672       for ( int iF = 0; iF < vol.NbFaces(); ++iF )
1673       {
1674         const int nbNodes = vol.NbFaceNodes( iF ) / iQ;
1675         const int*   nInd = vol.GetFaceNodesIndices( iF );
1676         // find common node of triangle facets of tetra to create
1677         int iCommon = 0; // index in linear numeration
1678         const list< TTriangleFacet >& triaSplits = triaSplitsByFace[ iF ];
1679         if ( !triaSplits.empty() )
1680         {
1681           // by found facets
1682           const TTriangleFacet* facet = &triaSplits.front();
1683           for ( ; iCommon < nbNodes-1 ; ++iCommon )
1684             if ( facet->contains( nInd[ iQ * iCommon ]) &&
1685                  facet->contains( nInd[ iQ * ((iCommon+2)%nbNodes) ]))
1686               break;
1687         }
1688         else if ( nbNodes > 3 && !is24TetMode )
1689         {
1690           // find the best method of splitting into triangles by aspect ratio
1691           SMESH::Controls::NumericalFunctorPtr aspectRatio( new SMESH::Controls::AspectRatio);
1692           map< double, int > badness2iCommon;
1693           const SMDS_MeshNode** nodes = vol.GetFaceNodes( iF );
1694           int nbVariants = ( nbNodes == 4 ? 2 : nbNodes );
1695           for ( int iVar = 0; iVar < nbVariants; ++iVar, ++iCommon )
1696           {
1697             double badness = 0;
1698             for ( int iLast = iCommon+2; iLast < iCommon+nbNodes; ++iLast )
1699             {
1700               SMDS_FaceOfNodes tria ( nodes[ iQ*( iCommon         )],
1701                                       nodes[ iQ*((iLast-1)%nbNodes)],
1702                                       nodes[ iQ*((iLast  )%nbNodes)]);
1703               badness += getBadRate( &tria, aspectRatio );
1704             }
1705             badness2iCommon.insert( make_pair( badness, iCommon ));
1706           }
1707           // use iCommon with lowest badness
1708           iCommon = badness2iCommon.begin()->second;
1709         }
1710         if ( iCommon >= nbNodes )
1711           iCommon = 0; // something wrong
1712
1713         // fill connectivity of tetrahedra based on a current face
1714         int nbTet = nbNodes - 2;
1715         if ( is24TetMode && nbNodes > 3 && triaSplits.empty())
1716         {
1717           int faceBaryCenInd;
1718           if ( isHex27 )
1719           {
1720             faceBaryCenInd = vol.GetCenterNodeIndex( iF );
1721             method._faceBaryNode[ iF ] = vol.GetNodes()[ faceBaryCenInd ];
1722           }
1723           else
1724           {
1725             method._faceBaryNode[ iF ] = 0;
1726             faceBaryCenInd = baryCenInd + method._faceBaryNode.size();
1727           }
1728           nbTet = nbNodes;
1729           for ( int i = 0; i < nbTet; ++i )
1730           {
1731             int i1 = i, i2 = (i+1) % nbNodes;
1732             if ( !vol.IsFaceExternal( iF )) swap( i1, i2 );
1733             connectivity[ connSize++ ] = nInd[ iQ * i1 ];
1734             connectivity[ connSize++ ] = nInd[ iQ * i2 ];
1735             connectivity[ connSize++ ] = faceBaryCenInd;
1736             connectivity[ connSize++ ] = baryCenInd;
1737           }
1738         }
1739         else
1740         {
1741           for ( int i = 0; i < nbTet; ++i )
1742           {
1743             int i1 = (iCommon+1+i) % nbNodes, i2 = (iCommon+2+i) % nbNodes;
1744             if ( !vol.IsFaceExternal( iF )) swap( i1, i2 );
1745             connectivity[ connSize++ ] = nInd[ iQ * iCommon ];
1746             connectivity[ connSize++ ] = nInd[ iQ * i1 ];
1747             connectivity[ connSize++ ] = nInd[ iQ * i2 ];
1748             connectivity[ connSize++ ] = baryCenInd;
1749           }
1750         }
1751         method._nbTetra += nbTet;
1752
1753       } // loop on volume faces
1754
1755       connectivity[ connSize++ ] = -1;
1756
1757     } // end of generic solution
1758
1759     return method;
1760   }
1761   //================================================================================
1762   /*!
1763    * \brief Check if there is a tetraherdon adjacent to the given element via this facet
1764    */
1765   //================================================================================
1766
1767   bool TTriangleFacet::hasAdjacentTetra( const SMDS_MeshElement* elem ) const
1768   {
1769     // find the tetrahedron including the three nodes of facet
1770     const SMDS_MeshNode* n1 = elem->GetNode(_n1);
1771     const SMDS_MeshNode* n2 = elem->GetNode(_n2);
1772     const SMDS_MeshNode* n3 = elem->GetNode(_n3);
1773     SMDS_ElemIteratorPtr volIt1 = n1->GetInverseElementIterator(SMDSAbs_Volume);
1774     while ( volIt1->more() )
1775     {
1776       const SMDS_MeshElement* v = volIt1->next();
1777       SMDSAbs_EntityType type = v->GetEntityType();
1778       if ( type != SMDSEntity_Tetra && type != SMDSEntity_Quad_Tetra )
1779         continue;
1780       if ( type == SMDSEntity_Quad_Tetra && v->GetNodeIndex( n1 ) > 3 )
1781         continue; // medium node not allowed
1782       const int ind2 = v->GetNodeIndex( n2 );
1783       if ( ind2 < 0 || 3 < ind2 )
1784         continue;
1785       const int ind3 = v->GetNodeIndex( n3 );
1786       if ( ind3 < 0 || 3 < ind3 )
1787         continue;
1788       return true;
1789     }
1790     return false;
1791   }
1792
1793   //=======================================================================
1794   /*!
1795    * \brief A key of a face of volume
1796    */
1797   //=======================================================================
1798
1799   struct TVolumeFaceKey: pair< pair< int, int>, pair< int, int> >
1800   {
1801     TVolumeFaceKey( SMDS_VolumeTool& vol, int iF )
1802     {
1803       TIDSortedNodeSet sortedNodes;
1804       const int iQ = vol.Element()->IsQuadratic() ? 2 : 1;
1805       int nbNodes = vol.NbFaceNodes( iF );
1806       const SMDS_MeshNode** fNodes = vol.GetFaceNodes( iF );
1807       for ( int i = 0; i < nbNodes; i += iQ )
1808         sortedNodes.insert( fNodes[i] );
1809       TIDSortedNodeSet::iterator n = sortedNodes.begin();
1810       first.first   = (*(n++))->GetID();
1811       first.second  = (*(n++))->GetID();
1812       second.first  = (*(n++))->GetID();
1813       second.second = ( sortedNodes.size() > 3 ) ? (*(n++))->GetID() : 0;
1814     }
1815   };
1816 } // namespace
1817
1818 //=======================================================================
1819 //function : SplitVolumesIntoTetra
1820 //purpose  : Split volume elements into tetrahedra.
1821 //=======================================================================
1822
1823 void SMESH_MeshEditor::SplitVolumesIntoTetra (const TIDSortedElemSet & theElems,
1824                                               const int                theMethodFlags)
1825 {
1826   // std-like iterator on coordinates of nodes of mesh element
1827   typedef SMDS_StdIterator< SMESH_TNodeXYZ, SMDS_ElemIteratorPtr > NXyzIterator;
1828   NXyzIterator xyzEnd;
1829
1830   SMDS_VolumeTool    volTool;
1831   SMESH_MesherHelper helper( *GetMesh());
1832
1833   SMESHDS_SubMesh* subMesh = 0;//GetMeshDS()->MeshElements(1);
1834   SMESHDS_SubMesh* fSubMesh = 0;//subMesh;
1835
1836   SMESH_SequenceOfElemPtr newNodes, newElems;
1837
1838   // map face of volume to it's baricenrtic node
1839   map< TVolumeFaceKey, const SMDS_MeshNode* > volFace2BaryNode;
1840   double bc[3];
1841
1842   TIDSortedElemSet::const_iterator elem = theElems.begin();
1843   for ( ; elem != theElems.end(); ++elem )
1844   {
1845     if ( (*elem)->GetType() != SMDSAbs_Volume )
1846       continue;
1847     SMDSAbs_EntityType geomType = (*elem)->GetEntityType();
1848     if ( geomType == SMDSEntity_Tetra || geomType == SMDSEntity_Quad_Tetra )
1849       continue;
1850
1851     if ( !volTool.Set( *elem, /*ignoreCentralNodes=*/false )) continue; // strange...
1852
1853     TSplitMethod splitMethod = getSplitMethod( volTool, theMethodFlags );
1854     if ( splitMethod._nbTetra < 1 ) continue;
1855
1856     // find submesh to add new tetras to
1857     if ( !subMesh || !subMesh->Contains( *elem ))
1858     {
1859       int shapeID = FindShape( *elem );
1860       helper.SetSubShape( shapeID ); // helper will add tetras to the found submesh
1861       subMesh = GetMeshDS()->MeshElements( shapeID );
1862     }
1863     int iQ;
1864     if ( (*elem)->IsQuadratic() )
1865     {
1866       iQ = 2;
1867       // add quadratic links to the helper
1868       for ( int iF = 0; iF < volTool.NbFaces(); ++iF )
1869       {
1870         const SMDS_MeshNode** fNodes = volTool.GetFaceNodes( iF );
1871         int nbN = volTool.NbFaceNodes( iF ) - bool( volTool.GetCenterNodeIndex(iF) > 0 );
1872         for ( int iN = 0; iN < nbN; iN += iQ )
1873           helper.AddTLinkNode( fNodes[iN], fNodes[iN+2], fNodes[iN+1] );
1874       }
1875       helper.SetIsQuadratic( true );
1876     }
1877     else
1878     {
1879       iQ = 1;
1880       helper.SetIsQuadratic( false );
1881     }
1882     vector<const SMDS_MeshNode*> nodes( (*elem)->begin_nodes(), (*elem)->end_nodes() );
1883     helper.SetElementsOnShape( true );
1884     if ( splitMethod._baryNode )
1885     {
1886       // make a node at barycenter
1887       volTool.GetBaryCenter( bc[0], bc[1], bc[2] );
1888       SMDS_MeshNode* gcNode = helper.AddNode( bc[0], bc[1], bc[2] );
1889       nodes.push_back( gcNode );
1890       newNodes.Append( gcNode );
1891     }
1892     if ( !splitMethod._faceBaryNode.empty() )
1893     {
1894       // make or find baricentric nodes of faces
1895       map<int, const SMDS_MeshNode*>::iterator iF_n = splitMethod._faceBaryNode.begin();
1896       for ( ; iF_n != splitMethod._faceBaryNode.end(); ++iF_n )
1897       {
1898         map< TVolumeFaceKey, const SMDS_MeshNode* >::iterator f_n =
1899           volFace2BaryNode.insert
1900           ( make_pair( TVolumeFaceKey( volTool,iF_n->first ), iF_n->second )).first;
1901         if ( !f_n->second )
1902         {
1903           volTool.GetFaceBaryCenter( iF_n->first, bc[0], bc[1], bc[2] );
1904           newNodes.Append( f_n->second = helper.AddNode( bc[0], bc[1], bc[2] ));
1905         }
1906         nodes.push_back( iF_n->second = f_n->second );
1907       }
1908     }
1909
1910     // make tetras
1911     vector<const SMDS_MeshElement* > tetras( splitMethod._nbTetra ); // splits of a volume
1912     const int* tetConn = splitMethod._connectivity;
1913     for ( int i = 0; i < splitMethod._nbTetra; ++i, tetConn += 4 )
1914       newElems.Append( tetras[ i ] = helper.AddVolume( nodes[ tetConn[0] ],
1915                                                        nodes[ tetConn[1] ],
1916                                                        nodes[ tetConn[2] ],
1917                                                        nodes[ tetConn[3] ]));
1918
1919     ReplaceElemInGroups( *elem, tetras, GetMeshDS() );
1920
1921     // Split faces on sides of the split volume
1922
1923     const SMDS_MeshNode** volNodes = volTool.GetNodes();
1924     for ( int iF = 0; iF < volTool.NbFaces(); ++iF )
1925     {
1926       const int nbNodes = volTool.NbFaceNodes( iF ) / iQ;
1927       if ( nbNodes < 4 ) continue;
1928
1929       // find an existing face
1930       vector<const SMDS_MeshNode*> fNodes( volTool.GetFaceNodes( iF ),
1931                                            volTool.GetFaceNodes( iF ) + volTool.NbFaceNodes( iF ));
1932       while ( const SMDS_MeshElement* face = GetMeshDS()->FindElement( fNodes, SMDSAbs_Face,
1933                                                                        /*noMedium=*/false))
1934       {
1935         // make triangles
1936         helper.SetElementsOnShape( false );
1937         vector< const SMDS_MeshElement* > triangles;
1938
1939         // find submesh to add new triangles in
1940         if ( !fSubMesh || !fSubMesh->Contains( face ))
1941         {
1942           int shapeID = FindShape( face );
1943           fSubMesh = GetMeshDS()->MeshElements( shapeID );
1944         }
1945         map<int, const SMDS_MeshNode*>::iterator iF_n = splitMethod._faceBaryNode.find(iF);
1946         if ( iF_n != splitMethod._faceBaryNode.end() )
1947         {
1948           for ( int iN = 0; iN < nbNodes*iQ; iN += iQ )
1949           {
1950             const SMDS_MeshNode* n1 = fNodes[iN];
1951             const SMDS_MeshNode *n2 = fNodes[(iN+iQ)%(nbNodes*iQ)];
1952             const SMDS_MeshNode *n3 = iF_n->second;
1953             if ( !volTool.IsFaceExternal( iF ))
1954               swap( n2, n3 );
1955             triangles.push_back( helper.AddFace( n1,n2,n3 ));
1956
1957             if ( fSubMesh && n3->getshapeId() < 1 )
1958               fSubMesh->AddNode( n3 );
1959           }
1960         }
1961         else
1962         {
1963           // among possible triangles create ones discribed by split method
1964           const int* nInd = volTool.GetFaceNodesIndices( iF );
1965           int nbVariants = ( nbNodes == 4 ? 2 : nbNodes );
1966           int iCom = 0; // common node of triangle faces to split into
1967           list< TTriangleFacet > facets;
1968           for ( int iVar = 0; iVar < nbVariants; ++iVar, ++iCom )
1969           {
1970             TTriangleFacet t012( nInd[ iQ * ( iCom                )],
1971                                  nInd[ iQ * ( (iCom+1)%nbNodes )],
1972                                  nInd[ iQ * ( (iCom+2)%nbNodes )]);
1973             TTriangleFacet t023( nInd[ iQ * ( iCom                )],
1974                                  nInd[ iQ * ( (iCom+2)%nbNodes )],
1975                                  nInd[ iQ * ( (iCom+3)%nbNodes )]);
1976             if ( splitMethod.hasFacet( t012 ) && splitMethod.hasFacet( t023 ))
1977             {
1978               facets.push_back( t012 );
1979               facets.push_back( t023 );
1980               for ( int iLast = iCom+4; iLast < iCom+nbNodes; ++iLast )
1981                 facets.push_back( TTriangleFacet( nInd[ iQ * ( iCom             )],
1982                                                   nInd[ iQ * ((iLast-1)%nbNodes )],
1983                                                   nInd[ iQ * ((iLast  )%nbNodes )]));
1984               break;
1985             }
1986           }
1987           list< TTriangleFacet >::iterator facet = facets.begin();
1988           for ( ; facet != facets.end(); ++facet )
1989           {
1990             if ( !volTool.IsFaceExternal( iF ))
1991               swap( facet->_n2, facet->_n3 );
1992             triangles.push_back( helper.AddFace( volNodes[ facet->_n1 ],
1993                                                  volNodes[ facet->_n2 ],
1994                                                  volNodes[ facet->_n3 ]));
1995           }
1996         }
1997         for ( int i = 0; i < triangles.size(); ++i )
1998         {
1999           if ( !triangles[i] ) continue;
2000           if ( fSubMesh )
2001             fSubMesh->AddElement( triangles[i]);
2002           newElems.Append( triangles[i] );
2003         }
2004         ReplaceElemInGroups( face, triangles, GetMeshDS() );
2005         GetMeshDS()->RemoveFreeElement( face, fSubMesh, /*fromGroups=*/false );
2006       }
2007
2008     } // loop on volume faces to split them into triangles
2009
2010     GetMeshDS()->RemoveFreeElement( *elem, subMesh, /*fromGroups=*/false );
2011
2012     if ( geomType == SMDSEntity_TriQuad_Hexa )
2013     {
2014       // remove medium nodes that could become free
2015       for ( int i = 20; i < volTool.NbNodes(); ++i )
2016         if ( volNodes[i]->NbInverseElements() == 0 )
2017           GetMeshDS()->RemoveNode( volNodes[i] );
2018     }
2019   } // loop on volumes to split
2020
2021   myLastCreatedNodes = newNodes;
2022   myLastCreatedElems = newElems;
2023 }
2024
2025 //=======================================================================
2026 //function : AddToSameGroups
2027 //purpose  : add elemToAdd to the groups the elemInGroups belongs to
2028 //=======================================================================
2029
2030 void SMESH_MeshEditor::AddToSameGroups (const SMDS_MeshElement* elemToAdd,
2031                                         const SMDS_MeshElement* elemInGroups,
2032                                         SMESHDS_Mesh *          aMesh)
2033 {
2034   const set<SMESHDS_GroupBase*>& groups = aMesh->GetGroups();
2035   if (!groups.empty()) {
2036     set<SMESHDS_GroupBase*>::const_iterator grIt = groups.begin();
2037     for ( ; grIt != groups.end(); grIt++ ) {
2038       SMESHDS_Group* group = dynamic_cast<SMESHDS_Group*>( *grIt );
2039       if ( group && group->Contains( elemInGroups ))
2040         group->SMDSGroup().Add( elemToAdd );
2041     }
2042   }
2043 }
2044
2045
2046 //=======================================================================
2047 //function : RemoveElemFromGroups
2048 //purpose  : Remove removeelem to the groups the elemInGroups belongs to
2049 //=======================================================================
2050 void SMESH_MeshEditor::RemoveElemFromGroups (const SMDS_MeshElement* removeelem,
2051                                              SMESHDS_Mesh *          aMesh)
2052 {
2053   const set<SMESHDS_GroupBase*>& groups = aMesh->GetGroups();
2054   if (!groups.empty())
2055   {
2056     set<SMESHDS_GroupBase*>::const_iterator GrIt = groups.begin();
2057     for (; GrIt != groups.end(); GrIt++)
2058     {
2059       SMESHDS_Group* grp = dynamic_cast<SMESHDS_Group*>(*GrIt);
2060       if (!grp || grp->IsEmpty()) continue;
2061       grp->SMDSGroup().Remove(removeelem);
2062     }
2063   }
2064 }
2065
2066 //================================================================================
2067 /*!
2068  * \brief Replace elemToRm by elemToAdd in the all groups
2069  */
2070 //================================================================================
2071
2072 void SMESH_MeshEditor::ReplaceElemInGroups (const SMDS_MeshElement* elemToRm,
2073                                             const SMDS_MeshElement* elemToAdd,
2074                                             SMESHDS_Mesh *          aMesh)
2075 {
2076   const set<SMESHDS_GroupBase*>& groups = aMesh->GetGroups();
2077   if (!groups.empty()) {
2078     set<SMESHDS_GroupBase*>::const_iterator grIt = groups.begin();
2079     for ( ; grIt != groups.end(); grIt++ ) {
2080       SMESHDS_Group* group = dynamic_cast<SMESHDS_Group*>( *grIt );
2081       if ( group && group->SMDSGroup().Remove( elemToRm ) && elemToAdd )
2082         group->SMDSGroup().Add( elemToAdd );
2083     }
2084   }
2085 }
2086
2087 //================================================================================
2088 /*!
2089  * \brief Replace elemToRm by elemToAdd in the all groups
2090  */
2091 //================================================================================
2092
2093 void SMESH_MeshEditor::ReplaceElemInGroups (const SMDS_MeshElement*                elemToRm,
2094                                             const vector<const SMDS_MeshElement*>& elemToAdd,
2095                                             SMESHDS_Mesh *                         aMesh)
2096 {
2097   const set<SMESHDS_GroupBase*>& groups = aMesh->GetGroups();
2098   if (!groups.empty())
2099   {
2100     set<SMESHDS_GroupBase*>::const_iterator grIt = groups.begin();
2101     for ( ; grIt != groups.end(); grIt++ ) {
2102       SMESHDS_Group* group = dynamic_cast<SMESHDS_Group*>( *grIt );
2103       if ( group && group->SMDSGroup().Remove( elemToRm ) )
2104         for ( int i = 0; i < elemToAdd.size(); ++i )
2105           group->SMDSGroup().Add( elemToAdd[ i ] );
2106     }
2107   }
2108 }
2109
2110 //=======================================================================
2111 //function : QuadToTri
2112 //purpose  : Cut quadrangles into triangles.
2113 //           theCrit is used to select a diagonal to cut
2114 //=======================================================================
2115
2116 bool SMESH_MeshEditor::QuadToTri (TIDSortedElemSet & theElems,
2117                                   const bool         the13Diag)
2118 {
2119   myLastCreatedElems.Clear();
2120   myLastCreatedNodes.Clear();
2121
2122   MESSAGE( "::QuadToTri()" );
2123
2124   SMESHDS_Mesh * aMesh = GetMeshDS();
2125
2126   Handle(Geom_Surface) surface;
2127   SMESH_MesherHelper   helper( *GetMesh() );
2128
2129   TIDSortedElemSet::iterator itElem;
2130   for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
2131     const SMDS_MeshElement* elem = *itElem;
2132     if ( !elem || elem->GetType() != SMDSAbs_Face )
2133       continue;
2134     bool isquad = elem->NbNodes()==4 || elem->NbNodes()==8;
2135     if(!isquad) continue;
2136
2137     if(elem->NbNodes()==4) {
2138       // retrieve element nodes
2139       const SMDS_MeshNode* aNodes [4];
2140       SMDS_ElemIteratorPtr itN = elem->nodesIterator();
2141       int i = 0;
2142       while ( itN->more() )
2143         aNodes[ i++ ] = static_cast<const SMDS_MeshNode*>( itN->next() );
2144
2145       int aShapeId = FindShape( elem );
2146       const SMDS_MeshElement* newElem1 = 0;
2147       const SMDS_MeshElement* newElem2 = 0;
2148       if ( the13Diag ) {
2149         newElem1 = aMesh->AddFace( aNodes[2], aNodes[0], aNodes[1] );
2150         newElem2 = aMesh->AddFace( aNodes[2], aNodes[3], aNodes[0] );
2151       }
2152       else {
2153         newElem1 = aMesh->AddFace( aNodes[3], aNodes[0], aNodes[1] );
2154         newElem2 = aMesh->AddFace( aNodes[3], aNodes[1], aNodes[2] );
2155       }
2156       myLastCreatedElems.Append(newElem1);
2157       myLastCreatedElems.Append(newElem2);
2158       // put a new triangle on the same shape and add to the same groups
2159       if ( aShapeId )
2160         {
2161           aMesh->SetMeshElementOnShape( newElem1, aShapeId );
2162           aMesh->SetMeshElementOnShape( newElem2, aShapeId );
2163         }
2164       AddToSameGroups( newElem1, elem, aMesh );
2165       AddToSameGroups( newElem2, elem, aMesh );
2166       //aMesh->RemoveFreeElement(elem, aMesh->MeshElements(aShapeId), true);
2167       aMesh->RemoveElement( elem );
2168     }
2169
2170     // Quadratic quadrangle
2171
2172     if( elem->NbNodes()==8 && elem->IsQuadratic() ) {
2173
2174       // get surface elem is on
2175       int aShapeId = FindShape( elem );
2176       if ( aShapeId != helper.GetSubShapeID() ) {
2177         surface.Nullify();
2178         TopoDS_Shape shape;
2179         if ( aShapeId > 0 )
2180           shape = aMesh->IndexToShape( aShapeId );
2181         if ( !shape.IsNull() && shape.ShapeType() == TopAbs_FACE ) {
2182           TopoDS_Face face = TopoDS::Face( shape );
2183           surface = BRep_Tool::Surface( face );
2184           if ( !surface.IsNull() )
2185             helper.SetSubShape( shape );
2186         }
2187       }
2188
2189       const SMDS_MeshNode* aNodes [8];
2190       const SMDS_MeshNode* inFaceNode = 0;
2191       SMDS_ElemIteratorPtr itN = elem->nodesIterator();
2192       int i = 0;
2193       while ( itN->more() ) {
2194         aNodes[ i++ ] = static_cast<const SMDS_MeshNode*>( itN->next() );
2195         if ( !inFaceNode && helper.GetNodeUVneedInFaceNode() &&
2196              aNodes[ i-1 ]->GetPosition()->GetTypeOfPosition() == SMDS_TOP_FACE )
2197         {
2198           inFaceNode = aNodes[ i-1 ];
2199         }
2200       }
2201
2202       // find middle point for (0,1,2,3)
2203       // and create a node in this point;
2204       gp_XYZ p( 0,0,0 );
2205       if ( surface.IsNull() ) {
2206         for(i=0; i<4; i++)
2207           p += gp_XYZ(aNodes[i]->X(), aNodes[i]->Y(), aNodes[i]->Z() );
2208         p /= 4;
2209       }
2210       else {
2211         TopoDS_Face geomFace = TopoDS::Face( helper.GetSubShape() );
2212         gp_XY uv( 0,0 );
2213         for(i=0; i<4; i++)
2214           uv += helper.GetNodeUV( geomFace, aNodes[i], inFaceNode );
2215         uv /= 4.;
2216         p = surface->Value( uv.X(), uv.Y() ).XYZ();
2217       }
2218       const SMDS_MeshNode* newN = aMesh->AddNode( p.X(), p.Y(), p.Z() );
2219       myLastCreatedNodes.Append(newN);
2220
2221       // create a new element
2222       const SMDS_MeshElement* newElem1 = 0;
2223       const SMDS_MeshElement* newElem2 = 0;
2224       if ( the13Diag ) {
2225         newElem1 = aMesh->AddFace(aNodes[2], aNodes[3], aNodes[0],
2226                                   aNodes[6], aNodes[7], newN );
2227         newElem2 = aMesh->AddFace(aNodes[2], aNodes[0], aNodes[1],
2228                                   newN,      aNodes[4], aNodes[5] );
2229       }
2230       else {
2231         newElem1 = aMesh->AddFace(aNodes[3], aNodes[0], aNodes[1],
2232                                   aNodes[7], aNodes[4], newN );
2233         newElem2 = aMesh->AddFace(aNodes[3], aNodes[1], aNodes[2],
2234                                   newN,      aNodes[5], aNodes[6] );
2235       }
2236       myLastCreatedElems.Append(newElem1);
2237       myLastCreatedElems.Append(newElem2);
2238       // put a new triangle on the same shape and add to the same groups
2239       if ( aShapeId )
2240         {
2241           aMesh->SetMeshElementOnShape( newElem1, aShapeId );
2242           aMesh->SetMeshElementOnShape( newElem2, aShapeId );
2243         }
2244       AddToSameGroups( newElem1, elem, aMesh );
2245       AddToSameGroups( newElem2, elem, aMesh );
2246       aMesh->RemoveElement( elem );
2247     }
2248   }
2249
2250   return true;
2251 }
2252
2253 //=======================================================================
2254 //function : getAngle
2255 //purpose  :
2256 //=======================================================================
2257
2258 double getAngle(const SMDS_MeshElement * tr1,
2259                 const SMDS_MeshElement * tr2,
2260                 const SMDS_MeshNode *    n1,
2261                 const SMDS_MeshNode *    n2)
2262 {
2263   double angle = 2. * M_PI; // bad angle
2264
2265   // get normals
2266   SMESH::Controls::TSequenceOfXYZ P1, P2;
2267   if ( !SMESH::Controls::NumericalFunctor::GetPoints( tr1, P1 ) ||
2268        !SMESH::Controls::NumericalFunctor::GetPoints( tr2, P2 ))
2269     return angle;
2270   gp_Vec N1,N2;
2271   if(!tr1->IsQuadratic())
2272     N1 = gp_Vec( P1(2) - P1(1) ) ^ gp_Vec( P1(3) - P1(1) );
2273   else
2274     N1 = gp_Vec( P1(3) - P1(1) ) ^ gp_Vec( P1(5) - P1(1) );
2275   if ( N1.SquareMagnitude() <= gp::Resolution() )
2276     return angle;
2277   if(!tr2->IsQuadratic())
2278     N2 = gp_Vec( P2(2) - P2(1) ) ^ gp_Vec( P2(3) - P2(1) );
2279   else
2280     N2 = gp_Vec( P2(3) - P2(1) ) ^ gp_Vec( P2(5) - P2(1) );
2281   if ( N2.SquareMagnitude() <= gp::Resolution() )
2282     return angle;
2283
2284   // find the first diagonal node n1 in the triangles:
2285   // take in account a diagonal link orientation
2286   const SMDS_MeshElement *nFirst[2], *tr[] = { tr1, tr2 };
2287   for ( int t = 0; t < 2; t++ ) {
2288     SMDS_ElemIteratorPtr it = tr[ t ]->nodesIterator();
2289     int i = 0, iDiag = -1;
2290     while ( it->more()) {
2291       const SMDS_MeshElement *n = it->next();
2292       if ( n == n1 || n == n2 ) {
2293         if ( iDiag < 0)
2294           iDiag = i;
2295         else {
2296           if ( i - iDiag == 1 )
2297             nFirst[ t ] = ( n == n1 ? n2 : n1 );
2298           else
2299             nFirst[ t ] = n;
2300           break;
2301         }
2302       }
2303       i++;
2304     }
2305   }
2306   if ( nFirst[ 0 ] == nFirst[ 1 ] )
2307     N2.Reverse();
2308
2309   angle = N1.Angle( N2 );
2310   //SCRUTE( angle );
2311   return angle;
2312 }
2313
2314 // =================================================
2315 // class generating a unique ID for a pair of nodes
2316 // and able to return nodes by that ID
2317 // =================================================
2318 class LinkID_Gen {
2319 public:
2320
2321   LinkID_Gen( const SMESHDS_Mesh* theMesh )
2322     :myMesh( theMesh ), myMaxID( theMesh->MaxNodeID() + 1)
2323   {}
2324
2325   long GetLinkID (const SMDS_MeshNode * n1,
2326                   const SMDS_MeshNode * n2) const
2327   {
2328     return ( Min(n1->GetID(),n2->GetID()) * myMaxID + Max(n1->GetID(),n2->GetID()));
2329   }
2330
2331   bool GetNodes (const long             theLinkID,
2332                  const SMDS_MeshNode* & theNode1,
2333                  const SMDS_MeshNode* & theNode2) const
2334   {
2335     theNode1 = myMesh->FindNode( theLinkID / myMaxID );
2336     if ( !theNode1 ) return false;
2337     theNode2 = myMesh->FindNode( theLinkID % myMaxID );
2338     if ( !theNode2 ) return false;
2339     return true;
2340   }
2341
2342 private:
2343   LinkID_Gen();
2344   const SMESHDS_Mesh* myMesh;
2345   long                myMaxID;
2346 };
2347
2348
2349 //=======================================================================
2350 //function : TriToQuad
2351 //purpose  : Fuse neighbour triangles into quadrangles.
2352 //           theCrit is used to select a neighbour to fuse with.
2353 //           theMaxAngle is a max angle between element normals at which
2354 //           fusion is still performed.
2355 //=======================================================================
2356
2357 bool SMESH_MeshEditor::TriToQuad (TIDSortedElemSet &                   theElems,
2358                                   SMESH::Controls::NumericalFunctorPtr theCrit,
2359                                   const double                         theMaxAngle)
2360 {
2361   myLastCreatedElems.Clear();
2362   myLastCreatedNodes.Clear();
2363
2364   MESSAGE( "::TriToQuad()" );
2365
2366   if ( !theCrit.get() )
2367     return false;
2368
2369   SMESHDS_Mesh * aMesh = GetMeshDS();
2370
2371   // Prepare data for algo: build
2372   // 1. map of elements with their linkIDs
2373   // 2. map of linkIDs with their elements
2374
2375   map< SMESH_TLink, list< const SMDS_MeshElement* > > mapLi_listEl;
2376   map< SMESH_TLink, list< const SMDS_MeshElement* > >::iterator itLE;
2377   map< const SMDS_MeshElement*, set< SMESH_TLink > >  mapEl_setLi;
2378   map< const SMDS_MeshElement*, set< SMESH_TLink > >::iterator itEL;
2379
2380   TIDSortedElemSet::iterator itElem;
2381   for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
2382     const SMDS_MeshElement* elem = *itElem;
2383     if(!elem || elem->GetType() != SMDSAbs_Face ) continue;
2384     bool IsTria = elem->NbNodes()==3 || (elem->NbNodes()==6 && elem->IsQuadratic());
2385     if(!IsTria) continue;
2386
2387     // retrieve element nodes
2388     const SMDS_MeshNode* aNodes [4];
2389     SMDS_ElemIteratorPtr itN = elem->nodesIterator();
2390     int i = 0;
2391     while ( i<3 )
2392       aNodes[ i++ ] = cast2Node( itN->next() );
2393     aNodes[ 3 ] = aNodes[ 0 ];
2394
2395     // fill maps
2396     for ( i = 0; i < 3; i++ ) {
2397       SMESH_TLink link( aNodes[i], aNodes[i+1] );
2398       // check if elements sharing a link can be fused
2399       itLE = mapLi_listEl.find( link );
2400       if ( itLE != mapLi_listEl.end() ) {
2401         if ((*itLE).second.size() > 1 ) // consider only 2 elems adjacent by a link
2402           continue;
2403         const SMDS_MeshElement* elem2 = (*itLE).second.front();
2404         //if ( FindShape( elem ) != FindShape( elem2 ))
2405         //  continue; // do not fuse triangles laying on different shapes
2406         if ( getAngle( elem, elem2, aNodes[i], aNodes[i+1] ) > theMaxAngle )
2407           continue; // avoid making badly shaped quads
2408         (*itLE).second.push_back( elem );
2409       }
2410       else {
2411         mapLi_listEl[ link ].push_back( elem );
2412       }
2413       mapEl_setLi [ elem ].insert( link );
2414     }
2415   }
2416   // Clean the maps from the links shared by a sole element, ie
2417   // links to which only one element is bound in mapLi_listEl
2418
2419   for ( itLE = mapLi_listEl.begin(); itLE != mapLi_listEl.end(); itLE++ ) {
2420     int nbElems = (*itLE).second.size();
2421     if ( nbElems < 2  ) {
2422       const SMDS_MeshElement* elem = (*itLE).second.front();
2423       SMESH_TLink link = (*itLE).first;
2424       mapEl_setLi[ elem ].erase( link );
2425       if ( mapEl_setLi[ elem ].empty() )
2426         mapEl_setLi.erase( elem );
2427     }
2428   }
2429
2430   // Algo: fuse triangles into quadrangles
2431
2432   while ( ! mapEl_setLi.empty() ) {
2433     // Look for the start element:
2434     // the element having the least nb of shared links
2435     const SMDS_MeshElement* startElem = 0;
2436     int minNbLinks = 4;
2437     for ( itEL = mapEl_setLi.begin(); itEL != mapEl_setLi.end(); itEL++ ) {
2438       int nbLinks = (*itEL).second.size();
2439       if ( nbLinks < minNbLinks ) {
2440         startElem = (*itEL).first;
2441         minNbLinks = nbLinks;
2442         if ( minNbLinks == 1 )
2443           break;
2444       }
2445     }
2446
2447     // search elements to fuse starting from startElem or links of elements
2448     // fused earlyer - startLinks
2449     list< SMESH_TLink > startLinks;
2450     while ( startElem || !startLinks.empty() ) {
2451       while ( !startElem && !startLinks.empty() ) {
2452         // Get an element to start, by a link
2453         SMESH_TLink linkId = startLinks.front();
2454         startLinks.pop_front();
2455         itLE = mapLi_listEl.find( linkId );
2456         if ( itLE != mapLi_listEl.end() ) {
2457           list< const SMDS_MeshElement* > & listElem = (*itLE).second;
2458           list< const SMDS_MeshElement* >::iterator itE = listElem.begin();
2459           for ( ; itE != listElem.end() ; itE++ )
2460             if ( mapEl_setLi.find( (*itE) ) != mapEl_setLi.end() )
2461               startElem = (*itE);
2462           mapLi_listEl.erase( itLE );
2463         }
2464       }
2465
2466       if ( startElem ) {
2467         // Get candidates to be fused
2468         const SMDS_MeshElement *tr1 = startElem, *tr2 = 0, *tr3 = 0;
2469         const SMESH_TLink *link12, *link13;
2470         startElem = 0;
2471         ASSERT( mapEl_setLi.find( tr1 ) != mapEl_setLi.end() );
2472         set< SMESH_TLink >& setLi = mapEl_setLi[ tr1 ];
2473         ASSERT( !setLi.empty() );
2474         set< SMESH_TLink >::iterator itLi;
2475         for ( itLi = setLi.begin(); itLi != setLi.end(); itLi++ )
2476         {
2477           const SMESH_TLink & link = (*itLi);
2478           itLE = mapLi_listEl.find( link );
2479           if ( itLE == mapLi_listEl.end() )
2480             continue;
2481
2482           const SMDS_MeshElement* elem = (*itLE).second.front();
2483           if ( elem == tr1 )
2484             elem = (*itLE).second.back();
2485           mapLi_listEl.erase( itLE );
2486           if ( mapEl_setLi.find( elem ) == mapEl_setLi.end())
2487             continue;
2488           if ( tr2 ) {
2489             tr3 = elem;
2490             link13 = &link;
2491           }
2492           else {
2493             tr2 = elem;
2494             link12 = &link;
2495           }
2496
2497           // add other links of elem to list of links to re-start from
2498           set< SMESH_TLink >& links = mapEl_setLi[ elem ];
2499           set< SMESH_TLink >::iterator it;
2500           for ( it = links.begin(); it != links.end(); it++ ) {
2501             const SMESH_TLink& link2 = (*it);
2502             if ( link2 != link )
2503               startLinks.push_back( link2 );
2504           }
2505         }
2506
2507         // Get nodes of possible quadrangles
2508         const SMDS_MeshNode *n12 [4], *n13 [4];
2509         bool Ok12 = false, Ok13 = false;
2510         const SMDS_MeshNode *linkNode1, *linkNode2;
2511         if(tr2) {
2512           linkNode1 = link12->first;
2513           linkNode2 = link12->second;
2514           if ( tr2 && getQuadrangleNodes( n12, linkNode1, linkNode2, tr1, tr2 ))
2515             Ok12 = true;
2516         }
2517         if(tr3) {
2518           linkNode1 = link13->first;
2519           linkNode2 = link13->second;
2520           if ( tr3 && getQuadrangleNodes( n13, linkNode1, linkNode2, tr1, tr3 ))
2521             Ok13 = true;
2522         }
2523
2524         // Choose a pair to fuse
2525         if ( Ok12 && Ok13 ) {
2526           SMDS_FaceOfNodes quad12 ( n12[ 0 ], n12[ 1 ], n12[ 2 ], n12[ 3 ] );
2527           SMDS_FaceOfNodes quad13 ( n13[ 0 ], n13[ 1 ], n13[ 2 ], n13[ 3 ] );
2528           double aBadRate12 = getBadRate( &quad12, theCrit );
2529           double aBadRate13 = getBadRate( &quad13, theCrit );
2530           if (  aBadRate13 < aBadRate12 )
2531             Ok12 = false;
2532           else
2533             Ok13 = false;
2534         }
2535
2536         // Make quadrangles
2537         // and remove fused elems and removed links from the maps
2538         mapEl_setLi.erase( tr1 );
2539         if ( Ok12 ) {
2540           mapEl_setLi.erase( tr2 );
2541           mapLi_listEl.erase( *link12 );
2542           if(tr1->NbNodes()==3) {
2543             const SMDS_MeshElement* newElem = 0;
2544             newElem = aMesh->AddFace(n12[0], n12[1], n12[2], n12[3] );
2545             myLastCreatedElems.Append(newElem);
2546             AddToSameGroups( newElem, tr1, aMesh );
2547             int aShapeId = tr1->getshapeId();
2548             if ( aShapeId )
2549               {
2550                 aMesh->SetMeshElementOnShape( newElem, aShapeId );
2551               }
2552             aMesh->RemoveElement( tr1 );
2553             aMesh->RemoveElement( tr2 );
2554           }
2555           else {
2556             const SMDS_MeshNode* N1 [6];
2557             const SMDS_MeshNode* N2 [6];
2558             GetNodesFromTwoTria(tr1,tr2,N1,N2);
2559             // now we receive following N1 and N2 (using numeration as above image)
2560             // tria1 : (1 2 4 5 9 7)  and  tria2 : (3 4 2 8 9 6)
2561             // i.e. first nodes from both arrays determ new diagonal
2562             const SMDS_MeshNode* aNodes[8];
2563             aNodes[0] = N1[0];
2564             aNodes[1] = N1[1];
2565             aNodes[2] = N2[0];
2566             aNodes[3] = N2[1];
2567             aNodes[4] = N1[3];
2568             aNodes[5] = N2[5];
2569             aNodes[6] = N2[3];
2570             aNodes[7] = N1[5];
2571             const SMDS_MeshElement* newElem = 0;
2572             newElem = aMesh->AddFace(aNodes[0], aNodes[1], aNodes[2], aNodes[3],
2573                                      aNodes[4], aNodes[5], aNodes[6], aNodes[7]);
2574             myLastCreatedElems.Append(newElem);
2575             AddToSameGroups( newElem, tr1, aMesh );
2576             int aShapeId = tr1->getshapeId();
2577             if ( aShapeId )
2578               {
2579                 aMesh->SetMeshElementOnShape( newElem, aShapeId );
2580               }
2581             aMesh->RemoveElement( tr1 );
2582             aMesh->RemoveElement( tr2 );
2583             // remove middle node (9)
2584             GetMeshDS()->RemoveNode( N1[4] );
2585           }
2586         }
2587         else if ( Ok13 ) {
2588           mapEl_setLi.erase( tr3 );
2589           mapLi_listEl.erase( *link13 );
2590           if(tr1->NbNodes()==3) {
2591             const SMDS_MeshElement* newElem = 0;
2592             newElem = aMesh->AddFace(n13[0], n13[1], n13[2], n13[3] );
2593             myLastCreatedElems.Append(newElem);
2594             AddToSameGroups( newElem, tr1, aMesh );
2595             int aShapeId = tr1->getshapeId();
2596             if ( aShapeId )
2597               {
2598                 aMesh->SetMeshElementOnShape( newElem, aShapeId );
2599               }
2600             aMesh->RemoveElement( tr1 );
2601             aMesh->RemoveElement( tr3 );
2602           }
2603           else {
2604             const SMDS_MeshNode* N1 [6];
2605             const SMDS_MeshNode* N2 [6];
2606             GetNodesFromTwoTria(tr1,tr3,N1,N2);
2607             // now we receive following N1 and N2 (using numeration as above image)
2608             // tria1 : (1 2 4 5 9 7)  and  tria2 : (3 4 2 8 9 6)
2609             // i.e. first nodes from both arrays determ new diagonal
2610             const SMDS_MeshNode* aNodes[8];
2611             aNodes[0] = N1[0];
2612             aNodes[1] = N1[1];
2613             aNodes[2] = N2[0];
2614             aNodes[3] = N2[1];
2615             aNodes[4] = N1[3];
2616             aNodes[5] = N2[5];
2617             aNodes[6] = N2[3];
2618             aNodes[7] = N1[5];
2619             const SMDS_MeshElement* newElem = 0;
2620             newElem = aMesh->AddFace(aNodes[0], aNodes[1], aNodes[2], aNodes[3],
2621                                      aNodes[4], aNodes[5], aNodes[6], aNodes[7]);
2622             myLastCreatedElems.Append(newElem);
2623             AddToSameGroups( newElem, tr1, aMesh );
2624             int aShapeId = tr1->getshapeId();
2625             if ( aShapeId )
2626               {
2627                 aMesh->SetMeshElementOnShape( newElem, aShapeId );
2628               }
2629             aMesh->RemoveElement( tr1 );
2630             aMesh->RemoveElement( tr3 );
2631             // remove middle node (9)
2632             GetMeshDS()->RemoveNode( N1[4] );
2633           }
2634         }
2635
2636         // Next element to fuse: the rejected one
2637         if ( tr3 )
2638           startElem = Ok12 ? tr3 : tr2;
2639
2640       } // if ( startElem )
2641     } // while ( startElem || !startLinks.empty() )
2642   } // while ( ! mapEl_setLi.empty() )
2643
2644   return true;
2645 }
2646
2647
2648 /*#define DUMPSO(txt) \
2649 //  cout << txt << endl;
2650 //=============================================================================
2651 //
2652 //
2653 //
2654 //=============================================================================
2655 static void swap( int i1, int i2, int idNodes[], gp_Pnt P[] )
2656 {
2657 if ( i1 == i2 )
2658 return;
2659 int tmp = idNodes[ i1 ];
2660 idNodes[ i1 ] = idNodes[ i2 ];
2661 idNodes[ i2 ] = tmp;
2662 gp_Pnt Ptmp = P[ i1 ];
2663 P[ i1 ] = P[ i2 ];
2664 P[ i2 ] = Ptmp;
2665 DUMPSO( i1 << "(" << idNodes[ i2 ] << ") <-> " << i2 << "(" << idNodes[ i1 ] << ")");
2666 }
2667
2668 //=======================================================================
2669 //function : SortQuadNodes
2670 //purpose  : Set 4 nodes of a quadrangle face in a good order.
2671 //           Swap 1<->2 or 2<->3 nodes and correspondingly return
2672 //           1 or 2 else 0.
2673 //=======================================================================
2674
2675 int SMESH_MeshEditor::SortQuadNodes (const SMDS_Mesh * theMesh,
2676 int               idNodes[] )
2677 {
2678   gp_Pnt P[4];
2679   int i;
2680   for ( i = 0; i < 4; i++ ) {
2681     const SMDS_MeshNode *n = theMesh->FindNode( idNodes[i] );
2682     if ( !n ) return 0;
2683     P[ i ].SetCoord( n->X(), n->Y(), n->Z() );
2684   }
2685
2686   gp_Vec V1(P[0], P[1]);
2687   gp_Vec V2(P[0], P[2]);
2688   gp_Vec V3(P[0], P[3]);
2689
2690   gp_Vec Cross1 = V1 ^ V2;
2691   gp_Vec Cross2 = V2 ^ V3;
2692
2693   i = 0;
2694   if (Cross1.Dot(Cross2) < 0)
2695   {
2696     Cross1 = V2 ^ V1;
2697     Cross2 = V1 ^ V3;
2698
2699     if (Cross1.Dot(Cross2) < 0)
2700       i = 2;
2701     else
2702       i = 1;
2703     swap ( i, i + 1, idNodes, P );
2704
2705     //     for ( int ii = 0; ii < 4; ii++ ) {
2706     //       const SMDS_MeshNode *n = theMesh->FindNode( idNodes[ii] );
2707     //       DUMPSO( ii << "(" << idNodes[ii] <<") : "<<n->X()<<" "<<n->Y()<<" "<<n->Z());
2708     //     }
2709   }
2710   return i;
2711 }
2712
2713 //=======================================================================
2714 //function : SortHexaNodes
2715 //purpose  : Set 8 nodes of a hexahedron in a good order.
2716 //           Return success status
2717 //=======================================================================
2718
2719 bool SMESH_MeshEditor::SortHexaNodes (const SMDS_Mesh * theMesh,
2720                                       int               idNodes[] )
2721 {
2722   gp_Pnt P[8];
2723   int i;
2724   DUMPSO( "INPUT: ========================================");
2725   for ( i = 0; i < 8; i++ ) {
2726     const SMDS_MeshNode *n = theMesh->FindNode( idNodes[i] );
2727     if ( !n ) return false;
2728     P[ i ].SetCoord( n->X(), n->Y(), n->Z() );
2729     DUMPSO( i << "(" << idNodes[i] <<") : "<<n->X()<<" "<<n->Y()<<" "<<n->Z());
2730   }
2731   DUMPSO( "========================================");
2732
2733
2734   set<int> faceNodes;  // ids of bottom face nodes, to be found
2735   set<int> checkedId1; // ids of tried 2-nd nodes
2736   Standard_Real leastDist = DBL_MAX; // dist of the 4-th node from 123 plane
2737   const Standard_Real tol = 1.e-6;   // tolerance to find nodes in plane
2738   int iMin, iLoop1 = 0;
2739
2740   // Loop to try the 2-nd nodes
2741
2742   while ( leastDist > DBL_MIN && ++iLoop1 < 8 )
2743   {
2744     // Find not checked 2-nd node
2745     for ( i = 1; i < 8; i++ )
2746       if ( checkedId1.find( idNodes[i] ) == checkedId1.end() ) {
2747         int id1 = idNodes[i];
2748         swap ( 1, i, idNodes, P );
2749         checkedId1.insert ( id1 );
2750         break;
2751       }
2752
2753     // Find the 3-d node so that 1-2-3 triangle to be on a hexa face,
2754     // ie that all but meybe one (id3 which is on the same face) nodes
2755     // lay on the same side from the triangle plane.
2756
2757     bool manyInPlane = false; // more than 4 nodes lay in plane
2758     int iLoop2 = 0;
2759     while ( ++iLoop2 < 6 ) {
2760
2761       // get 1-2-3 plane coeffs
2762       Standard_Real A, B, C, D;
2763       gp_Vec N = gp_Vec (P[0], P[1]).Crossed( gp_Vec (P[0], P[2]) );
2764       if ( N.SquareMagnitude() > gp::Resolution() )
2765       {
2766         gp_Pln pln ( P[0], N );
2767         pln.Coefficients( A, B, C, D );
2768
2769         // find the node (iMin) closest to pln
2770         Standard_Real dist[ 8 ], minDist = DBL_MAX;
2771         set<int> idInPln;
2772         for ( i = 3; i < 8; i++ ) {
2773           dist[i] = A * P[i].X() + B * P[i].Y() + C * P[i].Z() + D;
2774           if ( fabs( dist[i] ) < minDist ) {
2775             minDist = fabs( dist[i] );
2776             iMin = i;
2777           }
2778           if ( fabs( dist[i] ) <= tol )
2779             idInPln.insert( idNodes[i] );
2780         }
2781
2782         // there should not be more than 4 nodes in bottom plane
2783         if ( idInPln.size() > 1 )
2784         {
2785           DUMPSO( "### idInPln.size() = " << idInPln.size());
2786           // idInPlane does not contain the first 3 nodes
2787           if ( manyInPlane || idInPln.size() == 5)
2788             return false; // all nodes in one plane
2789           manyInPlane = true;
2790
2791           // set the 1-st node to be not in plane
2792           for ( i = 3; i < 8; i++ ) {
2793             if ( idInPln.find( idNodes[ i ] ) == idInPln.end() ) {
2794               DUMPSO( "### Reset 0-th node");
2795               swap( 0, i, idNodes, P );
2796               break;
2797             }
2798           }
2799
2800           // reset to re-check second nodes
2801           leastDist = DBL_MAX;
2802           faceNodes.clear();
2803           checkedId1.clear();
2804           iLoop1 = 0;
2805           break; // from iLoop2;
2806         }
2807
2808         // check that the other 4 nodes are on the same side
2809         bool sameSide = true;
2810         bool isNeg = dist[ iMin == 3 ? 4 : 3 ] <= 0.;
2811         for ( i = 3; sameSide && i < 8; i++ ) {
2812           if ( i != iMin )
2813             sameSide = ( isNeg == dist[i] <= 0.);
2814         }
2815
2816         // keep best solution
2817         if ( sameSide && minDist < leastDist ) {
2818           leastDist = minDist;
2819           faceNodes.clear();
2820           faceNodes.insert( idNodes[ 1 ] );
2821           faceNodes.insert( idNodes[ 2 ] );
2822           faceNodes.insert( idNodes[ iMin ] );
2823           DUMPSO( "loop " << iLoop2 << " id2 " << idNodes[ 1 ] << " id3 " << idNodes[ 2 ]
2824                   << " leastDist = " << leastDist);
2825           if ( leastDist <= DBL_MIN )
2826             break;
2827         }
2828       }
2829
2830       // set next 3-d node to check
2831       int iNext = 2 + iLoop2;
2832       if ( iNext < 8 ) {
2833         DUMPSO( "Try 2-nd");
2834         swap ( 2, iNext, idNodes, P );
2835       }
2836     } // while ( iLoop2 < 6 )
2837   } // iLoop1
2838
2839   if ( faceNodes.empty() ) return false;
2840
2841   // Put the faceNodes in proper places
2842   for ( i = 4; i < 8; i++ ) {
2843     if ( faceNodes.find( idNodes[ i ] ) != faceNodes.end() ) {
2844       // find a place to put
2845       int iTo = 1;
2846       while ( faceNodes.find( idNodes[ iTo ] ) != faceNodes.end() )
2847         iTo++;
2848       DUMPSO( "Set faceNodes");
2849       swap ( iTo, i, idNodes, P );
2850     }
2851   }
2852
2853
2854   // Set nodes of the found bottom face in good order
2855   DUMPSO( " Found bottom face: ");
2856   i = SortQuadNodes( theMesh, idNodes );
2857   if ( i ) {
2858     gp_Pnt Ptmp = P[ i ];
2859     P[ i ] = P[ i+1 ];
2860     P[ i+1 ] = Ptmp;
2861   }
2862   //   else
2863   //     for ( int ii = 0; ii < 4; ii++ ) {
2864   //       const SMDS_MeshNode *n = theMesh->FindNode( idNodes[ii] );
2865   //       DUMPSO( ii << "(" << idNodes[ii] <<") : "<<n->X()<<" "<<n->Y()<<" "<<n->Z());
2866   //    }
2867
2868   // Gravity center of the top and bottom faces
2869   gp_Pnt aGCb = ( P[0].XYZ() + P[1].XYZ() + P[2].XYZ() + P[3].XYZ() ) / 4.;
2870   gp_Pnt aGCt = ( P[4].XYZ() + P[5].XYZ() + P[6].XYZ() + P[7].XYZ() ) / 4.;
2871
2872   // Get direction from the bottom to the top face
2873   gp_Vec upDir ( aGCb, aGCt );
2874   Standard_Real upDirSize = upDir.Magnitude();
2875   if ( upDirSize <= gp::Resolution() ) return false;
2876   upDir / upDirSize;
2877
2878   // Assure that the bottom face normal points up
2879   gp_Vec Nb = gp_Vec (P[0], P[1]).Crossed( gp_Vec (P[0], P[2]) );
2880   Nb += gp_Vec (P[0], P[2]).Crossed( gp_Vec (P[0], P[3]) );
2881   if ( Nb.Dot( upDir ) < 0 ) {
2882     DUMPSO( "Reverse bottom face");
2883     swap( 1, 3, idNodes, P );
2884   }
2885
2886   // Find 5-th node - the one closest to the 1-st among the last 4 nodes.
2887   Standard_Real minDist = DBL_MAX;
2888   for ( i = 4; i < 8; i++ ) {
2889     // projection of P[i] to the plane defined by P[0] and upDir
2890     gp_Pnt Pp = P[i].Translated( upDir * ( upDir.Dot( gp_Vec( P[i], P[0] ))));
2891     Standard_Real sqDist = P[0].SquareDistance( Pp );
2892     if ( sqDist < minDist ) {
2893       minDist = sqDist;
2894       iMin = i;
2895     }
2896   }
2897   DUMPSO( "Set 4-th");
2898   swap ( 4, iMin, idNodes, P );
2899
2900   // Set nodes of the top face in good order
2901   DUMPSO( "Sort top face");
2902   i = SortQuadNodes( theMesh, &idNodes[4] );
2903   if ( i ) {
2904     i += 4;
2905     gp_Pnt Ptmp = P[ i ];
2906     P[ i ] = P[ i+1 ];
2907     P[ i+1 ] = Ptmp;
2908   }
2909
2910   // Assure that direction of the top face normal is from the bottom face
2911   gp_Vec Nt = gp_Vec (P[4], P[5]).Crossed( gp_Vec (P[4], P[6]) );
2912   Nt += gp_Vec (P[4], P[6]).Crossed( gp_Vec (P[4], P[7]) );
2913   if ( Nt.Dot( upDir ) < 0 ) {
2914     DUMPSO( "Reverse top face");
2915     swap( 5, 7, idNodes, P );
2916   }
2917
2918   //   DUMPSO( "OUTPUT: ========================================");
2919   //   for ( i = 0; i < 8; i++ ) {
2920   //     float *p = ugrid->GetPoint(idNodes[i]);
2921   //     DUMPSO( i << "(" << idNodes[i] << ") : " << p[0] << " " << p[1] << " " << p[2]);
2922   //   }
2923
2924   return true;
2925 }*/
2926
2927 //================================================================================
2928 /*!
2929  * \brief Return nodes linked to the given one
2930  * \param theNode - the node
2931  * \param linkedNodes - the found nodes
2932  * \param type - the type of elements to check
2933  *
2934  * Medium nodes are ignored
2935  */
2936 //================================================================================
2937
2938 void SMESH_MeshEditor::GetLinkedNodes( const SMDS_MeshNode* theNode,
2939                                        TIDSortedElemSet &   linkedNodes,
2940                                        SMDSAbs_ElementType  type )
2941 {
2942   SMDS_ElemIteratorPtr elemIt = theNode->GetInverseElementIterator(type);
2943   while ( elemIt->more() )
2944   {
2945     const SMDS_MeshElement* elem = elemIt->next();
2946     if(elem->GetType() == SMDSAbs_0DElement)
2947       continue;
2948
2949     SMDS_ElemIteratorPtr nodeIt = elem->nodesIterator();
2950     if ( elem->GetType() == SMDSAbs_Volume )
2951     {
2952       SMDS_VolumeTool vol( elem );
2953       while ( nodeIt->more() ) {
2954         const SMDS_MeshNode* n = cast2Node( nodeIt->next() );
2955         if ( theNode != n && vol.IsLinked( theNode, n ))
2956           linkedNodes.insert( n );
2957       }
2958     }
2959     else
2960     {
2961       for ( int i = 0; nodeIt->more(); ++i ) {
2962         const SMDS_MeshNode* n = cast2Node( nodeIt->next() );
2963         if ( n == theNode ) {
2964           int iBefore = i - 1;
2965           int iAfter  = i + 1;
2966           if ( elem->IsQuadratic() ) {
2967             int nb = elem->NbNodes() / 2;
2968             iAfter  = SMESH_MesherHelper::WrapIndex( iAfter, nb );
2969             iBefore = SMESH_MesherHelper::WrapIndex( iBefore, nb );
2970           }
2971           linkedNodes.insert( elem->GetNodeWrap( iAfter ));
2972           linkedNodes.insert( elem->GetNodeWrap( iBefore ));
2973         }
2974       }
2975     }
2976   }
2977 }
2978
2979 //=======================================================================
2980 //function : laplacianSmooth
2981 //purpose  : pulls theNode toward the center of surrounding nodes directly
2982 //           connected to that node along an element edge
2983 //=======================================================================
2984
2985 void laplacianSmooth(const SMDS_MeshNode*                 theNode,
2986                      const Handle(Geom_Surface)&          theSurface,
2987                      map< const SMDS_MeshNode*, gp_XY* >& theUVMap)
2988 {
2989   // find surrounding nodes
2990
2991   TIDSortedElemSet nodeSet;
2992   SMESH_MeshEditor::GetLinkedNodes( theNode, nodeSet, SMDSAbs_Face );
2993
2994   // compute new coodrs
2995
2996   double coord[] = { 0., 0., 0. };
2997   TIDSortedElemSet::iterator nodeSetIt = nodeSet.begin();
2998   for ( ; nodeSetIt != nodeSet.end(); nodeSetIt++ ) {
2999     const SMDS_MeshNode* node = cast2Node(*nodeSetIt);
3000     if ( theSurface.IsNull() ) { // smooth in 3D
3001       coord[0] += node->X();
3002       coord[1] += node->Y();
3003       coord[2] += node->Z();
3004     }
3005     else { // smooth in 2D
3006       ASSERT( theUVMap.find( node ) != theUVMap.end() );
3007       gp_XY* uv = theUVMap[ node ];
3008       coord[0] += uv->X();
3009       coord[1] += uv->Y();
3010     }
3011   }
3012   int nbNodes = nodeSet.size();
3013   if ( !nbNodes )
3014     return;
3015   coord[0] /= nbNodes;
3016   coord[1] /= nbNodes;
3017
3018   if ( !theSurface.IsNull() ) {
3019     ASSERT( theUVMap.find( theNode ) != theUVMap.end() );
3020     theUVMap[ theNode ]->SetCoord( coord[0], coord[1] );
3021     gp_Pnt p3d = theSurface->Value( coord[0], coord[1] );
3022     coord[0] = p3d.X();
3023     coord[1] = p3d.Y();
3024     coord[2] = p3d.Z();
3025   }
3026   else
3027     coord[2] /= nbNodes;
3028
3029   // move node
3030
3031   const_cast< SMDS_MeshNode* >( theNode )->setXYZ(coord[0],coord[1],coord[2]);
3032 }
3033
3034 //=======================================================================
3035 //function : centroidalSmooth
3036 //purpose  : pulls theNode toward the element-area-weighted centroid of the
3037 //           surrounding elements
3038 //=======================================================================
3039
3040 void centroidalSmooth(const SMDS_MeshNode*                 theNode,
3041                       const Handle(Geom_Surface)&          theSurface,
3042                       map< const SMDS_MeshNode*, gp_XY* >& theUVMap)
3043 {
3044   gp_XYZ aNewXYZ(0.,0.,0.);
3045   SMESH::Controls::Area anAreaFunc;
3046   double totalArea = 0.;
3047   int nbElems = 0;
3048
3049   // compute new XYZ
3050
3051   SMDS_ElemIteratorPtr elemIt = theNode->GetInverseElementIterator(SMDSAbs_Face);
3052   while ( elemIt->more() )
3053   {
3054     const SMDS_MeshElement* elem = elemIt->next();
3055     nbElems++;
3056
3057     gp_XYZ elemCenter(0.,0.,0.);
3058     SMESH::Controls::TSequenceOfXYZ aNodePoints;
3059     SMDS_ElemIteratorPtr itN = elem->nodesIterator();
3060     int nn = elem->NbNodes();
3061     if(elem->IsQuadratic()) nn = nn/2;
3062     int i=0;
3063     //while ( itN->more() ) {
3064     while ( i<nn ) {
3065       const SMDS_MeshNode* aNode = static_cast<const SMDS_MeshNode*>( itN->next() );
3066       i++;
3067       gp_XYZ aP( aNode->X(), aNode->Y(), aNode->Z() );
3068       aNodePoints.push_back( aP );
3069       if ( !theSurface.IsNull() ) { // smooth in 2D
3070         ASSERT( theUVMap.find( aNode ) != theUVMap.end() );
3071         gp_XY* uv = theUVMap[ aNode ];
3072         aP.SetCoord( uv->X(), uv->Y(), 0. );
3073       }
3074       elemCenter += aP;
3075     }
3076     double elemArea = anAreaFunc.GetValue( aNodePoints );
3077     totalArea += elemArea;
3078     elemCenter /= nn;
3079     aNewXYZ += elemCenter * elemArea;
3080   }
3081   aNewXYZ /= totalArea;
3082   if ( !theSurface.IsNull() ) {
3083     theUVMap[ theNode ]->SetCoord( aNewXYZ.X(), aNewXYZ.Y() );
3084     aNewXYZ = theSurface->Value( aNewXYZ.X(), aNewXYZ.Y() ).XYZ();
3085   }
3086
3087   // move node
3088
3089   const_cast< SMDS_MeshNode* >( theNode )->setXYZ(aNewXYZ.X(),aNewXYZ.Y(),aNewXYZ.Z());
3090 }
3091
3092 //=======================================================================
3093 //function : getClosestUV
3094 //purpose  : return UV of closest projection
3095 //=======================================================================
3096
3097 static bool getClosestUV (Extrema_GenExtPS& projector,
3098                           const gp_Pnt&     point,
3099                           gp_XY &           result)
3100 {
3101   projector.Perform( point );
3102   if ( projector.IsDone() ) {
3103     double u, v, minVal = DBL_MAX;
3104     for ( int i = projector.NbExt(); i > 0; i-- )
3105 #if OCC_VERSION_LARGE > 0x06040000 // Porting to OCCT6.5.1
3106       if ( projector.SquareDistance( i ) < minVal ) {
3107         minVal = projector.SquareDistance( i );
3108 #else
3109       if ( projector.Value( i ) < minVal ) {
3110         minVal = projector.Value( i );
3111 #endif
3112         projector.Point( i ).Parameter( u, v );
3113       }
3114     result.SetCoord( u, v );
3115     return true;
3116   }
3117   return false;
3118 }
3119
3120 //=======================================================================
3121 //function : Smooth
3122 //purpose  : Smooth theElements during theNbIterations or until a worst
3123 //           element has aspect ratio <= theTgtAspectRatio.
3124 //           Aspect Ratio varies in range [1.0, inf].
3125 //           If theElements is empty, the whole mesh is smoothed.
3126 //           theFixedNodes contains additionally fixed nodes. Nodes built
3127 //           on edges and boundary nodes are always fixed.
3128 //=======================================================================
3129
3130 void SMESH_MeshEditor::Smooth (TIDSortedElemSet &          theElems,
3131                                set<const SMDS_MeshNode*> & theFixedNodes,
3132                                const SmoothMethod          theSmoothMethod,
3133                                const int                   theNbIterations,
3134                                double                      theTgtAspectRatio,
3135                                const bool                  the2D)
3136 {
3137   myLastCreatedElems.Clear();
3138   myLastCreatedNodes.Clear();
3139
3140   MESSAGE((theSmoothMethod==LAPLACIAN ? "LAPLACIAN" : "CENTROIDAL") << "--::Smooth()");
3141
3142   if ( theTgtAspectRatio < 1.0 )
3143     theTgtAspectRatio = 1.0;
3144
3145   const double disttol = 1.e-16;
3146
3147   SMESH::Controls::AspectRatio aQualityFunc;
3148
3149   SMESHDS_Mesh* aMesh = GetMeshDS();
3150
3151   if ( theElems.empty() ) {
3152     // add all faces to theElems
3153     SMDS_FaceIteratorPtr fIt = aMesh->facesIterator();
3154     while ( fIt->more() ) {
3155       const SMDS_MeshElement* face = fIt->next();
3156       theElems.insert( theElems.end(), face );
3157     }
3158   }
3159   // get all face ids theElems are on
3160   set< int > faceIdSet;
3161   TIDSortedElemSet::iterator itElem;
3162   if ( the2D )
3163     for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
3164       int fId = FindShape( *itElem );
3165       // check that corresponding submesh exists and a shape is face
3166       if (fId &&
3167           faceIdSet.find( fId ) == faceIdSet.end() &&
3168           aMesh->MeshElements( fId )) {
3169         TopoDS_Shape F = aMesh->IndexToShape( fId );
3170         if ( !F.IsNull() && F.ShapeType() == TopAbs_FACE )
3171           faceIdSet.insert( fId );
3172       }
3173     }
3174   faceIdSet.insert( 0 ); // to smooth elements that are not on any TopoDS_Face
3175
3176   // ===============================================
3177   // smooth elements on each TopoDS_Face separately
3178   // ===============================================
3179
3180   set< int >::reverse_iterator fId = faceIdSet.rbegin(); // treate 0 fId at the end
3181   for ( ; fId != faceIdSet.rend(); ++fId ) {
3182     // get face surface and submesh
3183     Handle(Geom_Surface) surface;
3184     SMESHDS_SubMesh* faceSubMesh = 0;
3185     TopoDS_Face face;
3186     double fToler2 = 0, f,l;
3187     double u1 = 0, u2 = 0, v1 = 0, v2 = 0;
3188     bool isUPeriodic = false, isVPeriodic = false;
3189     if ( *fId ) {
3190       face = TopoDS::Face( aMesh->IndexToShape( *fId ));
3191       surface = BRep_Tool::Surface( face );
3192       faceSubMesh = aMesh->MeshElements( *fId );
3193       fToler2 = BRep_Tool::Tolerance( face );
3194       fToler2 *= fToler2 * 10.;
3195       isUPeriodic = surface->IsUPeriodic();
3196       if ( isUPeriodic )
3197         surface->UPeriod();
3198       isVPeriodic = surface->IsVPeriodic();
3199       if ( isVPeriodic )
3200         surface->VPeriod();
3201       surface->Bounds( u1, u2, v1, v2 );
3202     }
3203     // ---------------------------------------------------------
3204     // for elements on a face, find movable and fixed nodes and
3205     // compute UV for them
3206     // ---------------------------------------------------------
3207     bool checkBoundaryNodes = false;
3208     bool isQuadratic = false;
3209     set<const SMDS_MeshNode*> setMovableNodes;
3210     map< const SMDS_MeshNode*, gp_XY* > uvMap, uvMap2;
3211     list< gp_XY > listUV; // uvs the 2 uvMaps refer to
3212     list< const SMDS_MeshElement* > elemsOnFace;
3213
3214     Extrema_GenExtPS projector;
3215     GeomAdaptor_Surface surfAdaptor;
3216     if ( !surface.IsNull() ) {
3217       surfAdaptor.Load( surface );
3218       projector.Initialize( surfAdaptor, 20,20, 1e-5,1e-5 );
3219     }
3220     int nbElemOnFace = 0;
3221     itElem = theElems.begin();
3222     // loop on not yet smoothed elements: look for elems on a face
3223     while ( itElem != theElems.end() ) {
3224       if ( faceSubMesh && nbElemOnFace == faceSubMesh->NbElements() )
3225         break; // all elements found
3226
3227       const SMDS_MeshElement* elem = *itElem;
3228       if ( !elem || elem->GetType() != SMDSAbs_Face || elem->NbNodes() < 3 ||
3229            ( faceSubMesh && !faceSubMesh->Contains( elem ))) {
3230         ++itElem;
3231         continue;
3232       }
3233       elemsOnFace.push_back( elem );
3234       theElems.erase( itElem++ );
3235       nbElemOnFace++;
3236
3237       if ( !isQuadratic )
3238         isQuadratic = elem->IsQuadratic();
3239
3240       // get movable nodes of elem
3241       const SMDS_MeshNode* node;
3242       SMDS_TypeOfPosition posType;
3243       SMDS_ElemIteratorPtr itN = elem->nodesIterator();
3244       int nn = 0, nbn =  elem->NbNodes();
3245       if(elem->IsQuadratic())
3246         nbn = nbn/2;
3247       while ( nn++ < nbn ) {
3248         node = static_cast<const SMDS_MeshNode*>( itN->next() );
3249         const SMDS_PositionPtr& pos = node->GetPosition();
3250         posType = pos ? pos->GetTypeOfPosition() : SMDS_TOP_3DSPACE;
3251         if (posType != SMDS_TOP_EDGE &&
3252             posType != SMDS_TOP_VERTEX &&
3253             theFixedNodes.find( node ) == theFixedNodes.end())
3254         {
3255           // check if all faces around the node are on faceSubMesh
3256           // because a node on edge may be bound to face
3257           SMDS_ElemIteratorPtr eIt = node->GetInverseElementIterator(SMDSAbs_Face);
3258           bool all = true;
3259           if ( faceSubMesh ) {
3260             while ( eIt->more() && all ) {
3261               const SMDS_MeshElement* e = eIt->next();
3262               all = faceSubMesh->Contains( e );
3263             }
3264           }
3265           if ( all )
3266             setMovableNodes.insert( node );
3267           else
3268             checkBoundaryNodes = true;
3269         }
3270         if ( posType == SMDS_TOP_3DSPACE )
3271           checkBoundaryNodes = true;
3272       }
3273
3274       if ( surface.IsNull() )
3275         continue;
3276
3277       // get nodes to check UV
3278       list< const SMDS_MeshNode* > uvCheckNodes;
3279       itN = elem->nodesIterator();
3280       nn = 0; nbn =  elem->NbNodes();
3281       if(elem->IsQuadratic())
3282         nbn = nbn/2;
3283       while ( nn++ < nbn ) {
3284         node = static_cast<const SMDS_MeshNode*>( itN->next() );
3285         if ( uvMap.find( node ) == uvMap.end() )
3286           uvCheckNodes.push_back( node );
3287         // add nodes of elems sharing node
3288         //         SMDS_ElemIteratorPtr eIt = node->GetInverseElementIterator(SMDSAbs_Face);
3289         //         while ( eIt->more() ) {
3290         //           const SMDS_MeshElement* e = eIt->next();
3291         //           if ( e != elem ) {
3292         //             SMDS_ElemIteratorPtr nIt = e->nodesIterator();
3293         //             while ( nIt->more() ) {
3294         //               const SMDS_MeshNode* n =
3295         //                 static_cast<const SMDS_MeshNode*>( nIt->next() );
3296         //               if ( uvMap.find( n ) == uvMap.end() )
3297         //                 uvCheckNodes.push_back( n );
3298         //             }
3299         //           }
3300         //         }
3301       }
3302       // check UV on face
3303       list< const SMDS_MeshNode* >::iterator n = uvCheckNodes.begin();
3304       for ( ; n != uvCheckNodes.end(); ++n ) {
3305         node = *n;
3306         gp_XY uv( 0, 0 );
3307         const SMDS_PositionPtr& pos = node->GetPosition();
3308         posType = pos ? pos->GetTypeOfPosition() : SMDS_TOP_3DSPACE;
3309         // get existing UV
3310         switch ( posType ) {
3311         case SMDS_TOP_FACE: {
3312           SMDS_FacePosition* fPos = ( SMDS_FacePosition* ) pos;
3313           uv.SetCoord( fPos->GetUParameter(), fPos->GetVParameter() );
3314           break;
3315         }
3316         case SMDS_TOP_EDGE: {
3317           TopoDS_Shape S = aMesh->IndexToShape( node->getshapeId() );
3318           Handle(Geom2d_Curve) pcurve;
3319           if ( !S.IsNull() && S.ShapeType() == TopAbs_EDGE )
3320             pcurve = BRep_Tool::CurveOnSurface( TopoDS::Edge( S ), face, f,l );
3321           if ( !pcurve.IsNull() ) {
3322             double u = (( SMDS_EdgePosition* ) pos )->GetUParameter();
3323             uv = pcurve->Value( u ).XY();
3324           }
3325           break;
3326         }
3327         case SMDS_TOP_VERTEX: {
3328           TopoDS_Shape S = aMesh->IndexToShape( node->getshapeId() );
3329           if ( !S.IsNull() && S.ShapeType() == TopAbs_VERTEX )
3330             uv = BRep_Tool::Parameters( TopoDS::Vertex( S ), face ).XY();
3331           break;
3332         }
3333         default:;
3334         }
3335         // check existing UV
3336         bool project = true;
3337         gp_Pnt pNode ( node->X(), node->Y(), node->Z() );
3338         double dist1 = DBL_MAX, dist2 = 0;
3339         if ( posType != SMDS_TOP_3DSPACE ) {
3340           dist1 = pNode.SquareDistance( surface->Value( uv.X(), uv.Y() ));
3341           project = dist1 > fToler2;
3342         }
3343         if ( project ) { // compute new UV
3344           gp_XY newUV;
3345           if ( !getClosestUV( projector, pNode, newUV )) {
3346             MESSAGE("Node Projection Failed " << node);
3347           }
3348           else {
3349             if ( isUPeriodic )
3350               newUV.SetX( ElCLib::InPeriod( newUV.X(), u1, u2 ));
3351             if ( isVPeriodic )
3352               newUV.SetY( ElCLib::InPeriod( newUV.Y(), v1, v2 ));
3353             // check new UV
3354             if ( posType != SMDS_TOP_3DSPACE )
3355               dist2 = pNode.SquareDistance( surface->Value( newUV.X(), newUV.Y() ));
3356             if ( dist2 < dist1 )
3357               uv = newUV;
3358           }
3359         }
3360         // store UV in the map
3361         listUV.push_back( uv );
3362         uvMap.insert( make_pair( node, &listUV.back() ));
3363       }
3364     } // loop on not yet smoothed elements
3365
3366     if ( !faceSubMesh || nbElemOnFace != faceSubMesh->NbElements() )
3367       checkBoundaryNodes = true;
3368
3369     // fix nodes on mesh boundary
3370
3371     if ( checkBoundaryNodes ) {
3372       map< SMESH_TLink, int > linkNbMap; // how many times a link encounters in elemsOnFace
3373       map< SMESH_TLink, int >::iterator link_nb;
3374       // put all elements links to linkNbMap
3375       list< const SMDS_MeshElement* >::iterator elemIt = elemsOnFace.begin();
3376       for ( ; elemIt != elemsOnFace.end(); ++elemIt ) {
3377         const SMDS_MeshElement* elem = (*elemIt);
3378         int nbn =  elem->NbCornerNodes();
3379         // loop on elem links: insert them in linkNbMap
3380         for ( int iN = 0; iN < nbn; ++iN ) {
3381           const SMDS_MeshNode* n1 = elem->GetNode( iN );
3382           const SMDS_MeshNode* n2 = elem->GetNode(( iN+1 ) % nbn);
3383           SMESH_TLink link( n1, n2 );
3384           link_nb = linkNbMap.insert( make_pair( link, 0 )).first;
3385           link_nb->second++;
3386         }
3387       }
3388       // remove nodes that are in links encountered only once from setMovableNodes
3389       for ( link_nb = linkNbMap.begin(); link_nb != linkNbMap.end(); ++link_nb ) {
3390         if ( link_nb->second == 1 ) {
3391           setMovableNodes.erase( link_nb->first.node1() );
3392           setMovableNodes.erase( link_nb->first.node2() );
3393         }
3394       }
3395     }
3396
3397     // -----------------------------------------------------
3398     // for nodes on seam edge, compute one more UV ( uvMap2 );
3399     // find movable nodes linked to nodes on seam and which
3400     // are to be smoothed using the second UV ( uvMap2 )
3401     // -----------------------------------------------------
3402
3403     set<const SMDS_MeshNode*> nodesNearSeam; // to smooth using uvMap2
3404     if ( !surface.IsNull() ) {
3405       TopExp_Explorer eExp( face, TopAbs_EDGE );
3406       for ( ; eExp.More(); eExp.Next() ) {
3407         TopoDS_Edge edge = TopoDS::Edge( eExp.Current() );
3408         if ( !BRep_Tool::IsClosed( edge, face ))
3409           continue;
3410         SMESHDS_SubMesh* sm = aMesh->MeshElements( edge );
3411         if ( !sm ) continue;
3412         // find out which parameter varies for a node on seam
3413         double f,l;
3414         gp_Pnt2d uv1, uv2;
3415         Handle(Geom2d_Curve) pcurve = BRep_Tool::CurveOnSurface( edge, face, f, l );
3416         if ( pcurve.IsNull() ) continue;
3417         uv1 = pcurve->Value( f );
3418         edge.Reverse();
3419         pcurve = BRep_Tool::CurveOnSurface( edge, face, f, l );
3420         if ( pcurve.IsNull() ) continue;
3421         uv2 = pcurve->Value( f );
3422         int iPar = Abs( uv1.X() - uv2.X() ) > Abs( uv1.Y() - uv2.Y() ) ? 1 : 2;
3423         // assure uv1 < uv2
3424         if ( uv1.Coord( iPar ) > uv2.Coord( iPar )) {
3425           gp_Pnt2d tmp = uv1; uv1 = uv2; uv2 = tmp;
3426         }
3427         // get nodes on seam and its vertices
3428         list< const SMDS_MeshNode* > seamNodes;
3429         SMDS_NodeIteratorPtr nSeamIt = sm->GetNodes();
3430         while ( nSeamIt->more() ) {
3431           const SMDS_MeshNode* node = nSeamIt->next();
3432           if ( !isQuadratic || !IsMedium( node ))
3433             seamNodes.push_back( node );
3434         }
3435         TopExp_Explorer vExp( edge, TopAbs_VERTEX );
3436         for ( ; vExp.More(); vExp.Next() ) {
3437           sm = aMesh->MeshElements( vExp.Current() );
3438           if ( sm ) {
3439             nSeamIt = sm->GetNodes();
3440             while ( nSeamIt->more() )
3441               seamNodes.push_back( nSeamIt->next() );
3442           }
3443         }
3444         // loop on nodes on seam
3445         list< const SMDS_MeshNode* >::iterator noSeIt = seamNodes.begin();
3446         for ( ; noSeIt != seamNodes.end(); ++noSeIt ) {
3447           const SMDS_MeshNode* nSeam = *noSeIt;
3448           map< const SMDS_MeshNode*, gp_XY* >::iterator n_uv = uvMap.find( nSeam );
3449           if ( n_uv == uvMap.end() )
3450             continue;
3451           // set the first UV
3452           n_uv->second->SetCoord( iPar, uv1.Coord( iPar ));
3453           // set the second UV
3454           listUV.push_back( *n_uv->second );
3455           listUV.back().SetCoord( iPar, uv2.Coord( iPar ));
3456           if ( uvMap2.empty() )
3457             uvMap2 = uvMap; // copy the uvMap contents
3458           uvMap2[ nSeam ] = &listUV.back();
3459
3460           // collect movable nodes linked to ones on seam in nodesNearSeam
3461           SMDS_ElemIteratorPtr eIt = nSeam->GetInverseElementIterator(SMDSAbs_Face);
3462           while ( eIt->more() ) {
3463             const SMDS_MeshElement* e = eIt->next();
3464             int nbUseMap1 = 0, nbUseMap2 = 0;
3465             SMDS_ElemIteratorPtr nIt = e->nodesIterator();
3466             int nn = 0, nbn =  e->NbNodes();
3467             if(e->IsQuadratic()) nbn = nbn/2;
3468             while ( nn++ < nbn )
3469             {
3470               const SMDS_MeshNode* n =
3471                 static_cast<const SMDS_MeshNode*>( nIt->next() );
3472               if (n == nSeam ||
3473                   setMovableNodes.find( n ) == setMovableNodes.end() )
3474                 continue;
3475               // add only nodes being closer to uv2 than to uv1
3476               gp_Pnt pMid (0.5 * ( n->X() + nSeam->X() ),
3477                            0.5 * ( n->Y() + nSeam->Y() ),
3478                            0.5 * ( n->Z() + nSeam->Z() ));
3479               gp_XY uv;
3480               getClosestUV( projector, pMid, uv );
3481               if ( uv.Coord( iPar ) > uvMap[ n ]->Coord( iPar ) ) {
3482                 nodesNearSeam.insert( n );
3483                 nbUseMap2++;
3484               }
3485               else
3486                 nbUseMap1++;
3487             }
3488             // for centroidalSmooth all element nodes must
3489             // be on one side of a seam
3490             if ( theSmoothMethod == CENTROIDAL && nbUseMap1 && nbUseMap2 ) {
3491               SMDS_ElemIteratorPtr nIt = e->nodesIterator();
3492               nn = 0;
3493               while ( nn++ < nbn ) {
3494                 const SMDS_MeshNode* n =
3495                   static_cast<const SMDS_MeshNode*>( nIt->next() );
3496                 setMovableNodes.erase( n );
3497               }
3498             }
3499           }
3500         } // loop on nodes on seam
3501       } // loop on edge of a face
3502     } // if ( !face.IsNull() )
3503
3504     if ( setMovableNodes.empty() ) {
3505       MESSAGE( "Face id : " << *fId << " - NO SMOOTHING: no nodes to move!!!");
3506       continue; // goto next face
3507     }
3508
3509     // -------------
3510     // SMOOTHING //
3511     // -------------
3512
3513     int it = -1;
3514     double maxRatio = -1., maxDisplacement = -1.;
3515     set<const SMDS_MeshNode*>::iterator nodeToMove;
3516     for ( it = 0; it < theNbIterations; it++ ) {
3517       maxDisplacement = 0.;
3518       nodeToMove = setMovableNodes.begin();
3519       for ( ; nodeToMove != setMovableNodes.end(); nodeToMove++ ) {
3520         const SMDS_MeshNode* node = (*nodeToMove);
3521         gp_XYZ aPrevPos ( node->X(), node->Y(), node->Z() );
3522
3523         // smooth
3524         bool map2 = ( nodesNearSeam.find( node ) != nodesNearSeam.end() );
3525         if ( theSmoothMethod == LAPLACIAN )
3526           laplacianSmooth( node, surface, map2 ? uvMap2 : uvMap );
3527         else
3528           centroidalSmooth( node, surface, map2 ? uvMap2 : uvMap );
3529
3530         // node displacement
3531         gp_XYZ aNewPos ( node->X(), node->Y(), node->Z() );
3532         Standard_Real aDispl = (aPrevPos - aNewPos).SquareModulus();
3533         if ( aDispl > maxDisplacement )
3534           maxDisplacement = aDispl;
3535       }
3536       // no node movement => exit
3537       //if ( maxDisplacement < 1.e-16 ) {
3538       if ( maxDisplacement < disttol ) {
3539         MESSAGE("-- no node movement --");
3540         break;
3541       }
3542
3543       // check elements quality
3544       maxRatio  = 0;
3545       list< const SMDS_MeshElement* >::iterator elemIt = elemsOnFace.begin();
3546       for ( ; elemIt != elemsOnFace.end(); ++elemIt ) {
3547         const SMDS_MeshElement* elem = (*elemIt);
3548         if ( !elem || elem->GetType() != SMDSAbs_Face )
3549           continue;
3550         SMESH::Controls::TSequenceOfXYZ aPoints;
3551         if ( aQualityFunc.GetPoints( elem, aPoints )) {
3552           double aValue = aQualityFunc.GetValue( aPoints );
3553           if ( aValue > maxRatio )
3554             maxRatio = aValue;
3555         }
3556       }
3557       if ( maxRatio <= theTgtAspectRatio ) {
3558         MESSAGE("-- quality achived --");
3559         break;
3560       }
3561       if (it+1 == theNbIterations) {
3562         MESSAGE("-- Iteration limit exceeded --");
3563       }
3564     } // smoothing iterations
3565
3566     MESSAGE(" Face id: " << *fId <<
3567             " Nb iterstions: " << it <<
3568             " Displacement: " << maxDisplacement <<
3569             " Aspect Ratio " << maxRatio);
3570
3571     // ---------------------------------------
3572     // new nodes positions are computed,
3573     // record movement in DS and set new UV
3574     // ---------------------------------------
3575     nodeToMove = setMovableNodes.begin();
3576     for ( ; nodeToMove != setMovableNodes.end(); nodeToMove++ ) {
3577       SMDS_MeshNode* node = const_cast< SMDS_MeshNode* > (*nodeToMove);
3578       aMesh->MoveNode( node, node->X(), node->Y(), node->Z() );
3579       map< const SMDS_MeshNode*, gp_XY* >::iterator node_uv = uvMap.find( node );
3580       if ( node_uv != uvMap.end() ) {
3581         gp_XY* uv = node_uv->second;
3582         node->SetPosition
3583           ( SMDS_PositionPtr( new SMDS_FacePosition( uv->X(), uv->Y() )));
3584       }
3585     }
3586
3587     // move medium nodes of quadratic elements
3588     if ( isQuadratic )
3589     {
3590       SMESH_MesherHelper helper( *GetMesh() );
3591       if ( !face.IsNull() )
3592         helper.SetSubShape( face );
3593       list< const SMDS_MeshElement* >::iterator elemIt = elemsOnFace.begin();
3594       for ( ; elemIt != elemsOnFace.end(); ++elemIt ) {
3595         const SMDS_VtkFace* QF =
3596           dynamic_cast<const SMDS_VtkFace*> (*elemIt);
3597         if(QF && QF->IsQuadratic()) {
3598           vector<const SMDS_MeshNode*> Ns;
3599           Ns.reserve(QF->NbNodes()+1);
3600           SMDS_ElemIteratorPtr anIter = QF->interlacedNodesElemIterator();
3601           while ( anIter->more() )
3602             Ns.push_back( cast2Node(anIter->next()) );
3603           Ns.push_back( Ns[0] );
3604           double x, y, z;
3605           for(int i=0; i<QF->NbNodes(); i=i+2) {
3606             if ( !surface.IsNull() ) {
3607               gp_XY uv1 = helper.GetNodeUV( face, Ns[i], Ns[i+2] );
3608               gp_XY uv2 = helper.GetNodeUV( face, Ns[i+2], Ns[i] );
3609               gp_XY uv = ( uv1 + uv2 ) / 2.;
3610               gp_Pnt xyz = surface->Value( uv.X(), uv.Y() );
3611               x = xyz.X(); y = xyz.Y(); z = xyz.Z();
3612             }
3613             else {
3614               x = (Ns[i]->X() + Ns[i+2]->X())/2;
3615               y = (Ns[i]->Y() + Ns[i+2]->Y())/2;
3616               z = (Ns[i]->Z() + Ns[i+2]->Z())/2;
3617             }
3618             if( fabs( Ns[i+1]->X() - x ) > disttol ||
3619                 fabs( Ns[i+1]->Y() - y ) > disttol ||
3620                 fabs( Ns[i+1]->Z() - z ) > disttol ) {
3621               // we have to move i+1 node
3622               aMesh->MoveNode( Ns[i+1], x, y, z );
3623             }
3624           }
3625         }
3626       }
3627     }
3628
3629   } // loop on face ids
3630
3631 }
3632
3633 //=======================================================================
3634 //function : isReverse
3635 //purpose  : Return true if normal of prevNodes is not co-directied with
3636 //           gp_Vec(prevNodes[iNotSame],nextNodes[iNotSame]).
3637 //           iNotSame is where prevNodes and nextNodes are different.
3638 //           If result is true then future volume orientation is OK
3639 //=======================================================================
3640
3641 static bool isReverse(const SMDS_MeshElement*             face,
3642                       const vector<const SMDS_MeshNode*>& prevNodes,
3643                       const vector<const SMDS_MeshNode*>& nextNodes,
3644                       const int                           iNotSame)
3645 {
3646
3647   SMESH_TNodeXYZ pP = prevNodes[ iNotSame ];
3648   SMESH_TNodeXYZ pN = nextNodes[ iNotSame ];
3649   gp_XYZ extrDir( pN - pP ), faceNorm;
3650   SMESH_Algo::FaceNormal( face, faceNorm, /*normalized=*/false );
3651
3652   return faceNorm * extrDir < 0.0;
3653 }
3654
3655 //=======================================================================
3656 /*!
3657  * \brief Create elements by sweeping an element
3658  * \param elem - element to sweep
3659  * \param newNodesItVec - nodes generated from each node of the element
3660  * \param newElems - generated elements
3661  * \param nbSteps - number of sweeping steps
3662  * \param srcElements - to append elem for each generated element
3663  */
3664 //=======================================================================
3665
3666 void SMESH_MeshEditor::sweepElement(const SMDS_MeshElement*               elem,
3667                                     const vector<TNodeOfNodeListMapItr> & newNodesItVec,
3668                                     list<const SMDS_MeshElement*>&        newElems,
3669                                     const int                             nbSteps,
3670                                     SMESH_SequenceOfElemPtr&              srcElements)
3671 {
3672   //MESSAGE("sweepElement " << nbSteps);
3673   SMESHDS_Mesh* aMesh = GetMeshDS();
3674
3675   const int           nbNodes = elem->NbNodes();
3676   const int         nbCorners = elem->NbCornerNodes();
3677   SMDSAbs_EntityType baseType = elem->GetEntityType(); /* it can change in case of
3678                                                           polyhedron creation !!! */
3679   // Loop on elem nodes:
3680   // find new nodes and detect same nodes indices
3681   vector < list< const SMDS_MeshNode* >::const_iterator > itNN( nbNodes );
3682   vector<const SMDS_MeshNode*> prevNod( nbNodes );
3683   vector<const SMDS_MeshNode*> nextNod( nbNodes );
3684   vector<const SMDS_MeshNode*> midlNod( nbNodes );
3685
3686   int iNode, nbSame = 0, nbDouble = 0, iNotSameNode = 0;
3687   vector<int> sames(nbNodes);
3688   vector<bool> isSingleNode(nbNodes);
3689
3690   for ( iNode = 0; iNode < nbNodes; iNode++ ) {
3691     TNodeOfNodeListMapItr                        nnIt = newNodesItVec[ iNode ];
3692     const SMDS_MeshNode*                         node = nnIt->first;
3693     const list< const SMDS_MeshNode* > & listNewNodes = nnIt->second;
3694     if ( listNewNodes.empty() )
3695       return;
3696
3697     itNN   [ iNode ] = listNewNodes.begin();
3698     prevNod[ iNode ] = node;
3699     nextNod[ iNode ] = listNewNodes.front();
3700
3701     isSingleNode[iNode] = (listNewNodes.size()==nbSteps); /* medium node of quadratic or
3702                                                              corner node of linear */
3703     if ( prevNod[ iNode ] != nextNod [ iNode ])
3704       nbDouble += !isSingleNode[iNode];
3705
3706     if( iNode < nbCorners ) { // check corners only
3707       if ( prevNod[ iNode ] == nextNod [ iNode ])
3708         sames[nbSame++] = iNode;
3709       else
3710         iNotSameNode = iNode;
3711     }
3712   }
3713
3714   if ( nbSame == nbNodes || nbSame > 2) {
3715     MESSAGE( " Too many same nodes of element " << elem->GetID() );
3716     return;
3717   }
3718
3719   if ( elem->GetType() == SMDSAbs_Face && !isReverse( elem, prevNod, nextNod, iNotSameNode ))
3720   {
3721     // fix nodes order to have bottom normal external
3722     if ( baseType == SMDSEntity_Polygon )
3723     {
3724       std::reverse( itNN.begin(), itNN.end() );
3725       std::reverse( prevNod.begin(), prevNod.end() );
3726       std::reverse( midlNod.begin(), midlNod.end() );
3727       std::reverse( nextNod.begin(), nextNod.end() );
3728       std::reverse( isSingleNode.begin(), isSingleNode.end() );
3729     }
3730     else
3731     {
3732       const vector<int>& ind = SMDS_MeshCell::reverseSmdsOrder( baseType );
3733       SMDS_MeshCell::applyInterlace( ind, itNN );
3734       SMDS_MeshCell::applyInterlace( ind, prevNod );
3735       SMDS_MeshCell::applyInterlace( ind, nextNod );
3736       SMDS_MeshCell::applyInterlace( ind, midlNod );
3737       SMDS_MeshCell::applyInterlace( ind, isSingleNode );
3738       if ( nbSame > 0 )
3739       {
3740         sames[nbSame] = iNotSameNode;
3741         for ( int j = 0; j <= nbSame; ++j )
3742           for ( size_t i = 0; i < ind.size(); ++i )
3743             if ( ind[i] == sames[j] )
3744             {
3745               sames[j] = i;
3746               break;
3747             }
3748         iNotSameNode = sames[nbSame];
3749       }
3750     }
3751   }
3752
3753   int iSameNode = 0, iBeforeSame = 0, iAfterSame = 0, iOpposSame = 0;
3754   if ( nbSame > 0 ) {
3755     iSameNode    = sames[ nbSame-1 ];
3756     iBeforeSame  = ( iSameNode + nbCorners - 1 ) % nbCorners;
3757     iAfterSame   = ( iSameNode + 1 ) % nbCorners;
3758     iOpposSame   = ( iSameNode - 2 < 0  ? iSameNode + 2 : iSameNode - 2 );
3759   }
3760
3761   // make new elements
3762   for (int iStep = 0; iStep < nbSteps; iStep++ )
3763   {
3764     // get next nodes
3765     for ( iNode = 0; iNode < nbNodes; iNode++ )
3766     {
3767       midlNod[ iNode ] = isSingleNode[iNode] ? 0 : *itNN[ iNode ]++;
3768       nextNod[ iNode ] = *itNN[ iNode ]++;
3769     }
3770
3771     SMDS_MeshElement* aNewElem = 0;
3772     /*if(!elem->IsPoly())*/ {
3773       switch ( baseType ) {
3774       case SMDSEntity_0D:
3775       case SMDSEntity_Node: { // sweep NODE
3776         if ( nbSame == 0 ) {
3777           if ( isSingleNode[0] )
3778             aNewElem = aMesh->AddEdge( prevNod[ 0 ], nextNod[ 0 ] );
3779           else
3780             aNewElem = aMesh->AddEdge( prevNod[ 0 ], nextNod[ 0 ], midlNod[ 0 ] );
3781         }
3782         else
3783           return;
3784         break;
3785       }
3786       case SMDSEntity_Edge: { // sweep EDGE
3787         if ( nbDouble == 0 )
3788         {
3789           if ( nbSame == 0 ) // ---> quadrangle
3790             aNewElem = aMesh->AddFace(prevNod[ 0 ], prevNod[ 1 ],
3791                                       nextNod[ 1 ], nextNod[ 0 ] );
3792           else               // ---> triangle
3793             aNewElem = aMesh->AddFace(prevNod[ 0 ], prevNod[ 1 ],
3794                                       nextNod[ iNotSameNode ] );
3795         }
3796         else                 // ---> polygon
3797         {
3798           vector<const SMDS_MeshNode*> poly_nodes;
3799           poly_nodes.push_back( prevNod[0] );
3800           poly_nodes.push_back( prevNod[1] );
3801           if ( prevNod[1] != nextNod[1] )
3802           {
3803             if ( midlNod[1]) poly_nodes.push_back( midlNod[1]);
3804             poly_nodes.push_back( nextNod[1] );
3805           }
3806           if ( prevNod[0] != nextNod[0] )
3807           {
3808             poly_nodes.push_back( nextNod[0] );
3809             if ( midlNod[0]) poly_nodes.push_back( midlNod[0]);
3810           }
3811           switch ( poly_nodes.size() ) {
3812           case 3:
3813             aNewElem = aMesh->AddFace( poly_nodes[ 0 ], poly_nodes[ 1 ], poly_nodes[ 2 ]);
3814             break;
3815           case 4:
3816             aNewElem = aMesh->AddFace( poly_nodes[ 0 ], poly_nodes[ 1 ],
3817                                        poly_nodes[ 2 ], poly_nodes[ 3 ]);
3818             break;
3819           default:
3820             aNewElem = aMesh->AddPolygonalFace (poly_nodes);
3821           }
3822         }
3823         break;
3824       }
3825       case SMDSEntity_Triangle: // TRIANGLE --->
3826         {
3827           if ( nbDouble > 0 ) break;
3828           if ( nbSame == 0 )       // ---> pentahedron
3829             aNewElem = aMesh->AddVolume (prevNod[ 0 ], prevNod[ 1 ], prevNod[ 2 ],
3830                                          nextNod[ 0 ], nextNod[ 1 ], nextNod[ 2 ] );
3831
3832           else if ( nbSame == 1 )  // ---> pyramid
3833             aNewElem = aMesh->AddVolume (prevNod[ iBeforeSame ], prevNod[ iAfterSame ],
3834                                          nextNod[ iAfterSame ],  nextNod[ iBeforeSame ],
3835                                          nextNod[ iSameNode ]);
3836
3837           else // 2 same nodes:       ---> tetrahedron
3838             aNewElem = aMesh->AddVolume (prevNod[ 0 ], prevNod[ 1 ], prevNod[ 2 ],
3839                                          nextNod[ iNotSameNode ]);
3840           break;
3841         }
3842       case SMDSEntity_Quad_Edge: // sweep quadratic EDGE --->
3843         {
3844           if ( nbSame == 2 )
3845             return;
3846           if ( nbDouble+nbSame == 2 )
3847           {
3848             if(nbSame==0) {      // ---> quadratic quadrangle
3849               aNewElem = aMesh->AddFace(prevNod[0], prevNod[1], nextNod[1], nextNod[0],
3850                                         prevNod[2], midlNod[1], nextNod[2], midlNod[0]);
3851             }
3852             else { //(nbSame==1) // ---> quadratic triangle
3853               if(sames[0]==2) {
3854                 return; // medium node on axis
3855               }
3856               else if(sames[0]==0)
3857                 aNewElem = aMesh->AddFace(prevNod[0], nextNod[1], prevNod[1],
3858                                           nextNod[2], midlNod[1], prevNod[2]);
3859               else // sames[0]==1
3860                 aNewElem = aMesh->AddFace(prevNod[0], nextNod[0], prevNod[1],
3861                                           midlNod[0], nextNod[2], prevNod[2]);
3862             }
3863           }
3864           else if ( nbDouble == 3 )
3865           {
3866             if ( nbSame == 0 ) {  // ---> bi-quadratic quadrangle
3867               aNewElem = aMesh->AddFace(prevNod[0], prevNod[1], nextNod[1], nextNod[0],
3868                                         prevNod[2], midlNod[1], nextNod[2], midlNod[0], midlNod[2]);
3869             }
3870           }
3871           else
3872             return;
3873           break;
3874         }
3875       case SMDSEntity_Quadrangle: { // sweep QUADRANGLE --->
3876         if ( nbDouble > 0 ) break;
3877
3878         if ( nbSame == 0 )       // ---> hexahedron
3879           aNewElem = aMesh->AddVolume (prevNod[ 0 ], prevNod[ 1 ], prevNod[ 2 ], prevNod[ 3 ],
3880                                        nextNod[ 0 ], nextNod[ 1 ], nextNod[ 2 ], nextNod[ 3 ]);
3881
3882         else if ( nbSame == 1 ) { // ---> pyramid + pentahedron
3883           aNewElem = aMesh->AddVolume (prevNod[ iBeforeSame ], prevNod[ iAfterSame ],
3884                                        nextNod[ iAfterSame ],  nextNod[ iBeforeSame ],
3885                                        nextNod[ iSameNode ]);
3886           newElems.push_back( aNewElem );
3887           aNewElem = aMesh->AddVolume (prevNod[ iAfterSame ],  prevNod[ iOpposSame ],
3888                                        prevNod[ iBeforeSame ], nextNod[ iAfterSame ],
3889                                        nextNod[ iOpposSame ],  nextNod[ iBeforeSame ] );
3890         }
3891         else if ( nbSame == 2 ) { // ---> pentahedron
3892           if ( prevNod[ iBeforeSame ] == nextNod[ iBeforeSame ] )
3893             // iBeforeSame is same too
3894             aNewElem = aMesh->AddVolume (prevNod[ iBeforeSame ], prevNod[ iOpposSame ],
3895                                          nextNod[ iOpposSame ],  prevNod[ iSameNode ],
3896                                          prevNod[ iAfterSame ],  nextNod[ iAfterSame ]);
3897           else
3898             // iAfterSame is same too
3899             aNewElem = aMesh->AddVolume (prevNod[ iSameNode ],   prevNod[ iBeforeSame ],
3900                                          nextNod[ iBeforeSame ], prevNod[ iAfterSame ],
3901                                          prevNod[ iOpposSame ],  nextNod[ iOpposSame ]);
3902         }
3903         break;
3904       }
3905       case SMDSEntity_Quad_Triangle: { // sweep Quadratic TRIANGLE --->
3906         if ( nbDouble+nbSame != 3 ) break;
3907         if(nbSame==0) {
3908           // --->  pentahedron with 15 nodes
3909           aNewElem = aMesh->AddVolume (prevNod[0], prevNod[1], prevNod[2],
3910                                        nextNod[0], nextNod[1], nextNod[2],
3911                                        prevNod[3], prevNod[4], prevNod[5],
3912                                        nextNod[3], nextNod[4], nextNod[5],
3913                                        midlNod[0], midlNod[1], midlNod[2]);
3914         }
3915         else if(nbSame==1) {
3916           // --->  2d order pyramid of 13 nodes
3917           int apex = iSameNode;
3918           int i0 = ( apex + 1 ) % nbCorners;
3919           int i1 = ( apex - 1 + nbCorners ) % nbCorners;
3920           int i0a = apex + 3;
3921           int i1a = i1 + 3;
3922           int i01 = i0 + 3;
3923           aNewElem = aMesh->AddVolume(prevNod[i1], prevNod[i0],
3924                                       nextNod[i0], nextNod[i1], prevNod[apex],
3925                                       prevNod[i01], midlNod[i0],
3926                                       nextNod[i01], midlNod[i1],
3927                                       prevNod[i1a], prevNod[i0a],
3928                                       nextNod[i0a], nextNod[i1a]);
3929         }
3930         else if(nbSame==2) {
3931           // --->  2d order tetrahedron of 10 nodes
3932           int n1 = iNotSameNode;
3933           int n2 = ( n1 + 1             ) % nbCorners;
3934           int n3 = ( n1 + nbCorners - 1 ) % nbCorners;
3935           int n12 = n1 + 3;
3936           int n23 = n2 + 3;
3937           int n31 = n3 + 3;
3938           aNewElem = aMesh->AddVolume (prevNod[n1], prevNod[n2], prevNod[n3], nextNod[n1],
3939                                        prevNod[n12], prevNod[n23], prevNod[n31],
3940                                        midlNod[n1], nextNod[n12], nextNod[n31]);
3941         }
3942         break;
3943       }
3944       case SMDSEntity_Quad_Quadrangle: { // sweep Quadratic QUADRANGLE --->
3945         if( nbSame == 0 ) {
3946           if ( nbDouble != 4 ) break;
3947           // --->  hexahedron with 20 nodes
3948           aNewElem = aMesh->AddVolume (prevNod[0], prevNod[1], prevNod[2], prevNod[3],
3949                                        nextNod[0], nextNod[1], nextNod[2], nextNod[3],
3950                                        prevNod[4], prevNod[5], prevNod[6], prevNod[7],
3951                                        nextNod[4], nextNod[5], nextNod[6], nextNod[7],
3952                                        midlNod[0], midlNod[1], midlNod[2], midlNod[3]);
3953         }
3954         else if(nbSame==1) {
3955           // ---> pyramid + pentahedron - can not be created since it is needed
3956           // additional middle node at the center of face
3957           INFOS( " Sweep for face " << elem->GetID() << " can not be created" );
3958           return;
3959         }
3960         else if( nbSame == 2 ) {
3961           if ( nbDouble != 2 ) break;
3962           // --->  2d order Pentahedron with 15 nodes
3963           int n1,n2,n4,n5;
3964           if ( prevNod[ iBeforeSame ] == nextNod[ iBeforeSame ] ) {
3965             // iBeforeSame is same too
3966             n1 = iBeforeSame;
3967             n2 = iOpposSame;
3968             n4 = iSameNode;
3969             n5 = iAfterSame;
3970           }
3971           else {
3972             // iAfterSame is same too
3973             n1 = iSameNode;
3974             n2 = iBeforeSame;
3975             n4 = iAfterSame;
3976             n5 = iOpposSame;
3977           }
3978           int n12 = n2 + 4;
3979           int n45 = n4 + 4;
3980           int n14 = n1 + 4;
3981           int n25 = n5 + 4;
3982           aNewElem = aMesh->AddVolume (prevNod[n1], prevNod[n2], nextNod[n2],
3983                                        prevNod[n4], prevNod[n5], nextNod[n5],
3984                                        prevNod[n12], midlNod[n2], nextNod[n12],
3985                                        prevNod[n45], midlNod[n5], nextNod[n45],
3986                                        prevNod[n14], prevNod[n25], nextNod[n25]);
3987         }
3988         break;
3989       }
3990       case SMDSEntity_BiQuad_Quadrangle: { // sweep BiQuadratic QUADRANGLE --->
3991
3992         if( nbSame == 0 && nbDouble == 9 ) {
3993           // --->  tri-quadratic hexahedron with 27 nodes
3994           aNewElem = aMesh->AddVolume (prevNod[0], prevNod[1], prevNod[2], prevNod[3],
3995                                        nextNod[0], nextNod[1], nextNod[2], nextNod[3],
3996                                        prevNod[4], prevNod[5], prevNod[6], prevNod[7],
3997                                        nextNod[4], nextNod[5], nextNod[6], nextNod[7],
3998                                        midlNod[0], midlNod[1], midlNod[2], midlNod[3],
3999                                        prevNod[8], // bottom center
4000                                        midlNod[4], midlNod[5], midlNod[6], midlNod[7],
4001                                        nextNod[8], // top center
4002                                        midlNod[8]);// elem center
4003         }
4004         else
4005         {
4006           return;
4007         }
4008         break;
4009       }
4010       case SMDSEntity_Polygon: { // sweep POLYGON
4011
4012         if ( nbNodes == 6 && nbSame == 0 && nbDouble == 0 ) {
4013           // --->  hexagonal prism
4014           aNewElem = aMesh->AddVolume (prevNod[0], prevNod[1], prevNod[2],
4015                                        prevNod[3], prevNod[4], prevNod[5],
4016                                        nextNod[0], nextNod[1], nextNod[2],
4017                                        nextNod[3], nextNod[4], nextNod[5]);
4018         }
4019         break;
4020       }
4021       case SMDSEntity_Ball:
4022         return;
4023
4024       default:
4025         break;
4026       }
4027     }
4028
4029     if ( !aNewElem && elem->GetType() == SMDSAbs_Face ) // try to create a polyherdal prism
4030     {
4031       if ( baseType != SMDSEntity_Polygon )
4032       {
4033         const std::vector<int>& ind = SMDS_MeshCell::interlacedSmdsOrder(baseType);
4034         SMDS_MeshCell::applyInterlace( ind, prevNod );
4035         SMDS_MeshCell::applyInterlace( ind, nextNod );
4036         SMDS_MeshCell::applyInterlace( ind, midlNod );
4037         SMDS_MeshCell::applyInterlace( ind, itNN );
4038         SMDS_MeshCell::applyInterlace( ind, isSingleNode );
4039         baseType = SMDSEntity_Polygon; // WARNING: change baseType !!!!
4040       }
4041       vector<const SMDS_MeshNode*> polyedre_nodes (nbNodes*2 + 4*nbNodes);
4042       vector<int> quantities (nbNodes + 2);
4043       polyedre_nodes.clear();
4044       quantities.clear();
4045
4046       // bottom of prism
4047       for (int inode = 0; inode < nbNodes; inode++)
4048         polyedre_nodes.push_back( prevNod[inode] );
4049       quantities.push_back( nbNodes );
4050
4051       // top of prism
4052       polyedre_nodes.push_back( nextNod[0] );
4053       for (int inode = nbNodes; inode-1; --inode )
4054         polyedre_nodes.push_back( nextNod[inode-1] );
4055       quantities.push_back( nbNodes );
4056
4057       // side faces
4058       for (int iface = 0; iface < nbNodes; iface++)
4059       {
4060         const int prevNbNodes = polyedre_nodes.size();
4061         int inextface = (iface+1) % nbNodes;
4062         polyedre_nodes.push_back( prevNod[inextface] );
4063         polyedre_nodes.push_back( prevNod[iface] );
4064         if ( prevNod[iface] != nextNod[iface] )
4065         {
4066           if ( midlNod[ iface ]) polyedre_nodes.push_back( midlNod[ iface ]);
4067           polyedre_nodes.push_back( nextNod[iface] );
4068         }
4069         if ( prevNod[inextface] != nextNod[inextface] )
4070         {
4071           polyedre_nodes.push_back( nextNod[inextface] );
4072           if ( midlNod[ inextface ]) polyedre_nodes.push_back( midlNod[ inextface ]);
4073         }
4074         const int nbFaceNodes = polyedre_nodes.size() - prevNbNodes;
4075         if ( nbFaceNodes > 2 )
4076           quantities.push_back( nbFaceNodes );
4077         else // degenerated face
4078           polyedre_nodes.resize( prevNbNodes );
4079       }
4080       aNewElem = aMesh->AddPolyhedralVolume (polyedre_nodes, quantities);
4081     }
4082
4083     if ( aNewElem ) {
4084       newElems.push_back( aNewElem );
4085       myLastCreatedElems.Append(aNewElem);
4086       srcElements.Append( elem );
4087     }
4088
4089     // set new prev nodes
4090     for ( iNode = 0; iNode < nbNodes; iNode++ )
4091       prevNod[ iNode ] = nextNod[ iNode ];
4092
4093   } // for steps
4094 }
4095
4096 //=======================================================================
4097 /*!
4098  * \brief Create 1D and 2D elements around swept elements
4099  * \param mapNewNodes - source nodes and ones generated from them
4100  * \param newElemsMap - source elements and ones generated from them
4101  * \param elemNewNodesMap - nodes generated from each node of each element
4102  * \param elemSet - all swept elements
4103  * \param nbSteps - number of sweeping steps
4104  * \param srcElements - to append elem for each generated element
4105  */
4106 //=======================================================================
4107
4108 void SMESH_MeshEditor::makeWalls (TNodeOfNodeListMap &     mapNewNodes,
4109                                   TElemOfElemListMap &     newElemsMap,
4110                                   TElemOfVecOfNnlmiMap &   elemNewNodesMap,
4111                                   TIDSortedElemSet&        elemSet,
4112                                   const int                nbSteps,
4113                                   SMESH_SequenceOfElemPtr& srcElements)
4114 {
4115   ASSERT( newElemsMap.size() == elemNewNodesMap.size() );
4116   SMESHDS_Mesh* aMesh = GetMeshDS();
4117
4118   // Find nodes belonging to only one initial element - sweep them to get edges.
4119
4120   TNodeOfNodeListMapItr nList = mapNewNodes.begin();
4121   for ( ; nList != mapNewNodes.end(); nList++ )
4122   {
4123     const SMDS_MeshNode* node =
4124       static_cast<const SMDS_MeshNode*>( nList->first );
4125     if ( newElemsMap.count( node ))
4126       continue; // node was extruded into edge
4127     SMDS_ElemIteratorPtr eIt = node->GetInverseElementIterator();
4128     int nbInitElems = 0;
4129     const SMDS_MeshElement* el = 0;
4130     SMDSAbs_ElementType highType = SMDSAbs_Edge; // count most complex elements only
4131     while ( eIt->more() && nbInitElems < 2 ) {
4132       el = eIt->next();
4133       SMDSAbs_ElementType type = el->GetType();
4134       if ( type == SMDSAbs_Volume || type < highType ) continue;
4135       if ( type > highType ) {
4136         nbInitElems = 0;
4137         highType = type;
4138       }
4139       nbInitElems += elemSet.count(el);
4140     }
4141     if ( nbInitElems < 2 ) {
4142       bool NotCreateEdge = el && el->IsMediumNode(node);
4143       if(!NotCreateEdge) {
4144         vector<TNodeOfNodeListMapItr> newNodesItVec( 1, nList );
4145         list<const SMDS_MeshElement*> newEdges;
4146         sweepElement( node, newNodesItVec, newEdges, nbSteps, srcElements );
4147       }
4148     }
4149   }
4150
4151   // Make a ceiling for each element ie an equal element of last new nodes.
4152   // Find free links of faces - make edges and sweep them into faces.
4153
4154   TElemOfElemListMap::iterator   itElem      = newElemsMap.begin();
4155   TElemOfVecOfNnlmiMap::iterator itElemNodes = elemNewNodesMap.begin();
4156   for ( ; itElem != newElemsMap.end(); itElem++, itElemNodes++ )
4157   {
4158     const SMDS_MeshElement* elem = itElem->first;
4159     vector<TNodeOfNodeListMapItr>& vecNewNodes = itElemNodes->second;
4160
4161     if(itElem->second.size()==0) continue;
4162
4163     const bool isQuadratic = elem->IsQuadratic();
4164
4165     if ( elem->GetType() == SMDSAbs_Edge ) {
4166       // create a ceiling edge
4167       if ( !isQuadratic ) {
4168         if ( !aMesh->FindEdge( vecNewNodes[ 0 ]->second.back(),
4169                                vecNewNodes[ 1 ]->second.back())) {
4170           myLastCreatedElems.Append(aMesh->AddEdge(vecNewNodes[ 0 ]->second.back(),
4171                                                    vecNewNodes[ 1 ]->second.back()));
4172           srcElements.Append( myLastCreatedElems.Last() );
4173         }
4174       }
4175       else {
4176         if ( !aMesh->FindEdge( vecNewNodes[ 0 ]->second.back(),
4177                                vecNewNodes[ 1 ]->second.back(),
4178                                vecNewNodes[ 2 ]->second.back())) {
4179           myLastCreatedElems.Append(aMesh->AddEdge(vecNewNodes[ 0 ]->second.back(),
4180                                                    vecNewNodes[ 1 ]->second.back(),
4181                                                    vecNewNodes[ 2 ]->second.back()));
4182           srcElements.Append( myLastCreatedElems.Last() );
4183         }
4184       }
4185     }
4186     if ( elem->GetType() != SMDSAbs_Face )
4187       continue;
4188
4189     bool hasFreeLinks = false;
4190
4191     TIDSortedElemSet avoidSet;
4192     avoidSet.insert( elem );
4193
4194     set<const SMDS_MeshNode*> aFaceLastNodes;
4195     int iNode, nbNodes = vecNewNodes.size();
4196     if ( !isQuadratic ) {
4197       // loop on the face nodes
4198       for ( iNode = 0; iNode < nbNodes; iNode++ ) {
4199         aFaceLastNodes.insert( vecNewNodes[ iNode ]->second.back() );
4200         // look for free links of the face
4201         int iNext = ( iNode + 1 == nbNodes ) ? 0 : iNode + 1;
4202         const SMDS_MeshNode* n1 = vecNewNodes[ iNode ]->first;
4203         const SMDS_MeshNode* n2 = vecNewNodes[ iNext ]->first;
4204         // check if a link is free
4205         if ( ! SMESH_MeshEditor::FindFaceInSet ( n1, n2, elemSet, avoidSet )) {
4206           hasFreeLinks = true;
4207           // make an edge and a ceiling for a new edge
4208           if ( !aMesh->FindEdge( n1, n2 )) {
4209             myLastCreatedElems.Append(aMesh->AddEdge( n1, n2 )); // free link edge
4210             srcElements.Append( myLastCreatedElems.Last() );
4211           }
4212           n1 = vecNewNodes[ iNode ]->second.back();
4213           n2 = vecNewNodes[ iNext ]->second.back();
4214           if ( !aMesh->FindEdge( n1, n2 )) {
4215             myLastCreatedElems.Append(aMesh->AddEdge( n1, n2 )); // ceiling edge
4216             srcElements.Append( myLastCreatedElems.Last() );
4217           }
4218         }
4219       }
4220     }
4221     else { // elem is quadratic face
4222       int nbn = nbNodes/2;
4223       for ( iNode = 0; iNode < nbn; iNode++ ) {
4224         aFaceLastNodes.insert( vecNewNodes[ iNode ]->second.back() );
4225         int iNext = ( iNode + 1 == nbn ) ? 0 : iNode + 1;
4226         const SMDS_MeshNode* n1 = vecNewNodes[ iNode ]->first;
4227         const SMDS_MeshNode* n2 = vecNewNodes[ iNext ]->first;
4228         const SMDS_MeshNode* n3 = vecNewNodes[ iNode+nbn ]->first;
4229         // check if a link is free
4230         if ( ! SMESH_MeshEditor::FindFaceInSet ( n1, n2, elemSet, avoidSet ) &&
4231              ! SMESH_MeshEditor::FindFaceInSet ( n1, n3, elemSet, avoidSet ) &&
4232              ! SMESH_MeshEditor::FindFaceInSet ( n3, n2, elemSet, avoidSet ) ) {
4233           hasFreeLinks = true;
4234           // make an edge and a ceiling for a new edge
4235           // find medium node
4236           if ( !aMesh->FindEdge( n1, n2, n3 )) {
4237             myLastCreatedElems.Append(aMesh->AddEdge( n1, n2, n3 )); // free link edge
4238             srcElements.Append( myLastCreatedElems.Last() );
4239           }
4240           n1 = vecNewNodes[ iNode ]->second.back();
4241           n2 = vecNewNodes[ iNext ]->second.back();
4242           n3 = vecNewNodes[ iNode+nbn ]->second.back();
4243           if ( !aMesh->FindEdge( n1, n2, n3 )) {
4244             myLastCreatedElems.Append(aMesh->AddEdge( n1, n2, n3 )); // ceiling edge
4245             srcElements.Append( myLastCreatedElems.Last() );
4246           }
4247         }
4248       }
4249       for ( iNode = nbn; iNode < nbNodes; iNode++ ) {
4250         aFaceLastNodes.insert( vecNewNodes[ iNode ]->second.back() );
4251       }
4252     }
4253
4254     // sweep free links into faces
4255
4256     if ( hasFreeLinks )  {
4257       list<const SMDS_MeshElement*> & newVolumes = itElem->second;
4258       int iVol, volNb, nbVolumesByStep = newVolumes.size() / nbSteps;
4259
4260       set<const SMDS_MeshNode*> initNodeSet, topNodeSet, faceNodeSet;
4261       for ( iNode = 0; iNode < nbNodes; iNode++ ) {
4262         initNodeSet.insert( vecNewNodes[ iNode ]->first );
4263         topNodeSet .insert( vecNewNodes[ iNode ]->second.back() );
4264       }
4265       for ( volNb = 0; volNb < nbVolumesByStep; volNb++ ) {
4266         list<const SMDS_MeshElement*>::iterator v = newVolumes.begin();
4267         std::advance( v, volNb );
4268         // find indices of free faces of a volume and their source edges
4269         list< int > freeInd;
4270         list< const SMDS_MeshElement* > srcEdges; // source edges of free faces
4271         SMDS_VolumeTool vTool( *v, /*ignoreCentralNodes=*/false );
4272         int iF, nbF = vTool.NbFaces();
4273         for ( iF = 0; iF < nbF; iF ++ ) {
4274           if (vTool.IsFreeFace( iF ) &&
4275               vTool.GetFaceNodes( iF, faceNodeSet ) &&
4276               initNodeSet != faceNodeSet) // except an initial face
4277           {
4278             if ( nbSteps == 1 && faceNodeSet == topNodeSet )
4279               continue;
4280             freeInd.push_back( iF );
4281             // find source edge of a free face iF
4282             vector<const SMDS_MeshNode*> commonNodes; // shared by the initial and free faces
4283             commonNodes.resize( initNodeSet.size(), NULL ); // avoid spoiling memory
4284             std::set_intersection( faceNodeSet.begin(), faceNodeSet.end(),
4285                                    initNodeSet.begin(), initNodeSet.end(),
4286                                    commonNodes.begin());
4287             if ( (*v)->IsQuadratic() )
4288               srcEdges.push_back(aMesh->FindEdge (commonNodes[0],commonNodes[1],commonNodes[2]));
4289             else
4290               srcEdges.push_back(aMesh->FindEdge (commonNodes[0],commonNodes[1]));
4291 #ifdef _DEBUG_
4292             if ( !srcEdges.back() )
4293             {
4294               cout << "SMESH_MeshEditor::makeWalls(), no source edge found for a free face #"
4295                    << iF << " of volume #" << vTool.ID() << endl;
4296             }
4297 #endif
4298           }
4299         }
4300         if ( freeInd.empty() )
4301           continue;
4302
4303         // create faces for all steps;
4304         // if such a face has been already created by sweep of edge,
4305         // assure that its orientation is OK
4306         for ( int iStep = 0; iStep < nbSteps; iStep++ ) {
4307           vTool.Set( *v, /*ignoreCentralNodes=*/false );
4308           vTool.SetExternalNormal();
4309           const int nextShift = vTool.IsForward() ? +1 : -1;
4310           list< int >::iterator ind = freeInd.begin();
4311           list< const SMDS_MeshElement* >::iterator srcEdge = srcEdges.begin();
4312           for ( ; ind != freeInd.end(); ++ind, ++srcEdge ) // loop on free faces
4313           {
4314             const SMDS_MeshNode** nodes = vTool.GetFaceNodes( *ind );
4315             int nbn = vTool.NbFaceNodes( *ind );
4316             const SMDS_MeshElement * f = 0;
4317             if ( nbn == 3 )              ///// triangle
4318             {
4319               f = aMesh->FindFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ]);
4320               if ( !f ||
4321                    nodes[ 1 ] != f->GetNodeWrap( f->GetNodeIndex( nodes[ 0 ]) + nextShift ))
4322               {
4323                 const SMDS_MeshNode* newOrder[3] = { nodes[ 1 - nextShift ],
4324                                                      nodes[ 1 ],
4325                                                      nodes[ 1 + nextShift ] };
4326                 if ( f )
4327                   aMesh->ChangeElementNodes( f, &newOrder[0], nbn );
4328                 else
4329                   myLastCreatedElems.Append(aMesh->AddFace( newOrder[ 0 ], newOrder[ 1 ],
4330                                                             newOrder[ 2 ] ));
4331               }
4332             }
4333             else if ( nbn == 4 )       ///// quadrangle
4334             {
4335               f = aMesh->FindFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ], nodes[ 3 ]);
4336               if ( !f ||
4337                    nodes[ 1 ] != f->GetNodeWrap( f->GetNodeIndex( nodes[ 0 ]) + nextShift ))
4338               {
4339                 const SMDS_MeshNode* newOrder[4] = { nodes[ 0 ], nodes[ 2-nextShift ],
4340                                                      nodes[ 2 ], nodes[ 2+nextShift ] };
4341                 if ( f )
4342                   aMesh->ChangeElementNodes( f, &newOrder[0], nbn );
4343                 else
4344                   myLastCreatedElems.Append(aMesh->AddFace( newOrder[ 0 ], newOrder[ 1 ],
4345                                                             newOrder[ 2 ], newOrder[ 3 ]));
4346               }
4347             }
4348             else if ( nbn == 6 && isQuadratic ) /////// quadratic triangle
4349             {
4350               f = aMesh->FindFace( nodes[0], nodes[2], nodes[4], nodes[1], nodes[3], nodes[5] );
4351               if ( !f ||
4352                    nodes[2] != f->GetNodeWrap( f->GetNodeIndex( nodes[0] ) + 2*nextShift ))
4353               {
4354                 const SMDS_MeshNode* newOrder[6] = { nodes[2 - 2*nextShift],
4355                                                      nodes[2],
4356                                                      nodes[2 + 2*nextShift],
4357                                                      nodes[3 - 2*nextShift],
4358                                                      nodes[3],
4359                                                      nodes[3 + 2*nextShift]};
4360                 if ( f )
4361                   aMesh->ChangeElementNodes( f, &newOrder[0], nbn );
4362                 else
4363                   myLastCreatedElems.Append(aMesh->AddFace( newOrder[ 0 ],
4364                                                             newOrder[ 1 ],
4365                                                             newOrder[ 2 ],
4366                                                             newOrder[ 3 ],
4367                                                             newOrder[ 4 ],
4368                                                             newOrder[ 5 ] ));
4369               }
4370             }
4371             else if ( nbn == 8 && isQuadratic ) /////// quadratic quadrangle
4372             {
4373               f = aMesh->FindFace( nodes[0], nodes[2], nodes[4], nodes[6],
4374                                    nodes[1], nodes[3], nodes[5], nodes[7] );
4375               if ( !f ||
4376                    nodes[ 2 ] != f->GetNodeWrap( f->GetNodeIndex( nodes[ 0 ] ) + 2*nextShift ))
4377               {
4378                 const SMDS_MeshNode* newOrder[8] = { nodes[0],
4379                                                      nodes[4 - 2*nextShift],
4380                                                      nodes[4],
4381                                                      nodes[4 + 2*nextShift],
4382                                                      nodes[1],
4383                                                      nodes[5 - 2*nextShift],
4384                                                      nodes[5],
4385                                                      nodes[5 + 2*nextShift] };
4386                 if ( f )
4387                   aMesh->ChangeElementNodes( f, &newOrder[0], nbn );
4388                 else
4389                   myLastCreatedElems.Append(aMesh->AddFace(newOrder[ 0 ], newOrder[ 1 ],
4390                                                            newOrder[ 2 ], newOrder[ 3 ],
4391                                                            newOrder[ 4 ], newOrder[ 5 ],
4392                                                            newOrder[ 6 ], newOrder[ 7 ]));
4393               }
4394             }
4395             else if ( nbn == 9 && isQuadratic ) /////// bi-quadratic quadrangle
4396             {
4397               f = aMesh->FindElement( vector<const SMDS_MeshNode*>( nodes, nodes+nbn ),
4398                                       SMDSAbs_Face, /*noMedium=*/false);
4399               if ( !f ||
4400                    nodes[ 2 ] != f->GetNodeWrap( f->GetNodeIndex( nodes[ 0 ] ) + 2*nextShift ))
4401               {
4402                 const SMDS_MeshNode* newOrder[9] = { nodes[0],
4403                                                      nodes[4 - 2*nextShift],
4404                                                      nodes[4],
4405                                                      nodes[4 + 2*nextShift],
4406                                                      nodes[1],
4407                                                      nodes[5 - 2*nextShift],
4408                                                      nodes[5],
4409                                                      nodes[5 + 2*nextShift],
4410                                                      nodes[8] };
4411                 if ( f )
4412                   aMesh->ChangeElementNodes( f, &newOrder[0], nbn );
4413                 else
4414                   myLastCreatedElems.Append(aMesh->AddFace(newOrder[ 0 ], newOrder[ 1 ],
4415                                                            newOrder[ 2 ], newOrder[ 3 ],
4416                                                            newOrder[ 4 ], newOrder[ 5 ],
4417                                                            newOrder[ 6 ], newOrder[ 7 ],
4418                                                            newOrder[ 8 ]));
4419               }
4420             }
4421             else  //////// polygon
4422             {
4423               vector<const SMDS_MeshNode*> polygon_nodes ( nodes, nodes+nbn );
4424               const SMDS_MeshFace * f = aMesh->FindFace( polygon_nodes );
4425               if ( !f ||
4426                    nodes[ 1 ] != f->GetNodeWrap( f->GetNodeIndex( nodes[ 0 ] ) + nextShift ))
4427               {
4428                 if ( !vTool.IsForward() )
4429                   std::reverse( polygon_nodes.begin(), polygon_nodes.end());
4430                 if ( f )
4431                   aMesh->ChangeElementNodes( f, &polygon_nodes[0], nbn );
4432                 else
4433                   AddElement(polygon_nodes, SMDSAbs_Face, polygon_nodes.size()>4);
4434               }
4435             }
4436
4437             while ( srcElements.Length() < myLastCreatedElems.Length() )
4438               srcElements.Append( *srcEdge );
4439
4440           }  // loop on free faces
4441
4442           // go to the next volume
4443           iVol = 0;
4444           while ( iVol++ < nbVolumesByStep ) v++;
4445
4446         } // loop on steps
4447       } // loop on volumes of one step
4448     } // sweep free links into faces
4449
4450     // Make a ceiling face with a normal external to a volume
4451
4452     SMDS_VolumeTool lastVol( itElem->second.back(), /*ignoreCentralNodes=*/false );
4453
4454     int iF = lastVol.GetFaceIndex( aFaceLastNodes );
4455     if ( iF >= 0 ) {
4456       lastVol.SetExternalNormal();
4457       const SMDS_MeshNode** nodes = lastVol.GetFaceNodes( iF );
4458       int nbn = lastVol.NbFaceNodes( iF );
4459       if ( nbn == 3 ) {
4460         if (!hasFreeLinks ||
4461             !aMesh->FindFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ]))
4462           myLastCreatedElems.Append(aMesh->AddFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ] ));
4463       }
4464       else if ( nbn == 4 )
4465       {
4466         if (!hasFreeLinks ||
4467             !aMesh->FindFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ], nodes[ 3 ]))
4468           myLastCreatedElems.Append(aMesh->AddFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ], nodes[ 3 ]));
4469       }
4470       else if ( nbn == 6 && isQuadratic )
4471       {
4472         if (!hasFreeLinks ||
4473             !aMesh->FindFace(nodes[0], nodes[2], nodes[4], nodes[1], nodes[3], nodes[5]) )
4474           myLastCreatedElems.Append(aMesh->AddFace(nodes[0], nodes[2], nodes[4],
4475                                                    nodes[1], nodes[3], nodes[5]));
4476       }
4477       else if ( nbn == 8 && isQuadratic )
4478       {
4479         if (!hasFreeLinks ||
4480             !aMesh->FindFace(nodes[0], nodes[2], nodes[4], nodes[6],
4481                              nodes[1], nodes[3], nodes[5], nodes[7]) )
4482           myLastCreatedElems.Append(aMesh->AddFace(nodes[0], nodes[2], nodes[4], nodes[6],
4483                                                    nodes[1], nodes[3], nodes[5], nodes[7]));
4484       }
4485       else if ( nbn == 9 && isQuadratic )
4486       {
4487         if (!hasFreeLinks ||
4488             !aMesh->FindElement(vector<const SMDS_MeshNode*>( nodes, nodes+nbn ),
4489                                 SMDSAbs_Face, /*noMedium=*/false) )
4490           myLastCreatedElems.Append(aMesh->AddFace(nodes[0], nodes[2], nodes[4], nodes[6],
4491                                                    nodes[1], nodes[3], nodes[5], nodes[7],
4492                                                    nodes[8]));
4493       }
4494       else {
4495         vector<const SMDS_MeshNode*> polygon_nodes ( nodes, nodes + nbn );
4496         if (!hasFreeLinks || !aMesh->FindFace(polygon_nodes))
4497           myLastCreatedElems.Append(aMesh->AddPolygonalFace(polygon_nodes));
4498       }
4499
4500       while ( srcElements.Length() < myLastCreatedElems.Length() )
4501         srcElements.Append( myLastCreatedElems.Last() );
4502     }
4503   } // loop on swept elements
4504 }
4505
4506 //=======================================================================
4507 //function : RotationSweep
4508 //purpose  :
4509 //=======================================================================
4510
4511 SMESH_MeshEditor::PGroupIDs
4512 SMESH_MeshEditor::RotationSweep(TIDSortedElemSet & theElems,
4513                                 const gp_Ax1&      theAxis,
4514                                 const double       theAngle,
4515                                 const int          theNbSteps,
4516                                 const double       theTol,
4517                                 const bool         theMakeGroups,
4518                                 const bool         theMakeWalls)
4519 {
4520   myLastCreatedElems.Clear();
4521   myLastCreatedNodes.Clear();
4522
4523   // source elements for each generated one
4524   SMESH_SequenceOfElemPtr srcElems, srcNodes;
4525
4526   MESSAGE( "RotationSweep()");
4527   gp_Trsf aTrsf;
4528   aTrsf.SetRotation( theAxis, theAngle );
4529   gp_Trsf aTrsf2;
4530   aTrsf2.SetRotation( theAxis, theAngle/2. );
4531
4532   gp_Lin aLine( theAxis );
4533   double aSqTol = theTol * theTol;
4534
4535   SMESHDS_Mesh* aMesh = GetMeshDS();
4536
4537   TNodeOfNodeListMap mapNewNodes;
4538   TElemOfVecOfNnlmiMap mapElemNewNodes;
4539   TElemOfElemListMap newElemsMap;
4540
4541   const bool isQuadraticMesh = bool( myMesh->NbEdges(ORDER_QUADRATIC) +
4542                                      myMesh->NbFaces(ORDER_QUADRATIC) +
4543                                      myMesh->NbVolumes(ORDER_QUADRATIC) );
4544   // loop on theElems
4545   TIDSortedElemSet::iterator itElem;
4546   for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
4547     const SMDS_MeshElement* elem = *itElem;
4548     if ( !elem || elem->GetType() == SMDSAbs_Volume )
4549       continue;
4550     vector<TNodeOfNodeListMapItr> & newNodesItVec = mapElemNewNodes[ elem ];
4551     newNodesItVec.reserve( elem->NbNodes() );
4552
4553     // loop on elem nodes
4554     SMDS_ElemIteratorPtr itN = elem->nodesIterator();
4555     while ( itN->more() )
4556     {
4557       // check if a node has been already sweeped
4558       const SMDS_MeshNode* node = cast2Node( itN->next() );
4559
4560       gp_XYZ aXYZ( node->X(), node->Y(), node->Z() );
4561       double coord[3];
4562       aXYZ.Coord( coord[0], coord[1], coord[2] );
4563       bool isOnAxis = ( aLine.SquareDistance( aXYZ ) <= aSqTol );
4564
4565       TNodeOfNodeListMapItr nIt =
4566         mapNewNodes.insert( make_pair( node, list<const SMDS_MeshNode*>() )).first;
4567       list<const SMDS_MeshNode*>& listNewNodes = nIt->second;
4568       if ( listNewNodes.empty() )
4569       {
4570         // check if we are to create medium nodes between corner ones
4571         bool needMediumNodes = false;
4572         if ( isQuadraticMesh )
4573         {
4574           SMDS_ElemIteratorPtr it = node->GetInverseElementIterator();
4575           while (it->more() && !needMediumNodes )
4576           {
4577             const SMDS_MeshElement* invElem = it->next();
4578             if ( invElem != elem && !theElems.count( invElem )) continue;
4579             needMediumNodes = ( invElem->IsQuadratic() && !invElem->IsMediumNode(node) );
4580             if ( !needMediumNodes && invElem->GetEntityType() == SMDSEntity_BiQuad_Quadrangle )
4581               needMediumNodes = true;
4582           }
4583         }
4584
4585         // make new nodes
4586         const SMDS_MeshNode * newNode = node;
4587         for ( int i = 0; i < theNbSteps; i++ ) {
4588           if ( !isOnAxis ) {
4589             if ( needMediumNodes )  // create a medium node
4590             {
4591               aTrsf2.Transforms( coord[0], coord[1], coord[2] );
4592               newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
4593               myLastCreatedNodes.Append(newNode);
4594               srcNodes.Append( node );
4595               listNewNodes.push_back( newNode );
4596               aTrsf2.Transforms( coord[0], coord[1], coord[2] );
4597             }
4598             else {
4599               aTrsf.Transforms( coord[0], coord[1], coord[2] );
4600             }
4601             // create a corner node
4602             newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
4603             myLastCreatedNodes.Append(newNode);
4604             srcNodes.Append( node );
4605             listNewNodes.push_back( newNode );
4606           }
4607           else {
4608             listNewNodes.push_back( newNode );
4609             // if ( needMediumNodes )
4610             //   listNewNodes.push_back( newNode );
4611           }
4612         }
4613       }
4614       newNodesItVec.push_back( nIt );
4615     }
4616     // make new elements
4617     sweepElement( elem, newNodesItVec, newElemsMap[elem], theNbSteps, srcElems );
4618   }
4619
4620   if ( theMakeWalls )
4621     makeWalls( mapNewNodes, newElemsMap, mapElemNewNodes, theElems, theNbSteps, srcElems );
4622
4623   PGroupIDs newGroupIDs;
4624   if ( theMakeGroups )
4625     newGroupIDs = generateGroups( srcNodes, srcElems, "rotated");
4626
4627   return newGroupIDs;
4628 }
4629
4630
4631 //=======================================================================
4632 //function : CreateNode
4633 //purpose  :
4634 //=======================================================================
4635 const SMDS_MeshNode* SMESH_MeshEditor::CreateNode(const double x,
4636                                                   const double y,
4637                                                   const double z,
4638                                                   const double tolnode,
4639                                                   SMESH_SequenceOfNode& aNodes)
4640 {
4641   // myLastCreatedElems.Clear();
4642   // myLastCreatedNodes.Clear();
4643
4644   gp_Pnt P1(x,y,z);
4645   SMESHDS_Mesh * aMesh = myMesh->GetMeshDS();
4646
4647   // try to search in sequence of existing nodes
4648   // if aNodes.Length()>0 we 'nave to use given sequence
4649   // else - use all nodes of mesh
4650   if(aNodes.Length()>0) {
4651     int i;
4652     for(i=1; i<=aNodes.Length(); i++) {
4653       gp_Pnt P2(aNodes.Value(i)->X(),aNodes.Value(i)->Y(),aNodes.Value(i)->Z());
4654       if(P1.Distance(P2)<tolnode)
4655         return aNodes.Value(i);
4656     }
4657   }
4658   else {
4659     SMDS_NodeIteratorPtr itn = aMesh->nodesIterator();
4660     while(itn->more()) {
4661       const SMDS_MeshNode* aN = static_cast<const SMDS_MeshNode*> (itn->next());
4662       gp_Pnt P2(aN->X(),aN->Y(),aN->Z());
4663       if(P1.Distance(P2)<tolnode)
4664         return aN;
4665     }
4666   }
4667
4668   // create new node and return it
4669   const SMDS_MeshNode* NewNode = aMesh->AddNode(x,y,z);
4670   //myLastCreatedNodes.Append(NewNode);
4671   return NewNode;
4672 }
4673
4674
4675 //=======================================================================
4676 //function : ExtrusionSweep
4677 //purpose  :
4678 //=======================================================================
4679
4680 SMESH_MeshEditor::PGroupIDs
4681 SMESH_MeshEditor::ExtrusionSweep (TIDSortedElemSet &  theElems,
4682                                   const gp_Vec&       theStep,
4683                                   const int           theNbSteps,
4684                                   TElemOfElemListMap& newElemsMap,
4685                                   const bool          theMakeGroups,
4686                                   const int           theFlags,
4687                                   const double        theTolerance)
4688 {
4689   ExtrusParam aParams;
4690   aParams.myDir = gp_Dir(theStep);
4691   aParams.myNodes.Clear();
4692   aParams.mySteps = new TColStd_HSequenceOfReal;
4693   int i;
4694   for(i=1; i<=theNbSteps; i++)
4695     aParams.mySteps->Append(theStep.Magnitude());
4696
4697   return
4698     ExtrusionSweep(theElems,aParams,newElemsMap,theMakeGroups,theFlags,theTolerance);
4699 }
4700
4701
4702 //=======================================================================
4703 //function : ExtrusionSweep
4704 //purpose  :
4705 //=======================================================================
4706
4707 SMESH_MeshEditor::PGroupIDs
4708 SMESH_MeshEditor::ExtrusionSweep (TIDSortedElemSet &  theElems,
4709                                   ExtrusParam&        theParams,
4710                                   TElemOfElemListMap& newElemsMap,
4711                                   const bool          theMakeGroups,
4712                                   const int           theFlags,
4713                                   const double        theTolerance)
4714 {
4715   myLastCreatedElems.Clear();
4716   myLastCreatedNodes.Clear();
4717
4718   // source elements for each generated one
4719   SMESH_SequenceOfElemPtr srcElems, srcNodes;
4720
4721   SMESHDS_Mesh* aMesh = GetMeshDS();
4722
4723   int nbsteps = theParams.mySteps->Length();
4724
4725   TNodeOfNodeListMap mapNewNodes;
4726   //TNodeOfNodeVecMap mapNewNodes;
4727   TElemOfVecOfNnlmiMap mapElemNewNodes;
4728   //TElemOfVecOfMapNodesMap mapElemNewNodes;
4729
4730   const bool isQuadraticMesh = bool( myMesh->NbEdges(ORDER_QUADRATIC) +
4731                                      myMesh->NbFaces(ORDER_QUADRATIC) +
4732                                      myMesh->NbVolumes(ORDER_QUADRATIC) );
4733   // loop on theElems
4734   TIDSortedElemSet::iterator itElem;
4735   for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
4736     // check element type
4737     const SMDS_MeshElement* elem = *itElem;
4738     if ( !elem  || elem->GetType() == SMDSAbs_Volume )
4739       continue;
4740
4741     vector<TNodeOfNodeListMapItr> & newNodesItVec = mapElemNewNodes[ elem ];
4742     newNodesItVec.reserve( elem->NbNodes() );
4743
4744     // loop on elem nodes
4745     SMDS_ElemIteratorPtr itN = elem->nodesIterator();
4746     while ( itN->more() )
4747     {
4748       // check if a node has been already sweeped
4749       const SMDS_MeshNode* node = cast2Node( itN->next() );
4750       TNodeOfNodeListMap::iterator nIt =
4751         mapNewNodes.insert( make_pair( node, list<const SMDS_MeshNode*>() )).first;
4752       list<const SMDS_MeshNode*>& listNewNodes = nIt->second;
4753       if ( listNewNodes.empty() )
4754       {
4755         // make new nodes
4756
4757         // check if we are to create medium nodes between corner ones
4758         bool needMediumNodes = false;
4759         if ( isQuadraticMesh )
4760         {
4761           SMDS_ElemIteratorPtr it = node->GetInverseElementIterator();
4762           while (it->more() && !needMediumNodes )
4763           {
4764             const SMDS_MeshElement* invElem = it->next();
4765             if ( invElem != elem && !theElems.count( invElem )) continue;
4766             needMediumNodes = ( invElem->IsQuadratic() && !invElem->IsMediumNode(node) );
4767             if ( !needMediumNodes && invElem->GetEntityType() == SMDSEntity_BiQuad_Quadrangle )
4768               needMediumNodes = true;
4769           }
4770         }
4771
4772         double coord[] = { node->X(), node->Y(), node->Z() };
4773         for ( int i = 0; i < nbsteps; i++ )
4774         {
4775           if ( needMediumNodes ) // create a medium node
4776           {
4777             double x = coord[0] + theParams.myDir.X()*theParams.mySteps->Value(i+1)/2.;
4778             double y = coord[1] + theParams.myDir.Y()*theParams.mySteps->Value(i+1)/2.;
4779             double z = coord[2] + theParams.myDir.Z()*theParams.mySteps->Value(i+1)/2.;
4780             if( theFlags & EXTRUSION_FLAG_SEW ) {
4781               const SMDS_MeshNode * newNode = CreateNode(x, y, z,
4782                                                          theTolerance, theParams.myNodes);
4783               listNewNodes.push_back( newNode );
4784             }
4785             else {
4786               const SMDS_MeshNode * newNode = aMesh->AddNode(x, y, z);
4787               myLastCreatedNodes.Append(newNode);
4788               srcNodes.Append( node );
4789               listNewNodes.push_back( newNode );
4790             }
4791           }
4792           // create a corner node
4793           coord[0] = coord[0] + theParams.myDir.X()*theParams.mySteps->Value(i+1);
4794           coord[1] = coord[1] + theParams.myDir.Y()*theParams.mySteps->Value(i+1);
4795           coord[2] = coord[2] + theParams.myDir.Z()*theParams.mySteps->Value(i+1);
4796           if( theFlags & EXTRUSION_FLAG_SEW ) {
4797             const SMDS_MeshNode * newNode = CreateNode(coord[0], coord[1], coord[2],
4798                                                        theTolerance, theParams.myNodes);
4799             listNewNodes.push_back( newNode );
4800           }
4801           else {
4802             const SMDS_MeshNode * newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
4803             myLastCreatedNodes.Append(newNode);
4804             srcNodes.Append( node );
4805             listNewNodes.push_back( newNode );
4806           }
4807         }
4808       }
4809       newNodesItVec.push_back( nIt );
4810     }
4811     // make new elements
4812     sweepElement( elem, newNodesItVec, newElemsMap[elem], nbsteps, srcElems );
4813   }
4814
4815   if( theFlags & EXTRUSION_FLAG_BOUNDARY ) {
4816     makeWalls( mapNewNodes, newElemsMap, mapElemNewNodes, theElems, nbsteps, srcElems );
4817   }
4818   PGroupIDs newGroupIDs;
4819   if ( theMakeGroups )
4820     newGroupIDs = generateGroups( srcNodes, srcElems, "extruded");
4821
4822   return newGroupIDs;
4823 }
4824
4825 //=======================================================================
4826 //function : ExtrusionAlongTrack
4827 //purpose  :
4828 //=======================================================================
4829 SMESH_MeshEditor::Extrusion_Error
4830 SMESH_MeshEditor::ExtrusionAlongTrack (TIDSortedElemSet &   theElements,
4831                                        SMESH_subMesh*       theTrack,
4832                                        const SMDS_MeshNode* theN1,
4833                                        const bool           theHasAngles,
4834                                        list<double>&        theAngles,
4835                                        const bool           theLinearVariation,
4836                                        const bool           theHasRefPoint,
4837                                        const gp_Pnt&        theRefPoint,
4838                                        const bool           theMakeGroups)
4839 {
4840   MESSAGE("ExtrusionAlongTrack");
4841   myLastCreatedElems.Clear();
4842   myLastCreatedNodes.Clear();
4843
4844   int aNbE;
4845   std::list<double> aPrms;
4846   TIDSortedElemSet::iterator itElem;
4847
4848   gp_XYZ aGC;
4849   TopoDS_Edge aTrackEdge;
4850   TopoDS_Vertex aV1, aV2;
4851
4852   SMDS_ElemIteratorPtr aItE;
4853   SMDS_NodeIteratorPtr aItN;
4854   SMDSAbs_ElementType aTypeE;
4855
4856   TNodeOfNodeListMap mapNewNodes;
4857
4858   // 1. Check data
4859   aNbE = theElements.size();
4860   // nothing to do
4861   if ( !aNbE )
4862     return EXTR_NO_ELEMENTS;
4863
4864   // 1.1 Track Pattern
4865   ASSERT( theTrack );
4866
4867   SMESHDS_SubMesh* pSubMeshDS = theTrack->GetSubMeshDS();
4868
4869   aItE = pSubMeshDS->GetElements();
4870   while ( aItE->more() ) {
4871     const SMDS_MeshElement* pE = aItE->next();
4872     aTypeE = pE->GetType();
4873     // Pattern must contain links only
4874     if ( aTypeE != SMDSAbs_Edge )
4875       return EXTR_PATH_NOT_EDGE;
4876   }
4877
4878   list<SMESH_MeshEditor_PathPoint> fullList;
4879
4880   const TopoDS_Shape& aS = theTrack->GetSubShape();
4881   // Sub-shape for the Pattern must be an Edge or Wire
4882   if( aS.ShapeType() == TopAbs_EDGE ) {
4883     aTrackEdge = TopoDS::Edge( aS );
4884     // the Edge must not be degenerated
4885     if ( BRep_Tool::Degenerated( aTrackEdge ) )
4886       return EXTR_BAD_PATH_SHAPE;
4887     TopExp::Vertices( aTrackEdge, aV1, aV2 );
4888     aItN = theTrack->GetFather()->GetSubMesh( aV1 )->GetSubMeshDS()->GetNodes();
4889     const SMDS_MeshNode* aN1 = aItN->next();
4890     aItN = theTrack->GetFather()->GetSubMesh( aV2 )->GetSubMeshDS()->GetNodes();
4891     const SMDS_MeshNode* aN2 = aItN->next();
4892     // starting node must be aN1 or aN2
4893     if ( !( aN1 == theN1 || aN2 == theN1 ) )
4894       return EXTR_BAD_STARTING_NODE;
4895     aItN = pSubMeshDS->GetNodes();
4896     while ( aItN->more() ) {
4897       const SMDS_MeshNode* pNode = aItN->next();
4898       const SMDS_EdgePosition* pEPos =
4899         static_cast<const SMDS_EdgePosition*>( pNode->GetPosition() );
4900       double aT = pEPos->GetUParameter();
4901       aPrms.push_back( aT );
4902     }
4903     //Extrusion_Error err =
4904     MakeEdgePathPoints(aPrms, aTrackEdge, (aN1==theN1), fullList);
4905   } else if( aS.ShapeType() == TopAbs_WIRE ) {
4906     list< SMESH_subMesh* > LSM;
4907     TopTools_SequenceOfShape Edges;
4908     SMESH_subMeshIteratorPtr itSM = theTrack->getDependsOnIterator(false,true);
4909     while(itSM->more()) {
4910       SMESH_subMesh* SM = itSM->next();
4911       LSM.push_back(SM);
4912       const TopoDS_Shape& aS = SM->GetSubShape();
4913       Edges.Append(aS);
4914     }
4915     list< list<SMESH_MeshEditor_PathPoint> > LLPPs;
4916     int startNid = theN1->GetID();
4917     TColStd_MapOfInteger UsedNums;
4918
4919     int NbEdges = Edges.Length();
4920     int i = 1;
4921     for(; i<=NbEdges; i++) {
4922       int k = 0;
4923       list< SMESH_subMesh* >::iterator itLSM = LSM.begin();
4924       for(; itLSM!=LSM.end(); itLSM++) {
4925         k++;
4926         if(UsedNums.Contains(k)) continue;
4927         aTrackEdge = TopoDS::Edge( Edges.Value(k) );
4928         SMESH_subMesh* locTrack = *itLSM;
4929         SMESHDS_SubMesh* locMeshDS = locTrack->GetSubMeshDS();
4930         TopExp::Vertices( aTrackEdge, aV1, aV2 );
4931         aItN = locTrack->GetFather()->GetSubMesh(aV1)->GetSubMeshDS()->GetNodes();
4932         const SMDS_MeshNode* aN1 = aItN->next();
4933         aItN = locTrack->GetFather()->GetSubMesh(aV2)->GetSubMeshDS()->GetNodes();
4934         const SMDS_MeshNode* aN2 = aItN->next();
4935         // starting node must be aN1 or aN2
4936         if ( !( aN1->GetID() == startNid || aN2->GetID() == startNid ) ) continue;
4937         // 2. Collect parameters on the track edge
4938         aPrms.clear();
4939         aItN = locMeshDS->GetNodes();
4940         while ( aItN->more() ) {
4941           const SMDS_MeshNode* pNode = aItN->next();
4942           const SMDS_EdgePosition* pEPos =
4943             static_cast<const SMDS_EdgePosition*>( pNode->GetPosition() );
4944           double aT = pEPos->GetUParameter();
4945           aPrms.push_back( aT );
4946         }
4947         list<SMESH_MeshEditor_PathPoint> LPP;
4948         //Extrusion_Error err =
4949         MakeEdgePathPoints(aPrms, aTrackEdge,(aN1->GetID()==startNid), LPP);
4950         LLPPs.push_back(LPP);
4951         UsedNums.Add(k);
4952         // update startN for search following egde
4953         if( aN1->GetID() == startNid ) startNid = aN2->GetID();
4954         else startNid = aN1->GetID();
4955         break;
4956       }
4957     }
4958     list< list<SMESH_MeshEditor_PathPoint> >::iterator itLLPP = LLPPs.begin();
4959     list<SMESH_MeshEditor_PathPoint> firstList = *itLLPP;
4960     list<SMESH_MeshEditor_PathPoint>::iterator itPP = firstList.begin();
4961     for(; itPP!=firstList.end(); itPP++) {
4962       fullList.push_back( *itPP );
4963     }
4964     SMESH_MeshEditor_PathPoint PP1 = fullList.back();
4965     fullList.pop_back();
4966     itLLPP++;
4967     for(; itLLPP!=LLPPs.end(); itLLPP++) {
4968       list<SMESH_MeshEditor_PathPoint> currList = *itLLPP;
4969       itPP = currList.begin();
4970       SMESH_MeshEditor_PathPoint PP2 = currList.front();
4971       gp_Dir D1 = PP1.Tangent();
4972       gp_Dir D2 = PP2.Tangent();
4973       gp_Dir Dnew( gp_Vec( (D1.X()+D2.X())/2, (D1.Y()+D2.Y())/2,
4974                            (D1.Z()+D2.Z())/2 ) );
4975       PP1.SetTangent(Dnew);
4976       fullList.push_back(PP1);
4977       itPP++;
4978       for(; itPP!=firstList.end(); itPP++) {
4979         fullList.push_back( *itPP );
4980       }
4981       PP1 = fullList.back();
4982       fullList.pop_back();
4983     }
4984     // if wire not closed
4985     fullList.push_back(PP1);
4986     // else ???
4987   }
4988   else {
4989     return EXTR_BAD_PATH_SHAPE;
4990   }
4991
4992   return MakeExtrElements(theElements, fullList, theHasAngles, theAngles, theLinearVariation,
4993                           theHasRefPoint, theRefPoint, theMakeGroups);
4994 }
4995
4996
4997 //=======================================================================
4998 //function : ExtrusionAlongTrack
4999 //purpose  :
5000 //=======================================================================
5001 SMESH_MeshEditor::Extrusion_Error
5002 SMESH_MeshEditor::ExtrusionAlongTrack (TIDSortedElemSet &   theElements,
5003                                        SMESH_Mesh*          theTrack,
5004                                        const SMDS_MeshNode* theN1,
5005                                        const bool           theHasAngles,
5006                                        list<double>&        theAngles,
5007                                        const bool           theLinearVariation,
5008                                        const bool           theHasRefPoint,
5009                                        const gp_Pnt&        theRefPoint,
5010                                        const bool           theMakeGroups)
5011 {
5012   myLastCreatedElems.Clear();
5013   myLastCreatedNodes.Clear();
5014
5015   int aNbE;
5016   std::list<double> aPrms;
5017   TIDSortedElemSet::iterator itElem;
5018
5019   gp_XYZ aGC;
5020   TopoDS_Edge aTrackEdge;
5021   TopoDS_Vertex aV1, aV2;
5022
5023   SMDS_ElemIteratorPtr aItE;
5024   SMDS_NodeIteratorPtr aItN;
5025   SMDSAbs_ElementType aTypeE;
5026
5027   TNodeOfNodeListMap mapNewNodes;
5028
5029   // 1. Check data
5030   aNbE = theElements.size();
5031   // nothing to do
5032   if ( !aNbE )
5033     return EXTR_NO_ELEMENTS;
5034
5035   // 1.1 Track Pattern
5036   ASSERT( theTrack );
5037
5038   SMESHDS_Mesh* pMeshDS = theTrack->GetMeshDS();
5039
5040   aItE = pMeshDS->elementsIterator();
5041   while ( aItE->more() ) {
5042     const SMDS_MeshElement* pE = aItE->next();
5043     aTypeE = pE->GetType();
5044     // Pattern must contain links only
5045     if ( aTypeE != SMDSAbs_Edge )
5046       return EXTR_PATH_NOT_EDGE;
5047   }
5048
5049   list<SMESH_MeshEditor_PathPoint> fullList;
5050
5051   const TopoDS_Shape& aS = theTrack->GetShapeToMesh();
5052
5053   if( aS == SMESH_Mesh::PseudoShape() ) {
5054     //Mesh without shape
5055     const SMDS_MeshNode* currentNode = NULL;
5056     const SMDS_MeshNode* prevNode = theN1;
5057     std::vector<const SMDS_MeshNode*> aNodesList;
5058     aNodesList.push_back(theN1);
5059     int nbEdges = 0, conn=0;
5060     const SMDS_MeshElement* prevElem = NULL;
5061     const SMDS_MeshElement* currentElem = NULL;
5062     int totalNbEdges = theTrack->NbEdges();
5063     SMDS_ElemIteratorPtr nIt;
5064
5065     //check start node
5066     if( !theTrack->GetMeshDS()->Contains(theN1) ) {
5067       return EXTR_BAD_STARTING_NODE;
5068     }
5069
5070     conn = nbEdgeConnectivity(theN1);
5071     if(conn > 2)
5072       return EXTR_PATH_NOT_EDGE;
5073
5074     aItE = theN1->GetInverseElementIterator();
5075     prevElem = aItE->next();
5076     currentElem = prevElem;
5077     //Get all nodes
5078     if(totalNbEdges == 1 ) {
5079       nIt = currentElem->nodesIterator();
5080       currentNode = static_cast<const SMDS_MeshNode*>(nIt->next());
5081       if(currentNode == prevNode)
5082         currentNode = static_cast<const SMDS_MeshNode*>(nIt->next());
5083       aNodesList.push_back(currentNode);
5084     } else {
5085       nIt = currentElem->nodesIterator();
5086       while( nIt->more() ) {
5087         currentNode = static_cast<const SMDS_MeshNode*>(nIt->next());
5088         if(currentNode == prevNode)
5089           currentNode = static_cast<const SMDS_MeshNode*>(nIt->next());
5090         aNodesList.push_back(currentNode);
5091
5092         //case of the closed mesh
5093         if(currentNode == theN1) {
5094           nbEdges++;
5095           break;
5096         }
5097
5098         conn = nbEdgeConnectivity(currentNode);
5099         if(conn > 2) {
5100           return EXTR_PATH_NOT_EDGE;
5101         }else if( conn == 1 && nbEdges > 0 ) {
5102           //End of the path
5103           nbEdges++;
5104           break;
5105         }else {
5106           prevNode = currentNode;
5107           aItE = currentNode->GetInverseElementIterator();
5108           currentElem = aItE->next();
5109           if( currentElem  == prevElem)
5110             currentElem = aItE->next();
5111           nIt = currentElem->nodesIterator();
5112           prevElem = currentElem;
5113           nbEdges++;
5114         }
5115       }
5116     }
5117
5118     if(nbEdges != totalNbEdges)
5119       return EXTR_PATH_NOT_EDGE;
5120
5121     TopTools_SequenceOfShape Edges;
5122     double x1,x2,y1,y2,z1,z2;
5123     list< list<SMESH_MeshEditor_PathPoint> > LLPPs;
5124     int startNid = theN1->GetID();
5125     for(int i = 1; i < aNodesList.size(); i++) {
5126       x1 = aNodesList[i-1]->X();x2 = aNodesList[i]->X();
5127       y1 = aNodesList[i-1]->Y();y2 = aNodesList[i]->Y();
5128       z1 = aNodesList[i-1]->Z();z2 = aNodesList[i]->Z();
5129       TopoDS_Edge e = BRepBuilderAPI_MakeEdge(gp_Pnt(x1,y1,z1),gp_Pnt(x2,y2,z2));
5130       list<SMESH_MeshEditor_PathPoint> LPP;
5131       aPrms.clear();
5132       MakeEdgePathPoints(aPrms, e, (aNodesList[i-1]->GetID()==startNid), LPP);
5133       LLPPs.push_back(LPP);
5134       if( aNodesList[i-1]->GetID() == startNid ) startNid = aNodesList[i]->GetID();
5135       else startNid = aNodesList[i-1]->GetID();
5136
5137     }
5138
5139     list< list<SMESH_MeshEditor_PathPoint> >::iterator itLLPP = LLPPs.begin();
5140     list<SMESH_MeshEditor_PathPoint> firstList = *itLLPP;
5141     list<SMESH_MeshEditor_PathPoint>::iterator itPP = firstList.begin();
5142     for(; itPP!=firstList.end(); itPP++) {
5143       fullList.push_back( *itPP );
5144     }
5145
5146     SMESH_MeshEditor_PathPoint PP1 = fullList.back();
5147     SMESH_MeshEditor_PathPoint PP2;
5148     fullList.pop_back();
5149     itLLPP++;
5150     for(; itLLPP!=LLPPs.end(); itLLPP++) {
5151       list<SMESH_MeshEditor_PathPoint> currList = *itLLPP;
5152       itPP = currList.begin();
5153       PP2 = currList.front();
5154       gp_Dir D1 = PP1.Tangent();
5155       gp_Dir D2 = PP2.Tangent();
5156       gp_Dir Dnew( gp_Vec( (D1.X()+D2.X())/2, (D1.Y()+D2.Y())/2,
5157                            (D1.Z()+D2.Z())/2 ) );
5158       PP1.SetTangent(Dnew);
5159       fullList.push_back(PP1);
5160       itPP++;
5161       for(; itPP!=currList.end(); itPP++) {
5162         fullList.push_back( *itPP );
5163       }
5164       PP1 = fullList.back();
5165       fullList.pop_back();
5166     }
5167     fullList.push_back(PP1);
5168
5169   } // Sub-shape for the Pattern must be an Edge or Wire
5170   else if( aS.ShapeType() == TopAbs_EDGE ) {
5171     aTrackEdge = TopoDS::Edge( aS );
5172     // the Edge must not be degenerated
5173     if ( BRep_Tool::Degenerated( aTrackEdge ) )
5174       return EXTR_BAD_PATH_SHAPE;
5175     TopExp::Vertices( aTrackEdge, aV1, aV2 );
5176     const SMDS_MeshNode* aN1 = 0;
5177     const SMDS_MeshNode* aN2 = 0;
5178     if ( theTrack->GetSubMesh( aV1 ) && theTrack->GetSubMesh( aV1 )->GetSubMeshDS() ) {
5179       aItN = theTrack->GetSubMesh( aV1 )->GetSubMeshDS()->GetNodes();
5180       aN1 = aItN->next();
5181     }
5182     if ( theTrack->GetSubMesh( aV2 ) && theTrack->GetSubMesh( aV2 )->GetSubMeshDS() ) {
5183       aItN = theTrack->GetSubMesh( aV2 )->GetSubMeshDS()->GetNodes();
5184       aN2 = aItN->next();
5185     }
5186     // starting node must be aN1 or aN2
5187     if ( !( aN1 == theN1 || aN2 == theN1 ) )
5188       return EXTR_BAD_STARTING_NODE;
5189     aItN = pMeshDS->nodesIterator();
5190     while ( aItN->more() ) {
5191       const SMDS_MeshNode* pNode = aItN->next();
5192       if( pNode==aN1 || pNode==aN2 ) continue;
5193       const SMDS_EdgePosition* pEPos =
5194         static_cast<const SMDS_EdgePosition*>( pNode->GetPosition() );
5195       double aT = pEPos->GetUParameter();
5196       aPrms.push_back( aT );
5197     }
5198     //Extrusion_Error err =
5199     MakeEdgePathPoints(aPrms, aTrackEdge, (aN1==theN1), fullList);
5200   }
5201   else if( aS.ShapeType() == TopAbs_WIRE ) {
5202     list< SMESH_subMesh* > LSM;
5203     TopTools_SequenceOfShape Edges;
5204     TopExp_Explorer eExp(aS, TopAbs_EDGE);
5205     for(; eExp.More(); eExp.Next()) {
5206       TopoDS_Edge E = TopoDS::Edge( eExp.Current() );
5207       if( BRep_Tool::Degenerated(E) ) continue;
5208       SMESH_subMesh* SM = theTrack->GetSubMesh(E);
5209       if(SM) {
5210         LSM.push_back(SM);
5211         Edges.Append(E);
5212       }
5213     }
5214     list< list<SMESH_MeshEditor_PathPoint> > LLPPs;
5215     TopoDS_Vertex aVprev;
5216     TColStd_MapOfInteger UsedNums;
5217     int NbEdges = Edges.Length();
5218     int i = 1;
5219     for(; i<=NbEdges; i++) {
5220       int k = 0;
5221       list< SMESH_subMesh* >::iterator itLSM = LSM.begin();
5222       for(; itLSM!=LSM.end(); itLSM++) {
5223         k++;
5224         if(UsedNums.Contains(k)) continue;
5225         aTrackEdge = TopoDS::Edge( Edges.Value(k) );
5226         SMESH_subMesh* locTrack = *itLSM;
5227         SMESHDS_SubMesh* locMeshDS = locTrack->GetSubMeshDS();
5228         TopExp::Vertices( aTrackEdge, aV1, aV2 );
5229         bool aN1isOK = false, aN2isOK = false;
5230         if ( aVprev.IsNull() ) {
5231           // if previous vertex is not yet defined, it means that we in the beginning of wire
5232           // and we have to find initial vertex corresponding to starting node theN1
5233           const SMDS_MeshNode* aN1 = 0;
5234           const SMDS_MeshNode* aN2 = 0;
5235
5236           if ( locTrack->GetFather()->GetSubMesh(aV1) && locTrack->GetFather()->GetSubMesh(aV1)->GetSubMeshDS() ) {
5237             aItN = locTrack->GetFather()->GetSubMesh(aV1)->GetSubMeshDS()->GetNodes();
5238             aN1 = aItN->next();
5239           }
5240           if ( locTrack->GetFather()->GetSubMesh(aV2) && locTrack->GetFather()->GetSubMesh(aV2)->GetSubMeshDS() ) {
5241             aItN = locTrack->GetFather()->GetSubMesh(aV2)->GetSubMeshDS()->GetNodes();
5242             aN2 = aItN->next();
5243           }
5244           // starting node must be aN1 or aN2
5245           aN1isOK = ( aN1 && aN1 == theN1 );
5246           aN2isOK = ( aN2 && aN2 == theN1 );
5247         }
5248         else {
5249           // we have specified ending vertex of the previous edge on the previous iteration
5250           // and we have just to check that it corresponds to any vertex in current segment
5251           aN1isOK = aVprev.IsSame( aV1 );
5252           aN2isOK = aVprev.IsSame( aV2 );
5253         }
5254         if ( !aN1isOK && !aN2isOK ) continue;
5255         // 2. Collect parameters on the track edge
5256         aPrms.clear();
5257         aItN = locMeshDS->GetNodes();
5258         while ( aItN->more() ) {
5259           const SMDS_MeshNode*     pNode = aItN->next();
5260           const SMDS_EdgePosition* pEPos =
5261             static_cast<const SMDS_EdgePosition*>( pNode->GetPosition() );
5262           double aT = pEPos->GetUParameter();
5263           aPrms.push_back( aT );
5264         }
5265         list<SMESH_MeshEditor_PathPoint> LPP;
5266         //Extrusion_Error err =
5267         MakeEdgePathPoints(aPrms, aTrackEdge, aN1isOK, LPP);
5268         LLPPs.push_back(LPP);
5269         UsedNums.Add(k);
5270         // update startN for search following egde
5271         if ( aN1isOK ) aVprev = aV2;
5272         else           aVprev = aV1;
5273         break;
5274       }
5275     }
5276     list< list<SMESH_MeshEditor_PathPoint> >::iterator itLLPP = LLPPs.begin();
5277     list<SMESH_MeshEditor_PathPoint> firstList = *itLLPP;
5278     list<SMESH_MeshEditor_PathPoint>::iterator itPP = firstList.begin();
5279     for(; itPP!=firstList.end(); itPP++) {
5280       fullList.push_back( *itPP );
5281     }
5282     SMESH_MeshEditor_PathPoint PP1 = fullList.back();
5283     fullList.pop_back();
5284     itLLPP++;
5285     for(; itLLPP!=LLPPs.end(); itLLPP++) {
5286       list<SMESH_MeshEditor_PathPoint> currList = *itLLPP;
5287       itPP = currList.begin();
5288       SMESH_MeshEditor_PathPoint PP2 = currList.front();
5289       gp_Dir D1 = PP1.Tangent();
5290       gp_Dir D2 = PP2.Tangent();
5291       gp_Dir Dnew( ( D1.XYZ() + D2.XYZ() ) / 2 );
5292       PP1.SetTangent(Dnew);
5293       fullList.push_back(PP1);
5294       itPP++;
5295       for(; itPP!=currList.end(); itPP++) {
5296         fullList.push_back( *itPP );
5297       }
5298       PP1 = fullList.back();
5299       fullList.pop_back();
5300     }
5301     // if wire not closed
5302     fullList.push_back(PP1);
5303     // else ???
5304   }
5305   else {
5306     return EXTR_BAD_PATH_SHAPE;
5307   }
5308
5309   return MakeExtrElements(theElements, fullList, theHasAngles, theAngles, theLinearVariation,
5310                           theHasRefPoint, theRefPoint, theMakeGroups);
5311 }
5312
5313
5314 //=======================================================================
5315 //function : MakeEdgePathPoints
5316 //purpose  : auxilary for ExtrusionAlongTrack
5317 //=======================================================================
5318 SMESH_MeshEditor::Extrusion_Error
5319 SMESH_MeshEditor::MakeEdgePathPoints(std::list<double>& aPrms,
5320                                      const TopoDS_Edge& aTrackEdge,
5321                                      bool FirstIsStart,
5322                                      list<SMESH_MeshEditor_PathPoint>& LPP)
5323 {
5324   Standard_Real aTx1, aTx2, aL2, aTolVec, aTolVec2;
5325   aTolVec=1.e-7;
5326   aTolVec2=aTolVec*aTolVec;
5327   double aT1, aT2;
5328   TopoDS_Vertex aV1, aV2;
5329   TopExp::Vertices( aTrackEdge, aV1, aV2 );
5330   aT1=BRep_Tool::Parameter( aV1, aTrackEdge );
5331   aT2=BRep_Tool::Parameter( aV2, aTrackEdge );
5332   // 2. Collect parameters on the track edge
5333   aPrms.push_front( aT1 );
5334   aPrms.push_back( aT2 );
5335   // sort parameters
5336   aPrms.sort();
5337   if( FirstIsStart ) {
5338     if ( aT1 > aT2 ) {
5339       aPrms.reverse();
5340     }
5341   }
5342   else {
5343     if ( aT2 > aT1 ) {
5344       aPrms.reverse();
5345     }
5346   }
5347   // 3. Path Points
5348   SMESH_MeshEditor_PathPoint aPP;
5349   Handle(Geom_Curve) aC3D = BRep_Tool::Curve( aTrackEdge, aTx1, aTx2 );
5350   std::list<double>::iterator aItD = aPrms.begin();
5351   for(; aItD != aPrms.end(); ++aItD) {
5352     double aT = *aItD;
5353     gp_Pnt aP3D;
5354     gp_Vec aVec;
5355     aC3D->D1( aT, aP3D, aVec );
5356     aL2 = aVec.SquareMagnitude();
5357     if ( aL2 < aTolVec2 )
5358       return EXTR_CANT_GET_TANGENT;
5359     gp_Dir aTgt( aVec );
5360     aPP.SetPnt( aP3D );
5361     aPP.SetTangent( aTgt );
5362     aPP.SetParameter( aT );
5363     LPP.push_back(aPP);
5364   }
5365   return EXTR_OK;
5366 }
5367
5368
5369 //=======================================================================
5370 //function : MakeExtrElements
5371 //purpose  : auxilary for ExtrusionAlongTrack
5372 //=======================================================================
5373 SMESH_MeshEditor::Extrusion_Error
5374 SMESH_MeshEditor::MakeExtrElements(TIDSortedElemSet&  theElements,
5375                                    list<SMESH_MeshEditor_PathPoint>& fullList,
5376                                    const bool theHasAngles,
5377                                    list<double>& theAngles,
5378                                    const bool theLinearVariation,
5379                                    const bool theHasRefPoint,
5380                                    const gp_Pnt& theRefPoint,
5381                                    const bool theMakeGroups)
5382 {
5383   MESSAGE("MakeExtrElements");
5384   //cout<<"MakeExtrElements  fullList.size() = "<<fullList.size()<<endl;
5385   int aNbTP = fullList.size();
5386   vector<SMESH_MeshEditor_PathPoint> aPPs(aNbTP);
5387   // Angles
5388   if( theHasAngles && theAngles.size()>0 && theLinearVariation ) {
5389     LinearAngleVariation(aNbTP-1, theAngles);
5390   }
5391   vector<double> aAngles( aNbTP );
5392   int j = 0;
5393   for(; j<aNbTP; ++j) {
5394     aAngles[j] = 0.;
5395   }
5396   if ( theHasAngles ) {
5397     double anAngle;;
5398     std::list<double>::iterator aItD = theAngles.begin();
5399     for ( j=1; (aItD != theAngles.end()) && (j<aNbTP); ++aItD, ++j ) {
5400       anAngle = *aItD;
5401       aAngles[j] = anAngle;
5402     }
5403   }
5404   // fill vector of path points with angles
5405   //aPPs.resize(fullList.size());
5406   j = -1;
5407   list<SMESH_MeshEditor_PathPoint>::iterator itPP = fullList.begin();
5408   for(; itPP!=fullList.end(); itPP++) {
5409     j++;
5410     SMESH_MeshEditor_PathPoint PP = *itPP;
5411     PP.SetAngle(aAngles[j]);
5412     aPPs[j] = PP;
5413   }
5414
5415   TNodeOfNodeListMap mapNewNodes;
5416   TElemOfVecOfNnlmiMap mapElemNewNodes;
5417   TElemOfElemListMap newElemsMap;
5418   TIDSortedElemSet::iterator itElem;
5419   double aX, aY, aZ;
5420   int aNb;
5421   SMDSAbs_ElementType aTypeE;
5422   // source elements for each generated one
5423   SMESH_SequenceOfElemPtr srcElems, srcNodes;
5424
5425   // 3. Center of rotation aV0
5426   gp_Pnt aV0 = theRefPoint;
5427   gp_XYZ aGC;
5428   if ( !theHasRefPoint ) {
5429     aNb = 0;
5430     aGC.SetCoord( 0.,0.,0. );
5431
5432     itElem = theElements.begin();
5433     for ( ; itElem != theElements.end(); itElem++ ) {
5434       const SMDS_MeshElement* elem = *itElem;
5435
5436       SMDS_ElemIteratorPtr itN = elem->nodesIterator();
5437       while ( itN->more() ) {
5438         const SMDS_MeshNode* node = static_cast<const SMDS_MeshNode*>( itN->next() );
5439         aX = node->X();
5440         aY = node->Y();
5441         aZ = node->Z();
5442
5443         if ( mapNewNodes.find( node ) == mapNewNodes.end() ) {
5444           list<const SMDS_MeshNode*> aLNx;
5445           mapNewNodes[node] = aLNx;
5446           //
5447           gp_XYZ aXYZ( aX, aY, aZ );
5448           aGC += aXYZ;
5449           ++aNb;
5450         }
5451       }
5452     }
5453     aGC /= aNb;
5454     aV0.SetXYZ( aGC );
5455   } // if (!theHasRefPoint) {
5456   mapNewNodes.clear();
5457
5458   // 4. Processing the elements
5459   SMESHDS_Mesh* aMesh = GetMeshDS();
5460
5461   for ( itElem = theElements.begin(); itElem != theElements.end(); itElem++ ) {
5462     // check element type
5463     const SMDS_MeshElement* elem = *itElem;
5464     aTypeE = elem->GetType();
5465     if ( !elem || ( aTypeE != SMDSAbs_Face && aTypeE != SMDSAbs_Edge ) )
5466       continue;
5467
5468     vector<TNodeOfNodeListMapItr> & newNodesItVec = mapElemNewNodes[ elem ];
5469     newNodesItVec.reserve( elem->NbNodes() );
5470
5471     // loop on elem nodes
5472     int nodeIndex = -1;
5473     SMDS_ElemIteratorPtr itN = elem->nodesIterator();
5474     while ( itN->more() )
5475     {
5476       ++nodeIndex;
5477       // check if a node has been already processed
5478       const SMDS_MeshNode* node =
5479         static_cast<const SMDS_MeshNode*>( itN->next() );
5480       TNodeOfNodeListMap::iterator nIt = mapNewNodes.find( node );
5481       if ( nIt == mapNewNodes.end() ) {
5482         nIt = mapNewNodes.insert( make_pair( node, list<const SMDS_MeshNode*>() )).first;
5483         list<const SMDS_MeshNode*>& listNewNodes = nIt->second;
5484
5485         // make new nodes
5486         aX = node->X();  aY = node->Y(); aZ = node->Z();
5487
5488         Standard_Real aAngle1x, aAngleT1T0, aTolAng;
5489         gp_Pnt aP0x, aP1x, aPN0, aPN1, aV0x, aV1x;
5490         gp_Ax1 anAx1, anAxT1T0;
5491         gp_Dir aDT1x, aDT0x, aDT1T0;
5492
5493         aTolAng=1.e-4;
5494
5495         aV0x = aV0;
5496         aPN0.SetCoord(aX, aY, aZ);
5497
5498         const SMESH_MeshEditor_PathPoint& aPP0 = aPPs[0];
5499         aP0x = aPP0.Pnt();
5500         aDT0x= aPP0.Tangent();
5501         //cout<<"j = 0   PP: Pnt("<<aP0x.X()<<","<<aP0x.Y()<<","<<aP0x.Z()<<")"<<endl;
5502
5503         for ( j = 1; j < aNbTP; ++j ) {
5504           const SMESH_MeshEditor_PathPoint& aPP1 = aPPs[j];
5505           aP1x = aPP1.Pnt();
5506           aDT1x = aPP1.Tangent();
5507           aAngle1x = aPP1.Angle();
5508
5509           gp_Trsf aTrsf, aTrsfRot, aTrsfRotT1T0;
5510           // Translation
5511           gp_Vec aV01x( aP0x, aP1x );
5512           aTrsf.SetTranslation( aV01x );
5513
5514           // traslated point
5515           aV1x = aV0x.Transformed( aTrsf );
5516           aPN1 = aPN0.Transformed( aTrsf );
5517
5518           // rotation 1 [ T1,T0 ]
5519           aAngleT1T0=-aDT1x.Angle( aDT0x );
5520           if (fabs(aAngleT1T0) > aTolAng) {
5521             aDT1T0=aDT1x^aDT0x;
5522             anAxT1T0.SetLocation( aV1x );
5523             anAxT1T0.SetDirection( aDT1T0 );
5524             aTrsfRotT1T0.SetRotation( anAxT1T0, aAngleT1T0 );
5525
5526             aPN1 = aPN1.Transformed( aTrsfRotT1T0 );
5527           }
5528
5529           // rotation 2
5530           if ( theHasAngles ) {
5531             anAx1.SetLocation( aV1x );
5532             anAx1.SetDirection( aDT1x );
5533             aTrsfRot.SetRotation( anAx1, aAngle1x );
5534
5535             aPN1 = aPN1.Transformed( aTrsfRot );
5536           }
5537
5538           // make new node
5539           //MESSAGE("elem->IsQuadratic " << elem->IsQuadratic() << " " << elem->IsMediumNode(node));
5540           if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
5541             // create additional node
5542             double x = ( aPN1.X() + aPN0.X() )/2.;
5543             double y = ( aPN1.Y() + aPN0.Y() )/2.;
5544             double z = ( aPN1.Z() + aPN0.Z() )/2.;
5545             const SMDS_MeshNode* newNode = aMesh->AddNode(x,y,z);
5546             myLastCreatedNodes.Append(newNode);
5547             srcNodes.Append( node );
5548             listNewNodes.push_back( newNode );
5549           }
5550           aX = aPN1.X();
5551           aY = aPN1.Y();
5552           aZ = aPN1.Z();
5553           const SMDS_MeshNode* newNode = aMesh->AddNode( aX, aY, aZ );
5554           myLastCreatedNodes.Append(newNode);
5555           srcNodes.Append( node );
5556           listNewNodes.push_back( newNode );
5557
5558           aPN0 = aPN1;
5559           aP0x = aP1x;
5560           aV0x = aV1x;
5561           aDT0x = aDT1x;
5562         }
5563       }
5564
5565       else {
5566         // if current elem is quadratic and current node is not medium
5567         // we have to check - may be it is needed to insert additional nodes
5568         if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
5569           list< const SMDS_MeshNode* > & listNewNodes = nIt->second;
5570           if(listNewNodes.size()==aNbTP-1) {
5571             vector<const SMDS_MeshNode*> aNodes(2*(aNbTP-1));
5572             gp_XYZ P(node->X(), node->Y(), node->Z());
5573             list< const SMDS_MeshNode* >::iterator it = listNewNodes.begin();
5574             int i;
5575             for(i=0; i<aNbTP-1; i++) {
5576               const SMDS_MeshNode* N = *it;
5577               double x = ( N->X() + P.X() )/2.;
5578               double y = ( N->Y() + P.Y() )/2.;
5579               double z = ( N->Z() + P.Z() )/2.;
5580               const SMDS_MeshNode* newN = aMesh->AddNode(x,y,z);
5581               srcNodes.Append( node );
5582               myLastCreatedNodes.Append(newN);
5583               aNodes[2*i] = newN;
5584               aNodes[2*i+1] = N;
5585               P = gp_XYZ(N->X(),N->Y(),N->Z());
5586             }
5587             listNewNodes.clear();
5588             for(i=0; i<2*(aNbTP-1); i++) {
5589               listNewNodes.push_back(aNodes[i]);
5590             }
5591           }
5592         }
5593       }
5594
5595       newNodesItVec.push_back( nIt );
5596     }
5597     // make new elements
5598     //sweepElement( aMesh, elem, newNodesItVec, newElemsMap[elem],
5599     //              newNodesItVec[0]->second.size(), myLastCreatedElems );
5600     sweepElement( elem, newNodesItVec, newElemsMap[elem], aNbTP-1, srcElems );
5601   }
5602
5603   makeWalls( mapNewNodes, newElemsMap, mapElemNewNodes, theElements, aNbTP-1, srcElems );
5604
5605   if ( theMakeGroups )
5606     generateGroups( srcNodes, srcElems, "extruded");
5607
5608   return EXTR_OK;
5609 }
5610
5611
5612 //=======================================================================
5613 //function : LinearAngleVariation
5614 //purpose  : auxilary for ExtrusionAlongTrack
5615 //=======================================================================
5616 void SMESH_MeshEditor::LinearAngleVariation(const int nbSteps,
5617                                             list<double>& Angles)
5618 {
5619   int nbAngles = Angles.size();
5620   if( nbSteps > nbAngles ) {
5621     vector<double> theAngles(nbAngles);
5622     list<double>::iterator it = Angles.begin();
5623     int i = -1;
5624     for(; it!=Angles.end(); it++) {
5625       i++;
5626       theAngles[i] = (*it);
5627     }
5628     list<double> res;
5629     double rAn2St = double( nbAngles ) / double( nbSteps );
5630     double angPrev = 0, angle;
5631     for ( int iSt = 0; iSt < nbSteps; ++iSt ) {
5632       double angCur = rAn2St * ( iSt+1 );
5633       double angCurFloor  = floor( angCur );
5634       double angPrevFloor = floor( angPrev );
5635       if ( angPrevFloor == angCurFloor )
5636         angle = rAn2St * theAngles[ int( angCurFloor ) ];
5637       else {
5638         int iP = int( angPrevFloor );
5639         double angPrevCeil = ceil(angPrev);
5640         angle = ( angPrevCeil - angPrev ) * theAngles[ iP ];
5641
5642         int iC = int( angCurFloor );
5643         if ( iC < nbAngles )
5644           angle += ( angCur - angCurFloor ) * theAngles[ iC ];
5645
5646         iP = int( angPrevCeil );
5647         while ( iC-- > iP )
5648           angle += theAngles[ iC ];
5649       }
5650       res.push_back(angle);
5651       angPrev = angCur;
5652     }
5653     Angles.clear();
5654     it = res.begin();
5655     for(; it!=res.end(); it++)
5656       Angles.push_back( *it );
5657   }
5658 }
5659
5660
5661 //================================================================================
5662 /*!
5663  * \brief Move or copy theElements applying theTrsf to their nodes
5664  *  \param theElems - elements to transform, if theElems is empty then apply to all mesh nodes
5665  *  \param theTrsf - transformation to apply
5666  *  \param theCopy - if true, create translated copies of theElems
5667  *  \param theMakeGroups - if true and theCopy, create translated groups
5668  *  \param theTargetMesh - mesh to copy translated elements into
5669  *  \return SMESH_MeshEditor::PGroupIDs - list of ids of created groups
5670  */
5671 //================================================================================
5672
5673 SMESH_MeshEditor::PGroupIDs
5674 SMESH_MeshEditor::Transform (TIDSortedElemSet & theElems,
5675                              const gp_Trsf&     theTrsf,
5676                              const bool         theCopy,
5677                              const bool         theMakeGroups,
5678                              SMESH_Mesh*        theTargetMesh)
5679 {
5680   myLastCreatedElems.Clear();
5681   myLastCreatedNodes.Clear();
5682
5683   bool needReverse = false;
5684   string groupPostfix;
5685   switch ( theTrsf.Form() ) {
5686   case gp_PntMirror:
5687     MESSAGE("gp_PntMirror");
5688     needReverse = true;
5689     groupPostfix = "mirrored";
5690     break;
5691   case gp_Ax1Mirror:
5692     MESSAGE("gp_Ax1Mirror");
5693     groupPostfix = "mirrored";
5694     break;
5695   case gp_Ax2Mirror:
5696     MESSAGE("gp_Ax2Mirror");
5697     needReverse = true;
5698     groupPostfix = "mirrored";
5699     break;
5700   case gp_Rotation:
5701     MESSAGE("gp_Rotation");
5702     groupPostfix = "rotated";
5703     break;
5704   case gp_Translation:
5705     MESSAGE("gp_Translation");
5706     groupPostfix = "translated";
5707     break;
5708   case gp_Scale:
5709     MESSAGE("gp_Scale");
5710     groupPostfix = "scaled";
5711     break;
5712   case gp_CompoundTrsf: // different scale by axis
5713     MESSAGE("gp_CompoundTrsf");
5714     groupPostfix = "scaled";
5715     break;
5716   default:
5717     MESSAGE("default");
5718     needReverse = false;
5719     groupPostfix = "transformed";
5720   }
5721
5722   SMESH_MeshEditor targetMeshEditor( theTargetMesh );
5723   SMESHDS_Mesh* aTgtMesh = theTargetMesh ? theTargetMesh->GetMeshDS() : 0;
5724   SMESHDS_Mesh* aMesh    = GetMeshDS();
5725
5726
5727   // map old node to new one
5728   TNodeNodeMap nodeMap;
5729
5730   // elements sharing moved nodes; those of them which have all
5731   // nodes mirrored but are not in theElems are to be reversed
5732   TIDSortedElemSet inverseElemSet;
5733
5734   // source elements for each generated one
5735   SMESH_SequenceOfElemPtr srcElems, srcNodes;
5736
5737   // issue 021015: EDF 1578 SMESH: Free nodes are removed when translating a mesh
5738   TIDSortedElemSet orphanNode;
5739
5740   if ( theElems.empty() ) // transform the whole mesh
5741   {
5742     // add all elements
5743     SMDS_ElemIteratorPtr eIt = aMesh->elementsIterator();
5744     while ( eIt->more() ) theElems.insert( eIt->next() );
5745     // add orphan nodes
5746     SMDS_NodeIteratorPtr nIt = aMesh->nodesIterator();
5747     while ( nIt->more() )
5748     {
5749       const SMDS_MeshNode* node = nIt->next();
5750       if ( node->NbInverseElements() == 0)
5751         orphanNode.insert( node );
5752     }
5753   }
5754
5755   // loop on elements to transform nodes : first orphan nodes then elems
5756   TIDSortedElemSet::iterator itElem;
5757   TIDSortedElemSet *elements[] = {&orphanNode, &theElems };
5758   for (int i=0; i<2; i++)
5759   for ( itElem = elements[i]->begin(); itElem != elements[i]->end(); itElem++ ) {
5760     const SMDS_MeshElement* elem = *itElem;
5761     if ( !elem )
5762       continue;
5763
5764     // loop on elem nodes
5765     SMDS_ElemIteratorPtr itN = elem->nodesIterator();
5766     while ( itN->more() ) {
5767
5768       const SMDS_MeshNode* node = cast2Node( itN->next() );
5769       // check if a node has been already transformed
5770       pair<TNodeNodeMap::iterator,bool> n2n_isnew =
5771         nodeMap.insert( make_pair ( node, node ));
5772       if ( !n2n_isnew.second )
5773         continue;
5774
5775       double coord[3];
5776       coord[0] = node->X();
5777       coord[1] = node->Y();
5778       coord[2] = node->Z();
5779       theTrsf.Transforms( coord[0], coord[1], coord[2] );
5780       if ( theTargetMesh ) {
5781         const SMDS_MeshNode * newNode = aTgtMesh->AddNode( coord[0], coord[1], coord[2] );
5782         n2n_isnew.first->second = newNode;
5783         myLastCreatedNodes.Append(newNode);
5784         srcNodes.Append( node );
5785       }
5786       else if ( theCopy ) {
5787         const SMDS_MeshNode * newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
5788         n2n_isnew.first->second = newNode;
5789         myLastCreatedNodes.Append(newNode);
5790         srcNodes.Append( node );
5791       }
5792       else {
5793         aMesh->MoveNode( node, coord[0], coord[1], coord[2] );
5794         // node position on shape becomes invalid
5795         const_cast< SMDS_MeshNode* > ( node )->SetPosition
5796           ( SMDS_SpacePosition::originSpacePosition() );
5797       }
5798
5799       // keep inverse elements
5800       if ( !theCopy && !theTargetMesh && needReverse ) {
5801         SMDS_ElemIteratorPtr invElemIt = node->GetInverseElementIterator();
5802         while ( invElemIt->more() ) {
5803           const SMDS_MeshElement* iel = invElemIt->next();
5804           inverseElemSet.insert( iel );
5805         }
5806       }
5807     }
5808   }
5809
5810   // either create new elements or reverse mirrored ones
5811   if ( !theCopy && !needReverse && !theTargetMesh )
5812     return PGroupIDs();
5813
5814   TIDSortedElemSet::iterator invElemIt = inverseElemSet.begin();
5815   for ( ; invElemIt != inverseElemSet.end(); invElemIt++ )
5816     theElems.insert( *invElemIt );
5817
5818   // Replicate or reverse elements
5819
5820   std::vector<int> iForw;
5821   for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ )
5822   {
5823     const SMDS_MeshElement* elem = *itElem;
5824     if ( !elem ) continue;
5825
5826     SMDSAbs_GeometryType geomType = elem->GetGeomType();
5827     int                  nbNodes  = elem->NbNodes();
5828     if ( geomType == SMDSGeom_NONE ) continue; // node
5829
5830     switch ( geomType ) {
5831
5832     case SMDSGeom_POLYGON:  // ---------------------- polygon
5833       {
5834         vector<const SMDS_MeshNode*> poly_nodes (nbNodes);
5835         int iNode = 0;
5836         SMDS_ElemIteratorPtr itN = elem->nodesIterator();
5837         while (itN->more()) {
5838           const SMDS_MeshNode* node =
5839             static_cast<const SMDS_MeshNode*>(itN->next());
5840           TNodeNodeMap::iterator nodeMapIt = nodeMap.find(node);
5841           if (nodeMapIt == nodeMap.end())
5842             break; // not all nodes transformed
5843           if (needReverse) {
5844             // reverse mirrored faces and volumes
5845             poly_nodes[nbNodes - iNode - 1] = (*nodeMapIt).second;
5846           } else {
5847             poly_nodes[iNode] = (*nodeMapIt).second;
5848           }
5849           iNode++;
5850         }
5851         if ( iNode != nbNodes )
5852           continue; // not all nodes transformed
5853
5854         if ( theTargetMesh ) {
5855           myLastCreatedElems.Append(aTgtMesh->AddPolygonalFace(poly_nodes));
5856           srcElems.Append( elem );
5857         }
5858         else if ( theCopy ) {
5859           myLastCreatedElems.Append(aMesh->AddPolygonalFace(poly_nodes));
5860           srcElems.Append( elem );
5861         }
5862         else {
5863           aMesh->ChangePolygonNodes(elem, poly_nodes);
5864         }
5865       }
5866       break;
5867
5868     case SMDSGeom_POLYHEDRA:  // ------------------ polyhedral volume
5869       {
5870         const SMDS_VtkVolume* aPolyedre =
5871           dynamic_cast<const SMDS_VtkVolume*>( elem );
5872         if (!aPolyedre) {
5873           MESSAGE("Warning: bad volumic element");
5874           continue;
5875         }
5876
5877         vector<const SMDS_MeshNode*> poly_nodes; poly_nodes.reserve( nbNodes );
5878         vector<int> quantities; quantities.reserve( nbNodes );
5879
5880         bool allTransformed = true;
5881         int nbFaces = aPolyedre->NbFaces();
5882         for (int iface = 1; iface <= nbFaces && allTransformed; iface++) {
5883           int nbFaceNodes = aPolyedre->NbFaceNodes(iface);
5884           for (int inode = 1; inode <= nbFaceNodes && allTransformed; inode++) {
5885             const SMDS_MeshNode* node = aPolyedre->GetFaceNode(iface, inode);
5886             TNodeNodeMap::iterator nodeMapIt = nodeMap.find(node);
5887             if (nodeMapIt == nodeMap.end()) {
5888               allTransformed = false; // not all nodes transformed
5889             } else {
5890               poly_nodes.push_back((*nodeMapIt).second);
5891             }
5892             if ( needReverse && allTransformed )
5893               std::reverse( poly_nodes.end() - nbFaceNodes, poly_nodes.end() );
5894           }
5895           quantities.push_back(nbFaceNodes);
5896         }
5897         if ( !allTransformed )
5898           continue; // not all nodes transformed
5899
5900         if ( theTargetMesh ) {
5901           myLastCreatedElems.Append(aTgtMesh->AddPolyhedralVolume(poly_nodes, quantities));
5902           srcElems.Append( elem );
5903         }
5904         else if ( theCopy ) {
5905           myLastCreatedElems.Append(aMesh->AddPolyhedralVolume(poly_nodes, quantities));
5906           srcElems.Append( elem );
5907         }
5908         else {
5909           aMesh->ChangePolyhedronNodes(elem, poly_nodes, quantities);
5910         }
5911       }
5912       break;
5913
5914     case SMDSGeom_BALL: // -------------------- Ball
5915       {
5916         if ( !theCopy && !theTargetMesh ) continue;
5917
5918         TNodeNodeMap::iterator nodeMapIt = nodeMap.find( elem->GetNode(0) );
5919         if (nodeMapIt == nodeMap.end())
5920           continue; // not all nodes transformed
5921
5922         double diameter = static_cast<const SMDS_BallElement*>(elem)->GetDiameter();
5923         if ( theTargetMesh ) {
5924           myLastCreatedElems.Append(aTgtMesh->AddBall( nodeMapIt->second, diameter ));
5925           srcElems.Append( elem );
5926         }
5927         else {
5928           myLastCreatedElems.Append(aMesh->AddBall( nodeMapIt->second, diameter ));
5929           srcElems.Append( elem );
5930         }
5931       }
5932       break;
5933
5934     default: // ----------------------- Regular elements
5935
5936       while ( iForw.size() < nbNodes ) iForw.push_back( iForw.size() );
5937       const std::vector<int>& iRev = SMDS_MeshCell::reverseSmdsOrder( elem->GetEntityType() );
5938       const std::vector<int>& i = needReverse ? iRev : iForw;
5939
5940       // find transformed nodes
5941       vector<const SMDS_MeshNode*> nodes(nbNodes);
5942       int iNode = 0;
5943       SMDS_ElemIteratorPtr itN = elem->nodesIterator();
5944       while ( itN->more() ) {
5945         const SMDS_MeshNode* node =
5946           static_cast<const SMDS_MeshNode*>( itN->next() );
5947         TNodeNodeMap::iterator nodeMapIt = nodeMap.find( node );
5948         if ( nodeMapIt == nodeMap.end() )
5949           break; // not all nodes transformed
5950         nodes[ i [ iNode++ ]] = (*nodeMapIt).second;
5951       }
5952       if ( iNode != nbNodes )
5953         continue; // not all nodes transformed
5954
5955       if ( theTargetMesh ) {
5956         if ( SMDS_MeshElement* copy =
5957              targetMeshEditor.AddElement( nodes, elem->GetType(), elem->IsPoly() )) {
5958           myLastCreatedElems.Append( copy );
5959           srcElems.Append( elem );
5960         }
5961       }
5962       else if ( theCopy ) {
5963         if ( AddElement( nodes, elem->GetType(), elem->IsPoly() ))
5964           srcElems.Append( elem );
5965       }
5966       else {
5967         // reverse element as it was reversed by transformation
5968         if ( nbNodes > 2 )
5969           aMesh->ChangeElementNodes( elem, &nodes[0], nbNodes );
5970       }
5971     } // switch ( geomType )
5972
5973   } // loop on elements
5974
5975   PGroupIDs newGroupIDs;
5976
5977   if ( ( theMakeGroups && theCopy ) ||
5978        ( theMakeGroups && theTargetMesh ) )
5979     newGroupIDs = generateGroups( srcNodes, srcElems, groupPostfix, theTargetMesh );
5980
5981   return newGroupIDs;
5982 }
5983
5984 //=======================================================================
5985 /*!
5986  * \brief Create groups of elements made during transformation
5987  * \param nodeGens - nodes making corresponding myLastCreatedNodes
5988  * \param elemGens - elements making corresponding myLastCreatedElems
5989  * \param postfix - to append to names of new groups
5990  */
5991 //=======================================================================
5992
5993 SMESH_MeshEditor::PGroupIDs
5994 SMESH_MeshEditor::generateGroups(const SMESH_SequenceOfElemPtr& nodeGens,
5995                                  const SMESH_SequenceOfElemPtr& elemGens,
5996                                  const std::string&             postfix,
5997                                  SMESH_Mesh*                    targetMesh)
5998 {
5999   PGroupIDs newGroupIDs( new list<int> );
6000   SMESH_Mesh* mesh = targetMesh ? targetMesh : GetMesh();
6001
6002   // Sort existing groups by types and collect their names
6003
6004   // to store an old group and a generated new one
6005   typedef pair< SMESHDS_GroupBase*, SMESHDS_Group* > TOldNewGroup;
6006   vector< list< TOldNewGroup > > groupsByType( SMDSAbs_NbElementTypes );
6007   vector< TOldNewGroup* > orderedOldNewGroups; // in order of old groups
6008   // group names
6009   set< string > groupNames;
6010
6011   SMESH_Mesh::GroupIteratorPtr groupIt = GetMesh()->GetGroups();
6012   if ( !groupIt->more() ) return newGroupIDs;
6013
6014   int newGroupID = mesh->GetGroupIds().back()+1;
6015   while ( groupIt->more() )
6016   {
6017     SMESH_Group * group = groupIt->next();
6018     if ( !group ) continue;
6019     SMESHDS_GroupBase* groupDS = group->GetGroupDS();
6020     if ( !groupDS || groupDS->IsEmpty() ) continue;
6021     groupNames.insert( group->GetName() );
6022     groupDS->SetStoreName( group->GetName() );
6023     SMESHDS_Group* newGroup = new SMESHDS_Group( newGroupID++, mesh->GetMeshDS(),
6024                                                  groupDS->GetType() );
6025     groupsByType[ groupDS->GetType() ].push_back( make_pair( groupDS, newGroup ));
6026     orderedOldNewGroups.push_back( & groupsByType[ groupDS->GetType() ].back() );
6027   }
6028
6029   // Loop on nodes and elements to add them in new groups
6030
6031   for ( int isNodes = 0; isNodes < 2; ++isNodes )
6032   {
6033     const SMESH_SequenceOfElemPtr& gens  = isNodes ? nodeGens : elemGens;
6034     const SMESH_SequenceOfElemPtr& elems = isNodes ? myLastCreatedNodes : myLastCreatedElems;
6035     if ( gens.Length() != elems.Length() )
6036       throw SALOME_Exception(LOCALIZED("invalid args"));
6037
6038     // loop on created elements
6039     for (int iElem = 1; iElem <= elems.Length(); ++iElem )
6040     {
6041       const SMDS_MeshElement* sourceElem = gens( iElem );
6042       if ( !sourceElem ) {
6043         MESSAGE("generateGroups(): NULL source element");
6044         continue;
6045       }
6046       list< TOldNewGroup > & groupsOldNew = groupsByType[ sourceElem->GetType() ];
6047       if ( groupsOldNew.empty() ) { // no groups of this type at all
6048         while ( iElem < gens.Length() && gens( iElem+1 ) == sourceElem )
6049           ++iElem; // skip all elements made by sourceElem
6050         continue;
6051       }
6052       // collect all elements made by sourceElem
6053       list< const SMDS_MeshElement* > resultElems;
6054       if ( const SMDS_MeshElement* resElem = elems( iElem ))
6055         if ( resElem != sourceElem )
6056           resultElems.push_back( resElem );
6057       while ( iElem < gens.Length() && gens( iElem+1 ) == sourceElem )
6058         if ( const SMDS_MeshElement* resElem = elems( ++iElem ))
6059           if ( resElem != sourceElem )
6060             resultElems.push_back( resElem );
6061
6062       // add resultElems to groups made by ones the sourceElem belongs to
6063       list< TOldNewGroup >::iterator gOldNew, gLast = groupsOldNew.end();
6064       for ( gOldNew = groupsOldNew.begin(); gOldNew != gLast; ++gOldNew )
6065       {
6066         SMESHDS_GroupBase* oldGroup = gOldNew->first;
6067         if ( oldGroup->Contains( sourceElem )) // sourceElem is in oldGroup
6068         {
6069           // fill in a new group
6070           SMDS_MeshGroup & newGroup = gOldNew->second->SMDSGroup();
6071           list< const SMDS_MeshElement* >::iterator resLast = resultElems.end(), resElemIt;
6072           for ( resElemIt = resultElems.begin(); resElemIt != resLast; ++resElemIt )
6073             newGroup.Add( *resElemIt );
6074         }
6075       }
6076     } // loop on created elements
6077   }// loop on nodes and elements
6078
6079   // Create new SMESH_Groups from SMESHDS_Groups and remove empty SMESHDS_Groups
6080
6081   for ( size_t i = 0; i < orderedOldNewGroups.size(); ++i )
6082   {
6083     SMESHDS_GroupBase* oldGroupDS = orderedOldNewGroups[i]->first;
6084     SMESHDS_Group*     newGroupDS = orderedOldNewGroups[i]->second;
6085     if ( newGroupDS->IsEmpty() )
6086     {
6087       mesh->GetMeshDS()->RemoveGroup( newGroupDS );
6088     }
6089     else
6090     {
6091       // make a name
6092       string name = oldGroupDS->GetStoreName();
6093       if ( !targetMesh ) {
6094         name += "_";
6095         name += postfix;
6096         int nb = 1;
6097         while ( !groupNames.insert( name ).second ) // name exists
6098           name = SMESH_Comment( oldGroupDS->GetStoreName() ) << "_" << postfix << "_" << nb++;
6099       }
6100       newGroupDS->SetStoreName( name.c_str() );
6101
6102       // make a SMESH_Groups
6103       mesh->AddGroup( newGroupDS );
6104       newGroupIDs->push_back( newGroupDS->GetID() );
6105
6106       // set group type
6107       newGroupDS->SetType( newGroupDS->GetElements()->next()->GetType() );
6108     }
6109   }
6110
6111   return newGroupIDs;
6112 }
6113
6114 //================================================================================
6115 /*!
6116  * \brief Return list of group of nodes close to each other within theTolerance
6117  *        Search among theNodes or in the whole mesh if theNodes is empty using
6118  *        an Octree algorithm
6119  */
6120 //================================================================================
6121
6122 void SMESH_MeshEditor::FindCoincidentNodes (TIDSortedNodeSet &   theNodes,
6123                                             const double         theTolerance,
6124                                             TListOfListOfNodes & theGroupsOfNodes)
6125 {
6126   myLastCreatedElems.Clear();
6127   myLastCreatedNodes.Clear();
6128
6129   if ( theNodes.empty() )
6130   { // get all nodes in the mesh
6131     SMDS_NodeIteratorPtr nIt = GetMeshDS()->nodesIterator(/*idInceasingOrder=*/true);
6132     while ( nIt->more() )
6133       theNodes.insert( theNodes.end(),nIt->next());
6134   }
6135
6136   SMESH_OctreeNode::FindCoincidentNodes ( theNodes, &theGroupsOfNodes, theTolerance);
6137 }
6138
6139
6140 //=======================================================================
6141 /*!
6142  * \brief Implementation of search for the node closest to point
6143  */
6144 //=======================================================================
6145
6146 struct SMESH_NodeSearcherImpl: public SMESH_NodeSearcher
6147 {
6148   //---------------------------------------------------------------------
6149   /*!
6150    * \brief Constructor
6151    */
6152   SMESH_NodeSearcherImpl( const SMESHDS_Mesh* theMesh )
6153   {
6154     myMesh = ( SMESHDS_Mesh* ) theMesh;
6155
6156     TIDSortedNodeSet nodes;
6157     if ( theMesh ) {
6158       SMDS_NodeIteratorPtr nIt = theMesh->nodesIterator(/*idInceasingOrder=*/true);
6159       while ( nIt->more() )
6160         nodes.insert( nodes.end(), nIt->next() );
6161     }
6162     myOctreeNode = new SMESH_OctreeNode(nodes) ;
6163
6164     // get max size of a leaf box
6165     SMESH_OctreeNode* tree = myOctreeNode;
6166     while ( !tree->isLeaf() )
6167     {
6168       SMESH_OctreeNodeIteratorPtr cIt = tree->GetChildrenIterator();
6169       if ( cIt->more() )
6170         tree = cIt->next();
6171     }
6172     myHalfLeafSize = tree->maxSize() / 2.;
6173   }
6174
6175   //---------------------------------------------------------------------
6176   /*!
6177    * \brief Move node and update myOctreeNode accordingly
6178    */
6179   void MoveNode( const SMDS_MeshNode* node, const gp_Pnt& toPnt )
6180   {
6181     myOctreeNode->UpdateByMoveNode( node, toPnt );
6182     myMesh->MoveNode( node, toPnt.X(), toPnt.Y(), toPnt.Z() );
6183   }
6184
6185   //---------------------------------------------------------------------
6186   /*!
6187    * \brief Do it's job
6188    */
6189   const SMDS_MeshNode* FindClosestTo( const gp_Pnt& thePnt )
6190   {
6191     map<double, const SMDS_MeshNode*> dist2Nodes;
6192     myOctreeNode->NodesAround( thePnt.Coord(), dist2Nodes, myHalfLeafSize );
6193     if ( !dist2Nodes.empty() )
6194       return dist2Nodes.begin()->second;
6195     list<const SMDS_MeshNode*> nodes;
6196     //myOctreeNode->NodesAround( &tgtNode, &nodes, myHalfLeafSize );
6197
6198     double minSqDist = DBL_MAX;
6199     if ( nodes.empty() )  // get all nodes of OctreeNode's closest to thePnt
6200     {
6201       // sort leafs by their distance from thePnt
6202       typedef map< double, SMESH_OctreeNode* > TDistTreeMap;
6203       TDistTreeMap treeMap;
6204       list< SMESH_OctreeNode* > treeList;
6205       list< SMESH_OctreeNode* >::iterator trIt;
6206       treeList.push_back( myOctreeNode );
6207
6208       gp_XYZ pointNode( thePnt.X(), thePnt.Y(), thePnt.Z() );
6209       bool pointInside = myOctreeNode->isInside( pointNode, myHalfLeafSize );
6210       for ( trIt = treeList.begin(); trIt != treeList.end(); ++trIt)
6211       {
6212         SMESH_OctreeNode* tree = *trIt;
6213         if ( !tree->isLeaf() ) // put children to the queue
6214         {
6215           if ( pointInside && !tree->isInside( pointNode, myHalfLeafSize )) continue;
6216           SMESH_OctreeNodeIteratorPtr cIt = tree->GetChildrenIterator();
6217           while ( cIt->more() )
6218             treeList.push_back( cIt->next() );
6219         }
6220         else if ( tree->NbNodes() ) // put a tree to the treeMap
6221         {
6222           const Bnd_B3d& box = *tree->getBox();
6223           double sqDist = thePnt.SquareDistance( 0.5 * ( box.CornerMin() + box.CornerMax() ));
6224           pair<TDistTreeMap::iterator,bool> it_in = treeMap.insert( make_pair( sqDist, tree ));
6225           if ( !it_in.second ) // not unique distance to box center
6226             treeMap.insert( it_in.first, make_pair( sqDist + 1e-13*treeMap.size(), tree ));
6227         }
6228       }
6229       // find distance after which there is no sense to check tree's
6230       double sqLimit = DBL_MAX;
6231       TDistTreeMap::iterator sqDist_tree = treeMap.begin();
6232       if ( treeMap.size() > 5 ) {
6233         SMESH_OctreeNode* closestTree = sqDist_tree->second;
6234         const Bnd_B3d& box = *closestTree->getBox();
6235         double limit = sqrt( sqDist_tree->first ) + sqrt ( box.SquareExtent() );
6236         sqLimit = limit * limit;
6237       }
6238       // get all nodes from trees
6239       for ( ; sqDist_tree != treeMap.end(); ++sqDist_tree) {
6240         if ( sqDist_tree->first > sqLimit )
6241           break;
6242         SMESH_OctreeNode* tree = sqDist_tree->second;
6243         tree->NodesAround( tree->GetNodeIterator()->next(), &nodes );
6244       }
6245     }
6246     // find closest among nodes
6247     minSqDist = DBL_MAX;
6248     const SMDS_MeshNode* closestNode = 0;
6249     list<const SMDS_MeshNode*>::iterator nIt = nodes.begin();
6250     for ( ; nIt != nodes.end(); ++nIt ) {
6251       double sqDist = thePnt.SquareDistance( SMESH_TNodeXYZ( *nIt ) );
6252       if ( minSqDist > sqDist ) {
6253         closestNode = *nIt;
6254         minSqDist = sqDist;
6255       }
6256     }
6257     return closestNode;
6258   }
6259
6260   //---------------------------------------------------------------------
6261   /*!
6262    * \brief Destructor
6263    */
6264   ~SMESH_NodeSearcherImpl() { delete myOctreeNode; }
6265
6266   //---------------------------------------------------------------------
6267   /*!
6268    * \brief Return the node tree
6269    */
6270   const SMESH_OctreeNode* getTree() const { return myOctreeNode; }
6271
6272 private:
6273   SMESH_OctreeNode* myOctreeNode;
6274   SMESHDS_Mesh*     myMesh;
6275   double            myHalfLeafSize; // max size of a leaf box
6276 };
6277
6278 //=======================================================================
6279 /*!
6280  * \brief Return SMESH_NodeSearcher
6281  */
6282 //=======================================================================
6283
6284 SMESH_NodeSearcher* SMESH_MeshEditor::GetNodeSearcher()
6285 {
6286   return new SMESH_NodeSearcherImpl( GetMeshDS() );
6287 }
6288
6289 // ========================================================================
6290 namespace // Utils used in SMESH_ElementSearcherImpl::FindElementsByPoint()
6291 {
6292   const int MaxNbElemsInLeaf = 10; // maximal number of elements in a leaf of tree
6293   const int MaxLevel         = 7;  // maximal tree height -> nb terminal boxes: 8^7 = 2097152
6294   const double NodeRadius = 1e-9;  // to enlarge bnd box of element
6295
6296   //=======================================================================
6297   /*!
6298    * \brief Octal tree of bounding boxes of elements
6299    */
6300   //=======================================================================
6301
6302   class ElementBndBoxTree : public SMESH_Octree
6303   {
6304   public:
6305
6306     ElementBndBoxTree(const SMDS_Mesh&     mesh,
6307                       SMDSAbs_ElementType  elemType,
6308                       SMDS_ElemIteratorPtr theElemIt = SMDS_ElemIteratorPtr(),
6309                       double               tolerance = NodeRadius );
6310     void getElementsNearPoint( const gp_Pnt& point, TIDSortedElemSet& foundElems );
6311     void getElementsNearLine ( const gp_Ax1& line, TIDSortedElemSet& foundElems);
6312     void getElementsInSphere ( const gp_XYZ& center,
6313                                const double  radius, TIDSortedElemSet& foundElems);
6314     size_t getSize() { return std::max( _size, _elements.size() ); }
6315     ~ElementBndBoxTree();
6316
6317   protected:
6318     ElementBndBoxTree():_size(0) {}
6319     SMESH_Octree* newChild() const { return new ElementBndBoxTree; }
6320     void          buildChildrenData();
6321     Bnd_B3d*      buildRootBox();
6322   private:
6323     //!< Bounding box of element
6324     struct ElementBox : public Bnd_B3d
6325     {
6326       const SMDS_MeshElement* _element;
6327       int                     _refCount; // an ElementBox can be included in several tree branches
6328       ElementBox(const SMDS_MeshElement* elem, double tolerance);
6329     };
6330     vector< ElementBox* > _elements;
6331     size_t                _size;
6332   };
6333
6334   //================================================================================
6335   /*!
6336    * \brief ElementBndBoxTree creation
6337    */
6338   //================================================================================
6339
6340   ElementBndBoxTree::ElementBndBoxTree(const SMDS_Mesh& mesh, SMDSAbs_ElementType elemType, SMDS_ElemIteratorPtr theElemIt, double tolerance)
6341     :SMESH_Octree( new SMESH_TreeLimit( MaxLevel, /*minSize=*/0. ))
6342   {
6343     int nbElems = mesh.GetMeshInfo().NbElements( elemType );
6344     _elements.reserve( nbElems );
6345
6346     SMDS_ElemIteratorPtr elemIt = theElemIt ? theElemIt : mesh.elementsIterator( elemType );
6347     while ( elemIt->more() )
6348       _elements.push_back( new ElementBox( elemIt->next(),tolerance  ));
6349
6350     compute();
6351   }
6352
6353   //================================================================================
6354   /*!
6355    * \brief Destructor
6356    */
6357   //================================================================================
6358
6359   ElementBndBoxTree::~ElementBndBoxTree()
6360   {
6361     for ( int i = 0; i < _elements.size(); ++i )
6362       if ( --_elements[i]->_refCount <= 0 )
6363         delete _elements[i];
6364   }
6365
6366   //================================================================================
6367   /*!
6368    * \brief Return the maximal box
6369    */
6370   //================================================================================
6371
6372   Bnd_B3d* ElementBndBoxTree::buildRootBox()
6373   {
6374     Bnd_B3d* box = new Bnd_B3d;
6375     for ( int i = 0; i < _elements.size(); ++i )
6376       box->Add( *_elements[i] );
6377     return box;
6378   }
6379
6380   //================================================================================
6381   /*!
6382    * \brief Redistrubute element boxes among children
6383    */
6384   //================================================================================
6385
6386   void ElementBndBoxTree::buildChildrenData()
6387   {
6388     for ( int i = 0; i < _elements.size(); ++i )
6389     {
6390       for (int j = 0; j < 8; j++)
6391       {
6392         if ( !_elements[i]->IsOut( *myChildren[j]->getBox() ))
6393         {
6394           _elements[i]->_refCount++;
6395           ((ElementBndBoxTree*)myChildren[j])->_elements.push_back( _elements[i]);
6396         }
6397       }
6398       _elements[i]->_refCount--;
6399     }
6400     _size = _elements.size();
6401     SMESHUtils::FreeVector( _elements ); // = _elements.clear() + free memory
6402
6403     for (int j = 0; j < 8; j++)
6404     {
6405       ElementBndBoxTree* child = static_cast<ElementBndBoxTree*>( myChildren[j]);
6406       if ( child->_elements.size() <= MaxNbElemsInLeaf )
6407         child->myIsLeaf = true;
6408
6409       if ( child->_elements.capacity() - child->_elements.size() > 1000 )
6410         SMESHUtils::CompactVector( child->_elements );
6411     }
6412   }
6413
6414   //================================================================================
6415   /*!
6416    * \brief Return elements which can include the point
6417    */
6418   //================================================================================
6419
6420   void ElementBndBoxTree::getElementsNearPoint( const gp_Pnt&     point,
6421                                                 TIDSortedElemSet& foundElems)
6422   {
6423     if ( getBox()->IsOut( point.XYZ() ))
6424       return;
6425
6426     if ( isLeaf() )
6427     {
6428       for ( int i = 0; i < _elements.size(); ++i )
6429         if ( !_elements[i]->IsOut( point.XYZ() ))
6430           foundElems.insert( _elements[i]->_element );
6431     }
6432     else
6433     {
6434       for (int i = 0; i < 8; i++)
6435         ((ElementBndBoxTree*) myChildren[i])->getElementsNearPoint( point, foundElems );
6436     }
6437   }
6438
6439   //================================================================================
6440   /*!
6441    * \brief Return elements which can be intersected by the line
6442    */
6443   //================================================================================
6444
6445   void ElementBndBoxTree::getElementsNearLine( const gp_Ax1&     line,
6446                                                TIDSortedElemSet& foundElems)
6447   {
6448     if ( getBox()->IsOut( line ))
6449       return;
6450
6451     if ( isLeaf() )
6452     {
6453       for ( int i = 0; i < _elements.size(); ++i )
6454         if ( !_elements[i]->IsOut( line ))
6455           foundElems.insert( _elements[i]->_element );
6456     }
6457     else
6458     {
6459       for (int i = 0; i < 8; i++)
6460         ((ElementBndBoxTree*) myChildren[i])->getElementsNearLine( line, foundElems );
6461     }
6462   }
6463
6464   //================================================================================
6465   /*!
6466    * \brief Return elements from leaves intersecting the sphere
6467    */
6468   //================================================================================
6469
6470   void ElementBndBoxTree::getElementsInSphere ( const gp_XYZ&     center,
6471                                                 const double      radius,
6472                                                 TIDSortedElemSet& foundElems)
6473   {
6474     if ( getBox()->IsOut( center, radius ))
6475       return;
6476
6477     if ( isLeaf() )
6478     {
6479       for ( int i = 0; i < _elements.size(); ++i )
6480         if ( !_elements[i]->IsOut( center, radius ))
6481           foundElems.insert( _elements[i]->_element );
6482     }
6483     else
6484     {
6485       for (int i = 0; i < 8; i++)
6486         ((ElementBndBoxTree*) myChildren[i])->getElementsInSphere( center, radius, foundElems );
6487     }
6488   }
6489
6490   //================================================================================
6491   /*!
6492    * \brief Construct the element box
6493    */
6494   //================================================================================
6495
6496   ElementBndBoxTree::ElementBox::ElementBox(const SMDS_MeshElement* elem, double tolerance)
6497   {
6498     _element  = elem;
6499     _refCount = 1;
6500     SMDS_ElemIteratorPtr nIt = elem->nodesIterator();
6501     while ( nIt->more() )
6502       Add( SMESH_TNodeXYZ( nIt->next() ));
6503     Enlarge( tolerance );
6504   }
6505
6506 } // namespace
6507
6508 //=======================================================================
6509 /*!
6510  * \brief Implementation of search for the elements by point and
6511  *        of classification of point in 2D mesh
6512  */
6513 //=======================================================================
6514
6515 struct SMESH_ElementSearcherImpl: public SMESH_ElementSearcher
6516 {
6517   SMESHDS_Mesh*                _mesh;
6518   SMDS_ElemIteratorPtr         _meshPartIt;
6519   ElementBndBoxTree*           _ebbTree;
6520   SMESH_NodeSearcherImpl*      _nodeSearcher;
6521   SMDSAbs_ElementType          _elementType;
6522   double                       _tolerance;
6523   bool                         _outerFacesFound;
6524   set<const SMDS_MeshElement*> _outerFaces; // empty means "no internal faces at all"
6525
6526   SMESH_ElementSearcherImpl( SMESHDS_Mesh& mesh, SMDS_ElemIteratorPtr elemIt=SMDS_ElemIteratorPtr())
6527     : _mesh(&mesh),_meshPartIt(elemIt),_ebbTree(0),_nodeSearcher(0),_tolerance(-1),_outerFacesFound(false) {}
6528   ~SMESH_ElementSearcherImpl()
6529   {
6530     if ( _ebbTree )      delete _ebbTree;      _ebbTree      = 0;
6531     if ( _nodeSearcher ) delete _nodeSearcher; _nodeSearcher = 0;
6532   }
6533   virtual int FindElementsByPoint(const gp_Pnt&                      point,
6534                                   SMDSAbs_ElementType                type,
6535                                   vector< const SMDS_MeshElement* >& foundElements);
6536   virtual TopAbs_State GetPointState(const gp_Pnt& point);
6537   virtual const SMDS_MeshElement* FindClosestTo( const gp_Pnt&       point,
6538                                                  SMDSAbs_ElementType type );
6539
6540   void GetElementsNearLine( const gp_Ax1&                      line,
6541                             SMDSAbs_ElementType                type,
6542                             vector< const SMDS_MeshElement* >& foundElems);
6543   double getTolerance();
6544   bool getIntersParamOnLine(const gp_Lin& line, const SMDS_MeshElement* face,
6545                             const double tolerance, double & param);
6546   void findOuterBoundary(const SMDS_MeshElement* anyOuterFace);
6547   bool isOuterBoundary(const SMDS_MeshElement* face) const
6548   {
6549     return _outerFaces.empty() || _outerFaces.count(face);
6550   }
6551   struct TInters //!< data of intersection of the line and the mesh face (used in GetPointState())
6552   {
6553     const SMDS_MeshElement* _face;
6554     gp_Vec                  _faceNorm;
6555     bool                    _coincides; //!< the line lays in face plane
6556     TInters(const SMDS_MeshElement* face, const gp_Vec& faceNorm, bool coinc=false)
6557       : _face(face), _faceNorm( faceNorm ), _coincides( coinc ) {}
6558   };
6559   struct TFaceLink //!< link and faces sharing it (used in findOuterBoundary())
6560   {
6561     SMESH_TLink      _link;
6562     TIDSortedElemSet _faces;
6563     TFaceLink( const SMDS_MeshNode* n1, const SMDS_MeshNode* n2, const SMDS_MeshElement* face)
6564       : _link( n1, n2 ), _faces( &face, &face + 1) {}
6565   };
6566 };
6567
6568 ostream& operator<< (ostream& out, const SMESH_ElementSearcherImpl::TInters& i)
6569 {
6570   return out << "TInters(face=" << ( i._face ? i._face->GetID() : 0)
6571              << ", _coincides="<<i._coincides << ")";
6572 }
6573
6574 //=======================================================================
6575 /*!
6576  * \brief define tolerance for search
6577  */
6578 //=======================================================================
6579
6580 double SMESH_ElementSearcherImpl::getTolerance()
6581 {
6582   if ( _tolerance < 0 )
6583   {
6584     const SMDS_MeshInfo& meshInfo = _mesh->GetMeshInfo();
6585
6586     _tolerance = 0;
6587     if ( _nodeSearcher && meshInfo.NbNodes() > 1 )
6588     {
6589       double boxSize = _nodeSearcher->getTree()->maxSize();
6590       _tolerance = 1e-8 * boxSize/* / meshInfo.NbNodes()*/;
6591     }
6592     else if ( _ebbTree && meshInfo.NbElements() > 0 )
6593     {
6594       double boxSize = _ebbTree->maxSize();
6595       _tolerance = 1e-8 * boxSize/* / meshInfo.NbElements()*/;
6596     }
6597     if ( _tolerance == 0 )
6598     {
6599       // define tolerance by size of a most complex element
6600       int complexType = SMDSAbs_Volume;
6601       while ( complexType > SMDSAbs_All &&
6602               meshInfo.NbElements( SMDSAbs_ElementType( complexType )) < 1 )
6603         --complexType;
6604       if ( complexType == SMDSAbs_All ) return 0; // empty mesh
6605       double elemSize;
6606       if ( complexType == int( SMDSAbs_Node ))
6607       {
6608         SMDS_NodeIteratorPtr nodeIt = _mesh->nodesIterator();
6609         elemSize = 1;
6610         if ( meshInfo.NbNodes() > 2 )
6611           elemSize = SMESH_TNodeXYZ( nodeIt->next() ).Distance( nodeIt->next() );
6612       }
6613       else
6614       {
6615         SMDS_ElemIteratorPtr elemIt =
6616             _mesh->elementsIterator( SMDSAbs_ElementType( complexType ));
6617         const SMDS_MeshElement* elem = elemIt->next();
6618         SMDS_ElemIteratorPtr nodeIt = elem->nodesIterator();
6619         SMESH_TNodeXYZ n1( cast2Node( nodeIt->next() ));
6620         elemSize = 0;
6621         while ( nodeIt->more() )
6622         {
6623           double dist = n1.Distance( cast2Node( nodeIt->next() ));
6624           elemSize = max( dist, elemSize );
6625         }
6626       }
6627       _tolerance = 1e-4 * elemSize;
6628     }
6629   }
6630   return _tolerance;
6631 }
6632
6633 //================================================================================
6634 /*!
6635  * \brief Find intersection of the line and an edge of face and return parameter on line
6636  */
6637 //================================================================================
6638
6639 bool SMESH_ElementSearcherImpl::getIntersParamOnLine(const gp_Lin&           line,
6640                                                      const SMDS_MeshElement* face,
6641                                                      const double            tol,
6642                                                      double &                param)
6643 {
6644   int nbInts = 0;
6645   param = 0;
6646
6647   GeomAPI_ExtremaCurveCurve anExtCC;
6648   Handle(Geom_Curve) lineCurve = new Geom_Line( line );
6649
6650   int nbNodes = face->IsQuadratic() ? face->NbNodes()/2 : face->NbNodes();
6651   for ( int i = 0; i < nbNodes && nbInts < 2; ++i )
6652   {
6653     GC_MakeSegment edge( SMESH_TNodeXYZ( face->GetNode( i )),
6654                          SMESH_TNodeXYZ( face->GetNode( (i+1)%nbNodes) ));
6655     anExtCC.Init( lineCurve, edge);
6656     if ( anExtCC.NbExtrema() > 0 && anExtCC.LowerDistance() <= tol)
6657     {
6658       Quantity_Parameter pl, pe;
6659       anExtCC.LowerDistanceParameters( pl, pe );
6660       param += pl;
6661       if ( ++nbInts == 2 )
6662         break;
6663     }
6664   }
6665   if ( nbInts > 0 ) param /= nbInts;
6666   return nbInts > 0;
6667 }
6668 //================================================================================
6669 /*!
6670  * \brief Find all faces belonging to the outer boundary of mesh
6671  */
6672 //================================================================================
6673
6674 void SMESH_ElementSearcherImpl::findOuterBoundary(const SMDS_MeshElement* outerFace)
6675 {
6676   if ( _outerFacesFound ) return;
6677
6678   // Collect all outer faces by passing from one outer face to another via their links
6679   // and BTW find out if there are internal faces at all.
6680
6681   // checked links and links where outer boundary meets internal one
6682   set< SMESH_TLink > visitedLinks, seamLinks;
6683
6684   // links to treat with already visited faces sharing them
6685   list < TFaceLink > startLinks;
6686
6687   // load startLinks with the first outerFace
6688   startLinks.push_back( TFaceLink( outerFace->GetNode(0), outerFace->GetNode(1), outerFace));
6689   _outerFaces.insert( outerFace );
6690
6691   TIDSortedElemSet emptySet;
6692   while ( !startLinks.empty() )
6693   {
6694     const SMESH_TLink& link  = startLinks.front()._link;
6695     TIDSortedElemSet&  faces = startLinks.front()._faces;
6696
6697     outerFace = *faces.begin();
6698     // find other faces sharing the link
6699     const SMDS_MeshElement* f;
6700     while (( f = SMESH_MeshEditor::FindFaceInSet(link.node1(), link.node2(), emptySet, faces )))
6701       faces.insert( f );
6702
6703     // select another outer face among the found
6704     const SMDS_MeshElement* outerFace2 = 0;
6705     if ( faces.size() == 2 )
6706     {
6707       outerFace2 = (outerFace == *faces.begin() ? *faces.rbegin() : *faces.begin());
6708     }
6709     else if ( faces.size() > 2 )
6710     {
6711       seamLinks.insert( link );
6712
6713       // link direction within the outerFace
6714       gp_Vec n1n2( SMESH_TNodeXYZ( link.node1()),
6715                    SMESH_TNodeXYZ( link.node2()));
6716       int i1 = outerFace->GetNodeIndex( link.node1() );
6717       int i2 = outerFace->GetNodeIndex( link.node2() );
6718       bool rev = ( abs(i2-i1) == 1 ? i1 > i2 : i2 > i1 );
6719       if ( rev ) n1n2.Reverse();
6720       // outerFace normal
6721       gp_XYZ ofNorm, fNorm;
6722       if ( SMESH_Algo::FaceNormal( outerFace, ofNorm, /*normalized=*/false ))
6723       {
6724         // direction from the link inside outerFace
6725         gp_Vec dirInOF = gp_Vec( ofNorm ) ^ n1n2;
6726         // sort all other faces by angle with the dirInOF
6727         map< double, const SMDS_MeshElement* > angle2Face;
6728         set< const SMDS_MeshElement*, TIDCompare >::const_iterator face = faces.begin();
6729         for ( ; face != faces.end(); ++face )
6730         {
6731           if ( !SMESH_Algo::FaceNormal( *face, fNorm, /*normalized=*/false ))
6732             continue;
6733           gp_Vec dirInF = gp_Vec( fNorm ) ^ n1n2;
6734           double angle = dirInOF.AngleWithRef( dirInF, n1n2 );
6735           if ( angle < 0 ) angle += 2. * M_PI;
6736           angle2Face.insert( make_pair( angle, *face ));
6737         }
6738         if ( !angle2Face.empty() )
6739           outerFace2 = angle2Face.begin()->second;
6740       }
6741     }
6742     // store the found outer face and add its links to continue seaching from
6743     if ( outerFace2 )
6744     {
6745       _outerFaces.insert( outerFace );
6746       int nbNodes = outerFace2->NbNodes()/( outerFace2->IsQuadratic() ? 2 : 1 );
6747       for ( int i = 0; i < nbNodes; ++i )
6748       {
6749         SMESH_TLink link2( outerFace2->GetNode(i), outerFace2->GetNode((i+1)%nbNodes));
6750         if ( visitedLinks.insert( link2 ).second )
6751           startLinks.push_back( TFaceLink( link2.node1(), link2.node2(), outerFace2 ));
6752       }
6753     }
6754     startLinks.pop_front();
6755   }
6756   _outerFacesFound = true;
6757
6758   if ( !seamLinks.empty() )
6759   {
6760     // There are internal boundaries touching the outher one,
6761     // find all faces of internal boundaries in order to find
6762     // faces of boundaries of holes, if any.
6763
6764   }
6765   else
6766   {
6767     _outerFaces.clear();
6768   }
6769 }
6770
6771 //=======================================================================
6772 /*!
6773  * \brief Find elements of given type where the given point is IN or ON.
6774  *        Returns nb of found elements and elements them-selves.
6775  *
6776  * 'ALL' type means elements of any type excluding nodes, balls and 0D elements
6777  */
6778 //=======================================================================
6779
6780 int SMESH_ElementSearcherImpl::
6781 FindElementsByPoint(const gp_Pnt&                      point,
6782                     SMDSAbs_ElementType                type,
6783                     vector< const SMDS_MeshElement* >& foundElements)
6784 {
6785   foundElements.clear();
6786
6787   double tolerance = getTolerance();
6788
6789   // =================================================================================
6790   if ( type == SMDSAbs_Node || type == SMDSAbs_0DElement || type == SMDSAbs_Ball)
6791   {
6792     if ( !_nodeSearcher )
6793       _nodeSearcher = new SMESH_NodeSearcherImpl( _mesh );
6794
6795     const SMDS_MeshNode* closeNode = _nodeSearcher->FindClosestTo( point );
6796     if ( !closeNode ) return foundElements.size();
6797
6798     if ( point.Distance( SMESH_TNodeXYZ( closeNode )) > tolerance )
6799       return foundElements.size(); // to far from any node
6800
6801     if ( type == SMDSAbs_Node )
6802     {
6803       foundElements.push_back( closeNode );
6804     }
6805     else
6806     {
6807       SMDS_ElemIteratorPtr elemIt = closeNode->GetInverseElementIterator( type );
6808       while ( elemIt->more() )
6809         foundElements.push_back( elemIt->next() );
6810     }
6811   }
6812   // =================================================================================
6813   else // elements more complex than 0D
6814   {
6815     if ( !_ebbTree || _elementType != type )
6816     {
6817       if ( _ebbTree ) delete _ebbTree;
6818       _ebbTree = new ElementBndBoxTree( *_mesh, _elementType = type, _meshPartIt, tolerance );
6819     }
6820     TIDSortedElemSet suspectElems;
6821     _ebbTree->getElementsNearPoint( point, suspectElems );
6822     TIDSortedElemSet::iterator elem = suspectElems.begin();
6823     for ( ; elem != suspectElems.end(); ++elem )
6824       if ( !SMESH_MeshEditor::IsOut( *elem, point, tolerance ))
6825         foundElements.push_back( *elem );
6826   }
6827   return foundElements.size();
6828 }
6829
6830 //=======================================================================
6831 /*!
6832  * \brief Find an element of given type most close to the given point
6833  *
6834  * WARNING: Only face search is implemeneted so far
6835  */
6836 //=======================================================================
6837
6838 const SMDS_MeshElement*
6839 SMESH_ElementSearcherImpl::FindClosestTo( const gp_Pnt&       point,
6840                                           SMDSAbs_ElementType type )
6841 {
6842   const SMDS_MeshElement* closestElem = 0;
6843
6844   if ( type == SMDSAbs_Face )
6845   {
6846     if ( !_ebbTree || _elementType != type )
6847     {
6848       if ( _ebbTree ) delete _ebbTree;
6849       _ebbTree = new ElementBndBoxTree( *_mesh, _elementType = type, _meshPartIt );
6850     }
6851     TIDSortedElemSet suspectElems;
6852     _ebbTree->getElementsNearPoint( point, suspectElems );
6853
6854     if ( suspectElems.empty() && _ebbTree->maxSize() > 0 )
6855     {
6856       gp_Pnt boxCenter = 0.5 * ( _ebbTree->getBox()->CornerMin() +
6857                                  _ebbTree->getBox()->CornerMax() );
6858       double radius;
6859       if ( _ebbTree->getBox()->IsOut( point.XYZ() ))
6860         radius = point.Distance( boxCenter ) - 0.5 * _ebbTree->maxSize();
6861       else
6862         radius = _ebbTree->maxSize() / pow( 2., _ebbTree->getHeight()) / 2;
6863       while ( suspectElems.empty() )
6864       {
6865         _ebbTree->getElementsInSphere( point.XYZ(), radius, suspectElems );
6866         radius *= 1.1;
6867       }
6868     }
6869     double minDist = std::numeric_limits<double>::max();
6870     multimap< double, const SMDS_MeshElement* > dist2face;
6871     TIDSortedElemSet::iterator elem = suspectElems.begin();
6872     for ( ; elem != suspectElems.end(); ++elem )
6873     {
6874       double dist = SMESH_MeshEditor::GetDistance( dynamic_cast<const SMDS_MeshFace*>(*elem),
6875                                                    point );
6876       if ( dist < minDist + 1e-10)
6877       {
6878         minDist = dist;
6879         dist2face.insert( dist2face.begin(), make_pair( dist, *elem ));
6880       }
6881     }
6882     if ( !dist2face.empty() )
6883     {
6884       multimap< double, const SMDS_MeshElement* >::iterator d2f = dist2face.begin();
6885       closestElem = d2f->second;
6886       // if there are several elements at the same distance, select one
6887       // with GC closest to the point
6888       typedef SMDS_StdIterator< SMESH_TNodeXYZ, SMDS_ElemIteratorPtr > TXyzIterator;
6889       double minDistToGC = 0;
6890       for ( ++d2f; d2f != dist2face.end() && fabs( d2f->first - minDist ) < 1e-10; ++d2f )
6891       {
6892         if ( minDistToGC == 0 )
6893         {
6894           gp_XYZ gc(0,0,0);
6895           gc = accumulate( TXyzIterator(closestElem->nodesIterator()),
6896                            TXyzIterator(), gc ) / closestElem->NbNodes();
6897           minDistToGC = point.SquareDistance( gc );
6898         }
6899         gp_XYZ gc(0,0,0);
6900         gc = accumulate( TXyzIterator( d2f->second->nodesIterator()),
6901                          TXyzIterator(), gc ) / d2f->second->NbNodes();
6902         double d = point.SquareDistance( gc );
6903         if ( d < minDistToGC )
6904         {
6905           minDistToGC = d;
6906           closestElem = d2f->second;
6907         }
6908       }
6909       // cout << "FindClosestTo( " <<point.X()<<", "<<point.Y()<<", "<<point.Z()<<" ) FACE "
6910       //      <<closestElem->GetID() << " DIST " << minDist << endl;
6911     }
6912   }
6913   else
6914   {
6915     // NOT IMPLEMENTED SO FAR
6916   }
6917   return closestElem;
6918 }
6919
6920
6921 //================================================================================
6922 /*!
6923  * \brief Classify the given point in the closed 2D mesh
6924  */
6925 //================================================================================
6926
6927 TopAbs_State SMESH_ElementSearcherImpl::GetPointState(const gp_Pnt& point)
6928 {
6929   double tolerance = getTolerance();
6930   if ( !_ebbTree || _elementType != SMDSAbs_Face )
6931   {
6932     if ( _ebbTree ) delete _ebbTree;
6933     _ebbTree = new ElementBndBoxTree( *_mesh, _elementType = SMDSAbs_Face, _meshPartIt );
6934   }
6935   // Algo: analyse transition of a line starting at the point through mesh boundary;
6936   // try three lines parallel to axis of the coordinate system and perform rough
6937   // analysis. If solution is not clear perform thorough analysis.
6938
6939   const int nbAxes = 3;
6940   gp_Dir axisDir[ nbAxes ] = { gp::DX(), gp::DY(), gp::DZ() };
6941   map< double, TInters >   paramOnLine2TInters[ nbAxes ];
6942   list< TInters > tangentInters[ nbAxes ]; // of faces whose plane includes the line
6943   multimap< int, int > nbInt2Axis; // to find the simplest case
6944   for ( int axis = 0; axis < nbAxes; ++axis )
6945   {
6946     gp_Ax1 lineAxis( point, axisDir[axis]);
6947     gp_Lin line    ( lineAxis );
6948
6949     TIDSortedElemSet suspectFaces; // faces possibly intersecting the line
6950     _ebbTree->getElementsNearLine( lineAxis, suspectFaces );
6951
6952     // Intersect faces with the line
6953
6954     map< double, TInters > & u2inters = paramOnLine2TInters[ axis ];
6955     TIDSortedElemSet::iterator face = suspectFaces.begin();
6956     for ( ; face != suspectFaces.end(); ++face )
6957     {
6958       // get face plane
6959       gp_XYZ fNorm;
6960       if ( !SMESH_Algo::FaceNormal( *face, fNorm, /*normalized=*/false)) continue;
6961       gp_Pln facePlane( SMESH_TNodeXYZ( (*face)->GetNode(0)), fNorm );
6962
6963       // perform intersection
6964       IntAna_IntConicQuad intersection( line, IntAna_Quadric( facePlane ));
6965       if ( !intersection.IsDone() )
6966         continue;
6967       if ( intersection.IsInQuadric() )
6968       {
6969         tangentInters[ axis ].push_back( TInters( *face, fNorm, true ));
6970       }
6971       else if ( ! intersection.IsParallel() && intersection.NbPoints() > 0 )
6972       {
6973         gp_Pnt intersectionPoint = intersection.Point(1);
6974         if ( !SMESH_MeshEditor::IsOut( *face, intersectionPoint, tolerance ))
6975           u2inters.insert(make_pair( intersection.ParamOnConic(1), TInters( *face, fNorm )));
6976       }
6977     }
6978     // Analyse intersections roughly
6979
6980     int nbInter = u2inters.size();
6981     if ( nbInter == 0 )
6982       return TopAbs_OUT;
6983
6984     double f = u2inters.begin()->first, l = u2inters.rbegin()->first;
6985     if ( nbInter == 1 ) // not closed mesh
6986       return fabs( f ) < tolerance ? TopAbs_ON : TopAbs_UNKNOWN;
6987
6988     if ( fabs( f ) < tolerance || fabs( l ) < tolerance )
6989       return TopAbs_ON;
6990
6991     if ( (f<0) == (l<0) )
6992       return TopAbs_OUT;
6993
6994     int nbIntBeforePoint = std::distance( u2inters.begin(), u2inters.lower_bound(0));
6995     int nbIntAfterPoint  = nbInter - nbIntBeforePoint;
6996     if ( nbIntBeforePoint == 1 || nbIntAfterPoint == 1 )
6997       return TopAbs_IN;
6998
6999     nbInt2Axis.insert( make_pair( min( nbIntBeforePoint, nbIntAfterPoint ), axis ));
7000
7001     if ( _outerFacesFound ) break; // pass to thorough analysis
7002
7003   } // three attempts - loop on CS axes
7004
7005   // Analyse intersections thoroughly.
7006   // We make two loops maximum, on the first one we only exclude touching intersections,
7007   // on the second, if situation is still unclear, we gather and use information on
7008   // position of faces (internal or outer). If faces position is already gathered,
7009   // we make the second loop right away.
7010
7011   for ( int hasPositionInfo = _outerFacesFound; hasPositionInfo < 2; ++hasPositionInfo )
7012   {
7013     multimap< int, int >::const_iterator nb_axis = nbInt2Axis.begin();
7014     for ( ; nb_axis != nbInt2Axis.end(); ++nb_axis )
7015     {
7016       int axis = nb_axis->second;
7017       map< double, TInters > & u2inters = paramOnLine2TInters[ axis ];
7018
7019       gp_Ax1 lineAxis( point, axisDir[axis]);
7020       gp_Lin line    ( lineAxis );
7021
7022       // add tangent intersections to u2inters
7023       double param;
7024       list< TInters >::const_iterator tgtInt = tangentInters[ axis ].begin();
7025       for ( ; tgtInt != tangentInters[ axis ].end(); ++tgtInt )
7026         if ( getIntersParamOnLine( line, tgtInt->_face, tolerance, param ))
7027           u2inters.insert(make_pair( param, *tgtInt ));
7028       tangentInters[ axis ].clear();
7029
7030       // Count intersections before and after the point excluding touching ones.
7031       // If hasPositionInfo we count intersections of outer boundary only
7032
7033       int nbIntBeforePoint = 0, nbIntAfterPoint = 0;
7034       double f = numeric_limits<double>::max(), l = -numeric_limits<double>::max();
7035       map< double, TInters >::iterator u_int1 = u2inters.begin(), u_int2 = u_int1;
7036       bool ok = ! u_int1->second._coincides;
7037       while ( ok && u_int1 != u2inters.end() )
7038       {
7039         double u = u_int1->first;
7040         bool touchingInt = false;
7041         if ( ++u_int2 != u2inters.end() )
7042         {
7043           // skip intersections at the same point (if the line passes through edge or node)
7044           int nbSamePnt = 0;
7045           while ( u_int2 != u2inters.end() && fabs( u_int2->first - u ) < tolerance )
7046           {
7047             ++nbSamePnt;
7048             ++u_int2;
7049           }
7050
7051           // skip tangent intersections
7052           int nbTgt = 0;
7053           const SMDS_MeshElement* prevFace = u_int1->second._face;
7054           while ( ok && u_int2->second._coincides )
7055           {
7056             if ( SMESH_Algo::GetCommonNodes(prevFace , u_int2->second._face).empty() )
7057               ok = false;
7058             else
7059             {
7060               nbTgt++;
7061               u_int2++;
7062               ok = ( u_int2 != u2inters.end() );
7063             }
7064           }
7065           if ( !ok ) break;
7066
7067           // skip intersections at the same point after tangent intersections
7068           if ( nbTgt > 0 )
7069           {
7070             double u2 = u_int2->first;
7071             ++u_int2;
7072             while ( u_int2 != u2inters.end() && fabs( u_int2->first - u2 ) < tolerance )
7073             {
7074               ++nbSamePnt;
7075               ++u_int2;
7076             }
7077           }
7078           // decide if we skipped a touching intersection
7079           if ( nbSamePnt + nbTgt > 0 )
7080           {
7081             double minDot = numeric_limits<double>::max(), maxDot = -numeric_limits<double>::max();
7082             map< double, TInters >::iterator u_int = u_int1;
7083             for ( ; u_int != u_int2; ++u_int )
7084             {
7085               if ( u_int->second._coincides ) continue;
7086               double dot = u_int->second._faceNorm * line.Direction();
7087               if ( dot > maxDot ) maxDot = dot;
7088               if ( dot < minDot ) minDot = dot;
7089             }
7090             touchingInt = ( minDot*maxDot < 0 );
7091           }
7092         }
7093         if ( !touchingInt )
7094         {
7095           if ( !hasPositionInfo || isOuterBoundary( u_int1->second._face ))
7096           {
7097             if ( u < 0 )
7098               ++nbIntBeforePoint;
7099             else
7100               ++nbIntAfterPoint;
7101           }
7102           if ( u < f ) f = u;
7103           if ( u > l ) l = u;
7104         }
7105
7106         u_int1 = u_int2; // to next intersection
7107
7108       } // loop on intersections with one line
7109
7110       if ( ok )
7111       {
7112         if ( fabs( f ) < tolerance || fabs( l ) < tolerance )
7113           return TopAbs_ON;
7114
7115         if ( nbIntBeforePoint == 0  || nbIntAfterPoint == 0)
7116           return TopAbs_OUT;
7117
7118         if ( nbIntBeforePoint + nbIntAfterPoint == 1 ) // not closed mesh
7119           return fabs( f ) < tolerance ? TopAbs_ON : TopAbs_UNKNOWN;
7120
7121         if ( nbIntBeforePoint == 1 || nbIntAfterPoint == 1 )
7122           return TopAbs_IN;
7123
7124         if ( (f<0) == (l<0) )
7125           return TopAbs_OUT;
7126
7127         if ( hasPositionInfo )
7128           return nbIntBeforePoint % 2 ? TopAbs_IN : TopAbs_OUT;
7129       }
7130     } // loop on intersections of the tree lines - thorough analysis
7131
7132     if ( !hasPositionInfo )
7133     {
7134       // gather info on faces position - is face in the outer boundary or not
7135       map< double, TInters > & u2inters = paramOnLine2TInters[ 0 ];
7136       findOuterBoundary( u2inters.begin()->second._face );
7137     }
7138
7139   } // two attempts - with and w/o faces position info in the mesh
7140
7141   return TopAbs_UNKNOWN;
7142 }
7143
7144 //=======================================================================
7145 /*!
7146  * \brief Return elements possibly intersecting the line
7147  */
7148 //=======================================================================
7149
7150 void SMESH_ElementSearcherImpl::GetElementsNearLine( const gp_Ax1&                      line,
7151                                                      SMDSAbs_ElementType                type,
7152                                                      vector< const SMDS_MeshElement* >& foundElems)
7153 {
7154   if ( !_ebbTree || _elementType != type )
7155   {
7156     if ( _ebbTree ) delete _ebbTree;
7157     _ebbTree = new ElementBndBoxTree( *_mesh, _elementType = type, _meshPartIt );
7158   }
7159   TIDSortedElemSet suspectFaces; // elements possibly intersecting the line
7160   _ebbTree->getElementsNearLine( line, suspectFaces );
7161   foundElems.assign( suspectFaces.begin(), suspectFaces.end());
7162 }
7163
7164 //=======================================================================
7165 /*!
7166  * \brief Return SMESH_ElementSearcher
7167  */
7168 //=======================================================================
7169
7170 SMESH_ElementSearcher* SMESH_MeshEditor::GetElementSearcher()
7171 {
7172   return new SMESH_ElementSearcherImpl( *GetMeshDS() );
7173 }
7174
7175 //=======================================================================
7176 /*!
7177  * \brief Return SMESH_ElementSearcher acting on a sub-set of elements
7178  */
7179 //=======================================================================
7180
7181 SMESH_ElementSearcher* SMESH_MeshEditor::GetElementSearcher(SMDS_ElemIteratorPtr elemIt)
7182 {
7183   return new SMESH_ElementSearcherImpl( *GetMeshDS(), elemIt );
7184 }
7185
7186 //=======================================================================
7187 /*!
7188  * \brief Return true if the point is IN or ON of the element
7189  */
7190 //=======================================================================
7191
7192 bool SMESH_MeshEditor::IsOut( const SMDS_MeshElement* element, const gp_Pnt& point, double tol )
7193 {
7194   if ( element->GetType() == SMDSAbs_Volume)
7195   {
7196     return SMDS_VolumeTool( element ).IsOut( point.X(), point.Y(), point.Z(), tol );
7197   }
7198
7199   // get ordered nodes
7200
7201   vector< gp_XYZ > xyz;
7202   vector<const SMDS_MeshNode*> nodeList;
7203
7204   SMDS_ElemIteratorPtr nodeIt = element->nodesIterator();
7205   if ( element->IsQuadratic() ) {
7206     if (const SMDS_VtkFace* f=dynamic_cast<const SMDS_VtkFace*>(element))
7207       nodeIt = f->interlacedNodesElemIterator();
7208     else if (const SMDS_VtkEdge*  e =dynamic_cast<const SMDS_VtkEdge*>(element))
7209       nodeIt = e->interlacedNodesElemIterator();
7210   }
7211   while ( nodeIt->more() )
7212     {
7213       const SMDS_MeshNode* node = cast2Node( nodeIt->next() );
7214       xyz.push_back( SMESH_TNodeXYZ(node) );
7215       nodeList.push_back(node);
7216     }
7217
7218   int i, nbNodes = element->NbNodes();
7219
7220   if ( element->GetType() == SMDSAbs_Face ) // --------------------------------------------------
7221   {
7222     // compute face normal
7223     gp_Vec faceNorm(0,0,0);
7224     xyz.push_back( xyz.front() );
7225     nodeList.push_back( nodeList.front() );
7226     for ( i = 0; i < nbNodes; ++i )
7227     {
7228       gp_Vec edge1( xyz[i+1], xyz[i]);
7229       gp_Vec edge2( xyz[i+1], xyz[(i+2)%nbNodes] );
7230       faceNorm += edge1 ^ edge2;
7231     }
7232     double normSize = faceNorm.Magnitude();
7233     if ( normSize <= tol )
7234     {
7235       // degenerated face: point is out if it is out of all face edges
7236       for ( i = 0; i < nbNodes; ++i )
7237       {
7238         SMDS_LinearEdge edge( nodeList[i], nodeList[i+1] );
7239         if ( !IsOut( &edge, point, tol ))
7240           return false;
7241       }
7242       return true;
7243     }
7244     faceNorm /= normSize;
7245
7246     // check if the point lays on face plane
7247     gp_Vec n2p( xyz[0], point );
7248     if ( fabs( n2p * faceNorm ) > tol )
7249       return true; // not on face plane
7250
7251     // check if point is out of face boundary:
7252     // define it by closest transition of a ray point->infinity through face boundary
7253     // on the face plane.
7254     // First, find normal of a plane perpendicular to face plane, to be used as a cutting tool
7255     // to find intersections of the ray with the boundary.
7256     gp_Vec ray = n2p;
7257     gp_Vec plnNorm = ray ^ faceNorm;
7258     normSize = plnNorm.Magnitude();
7259     if ( normSize <= tol ) return false; // point coincides with the first node
7260     plnNorm /= normSize;
7261     // for each node of the face, compute its signed distance to the plane
7262     vector<double> dist( nbNodes + 1);
7263     for ( i = 0; i < nbNodes; ++i )
7264     {
7265       gp_Vec n2p( xyz[i], point );
7266       dist[i] = n2p * plnNorm;
7267     }
7268     dist.back() = dist.front();
7269     // find the closest intersection
7270     int    iClosest = -1;
7271     double rClosest, distClosest = 1e100;;
7272     gp_Pnt pClosest;
7273     for ( i = 0; i < nbNodes; ++i )
7274     {
7275       double r;
7276       if ( fabs( dist[i]) < tol )
7277         r = 0.;
7278       else if ( fabs( dist[i+1]) < tol )
7279         r = 1.;
7280       else if ( dist[i] * dist[i+1] < 0 )
7281         r = dist[i] / ( dist[i] - dist[i+1] );
7282       else
7283         continue; // no intersection
7284       gp_Pnt pInt = xyz[i] * (1.-r) + xyz[i+1] * r;
7285       gp_Vec p2int ( point, pInt);
7286       if ( p2int * ray > -tol ) // right half-space
7287       {
7288         double intDist = p2int.SquareMagnitude();
7289         if ( intDist < distClosest )
7290         {
7291           iClosest = i;
7292           rClosest = r;
7293           pClosest = pInt;
7294           distClosest = intDist;
7295         }
7296       }
7297     }
7298     if ( iClosest < 0 )
7299       return true; // no intesections - out
7300
7301     // analyse transition
7302     gp_Vec edge( xyz[iClosest], xyz[iClosest+1] );
7303     gp_Vec edgeNorm = -( edge ^ faceNorm ); // normal to intersected edge pointing out of face
7304     gp_Vec p2int ( point, pClosest );
7305     bool out = (edgeNorm * p2int) < -tol;
7306     if ( rClosest > 0. && rClosest < 1. ) // not node intersection
7307       return out;
7308
7309     // ray pass through a face node; analyze transition through an adjacent edge
7310     gp_Pnt p1 = xyz[ (rClosest == 0.) ? ((iClosest+nbNodes-1) % nbNodes) : (iClosest+1) ];
7311     gp_Pnt p2 = xyz[ (rClosest == 0.) ? iClosest : ((iClosest+2) % nbNodes) ];
7312     gp_Vec edgeAdjacent( p1, p2 );
7313     gp_Vec edgeNorm2 = -( edgeAdjacent ^ faceNorm );
7314     bool out2 = (edgeNorm2 * p2int) < -tol;
7315
7316     bool covexCorner = ( edgeNorm * edgeAdjacent * (rClosest==1. ? 1. : -1.)) < 0;
7317     return covexCorner ? (out || out2) : (out && out2);
7318   }
7319   if ( element->GetType() == SMDSAbs_Edge ) // --------------------------------------------------
7320   {
7321     // point is out of edge if it is NOT ON any straight part of edge
7322     // (we consider quadratic edge as being composed of two straight parts)
7323     for ( i = 1; i < nbNodes; ++i )
7324     {
7325       gp_Vec edge( xyz[i-1], xyz[i]);
7326       gp_Vec n1p ( xyz[i-1], point);
7327       double dist = ( edge ^ n1p ).Magnitude() / edge.Magnitude();
7328       if ( dist > tol )
7329         continue;
7330       gp_Vec n2p( xyz[i], point );
7331       if ( fabs( edge.Magnitude() - n1p.Magnitude() - n2p.Magnitude()) > tol )
7332         continue;
7333       return false; // point is ON this part
7334     }
7335     return true;
7336   }
7337   // Node or 0D element -------------------------------------------------------------------------
7338   {
7339     gp_Vec n2p ( xyz[0], point );
7340     return n2p.Magnitude() <= tol;
7341   }
7342   return true;
7343 }
7344
7345 //=======================================================================
7346
7347 namespace
7348 {
7349   // Position of a point relative to a segment
7350   //            .           .
7351   //            .  LEFT     .
7352   //            .           .
7353   //  VERTEX 1  o----ON----->  VERTEX 2
7354   //            .           .
7355   //            .  RIGHT    .
7356   //            .           .
7357   enum PositionName { POS_LEFT = 1, POS_VERTEX = 2, POS_RIGHT = 4, //POS_ON = 8,
7358                       POS_ALL = POS_LEFT | POS_RIGHT | POS_VERTEX };
7359   struct PointPos
7360   {
7361     PositionName _name;
7362     int          _index; // index of vertex or segment
7363
7364     PointPos( PositionName n, int i=-1 ): _name(n), _index(i) {}
7365     bool operator < (const PointPos& other ) const
7366     {
7367       if ( _name == other._name )
7368         return  ( _index < 0 || other._index < 0 ) ? false : _index < other._index;
7369       return _name < other._name;
7370     }
7371   };
7372
7373   //================================================================================
7374   /*!
7375    * \brief Return of a point relative to a segment
7376    *  \param point2D      - the point to analyze position of
7377    *  \param xyVec        - end points of segments
7378    *  \param index0       - 0-based index of the first point of segment
7379    *  \param posToFindOut - flags of positions to detect
7380    *  \retval PointPos - point position
7381    */
7382   //================================================================================
7383
7384   PointPos getPointPosition( const gp_XY& point2D,
7385                              const gp_XY* segEnds,
7386                              const int    index0 = 0,
7387                              const int    posToFindOut = POS_ALL)
7388   {
7389     const gp_XY& p1 = segEnds[ index0   ];
7390     const gp_XY& p2 = segEnds[ index0+1 ];
7391     const gp_XY grad = p2 - p1;
7392
7393     if ( posToFindOut & POS_VERTEX )
7394     {
7395       // check if the point2D is at "vertex 1" zone
7396       gp_XY pp1[2] = { p1, gp_XY( p1.X() - grad.Y(),
7397                                   p1.Y() + grad.X() ) };
7398       if ( getPointPosition( point2D, pp1, 0, POS_LEFT|POS_RIGHT )._name == POS_LEFT )
7399         return PointPos( POS_VERTEX, index0 );
7400
7401       // check if the point2D is at "vertex 2" zone
7402       gp_XY pp2[2] = { p2, gp_XY( p2.X() - grad.Y(),
7403                                   p2.Y() + grad.X() ) };
7404       if ( getPointPosition( point2D, pp2, 0, POS_LEFT|POS_RIGHT )._name == POS_RIGHT )
7405         return PointPos( POS_VERTEX, index0 + 1);
7406     }
7407     double edgeEquation =
7408       ( point2D.X() - p1.X() ) * grad.Y() - ( point2D.Y() - p1.Y() ) * grad.X();
7409     return PointPos( edgeEquation < 0 ? POS_LEFT : POS_RIGHT, index0 );
7410   }
7411 }
7412
7413 //=======================================================================
7414 /*!
7415  * \brief Return minimal distance from a point to a face
7416  *
7417  * Currently we ignore non-planarity and 2nd order of face
7418  */
7419 //=======================================================================
7420
7421 double SMESH_MeshEditor::GetDistance( const SMDS_MeshFace* face,
7422                                       const gp_Pnt&        point )
7423 {
7424   double badDistance = -1;
7425   if ( !face ) return badDistance;
7426
7427   // coordinates of nodes (medium nodes, if any, ignored)
7428   typedef SMDS_StdIterator< SMESH_TNodeXYZ, SMDS_ElemIteratorPtr > TXyzIterator;
7429   vector<gp_XYZ> xyz( TXyzIterator( face->nodesIterator()), TXyzIterator() );
7430   xyz.resize( face->NbCornerNodes()+1 );
7431
7432   // transformation to get xyz[0] lies on the origin, xyz[1] lies on the Z axis,
7433   // and xyz[2] lies in the XZ plane. This is to pass to 2D space on XZ plane.
7434   gp_Trsf trsf;
7435   gp_Vec OZ ( xyz[0], xyz[1] );
7436   gp_Vec OX ( xyz[0], xyz[2] );
7437   if ( OZ.Magnitude() < std::numeric_limits<double>::min() )
7438   {
7439     if ( xyz.size() < 4 ) return badDistance;
7440     OZ = gp_Vec ( xyz[0], xyz[2] );
7441     OX = gp_Vec ( xyz[0], xyz[3] );
7442   }
7443   gp_Ax3 tgtCS;
7444   try {
7445     tgtCS = gp_Ax3( xyz[0], OZ, OX );
7446   }
7447   catch ( Standard_Failure ) {
7448     return badDistance;
7449   }
7450   trsf.SetTransformation( tgtCS );
7451
7452   // move all the nodes to 2D
7453   vector<gp_XY> xy( xyz.size() );
7454   for ( size_t i = 0;i < xyz.size()-1; ++i )
7455   {
7456     gp_XYZ p3d = xyz[i];
7457     trsf.Transforms( p3d );
7458     xy[i].SetCoord( p3d.X(), p3d.Z() );
7459   }
7460   xyz.back() = xyz.front();
7461   xy.back() = xy.front();
7462
7463   // // move the point in 2D
7464   gp_XYZ tmpPnt = point.XYZ();
7465   trsf.Transforms( tmpPnt );
7466   gp_XY point2D( tmpPnt.X(), tmpPnt.Z() );
7467
7468   // loop on segments of the face to analyze point position ralative to the face
7469   set< PointPos > pntPosSet;
7470   for ( size_t i = 1; i < xy.size(); ++i )
7471   {
7472     PointPos pos = getPointPosition( point2D, &xy[0], i-1 );
7473     pntPosSet.insert( pos );
7474   }
7475
7476   // compute distance
7477   PointPos pos = *pntPosSet.begin();
7478   // cout << "Face " << face->GetID() << " DIST: ";
7479   switch ( pos._name )
7480   {
7481   case POS_LEFT: {
7482     // point is most close to a segment
7483     gp_Vec p0p1( point, xyz[ pos._index ] );
7484     gp_Vec p1p2( xyz[ pos._index ], xyz[ pos._index+1 ]); // segment vector
7485     p1p2.Normalize();
7486     double projDist = p0p1 * p1p2; // distance projected to the segment
7487     gp_Vec projVec = p1p2 * projDist;
7488     gp_Vec distVec = p0p1 - projVec;
7489     // cout << distVec.Magnitude()  << ", SEG " << face->GetNode(pos._index)->GetID()
7490     //      << " - " << face->GetNodeWrap(pos._index+1)->GetID() << endl;
7491     return distVec.Magnitude();
7492   }
7493   case POS_RIGHT: {
7494     // point is inside the face
7495     double distToFacePlane = tmpPnt.Y();
7496     // cout << distToFacePlane << ", INSIDE " << endl;
7497     return Abs( distToFacePlane );
7498   }
7499   case POS_VERTEX: {
7500     // point is most close to a node
7501     gp_Vec distVec( point, xyz[ pos._index ]);
7502     // cout << distVec.Magnitude()  << " VERTEX " << face->GetNode(pos._index)->GetID() << endl;
7503     return distVec.Magnitude();
7504   }
7505   }
7506   return badDistance;
7507 }
7508
7509 //=======================================================================
7510 //function : SimplifyFace
7511 //purpose  :
7512 //=======================================================================
7513 int SMESH_MeshEditor::SimplifyFace (const vector<const SMDS_MeshNode *> faceNodes,
7514                                     vector<const SMDS_MeshNode *>&      poly_nodes,
7515                                     vector<int>&                        quantities) const
7516 {
7517   int nbNodes = faceNodes.size();
7518
7519   if (nbNodes < 3)
7520     return 0;
7521
7522   set<const SMDS_MeshNode*> nodeSet;
7523
7524   // get simple seq of nodes
7525   //const SMDS_MeshNode* simpleNodes[ nbNodes ];
7526   vector<const SMDS_MeshNode*> simpleNodes( nbNodes );
7527   int iSimple = 0, nbUnique = 0;
7528
7529   simpleNodes[iSimple++] = faceNodes[0];
7530   nbUnique++;
7531   for (int iCur = 1; iCur < nbNodes; iCur++) {
7532     if (faceNodes[iCur] != simpleNodes[iSimple - 1]) {
7533       simpleNodes[iSimple++] = faceNodes[iCur];
7534       if (nodeSet.insert( faceNodes[iCur] ).second)
7535         nbUnique++;
7536     }
7537   }
7538   int nbSimple = iSimple;
7539   if (simpleNodes[nbSimple - 1] == simpleNodes[0]) {
7540     nbSimple--;
7541     iSimple--;
7542   }
7543
7544   if (nbUnique < 3)
7545     return 0;
7546
7547   // separate loops
7548   int nbNew = 0;
7549   bool foundLoop = (nbSimple > nbUnique);
7550   while (foundLoop) {
7551     foundLoop = false;
7552     set<const SMDS_MeshNode*> loopSet;
7553     for (iSimple = 0; iSimple < nbSimple && !foundLoop; iSimple++) {
7554       const SMDS_MeshNode* n = simpleNodes[iSimple];
7555       if (!loopSet.insert( n ).second) {
7556         foundLoop = true;
7557
7558         // separate loop
7559         int iC = 0, curLast = iSimple;
7560         for (; iC < curLast; iC++) {
7561           if (simpleNodes[iC] == n) break;
7562         }
7563         int loopLen = curLast - iC;
7564         if (loopLen > 2) {
7565           // create sub-element
7566           nbNew++;
7567           quantities.push_back(loopLen);
7568           for (; iC < curLast; iC++) {
7569             poly_nodes.push_back(simpleNodes[iC]);
7570           }
7571         }
7572         // shift the rest nodes (place from the first loop position)
7573         for (iC = curLast + 1; iC < nbSimple; iC++) {
7574           simpleNodes[iC - loopLen] = simpleNodes[iC];
7575         }
7576         nbSimple -= loopLen;
7577         iSimple -= loopLen;
7578       }
7579     } // for (iSimple = 0; iSimple < nbSimple; iSimple++)
7580   } // while (foundLoop)
7581
7582   if (iSimple > 2) {
7583     nbNew++;
7584     quantities.push_back(iSimple);
7585     for (int i = 0; i < iSimple; i++)
7586       poly_nodes.push_back(simpleNodes[i]);
7587   }
7588
7589   return nbNew;
7590 }
7591
7592 //=======================================================================
7593 //function : MergeNodes
7594 //purpose  : In each group, the cdr of nodes are substituted by the first one
7595 //           in all elements.
7596 //=======================================================================
7597
7598 void SMESH_MeshEditor::MergeNodes (TListOfListOfNodes & theGroupsOfNodes)
7599 {
7600   MESSAGE("MergeNodes");
7601   myLastCreatedElems.Clear();
7602   myLastCreatedNodes.Clear();
7603
7604   SMESHDS_Mesh* aMesh = GetMeshDS();
7605
7606   TNodeNodeMap nodeNodeMap; // node to replace - new node
7607   set<const SMDS_MeshElement*> elems; // all elements with changed nodes
7608   list< int > rmElemIds, rmNodeIds;
7609
7610   // Fill nodeNodeMap and elems
7611
7612   TListOfListOfNodes::iterator grIt = theGroupsOfNodes.begin();
7613   for ( ; grIt != theGroupsOfNodes.end(); grIt++ ) {
7614     list<const SMDS_MeshNode*>& nodes = *grIt;
7615     list<const SMDS_MeshNode*>::iterator nIt = nodes.begin();
7616     const SMDS_MeshNode* nToKeep = *nIt;
7617     //MESSAGE("node to keep " << nToKeep->GetID());
7618     for ( ++nIt; nIt != nodes.end(); nIt++ ) {
7619       const SMDS_MeshNode* nToRemove = *nIt;
7620       nodeNodeMap.insert( TNodeNodeMap::value_type( nToRemove, nToKeep ));
7621       if ( nToRemove != nToKeep ) {
7622         //MESSAGE("  node to remove " << nToRemove->GetID());
7623         rmNodeIds.push_back( nToRemove->GetID() );
7624         AddToSameGroups( nToKeep, nToRemove, aMesh );
7625       }
7626
7627       SMDS_ElemIteratorPtr invElemIt = nToRemove->GetInverseElementIterator();
7628       while ( invElemIt->more() ) {
7629         const SMDS_MeshElement* elem = invElemIt->next();
7630         elems.insert(elem);
7631       }
7632     }
7633   }
7634   // Change element nodes or remove an element
7635
7636   set<const SMDS_MeshElement*>::iterator eIt = elems.begin();
7637   for ( ; eIt != elems.end(); eIt++ ) {
7638     const SMDS_MeshElement* elem = *eIt;
7639     //MESSAGE(" ---- inverse elem on node to remove " << elem->GetID());
7640     int nbNodes = elem->NbNodes();
7641     int aShapeId = FindShape( elem );
7642
7643     set<const SMDS_MeshNode*> nodeSet;
7644     vector< const SMDS_MeshNode*> curNodes( nbNodes ), uniqueNodes( nbNodes );
7645     int iUnique = 0, iCur = 0, nbRepl = 0;
7646     vector<int> iRepl( nbNodes );
7647
7648     // get new seq of nodes
7649     SMDS_ElemIteratorPtr itN = elem->nodesIterator();
7650     while ( itN->more() ) {
7651       const SMDS_MeshNode* n =
7652         static_cast<const SMDS_MeshNode*>( itN->next() );
7653
7654       TNodeNodeMap::iterator nnIt = nodeNodeMap.find( n );
7655       if ( nnIt != nodeNodeMap.end() ) { // n sticks
7656         n = (*nnIt).second;
7657         // BUG 0020185: begin
7658         {
7659           bool stopRecur = false;
7660           set<const SMDS_MeshNode*> nodesRecur;
7661           nodesRecur.insert(n);
7662           while (!stopRecur) {
7663             TNodeNodeMap::iterator nnIt_i = nodeNodeMap.find( n );
7664             if ( nnIt_i != nodeNodeMap.end() ) { // n sticks
7665               n = (*nnIt_i).second;
7666               if (!nodesRecur.insert(n).second) {
7667                 // error: recursive dependancy
7668                 stopRecur = true;
7669               }
7670             }
7671             else
7672               stopRecur = true;
7673           }
7674         }
7675         // BUG 0020185: end
7676       }
7677       curNodes[ iCur ] = n;
7678       bool isUnique = nodeSet.insert( n ).second;
7679       if ( isUnique )
7680         uniqueNodes[ iUnique++ ] = n;
7681       else
7682         iRepl[ nbRepl++ ] = iCur;
7683       iCur++;
7684     }
7685
7686     // Analyse element topology after replacement
7687
7688     bool isOk = true;
7689     int nbUniqueNodes = nodeSet.size();
7690     //MESSAGE("nbNodes nbUniqueNodes " << nbNodes << " " << nbUniqueNodes);
7691     if ( nbNodes != nbUniqueNodes ) { // some nodes stick
7692       // Polygons and Polyhedral volumes
7693       if (elem->IsPoly()) {
7694
7695         if (elem->GetType() == SMDSAbs_Face) {
7696           // Polygon
7697           vector<const SMDS_MeshNode *> face_nodes (nbNodes);
7698           int inode = 0;
7699           for (; inode < nbNodes; inode++) {
7700             face_nodes[inode] = curNodes[inode];
7701           }
7702
7703           vector<const SMDS_MeshNode *> polygons_nodes;
7704           vector<int> quantities;
7705           int nbNew = SimplifyFace(face_nodes, polygons_nodes, quantities);
7706           if (nbNew > 0) {
7707             inode = 0;
7708             for (int iface = 0; iface < nbNew; iface++) {
7709               int nbNodes = quantities[iface];
7710               vector<const SMDS_MeshNode *> poly_nodes (nbNodes);
7711               for (int ii = 0; ii < nbNodes; ii++, inode++) {
7712                 poly_nodes[ii] = polygons_nodes[inode];
7713               }
7714               SMDS_MeshElement* newElem = aMesh->AddPolygonalFace(poly_nodes);
7715               myLastCreatedElems.Append(newElem);
7716               if (aShapeId)
7717                 aMesh->SetMeshElementOnShape(newElem, aShapeId);
7718             }
7719
7720             MESSAGE("ChangeElementNodes MergeNodes Polygon");
7721             //aMesh->ChangeElementNodes(elem, &polygons_nodes[inode], quantities[nbNew - 1]);
7722             vector<const SMDS_MeshNode *> polynodes(polygons_nodes.begin()+inode,polygons_nodes.end());
7723             int quid =0;
7724             if (nbNew > 0) quid = nbNew - 1;
7725             vector<int> newquant(quantities.begin()+quid, quantities.end());
7726             const SMDS_MeshElement* newElem = 0;
7727             newElem = aMesh->AddPolyhedralVolume(polynodes, newquant);
7728             myLastCreatedElems.Append(newElem);
7729             if ( aShapeId && newElem )
7730               aMesh->SetMeshElementOnShape( newElem, aShapeId );
7731             rmElemIds.push_back(elem->GetID());
7732           }
7733           else {
7734             rmElemIds.push_back(elem->GetID());
7735           }
7736
7737         }
7738         else if (elem->GetType() == SMDSAbs_Volume) {
7739           // Polyhedral volume
7740           if (nbUniqueNodes < 4) {
7741             rmElemIds.push_back(elem->GetID());
7742           }
7743           else {
7744             // each face has to be analyzed in order to check volume validity
7745             const SMDS_VtkVolume* aPolyedre =
7746               dynamic_cast<const SMDS_VtkVolume*>( elem );
7747             if (aPolyedre) {
7748               int nbFaces = aPolyedre->NbFaces();
7749
7750               vector<const SMDS_MeshNode *> poly_nodes;
7751               vector<int> quantities;
7752
7753               for (int iface = 1; iface <= nbFaces; iface++) {
7754                 int nbFaceNodes = aPolyedre->NbFaceNodes(iface);
7755                 vector<const SMDS_MeshNode *> faceNodes (nbFaceNodes);
7756
7757                 for (int inode = 1; inode <= nbFaceNodes; inode++) {
7758                   const SMDS_MeshNode * faceNode = aPolyedre->GetFaceNode(iface, inode);
7759                   TNodeNodeMap::iterator nnIt = nodeNodeMap.find(faceNode);
7760                   if (nnIt != nodeNodeMap.end()) { // faceNode sticks
7761                     faceNode = (*nnIt).second;
7762                   }
7763                   faceNodes[inode - 1] = faceNode;
7764                 }
7765
7766                 SimplifyFace(faceNodes, poly_nodes, quantities);
7767               }
7768
7769               if (quantities.size() > 3) {
7770                 // to be done: remove coincident faces
7771               }
7772
7773               if (quantities.size() > 3)
7774                 {
7775                   MESSAGE("ChangeElementNodes MergeNodes Polyhedron");
7776                   //aMesh->ChangePolyhedronNodes(elem, poly_nodes, quantities);
7777                   const SMDS_MeshElement* newElem = 0;
7778                   newElem = aMesh->AddPolyhedralVolume(poly_nodes, quantities);
7779                   myLastCreatedElems.Append(newElem);
7780                   if ( aShapeId && newElem )
7781                     aMesh->SetMeshElementOnShape( newElem, aShapeId );
7782                   rmElemIds.push_back(elem->GetID());
7783                 }
7784             }
7785             else {
7786               rmElemIds.push_back(elem->GetID());
7787             }
7788           }
7789         }
7790         else {
7791         }
7792
7793         continue;
7794       } // poly element
7795
7796       // Regular elements
7797       // TODO not all the possible cases are solved. Find something more generic?
7798       switch ( nbNodes ) {
7799       case 2: ///////////////////////////////////// EDGE
7800         isOk = false; break;
7801       case 3: ///////////////////////////////////// TRIANGLE
7802         isOk = false; break;
7803       case 4:
7804         if ( elem->GetType() == SMDSAbs_Volume ) // TETRAHEDRON
7805           isOk = false;
7806         else { //////////////////////////////////// QUADRANGLE
7807           if ( nbUniqueNodes < 3 )
7808             isOk = false;
7809           else if ( nbRepl == 2 && iRepl[ 1 ] - iRepl[ 0 ] == 2 )
7810             isOk = false; // opposite nodes stick
7811           //MESSAGE("isOk " << isOk);
7812         }
7813         break;
7814       case 6: ///////////////////////////////////// PENTAHEDRON
7815         if ( nbUniqueNodes == 4 ) {
7816           // ---------------------------------> tetrahedron
7817           if (nbRepl == 3 &&
7818               iRepl[ 0 ] > 2 && iRepl[ 1 ] > 2 && iRepl[ 2 ] > 2 ) {
7819             // all top nodes stick: reverse a bottom
7820             uniqueNodes[ 0 ] = curNodes [ 1 ];
7821             uniqueNodes[ 1 ] = curNodes [ 0 ];
7822           }
7823           else if (nbRepl == 3 &&
7824                    iRepl[ 0 ] < 3 && iRepl[ 1 ] < 3 && iRepl[ 2 ] < 3 ) {
7825             // all bottom nodes stick: set a top before
7826             uniqueNodes[ 3 ] = uniqueNodes [ 0 ];
7827             uniqueNodes[ 0 ] = curNodes [ 3 ];
7828             uniqueNodes[ 1 ] = curNodes [ 4 ];
7829             uniqueNodes[ 2 ] = curNodes [ 5 ];
7830           }
7831           else if (nbRepl == 4 &&
7832                    iRepl[ 2 ] - iRepl [ 0 ] == 3 && iRepl[ 3 ] - iRepl [ 1 ] == 3 ) {
7833             // a lateral face turns into a line: reverse a bottom
7834             uniqueNodes[ 0 ] = curNodes [ 1 ];
7835             uniqueNodes[ 1 ] = curNodes [ 0 ];
7836           }
7837           else
7838             isOk = false;
7839         }
7840         else if ( nbUniqueNodes == 5 ) {
7841           // PENTAHEDRON --------------------> 2 tetrahedrons
7842           if ( nbRepl == 2 && iRepl[ 1 ] - iRepl [ 0 ] == 3 ) {
7843             // a bottom node sticks with a linked top one
7844             // 1.
7845             SMDS_MeshElement* newElem =
7846               aMesh->AddVolume(curNodes[ 3 ],
7847                                curNodes[ 4 ],
7848                                curNodes[ 5 ],
7849                                curNodes[ iRepl[ 0 ] == 2 ? 1 : 2 ]);
7850             myLastCreatedElems.Append(newElem);
7851             if ( aShapeId )
7852               aMesh->SetMeshElementOnShape( newElem, aShapeId );
7853             // 2. : reverse a bottom
7854             uniqueNodes[ 0 ] = curNodes [ 1 ];
7855             uniqueNodes[ 1 ] = curNodes [ 0 ];
7856             nbUniqueNodes = 4;
7857           }
7858           else
7859             isOk = false;
7860         }
7861         else
7862           isOk = false;
7863         break;
7864       case 8: {
7865         if(elem->IsQuadratic()) { // Quadratic quadrangle
7866           //   1    5    2
7867           //    +---+---+
7868           //    |       |
7869           //    |       |
7870           //   4+       +6
7871           //    |       |
7872           //    |       |
7873           //    +---+---+
7874           //   0    7    3
7875           isOk = false;
7876           if(nbRepl==2) {
7877             MESSAGE("nbRepl=2: " << iRepl[0] << " " << iRepl[1]);
7878           }
7879           if(nbRepl==3) {
7880             MESSAGE("nbRepl=3: " << iRepl[0] << " " << iRepl[1]  << " " << iRepl[2]);
7881             nbUniqueNodes = 6;
7882             if( iRepl[0]==0 && iRepl[1]==1 && iRepl[2]==4 ) {
7883               uniqueNodes[0] = curNodes[0];
7884               uniqueNodes[1] = curNodes[2];
7885               uniqueNodes[2] = curNodes[3];
7886               uniqueNodes[3] = curNodes[5];
7887               uniqueNodes[4] = curNodes[6];
7888               uniqueNodes[5] = curNodes[7];
7889               isOk = true;
7890             }
7891             if( iRepl[0]==0 && iRepl[1]==3 && iRepl[2]==7 ) {
7892               uniqueNodes[0] = curNodes[0];
7893               uniqueNodes[1] = curNodes[1];
7894               uniqueNodes[2] = curNodes[2];
7895               uniqueNodes[3] = curNodes[4];
7896               uniqueNodes[4] = curNodes[5];
7897               uniqueNodes[5] = curNodes[6];
7898               isOk = true;
7899             }
7900             if( iRepl[0]==0 && iRepl[1]==4 && iRepl[2]==7 ) {
7901               uniqueNodes[0] = curNodes[1];
7902               uniqueNodes[1] = curNodes[2];
7903               uniqueNodes[2] = curNodes[3];
7904               uniqueNodes[3] = curNodes[5];
7905               uniqueNodes[4] = curNodes[6];
7906               uniqueNodes[5] = curNodes[0];
7907               isOk = true;
7908             }
7909             if( iRepl[0]==1 && iRepl[1]==2 && iRepl[2]==5 ) {
7910               uniqueNodes[0] = curNodes[0];
7911               uniqueNodes[1] = curNodes[1];
7912               uniqueNodes[2] = curNodes[3];
7913               uniqueNodes[3] = curNodes[4];
7914               uniqueNodes[4] = curNodes[6];
7915               uniqueNodes[5] = curNodes[7];
7916               isOk = true;
7917             }
7918             if( iRepl[0]==1 && iRepl[1]==4 && iRepl[2]==5 ) {
7919               uniqueNodes[0] = curNodes[0];
7920               uniqueNodes[1] = curNodes[2];
7921               uniqueNodes[2] = curNodes[3];
7922               uniqueNodes[3] = curNodes[1];
7923               uniqueNodes[4] = curNodes[6];
7924               uniqueNodes[5] = curNodes[7];
7925               isOk = true;
7926             }
7927             if( iRepl[0]==2 && iRepl[1]==3 && iRepl[2]==6 ) {
7928               uniqueNodes[0] = curNodes[0];
7929               uniqueNodes[1] = curNodes[1];
7930               uniqueNodes[2] = curNodes[2];
7931               uniqueNodes[3] = curNodes[4];
7932               uniqueNodes[4] = curNodes[5];
7933               uniqueNodes[5] = curNodes[7];
7934               isOk = true;
7935             }
7936             if( iRepl[0]==2 && iRepl[1]==5 && iRepl[2]==6 ) {
7937               uniqueNodes[0] = curNodes[0];
7938               uniqueNodes[1] = curNodes[1];
7939               uniqueNodes[2] = curNodes[3];
7940               uniqueNodes[3] = curNodes[4];
7941               uniqueNodes[4] = curNodes[2];
7942               uniqueNodes[5] = curNodes[7];
7943               isOk = true;
7944             }
7945             if( iRepl[0]==3 && iRepl[1]==6 && iRepl[2]==7 ) {
7946               uniqueNodes[0] = curNodes[0];
7947               uniqueNodes[1] = curNodes[1];
7948               uniqueNodes[2] = curNodes[2];
7949               uniqueNodes[3] = curNodes[4];
7950               uniqueNodes[4] = curNodes[5];
7951               uniqueNodes[5] = curNodes[3];
7952               isOk = true;
7953             }
7954           }
7955           if(nbRepl==4) {
7956             MESSAGE("nbRepl=4: " << iRepl[0] << " " << iRepl[1]  << " " << iRepl[2] << " " << iRepl[3]);
7957           }
7958           if(nbRepl==5) {
7959             MESSAGE("nbRepl=5: " << iRepl[0] << " " << iRepl[1]  << " " << iRepl[2] << " " << iRepl[3] << " " << iRepl[4]);
7960           }
7961           break;
7962         }
7963         //////////////////////////////////// HEXAHEDRON
7964         isOk = false;
7965         SMDS_VolumeTool hexa (elem);
7966         hexa.SetExternalNormal();
7967         if ( nbUniqueNodes == 4 && nbRepl == 4 ) {
7968           //////////////////////// HEX ---> 1 tetrahedron
7969           for ( int iFace = 0; iFace < 6; iFace++ ) {
7970             const int *ind = hexa.GetFaceNodesIndices( iFace ); // indices of face nodes
7971             if (curNodes[ind[ 0 ]] == curNodes[ind[ 1 ]] &&
7972                 curNodes[ind[ 0 ]] == curNodes[ind[ 2 ]] &&
7973                 curNodes[ind[ 0 ]] == curNodes[ind[ 3 ]] ) {
7974               // one face turns into a point ...
7975               int iOppFace = hexa.GetOppFaceIndex( iFace );
7976               ind = hexa.GetFaceNodesIndices( iOppFace );
7977               int nbStick = 0;
7978               for ( iCur = 0; iCur < 4 && nbStick < 2; iCur++ ) {
7979                 if ( curNodes[ind[ iCur ]] == curNodes[ind[ iCur + 1 ]] )
7980                   nbStick++;
7981               }
7982               if ( nbStick == 1 ) {
7983                 // ... and the opposite one - into a triangle.
7984                 // set a top node
7985                 ind = hexa.GetFaceNodesIndices( iFace );
7986                 uniqueNodes[ 3 ] = curNodes[ind[ 0 ]];
7987                 isOk = true;
7988               }
7989               break;
7990             }
7991           }
7992         }
7993         else if ( nbUniqueNodes == 6 && nbRepl == 2 ) {
7994           //////////////////////// HEX ---> 1 prism
7995           int nbTria = 0, iTria[3];
7996           const int *ind; // indices of face nodes
7997           // look for triangular faces
7998           for ( int iFace = 0; iFace < 6 && nbTria < 3; iFace++ ) {
7999             ind = hexa.GetFaceNodesIndices( iFace );
8000             TIDSortedNodeSet faceNodes;
8001             for ( iCur = 0; iCur < 4; iCur++ )
8002               faceNodes.insert( curNodes[ind[iCur]] );
8003             if ( faceNodes.size() == 3 )
8004               iTria[ nbTria++ ] = iFace;
8005           }
8006           // check if triangles are opposite
8007           if ( nbTria == 2 && iTria[0] == hexa.GetOppFaceIndex( iTria[1] ))
8008           {
8009             isOk = true;
8010             // set nodes of the bottom triangle
8011             ind = hexa.GetFaceNodesIndices( iTria[ 0 ]);
8012             vector<int> indB;
8013             for ( iCur = 0; iCur < 4; iCur++ )
8014               if ( ind[iCur] != iRepl[0] && ind[iCur] != iRepl[1])
8015                 indB.push_back( ind[iCur] );
8016             if ( !hexa.IsForward() )
8017               std::swap( indB[0], indB[2] );
8018             for ( iCur = 0; iCur < 3; iCur++ )
8019               uniqueNodes[ iCur ] = curNodes[indB[iCur]];
8020             // set nodes of the top triangle
8021             const int *indT = hexa.GetFaceNodesIndices( iTria[ 1 ]);
8022             for ( iCur = 0; iCur < 3; ++iCur )
8023               for ( int j = 0; j < 4; ++j )
8024                 if ( hexa.IsLinked( indB[ iCur ], indT[ j ] ))
8025                 {
8026                   uniqueNodes[ iCur + 3 ] = curNodes[ indT[ j ]];
8027                   break;
8028                 }
8029           }
8030           break;
8031         }
8032         else if (nbUniqueNodes == 5 && nbRepl == 4 ) {
8033           //////////////////// HEXAHEDRON ---> 2 tetrahedrons
8034           for ( int iFace = 0; iFace < 6; iFace++ ) {
8035             const int *ind = hexa.GetFaceNodesIndices( iFace ); // indices of face nodes
8036             if (curNodes[ind[ 0 ]] == curNodes[ind[ 1 ]] &&
8037                 curNodes[ind[ 0 ]] == curNodes[ind[ 2 ]] &&
8038                 curNodes[ind[ 0 ]] == curNodes[ind[ 3 ]] ) {
8039               // one face turns into a point ...
8040               int iOppFace = hexa.GetOppFaceIndex( iFace );
8041               ind = hexa.GetFaceNodesIndices( iOppFace );
8042               int nbStick = 0;
8043               iUnique = 2;  // reverse a tetrahedron 1 bottom
8044               for ( iCur = 0; iCur < 4 && nbStick == 0; iCur++ ) {
8045                 if ( curNodes[ind[ iCur ]] == curNodes[ind[ iCur + 1 ]] )
8046                   nbStick++;
8047                 else if ( iUnique >= 0 )
8048                   uniqueNodes[ iUnique-- ] = curNodes[ind[ iCur ]];
8049               }
8050               if ( nbStick == 0 ) {
8051                 // ... and the opposite one is a quadrangle
8052                 // set a top node
8053                 const int* indTop = hexa.GetFaceNodesIndices( iFace );
8054                 uniqueNodes[ 3 ] = curNodes[indTop[ 0 ]];
8055                 nbUniqueNodes = 4;
8056                 // tetrahedron 2
8057                 SMDS_MeshElement* newElem =
8058                   aMesh->AddVolume(curNodes[ind[ 0 ]],
8059                                    curNodes[ind[ 3 ]],
8060                                    curNodes[ind[ 2 ]],
8061                                    curNodes[indTop[ 0 ]]);
8062                 myLastCreatedElems.Append(newElem);
8063                 if ( aShapeId )
8064                   aMesh->SetMeshElementOnShape( newElem, aShapeId );
8065                 isOk = true;
8066               }
8067               break;
8068             }
8069           }
8070         }
8071         else if ( nbUniqueNodes == 6 && nbRepl == 4 ) {
8072           ////////////////// HEXAHEDRON ---> 2 tetrahedrons or 1 prism
8073           // find indices of quad and tri faces
8074           int iQuadFace[ 6 ], iTriFace[ 6 ], nbQuad = 0, nbTri = 0, iFace;
8075           for ( iFace = 0; iFace < 6; iFace++ ) {
8076             const int *ind = hexa.GetFaceNodesIndices( iFace ); // indices of face nodes
8077             nodeSet.clear();
8078             for ( iCur = 0; iCur < 4; iCur++ )
8079               nodeSet.insert( curNodes[ind[ iCur ]] );
8080             nbUniqueNodes = nodeSet.size();
8081             if ( nbUniqueNodes == 3 )
8082               iTriFace[ nbTri++ ] = iFace;
8083             else if ( nbUniqueNodes == 4 )
8084               iQuadFace[ nbQuad++ ] = iFace;
8085           }
8086           if (nbQuad == 2 && nbTri == 4 &&
8087               hexa.GetOppFaceIndex( iQuadFace[ 0 ] ) == iQuadFace[ 1 ]) {
8088             // 2 opposite quadrangles stuck with a diagonal;
8089             // sample groups of merged indices: (0-4)(2-6)
8090             // --------------------------------------------> 2 tetrahedrons
8091             const int *ind1 = hexa.GetFaceNodesIndices( iQuadFace[ 0 ]); // indices of quad1 nodes
8092             const int *ind2 = hexa.GetFaceNodesIndices( iQuadFace[ 1 ]);
8093             int i0, i1d, i2, i3d, i0t, i2t; // d-daigonal, t-top
8094             if (curNodes[ind1[ 0 ]] == curNodes[ind2[ 0 ]] &&
8095                 curNodes[ind1[ 2 ]] == curNodes[ind2[ 2 ]]) {
8096               // stuck with 0-2 diagonal
8097               i0  = ind1[ 3 ];
8098               i1d = ind1[ 0 ];
8099               i2  = ind1[ 1 ];
8100               i3d = ind1[ 2 ];
8101               i0t = ind2[ 1 ];
8102               i2t = ind2[ 3 ];
8103             }
8104             else if (curNodes[ind1[ 1 ]] == curNodes[ind2[ 3 ]] &&
8105                      curNodes[ind1[ 3 ]] == curNodes[ind2[ 1 ]]) {
8106               // stuck with 1-3 diagonal
8107               i0  = ind1[ 0 ];
8108               i1d = ind1[ 1 ];
8109               i2  = ind1[ 2 ];
8110               i3d = ind1[ 3 ];
8111               i0t = ind2[ 0 ];
8112               i2t = ind2[ 1 ];
8113             }
8114             else {
8115               ASSERT(0);
8116             }
8117             // tetrahedron 1
8118             uniqueNodes[ 0 ] = curNodes [ i0 ];
8119             uniqueNodes[ 1 ] = curNodes [ i1d ];
8120             uniqueNodes[ 2 ] = curNodes [ i3d ];
8121             uniqueNodes[ 3 ] = curNodes [ i0t ];
8122             nbUniqueNodes = 4;
8123             // tetrahedron 2
8124             SMDS_MeshElement* newElem = aMesh->AddVolume(curNodes[ i1d ],
8125                                                          curNodes[ i2 ],
8126                                                          curNodes[ i3d ],
8127                                                          curNodes[ i2t ]);
8128             myLastCreatedElems.Append(newElem);
8129             if ( aShapeId )
8130               aMesh->SetMeshElementOnShape( newElem, aShapeId );
8131             isOk = true;
8132           }
8133           else if (( nbTri == 2 && nbQuad == 3 ) || // merged (0-4)(1-5)
8134                    ( nbTri == 4 && nbQuad == 2 )) { // merged (7-4)(1-5)
8135             // --------------------------------------------> prism
8136             // find 2 opposite triangles
8137             nbUniqueNodes = 6;
8138             for ( iFace = 0; iFace + 1 < nbTri; iFace++ ) {
8139               if ( hexa.GetOppFaceIndex( iTriFace[ iFace ] ) == iTriFace[ iFace + 1 ]) {
8140                 // find indices of kept and replaced nodes
8141                 // and fill unique nodes of 2 opposite triangles
8142                 const int *ind1 = hexa.GetFaceNodesIndices( iTriFace[ iFace ]);
8143                 const int *ind2 = hexa.GetFaceNodesIndices( iTriFace[ iFace + 1 ]);
8144                 const SMDS_MeshNode** hexanodes = hexa.GetNodes();
8145                 // fill unique nodes
8146                 iUnique = 0;
8147                 isOk = true;
8148                 for ( iCur = 0; iCur < 4 && isOk; iCur++ ) {
8149                   const SMDS_MeshNode* n     = curNodes[ind1[ iCur ]];
8150                   const SMDS_MeshNode* nInit = hexanodes[ind1[ iCur ]];
8151                   if ( n == nInit ) {
8152                     // iCur of a linked node of the opposite face (make normals co-directed):
8153                     int iCurOpp = ( iCur == 1 || iCur == 3 ) ? 4 - iCur : iCur;
8154                     // check that correspondent corners of triangles are linked
8155                     if ( !hexa.IsLinked( ind1[ iCur ], ind2[ iCurOpp ] ))
8156                       isOk = false;
8157                     else {
8158                       uniqueNodes[ iUnique ] = n;
8159                       uniqueNodes[ iUnique + 3 ] = curNodes[ind2[ iCurOpp ]];
8160                       iUnique++;
8161                     }
8162                   }
8163                 }
8164                 break;
8165               }
8166             }
8167           }
8168         } // if ( nbUniqueNodes == 6 && nbRepl == 4 )
8169         else
8170         {
8171           MESSAGE("MergeNodes() removes hexahedron "<< elem);
8172         }
8173         break;
8174       } // HEXAHEDRON
8175
8176       default:
8177         isOk = false;
8178       } // switch ( nbNodes )
8179
8180     } // if ( nbNodes != nbUniqueNodes ) // some nodes stick
8181
8182     if ( isOk ) { // the elem remains valid after sticking nodes
8183       if (elem->IsPoly() && elem->GetType() == SMDSAbs_Volume)
8184       {
8185         // Change nodes of polyedre
8186         const SMDS_VtkVolume* aPolyedre =
8187           dynamic_cast<const SMDS_VtkVolume*>( elem );
8188         if (aPolyedre) {
8189           int nbFaces = aPolyedre->NbFaces();
8190
8191           vector<const SMDS_MeshNode *> poly_nodes;
8192           vector<int> quantities (nbFaces);
8193
8194           for (int iface = 1; iface <= nbFaces; iface++) {
8195             int inode, nbFaceNodes = aPolyedre->NbFaceNodes(iface);
8196             quantities[iface - 1] = nbFaceNodes;
8197
8198             for (inode = 1; inode <= nbFaceNodes; inode++) {
8199               const SMDS_MeshNode* curNode = aPolyedre->GetFaceNode(iface, inode);
8200
8201               TNodeNodeMap::iterator nnIt = nodeNodeMap.find( curNode );
8202               if (nnIt != nodeNodeMap.end()) { // curNode sticks
8203                 curNode = (*nnIt).second;
8204               }
8205               poly_nodes.push_back(curNode);
8206             }
8207           }
8208           aMesh->ChangePolyhedronNodes( elem, poly_nodes, quantities );
8209         }
8210       }
8211       else // replace non-polyhedron elements
8212       {
8213         const SMDSAbs_ElementType etyp = elem->GetType();
8214         const int elemId               = elem->GetID();
8215         const bool isPoly              = (elem->GetEntityType() == SMDSEntity_Polygon);
8216         uniqueNodes.resize(nbUniqueNodes);
8217
8218         SMESHDS_SubMesh * sm = aShapeId > 0 ? aMesh->MeshElements(aShapeId) : 0;
8219
8220         aMesh->RemoveFreeElement(elem, sm, /*fromGroups=*/false);
8221         SMDS_MeshElement* newElem = this->AddElement(uniqueNodes, etyp, isPoly, elemId);
8222         if ( sm && newElem )
8223           sm->AddElement( newElem );
8224         if ( elem != newElem )
8225           ReplaceElemInGroups( elem, newElem, aMesh );
8226       }
8227     }
8228     else {
8229       // Remove invalid regular element or invalid polygon
8230       rmElemIds.push_back( elem->GetID() );
8231     }
8232
8233   } // loop on elements
8234
8235   // Remove bad elements, then equal nodes (order important)
8236
8237   Remove( rmElemIds, false );
8238   Remove( rmNodeIds, true );
8239
8240 }
8241
8242
8243 // ========================================================
8244 // class   : SortableElement
8245 // purpose : allow sorting elements basing on their nodes
8246 // ========================================================
8247 class SortableElement : public set <const SMDS_MeshElement*>
8248 {
8249 public:
8250
8251   SortableElement( const SMDS_MeshElement* theElem )
8252   {
8253     myElem = theElem;
8254     SMDS_ElemIteratorPtr nodeIt = theElem->nodesIterator();
8255     while ( nodeIt->more() )
8256       this->insert( nodeIt->next() );
8257   }
8258
8259   const SMDS_MeshElement* Get() const
8260   { return myElem; }
8261
8262   void Set(const SMDS_MeshElement* e) const
8263   { myElem = e; }
8264
8265
8266 private:
8267   mutable const SMDS_MeshElement* myElem;
8268 };
8269
8270 //=======================================================================
8271 //function : FindEqualElements
8272 //purpose  : Return list of group of elements built on the same nodes.
8273 //           Search among theElements or in the whole mesh if theElements is empty
8274 //=======================================================================
8275
8276 void SMESH_MeshEditor::FindEqualElements(TIDSortedElemSet &        theElements,
8277                                          TListOfListOfElementsID & theGroupsOfElementsID)
8278 {
8279   myLastCreatedElems.Clear();
8280   myLastCreatedNodes.Clear();
8281
8282   typedef map< SortableElement, int > TMapOfNodeSet;
8283   typedef list<int> TGroupOfElems;
8284
8285   if ( theElements.empty() )
8286   { // get all elements in the mesh
8287     SMDS_ElemIteratorPtr eIt = GetMeshDS()->elementsIterator();
8288     while ( eIt->more() )
8289       theElements.insert( theElements.end(), eIt->next());
8290   }
8291
8292   vector< TGroupOfElems > arrayOfGroups;
8293   TGroupOfElems groupOfElems;
8294   TMapOfNodeSet mapOfNodeSet;
8295
8296   TIDSortedElemSet::iterator elemIt = theElements.begin();
8297   for ( int i = 0, j=0; elemIt != theElements.end(); ++elemIt, ++j ) {
8298     const SMDS_MeshElement* curElem = *elemIt;
8299     SortableElement SE(curElem);
8300     int ind = -1;
8301     // check uniqueness
8302     pair< TMapOfNodeSet::iterator, bool> pp = mapOfNodeSet.insert(make_pair(SE, i));
8303     if( !(pp.second) ) {
8304       TMapOfNodeSet::iterator& itSE = pp.first;
8305       ind = (*itSE).second;
8306       arrayOfGroups[ind].push_back(curElem->GetID());
8307     }
8308     else {
8309       groupOfElems.clear();
8310       groupOfElems.push_back(curElem->GetID());
8311       arrayOfGroups.push_back(groupOfElems);
8312       i++;
8313     }
8314   }
8315
8316   vector< TGroupOfElems >::iterator groupIt = arrayOfGroups.begin();
8317   for ( ; groupIt != arrayOfGroups.end(); ++groupIt ) {
8318     groupOfElems = *groupIt;
8319     if ( groupOfElems.size() > 1 ) {
8320       groupOfElems.sort();
8321       theGroupsOfElementsID.push_back(groupOfElems);
8322     }
8323   }
8324 }
8325
8326 //=======================================================================
8327 //function : MergeElements
8328 //purpose  : In each given group, substitute all elements by the first one.
8329 //=======================================================================
8330
8331 void SMESH_MeshEditor::MergeElements(TListOfListOfElementsID & theGroupsOfElementsID)
8332 {
8333   myLastCreatedElems.Clear();
8334   myLastCreatedNodes.Clear();
8335
8336   typedef list<int> TListOfIDs;
8337   TListOfIDs rmElemIds; // IDs of elems to remove
8338
8339   SMESHDS_Mesh* aMesh = GetMeshDS();
8340
8341   TListOfListOfElementsID::iterator groupsIt = theGroupsOfElementsID.begin();
8342   while ( groupsIt != theGroupsOfElementsID.end() ) {
8343     TListOfIDs& aGroupOfElemID = *groupsIt;
8344     aGroupOfElemID.sort();
8345     int elemIDToKeep = aGroupOfElemID.front();
8346     const SMDS_MeshElement* elemToKeep = aMesh->FindElement(elemIDToKeep);
8347     aGroupOfElemID.pop_front();
8348     TListOfIDs::iterator idIt = aGroupOfElemID.begin();
8349     while ( idIt != aGroupOfElemID.end() ) {
8350       int elemIDToRemove = *idIt;
8351       const SMDS_MeshElement* elemToRemove = aMesh->FindElement(elemIDToRemove);
8352       // add the kept element in groups of removed one (PAL15188)
8353       AddToSameGroups( elemToKeep, elemToRemove, aMesh );
8354       rmElemIds.push_back( elemIDToRemove );
8355       ++idIt;
8356     }
8357     ++groupsIt;
8358   }
8359
8360   Remove( rmElemIds, false );
8361 }
8362
8363 //=======================================================================
8364 //function : MergeEqualElements
8365 //purpose  : Remove all but one of elements built on the same nodes.
8366 //=======================================================================
8367
8368 void SMESH_MeshEditor::MergeEqualElements()
8369 {
8370   TIDSortedElemSet aMeshElements; /* empty input ==
8371                                      to merge equal elements in the whole mesh */
8372   TListOfListOfElementsID aGroupsOfElementsID;
8373   FindEqualElements(aMeshElements, aGroupsOfElementsID);
8374   MergeElements(aGroupsOfElementsID);
8375 }
8376
8377 //=======================================================================
8378 //function : FindFaceInSet
8379 //purpose  : Return a face having linked nodes n1 and n2 and which is
8380 //           - not in avoidSet,
8381 //           - in elemSet provided that !elemSet.empty()
8382 //           i1 and i2 optionally returns indices of n1 and n2
8383 //=======================================================================
8384
8385 const SMDS_MeshElement*
8386 SMESH_MeshEditor::FindFaceInSet(const SMDS_MeshNode*    n1,
8387                                 const SMDS_MeshNode*    n2,
8388                                 const TIDSortedElemSet& elemSet,
8389                                 const TIDSortedElemSet& avoidSet,
8390                                 int*                    n1ind,
8391                                 int*                    n2ind)
8392
8393 {
8394   int i1, i2;
8395   const SMDS_MeshElement* face = 0;
8396
8397   SMDS_ElemIteratorPtr invElemIt = n1->GetInverseElementIterator(SMDSAbs_Face);
8398   //MESSAGE("n1->GetInverseElementIterator(SMDSAbs_Face) " << invElemIt);
8399   while ( invElemIt->more() && !face ) // loop on inverse faces of n1
8400   {
8401     //MESSAGE("in while ( invElemIt->more() && !face )");
8402     const SMDS_MeshElement* elem = invElemIt->next();
8403     if (avoidSet.count( elem ))
8404       continue;
8405     if ( !elemSet.empty() && !elemSet.count( elem ))
8406       continue;
8407     // index of n1
8408     i1 = elem->GetNodeIndex( n1 );
8409     // find a n2 linked to n1
8410     int nbN = elem->IsQuadratic() ? elem->NbNodes()/2 : elem->NbNodes();
8411     for ( int di = -1; di < 2 && !face; di += 2 )
8412     {
8413       i2 = (i1+di+nbN) % nbN;
8414       if ( elem->GetNode( i2 ) == n2 )
8415         face = elem;
8416     }
8417     if ( !face && elem->IsQuadratic())
8418     {
8419       // analysis for quadratic elements using all nodes
8420       const SMDS_VtkFace* F =
8421         dynamic_cast<const SMDS_VtkFace*>(elem);
8422       if (!F) throw SALOME_Exception(LOCALIZED("not an SMDS_VtkFace"));
8423       // use special nodes iterator
8424       SMDS_ElemIteratorPtr anIter = F->interlacedNodesElemIterator();
8425       const SMDS_MeshNode* prevN = cast2Node( anIter->next() );
8426       for ( i1 = -1, i2 = 0; anIter->more() && !face; i1++, i2++ )
8427       {
8428         const SMDS_MeshNode* n = cast2Node( anIter->next() );
8429         if ( n1 == prevN && n2 == n )
8430         {
8431           face = elem;
8432         }
8433         else if ( n2 == prevN && n1 == n )
8434         {
8435           face = elem; swap( i1, i2 );
8436         }
8437         prevN = n;
8438       }
8439     }
8440   }
8441   if ( n1ind ) *n1ind = i1;
8442   if ( n2ind ) *n2ind = i2;
8443   return face;
8444 }
8445
8446 //=======================================================================
8447 //function : findAdjacentFace
8448 //purpose  :
8449 //=======================================================================
8450
8451 static const SMDS_MeshElement* findAdjacentFace(const SMDS_MeshNode* n1,
8452                                                 const SMDS_MeshNode* n2,
8453                                                 const SMDS_MeshElement* elem)
8454 {
8455   TIDSortedElemSet elemSet, avoidSet;
8456   if ( elem )
8457     avoidSet.insert ( elem );
8458   return SMESH_MeshEditor::FindFaceInSet( n1, n2, elemSet, avoidSet );
8459 }
8460
8461 //=======================================================================
8462 //function : FindFreeBorder
8463 //purpose  :
8464 //=======================================================================
8465
8466 #define ControlFreeBorder SMESH::Controls::FreeEdges::IsFreeEdge
8467
8468 bool SMESH_MeshEditor::FindFreeBorder (const SMDS_MeshNode*             theFirstNode,
8469                                        const SMDS_MeshNode*             theSecondNode,
8470                                        const SMDS_MeshNode*             theLastNode,
8471                                        list< const SMDS_MeshNode* > &   theNodes,
8472                                        list< const SMDS_MeshElement* >& theFaces)
8473 {
8474   if ( !theFirstNode || !theSecondNode )
8475     return false;
8476   // find border face between theFirstNode and theSecondNode
8477   const SMDS_MeshElement* curElem = findAdjacentFace( theFirstNode, theSecondNode, 0 );
8478   if ( !curElem )
8479     return false;
8480
8481   theFaces.push_back( curElem );
8482   theNodes.push_back( theFirstNode );
8483   theNodes.push_back( theSecondNode );
8484
8485   //vector<const SMDS_MeshNode*> nodes;
8486   const SMDS_MeshNode *nIgnore = theFirstNode, *nStart = theSecondNode;
8487   TIDSortedElemSet foundElems;
8488   bool needTheLast = ( theLastNode != 0 );
8489
8490   while ( nStart != theLastNode ) {
8491     if ( nStart == theFirstNode )
8492       return !needTheLast;
8493
8494     // find all free border faces sharing form nStart
8495
8496     list< const SMDS_MeshElement* > curElemList;
8497     list< const SMDS_MeshNode* > nStartList;
8498     SMDS_ElemIteratorPtr invElemIt = nStart->GetInverseElementIterator(SMDSAbs_Face);
8499     while ( invElemIt->more() ) {
8500       const SMDS_MeshElement* e = invElemIt->next();
8501       if ( e == curElem || foundElems.insert( e ).second ) {
8502         // get nodes
8503         int iNode = 0, nbNodes = e->NbNodes();
8504         //const SMDS_MeshNode* nodes[nbNodes+1];
8505         vector<const SMDS_MeshNode*> nodes(nbNodes+1);
8506
8507         if(e->IsQuadratic()) {
8508           const SMDS_VtkFace* F =
8509             dynamic_cast<const SMDS_VtkFace*>(e);
8510           if (!F) throw SALOME_Exception(LOCALIZED("not an SMDS_VtkFace"));
8511           // use special nodes iterator
8512           SMDS_ElemIteratorPtr anIter = F->interlacedNodesElemIterator();
8513           while( anIter->more() ) {
8514             nodes[ iNode++ ] = cast2Node(anIter->next());
8515           }
8516         }
8517         else {
8518           SMDS_ElemIteratorPtr nIt = e->nodesIterator();
8519           while ( nIt->more() )
8520             nodes[ iNode++ ] = static_cast<const SMDS_MeshNode*>( nIt->next() );
8521         }
8522         nodes[ iNode ] = nodes[ 0 ];
8523         // check 2 links
8524         for ( iNode = 0; iNode < nbNodes; iNode++ )
8525           if (((nodes[ iNode ] == nStart && nodes[ iNode + 1] != nIgnore ) ||
8526                (nodes[ iNode + 1] == nStart && nodes[ iNode ] != nIgnore )) &&
8527               ControlFreeBorder( &nodes[ iNode ], e->GetID() ))
8528           {
8529             nStartList.push_back( nodes[ iNode + ( nodes[ iNode ] == nStart ? 1 : 0 )]);
8530             curElemList.push_back( e );
8531           }
8532       }
8533     }
8534     // analyse the found
8535
8536     int nbNewBorders = curElemList.size();
8537     if ( nbNewBorders == 0 ) {
8538       // no free border furthermore
8539       return !needTheLast;
8540     }
8541     else if ( nbNewBorders == 1 ) {
8542       // one more element found
8543       nIgnore = nStart;
8544       nStart = nStartList.front();
8545       curElem = curElemList.front();
8546       theFaces.push_back( curElem );
8547       theNodes.push_back( nStart );
8548     }
8549     else {
8550       // several continuations found
8551       list< const SMDS_MeshElement* >::iterator curElemIt;
8552       list< const SMDS_MeshNode* >::iterator nStartIt;
8553       // check if one of them reached the last node
8554       if ( needTheLast ) {
8555         for (curElemIt = curElemList.begin(), nStartIt = nStartList.begin();
8556              curElemIt!= curElemList.end();
8557              curElemIt++, nStartIt++ )
8558           if ( *nStartIt == theLastNode ) {
8559             theFaces.push_back( *curElemIt );
8560             theNodes.push_back( *nStartIt );
8561             return true;
8562           }
8563       }
8564       // find the best free border by the continuations
8565       list<const SMDS_MeshNode*>    contNodes[ 2 ], *cNL;
8566       list<const SMDS_MeshElement*> contFaces[ 2 ], *cFL;
8567       for (curElemIt = curElemList.begin(), nStartIt = nStartList.begin();
8568            curElemIt!= curElemList.end();
8569            curElemIt++, nStartIt++ )
8570       {
8571         cNL = & contNodes[ contNodes[0].empty() ? 0 : 1 ];
8572         cFL = & contFaces[ contFaces[0].empty() ? 0 : 1 ];
8573         // find one more free border
8574         if ( ! FindFreeBorder( nStart, *nStartIt, theLastNode, *cNL, *cFL )) {
8575           cNL->clear();
8576           cFL->clear();
8577         }
8578         else if ( !contNodes[0].empty() && !contNodes[1].empty() ) {
8579           // choice: clear a worse one
8580           int iLongest = ( contNodes[0].size() < contNodes[1].size() ? 1 : 0 );
8581           int iWorse = ( needTheLast ? 1 - iLongest : iLongest );
8582           contNodes[ iWorse ].clear();
8583           contFaces[ iWorse ].clear();
8584         }
8585       }
8586       if ( contNodes[0].empty() && contNodes[1].empty() )
8587         return false;
8588
8589       // append the best free border
8590       cNL = & contNodes[ contNodes[0].empty() ? 1 : 0 ];
8591       cFL = & contFaces[ contFaces[0].empty() ? 1 : 0 ];
8592       theNodes.pop_back(); // remove nIgnore
8593       theNodes.pop_back(); // remove nStart
8594       theFaces.pop_back(); // remove curElem
8595       list< const SMDS_MeshNode* >::iterator nIt = cNL->begin();
8596       list< const SMDS_MeshElement* >::iterator fIt = cFL->begin();
8597       for ( ; nIt != cNL->end(); nIt++ ) theNodes.push_back( *nIt );
8598       for ( ; fIt != cFL->end(); fIt++ ) theFaces.push_back( *fIt );
8599       return true;
8600
8601     } // several continuations found
8602   } // while ( nStart != theLastNode )
8603
8604   return true;
8605 }
8606
8607 //=======================================================================
8608 //function : CheckFreeBorderNodes
8609 //purpose  : Return true if the tree nodes are on a free border
8610 //=======================================================================
8611
8612 bool SMESH_MeshEditor::CheckFreeBorderNodes(const SMDS_MeshNode* theNode1,
8613                                             const SMDS_MeshNode* theNode2,
8614                                             const SMDS_MeshNode* theNode3)
8615 {
8616   list< const SMDS_MeshNode* > nodes;
8617   list< const SMDS_MeshElement* > faces;
8618   return FindFreeBorder( theNode1, theNode2, theNode3, nodes, faces);
8619 }
8620
8621 //=======================================================================
8622 //function : SewFreeBorder
8623 //purpose  :
8624 //=======================================================================
8625
8626 SMESH_MeshEditor::Sew_Error
8627 SMESH_MeshEditor::SewFreeBorder (const SMDS_MeshNode* theBordFirstNode,
8628                                  const SMDS_MeshNode* theBordSecondNode,
8629                                  const SMDS_MeshNode* theBordLastNode,
8630                                  const SMDS_MeshNode* theSideFirstNode,
8631                                  const SMDS_MeshNode* theSideSecondNode,
8632                                  const SMDS_MeshNode* theSideThirdNode,
8633                                  const bool           theSideIsFreeBorder,
8634                                  const bool           toCreatePolygons,
8635                                  const bool           toCreatePolyedrs)
8636 {
8637   myLastCreatedElems.Clear();
8638   myLastCreatedNodes.Clear();
8639
8640   MESSAGE("::SewFreeBorder()");
8641   Sew_Error aResult = SEW_OK;
8642
8643   // ====================================
8644   //    find side nodes and elements
8645   // ====================================
8646
8647   list< const SMDS_MeshNode* > nSide[ 2 ];
8648   list< const SMDS_MeshElement* > eSide[ 2 ];
8649   list< const SMDS_MeshNode* >::iterator nIt[ 2 ];
8650   list< const SMDS_MeshElement* >::iterator eIt[ 2 ];
8651
8652   // Free border 1
8653   // --------------
8654   if (!FindFreeBorder(theBordFirstNode,theBordSecondNode,theBordLastNode,
8655                       nSide[0], eSide[0])) {
8656     MESSAGE(" Free Border 1 not found " );
8657     aResult = SEW_BORDER1_NOT_FOUND;
8658   }
8659   if (theSideIsFreeBorder) {
8660     // Free border 2
8661     // --------------
8662     if (!FindFreeBorder(theSideFirstNode, theSideSecondNode, theSideThirdNode,
8663                         nSide[1], eSide[1])) {
8664       MESSAGE(" Free Border 2 not found " );
8665       aResult = ( aResult != SEW_OK ? SEW_BOTH_BORDERS_NOT_FOUND : SEW_BORDER2_NOT_FOUND );
8666     }
8667   }
8668   if ( aResult != SEW_OK )
8669     return aResult;
8670
8671   if (!theSideIsFreeBorder) {
8672     // Side 2
8673     // --------------
8674
8675     // -------------------------------------------------------------------------
8676     // Algo:
8677     // 1. If nodes to merge are not coincident, move nodes of the free border
8678     //    from the coord sys defined by the direction from the first to last
8679     //    nodes of the border to the correspondent sys of the side 2
8680     // 2. On the side 2, find the links most co-directed with the correspondent
8681     //    links of the free border
8682     // -------------------------------------------------------------------------
8683
8684     // 1. Since sewing may break if there are volumes to split on the side 2,
8685     //    we wont move nodes but just compute new coordinates for them
8686     typedef map<const SMDS_MeshNode*, gp_XYZ> TNodeXYZMap;
8687     TNodeXYZMap nBordXYZ;
8688     list< const SMDS_MeshNode* >& bordNodes = nSide[ 0 ];
8689     list< const SMDS_MeshNode* >::iterator nBordIt;
8690
8691     gp_XYZ Pb1( theBordFirstNode->X(), theBordFirstNode->Y(), theBordFirstNode->Z() );
8692     gp_XYZ Pb2( theBordLastNode->X(), theBordLastNode->Y(), theBordLastNode->Z() );
8693     gp_XYZ Ps1( theSideFirstNode->X(), theSideFirstNode->Y(), theSideFirstNode->Z() );
8694     gp_XYZ Ps2( theSideSecondNode->X(), theSideSecondNode->Y(), theSideSecondNode->Z() );
8695     double tol2 = 1.e-8;
8696     gp_Vec Vbs1( Pb1 - Ps1 ),Vbs2( Pb2 - Ps2 );
8697     if ( Vbs1.SquareMagnitude() > tol2 || Vbs2.SquareMagnitude() > tol2 ) {
8698       // Need node movement.
8699
8700       // find X and Z axes to create trsf
8701       gp_Vec Zb( Pb1 - Pb2 ), Zs( Ps1 - Ps2 );
8702       gp_Vec X = Zs ^ Zb;
8703       if ( X.SquareMagnitude() <= gp::Resolution() * gp::Resolution() )
8704         // Zb || Zs
8705         X = gp_Ax2( gp::Origin(), Zb ).XDirection();
8706
8707       // coord systems
8708       gp_Ax3 toBordAx( Pb1, Zb, X );
8709       gp_Ax3 fromSideAx( Ps1, Zs, X );
8710       gp_Ax3 toGlobalAx( gp::Origin(), gp::DZ(), gp::DX() );
8711       // set trsf
8712       gp_Trsf toBordSys, fromSide2Sys;
8713       toBordSys.SetTransformation( toBordAx );
8714       fromSide2Sys.SetTransformation( fromSideAx, toGlobalAx );
8715       fromSide2Sys.SetScaleFactor( Zs.Magnitude() / Zb.Magnitude() );
8716
8717       // move
8718       for ( nBordIt = bordNodes.begin(); nBordIt != bordNodes.end(); nBordIt++ ) {
8719         const SMDS_MeshNode* n = *nBordIt;
8720         gp_XYZ xyz( n->X(),n->Y(),n->Z() );
8721         toBordSys.Transforms( xyz );
8722         fromSide2Sys.Transforms( xyz );
8723         nBordXYZ.insert( TNodeXYZMap::value_type( n, xyz ));
8724       }
8725     }
8726     else {
8727       // just insert nodes XYZ in the nBordXYZ map
8728       for ( nBordIt = bordNodes.begin(); nBordIt != bordNodes.end(); nBordIt++ ) {
8729         const SMDS_MeshNode* n = *nBordIt;
8730         nBordXYZ.insert( TNodeXYZMap::value_type( n, gp_XYZ( n->X(),n->Y(),n->Z() )));
8731       }
8732     }
8733
8734     // 2. On the side 2, find the links most co-directed with the correspondent
8735     //    links of the free border
8736
8737     list< const SMDS_MeshElement* >& sideElems = eSide[ 1 ];
8738     list< const SMDS_MeshNode* >& sideNodes = nSide[ 1 ];
8739     sideNodes.push_back( theSideFirstNode );
8740
8741     bool hasVolumes = false;
8742     LinkID_Gen aLinkID_Gen( GetMeshDS() );
8743     set<long> foundSideLinkIDs, checkedLinkIDs;
8744     SMDS_VolumeTool volume;
8745     //const SMDS_MeshNode* faceNodes[ 4 ];
8746
8747     const SMDS_MeshNode*    sideNode;
8748     const SMDS_MeshElement* sideElem;
8749     const SMDS_MeshNode* prevSideNode = theSideFirstNode;
8750     const SMDS_MeshNode* prevBordNode = theBordFirstNode;
8751     nBordIt = bordNodes.begin();
8752     nBordIt++;
8753     // border node position and border link direction to compare with
8754     gp_XYZ bordPos = nBordXYZ[ *nBordIt ];
8755     gp_XYZ bordDir = bordPos - nBordXYZ[ prevBordNode ];
8756     // choose next side node by link direction or by closeness to
8757     // the current border node:
8758     bool searchByDir = ( *nBordIt != theBordLastNode );
8759     do {
8760       // find the next node on the Side 2
8761       sideNode = 0;
8762       double maxDot = -DBL_MAX, minDist = DBL_MAX;
8763       long linkID;
8764       checkedLinkIDs.clear();
8765       gp_XYZ prevXYZ( prevSideNode->X(), prevSideNode->Y(), prevSideNode->Z() );
8766
8767       // loop on inverse elements of current node (prevSideNode) on the Side 2
8768       SMDS_ElemIteratorPtr invElemIt = prevSideNode->GetInverseElementIterator();
8769       while ( invElemIt->more() )
8770       {
8771         const SMDS_MeshElement* elem = invElemIt->next();
8772         // prepare data for a loop on links coming to prevSideNode, of a face or a volume
8773         int iPrevNode, iNode = 0, nbNodes = elem->NbNodes();
8774         vector< const SMDS_MeshNode* > faceNodes( nbNodes, (const SMDS_MeshNode*)0 );
8775         bool isVolume = volume.Set( elem );
8776         const SMDS_MeshNode** nodes = isVolume ? volume.GetNodes() : & faceNodes[0];
8777         if ( isVolume ) // --volume
8778           hasVolumes = true;
8779         else if ( elem->GetType()==SMDSAbs_Face ) { // --face
8780           // retrieve all face nodes and find iPrevNode - an index of the prevSideNode
8781           if(elem->IsQuadratic()) {
8782             const SMDS_VtkFace* F =
8783               dynamic_cast<const SMDS_VtkFace*>(elem);
8784             if (!F) throw SALOME_Exception(LOCALIZED("not an SMDS_VtkFace"));
8785             // use special nodes iterator
8786             SMDS_ElemIteratorPtr anIter = F->interlacedNodesElemIterator();
8787             while( anIter->more() ) {
8788               nodes[ iNode ] = cast2Node(anIter->next());
8789               if ( nodes[ iNode++ ] == prevSideNode )
8790                 iPrevNode = iNode - 1;
8791             }
8792           }
8793           else {
8794             SMDS_ElemIteratorPtr nIt = elem->nodesIterator();
8795             while ( nIt->more() ) {
8796               nodes[ iNode ] = cast2Node( nIt->next() );
8797               if ( nodes[ iNode++ ] == prevSideNode )
8798                 iPrevNode = iNode - 1;
8799             }
8800           }
8801           // there are 2 links to check
8802           nbNodes = 2;
8803         }
8804         else // --edge
8805           continue;
8806         // loop on links, to be precise, on the second node of links
8807         for ( iNode = 0; iNode < nbNodes; iNode++ ) {
8808           const SMDS_MeshNode* n = nodes[ iNode ];
8809           if ( isVolume ) {
8810             if ( !volume.IsLinked( n, prevSideNode ))
8811               continue;
8812           }
8813           else {
8814             if ( iNode ) // a node before prevSideNode
8815               n = nodes[ iPrevNode == 0 ? elem->NbNodes() - 1 : iPrevNode - 1 ];
8816             else         // a node after prevSideNode
8817               n = nodes[ iPrevNode + 1 == elem->NbNodes() ? 0 : iPrevNode + 1 ];
8818           }
8819           // check if this link was already used
8820           long iLink = aLinkID_Gen.GetLinkID( prevSideNode, n );
8821           bool isJustChecked = !checkedLinkIDs.insert( iLink ).second;
8822           if (!isJustChecked &&
8823               foundSideLinkIDs.find( iLink ) == foundSideLinkIDs.end() )
8824           {
8825             // test a link geometrically
8826             gp_XYZ nextXYZ ( n->X(), n->Y(), n->Z() );
8827             bool linkIsBetter = false;
8828             double dot = 0.0, dist = 0.0;
8829             if ( searchByDir ) { // choose most co-directed link
8830               dot = bordDir * ( nextXYZ - prevXYZ ).Normalized();
8831               linkIsBetter = ( dot > maxDot );
8832             }
8833             else { // choose link with the node closest to bordPos
8834               dist = ( nextXYZ - bordPos ).SquareModulus();
8835               linkIsBetter = ( dist < minDist );
8836             }
8837             if ( linkIsBetter ) {
8838               maxDot = dot;
8839               minDist = dist;
8840               linkID = iLink;
8841               sideNode = n;
8842               sideElem = elem;
8843             }
8844           }
8845         }
8846       } // loop on inverse elements of prevSideNode
8847
8848       if ( !sideNode ) {
8849         MESSAGE(" Cant find path by links of the Side 2 ");
8850         return SEW_BAD_SIDE_NODES;
8851       }
8852       sideNodes.push_back( sideNode );
8853       sideElems.push_back( sideElem );
8854       foundSideLinkIDs.insert ( linkID );
8855       prevSideNode = sideNode;
8856
8857       if ( *nBordIt == theBordLastNode )
8858         searchByDir = false;
8859       else {
8860         // find the next border link to compare with
8861         gp_XYZ sidePos( sideNode->X(), sideNode->Y(), sideNode->Z() );
8862         searchByDir = ( bordDir * ( sidePos - bordPos ) <= 0 );
8863         // move to next border node if sideNode is before forward border node (bordPos)
8864         while ( *nBordIt != theBordLastNode && !searchByDir ) {
8865           prevBordNode = *nBordIt;
8866           nBordIt++;
8867           bordPos = nBordXYZ[ *nBordIt ];
8868           bordDir = bordPos - nBordXYZ[ prevBordNode ];
8869           searchByDir = ( bordDir * ( sidePos - bordPos ) <= 0 );
8870         }
8871       }
8872     }
8873     while ( sideNode != theSideSecondNode );
8874
8875     if ( hasVolumes && sideNodes.size () != bordNodes.size() && !toCreatePolyedrs) {
8876       MESSAGE("VOLUME SPLITTING IS FORBIDDEN");
8877       return SEW_VOLUMES_TO_SPLIT; // volume splitting is forbidden
8878     }
8879   } // end nodes search on the side 2
8880
8881   // ============================
8882   // sew the border to the side 2
8883   // ============================
8884
8885   int nbNodes[]  = { nSide[0].size(), nSide[1].size() };
8886   int maxNbNodes = Max( nbNodes[0], nbNodes[1] );
8887
8888   TListOfListOfNodes nodeGroupsToMerge;
8889   if ( nbNodes[0] == nbNodes[1] ||
8890        ( theSideIsFreeBorder && !theSideThirdNode)) {
8891
8892     // all nodes are to be merged
8893
8894     for (nIt[0] = nSide[0].begin(), nIt[1] = nSide[1].begin();
8895          nIt[0] != nSide[0].end() && nIt[1] != nSide[1].end();
8896          nIt[0]++, nIt[1]++ )
8897     {
8898       nodeGroupsToMerge.push_back( list<const SMDS_MeshNode*>() );
8899       nodeGroupsToMerge.back().push_back( *nIt[1] ); // to keep
8900       nodeGroupsToMerge.back().push_back( *nIt[0] ); // to remove
8901     }
8902   }
8903   else {
8904
8905     // insert new nodes into the border and the side to get equal nb of segments
8906
8907     // get normalized parameters of nodes on the borders
8908     //double param[ 2 ][ maxNbNodes ];
8909     double* param[ 2 ];
8910     param[0] = new double [ maxNbNodes ];
8911     param[1] = new double [ maxNbNodes ];
8912     int iNode, iBord;
8913     for ( iBord = 0; iBord < 2; iBord++ ) { // loop on 2 borders
8914       list< const SMDS_MeshNode* >& nodes = nSide[ iBord ];
8915       list< const SMDS_MeshNode* >::iterator nIt = nodes.begin();
8916       const SMDS_MeshNode* nPrev = *nIt;
8917       double bordLength = 0;
8918       for ( iNode = 0; nIt != nodes.end(); nIt++, iNode++ ) { // loop on border nodes
8919         const SMDS_MeshNode* nCur = *nIt;
8920         gp_XYZ segment (nCur->X() - nPrev->X(),
8921                         nCur->Y() - nPrev->Y(),
8922                         nCur->Z() - nPrev->Z());
8923         double segmentLen = segment.Modulus();
8924         bordLength += segmentLen;
8925         param[ iBord ][ iNode ] = bordLength;
8926         nPrev = nCur;
8927       }
8928       // normalize within [0,1]
8929       for ( iNode = 0; iNode < nbNodes[ iBord ]; iNode++ ) {
8930         param[ iBord ][ iNode ] /= bordLength;
8931       }
8932     }
8933
8934     // loop on border segments
8935     const SMDS_MeshNode *nPrev[ 2 ] = { 0, 0 };
8936     int i[ 2 ] = { 0, 0 };
8937     nIt[0] = nSide[0].begin(); eIt[0] = eSide[0].begin();
8938     nIt[1] = nSide[1].begin(); eIt[1] = eSide[1].begin();
8939
8940     TElemOfNodeListMap insertMap;
8941     TElemOfNodeListMap::iterator insertMapIt;
8942     // insertMap is
8943     // key:   elem to insert nodes into
8944     // value: 2 nodes to insert between + nodes to be inserted
8945     do {
8946       bool next[ 2 ] = { false, false };
8947
8948       // find min adjacent segment length after sewing
8949       double nextParam = 10., prevParam = 0;
8950       for ( iBord = 0; iBord < 2; iBord++ ) { // loop on 2 borders
8951         if ( i[ iBord ] + 1 < nbNodes[ iBord ])
8952           nextParam = Min( nextParam, param[iBord][ i[iBord] + 1 ]);
8953         if ( i[ iBord ] > 0 )
8954           prevParam = Max( prevParam, param[iBord][ i[iBord] - 1 ]);
8955       }
8956       double minParam = Min( param[ 0 ][ i[0] ], param[ 1 ][ i[1] ]);
8957       double maxParam = Max( param[ 0 ][ i[0] ], param[ 1 ][ i[1] ]);
8958       double minSegLen = Min( nextParam - minParam, maxParam - prevParam );
8959
8960       // choose to insert or to merge nodes
8961       double du = param[ 1 ][ i[1] ] - param[ 0 ][ i[0] ];
8962       if ( Abs( du ) <= minSegLen * 0.2 ) {
8963         // merge
8964         // ------
8965         nodeGroupsToMerge.push_back( list<const SMDS_MeshNode*>() );
8966         const SMDS_MeshNode* n0 = *nIt[0];
8967         const SMDS_MeshNode* n1 = *nIt[1];
8968         nodeGroupsToMerge.back().push_back( n1 );
8969         nodeGroupsToMerge.back().push_back( n0 );
8970         // position of node of the border changes due to merge
8971         param[ 0 ][ i[0] ] += du;
8972         // move n1 for the sake of elem shape evaluation during insertion.
8973         // n1 will be removed by MergeNodes() anyway
8974         const_cast<SMDS_MeshNode*>( n0 )->setXYZ( n1->X(), n1->Y(), n1->Z() );
8975         next[0] = next[1] = true;
8976       }
8977       else {
8978         // insert
8979         // ------
8980         int intoBord = ( du < 0 ) ? 0 : 1;
8981         const SMDS_MeshElement* elem = *eIt[ intoBord ];
8982         const SMDS_MeshNode*    n1   = nPrev[ intoBord ];
8983         const SMDS_MeshNode*    n2   = *nIt[ intoBord ];
8984         const SMDS_MeshNode*    nIns = *nIt[ 1 - intoBord ];
8985         if ( intoBord == 1 ) {
8986           // move node of the border to be on a link of elem of the side
8987           gp_XYZ p1 (n1->X(), n1->Y(), n1->Z());
8988           gp_XYZ p2 (n2->X(), n2->Y(), n2->Z());
8989           double ratio = du / ( param[ 1 ][ i[1] ] - param[ 1 ][ i[1]-1 ]);
8990           gp_XYZ p = p2 * ( 1 - ratio ) + p1 * ratio;
8991           GetMeshDS()->MoveNode( nIns, p.X(), p.Y(), p.Z() );
8992         }
8993         insertMapIt = insertMap.find( elem );
8994         bool notFound = ( insertMapIt == insertMap.end() );
8995         bool otherLink = ( !notFound && (*insertMapIt).second.front() != n1 );
8996         if ( otherLink ) {
8997           // insert into another link of the same element:
8998           // 1. perform insertion into the other link of the elem
8999           list<const SMDS_MeshNode*> & nodeList = (*insertMapIt).second;
9000           const SMDS_MeshNode* n12 = nodeList.front(); nodeList.pop_front();
9001           const SMDS_MeshNode* n22 = nodeList.front(); nodeList.pop_front();
9002           InsertNodesIntoLink( elem, n12, n22, nodeList, toCreatePolygons );
9003           // 2. perform insertion into the link of adjacent faces
9004           while (true) {
9005             const SMDS_MeshElement* adjElem = findAdjacentFace( n12, n22, elem );
9006             if ( adjElem )
9007               InsertNodesIntoLink( adjElem, n12, n22, nodeList, toCreatePolygons );
9008             else
9009               break;
9010           }
9011           if (toCreatePolyedrs) {
9012             // perform insertion into the links of adjacent volumes
9013             UpdateVolumes(n12, n22, nodeList);
9014           }
9015           // 3. find an element appeared on n1 and n2 after the insertion
9016           insertMap.erase( elem );
9017           elem = findAdjacentFace( n1, n2, 0 );
9018         }
9019         if ( notFound || otherLink ) {
9020           // add element and nodes of the side into the insertMap
9021           insertMapIt = insertMap.insert
9022             ( TElemOfNodeListMap::value_type( elem, list<const SMDS_MeshNode*>() )).first;
9023           (*insertMapIt).second.push_back( n1 );
9024           (*insertMapIt).second.push_back( n2 );
9025         }
9026         // add node to be inserted into elem
9027         (*insertMapIt).second.push_back( nIns );
9028         next[ 1 - intoBord ] = true;
9029       }
9030
9031       // go to the next segment
9032       for ( iBord = 0; iBord < 2; iBord++ ) { // loop on 2 borders
9033         if ( next[ iBord ] ) {
9034           if ( i[ iBord ] != 0 && eIt[ iBord ] != eSide[ iBord ].end())
9035             eIt[ iBord ]++;
9036           nPrev[ iBord ] = *nIt[ iBord ];
9037           nIt[ iBord ]++; i[ iBord ]++;
9038         }
9039       }
9040     }
9041     while ( nIt[0] != nSide[0].end() && nIt[1] != nSide[1].end());
9042
9043     // perform insertion of nodes into elements
9044
9045     for (insertMapIt = insertMap.begin();
9046          insertMapIt != insertMap.end();
9047          insertMapIt++ )
9048     {
9049       const SMDS_MeshElement* elem = (*insertMapIt).first;
9050       list<const SMDS_MeshNode*> & nodeList = (*insertMapIt).second;
9051       const SMDS_MeshNode* n1 = nodeList.front(); nodeList.pop_front();
9052       const SMDS_MeshNode* n2 = nodeList.front(); nodeList.pop_front();
9053
9054       InsertNodesIntoLink( elem, n1, n2, nodeList, toCreatePolygons );
9055
9056       if ( !theSideIsFreeBorder ) {
9057         // look for and insert nodes into the faces adjacent to elem
9058         while (true) {
9059           const SMDS_MeshElement* adjElem = findAdjacentFace( n1, n2, elem );
9060           if ( adjElem )
9061             InsertNodesIntoLink( adjElem, n1, n2, nodeList, toCreatePolygons );
9062           else
9063             break;
9064         }
9065       }
9066       if (toCreatePolyedrs) {
9067         // perform insertion into the links of adjacent volumes
9068         UpdateVolumes(n1, n2, nodeList);
9069       }
9070     }
9071
9072     delete param[0];
9073     delete param[1];
9074   } // end: insert new nodes
9075
9076   MergeNodes ( nodeGroupsToMerge );
9077
9078   return aResult;
9079 }
9080
9081 //=======================================================================
9082 //function : InsertNodesIntoLink
9083 //purpose  : insert theNodesToInsert into theFace between theBetweenNode1
9084 //           and theBetweenNode2 and split theElement
9085 //=======================================================================
9086
9087 void SMESH_MeshEditor::InsertNodesIntoLink(const SMDS_MeshElement*     theFace,
9088                                            const SMDS_MeshNode*        theBetweenNode1,
9089                                            const SMDS_MeshNode*        theBetweenNode2,
9090                                            list<const SMDS_MeshNode*>& theNodesToInsert,
9091                                            const bool                  toCreatePoly)
9092 {
9093   if ( theFace->GetType() != SMDSAbs_Face ) return;
9094
9095   // find indices of 2 link nodes and of the rest nodes
9096   int iNode = 0, il1, il2, i3, i4;
9097   il1 = il2 = i3 = i4 = -1;
9098   //const SMDS_MeshNode* nodes[ theFace->NbNodes() ];
9099   vector<const SMDS_MeshNode*> nodes( theFace->NbNodes() );
9100
9101   if(theFace->IsQuadratic()) {
9102     const SMDS_VtkFace* F =
9103       dynamic_cast<const SMDS_VtkFace*>(theFace);
9104     if (!F) throw SALOME_Exception(LOCALIZED("not an SMDS_VtkFace"));
9105     // use special nodes iterator
9106     SMDS_ElemIteratorPtr anIter = F->interlacedNodesElemIterator();
9107     while( anIter->more() ) {
9108       const SMDS_MeshNode* n = cast2Node(anIter->next());
9109       if ( n == theBetweenNode1 )
9110         il1 = iNode;
9111       else if ( n == theBetweenNode2 )
9112         il2 = iNode;
9113       else if ( i3 < 0 )
9114         i3 = iNode;
9115       else
9116         i4 = iNode;
9117       nodes[ iNode++ ] = n;
9118     }
9119   }
9120   else {
9121     SMDS_ElemIteratorPtr nodeIt = theFace->nodesIterator();
9122     while ( nodeIt->more() ) {
9123       const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
9124       if ( n == theBetweenNode1 )
9125         il1 = iNode;
9126       else if ( n == theBetweenNode2 )
9127         il2 = iNode;
9128       else if ( i3 < 0 )
9129         i3 = iNode;
9130       else
9131         i4 = iNode;
9132       nodes[ iNode++ ] = n;
9133     }
9134   }
9135   if ( il1 < 0 || il2 < 0 || i3 < 0 )
9136     return ;
9137
9138   // arrange link nodes to go one after another regarding the face orientation
9139   bool reverse = ( Abs( il2 - il1 ) == 1 ? il2 < il1 : il1 < il2 );
9140   list<const SMDS_MeshNode *> aNodesToInsert = theNodesToInsert;
9141   if ( reverse ) {
9142     iNode = il1;
9143     il1 = il2;
9144     il2 = iNode;
9145     aNodesToInsert.reverse();
9146   }
9147   // check that not link nodes of a quadrangles are in good order
9148   int nbFaceNodes = theFace->NbNodes();
9149   if ( nbFaceNodes == 4 && i4 - i3 != 1 ) {
9150     iNode = i3;
9151     i3 = i4;
9152     i4 = iNode;
9153   }
9154
9155   if (toCreatePoly || theFace->IsPoly()) {
9156
9157     iNode = 0;
9158     vector<const SMDS_MeshNode *> poly_nodes (nbFaceNodes + aNodesToInsert.size());
9159
9160     // add nodes of face up to first node of link
9161     bool isFLN = false;
9162
9163     if(theFace->IsQuadratic()) {
9164       const SMDS_VtkFace* F =
9165         dynamic_cast<const SMDS_VtkFace*>(theFace);
9166       if (!F) throw SALOME_Exception(LOCALIZED("not an SMDS_VtkFace"));
9167       // use special nodes iterator
9168       SMDS_ElemIteratorPtr anIter = F->interlacedNodesElemIterator();
9169       while( anIter->more()  && !isFLN ) {
9170         const SMDS_MeshNode* n = cast2Node(anIter->next());
9171         poly_nodes[iNode++] = n;
9172         if (n == nodes[il1]) {
9173           isFLN = true;
9174         }
9175       }
9176       // add nodes to insert
9177       list<const SMDS_MeshNode*>::iterator nIt = aNodesToInsert.begin();
9178       for (; nIt != aNodesToInsert.end(); nIt++) {
9179         poly_nodes[iNode++] = *nIt;
9180       }
9181       // add nodes of face starting from last node of link
9182       while ( anIter->more() ) {
9183         poly_nodes[iNode++] = cast2Node(anIter->next());
9184       }
9185     }
9186     else {
9187       SMDS_ElemIteratorPtr nodeIt = theFace->nodesIterator();
9188       while ( nodeIt->more() && !isFLN ) {
9189         const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
9190         poly_nodes[iNode++] = n;
9191         if (n == nodes[il1]) {
9192           isFLN = true;
9193         }
9194       }
9195       // add nodes to insert
9196       list<const SMDS_MeshNode*>::iterator nIt = aNodesToInsert.begin();
9197       for (; nIt != aNodesToInsert.end(); nIt++) {
9198         poly_nodes[iNode++] = *nIt;
9199       }
9200       // add nodes of face starting from last node of link
9201       while ( nodeIt->more() ) {
9202         const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
9203         poly_nodes[iNode++] = n;
9204       }
9205     }
9206
9207     // edit or replace the face
9208     SMESHDS_Mesh *aMesh = GetMeshDS();
9209
9210     if (theFace->IsPoly()) {
9211       aMesh->ChangePolygonNodes(theFace, poly_nodes);
9212     }
9213     else {
9214       int aShapeId = FindShape( theFace );
9215
9216       SMDS_MeshElement* newElem = aMesh->AddPolygonalFace(poly_nodes);
9217       myLastCreatedElems.Append(newElem);
9218       if ( aShapeId && newElem )
9219         aMesh->SetMeshElementOnShape( newElem, aShapeId );
9220
9221       aMesh->RemoveElement(theFace);
9222     }
9223     return;
9224   }
9225
9226   SMESHDS_Mesh *aMesh = GetMeshDS();
9227   if( !theFace->IsQuadratic() ) {
9228
9229     // put aNodesToInsert between theBetweenNode1 and theBetweenNode2
9230     int nbLinkNodes = 2 + aNodesToInsert.size();
9231     //const SMDS_MeshNode* linkNodes[ nbLinkNodes ];
9232     vector<const SMDS_MeshNode*> linkNodes( nbLinkNodes );
9233     linkNodes[ 0 ] = nodes[ il1 ];
9234     linkNodes[ nbLinkNodes - 1 ] = nodes[ il2 ];
9235     list<const SMDS_MeshNode*>::iterator nIt = aNodesToInsert.begin();
9236     for ( iNode = 1; nIt != aNodesToInsert.end(); nIt++ ) {
9237       linkNodes[ iNode++ ] = *nIt;
9238     }
9239     // decide how to split a quadrangle: compare possible variants
9240     // and choose which of splits to be a quadrangle
9241     int i1, i2, iSplit, nbSplits = nbLinkNodes - 1, iBestQuad;
9242     if ( nbFaceNodes == 3 ) {
9243       iBestQuad = nbSplits;
9244       i4 = i3;
9245     }
9246     else if ( nbFaceNodes == 4 ) {
9247       SMESH::Controls::NumericalFunctorPtr aCrit( new SMESH::Controls::AspectRatio);
9248       double aBestRate = DBL_MAX;
9249       for ( int iQuad = 0; iQuad < nbSplits; iQuad++ ) {
9250         i1 = 0; i2 = 1;
9251         double aBadRate = 0;
9252         // evaluate elements quality
9253         for ( iSplit = 0; iSplit < nbSplits; iSplit++ ) {
9254           if ( iSplit == iQuad ) {
9255             SMDS_FaceOfNodes quad (linkNodes[ i1++ ],
9256                                    linkNodes[ i2++ ],
9257                                    nodes[ i3 ],
9258                                    nodes[ i4 ]);
9259             aBadRate += getBadRate( &quad, aCrit );
9260           }
9261           else {
9262             SMDS_FaceOfNodes tria (linkNodes[ i1++ ],
9263                                    linkNodes[ i2++ ],
9264                                    nodes[ iSplit < iQuad ? i4 : i3 ]);
9265             aBadRate += getBadRate( &tria, aCrit );
9266           }
9267         }
9268         // choice
9269         if ( aBadRate < aBestRate ) {
9270           iBestQuad = iQuad;
9271           aBestRate = aBadRate;
9272         }
9273       }
9274     }
9275
9276     // create new elements
9277     int aShapeId = FindShape( theFace );
9278
9279     i1 = 0; i2 = 1;
9280     for ( iSplit = 0; iSplit < nbSplits - 1; iSplit++ ) {
9281       SMDS_MeshElement* newElem = 0;
9282       if ( iSplit == iBestQuad )
9283         newElem = aMesh->AddFace (linkNodes[ i1++ ],
9284                                   linkNodes[ i2++ ],
9285                                   nodes[ i3 ],
9286                                   nodes[ i4 ]);
9287       else
9288         newElem = aMesh->AddFace (linkNodes[ i1++ ],
9289                                   linkNodes[ i2++ ],
9290                                   nodes[ iSplit < iBestQuad ? i4 : i3 ]);
9291       myLastCreatedElems.Append(newElem);
9292       if ( aShapeId && newElem )
9293         aMesh->SetMeshElementOnShape( newElem, aShapeId );
9294     }
9295
9296     // change nodes of theFace
9297     const SMDS_MeshNode* newNodes[ 4 ];
9298     newNodes[ 0 ] = linkNodes[ i1 ];
9299     newNodes[ 1 ] = linkNodes[ i2 ];
9300     newNodes[ 2 ] = nodes[ iSplit >= iBestQuad ? i3 : i4 ];
9301     newNodes[ 3 ] = nodes[ i4 ];
9302     //aMesh->ChangeElementNodes( theFace, newNodes, iSplit == iBestQuad ? 4 : 3 );
9303     const SMDS_MeshElement* newElem = 0;
9304     if (iSplit == iBestQuad)
9305       newElem = aMesh->AddFace( newNodes[0], newNodes[1], newNodes[2], newNodes[3] );
9306     else
9307       newElem = aMesh->AddFace( newNodes[0], newNodes[1], newNodes[2] );
9308     myLastCreatedElems.Append(newElem);
9309     if ( aShapeId && newElem )
9310       aMesh->SetMeshElementOnShape( newElem, aShapeId );
9311 } // end if(!theFace->IsQuadratic())
9312   else { // theFace is quadratic
9313     // we have to split theFace on simple triangles and one simple quadrangle
9314     int tmp = il1/2;
9315     int nbshift = tmp*2;
9316     // shift nodes in nodes[] by nbshift
9317     int i,j;
9318     for(i=0; i<nbshift; i++) {
9319       const SMDS_MeshNode* n = nodes[0];
9320       for(j=0; j<nbFaceNodes-1; j++) {
9321         nodes[j] = nodes[j+1];
9322       }
9323       nodes[nbFaceNodes-1] = n;
9324     }
9325     il1 = il1 - nbshift;
9326     // now have to insert nodes between n0 and n1 or n1 and n2 (see below)
9327     //   n0      n1     n2    n0      n1     n2
9328     //     +-----+-----+        +-----+-----+
9329     //      \         /         |           |
9330     //       \       /          |           |
9331     //      n5+     +n3       n7+           +n3
9332     //         \   /            |           |
9333     //          \ /             |           |
9334     //           +              +-----+-----+
9335     //           n4           n6      n5     n4
9336
9337     // create new elements
9338     int aShapeId = FindShape( theFace );
9339
9340     int n1,n2,n3;
9341     if(nbFaceNodes==6) { // quadratic triangle
9342       SMDS_MeshElement* newElem =
9343         aMesh->AddFace(nodes[3],nodes[4],nodes[5]);
9344       myLastCreatedElems.Append(newElem);
9345       if ( aShapeId && newElem )
9346         aMesh->SetMeshElementOnShape( newElem, aShapeId );
9347       if(theFace->IsMediumNode(nodes[il1])) {
9348         // create quadrangle
9349         newElem = aMesh->AddFace(nodes[0],nodes[1],nodes[3],nodes[5]);
9350         myLastCreatedElems.Append(newElem);
9351         if ( aShapeId && newElem )
9352           aMesh->SetMeshElementOnShape( newElem, aShapeId );
9353         n1 = 1;
9354         n2 = 2;
9355         n3 = 3;
9356       }
9357       else {
9358         // create quadrangle
9359         newElem = aMesh->AddFace(nodes[1],nodes[2],nodes[3],nodes[5]);
9360         myLastCreatedElems.Append(newElem);
9361         if ( aShapeId && newElem )
9362           aMesh->SetMeshElementOnShape( newElem, aShapeId );
9363         n1 = 0;
9364         n2 = 1;
9365         n3 = 5;
9366       }
9367     }
9368     else { // nbFaceNodes==8 - quadratic quadrangle
9369       SMDS_MeshElement* newElem =
9370         aMesh->AddFace(nodes[3],nodes[4],nodes[5]);
9371       myLastCreatedElems.Append(newElem);
9372       if ( aShapeId && newElem )
9373         aMesh->SetMeshElementOnShape( newElem, aShapeId );
9374       newElem = aMesh->AddFace(nodes[5],nodes[6],nodes[7]);
9375       myLastCreatedElems.Append(newElem);
9376       if ( aShapeId && newElem )
9377         aMesh->SetMeshElementOnShape( newElem, aShapeId );
9378       newElem = aMesh->AddFace(nodes[5],nodes[7],nodes[3]);
9379       myLastCreatedElems.Append(newElem);
9380       if ( aShapeId && newElem )
9381         aMesh->SetMeshElementOnShape( newElem, aShapeId );
9382       if(theFace->IsMediumNode(nodes[il1])) {
9383         // create quadrangle
9384         newElem = aMesh->AddFace(nodes[0],nodes[1],nodes[3],nodes[7]);
9385         myLastCreatedElems.Append(newElem);
9386         if ( aShapeId && newElem )
9387           aMesh->SetMeshElementOnShape( newElem, aShapeId );
9388         n1 = 1;
9389         n2 = 2;
9390         n3 = 3;
9391       }
9392       else {
9393         // create quadrangle
9394         newElem = aMesh->AddFace(nodes[1],nodes[2],nodes[3],nodes[7]);
9395         myLastCreatedElems.Append(newElem);
9396         if ( aShapeId && newElem )
9397           aMesh->SetMeshElementOnShape( newElem, aShapeId );
9398         n1 = 0;
9399         n2 = 1;
9400         n3 = 7;
9401       }
9402     }
9403     // create needed triangles using n1,n2,n3 and inserted nodes
9404     int nbn = 2 + aNodesToInsert.size();
9405     //const SMDS_MeshNode* aNodes[nbn];
9406     vector<const SMDS_MeshNode*> aNodes(nbn);
9407     aNodes[0] = nodes[n1];
9408     aNodes[nbn-1] = nodes[n2];
9409     list<const SMDS_MeshNode*>::iterator nIt = aNodesToInsert.begin();
9410     for ( iNode = 1; nIt != aNodesToInsert.end(); nIt++ ) {
9411       aNodes[iNode++] = *nIt;
9412     }
9413     for(i=1; i<nbn; i++) {
9414       SMDS_MeshElement* newElem =
9415         aMesh->AddFace(aNodes[i-1],aNodes[i],nodes[n3]);
9416       myLastCreatedElems.Append(newElem);
9417       if ( aShapeId && newElem )
9418         aMesh->SetMeshElementOnShape( newElem, aShapeId );
9419     }
9420   }
9421   // remove old face
9422   aMesh->RemoveElement(theFace);
9423 }
9424
9425 //=======================================================================
9426 //function : UpdateVolumes
9427 //purpose  :
9428 //=======================================================================
9429 void SMESH_MeshEditor::UpdateVolumes (const SMDS_MeshNode*        theBetweenNode1,
9430                                       const SMDS_MeshNode*        theBetweenNode2,
9431                                       list<const SMDS_MeshNode*>& theNodesToInsert)
9432 {
9433   myLastCreatedElems.Clear();
9434   myLastCreatedNodes.Clear();
9435
9436   SMDS_ElemIteratorPtr invElemIt = theBetweenNode1->GetInverseElementIterator(SMDSAbs_Volume);
9437   while (invElemIt->more()) { // loop on inverse elements of theBetweenNode1
9438     const SMDS_MeshElement* elem = invElemIt->next();
9439
9440     // check, if current volume has link theBetweenNode1 - theBetweenNode2
9441     SMDS_VolumeTool aVolume (elem);
9442     if (!aVolume.IsLinked(theBetweenNode1, theBetweenNode2))
9443       continue;
9444
9445     // insert new nodes in all faces of the volume, sharing link theBetweenNode1 - theBetweenNode2
9446     int iface, nbFaces = aVolume.NbFaces();
9447     vector<const SMDS_MeshNode *> poly_nodes;
9448     vector<int> quantities (nbFaces);
9449
9450     for (iface = 0; iface < nbFaces; iface++) {
9451       int nbFaceNodes = aVolume.NbFaceNodes(iface), nbInserted = 0;
9452       // faceNodes will contain (nbFaceNodes + 1) nodes, last = first
9453       const SMDS_MeshNode** faceNodes = aVolume.GetFaceNodes(iface);
9454
9455       for (int inode = 0; inode < nbFaceNodes; inode++) {
9456         poly_nodes.push_back(faceNodes[inode]);
9457
9458         if (nbInserted == 0) {
9459           if (faceNodes[inode] == theBetweenNode1) {
9460             if (faceNodes[inode + 1] == theBetweenNode2) {
9461               nbInserted = theNodesToInsert.size();
9462
9463               // add nodes to insert
9464               list<const SMDS_MeshNode*>::iterator nIt = theNodesToInsert.begin();
9465               for (; nIt != theNodesToInsert.end(); nIt++) {
9466                 poly_nodes.push_back(*nIt);
9467               }
9468             }
9469           }
9470           else if (faceNodes[inode] == theBetweenNode2) {
9471             if (faceNodes[inode + 1] == theBetweenNode1) {
9472               nbInserted = theNodesToInsert.size();
9473
9474               // add nodes to insert in reversed order
9475               list<const SMDS_MeshNode*>::iterator nIt = theNodesToInsert.end();
9476               nIt--;
9477               for (; nIt != theNodesToInsert.begin(); nIt--) {
9478                 poly_nodes.push_back(*nIt);
9479               }
9480               poly_nodes.push_back(*nIt);
9481             }
9482           }
9483           else {
9484           }
9485         }
9486       }
9487       quantities[iface] = nbFaceNodes + nbInserted;
9488     }
9489
9490     // Replace or update the volume
9491     SMESHDS_Mesh *aMesh = GetMeshDS();
9492
9493     if (elem->IsPoly()) {
9494       aMesh->ChangePolyhedronNodes(elem, poly_nodes, quantities);
9495
9496     }
9497     else {
9498       int aShapeId = FindShape( elem );
9499
9500       SMDS_MeshElement* newElem =
9501         aMesh->AddPolyhedralVolume(poly_nodes, quantities);
9502       myLastCreatedElems.Append(newElem);
9503       if (aShapeId && newElem)
9504         aMesh->SetMeshElementOnShape(newElem, aShapeId);
9505
9506       aMesh->RemoveElement(elem);
9507     }
9508   }
9509 }
9510
9511 namespace
9512 {
9513   //================================================================================
9514   /*!
9515    * \brief Transform any volume into data of SMDSEntity_Polyhedra
9516    */
9517   //================================================================================
9518
9519   void volumeToPolyhedron( const SMDS_MeshElement*         elem,
9520                            vector<const SMDS_MeshNode *> & nodes,
9521                            vector<int> &                   nbNodeInFaces )
9522   {
9523     nodes.clear();
9524     nbNodeInFaces.clear();
9525     SMDS_VolumeTool vTool ( elem );
9526     for ( int iF = 0; iF < vTool.NbFaces(); ++iF )
9527     {
9528       const SMDS_MeshNode** fNodes = vTool.GetFaceNodes( iF );
9529       nodes.insert( nodes.end(), fNodes, fNodes + vTool.NbFaceNodes( iF ));
9530       nbNodeInFaces.push_back( vTool.NbFaceNodes( iF ));
9531     }
9532   }
9533 }
9534
9535 //=======================================================================
9536 /*!
9537  * \brief Convert elements contained in a submesh to quadratic
9538  * \return int - nb of checked elements
9539  */
9540 //=======================================================================
9541
9542 int SMESH_MeshEditor::convertElemToQuadratic(SMESHDS_SubMesh *   theSm,
9543                                              SMESH_MesherHelper& theHelper,
9544                                              const bool          theForce3d)
9545 {
9546   int nbElem = 0;
9547   if( !theSm ) return nbElem;
9548
9549   vector<int> nbNodeInFaces;
9550   vector<const SMDS_MeshNode *> nodes;
9551   SMDS_ElemIteratorPtr ElemItr = theSm->GetElements();
9552   while(ElemItr->more())
9553   {
9554     nbElem++;
9555     const SMDS_MeshElement* elem = ElemItr->next();
9556     if( !elem || elem->IsQuadratic() ) continue;
9557
9558     // get elem data needed to re-create it
9559     //
9560     const int id                        = elem->GetID();
9561     const int nbNodes                   = elem->NbNodes();
9562     const SMDSAbs_ElementType aType     = elem->GetType();
9563     const SMDSAbs_EntityType  aGeomType = elem->GetEntityType();
9564     nodes.assign(elem->begin_nodes(), elem->end_nodes());
9565     if ( aGeomType == SMDSEntity_Polyhedra )
9566       nbNodeInFaces = static_cast<const SMDS_VtkVolume* >( elem )->GetQuantities();
9567     else if ( aGeomType == SMDSEntity_Hexagonal_Prism )
9568       volumeToPolyhedron( elem, nodes, nbNodeInFaces );
9569
9570     // remove a linear element
9571     GetMeshDS()->RemoveFreeElement(elem, theSm, /*fromGroups=*/false);
9572
9573     const SMDS_MeshElement* NewElem = 0;
9574
9575     switch( aType )
9576     {
9577     case SMDSAbs_Edge :
9578       {
9579         NewElem = theHelper.AddEdge(nodes[0], nodes[1], id, theForce3d);
9580         break;
9581       }
9582     case SMDSAbs_Face :
9583       {
9584         switch(nbNodes)
9585         {
9586         case 3:
9587           NewElem = theHelper.AddFace(nodes[0], nodes[1], nodes[2], id, theForce3d);
9588           break;
9589         case 4:
9590           NewElem = theHelper.AddFace(nodes[0], nodes[1], nodes[2], nodes[3], id, theForce3d);
9591           break;
9592         default:
9593           NewElem = theHelper.AddPolygonalFace(nodes, id, theForce3d);
9594           continue;
9595         }
9596         break;
9597       }
9598     case SMDSAbs_Volume :
9599       {
9600         switch( aGeomType )
9601         {
9602         case SMDSEntity_Tetra:
9603           NewElem = theHelper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3], id, theForce3d);
9604           break;
9605         case SMDSEntity_Pyramid:
9606           NewElem = theHelper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3], nodes[4], id, theForce3d);
9607           break;
9608         case SMDSEntity_Penta:
9609           NewElem = theHelper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3], nodes[4], nodes[5], id, theForce3d);
9610           break;
9611         case SMDSEntity_Hexa:
9612           NewElem = theHelper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3],
9613                                         nodes[4], nodes[5], nodes[6], nodes[7], id, theForce3d);
9614           break;
9615         case SMDSEntity_Hexagonal_Prism:
9616         default:
9617           NewElem = theHelper.AddPolyhedralVolume(nodes, nbNodeInFaces, id, theForce3d);
9618         }
9619         break;
9620       }
9621     default :
9622       continue;
9623     }
9624     ReplaceElemInGroups( elem, NewElem, GetMeshDS());
9625     if( NewElem )
9626       theSm->AddElement( NewElem );
9627   }
9628   return nbElem;
9629 }
9630
9631 //=======================================================================
9632 //function : ConvertToQuadratic
9633 //purpose  :
9634 //=======================================================================
9635
9636 void SMESH_MeshEditor::ConvertToQuadratic(const bool theForce3d)
9637 {
9638   SMESHDS_Mesh* meshDS = GetMeshDS();
9639
9640   SMESH_MesherHelper aHelper(*myMesh);
9641   aHelper.SetIsQuadratic( true );
9642
9643   int nbCheckedElems = 0;
9644   if ( myMesh->HasShapeToMesh() )
9645   {
9646     if ( SMESH_subMesh *aSubMesh = myMesh->GetSubMeshContaining(myMesh->GetShapeToMesh()))
9647     {
9648       SMESH_subMeshIteratorPtr smIt = aSubMesh->getDependsOnIterator(true,false);
9649       while ( smIt->more() ) {
9650         SMESH_subMesh* sm = smIt->next();
9651         if ( SMESHDS_SubMesh *smDS = sm->GetSubMeshDS() ) {
9652           aHelper.SetSubShape( sm->GetSubShape() );
9653           nbCheckedElems += convertElemToQuadratic(smDS, aHelper, theForce3d);
9654         }
9655       }
9656     }
9657   }
9658   int totalNbElems = meshDS->NbEdges() + meshDS->NbFaces() + meshDS->NbVolumes();
9659   if ( nbCheckedElems < totalNbElems ) // not all elements are in submeshes
9660   {
9661     SMESHDS_SubMesh *smDS = 0;
9662     SMDS_EdgeIteratorPtr aEdgeItr = meshDS->edgesIterator();
9663     while(aEdgeItr->more())
9664     {
9665       const SMDS_MeshEdge* edge = aEdgeItr->next();
9666       if(edge && !edge->IsQuadratic())
9667       {
9668         int id = edge->GetID();
9669         //MESSAGE("edge->GetID() " << id);
9670         const SMDS_MeshNode* n1 = edge->GetNode(0);
9671         const SMDS_MeshNode* n2 = edge->GetNode(1);
9672
9673         meshDS->RemoveFreeElement(edge, smDS, /*fromGroups=*/false);
9674
9675         const SMDS_MeshEdge* NewEdge = aHelper.AddEdge(n1, n2, id, theForce3d);
9676         ReplaceElemInGroups( edge, NewEdge, GetMeshDS());
9677       }
9678     }
9679     SMDS_FaceIteratorPtr aFaceItr = meshDS->facesIterator();
9680     while(aFaceItr->more())
9681     {
9682       const SMDS_MeshFace* face = aFaceItr->next();
9683       if(!face || face->IsQuadratic() ) continue;
9684
9685       const int id = face->GetID();
9686       const SMDSAbs_EntityType type = face->GetEntityType();
9687       vector<const SMDS_MeshNode *> nodes ( face->begin_nodes(), face->end_nodes());
9688
9689       meshDS->RemoveFreeElement(face, smDS, /*fromGroups=*/false);
9690
9691       SMDS_MeshFace * NewFace = 0;
9692       switch( type )
9693       {
9694       case SMDSEntity_Triangle:
9695         NewFace = aHelper.AddFace(nodes[0], nodes[1], nodes[2], id, theForce3d);
9696         break;
9697       case SMDSEntity_Quadrangle:
9698         NewFace = aHelper.AddFace(nodes[0], nodes[1], nodes[2], nodes[3], id, theForce3d);
9699         break;
9700       default:
9701         NewFace = aHelper.AddPolygonalFace(nodes, id, theForce3d);
9702       }
9703       ReplaceElemInGroups( face, NewFace, GetMeshDS());
9704     }
9705     vector<int> nbNodeInFaces;
9706     SMDS_VolumeIteratorPtr aVolumeItr = meshDS->volumesIterator();
9707     while(aVolumeItr->more())
9708     {
9709       const SMDS_MeshVolume* volume = aVolumeItr->next();
9710       if(!volume || volume->IsQuadratic() ) continue;
9711
9712       const int id = volume->GetID();
9713       const SMDSAbs_EntityType type = volume->GetEntityType();
9714       vector<const SMDS_MeshNode *> nodes (volume->begin_nodes(), volume->end_nodes());
9715       if ( type == SMDSEntity_Polyhedra )
9716         nbNodeInFaces = static_cast<const SMDS_VtkVolume* >(volume)->GetQuantities();
9717       else if ( type == SMDSEntity_Hexagonal_Prism )
9718         volumeToPolyhedron( volume, nodes, nbNodeInFaces );
9719
9720       meshDS->RemoveFreeElement(volume, smDS, /*fromGroups=*/false);
9721
9722       SMDS_MeshVolume * NewVolume = 0;
9723       switch ( type )
9724       {
9725       case SMDSEntity_Tetra:
9726         NewVolume = aHelper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3], id, theForce3d );
9727         break;
9728       case SMDSEntity_Hexa:
9729         NewVolume = aHelper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3],
9730                                       nodes[4], nodes[5], nodes[6], nodes[7], id, theForce3d);
9731         break;
9732       case SMDSEntity_Pyramid:
9733         NewVolume = aHelper.AddVolume(nodes[0], nodes[1], nodes[2],
9734                                       nodes[3], nodes[4], id, theForce3d);
9735         break;
9736       case SMDSEntity_Penta:
9737         NewVolume = aHelper.AddVolume(nodes[0], nodes[1], nodes[2],
9738                                       nodes[3], nodes[4], nodes[5], id, theForce3d);
9739         break;
9740       case SMDSEntity_Hexagonal_Prism:
9741       default:
9742         NewVolume = aHelper.AddPolyhedralVolume(nodes, nbNodeInFaces, id, theForce3d);
9743       }
9744       ReplaceElemInGroups(volume, NewVolume, meshDS);
9745     }
9746   }
9747
9748   if ( !theForce3d )
9749   { // setenv NO_FixQuadraticElements to know if FixQuadraticElements() is guilty of bad conversion
9750     aHelper.SetSubShape(0); // apply FixQuadraticElements() to the whole mesh
9751     aHelper.FixQuadraticElements(myError);
9752   }
9753 }
9754
9755 //================================================================================
9756 /*!
9757  * \brief Makes given elements quadratic
9758  *  \param theForce3d - if true, the medium nodes will be placed in the middle of link
9759  *  \param theElements - elements to make quadratic
9760  */
9761 //================================================================================
9762
9763 void SMESH_MeshEditor::ConvertToQuadratic(const bool        theForce3d,
9764                                           TIDSortedElemSet& theElements)
9765 {
9766   if ( theElements.empty() ) return;
9767
9768   // we believe that all theElements are of the same type
9769   const SMDSAbs_ElementType elemType = (*theElements.begin())->GetType();
9770
9771   // get all nodes shared by theElements
9772   TIDSortedNodeSet allNodes;
9773   TIDSortedElemSet::iterator eIt = theElements.begin();
9774   for ( ; eIt != theElements.end(); ++eIt )
9775     allNodes.insert( (*eIt)->begin_nodes(), (*eIt)->end_nodes() );
9776
9777   // complete theElements with elements of lower dim whose all nodes are in allNodes
9778
9779   TIDSortedElemSet quadAdjacentElems    [ SMDSAbs_NbElementTypes ]; // quadratic adjacent elements
9780   TIDSortedElemSet checkedAdjacentElems [ SMDSAbs_NbElementTypes ];
9781   TIDSortedNodeSet::iterator nIt = allNodes.begin();
9782   for ( ; nIt != allNodes.end(); ++nIt )
9783   {
9784     const SMDS_MeshNode* n = *nIt;
9785     SMDS_ElemIteratorPtr invIt = n->GetInverseElementIterator();
9786     while ( invIt->more() )
9787     {
9788       const SMDS_MeshElement* e = invIt->next();
9789       if ( e->IsQuadratic() )
9790       {
9791         quadAdjacentElems[ e->GetType() ].insert( e );
9792         continue;
9793       }
9794       if ( e->GetType() >= elemType )
9795       {
9796         continue; // same type of more complex linear element
9797       }
9798
9799       if ( !checkedAdjacentElems[ e->GetType() ].insert( e ).second )
9800         continue; // e is already checked
9801
9802       // check nodes
9803       bool allIn = true;
9804       SMDS_ElemIteratorPtr nodeIt = e->nodesIterator();
9805       while ( nodeIt->more() && allIn )
9806         allIn = allNodes.count( cast2Node( nodeIt->next() ));
9807       if ( allIn )
9808         theElements.insert(e );
9809     }
9810   }
9811
9812   SMESH_MesherHelper helper(*myMesh);
9813   helper.SetIsQuadratic( true );
9814
9815   // add links of quadratic adjacent elements to the helper
9816
9817   if ( !quadAdjacentElems[SMDSAbs_Edge].empty() )
9818     for ( eIt  = quadAdjacentElems[SMDSAbs_Edge].begin();
9819           eIt != quadAdjacentElems[SMDSAbs_Edge].end(); ++eIt )
9820     {
9821       helper.AddTLinks( static_cast< const SMDS_MeshEdge*> (*eIt) );
9822     }
9823   if ( !quadAdjacentElems[SMDSAbs_Face].empty() )
9824     for ( eIt  = quadAdjacentElems[SMDSAbs_Face].begin();
9825           eIt != quadAdjacentElems[SMDSAbs_Face].end(); ++eIt )
9826     {
9827       helper.AddTLinks( static_cast< const SMDS_MeshFace*> (*eIt) );
9828     }
9829   if ( !quadAdjacentElems[SMDSAbs_Volume].empty() )
9830     for ( eIt  = quadAdjacentElems[SMDSAbs_Volume].begin();
9831           eIt != quadAdjacentElems[SMDSAbs_Volume].end(); ++eIt )
9832     {
9833       helper.AddTLinks( static_cast< const SMDS_MeshVolume*> (*eIt) );
9834     }
9835
9836   // make quadratic elements instead of linear ones
9837
9838   SMESHDS_Mesh* meshDS = GetMeshDS();
9839   SMESHDS_SubMesh* smDS = 0;
9840   for ( eIt = theElements.begin(); eIt != theElements.end(); ++eIt )
9841   {
9842     const SMDS_MeshElement* elem = *eIt;
9843     if( elem->IsQuadratic() || elem->NbNodes() < 2 || elem->IsPoly() )
9844       continue;
9845
9846     const int id                   = elem->GetID();
9847     const SMDSAbs_ElementType type = elem->GetType();
9848     vector<const SMDS_MeshNode *> nodes ( elem->begin_nodes(), elem->end_nodes());
9849
9850     if ( !smDS || !smDS->Contains( elem ))
9851       smDS = meshDS->MeshElements( elem->getshapeId() );
9852     meshDS->RemoveFreeElement(elem, smDS, /*fromGroups=*/false);
9853
9854     SMDS_MeshElement * newElem = 0;
9855     switch( nodes.size() )
9856     {
9857     case 4: // cases for most frequently used element types go first (for optimization)
9858       if ( type == SMDSAbs_Volume )
9859         newElem = helper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3], id, theForce3d);
9860       else
9861         newElem = helper.AddFace  (nodes[0], nodes[1], nodes[2], nodes[3], id, theForce3d);
9862       break;
9863     case 8:
9864       newElem = helper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3],
9865                                  nodes[4], nodes[5], nodes[6], nodes[7], id, theForce3d);
9866       break;
9867     case 3:
9868       newElem = helper.AddFace  (nodes[0], nodes[1], nodes[2], id, theForce3d);
9869       break;
9870     case 2:
9871       newElem = helper.AddEdge(nodes[0], nodes[1], id, theForce3d);
9872       break;
9873     case 5:
9874       newElem = helper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3],
9875                                  nodes[4], id, theForce3d);
9876       break;
9877     case 6:
9878       newElem = helper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3],
9879                                  nodes[4], nodes[5], id, theForce3d);
9880       break;
9881     default:;
9882     }
9883     ReplaceElemInGroups( elem, newElem, meshDS);
9884     if( newElem && smDS )
9885       smDS->AddElement( newElem );
9886   }
9887
9888   if ( !theForce3d  && !getenv("NO_FixQuadraticElements"))
9889   { // setenv NO_FixQuadraticElements to know if FixQuadraticElements() is guilty of bad conversion
9890     helper.SetSubShape(0); // apply FixQuadraticElements() to the whole mesh
9891     helper.FixQuadraticElements( myError );
9892   }
9893 }
9894
9895 //=======================================================================
9896 /*!
9897  * \brief Convert quadratic elements to linear ones and remove quadratic nodes
9898  * \return int - nb of checked elements
9899  */
9900 //=======================================================================
9901
9902 int SMESH_MeshEditor::removeQuadElem(SMESHDS_SubMesh *    theSm,
9903                                      SMDS_ElemIteratorPtr theItr,
9904                                      const int            theShapeID)
9905 {
9906   int nbElem = 0;
9907   SMESHDS_Mesh* meshDS = GetMeshDS();
9908
9909   while( theItr->more() )
9910   {
9911     const SMDS_MeshElement* elem = theItr->next();
9912     nbElem++;
9913     if( elem && elem->IsQuadratic())
9914     {
9915       int id                    = elem->GetID();
9916       int nbCornerNodes         = elem->NbCornerNodes();
9917       SMDSAbs_ElementType aType = elem->GetType();
9918
9919       vector<const SMDS_MeshNode *> nodes( elem->begin_nodes(), elem->end_nodes() );
9920
9921       //remove a quadratic element
9922       if ( !theSm || !theSm->Contains( elem ))
9923         theSm = meshDS->MeshElements( elem->getshapeId() );
9924       meshDS->RemoveFreeElement( elem, theSm, /*fromGroups=*/false );
9925
9926       // remove medium nodes
9927       for ( unsigned i = nbCornerNodes; i < nodes.size(); ++i )
9928         if ( nodes[i]->NbInverseElements() == 0 )
9929           meshDS->RemoveFreeNode( nodes[i], theSm );
9930
9931       // add a linear element
9932       nodes.resize( nbCornerNodes );
9933       SMDS_MeshElement * newElem = AddElement( nodes, aType, false, id );
9934       ReplaceElemInGroups(elem, newElem, meshDS);
9935       if( theSm && newElem )
9936         theSm->AddElement( newElem );
9937     }
9938   }
9939   return nbElem;
9940 }
9941
9942 //=======================================================================
9943 //function : ConvertFromQuadratic
9944 //purpose  :
9945 //=======================================================================
9946
9947 bool SMESH_MeshEditor::ConvertFromQuadratic()
9948 {
9949   int nbCheckedElems = 0;
9950   if ( myMesh->HasShapeToMesh() )
9951   {
9952     if ( SMESH_subMesh *aSubMesh = myMesh->GetSubMeshContaining(myMesh->GetShapeToMesh()))
9953     {
9954       SMESH_subMeshIteratorPtr smIt = aSubMesh->getDependsOnIterator(true,false);
9955       while ( smIt->more() ) {
9956         SMESH_subMesh* sm = smIt->next();
9957         if ( SMESHDS_SubMesh *smDS = sm->GetSubMeshDS() )
9958           nbCheckedElems += removeQuadElem( smDS, smDS->GetElements(), sm->GetId() );
9959       }
9960     }
9961   }
9962
9963   int totalNbElems =
9964     GetMeshDS()->NbEdges() + GetMeshDS()->NbFaces() + GetMeshDS()->NbVolumes();
9965   if ( nbCheckedElems < totalNbElems ) // not all elements are in submeshes
9966   {
9967     SMESHDS_SubMesh *aSM = 0;
9968     removeQuadElem( aSM, GetMeshDS()->elementsIterator(), 0 );
9969   }
9970
9971   return true;
9972 }
9973
9974 namespace
9975 {
9976   //================================================================================
9977   /*!
9978    * \brief Return true if all medium nodes of the element are in the node set
9979    */
9980   //================================================================================
9981
9982   bool allMediumNodesIn(const SMDS_MeshElement* elem, TIDSortedNodeSet& nodeSet )
9983   {
9984     for ( int i = elem->NbCornerNodes(); i < elem->NbNodes(); ++i )
9985       if ( !nodeSet.count( elem->GetNode(i) ))
9986         return false;
9987     return true;
9988   }
9989 }
9990
9991 //================================================================================
9992 /*!
9993  * \brief Makes given elements linear
9994  */
9995 //================================================================================
9996
9997 void SMESH_MeshEditor::ConvertFromQuadratic(TIDSortedElemSet& theElements)
9998 {
9999   if ( theElements.empty() ) return;
10000
10001   // collect IDs of medium nodes of theElements; some of these nodes will be removed
10002   set<int> mediumNodeIDs;
10003   TIDSortedElemSet::iterator eIt = theElements.begin();
10004   for ( ; eIt != theElements.end(); ++eIt )
10005   {
10006     const SMDS_MeshElement* e = *eIt;
10007     for ( int i = e->NbCornerNodes(); i < e->NbNodes(); ++i )
10008       mediumNodeIDs.insert( e->GetNode(i)->GetID() );
10009   }
10010
10011   // replace given elements by linear ones
10012   typedef SMDS_SetIterator<const SMDS_MeshElement*, TIDSortedElemSet::iterator> TSetIterator;
10013   SMDS_ElemIteratorPtr elemIt( new TSetIterator( theElements.begin(), theElements.end() ));
10014   removeQuadElem( /*theSm=*/0, elemIt, /*theShapeID=*/0 );
10015
10016   // we need to convert remaining elements whose all medium nodes are in mediumNodeIDs
10017   // except those elements sharing medium nodes of quadratic element whose medium nodes
10018   // are not all in mediumNodeIDs
10019
10020   // get remaining medium nodes
10021   TIDSortedNodeSet mediumNodes;
10022   set<int>::iterator nIdsIt = mediumNodeIDs.begin();
10023   for ( ; nIdsIt != mediumNodeIDs.end(); ++nIdsIt )
10024     if ( const SMDS_MeshNode* n = GetMeshDS()->FindNode( *nIdsIt ))
10025       mediumNodes.insert( mediumNodes.end(), n );
10026
10027   // find more quadratic elements to convert
10028   TIDSortedElemSet moreElemsToConvert;
10029   TIDSortedNodeSet::iterator nIt = mediumNodes.begin();
10030   for ( ; nIt != mediumNodes.end(); ++nIt )
10031   {
10032     SMDS_ElemIteratorPtr invIt = (*nIt)->GetInverseElementIterator();
10033     while ( invIt->more() )
10034     {
10035       const SMDS_MeshElement* e = invIt->next();
10036       if ( e->IsQuadratic() && allMediumNodesIn( e, mediumNodes ))
10037       {
10038         // find a more complex element including e and
10039         // whose medium nodes are not in mediumNodes
10040         bool complexFound = false;
10041         for ( int type = e->GetType() + 1; type < SMDSAbs_0DElement; ++type )
10042         {
10043           SMDS_ElemIteratorPtr invIt2 =
10044             (*nIt)->GetInverseElementIterator( SMDSAbs_ElementType( type ));
10045           while ( invIt2->more() )
10046           {
10047             const SMDS_MeshElement* eComplex = invIt2->next();
10048             if ( eComplex->IsQuadratic() && !allMediumNodesIn( eComplex, mediumNodes))
10049             {
10050               int nbCommonNodes = SMESH_Algo::GetCommonNodes( e, eComplex ).size();
10051               if ( nbCommonNodes == e->NbNodes())
10052               {
10053                 complexFound = true;
10054                 type = SMDSAbs_NbElementTypes; // to quit from the outer loop
10055                 break;
10056               }
10057             }
10058           }
10059         }
10060         if ( !complexFound )
10061           moreElemsToConvert.insert( e );
10062       }
10063     }
10064   }
10065   elemIt = SMDS_ElemIteratorPtr
10066     (new TSetIterator( moreElemsToConvert.begin(), moreElemsToConvert.end() ));
10067   removeQuadElem( /*theSm=*/0, elemIt, /*theShapeID=*/0 );
10068 }
10069
10070 //=======================================================================
10071 //function : SewSideElements
10072 //purpose  :
10073 //=======================================================================
10074
10075 SMESH_MeshEditor::Sew_Error
10076 SMESH_MeshEditor::SewSideElements (TIDSortedElemSet&    theSide1,
10077                                    TIDSortedElemSet&    theSide2,
10078                                    const SMDS_MeshNode* theFirstNode1,
10079                                    const SMDS_MeshNode* theFirstNode2,
10080                                    const SMDS_MeshNode* theSecondNode1,
10081                                    const SMDS_MeshNode* theSecondNode2)
10082 {
10083   myLastCreatedElems.Clear();
10084   myLastCreatedNodes.Clear();
10085
10086   MESSAGE ("::::SewSideElements()");
10087   if ( theSide1.size() != theSide2.size() )
10088     return SEW_DIFF_NB_OF_ELEMENTS;
10089
10090   Sew_Error aResult = SEW_OK;
10091   // Algo:
10092   // 1. Build set of faces representing each side
10093   // 2. Find which nodes of the side 1 to merge with ones on the side 2
10094   // 3. Replace nodes in elements of the side 1 and remove replaced nodes
10095
10096   // =======================================================================
10097   // 1. Build set of faces representing each side:
10098   // =======================================================================
10099   // a. build set of nodes belonging to faces
10100   // b. complete set of faces: find missing faces whose nodes are in set of nodes
10101   // c. create temporary faces representing side of volumes if correspondent
10102   //    face does not exist
10103
10104   SMESHDS_Mesh* aMesh = GetMeshDS();
10105   // TODO algoritm not OK with vtkUnstructuredGrid: 2 meshes can't share nodes
10106   //SMDS_Mesh aTmpFacesMesh; // try to use the same mesh
10107   TIDSortedElemSet             faceSet1, faceSet2;
10108   set<const SMDS_MeshElement*> volSet1,  volSet2;
10109   set<const SMDS_MeshNode*>    nodeSet1, nodeSet2;
10110   TIDSortedElemSet             * faceSetPtr[] = { &faceSet1, &faceSet2 };
10111   set<const SMDS_MeshElement*> *  volSetPtr[] = { &volSet1,  &volSet2  };
10112   set<const SMDS_MeshNode*>    * nodeSetPtr[] = { &nodeSet1, &nodeSet2 };
10113   TIDSortedElemSet             * elemSetPtr[] = { &theSide1, &theSide2 };
10114   int iSide, iFace, iNode;
10115
10116   list<const SMDS_MeshElement* > tempFaceList;
10117   for ( iSide = 0; iSide < 2; iSide++ ) {
10118     set<const SMDS_MeshNode*>    * nodeSet = nodeSetPtr[ iSide ];
10119     TIDSortedElemSet             * elemSet = elemSetPtr[ iSide ];
10120     TIDSortedElemSet             * faceSet = faceSetPtr[ iSide ];
10121     set<const SMDS_MeshElement*> * volSet  = volSetPtr [ iSide ];
10122     set<const SMDS_MeshElement*>::iterator vIt;
10123     TIDSortedElemSet::iterator eIt;
10124     set<const SMDS_MeshNode*>::iterator    nIt;
10125
10126     // check that given nodes belong to given elements
10127     const SMDS_MeshNode* n1 = ( iSide == 0 ) ? theFirstNode1 : theFirstNode2;
10128     const SMDS_MeshNode* n2 = ( iSide == 0 ) ? theSecondNode1 : theSecondNode2;
10129     int firstIndex = -1, secondIndex = -1;
10130     for (eIt = elemSet->begin(); eIt != elemSet->end(); eIt++ ) {
10131       const SMDS_MeshElement* elem = *eIt;
10132       if ( firstIndex  < 0 ) firstIndex  = elem->GetNodeIndex( n1 );
10133       if ( secondIndex < 0 ) secondIndex = elem->GetNodeIndex( n2 );
10134       if ( firstIndex > -1 && secondIndex > -1 ) break;
10135     }
10136     if ( firstIndex < 0 || secondIndex < 0 ) {
10137       // we can simply return until temporary faces created
10138       return (iSide == 0 ) ? SEW_BAD_SIDE1_NODES : SEW_BAD_SIDE2_NODES;
10139     }
10140
10141     // -----------------------------------------------------------
10142     // 1a. Collect nodes of existing faces
10143     //     and build set of face nodes in order to detect missing
10144     //     faces corresponding to sides of volumes
10145     // -----------------------------------------------------------
10146
10147     set< set <const SMDS_MeshNode*> > setOfFaceNodeSet;
10148
10149     // loop on the given element of a side
10150     for (eIt = elemSet->begin(); eIt != elemSet->end(); eIt++ ) {
10151       //const SMDS_MeshElement* elem = *eIt;
10152       const SMDS_MeshElement* elem = *eIt;
10153       if ( elem->GetType() == SMDSAbs_Face ) {
10154         faceSet->insert( elem );
10155         set <const SMDS_MeshNode*> faceNodeSet;
10156         SMDS_ElemIteratorPtr nodeIt = elem->nodesIterator();
10157         while ( nodeIt->more() ) {
10158           const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
10159           nodeSet->insert( n );
10160           faceNodeSet.insert( n );
10161         }
10162         setOfFaceNodeSet.insert( faceNodeSet );
10163       }
10164       else if ( elem->GetType() == SMDSAbs_Volume )
10165         volSet->insert( elem );
10166     }
10167     // ------------------------------------------------------------------------------
10168     // 1b. Complete set of faces: find missing faces whose nodes are in set of nodes
10169     // ------------------------------------------------------------------------------
10170
10171     for ( nIt = nodeSet->begin(); nIt != nodeSet->end(); nIt++ ) { // loop on nodes of iSide
10172       SMDS_ElemIteratorPtr fIt = (*nIt)->GetInverseElementIterator(SMDSAbs_Face);
10173       while ( fIt->more() ) { // loop on faces sharing a node
10174         const SMDS_MeshElement* f = fIt->next();
10175         if ( faceSet->find( f ) == faceSet->end() ) {
10176           // check if all nodes are in nodeSet and
10177           // complete setOfFaceNodeSet if they are
10178           set <const SMDS_MeshNode*> faceNodeSet;
10179           SMDS_ElemIteratorPtr nodeIt = f->nodesIterator();
10180           bool allInSet = true;
10181           while ( nodeIt->more() && allInSet ) { // loop on nodes of a face
10182             const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
10183             if ( nodeSet->find( n ) == nodeSet->end() )
10184               allInSet = false;
10185             else
10186               faceNodeSet.insert( n );
10187           }
10188           if ( allInSet ) {
10189             faceSet->insert( f );
10190             setOfFaceNodeSet.insert( faceNodeSet );
10191           }
10192         }
10193       }
10194     }
10195
10196     // -------------------------------------------------------------------------
10197     // 1c. Create temporary faces representing sides of volumes if correspondent
10198     //     face does not exist
10199     // -------------------------------------------------------------------------
10200
10201     if ( !volSet->empty() ) {
10202       //int nodeSetSize = nodeSet->size();
10203
10204       // loop on given volumes
10205       for ( vIt = volSet->begin(); vIt != volSet->end(); vIt++ ) {
10206         SMDS_VolumeTool vol (*vIt);
10207         // loop on volume faces: find free faces
10208         // --------------------------------------
10209         list<const SMDS_MeshElement* > freeFaceList;
10210         for ( iFace = 0; iFace < vol.NbFaces(); iFace++ ) {
10211           if ( !vol.IsFreeFace( iFace ))
10212             continue;
10213           // check if there is already a face with same nodes in a face set
10214           const SMDS_MeshElement* aFreeFace = 0;
10215           const SMDS_MeshNode** fNodes = vol.GetFaceNodes( iFace );
10216           int nbNodes = vol.NbFaceNodes( iFace );
10217           set <const SMDS_MeshNode*> faceNodeSet;
10218           vol.GetFaceNodes( iFace, faceNodeSet );
10219           bool isNewFace = setOfFaceNodeSet.insert( faceNodeSet ).second;
10220           if ( isNewFace ) {
10221             // no such a face is given but it still can exist, check it
10222             vector<const SMDS_MeshNode *> nodes ( fNodes, fNodes + nbNodes);
10223             aFreeFace = aMesh->FindElement( nodes, SMDSAbs_Face, /*noMedium=*/false );
10224           }
10225           if ( !aFreeFace ) {
10226             // create a temporary face
10227             if ( nbNodes == 3 ) {
10228               //aFreeFace = aTmpFacesMesh.AddFace( fNodes[0],fNodes[1],fNodes[2] );
10229               aFreeFace = aMesh->AddFace( fNodes[0],fNodes[1],fNodes[2] );
10230             }
10231             else if ( nbNodes == 4 ) {
10232               //aFreeFace = aTmpFacesMesh.AddFace( fNodes[0],fNodes[1],fNodes[2],fNodes[3] );
10233               aFreeFace = aMesh->AddFace( fNodes[0],fNodes[1],fNodes[2],fNodes[3] );
10234             }
10235             else {
10236               vector<const SMDS_MeshNode *> poly_nodes ( fNodes, & fNodes[nbNodes]);
10237               //aFreeFace = aTmpFacesMesh.AddPolygonalFace(poly_nodes);
10238               aFreeFace = aMesh->AddPolygonalFace(poly_nodes);
10239             }
10240             if ( aFreeFace )
10241               tempFaceList.push_back( aFreeFace );
10242           }
10243
10244           if ( aFreeFace )
10245             freeFaceList.push_back( aFreeFace );
10246
10247         } // loop on faces of a volume
10248
10249         // choose one of several free faces of a volume
10250         // --------------------------------------------
10251         if ( freeFaceList.size() > 1 ) {
10252           // choose a face having max nb of nodes shared by other elems of a side
10253           int maxNbNodes = -1;
10254           list<const SMDS_MeshElement* >::iterator fIt = freeFaceList.begin();
10255           while ( fIt != freeFaceList.end() ) { // loop on free faces
10256             int nbSharedNodes = 0;
10257             SMDS_ElemIteratorPtr nodeIt = (*fIt)->nodesIterator();
10258             while ( nodeIt->more() ) { // loop on free face nodes
10259               const SMDS_MeshNode* n =
10260                 static_cast<const SMDS_MeshNode*>( nodeIt->next() );
10261               SMDS_ElemIteratorPtr invElemIt = n->GetInverseElementIterator();
10262               while ( invElemIt->more() ) {
10263                 const SMDS_MeshElement* e = invElemIt->next();
10264                 nbSharedNodes += faceSet->count( e );
10265                 nbSharedNodes += elemSet->count( e );
10266               }
10267             }
10268             if ( nbSharedNodes > maxNbNodes ) {
10269               maxNbNodes = nbSharedNodes;
10270               freeFaceList.erase( freeFaceList.begin(), fIt++ );
10271             }
10272             else if ( nbSharedNodes == maxNbNodes ) {
10273               fIt++;
10274             }
10275             else {
10276               freeFaceList.erase( fIt++ ); // here fIt++ occurs before erase
10277             }
10278           }
10279           if ( freeFaceList.size() > 1 )
10280           {
10281             // could not choose one face, use another way
10282             // choose a face most close to the bary center of the opposite side
10283             gp_XYZ aBC( 0., 0., 0. );
10284             set <const SMDS_MeshNode*> addedNodes;
10285             TIDSortedElemSet * elemSet2 = elemSetPtr[ 1 - iSide ];
10286             eIt = elemSet2->begin();
10287             for ( eIt = elemSet2->begin(); eIt != elemSet2->end(); eIt++ ) {
10288               SMDS_ElemIteratorPtr nodeIt = (*eIt)->nodesIterator();
10289               while ( nodeIt->more() ) { // loop on free face nodes
10290                 const SMDS_MeshNode* n =
10291                   static_cast<const SMDS_MeshNode*>( nodeIt->next() );
10292                 if ( addedNodes.insert( n ).second )
10293                   aBC += gp_XYZ( n->X(),n->Y(),n->Z() );
10294               }
10295             }
10296             aBC /= addedNodes.size();
10297             double minDist = DBL_MAX;
10298             fIt = freeFaceList.begin();
10299             while ( fIt != freeFaceList.end() ) { // loop on free faces
10300               double dist = 0;
10301               SMDS_ElemIteratorPtr nodeIt = (*fIt)->nodesIterator();
10302               while ( nodeIt->more() ) { // loop on free face nodes
10303                 const SMDS_MeshNode* n =
10304                   static_cast<const SMDS_MeshNode*>( nodeIt->next() );
10305                 gp_XYZ p( n->X(),n->Y(),n->Z() );
10306                 dist += ( aBC - p ).SquareModulus();
10307               }
10308               if ( dist < minDist ) {
10309                 minDist = dist;
10310                 freeFaceList.erase( freeFaceList.begin(), fIt++ );
10311               }
10312               else
10313                 fIt = freeFaceList.erase( fIt++ );
10314             }
10315           }
10316         } // choose one of several free faces of a volume
10317
10318         if ( freeFaceList.size() == 1 ) {
10319           const SMDS_MeshElement* aFreeFace = freeFaceList.front();
10320           faceSet->insert( aFreeFace );
10321           // complete a node set with nodes of a found free face
10322           //           for ( iNode = 0; iNode < ; iNode++ )
10323           //             nodeSet->insert( fNodes[ iNode ] );
10324         }
10325
10326       } // loop on volumes of a side
10327
10328       //       // complete a set of faces if new nodes in a nodeSet appeared
10329       //       // ----------------------------------------------------------
10330       //       if ( nodeSetSize != nodeSet->size() ) {
10331       //         for ( ; nIt != nodeSet->end(); nIt++ ) { // loop on nodes of iSide
10332       //           SMDS_ElemIteratorPtr fIt = (*nIt)->GetInverseElementIterator(SMDSAbs_Face);
10333       //           while ( fIt->more() ) { // loop on faces sharing a node
10334       //             const SMDS_MeshElement* f = fIt->next();
10335       //             if ( faceSet->find( f ) == faceSet->end() ) {
10336       //               // check if all nodes are in nodeSet and
10337       //               // complete setOfFaceNodeSet if they are
10338       //               set <const SMDS_MeshNode*> faceNodeSet;
10339       //               SMDS_ElemIteratorPtr nodeIt = f->nodesIterator();
10340       //               bool allInSet = true;
10341       //               while ( nodeIt->more() && allInSet ) { // loop on nodes of a face
10342       //                 const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
10343       //                 if ( nodeSet->find( n ) == nodeSet->end() )
10344       //                   allInSet = false;
10345       //                 else
10346       //                   faceNodeSet.insert( n );
10347       //               }
10348       //               if ( allInSet ) {
10349       //                 faceSet->insert( f );
10350       //                 setOfFaceNodeSet.insert( faceNodeSet );
10351       //               }
10352       //             }
10353       //           }
10354       //         }
10355       //       }
10356     } // Create temporary faces, if there are volumes given
10357   } // loop on sides
10358
10359   if ( faceSet1.size() != faceSet2.size() ) {
10360     // delete temporary faces: they are in reverseElements of actual nodes
10361 //    SMDS_FaceIteratorPtr tmpFaceIt = aTmpFacesMesh.facesIterator();
10362 //    while ( tmpFaceIt->more() )
10363 //      aTmpFacesMesh.RemoveElement( tmpFaceIt->next() );
10364 //    list<const SMDS_MeshElement* >::iterator tmpFaceIt = tempFaceList.begin();
10365 //    for (; tmpFaceIt !=tempFaceList.end(); ++tmpFaceIt)
10366 //      aMesh->RemoveElement(*tmpFaceIt);
10367     MESSAGE("Diff nb of faces");
10368     return SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
10369   }
10370
10371   // ============================================================
10372   // 2. Find nodes to merge:
10373   //              bind a node to remove to a node to put instead
10374   // ============================================================
10375
10376   TNodeNodeMap nReplaceMap; // bind a node to remove to a node to put instead
10377   if ( theFirstNode1 != theFirstNode2 )
10378     nReplaceMap.insert( make_pair( theFirstNode1, theFirstNode2 ));
10379   if ( theSecondNode1 != theSecondNode2 )
10380     nReplaceMap.insert( make_pair( theSecondNode1, theSecondNode2 ));
10381
10382   LinkID_Gen aLinkID_Gen( GetMeshDS() );
10383   set< long > linkIdSet; // links to process
10384   linkIdSet.insert( aLinkID_Gen.GetLinkID( theFirstNode1, theSecondNode1 ));
10385
10386   typedef pair< const SMDS_MeshNode*, const SMDS_MeshNode* > NLink;
10387   list< NLink > linkList[2];
10388   linkList[0].push_back( NLink( theFirstNode1, theSecondNode1 ));
10389   linkList[1].push_back( NLink( theFirstNode2, theSecondNode2 ));
10390   // loop on links in linkList; find faces by links and append links
10391   // of the found faces to linkList
10392   list< NLink >::iterator linkIt[] = { linkList[0].begin(), linkList[1].begin() } ;
10393   for ( ; linkIt[0] != linkList[0].end(); linkIt[0]++, linkIt[1]++ )
10394   {
10395     NLink link[] = { *linkIt[0], *linkIt[1] };
10396     long linkID = aLinkID_Gen.GetLinkID( link[0].first, link[0].second );
10397     if ( !linkIdSet.count( linkID ) )
10398       continue;
10399
10400     // by links, find faces in the face sets,
10401     // and find indices of link nodes in the found faces;
10402     // in a face set, there is only one or no face sharing a link
10403     // ---------------------------------------------------------------
10404
10405     const SMDS_MeshElement* face[] = { 0, 0 };
10406     vector<const SMDS_MeshNode*> fnodes[2];
10407     int iLinkNode[2][2];
10408     TIDSortedElemSet avoidSet;
10409     for ( iSide = 0; iSide < 2; iSide++ ) { // loop on 2 sides
10410       const SMDS_MeshNode* n1 = link[iSide].first;
10411       const SMDS_MeshNode* n2 = link[iSide].second;
10412       //cout << "Side " << iSide << " ";
10413       //cout << "L( " << n1->GetID() << ", " << n2->GetID() << " ) " << endl;
10414       // find a face by two link nodes
10415       face[ iSide ] = FindFaceInSet( n1, n2, *faceSetPtr[ iSide ], avoidSet,
10416                                      &iLinkNode[iSide][0], &iLinkNode[iSide][1] );
10417       if ( face[ iSide ])
10418       {
10419         //cout << " F " << face[ iSide]->GetID() <<endl;
10420         faceSetPtr[ iSide ]->erase( face[ iSide ]);
10421         // put face nodes to fnodes
10422         if ( face[ iSide ]->IsQuadratic() )
10423         {
10424           // use interlaced nodes iterator
10425           const SMDS_VtkFace* F = dynamic_cast<const SMDS_VtkFace*>( face[ iSide ]);
10426           if (!F) throw SALOME_Exception(LOCALIZED("not an SMDS_VtkFace"));
10427           SMDS_ElemIteratorPtr nIter = F->interlacedNodesElemIterator();
10428           while ( nIter->more() )
10429             fnodes[ iSide ].push_back( cast2Node( nIter->next() ));
10430         }
10431         else
10432         {
10433           fnodes[ iSide ].assign( face[ iSide ]->begin_nodes(),
10434                                   face[ iSide ]->end_nodes() );
10435         }
10436         fnodes[ iSide ].push_back( fnodes[ iSide ].front());
10437       }
10438     }
10439
10440     // check similarity of elements of the sides
10441     if (aResult == SEW_OK && (( face[0] && !face[1] ) || ( !face[0] && face[1] ))) {
10442       MESSAGE("Correspondent face not found on side " << ( face[0] ? 1 : 0 ));
10443       if ( nReplaceMap.size() == 2 ) { // faces on input nodes not found
10444         aResult = ( face[0] ? SEW_BAD_SIDE2_NODES : SEW_BAD_SIDE1_NODES );
10445       }
10446       else {
10447         aResult = SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
10448       }
10449       break; // do not return because it's necessary to remove tmp faces
10450     }
10451
10452     // set nodes to merge
10453     // -------------------
10454
10455     if ( face[0] && face[1] )  {
10456       const int nbNodes = face[0]->NbNodes();
10457       if ( nbNodes != face[1]->NbNodes() ) {
10458         MESSAGE("Diff nb of face nodes");
10459         aResult = SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
10460         break; // do not return because it s necessary to remove tmp faces
10461       }
10462       bool reverse[] = { false, false }; // order of nodes in the link
10463       for ( iSide = 0; iSide < 2; iSide++ ) { // loop on 2 sides
10464         // analyse link orientation in faces
10465         int i1 = iLinkNode[ iSide ][ 0 ];
10466         int i2 = iLinkNode[ iSide ][ 1 ];
10467         reverse[ iSide ] = Abs( i1 - i2 ) == 1 ? i1 > i2 : i2 > i1;
10468       }
10469       int di1 = reverse[0] ? -1 : +1, i1 = iLinkNode[0][1] + di1;
10470       int di2 = reverse[1] ? -1 : +1, i2 = iLinkNode[1][1] + di2;
10471       for ( int i = nbNodes - 2; i > 0; --i, i1 += di1, i2 += di2 )
10472       {
10473         nReplaceMap.insert  ( make_pair ( fnodes[0][ ( i1 + nbNodes ) % nbNodes ],
10474                                           fnodes[1][ ( i2 + nbNodes ) % nbNodes ]));
10475       }
10476
10477       // add other links of the faces to linkList
10478       // -----------------------------------------
10479
10480       for ( iNode = 0; iNode < nbNodes; iNode++ )  {
10481         linkID = aLinkID_Gen.GetLinkID( fnodes[0][iNode], fnodes[0][iNode+1] );
10482         pair< set<long>::iterator, bool > iter_isnew = linkIdSet.insert( linkID );
10483         if ( !iter_isnew.second ) { // already in a set: no need to process
10484           linkIdSet.erase( iter_isnew.first );
10485         }
10486         else // new in set == encountered for the first time: add
10487         {
10488           const SMDS_MeshNode* n1 = fnodes[0][ iNode ];
10489           const SMDS_MeshNode* n2 = fnodes[0][ iNode + 1];
10490           linkList[0].push_back ( NLink( n1, n2 ));
10491           linkList[1].push_back ( NLink( nReplaceMap[n1], nReplaceMap[n2] ));
10492         }
10493       }
10494     } // 2 faces found
10495
10496     if ( faceSetPtr[0]->empty() || faceSetPtr[1]->empty() )
10497       break;
10498
10499   } // loop on link lists
10500
10501   if ( aResult == SEW_OK &&
10502        ( //linkIt[0] != linkList[0].end() ||
10503          !faceSetPtr[0]->empty() || !faceSetPtr[1]->empty() )) {
10504     MESSAGE( (linkIt[0] != linkList[0].end()) <<" "<< (faceSetPtr[0]->empty()) <<
10505              " " << (faceSetPtr[1]->empty()));
10506     aResult = SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
10507   }
10508
10509   // ====================================================================
10510   // 3. Replace nodes in elements of the side 1 and remove replaced nodes
10511   // ====================================================================
10512
10513   // delete temporary faces
10514 //  SMDS_FaceIteratorPtr tmpFaceIt = aTmpFacesMesh.facesIterator();
10515 //  while ( tmpFaceIt->more() )
10516 //    aTmpFacesMesh.RemoveElement( tmpFaceIt->next() );
10517   list<const SMDS_MeshElement* >::iterator tmpFaceIt = tempFaceList.begin();
10518   for (; tmpFaceIt !=tempFaceList.end(); ++tmpFaceIt)
10519     aMesh->RemoveElement(*tmpFaceIt);
10520
10521   if ( aResult != SEW_OK)
10522     return aResult;
10523
10524   list< int > nodeIDsToRemove/*, elemIDsToRemove*/;
10525   // loop on nodes replacement map
10526   TNodeNodeMap::iterator nReplaceMapIt = nReplaceMap.begin(), nnIt;
10527   for ( ; nReplaceMapIt != nReplaceMap.end(); nReplaceMapIt++ )
10528     if ( (*nReplaceMapIt).first != (*nReplaceMapIt).second ) {
10529       const SMDS_MeshNode* nToRemove = (*nReplaceMapIt).first;
10530       nodeIDsToRemove.push_back( nToRemove->GetID() );
10531       // loop on elements sharing nToRemove
10532       SMDS_ElemIteratorPtr invElemIt = nToRemove->GetInverseElementIterator();
10533       while ( invElemIt->more() ) {
10534         const SMDS_MeshElement* e = invElemIt->next();
10535         // get a new suite of nodes: make replacement
10536         int nbReplaced = 0, i = 0, nbNodes = e->NbNodes();
10537         vector< const SMDS_MeshNode*> nodes( nbNodes );
10538         SMDS_ElemIteratorPtr nIt = e->nodesIterator();
10539         while ( nIt->more() ) {
10540           const SMDS_MeshNode* n =
10541             static_cast<const SMDS_MeshNode*>( nIt->next() );
10542           nnIt = nReplaceMap.find( n );
10543           if ( nnIt != nReplaceMap.end() ) {
10544             nbReplaced++;
10545             n = (*nnIt).second;
10546           }
10547           nodes[ i++ ] = n;
10548         }
10549         //       if ( nbReplaced == nbNodes && e->GetType() == SMDSAbs_Face )
10550         //         elemIDsToRemove.push_back( e->GetID() );
10551         //       else
10552         if ( nbReplaced )
10553           {
10554             SMDSAbs_ElementType etyp = e->GetType();
10555             SMDS_MeshElement* newElem = this->AddElement(nodes, etyp, false);
10556             if (newElem)
10557               {
10558                 myLastCreatedElems.Append(newElem);
10559                 AddToSameGroups(newElem, e, aMesh);
10560                 int aShapeId = e->getshapeId();
10561                 if ( aShapeId )
10562                   {
10563                     aMesh->SetMeshElementOnShape( newElem, aShapeId );
10564                   }
10565               }
10566             aMesh->RemoveElement(e);
10567           }
10568       }
10569     }
10570
10571   Remove( nodeIDsToRemove, true );
10572
10573   return aResult;
10574 }
10575
10576 //================================================================================
10577 /*!
10578  * \brief Find corresponding nodes in two sets of faces
10579  * \param theSide1 - first face set
10580  * \param theSide2 - second first face
10581  * \param theFirstNode1 - a boundary node of set 1
10582  * \param theFirstNode2 - a node of set 2 corresponding to theFirstNode1
10583  * \param theSecondNode1 - a boundary node of set 1 linked with theFirstNode1
10584  * \param theSecondNode2 - a node of set 2 corresponding to theSecondNode1
10585  * \param nReplaceMap - output map of corresponding nodes
10586  * \return bool  - is a success or not
10587  */
10588 //================================================================================
10589
10590 #ifdef _DEBUG_
10591 //#define DEBUG_MATCHING_NODES
10592 #endif
10593
10594 SMESH_MeshEditor::Sew_Error
10595 SMESH_MeshEditor::FindMatchingNodes(set<const SMDS_MeshElement*>& theSide1,
10596                                     set<const SMDS_MeshElement*>& theSide2,
10597                                     const SMDS_MeshNode*          theFirstNode1,
10598                                     const SMDS_MeshNode*          theFirstNode2,
10599                                     const SMDS_MeshNode*          theSecondNode1,
10600                                     const SMDS_MeshNode*          theSecondNode2,
10601                                     TNodeNodeMap &                nReplaceMap)
10602 {
10603   set<const SMDS_MeshElement*> * faceSetPtr[] = { &theSide1, &theSide2 };
10604
10605   nReplaceMap.clear();
10606   if ( theFirstNode1 != theFirstNode2 )
10607     nReplaceMap.insert( make_pair( theFirstNode1, theFirstNode2 ));
10608   if ( theSecondNode1 != theSecondNode2 )
10609     nReplaceMap.insert( make_pair( theSecondNode1, theSecondNode2 ));
10610
10611   set< SMESH_TLink > linkSet; // set of nodes where order of nodes is ignored
10612   linkSet.insert( SMESH_TLink( theFirstNode1, theSecondNode1 ));
10613
10614   list< NLink > linkList[2];
10615   linkList[0].push_back( NLink( theFirstNode1, theSecondNode1 ));
10616   linkList[1].push_back( NLink( theFirstNode2, theSecondNode2 ));
10617
10618   // loop on links in linkList; find faces by links and append links
10619   // of the found faces to linkList
10620   list< NLink >::iterator linkIt[] = { linkList[0].begin(), linkList[1].begin() } ;
10621   for ( ; linkIt[0] != linkList[0].end(); linkIt[0]++, linkIt[1]++ ) {
10622     NLink link[] = { *linkIt[0], *linkIt[1] };
10623     if ( linkSet.find( link[0] ) == linkSet.end() )
10624       continue;
10625
10626     // by links, find faces in the face sets,
10627     // and find indices of link nodes in the found faces;
10628     // in a face set, there is only one or no face sharing a link
10629     // ---------------------------------------------------------------
10630
10631     const SMDS_MeshElement* face[] = { 0, 0 };
10632     list<const SMDS_MeshNode*> notLinkNodes[2];
10633     //bool reverse[] = { false, false }; // order of notLinkNodes
10634     int nbNodes[2];
10635     for ( int iSide = 0; iSide < 2; iSide++ ) // loop on 2 sides
10636     {
10637       const SMDS_MeshNode* n1 = link[iSide].first;
10638       const SMDS_MeshNode* n2 = link[iSide].second;
10639       set<const SMDS_MeshElement*> * faceSet = faceSetPtr[ iSide ];
10640       set< const SMDS_MeshElement* > facesOfNode1;
10641       for ( int iNode = 0; iNode < 2; iNode++ ) // loop on 2 nodes of a link
10642       {
10643         // during a loop of the first node, we find all faces around n1,
10644         // during a loop of the second node, we find one face sharing both n1 and n2
10645         const SMDS_MeshNode* n = iNode ? n1 : n2; // a node of a link
10646         SMDS_ElemIteratorPtr fIt = n->GetInverseElementIterator(SMDSAbs_Face);
10647         while ( fIt->more() ) { // loop on faces sharing a node
10648           const SMDS_MeshElement* f = fIt->next();
10649           if (faceSet->find( f ) != faceSet->end() && // f is in face set
10650               ! facesOfNode1.insert( f ).second ) // f encounters twice
10651           {
10652             if ( face[ iSide ] ) {
10653               MESSAGE( "2 faces per link " );
10654               return ( iSide ? SEW_BAD_SIDE2_NODES : SEW_BAD_SIDE1_NODES );
10655             }
10656             face[ iSide ] = f;
10657             faceSet->erase( f );
10658
10659             // get not link nodes
10660             int nbN = f->NbNodes();
10661             if ( f->IsQuadratic() )
10662               nbN /= 2;
10663             nbNodes[ iSide ] = nbN;
10664             list< const SMDS_MeshNode* > & nodes = notLinkNodes[ iSide ];
10665             int i1 = f->GetNodeIndex( n1 );
10666             int i2 = f->GetNodeIndex( n2 );
10667             int iEnd = nbN, iBeg = -1, iDelta = 1;
10668             bool reverse = ( Abs( i1 - i2 ) == 1 ? i1 > i2 : i2 > i1 );
10669             if ( reverse ) {
10670               std::swap( iEnd, iBeg ); iDelta = -1;
10671             }
10672             int i = i2;
10673             while ( true ) {
10674               i += iDelta;
10675               if ( i == iEnd ) i = iBeg + iDelta;
10676               if ( i == i1 ) break;
10677               nodes.push_back ( f->GetNode( i ) );
10678             }
10679           }
10680         }
10681       }
10682     }
10683     // check similarity of elements of the sides
10684     if (( face[0] && !face[1] ) || ( !face[0] && face[1] )) {
10685       MESSAGE("Correspondent face not found on side " << ( face[0] ? 1 : 0 ));
10686       if ( nReplaceMap.size() == 2 ) { // faces on input nodes not found
10687         return ( face[0] ? SEW_BAD_SIDE2_NODES : SEW_BAD_SIDE1_NODES );
10688       }
10689       else {
10690         return SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
10691       }
10692     }
10693
10694     // set nodes to merge
10695     // -------------------
10696
10697     if ( face[0] && face[1] )  {
10698       if ( nbNodes[0] != nbNodes[1] ) {
10699         MESSAGE("Diff nb of face nodes");
10700         return SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
10701       }
10702 #ifdef DEBUG_MATCHING_NODES
10703       MESSAGE ( " Link 1: " << link[0].first->GetID() <<" "<< link[0].second->GetID()
10704                 << " F 1: " << face[0] << "| Link 2: " << link[1].first->GetID() <<" "
10705                 << link[1].second->GetID() << " F 2: " << face[1] << " | Bind: " ) ;
10706 #endif
10707       int nbN = nbNodes[0];
10708       {
10709         list<const SMDS_MeshNode*>::iterator n1 = notLinkNodes[0].begin();
10710         list<const SMDS_MeshNode*>::iterator n2 = notLinkNodes[1].begin();
10711         for ( int i = 0 ; i < nbN - 2; ++i ) {
10712 #ifdef DEBUG_MATCHING_NODES
10713           MESSAGE ( (*n1)->GetID() << " to " << (*n2)->GetID() );
10714 #endif
10715           nReplaceMap.insert( make_pair( *(n1++), *(n2++) ));
10716         }
10717       }
10718
10719       // add other links of the face 1 to linkList
10720       // -----------------------------------------
10721
10722       const SMDS_MeshElement* f0 = face[0];
10723       const SMDS_MeshNode* n1 = f0->GetNode( nbN - 1 );
10724       for ( int i = 0; i < nbN; i++ )
10725       {
10726         const SMDS_MeshNode* n2 = f0->GetNode( i );
10727         pair< set< SMESH_TLink >::iterator, bool > iter_isnew =
10728           linkSet.insert( SMESH_TLink( n1, n2 ));
10729         if ( !iter_isnew.second ) { // already in a set: no need to process
10730           linkSet.erase( iter_isnew.first );
10731         }
10732         else // new in set == encountered for the first time: add
10733         {
10734 #ifdef DEBUG_MATCHING_NODES
10735           MESSAGE ( "Add link 1: " << n1->GetID() << " " << n2->GetID() << " "
10736                     << " | link 2: " << nReplaceMap[n1]->GetID() << " " << nReplaceMap[n2]->GetID() << " " );
10737 #endif
10738           linkList[0].push_back ( NLink( n1, n2 ));
10739           linkList[1].push_back ( NLink( nReplaceMap[n1], nReplaceMap[n2] ));
10740         }
10741         n1 = n2;
10742       }
10743     } // 2 faces found
10744   } // loop on link lists
10745
10746   return SEW_OK;
10747 }
10748
10749 //================================================================================
10750 /*!
10751   \brief Creates a hole in a mesh by doubling the nodes of some particular elements
10752   \param theElems - the list of elements (edges or faces) to be replicated
10753   The nodes for duplication could be found from these elements
10754   \param theNodesNot - list of nodes to NOT replicate
10755   \param theAffectedElems - the list of elements (cells and edges) to which the
10756   replicated nodes should be associated to.
10757   \return TRUE if operation has been completed successfully, FALSE otherwise
10758 */
10759 //================================================================================
10760
10761 bool SMESH_MeshEditor::DoubleNodes( const TIDSortedElemSet& theElems,
10762                                     const TIDSortedElemSet& theNodesNot,
10763                                     const TIDSortedElemSet& theAffectedElems )
10764 {
10765   myLastCreatedElems.Clear();
10766   myLastCreatedNodes.Clear();
10767
10768   if ( theElems.size() == 0 )
10769     return false;
10770
10771   SMESHDS_Mesh* aMeshDS = GetMeshDS();
10772   if ( !aMeshDS )
10773     return false;
10774
10775   bool res = false;
10776   std::map< const SMDS_MeshNode*, const SMDS_MeshNode* > anOldNodeToNewNode;
10777   // duplicate elements and nodes
10778   res = doubleNodes( aMeshDS, theElems, theNodesNot, anOldNodeToNewNode, true );
10779   // replce nodes by duplications
10780   res = doubleNodes( aMeshDS, theAffectedElems, theNodesNot, anOldNodeToNewNode, false );
10781   return res;
10782 }
10783
10784 //================================================================================
10785 /*!
10786   \brief Creates a hole in a mesh by doubling the nodes of some particular elements
10787   \param theMeshDS - mesh instance
10788   \param theElems - the elements replicated or modified (nodes should be changed)
10789   \param theNodesNot - nodes to NOT replicate
10790   \param theNodeNodeMap - relation of old node to new created node
10791   \param theIsDoubleElem - flag os to replicate element or modify
10792   \return TRUE if operation has been completed successfully, FALSE otherwise
10793 */
10794 //================================================================================
10795
10796 bool SMESH_MeshEditor::doubleNodes( SMESHDS_Mesh*     theMeshDS,
10797                                     const TIDSortedElemSet& theElems,
10798                                     const TIDSortedElemSet& theNodesNot,
10799                                     std::map< const SMDS_MeshNode*,
10800                                     const SMDS_MeshNode* >& theNodeNodeMap,
10801                                     const bool theIsDoubleElem )
10802 {
10803   MESSAGE("doubleNodes");
10804   // iterate on through element and duplicate them (by nodes duplication)
10805   bool res = false;
10806   TIDSortedElemSet::const_iterator elemItr = theElems.begin();
10807   for ( ;  elemItr != theElems.end(); ++elemItr )
10808   {
10809     const SMDS_MeshElement* anElem = *elemItr;
10810     if (!anElem)
10811       continue;
10812
10813     bool isDuplicate = false;
10814     // duplicate nodes to duplicate element
10815     std::vector<const SMDS_MeshNode*> newNodes( anElem->NbNodes() );
10816     SMDS_ElemIteratorPtr anIter = anElem->nodesIterator();
10817     int ind = 0;
10818     while ( anIter->more() )
10819     {
10820
10821       SMDS_MeshNode* aCurrNode = (SMDS_MeshNode*)anIter->next();
10822       SMDS_MeshNode* aNewNode = aCurrNode;
10823       if ( theNodeNodeMap.find( aCurrNode ) != theNodeNodeMap.end() )
10824         aNewNode = (SMDS_MeshNode*)theNodeNodeMap[ aCurrNode ];
10825       else if ( theIsDoubleElem && theNodesNot.find( aCurrNode ) == theNodesNot.end() )
10826       {
10827         // duplicate node
10828         aNewNode = theMeshDS->AddNode( aCurrNode->X(), aCurrNode->Y(), aCurrNode->Z() );
10829         theNodeNodeMap[ aCurrNode ] = aNewNode;
10830         myLastCreatedNodes.Append( aNewNode );
10831       }
10832       isDuplicate |= (aCurrNode != aNewNode);
10833       newNodes[ ind++ ] = aNewNode;
10834     }
10835     if ( !isDuplicate )
10836       continue;
10837
10838     if ( theIsDoubleElem )
10839       AddElement(newNodes, anElem->GetType(), anElem->IsPoly());
10840     else
10841       {
10842       MESSAGE("ChangeElementNodes");
10843       theMeshDS->ChangeElementNodes( anElem, &newNodes[ 0 ], anElem->NbNodes() );
10844       }
10845     res = true;
10846   }
10847   return res;
10848 }
10849
10850 //================================================================================
10851 /*!
10852   \brief Creates a hole in a mesh by doubling the nodes of some particular elements
10853   \param theNodes - identifiers of nodes to be doubled
10854   \param theModifiedElems - identifiers of elements to be updated by the new (doubled)
10855          nodes. If list of element identifiers is empty then nodes are doubled but
10856          they not assigned to elements
10857   \return TRUE if operation has been completed successfully, FALSE otherwise
10858 */
10859 //================================================================================
10860
10861 bool SMESH_MeshEditor::DoubleNodes( const std::list< int >& theListOfNodes,
10862                                     const std::list< int >& theListOfModifiedElems )
10863 {
10864   MESSAGE("DoubleNodes");
10865   myLastCreatedElems.Clear();
10866   myLastCreatedNodes.Clear();
10867
10868   if ( theListOfNodes.size() == 0 )
10869     return false;
10870
10871   SMESHDS_Mesh* aMeshDS = GetMeshDS();
10872   if ( !aMeshDS )
10873     return false;
10874
10875   // iterate through nodes and duplicate them
10876
10877   std::map< const SMDS_MeshNode*, const SMDS_MeshNode* > anOldNodeToNewNode;
10878
10879   std::list< int >::const_iterator aNodeIter;
10880   for ( aNodeIter = theListOfNodes.begin(); aNodeIter != theListOfNodes.end(); ++aNodeIter )
10881   {
10882     int aCurr = *aNodeIter;
10883     SMDS_MeshNode* aNode = (SMDS_MeshNode*)aMeshDS->FindNode( aCurr );
10884     if ( !aNode )
10885       continue;
10886
10887     // duplicate node
10888
10889     const SMDS_MeshNode* aNewNode = aMeshDS->AddNode( aNode->X(), aNode->Y(), aNode->Z() );
10890     if ( aNewNode )
10891     {
10892       anOldNodeToNewNode[ aNode ] = aNewNode;
10893       myLastCreatedNodes.Append( aNewNode );
10894     }
10895   }
10896
10897   // Create map of new nodes for modified elements
10898
10899   std::map< SMDS_MeshElement*, vector<const SMDS_MeshNode*> > anElemToNodes;
10900
10901   std::list< int >::const_iterator anElemIter;
10902   for ( anElemIter = theListOfModifiedElems.begin();
10903         anElemIter != theListOfModifiedElems.end(); ++anElemIter )
10904   {
10905     int aCurr = *anElemIter;
10906     SMDS_MeshElement* anElem = (SMDS_MeshElement*)aMeshDS->FindElement( aCurr );
10907     if ( !anElem )
10908       continue;
10909
10910     vector<const SMDS_MeshNode*> aNodeArr( anElem->NbNodes() );
10911
10912     SMDS_ElemIteratorPtr anIter = anElem->nodesIterator();
10913     int ind = 0;
10914     while ( anIter->more() )
10915     {
10916       SMDS_MeshNode* aCurrNode = (SMDS_MeshNode*)anIter->next();
10917       if ( aCurr && anOldNodeToNewNode.find( aCurrNode ) != anOldNodeToNewNode.end() )
10918       {
10919         const SMDS_MeshNode* aNewNode = anOldNodeToNewNode[ aCurrNode ];
10920         aNodeArr[ ind++ ] = aNewNode;
10921       }
10922       else
10923         aNodeArr[ ind++ ] = aCurrNode;
10924     }
10925     anElemToNodes[ anElem ] = aNodeArr;
10926   }
10927
10928   // Change nodes of elements
10929
10930   std::map< SMDS_MeshElement*, vector<const SMDS_MeshNode*> >::iterator
10931     anElemToNodesIter = anElemToNodes.begin();
10932   for ( ; anElemToNodesIter != anElemToNodes.end(); ++anElemToNodesIter )
10933   {
10934     const SMDS_MeshElement* anElem = anElemToNodesIter->first;
10935     vector<const SMDS_MeshNode*> aNodeArr = anElemToNodesIter->second;
10936     if ( anElem )
10937       {
10938       MESSAGE("ChangeElementNodes");
10939       aMeshDS->ChangeElementNodes( anElem, &aNodeArr[ 0 ], anElem->NbNodes() );
10940       }
10941   }
10942
10943   return true;
10944 }
10945
10946 namespace {
10947
10948   //================================================================================
10949   /*!
10950   \brief Check if element located inside shape
10951   \return TRUE if IN or ON shape, FALSE otherwise
10952   */
10953   //================================================================================
10954
10955   template<class Classifier>
10956   bool isInside(const SMDS_MeshElement* theElem,
10957                 Classifier&             theClassifier,
10958                 const double            theTol)
10959   {
10960     gp_XYZ centerXYZ (0, 0, 0);
10961     SMDS_ElemIteratorPtr aNodeItr = theElem->nodesIterator();
10962     while (aNodeItr->more())
10963       centerXYZ += SMESH_TNodeXYZ(cast2Node( aNodeItr->next()));
10964
10965     gp_Pnt aPnt = centerXYZ / theElem->NbNodes();
10966     theClassifier.Perform(aPnt, theTol);
10967     TopAbs_State aState = theClassifier.State();
10968     return (aState == TopAbs_IN || aState == TopAbs_ON );
10969   }
10970
10971   //================================================================================
10972   /*!
10973    * \brief Classifier of the 3D point on the TopoDS_Face
10974    *        with interaface suitable for isInside()
10975    */
10976   //================================================================================
10977
10978   struct _FaceClassifier
10979   {
10980     Extrema_ExtPS       _extremum;
10981     BRepAdaptor_Surface _surface;
10982     TopAbs_State        _state;
10983
10984     _FaceClassifier(const TopoDS_Face& face):_extremum(),_surface(face),_state(TopAbs_OUT)
10985     {
10986       _extremum.Initialize( _surface,
10987                             _surface.FirstUParameter(), _surface.LastUParameter(),
10988                             _surface.FirstVParameter(), _surface.LastVParameter(),
10989                             _surface.Tolerance(), _surface.Tolerance() );
10990     }
10991     void Perform(const gp_Pnt& aPnt, double theTol)
10992     {
10993       _state = TopAbs_OUT;
10994       _extremum.Perform(aPnt);
10995       if ( _extremum.IsDone() )
10996         for ( int iSol = 1; iSol <= _extremum.NbExt() && _state == TopAbs_OUT; ++iSol)
10997 #if OCC_VERSION_LARGE > 0x06040000 // Porting to OCCT6.5.1
10998           _state = ( _extremum.SquareDistance(iSol) <= theTol ? TopAbs_IN : TopAbs_OUT );
10999 #else
11000           _state = ( _extremum.Value(iSol) <= theTol ? TopAbs_IN : TopAbs_OUT );
11001 #endif
11002     }
11003     TopAbs_State State() const
11004     {
11005       return _state;
11006     }
11007   };
11008 }
11009
11010 //================================================================================
11011 /*!
11012   \brief Identify the elements that will be affected by node duplication (actual duplication is not performed.
11013   This method is the first step of DoubleNodeElemGroupsInRegion.
11014   \param theElems - list of groups of elements (edges or faces) to be replicated
11015   \param theNodesNot - list of groups of nodes not to replicated
11016   \param theShape - shape to detect affected elements (element which geometric center
11017          located on or inside shape).
11018          The replicated nodes should be associated to affected elements.
11019   \return groups of affected elements
11020   \sa DoubleNodeElemGroupsInRegion()
11021  */
11022 //================================================================================
11023
11024 bool SMESH_MeshEditor::AffectedElemGroupsInRegion( const TIDSortedElemSet& theElems,
11025                                                    const TIDSortedElemSet& theNodesNot,
11026                                                    const TopoDS_Shape&     theShape,
11027                                                    TIDSortedElemSet&       theAffectedElems)
11028 {
11029   if ( theShape.IsNull() )
11030     return false;
11031
11032   const double aTol = Precision::Confusion();
11033   auto_ptr< BRepClass3d_SolidClassifier> bsc3d;
11034   auto_ptr<_FaceClassifier>              aFaceClassifier;
11035   if ( theShape.ShapeType() == TopAbs_SOLID )
11036   {
11037     bsc3d.reset( new BRepClass3d_SolidClassifier(theShape));;
11038     bsc3d->PerformInfinitePoint(aTol);
11039   }
11040   else if (theShape.ShapeType() == TopAbs_FACE )
11041   {
11042     aFaceClassifier.reset( new _FaceClassifier(TopoDS::Face(theShape)));
11043   }
11044
11045   // iterates on indicated elements and get elements by back references from their nodes
11046   TIDSortedElemSet::const_iterator elemItr = theElems.begin();
11047   for ( ;  elemItr != theElems.end(); ++elemItr )
11048   {
11049     SMDS_MeshElement* anElem = (SMDS_MeshElement*)*elemItr;
11050     if (!anElem)
11051       continue;
11052
11053     SMDS_ElemIteratorPtr nodeItr = anElem->nodesIterator();
11054     while ( nodeItr->more() )
11055     {
11056       const SMDS_MeshNode* aNode = cast2Node(nodeItr->next());
11057       if ( !aNode || theNodesNot.find(aNode) != theNodesNot.end() )
11058         continue;
11059       SMDS_ElemIteratorPtr backElemItr = aNode->GetInverseElementIterator();
11060       while ( backElemItr->more() )
11061       {
11062         const SMDS_MeshElement* curElem = backElemItr->next();
11063         if ( curElem && theElems.find(curElem) == theElems.end() &&
11064              ( bsc3d.get() ?
11065                isInside( curElem, *bsc3d, aTol ) :
11066                isInside( curElem, *aFaceClassifier, aTol )))
11067           theAffectedElems.insert( curElem );
11068       }
11069     }
11070   }
11071   return true;
11072 }
11073
11074 //================================================================================
11075 /*!
11076   \brief Creates a hole in a mesh by doubling the nodes of some particular elements
11077   \param theElems - group of of elements (edges or faces) to be replicated
11078   \param theNodesNot - group of nodes not to replicate
11079   \param theShape - shape to detect affected elements (element which geometric center
11080   located on or inside shape).
11081   The replicated nodes should be associated to affected elements.
11082   \return TRUE if operation has been completed successfully, FALSE otherwise
11083 */
11084 //================================================================================
11085
11086 bool SMESH_MeshEditor::DoubleNodesInRegion( const TIDSortedElemSet& theElems,
11087                                             const TIDSortedElemSet& theNodesNot,
11088                                             const TopoDS_Shape&     theShape )
11089 {
11090   if ( theShape.IsNull() )
11091     return false;
11092
11093   const double aTol = Precision::Confusion();
11094   auto_ptr< BRepClass3d_SolidClassifier> bsc3d;
11095   auto_ptr<_FaceClassifier>              aFaceClassifier;
11096   if ( theShape.ShapeType() == TopAbs_SOLID )
11097   {
11098     bsc3d.reset( new BRepClass3d_SolidClassifier(theShape));;
11099     bsc3d->PerformInfinitePoint(aTol);
11100   }
11101   else if (theShape.ShapeType() == TopAbs_FACE )
11102   {
11103     aFaceClassifier.reset( new _FaceClassifier(TopoDS::Face(theShape)));
11104   }
11105
11106   // iterates on indicated elements and get elements by back references from their nodes
11107   TIDSortedElemSet anAffected;
11108   TIDSortedElemSet::const_iterator elemItr = theElems.begin();
11109   for ( ;  elemItr != theElems.end(); ++elemItr )
11110   {
11111     SMDS_MeshElement* anElem = (SMDS_MeshElement*)*elemItr;
11112     if (!anElem)
11113       continue;
11114
11115     SMDS_ElemIteratorPtr nodeItr = anElem->nodesIterator();
11116     while ( nodeItr->more() )
11117     {
11118       const SMDS_MeshNode* aNode = cast2Node(nodeItr->next());
11119       if ( !aNode || theNodesNot.find(aNode) != theNodesNot.end() )
11120         continue;
11121       SMDS_ElemIteratorPtr backElemItr = aNode->GetInverseElementIterator();
11122       while ( backElemItr->more() )
11123       {
11124         const SMDS_MeshElement* curElem = backElemItr->next();
11125         if ( curElem && theElems.find(curElem) == theElems.end() &&
11126              ( bsc3d.get() ?
11127                isInside( curElem, *bsc3d, aTol ) :
11128                isInside( curElem, *aFaceClassifier, aTol )))
11129           anAffected.insert( curElem );
11130       }
11131     }
11132   }
11133   return DoubleNodes( theElems, theNodesNot, anAffected );
11134 }
11135
11136 /*!
11137  *  \brief compute an oriented angle between two planes defined by four points.
11138  *  The vector (p0,p1) defines the intersection of the 2 planes (p0,p1,g1) and (p0,p1,g2)
11139  *  @param p0 base of the rotation axe
11140  *  @param p1 extremity of the rotation axe
11141  *  @param g1 belongs to the first plane
11142  *  @param g2 belongs to the second plane
11143  */
11144 double SMESH_MeshEditor::OrientedAngle(const gp_Pnt& p0, const gp_Pnt& p1, const gp_Pnt& g1, const gp_Pnt& g2)
11145 {
11146 //  MESSAGE("    p0: " << p0.X() << " " << p0.Y() << " " << p0.Z());
11147 //  MESSAGE("    p1: " << p1.X() << " " << p1.Y() << " " << p1.Z());
11148 //  MESSAGE("    g1: " << g1.X() << " " << g1.Y() << " " << g1.Z());
11149 //  MESSAGE("    g2: " << g2.X() << " " << g2.Y() << " " << g2.Z());
11150   gp_Vec vref(p0, p1);
11151   gp_Vec v1(p0, g1);
11152   gp_Vec v2(p0, g2);
11153   gp_Vec n1 = vref.Crossed(v1);
11154   gp_Vec n2 = vref.Crossed(v2);
11155   return n2.AngleWithRef(n1, vref);
11156 }
11157
11158 /*!
11159  * \brief Double nodes on shared faces between groups of volumes and create flat elements on demand.
11160  * The list of groups must describe a partition of the mesh volumes.
11161  * The nodes of the internal faces at the boundaries of the groups are doubled.
11162  * In option, the internal faces are replaced by flat elements.
11163  * Triangles are transformed in prisms, and quadrangles in hexahedrons.
11164  * The flat elements are stored in groups of volumes.
11165  * @param theElems - list of groups of volumes, where a group of volume is a set of
11166  * SMDS_MeshElements sorted by Id.
11167  * @param createJointElems - if TRUE, create the elements
11168  * @return TRUE if operation has been completed successfully, FALSE otherwise
11169  */
11170 bool SMESH_MeshEditor::DoubleNodesOnGroupBoundaries( const std::vector<TIDSortedElemSet>& theElems,
11171                                                      bool createJointElems)
11172 {
11173   MESSAGE("----------------------------------------------");
11174   MESSAGE("SMESH_MeshEditor::doubleNodesOnGroupBoundaries");
11175   MESSAGE("----------------------------------------------");
11176
11177   SMESHDS_Mesh *meshDS = this->myMesh->GetMeshDS();
11178   meshDS->BuildDownWardConnectivity(true);
11179   CHRONO(50);
11180   SMDS_UnstructuredGrid *grid = meshDS->getGrid();
11181
11182   // --- build the list of faces shared by 2 domains (group of elements), with their domain and volume indexes
11183   //     build the list of cells with only a node or an edge on the border, with their domain and volume indexes
11184   //     build the list of nodes shared by 2 or more domains, with their domain indexes
11185
11186   std::map<DownIdType, std::map<int,int>, DownIdCompare> faceDomains; // face --> (id domain --> id volume)
11187   std::map<int,int>celldom; // cell vtkId --> domain
11188   std::map<DownIdType, std::map<int,int>, DownIdCompare> cellDomains;  // oldNode --> (id domain --> id cell)
11189   std::map<int, std::map<int,int> > nodeDomains; // oldId -->  (domainId --> newId)
11190   faceDomains.clear();
11191   celldom.clear();
11192   cellDomains.clear();
11193   nodeDomains.clear();
11194   std::map<int,int> emptyMap;
11195   std::set<int> emptySet;
11196   emptyMap.clear();
11197
11198   for (int idom = 0; idom < theElems.size(); idom++)
11199     {
11200
11201       // --- build a map (face to duplicate --> volume to modify)
11202       //     with all the faces shared by 2 domains (group of elements)
11203       //     and corresponding volume of this domain, for each shared face.
11204       //     a volume has a face shared by 2 domains if it has a neighbor which is not in his domain.
11205
11206       //MESSAGE("Domain " << idom);
11207       const TIDSortedElemSet& domain = theElems[idom];
11208       TIDSortedElemSet::const_iterator elemItr = domain.begin();
11209       for (; elemItr != domain.end(); ++elemItr)
11210         {
11211           SMDS_MeshElement* anElem = (SMDS_MeshElement*) *elemItr;
11212           if (!anElem)
11213             continue;
11214           int vtkId = anElem->getVtkId();
11215           //MESSAGE("  vtkId " << vtkId << " smdsId " << anElem->GetID());
11216           int neighborsVtkIds[NBMAXNEIGHBORS];
11217           int downIds[NBMAXNEIGHBORS];
11218           unsigned char downTypes[NBMAXNEIGHBORS];
11219           int nbNeighbors = grid->GetNeighbors(neighborsVtkIds, downIds, downTypes, vtkId);
11220           for (int n = 0; n < nbNeighbors; n++)
11221             {
11222               int smdsId = meshDS->fromVtkToSmds(neighborsVtkIds[n]);
11223               const SMDS_MeshElement* elem = meshDS->FindElement(smdsId);
11224               if (! domain.count(elem)) // neighbor is in another domain : face is shared
11225                 {
11226                   DownIdType face(downIds[n], downTypes[n]);
11227                   if (!faceDomains.count(face))
11228                     faceDomains[face] = emptyMap; // create an empty entry for face
11229                   if (!faceDomains[face].count(idom))
11230                     {
11231                       faceDomains[face][idom] = vtkId; // volume associated to face in this domain
11232                       celldom[vtkId] = idom;
11233                       //MESSAGE("       cell with a border " << vtkId << " domain " << idom);
11234                     }
11235                 }
11236             }
11237         }
11238     }
11239
11240   //MESSAGE("Number of shared faces " << faceDomains.size());
11241   std::map<DownIdType, std::map<int, int>, DownIdCompare>::iterator itface;
11242
11243   // --- explore the shared faces domain by domain,
11244   //     explore the nodes of the face and see if they belong to a cell in the domain,
11245   //     which has only a node or an edge on the border (not a shared face)
11246
11247   for (int idomain = 0; idomain < theElems.size(); idomain++)
11248     {
11249       //MESSAGE("Domain " << idomain);
11250       const TIDSortedElemSet& domain = theElems[idomain];
11251       itface = faceDomains.begin();
11252       for (; itface != faceDomains.end(); ++itface)
11253         {
11254           std::map<int, int> domvol = itface->second;
11255           if (!domvol.count(idomain))
11256             continue;
11257           DownIdType face = itface->first;
11258           //MESSAGE(" --- face " << face.cellId);
11259           std::set<int> oldNodes;
11260           oldNodes.clear();
11261           grid->GetNodeIds(oldNodes, face.cellId, face.cellType);
11262           std::set<int>::iterator itn = oldNodes.begin();
11263           for (; itn != oldNodes.end(); ++itn)
11264             {
11265               int oldId = *itn;
11266               //MESSAGE("     node " << oldId);
11267               vtkCellLinks::Link l = grid->GetCellLinks()->GetLink(oldId);
11268               for (int i=0; i<l.ncells; i++)
11269                 {
11270                   int vtkId = l.cells[i];
11271                   const SMDS_MeshElement* anElem = GetMeshDS()->FindElement(GetMeshDS()->fromVtkToSmds(vtkId));
11272                   if (!domain.count(anElem))
11273                     continue;
11274                   int vtkType = grid->GetCellType(vtkId);
11275                   int downId = grid->CellIdToDownId(vtkId);
11276                   if (downId < 0)
11277                     {
11278                       MESSAGE("doubleNodesOnGroupBoundaries: internal algorithm problem");
11279                       continue; // not OK at this stage of the algorithm:
11280                                 //no cells created after BuildDownWardConnectivity
11281                     }
11282                   DownIdType aCell(downId, vtkType);
11283                   if (!cellDomains.count(aCell))
11284                     cellDomains[aCell] = emptyMap; // create an empty entry for cell
11285                   cellDomains[aCell][idomain] = vtkId;
11286                   celldom[vtkId] = idomain;
11287                   //MESSAGE("       cell " << vtkId << " domain " << idomain);
11288                 }
11289             }
11290         }
11291     }
11292
11293   // --- explore the shared faces domain by domain, to duplicate the nodes in a coherent way
11294   //     for each shared face, get the nodes
11295   //     for each node, for each domain of the face, create a clone of the node
11296
11297   // --- edges at the intersection of 3 or 4 domains, with the order of domains to build
11298   //     junction elements of type prism or hexa. the key is the pair of nodesId (lower first)
11299   //     the value is the ordered domain ids. (more than 4 domains not taken into account)
11300
11301   std::map<std::vector<int>, std::vector<int> > edgesMultiDomains; // nodes of edge --> ordered domains
11302   std::map<int, std::vector<int> > mutipleNodes; // nodes multi domains with domain order
11303   std::map<int, std::vector<int> > mutipleNodesToFace; // nodes multi domains with domain order to transform in Face (junction between 3 or more 2D domains)
11304
11305   for (int idomain = 0; idomain < theElems.size(); idomain++)
11306     {
11307       itface = faceDomains.begin();
11308       for (; itface != faceDomains.end(); ++itface)
11309         {
11310           std::map<int, int> domvol = itface->second;
11311           if (!domvol.count(idomain))
11312             continue;
11313           DownIdType face = itface->first;
11314           //MESSAGE(" --- face " << face.cellId);
11315           std::set<int> oldNodes;
11316           oldNodes.clear();
11317           grid->GetNodeIds(oldNodes, face.cellId, face.cellType);
11318           std::set<int>::iterator itn = oldNodes.begin();
11319           for (; itn != oldNodes.end(); ++itn)
11320             {
11321               int oldId = *itn;
11322               //MESSAGE("-+-+-a node " << oldId);
11323               if (!nodeDomains.count(oldId))
11324                 nodeDomains[oldId] = emptyMap; // create an empty entry for node
11325               if (nodeDomains[oldId].empty())
11326                 {
11327                   nodeDomains[oldId][idomain] = oldId; // keep the old node in the first domain
11328                   //MESSAGE("-+-+-b     oldNode " << oldId << " domain " << idomain);
11329                 }
11330               std::map<int, int>::iterator itdom = domvol.begin();
11331               for (; itdom != domvol.end(); ++itdom)
11332                 {
11333                   int idom = itdom->first;
11334                   //MESSAGE("         domain " << idom);
11335                   if (!nodeDomains[oldId].count(idom)) // --- node to clone
11336                     {
11337                       if (nodeDomains[oldId].size() >= 2) // a multiple node
11338                         {
11339                           vector<int> orderedDoms;
11340                           //MESSAGE("multiple node " << oldId);
11341                           if (mutipleNodes.count(oldId))
11342                             orderedDoms = mutipleNodes[oldId];
11343                           else
11344                             {
11345                               map<int,int>::iterator it = nodeDomains[oldId].begin();
11346                               for (; it != nodeDomains[oldId].end(); ++it)
11347                                 orderedDoms.push_back(it->first);
11348                             }
11349                           orderedDoms.push_back(idom); // TODO order ==> push_front or back
11350                           //stringstream txt;
11351                           //for (int i=0; i<orderedDoms.size(); i++)
11352                           //  txt << orderedDoms[i] << " ";
11353                           //MESSAGE("orderedDoms " << txt.str());
11354                           mutipleNodes[oldId] = orderedDoms;
11355                         }
11356                       double *coords = grid->GetPoint(oldId);
11357                       SMDS_MeshNode *newNode = meshDS->AddNode(coords[0], coords[1], coords[2]);
11358                       int newId = newNode->getVtkId();
11359                       nodeDomains[oldId][idom] = newId; // cloned node for other domains
11360                       //MESSAGE("-+-+-c     oldNode " << oldId << " domain " << idomain << " newNode " << newId << " domain " << idom << " size=" <<nodeDomains[oldId].size());
11361                     }
11362                 }
11363             }
11364         }
11365     }
11366
11367   for (int idomain = 0; idomain < theElems.size(); idomain++)
11368     {
11369       itface = faceDomains.begin();
11370       for (; itface != faceDomains.end(); ++itface)
11371         {
11372           std::map<int, int> domvol = itface->second;
11373           if (!domvol.count(idomain))
11374             continue;
11375           DownIdType face = itface->first;
11376           //MESSAGE(" --- face " << face.cellId);
11377           std::set<int> oldNodes;
11378           oldNodes.clear();
11379           grid->GetNodeIds(oldNodes, face.cellId, face.cellType);
11380           int nbMultipleNodes = 0;
11381           std::set<int>::iterator itn = oldNodes.begin();
11382           for (; itn != oldNodes.end(); ++itn)
11383             {
11384               int oldId = *itn;
11385               if (mutipleNodes.count(oldId))
11386                 nbMultipleNodes++;
11387             }
11388           if (nbMultipleNodes > 1) // check if an edge of the face is shared between 3 or more domains
11389             {
11390               //MESSAGE("multiple Nodes detected on a shared face");
11391               int downId = itface->first.cellId;
11392               unsigned char cellType = itface->first.cellType;
11393               // --- shared edge or shared face ?
11394               if ((cellType == VTK_LINE) || (cellType == VTK_QUADRATIC_EDGE)) // shared edge (between two faces)
11395                 {
11396                   int nodes[3];
11397                   int nbNodes = grid->getDownArray(cellType)->getNodes(downId, nodes);
11398                   for (int i=0; i< nbNodes; i=i+nbNodes-1) // i=0 , i=nbNodes-1
11399                     if (mutipleNodes.count(nodes[i]))
11400                       if (!mutipleNodesToFace.count(nodes[i]))
11401                         mutipleNodesToFace[nodes[i]] = mutipleNodes[nodes[i]];
11402                 }
11403               else // shared face (between two volumes)
11404                 {
11405                   int nbEdges = grid->getDownArray(cellType)->getNumberOfDownCells(downId);
11406                   const int* downEdgeIds = grid->getDownArray(cellType)->getDownCells(downId);
11407                   const unsigned char* edgeType = grid->getDownArray(cellType)->getDownTypes(downId);
11408                   for (int ie =0; ie < nbEdges; ie++)
11409                     {
11410                       int nodes[3];
11411                       int nbNodes = grid->getDownArray(edgeType[ie])->getNodes(downEdgeIds[ie], nodes);
11412                       if (mutipleNodes.count(nodes[0]) && mutipleNodes.count(nodes[nbNodes-1]))
11413                         {
11414                           vector<int> vn0 = mutipleNodes[nodes[0]];
11415                           vector<int> vn1 = mutipleNodes[nodes[nbNodes - 1]];
11416                           vector<int> doms;
11417                           for (int i0 = 0; i0 < vn0.size(); i0++)
11418                             for (int i1 = 0; i1 < vn1.size(); i1++)
11419                               if (vn0[i0] == vn1[i1])
11420                                 doms.push_back(vn0[i0]);
11421                           if (doms.size() >2)
11422                             {
11423                               //MESSAGE(" detect edgesMultiDomains " << nodes[0] << " " << nodes[nbNodes - 1]);
11424                               double *coords = grid->GetPoint(nodes[0]);
11425                               gp_Pnt p0(coords[0], coords[1], coords[2]);
11426                               coords = grid->GetPoint(nodes[nbNodes - 1]);
11427                               gp_Pnt p1(coords[0], coords[1], coords[2]);
11428                               gp_Pnt gref;
11429                               int vtkVolIds[1000];  // an edge can belong to a lot of volumes
11430                               map<int, SMDS_VtkVolume*> domvol; // domain --> a volume with the edge
11431                               map<int, double> angleDom; // oriented angles between planes defined by edge and volume centers
11432                               int nbvol = grid->GetParentVolumes(vtkVolIds, downEdgeIds[ie], edgeType[ie]);
11433                               for (int id=0; id < doms.size(); id++)
11434                                 {
11435                                   int idom = doms[id];
11436                                   for (int ivol=0; ivol<nbvol; ivol++)
11437                                     {
11438                                       int smdsId = meshDS->fromVtkToSmds(vtkVolIds[ivol]);
11439                                       SMDS_MeshElement* elem = (SMDS_MeshElement*)meshDS->FindElement(smdsId);
11440                                       if (theElems[idom].count(elem))
11441                                         {
11442                                           SMDS_VtkVolume* svol = dynamic_cast<SMDS_VtkVolume*>(elem);
11443                                           domvol[idom] = svol;
11444                                           //MESSAGE("  domain " << idom << " volume " << elem->GetID());
11445                                           double values[3];
11446                                           vtkIdType npts = 0;
11447                                           vtkIdType* pts = 0;
11448                                           grid->GetCellPoints(vtkVolIds[ivol], npts, pts);
11449                                           SMDS_VtkVolume::gravityCenter(grid, pts, npts, values);
11450                                           if (id ==0)
11451                                             {
11452                                               gref.SetXYZ(gp_XYZ(values[0], values[1], values[2]));
11453                                               angleDom[idom] = 0;
11454                                             }
11455                                           else
11456                                             {
11457                                               gp_Pnt g(values[0], values[1], values[2]);
11458                                               angleDom[idom] = OrientedAngle(p0, p1, gref, g); // -pi<angle<+pi
11459                                               //MESSAGE("  angle=" << angleDom[idom]);
11460                                             }
11461                                           break;
11462                                         }
11463                                     }
11464                                 }
11465                               map<double, int> sortedDom; // sort domains by angle
11466                               for (map<int, double>::iterator ia = angleDom.begin(); ia != angleDom.end(); ++ia)
11467                                 sortedDom[ia->second] = ia->first;
11468                               vector<int> vnodes;
11469                               vector<int> vdom;
11470                               for (map<double, int>::iterator ib = sortedDom.begin(); ib != sortedDom.end(); ++ib)
11471                                 {
11472                                   vdom.push_back(ib->second);
11473                                   //MESSAGE("  ordered domain " << ib->second << "  angle " << ib->first);
11474                                 }
11475                               for (int ino = 0; ino < nbNodes; ino++)
11476                                 vnodes.push_back(nodes[ino]);
11477                               edgesMultiDomains[vnodes] = vdom; // nodes vector --> ordered domains
11478                             }
11479                         }
11480                     }
11481                 }
11482             }
11483         }
11484     }
11485
11486   // --- iterate on shared faces (volumes to modify, face to extrude)
11487   //     get node id's of the face (id SMDS = id VTK)
11488   //     create flat element with old and new nodes if requested
11489
11490   // --- new quad nodes on flat quad elements: oldId --> ((domain1 X domain2) --> newId)
11491   //     (domain1 X domain2) = domain1 + MAXINT*domain2
11492
11493   std::map<int, std::map<long,int> > nodeQuadDomains;
11494   std::map<std::string, SMESH_Group*> mapOfJunctionGroups;
11495
11496   if (createJointElems)
11497     {
11498       int idg;
11499       string joints2DName = "joints2D";
11500       mapOfJunctionGroups[joints2DName] = this->myMesh->AddGroup(SMDSAbs_Face, joints2DName.c_str(), idg);
11501       SMESHDS_Group *joints2DGrp = dynamic_cast<SMESHDS_Group*>(mapOfJunctionGroups[joints2DName]->GetGroupDS());
11502       string joints3DName = "joints3D";
11503       mapOfJunctionGroups[joints3DName] = this->myMesh->AddGroup(SMDSAbs_Volume, joints3DName.c_str(), idg);
11504       SMESHDS_Group *joints3DGrp = dynamic_cast<SMESHDS_Group*>(mapOfJunctionGroups[joints3DName]->GetGroupDS());
11505
11506       itface = faceDomains.begin();
11507       for (; itface != faceDomains.end(); ++itface)
11508         {
11509           DownIdType face = itface->first;
11510           std::set<int> oldNodes;
11511           std::set<int>::iterator itn;
11512           oldNodes.clear();
11513           grid->GetNodeIds(oldNodes, face.cellId, face.cellType);
11514
11515           std::map<int, int> domvol = itface->second;
11516           std::map<int, int>::iterator itdom = domvol.begin();
11517           int dom1 = itdom->first;
11518           int vtkVolId = itdom->second;
11519           itdom++;
11520           int dom2 = itdom->first;
11521           SMDS_MeshCell *vol = grid->extrudeVolumeFromFace(vtkVolId, dom1, dom2, oldNodes, nodeDomains,
11522                                                              nodeQuadDomains);
11523           stringstream grpname;
11524           grpname << "j_";
11525           if (dom1 < dom2)
11526             grpname << dom1 << "_" << dom2;
11527           else
11528             grpname << dom2 << "_" << dom1;
11529           string namegrp = grpname.str();
11530           if (!mapOfJunctionGroups.count(namegrp))
11531             mapOfJunctionGroups[namegrp] = this->myMesh->AddGroup(vol->GetType(), namegrp.c_str(), idg);
11532           SMESHDS_Group *sgrp = dynamic_cast<SMESHDS_Group*>(mapOfJunctionGroups[namegrp]->GetGroupDS());
11533           if (sgrp)
11534             sgrp->Add(vol->GetID());
11535           if (vol->GetType() == SMDSAbs_Volume)
11536             joints3DGrp->Add(vol->GetID());
11537           else if (vol->GetType() == SMDSAbs_Face)
11538             joints2DGrp->Add(vol->GetID());
11539         }
11540     }
11541
11542   // --- create volumes on multiple domain intersection if requested
11543   //     iterate on mutipleNodesToFace
11544   //     iterate on edgesMultiDomains
11545
11546   if (createJointElems)
11547     {
11548       // --- iterate on mutipleNodesToFace
11549
11550       std::map<int, std::vector<int> >::iterator itn =  mutipleNodesToFace.begin();
11551       for (; itn != mutipleNodesToFace.end(); ++itn)
11552         {
11553           int node = itn->first;
11554           vector<int> orderDom = itn->second;
11555           vector<vtkIdType> orderedNodes;
11556           for (int idom = 0; idom <orderDom.size(); idom++)
11557             orderedNodes.push_back( nodeDomains[node][orderDom[idom]] );
11558             SMDS_MeshFace* face = this->GetMeshDS()->AddFaceFromVtkIds(orderedNodes);
11559
11560             stringstream grpname;
11561             grpname << "m2j_";
11562             grpname << 0 << "_" << 0;
11563             int idg;
11564             string namegrp = grpname.str();
11565             if (!mapOfJunctionGroups.count(namegrp))
11566               mapOfJunctionGroups[namegrp] = this->myMesh->AddGroup(SMDSAbs_Face, namegrp.c_str(), idg);
11567             SMESHDS_Group *sgrp = dynamic_cast<SMESHDS_Group*>(mapOfJunctionGroups[namegrp]->GetGroupDS());
11568             if (sgrp)
11569               sgrp->Add(face->GetID());
11570         }
11571
11572       // --- iterate on edgesMultiDomains
11573
11574       std::map<std::vector<int>, std::vector<int> >::iterator ite = edgesMultiDomains.begin();
11575       for (; ite != edgesMultiDomains.end(); ++ite)
11576         {
11577           vector<int> nodes = ite->first;
11578           vector<int> orderDom = ite->second;
11579           vector<vtkIdType> orderedNodes;
11580           if (nodes.size() == 2)
11581             {
11582               //MESSAGE(" use edgesMultiDomains " << nodes[0] << " " << nodes[1]);
11583               for (int ino=0; ino < nodes.size(); ino++)
11584                 if (orderDom.size() == 3)
11585                   for (int idom = 0; idom <orderDom.size(); idom++)
11586                     orderedNodes.push_back( nodeDomains[nodes[ino]][orderDom[idom]] );
11587                 else
11588                   for (int idom = orderDom.size()-1; idom >=0; idom--)
11589                     orderedNodes.push_back( nodeDomains[nodes[ino]][orderDom[idom]] );
11590               SMDS_MeshVolume* vol = this->GetMeshDS()->AddVolumeFromVtkIds(orderedNodes);
11591
11592               int idg;
11593               string namegrp = "jointsMultiples";
11594               if (!mapOfJunctionGroups.count(namegrp))
11595                 mapOfJunctionGroups[namegrp] = this->myMesh->AddGroup(SMDSAbs_Volume, namegrp.c_str(), idg);
11596               SMESHDS_Group *sgrp = dynamic_cast<SMESHDS_Group*>(mapOfJunctionGroups[namegrp]->GetGroupDS());
11597               if (sgrp)
11598                 sgrp->Add(vol->GetID());
11599             }
11600           else
11601             {
11602               INFOS("Quadratic multiple joints not implemented");
11603               // TODO quadratic nodes
11604             }
11605         }
11606     }
11607
11608   // --- list the explicit faces and edges of the mesh that need to be modified,
11609   //     i.e. faces and edges built with one or more duplicated nodes.
11610   //     associate these faces or edges to their corresponding domain.
11611   //     only the first domain found is kept when a face or edge is shared
11612
11613   std::map<DownIdType, std::map<int,int>, DownIdCompare> faceOrEdgeDom; // cellToModify --> (id domain --> id cell)
11614   std::map<int,int> feDom; // vtk id of cell to modify --> id domain
11615   faceOrEdgeDom.clear();
11616   feDom.clear();
11617
11618   for (int idomain = 0; idomain < theElems.size(); idomain++)
11619     {
11620       std::map<int, std::map<int, int> >::const_iterator itnod = nodeDomains.begin();
11621       for (; itnod != nodeDomains.end(); ++itnod)
11622         {
11623           int oldId = itnod->first;
11624           //MESSAGE("     node " << oldId);
11625           vtkCellLinks::Link l = grid->GetCellLinks()->GetLink(oldId);
11626           for (int i = 0; i < l.ncells; i++)
11627             {
11628               int vtkId = l.cells[i];
11629               int vtkType = grid->GetCellType(vtkId);
11630               int downId = grid->CellIdToDownId(vtkId);
11631               if (downId < 0)
11632                 continue; // new cells: not to be modified
11633               DownIdType aCell(downId, vtkType);
11634               int volParents[1000];
11635               int nbvol = grid->GetParentVolumes(volParents, vtkId);
11636               for (int j = 0; j < nbvol; j++)
11637                 if (celldom.count(volParents[j]) && (celldom[volParents[j]] == idomain))
11638                   if (!feDom.count(vtkId))
11639                     {
11640                       feDom[vtkId] = idomain;
11641                       faceOrEdgeDom[aCell] = emptyMap;
11642                       faceOrEdgeDom[aCell][idomain] = vtkId; // affect face or edge to the first domain only
11643                       //MESSAGE("affect cell " << this->GetMeshDS()->fromVtkToSmds(vtkId) << " domain " << idomain
11644                       //        << " type " << vtkType << " downId " << downId);
11645                     }
11646             }
11647         }
11648     }
11649
11650   // --- iterate on shared faces (volumes to modify, face to extrude)
11651   //     get node id's of the face
11652   //     replace old nodes by new nodes in volumes, and update inverse connectivity
11653
11654   std::map<DownIdType, std::map<int,int>, DownIdCompare>* maps[3] = {&faceDomains, &cellDomains, &faceOrEdgeDom};
11655   for (int m=0; m<3; m++)
11656     {
11657       std::map<DownIdType, std::map<int,int>, DownIdCompare>* amap = maps[m];
11658       itface = (*amap).begin();
11659       for (; itface != (*amap).end(); ++itface)
11660         {
11661           DownIdType face = itface->first;
11662           std::set<int> oldNodes;
11663           std::set<int>::iterator itn;
11664           oldNodes.clear();
11665           grid->GetNodeIds(oldNodes, face.cellId, face.cellType);
11666           //MESSAGE("examine cell, downId " << face.cellId << " type " << int(face.cellType));
11667           std::map<int, int> localClonedNodeIds;
11668
11669           std::map<int, int> domvol = itface->second;
11670           std::map<int, int>::iterator itdom = domvol.begin();
11671           for (; itdom != domvol.end(); ++itdom)
11672             {
11673               int idom = itdom->first;
11674               int vtkVolId = itdom->second;
11675               //MESSAGE("modify nodes of cell " << this->GetMeshDS()->fromVtkToSmds(vtkVolId) << " domain " << idom);
11676               localClonedNodeIds.clear();
11677               for (itn = oldNodes.begin(); itn != oldNodes.end(); ++itn)
11678                 {
11679                   int oldId = *itn;
11680                   if (nodeDomains[oldId].count(idom))
11681                     {
11682                       localClonedNodeIds[oldId] = nodeDomains[oldId][idom];
11683                       //MESSAGE("     node " << oldId << " --> " << localClonedNodeIds[oldId]);
11684                     }
11685                 }
11686               meshDS->ModifyCellNodes(vtkVolId, localClonedNodeIds);
11687             }
11688         }
11689     }
11690
11691   meshDS->CleanDownWardConnectivity(); // Mesh has been modified, downward connectivity is no more usable, free memory
11692   grid->BuildLinks();
11693
11694   CHRONOSTOP(50);
11695   counters::stats();
11696   return true;
11697 }
11698
11699 /*!
11700  * \brief Double nodes on some external faces and create flat elements.
11701  * Flat elements are mainly used by some types of mechanic calculations.
11702  *
11703  * Each group of the list must be constituted of faces.
11704  * Triangles are transformed in prisms, and quadrangles in hexahedrons.
11705  * @param theElems - list of groups of faces, where a group of faces is a set of
11706  * SMDS_MeshElements sorted by Id.
11707  * @return TRUE if operation has been completed successfully, FALSE otherwise
11708  */
11709 bool SMESH_MeshEditor::CreateFlatElementsOnFacesGroups(const std::vector<TIDSortedElemSet>& theElems)
11710 {
11711   MESSAGE("-------------------------------------------------");
11712   MESSAGE("SMESH_MeshEditor::CreateFlatElementsOnFacesGroups");
11713   MESSAGE("-------------------------------------------------");
11714
11715   SMESHDS_Mesh *meshDS = this->myMesh->GetMeshDS();
11716
11717   // --- For each group of faces
11718   //     duplicate the nodes, create a flat element based on the face
11719   //     replace the nodes of the faces by their clones
11720
11721   std::map<const SMDS_MeshNode*, const SMDS_MeshNode*> clonedNodes;
11722   std::map<const SMDS_MeshNode*, const SMDS_MeshNode*> intermediateNodes;
11723   clonedNodes.clear();
11724   intermediateNodes.clear();
11725   std::map<std::string, SMESH_Group*> mapOfJunctionGroups;
11726   mapOfJunctionGroups.clear();
11727
11728   for (int idom = 0; idom < theElems.size(); idom++)
11729     {
11730       const TIDSortedElemSet& domain = theElems[idom];
11731       TIDSortedElemSet::const_iterator elemItr = domain.begin();
11732       for (; elemItr != domain.end(); ++elemItr)
11733         {
11734           SMDS_MeshElement* anElem = (SMDS_MeshElement*) *elemItr;
11735           SMDS_MeshFace* aFace = dynamic_cast<SMDS_MeshFace*> (anElem);
11736           if (!aFace)
11737             continue;
11738           // MESSAGE("aFace=" << aFace->GetID());
11739           bool isQuad = aFace->IsQuadratic();
11740           vector<const SMDS_MeshNode*> ln0, ln1, ln2, ln3, ln4;
11741
11742           // --- clone the nodes, create intermediate nodes for non medium nodes of a quad face
11743
11744           SMDS_ElemIteratorPtr nodeIt = aFace->nodesIterator();
11745           while (nodeIt->more())
11746             {
11747               const SMDS_MeshNode* node = static_cast<const SMDS_MeshNode*> (nodeIt->next());
11748               bool isMedium = isQuad && (aFace->IsMediumNode(node));
11749               if (isMedium)
11750                 ln2.push_back(node);
11751               else
11752                 ln0.push_back(node);
11753
11754               const SMDS_MeshNode* clone = 0;
11755               if (!clonedNodes.count(node))
11756                 {
11757                   clone = meshDS->AddNode(node->X(), node->Y(), node->Z());
11758                   clonedNodes[node] = clone;
11759                 }
11760               else
11761                 clone = clonedNodes[node];
11762
11763               if (isMedium)
11764                 ln3.push_back(clone);
11765               else
11766                 ln1.push_back(clone);
11767
11768               const SMDS_MeshNode* inter = 0;
11769               if (isQuad && (!isMedium))
11770                 {
11771                   if (!intermediateNodes.count(node))
11772                     {
11773                       inter = meshDS->AddNode(node->X(), node->Y(), node->Z());
11774                       intermediateNodes[node] = inter;
11775                     }
11776                   else
11777                     inter = intermediateNodes[node];
11778                   ln4.push_back(inter);
11779                 }
11780             }
11781
11782           // --- extrude the face
11783
11784           vector<const SMDS_MeshNode*> ln;
11785           SMDS_MeshVolume* vol = 0;
11786           vtkIdType aType = aFace->GetVtkType();
11787           switch (aType)
11788           {
11789             case VTK_TRIANGLE:
11790               vol = meshDS->AddVolume(ln0[2], ln0[1], ln0[0], ln1[2], ln1[1], ln1[0]);
11791               // MESSAGE("vol prism " << vol->GetID());
11792               ln.push_back(ln1[0]);
11793               ln.push_back(ln1[1]);
11794               ln.push_back(ln1[2]);
11795               break;
11796             case VTK_QUAD:
11797               vol = meshDS->AddVolume(ln0[3], ln0[2], ln0[1], ln0[0], ln1[3], ln1[2], ln1[1], ln1[0]);
11798               // MESSAGE("vol hexa " << vol->GetID());
11799               ln.push_back(ln1[0]);
11800               ln.push_back(ln1[1]);
11801               ln.push_back(ln1[2]);
11802               ln.push_back(ln1[3]);
11803               break;
11804             case VTK_QUADRATIC_TRIANGLE:
11805               vol = meshDS->AddVolume(ln1[0], ln1[1], ln1[2], ln0[0], ln0[1], ln0[2], ln3[0], ln3[1], ln3[2],
11806                                       ln2[0], ln2[1], ln2[2], ln4[0], ln4[1], ln4[2]);
11807               // MESSAGE("vol quad prism " << vol->GetID());
11808               ln.push_back(ln1[0]);
11809               ln.push_back(ln1[1]);
11810               ln.push_back(ln1[2]);
11811               ln.push_back(ln3[0]);
11812               ln.push_back(ln3[1]);
11813               ln.push_back(ln3[2]);
11814               break;
11815             case VTK_QUADRATIC_QUAD:
11816 //              vol = meshDS->AddVolume(ln0[0], ln0[1], ln0[2], ln0[3], ln1[0], ln1[1], ln1[2], ln1[3],
11817 //                                      ln2[0], ln2[1], ln2[2], ln2[3], ln3[0], ln3[1], ln3[2], ln3[3],
11818 //                                      ln4[0], ln4[1], ln4[2], ln4[3]);
11819               vol = meshDS->AddVolume(ln1[0], ln1[1], ln1[2], ln1[3], ln0[0], ln0[1], ln0[2], ln0[3],
11820                                       ln3[0], ln3[1], ln3[2], ln3[3], ln2[0], ln2[1], ln2[2], ln2[3],
11821                                       ln4[0], ln4[1], ln4[2], ln4[3]);
11822               // MESSAGE("vol quad hexa " << vol->GetID());
11823               ln.push_back(ln1[0]);
11824               ln.push_back(ln1[1]);
11825               ln.push_back(ln1[2]);
11826               ln.push_back(ln1[3]);
11827               ln.push_back(ln3[0]);
11828               ln.push_back(ln3[1]);
11829               ln.push_back(ln3[2]);
11830               ln.push_back(ln3[3]);
11831               break;
11832             case VTK_POLYGON:
11833               break;
11834             default:
11835               break;
11836           }
11837
11838           if (vol)
11839             {
11840               stringstream grpname;
11841               grpname << "jf_";
11842               grpname << idom;
11843               int idg;
11844               string namegrp = grpname.str();
11845               if (!mapOfJunctionGroups.count(namegrp))
11846                 mapOfJunctionGroups[namegrp] = this->myMesh->AddGroup(SMDSAbs_Volume, namegrp.c_str(), idg);
11847               SMESHDS_Group *sgrp = dynamic_cast<SMESHDS_Group*>(mapOfJunctionGroups[namegrp]->GetGroupDS());
11848               if (sgrp)
11849                 sgrp->Add(vol->GetID());
11850             }
11851
11852           // --- modify the face
11853
11854           aFace->ChangeNodes(&ln[0], ln.size());
11855         }
11856     }
11857   return true;
11858 }
11859
11860 /*!
11861  *  \brief identify all the elements around a geom shape, get the faces delimiting the hole
11862  *  Build groups of volume to remove, groups of faces to replace on the skin of the object,
11863  *  groups of faces to remove inside the object, (idem edges).
11864  *  Build ordered list of nodes at the border of each group of faces to replace (to be used to build a geom subshape)
11865  */
11866 void SMESH_MeshEditor::CreateHoleSkin(double radius,
11867                                       const TopoDS_Shape& theShape,
11868                                       SMESH_NodeSearcher* theNodeSearcher,
11869                                       const char* groupName,
11870                                       std::vector<double>&   nodesCoords,
11871                                       std::vector<std::vector<int> >& listOfListOfNodes)
11872 {
11873   MESSAGE("--------------------------------");
11874   MESSAGE("SMESH_MeshEditor::CreateHoleSkin");
11875   MESSAGE("--------------------------------");
11876
11877   // --- zone of volumes to remove is given :
11878   //     1 either by a geom shape (one or more vertices) and a radius,
11879   //     2 either by a group of nodes (representative of the shape)to use with the radius,
11880   //     3 either by a group of nodes where all the elements build on one of this nodes are to remove,
11881   //     In the case 2, the group of nodes is an external group of nodes from another mesh,
11882   //     In the case 3, the group of nodes is an internal group of the mesh (obtained for instance by a filter),
11883   //     defined by it's name.
11884
11885   SMESHDS_GroupBase* groupDS = 0;
11886   SMESH_Mesh::GroupIteratorPtr groupIt = this->myMesh->GetGroups();
11887   while ( groupIt->more() )
11888     {
11889       groupDS = 0;
11890       SMESH_Group * group = groupIt->next();
11891       if ( !group ) continue;
11892       groupDS = group->GetGroupDS();
11893       if ( !groupDS || groupDS->IsEmpty() ) continue;
11894       std::string grpName = group->GetName();
11895       //MESSAGE("grpName=" << grpName);
11896       if (grpName == groupName)
11897         break;
11898       else
11899         groupDS = 0;
11900     }
11901
11902   bool isNodeGroup = false;
11903   bool isNodeCoords = false;
11904   if (groupDS)
11905     {
11906       if (groupDS->GetType() != SMDSAbs_Node)
11907         return;
11908       isNodeGroup = true;     // a group of nodes exists and it is in this mesh
11909     }
11910
11911   if (nodesCoords.size() > 0)
11912     isNodeCoords = true; // a list o nodes given by their coordinates
11913   //MESSAGE("---" << isNodeGroup << " " << isNodeCoords);
11914
11915   // --- define groups to build
11916
11917   int idg; // --- group of SMDS volumes
11918   string grpvName = groupName;
11919   grpvName += "_vol";
11920   SMESH_Group *grp = this->myMesh->AddGroup(SMDSAbs_Volume, grpvName.c_str(), idg);
11921   if (!grp)
11922     {
11923       MESSAGE("group not created " << grpvName);
11924       return;
11925     }
11926   SMESHDS_Group *sgrp = dynamic_cast<SMESHDS_Group*>(grp->GetGroupDS());
11927
11928   int idgs; // --- group of SMDS faces on the skin
11929   string grpsName = groupName;
11930   grpsName += "_skin";
11931   SMESH_Group *grps = this->myMesh->AddGroup(SMDSAbs_Face, grpsName.c_str(), idgs);
11932   if (!grps)
11933     {
11934       MESSAGE("group not created " << grpsName);
11935       return;
11936     }
11937   SMESHDS_Group *sgrps = dynamic_cast<SMESHDS_Group*>(grps->GetGroupDS());
11938
11939   int idgi; // --- group of SMDS faces internal (several shapes)
11940   string grpiName = groupName;
11941   grpiName += "_internalFaces";
11942   SMESH_Group *grpi = this->myMesh->AddGroup(SMDSAbs_Face, grpiName.c_str(), idgi);
11943   if (!grpi)
11944     {
11945       MESSAGE("group not created " << grpiName);
11946       return;
11947     }
11948   SMESHDS_Group *sgrpi = dynamic_cast<SMESHDS_Group*>(grpi->GetGroupDS());
11949
11950   int idgei; // --- group of SMDS faces internal (several shapes)
11951   string grpeiName = groupName;
11952   grpeiName += "_internalEdges";
11953   SMESH_Group *grpei = this->myMesh->AddGroup(SMDSAbs_Edge, grpeiName.c_str(), idgei);
11954   if (!grpei)
11955     {
11956       MESSAGE("group not created " << grpeiName);
11957       return;
11958     }
11959   SMESHDS_Group *sgrpei = dynamic_cast<SMESHDS_Group*>(grpei->GetGroupDS());
11960
11961   // --- build downward connectivity
11962
11963   SMESHDS_Mesh *meshDS = this->myMesh->GetMeshDS();
11964   meshDS->BuildDownWardConnectivity(true);
11965   SMDS_UnstructuredGrid* grid = meshDS->getGrid();
11966
11967   // --- set of volumes detected inside
11968
11969   std::set<int> setOfInsideVol;
11970   std::set<int> setOfVolToCheck;
11971
11972   std::vector<gp_Pnt> gpnts;
11973   gpnts.clear();
11974
11975   if (isNodeGroup) // --- a group of nodes is provided : find all the volumes using one or more of this nodes
11976     {
11977       MESSAGE("group of nodes provided");
11978       SMDS_ElemIteratorPtr elemIt = groupDS->GetElements();
11979       while ( elemIt->more() )
11980         {
11981           const SMDS_MeshElement* elem = elemIt->next();
11982           if (!elem)
11983             continue;
11984           const SMDS_MeshNode* node = dynamic_cast<const SMDS_MeshNode*>(elem);
11985           if (!node)
11986             continue;
11987           SMDS_MeshElement* vol = 0;
11988           SMDS_ElemIteratorPtr volItr = node->GetInverseElementIterator(SMDSAbs_Volume);
11989           while (volItr->more())
11990             {
11991               vol = (SMDS_MeshElement*)volItr->next();
11992               setOfInsideVol.insert(vol->getVtkId());
11993               sgrp->Add(vol->GetID());
11994             }
11995         }
11996     }
11997   else if (isNodeCoords)
11998     {
11999       MESSAGE("list of nodes coordinates provided");
12000       int i = 0;
12001       int k = 0;
12002       while (i < nodesCoords.size()-2)
12003         {
12004           double x = nodesCoords[i++];
12005           double y = nodesCoords[i++];
12006           double z = nodesCoords[i++];
12007           gp_Pnt p = gp_Pnt(x, y ,z);
12008           gpnts.push_back(p);
12009           MESSAGE("TopoDS_Vertex " << k++ << " " << p.X() << " " << p.Y() << " " << p.Z());
12010         }
12011     }
12012   else // --- no group, no coordinates : use the vertices of the geom shape provided, and radius
12013     {
12014       MESSAGE("no group of nodes provided, using vertices from geom shape, and radius");
12015       TopTools_IndexedMapOfShape vertexMap;
12016       TopExp::MapShapes( theShape, TopAbs_VERTEX, vertexMap );
12017       gp_Pnt p = gp_Pnt(0,0,0);
12018       if (vertexMap.Extent() < 1)
12019         return;
12020
12021       for ( int i = 1; i <= vertexMap.Extent(); ++i )
12022         {
12023           const TopoDS_Vertex& vertex = TopoDS::Vertex( vertexMap( i ));
12024           p = BRep_Tool::Pnt(vertex);
12025           gpnts.push_back(p);
12026           MESSAGE("TopoDS_Vertex " << i << " " << p.X() << " " << p.Y() << " " << p.Z());
12027         }
12028     }
12029
12030   if (gpnts.size() > 0)
12031     {
12032       int nodeId = 0;
12033       const SMDS_MeshNode* startNode = theNodeSearcher->FindClosestTo(gpnts[0]);
12034       if (startNode)
12035         nodeId = startNode->GetID();
12036       MESSAGE("nodeId " << nodeId);
12037
12038       double radius2 = radius*radius;
12039       MESSAGE("radius2 " << radius2);
12040
12041       // --- volumes on start node
12042
12043       setOfVolToCheck.clear();
12044       SMDS_MeshElement* startVol = 0;
12045       SMDS_ElemIteratorPtr volItr = startNode->GetInverseElementIterator(SMDSAbs_Volume);
12046       while (volItr->more())
12047         {
12048           startVol = (SMDS_MeshElement*)volItr->next();
12049           setOfVolToCheck.insert(startVol->getVtkId());
12050         }
12051       if (setOfVolToCheck.empty())
12052         {
12053           MESSAGE("No volumes found");
12054           return;
12055         }
12056
12057       // --- starting with central volumes then their neighbors, check if they are inside
12058       //     or outside the domain, until no more new neighbor volume is inside.
12059       //     Fill the group of inside volumes
12060
12061       std::map<int, double> mapOfNodeDistance2;
12062       mapOfNodeDistance2.clear();
12063       std::set<int> setOfOutsideVol;
12064       while (!setOfVolToCheck.empty())
12065         {
12066           std::set<int>::iterator it = setOfVolToCheck.begin();
12067           int vtkId = *it;
12068           MESSAGE("volume to check,  vtkId " << vtkId << " smdsId " << meshDS->fromVtkToSmds(vtkId));
12069           bool volInside = false;
12070           vtkIdType npts = 0;
12071           vtkIdType* pts = 0;
12072           grid->GetCellPoints(vtkId, npts, pts);
12073           for (int i=0; i<npts; i++)
12074             {
12075               double distance2 = 0;
12076               if (mapOfNodeDistance2.count(pts[i]))
12077                 {
12078                   distance2 = mapOfNodeDistance2[pts[i]];
12079                   MESSAGE("point " << pts[i] << " distance2 " << distance2);
12080                 }
12081               else
12082                 {
12083                   double *coords = grid->GetPoint(pts[i]);
12084                   gp_Pnt aPoint = gp_Pnt(coords[0], coords[1], coords[2]);
12085                   distance2 = 1.E40;
12086                   for (int j=0; j<gpnts.size(); j++)
12087                     {
12088                       double d2 = aPoint.SquareDistance(gpnts[j]);
12089                       if (d2 < distance2)
12090                         {
12091                           distance2 = d2;
12092                           if (distance2 < radius2)
12093                             break;
12094                         }
12095                     }
12096                   mapOfNodeDistance2[pts[i]] = distance2;
12097                   MESSAGE("  point "  << pts[i]  << " distance2 " << distance2 << " coords " << coords[0] << " " << coords[1] << " " <<  coords[2]);
12098                 }
12099               if (distance2 < radius2)
12100                 {
12101                   volInside = true; // one or more nodes inside the domain
12102                   sgrp->Add(meshDS->fromVtkToSmds(vtkId));
12103                   break;
12104                 }
12105             }
12106           if (volInside)
12107             {
12108               setOfInsideVol.insert(vtkId);
12109               MESSAGE("  volume inside,  vtkId " << vtkId << " smdsId " << meshDS->fromVtkToSmds(vtkId));
12110               int neighborsVtkIds[NBMAXNEIGHBORS];
12111               int downIds[NBMAXNEIGHBORS];
12112               unsigned char downTypes[NBMAXNEIGHBORS];
12113               int nbNeighbors = grid->GetNeighbors(neighborsVtkIds, downIds, downTypes, vtkId);
12114               for (int n = 0; n < nbNeighbors; n++)
12115                 if (!setOfInsideVol.count(neighborsVtkIds[n]) ||setOfOutsideVol.count(neighborsVtkIds[n]))
12116                   setOfVolToCheck.insert(neighborsVtkIds[n]);
12117             }
12118           else
12119             {
12120               setOfOutsideVol.insert(vtkId);
12121               MESSAGE("  volume outside, vtkId " << vtkId << " smdsId " << meshDS->fromVtkToSmds(vtkId));
12122             }
12123           setOfVolToCheck.erase(vtkId);
12124         }
12125     }
12126
12127   // --- for outside hexahedrons, check if they have more than one neighbor volume inside
12128   //     If yes, add the volume to the inside set
12129
12130   bool addedInside = true;
12131   std::set<int> setOfVolToReCheck;
12132   while (addedInside)
12133     {
12134       MESSAGE(" --------------------------- re check");
12135       addedInside = false;
12136       std::set<int>::iterator itv = setOfInsideVol.begin();
12137       for (; itv != setOfInsideVol.end(); ++itv)
12138         {
12139           int vtkId = *itv;
12140           int neighborsVtkIds[NBMAXNEIGHBORS];
12141           int downIds[NBMAXNEIGHBORS];
12142           unsigned char downTypes[NBMAXNEIGHBORS];
12143           int nbNeighbors = grid->GetNeighbors(neighborsVtkIds, downIds, downTypes, vtkId);
12144           for (int n = 0; n < nbNeighbors; n++)
12145             if (!setOfInsideVol.count(neighborsVtkIds[n]))
12146               setOfVolToReCheck.insert(neighborsVtkIds[n]);
12147         }
12148       setOfVolToCheck = setOfVolToReCheck;
12149       setOfVolToReCheck.clear();
12150       while  (!setOfVolToCheck.empty())
12151         {
12152           std::set<int>::iterator it = setOfVolToCheck.begin();
12153           int vtkId = *it;
12154           if (grid->GetCellType(vtkId) == VTK_HEXAHEDRON)
12155             {
12156               MESSAGE("volume to recheck,  vtkId " << vtkId << " smdsId " << meshDS->fromVtkToSmds(vtkId));
12157               int countInside = 0;
12158               int neighborsVtkIds[NBMAXNEIGHBORS];
12159               int downIds[NBMAXNEIGHBORS];
12160               unsigned char downTypes[NBMAXNEIGHBORS];
12161               int nbNeighbors = grid->GetNeighbors(neighborsVtkIds, downIds, downTypes, vtkId);
12162               for (int n = 0; n < nbNeighbors; n++)
12163                 if (setOfInsideVol.count(neighborsVtkIds[n]))
12164                   countInside++;
12165               MESSAGE("countInside " << countInside);
12166               if (countInside > 1)
12167                 {
12168                   MESSAGE("  volume inside,  vtkId " << vtkId << " smdsId " << meshDS->fromVtkToSmds(vtkId));
12169                   setOfInsideVol.insert(vtkId);
12170                   sgrp->Add(meshDS->fromVtkToSmds(vtkId));
12171                   addedInside = true;
12172                 }
12173               else
12174                 setOfVolToReCheck.insert(vtkId);
12175             }
12176           setOfVolToCheck.erase(vtkId);
12177         }
12178     }
12179
12180   // --- map of Downward faces at the boundary, inside the global volume
12181   //     map of Downward faces on the skin of the global volume (equivalent to SMDS faces on the skin)
12182   //     fill group of SMDS faces inside the volume (when several volume shapes)
12183   //     fill group of SMDS faces on the skin of the global volume (if skin)
12184
12185   std::map<DownIdType, int, DownIdCompare> boundaryFaces; // boundary faces inside the volume --> corresponding cell
12186   std::map<DownIdType, int, DownIdCompare> skinFaces;     // faces on the skin of the global volume --> corresponding cell
12187   std::set<int>::iterator it = setOfInsideVol.begin();
12188   for (; it != setOfInsideVol.end(); ++it)
12189     {
12190       int vtkId = *it;
12191       //MESSAGE("  vtkId " << vtkId  << " smdsId " << meshDS->fromVtkToSmds(vtkId));
12192       int neighborsVtkIds[NBMAXNEIGHBORS];
12193       int downIds[NBMAXNEIGHBORS];
12194       unsigned char downTypes[NBMAXNEIGHBORS];
12195       int nbNeighbors = grid->GetNeighbors(neighborsVtkIds, downIds, downTypes, vtkId, true);
12196       for (int n = 0; n < nbNeighbors; n++)
12197         {
12198           int neighborDim = SMDS_Downward::getCellDimension(grid->GetCellType(neighborsVtkIds[n]));
12199           if (neighborDim == 3)
12200             {
12201               if (! setOfInsideVol.count(neighborsVtkIds[n])) // neighbor volume is not inside : face is boundary
12202                 {
12203                   DownIdType face(downIds[n], downTypes[n]);
12204                   boundaryFaces[face] = vtkId;
12205                 }
12206               // if the face between to volumes is in the mesh, get it (internal face between shapes)
12207               int vtkFaceId = grid->getDownArray(downTypes[n])->getVtkCellId(downIds[n]);
12208               if (vtkFaceId >= 0)
12209                 {
12210                   sgrpi->Add(meshDS->fromVtkToSmds(vtkFaceId));
12211                   // find also the smds edges on this face
12212                   int nbEdges = grid->getDownArray(downTypes[n])->getNumberOfDownCells(downIds[n]);
12213                   const int* dEdges = grid->getDownArray(downTypes[n])->getDownCells(downIds[n]);
12214                   const unsigned char* dTypes = grid->getDownArray(downTypes[n])->getDownTypes(downIds[n]);
12215                   for (int i = 0; i < nbEdges; i++)
12216                     {
12217                       int vtkEdgeId = grid->getDownArray(dTypes[i])->getVtkCellId(dEdges[i]);
12218                       if (vtkEdgeId >= 0)
12219                         sgrpei->Add(meshDS->fromVtkToSmds(vtkEdgeId));
12220                     }
12221                 }
12222             }
12223           else if (neighborDim == 2) // skin of the volume
12224             {
12225               DownIdType face(downIds[n], downTypes[n]);
12226               skinFaces[face] = vtkId;
12227               int vtkFaceId = grid->getDownArray(downTypes[n])->getVtkCellId(downIds[n]);
12228               if (vtkFaceId >= 0)
12229                 sgrps->Add(meshDS->fromVtkToSmds(vtkFaceId));
12230             }
12231         }
12232     }
12233
12234   // --- identify the edges constituting the wire of each subshape on the skin
12235   //     define polylines with the nodes of edges, equivalent to wires
12236   //     project polylines on subshapes, and partition, to get geom faces
12237
12238   std::map<int, std::set<int> > shapeIdToVtkIdSet; // shapeId --> set of vtkId on skin
12239   std::set<int> emptySet;
12240   emptySet.clear();
12241   std::set<int> shapeIds;
12242
12243   SMDS_ElemIteratorPtr itelem = sgrps->GetElements();
12244   while (itelem->more())
12245     {
12246       const SMDS_MeshElement *elem = itelem->next();
12247       int shapeId = elem->getshapeId();
12248       int vtkId = elem->getVtkId();
12249       if (!shapeIdToVtkIdSet.count(shapeId))
12250         {
12251           shapeIdToVtkIdSet[shapeId] = emptySet;
12252           shapeIds.insert(shapeId);
12253         }
12254       shapeIdToVtkIdSet[shapeId].insert(vtkId);
12255     }
12256
12257   std::map<int, std::set<DownIdType, DownIdCompare> > shapeIdToEdges; // shapeId --> set of downward edges
12258   std::set<DownIdType, DownIdCompare> emptyEdges;
12259   emptyEdges.clear();
12260
12261   std::map<int, std::set<int> >::iterator itShape =  shapeIdToVtkIdSet.begin();
12262   for (; itShape != shapeIdToVtkIdSet.end(); ++itShape)
12263     {
12264       int shapeId = itShape->first;
12265       MESSAGE(" --- Shape ID --- "<< shapeId);
12266       shapeIdToEdges[shapeId] = emptyEdges;
12267
12268       std::vector<int> nodesEdges;
12269
12270       std::set<int>::iterator its = itShape->second.begin();
12271       for (; its != itShape->second.end(); ++its)
12272         {
12273           int vtkId = *its;
12274           MESSAGE("     " << vtkId);
12275           int neighborsVtkIds[NBMAXNEIGHBORS];
12276           int downIds[NBMAXNEIGHBORS];
12277           unsigned char downTypes[NBMAXNEIGHBORS];
12278           int nbNeighbors = grid->GetNeighbors(neighborsVtkIds, downIds, downTypes, vtkId);
12279           for (int n = 0; n < nbNeighbors; n++)
12280             {
12281               if (neighborsVtkIds[n]<0) // only smds faces are considered as neighbors here
12282                 continue;
12283               int smdsId = meshDS->fromVtkToSmds(neighborsVtkIds[n]);
12284               const SMDS_MeshElement* elem = meshDS->FindElement(smdsId);
12285               if ( shapeIds.count(elem->getshapeId()) && !sgrps->Contains(elem)) // edge : neighbor in the set of shape, not in the group
12286                 {
12287                   DownIdType edge(downIds[n], downTypes[n]);
12288                   if (!shapeIdToEdges[shapeId].count(edge))
12289                     {
12290                       shapeIdToEdges[shapeId].insert(edge);
12291                       int vtkNodeId[3];
12292                       int nbNodes = grid->getDownArray(downTypes[n])->getNodes(downIds[n],vtkNodeId);
12293                       nodesEdges.push_back(vtkNodeId[0]);
12294                       nodesEdges.push_back(vtkNodeId[nbNodes-1]);
12295                       MESSAGE("       --- nodes " << vtkNodeId[0]+1 << " " << vtkNodeId[nbNodes-1]+1);
12296                     }
12297                 }
12298             }
12299         }
12300
12301       std::list<int> order;
12302       order.clear();
12303       if (nodesEdges.size() > 0)
12304         {
12305           order.push_back(nodesEdges[0]); MESSAGE("       --- back " << order.back()+1); // SMDS id = VTK id + 1;
12306           nodesEdges[0] = -1;
12307           order.push_back(nodesEdges[1]); MESSAGE("       --- back " << order.back()+1);
12308           nodesEdges[1] = -1; // do not reuse this edge
12309           bool found = true;
12310           while (found)
12311             {
12312               int nodeTofind = order.back(); // try first to push back
12313               int i = 0;
12314               for (i = 0; i<nodesEdges.size(); i++)
12315                 if (nodesEdges[i] == nodeTofind)
12316                   break;
12317               if (i == nodesEdges.size())
12318                 found = false; // no follower found on back
12319               else
12320                 {
12321                   if (i%2) // odd ==> use the previous one
12322                     if (nodesEdges[i-1] < 0)
12323                       found = false;
12324                     else
12325                       {
12326                         order.push_back(nodesEdges[i-1]); MESSAGE("       --- back " << order.back()+1);
12327                         nodesEdges[i-1] = -1;
12328                       }
12329                   else // even ==> use the next one
12330                     if (nodesEdges[i+1] < 0)
12331                       found = false;
12332                     else
12333                       {
12334                         order.push_back(nodesEdges[i+1]); MESSAGE("       --- back " << order.back()+1);
12335                         nodesEdges[i+1] = -1;
12336                       }
12337                 }
12338               if (found)
12339                 continue;
12340               // try to push front
12341               found = true;
12342               nodeTofind = order.front(); // try to push front
12343               for (i = 0; i<nodesEdges.size(); i++)
12344                 if (nodesEdges[i] == nodeTofind)
12345                   break;
12346               if (i == nodesEdges.size())
12347                 {
12348                   found = false; // no predecessor found on front
12349                   continue;
12350                 }
12351               if (i%2) // odd ==> use the previous one
12352                 if (nodesEdges[i-1] < 0)
12353                   found = false;
12354                 else
12355                   {
12356                     order.push_front(nodesEdges[i-1]); MESSAGE("       --- front " << order.front()+1);
12357                     nodesEdges[i-1] = -1;
12358                   }
12359               else // even ==> use the next one
12360                 if (nodesEdges[i+1] < 0)
12361                   found = false;
12362                 else
12363                   {
12364                     order.push_front(nodesEdges[i+1]); MESSAGE("       --- front " << order.front()+1);
12365                     nodesEdges[i+1] = -1;
12366                   }
12367             }
12368         }
12369
12370
12371       std::vector<int> nodes;
12372       nodes.push_back(shapeId);
12373       std::list<int>::iterator itl = order.begin();
12374       for (; itl != order.end(); itl++)
12375         {
12376           nodes.push_back((*itl) + 1); // SMDS id = VTK id + 1;
12377           MESSAGE("              ordered node " << nodes[nodes.size()-1]);
12378         }
12379       listOfListOfNodes.push_back(nodes);
12380     }
12381
12382   //     partition geom faces with blocFissure
12383   //     mesh blocFissure and geom faces of the skin (external wires given, triangle algo to choose)
12384   //     mesh volume around blocFissure (skin triangles and quadrangle given, tetra algo to choose)
12385
12386   return;
12387 }
12388
12389
12390 //================================================================================
12391 /*!
12392  * \brief Generates skin mesh (containing 2D cells) from 3D mesh
12393  * The created 2D mesh elements based on nodes of free faces of boundary volumes
12394  * \return TRUE if operation has been completed successfully, FALSE otherwise
12395  */
12396 //================================================================================
12397
12398 bool SMESH_MeshEditor::Make2DMeshFrom3D()
12399 {
12400   // iterates on volume elements and detect all free faces on them
12401   SMESHDS_Mesh* aMesh = GetMeshDS();
12402   if (!aMesh)
12403     return false;
12404   //bool res = false;
12405   int nbFree = 0, nbExisted = 0, nbCreated = 0;
12406   SMDS_VolumeIteratorPtr vIt = aMesh->volumesIterator();
12407   while(vIt->more())
12408   {
12409     const SMDS_MeshVolume* volume = vIt->next();
12410     SMDS_VolumeTool vTool( volume, /*ignoreCentralNodes=*/false );
12411     vTool.SetExternalNormal();
12412     //const bool isPoly = volume->IsPoly();
12413     const int iQuad = volume->IsQuadratic();
12414     for ( int iface = 0, n = vTool.NbFaces(); iface < n; iface++ )
12415     {
12416       if (!vTool.IsFreeFace(iface))
12417         continue;
12418       nbFree++;
12419       vector<const SMDS_MeshNode *> nodes;
12420       int nbFaceNodes = vTool.NbFaceNodes(iface);
12421       const SMDS_MeshNode** faceNodes = vTool.GetFaceNodes(iface);
12422       int inode = 0;
12423       for ( ; inode < nbFaceNodes; inode += iQuad+1)
12424         nodes.push_back(faceNodes[inode]);
12425       if (iQuad) { // add medium nodes
12426         for ( inode = 1; inode < nbFaceNodes; inode += 2)
12427           nodes.push_back(faceNodes[inode]);
12428         if ( nbFaceNodes == 9 ) // bi-quadratic quad
12429           nodes.push_back(faceNodes[8]);
12430       }
12431       // add new face based on volume nodes
12432       if (aMesh->FindElement( nodes, SMDSAbs_Face, /*noMedium=*/false) ) {
12433         nbExisted++;
12434         continue; // face already exsist
12435       }
12436       AddElement(nodes, SMDSAbs_Face, ( !iQuad && nbFaceNodes/(iQuad+1) > 4 ));
12437       nbCreated++;
12438     }
12439   }
12440   return ( nbFree==(nbExisted+nbCreated) );
12441 }
12442
12443 namespace
12444 {
12445   inline const SMDS_MeshNode* getNodeWithSameID(SMESHDS_Mesh* mesh, const SMDS_MeshNode* node)
12446   {
12447     if ( const SMDS_MeshNode* n = mesh->FindNode( node->GetID() ))
12448       return n;
12449     return mesh->AddNodeWithID( node->X(),node->Y(),node->Z(), node->GetID() );
12450   }
12451 }
12452 //================================================================================
12453 /*!
12454  * \brief Creates missing boundary elements
12455  *  \param elements - elements whose boundary is to be checked
12456  *  \param dimension - defines type of boundary elements to create
12457  *  \param group - a group to store created boundary elements in
12458  *  \param targetMesh - a mesh to store created boundary elements in
12459  *  \param toCopyElements - if true, the checked elements will be copied into the targetMesh
12460  *  \param toCopyExistingBoundary - if true, not only new but also pre-existing
12461  *                                boundary elements will be copied into the targetMesh
12462  *  \param toAddExistingBondary - if true, not only new but also pre-existing
12463  *                                boundary elements will be added into the new group
12464  *  \param aroundElements - if true, elements will be created on boundary of given
12465  *                          elements else, on boundary of the whole mesh.
12466  * \return nb of added boundary elements
12467  */
12468 //================================================================================
12469
12470 int SMESH_MeshEditor::MakeBoundaryMesh(const TIDSortedElemSet& elements,
12471                                        Bnd_Dimension           dimension,
12472                                        SMESH_Group*            group/*=0*/,
12473                                        SMESH_Mesh*             targetMesh/*=0*/,
12474                                        bool                    toCopyElements/*=false*/,
12475                                        bool                    toCopyExistingBoundary/*=false*/,
12476                                        bool                    toAddExistingBondary/*= false*/,
12477                                        bool                    aroundElements/*= false*/)
12478 {
12479   SMDSAbs_ElementType missType = (dimension == BND_2DFROM3D) ? SMDSAbs_Face : SMDSAbs_Edge;
12480   SMDSAbs_ElementType elemType = (dimension == BND_1DFROM2D) ? SMDSAbs_Face : SMDSAbs_Volume;
12481   // hope that all elements are of the same type, do not check them all
12482   if ( !elements.empty() && (*elements.begin())->GetType() != elemType )
12483     throw SALOME_Exception(LOCALIZED("wrong element type"));
12484
12485   if ( !targetMesh )
12486     toCopyElements = toCopyExistingBoundary = false;
12487
12488   SMESH_MeshEditor tgtEditor( targetMesh ? targetMesh : myMesh );
12489   SMESHDS_Mesh* aMesh = GetMeshDS(), *tgtMeshDS = tgtEditor.GetMeshDS();
12490   int nbAddedBnd = 0;
12491
12492   // editor adding present bnd elements and optionally holding elements to add to the group
12493   SMESH_MeshEditor* presentEditor;
12494   SMESH_MeshEditor tgtEditor2( tgtEditor.GetMesh() );
12495   presentEditor = toAddExistingBondary ? &tgtEditor : &tgtEditor2;
12496
12497   SMESH_MesherHelper helper( *myMesh );
12498   const TopAbs_ShapeEnum missShapeType = ( missType==SMDSAbs_Face ? TopAbs_FACE : TopAbs_EDGE );
12499   SMDS_VolumeTool vTool;
12500   TIDSortedElemSet avoidSet;
12501   const TIDSortedElemSet emptySet, *elemSet = aroundElements ? &elements : &emptySet;
12502   int inode;
12503
12504   typedef vector<const SMDS_MeshNode*> TConnectivity;
12505
12506   SMDS_ElemIteratorPtr eIt;
12507   if (elements.empty())
12508     eIt = aMesh->elementsIterator(elemType);
12509   else
12510     eIt = SMDS_ElemIteratorPtr( new TSetIterator( elements.begin(), elements.end() ));
12511
12512   while (eIt->more())
12513   {
12514     const SMDS_MeshElement* elem = eIt->next();
12515     const int iQuad = elem->IsQuadratic();
12516
12517     // ------------------------------------------------------------------------------------
12518     // 1. For an elem, get present bnd elements and connectivities of missing bnd elements
12519     // ------------------------------------------------------------------------------------
12520     vector<const SMDS_MeshElement*> presentBndElems;
12521     vector<TConnectivity>           missingBndElems;
12522     TConnectivity nodes;
12523     if ( vTool.Set(elem, /*ignoreCentralNodes=*/true) ) // elem is a volume --------------
12524     {
12525       vTool.SetExternalNormal();
12526       const SMDS_MeshElement* otherVol = 0;
12527       for ( int iface = 0, n = vTool.NbFaces(); iface < n; iface++ )
12528       {
12529         if ( !vTool.IsFreeFace(iface, &otherVol) &&
12530              ( !aroundElements || elements.count( otherVol )))
12531           continue;
12532         const int nbFaceNodes = vTool.NbFaceNodes(iface);
12533         const SMDS_MeshNode** nn = vTool.GetFaceNodes(iface);
12534         if ( missType == SMDSAbs_Edge ) // boundary edges
12535         {
12536           nodes.resize( 2+iQuad );
12537           for ( int i = 0; i < nbFaceNodes; i += 1+iQuad)
12538           {
12539             for ( int j = 0; j < nodes.size(); ++j )
12540               nodes[j] =nn[i+j];
12541             if ( const SMDS_MeshElement* edge =
12542                  aMesh->FindElement(nodes,SMDSAbs_Edge,/*noMedium=*/false))
12543               presentBndElems.push_back( edge );
12544             else
12545               missingBndElems.push_back( nodes );
12546           }
12547         }
12548         else // boundary face
12549         {
12550           nodes.clear();
12551           for ( inode = 0; inode < nbFaceNodes; inode += 1+iQuad)
12552             nodes.push_back( nn[inode] );
12553           if (iQuad) // add medium nodes
12554             for ( inode = 1; inode < nbFaceNodes; inode += 2)
12555               nodes.push_back( nn[inode] );
12556           int iCenter = vTool.GetCenterNodeIndex(iface); // for HEX27
12557           if ( iCenter > 0 )
12558             nodes.push_back( vTool.GetNodes()[ iCenter ] );
12559
12560           if (const SMDS_MeshElement * f = aMesh->FindElement( nodes,
12561                                                                SMDSAbs_Face, /*noMedium=*/false ))
12562             presentBndElems.push_back( f );
12563           else
12564             missingBndElems.push_back( nodes );
12565
12566           if ( targetMesh != myMesh )
12567           {
12568             // add 1D elements on face boundary to be added to a new mesh
12569             const SMDS_MeshElement* edge;
12570             for ( inode = 0; inode < nbFaceNodes; inode += 1+iQuad)
12571             {
12572               if ( iQuad )
12573                 edge = aMesh->FindEdge( nn[inode], nn[inode+1], nn[inode+2]);
12574               else
12575                 edge = aMesh->FindEdge( nn[inode], nn[inode+1]);
12576               if ( edge && avoidSet.insert( edge ).second )
12577                 presentBndElems.push_back( edge );
12578             }
12579           }
12580         }
12581       }
12582     }
12583     else                     // elem is a face ------------------------------------------
12584     {
12585       avoidSet.clear(), avoidSet.insert( elem );
12586       int nbNodes = elem->NbCornerNodes();
12587       nodes.resize( 2 /*+ iQuad*/);
12588       for ( int i = 0; i < nbNodes; i++ )
12589       {
12590         nodes[0] = elem->GetNode(i);
12591         nodes[1] = elem->GetNode((i+1)%nbNodes);
12592         if ( FindFaceInSet( nodes[0], nodes[1], *elemSet, avoidSet))
12593           continue; // not free link
12594
12595         //if ( iQuad )
12596         //nodes[2] = elem->GetNode( i + nbNodes );
12597         if ( const SMDS_MeshElement* edge =
12598              aMesh->FindElement(nodes,SMDSAbs_Edge,/*noMedium=*/true))
12599           presentBndElems.push_back( edge );
12600         else
12601           missingBndElems.push_back( nodes );
12602       }
12603     }
12604
12605     // ---------------------------------
12606     // 2. Add missing boundary elements
12607     // ---------------------------------
12608     if ( targetMesh != myMesh )
12609       // instead of making a map of nodes in this mesh and targetMesh,
12610       // we create nodes with same IDs.
12611       for ( int i = 0; i < missingBndElems.size(); ++i )
12612       {
12613         TConnectivity& srcNodes = missingBndElems[i];
12614         TConnectivity  nodes( srcNodes.size() );
12615         for ( inode = 0; inode < nodes.size(); ++inode )
12616           nodes[inode] = getNodeWithSameID( tgtMeshDS, srcNodes[inode] );
12617         if ( aroundElements && tgtEditor.GetMeshDS()->FindElement( nodes,
12618                                                                    missType,
12619                                                                    /*noMedium=*/false))
12620           continue;
12621         tgtEditor.AddElement(nodes, missType, !iQuad && nodes.size()/(iQuad+1)>4);
12622         ++nbAddedBnd;
12623       }
12624     else
12625       for ( int i = 0; i < missingBndElems.size(); ++i )
12626       {
12627         TConnectivity& nodes = missingBndElems[i];
12628         if ( aroundElements && tgtEditor.GetMeshDS()->FindElement( nodes,
12629                                                                    missType,
12630                                                                    /*noMedium=*/false))
12631           continue;
12632         SMDS_MeshElement* elem =
12633           tgtEditor.AddElement(nodes, missType, !iQuad && nodes.size()/(iQuad+1)>4);
12634         ++nbAddedBnd;
12635
12636         // try to set a new element to a shape
12637         if ( myMesh->HasShapeToMesh() )
12638         {
12639           bool ok = true;
12640           set< pair<TopAbs_ShapeEnum, int > > mediumShapes;
12641           const int nbN = nodes.size() / (iQuad+1 );
12642           for ( inode = 0; inode < nbN && ok; ++inode )
12643           {
12644             pair<int, TopAbs_ShapeEnum> i_stype =
12645               helper.GetMediumPos( nodes[inode], nodes[(inode+1)%nbN]);
12646             if (( ok = ( i_stype.first > 0 && i_stype.second >= TopAbs_FACE )))
12647               mediumShapes.insert( make_pair ( i_stype.second, i_stype.first ));
12648           }
12649           if ( ok && mediumShapes.size() > 1 )
12650           {
12651             set< pair<TopAbs_ShapeEnum, int > >::iterator stype_i = mediumShapes.begin();
12652             pair<TopAbs_ShapeEnum, int> stype_i_0 = *stype_i;
12653             for ( ++stype_i; stype_i != mediumShapes.end() && ok; ++stype_i )
12654             {
12655               if (( ok = ( stype_i->first != stype_i_0.first )))
12656                 ok = helper.IsSubShape( aMesh->IndexToShape( stype_i->second ),
12657                                         aMesh->IndexToShape( stype_i_0.second ));
12658             }
12659           }
12660           if ( ok && mediumShapes.begin()->first == missShapeType )
12661             aMesh->SetMeshElementOnShape( elem, mediumShapes.begin()->second );
12662         }
12663       }
12664
12665     // ----------------------------------
12666     // 3. Copy present boundary elements
12667     // ----------------------------------
12668     if ( toCopyExistingBoundary )
12669       for ( int i = 0 ; i < presentBndElems.size(); ++i )
12670       {
12671         const SMDS_MeshElement* e = presentBndElems[i];
12672         TConnectivity nodes( e->NbNodes() );
12673         for ( inode = 0; inode < nodes.size(); ++inode )
12674           nodes[inode] = getNodeWithSameID( tgtMeshDS, e->GetNode(inode) );
12675         presentEditor->AddElement(nodes, e->GetType(), e->IsPoly());
12676       }
12677     else // store present elements to add them to a group
12678       for ( int i = 0 ; i < presentBndElems.size(); ++i )
12679       {
12680         presentEditor->myLastCreatedElems.Append(presentBndElems[i]);
12681       }
12682
12683   } // loop on given elements
12684
12685   // ---------------------------------------------
12686   // 4. Fill group with boundary elements
12687   // ---------------------------------------------
12688   if ( group )
12689   {
12690     if ( SMESHDS_Group* g = dynamic_cast<SMESHDS_Group*>( group->GetGroupDS() ))
12691       for ( int i = 0; i < tgtEditor.myLastCreatedElems.Size(); ++i )
12692         g->SMDSGroup().Add( tgtEditor.myLastCreatedElems( i+1 ));
12693   }
12694   tgtEditor.myLastCreatedElems.Clear();
12695   tgtEditor2.myLastCreatedElems.Clear();
12696
12697   // -----------------------
12698   // 5. Copy given elements
12699   // -----------------------
12700   if ( toCopyElements && targetMesh != myMesh )
12701   {
12702     if (elements.empty())
12703       eIt = aMesh->elementsIterator(elemType);
12704     else
12705       eIt = SMDS_ElemIteratorPtr( new TSetIterator( elements.begin(), elements.end() ));
12706     while (eIt->more())
12707     {
12708       const SMDS_MeshElement* elem = eIt->next();
12709       TConnectivity nodes( elem->NbNodes() );
12710       for ( inode = 0; inode < nodes.size(); ++inode )
12711         nodes[inode] = getNodeWithSameID( tgtMeshDS, elem->GetNode(inode) );
12712       tgtEditor.AddElement(nodes, elemType, elem->IsPoly());
12713
12714       tgtEditor.myLastCreatedElems.Clear();
12715     }
12716   }
12717   return nbAddedBnd;
12718 }