]> SALOME platform Git repositories - modules/smesh.git/blob - src/SMESH/SMESH_MeshEditor.cxx
Salome HOME
fix after review. Build completed
[modules/smesh.git] / src / SMESH / SMESH_MeshEditor.cxx
1 // Copyright (C) 2007-2020  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, or (at your option) any later version.
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_Downward.hxx"
30 #include "SMDS_EdgePosition.hxx"
31 #include "SMDS_FaceOfNodes.hxx"
32 #include "SMDS_FacePosition.hxx"
33 #include "SMDS_LinearEdge.hxx"
34 #include "SMDS_MeshGroup.hxx"
35 #include "SMDS_SetIterator.hxx"
36 #include "SMDS_SpacePosition.hxx"
37 #include "SMDS_VolumeTool.hxx"
38 #include "SMESHDS_Group.hxx"
39 #include "SMESHDS_Mesh.hxx"
40 #include "SMESH_Algo.hxx"
41 #include "SMESH_ControlsDef.hxx"
42 #include "SMESH_Group.hxx"
43 #include "SMESH_Mesh.hxx"
44 #include "SMESH_MeshAlgos.hxx"
45 #include "SMESH_MesherHelper.hxx"
46 #include "SMESH_OctreeNode.hxx"
47 #include "SMESH_subMesh.hxx"
48
49 #include "utilities.h"
50 #include "chrono.hxx"
51
52 #include <BRepAdaptor_Surface.hxx>
53 #include <BRepBuilderAPI_MakeEdge.hxx>
54 #include <BRepClass3d_SolidClassifier.hxx>
55 #include <BRep_Tool.hxx>
56 #include <ElCLib.hxx>
57 #include <Extrema_GenExtPS.hxx>
58 #include <Extrema_POnCurv.hxx>
59 #include <Extrema_POnSurf.hxx>
60 #include <Geom2d_Curve.hxx>
61 #include <GeomAdaptor_Surface.hxx>
62 #include <Geom_Curve.hxx>
63 #include <Geom_Surface.hxx>
64 #include <Precision.hxx>
65 #include <TColStd_ListOfInteger.hxx>
66 #include <TopAbs_State.hxx>
67 #include <TopExp.hxx>
68 #include <TopExp_Explorer.hxx>
69 #include <TopTools_ListIteratorOfListOfShape.hxx>
70 #include <TopTools_ListOfShape.hxx>
71 #include <TopTools_SequenceOfShape.hxx>
72 #include <TopoDS.hxx>
73 #include <TopoDS_Edge.hxx>
74 #include <TopoDS_Face.hxx>
75 #include <TopoDS_Solid.hxx>
76 #include <gp.hxx>
77 #include <gp_Ax1.hxx>
78 #include <gp_Dir.hxx>
79 #include <gp_Lin.hxx>
80 #include <gp_Pln.hxx>
81 #include <gp_Trsf.hxx>
82 #include <gp_Vec.hxx>
83 #include <gp_XY.hxx>
84 #include <gp_XYZ.hxx>
85
86 #include <cmath>
87
88 #include <map>
89 #include <set>
90 #include <numeric>
91 #include <limits>
92 #include <algorithm>
93 #include <sstream>
94
95 #include <boost/tuple/tuple.hpp>
96 #include <boost/container/flat_set.hpp>
97
98 #include <Standard_Failure.hxx>
99 #include <Standard_ErrorHandler.hxx>
100
101 #include "SMESH_TryCatch.hxx" // include after OCCT headers!
102
103 #include <smIdType.hxx>
104
105 #define cast2Node(elem) static_cast<const SMDS_MeshNode*>( elem )
106
107 using namespace std;
108 using namespace SMESH::Controls;
109
110 //=======================================================================
111 //function : SMESH_MeshEditor
112 //purpose  :
113 //=======================================================================
114
115 SMESH_MeshEditor::SMESH_MeshEditor( SMESH_Mesh* theMesh )
116   :myMesh( theMesh ) // theMesh may be NULL
117 {
118 }
119
120 //================================================================================
121 /*!
122  * \brief Return mesh DS
123  */
124 //================================================================================
125
126 SMESHDS_Mesh * SMESH_MeshEditor::GetMeshDS()
127 {
128   return myMesh->GetMeshDS();
129 }
130
131
132 //================================================================================
133 /*!
134  * \brief Clears myLastCreatedNodes and myLastCreatedElems
135  */
136 //================================================================================
137
138 void SMESH_MeshEditor::ClearLastCreated()
139 {
140   SMESHUtils::FreeVector( myLastCreatedElems );
141   SMESHUtils::FreeVector( myLastCreatedNodes );
142 }
143
144 //================================================================================
145 /*!
146  * \brief Initializes members by an existing element
147  *  \param [in] elem - the source element
148  *  \param [in] basicOnly - if true, does not set additional data of Ball and Polyhedron
149  */
150 //================================================================================
151
152 SMESH_MeshEditor::ElemFeatures&
153 SMESH_MeshEditor::ElemFeatures::Init( const SMDS_MeshElement* elem, bool basicOnly )
154 {
155   if ( elem )
156   {
157     myType = elem->GetType();
158     if ( myType == SMDSAbs_Face || myType == SMDSAbs_Volume )
159     {
160       myIsPoly = elem->IsPoly();
161       if ( myIsPoly )
162       {
163         myIsQuad = elem->IsQuadratic();
164         if ( myType == SMDSAbs_Volume && !basicOnly )
165         {
166           myPolyhedQuantities = static_cast<const SMDS_MeshVolume* >( elem )->GetQuantities();
167         }
168       }
169     }
170     else if ( myType == SMDSAbs_Ball && !basicOnly )
171     {
172       myBallDiameter = static_cast<const SMDS_BallElement*>(elem)->GetDiameter();
173     }
174   }
175   return *this;
176 }
177
178 //=======================================================================
179 /*!
180  * \brief Add element
181  */
182 //=======================================================================
183
184 SMDS_MeshElement*
185 SMESH_MeshEditor::AddElement(const vector<const SMDS_MeshNode*> & node,
186                              const ElemFeatures&                  features)
187 {
188   SMDS_MeshElement* e = 0;
189   int nbnode = node.size();
190   SMESHDS_Mesh* mesh = GetMeshDS();
191   const int ID = features.myID;
192
193   switch ( features.myType ) {
194   case SMDSAbs_Face:
195     if ( !features.myIsPoly ) {
196       if      (nbnode == 3) {
197         if ( ID >= 1 ) e = mesh->AddFaceWithID(node[0], node[1], node[2], ID);
198         else           e = mesh->AddFace      (node[0], node[1], node[2] );
199       }
200       else if (nbnode == 4) {
201         if ( ID >= 1 ) e = mesh->AddFaceWithID(node[0], node[1], node[2], node[3], ID);
202         else           e = mesh->AddFace      (node[0], node[1], node[2], node[3] );
203       }
204       else if (nbnode == 6) {
205         if ( ID >= 1 ) e = mesh->AddFaceWithID(node[0], node[1], node[2], node[3],
206                                                node[4], node[5], ID);
207         else           e = mesh->AddFace      (node[0], node[1], node[2], node[3],
208                                                node[4], node[5] );
209       }
210       else if (nbnode == 7) {
211         if ( ID >= 1 ) e = mesh->AddFaceWithID(node[0], node[1], node[2], node[3],
212                                                node[4], node[5], node[6], ID);
213         else           e = mesh->AddFace      (node[0], node[1], node[2], node[3],
214                                                node[4], node[5], node[6] );
215       }
216       else if (nbnode == 8) {
217         if ( ID >= 1 ) e = mesh->AddFaceWithID(node[0], node[1], node[2], node[3],
218                                                node[4], node[5], node[6], node[7], ID);
219         else           e = mesh->AddFace      (node[0], node[1], node[2], node[3],
220                                                node[4], node[5], node[6], node[7] );
221       }
222       else if (nbnode == 9) {
223         if ( ID >= 1 ) e = mesh->AddFaceWithID(node[0], node[1], node[2], node[3],
224                                                node[4], node[5], node[6], node[7], node[8], ID);
225         else           e = mesh->AddFace      (node[0], node[1], node[2], node[3],
226                                                node[4], node[5], node[6], node[7], node[8] );
227       }
228     }
229     else if ( !features.myIsQuad )
230     {
231       if ( ID >= 1 ) e = mesh->AddPolygonalFaceWithID(node, ID);
232       else           e = mesh->AddPolygonalFace      (node    );
233     }
234     else if ( nbnode % 2 == 0 ) // just a protection
235     {
236       if ( ID >= 1 ) e = mesh->AddQuadPolygonalFaceWithID(node, ID);
237       else           e = mesh->AddQuadPolygonalFace      (node    );
238     }
239     break;
240
241   case SMDSAbs_Volume:
242     if ( !features.myIsPoly ) {
243       if      (nbnode == 4) {
244         if ( ID >= 1 ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3], ID);
245         else           e = mesh->AddVolume      (node[0], node[1], node[2], node[3] );
246       }
247       else if (nbnode == 5) {
248         if ( ID >= 1 ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
249                                                  node[4], ID);
250         else           e = mesh->AddVolume      (node[0], node[1], node[2], node[3],
251                                                  node[4] );
252       }
253       else if (nbnode == 6) {
254         if ( ID >= 1 ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
255                                                  node[4], node[5], ID);
256         else           e = mesh->AddVolume      (node[0], node[1], node[2], node[3],
257                                                  node[4], node[5] );
258       }
259       else if (nbnode == 8) {
260         if ( ID >= 1 ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
261                                                  node[4], node[5], node[6], node[7], ID);
262         else           e = mesh->AddVolume      (node[0], node[1], node[2], node[3],
263                                                  node[4], node[5], node[6], node[7] );
264       }
265       else if (nbnode == 10) {
266         if ( ID >= 1 ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
267                                                  node[4], node[5], node[6], node[7],
268                                                  node[8], node[9], ID);
269         else           e = mesh->AddVolume      (node[0], node[1], node[2], node[3],
270                                                  node[4], node[5], node[6], node[7],
271                                                  node[8], node[9] );
272       }
273       else if (nbnode == 12) {
274         if ( ID >= 1 ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
275                                                  node[4], node[5], node[6], node[7],
276                                                  node[8], node[9], node[10], node[11], ID);
277         else           e = mesh->AddVolume      (node[0], node[1], node[2], node[3],
278                                                  node[4], node[5], node[6], node[7],
279                                                  node[8], node[9], node[10], node[11] );
280       }
281       else if (nbnode == 13) {
282         if ( ID >= 1 ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
283                                                  node[4], node[5], node[6], node[7],
284                                                  node[8], node[9], node[10],node[11],
285                                                  node[12],ID);
286         else           e = mesh->AddVolume      (node[0], node[1], node[2], node[3],
287                                                  node[4], node[5], node[6], node[7],
288                                                  node[8], node[9], node[10],node[11],
289                                                  node[12] );
290       }
291       else if (nbnode == 15) {
292         if ( ID >= 1 ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
293                                                  node[4], node[5], node[6], node[7],
294                                                  node[8], node[9], node[10],node[11],
295                                                  node[12],node[13],node[14],ID);
296         else           e = mesh->AddVolume      (node[0], node[1], node[2], node[3],
297                                                  node[4], node[5], node[6], node[7],
298                                                  node[8], node[9], node[10],node[11],
299                                                  node[12],node[13],node[14] );
300       }
301       else if (nbnode == 18) {
302         if ( ID >= 1 ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
303                                                  node[4], node[5], node[6], node[7],
304                                                  node[8], node[9], node[10],node[11],
305                                                  node[12],node[13],node[14],
306                                                  node[15],node[16],node[17],ID );
307         else           e = mesh->AddVolume      (node[0], node[1], node[2], node[3],
308                                                  node[4], node[5], node[6], node[7],
309                                                  node[8], node[9], node[10],node[11],
310                                                  node[12],node[13],node[14],
311                                                  node[15],node[16],node[17] );
312       }
313       else if (nbnode == 20) {
314         if ( ID >= 1 ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
315                                                  node[4], node[5], node[6], node[7],
316                                                  node[8], node[9], node[10],node[11],
317                                                  node[12],node[13],node[14],node[15],
318                                                  node[16],node[17],node[18],node[19],ID);
319         else           e = mesh->AddVolume      (node[0], node[1], node[2], node[3],
320                                                  node[4], node[5], node[6], node[7],
321                                                  node[8], node[9], node[10],node[11],
322                                                  node[12],node[13],node[14],node[15],
323                                                  node[16],node[17],node[18],node[19] );
324       }
325       else if (nbnode == 27) {
326         if ( ID >= 1 ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
327                                                  node[4], node[5], node[6], node[7],
328                                                  node[8], node[9], node[10],node[11],
329                                                  node[12],node[13],node[14],node[15],
330                                                  node[16],node[17],node[18],node[19],
331                                                  node[20],node[21],node[22],node[23],
332                                                  node[24],node[25],node[26], ID);
333         else           e = mesh->AddVolume      (node[0], node[1], node[2], node[3],
334                                                  node[4], node[5], node[6], node[7],
335                                                  node[8], node[9], node[10],node[11],
336                                                  node[12],node[13],node[14],node[15],
337                                                  node[16],node[17],node[18],node[19],
338                                                  node[20],node[21],node[22],node[23],
339                                                  node[24],node[25],node[26] );
340       }
341     }
342     else if ( !features.myIsQuad )
343     {
344       if ( ID >= 1 ) e = mesh->AddPolyhedralVolumeWithID(node, features.myPolyhedQuantities, ID);
345       else           e = mesh->AddPolyhedralVolume      (node, features.myPolyhedQuantities    );
346     }
347     else
348     {
349       // if ( ID >= 1 ) e = mesh->AddQuadPolyhedralVolumeWithID(node, features.myPolyhedQuantities,ID);
350       // else           e = mesh->AddQuadPolyhedralVolume      (node, features.myPolyhedQuantities   );
351     }
352     break;
353
354   case SMDSAbs_Edge:
355     if ( nbnode == 2 ) {
356       if ( ID >= 1 ) e = mesh->AddEdgeWithID(node[0], node[1], ID);
357       else           e = mesh->AddEdge      (node[0], node[1] );
358     }
359     else if ( nbnode == 3 ) {
360       if ( ID >= 1 ) e = mesh->AddEdgeWithID(node[0], node[1], node[2], ID);
361       else           e = mesh->AddEdge      (node[0], node[1], node[2] );
362     }
363     break;
364
365   case SMDSAbs_0DElement:
366     if ( nbnode == 1 ) {
367       if ( ID >= 1 ) e = mesh->Add0DElementWithID(node[0], ID);
368       else           e = mesh->Add0DElement      (node[0] );
369     }
370     break;
371
372   case SMDSAbs_Node:
373     if ( ID >= 1 ) e = mesh->AddNodeWithID(node[0]->X(), node[0]->Y(), node[0]->Z(), ID);
374     else           e = mesh->AddNode      (node[0]->X(), node[0]->Y(), node[0]->Z()    );
375     break;
376
377   case SMDSAbs_Ball:
378     if ( ID >= 1 ) e = mesh->AddBallWithID(node[0], features.myBallDiameter, ID);
379     else           e = mesh->AddBall      (node[0], features.myBallDiameter    );
380     break;
381
382   default:;
383   }
384   if ( e ) myLastCreatedElems.push_back( e );
385   return e;
386 }
387
388 //=======================================================================
389 /*!
390  * \brief Add element
391  */
392 //=======================================================================
393
394 SMDS_MeshElement* SMESH_MeshEditor::AddElement(const vector<int> & nodeIDs,
395                                                const ElemFeatures& features)
396 {
397   vector<const SMDS_MeshNode*> nodes;
398   nodes.reserve( nodeIDs.size() );
399   vector<int>::const_iterator id = nodeIDs.begin();
400   while ( id != nodeIDs.end() ) {
401     if ( const SMDS_MeshNode* node = GetMeshDS()->FindNode( *id++ ))
402       nodes.push_back( node );
403     else
404       return 0;
405   }
406   return AddElement( nodes, features );
407 }
408
409 //=======================================================================
410 //function : Remove
411 //purpose  : Remove a node or an element.
412 //           Modify a compute state of sub-meshes which become empty
413 //=======================================================================
414
415 int SMESH_MeshEditor::Remove (const list< int >& theIDs,
416                               const bool         isNodes )
417 {
418   ClearLastCreated();
419
420   SMESHDS_Mesh* aMesh = GetMeshDS();
421   set< SMESH_subMesh *> smmap;
422
423   int removed = 0;
424   list<int>::const_iterator it = theIDs.begin();
425   for ( ; it != theIDs.end(); it++ ) {
426     const SMDS_MeshElement * elem;
427     if ( isNodes )
428       elem = aMesh->FindNode( *it );
429     else
430       elem = aMesh->FindElement( *it );
431     if ( !elem )
432       continue;
433
434     // Notify VERTEX sub-meshes about modification
435     if ( isNodes ) {
436       const SMDS_MeshNode* node = cast2Node( elem );
437       if ( node->GetPosition()->GetTypeOfPosition() == SMDS_TOP_VERTEX )
438         if ( int aShapeID = node->getshapeId() )
439           if ( SMESH_subMesh * sm = GetMesh()->GetSubMeshContaining( aShapeID ) )
440             smmap.insert( sm );
441     }
442     // Find sub-meshes to notify about modification
443     //     SMDS_ElemIteratorPtr nodeIt = elem->nodesIterator();
444     //     while ( nodeIt->more() ) {
445     //       const SMDS_MeshNode* node = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
446     //       const SMDS_PositionPtr& aPosition = node->GetPosition();
447     //       if ( aPosition.get() ) {
448     //         if ( int aShapeID = aPosition->GetShapeId() ) {
449     //           if ( SMESH_subMesh * sm = GetMesh()->GetSubMeshContaining( aShapeID ) )
450     //             smmap.insert( sm );
451     //         }
452     //       }
453     //     }
454
455     // Do remove
456     if ( isNodes )
457       aMesh->RemoveNode( static_cast< const SMDS_MeshNode* >( elem ));
458     else
459       aMesh->RemoveElement( elem );
460     removed++;
461   }
462
463   // Notify sub-meshes about modification
464   if ( !smmap.empty() ) {
465     set< SMESH_subMesh *>::iterator smIt;
466     for ( smIt = smmap.begin(); smIt != smmap.end(); smIt++ )
467       (*smIt)->ComputeStateEngine( SMESH_subMesh::MESH_ENTITY_REMOVED );
468   }
469
470   //   // Check if the whole mesh becomes empty
471   //   if ( SMESH_subMesh * sm = GetMesh()->GetSubMeshContaining( 1 ) )
472   //     sm->ComputeStateEngine( SMESH_subMesh::CHECK_COMPUTE_STATE );
473
474   return removed;
475 }
476
477 //================================================================================
478 /*!
479  * \brief Create 0D elements on all nodes of the given object.
480  *  \param elements - Elements on whose nodes to create 0D elements; if empty, 
481  *                    the all mesh is treated
482  *  \param all0DElems - returns all 0D elements found or created on nodes of \a elements
483  *  \param duplicateElements - to add one more 0D element to a node or not
484  */
485 //================================================================================
486
487 void SMESH_MeshEditor::Create0DElementsOnAllNodes( const TIDSortedElemSet& elements,
488                                                    TIDSortedElemSet&       all0DElems,
489                                                    const bool              duplicateElements )
490 {
491   SMDS_ElemIteratorPtr elemIt;
492   if ( elements.empty() )
493   {
494     elemIt = GetMeshDS()->elementsIterator( SMDSAbs_Node );
495   }
496   else
497   {
498     elemIt = SMESHUtils::elemSetIterator( elements );
499   }
500
501   while ( elemIt->more() )
502   {
503     const SMDS_MeshElement* e = elemIt->next();
504     SMDS_ElemIteratorPtr nodeIt = e->nodesIterator();
505     while ( nodeIt->more() )
506     {
507       const SMDS_MeshNode* n = cast2Node( nodeIt->next() );
508       SMDS_ElemIteratorPtr it0D = n->GetInverseElementIterator( SMDSAbs_0DElement );
509       if ( duplicateElements || !it0D->more() )
510       {
511         myLastCreatedElems.push_back( GetMeshDS()->Add0DElement( n ));
512         all0DElems.insert( myLastCreatedElems.back() );
513       }
514       while ( it0D->more() )
515         all0DElems.insert( it0D->next() );
516     }
517   }
518 }
519
520 //=======================================================================
521 //function : FindShape
522 //purpose  : Return an index of the shape theElem is on
523 //           or zero if a shape not found
524 //=======================================================================
525
526 int SMESH_MeshEditor::FindShape (const SMDS_MeshElement * theElem)
527 {
528   ClearLastCreated();
529
530   SMESHDS_Mesh * aMesh = GetMeshDS();
531   if ( aMesh->ShapeToMesh().IsNull() )
532     return 0;
533
534   int aShapeID = theElem->getshapeId();
535   if ( aShapeID < 1 )
536     return 0;
537
538   if ( SMESHDS_SubMesh * sm = aMesh->MeshElements( aShapeID ))
539     if ( sm->Contains( theElem ))
540       return aShapeID;
541
542   if ( theElem->GetType() == SMDSAbs_Node ) {
543     MESSAGE( ":( Error: invalid myShapeId of node " << theElem->GetID() );
544   }
545   else {
546     MESSAGE( ":( Error: invalid myShapeId of element " << theElem->GetID() );
547   }
548
549   TopoDS_Shape aShape; // the shape a node of theElem is on
550   if ( theElem->GetType() != SMDSAbs_Node )
551   {
552     SMDS_ElemIteratorPtr nodeIt = theElem->nodesIterator();
553     while ( nodeIt->more() ) {
554       const SMDS_MeshNode* node = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
555       if ((aShapeID = node->getshapeId()) > 0) {
556         if ( SMESHDS_SubMesh * sm = aMesh->MeshElements( aShapeID ) ) {
557           if ( sm->Contains( theElem ))
558             return aShapeID;
559           if ( aShape.IsNull() )
560             aShape = aMesh->IndexToShape( aShapeID );
561         }
562       }
563     }
564   }
565
566   // None of nodes is on a proper shape,
567   // find the shape among ancestors of aShape on which a node is
568   if ( !aShape.IsNull() ) {
569     TopTools_ListIteratorOfListOfShape ancIt( GetMesh()->GetAncestors( aShape ));
570     for ( ; ancIt.More(); ancIt.Next() ) {
571       SMESHDS_SubMesh * sm = aMesh->MeshElements( ancIt.Value() );
572       if ( sm && sm->Contains( theElem ))
573         return aMesh->ShapeToIndex( ancIt.Value() );
574     }
575   }
576   else
577   {
578     SMESHDS_SubMeshIteratorPtr smIt = GetMeshDS()->SubMeshes();
579     while ( const SMESHDS_SubMesh* sm = smIt->next() )
580       if ( sm->Contains( theElem ))
581         return sm->GetID();
582   }
583
584   return 0;
585 }
586
587 //=======================================================================
588 //function : IsMedium
589 //purpose  :
590 //=======================================================================
591
592 bool SMESH_MeshEditor::IsMedium(const SMDS_MeshNode*      node,
593                                 const SMDSAbs_ElementType typeToCheck)
594 {
595   bool isMedium = false;
596   SMDS_ElemIteratorPtr it = node->GetInverseElementIterator(typeToCheck);
597   while (it->more() && !isMedium ) {
598     const SMDS_MeshElement* elem = it->next();
599     isMedium = elem->IsMediumNode(node);
600   }
601   return isMedium;
602 }
603
604 //=======================================================================
605 //function : shiftNodesQuadTria
606 //purpose  : Shift nodes in the array corresponded to quadratic triangle
607 //           example: (0,1,2,3,4,5) -> (1,2,0,4,5,3)
608 //=======================================================================
609
610 static void shiftNodesQuadTria(vector< const SMDS_MeshNode* >& aNodes)
611 {
612   const SMDS_MeshNode* nd1 = aNodes[0];
613   aNodes[0] = aNodes[1];
614   aNodes[1] = aNodes[2];
615   aNodes[2] = nd1;
616   const SMDS_MeshNode* nd2 = aNodes[3];
617   aNodes[3] = aNodes[4];
618   aNodes[4] = aNodes[5];
619   aNodes[5] = nd2;
620 }
621
622 //=======================================================================
623 //function : getNodesFromTwoTria
624 //purpose  : 
625 //=======================================================================
626
627 static bool getNodesFromTwoTria(const SMDS_MeshElement * theTria1,
628                                 const SMDS_MeshElement * theTria2,
629                                 vector< const SMDS_MeshNode*>& N1,
630                                 vector< const SMDS_MeshNode*>& N2)
631 {
632   N1.assign( theTria1->begin_nodes(), theTria1->end_nodes() );
633   if ( N1.size() < 6 ) return false;
634   N2.assign( theTria2->begin_nodes(), theTria2->end_nodes() );
635   if ( N2.size() < 6 ) return false;
636
637   int sames[3] = {-1,-1,-1};
638   int nbsames = 0;
639   int i, j;
640   for(i=0; i<3; i++) {
641     for(j=0; j<3; j++) {
642       if(N1[i]==N2[j]) {
643         sames[i] = j;
644         nbsames++;
645         break;
646       }
647     }
648   }
649   if(nbsames!=2) return false;
650   if(sames[0]>-1) {
651     shiftNodesQuadTria(N1);
652     if(sames[1]>-1) {
653       shiftNodesQuadTria(N1);
654     }
655   }
656   i = sames[0] + sames[1] + sames[2];
657   for(; i<2; i++) {
658     shiftNodesQuadTria(N2);
659   }
660   // now we receive following N1 and N2 (using numeration as in the image below)
661   // tria1 : (1 2 4 5 9 7)  and  tria2 : (3 4 2 8 9 6)
662   // i.e. first nodes from both arrays form a new diagonal
663   return true;
664 }
665
666 //=======================================================================
667 //function : InverseDiag
668 //purpose  : Replace two neighbour triangles with ones built on the same 4 nodes
669 //           but having other common link.
670 //           Return False if args are improper
671 //=======================================================================
672
673 bool SMESH_MeshEditor::InverseDiag (const SMDS_MeshElement * theTria1,
674                                     const SMDS_MeshElement * theTria2 )
675 {
676   ClearLastCreated();
677
678   if ( !theTria1 || !theTria2 ||
679        !dynamic_cast<const SMDS_MeshCell*>( theTria1 ) ||
680        !dynamic_cast<const SMDS_MeshCell*>( theTria2 ) ||
681        theTria1->GetType() != SMDSAbs_Face ||
682        theTria2->GetType() != SMDSAbs_Face )
683     return false;
684
685   if ((theTria1->GetEntityType() == SMDSEntity_Triangle) &&
686       (theTria2->GetEntityType() == SMDSEntity_Triangle))
687   {
688     //  1 +--+ A  theTria1: ( 1 A B ) A->2 ( 1 2 B ) 1 +--+ A
689     //    | /|    theTria2: ( B A 2 ) B->1 ( 1 A 2 )   |\ |
690     //    |/ |                                         | \|
691     //  B +--+ 2                                     B +--+ 2
692
693     // put nodes in array and find out indices of the same ones
694     const SMDS_MeshNode* aNodes [6];
695     int sameInd [] = { -1, -1, -1, -1, -1, -1 };
696     int i = 0;
697     SMDS_ElemIteratorPtr it = theTria1->nodesIterator();
698     while ( it->more() ) {
699       aNodes[ i ] = static_cast<const SMDS_MeshNode*>( it->next() );
700
701       if ( i > 2 ) // theTria2
702         // find same node of theTria1
703         for ( int j = 0; j < 3; j++ )
704           if ( aNodes[ i ] == aNodes[ j ]) {
705             sameInd[ j ] = i;
706             sameInd[ i ] = j;
707             break;
708           }
709       // next
710       i++;
711       if ( i == 3 ) {
712         if ( it->more() )
713           return false; // theTria1 is not a triangle
714         it = theTria2->nodesIterator();
715       }
716       if ( i == 6 && it->more() )
717         return false; // theTria2 is not a triangle
718     }
719
720     // find indices of 1,2 and of A,B in theTria1
721     int iA = -1, iB = 0, i1 = 0, i2 = 0;
722     for ( i = 0; i < 6; i++ ) {
723       if ( sameInd [ i ] == -1 ) {
724         if ( i < 3 ) i1 = i;
725         else         i2 = i;
726       }
727       else if (i < 3) {
728         if ( iA >= 0) iB = i;
729         else          iA = i;
730       }
731     }
732     // nodes 1 and 2 should not be the same
733     if ( aNodes[ i1 ] == aNodes[ i2 ] )
734       return false;
735
736     // theTria1: A->2
737     aNodes[ iA ] = aNodes[ i2 ];
738     // theTria2: B->1
739     aNodes[ sameInd[ iB ]] = aNodes[ i1 ];
740
741     GetMeshDS()->ChangeElementNodes( theTria1, aNodes, 3 );
742     GetMeshDS()->ChangeElementNodes( theTria2, &aNodes[ 3 ], 3 );
743
744     return true;
745
746   } // end if(F1 && F2)
747
748   // check case of quadratic faces
749   if (theTria1->GetEntityType() != SMDSEntity_Quad_Triangle &&
750       theTria1->GetEntityType() != SMDSEntity_BiQuad_Triangle)
751     return false;
752   if (theTria2->GetEntityType() != SMDSEntity_Quad_Triangle&&
753       theTria2->GetEntityType() != SMDSEntity_BiQuad_Triangle)
754     return false;
755
756   //       5
757   //  1 +--+--+ 2  theTria1: (1 2 4 5 9 7) or (2 4 1 9 7 5) or (4 1 2 7 5 9)
758   //    |    /|    theTria2: (2 3 4 6 8 9) or (3 4 2 8 9 6) or (4 2 3 9 6 8)
759   //    |   / |
760   //  7 +  +  + 6
761   //    | /9  |
762   //    |/    |
763   //  4 +--+--+ 3
764   //       8
765
766   vector< const SMDS_MeshNode* > N1;
767   vector< const SMDS_MeshNode* > N2;
768   if(!getNodesFromTwoTria(theTria1,theTria2,N1,N2))
769     return false;
770   // now we receive following N1 and N2 (using numeration as above image)
771   // tria1 : (1 2 4 5 9 7)  and  tria2 : (3 4 2 8 9 6)
772   // i.e. first nodes from both arrays determ new diagonal
773
774   vector< const SMDS_MeshNode*> N1new( N1.size() );
775   vector< const SMDS_MeshNode*> N2new( N2.size() );
776   N1new.back() = N1.back(); // central node of biquadratic
777   N2new.back() = N2.back();
778   N1new[0] = N1[0];  N2new[0] = N1[0];
779   N1new[1] = N2[0];  N2new[1] = N1[1];
780   N1new[2] = N2[1];  N2new[2] = N2[0];
781   N1new[3] = N1[4];  N2new[3] = N1[3];
782   N1new[4] = N2[3];  N2new[4] = N2[5];
783   N1new[5] = N1[5];  N2new[5] = N1[4];
784   // change nodes in faces
785   GetMeshDS()->ChangeElementNodes( theTria1, &N1new[0], N1new.size() );
786   GetMeshDS()->ChangeElementNodes( theTria2, &N2new[0], N2new.size() );
787
788   // move the central node of biquadratic triangle
789   SMESH_MesherHelper helper( *GetMesh() );
790   for ( int is2nd = 0; is2nd < 2; ++is2nd )
791   {
792     const SMDS_MeshElement*         tria = is2nd ? theTria2 : theTria1;
793     vector< const SMDS_MeshNode*>& nodes = is2nd ? N2new : N1new;
794     if ( nodes.size() < 7 )
795       continue;
796     helper.SetSubShape( tria->getshapeId() );
797     const TopoDS_Face& F = TopoDS::Face( helper.GetSubShape() );
798     gp_Pnt xyz;
799     if ( F.IsNull() )
800     {
801       xyz = ( SMESH_NodeXYZ( nodes[3] ) +
802               SMESH_NodeXYZ( nodes[4] ) +
803               SMESH_NodeXYZ( nodes[5] )) / 3.;
804     }
805     else
806     {
807       bool checkUV;
808       gp_XY uv = ( helper.GetNodeUV( F, nodes[3], nodes[2], &checkUV ) +
809                    helper.GetNodeUV( F, nodes[4], nodes[0], &checkUV ) +
810                    helper.GetNodeUV( F, nodes[5], nodes[1], &checkUV )) / 3.;
811       TopLoc_Location loc;
812       Handle(Geom_Surface) S = BRep_Tool::Surface(F,loc);
813       xyz = S->Value( uv.X(), uv.Y() );
814       xyz.Transform( loc );
815       if ( nodes[6]->GetPosition()->GetTypeOfPosition() == SMDS_TOP_FACE &&  // set UV
816            nodes[6]->getshapeId() > 0 )
817         GetMeshDS()->SetNodeOnFace( nodes[6], nodes[6]->getshapeId(), uv.X(), uv.Y() );
818     }
819     GetMeshDS()->MoveNode( nodes[6], xyz.X(), xyz.Y(), xyz.Z() );
820   }
821   return true;
822 }
823
824 //=======================================================================
825 //function : findTriangles
826 //purpose  : find triangles sharing theNode1-theNode2 link
827 //=======================================================================
828
829 static bool findTriangles(const SMDS_MeshNode *    theNode1,
830                           const SMDS_MeshNode *    theNode2,
831                           const SMDS_MeshElement*& theTria1,
832                           const SMDS_MeshElement*& theTria2)
833 {
834   if ( !theNode1 || !theNode2 ) return false;
835
836   theTria1 = theTria2 = 0;
837
838   set< const SMDS_MeshElement* > emap;
839   SMDS_ElemIteratorPtr it = theNode1->GetInverseElementIterator(SMDSAbs_Face);
840   while (it->more()) {
841     const SMDS_MeshElement* elem = it->next();
842     if ( elem->NbCornerNodes() == 3 )
843       emap.insert( elem );
844   }
845   it = theNode2->GetInverseElementIterator(SMDSAbs_Face);
846   while (it->more()) {
847     const SMDS_MeshElement* elem = it->next();
848     if ( emap.count( elem )) {
849       if ( !theTria1 )
850       {
851         theTria1 = elem;
852       }
853       else  
854       {
855         theTria2 = elem;
856         // theTria1 must be element with minimum ID
857         if ( theTria2->GetID() < theTria1->GetID() )
858           std::swap( theTria2, theTria1 );
859         return true;
860       }
861     }
862   }
863   return false;
864 }
865
866 //=======================================================================
867 //function : InverseDiag
868 //purpose  : Replace two neighbour triangles sharing theNode1-theNode2 link
869 //           with ones built on the same 4 nodes but having other common link.
870 //           Return false if proper faces not found
871 //=======================================================================
872
873 bool SMESH_MeshEditor::InverseDiag (const SMDS_MeshNode * theNode1,
874                                     const SMDS_MeshNode * theNode2)
875 {
876   ClearLastCreated();
877
878   const SMDS_MeshElement *tr1, *tr2;
879   if ( !findTriangles( theNode1, theNode2, tr1, tr2 ))
880     return false;
881
882   if ( !dynamic_cast<const SMDS_MeshCell*>( tr1 ) ||
883        !dynamic_cast<const SMDS_MeshCell*>( tr2 ))
884     return false;
885
886   if ((tr1->GetEntityType() == SMDSEntity_Triangle) &&
887       (tr2->GetEntityType() == SMDSEntity_Triangle)) {
888
889     //  1 +--+ A  tr1: ( 1 A B ) A->2 ( 1 2 B ) 1 +--+ A
890     //    | /|    tr2: ( B A 2 ) B->1 ( 1 A 2 )   |\ |
891     //    |/ |                                    | \|
892     //  B +--+ 2                                B +--+ 2
893
894     // put nodes in array
895     // and find indices of 1,2 and of A in tr1 and of B in tr2
896     int i, iA1 = 0, i1 = 0;
897     const SMDS_MeshNode* aNodes1 [3];
898     SMDS_ElemIteratorPtr it;
899     for (i = 0, it = tr1->nodesIterator(); it->more(); i++ ) {
900       aNodes1[ i ] = static_cast<const SMDS_MeshNode*>( it->next() );
901       if ( aNodes1[ i ] == theNode1 )
902         iA1 = i; // node A in tr1
903       else if ( aNodes1[ i ] != theNode2 )
904         i1 = i;  // node 1
905     }
906     int iB2 = 0, i2 = 0;
907     const SMDS_MeshNode* aNodes2 [3];
908     for (i = 0, it = tr2->nodesIterator(); it->more(); i++ ) {
909       aNodes2[ i ] = static_cast<const SMDS_MeshNode*>( it->next() );
910       if ( aNodes2[ i ] == theNode2 )
911         iB2 = i; // node B in tr2
912       else if ( aNodes2[ i ] != theNode1 )
913         i2 = i;  // node 2
914     }
915
916     // nodes 1 and 2 should not be the same
917     if ( aNodes1[ i1 ] == aNodes2[ i2 ] )
918       return false;
919
920     // tr1: A->2
921     aNodes1[ iA1 ] = aNodes2[ i2 ];
922     // tr2: B->1
923     aNodes2[ iB2 ] = aNodes1[ i1 ];
924
925     GetMeshDS()->ChangeElementNodes( tr1, aNodes1, 3 );
926     GetMeshDS()->ChangeElementNodes( tr2, aNodes2, 3 );
927
928     return true;
929   }
930
931   // check case of quadratic faces
932   return InverseDiag(tr1,tr2);
933 }
934
935 //=======================================================================
936 //function : getQuadrangleNodes
937 //purpose  : fill theQuadNodes - nodes of a quadrangle resulting from
938 //           fusion of triangles tr1 and tr2 having shared link on
939 //           theNode1 and theNode2
940 //=======================================================================
941
942 bool getQuadrangleNodes(const SMDS_MeshNode *    theQuadNodes [],
943                         const SMDS_MeshNode *    theNode1,
944                         const SMDS_MeshNode *    theNode2,
945                         const SMDS_MeshElement * tr1,
946                         const SMDS_MeshElement * tr2 )
947 {
948   if( tr1->NbNodes() != tr2->NbNodes() )
949     return false;
950   // find the 4-th node to insert into tr1
951   const SMDS_MeshNode* n4 = 0;
952   SMDS_ElemIteratorPtr it = tr2->nodesIterator();
953   int i=0;
954   while ( !n4 && i<3 ) {
955     const SMDS_MeshNode * n = cast2Node( it->next() );
956     i++;
957     bool isDiag = ( n == theNode1 || n == theNode2 );
958     if ( !isDiag )
959       n4 = n;
960   }
961   // Make an array of nodes to be in a quadrangle
962   int iNode = 0, iFirstDiag = -1;
963   it = tr1->nodesIterator();
964   i=0;
965   while ( i<3 ) {
966     const SMDS_MeshNode * n = cast2Node( it->next() );
967     i++;
968     bool isDiag = ( n == theNode1 || n == theNode2 );
969     if ( isDiag ) {
970       if ( iFirstDiag < 0 )
971         iFirstDiag = iNode;
972       else if ( iNode - iFirstDiag == 1 )
973         theQuadNodes[ iNode++ ] = n4; // insert the 4-th node between diagonal nodes
974     }
975     else if ( n == n4 ) {
976       return false; // tr1 and tr2 should not have all the same nodes
977     }
978     theQuadNodes[ iNode++ ] = n;
979   }
980   if ( iNode == 3 ) // diagonal nodes have 0 and 2 indices
981     theQuadNodes[ iNode ] = n4;
982
983   return true;
984 }
985
986 //=======================================================================
987 //function : DeleteDiag
988 //purpose  : Replace two neighbour triangles sharing theNode1-theNode2 link
989 //           with a quadrangle built on the same 4 nodes.
990 //           Return false if proper faces not found
991 //=======================================================================
992
993 bool SMESH_MeshEditor::DeleteDiag (const SMDS_MeshNode * theNode1,
994                                    const SMDS_MeshNode * theNode2)
995 {
996   ClearLastCreated();
997
998   const SMDS_MeshElement *tr1, *tr2;
999   if ( !findTriangles( theNode1, theNode2, tr1, tr2 ))
1000     return false;
1001
1002   if ( !dynamic_cast<const SMDS_MeshCell*>( tr1 ) ||
1003        !dynamic_cast<const SMDS_MeshCell*>( tr2 ))
1004     return false;
1005
1006   SMESHDS_Mesh * aMesh = GetMeshDS();
1007
1008   if ((tr1->GetEntityType() == SMDSEntity_Triangle) &&
1009       (tr2->GetEntityType() == SMDSEntity_Triangle))
1010   {
1011     const SMDS_MeshNode* aNodes [ 4 ];
1012     if ( ! getQuadrangleNodes( aNodes, theNode1, theNode2, tr1, tr2 ))
1013       return false;
1014
1015     const SMDS_MeshElement* newElem = 0;
1016     newElem = aMesh->AddFace( aNodes[0], aNodes[1], aNodes[2], aNodes[3] );
1017     myLastCreatedElems.push_back(newElem);
1018     AddToSameGroups( newElem, tr1, aMesh );
1019     int aShapeId = tr1->getshapeId();
1020     if ( aShapeId )
1021       aMesh->SetMeshElementOnShape( newElem, aShapeId );
1022
1023     aMesh->RemoveElement( tr1 );
1024     aMesh->RemoveElement( tr2 );
1025
1026     return true;
1027   }
1028
1029   // check case of quadratic faces
1030   if (tr1->GetEntityType() != SMDSEntity_Quad_Triangle)
1031     return false;
1032   if (tr2->GetEntityType() != SMDSEntity_Quad_Triangle)
1033     return false;
1034
1035   //       5
1036   //  1 +--+--+ 2  tr1: (1 2 4 5 9 7) or (2 4 1 9 7 5) or (4 1 2 7 5 9)
1037   //    |    /|    tr2: (2 3 4 6 8 9) or (3 4 2 8 9 6) or (4 2 3 9 6 8)
1038   //    |   / |
1039   //  7 +  +  + 6
1040   //    | /9  |
1041   //    |/    |
1042   //  4 +--+--+ 3
1043   //       8
1044
1045   vector< const SMDS_MeshNode* > N1;
1046   vector< const SMDS_MeshNode* > N2;
1047   if(!getNodesFromTwoTria(tr1,tr2,N1,N2))
1048     return false;
1049   // now we receive following N1 and N2 (using numeration as above image)
1050   // tria1 : (1 2 4 5 9 7)  and  tria2 : (3 4 2 8 9 6)
1051   // i.e. first nodes from both arrays determ new diagonal
1052
1053   const SMDS_MeshNode* aNodes[8];
1054   aNodes[0] = N1[0];
1055   aNodes[1] = N1[1];
1056   aNodes[2] = N2[0];
1057   aNodes[3] = N2[1];
1058   aNodes[4] = N1[3];
1059   aNodes[5] = N2[5];
1060   aNodes[6] = N2[3];
1061   aNodes[7] = N1[5];
1062
1063   const SMDS_MeshElement* newElem = 0;
1064   newElem = aMesh->AddFace( aNodes[0], aNodes[1], aNodes[2], aNodes[3],
1065                             aNodes[4], aNodes[5], aNodes[6], aNodes[7]);
1066   myLastCreatedElems.push_back(newElem);
1067   AddToSameGroups( newElem, tr1, aMesh );
1068   int aShapeId = tr1->getshapeId();
1069   if ( aShapeId )
1070   {
1071     aMesh->SetMeshElementOnShape( newElem, aShapeId );
1072   }
1073   aMesh->RemoveElement( tr1 );
1074   aMesh->RemoveElement( tr2 );
1075
1076   // remove middle node (9)
1077   GetMeshDS()->RemoveNode( N1[4] );
1078
1079   return true;
1080 }
1081
1082 //=======================================================================
1083 //function : Reorient
1084 //purpose  : Reverse theElement orientation
1085 //=======================================================================
1086
1087 bool SMESH_MeshEditor::Reorient (const SMDS_MeshElement * theElem)
1088 {
1089   ClearLastCreated();
1090
1091   if (!theElem)
1092     return false;
1093   SMDS_ElemIteratorPtr it = theElem->nodesIterator();
1094   if ( !it || !it->more() )
1095     return false;
1096
1097   const SMDSAbs_ElementType type = theElem->GetType();
1098   if ( type < SMDSAbs_Edge || type > SMDSAbs_Volume )
1099     return false;
1100
1101   const SMDSAbs_EntityType geomType = theElem->GetEntityType();
1102   if ( geomType == SMDSEntity_Polyhedra ) // polyhedron
1103   {
1104     const SMDS_MeshVolume* aPolyedre = SMDS_Mesh::DownCast< SMDS_MeshVolume >( theElem );
1105     if (!aPolyedre) {
1106       MESSAGE("Warning: bad volumic element");
1107       return false;
1108     }
1109     SMDS_VolumeTool vTool( aPolyedre );
1110     const int nbFaces = vTool.NbFaces();
1111     vector<int> quantities( nbFaces );
1112     vector<const SMDS_MeshNode *> poly_nodes;
1113
1114     // check if all facets are oriented equally
1115     bool sameOri = true;
1116     vector<int>& facetOri = quantities; // keep orientation in quantities so far
1117     for (int iface = 0; iface < nbFaces; iface++)
1118     {
1119       facetOri[ iface ] = vTool.IsFaceExternal( iface );
1120       if ( facetOri[ iface ] != facetOri[ 0 ])
1121         sameOri = false;
1122     }
1123
1124     // reverse faces of the polyhedron
1125     int neededOri = sameOri ? 1 - facetOri[0] : 1;
1126     poly_nodes.reserve( vTool.NbNodes() );
1127     for ( int iface = 0; iface < nbFaces; iface++ )
1128     {
1129       int             nbFaceNodes = vTool.NbFaceNodes( iface );
1130       const SMDS_MeshNode** nodes = vTool.GetFaceNodes( iface );
1131       bool toReverse = ( facetOri[ iface ] != neededOri );
1132
1133       quantities[ iface ] = nbFaceNodes;
1134
1135       if ( toReverse )
1136         for ( int inode = nbFaceNodes - 1; inode >= 0; inode-- )
1137           poly_nodes.push_back( nodes[ inode ]);
1138       else
1139         poly_nodes.insert( poly_nodes.end(), nodes, nodes + nbFaceNodes );
1140     }
1141     return GetMeshDS()->ChangePolyhedronNodes( theElem, poly_nodes, quantities );
1142   }
1143   else // other elements
1144   {
1145     vector<const SMDS_MeshNode*> nodes( theElem->begin_nodes(), theElem->end_nodes() );
1146     const std::vector<int>& interlace = SMDS_MeshCell::reverseSmdsOrder( geomType, nodes.size() );
1147     if ( interlace.empty() )
1148     {
1149       std::reverse( nodes.begin(), nodes.end() ); // obsolete, just in case
1150     }
1151     else
1152     {
1153       SMDS_MeshCell::applyInterlace( interlace, nodes );
1154     }
1155     return GetMeshDS()->ChangeElementNodes( theElem, &nodes[0], nodes.size() );
1156   }
1157   return false;
1158 }
1159
1160 //================================================================================
1161 /*!
1162  * \brief Reorient faces.
1163  * \param theFaces - the faces to reorient. If empty the whole mesh is meant
1164  * \param theDirection - desired direction of normal of \a theFace
1165  * \param theFace - one of \a theFaces that should be oriented according to
1166  *        \a theDirection and whose orientation defines orientation of other faces
1167  * \return number of reoriented faces.
1168  */
1169 //================================================================================
1170
1171 int SMESH_MeshEditor::Reorient2D (TIDSortedElemSet &       theFaces,
1172                                   const gp_Dir&            theDirection,
1173                                   const SMDS_MeshElement * theFace)
1174 {
1175   int nbReori = 0;
1176   if ( !theFace || theFace->GetType() != SMDSAbs_Face ) return nbReori;
1177
1178   if ( theFaces.empty() )
1179   {
1180     SMDS_FaceIteratorPtr fIt = GetMeshDS()->facesIterator(/*idInceasingOrder=true*/);
1181     while ( fIt->more() )
1182       theFaces.insert( theFaces.end(), fIt->next() );
1183   }
1184
1185   // orient theFace according to theDirection
1186   gp_XYZ normal;
1187   SMESH_MeshAlgos::FaceNormal( theFace, normal, /*normalized=*/false );
1188   if ( normal * theDirection.XYZ() < 0 )
1189     nbReori += Reorient( theFace );
1190
1191   // Orient other faces
1192
1193   set< const SMDS_MeshElement* > startFaces, visitedFaces;
1194   TIDSortedElemSet avoidSet;
1195   set< SMESH_TLink > checkedLinks;
1196   pair< set< SMESH_TLink >::iterator, bool > linkIt_isNew;
1197
1198   if ( theFaces.size() > 1 )// leave 1 face to prevent finding not selected faces
1199     theFaces.erase( theFace );
1200   startFaces.insert( theFace );
1201
1202   int nodeInd1, nodeInd2;
1203   const SMDS_MeshElement*           otherFace;
1204   vector< const SMDS_MeshElement* > facesNearLink;
1205   vector< std::pair< int, int > >   nodeIndsOfFace;
1206
1207   set< const SMDS_MeshElement* >::iterator startFace = startFaces.begin();
1208   while ( !startFaces.empty() )
1209   {
1210     startFace = startFaces.begin();
1211     theFace = *startFace;
1212     startFaces.erase( startFace );
1213     if ( !visitedFaces.insert( theFace ).second )
1214       continue;
1215
1216     avoidSet.clear();
1217     avoidSet.insert(theFace);
1218
1219     NLink link( theFace->GetNode( 0 ), (SMDS_MeshNode *) 0 );
1220
1221     const int nbNodes = theFace->NbCornerNodes();
1222     for ( int i = 0; i < nbNodes; ++i ) // loop on links of theFace
1223     {
1224       link.second = theFace->GetNode(( i+1 ) % nbNodes );
1225       linkIt_isNew = checkedLinks.insert( link );
1226       if ( !linkIt_isNew.second )
1227       {
1228         // link has already been checked and won't be encountered more
1229         // if the group (theFaces) is manifold
1230         //checkedLinks.erase( linkIt_isNew.first );
1231       }
1232       else
1233       {
1234         facesNearLink.clear();
1235         nodeIndsOfFace.clear();
1236         while (( otherFace = SMESH_MeshAlgos::FindFaceInSet( link.first, link.second,
1237                                                              theFaces, avoidSet,
1238                                                              &nodeInd1, &nodeInd2 )))
1239           if ( otherFace != theFace)
1240           {
1241             facesNearLink.push_back( otherFace );
1242             nodeIndsOfFace.push_back( make_pair( nodeInd1, nodeInd2 ));
1243             avoidSet.insert( otherFace );
1244           }
1245         if ( facesNearLink.size() > 1 )
1246         {
1247           // NON-MANIFOLD mesh shell !
1248           // select a face most co-directed with theFace,
1249           // other faces won't be visited this time
1250           gp_XYZ NF, NOF;
1251           SMESH_MeshAlgos::FaceNormal( theFace, NF, /*normalized=*/false );
1252           double proj, maxProj = -1;
1253           for ( size_t i = 0; i < facesNearLink.size(); ++i ) {
1254             SMESH_MeshAlgos::FaceNormal( facesNearLink[i], NOF, /*normalized=*/false );
1255             if (( proj = Abs( NF * NOF )) > maxProj ) {
1256               maxProj = proj;
1257               otherFace = facesNearLink[i];
1258               nodeInd1  = nodeIndsOfFace[i].first;
1259               nodeInd2  = nodeIndsOfFace[i].second;
1260             }
1261           }
1262           // not to visit rejected faces
1263           for ( size_t i = 0; i < facesNearLink.size(); ++i )
1264             if ( facesNearLink[i] != otherFace && theFaces.size() > 1 )
1265               visitedFaces.insert( facesNearLink[i] );
1266         }
1267         else if ( facesNearLink.size() == 1 )
1268         {
1269           otherFace = facesNearLink[0];
1270           nodeInd1  = nodeIndsOfFace.back().first;
1271           nodeInd2  = nodeIndsOfFace.back().second;
1272         }
1273         if ( otherFace && otherFace != theFace)
1274         {
1275           // link must be reverse in otherFace if orientation to otherFace
1276           // is same as that of theFace
1277           if ( abs(nodeInd2-nodeInd1) == 1 ? nodeInd2 > nodeInd1 : nodeInd1 > nodeInd2 )
1278           {
1279             nbReori += Reorient( otherFace );
1280           }
1281           startFaces.insert( otherFace );
1282         }
1283       }
1284       std::swap( link.first, link.second ); // reverse the link
1285     }
1286   }
1287   return nbReori;
1288 }
1289
1290 //================================================================================
1291 /*!
1292  * \brief Reorient faces basing on orientation of adjacent volumes.
1293  * \param theFaces - faces to reorient. If empty, all mesh faces are treated.
1294  * \param theVolumes - reference volumes.
1295  * \param theOutsideNormal - to orient faces to have their normal
1296  *        pointing either \a outside or \a inside the adjacent volumes.
1297  * \return number of reoriented faces.
1298  */
1299 //================================================================================
1300
1301 int SMESH_MeshEditor::Reorient2DBy3D (TIDSortedElemSet & theFaces,
1302                                       TIDSortedElemSet & theVolumes,
1303                                       const bool         theOutsideNormal)
1304 {
1305   int nbReori = 0;
1306
1307   SMDS_ElemIteratorPtr faceIt;
1308   if ( theFaces.empty() )
1309     faceIt = GetMeshDS()->elementsIterator( SMDSAbs_Face );
1310   else
1311     faceIt = SMESHUtils::elemSetIterator( theFaces );
1312
1313   vector< const SMDS_MeshNode* > faceNodes;
1314   TIDSortedElemSet checkedVolumes;
1315   set< const SMDS_MeshNode* > faceNodesSet;
1316   SMDS_VolumeTool volumeTool;
1317
1318   while ( faceIt->more() ) // loop on given faces
1319   {
1320     const SMDS_MeshElement* face = faceIt->next();
1321     if ( face->GetType() != SMDSAbs_Face )
1322       continue;
1323
1324     const size_t nbCornersNodes = face->NbCornerNodes();
1325     faceNodes.assign( face->begin_nodes(), face->end_nodes() );
1326
1327     checkedVolumes.clear();
1328     SMDS_ElemIteratorPtr vIt = faceNodes[ 0 ]->GetInverseElementIterator( SMDSAbs_Volume );
1329     while ( vIt->more() )
1330     {
1331       const SMDS_MeshElement* volume = vIt->next();
1332
1333       if ( !checkedVolumes.insert( volume ).second )
1334         continue;
1335       if ( !theVolumes.empty() && !theVolumes.count( volume ))
1336         continue;
1337
1338       // is volume adjacent?
1339       bool allNodesCommon = true;
1340       for ( size_t iN = 1; iN < nbCornersNodes && allNodesCommon; ++iN )
1341         allNodesCommon = ( volume->GetNodeIndex( faceNodes[ iN ]) > -1 );
1342       if ( !allNodesCommon )
1343         continue;
1344
1345       // get nodes of a corresponding volume facet
1346       faceNodesSet.clear();
1347       faceNodesSet.insert( faceNodes.begin(), faceNodes.end() );
1348       volumeTool.Set( volume );
1349       int facetID = volumeTool.GetFaceIndex( faceNodesSet );
1350       if ( facetID < 0 ) continue;
1351       volumeTool.SetExternalNormal();
1352       const SMDS_MeshNode** facetNodes = volumeTool.GetFaceNodes( facetID );
1353
1354       // compare order of faceNodes and facetNodes
1355       const int iQ = 1 + ( nbCornersNodes < faceNodes.size() );
1356       int iNN[2];
1357       for ( int i = 0; i < 2; ++i )
1358       {
1359         const SMDS_MeshNode* n = facetNodes[ i*iQ ];
1360         for ( size_t iN = 0; iN < nbCornersNodes; ++iN )
1361           if ( faceNodes[ iN ] == n )
1362           {
1363             iNN[ i ] = iN;
1364             break;
1365           }
1366       }
1367       bool isOutside = Abs( iNN[0]-iNN[1] ) == 1 ? iNN[0] < iNN[1] : iNN[0] > iNN[1];
1368       if ( isOutside != theOutsideNormal )
1369         nbReori += Reorient( face );
1370     }
1371   }  // loop on given faces
1372
1373   return nbReori;
1374 }
1375
1376 //=======================================================================
1377 //function : getBadRate
1378 //purpose  :
1379 //=======================================================================
1380
1381 static double getBadRate (const SMDS_MeshElement*               theElem,
1382                           SMESH::Controls::NumericalFunctorPtr& theCrit)
1383 {
1384   SMESH::Controls::TSequenceOfXYZ P;
1385   if ( !theElem || !theCrit->GetPoints( theElem, P ))
1386     return 1e100;
1387   return theCrit->GetBadRate( theCrit->GetValue( P ), theElem->NbNodes() );
1388   //return theCrit->GetBadRate( theCrit->GetValue( theElem->GetID() ), theElem->NbNodes() );
1389 }
1390
1391 //=======================================================================
1392 //function : QuadToTri
1393 //purpose  : Cut quadrangles into triangles.
1394 //           theCrit is used to select a diagonal to cut
1395 //=======================================================================
1396
1397 bool SMESH_MeshEditor::QuadToTri (TIDSortedElemSet &                   theElems,
1398                                   SMESH::Controls::NumericalFunctorPtr theCrit)
1399 {
1400   ClearLastCreated();
1401
1402   if ( !theCrit.get() )
1403     return false;
1404
1405   SMESHDS_Mesh *       aMesh = GetMeshDS();
1406   Handle(Geom_Surface) surface;
1407   SMESH_MesherHelper   helper( *GetMesh() );
1408
1409   myLastCreatedElems.reserve( theElems.size() * 2 );
1410
1411   TIDSortedElemSet::iterator itElem;
1412   for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ )
1413   {
1414     const SMDS_MeshElement* elem = *itElem;
1415     if ( !elem || elem->GetType() != SMDSAbs_Face )
1416       continue;
1417     if ( elem->NbCornerNodes() != 4 )
1418       continue;
1419
1420     // retrieve element nodes
1421     vector< const SMDS_MeshNode* > aNodes( elem->begin_nodes(), elem->end_nodes() );
1422
1423     // compare two sets of possible triangles
1424     double aBadRate1, aBadRate2; // to what extent a set is bad
1425     SMDS_FaceOfNodes tr1 ( aNodes[0], aNodes[1], aNodes[2] );
1426     SMDS_FaceOfNodes tr2 ( aNodes[2], aNodes[3], aNodes[0] );
1427     aBadRate1 = getBadRate( &tr1, theCrit ) + getBadRate( &tr2, theCrit );
1428
1429     SMDS_FaceOfNodes tr3 ( aNodes[1], aNodes[2], aNodes[3] );
1430     SMDS_FaceOfNodes tr4 ( aNodes[3], aNodes[0], aNodes[1] );
1431     aBadRate2 = getBadRate( &tr3, theCrit ) + getBadRate( &tr4, theCrit );
1432
1433     const int aShapeId = FindShape( elem );
1434     const SMDS_MeshElement* newElem1 = 0;
1435     const SMDS_MeshElement* newElem2 = 0;
1436
1437     if ( !elem->IsQuadratic() ) // split linear quadrangle
1438     {
1439       // for MaxElementLength2D functor we return minimum diagonal for splitting,
1440       // because aBadRate1=2*len(diagonal 1-3); aBadRate2=2*len(diagonal 2-4)
1441       if ( aBadRate1 <= aBadRate2 ) {
1442         // tr1 + tr2 is better
1443         newElem1 = aMesh->AddFace( aNodes[2], aNodes[3], aNodes[0] );
1444         newElem2 = aMesh->AddFace( aNodes[2], aNodes[0], aNodes[1] );
1445       }
1446       else {
1447         // tr3 + tr4 is better
1448         newElem1 = aMesh->AddFace( aNodes[3], aNodes[0], aNodes[1] );
1449         newElem2 = aMesh->AddFace( aNodes[3], aNodes[1], aNodes[2] );
1450       }
1451     }
1452     else // split quadratic quadrangle
1453     {
1454       helper.SetIsQuadratic( true );
1455       helper.SetIsBiQuadratic( aNodes.size() == 9 );
1456
1457       helper.AddTLinks( static_cast< const SMDS_MeshFace* >( elem ));
1458       if ( aNodes.size() == 9 )
1459       {
1460         helper.SetIsBiQuadratic( true );
1461         if ( aBadRate1 <= aBadRate2 )
1462           helper.AddTLinkNode( aNodes[0], aNodes[2], aNodes[8] );
1463         else
1464           helper.AddTLinkNode( aNodes[1], aNodes[3], aNodes[8] );
1465       }
1466       // create a new element
1467       if ( aBadRate1 <= aBadRate2 ) {
1468         newElem1 = helper.AddFace( aNodes[2], aNodes[3], aNodes[0] );
1469         newElem2 = helper.AddFace( aNodes[2], aNodes[0], aNodes[1] );
1470       }
1471       else {
1472         newElem1 = helper.AddFace( aNodes[3], aNodes[0], aNodes[1] );
1473         newElem2 = helper.AddFace( aNodes[3], aNodes[1], aNodes[2] );
1474       }
1475     } // quadratic case
1476
1477     // care of a new element
1478
1479     myLastCreatedElems.push_back(newElem1);
1480     myLastCreatedElems.push_back(newElem2);
1481     AddToSameGroups( newElem1, elem, aMesh );
1482     AddToSameGroups( newElem2, elem, aMesh );
1483
1484     // put a new triangle on the same shape
1485     if ( aShapeId )
1486       aMesh->SetMeshElementOnShape( newElem1, aShapeId );
1487     aMesh->SetMeshElementOnShape( newElem2, aShapeId );
1488
1489     aMesh->RemoveElement( elem );
1490   }
1491   return true;
1492 }
1493
1494 //=======================================================================
1495 /*!
1496  * \brief Split each of given quadrangles into 4 triangles.
1497  * \param theElems - The faces to be split. If empty all faces are split.
1498  */
1499 //=======================================================================
1500
1501 void SMESH_MeshEditor::QuadTo4Tri (TIDSortedElemSet & theElems)
1502 {
1503   ClearLastCreated();
1504   myLastCreatedElems.reserve( theElems.size() * 4 );
1505
1506   SMESH_MesherHelper helper( *GetMesh() );
1507   helper.SetElementsOnShape( true );
1508
1509   // get standalone groups of faces
1510   vector< SMDS_MeshGroup* > allFaceGroups, faceGroups;
1511   for ( SMESHDS_GroupBase* grBase : GetMeshDS()->GetGroups() )
1512     if ( SMESHDS_Group* group = dynamic_cast<SMESHDS_Group*>( grBase ))
1513       if ( group->GetType() == SMDSAbs_Face && !group->IsEmpty() )
1514         allFaceGroups.push_back( & group->SMDSGroup() );
1515
1516   bool   checkUV;
1517   gp_XY  uv [9]; uv[8] = gp_XY(0,0);
1518   gp_XYZ xyz[9];
1519   vector< const SMDS_MeshNode* > nodes;
1520   SMESHDS_SubMesh*               subMeshDS = 0;
1521   TopoDS_Face                    F;
1522   Handle(Geom_Surface)           surface;
1523   TopLoc_Location                loc;
1524
1525   SMDS_ElemIteratorPtr faceIt;
1526   if ( theElems.empty() ) faceIt = GetMeshDS()->elementsIterator(SMDSAbs_Face);
1527   else                    faceIt = SMESHUtils::elemSetIterator( theElems );
1528
1529   while ( faceIt->more() )
1530   {
1531     const SMDS_MeshElement* quad = faceIt->next();
1532     if ( !quad || quad->NbCornerNodes() != 4 )
1533       continue;
1534
1535     // get a surface the quad is on
1536
1537     if ( quad->getshapeId() < 1 )
1538     {
1539       F.Nullify();
1540       helper.SetSubShape( 0 );
1541       subMeshDS = 0;
1542     }
1543     else if ( quad->getshapeId() != helper.GetSubShapeID() )
1544     {
1545       helper.SetSubShape( quad->getshapeId() );
1546       if ( !helper.GetSubShape().IsNull() &&
1547            helper.GetSubShape().ShapeType() == TopAbs_FACE )
1548       {
1549         F = TopoDS::Face( helper.GetSubShape() );
1550         surface = BRep_Tool::Surface( F, loc );
1551         subMeshDS = GetMeshDS()->MeshElements( quad->getshapeId() );
1552       }
1553       else
1554       {
1555         helper.SetSubShape( 0 );
1556         subMeshDS = 0;
1557       }
1558     }
1559
1560     // create a central node
1561
1562     const SMDS_MeshNode* nCentral;
1563     nodes.assign( quad->begin_nodes(), quad->end_nodes() );
1564
1565     if ( nodes.size() == 9 )
1566     {
1567       nCentral = nodes.back();
1568     }
1569     else
1570     {
1571       size_t iN = 0;
1572       if ( F.IsNull() )
1573       {
1574         for ( ; iN < nodes.size(); ++iN )
1575           xyz[ iN ] = SMESH_NodeXYZ( nodes[ iN ] );
1576
1577         for ( ; iN < 8; ++iN ) // mid-side points of a linear qudrangle
1578           xyz[ iN ] = 0.5 * ( xyz[ iN - 4 ] + xyz[( iN - 3 )%4 ] );
1579
1580         xyz[ 8 ] = helper.calcTFI( 0.5, 0.5,
1581                                    xyz[0], xyz[1], xyz[2], xyz[3],
1582                                    xyz[4], xyz[5], xyz[6], xyz[7] );
1583       }
1584       else
1585       {
1586         for ( ; iN < nodes.size(); ++iN )
1587           uv[ iN ] = helper.GetNodeUV( F, nodes[iN], nodes[(iN+2)%4], &checkUV );
1588
1589         for ( ; iN < 8; ++iN ) // UV of mid-side points of a linear qudrangle
1590           uv[ iN ] = helper.GetMiddleUV( surface, uv[ iN - 4 ], uv[( iN - 3 )%4 ] );
1591
1592         uv[ 8 ] = helper.calcTFI( 0.5, 0.5,
1593                                   uv[0], uv[1], uv[2], uv[3],
1594                                   uv[4], uv[5], uv[6], uv[7] );
1595
1596         gp_Pnt p = surface->Value( uv[8].X(), uv[8].Y() ).Transformed( loc );
1597         xyz[ 8 ] = p.XYZ();
1598       }
1599
1600       nCentral = helper.AddNode( xyz[8].X(), xyz[8].Y(), xyz[8].Z(), /*id=*/0,
1601                                  uv[8].X(), uv[8].Y() );
1602       myLastCreatedNodes.push_back( nCentral );
1603     }
1604
1605     helper.SetIsQuadratic  ( nodes.size() > 4 );
1606     helper.SetIsBiQuadratic( nodes.size() == 9 );
1607     if ( helper.GetIsQuadratic() )
1608       helper.AddTLinks( static_cast< const SMDS_MeshFace*>( quad ));
1609
1610     // select groups to update
1611     faceGroups.clear();
1612     for ( SMDS_MeshGroup* group : allFaceGroups )
1613       if ( group->Remove( quad ))
1614         faceGroups.push_back( group );
1615
1616     // create 4 triangles
1617
1618     GetMeshDS()->RemoveFreeElement( quad, subMeshDS, /*fromGroups=*/false );
1619
1620     for ( int i = 0; i < 4; ++i )
1621     {
1622       SMDS_MeshElement* tria = helper.AddFace( nodes[ i ],
1623                                                nodes[(i+1)%4],
1624                                                nCentral );
1625       myLastCreatedElems.push_back( tria );
1626       for ( SMDS_MeshGroup* group : faceGroups )
1627         group->Add( tria );
1628     }
1629   }
1630 }
1631
1632 //=======================================================================
1633 //function : BestSplit
1634 //purpose  : Find better diagonal for cutting.
1635 //=======================================================================
1636
1637 int SMESH_MeshEditor::BestSplit (const SMDS_MeshElement*              theQuad,
1638                                  SMESH::Controls::NumericalFunctorPtr theCrit)
1639 {
1640   ClearLastCreated();
1641
1642   if (!theCrit.get())
1643     return -1;
1644
1645   if (!theQuad || theQuad->GetType() != SMDSAbs_Face )
1646     return -1;
1647
1648   if( theQuad->NbNodes()==4 ||
1649       (theQuad->NbNodes()==8 && theQuad->IsQuadratic()) ) {
1650
1651     // retrieve element nodes
1652     const SMDS_MeshNode* aNodes [4];
1653     SMDS_ElemIteratorPtr itN = theQuad->nodesIterator();
1654     int i = 0;
1655     //while (itN->more())
1656     while (i<4) {
1657       aNodes[ i++ ] = static_cast<const SMDS_MeshNode*>( itN->next() );
1658     }
1659     // compare two sets of possible triangles
1660     double aBadRate1, aBadRate2; // to what extent a set is bad
1661     SMDS_FaceOfNodes tr1 ( aNodes[0], aNodes[1], aNodes[2] );
1662     SMDS_FaceOfNodes tr2 ( aNodes[2], aNodes[3], aNodes[0] );
1663     aBadRate1 = getBadRate( &tr1, theCrit ) + getBadRate( &tr2, theCrit );
1664
1665     SMDS_FaceOfNodes tr3 ( aNodes[1], aNodes[2], aNodes[3] );
1666     SMDS_FaceOfNodes tr4 ( aNodes[3], aNodes[0], aNodes[1] );
1667     aBadRate2 = getBadRate( &tr3, theCrit ) + getBadRate( &tr4, theCrit );
1668     // for MaxElementLength2D functor we return minimum diagonal for splitting,
1669     // because aBadRate1=2*len(diagonal 1-3); aBadRate2=2*len(diagonal 2-4)
1670     if (aBadRate1 <= aBadRate2) // tr1 + tr2 is better
1671       return 1; // diagonal 1-3
1672
1673     return 2; // diagonal 2-4
1674   }
1675   return -1;
1676 }
1677
1678 namespace
1679 {
1680   // Methods of splitting volumes into tetra
1681
1682   const int theHexTo5_1[5*4+1] =
1683     {
1684       0, 1, 2, 5,    0, 4, 5, 7,     0, 2, 3, 7,    2, 5, 6, 7,     0, 5, 2, 7,   -1
1685     };
1686   const int theHexTo5_2[5*4+1] =
1687     {
1688       1, 2, 3, 6,    1, 4, 5, 6,     0, 1, 3, 4,    3, 4, 6, 7,     1, 3, 4, 6,   -1
1689     };
1690   const int* theHexTo5[2] = { theHexTo5_1, theHexTo5_2 };
1691
1692   const int theHexTo6_1[6*4+1] =
1693     {
1694       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
1695     };
1696   const int theHexTo6_2[6*4+1] =
1697     {
1698       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
1699     };
1700   const int theHexTo6_3[6*4+1] =
1701     {
1702       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
1703     };
1704   const int theHexTo6_4[6*4+1] =
1705     {
1706       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
1707     };
1708   const int* theHexTo6[4] = { theHexTo6_1, theHexTo6_2, theHexTo6_3, theHexTo6_4 };
1709
1710   const int thePyraTo2_1[2*4+1] =
1711     {
1712       0, 1, 2, 4,    0, 2, 3, 4,   -1
1713     };
1714   const int thePyraTo2_2[2*4+1] =
1715     {
1716       1, 2, 3, 4,    1, 3, 0, 4,   -1
1717     };
1718   const int* thePyraTo2[2] = { thePyraTo2_1, thePyraTo2_2 };
1719
1720   const int thePentaTo3_1[3*4+1] =
1721     {
1722       0, 1, 2, 3,    1, 3, 4, 2,     2, 3, 4, 5,    -1
1723     };
1724   const int thePentaTo3_2[3*4+1] =
1725     {
1726       1, 2, 0, 4,    2, 4, 5, 0,     0, 4, 5, 3,    -1
1727     };
1728   const int thePentaTo3_3[3*4+1] =
1729     {
1730       2, 0, 1, 5,    0, 5, 3, 1,     1, 5, 3, 4,    -1
1731     };
1732   const int thePentaTo3_4[3*4+1] =
1733     {
1734       0, 1, 2, 3,    1, 3, 4, 5,     2, 3, 1, 5,    -1
1735     };
1736   const int thePentaTo3_5[3*4+1] =
1737     {
1738       1, 2, 0, 4,    2, 4, 5, 3,     0, 4, 2, 3,    -1
1739     };
1740   const int thePentaTo3_6[3*4+1] =
1741     {
1742       2, 0, 1, 5,    0, 5, 3, 4,     1, 5, 0, 4,    -1
1743     };
1744   const int* thePentaTo3[6] = { thePentaTo3_1, thePentaTo3_2, thePentaTo3_3,
1745                                 thePentaTo3_4, thePentaTo3_5, thePentaTo3_6 };
1746
1747   // Methods of splitting hexahedron into prisms
1748
1749   const int theHexTo4Prisms_BT[6*4+1] = // bottom-top
1750     {
1751       0, 1, 8, 4, 5, 9,    1, 2, 8, 5, 6, 9,    2, 3, 8, 6, 7, 9,   3, 0, 8, 7, 4, 9,    -1
1752     };
1753   const int theHexTo4Prisms_LR[6*4+1] = // left-right
1754     {
1755       1, 0, 8, 2, 3, 9,    0, 4, 8, 3, 7, 9,    4, 5, 8, 7, 6, 9,   5, 1, 8, 6, 2, 9,    -1
1756     };
1757   const int theHexTo4Prisms_FB[6*4+1] = // front-back
1758     {
1759       0, 3, 9, 1, 2, 8,    3, 7, 9, 2, 6, 8,    7, 4, 9, 6, 5, 8,   4, 0, 9, 5, 1, 8,    -1
1760     };
1761
1762   const int theHexTo2Prisms_BT_1[6*2+1] =
1763     {
1764       0, 1, 3, 4, 5, 7,    1, 2, 3, 5, 6, 7,   -1
1765     };
1766   const int theHexTo2Prisms_BT_2[6*2+1] =
1767     {
1768       0, 1, 2, 4, 5, 6,    0, 2, 3, 4, 6, 7,   -1
1769     };
1770   const int* theHexTo2Prisms_BT[2] = { theHexTo2Prisms_BT_1, theHexTo2Prisms_BT_2 };
1771
1772   const int theHexTo2Prisms_LR_1[6*2+1] =
1773     {
1774       1, 0, 4, 2, 3, 7,    1, 4, 5, 2, 7, 6,   -1
1775     };
1776   const int theHexTo2Prisms_LR_2[6*2+1] =
1777     {
1778       1, 0, 4, 2, 3, 7,    1, 4, 5, 2, 7, 6,   -1
1779     };
1780   const int* theHexTo2Prisms_LR[2] = { theHexTo2Prisms_LR_1, theHexTo2Prisms_LR_2 };
1781
1782   const int theHexTo2Prisms_FB_1[6*2+1] =
1783     {
1784       0, 3, 4, 1, 2, 5,    3, 7, 4, 2, 6, 5,   -1
1785     };
1786   const int theHexTo2Prisms_FB_2[6*2+1] =
1787     {
1788       0, 3, 7, 1, 2, 7,    0, 7, 4, 1, 6, 5,   -1
1789     };
1790   const int* theHexTo2Prisms_FB[2] = { theHexTo2Prisms_FB_1, theHexTo2Prisms_FB_2 };
1791
1792
1793   struct TTriangleFacet //!< stores indices of three nodes of tetra facet
1794   {
1795     int _n1, _n2, _n3;
1796     TTriangleFacet(int n1, int n2, int n3): _n1(n1), _n2(n2), _n3(n3) {}
1797     bool contains(int n) const { return ( n == _n1 || n == _n2 || n == _n3 ); }
1798     bool hasAdjacentVol( const SMDS_MeshElement*    elem,
1799                          const SMDSAbs_GeometryType geom = SMDSGeom_TETRA) const;
1800   };
1801   struct TSplitMethod
1802   {
1803     int        _nbSplits;
1804     int        _nbCorners;
1805     const int* _connectivity; //!< foursomes of tetra connectivy finished by -1
1806     bool       _baryNode;     //!< additional node is to be created at cell barycenter
1807     bool       _ownConn;      //!< to delete _connectivity in destructor
1808     map<int, const SMDS_MeshNode*> _faceBaryNode; //!< map face index to node at BC of face
1809
1810     TSplitMethod( int nbTet=0, const int* conn=0, bool addNode=false)
1811       : _nbSplits(nbTet), _nbCorners(4), _connectivity(conn), _baryNode(addNode), _ownConn(false) {}
1812     ~TSplitMethod() { if ( _ownConn ) delete [] _connectivity; _connectivity = 0; }
1813     bool hasFacet( const TTriangleFacet& facet ) const
1814     {
1815       if ( _nbCorners == 4 )
1816       {
1817         const int* tetConn = _connectivity;
1818         for ( ; tetConn[0] >= 0; tetConn += 4 )
1819           if (( facet.contains( tetConn[0] ) +
1820                 facet.contains( tetConn[1] ) +
1821                 facet.contains( tetConn[2] ) +
1822                 facet.contains( tetConn[3] )) == 3 )
1823             return true;
1824       }
1825       else // prism, _nbCorners == 6
1826       {
1827         const int* prismConn = _connectivity;
1828         for ( ; prismConn[0] >= 0; prismConn += 6 )
1829         {
1830           if (( facet.contains( prismConn[0] ) &&
1831                 facet.contains( prismConn[1] ) &&
1832                 facet.contains( prismConn[2] ))
1833               ||
1834               ( facet.contains( prismConn[3] ) &&
1835                 facet.contains( prismConn[4] ) &&
1836                 facet.contains( prismConn[5] )))
1837             return true;
1838         }
1839       }
1840       return false;
1841     }
1842   };
1843
1844   //=======================================================================
1845   /*!
1846    * \brief return TSplitMethod for the given element to split into tetrahedra
1847    */
1848   //=======================================================================
1849
1850   TSplitMethod getTetraSplitMethod( SMDS_VolumeTool& vol, const int theMethodFlags)
1851   {
1852     const int iQ = vol.Element()->IsQuadratic() ? 2 : 1;
1853
1854     // at HEXA_TO_24 method, each face of volume is split into triangles each based on
1855     // an edge and a face barycenter; tertaherdons are based on triangles and
1856     // a volume barycenter
1857     const bool is24TetMode = ( theMethodFlags == SMESH_MeshEditor::HEXA_TO_24 );
1858
1859     // Find out how adjacent volumes are split
1860
1861     vector < list< TTriangleFacet > > triaSplitsByFace( vol.NbFaces() ); // splits of each side
1862     int hasAdjacentSplits = 0, maxTetConnSize = 0;
1863     for ( int iF = 0; iF < vol.NbFaces(); ++iF )
1864     {
1865       int nbNodes = vol.NbFaceNodes( iF ) / iQ;
1866       maxTetConnSize += 4 * ( nbNodes - (is24TetMode ? 0 : 2));
1867       if ( nbNodes < 4 ) continue;
1868
1869       list< TTriangleFacet >& triaSplits = triaSplitsByFace[ iF ];
1870       const int* nInd = vol.GetFaceNodesIndices( iF );
1871       if ( nbNodes == 4 )
1872       {
1873         TTriangleFacet t012( nInd[0*iQ], nInd[1*iQ], nInd[2*iQ] );
1874         TTriangleFacet t123( nInd[1*iQ], nInd[2*iQ], nInd[3*iQ] );
1875         if      ( t012.hasAdjacentVol( vol.Element() )) triaSplits.push_back( t012 );
1876         else if ( t123.hasAdjacentVol( vol.Element() )) triaSplits.push_back( t123 );
1877       }
1878       else
1879       {
1880         int iCom = 0; // common node of triangle faces to split into
1881         for ( int iVar = 0; iVar < nbNodes; ++iVar, ++iCom )
1882         {
1883           TTriangleFacet t012( nInd[ iQ * ( iCom             )],
1884                                nInd[ iQ * ( (iCom+1)%nbNodes )],
1885                                nInd[ iQ * ( (iCom+2)%nbNodes )]);
1886           TTriangleFacet t023( nInd[ iQ * ( iCom             )],
1887                                nInd[ iQ * ( (iCom+2)%nbNodes )],
1888                                nInd[ iQ * ( (iCom+3)%nbNodes )]);
1889           if ( t012.hasAdjacentVol( vol.Element() ) && t023.hasAdjacentVol( vol.Element() ))
1890           {
1891             triaSplits.push_back( t012 );
1892             triaSplits.push_back( t023 );
1893             break;
1894           }
1895         }
1896       }
1897       if ( !triaSplits.empty() )
1898         hasAdjacentSplits = true;
1899     }
1900
1901     // Among variants of split method select one compliant with adjacent volumes
1902
1903     TSplitMethod method;
1904     if ( !vol.Element()->IsPoly() && !is24TetMode )
1905     {
1906       int nbVariants = 2, nbTet = 0;
1907       const int** connVariants = 0;
1908       switch ( vol.Element()->GetEntityType() )
1909       {
1910       case SMDSEntity_Hexa:
1911       case SMDSEntity_Quad_Hexa:
1912       case SMDSEntity_TriQuad_Hexa:
1913         if ( theMethodFlags == SMESH_MeshEditor::HEXA_TO_5 )
1914           connVariants = theHexTo5, nbTet = 5;
1915         else
1916           connVariants = theHexTo6, nbTet = 6, nbVariants = 4;
1917         break;
1918       case SMDSEntity_Pyramid:
1919       case SMDSEntity_Quad_Pyramid:
1920         connVariants = thePyraTo2;  nbTet = 2;
1921         break;
1922       case SMDSEntity_Penta:
1923       case SMDSEntity_Quad_Penta:
1924       case SMDSEntity_BiQuad_Penta:
1925         connVariants = thePentaTo3; nbTet = 3; nbVariants = 6;
1926         break;
1927       default:
1928         nbVariants = 0;
1929       }
1930       for ( int variant = 0; variant < nbVariants && method._nbSplits == 0; ++variant )
1931       {
1932         // check method compliance with adjacent tetras,
1933         // all found splits must be among facets of tetras described by this method
1934         method = TSplitMethod( nbTet, connVariants[variant] );
1935         if ( hasAdjacentSplits && method._nbSplits > 0 )
1936         {
1937           bool facetCreated = true;
1938           for ( size_t iF = 0; facetCreated && iF < triaSplitsByFace.size(); ++iF )
1939           {
1940             list< TTriangleFacet >::const_iterator facet = triaSplitsByFace[iF].begin();
1941             for ( ; facetCreated && facet != triaSplitsByFace[iF].end(); ++facet )
1942               facetCreated = method.hasFacet( *facet );
1943           }
1944           if ( !facetCreated )
1945             method = TSplitMethod(0); // incompatible method
1946         }
1947       }
1948     }
1949     if ( method._nbSplits < 1 )
1950     {
1951       // No standard method is applicable, use a generic solution:
1952       // each facet of a volume is split into triangles and
1953       // each of triangles and a volume barycenter form a tetrahedron.
1954
1955       const bool isHex27 = ( vol.Element()->GetEntityType() == SMDSEntity_TriQuad_Hexa );
1956
1957       int* connectivity = new int[ maxTetConnSize + 1 ];
1958       method._connectivity = connectivity;
1959       method._ownConn = true;
1960       method._baryNode = !isHex27; // to create central node or not
1961
1962       int connSize = 0;
1963       int baryCenInd = vol.NbNodes() - int( isHex27 );
1964       for ( int iF = 0; iF < vol.NbFaces(); ++iF )
1965       {
1966         const int nbNodes = vol.NbFaceNodes( iF ) / iQ;
1967         const int*   nInd = vol.GetFaceNodesIndices( iF );
1968         // find common node of triangle facets of tetra to create
1969         int iCommon = 0; // index in linear numeration
1970         const list< TTriangleFacet >& triaSplits = triaSplitsByFace[ iF ];
1971         if ( !triaSplits.empty() )
1972         {
1973           // by found facets
1974           const TTriangleFacet* facet = &triaSplits.front();
1975           for ( ; iCommon < nbNodes-1 ; ++iCommon )
1976             if ( facet->contains( nInd[ iQ * iCommon ]) &&
1977                  facet->contains( nInd[ iQ * ((iCommon+2)%nbNodes) ]))
1978               break;
1979         }
1980         else if ( nbNodes > 3 && !is24TetMode )
1981         {
1982           // find the best method of splitting into triangles by aspect ratio
1983           SMESH::Controls::NumericalFunctorPtr aspectRatio( new SMESH::Controls::AspectRatio);
1984           map< double, int > badness2iCommon;
1985           const SMDS_MeshNode** nodes = vol.GetFaceNodes( iF );
1986           int nbVariants = ( nbNodes == 4 ? 2 : nbNodes );
1987           for ( int iVar = 0; iVar < nbVariants; ++iVar, ++iCommon )
1988           {
1989             double badness = 0;
1990             for ( int iLast = iCommon+2; iLast < iCommon+nbNodes; ++iLast )
1991             {
1992               SMDS_FaceOfNodes tria ( nodes[ iQ*( iCommon         )],
1993                                       nodes[ iQ*((iLast-1)%nbNodes)],
1994                                       nodes[ iQ*((iLast  )%nbNodes)]);
1995               badness += getBadRate( &tria, aspectRatio );
1996             }
1997             badness2iCommon.insert( make_pair( badness, iCommon ));
1998           }
1999           // use iCommon with lowest badness
2000           iCommon = badness2iCommon.begin()->second;
2001         }
2002         if ( iCommon >= nbNodes )
2003           iCommon = 0; // something wrong
2004
2005         // fill connectivity of tetrahedra based on a current face
2006         int nbTet = nbNodes - 2;
2007         if ( is24TetMode && nbNodes > 3 && triaSplits.empty())
2008         {
2009           int faceBaryCenInd;
2010           if ( isHex27 )
2011           {
2012             faceBaryCenInd = vol.GetCenterNodeIndex( iF );
2013             method._faceBaryNode[ iF ] = vol.GetNodes()[ faceBaryCenInd ];
2014           }
2015           else
2016           {
2017             method._faceBaryNode[ iF ] = 0;
2018             faceBaryCenInd = baryCenInd + method._faceBaryNode.size();
2019           }
2020           nbTet = nbNodes;
2021           for ( int i = 0; i < nbTet; ++i )
2022           {
2023             int i1 = i, i2 = (i+1) % nbNodes;
2024             if ( !vol.IsFaceExternal( iF )) swap( i1, i2 );
2025             connectivity[ connSize++ ] = nInd[ iQ * i1 ];
2026             connectivity[ connSize++ ] = nInd[ iQ * i2 ];
2027             connectivity[ connSize++ ] = faceBaryCenInd;
2028             connectivity[ connSize++ ] = baryCenInd;
2029           }
2030         }
2031         else
2032         {
2033           for ( int i = 0; i < nbTet; ++i )
2034           {
2035             int i1 = (iCommon+1+i) % nbNodes, i2 = (iCommon+2+i) % nbNodes;
2036             if ( !vol.IsFaceExternal( iF )) swap( i1, i2 );
2037             connectivity[ connSize++ ] = nInd[ iQ * iCommon ];
2038             connectivity[ connSize++ ] = nInd[ iQ * i1 ];
2039             connectivity[ connSize++ ] = nInd[ iQ * i2 ];
2040             connectivity[ connSize++ ] = baryCenInd;
2041           }
2042         }
2043         method._nbSplits += nbTet;
2044
2045       } // loop on volume faces
2046
2047       connectivity[ connSize++ ] = -1;
2048
2049     } // end of generic solution
2050
2051     return method;
2052   }
2053   //=======================================================================
2054   /*!
2055    * \brief return TSplitMethod to split haxhedron into prisms
2056    */
2057   //=======================================================================
2058
2059   TSplitMethod getPrismSplitMethod( SMDS_VolumeTool& vol,
2060                                     const int        methodFlags,
2061                                     const int        facetToSplit)
2062   {
2063     // order of facets in HEX according to SMDS_VolumeTool::Hexa_F :
2064     // B, T, L, B, R, F
2065     const int iF = ( facetToSplit < 2 ) ? 0 : 1 + ( facetToSplit-2 ) % 2; // [0,1,2]
2066
2067     if ( methodFlags == SMESH_MeshEditor::HEXA_TO_4_PRISMS )
2068     {
2069       static TSplitMethod to4methods[4]; // order BT, LR, FB
2070       if ( to4methods[iF]._nbSplits == 0 )
2071       {
2072         switch ( iF ) {
2073         case 0:
2074           to4methods[iF]._connectivity = theHexTo4Prisms_BT;
2075           to4methods[iF]._faceBaryNode[ 0 ] = 0;
2076           to4methods[iF]._faceBaryNode[ 1 ] = 0;
2077           break;
2078         case 1:
2079           to4methods[iF]._connectivity = theHexTo4Prisms_LR;
2080           to4methods[iF]._faceBaryNode[ 2 ] = 0;
2081           to4methods[iF]._faceBaryNode[ 4 ] = 0;
2082           break;
2083         case 2:
2084           to4methods[iF]._connectivity = theHexTo4Prisms_FB;
2085           to4methods[iF]._faceBaryNode[ 3 ] = 0;
2086           to4methods[iF]._faceBaryNode[ 5 ] = 0;
2087           break;
2088         default: return to4methods[3];
2089         }
2090         to4methods[iF]._nbSplits  = 4;
2091         to4methods[iF]._nbCorners = 6;
2092       }
2093       return to4methods[iF];
2094     }
2095     // else if ( methodFlags == HEXA_TO_2_PRISMS )
2096
2097     TSplitMethod method;
2098
2099     const int iQ = vol.Element()->IsQuadratic() ? 2 : 1;
2100
2101     const int nbVariants = 2, nbSplits = 2;
2102     const int** connVariants = 0;
2103     switch ( iF ) {
2104     case 0: connVariants = theHexTo2Prisms_BT; break;
2105     case 1: connVariants = theHexTo2Prisms_LR; break;
2106     case 2: connVariants = theHexTo2Prisms_FB; break;
2107     default: return method;
2108     }
2109
2110     // look for prisms adjacent via facetToSplit and an opposite one
2111     for ( int is2nd = 0; is2nd < 2; ++is2nd )
2112     {
2113       int iFacet = is2nd ? vol.GetOppFaceIndexOfHex( facetToSplit ) : facetToSplit;
2114       int nbNodes = vol.NbFaceNodes( iFacet ) / iQ;
2115       if ( nbNodes != 4 ) return method;
2116
2117       const int* nInd = vol.GetFaceNodesIndices( iFacet );
2118       TTriangleFacet t012( nInd[0*iQ], nInd[1*iQ], nInd[2*iQ] );
2119       TTriangleFacet t123( nInd[1*iQ], nInd[2*iQ], nInd[3*iQ] );
2120       TTriangleFacet* t;
2121       if      ( t012.hasAdjacentVol( vol.Element(), SMDSGeom_PENTA ))
2122         t = &t012;
2123       else if ( t123.hasAdjacentVol( vol.Element(), SMDSGeom_PENTA ))
2124         t = &t123;
2125       else
2126         continue;
2127
2128       // there are adjacent prism
2129       for ( int variant = 0; variant < nbVariants; ++variant )
2130       {
2131         // check method compliance with adjacent prisms,
2132         // the found prism facets must be among facets of prisms described by current method
2133         method._nbSplits     = nbSplits;
2134         method._nbCorners    = 6;
2135         method._connectivity = connVariants[ variant ];
2136         if ( method.hasFacet( *t ))
2137           return method;
2138       }
2139     }
2140
2141     // No adjacent prisms. Select a variant with a best aspect ratio.
2142
2143     double badness[2] = { 0., 0. };
2144     static SMESH::Controls::NumericalFunctorPtr aspectRatio( new SMESH::Controls::AspectRatio);
2145     const SMDS_MeshNode** nodes = vol.GetNodes();
2146     for ( int variant = 0; variant < nbVariants; ++variant )
2147       for ( int is2nd = 0; is2nd < 2; ++is2nd )
2148       {
2149         int iFacet = is2nd ? vol.GetOppFaceIndexOfHex( facetToSplit ) : facetToSplit;
2150         const int*             nInd = vol.GetFaceNodesIndices( iFacet );
2151
2152         method._connectivity = connVariants[ variant ];
2153         TTriangleFacet t012( nInd[0*iQ], nInd[1*iQ], nInd[2*iQ] );
2154         TTriangleFacet t123( nInd[1*iQ], nInd[2*iQ], nInd[3*iQ] );
2155         TTriangleFacet* t = ( method.hasFacet( t012 )) ? & t012 : & t123;
2156
2157         SMDS_FaceOfNodes tria ( nodes[ t->_n1 ],
2158                                 nodes[ t->_n2 ],
2159                                 nodes[ t->_n3 ] );
2160         badness[ variant ] += getBadRate( &tria, aspectRatio );
2161       }
2162     const int iBetter = ( badness[1] < badness[0] && badness[0]-badness[1] > 0.1 * badness[0] );
2163
2164     method._nbSplits     = nbSplits;
2165     method._nbCorners    = 6;
2166     method._connectivity = connVariants[ iBetter ];
2167
2168     return method;
2169   }
2170
2171   //================================================================================
2172   /*!
2173    * \brief Check if there is a tetraherdon adjacent to the given element via this facet
2174    */
2175   //================================================================================
2176
2177   bool TTriangleFacet::hasAdjacentVol( const SMDS_MeshElement*    elem,
2178                                        const SMDSAbs_GeometryType geom ) const
2179   {
2180     // find the tetrahedron including the three nodes of facet
2181     const SMDS_MeshNode* n1 = elem->GetNode(_n1);
2182     const SMDS_MeshNode* n2 = elem->GetNode(_n2);
2183     const SMDS_MeshNode* n3 = elem->GetNode(_n3);
2184     SMDS_ElemIteratorPtr volIt1 = n1->GetInverseElementIterator(SMDSAbs_Volume);
2185     while ( volIt1->more() )
2186     {
2187       const SMDS_MeshElement* v = volIt1->next();
2188       if ( v->GetGeomType() != geom )
2189         continue;
2190       const int lastCornerInd = v->NbCornerNodes() - 1;
2191       if ( v->IsQuadratic() && v->GetNodeIndex( n1 ) > lastCornerInd )
2192         continue; // medium node not allowed
2193       const int ind2 = v->GetNodeIndex( n2 );
2194       if ( ind2 < 0 || lastCornerInd < ind2 )
2195         continue;
2196       const int ind3 = v->GetNodeIndex( n3 );
2197       if ( ind3 < 0 || lastCornerInd < ind3 )
2198         continue;
2199       return true;
2200     }
2201     return false;
2202   }
2203
2204   //=======================================================================
2205   /*!
2206    * \brief A key of a face of volume
2207    */
2208   //=======================================================================
2209
2210   struct TVolumeFaceKey: pair< pair< int, int>, pair< int, int> >
2211   {
2212     TVolumeFaceKey( SMDS_VolumeTool& vol, int iF )
2213     {
2214       TIDSortedNodeSet sortedNodes;
2215       const int iQ = vol.Element()->IsQuadratic() ? 2 : 1;
2216       int nbNodes = vol.NbFaceNodes( iF );
2217       const SMDS_MeshNode** fNodes = vol.GetFaceNodes( iF );
2218       for ( int i = 0; i < nbNodes; i += iQ )
2219         sortedNodes.insert( fNodes[i] );
2220       TIDSortedNodeSet::iterator n = sortedNodes.begin();
2221       first.first   = (*(n++))->GetID();
2222       first.second  = (*(n++))->GetID();
2223       second.first  = (*(n++))->GetID();
2224       second.second = ( sortedNodes.size() > 3 ) ? (*(n++))->GetID() : 0;
2225     }
2226   };
2227 } // namespace
2228
2229 //=======================================================================
2230 //function : SplitVolumes
2231 //purpose  : Split volume elements into tetrahedra or prisms.
2232 //           If facet ID < 0, element is split into tetrahedra,
2233 //           else a hexahedron is split into prisms so that the given facet is
2234 //           split into triangles
2235 //=======================================================================
2236
2237 void SMESH_MeshEditor::SplitVolumes (const TFacetOfElem & theElems,
2238                                      const int            theMethodFlags)
2239 {
2240   SMDS_VolumeTool    volTool;
2241   SMESH_MesherHelper helper( *GetMesh()), fHelper(*GetMesh());
2242   fHelper.ToFixNodeParameters( true );
2243
2244   SMESHDS_SubMesh* subMesh = 0;//GetMeshDS()->MeshElements(1);
2245   SMESHDS_SubMesh* fSubMesh = 0;//subMesh;
2246
2247   SMESH_SequenceOfElemPtr newNodes, newElems;
2248
2249   // map face of volume to it's baricenrtic node
2250   map< TVolumeFaceKey, const SMDS_MeshNode* > volFace2BaryNode;
2251   double bc[3];
2252   vector<const SMDS_MeshElement* > splitVols;
2253
2254   TFacetOfElem::const_iterator elem2facet = theElems.begin();
2255   for ( ; elem2facet != theElems.end(); ++elem2facet )
2256   {
2257     const SMDS_MeshElement* elem = elem2facet->first;
2258     const int       facetToSplit = elem2facet->second;
2259     if ( elem->GetType() != SMDSAbs_Volume )
2260       continue;
2261     const SMDSAbs_EntityType geomType = elem->GetEntityType();
2262     if ( geomType == SMDSEntity_Tetra || geomType == SMDSEntity_Quad_Tetra )
2263       continue;
2264
2265     if ( !volTool.Set( elem, /*ignoreCentralNodes=*/false )) continue; // strange...
2266
2267     TSplitMethod splitMethod = ( facetToSplit < 0  ?
2268                                  getTetraSplitMethod( volTool, theMethodFlags ) :
2269                                  getPrismSplitMethod( volTool, theMethodFlags, facetToSplit ));
2270     if ( splitMethod._nbSplits < 1 ) continue;
2271
2272     // find submesh to add new tetras to
2273     if ( !subMesh || !subMesh->Contains( elem ))
2274     {
2275       int shapeID = FindShape( elem );
2276       helper.SetSubShape( shapeID ); // helper will add tetras to the found submesh
2277       subMesh = GetMeshDS()->MeshElements( shapeID );
2278     }
2279     int iQ;
2280     if ( elem->IsQuadratic() )
2281     {
2282       iQ = 2;
2283       // add quadratic links to the helper
2284       for ( int iF = 0; iF < volTool.NbFaces(); ++iF )
2285       {
2286         const SMDS_MeshNode** fNodes = volTool.GetFaceNodes( iF );
2287         int nbN = volTool.NbFaceNodes( iF ) - bool( volTool.GetCenterNodeIndex(iF) > 0 );
2288         for ( int iN = 0; iN < nbN; iN += iQ )
2289           helper.AddTLinkNode( fNodes[iN], fNodes[iN+2], fNodes[iN+1] );
2290       }
2291       helper.SetIsQuadratic( true );
2292     }
2293     else
2294     {
2295       iQ = 1;
2296       helper.SetIsQuadratic( false );
2297     }
2298     vector<const SMDS_MeshNode*> nodes( volTool.GetNodes(),
2299                                         volTool.GetNodes() + elem->NbNodes() );
2300     helper.SetElementsOnShape( true );
2301     if ( splitMethod._baryNode )
2302     {
2303       // make a node at barycenter
2304       volTool.GetBaryCenter( bc[0], bc[1], bc[2] );
2305       SMDS_MeshNode* gcNode = helper.AddNode( bc[0], bc[1], bc[2] );
2306       nodes.push_back( gcNode );
2307       newNodes.push_back( gcNode );
2308     }
2309     if ( !splitMethod._faceBaryNode.empty() )
2310     {
2311       // make or find baricentric nodes of faces
2312       map<int, const SMDS_MeshNode*>::iterator iF_n = splitMethod._faceBaryNode.begin();
2313       for ( ; iF_n != splitMethod._faceBaryNode.end(); ++iF_n )
2314       {
2315         map< TVolumeFaceKey, const SMDS_MeshNode* >::iterator f_n =
2316           volFace2BaryNode.insert
2317           ( make_pair( TVolumeFaceKey( volTool,iF_n->first ), iF_n->second )).first;
2318         if ( !f_n->second )
2319         {
2320           volTool.GetFaceBaryCenter( iF_n->first, bc[0], bc[1], bc[2] );
2321           newNodes.push_back( f_n->second = helper.AddNode( bc[0], bc[1], bc[2] ));
2322         }
2323         nodes.push_back( iF_n->second = f_n->second );
2324       }
2325     }
2326
2327     // make new volumes
2328     splitVols.resize( splitMethod._nbSplits ); // splits of a volume
2329     const int* volConn = splitMethod._connectivity;
2330     if ( splitMethod._nbCorners == 4 ) // tetra
2331       for ( int i = 0; i < splitMethod._nbSplits; ++i, volConn += splitMethod._nbCorners )
2332         newElems.push_back( splitVols[ i ] = helper.AddVolume( nodes[ volConn[0] ],
2333                                                                nodes[ volConn[1] ],
2334                                                                nodes[ volConn[2] ],
2335                                                                nodes[ volConn[3] ]));
2336     else // prisms
2337       for ( int i = 0; i < splitMethod._nbSplits; ++i, volConn += splitMethod._nbCorners )
2338         newElems.push_back( splitVols[ i ] = helper.AddVolume( nodes[ volConn[0] ],
2339                                                                nodes[ volConn[1] ],
2340                                                                nodes[ volConn[2] ],
2341                                                                nodes[ volConn[3] ],
2342                                                                nodes[ volConn[4] ],
2343                                                                nodes[ volConn[5] ]));
2344
2345     ReplaceElemInGroups( elem, splitVols, GetMeshDS() );
2346
2347     // Split faces on sides of the split volume
2348
2349     const SMDS_MeshNode** volNodes = volTool.GetNodes();
2350     for ( int iF = 0; iF < volTool.NbFaces(); ++iF )
2351     {
2352       const int nbNodes = volTool.NbFaceNodes( iF ) / iQ;
2353       if ( nbNodes < 4 ) continue;
2354
2355       // find an existing face
2356       vector<const SMDS_MeshNode*> fNodes( volTool.GetFaceNodes( iF ),
2357                                            volTool.GetFaceNodes( iF ) + volTool.NbFaceNodes( iF ));
2358       while ( const SMDS_MeshElement* face = GetMeshDS()->FindElement( fNodes, SMDSAbs_Face,
2359                                                                        /*noMedium=*/false))
2360       {
2361         // make triangles
2362         helper.SetElementsOnShape( false );
2363         vector< const SMDS_MeshElement* > triangles;
2364
2365         // find submesh to add new triangles in
2366         if ( !fSubMesh || !fSubMesh->Contains( face ))
2367         {
2368           int shapeID = FindShape( face );
2369           fSubMesh = GetMeshDS()->MeshElements( shapeID );
2370         }
2371         map<int, const SMDS_MeshNode*>::iterator iF_n = splitMethod._faceBaryNode.find(iF);
2372         if ( iF_n != splitMethod._faceBaryNode.end() )
2373         {
2374           const SMDS_MeshNode *baryNode = iF_n->second;
2375           for ( int iN = 0; iN < nbNodes*iQ; iN += iQ )
2376           {
2377             const SMDS_MeshNode* n1 = fNodes[iN];
2378             const SMDS_MeshNode *n2 = fNodes[(iN+iQ)%(nbNodes*iQ)];
2379             const SMDS_MeshNode *n3 = baryNode;
2380             if ( !volTool.IsFaceExternal( iF ))
2381               swap( n2, n3 );
2382             triangles.push_back( helper.AddFace( n1,n2,n3 ));
2383           }
2384           if ( fSubMesh ) // update position of the bary node on geometry
2385           {
2386             if ( subMesh )
2387               subMesh->RemoveNode( baryNode );
2388             GetMeshDS()->SetNodeOnFace( baryNode, fSubMesh->GetID() );
2389             const TopoDS_Shape& s = GetMeshDS()->IndexToShape( fSubMesh->GetID() );
2390             if ( !s.IsNull() && s.ShapeType() == TopAbs_FACE )
2391             {
2392               fHelper.SetSubShape( s );
2393               gp_XY uv( 1e100, 1e100 );
2394               double distXYZ[4];
2395               if ( !fHelper.CheckNodeUV( TopoDS::Face( s ), baryNode,
2396                                          uv, /*tol=*/1e-7, /*force=*/true, distXYZ ) &&
2397                    uv.X() < 1e100 )
2398               {
2399                 // node is too far from the surface
2400                 GetMeshDS()->MoveNode( baryNode, distXYZ[1], distXYZ[2], distXYZ[3] );
2401                 const_cast<SMDS_MeshNode*>( baryNode )->SetPosition
2402                   ( SMDS_PositionPtr( new SMDS_FacePosition( uv.X(), uv.Y() )));
2403               }
2404             }
2405           }
2406         }
2407         else
2408         {
2409           // among possible triangles create ones described by split method
2410           const int* nInd = volTool.GetFaceNodesIndices( iF );
2411           int nbVariants = ( nbNodes == 4 ? 2 : nbNodes );
2412           int iCom = 0; // common node of triangle faces to split into
2413           list< TTriangleFacet > facets;
2414           for ( int iVar = 0; iVar < nbVariants; ++iVar, ++iCom )
2415           {
2416             TTriangleFacet t012( nInd[ iQ * ( iCom                )],
2417                                  nInd[ iQ * ( (iCom+1)%nbNodes )],
2418                                  nInd[ iQ * ( (iCom+2)%nbNodes )]);
2419             TTriangleFacet t023( nInd[ iQ * ( iCom                )],
2420                                  nInd[ iQ * ( (iCom+2)%nbNodes )],
2421                                  nInd[ iQ * ( (iCom+3)%nbNodes )]);
2422             if ( splitMethod.hasFacet( t012 ) && splitMethod.hasFacet( t023 ))
2423             {
2424               facets.push_back( t012 );
2425               facets.push_back( t023 );
2426               for ( int iLast = iCom+4; iLast < iCom+nbNodes; ++iLast )
2427                 facets.push_back( TTriangleFacet( nInd[ iQ * ( iCom             )],
2428                                                   nInd[ iQ * ((iLast-1)%nbNodes )],
2429                                                   nInd[ iQ * ((iLast  )%nbNodes )]));
2430               break;
2431             }
2432           }
2433           list< TTriangleFacet >::iterator facet = facets.begin();
2434           if ( facet == facets.end() )
2435             break;
2436           for ( ; facet != facets.end(); ++facet )
2437           {
2438             if ( !volTool.IsFaceExternal( iF ))
2439               swap( facet->_n2, facet->_n3 );
2440             triangles.push_back( helper.AddFace( volNodes[ facet->_n1 ],
2441                                                  volNodes[ facet->_n2 ],
2442                                                  volNodes[ facet->_n3 ]));
2443           }
2444         }
2445         for ( size_t i = 0; i < triangles.size(); ++i )
2446         {
2447           if ( !triangles[ i ]) continue;
2448           if ( fSubMesh )
2449             fSubMesh->AddElement( triangles[ i ]);
2450           newElems.push_back( triangles[ i ]);
2451         }
2452         ReplaceElemInGroups( face, triangles, GetMeshDS() );
2453         GetMeshDS()->RemoveFreeElement( face, fSubMesh, /*fromGroups=*/false );
2454
2455       } // while a face based on facet nodes exists
2456     } // loop on volume faces to split them into triangles
2457
2458     GetMeshDS()->RemoveFreeElement( elem, subMesh, /*fromGroups=*/false );
2459
2460     if ( geomType == SMDSEntity_TriQuad_Hexa )
2461     {
2462       // remove medium nodes that could become free
2463       for ( int i = 20; i < volTool.NbNodes(); ++i )
2464         if ( volNodes[i]->NbInverseElements() == 0 )
2465           GetMeshDS()->RemoveNode( volNodes[i] );
2466     }
2467   } // loop on volumes to split
2468
2469   myLastCreatedNodes = newNodes;
2470   myLastCreatedElems = newElems;
2471 }
2472
2473 //=======================================================================
2474 //function : GetHexaFacetsToSplit
2475 //purpose  : For hexahedra that will be split into prisms, finds facets to
2476 //           split into triangles. Only hexahedra adjacent to the one closest
2477 //           to theFacetNormal.Location() are returned.
2478 //param [in,out] theHexas - the hexahedra
2479 //param [in]     theFacetNormal - facet normal
2480 //param [out]    theFacets - the hexahedra and found facet IDs
2481 //=======================================================================
2482
2483 void SMESH_MeshEditor::GetHexaFacetsToSplit( TIDSortedElemSet& theHexas,
2484                                              const gp_Ax1&     theFacetNormal,
2485                                              TFacetOfElem &    theFacets)
2486 {
2487 #define THIS_METHOD "SMESH_MeshEditor::GetHexaFacetsToSplit(): "
2488
2489   // Find a hexa closest to the location of theFacetNormal
2490
2491   const SMDS_MeshElement* startHex;
2492   {
2493     // get SMDS_ElemIteratorPtr on theHexas
2494     typedef const SMDS_MeshElement*                                      TValue;
2495     typedef TIDSortedElemSet::iterator                                   TSetIterator;
2496     typedef SMDS::SimpleAccessor<TValue,TSetIterator>                    TAccesor;
2497     typedef SMDS_MeshElement::GeomFilter                                 TFilter;
2498     typedef SMDS_SetIterator < TValue, TSetIterator, TAccesor, TFilter > TElemSetIter;
2499     SMDS_ElemIteratorPtr elemIt = SMDS_ElemIteratorPtr
2500       ( new TElemSetIter( theHexas.begin(),
2501                           theHexas.end(),
2502                           SMDS_MeshElement::GeomFilter( SMDSGeom_HEXA )));
2503
2504     SMESH_ElementSearcher* searcher =
2505       SMESH_MeshAlgos::GetElementSearcher( *myMesh->GetMeshDS(), elemIt );
2506
2507     startHex = searcher->FindClosestTo( theFacetNormal.Location(), SMDSAbs_Volume );
2508
2509     delete searcher;
2510
2511     if ( !startHex )
2512       throw SALOME_Exception( THIS_METHOD "startHex not found");
2513   }
2514
2515   // Select a facet of startHex by theFacetNormal
2516
2517   SMDS_VolumeTool vTool( startHex );
2518   double norm[3], dot, maxDot = 0;
2519   int facetID = -1;
2520   for ( int iF = 0; iF < vTool.NbFaces(); ++iF )
2521     if ( vTool.GetFaceNormal( iF, norm[0], norm[1], norm[2] ))
2522     {
2523       dot = Abs( theFacetNormal.Direction().Dot( gp_Dir( norm[0], norm[1], norm[2] )));
2524       if ( dot > maxDot )
2525       {
2526         facetID = iF;
2527         maxDot = dot;
2528       }
2529     }
2530   if ( facetID < 0 )
2531     throw SALOME_Exception( THIS_METHOD "facet of startHex not found");
2532
2533   // Fill theFacets starting from facetID of startHex
2534
2535   // facets used for searching of volumes adjacent to already treated ones
2536   typedef pair< TFacetOfElem::iterator, int > TElemFacets;
2537   typedef map< TVolumeFaceKey, TElemFacets  > TFacetMap;
2538   TFacetMap facetsToCheck;
2539
2540   set<const SMDS_MeshNode*> facetNodes;
2541   const SMDS_MeshElement*   curHex;
2542
2543   const bool allHex = ((int) theHexas.size() == myMesh->NbHexas() );
2544
2545   while ( startHex )
2546   {
2547     // move in two directions from startHex via facetID
2548     for ( int is2nd = 0; is2nd < 2; ++is2nd )
2549     {
2550       curHex       = startHex;
2551       int curFacet = facetID;
2552       if ( is2nd ) // do not treat startHex twice
2553       {
2554         vTool.Set( curHex );
2555         if ( vTool.IsFreeFace( curFacet, &curHex ))
2556         {
2557           curHex = 0;
2558         }
2559         else
2560         {
2561           vTool.GetFaceNodes( curFacet, facetNodes );
2562           vTool.Set( curHex );
2563           curFacet = vTool.GetFaceIndex( facetNodes );
2564         }
2565       }
2566       while ( curHex )
2567       {
2568         // store a facet to split
2569         if ( curHex->GetGeomType() != SMDSGeom_HEXA )
2570         {
2571           theFacets.insert( make_pair( curHex, -1 ));
2572           break;
2573         }
2574         if ( !allHex && !theHexas.count( curHex ))
2575           break;
2576
2577         pair< TFacetOfElem::iterator, bool > facetIt2isNew =
2578           theFacets.insert( make_pair( curHex, curFacet ));
2579         if ( !facetIt2isNew.second )
2580           break;
2581
2582         // remember not-to-split facets in facetsToCheck
2583         int oppFacet = vTool.GetOppFaceIndexOfHex( curFacet );
2584         for ( int iF = 0; iF < vTool.NbFaces(); ++iF )
2585         {
2586           if ( iF == curFacet && iF == oppFacet )
2587             continue;
2588           TVolumeFaceKey facetKey ( vTool, iF );
2589           TElemFacets    elemFacet( facetIt2isNew.first, iF );
2590           pair< TFacetMap::iterator, bool > it2isnew =
2591             facetsToCheck.insert( make_pair( facetKey, elemFacet ));
2592           if ( !it2isnew.second )
2593             facetsToCheck.erase( it2isnew.first ); // adjacent hex already checked
2594         }
2595         // pass to a volume adjacent via oppFacet
2596         if ( vTool.IsFreeFace( oppFacet, &curHex ))
2597         {
2598           curHex = 0;
2599         }
2600         else
2601         {
2602           // get a new curFacet
2603           vTool.GetFaceNodes( oppFacet, facetNodes );
2604           vTool.Set( curHex );
2605           curFacet = vTool.GetFaceIndex( facetNodes, /*hint=*/curFacet );
2606         }
2607       }
2608     } // move in two directions from startHex via facetID
2609
2610     // Find a new startHex by facetsToCheck
2611
2612     startHex = 0;
2613     facetID  = -1;
2614     TFacetMap::iterator fIt = facetsToCheck.begin();
2615     while ( !startHex && fIt != facetsToCheck.end() )
2616     {
2617       const TElemFacets&  elemFacets = fIt->second;
2618       const SMDS_MeshElement*    hex = elemFacets.first->first;
2619       int                 splitFacet = elemFacets.first->second;
2620       int               lateralFacet = elemFacets.second;
2621       facetsToCheck.erase( fIt );
2622       fIt = facetsToCheck.begin();
2623
2624       vTool.Set( hex );
2625       if ( vTool.IsFreeFace( lateralFacet, &curHex ) || 
2626            curHex->GetGeomType() != SMDSGeom_HEXA )
2627         continue;
2628       if ( !allHex && !theHexas.count( curHex ))
2629         continue;
2630
2631       startHex = curHex;
2632
2633       // find a facet of startHex to split
2634
2635       set<const SMDS_MeshNode*> lateralNodes;
2636       vTool.GetFaceNodes( lateralFacet, lateralNodes );
2637       vTool.GetFaceNodes( splitFacet,   facetNodes );
2638       int oppLateralFacet = vTool.GetOppFaceIndexOfHex( lateralFacet );
2639       vTool.Set( startHex );
2640       lateralFacet = vTool.GetFaceIndex( lateralNodes, oppLateralFacet );
2641
2642       // look for a facet of startHex having common nodes with facetNodes
2643       // but not lateralFacet
2644       for ( int iF = 0; iF < vTool.NbFaces(); ++iF )
2645       {
2646         if ( iF == lateralFacet )
2647           continue;
2648         int nbCommonNodes = 0;
2649         const SMDS_MeshNode** nn = vTool.GetFaceNodes( iF );
2650         for ( int iN = 0, nbN = vTool.NbFaceNodes( iF ); iN < nbN; ++iN )
2651           nbCommonNodes += facetNodes.count( nn[ iN ]);
2652
2653         if ( nbCommonNodes >= 2 )
2654         {
2655           facetID = iF;
2656           break;
2657         }
2658       }
2659       if ( facetID < 0 )
2660         throw SALOME_Exception( THIS_METHOD "facet of a new startHex not found");
2661     }
2662   } //   while ( startHex )
2663
2664   return;
2665 }
2666
2667 namespace
2668 {
2669   //================================================================================
2670   /*!
2671    * \brief Selects nodes of several elements according to a given interlace
2672    *  \param [in] srcNodes - nodes to select from
2673    *  \param [out] tgtNodesVec - array of nodes of several elements to fill in
2674    *  \param [in] interlace - indices of nodes for all elements
2675    *  \param [in] nbElems - nb of elements
2676    *  \param [in] nbNodes - nb of nodes in each element
2677    *  \param [in] mesh - the mesh
2678    *  \param [out] elemQueue - a list to push elements found by the selected nodes
2679    *  \param [in] type - type of elements to look for
2680    */
2681   //================================================================================
2682
2683   void selectNodes( const vector< const SMDS_MeshNode* >& srcNodes,
2684                     vector< const SMDS_MeshNode* >*       tgtNodesVec,
2685                     const int*                            interlace,
2686                     const int                             nbElems,
2687                     const int                             nbNodes,
2688                     SMESHDS_Mesh*                         mesh = 0,
2689                     list< const SMDS_MeshElement* >*      elemQueue=0,
2690                     SMDSAbs_ElementType                   type=SMDSAbs_All)
2691   {
2692     for ( int iE = 0; iE < nbElems; ++iE )
2693     {
2694       vector< const SMDS_MeshNode* >& elemNodes = tgtNodesVec[iE];
2695       const int*                         select = & interlace[iE*nbNodes];
2696       elemNodes.resize( nbNodes );
2697       for ( int iN = 0; iN < nbNodes; ++iN )
2698         elemNodes[iN] = srcNodes[ select[ iN ]];
2699     }
2700     const SMDS_MeshElement* e;
2701     if ( elemQueue )
2702       for ( int iE = 0; iE < nbElems; ++iE )
2703         if (( e = mesh->FindElement( tgtNodesVec[iE], type, /*noMedium=*/false)))
2704           elemQueue->push_back( e );
2705   }
2706 }
2707
2708 //=======================================================================
2709 /*
2710  * Split bi-quadratic elements into linear ones without creation of additional nodes
2711  *   - bi-quadratic triangle will be split into 3 linear quadrangles;
2712  *   - bi-quadratic quadrangle will be split into 4 linear quadrangles;
2713  *   - tri-quadratic hexahedron will be split into 8 linear hexahedra;
2714  *   Quadratic elements of lower dimension  adjacent to the split bi-quadratic element
2715  *   will be split in order to keep the mesh conformal.
2716  *  \param elems - elements to split
2717  */
2718 //=======================================================================
2719
2720 void SMESH_MeshEditor::SplitBiQuadraticIntoLinear(TIDSortedElemSet& theElems)
2721 {
2722   vector< const SMDS_MeshNode* > elemNodes(27), subNodes[12], splitNodes[8];
2723   vector<const SMDS_MeshElement* > splitElems;
2724   list< const SMDS_MeshElement* > elemQueue;
2725   list< const SMDS_MeshElement* >::iterator elemIt;
2726
2727   SMESHDS_Mesh * mesh = GetMeshDS();
2728   ElemFeatures *elemType, hexaType(SMDSAbs_Volume), quadType(SMDSAbs_Face), segType(SMDSAbs_Edge);
2729   int nbElems, nbNodes;
2730
2731   TIDSortedElemSet::iterator elemSetIt = theElems.begin();
2732   for ( ; elemSetIt != theElems.end(); ++elemSetIt )
2733   {
2734     elemQueue.clear();
2735     elemQueue.push_back( *elemSetIt );
2736     for ( elemIt = elemQueue.begin(); elemIt != elemQueue.end(); ++elemIt )
2737     {
2738       const SMDS_MeshElement* elem = *elemIt;
2739       switch( elem->GetEntityType() )
2740       {
2741       case SMDSEntity_TriQuad_Hexa: // HEX27
2742       {
2743         elemNodes.assign( elem->begin_nodes(), elem->end_nodes() );
2744         nbElems  = nbNodes = 8;
2745         elemType = & hexaType;
2746
2747         // get nodes for new elements
2748         static int vInd[8][8] = {{ 0,8,20,11,   16,21,26,24 },
2749                                  { 1,9,20,8,    17,22,26,21 },
2750                                  { 2,10,20,9,   18,23,26,22 },
2751                                  { 3,11,20,10,  19,24,26,23 },
2752                                  { 16,21,26,24, 4,12,25,15  },
2753                                  { 17,22,26,21, 5,13,25,12  },
2754                                  { 18,23,26,22, 6,14,25,13  },
2755                                  { 19,24,26,23, 7,15,25,14  }};
2756         selectNodes( elemNodes, & splitNodes[0], &vInd[0][0], nbElems, nbNodes );
2757
2758         // add boundary faces to elemQueue
2759         static int fInd[6][9] = {{ 0,1,2,3, 8,9,10,11,   20 },
2760                                  { 4,5,6,7, 12,13,14,15, 25 },
2761                                  { 0,1,5,4, 8,17,12,16,  21 },
2762                                  { 1,2,6,5, 9,18,13,17,  22 },
2763                                  { 2,3,7,6, 10,19,14,18, 23 },
2764                                  { 3,0,4,7, 11,16,15,19, 24 }};
2765         selectNodes( elemNodes, & subNodes[0], &fInd[0][0], 6,9, mesh, &elemQueue, SMDSAbs_Face );
2766
2767         // add boundary segments to elemQueue
2768         static int eInd[12][3] = {{ 0,1,8 }, { 1,2,9 }, { 2,3,10 }, { 3,0,11 },
2769                                   { 4,5,12}, { 5,6,13}, { 6,7,14 }, { 7,4,15 },
2770                                   { 0,4,16}, { 1,5,17}, { 2,6,18 }, { 3,7,19 }};
2771         selectNodes( elemNodes, & subNodes[0], &eInd[0][0], 12,3, mesh, &elemQueue, SMDSAbs_Edge );
2772         break;
2773       }
2774       case SMDSEntity_BiQuad_Triangle: // TRIA7
2775       {
2776         elemNodes.assign( elem->begin_nodes(), elem->end_nodes() );
2777         nbElems = 3;
2778         nbNodes = 4;
2779         elemType = & quadType;
2780
2781         // get nodes for new elements
2782         static int fInd[3][4] = {{ 0,3,6,5 }, { 1,4,6,3 }, { 2,5,6,4 }};
2783         selectNodes( elemNodes, & splitNodes[0], &fInd[0][0], nbElems, nbNodes );
2784
2785         // add boundary segments to elemQueue
2786         static int eInd[3][3] = {{ 0,1,3 }, { 1,2,4 }, { 2,0,5 }};
2787         selectNodes( elemNodes, & subNodes[0], &eInd[0][0], 3,3, mesh, &elemQueue, SMDSAbs_Edge );
2788         break;
2789       }
2790       case SMDSEntity_BiQuad_Quadrangle: // QUAD9
2791       {
2792         elemNodes.assign( elem->begin_nodes(), elem->end_nodes() );
2793         nbElems = 4;
2794         nbNodes = 4;
2795         elemType = & quadType;
2796
2797         // get nodes for new elements
2798         static int fInd[4][4] = {{ 0,4,8,7 }, { 1,5,8,4 }, { 2,6,8,5 }, { 3,7,8,6 }};
2799         selectNodes( elemNodes, & splitNodes[0], &fInd[0][0], nbElems, nbNodes );
2800
2801         // add boundary segments to elemQueue
2802         static int eInd[4][3] = {{ 0,1,4 }, { 1,2,5 }, { 2,3,6 }, { 3,0,7 }};
2803         selectNodes( elemNodes, & subNodes[0], &eInd[0][0], 4,3, mesh, &elemQueue, SMDSAbs_Edge );
2804         break;
2805       }
2806       case SMDSEntity_Quad_Edge:
2807       {
2808         if ( elemIt == elemQueue.begin() )
2809           continue; // an elem is in theElems
2810         elemNodes.assign( elem->begin_nodes(), elem->end_nodes() );
2811         nbElems = 2;
2812         nbNodes = 2;
2813         elemType = & segType;
2814
2815         // get nodes for new elements
2816         static int eInd[2][2] = {{ 0,2 }, { 2,1 }};
2817         selectNodes( elemNodes, & splitNodes[0], &eInd[0][0], nbElems, nbNodes );
2818         break;
2819       }
2820       default: continue;
2821       } // switch( elem->GetEntityType() )
2822
2823       // Create new elements
2824
2825       SMESHDS_SubMesh* subMesh = mesh->MeshElements( elem->getshapeId() );
2826
2827       splitElems.clear();
2828
2829       //elemType->SetID( elem->GetID() ); // create an elem with the same ID as a removed one
2830       mesh->RemoveFreeElement( elem, subMesh, /*fromGroups=*/false );
2831       //splitElems.push_back( AddElement( splitNodes[ 0 ], *elemType ));
2832       //elemType->SetID( -1 );
2833
2834       for ( int iE = 0; iE < nbElems; ++iE )
2835         splitElems.push_back( AddElement( splitNodes[ iE ], *elemType ));
2836
2837
2838       ReplaceElemInGroups( elem, splitElems, mesh );
2839
2840       if ( subMesh )
2841         for ( size_t i = 0; i < splitElems.size(); ++i )
2842           subMesh->AddElement( splitElems[i] );
2843     }
2844   }
2845 }
2846
2847 //=======================================================================
2848 //function : AddToSameGroups
2849 //purpose  : add elemToAdd to the groups the elemInGroups belongs to
2850 //=======================================================================
2851
2852 void SMESH_MeshEditor::AddToSameGroups (const SMDS_MeshElement* elemToAdd,
2853                                         const SMDS_MeshElement* elemInGroups,
2854                                         SMESHDS_Mesh *          aMesh)
2855 {
2856   const set<SMESHDS_GroupBase*>& groups = aMesh->GetGroups();
2857   if (!groups.empty()) {
2858     set<SMESHDS_GroupBase*>::const_iterator grIt = groups.begin();
2859     for ( ; grIt != groups.end(); grIt++ ) {
2860       SMESHDS_Group* group = dynamic_cast<SMESHDS_Group*>( *grIt );
2861       if ( group && group->Contains( elemInGroups ))
2862         group->SMDSGroup().Add( elemToAdd );
2863     }
2864   }
2865 }
2866
2867
2868 //=======================================================================
2869 //function : RemoveElemFromGroups
2870 //purpose  : Remove removeelem to the groups the elemInGroups belongs to
2871 //=======================================================================
2872 void SMESH_MeshEditor::RemoveElemFromGroups (const SMDS_MeshElement* removeelem,
2873                                              SMESHDS_Mesh *          aMesh)
2874 {
2875   const set<SMESHDS_GroupBase*>& groups = aMesh->GetGroups();
2876   if (!groups.empty())
2877   {
2878     set<SMESHDS_GroupBase*>::const_iterator GrIt = groups.begin();
2879     for (; GrIt != groups.end(); GrIt++)
2880     {
2881       SMESHDS_Group* grp = dynamic_cast<SMESHDS_Group*>(*GrIt);
2882       if (!grp || grp->IsEmpty()) continue;
2883       grp->SMDSGroup().Remove(removeelem);
2884     }
2885   }
2886 }
2887
2888 //================================================================================
2889 /*!
2890  * \brief Replace elemToRm by elemToAdd in the all groups
2891  */
2892 //================================================================================
2893
2894 void SMESH_MeshEditor::ReplaceElemInGroups (const SMDS_MeshElement* elemToRm,
2895                                             const SMDS_MeshElement* elemToAdd,
2896                                             SMESHDS_Mesh *          aMesh)
2897 {
2898   const set<SMESHDS_GroupBase*>& groups = aMesh->GetGroups();
2899   if (!groups.empty()) {
2900     set<SMESHDS_GroupBase*>::const_iterator grIt = groups.begin();
2901     for ( ; grIt != groups.end(); grIt++ ) {
2902       SMESHDS_Group* group = dynamic_cast<SMESHDS_Group*>( *grIt );
2903       if ( group && group->SMDSGroup().Remove( elemToRm ) && elemToAdd )
2904         group->SMDSGroup().Add( elemToAdd );
2905     }
2906   }
2907 }
2908
2909 //================================================================================
2910 /*!
2911  * \brief Replace elemToRm by elemToAdd in the all groups
2912  */
2913 //================================================================================
2914
2915 void SMESH_MeshEditor::ReplaceElemInGroups (const SMDS_MeshElement*                elemToRm,
2916                                             const vector<const SMDS_MeshElement*>& elemToAdd,
2917                                             SMESHDS_Mesh *                         aMesh)
2918 {
2919   const set<SMESHDS_GroupBase*>& groups = aMesh->GetGroups();
2920   if (!groups.empty())
2921   {
2922     set<SMESHDS_GroupBase*>::const_iterator grIt = groups.begin();
2923     for ( ; grIt != groups.end(); grIt++ ) {
2924       SMESHDS_Group* group = dynamic_cast<SMESHDS_Group*>( *grIt );
2925       if ( group && group->SMDSGroup().Remove( elemToRm ) )
2926         for ( size_t i = 0; i < elemToAdd.size(); ++i )
2927           group->SMDSGroup().Add( elemToAdd[ i ] );
2928     }
2929   }
2930 }
2931
2932 //=======================================================================
2933 //function : QuadToTri
2934 //purpose  : Cut quadrangles into triangles.
2935 //           theCrit is used to select a diagonal to cut
2936 //=======================================================================
2937
2938 bool SMESH_MeshEditor::QuadToTri (TIDSortedElemSet & theElems,
2939                                   const bool         the13Diag)
2940 {
2941   ClearLastCreated();
2942   myLastCreatedElems.reserve( theElems.size() * 2 );
2943
2944   SMESHDS_Mesh *       aMesh = GetMeshDS();
2945   Handle(Geom_Surface) surface;
2946   SMESH_MesherHelper   helper( *GetMesh() );
2947
2948   TIDSortedElemSet::iterator itElem;
2949   for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ )
2950   {
2951     const SMDS_MeshElement* elem = *itElem;
2952     if ( !elem || elem->GetGeomType() != SMDSGeom_QUADRANGLE )
2953       continue;
2954
2955     if ( elem->NbNodes() == 4 ) {
2956       // retrieve element nodes
2957       const SMDS_MeshNode* aNodes [4];
2958       SMDS_ElemIteratorPtr itN = elem->nodesIterator();
2959       int i = 0;
2960       while ( itN->more() )
2961         aNodes[ i++ ] = static_cast<const SMDS_MeshNode*>( itN->next() );
2962
2963       int aShapeId = FindShape( elem );
2964       const SMDS_MeshElement* newElem1 = 0;
2965       const SMDS_MeshElement* newElem2 = 0;
2966       if ( the13Diag ) {
2967         newElem1 = aMesh->AddFace( aNodes[2], aNodes[0], aNodes[1] );
2968         newElem2 = aMesh->AddFace( aNodes[2], aNodes[3], aNodes[0] );
2969       }
2970       else {
2971         newElem1 = aMesh->AddFace( aNodes[3], aNodes[0], aNodes[1] );
2972         newElem2 = aMesh->AddFace( aNodes[3], aNodes[1], aNodes[2] );
2973       }
2974       myLastCreatedElems.push_back(newElem1);
2975       myLastCreatedElems.push_back(newElem2);
2976       // put a new triangle on the same shape and add to the same groups
2977       if ( aShapeId )
2978       {
2979         aMesh->SetMeshElementOnShape( newElem1, aShapeId );
2980         aMesh->SetMeshElementOnShape( newElem2, aShapeId );
2981       }
2982       AddToSameGroups( newElem1, elem, aMesh );
2983       AddToSameGroups( newElem2, elem, aMesh );
2984       aMesh->RemoveElement( elem );
2985     }
2986
2987     // Quadratic quadrangle
2988
2989     else if ( elem->NbNodes() >= 8 )
2990     {
2991       // get surface elem is on
2992       int aShapeId = FindShape( elem );
2993       if ( aShapeId != helper.GetSubShapeID() ) {
2994         surface.Nullify();
2995         TopoDS_Shape shape;
2996         if ( aShapeId > 0 )
2997           shape = aMesh->IndexToShape( aShapeId );
2998         if ( !shape.IsNull() && shape.ShapeType() == TopAbs_FACE ) {
2999           TopoDS_Face face = TopoDS::Face( shape );
3000           surface = BRep_Tool::Surface( face );
3001           if ( !surface.IsNull() )
3002             helper.SetSubShape( shape );
3003         }
3004       }
3005
3006       const SMDS_MeshNode* aNodes [9]; aNodes[8] = 0;
3007       SMDS_ElemIteratorPtr itN = elem->nodesIterator();
3008       for ( int i = 0; itN->more(); ++i )
3009         aNodes[ i ] = static_cast<const SMDS_MeshNode*>( itN->next() );
3010
3011       const SMDS_MeshNode* centrNode = aNodes[8];
3012       if ( centrNode == 0 )
3013       {
3014         centrNode = helper.GetCentralNode( aNodes[0], aNodes[1], aNodes[2], aNodes[3],
3015                                            aNodes[4], aNodes[5], aNodes[6], aNodes[7],
3016                                            surface.IsNull() );
3017         myLastCreatedNodes.push_back(centrNode);
3018       }
3019
3020       // create a new element
3021       const SMDS_MeshElement* newElem1 = 0;
3022       const SMDS_MeshElement* newElem2 = 0;
3023       if ( the13Diag ) {
3024         newElem1 = aMesh->AddFace(aNodes[2], aNodes[3], aNodes[0],
3025                                   aNodes[6], aNodes[7], centrNode );
3026         newElem2 = aMesh->AddFace(aNodes[2], aNodes[0], aNodes[1],
3027                                   centrNode, aNodes[4], aNodes[5] );
3028       }
3029       else {
3030         newElem1 = aMesh->AddFace(aNodes[3], aNodes[0], aNodes[1],
3031                                   aNodes[7], aNodes[4], centrNode );
3032         newElem2 = aMesh->AddFace(aNodes[3], aNodes[1], aNodes[2],
3033                                   centrNode, aNodes[5], aNodes[6] );
3034       }
3035       myLastCreatedElems.push_back(newElem1);
3036       myLastCreatedElems.push_back(newElem2);
3037       // put a new triangle on the same shape and add to the same groups
3038       if ( aShapeId )
3039       {
3040         aMesh->SetMeshElementOnShape( newElem1, aShapeId );
3041         aMesh->SetMeshElementOnShape( newElem2, aShapeId );
3042       }
3043       AddToSameGroups( newElem1, elem, aMesh );
3044       AddToSameGroups( newElem2, elem, aMesh );
3045       aMesh->RemoveElement( elem );
3046     }
3047   }
3048
3049   return true;
3050 }
3051
3052 //=======================================================================
3053 //function : getAngle
3054 //purpose  :
3055 //=======================================================================
3056
3057 double getAngle(const SMDS_MeshElement * tr1,
3058                 const SMDS_MeshElement * tr2,
3059                 const SMDS_MeshNode *    n1,
3060                 const SMDS_MeshNode *    n2)
3061 {
3062   double angle = 2. * M_PI; // bad angle
3063
3064   // get normals
3065   SMESH::Controls::TSequenceOfXYZ P1, P2;
3066   if ( !SMESH::Controls::NumericalFunctor::GetPoints( tr1, P1 ) ||
3067        !SMESH::Controls::NumericalFunctor::GetPoints( tr2, P2 ))
3068     return angle;
3069   gp_Vec N1,N2;
3070   if(!tr1->IsQuadratic())
3071     N1 = gp_Vec( P1(2) - P1(1) ) ^ gp_Vec( P1(3) - P1(1) );
3072   else
3073     N1 = gp_Vec( P1(3) - P1(1) ) ^ gp_Vec( P1(5) - P1(1) );
3074   if ( N1.SquareMagnitude() <= gp::Resolution() )
3075     return angle;
3076   if(!tr2->IsQuadratic())
3077     N2 = gp_Vec( P2(2) - P2(1) ) ^ gp_Vec( P2(3) - P2(1) );
3078   else
3079     N2 = gp_Vec( P2(3) - P2(1) ) ^ gp_Vec( P2(5) - P2(1) );
3080   if ( N2.SquareMagnitude() <= gp::Resolution() )
3081     return angle;
3082
3083   // find the first diagonal node n1 in the triangles:
3084   // take in account a diagonal link orientation
3085   const SMDS_MeshElement *nFirst[2], *tr[] = { tr1, tr2 };
3086   for ( int t = 0; t < 2; t++ ) {
3087     SMDS_ElemIteratorPtr it = tr[ t ]->nodesIterator();
3088     int i = 0, iDiag = -1;
3089     while ( it->more()) {
3090       const SMDS_MeshElement *n = it->next();
3091       if ( n == n1 || n == n2 ) {
3092         if ( iDiag < 0)
3093           iDiag = i;
3094         else {
3095           if ( i - iDiag == 1 )
3096             nFirst[ t ] = ( n == n1 ? n2 : n1 );
3097           else
3098             nFirst[ t ] = n;
3099           break;
3100         }
3101       }
3102       i++;
3103     }
3104   }
3105   if ( nFirst[ 0 ] == nFirst[ 1 ] )
3106     N2.Reverse();
3107
3108   angle = N1.Angle( N2 );
3109   //SCRUTE( angle );
3110   return angle;
3111 }
3112
3113 // =================================================
3114 // class generating a unique ID for a pair of nodes
3115 // and able to return nodes by that ID
3116 // =================================================
3117 class LinkID_Gen {
3118 public:
3119
3120   LinkID_Gen( const SMESHDS_Mesh* theMesh )
3121     :myMesh( theMesh ), myMaxID( theMesh->MaxNodeID() + 1)
3122   {}
3123
3124   smIdType GetLinkID (const SMDS_MeshNode * n1,
3125                   const SMDS_MeshNode * n2) const
3126   {
3127     return ( Min(FromIdType<int>(n1->GetID()),FromIdType<int>(n2->GetID())) * myMaxID + Max(FromIdType<int>(n1->GetID()),FromIdType<int>(n2->GetID())));
3128   }
3129
3130   bool GetNodes (const long             theLinkID,
3131                  const SMDS_MeshNode* & theNode1,
3132                  const SMDS_MeshNode* & theNode2) const
3133   {
3134     theNode1 = myMesh->FindNode( theLinkID / myMaxID );
3135     if ( !theNode1 ) return false;
3136     theNode2 = myMesh->FindNode( theLinkID % myMaxID );
3137     if ( !theNode2 ) return false;
3138     return true;
3139   }
3140
3141 private:
3142   LinkID_Gen();
3143   const SMESHDS_Mesh* myMesh;
3144   long                myMaxID;
3145 };
3146
3147
3148 //=======================================================================
3149 //function : TriToQuad
3150 //purpose  : Fuse neighbour triangles into quadrangles.
3151 //           theCrit is used to select a neighbour to fuse with.
3152 //           theMaxAngle is a max angle between element normals at which
3153 //           fusion is still performed.
3154 //=======================================================================
3155
3156 bool SMESH_MeshEditor::TriToQuad (TIDSortedElemSet &                   theElems,
3157                                   SMESH::Controls::NumericalFunctorPtr theCrit,
3158                                   const double                         theMaxAngle)
3159 {
3160   ClearLastCreated();
3161   myLastCreatedElems.reserve( theElems.size() / 2 );
3162
3163   if ( !theCrit.get() )
3164     return false;
3165
3166   SMESHDS_Mesh * aMesh = GetMeshDS();
3167
3168   // Prepare data for algo: build
3169   // 1. map of elements with their linkIDs
3170   // 2. map of linkIDs with their elements
3171
3172   map< SMESH_TLink, list< const SMDS_MeshElement* > > mapLi_listEl;
3173   map< SMESH_TLink, list< const SMDS_MeshElement* > >::iterator itLE;
3174   map< const SMDS_MeshElement*, set< SMESH_TLink > >  mapEl_setLi;
3175   map< const SMDS_MeshElement*, set< SMESH_TLink > >::iterator itEL;
3176
3177   TIDSortedElemSet::iterator itElem;
3178   for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ )
3179   {
3180     const SMDS_MeshElement* elem = *itElem;
3181     if(!elem || elem->GetType() != SMDSAbs_Face ) continue;
3182     bool IsTria = ( elem->NbCornerNodes()==3 );
3183     if (!IsTria) continue;
3184
3185     // retrieve element nodes
3186     const SMDS_MeshNode* aNodes [4];
3187     SMDS_NodeIteratorPtr itN = elem->nodeIterator();
3188     int i = 0;
3189     while ( i < 3 )
3190       aNodes[ i++ ] = itN->next();
3191     aNodes[ 3 ] = aNodes[ 0 ];
3192
3193     // fill maps
3194     for ( i = 0; i < 3; i++ ) {
3195       SMESH_TLink link( aNodes[i], aNodes[i+1] );
3196       // check if elements sharing a link can be fused
3197       itLE = mapLi_listEl.find( link );
3198       if ( itLE != mapLi_listEl.end() ) {
3199         if ((*itLE).second.size() > 1 ) // consider only 2 elems adjacent by a link
3200           continue;
3201         const SMDS_MeshElement* elem2 = (*itLE).second.front();
3202         //if ( FindShape( elem ) != FindShape( elem2 ))
3203         //  continue; // do not fuse triangles laying on different shapes
3204         if ( getAngle( elem, elem2, aNodes[i], aNodes[i+1] ) > theMaxAngle )
3205           continue; // avoid making badly shaped quads
3206         (*itLE).second.push_back( elem );
3207       }
3208       else {
3209         mapLi_listEl[ link ].push_back( elem );
3210       }
3211       mapEl_setLi [ elem ].insert( link );
3212     }
3213   }
3214   // Clean the maps from the links shared by a sole element, ie
3215   // links to which only one element is bound in mapLi_listEl
3216
3217   for ( itLE = mapLi_listEl.begin(); itLE != mapLi_listEl.end(); itLE++ ) {
3218     int nbElems = (*itLE).second.size();
3219     if ( nbElems < 2  ) {
3220       const SMDS_MeshElement* elem = (*itLE).second.front();
3221       SMESH_TLink link = (*itLE).first;
3222       mapEl_setLi[ elem ].erase( link );
3223       if ( mapEl_setLi[ elem ].empty() )
3224         mapEl_setLi.erase( elem );
3225     }
3226   }
3227
3228   // Algo: fuse triangles into quadrangles
3229
3230   while ( ! mapEl_setLi.empty() ) {
3231     // Look for the start element:
3232     // the element having the least nb of shared links
3233     const SMDS_MeshElement* startElem = 0;
3234     int minNbLinks = 4;
3235     for ( itEL = mapEl_setLi.begin(); itEL != mapEl_setLi.end(); itEL++ ) {
3236       int nbLinks = (*itEL).second.size();
3237       if ( nbLinks < minNbLinks ) {
3238         startElem = (*itEL).first;
3239         minNbLinks = nbLinks;
3240         if ( minNbLinks == 1 )
3241           break;
3242       }
3243     }
3244
3245     // search elements to fuse starting from startElem or links of elements
3246     // fused earlyer - startLinks
3247     list< SMESH_TLink > startLinks;
3248     while ( startElem || !startLinks.empty() ) {
3249       while ( !startElem && !startLinks.empty() ) {
3250         // Get an element to start, by a link
3251         SMESH_TLink linkId = startLinks.front();
3252         startLinks.pop_front();
3253         itLE = mapLi_listEl.find( linkId );
3254         if ( itLE != mapLi_listEl.end() ) {
3255           list< const SMDS_MeshElement* > & listElem = (*itLE).second;
3256           list< const SMDS_MeshElement* >::iterator itE = listElem.begin();
3257           for ( ; itE != listElem.end() ; itE++ )
3258             if ( mapEl_setLi.find( (*itE) ) != mapEl_setLi.end() )
3259               startElem = (*itE);
3260           mapLi_listEl.erase( itLE );
3261         }
3262       }
3263
3264       if ( startElem ) {
3265         // Get candidates to be fused
3266         const SMDS_MeshElement *tr1 = startElem, *tr2 = 0, *tr3 = 0;
3267         const SMESH_TLink *link12 = 0, *link13 = 0;
3268         startElem = 0;
3269         ASSERT( mapEl_setLi.find( tr1 ) != mapEl_setLi.end() );
3270         set< SMESH_TLink >& setLi = mapEl_setLi[ tr1 ];
3271         ASSERT( !setLi.empty() );
3272         set< SMESH_TLink >::iterator itLi;
3273         for ( itLi = setLi.begin(); itLi != setLi.end(); itLi++ )
3274         {
3275           const SMESH_TLink & link = (*itLi);
3276           itLE = mapLi_listEl.find( link );
3277           if ( itLE == mapLi_listEl.end() )
3278             continue;
3279
3280           const SMDS_MeshElement* elem = (*itLE).second.front();
3281           if ( elem == tr1 )
3282             elem = (*itLE).second.back();
3283           mapLi_listEl.erase( itLE );
3284           if ( mapEl_setLi.find( elem ) == mapEl_setLi.end())
3285             continue;
3286           if ( tr2 ) {
3287             tr3 = elem;
3288             link13 = &link;
3289           }
3290           else {
3291             tr2 = elem;
3292             link12 = &link;
3293           }
3294
3295           // add other links of elem to list of links to re-start from
3296           set< SMESH_TLink >& links = mapEl_setLi[ elem ];
3297           set< SMESH_TLink >::iterator it;
3298           for ( it = links.begin(); it != links.end(); it++ ) {
3299             const SMESH_TLink& link2 = (*it);
3300             if ( link2 != link )
3301               startLinks.push_back( link2 );
3302           }
3303         }
3304
3305         // Get nodes of possible quadrangles
3306         const SMDS_MeshNode *n12 [4], *n13 [4];
3307         bool Ok12 = false, Ok13 = false;
3308         const SMDS_MeshNode *linkNode1, *linkNode2;
3309         if(tr2) {
3310           linkNode1 = link12->first;
3311           linkNode2 = link12->second;
3312           if ( tr2 && getQuadrangleNodes( n12, linkNode1, linkNode2, tr1, tr2 ))
3313             Ok12 = true;
3314         }
3315         if(tr3) {
3316           linkNode1 = link13->first;
3317           linkNode2 = link13->second;
3318           if ( tr3 && getQuadrangleNodes( n13, linkNode1, linkNode2, tr1, tr3 ))
3319             Ok13 = true;
3320         }
3321
3322         // Choose a pair to fuse
3323         if ( Ok12 && Ok13 ) {
3324           SMDS_FaceOfNodes quad12 ( n12[ 0 ], n12[ 1 ], n12[ 2 ], n12[ 3 ] );
3325           SMDS_FaceOfNodes quad13 ( n13[ 0 ], n13[ 1 ], n13[ 2 ], n13[ 3 ] );
3326           double aBadRate12 = getBadRate( &quad12, theCrit );
3327           double aBadRate13 = getBadRate( &quad13, theCrit );
3328           if (  aBadRate13 < aBadRate12 )
3329             Ok12 = false;
3330           else
3331             Ok13 = false;
3332         }
3333
3334         // Make quadrangles
3335         // and remove fused elems and remove links from the maps
3336         mapEl_setLi.erase( tr1 );
3337         if ( Ok12 )
3338         {
3339           mapEl_setLi.erase( tr2 );
3340           mapLi_listEl.erase( *link12 );
3341           if ( tr1->NbNodes() == 3 )
3342           {
3343             const SMDS_MeshElement* newElem = 0;
3344             newElem = aMesh->AddFace(n12[0], n12[1], n12[2], n12[3] );
3345             myLastCreatedElems.push_back(newElem);
3346             AddToSameGroups( newElem, tr1, aMesh );
3347             int aShapeId = tr1->getshapeId();
3348             if ( aShapeId )
3349               aMesh->SetMeshElementOnShape( newElem, aShapeId );
3350             aMesh->RemoveElement( tr1 );
3351             aMesh->RemoveElement( tr2 );
3352           }
3353           else {
3354             vector< const SMDS_MeshNode* > N1;
3355             vector< const SMDS_MeshNode* > N2;
3356             getNodesFromTwoTria(tr1,tr2,N1,N2);
3357             // now we receive following N1 and N2 (using numeration as in image in InverseDiag())
3358             // tria1 : (1 2 4 5 9 7)  and  tria2 : (3 4 2 8 9 6)
3359             // i.e. first nodes from both arrays form a new diagonal
3360             const SMDS_MeshNode* aNodes[8];
3361             aNodes[0] = N1[0];
3362             aNodes[1] = N1[1];
3363             aNodes[2] = N2[0];
3364             aNodes[3] = N2[1];
3365             aNodes[4] = N1[3];
3366             aNodes[5] = N2[5];
3367             aNodes[6] = N2[3];
3368             aNodes[7] = N1[5];
3369             const SMDS_MeshElement* newElem = 0;
3370             if ( N1.size() == 7 || N2.size() == 7 ) // biquadratic
3371               newElem = aMesh->AddFace(aNodes[0], aNodes[1], aNodes[2], aNodes[3],
3372                                        aNodes[4], aNodes[5], aNodes[6], aNodes[7], N1[4]);
3373             else
3374               newElem = aMesh->AddFace(aNodes[0], aNodes[1], aNodes[2], aNodes[3],
3375                                        aNodes[4], aNodes[5], aNodes[6], aNodes[7]);
3376             myLastCreatedElems.push_back(newElem);
3377             AddToSameGroups( newElem, tr1, aMesh );
3378             int aShapeId = tr1->getshapeId();
3379             if ( aShapeId )
3380               aMesh->SetMeshElementOnShape( newElem, aShapeId );
3381             aMesh->RemoveElement( tr1 );
3382             aMesh->RemoveElement( tr2 );
3383             // remove middle node (9)
3384             if ( N1[4]->NbInverseElements() == 0 )
3385               aMesh->RemoveNode( N1[4] );
3386             if ( N1.size() == 7 && N1[6]->NbInverseElements() == 0 )
3387               aMesh->RemoveNode( N1[6] );
3388             if ( N2.size() == 7 && N2[6]->NbInverseElements() == 0 )
3389               aMesh->RemoveNode( N2[6] );
3390           }
3391         }
3392         else if ( Ok13 )
3393         {
3394           mapEl_setLi.erase( tr3 );
3395           mapLi_listEl.erase( *link13 );
3396           if ( tr1->NbNodes() == 3 ) {
3397             const SMDS_MeshElement* newElem = 0;
3398             newElem = aMesh->AddFace(n13[0], n13[1], n13[2], n13[3] );
3399             myLastCreatedElems.push_back(newElem);
3400             AddToSameGroups( newElem, tr1, aMesh );
3401             int aShapeId = tr1->getshapeId();
3402             if ( aShapeId )
3403               aMesh->SetMeshElementOnShape( newElem, aShapeId );
3404             aMesh->RemoveElement( tr1 );
3405             aMesh->RemoveElement( tr3 );
3406           }
3407           else {
3408             vector< const SMDS_MeshNode* > N1;
3409             vector< const SMDS_MeshNode* > N2;
3410             getNodesFromTwoTria(tr1,tr3,N1,N2);
3411             // now we receive following N1 and N2 (using numeration as above image)
3412             // tria1 : (1 2 4 5 9 7)  and  tria2 : (3 4 2 8 9 6)
3413             // i.e. first nodes from both arrays form a new diagonal
3414             const SMDS_MeshNode* aNodes[8];
3415             aNodes[0] = N1[0];
3416             aNodes[1] = N1[1];
3417             aNodes[2] = N2[0];
3418             aNodes[3] = N2[1];
3419             aNodes[4] = N1[3];
3420             aNodes[5] = N2[5];
3421             aNodes[6] = N2[3];
3422             aNodes[7] = N1[5];
3423             const SMDS_MeshElement* newElem = 0;
3424             if ( N1.size() == 7 || N2.size() == 7 ) // biquadratic
3425               newElem = aMesh->AddFace(aNodes[0], aNodes[1], aNodes[2], aNodes[3],
3426                                        aNodes[4], aNodes[5], aNodes[6], aNodes[7], N1[4]);
3427             else
3428               newElem = aMesh->AddFace(aNodes[0], aNodes[1], aNodes[2], aNodes[3],
3429                                        aNodes[4], aNodes[5], aNodes[6], aNodes[7]);
3430             myLastCreatedElems.push_back(newElem);
3431             AddToSameGroups( newElem, tr1, aMesh );
3432             int aShapeId = tr1->getshapeId();
3433             if ( aShapeId )
3434               aMesh->SetMeshElementOnShape( newElem, aShapeId );
3435             aMesh->RemoveElement( tr1 );
3436             aMesh->RemoveElement( tr3 );
3437             // remove middle node (9)
3438             if ( N1[4]->NbInverseElements() == 0 )
3439               aMesh->RemoveNode( N1[4] );
3440             if ( N1.size() == 7 && N1[6]->NbInverseElements() == 0 )
3441               aMesh->RemoveNode( N1[6] );
3442             if ( N2.size() == 7 && N2[6]->NbInverseElements() == 0 )
3443               aMesh->RemoveNode( N2[6] );
3444           }
3445         }
3446
3447         // Next element to fuse: the rejected one
3448         if ( tr3 )
3449           startElem = Ok12 ? tr3 : tr2;
3450
3451       } // if ( startElem )
3452     } // while ( startElem || !startLinks.empty() )
3453   } // while ( ! mapEl_setLi.empty() )
3454
3455   return true;
3456 }
3457
3458 //================================================================================
3459 /*!
3460  * \brief Return nodes linked to the given one
3461  * \param theNode - the node
3462  * \param linkedNodes - the found nodes
3463  * \param type - the type of elements to check
3464  *
3465  * Medium nodes are ignored
3466  */
3467 //================================================================================
3468
3469 void SMESH_MeshEditor::GetLinkedNodes( const SMDS_MeshNode* theNode,
3470                                        TIDSortedElemSet &   linkedNodes,
3471                                        SMDSAbs_ElementType  type )
3472 {
3473   SMDS_ElemIteratorPtr elemIt = theNode->GetInverseElementIterator(type);
3474   while ( elemIt->more() )
3475   {
3476     const SMDS_MeshElement* elem = elemIt->next();
3477     if(elem->GetType() == SMDSAbs_0DElement)
3478       continue;
3479
3480     SMDS_ElemIteratorPtr nodeIt = elem->nodesIterator();
3481     if ( elem->GetType() == SMDSAbs_Volume )
3482     {
3483       SMDS_VolumeTool vol( elem );
3484       while ( nodeIt->more() ) {
3485         const SMDS_MeshNode* n = cast2Node( nodeIt->next() );
3486         if ( theNode != n && vol.IsLinked( theNode, n ))
3487           linkedNodes.insert( n );
3488       }
3489     }
3490     else
3491     {
3492       for ( int i = 0; nodeIt->more(); ++i ) {
3493         const SMDS_MeshNode* n = cast2Node( nodeIt->next() );
3494         if ( n == theNode ) {
3495           int iBefore = i - 1;
3496           int iAfter  = i + 1;
3497           if ( elem->IsQuadratic() ) {
3498             int nb = elem->NbNodes() / 2;
3499             iAfter  = SMESH_MesherHelper::WrapIndex( iAfter, nb );
3500             iBefore = SMESH_MesherHelper::WrapIndex( iBefore, nb );
3501           }
3502           linkedNodes.insert( elem->GetNodeWrap( iAfter ));
3503           linkedNodes.insert( elem->GetNodeWrap( iBefore ));
3504         }
3505       }
3506     }
3507   }
3508 }
3509
3510 //=======================================================================
3511 //function : laplacianSmooth
3512 //purpose  : pulls theNode toward the center of surrounding nodes directly
3513 //           connected to that node along an element edge
3514 //=======================================================================
3515
3516 void laplacianSmooth(const SMDS_MeshNode*                 theNode,
3517                      const Handle(Geom_Surface)&          theSurface,
3518                      map< const SMDS_MeshNode*, gp_XY* >& theUVMap)
3519 {
3520   // find surrounding nodes
3521
3522   TIDSortedElemSet nodeSet;
3523   SMESH_MeshEditor::GetLinkedNodes( theNode, nodeSet, SMDSAbs_Face );
3524
3525   // compute new coodrs
3526
3527   double coord[] = { 0., 0., 0. };
3528   TIDSortedElemSet::iterator nodeSetIt = nodeSet.begin();
3529   for ( ; nodeSetIt != nodeSet.end(); nodeSetIt++ ) {
3530     const SMDS_MeshNode* node = cast2Node(*nodeSetIt);
3531     if ( theSurface.IsNull() ) { // smooth in 3D
3532       coord[0] += node->X();
3533       coord[1] += node->Y();
3534       coord[2] += node->Z();
3535     }
3536     else { // smooth in 2D
3537       ASSERT( theUVMap.find( node ) != theUVMap.end() );
3538       gp_XY* uv = theUVMap[ node ];
3539       coord[0] += uv->X();
3540       coord[1] += uv->Y();
3541     }
3542   }
3543   int nbNodes = nodeSet.size();
3544   if ( !nbNodes )
3545     return;
3546   coord[0] /= nbNodes;
3547   coord[1] /= nbNodes;
3548
3549   if ( !theSurface.IsNull() ) {
3550     ASSERT( theUVMap.find( theNode ) != theUVMap.end() );
3551     theUVMap[ theNode ]->SetCoord( coord[0], coord[1] );
3552     gp_Pnt p3d = theSurface->Value( coord[0], coord[1] );
3553     coord[0] = p3d.X();
3554     coord[1] = p3d.Y();
3555     coord[2] = p3d.Z();
3556   }
3557   else
3558     coord[2] /= nbNodes;
3559
3560   // move node
3561
3562   const_cast< SMDS_MeshNode* >( theNode )->setXYZ(coord[0],coord[1],coord[2]);
3563 }
3564
3565 //=======================================================================
3566 //function : centroidalSmooth
3567 //purpose  : pulls theNode toward the element-area-weighted centroid of the
3568 //           surrounding elements
3569 //=======================================================================
3570
3571 void centroidalSmooth(const SMDS_MeshNode*                 theNode,
3572                       const Handle(Geom_Surface)&          theSurface,
3573                       map< const SMDS_MeshNode*, gp_XY* >& theUVMap)
3574 {
3575   gp_XYZ aNewXYZ(0.,0.,0.);
3576   SMESH::Controls::Area anAreaFunc;
3577   double totalArea = 0.;
3578   int nbElems = 0;
3579
3580   // compute new XYZ
3581
3582   SMDS_ElemIteratorPtr elemIt = theNode->GetInverseElementIterator(SMDSAbs_Face);
3583   while ( elemIt->more() )
3584   {
3585     const SMDS_MeshElement* elem = elemIt->next();
3586     nbElems++;
3587
3588     gp_XYZ elemCenter(0.,0.,0.);
3589     SMESH::Controls::TSequenceOfXYZ aNodePoints;
3590     SMDS_ElemIteratorPtr itN = elem->nodesIterator();
3591     int nn = elem->NbNodes();
3592     if(elem->IsQuadratic()) nn = nn/2;
3593     int i=0;
3594     //while ( itN->more() ) {
3595     while ( i<nn ) {
3596       const SMDS_MeshNode* aNode = static_cast<const SMDS_MeshNode*>( itN->next() );
3597       i++;
3598       gp_XYZ aP( aNode->X(), aNode->Y(), aNode->Z() );
3599       aNodePoints.push_back( aP );
3600       if ( !theSurface.IsNull() ) { // smooth in 2D
3601         ASSERT( theUVMap.find( aNode ) != theUVMap.end() );
3602         gp_XY* uv = theUVMap[ aNode ];
3603         aP.SetCoord( uv->X(), uv->Y(), 0. );
3604       }
3605       elemCenter += aP;
3606     }
3607     double elemArea = anAreaFunc.GetValue( aNodePoints );
3608     totalArea += elemArea;
3609     elemCenter /= nn;
3610     aNewXYZ += elemCenter * elemArea;
3611   }
3612   aNewXYZ /= totalArea;
3613   if ( !theSurface.IsNull() ) {
3614     theUVMap[ theNode ]->SetCoord( aNewXYZ.X(), aNewXYZ.Y() );
3615     aNewXYZ = theSurface->Value( aNewXYZ.X(), aNewXYZ.Y() ).XYZ();
3616   }
3617
3618   // move node
3619
3620   const_cast< SMDS_MeshNode* >( theNode )->setXYZ(aNewXYZ.X(),aNewXYZ.Y(),aNewXYZ.Z());
3621 }
3622
3623 //=======================================================================
3624 //function : getClosestUV
3625 //purpose  : return UV of closest projection
3626 //=======================================================================
3627
3628 static bool getClosestUV (Extrema_GenExtPS& projector,
3629                           const gp_Pnt&     point,
3630                           gp_XY &           result)
3631 {
3632   projector.Perform( point );
3633   if ( projector.IsDone() ) {
3634     double u = 0, v = 0, minVal = DBL_MAX;
3635     for ( int i = projector.NbExt(); i > 0; i-- )
3636       if ( projector.SquareDistance( i ) < minVal ) {
3637         minVal = projector.SquareDistance( i );
3638         projector.Point( i ).Parameter( u, v );
3639       }
3640     result.SetCoord( u, v );
3641     return true;
3642   }
3643   return false;
3644 }
3645
3646 //=======================================================================
3647 //function : Smooth
3648 //purpose  : Smooth theElements during theNbIterations or until a worst
3649 //           element has aspect ratio <= theTgtAspectRatio.
3650 //           Aspect Ratio varies in range [1.0, inf].
3651 //           If theElements is empty, the whole mesh is smoothed.
3652 //           theFixedNodes contains additionally fixed nodes. Nodes built
3653 //           on edges and boundary nodes are always fixed.
3654 //=======================================================================
3655
3656 void SMESH_MeshEditor::Smooth (TIDSortedElemSet &          theElems,
3657                                set<const SMDS_MeshNode*> & theFixedNodes,
3658                                const SmoothMethod          theSmoothMethod,
3659                                const int                   theNbIterations,
3660                                double                      theTgtAspectRatio,
3661                                const bool                  the2D)
3662 {
3663   ClearLastCreated();
3664
3665   if ( theTgtAspectRatio < 1.0 )
3666     theTgtAspectRatio = 1.0;
3667
3668   const double disttol = 1.e-16;
3669
3670   SMESH::Controls::AspectRatio aQualityFunc;
3671
3672   SMESHDS_Mesh* aMesh = GetMeshDS();
3673
3674   if ( theElems.empty() ) {
3675     // add all faces to theElems
3676     SMDS_FaceIteratorPtr fIt = aMesh->facesIterator();
3677     while ( fIt->more() ) {
3678       const SMDS_MeshElement* face = fIt->next();
3679       theElems.insert( theElems.end(), face );
3680     }
3681   }
3682   // get all face ids theElems are on
3683   set< int > faceIdSet;
3684   TIDSortedElemSet::iterator itElem;
3685   if ( the2D )
3686     for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
3687       int fId = FindShape( *itElem );
3688       // check that corresponding submesh exists and a shape is face
3689       if (fId &&
3690           faceIdSet.find( fId ) == faceIdSet.end() &&
3691           aMesh->MeshElements( fId )) {
3692         TopoDS_Shape F = aMesh->IndexToShape( fId );
3693         if ( !F.IsNull() && F.ShapeType() == TopAbs_FACE )
3694           faceIdSet.insert( fId );
3695       }
3696     }
3697   faceIdSet.insert( 0 ); // to smooth elements that are not on any TopoDS_Face
3698
3699   // ===============================================
3700   // smooth elements on each TopoDS_Face separately
3701   // ===============================================
3702
3703   SMESH_MesherHelper helper( *GetMesh() );
3704
3705   set< int >::reverse_iterator fId = faceIdSet.rbegin(); // treat 0 fId at the end
3706   for ( ; fId != faceIdSet.rend(); ++fId )
3707   {
3708     // get face surface and submesh
3709     Handle(Geom_Surface) surface;
3710     SMESHDS_SubMesh* faceSubMesh = 0;
3711     TopoDS_Face face;
3712     double fToler2 = 0;
3713     double u1 = 0, u2 = 0, v1 = 0, v2 = 0;
3714     bool isUPeriodic = false, isVPeriodic = false;
3715     if ( *fId )
3716     {
3717       face = TopoDS::Face( aMesh->IndexToShape( *fId ));
3718       surface = BRep_Tool::Surface( face );
3719       faceSubMesh = aMesh->MeshElements( *fId );
3720       fToler2 = BRep_Tool::Tolerance( face );
3721       fToler2 *= fToler2 * 10.;
3722       isUPeriodic = surface->IsUPeriodic();
3723       // if ( isUPeriodic )
3724       //   surface->UPeriod();
3725       isVPeriodic = surface->IsVPeriodic();
3726       // if ( isVPeriodic )
3727       //   surface->VPeriod();
3728       surface->Bounds( u1, u2, v1, v2 );
3729       helper.SetSubShape( face );
3730     }
3731     // ---------------------------------------------------------
3732     // for elements on a face, find movable and fixed nodes and
3733     // compute UV for them
3734     // ---------------------------------------------------------
3735     bool checkBoundaryNodes = false;
3736     bool isQuadratic = false;
3737     set<const SMDS_MeshNode*> setMovableNodes;
3738     map< const SMDS_MeshNode*, gp_XY* > uvMap, uvMap2;
3739     list< gp_XY > listUV; // uvs the 2 uvMaps refer to
3740     list< const SMDS_MeshElement* > elemsOnFace;
3741
3742     Extrema_GenExtPS projector;
3743     GeomAdaptor_Surface surfAdaptor;
3744     if ( !surface.IsNull() ) {
3745       surfAdaptor.Load( surface );
3746       projector.Initialize( surfAdaptor, 20,20, 1e-5,1e-5 );
3747     }
3748     int nbElemOnFace = 0;
3749     itElem = theElems.begin();
3750     // loop on not yet smoothed elements: look for elems on a face
3751     while ( itElem != theElems.end() )
3752     {
3753       if ( faceSubMesh && nbElemOnFace == faceSubMesh->NbElements() )
3754         break; // all elements found
3755
3756       const SMDS_MeshElement* elem = *itElem;
3757       if ( !elem || elem->GetType() != SMDSAbs_Face || elem->NbNodes() < 3 ||
3758            ( faceSubMesh && !faceSubMesh->Contains( elem ))) {
3759         ++itElem;
3760         continue;
3761       }
3762       elemsOnFace.push_back( elem );
3763       theElems.erase( itElem++ );
3764       nbElemOnFace++;
3765
3766       if ( !isQuadratic )
3767         isQuadratic = elem->IsQuadratic();
3768
3769       // get movable nodes of elem
3770       const SMDS_MeshNode* node;
3771       SMDS_TypeOfPosition posType;
3772       SMDS_ElemIteratorPtr itN = elem->nodesIterator();
3773       int nn = 0, nbn =  elem->NbNodes();
3774       if(elem->IsQuadratic())
3775         nbn = nbn/2;
3776       while ( nn++ < nbn ) {
3777         node = static_cast<const SMDS_MeshNode*>( itN->next() );
3778         const SMDS_PositionPtr& pos = node->GetPosition();
3779         posType = pos ? pos->GetTypeOfPosition() : SMDS_TOP_3DSPACE;
3780         if (posType != SMDS_TOP_EDGE &&
3781             posType != SMDS_TOP_VERTEX &&
3782             theFixedNodes.find( node ) == theFixedNodes.end())
3783         {
3784           // check if all faces around the node are on faceSubMesh
3785           // because a node on edge may be bound to face
3786           bool all = true;
3787           if ( faceSubMesh ) {
3788             SMDS_ElemIteratorPtr eIt = node->GetInverseElementIterator(SMDSAbs_Face);
3789             while ( eIt->more() && all ) {
3790               const SMDS_MeshElement* e = eIt->next();
3791               all = faceSubMesh->Contains( e );
3792             }
3793           }
3794           if ( all )
3795             setMovableNodes.insert( node );
3796           else
3797             checkBoundaryNodes = true;
3798         }
3799         if ( posType == SMDS_TOP_3DSPACE )
3800           checkBoundaryNodes = true;
3801       }
3802
3803       if ( surface.IsNull() )
3804         continue;
3805
3806       // get nodes to check UV
3807       list< const SMDS_MeshNode* > uvCheckNodes;
3808       const SMDS_MeshNode* nodeInFace = 0;
3809       itN = elem->nodesIterator();
3810       nn = 0; nbn =  elem->NbNodes();
3811       if(elem->IsQuadratic())
3812         nbn = nbn/2;
3813       while ( nn++ < nbn ) {
3814         node = static_cast<const SMDS_MeshNode*>( itN->next() );
3815         if ( node->GetPosition()->GetDim() == 2 )
3816           nodeInFace = node;
3817         if ( uvMap.find( node ) == uvMap.end() )
3818           uvCheckNodes.push_back( node );
3819         // add nodes of elems sharing node
3820         //         SMDS_ElemIteratorPtr eIt = node->GetInverseElementIterator(SMDSAbs_Face);
3821         //         while ( eIt->more() ) {
3822         //           const SMDS_MeshElement* e = eIt->next();
3823         //           if ( e != elem ) {
3824         //             SMDS_ElemIteratorPtr nIt = e->nodesIterator();
3825         //             while ( nIt->more() ) {
3826         //               const SMDS_MeshNode* n =
3827         //                 static_cast<const SMDS_MeshNode*>( nIt->next() );
3828         //               if ( uvMap.find( n ) == uvMap.end() )
3829         //                 uvCheckNodes.push_back( n );
3830         //             }
3831         //           }
3832         //         }
3833       }
3834       // check UV on face
3835       list< const SMDS_MeshNode* >::iterator n = uvCheckNodes.begin();
3836       for ( ; n != uvCheckNodes.end(); ++n ) {
3837         node = *n;
3838         gp_XY uv( 0, 0 );
3839         const SMDS_PositionPtr& pos = node->GetPosition();
3840         posType = pos ? pos->GetTypeOfPosition() : SMDS_TOP_3DSPACE;
3841         // get existing UV
3842         if ( pos )
3843         {
3844           bool toCheck = true;
3845           uv = helper.GetNodeUV( face, node, nodeInFace, &toCheck );
3846         }
3847         // compute not existing UV
3848         bool project = ( posType == SMDS_TOP_3DSPACE );
3849         // double dist1 = DBL_MAX, dist2 = 0;
3850         // if ( posType != SMDS_TOP_3DSPACE ) {
3851         //   dist1 = pNode.SquareDistance( surface->Value( uv.X(), uv.Y() ));
3852         //   project = dist1 > fToler2;
3853         // }
3854         if ( project ) { // compute new UV
3855           gp_XY newUV;
3856           gp_Pnt pNode = SMESH_NodeXYZ( node );
3857           if ( !getClosestUV( projector, pNode, newUV )) {
3858             MESSAGE("Node Projection Failed " << node);
3859           }
3860           else {
3861             if ( isUPeriodic )
3862               newUV.SetX( ElCLib::InPeriod( newUV.X(), u1, u2 ));
3863             if ( isVPeriodic )
3864               newUV.SetY( ElCLib::InPeriod( newUV.Y(), v1, v2 ));
3865             // check new UV
3866             // if ( posType != SMDS_TOP_3DSPACE )
3867             //   dist2 = pNode.SquareDistance( surface->Value( newUV.X(), newUV.Y() ));
3868             // if ( dist2 < dist1 )
3869             uv = newUV;
3870           }
3871         }
3872         // store UV in the map
3873         listUV.push_back( uv );
3874         uvMap.insert( make_pair( node, &listUV.back() ));
3875       }
3876     } // loop on not yet smoothed elements
3877
3878     if ( !faceSubMesh || nbElemOnFace != faceSubMesh->NbElements() )
3879       checkBoundaryNodes = true;
3880
3881     // fix nodes on mesh boundary
3882
3883     if ( checkBoundaryNodes ) {
3884       map< SMESH_TLink, int > linkNbMap; // how many times a link encounters in elemsOnFace
3885       map< SMESH_TLink, int >::iterator link_nb;
3886       // put all elements links to linkNbMap
3887       list< const SMDS_MeshElement* >::iterator elemIt = elemsOnFace.begin();
3888       for ( ; elemIt != elemsOnFace.end(); ++elemIt ) {
3889         const SMDS_MeshElement* elem = (*elemIt);
3890         int nbn =  elem->NbCornerNodes();
3891         // loop on elem links: insert them in linkNbMap
3892         for ( int iN = 0; iN < nbn; ++iN ) {
3893           const SMDS_MeshNode* n1 = elem->GetNode( iN );
3894           const SMDS_MeshNode* n2 = elem->GetNode(( iN+1 ) % nbn);
3895           SMESH_TLink link( n1, n2 );
3896           link_nb = linkNbMap.insert( make_pair( link, 0 )).first;
3897           link_nb->second++;
3898         }
3899       }
3900       // remove nodes that are in links encountered only once from setMovableNodes
3901       for ( link_nb = linkNbMap.begin(); link_nb != linkNbMap.end(); ++link_nb ) {
3902         if ( link_nb->second == 1 ) {
3903           setMovableNodes.erase( link_nb->first.node1() );
3904           setMovableNodes.erase( link_nb->first.node2() );
3905         }
3906       }
3907     }
3908
3909     // -----------------------------------------------------
3910     // for nodes on seam edge, compute one more UV ( uvMap2 );
3911     // find movable nodes linked to nodes on seam and which
3912     // are to be smoothed using the second UV ( uvMap2 )
3913     // -----------------------------------------------------
3914
3915     set<const SMDS_MeshNode*> nodesNearSeam; // to smooth using uvMap2
3916     if ( !surface.IsNull() ) {
3917       TopExp_Explorer eExp( face, TopAbs_EDGE );
3918       for ( ; eExp.More(); eExp.Next() ) {
3919         TopoDS_Edge edge = TopoDS::Edge( eExp.Current() );
3920         if ( !BRep_Tool::IsClosed( edge, face ))
3921           continue;
3922         SMESHDS_SubMesh* sm = aMesh->MeshElements( edge );
3923         if ( !sm ) continue;
3924         // find out which parameter varies for a node on seam
3925         double f,l;
3926         gp_Pnt2d uv1, uv2;
3927         Handle(Geom2d_Curve) pcurve = BRep_Tool::CurveOnSurface( edge, face, f, l );
3928         if ( pcurve.IsNull() ) continue;
3929         uv1 = pcurve->Value( f );
3930         edge.Reverse();
3931         pcurve = BRep_Tool::CurveOnSurface( edge, face, f, l );
3932         if ( pcurve.IsNull() ) continue;
3933         uv2 = pcurve->Value( f );
3934         int iPar = Abs( uv1.X() - uv2.X() ) > Abs( uv1.Y() - uv2.Y() ) ? 1 : 2;
3935         // assure uv1 < uv2
3936         if ( uv1.Coord( iPar ) > uv2.Coord( iPar ))
3937           std::swap( uv1, uv2 );
3938         // get nodes on seam and its vertices
3939         list< const SMDS_MeshNode* > seamNodes;
3940         SMDS_NodeIteratorPtr nSeamIt = sm->GetNodes();
3941         while ( nSeamIt->more() ) {
3942           const SMDS_MeshNode* node = nSeamIt->next();
3943           if ( !isQuadratic || !IsMedium( node ))
3944             seamNodes.push_back( node );
3945         }
3946         TopExp_Explorer vExp( edge, TopAbs_VERTEX );
3947         for ( ; vExp.More(); vExp.Next() ) {
3948           sm = aMesh->MeshElements( vExp.Current() );
3949           if ( sm ) {
3950             nSeamIt = sm->GetNodes();
3951             while ( nSeamIt->more() )
3952               seamNodes.push_back( nSeamIt->next() );
3953           }
3954         }
3955         // loop on nodes on seam
3956         list< const SMDS_MeshNode* >::iterator noSeIt = seamNodes.begin();
3957         for ( ; noSeIt != seamNodes.end(); ++noSeIt ) {
3958           const SMDS_MeshNode* nSeam = *noSeIt;
3959           map< const SMDS_MeshNode*, gp_XY* >::iterator n_uv = uvMap.find( nSeam );
3960           if ( n_uv == uvMap.end() )
3961             continue;
3962           // set the first UV
3963           n_uv->second->SetCoord( iPar, uv1.Coord( iPar ));
3964           // set the second UV
3965           listUV.push_back( *n_uv->second );
3966           listUV.back().SetCoord( iPar, uv2.Coord( iPar ));
3967           if ( uvMap2.empty() )
3968             uvMap2 = uvMap; // copy the uvMap contents
3969           uvMap2[ nSeam ] = &listUV.back();
3970
3971           // collect movable nodes linked to ones on seam in nodesNearSeam
3972           SMDS_ElemIteratorPtr eIt = nSeam->GetInverseElementIterator(SMDSAbs_Face);
3973           while ( eIt->more() ) {
3974             const SMDS_MeshElement* e = eIt->next();
3975             int nbUseMap1 = 0, nbUseMap2 = 0;
3976             SMDS_ElemIteratorPtr nIt = e->nodesIterator();
3977             int nn = 0, nbn =  e->NbNodes();
3978             if(e->IsQuadratic()) nbn = nbn/2;
3979             while ( nn++ < nbn )
3980             {
3981               const SMDS_MeshNode* n =
3982                 static_cast<const SMDS_MeshNode*>( nIt->next() );
3983               if (n == nSeam ||
3984                   setMovableNodes.find( n ) == setMovableNodes.end() )
3985                 continue;
3986               // add only nodes being closer to uv2 than to uv1
3987               // gp_Pnt pMid (0.5 * ( n->X() + nSeam->X() ),
3988               //              0.5 * ( n->Y() + nSeam->Y() ),
3989               //              0.5 * ( n->Z() + nSeam->Z() ));
3990               // gp_XY uv;
3991               // getClosestUV( projector, pMid, uv );
3992               double x = uvMap[ n ]->Coord( iPar );
3993               if ( Abs( uv1.Coord( iPar ) - x ) >
3994                    Abs( uv2.Coord( iPar ) - x )) {
3995                 nodesNearSeam.insert( n );
3996                 nbUseMap2++;
3997               }
3998               else
3999                 nbUseMap1++;
4000             }
4001             // for centroidalSmooth all element nodes must
4002             // be on one side of a seam
4003             if ( theSmoothMethod == CENTROIDAL && nbUseMap1 && nbUseMap2 ) {
4004               SMDS_ElemIteratorPtr nIt = e->nodesIterator();
4005               nn = 0;
4006               while ( nn++ < nbn ) {
4007                 const SMDS_MeshNode* n =
4008                   static_cast<const SMDS_MeshNode*>( nIt->next() );
4009                 setMovableNodes.erase( n );
4010               }
4011             }
4012           }
4013         } // loop on nodes on seam
4014       } // loop on edge of a face
4015     } // if ( !face.IsNull() )
4016
4017     if ( setMovableNodes.empty() ) {
4018       MESSAGE( "Face id : " << *fId << " - NO SMOOTHING: no nodes to move!!!");
4019       continue; // goto next face
4020     }
4021
4022     // -------------
4023     // SMOOTHING //
4024     // -------------
4025
4026     int it = -1;
4027     double maxRatio = -1., maxDisplacement = -1.;
4028     set<const SMDS_MeshNode*>::iterator nodeToMove;
4029     for ( it = 0; it < theNbIterations; it++ ) {
4030       maxDisplacement = 0.;
4031       nodeToMove = setMovableNodes.begin();
4032       for ( ; nodeToMove != setMovableNodes.end(); nodeToMove++ ) {
4033         const SMDS_MeshNode* node = (*nodeToMove);
4034         gp_XYZ aPrevPos ( node->X(), node->Y(), node->Z() );
4035
4036         // smooth
4037         bool map2 = ( nodesNearSeam.find( node ) != nodesNearSeam.end() );
4038         if ( theSmoothMethod == LAPLACIAN )
4039           laplacianSmooth( node, surface, map2 ? uvMap2 : uvMap );
4040         else
4041           centroidalSmooth( node, surface, map2 ? uvMap2 : uvMap );
4042
4043         // node displacement
4044         gp_XYZ aNewPos ( node->X(), node->Y(), node->Z() );
4045         Standard_Real aDispl = (aPrevPos - aNewPos).SquareModulus();
4046         if ( aDispl > maxDisplacement )
4047           maxDisplacement = aDispl;
4048       }
4049       // no node movement => exit
4050       //if ( maxDisplacement < 1.e-16 ) {
4051       if ( maxDisplacement < disttol ) {
4052         MESSAGE("-- no node movement --");
4053         break;
4054       }
4055
4056       // check elements quality
4057       maxRatio  = 0;
4058       list< const SMDS_MeshElement* >::iterator elemIt = elemsOnFace.begin();
4059       for ( ; elemIt != elemsOnFace.end(); ++elemIt ) {
4060         const SMDS_MeshElement* elem = (*elemIt);
4061         if ( !elem || elem->GetType() != SMDSAbs_Face )
4062           continue;
4063         SMESH::Controls::TSequenceOfXYZ aPoints;
4064         if ( aQualityFunc.GetPoints( elem, aPoints )) {
4065           double aValue = aQualityFunc.GetValue( aPoints );
4066           if ( aValue > maxRatio )
4067             maxRatio = aValue;
4068         }
4069       }
4070       if ( maxRatio <= theTgtAspectRatio ) {
4071         //MESSAGE("-- quality achieved --");
4072         break;
4073       }
4074       if (it+1 == theNbIterations) {
4075         //MESSAGE("-- Iteration limit exceeded --");
4076       }
4077     } // smoothing iterations
4078
4079     // MESSAGE(" Face id: " << *fId <<
4080     //         " Nb iterstions: " << it <<
4081     //         " Displacement: " << maxDisplacement <<
4082     //         " Aspect Ratio " << maxRatio);
4083
4084     // ---------------------------------------
4085     // new nodes positions are computed,
4086     // record movement in DS and set new UV
4087     // ---------------------------------------
4088     nodeToMove = setMovableNodes.begin();
4089     for ( ; nodeToMove != setMovableNodes.end(); nodeToMove++ ) {
4090       SMDS_MeshNode* node = const_cast< SMDS_MeshNode* > (*nodeToMove);
4091       aMesh->MoveNode( node, node->X(), node->Y(), node->Z() );
4092       map< const SMDS_MeshNode*, gp_XY* >::iterator node_uv = uvMap.find( node );
4093       if ( node_uv != uvMap.end() ) {
4094         gp_XY* uv = node_uv->second;
4095         node->SetPosition
4096           ( SMDS_PositionPtr( new SMDS_FacePosition( uv->X(), uv->Y() )));
4097       }
4098     }
4099
4100     // move medium nodes of quadratic elements
4101     if ( isQuadratic )
4102     {
4103       vector<const SMDS_MeshNode*> nodes;
4104       bool checkUV;
4105       list< const SMDS_MeshElement* >::iterator elemIt = elemsOnFace.begin();
4106       for ( ; elemIt != elemsOnFace.end(); ++elemIt )
4107       {
4108         const SMDS_MeshElement* QF = *elemIt;
4109         if ( QF->IsQuadratic() )
4110         {
4111           nodes.assign( SMDS_MeshElement::iterator( QF->interlacedNodesIterator() ),
4112                         SMDS_MeshElement::iterator() );
4113           nodes.push_back( nodes[0] );
4114           gp_Pnt xyz;
4115           for (size_t i = 1; i < nodes.size(); i += 2 ) // i points to a medium node
4116           {
4117             if ( !surface.IsNull() )
4118             {
4119               gp_XY uv1 = helper.GetNodeUV( face, nodes[i-1], nodes[i+1], &checkUV );
4120               gp_XY uv2 = helper.GetNodeUV( face, nodes[i+1], nodes[i-1], &checkUV );
4121               gp_XY uv  = helper.GetMiddleUV( surface, uv1, uv2 );
4122               xyz = surface->Value( uv.X(), uv.Y() );
4123             }
4124             else {
4125               xyz = 0.5 * ( SMESH_NodeXYZ( nodes[i-1] ) + SMESH_NodeXYZ( nodes[i+1] ));
4126             }
4127             if (( SMESH_NodeXYZ( nodes[i] ) - xyz.XYZ() ).Modulus() > disttol )
4128               // we have to move a medium node
4129               aMesh->MoveNode( nodes[i], xyz.X(), xyz.Y(), xyz.Z() );
4130           }
4131         }
4132       }
4133     }
4134
4135   } // loop on face ids
4136
4137 }
4138
4139 namespace
4140 {
4141   //=======================================================================
4142   //function : isReverse
4143   //purpose  : Return true if normal of prevNodes is not co-directied with
4144   //           gp_Vec(prevNodes[iNotSame],nextNodes[iNotSame]).
4145   //           iNotSame is where prevNodes and nextNodes are different.
4146   //           If result is true then future volume orientation is OK
4147   //=======================================================================
4148
4149   bool isReverse(const SMDS_MeshElement*             face,
4150                  const vector<const SMDS_MeshNode*>& prevNodes,
4151                  const vector<const SMDS_MeshNode*>& nextNodes,
4152                  const int                           iNotSame)
4153   {
4154
4155     SMESH_NodeXYZ pP = prevNodes[ iNotSame ];
4156     SMESH_NodeXYZ pN = nextNodes[ iNotSame ];
4157     gp_XYZ extrDir( pN - pP ), faceNorm;
4158     SMESH_MeshAlgos::FaceNormal( face, faceNorm, /*normalized=*/false );
4159
4160     return faceNorm * extrDir < 0.0;
4161   }
4162
4163   //================================================================================
4164   /*!
4165    * \brief Assure that theElemSets[0] holds elements, not nodes
4166    */
4167   //================================================================================
4168
4169   void setElemsFirst( TIDSortedElemSet theElemSets[2] )
4170   {
4171     if ( !theElemSets[0].empty() &&
4172          (*theElemSets[0].begin())->GetType() == SMDSAbs_Node )
4173     {
4174       std::swap( theElemSets[0], theElemSets[1] );
4175     }
4176     else if ( !theElemSets[1].empty() &&
4177               (*theElemSets[1].begin())->GetType() != SMDSAbs_Node )
4178     {
4179       std::swap( theElemSets[0], theElemSets[1] );
4180     }
4181   }
4182 }
4183
4184 //=======================================================================
4185 /*!
4186  * \brief Create elements by sweeping an element
4187  * \param elem - element to sweep
4188  * \param newNodesItVec - nodes generated from each node of the element
4189  * \param newElems - generated elements
4190  * \param nbSteps - number of sweeping steps
4191  * \param srcElements - to append elem for each generated element
4192  */
4193 //=======================================================================
4194
4195 void SMESH_MeshEditor::sweepElement(const SMDS_MeshElement*               elem,
4196                                     const vector<TNodeOfNodeListMapItr> & newNodesItVec,
4197                                     list<const SMDS_MeshElement*>&        newElems,
4198                                     const size_t                          nbSteps,
4199                                     SMESH_SequenceOfElemPtr&              srcElements)
4200 {
4201   SMESHDS_Mesh* aMesh = GetMeshDS();
4202
4203   const int           nbNodes = elem->NbNodes();
4204   const int         nbCorners = elem->NbCornerNodes();
4205   SMDSAbs_EntityType baseType = elem->GetEntityType(); /* it can change in case of
4206                                                           polyhedron creation !!! */
4207   // Loop on elem nodes:
4208   // find new nodes and detect same nodes indices
4209   vector < list< const SMDS_MeshNode* >::const_iterator > itNN( nbNodes );
4210   vector<const SMDS_MeshNode*> prevNod( nbNodes );
4211   vector<const SMDS_MeshNode*> nextNod( nbNodes );
4212   vector<const SMDS_MeshNode*> midlNod( nbNodes );
4213
4214   int iNode, nbSame = 0, nbDouble = 0, iNotSameNode = 0;
4215   vector<int> sames(nbNodes);
4216   vector<bool> isSingleNode(nbNodes);
4217
4218   for ( iNode = 0; iNode < nbNodes; iNode++ ) {
4219     TNodeOfNodeListMapItr                        nnIt = newNodesItVec[ iNode ];
4220     const SMDS_MeshNode*                         node = nnIt->first;
4221     const list< const SMDS_MeshNode* > & listNewNodes = nnIt->second;
4222     if ( listNewNodes.empty() )
4223       return;
4224
4225     itNN   [ iNode ] = listNewNodes.begin();
4226     prevNod[ iNode ] = node;
4227     nextNod[ iNode ] = listNewNodes.front();
4228
4229     isSingleNode[iNode] = (listNewNodes.size()==nbSteps); /* medium node of quadratic or
4230                                                              corner node of linear */
4231     if ( prevNod[ iNode ] != nextNod [ iNode ])
4232       nbDouble += !isSingleNode[iNode];
4233
4234     if( iNode < nbCorners ) { // check corners only
4235       if ( prevNod[ iNode ] == nextNod [ iNode ])
4236         sames[nbSame++] = iNode;
4237       else
4238         iNotSameNode = iNode;
4239     }
4240   }
4241
4242   if ( nbSame == nbNodes || nbSame > 2) {
4243     MESSAGE( " Too many same nodes of element " << elem->GetID() );
4244     return;
4245   }
4246
4247   if ( elem->GetType() == SMDSAbs_Face && !isReverse( elem, prevNod, nextNod, iNotSameNode ))
4248   {
4249     // fix nodes order to have bottom normal external
4250     if ( baseType == SMDSEntity_Polygon )
4251     {
4252       std::reverse( itNN.begin(), itNN.end() );
4253       std::reverse( prevNod.begin(), prevNod.end() );
4254       std::reverse( midlNod.begin(), midlNod.end() );
4255       std::reverse( nextNod.begin(), nextNod.end() );
4256       std::reverse( isSingleNode.begin(), isSingleNode.end() );
4257     }
4258     else
4259     {
4260       const vector<int>& ind = SMDS_MeshCell::reverseSmdsOrder( baseType, nbNodes );
4261       SMDS_MeshCell::applyInterlace( ind, itNN );
4262       SMDS_MeshCell::applyInterlace( ind, prevNod );
4263       SMDS_MeshCell::applyInterlace( ind, nextNod );
4264       SMDS_MeshCell::applyInterlace( ind, midlNod );
4265       SMDS_MeshCell::applyInterlace( ind, isSingleNode );
4266       if ( nbSame > 0 )
4267       {
4268         sames[nbSame] = iNotSameNode;
4269         for ( int j = 0; j <= nbSame; ++j )
4270           for ( size_t i = 0; i < ind.size(); ++i )
4271             if ( ind[i] == sames[j] )
4272             {
4273               sames[j] = i;
4274               break;
4275             }
4276         iNotSameNode = sames[nbSame];
4277       }
4278     }
4279   }
4280   else if ( elem->GetType() == SMDSAbs_Edge )
4281   {
4282     // orient a new face same as adjacent one
4283     int i1, i2;
4284     const SMDS_MeshElement* e;
4285     TIDSortedElemSet dummy;
4286     if (( e = SMESH_MeshAlgos::FindFaceInSet( nextNod[0], prevNod[0], dummy,dummy, &i1, &i2 )) ||
4287         ( e = SMESH_MeshAlgos::FindFaceInSet( prevNod[1], nextNod[1], dummy,dummy, &i1, &i2 )) ||
4288         ( e = SMESH_MeshAlgos::FindFaceInSet( prevNod[0], prevNod[1], dummy,dummy, &i1, &i2 )))
4289     {
4290       // there is an adjacent face, check order of nodes in it
4291       bool sameOrder = ( Abs( i2 - i1 ) == 1 ) ? ( i2 > i1 ) : ( i2 < i1 );
4292       if ( sameOrder )
4293       {
4294         std::swap( itNN[0],    itNN[1] );
4295         std::swap( prevNod[0], prevNod[1] );
4296         std::swap( nextNod[0], nextNod[1] );
4297         std::swap( isSingleNode[0], isSingleNode[1] );
4298         if ( nbSame > 0 )
4299           sames[0] = 1 - sames[0];
4300         iNotSameNode = 1 - iNotSameNode;
4301       }
4302     }
4303   }
4304
4305   int iSameNode = 0, iBeforeSame = 0, iAfterSame = 0, iOpposSame = 0;
4306   if ( nbSame > 0 ) {
4307     iSameNode    = sames[ nbSame-1 ];
4308     iBeforeSame  = ( iSameNode + nbCorners - 1 ) % nbCorners;
4309     iAfterSame   = ( iSameNode + 1 ) % nbCorners;
4310     iOpposSame   = ( iSameNode - 2 < 0  ? iSameNode + 2 : iSameNode - 2 );
4311   }
4312
4313   if ( baseType == SMDSEntity_Polygon )
4314   {
4315     if      ( nbNodes == 3 ) baseType = SMDSEntity_Triangle;
4316     else if ( nbNodes == 4 ) baseType = SMDSEntity_Quadrangle;
4317   }
4318   else if ( baseType == SMDSEntity_Quad_Polygon )
4319   {
4320     if      ( nbNodes == 6 ) baseType = SMDSEntity_Quad_Triangle;
4321     else if ( nbNodes == 8 ) baseType = SMDSEntity_Quad_Quadrangle;
4322   }
4323
4324   // make new elements
4325   for ( size_t iStep = 0; iStep < nbSteps; iStep++ )
4326   {
4327     // get next nodes
4328     for ( iNode = 0; iNode < nbNodes; iNode++ )
4329     {
4330       midlNod[ iNode ] = isSingleNode[iNode] ? 0 : *itNN[ iNode ]++;
4331       nextNod[ iNode ] = *itNN[ iNode ]++;
4332     }
4333
4334     SMDS_MeshElement* aNewElem = 0;
4335     /*if(!elem->IsPoly())*/ {
4336       switch ( baseType ) {
4337       case SMDSEntity_0D:
4338       case SMDSEntity_Node: { // sweep NODE
4339         if ( nbSame == 0 ) {
4340           if ( isSingleNode[0] )
4341             aNewElem = aMesh->AddEdge( prevNod[ 0 ], nextNod[ 0 ] );
4342           else
4343             aNewElem = aMesh->AddEdge( prevNod[ 0 ], nextNod[ 0 ], midlNod[ 0 ] );
4344         }
4345         else
4346           return;
4347         break;
4348       }
4349       case SMDSEntity_Edge: { // sweep EDGE
4350         if ( nbDouble == 0 )
4351         {
4352           if ( nbSame == 0 ) // ---> quadrangle
4353             aNewElem = aMesh->AddFace(prevNod[ 0 ], prevNod[ 1 ],
4354                                       nextNod[ 1 ], nextNod[ 0 ] );
4355           else               // ---> triangle
4356             aNewElem = aMesh->AddFace(prevNod[ 0 ], prevNod[ 1 ],
4357                                       nextNod[ iNotSameNode ] );
4358         }
4359         else                 // ---> polygon
4360         {
4361           vector<const SMDS_MeshNode*> poly_nodes;
4362           poly_nodes.push_back( prevNod[0] );
4363           poly_nodes.push_back( prevNod[1] );
4364           if ( prevNod[1] != nextNod[1] )
4365           {
4366             if ( midlNod[1]) poly_nodes.push_back( midlNod[1]);
4367             poly_nodes.push_back( nextNod[1] );
4368           }
4369           if ( prevNod[0] != nextNod[0] )
4370           {
4371             poly_nodes.push_back( nextNod[0] );
4372             if ( midlNod[0]) poly_nodes.push_back( midlNod[0]);
4373           }
4374           switch ( poly_nodes.size() ) {
4375           case 3:
4376             aNewElem = aMesh->AddFace( poly_nodes[ 0 ], poly_nodes[ 1 ], poly_nodes[ 2 ]);
4377             break;
4378           case 4:
4379             aNewElem = aMesh->AddFace( poly_nodes[ 0 ], poly_nodes[ 1 ],
4380                                        poly_nodes[ 2 ], poly_nodes[ 3 ]);
4381             break;
4382           default:
4383             aNewElem = aMesh->AddPolygonalFace (poly_nodes);
4384           }
4385         }
4386         break;
4387       }
4388       case SMDSEntity_Triangle: // TRIANGLE --->
4389       {
4390         if ( nbDouble > 0 ) break;
4391         if ( nbSame == 0 )       // ---> pentahedron
4392           aNewElem = aMesh->AddVolume (prevNod[ 0 ], prevNod[ 1 ], prevNod[ 2 ],
4393                                        nextNod[ 0 ], nextNod[ 1 ], nextNod[ 2 ] );
4394
4395         else if ( nbSame == 1 )  // ---> pyramid
4396           aNewElem = aMesh->AddVolume (prevNod[ iBeforeSame ], prevNod[ iAfterSame ],
4397                                        nextNod[ iAfterSame ],  nextNod[ iBeforeSame ],
4398                                        nextNod[ iSameNode ]);
4399
4400         else // 2 same nodes:       ---> tetrahedron
4401           aNewElem = aMesh->AddVolume (prevNod[ 0 ], prevNod[ 1 ], prevNod[ 2 ],
4402                                        nextNod[ iNotSameNode ]);
4403         break;
4404       }
4405       case SMDSEntity_Quad_Edge: // sweep quadratic EDGE --->
4406       {
4407         if ( nbSame == 2 )
4408           return;
4409         if ( nbDouble+nbSame == 2 )
4410         {
4411           if(nbSame==0) {      // ---> quadratic quadrangle
4412             aNewElem = aMesh->AddFace(prevNod[0], prevNod[1], nextNod[1], nextNod[0],
4413                                       prevNod[2], midlNod[1], nextNod[2], midlNod[0]);
4414           }
4415           else { //(nbSame==1) // ---> quadratic triangle
4416             if(sames[0]==2) {
4417               return; // medium node on axis
4418             }
4419             else if(sames[0]==0)
4420               aNewElem = aMesh->AddFace(prevNod[0], prevNod[1], nextNod[1],
4421                                         prevNod[2], midlNod[1], nextNod[2] );
4422             else // sames[0]==1
4423               aNewElem = aMesh->AddFace(prevNod[0], prevNod[1], nextNod[0],
4424                                         prevNod[2], nextNod[2], midlNod[0]);
4425           }
4426         }
4427         else if ( nbDouble == 3 )
4428         {
4429           if ( nbSame == 0 ) {  // ---> bi-quadratic quadrangle
4430             aNewElem = aMesh->AddFace(prevNod[0], prevNod[1], nextNod[1], nextNod[0],
4431                                       prevNod[2], midlNod[1], nextNod[2], midlNod[0], midlNod[2]);
4432           }
4433         }
4434         else
4435           return;
4436         break;
4437       }
4438       case SMDSEntity_Quadrangle: { // sweep QUADRANGLE --->
4439         if ( nbDouble > 0 ) break;
4440
4441         if ( nbSame == 0 )       // ---> hexahedron
4442           aNewElem = aMesh->AddVolume (prevNod[ 0 ], prevNod[ 1 ], prevNod[ 2 ], prevNod[ 3 ],
4443                                        nextNod[ 0 ], nextNod[ 1 ], nextNod[ 2 ], nextNod[ 3 ]);
4444
4445         else if ( nbSame == 1 ) { // ---> pyramid + pentahedron
4446           aNewElem = aMesh->AddVolume (prevNod[ iBeforeSame ], prevNod[ iAfterSame ],
4447                                        nextNod[ iAfterSame ],  nextNod[ iBeforeSame ],
4448                                        nextNod[ iSameNode ]);
4449           newElems.push_back( aNewElem );
4450           aNewElem = aMesh->AddVolume (prevNod[ iAfterSame ],  prevNod[ iOpposSame ],
4451                                        prevNod[ iBeforeSame ], nextNod[ iAfterSame ],
4452                                        nextNod[ iOpposSame ],  nextNod[ iBeforeSame ] );
4453         }
4454         else if ( nbSame == 2 ) { // ---> pentahedron
4455           if ( prevNod[ iBeforeSame ] == nextNod[ iBeforeSame ] )
4456             // iBeforeSame is same too
4457             aNewElem = aMesh->AddVolume (prevNod[ iBeforeSame ], prevNod[ iOpposSame ],
4458                                          nextNod[ iOpposSame ],  prevNod[ iSameNode ],
4459                                          prevNod[ iAfterSame ],  nextNod[ iAfterSame ]);
4460           else
4461             // iAfterSame is same too
4462             aNewElem = aMesh->AddVolume (prevNod[ iSameNode ],   prevNod[ iBeforeSame ],
4463                                          nextNod[ iBeforeSame ], prevNod[ iAfterSame ],
4464                                          prevNod[ iOpposSame ],  nextNod[ iOpposSame ]);
4465         }
4466         break;
4467       }
4468       case SMDSEntity_Quad_Triangle:  // sweep (Bi)Quadratic TRIANGLE --->
4469       case SMDSEntity_BiQuad_Triangle: /* ??? */ {
4470         if ( nbDouble+nbSame != 3 ) break;
4471         if(nbSame==0) {
4472           // --->  pentahedron with 15 nodes
4473           aNewElem = aMesh->AddVolume (prevNod[0], prevNod[1], prevNod[2],
4474                                        nextNod[0], nextNod[1], nextNod[2],
4475                                        prevNod[3], prevNod[4], prevNod[5],
4476                                        nextNod[3], nextNod[4], nextNod[5],
4477                                        midlNod[0], midlNod[1], midlNod[2]);
4478         }
4479         else if(nbSame==1) {
4480           // --->  2d order pyramid of 13 nodes
4481           int apex = iSameNode;
4482           int i0 = ( apex + 1 ) % nbCorners;
4483           int i1 = ( apex - 1 + nbCorners ) % nbCorners;
4484           int i0a = apex + 3;
4485           int i1a = i1 + 3;
4486           int i01 = i0 + 3;
4487           aNewElem = aMesh->AddVolume(prevNod[i1], prevNod[i0],
4488                                       nextNod[i0], nextNod[i1], prevNod[apex],
4489                                       prevNod[i01], midlNod[i0],
4490                                       nextNod[i01], midlNod[i1],
4491                                       prevNod[i1a], prevNod[i0a],
4492                                       nextNod[i0a], nextNod[i1a]);
4493         }
4494         else if(nbSame==2) {
4495           // --->  2d order tetrahedron of 10 nodes
4496           int n1 = iNotSameNode;
4497           int n2 = ( n1 + 1             ) % nbCorners;
4498           int n3 = ( n1 + nbCorners - 1 ) % nbCorners;
4499           int n12 = n1 + 3;
4500           int n23 = n2 + 3;
4501           int n31 = n3 + 3;
4502           aNewElem = aMesh->AddVolume (prevNod[n1], prevNod[n2], prevNod[n3], nextNod[n1],
4503                                        prevNod[n12], prevNod[n23], prevNod[n31],
4504                                        midlNod[n1], nextNod[n12], nextNod[n31]);
4505         }
4506         break;
4507       }
4508       case SMDSEntity_Quad_Quadrangle: { // sweep Quadratic QUADRANGLE --->
4509         if( nbSame == 0 ) {
4510           if ( nbDouble != 4 ) break;
4511           // --->  hexahedron with 20 nodes
4512           aNewElem = aMesh->AddVolume (prevNod[0], prevNod[1], prevNod[2], prevNod[3],
4513                                        nextNod[0], nextNod[1], nextNod[2], nextNod[3],
4514                                        prevNod[4], prevNod[5], prevNod[6], prevNod[7],
4515                                        nextNod[4], nextNod[5], nextNod[6], nextNod[7],
4516                                        midlNod[0], midlNod[1], midlNod[2], midlNod[3]);
4517         }
4518         else if(nbSame==1) {
4519           // ---> pyramid + pentahedron - can not be created since it is needed
4520           // additional middle node at the center of face
4521           //INFOS( " Sweep for face " << elem->GetID() << " can not be created" );
4522           return;
4523         }
4524         else if( nbSame == 2 ) {
4525           if ( nbDouble != 2 ) break;
4526           // --->  2d order Pentahedron with 15 nodes
4527           int n1,n2,n4,n5;
4528           if ( prevNod[ iBeforeSame ] == nextNod[ iBeforeSame ] ) {
4529             // iBeforeSame is same too
4530             n1 = iBeforeSame;
4531             n2 = iOpposSame;
4532             n4 = iSameNode;
4533             n5 = iAfterSame;
4534           }
4535           else {
4536             // iAfterSame is same too
4537             n1 = iSameNode;
4538             n2 = iBeforeSame;
4539             n4 = iAfterSame;
4540             n5 = iOpposSame;
4541           }
4542           int n12 = n2 + 4;
4543           int n45 = n4 + 4;
4544           int n14 = n1 + 4;
4545           int n25 = n5 + 4;
4546           aNewElem = aMesh->AddVolume (prevNod[n1], prevNod[n2], nextNod[n2],
4547                                        prevNod[n4], prevNod[n5], nextNod[n5],
4548                                        prevNod[n12], midlNod[n2], nextNod[n12],
4549                                        prevNod[n45], midlNod[n5], nextNod[n45],
4550                                        prevNod[n14], prevNod[n25], nextNod[n25]);
4551         }
4552         break;
4553       }
4554       case SMDSEntity_BiQuad_Quadrangle: { // sweep BiQuadratic QUADRANGLE --->
4555
4556         if( nbSame == 0 && nbDouble == 9 ) {
4557           // --->  tri-quadratic hexahedron with 27 nodes
4558           aNewElem = aMesh->AddVolume (prevNod[0], prevNod[1], prevNod[2], prevNod[3],
4559                                        nextNod[0], nextNod[1], nextNod[2], nextNod[3],
4560                                        prevNod[4], prevNod[5], prevNod[6], prevNod[7],
4561                                        nextNod[4], nextNod[5], nextNod[6], nextNod[7],
4562                                        midlNod[0], midlNod[1], midlNod[2], midlNod[3],
4563                                        prevNod[8], // bottom center
4564                                        midlNod[4], midlNod[5], midlNod[6], midlNod[7],
4565                                        nextNod[8], // top center
4566                                        midlNod[8]);// elem center
4567         }
4568         else
4569         {
4570           return;
4571         }
4572         break;
4573       }
4574       case SMDSEntity_Polygon: { // sweep POLYGON
4575
4576         if ( nbNodes == 6 && nbSame == 0 && nbDouble == 0 ) {
4577           // --->  hexagonal prism
4578           aNewElem = aMesh->AddVolume (prevNod[0], prevNod[1], prevNod[2],
4579                                        prevNod[3], prevNod[4], prevNod[5],
4580                                        nextNod[0], nextNod[1], nextNod[2],
4581                                        nextNod[3], nextNod[4], nextNod[5]);
4582         }
4583         break;
4584       }
4585       case SMDSEntity_Ball:
4586         return;
4587
4588       default:
4589         break;
4590       } // switch ( baseType )
4591     } // scope
4592
4593     if ( !aNewElem && elem->GetType() == SMDSAbs_Face ) // try to create a polyherdal prism
4594     {
4595       if ( baseType != SMDSEntity_Polygon )
4596       {
4597         const std::vector<int>& ind = SMDS_MeshCell::interlacedSmdsOrder(baseType,nbNodes);
4598         SMDS_MeshCell::applyInterlace( ind, prevNod );
4599         SMDS_MeshCell::applyInterlace( ind, nextNod );
4600         SMDS_MeshCell::applyInterlace( ind, midlNod );
4601         SMDS_MeshCell::applyInterlace( ind, itNN );
4602         SMDS_MeshCell::applyInterlace( ind, isSingleNode );
4603         baseType = SMDSEntity_Polygon; // WARNING: change baseType !!!!
4604       }
4605       vector<const SMDS_MeshNode*> polyedre_nodes (nbNodes*2 + 4*nbNodes);
4606       vector<smIdType> quantities (nbNodes + 2);
4607       polyedre_nodes.clear();
4608       quantities.clear();
4609
4610       // bottom of prism
4611       for (int inode = 0; inode < nbNodes; inode++)
4612         polyedre_nodes.push_back( prevNod[inode] );
4613       quantities.push_back( nbNodes );
4614
4615       // top of prism
4616       polyedre_nodes.push_back( nextNod[0] );
4617       for (int inode = nbNodes; inode-1; --inode )
4618         polyedre_nodes.push_back( nextNod[inode-1] );
4619       quantities.push_back( nbNodes );
4620
4621       // side faces
4622       // 3--6--2
4623       // |     |
4624       // 7     5
4625       // |     |
4626       // 0--4--1
4627       const int iQuad = elem->IsQuadratic();
4628       for (int iface = 0; iface < nbNodes; iface += 1+iQuad )
4629       {
4630         const int prevNbNodes = polyedre_nodes.size(); // to detect degenerated face
4631         int inextface = (iface+1+iQuad) % nbNodes;
4632         int imid      = (iface+1) % nbNodes;
4633         polyedre_nodes.push_back( prevNod[inextface] );         // 0
4634         if ( iQuad ) polyedre_nodes.push_back( prevNod[imid] ); // 4
4635         polyedre_nodes.push_back( prevNod[iface] );             // 1
4636         if ( prevNod[iface] != nextNod[iface] ) // 1 != 2
4637         {
4638           if ( midlNod[ iface ]) polyedre_nodes.push_back( midlNod[ iface ]); // 5
4639           polyedre_nodes.push_back( nextNod[iface] );                         // 2
4640         }
4641         if ( iQuad ) polyedre_nodes.push_back( nextNod[imid] );               // 6
4642         if ( prevNod[inextface] != nextNod[inextface] ) // 0 != 3
4643         {
4644           polyedre_nodes.push_back( nextNod[inextface] );                            // 3
4645           if ( midlNod[ inextface ]) polyedre_nodes.push_back( midlNod[ inextface ]);// 7
4646         }
4647         const int nbFaceNodes = polyedre_nodes.size() - prevNbNodes;
4648         if ( nbFaceNodes > 2 )
4649           quantities.push_back( nbFaceNodes );
4650         else // degenerated face
4651           polyedre_nodes.resize( prevNbNodes );
4652       }
4653       aNewElem = aMesh->AddPolyhedralVolume (polyedre_nodes, quantities);
4654
4655     } // try to create a polyherdal prism
4656
4657     if ( aNewElem ) {
4658       newElems.push_back( aNewElem );
4659       myLastCreatedElems.push_back(aNewElem);
4660       srcElements.push_back( elem );
4661     }
4662
4663     // set new prev nodes
4664     for ( iNode = 0; iNode < nbNodes; iNode++ )
4665       prevNod[ iNode ] = nextNod[ iNode ];
4666
4667   } // loop on steps
4668 }
4669
4670 //=======================================================================
4671 /*!
4672  * \brief Create 1D and 2D elements around swept elements
4673  * \param mapNewNodes - source nodes and ones generated from them
4674  * \param newElemsMap - source elements and ones generated from them
4675  * \param elemNewNodesMap - nodes generated from each node of each element
4676  * \param elemSet - all swept elements
4677  * \param nbSteps - number of sweeping steps
4678  * \param srcElements - to append elem for each generated element
4679  */
4680 //=======================================================================
4681
4682 void SMESH_MeshEditor::makeWalls (TNodeOfNodeListMap &     mapNewNodes,
4683                                   TTElemOfElemListMap &    newElemsMap,
4684                                   TElemOfVecOfNnlmiMap &   elemNewNodesMap,
4685                                   TIDSortedElemSet&        elemSet,
4686                                   const int                nbSteps,
4687                                   SMESH_SequenceOfElemPtr& srcElements)
4688 {
4689   ASSERT( newElemsMap.size() == elemNewNodesMap.size() );
4690   SMESHDS_Mesh* aMesh = GetMeshDS();
4691
4692   // Find nodes belonging to only one initial element - sweep them into edges.
4693
4694   TNodeOfNodeListMapItr nList = mapNewNodes.begin();
4695   for ( ; nList != mapNewNodes.end(); nList++ )
4696   {
4697     const SMDS_MeshNode* node =
4698       static_cast<const SMDS_MeshNode*>( nList->first );
4699     if ( newElemsMap.count( node ))
4700       continue; // node was extruded into edge
4701     SMDS_ElemIteratorPtr eIt = node->GetInverseElementIterator();
4702     int nbInitElems = 0;
4703     const SMDS_MeshElement* el = 0;
4704     SMDSAbs_ElementType highType = SMDSAbs_Edge; // count most complex elements only
4705     while ( eIt->more() && nbInitElems < 2 ) {
4706       const SMDS_MeshElement* e = eIt->next();
4707       SMDSAbs_ElementType  type = e->GetType();
4708       if ( type == SMDSAbs_Volume ||
4709            type < highType ||
4710            !elemSet.count(e))
4711         continue;
4712       if ( type > highType ) {
4713         nbInitElems = 0;
4714         highType    = type;
4715       }
4716       el = e;
4717       ++nbInitElems;
4718     }
4719     if ( nbInitElems == 1 ) {
4720       bool NotCreateEdge = el && el->IsMediumNode(node);
4721       if(!NotCreateEdge) {
4722         vector<TNodeOfNodeListMapItr> newNodesItVec( 1, nList );
4723         list<const SMDS_MeshElement*> newEdges;
4724         sweepElement( node, newNodesItVec, newEdges, nbSteps, srcElements );
4725       }
4726     }
4727   }
4728
4729   // Make a ceiling for each element ie an equal element of last new nodes.
4730   // Find free links of faces - make edges and sweep them into faces.
4731
4732   ElemFeatures polyFace( SMDSAbs_Face, /*isPoly=*/true ), anyFace;
4733
4734   TTElemOfElemListMap::iterator  itElem      = newElemsMap.begin();
4735   TElemOfVecOfNnlmiMap::iterator itElemNodes = elemNewNodesMap.begin();
4736   for ( ; itElem != newElemsMap.end(); itElem++, itElemNodes++ )
4737   {
4738     const SMDS_MeshElement* elem = itElem->first;
4739     vector<TNodeOfNodeListMapItr>& vecNewNodes = itElemNodes->second;
4740
4741     if(itElem->second.size()==0) continue;
4742
4743     const bool isQuadratic = elem->IsQuadratic();
4744
4745     if ( elem->GetType() == SMDSAbs_Edge ) {
4746       // create a ceiling edge
4747       if ( !isQuadratic ) {
4748         if ( !aMesh->FindEdge( vecNewNodes[ 0 ]->second.back(),
4749                                vecNewNodes[ 1 ]->second.back())) {
4750           myLastCreatedElems.push_back(aMesh->AddEdge(vecNewNodes[ 0 ]->second.back(),
4751                                                       vecNewNodes[ 1 ]->second.back()));
4752           srcElements.push_back( elem );
4753         }
4754       }
4755       else {
4756         if ( !aMesh->FindEdge( vecNewNodes[ 0 ]->second.back(),
4757                                vecNewNodes[ 1 ]->second.back(),
4758                                vecNewNodes[ 2 ]->second.back())) {
4759           myLastCreatedElems.push_back(aMesh->AddEdge(vecNewNodes[ 0 ]->second.back(),
4760                                                       vecNewNodes[ 1 ]->second.back(),
4761                                                       vecNewNodes[ 2 ]->second.back()));
4762           srcElements.push_back( elem );
4763         }
4764       }
4765     }
4766     if ( elem->GetType() != SMDSAbs_Face )
4767       continue;
4768
4769     bool hasFreeLinks = false;
4770
4771     TIDSortedElemSet avoidSet;
4772     avoidSet.insert( elem );
4773
4774     set<const SMDS_MeshNode*> aFaceLastNodes;
4775     int iNode, nbNodes = vecNewNodes.size();
4776     if ( !isQuadratic ) {
4777       // loop on the face nodes
4778       for ( iNode = 0; iNode < nbNodes; iNode++ ) {
4779         aFaceLastNodes.insert( vecNewNodes[ iNode ]->second.back() );
4780         // look for free links of the face
4781         int iNext = ( iNode + 1 == nbNodes ) ? 0 : iNode + 1;
4782         const SMDS_MeshNode* n1 = vecNewNodes[ iNode ]->first;
4783         const SMDS_MeshNode* n2 = vecNewNodes[ iNext ]->first;
4784         // check if a link n1-n2 is free
4785         if ( ! SMESH_MeshAlgos::FindFaceInSet ( n1, n2, elemSet, avoidSet )) {
4786           hasFreeLinks = true;
4787           // make a new edge and a ceiling for a new edge
4788           const SMDS_MeshElement* edge;
4789           if ( ! ( edge = aMesh->FindEdge( n1, n2 ))) {
4790             myLastCreatedElems.push_back( edge = aMesh->AddEdge( n1, n2 )); // free link edge
4791             srcElements.push_back( myLastCreatedElems.back() );
4792           }
4793           n1 = vecNewNodes[ iNode ]->second.back();
4794           n2 = vecNewNodes[ iNext ]->second.back();
4795           if ( !aMesh->FindEdge( n1, n2 )) {
4796             myLastCreatedElems.push_back(aMesh->AddEdge( n1, n2 )); // new edge ceiling
4797             srcElements.push_back( edge );
4798           }
4799         }
4800       }
4801     }
4802     else { // elem is quadratic face
4803       int nbn = nbNodes/2;
4804       for ( iNode = 0; iNode < nbn; iNode++ ) {
4805         aFaceLastNodes.insert( vecNewNodes[ iNode ]->second.back() );
4806         int iNext = ( iNode + 1 == nbn ) ? 0 : iNode + 1;
4807         const SMDS_MeshNode* n1 = vecNewNodes[ iNode ]->first;
4808         const SMDS_MeshNode* n2 = vecNewNodes[ iNext ]->first;
4809         const SMDS_MeshNode* n3 = vecNewNodes[ iNode+nbn ]->first;
4810         // check if a link is free
4811         if ( ! SMESH_MeshAlgos::FindFaceInSet ( n1, n2, elemSet, avoidSet ) &&
4812              ! SMESH_MeshAlgos::FindFaceInSet ( n1, n3, elemSet, avoidSet ) &&
4813              ! SMESH_MeshAlgos::FindFaceInSet ( n3, n2, elemSet, avoidSet ) ) {
4814           hasFreeLinks = true;
4815           // make an edge and a ceiling for a new edge
4816           // find medium node
4817           if ( !aMesh->FindEdge( n1, n2, n3 )) {
4818             myLastCreatedElems.push_back(aMesh->AddEdge( n1, n2, n3 )); // free link edge
4819             srcElements.push_back( elem );
4820           }
4821           n1 = vecNewNodes[ iNode ]->second.back();
4822           n2 = vecNewNodes[ iNext ]->second.back();
4823           n3 = vecNewNodes[ iNode+nbn ]->second.back();
4824           if ( !aMesh->FindEdge( n1, n2, n3 )) {
4825             myLastCreatedElems.push_back(aMesh->AddEdge( n1, n2, n3 )); // ceiling edge
4826             srcElements.push_back( elem );
4827           }
4828         }
4829       }
4830       for ( iNode = nbn; iNode < nbNodes; iNode++ ) {
4831         aFaceLastNodes.insert( vecNewNodes[ iNode ]->second.back() );
4832       }
4833     }
4834
4835     // sweep free links into faces
4836
4837     if ( hasFreeLinks ) {
4838       list<const SMDS_MeshElement*> & newVolumes = itElem->second;
4839       int iVol, volNb, nbVolumesByStep = newVolumes.size() / nbSteps;
4840
4841       set<const SMDS_MeshNode*> initNodeSet, topNodeSet, faceNodeSet;
4842       set<const SMDS_MeshNode*> initNodeSetNoCenter/*, topNodeSetNoCenter*/;
4843       for ( iNode = 0; iNode < nbNodes; iNode++ ) {
4844         initNodeSet.insert( vecNewNodes[ iNode ]->first );
4845         topNodeSet .insert( vecNewNodes[ iNode ]->second.back() );
4846       }
4847       if ( isQuadratic && nbNodes % 2 ) {  // node set for the case of a biquadratic
4848         initNodeSetNoCenter = initNodeSet; // swept face and a not biquadratic volume
4849         initNodeSetNoCenter.erase( vecNewNodes.back()->first );
4850       }
4851       for ( volNb = 0; volNb < nbVolumesByStep; volNb++ ) {
4852         list<const SMDS_MeshElement*>::iterator v = newVolumes.begin();
4853         std::advance( v, volNb );
4854         // find indices of free faces of a volume and their source edges
4855         list< int > freeInd;
4856         list< const SMDS_MeshElement* > srcEdges; // source edges of free faces
4857         SMDS_VolumeTool vTool( *v, /*ignoreCentralNodes=*/false );
4858         int iF, nbF = vTool.NbFaces();
4859         for ( iF = 0; iF < nbF; iF ++ ) {
4860           if ( vTool.IsFreeFace( iF ) &&
4861                vTool.GetFaceNodes( iF, faceNodeSet ) &&
4862                initNodeSet != faceNodeSet) // except an initial face
4863           {
4864             if ( nbSteps == 1 && faceNodeSet == topNodeSet )
4865               continue;
4866             if ( faceNodeSet == initNodeSetNoCenter )
4867               continue;
4868             freeInd.push_back( iF );
4869             // find source edge of a free face iF
4870             vector<const SMDS_MeshNode*> commonNodes; // shared by the initial and free faces
4871             vector<const SMDS_MeshNode*>::iterator lastCommom;
4872             commonNodes.resize( nbNodes, 0 );
4873             lastCommom = std::set_intersection( faceNodeSet.begin(), faceNodeSet.end(),
4874                                                 initNodeSet.begin(), initNodeSet.end(),
4875                                                 commonNodes.begin());
4876             if ( std::distance( commonNodes.begin(), lastCommom ) == 3 )
4877               srcEdges.push_back(aMesh->FindEdge (commonNodes[0],commonNodes[1],commonNodes[2]));
4878             else
4879               srcEdges.push_back(aMesh->FindEdge (commonNodes[0],commonNodes[1]));
4880 #ifdef _DEBUG_
4881             if ( !srcEdges.back() )
4882             {
4883               cout << "SMESH_MeshEditor::makeWalls(), no source edge found for a free face #"
4884                    << iF << " of volume #" << vTool.ID() << endl;
4885             }
4886 #endif
4887           }
4888         }
4889         if ( freeInd.empty() )
4890           continue;
4891
4892         // create wall faces for all steps;
4893         // if such a face has been already created by sweep of edge,
4894         // assure that its orientation is OK
4895         for ( int iStep = 0; iStep < nbSteps; iStep++ )
4896         {
4897           vTool.Set( *v, /*ignoreCentralNodes=*/false );
4898           vTool.SetExternalNormal();
4899           const int nextShift = vTool.IsForward() ? +1 : -1;
4900           list< int >::iterator ind = freeInd.begin();
4901           list< const SMDS_MeshElement* >::iterator srcEdge = srcEdges.begin();
4902           for ( ; ind != freeInd.end(); ++ind, ++srcEdge ) // loop on free faces
4903           {
4904             const SMDS_MeshNode** nodes = vTool.GetFaceNodes( *ind );
4905             int nbn = vTool.NbFaceNodes( *ind );
4906             const SMDS_MeshElement * f = 0;
4907             if ( nbn == 3 )              ///// triangle
4908             {
4909               f = aMesh->FindFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ]);
4910               if ( !f ||
4911                    nodes[ 1 ] != f->GetNodeWrap( f->GetNodeIndex( nodes[ 0 ]) + nextShift ))
4912               {
4913                 const SMDS_MeshNode* newOrder[3] = { nodes[ 1 - nextShift ],
4914                                                      nodes[ 1 ],
4915                                                      nodes[ 1 + nextShift ] };
4916                 if ( f )
4917                   aMesh->ChangeElementNodes( f, &newOrder[0], nbn );
4918                 else
4919                   myLastCreatedElems.push_back(aMesh->AddFace( newOrder[ 0 ], newOrder[ 1 ],
4920                                                                newOrder[ 2 ] ));
4921               }
4922             }
4923             else if ( nbn == 4 )       ///// quadrangle
4924             {
4925               f = aMesh->FindFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ], nodes[ 3 ]);
4926               if ( !f ||
4927                    nodes[ 1 ] != f->GetNodeWrap( f->GetNodeIndex( nodes[ 0 ]) + nextShift ))
4928               {
4929                 const SMDS_MeshNode* newOrder[4] = { nodes[ 0 ], nodes[ 2-nextShift ],
4930                                                      nodes[ 2 ], nodes[ 2+nextShift ] };
4931                 if ( f )
4932                   aMesh->ChangeElementNodes( f, &newOrder[0], nbn );
4933                 else
4934                   myLastCreatedElems.push_back(aMesh->AddFace( newOrder[ 0 ], newOrder[ 1 ],
4935                                                                newOrder[ 2 ], newOrder[ 3 ]));
4936               }
4937             }
4938             else if ( nbn == 6 && isQuadratic ) /////// quadratic triangle
4939             {
4940               f = aMesh->FindFace( nodes[0], nodes[2], nodes[4], nodes[1], nodes[3], nodes[5] );
4941               if ( !f ||
4942                    nodes[2] != f->GetNodeWrap( f->GetNodeIndex( nodes[0] ) + 2*nextShift ))
4943               {
4944                 const SMDS_MeshNode* newOrder[6] = { nodes[2 - 2*nextShift],
4945                                                      nodes[2],
4946                                                      nodes[2 + 2*nextShift],
4947                                                      nodes[3 - 2*nextShift],
4948                                                      nodes[3],
4949                                                      nodes[3 + 2*nextShift]};
4950                 if ( f )
4951                   aMesh->ChangeElementNodes( f, &newOrder[0], nbn );
4952                 else
4953                   myLastCreatedElems.push_back(aMesh->AddFace( newOrder[ 0 ],
4954                                                                newOrder[ 1 ],
4955                                                                newOrder[ 2 ],
4956                                                                newOrder[ 3 ],
4957                                                                newOrder[ 4 ],
4958                                                                newOrder[ 5 ] ));
4959               }
4960             }
4961             else if ( nbn == 8 && isQuadratic ) /////// quadratic quadrangle
4962             {
4963               f = aMesh->FindFace( nodes[0], nodes[2], nodes[4], nodes[6],
4964                                    nodes[1], nodes[3], nodes[5], nodes[7] );
4965               if ( !f ||
4966                    nodes[ 2 ] != f->GetNodeWrap( f->GetNodeIndex( nodes[ 0 ] ) + 2*nextShift ))
4967               {
4968                 const SMDS_MeshNode* newOrder[8] = { nodes[0],
4969                                                      nodes[4 - 2*nextShift],
4970                                                      nodes[4],
4971                                                      nodes[4 + 2*nextShift],
4972                                                      nodes[1],
4973                                                      nodes[5 - 2*nextShift],
4974                                                      nodes[5],
4975                                                      nodes[5 + 2*nextShift] };
4976                 if ( f )
4977                   aMesh->ChangeElementNodes( f, &newOrder[0], nbn );
4978                 else
4979                   myLastCreatedElems.push_back(aMesh->AddFace(newOrder[ 0 ], newOrder[ 1 ],
4980                                                               newOrder[ 2 ], newOrder[ 3 ],
4981                                                               newOrder[ 4 ], newOrder[ 5 ],
4982                                                               newOrder[ 6 ], newOrder[ 7 ]));
4983               }
4984             }
4985             else if ( nbn == 9 && isQuadratic ) /////// bi-quadratic quadrangle
4986             {
4987               f = aMesh->FindElement( vector<const SMDS_MeshNode*>( nodes, nodes+nbn ),
4988                                       SMDSAbs_Face, /*noMedium=*/false);
4989               if ( !f ||
4990                    nodes[ 2 ] != f->GetNodeWrap( f->GetNodeIndex( nodes[ 0 ] ) + 2*nextShift ))
4991               {
4992                 const SMDS_MeshNode* newOrder[9] = { nodes[0],
4993                                                      nodes[4 - 2*nextShift],
4994                                                      nodes[4],
4995                                                      nodes[4 + 2*nextShift],
4996                                                      nodes[1],
4997                                                      nodes[5 - 2*nextShift],
4998                                                      nodes[5],
4999                                                      nodes[5 + 2*nextShift],
5000                                                      nodes[8] };
5001                 if ( f )
5002                   aMesh->ChangeElementNodes( f, &newOrder[0], nbn );
5003                 else
5004                   myLastCreatedElems.push_back(aMesh->AddFace(newOrder[ 0 ], newOrder[ 1 ],
5005                                                               newOrder[ 2 ], newOrder[ 3 ],
5006                                                               newOrder[ 4 ], newOrder[ 5 ],
5007                                                               newOrder[ 6 ], newOrder[ 7 ],
5008                                                               newOrder[ 8 ]));
5009               }
5010             }
5011             else  //////// polygon
5012             {
5013               vector<const SMDS_MeshNode*> polygon_nodes ( nodes, nodes+nbn );
5014               const SMDS_MeshFace * f = aMesh->FindFace( polygon_nodes );
5015               if ( !f ||
5016                    nodes[ 1 ] != f->GetNodeWrap( f->GetNodeIndex( nodes[ 0 ] ) + nextShift ))
5017               {
5018                 if ( !vTool.IsForward() )
5019                   std::reverse( polygon_nodes.begin(), polygon_nodes.end());
5020                 if ( f )
5021                   aMesh->ChangeElementNodes( f, &polygon_nodes[0], nbn );
5022                 else
5023                   AddElement( polygon_nodes, polyFace.SetQuad( (*v)->IsQuadratic() ));
5024               }
5025             }
5026
5027             while ( srcElements.size() < myLastCreatedElems.size() )
5028               srcElements.push_back( *srcEdge );
5029
5030           }  // loop on free faces
5031
5032           // go to the next volume
5033           iVol = 0;
5034           while ( iVol++ < nbVolumesByStep ) v++;
5035
5036         } // loop on steps
5037       } // loop on volumes of one step
5038     } // sweep free links into faces
5039
5040     // Make a ceiling face with a normal external to a volume
5041
5042     // use SMDS_VolumeTool to get a correctly ordered nodes of a ceiling face
5043     SMDS_VolumeTool lastVol( itElem->second.back(), /*ignoreCentralNodes=*/false );
5044     int iF = lastVol.GetFaceIndex( aFaceLastNodes );
5045
5046     if ( iF < 0 && isQuadratic && nbNodes % 2 ) { // remove a central node of biquadratic
5047       aFaceLastNodes.erase( vecNewNodes.back()->second.back() );
5048       iF = lastVol.GetFaceIndex( aFaceLastNodes );
5049     }
5050     if ( iF >= 0 )
5051     {
5052       lastVol.SetExternalNormal();
5053       const SMDS_MeshNode** nodes = lastVol.GetFaceNodes( iF );
5054       const               int nbn = lastVol.NbFaceNodes( iF );
5055       vector<const SMDS_MeshNode*> nodeVec( nodes, nodes+nbn );
5056       if ( !hasFreeLinks ||
5057            !aMesh->FindElement( nodeVec, SMDSAbs_Face, /*noMedium=*/false) )
5058       {
5059         const vector<int>& interlace =
5060           SMDS_MeshCell::interlacedSmdsOrder( elem->GetEntityType(), nbn );
5061         SMDS_MeshCell::applyInterlaceRev( interlace, nodeVec );
5062
5063         AddElement( nodeVec, anyFace.Init( elem ));
5064
5065         while ( srcElements.size() < myLastCreatedElems.size() )
5066           srcElements.push_back( elem );
5067       }
5068     }
5069   } // loop on swept elements
5070 }
5071
5072 //=======================================================================
5073 //function : RotationSweep
5074 //purpose  :
5075 //=======================================================================
5076
5077 SMESH_MeshEditor::PGroupIDs
5078 SMESH_MeshEditor::RotationSweep(TIDSortedElemSet   theElemSets[2],
5079                                 const gp_Ax1&      theAxis,
5080                                 const double       theAngle,
5081                                 const int          theNbSteps,
5082                                 const double       theTol,
5083                                 const bool         theMakeGroups,
5084                                 const bool         theMakeWalls)
5085 {
5086   ClearLastCreated();
5087
5088   setElemsFirst( theElemSets );
5089   myLastCreatedElems.reserve( theElemSets[0].size() * theNbSteps );
5090   myLastCreatedNodes.reserve( theElemSets[1].size() * theNbSteps );
5091
5092   // source elements for each generated one
5093   SMESH_SequenceOfElemPtr srcElems, srcNodes;
5094   srcElems.reserve( theElemSets[0].size() );
5095   srcNodes.reserve( theElemSets[1].size() );
5096
5097   gp_Trsf aTrsf;
5098   aTrsf.SetRotation( theAxis, theAngle );
5099   gp_Trsf aTrsf2;
5100   aTrsf2.SetRotation( theAxis, theAngle/2. );
5101
5102   gp_Lin aLine( theAxis );
5103   double aSqTol = theTol * theTol;
5104
5105   SMESHDS_Mesh* aMesh = GetMeshDS();
5106
5107   TNodeOfNodeListMap mapNewNodes;
5108   TElemOfVecOfNnlmiMap mapElemNewNodes;
5109   TTElemOfElemListMap newElemsMap;
5110
5111   const bool isQuadraticMesh = bool( myMesh->NbEdges(ORDER_QUADRATIC) +
5112                                      myMesh->NbFaces(ORDER_QUADRATIC) +
5113                                      myMesh->NbVolumes(ORDER_QUADRATIC) );
5114   // loop on theElemSets
5115   TIDSortedElemSet::iterator itElem;
5116   for ( int is2ndSet = 0; is2ndSet < 2; ++is2ndSet )
5117   {
5118     TIDSortedElemSet& theElems = theElemSets[ is2ndSet ];
5119     for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
5120       const SMDS_MeshElement* elem = *itElem;
5121       if ( !elem || elem->GetType() == SMDSAbs_Volume )
5122         continue;
5123       vector<TNodeOfNodeListMapItr> & newNodesItVec = mapElemNewNodes[ elem ];
5124       newNodesItVec.reserve( elem->NbNodes() );
5125
5126       // loop on elem nodes
5127       SMDS_ElemIteratorPtr itN = elem->nodesIterator();
5128       while ( itN->more() )
5129       {
5130         const SMDS_MeshNode* node = cast2Node( itN->next() );
5131
5132         gp_XYZ aXYZ( node->X(), node->Y(), node->Z() );
5133         double coord[3];
5134         aXYZ.Coord( coord[0], coord[1], coord[2] );
5135         bool isOnAxis = ( aLine.SquareDistance( aXYZ ) <= aSqTol );
5136
5137         // check if a node has been already sweeped
5138         TNodeOfNodeListMapItr nIt =
5139           mapNewNodes.insert( make_pair( node, list<const SMDS_MeshNode*>() )).first;
5140         list<const SMDS_MeshNode*>& listNewNodes = nIt->second;
5141         if ( listNewNodes.empty() )
5142         {
5143           // check if we are to create medium nodes between corner ones
5144           bool needMediumNodes = false;
5145           if ( isQuadraticMesh )
5146           {
5147             SMDS_ElemIteratorPtr it = node->GetInverseElementIterator();
5148             while (it->more() && !needMediumNodes )
5149             {
5150               const SMDS_MeshElement* invElem = it->next();
5151               if ( invElem != elem && !theElems.count( invElem )) continue;
5152               needMediumNodes = ( invElem->IsQuadratic() && !invElem->IsMediumNode(node) );
5153               if ( !needMediumNodes && invElem->GetEntityType() == SMDSEntity_BiQuad_Quadrangle )
5154                 needMediumNodes = true;
5155             }
5156           }
5157
5158           // make new nodes
5159           const SMDS_MeshNode * newNode = node;
5160           for ( int i = 0; i < theNbSteps; i++ ) {
5161             if ( !isOnAxis ) {
5162               if ( needMediumNodes )  // create a medium node
5163               {
5164                 aTrsf2.Transforms( coord[0], coord[1], coord[2] );
5165                 newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
5166                 myLastCreatedNodes.push_back(newNode);
5167                 srcNodes.push_back( node );
5168                 listNewNodes.push_back( newNode );
5169                 aTrsf2.Transforms( coord[0], coord[1], coord[2] );
5170               }
5171               else {
5172                 aTrsf.Transforms( coord[0], coord[1], coord[2] );
5173               }
5174               // create a corner node
5175               newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
5176               myLastCreatedNodes.push_back(newNode);
5177               srcNodes.push_back( node );
5178               listNewNodes.push_back( newNode );
5179             }
5180             else {
5181               listNewNodes.push_back( newNode );
5182               // if ( needMediumNodes )
5183               //   listNewNodes.push_back( newNode );
5184             }
5185           }
5186         }
5187         newNodesItVec.push_back( nIt );
5188       }
5189       // make new elements
5190       sweepElement( elem, newNodesItVec, newElemsMap[elem], theNbSteps, srcElems );
5191     }
5192   }
5193
5194   if ( theMakeWalls )
5195     makeWalls( mapNewNodes, newElemsMap, mapElemNewNodes, theElemSets[0], theNbSteps, srcElems );
5196
5197   PGroupIDs newGroupIDs;
5198   if ( theMakeGroups )
5199     newGroupIDs = generateGroups( srcNodes, srcElems, "rotated");
5200
5201   return newGroupIDs;
5202 }
5203
5204 //=======================================================================
5205 //function : ExtrusParam
5206 //purpose  : standard construction
5207 //=======================================================================
5208
5209 SMESH_MeshEditor::ExtrusParam::ExtrusParam( const gp_Vec&            theStep,
5210                                             const int                theNbSteps,
5211                                             const std::list<double>& theScales,
5212                                             const std::list<double>& theAngles,
5213                                             const gp_XYZ*            theBasePoint,
5214                                             const int                theFlags,
5215                                             const double             theTolerance):
5216   myDir( theStep ),
5217   myBaseP( Precision::Infinite(), 0, 0 ),
5218   myFlags( theFlags ),
5219   myTolerance( theTolerance ),
5220   myElemsToUse( NULL )
5221 {
5222   mySteps = new TColStd_HSequenceOfReal;
5223   const double stepSize = theStep.Magnitude();
5224   for (int i=1; i<=theNbSteps; i++ )
5225     mySteps->Append( stepSize );
5226
5227   if ( !theScales.empty() )
5228   {
5229     if ( IsScaleVariation() && (int)theScales.size() < theNbSteps )
5230       linearScaleVariation( theNbSteps, const_cast< std::list<double>& >( theScales ));
5231
5232     // add medium scales
5233     std::list<double>::const_iterator s2 = theScales.begin(), s1 = s2++;
5234     myScales.reserve( theNbSteps * 2 );
5235     myScales.push_back( 0.5 * ( *s1 + 1. ));
5236     myScales.push_back( *s1 );
5237     for ( ; s2 != theScales.end(); s1 = s2++ )
5238     {
5239       myScales.push_back( 0.5 * ( *s1 + *s2 ));
5240       myScales.push_back( *s2 );
5241     }
5242   }
5243
5244   if ( !theAngles.empty() )
5245   {
5246     std::list<double>& angles = const_cast< std::list<double>& >( theAngles );
5247     if ( IsAngleVariation() && (int)theAngles.size() < theNbSteps )
5248       linearAngleVariation( theNbSteps, angles );
5249
5250     // accumulate angles
5251     double angle = 0;
5252     int nbAngles = 0;
5253     std::list<double>::iterator a1 = angles.begin(), a2;
5254     for ( ; a1 != angles.end(); ++a1, ++nbAngles )
5255     {
5256       angle += *a1;
5257       *a1 = angle;
5258     }
5259     while ( nbAngles++ < theNbSteps )
5260       angles.push_back( angles.back() );
5261
5262     // add medium angles
5263     a2 = angles.begin(), a1 = a2++;
5264     myAngles.push_back( 0.5 * *a1 );
5265     myAngles.push_back( *a1 );
5266     for ( ; a2 != angles.end(); a1 = a2++ )
5267     {
5268       myAngles.push_back( 0.5 * ( *a1 + *a2 ));
5269       myAngles.push_back( *a2 );
5270     }
5271   }
5272
5273   if ( theBasePoint )
5274   {
5275     myBaseP = *theBasePoint;
5276   }
5277
5278   if (( theFlags & EXTRUSION_FLAG_SEW ) &&
5279       ( theTolerance > 0 ))
5280   {
5281     myMakeNodesFun = & SMESH_MeshEditor::ExtrusParam::makeNodesByDirAndSew;
5282   }
5283   else
5284   {
5285     myMakeNodesFun = & SMESH_MeshEditor::ExtrusParam::makeNodesByDir;
5286   }
5287 }
5288
5289 //=======================================================================
5290 //function : ExtrusParam
5291 //purpose  : steps are given explicitly
5292 //=======================================================================
5293
5294 SMESH_MeshEditor::ExtrusParam::ExtrusParam( const gp_Dir&                   theDir,
5295                                             Handle(TColStd_HSequenceOfReal) theSteps,
5296                                             const int                       theFlags,
5297                                             const double                    theTolerance):
5298   myDir( theDir ),
5299   mySteps( theSteps ),
5300   myFlags( theFlags ),
5301   myTolerance( theTolerance ),
5302   myElemsToUse( NULL )
5303 {
5304   if (( theFlags & EXTRUSION_FLAG_SEW ) &&
5305       ( theTolerance > 0 ))
5306   {
5307     myMakeNodesFun = & SMESH_MeshEditor::ExtrusParam::makeNodesByDirAndSew;
5308   }
5309   else
5310   {
5311     myMakeNodesFun = & SMESH_MeshEditor::ExtrusParam::makeNodesByDir;
5312   }
5313 }
5314
5315 //=======================================================================
5316 //function : ExtrusParam
5317 //purpose  : for extrusion by normal
5318 //=======================================================================
5319
5320 SMESH_MeshEditor::ExtrusParam::ExtrusParam( const double theStepSize,
5321                                             const int    theNbSteps,
5322                                             const int    theFlags,
5323                                             const int    theDim ):
5324   myDir( 1,0,0 ),
5325   mySteps( new TColStd_HSequenceOfReal ),
5326   myFlags( theFlags ),
5327   myTolerance( 0 ),
5328   myElemsToUse( NULL )
5329 {
5330   for (int i = 0; i < theNbSteps; i++ )
5331     mySteps->Append( theStepSize );
5332
5333   if ( theDim == 1 )
5334   {
5335     myMakeNodesFun = & SMESH_MeshEditor::ExtrusParam::makeNodesByNormal1D;
5336   }
5337   else
5338   {
5339     myMakeNodesFun = & SMESH_MeshEditor::ExtrusParam::makeNodesByNormal2D;
5340   }
5341 }
5342
5343 //=======================================================================
5344 //function : ExtrusParam
5345 //purpose  : for extrusion along path
5346 //=======================================================================
5347
5348 SMESH_MeshEditor::ExtrusParam::ExtrusParam( const std::vector< PathPoint >& thePoints,
5349                                             const gp_Pnt*                   theBasePoint,
5350                                             const std::list<double>&        theScales,
5351                                             const bool                      theMakeGroups )
5352   : myBaseP( Precision::Infinite(), 0, 0 ),
5353     myFlags( EXTRUSION_FLAG_BOUNDARY | ( theMakeGroups ? EXTRUSION_FLAG_GROUPS : 0 )),
5354     myPathPoints( thePoints )
5355 {
5356   if ( theBasePoint )
5357   {
5358     myBaseP = theBasePoint->XYZ();
5359   }
5360
5361   if ( !theScales.empty() )
5362   {
5363     // add medium scales
5364     std::list<double>::const_iterator s2 = theScales.begin(), s1 = s2++;
5365     myScales.reserve( thePoints.size() * 2 );
5366     myScales.push_back( 0.5 * ( 1. + *s1 ));
5367     myScales.push_back( *s1 );
5368     for ( ; s2 != theScales.end(); s1 = s2++ )
5369     {
5370       myScales.push_back( 0.5 * ( *s1 + *s2 ));
5371       myScales.push_back( *s2 );
5372     }
5373   }
5374
5375   myMakeNodesFun = & SMESH_MeshEditor::ExtrusParam::makeNodesAlongTrack;
5376 }
5377
5378 //=======================================================================
5379 //function : ExtrusParam::SetElementsToUse
5380 //purpose  : stores elements to use for extrusion by normal, depending on
5381 //           state of EXTRUSION_FLAG_USE_INPUT_ELEMS_ONLY flag;
5382 //           define myBaseP for scaling
5383 //=======================================================================
5384
5385 void SMESH_MeshEditor::ExtrusParam::SetElementsToUse( const TIDSortedElemSet& elems,
5386                                                       const TIDSortedElemSet& nodes )
5387 {
5388   myElemsToUse = ToUseInpElemsOnly() ? & elems : 0;
5389
5390   if ( Precision::IsInfinite( myBaseP.X() )) // myBaseP not defined
5391   {
5392     myBaseP.SetCoord( 0.,0.,0. );
5393     TIDSortedElemSet newNodes;
5394
5395     const TIDSortedElemSet* elemSets[] = { &elems, &nodes };
5396     for ( int is2ndSet = 0; is2ndSet < 2; ++is2ndSet )
5397     {
5398       const TIDSortedElemSet& elements = *( elemSets[ is2ndSet ]);
5399       TIDSortedElemSet::const_iterator itElem = elements.begin();
5400       for ( ; itElem != elements.end(); itElem++ )
5401       {
5402         const SMDS_MeshElement* elem = *itElem;
5403         SMDS_ElemIteratorPtr     itN = elem->nodesIterator();
5404         while ( itN->more() ) {
5405           const SMDS_MeshElement* node = itN->next();
5406           if ( newNodes.insert( node ).second )
5407             myBaseP += SMESH_NodeXYZ( node );
5408         }
5409       }
5410     }
5411     myBaseP /= newNodes.size();
5412   }
5413 }
5414
5415 //=======================================================================
5416 //function : ExtrusParam::beginStepIter
5417 //purpose  : prepare iteration on steps
5418 //=======================================================================
5419
5420 void SMESH_MeshEditor::ExtrusParam::beginStepIter( bool withMediumNodes )
5421 {
5422   myWithMediumNodes = withMediumNodes;
5423   myNextStep = 1;
5424   myCurSteps.clear();
5425 }
5426 //=======================================================================
5427 //function : ExtrusParam::moreSteps
5428 //purpose  : are there more steps?
5429 //=======================================================================
5430
5431 bool SMESH_MeshEditor::ExtrusParam::moreSteps()
5432 {
5433   return myNextStep <= mySteps->Length() || !myCurSteps.empty();
5434 }
5435 //=======================================================================
5436 //function : ExtrusParam::nextStep
5437 //purpose  : returns the next step
5438 //=======================================================================
5439
5440 double SMESH_MeshEditor::ExtrusParam::nextStep()
5441 {
5442   double res = 0;
5443   if ( !myCurSteps.empty() )
5444   {
5445     res = myCurSteps.back();
5446     myCurSteps.pop_back();
5447   }
5448   else if ( myNextStep <= mySteps->Length() )
5449   {
5450     myCurSteps.push_back( mySteps->Value( myNextStep ));
5451     ++myNextStep;
5452     if ( myWithMediumNodes )
5453     {
5454       myCurSteps.back() /= 2.;
5455       myCurSteps.push_back( myCurSteps.back() );
5456     }
5457     res = nextStep();
5458   }
5459   return res;
5460 }
5461
5462 //=======================================================================
5463 //function : ExtrusParam::makeNodesByDir
5464 //purpose  : create nodes for standard extrusion
5465 //=======================================================================
5466
5467 int SMESH_MeshEditor::ExtrusParam::
5468 makeNodesByDir( SMESHDS_Mesh*                     mesh,
5469                 const SMDS_MeshNode*              srcNode,
5470                 std::list<const SMDS_MeshNode*> & newNodes,
5471                 const bool                        makeMediumNodes)
5472 {
5473   gp_XYZ p = SMESH_NodeXYZ( srcNode );
5474
5475   int nbNodes = 0;
5476   for ( beginStepIter( makeMediumNodes ); moreSteps(); ++nbNodes ) // loop on steps
5477   {
5478     p += myDir.XYZ() * nextStep();
5479     const SMDS_MeshNode * newNode = mesh->AddNode( p.X(), p.Y(), p.Z() );
5480     newNodes.push_back( newNode );
5481   }
5482
5483   if ( !myScales.empty() || !myAngles.empty() )
5484   {
5485     gp_XYZ  center = myBaseP;
5486     gp_Ax1  ratationAxis( center, myDir );
5487     gp_Trsf rotation;
5488
5489     std::list<const SMDS_MeshNode*>::iterator nIt = newNodes.begin();
5490     size_t i = !makeMediumNodes;
5491     for ( beginStepIter( makeMediumNodes );
5492           moreSteps();
5493           ++nIt, i += 1 + !makeMediumNodes )
5494     {
5495       center += myDir.XYZ() * nextStep();
5496
5497       gp_XYZ xyz = SMESH_NodeXYZ( *nIt );
5498       bool moved = false;
5499       if ( i < myScales.size() )
5500       {
5501         xyz = ( myScales[i] * ( xyz - center )) + center;
5502         moved = true;
5503       }
5504       if ( !myAngles.empty() )
5505       {
5506         rotation.SetRotation( ratationAxis, myAngles[i] );
5507         rotation.Transforms( xyz );
5508         moved = true;
5509       }
5510       if ( moved )
5511         mesh->MoveNode( *nIt, xyz.X(), xyz.Y(), xyz.Z() );
5512       else
5513         break;
5514     }
5515   }
5516   return nbNodes;
5517 }
5518
5519 //=======================================================================
5520 //function : ExtrusParam::makeNodesByDirAndSew
5521 //purpose  : create nodes for standard extrusion with sewing
5522 //=======================================================================
5523
5524 int SMESH_MeshEditor::ExtrusParam::
5525 makeNodesByDirAndSew( SMESHDS_Mesh*                     mesh,
5526                       const SMDS_MeshNode*              srcNode,
5527                       std::list<const SMDS_MeshNode*> & newNodes,
5528                       const bool                        makeMediumNodes)
5529 {
5530   gp_XYZ P1 = SMESH_NodeXYZ( srcNode );
5531
5532   int nbNodes = 0;
5533   for ( beginStepIter( makeMediumNodes ); moreSteps(); ++nbNodes ) // loop on steps
5534   {
5535     P1 += myDir.XYZ() * nextStep();
5536
5537     // try to search in sequence of existing nodes
5538     // if myNodes.size()>0 we 'nave to use given sequence
5539     // else - use all nodes of mesh
5540     const SMDS_MeshNode * node = 0;
5541     if ( myNodes.Length() > 0 )
5542     {
5543       for ( int i = 1; i <= myNodes.Length(); i++ )
5544       {
5545         SMESH_NodeXYZ P2 = myNodes.Value(i);
5546         if (( P1 - P2 ).SquareModulus() < myTolerance * myTolerance )
5547         {
5548           node = myNodes.Value(i);
5549           break;
5550         }
5551       }
5552     }
5553     else
5554     {
5555       SMDS_NodeIteratorPtr itn = mesh->nodesIterator();
5556       while(itn->more())
5557       {
5558         SMESH_NodeXYZ P2 = itn->next();
5559         if (( P1 - P2 ).SquareModulus() < myTolerance * myTolerance )
5560         {
5561           node = P2._node;
5562           break;
5563         }
5564       }
5565     }
5566
5567     if ( !node )
5568       node = mesh->AddNode( P1.X(), P1.Y(), P1.Z() );
5569
5570     newNodes.push_back( node );
5571
5572   } // loop on steps
5573
5574   return nbNodes;
5575 }
5576
5577 //=======================================================================
5578 //function : ExtrusParam::makeNodesByNormal2D
5579 //purpose  : create nodes for extrusion using normals of faces
5580 //=======================================================================
5581
5582 int SMESH_MeshEditor::ExtrusParam::
5583 makeNodesByNormal2D( SMESHDS_Mesh*                     mesh,
5584                      const SMDS_MeshNode*              srcNode,
5585                      std::list<const SMDS_MeshNode*> & newNodes,
5586                      const bool                        makeMediumNodes)
5587 {
5588   const bool alongAvgNorm = ( myFlags & EXTRUSION_FLAG_BY_AVG_NORMAL );
5589
5590   gp_XYZ p = SMESH_NodeXYZ( srcNode );
5591
5592   // get normals to faces sharing srcNode
5593   vector< gp_XYZ > norms, baryCenters;
5594   gp_XYZ norm, avgNorm( 0,0,0 );
5595   SMDS_ElemIteratorPtr faceIt = srcNode->GetInverseElementIterator( SMDSAbs_Face );
5596   while ( faceIt->more() )
5597   {
5598     const SMDS_MeshElement* face = faceIt->next();
5599     if ( myElemsToUse && !myElemsToUse->count( face ))
5600       continue;
5601     if ( SMESH_MeshAlgos::FaceNormal( face, norm, /*normalized=*/true ))
5602     {
5603       norms.push_back( norm );
5604       avgNorm += norm;
5605       if ( !alongAvgNorm )
5606       {
5607         gp_XYZ bc(0,0,0);
5608         int nbN = 0;
5609         for ( SMDS_ElemIteratorPtr nIt = face->nodesIterator(); nIt->more(); ++nbN )
5610           bc += SMESH_NodeXYZ( nIt->next() );
5611         baryCenters.push_back( bc / nbN );
5612       }
5613     }
5614   }
5615
5616   if ( norms.empty() ) return 0;
5617
5618   double normSize = avgNorm.Modulus();
5619   if ( normSize < std::numeric_limits<double>::min() )
5620     return 0;
5621
5622   if ( myFlags & EXTRUSION_FLAG_BY_AVG_NORMAL ) // extrude along avgNorm
5623   {
5624     myDir = avgNorm;
5625     return makeNodesByDir( mesh, srcNode, newNodes, makeMediumNodes );
5626   }
5627
5628   avgNorm /= normSize;
5629
5630   int nbNodes = 0;
5631   for ( beginStepIter( makeMediumNodes ); moreSteps(); ++nbNodes ) // loop on steps
5632   {
5633     gp_XYZ pNew = p;
5634     double stepSize = nextStep();
5635
5636     if ( norms.size() > 1 )
5637     {
5638       for ( size_t iF = 0; iF < norms.size(); ++iF ) // loop on faces
5639       {
5640         // translate plane of a face
5641         baryCenters[ iF ] += norms[ iF ] * stepSize;
5642
5643         // find point of intersection of the face plane located at baryCenters[ iF ]
5644         // and avgNorm located at pNew
5645         double d    = -( norms[ iF ] * baryCenters[ iF ]); // d of plane equation ax+by+cz+d=0
5646         double dot  = ( norms[ iF ] * avgNorm );
5647         if ( dot < std::numeric_limits<double>::min() )
5648           dot = stepSize * 1e-3;
5649         double step = -( norms[ iF ] * pNew + d ) / dot;
5650         pNew += step * avgNorm;
5651       }
5652     }
5653     else
5654     {
5655       pNew += stepSize * avgNorm;
5656     }
5657     p = pNew;
5658
5659     const SMDS_MeshNode * newNode = mesh->AddNode( p.X(), p.Y(), p.Z() );
5660     newNodes.push_back( newNode );
5661   }
5662   return nbNodes;
5663 }
5664
5665 //=======================================================================
5666 //function : ExtrusParam::makeNodesByNormal1D
5667 //purpose  : create nodes for extrusion using normals of edges
5668 //=======================================================================
5669
5670 int SMESH_MeshEditor::ExtrusParam::
5671 makeNodesByNormal1D( SMESHDS_Mesh*                     /*mesh*/,
5672                      const SMDS_MeshNode*              /*srcNode*/,
5673                      std::list<const SMDS_MeshNode*> & /*newNodes*/,
5674                      const bool                        /*makeMediumNodes*/)
5675 {
5676   throw SALOME_Exception("Extrusion 1D by Normal not implemented");
5677   return 0;
5678 }
5679
5680 //=======================================================================
5681 //function : ExtrusParam::makeNodesAlongTrack
5682 //purpose  : create nodes for extrusion along path
5683 //=======================================================================
5684
5685 int SMESH_MeshEditor::ExtrusParam::
5686 makeNodesAlongTrack( SMESHDS_Mesh*                     mesh,
5687                      const SMDS_MeshNode*              srcNode,
5688                      std::list<const SMDS_MeshNode*> & newNodes,
5689                      const bool                        makeMediumNodes)
5690 {
5691   const Standard_Real aTolAng=1.e-4;
5692
5693   gp_Pnt aV0x = myBaseP;
5694   gp_Pnt aPN0 = SMESH_NodeXYZ( srcNode );
5695
5696   const PathPoint& aPP0 = myPathPoints[0];
5697   gp_Pnt aP0x = aPP0.myPnt;
5698   gp_Dir aDT0x= aPP0.myTgt;
5699
5700   std::vector< gp_Pnt > centers;
5701   centers.reserve( NbSteps() * 2 );
5702
5703   gp_Trsf aTrsf, aTrsfRot, aTrsfRotT1T0;
5704
5705   for ( size_t j = 1; j < myPathPoints.size(); ++j )
5706   {
5707     const PathPoint&  aPP  = myPathPoints[j];
5708     const gp_Pnt&     aP1x = aPP.myPnt;
5709     const gp_Dir&    aDT1x = aPP.myTgt;
5710
5711     // Translation
5712     gp_Vec aV01x( aP0x, aP1x );
5713     aTrsf.SetTranslation( aV01x );
5714     gp_Pnt aV1x = aV0x.Transformed( aTrsf );
5715     gp_Pnt aPN1 = aPN0.Transformed( aTrsf );
5716
5717     // rotation 1 [ T1,T0 ]
5718     Standard_Real aAngleT1T0 = -aDT1x.Angle( aDT0x );
5719     if ( fabs( aAngleT1T0 ) > aTolAng )
5720     {
5721       gp_Dir aDT1T0 = aDT1x ^ aDT0x;
5722       aTrsfRotT1T0.SetRotation( gp_Ax1( aV1x, aDT1T0 ), aAngleT1T0 );
5723
5724       aPN1 = aPN1.Transformed( aTrsfRotT1T0 );
5725     }
5726
5727     // rotation 2
5728     if ( aPP.myAngle != 0. )
5729     {
5730       aTrsfRot.SetRotation( gp_Ax1( aV1x, aDT1x ), aPP.myAngle );
5731       aPN1 = aPN1.Transformed( aTrsfRot );
5732     }
5733
5734     // make new node
5735     if ( makeMediumNodes )
5736     {
5737       // create additional node
5738       gp_XYZ midP = 0.5 * ( aPN1.XYZ() + aPN0.XYZ() );
5739       const SMDS_MeshNode* newNode = mesh->AddNode( midP.X(), midP.Y(), midP.Z() );
5740       newNodes.push_back( newNode );
5741
5742     }
5743     const SMDS_MeshNode* newNode = mesh->AddNode( aPN1.X(), aPN1.Y(), aPN1.Z() );
5744     newNodes.push_back( newNode );
5745
5746     centers.push_back( 0.5 * ( aV0x.XYZ() + aV1x.XYZ() ));
5747     centers.push_back( aV1x );
5748
5749     aPN0 = aPN1;
5750     aP0x = aP1x;
5751     aV0x = aV1x;
5752     aDT0x = aDT1x;
5753   }
5754
5755   // scale
5756   if ( !myScales.empty() )
5757   {
5758     gp_Trsf aTrsfScale;
5759     std::list<const SMDS_MeshNode*>::iterator node = newNodes.begin();
5760     for ( size_t i = !makeMediumNodes;
5761           i < myScales.size() && node != newNodes.end();
5762           i += ( 1 + !makeMediumNodes ), ++node )
5763     {
5764       aTrsfScale.SetScale( centers[ i ], myScales[ i ] );
5765       gp_Pnt aN = SMESH_NodeXYZ( *node );
5766       gp_Pnt aP = aN.Transformed( aTrsfScale );
5767       mesh->MoveNode( *node, aP.X(), aP.Y(), aP.Z() );
5768     }
5769   }
5770
5771   return myPathPoints.size() + makeMediumNodes * ( myPathPoints.size() - 2 );
5772 }
5773
5774 //=======================================================================
5775 //function : ExtrusionSweep
5776 //purpose  :
5777 //=======================================================================
5778
5779 SMESH_MeshEditor::PGroupIDs
5780 SMESH_MeshEditor::ExtrusionSweep (TIDSortedElemSet     theElems[2],
5781                                   const gp_Vec&        theStep,
5782                                   const int            theNbSteps,
5783                                   TTElemOfElemListMap& newElemsMap,
5784                                   const int            theFlags,
5785                                   const double         theTolerance)
5786 {
5787   std::list<double> dummy;
5788   ExtrusParam aParams( theStep, theNbSteps, dummy, dummy, 0,
5789                        theFlags, theTolerance );
5790   return ExtrusionSweep( theElems, aParams, newElemsMap );
5791 }
5792
5793 namespace
5794 {
5795
5796 //=======================================================================
5797 //function : getOriFactor
5798 //purpose  : Return -1 or 1 depending on if order of given nodes corresponds to
5799 //           edge curve orientation
5800 //=======================================================================
5801
5802   double getOriFactor( const TopoDS_Edge&   edge,
5803                        const SMDS_MeshNode* n1,
5804                        const SMDS_MeshNode* n2,
5805                        SMESH_MesherHelper&  helper)
5806   {
5807     double u1 = helper.GetNodeU( edge, n1, n2 );
5808     double u2 = helper.GetNodeU( edge, n2, n1 );
5809     return u1 < u2 ? 1. : -1.;
5810   }
5811 }
5812
5813 //=======================================================================
5814 //function : ExtrusionSweep
5815 //purpose  :
5816 //=======================================================================
5817
5818 SMESH_MeshEditor::PGroupIDs
5819 SMESH_MeshEditor::ExtrusionSweep (TIDSortedElemSet     theElemSets[2],
5820                                   ExtrusParam&         theParams,
5821                                   TTElemOfElemListMap& newElemsMap)
5822 {
5823   ClearLastCreated();
5824
5825   setElemsFirst( theElemSets );
5826   myLastCreatedElems.reserve( theElemSets[0].size() * theParams.NbSteps() );
5827   myLastCreatedNodes.reserve( theElemSets[1].size() * theParams.NbSteps() );
5828
5829   // source elements for each generated one
5830   SMESH_SequenceOfElemPtr srcElems, srcNodes;
5831   srcElems.reserve( theElemSets[0].size() );
5832   srcNodes.reserve( theElemSets[1].size() );
5833
5834   const int nbSteps = theParams.NbSteps();
5835   theParams.SetElementsToUse( theElemSets[0], theElemSets[1] );
5836
5837   TNodeOfNodeListMap   mapNewNodes;
5838   TElemOfVecOfNnlmiMap mapElemNewNodes;
5839
5840   const bool isQuadraticMesh = bool( myMesh->NbEdges(ORDER_QUADRATIC) +
5841                                      myMesh->NbFaces(ORDER_QUADRATIC) +
5842                                      myMesh->NbVolumes(ORDER_QUADRATIC) );
5843   // loop on theElems
5844   TIDSortedElemSet::iterator itElem;
5845   for ( int is2ndSet = 0; is2ndSet < 2; ++is2ndSet )
5846   {
5847     TIDSortedElemSet& theElems = theElemSets[ is2ndSet ];
5848     for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ )
5849     {
5850       // check element type
5851       const SMDS_MeshElement* elem = *itElem;
5852       if ( !elem  || elem->GetType() == SMDSAbs_Volume )
5853         continue;
5854
5855       const size_t nbNodes = elem->NbNodes();
5856       vector<TNodeOfNodeListMapItr> & newNodesItVec = mapElemNewNodes[ elem ];
5857       newNodesItVec.reserve( nbNodes );
5858
5859       // loop on elem nodes
5860       SMDS_NodeIteratorPtr itN = elem->nodeIterator();
5861       while ( itN->more() )
5862       {
5863         // check if a node has been already sweeped
5864         const SMDS_MeshNode* node = itN->next();
5865         TNodeOfNodeListMap::iterator nIt =
5866           mapNewNodes.insert( make_pair( node, list<const SMDS_MeshNode*>() )).first;
5867         list<const SMDS_MeshNode*>& listNewNodes = nIt->second;
5868         if ( listNewNodes.empty() )
5869         {
5870           // make new nodes
5871
5872           // check if we are to create medium nodes between corner ones
5873           bool needMediumNodes = false;
5874           if ( isQuadraticMesh )
5875           {
5876             SMDS_ElemIteratorPtr it = node->GetInverseElementIterator();
5877             while (it->more() && !needMediumNodes )
5878             {
5879               const SMDS_MeshElement* invElem = it->next();
5880               if ( invElem != elem && !theElems.count( invElem )) continue;
5881               needMediumNodes = ( invElem->IsQuadratic() && !invElem->IsMediumNode(node) );
5882               if ( !needMediumNodes && invElem->GetEntityType() == SMDSEntity_BiQuad_Quadrangle )
5883                 needMediumNodes = true;
5884             }
5885           }
5886           // create nodes for all steps
5887           if ( theParams.MakeNodes( GetMeshDS(), node, listNewNodes, needMediumNodes ))
5888           {
5889             list<const SMDS_MeshNode*>::iterator newNodesIt = listNewNodes.begin();
5890             for ( ; newNodesIt != listNewNodes.end(); ++newNodesIt )
5891             {
5892               myLastCreatedNodes.push_back( *newNodesIt );
5893               srcNodes.push_back( node );
5894             }
5895           }
5896           else
5897           {
5898             if ( theParams.ToMakeBoundary() )
5899             {
5900               GetMeshDS()->Modified();
5901               throw SALOME_Exception( SMESH_Comment("Can't extrude node #") << node->GetID() );
5902             }
5903             break; // newNodesItVec will be shorter than nbNodes
5904           }
5905         }
5906         newNodesItVec.push_back( nIt );
5907       }
5908       // make new elements
5909       if ( newNodesItVec.size() == nbNodes )
5910         sweepElement( elem, newNodesItVec, newElemsMap[elem], nbSteps, srcElems );
5911     }
5912   }
5913
5914   if ( theParams.ToMakeBoundary() ) {
5915     makeWalls( mapNewNodes, newElemsMap, mapElemNewNodes, theElemSets[0], nbSteps, srcElems );
5916   }
5917   PGroupIDs newGroupIDs;
5918   if ( theParams.ToMakeGroups() )
5919     newGroupIDs = generateGroups( srcNodes, srcElems, "extruded");
5920
5921   return newGroupIDs;
5922 }
5923
5924 //=======================================================================
5925 //function : ExtrusionAlongTrack
5926 //purpose  :
5927 //=======================================================================
5928 SMESH_MeshEditor::Extrusion_Error
5929 SMESH_MeshEditor::ExtrusionAlongTrack (TIDSortedElemSet     theElements[2],
5930                                        SMESH_Mesh*          theTrackMesh,
5931                                        SMDS_ElemIteratorPtr theTrackIterator,
5932                                        const SMDS_MeshNode* theN1,
5933                                        std::list<double>&   theAngles,
5934                                        const bool           theAngleVariation,
5935                                        std::list<double>&   theScales,
5936                                        const bool           theScaleVariation,
5937                                        const gp_Pnt*        theRefPoint,
5938                                        const bool           theMakeGroups)
5939 {
5940   ClearLastCreated();
5941
5942   // 1. Check data
5943   if ( theElements[0].empty() && theElements[1].empty() )
5944     return EXTR_NO_ELEMENTS;
5945
5946   ASSERT( theTrackMesh );
5947   if ( ! theTrackIterator || !theTrackIterator->more() )
5948     return EXTR_NO_ELEMENTS;
5949
5950   // 2. Get ordered nodes
5951   SMESH_MeshAlgos::TElemGroupVector branchEdges;
5952   SMESH_MeshAlgos::TNodeGroupVector branchNods;
5953   SMESH_MeshAlgos::Get1DBranches( theTrackIterator, branchEdges, branchNods, theN1 );
5954   if ( branchEdges.empty() )
5955     return EXTR_PATH_NOT_EDGE;
5956
5957   if ( branchEdges.size() > 1 )
5958     return EXTR_BAD_PATH_SHAPE;
5959
5960   std::vector< const SMDS_MeshNode* >&    pathNodes = branchNods[0];
5961   std::vector< const SMDS_MeshElement* >& pathEdges = branchEdges[0];
5962   if ( pathNodes[0] != theN1 && pathNodes[1] != theN1 )
5963     return EXTR_BAD_STARTING_NODE;
5964
5965   if ( theTrackMesh->NbEdges( ORDER_QUADRATIC ) > 0 )
5966   {
5967     // add medium nodes to pathNodes
5968     std::vector< const SMDS_MeshNode* >    pathNodes2;
5969     std::vector< const SMDS_MeshElement* > pathEdges2;
5970     pathNodes2.reserve( pathNodes.size() * 2 );
5971     pathEdges2.reserve( pathEdges.size() * 2 );
5972     for ( size_t i = 0; i < pathEdges.size(); ++i )
5973     {
5974       pathNodes2.push_back( pathNodes[i] );
5975       pathEdges2.push_back( pathEdges[i] );
5976       if ( pathEdges[i]->IsQuadratic() )
5977       {
5978         pathNodes2.push_back( pathEdges[i]->GetNode(2) );
5979         pathEdges2.push_back( pathEdges[i] );
5980       }
5981     }
5982     pathNodes2.push_back( pathNodes.back() );
5983     pathEdges.swap( pathEdges2 );
5984     pathNodes.swap( pathNodes2 );
5985   }
5986
5987   // 3. Get path data at pathNodes
5988
5989   std::vector< ExtrusParam::PathPoint > points( pathNodes.size() );
5990
5991   if ( theAngleVariation )
5992     linearAngleVariation( points.size()-1, theAngles );
5993   if ( theScaleVariation )
5994     linearScaleVariation( points.size()-1, theScales );
5995
5996   theAngles.push_front( 0 ); // for the 1st point that is not transformed
5997   std::list<double>::iterator angle = theAngles.begin();
5998
5999   SMESHDS_Mesh* pathMeshDS = theTrackMesh->GetMeshDS();
6000
6001   std::map< int, double > edgeID2OriFactor; // orientation of EDGEs
6002   std::map< int, double >::iterator id2factor;
6003   SMESH_MesherHelper pathHelper( *theTrackMesh );
6004   gp_Pnt p; gp_Vec tangent;
6005   const double tol2 = gp::Resolution() * gp::Resolution();
6006
6007   for ( size_t i = 0; i < pathNodes.size(); ++i )
6008   {
6009     ExtrusParam::PathPoint & point = points[ i ];
6010
6011     point.myPnt = SMESH_NodeXYZ( pathNodes[ i ]);
6012
6013     if ( angle != theAngles.end() )
6014       point.myAngle = *angle++;
6015
6016     tangent.SetCoord( 0,0,0 );
6017     const int          shapeID = pathNodes[ i ]->GetShapeID();
6018     const TopoDS_Shape&  shape = pathMeshDS->IndexToShape( shapeID );
6019     TopAbs_ShapeEnum shapeType = shape.IsNull() ? TopAbs_SHAPE : shape.ShapeType();
6020     switch ( shapeType )
6021     {
6022     case TopAbs_EDGE:
6023     {
6024       TopoDS_Edge edge = TopoDS::Edge( shape );
6025       id2factor = edgeID2OriFactor.insert( std::make_pair( shapeID, 0 )).first;
6026       if ( id2factor->second == 0 )
6027       {
6028         if ( i ) id2factor->second = getOriFactor( edge, pathNodes[i-1], pathNodes[i], pathHelper );
6029         else     id2factor->second = getOriFactor( edge, pathNodes[i], pathNodes[i+1], pathHelper );
6030       }
6031       double u = pathHelper.GetNodeU( edge, pathNodes[i] ), u0, u1;
6032       Handle(Geom_Curve) curve = BRep_Tool::Curve( edge, u0, u1 );
6033       curve->D1( u, p, tangent );
6034       tangent *= id2factor->second;
6035       break;
6036     }
6037     case TopAbs_VERTEX:
6038     {
6039       int nbEdges = 0;
6040       PShapeIteratorPtr shapeIt = pathHelper.GetAncestors( shape, *theTrackMesh, TopAbs_EDGE );
6041       while ( const TopoDS_Shape* edgePtr = shapeIt->next() )
6042       {
6043         int edgeID = pathMeshDS->ShapeToIndex( *edgePtr );
6044         for ( int di = -1; di <= 0; ++di )
6045         {
6046           size_t j = i + di;
6047           if ( j < pathEdges.size() && edgeID == pathEdges[ j ]->GetShapeID() )
6048           {
6049             TopoDS_Edge edge = TopoDS::Edge( *edgePtr );
6050             id2factor = edgeID2OriFactor.insert( std::make_pair( edgeID, 0 )).first;
6051             if ( id2factor->second == 0 )
6052             {
6053               if ( j < i )
6054                 id2factor->second = getOriFactor( edge, pathNodes[i-1], pathNodes[i], pathHelper );
6055               else
6056                 id2factor->second = getOriFactor( edge, pathNodes[i], pathNodes[i+1], pathHelper );
6057             }
6058             double u = pathHelper.GetNodeU( edge, pathNodes[i] ), u0, u1;
6059             Handle(Geom_Curve) curve = BRep_Tool::Curve( edge, u0, u1 );
6060             gp_Vec du;
6061             curve->D1( u, p, du );
6062             double size2 = du.SquareMagnitude();
6063             if ( du.SquareMagnitude() > tol2 )
6064             {
6065               tangent += du.Divided( Sqrt( size2 )) * id2factor->second;
6066               nbEdges++;
6067             }
6068             break;
6069           }
6070         }
6071       }
6072       if ( nbEdges > 0 )
6073         break;
6074     }
6075     // fall through
6076     default:
6077     {
6078       for ( int di = -1; di <= 1; di += 2 )
6079       {
6080         size_t j = i + di;
6081         if ( j < pathNodes.size() )
6082         {
6083           gp_Vec dir( point.myPnt, SMESH_NodeXYZ( pathNodes[ j ]));
6084           double size2 = dir.SquareMagnitude();
6085           if ( size2 > tol2 )
6086             tangent += dir.Divided( Sqrt( size2 )) * di;
6087         }
6088       }
6089     }
6090     } // switch ( shapeType )
6091
6092     if ( tangent.SquareMagnitude() < tol2 )
6093       return EXTR_CANT_GET_TANGENT;
6094
6095     point.myTgt = tangent;
6096
6097   } // loop on pathNodes
6098
6099
6100   ExtrusParam nodeMaker( points, theRefPoint, theScales, theMakeGroups );
6101   TTElemOfElemListMap newElemsMap;
6102
6103   ExtrusionSweep( theElements, nodeMaker, newElemsMap );
6104
6105   return EXTR_OK;
6106 }
6107
6108 //=======================================================================
6109 //function : linearAngleVariation
6110 //purpose  : spread values over nbSteps
6111 //=======================================================================
6112
6113 void SMESH_MeshEditor::linearAngleVariation(const int     nbSteps,
6114                                             list<double>& Angles)
6115 {
6116   int nbAngles = Angles.size();
6117   if( nbSteps > nbAngles && nbAngles > 0 )
6118   {
6119     vector<double> theAngles(nbAngles);
6120     theAngles.assign( Angles.begin(), Angles.end() );
6121
6122     list<double> res;
6123     double rAn2St = double( nbAngles ) / double( nbSteps );
6124     double angPrev = 0, angle;
6125     for ( int iSt = 0; iSt < nbSteps; ++iSt )
6126     {
6127       double angCur = rAn2St * ( iSt+1 );
6128       double angCurFloor  = floor( angCur );
6129       double angPrevFloor = floor( angPrev );
6130       if ( angPrevFloor == angCurFloor )
6131         angle = rAn2St * theAngles[ int( angCurFloor ) ];
6132       else {
6133         int iP = int( angPrevFloor );
6134         double angPrevCeil = ceil(angPrev);
6135         angle = ( angPrevCeil - angPrev ) * theAngles[ iP ];
6136
6137         int iC = int( angCurFloor );
6138         if ( iC < nbAngles )
6139           angle += ( angCur - angCurFloor ) * theAngles[ iC ];
6140
6141         iP = int( angPrevCeil );
6142         while ( iC-- > iP )
6143           angle += theAngles[ iC ];
6144       }
6145       res.push_back(angle);
6146       angPrev = angCur;
6147     }
6148     Angles.swap( res );
6149   }
6150 }
6151
6152 //=======================================================================
6153 //function : linearScaleVariation
6154 //purpose  : spread values over nbSteps 
6155 //=======================================================================
6156
6157 void SMESH_MeshEditor::linearScaleVariation(const int          theNbSteps,
6158                                             std::list<double>& theScales)
6159 {
6160   int nbScales = theScales.size();
6161   std::vector<double> myScales;
6162   myScales.reserve( theNbSteps );
6163   std::list<double>::const_iterator scale = theScales.begin();
6164   double prevScale = 1.0;
6165   for ( int iSc = 1; scale != theScales.end(); ++scale, ++iSc )
6166   {
6167     int      iStep = int( iSc / double( nbScales ) * theNbSteps + 0.5 );
6168     int    stDelta = Max( 1, iStep - myScales.size());
6169     double scDelta = ( *scale - prevScale ) / stDelta;
6170     for ( int iStep = 0; iStep < stDelta; ++iStep )
6171     {
6172       myScales.push_back( prevScale + scDelta );
6173       prevScale = myScales.back();
6174     }
6175     prevScale = *scale;
6176   }
6177   theScales.assign( myScales.begin(), myScales.end() );
6178 }
6179
6180 //================================================================================
6181 /*!
6182  * \brief Move or copy theElements applying theTrsf to their nodes
6183  *  \param theElems - elements to transform, if theElems is empty then apply to all mesh nodes
6184  *  \param theTrsf - transformation to apply
6185  *  \param theCopy - if true, create translated copies of theElems
6186  *  \param theMakeGroups - if true and theCopy, create translated groups
6187  *  \param theTargetMesh - mesh to copy translated elements into
6188  *  \return SMESH_MeshEditor::PGroupIDs - list of ids of created groups
6189  */
6190 //================================================================================
6191
6192 SMESH_MeshEditor::PGroupIDs
6193 SMESH_MeshEditor::Transform (TIDSortedElemSet & theElems,
6194                              const gp_Trsf&     theTrsf,
6195                              const bool         theCopy,
6196                              const bool         theMakeGroups,
6197                              SMESH_Mesh*        theTargetMesh)
6198 {
6199   ClearLastCreated();
6200   myLastCreatedElems.reserve( theElems.size() );
6201
6202   bool needReverse = false;
6203   string groupPostfix;
6204   switch ( theTrsf.Form() ) {
6205   case gp_PntMirror:
6206     needReverse = true;
6207     groupPostfix = "mirrored";
6208     break;
6209   case gp_Ax1Mirror:
6210     groupPostfix = "mirrored";
6211     break;
6212   case gp_Ax2Mirror:
6213     needReverse = true;
6214     groupPostfix = "mirrored";
6215     break;
6216   case gp_Rotation:
6217     groupPostfix = "rotated";
6218     break;
6219   case gp_Translation:
6220     groupPostfix = "translated";
6221     break;
6222   case gp_Scale:
6223     groupPostfix = "scaled";
6224     break;
6225   case gp_CompoundTrsf: // different scale by axis
6226     groupPostfix = "scaled";
6227     break;
6228   default:
6229     needReverse = false;
6230     groupPostfix = "transformed";
6231   }
6232
6233   SMESHDS_Mesh* aTgtMesh = theTargetMesh ? theTargetMesh->GetMeshDS() : 0;
6234   SMESHDS_Mesh* aMesh    = GetMeshDS();
6235
6236   SMESH_MeshEditor targetMeshEditor( theTargetMesh );
6237   SMESH_MeshEditor* editor = theTargetMesh ? & targetMeshEditor : theCopy ? this : 0;
6238   SMESH_MeshEditor::ElemFeatures elemType;
6239
6240   // map old node to new one
6241   TNodeNodeMap nodeMap;
6242
6243   // elements sharing moved nodes; those of them which have all
6244   // nodes mirrored but are not in theElems are to be reversed
6245   TIDSortedElemSet inverseElemSet;
6246
6247   // source elements for each generated one
6248   SMESH_SequenceOfElemPtr srcElems, srcNodes;
6249
6250   // issue 021015: EDF 1578 SMESH: Free nodes are removed when translating a mesh
6251   TIDSortedElemSet orphanNode;
6252
6253   if ( theElems.empty() ) // transform the whole mesh
6254   {
6255     // add all elements
6256     SMDS_ElemIteratorPtr eIt = aMesh->elementsIterator();
6257     while ( eIt->more() ) theElems.insert( eIt->next() );
6258     // add orphan nodes
6259     SMDS_NodeIteratorPtr nIt = aMesh->nodesIterator();
6260     while ( nIt->more() )
6261     {
6262       const SMDS_MeshNode* node = nIt->next();
6263       if ( node->NbInverseElements() == 0)
6264         orphanNode.insert( node );
6265     }
6266   }
6267
6268   // loop on elements to transform nodes : first orphan nodes then elems
6269   TIDSortedElemSet::iterator itElem;
6270   TIDSortedElemSet *elements[] = { &orphanNode, &theElems };
6271   for (int i=0; i<2; i++)
6272     for ( itElem = elements[i]->begin(); itElem != elements[i]->end(); itElem++ )
6273     {
6274       const SMDS_MeshElement* elem = *itElem;
6275       if ( !elem )
6276         continue;
6277
6278       // loop on elem nodes
6279       double coord[3];
6280       SMDS_ElemIteratorPtr itN = elem->nodesIterator();
6281       while ( itN->more() )
6282       {
6283         const SMDS_MeshNode* node = cast2Node( itN->next() );
6284         // check if a node has been already transformed
6285         pair<TNodeNodeMap::iterator,bool> n2n_isnew =
6286           nodeMap.insert( make_pair ( node, node ));
6287         if ( !n2n_isnew.second )
6288           continue;
6289
6290         node->GetXYZ( coord );
6291         theTrsf.Transforms( coord[0], coord[1], coord[2] );
6292         if ( theTargetMesh ) {
6293           const SMDS_MeshNode * newNode = aTgtMesh->AddNode( coord[0], coord[1], coord[2] );
6294           n2n_isnew.first->second = newNode;
6295           myLastCreatedNodes.push_back(newNode);
6296           srcNodes.push_back( node );
6297         }
6298         else if ( theCopy ) {
6299           const SMDS_MeshNode * newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
6300           n2n_isnew.first->second = newNode;
6301           myLastCreatedNodes.push_back(newNode);
6302           srcNodes.push_back( node );
6303         }
6304         else {
6305           aMesh->MoveNode( node, coord[0], coord[1], coord[2] );
6306           // node position on shape becomes invalid
6307           const_cast< SMDS_MeshNode* > ( node )->SetPosition
6308             ( SMDS_SpacePosition::originSpacePosition() );
6309         }
6310
6311         // keep inverse elements
6312         if ( !theCopy && !theTargetMesh && needReverse ) {
6313           SMDS_ElemIteratorPtr invElemIt = node->GetInverseElementIterator();
6314           while ( invElemIt->more() ) {
6315             const SMDS_MeshElement* iel = invElemIt->next();
6316             inverseElemSet.insert( iel );
6317           }
6318         }
6319       }
6320     } // loop on elems in { &orphanNode, &theElems };
6321
6322   // either create new elements or reverse mirrored ones
6323   if ( !theCopy && !needReverse && !theTargetMesh )
6324     return PGroupIDs();
6325
6326   theElems.insert( inverseElemSet.begin(),inverseElemSet.end() );
6327
6328   // Replicate or reverse elements
6329
6330   std::vector<int> iForw;
6331   vector<const SMDS_MeshNode*> nodes;
6332   for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ )
6333   {
6334     const SMDS_MeshElement* elem = *itElem;
6335     if ( !elem ) continue;
6336
6337     SMDSAbs_GeometryType geomType = elem->GetGeomType();
6338     size_t               nbNodes  = elem->NbNodes();
6339     if ( geomType == SMDSGeom_NONE ) continue; // node
6340
6341     nodes.resize( nbNodes );
6342
6343     if ( geomType == SMDSGeom_POLYHEDRA )  // ------------------ polyhedral volume
6344     {
6345       const SMDS_MeshVolume* aPolyedre = SMDS_Mesh::DownCast< SMDS_MeshVolume >( elem );
6346       if ( !aPolyedre )
6347         continue;
6348       nodes.clear();
6349       bool allTransformed = true;
6350       int nbFaces = aPolyedre->NbFaces();
6351       for (int iface = 1; iface <= nbFaces && allTransformed; iface++)
6352       {
6353         int nbFaceNodes = aPolyedre->NbFaceNodes(iface);
6354         for (int inode = 1; inode <= nbFaceNodes && allTransformed; inode++)
6355         {
6356           const SMDS_MeshNode* node = aPolyedre->GetFaceNode(iface, inode);
6357           TNodeNodeMap::iterator nodeMapIt = nodeMap.find(node);
6358           if ( nodeMapIt == nodeMap.end() )
6359             allTransformed = false; // not all nodes transformed
6360           else
6361             nodes.push_back((*nodeMapIt).second);
6362         }
6363         if ( needReverse && allTransformed )
6364           std::reverse( nodes.end() - nbFaceNodes, nodes.end() );
6365       }
6366       if ( !allTransformed )
6367         continue; // not all nodes transformed
6368     }
6369     else // ----------------------- the rest element types
6370     {
6371       while ( iForw.size() < nbNodes ) iForw.push_back( iForw.size() );
6372       const vector<int>& iRev = SMDS_MeshCell::reverseSmdsOrder( elem->GetEntityType(), nbNodes );
6373       const vector<int>&    i = needReverse ? iRev : iForw;
6374
6375       // find transformed nodes
6376       size_t iNode = 0;
6377       SMDS_ElemIteratorPtr itN = elem->nodesIterator();
6378       while ( itN->more() ) {
6379         const SMDS_MeshNode* node = static_cast<const SMDS_MeshNode*>( itN->next() );
6380         TNodeNodeMap::iterator nodeMapIt = nodeMap.find( node );
6381         if ( nodeMapIt == nodeMap.end() )
6382           break; // not all nodes transformed
6383         nodes[ i [ iNode++ ]] = (*nodeMapIt).second;
6384       }
6385       if ( iNode != nbNodes )
6386         continue; // not all nodes transformed
6387     }
6388
6389     if ( editor ) {
6390       // copy in this or a new mesh
6391       if ( editor->AddElement( nodes, elemType.Init( elem, /*basicOnly=*/false )))
6392         srcElems.push_back( elem );
6393     }
6394     else {
6395       // reverse element as it was reversed by transformation
6396       if ( nbNodes > 2 )
6397         aMesh->ChangeElementNodes( elem, &nodes[0], nbNodes );
6398     }
6399
6400   } // loop on elements
6401
6402   if ( editor && editor != this )
6403     myLastCreatedElems.swap( editor->myLastCreatedElems );
6404
6405   PGroupIDs newGroupIDs;
6406
6407   if ( ( theMakeGroups && theCopy ) ||
6408        ( theMakeGroups && theTargetMesh ) )
6409     newGroupIDs = generateGroups( srcNodes, srcElems, groupPostfix, theTargetMesh, false );
6410
6411   return newGroupIDs;
6412 }
6413
6414 //================================================================================
6415 /*!
6416  * \brief Make an offset mesh from a source 2D mesh
6417  *  \param [in] theElements - source faces
6418  *  \param [in] theValue - offset value
6419  *  \param [out] theTgtMesh - a mesh to add offset elements to
6420  *  \param [in] theMakeGroups - to generate groups
6421  *  \return PGroupIDs - IDs of created groups. NULL means failure
6422  */
6423 //================================================================================
6424
6425 SMESH_MeshEditor::PGroupIDs SMESH_MeshEditor::Offset( TIDSortedElemSet & theElements,
6426                                                       const double       theValue,
6427                                                       SMESH_Mesh*        theTgtMesh,
6428                                                       const bool         theMakeGroups,
6429                                                       const bool         theCopyElements,
6430                                                       const bool         theFixSelfIntersection)
6431 {
6432   SMESHDS_Mesh*    meshDS = GetMeshDS();
6433   SMESHDS_Mesh* tgtMeshDS = theTgtMesh->GetMeshDS();
6434   SMESH_MeshEditor tgtEditor( theTgtMesh );
6435
6436   SMDS_ElemIteratorPtr eIt;
6437   if ( theElements.empty() ) eIt = meshDS->elementsIterator( SMDSAbs_Face );
6438   else                       eIt = SMESHUtils::elemSetIterator( theElements );
6439
6440   SMESH_MeshAlgos::TElemIntPairVec new2OldFaces;
6441   SMESH_MeshAlgos::TNodeIntPairVec new2OldNodes;
6442   std::unique_ptr< SMDS_Mesh > offsetMesh
6443     ( SMESH_MeshAlgos::MakeOffset( eIt, *meshDS, theValue,
6444                                    theFixSelfIntersection,
6445                                    new2OldFaces, new2OldNodes ));
6446   if ( offsetMesh->NbElements() == 0 )
6447     return PGroupIDs(); // MakeOffset() failed
6448
6449
6450   if ( theTgtMesh == myMesh && !theCopyElements )
6451   {
6452     // clear the source elements
6453     if ( theElements.empty() ) eIt = meshDS->elementsIterator( SMDSAbs_Face );
6454     else                       eIt = SMESHUtils::elemSetIterator( theElements );
6455     while ( eIt->more() )
6456       meshDS->RemoveFreeElement( eIt->next(), 0 );
6457   }
6458
6459   // offsetMesh->Modified();
6460   // offsetMesh->CompactMesh(); // make IDs start from 1
6461
6462   // source elements for each generated one
6463   SMESH_SequenceOfElemPtr srcElems, srcNodes;
6464   srcElems.reserve( new2OldFaces.size() );
6465   srcNodes.reserve( new2OldNodes.size() );
6466
6467   ClearLastCreated();
6468   myLastCreatedElems.reserve( new2OldFaces.size() );
6469   myLastCreatedNodes.reserve( new2OldNodes.size() );
6470
6471   // copy offsetMesh to theTgtMesh
6472
6473   int idShift = meshDS->MaxNodeID();
6474   for ( size_t i = 0; i < new2OldNodes.size(); ++i )
6475     if ( const SMDS_MeshNode* n = new2OldNodes[ i ].first )
6476     {
6477 #ifndef _DEBUG_
6478       if ( n->NbInverseElements() > 0 )
6479 #endif
6480       {
6481         const SMDS_MeshNode* n2 =
6482           tgtMeshDS->AddNodeWithID( n->X(), n->Y(), n->Z(), idShift + n->GetID() );
6483         myLastCreatedNodes.push_back( n2 );
6484         srcNodes.push_back( meshDS->FindNode( new2OldNodes[ i ].second ));
6485       }
6486     }
6487
6488   ElemFeatures elemType;
6489   for ( size_t i = 0; i < new2OldFaces.size(); ++i )
6490     if ( const SMDS_MeshElement* f = new2OldFaces[ i ].first )
6491     {
6492       elemType.Init( f );
6493       elemType.myNodes.clear();
6494       for ( SMDS_NodeIteratorPtr nIt = f->nodeIterator(); nIt->more(); )
6495       {
6496         const SMDS_MeshNode* n2 = nIt->next();
6497         elemType.myNodes.push_back( tgtMeshDS->FindNode( idShift + n2->GetID() ));
6498       }
6499       tgtEditor.AddElement( elemType.myNodes, elemType );
6500       srcElems.push_back( meshDS->FindElement( new2OldFaces[ i ].second ));
6501     }
6502
6503   myLastCreatedElems.swap( tgtEditor.myLastCreatedElems );
6504
6505   PGroupIDs newGroupIDs;
6506   if ( theMakeGroups )
6507     newGroupIDs = generateGroups( srcNodes, srcElems, "offset", theTgtMesh, false );
6508   else
6509     newGroupIDs.reset( new std::list< int > );
6510
6511   return newGroupIDs;
6512 }
6513
6514 //=======================================================================
6515 /*!
6516  * \brief Create groups of elements made during transformation
6517  *  \param nodeGens - nodes making corresponding myLastCreatedNodes
6518  *  \param elemGens - elements making corresponding myLastCreatedElems
6519  *  \param postfix - to push_back to names of new groups
6520  *  \param targetMesh - mesh to create groups in
6521  *  \param topPresent - is there are "top" elements that are created by sweeping
6522  */
6523 //=======================================================================
6524
6525 SMESH_MeshEditor::PGroupIDs
6526 SMESH_MeshEditor::generateGroups(const SMESH_SequenceOfElemPtr& nodeGens,
6527                                  const SMESH_SequenceOfElemPtr& elemGens,
6528                                  const std::string&             postfix,
6529                                  SMESH_Mesh*                    targetMesh,
6530                                  const bool                     topPresent)
6531 {
6532   PGroupIDs newGroupIDs( new list<int> );
6533   SMESH_Mesh* mesh = targetMesh ? targetMesh : GetMesh();
6534
6535   // Sort existing groups by types and collect their names
6536
6537   // containers to store an old group and generated new ones;
6538   // 1st new group is for result elems of different type than a source one;
6539   // 2nd new group is for same type result elems ("top" group at extrusion)
6540   using boost::tuple;
6541   using boost::make_tuple;
6542   typedef tuple< SMESHDS_GroupBase*, SMESHDS_Group*, SMESHDS_Group* > TOldNewGroup;
6543   vector< list< TOldNewGroup > > groupsByType( SMDSAbs_NbElementTypes );
6544   vector< TOldNewGroup* > orderedOldNewGroups; // in order of old groups
6545   // group names
6546   set< string > groupNames;
6547
6548   SMESH_Mesh::GroupIteratorPtr groupIt = GetMesh()->GetGroups();
6549   if ( !groupIt->more() ) return newGroupIDs;
6550
6551   int newGroupID = mesh->GetGroupIds().back()+1;
6552   while ( groupIt->more() )
6553   {
6554     SMESH_Group * group = groupIt->next();
6555     if ( !group ) continue;
6556     SMESHDS_GroupBase* groupDS = group->GetGroupDS();
6557     if ( !groupDS || groupDS->IsEmpty() ) continue;
6558     groupNames.insert    ( group->GetName() );
6559     groupDS->SetStoreName( group->GetName() );
6560     const SMDSAbs_ElementType type = groupDS->GetType();
6561     SMESHDS_Group* newGroup    = new SMESHDS_Group( newGroupID++, mesh->GetMeshDS(), type );
6562     SMESHDS_Group* newTopGroup = new SMESHDS_Group( newGroupID++, mesh->GetMeshDS(), type );
6563     groupsByType[ type ].push_back( make_tuple( groupDS, newGroup, newTopGroup ));
6564     orderedOldNewGroups.push_back( & groupsByType[ type ].back() );
6565   }
6566
6567   // Loop on nodes and elements to add them in new groups
6568
6569   vector< const SMDS_MeshElement* > resultElems;
6570   for ( int isNodes = 0; isNodes < 2; ++isNodes )
6571   {
6572     const SMESH_SequenceOfElemPtr& gens  = isNodes ? nodeGens : elemGens;
6573     const SMESH_SequenceOfElemPtr& elems = isNodes ? myLastCreatedNodes : myLastCreatedElems;
6574     if ( gens.size() != elems.size() )
6575       throw SALOME_Exception("SMESH_MeshEditor::generateGroups(): invalid args");
6576
6577     // loop on created elements
6578     for (size_t iElem = 0; iElem < elems.size(); ++iElem )
6579     {
6580       const SMDS_MeshElement* sourceElem = gens[ iElem ];
6581       if ( !sourceElem ) {
6582         MESSAGE("generateGroups(): NULL source element");
6583         continue;
6584       }
6585       list< TOldNewGroup > & groupsOldNew = groupsByType[ sourceElem->GetType() ];
6586       if ( groupsOldNew.empty() ) { // no groups of this type at all
6587         while ( iElem+1 < gens.size() && gens[ iElem+1 ] == sourceElem )
6588           ++iElem; // skip all elements made by sourceElem
6589         continue;
6590       }
6591       // collect all elements made by the iElem-th sourceElem
6592       resultElems.clear();
6593       if ( const SMDS_MeshElement* resElem = elems[ iElem ])
6594         if ( resElem != sourceElem )
6595           resultElems.push_back( resElem );
6596       while ( iElem+1 < gens.size() && gens[ iElem+1 ] == sourceElem )
6597         if ( const SMDS_MeshElement* resElem = elems[ ++iElem ])
6598           if ( resElem != sourceElem )
6599             resultElems.push_back( resElem );
6600
6601       const SMDS_MeshElement* topElem = 0;
6602       if ( isNodes ) // there must be a top element
6603       {
6604         topElem = resultElems.back();
6605         resultElems.pop_back();
6606       }
6607       else
6608       {
6609         vector< const SMDS_MeshElement* >::reverse_iterator resElemIt = resultElems.rbegin();
6610         for ( ; resElemIt != resultElems.rend() ; ++resElemIt )
6611           if ( (*resElemIt)->GetType() == sourceElem->GetType() )
6612           {
6613             topElem = *resElemIt;
6614             *resElemIt = 0; // erase *resElemIt
6615             break;
6616           }
6617       }
6618       // add resultElems to groups originted from ones the sourceElem belongs to
6619       list< TOldNewGroup >::iterator gOldNew, gLast = groupsOldNew.end();
6620       for ( gOldNew = groupsOldNew.begin(); gOldNew != gLast; ++gOldNew )
6621       {
6622         SMESHDS_GroupBase* oldGroup = gOldNew->get<0>();
6623         if ( oldGroup->Contains( sourceElem )) // sourceElem is in oldGroup
6624         {
6625           // fill in a new group
6626           SMDS_MeshGroup & newGroup = gOldNew->get<1>()->SMDSGroup();
6627           vector< const SMDS_MeshElement* >::iterator resLast = resultElems.end(), resElemIt;
6628           for ( resElemIt = resultElems.begin(); resElemIt != resLast; ++resElemIt )
6629             if ( *resElemIt )
6630               newGroup.Add( *resElemIt );
6631
6632           // fill a "top" group
6633           if ( topElem )
6634           {
6635             SMDS_MeshGroup & newTopGroup = gOldNew->get<2>()->SMDSGroup();
6636             newTopGroup.Add( topElem );
6637           }
6638         }
6639       }
6640     } // loop on created elements
6641   }// loop on nodes and elements
6642
6643   // Create new SMESH_Groups from SMESHDS_Groups and remove empty SMESHDS_Groups
6644
6645   list<int> topGrouIds;
6646   for ( size_t i = 0; i < orderedOldNewGroups.size(); ++i )
6647   {
6648     SMESHDS_GroupBase* oldGroupDS =   orderedOldNewGroups[i]->get<0>();
6649     SMESHDS_Group*   newGroups[2] = { orderedOldNewGroups[i]->get<1>(),
6650                                       orderedOldNewGroups[i]->get<2>() };
6651     for ( int is2nd = 0; is2nd < 2; ++is2nd )
6652     {
6653       SMESHDS_Group* newGroupDS = newGroups[ is2nd ];
6654       if ( newGroupDS->IsEmpty() )
6655       {
6656         mesh->GetMeshDS()->RemoveGroup( newGroupDS );
6657       }
6658       else
6659       {
6660         // set group type
6661         newGroupDS->SetType( newGroupDS->GetElements()->next()->GetType() );
6662
6663         // make a name
6664         const bool isTop = ( topPresent &&
6665                              newGroupDS->GetType() == oldGroupDS->GetType() &&
6666                              is2nd );
6667
6668         string name = oldGroupDS->GetStoreName();
6669         { // remove trailing whitespaces (issue 22599)
6670           size_t size = name.size();
6671           while ( size > 1 && isspace( name[ size-1 ]))
6672             --size;
6673           if ( size != name.size() )
6674           {
6675             name.resize( size );
6676             oldGroupDS->SetStoreName( name.c_str() );
6677           }
6678         }
6679         if ( !targetMesh ) {
6680           string suffix = ( isTop ? "top": postfix.c_str() );
6681           name += "_";
6682           name += suffix;
6683           int nb = 1;
6684           while ( !groupNames.insert( name ).second ) // name exists
6685             name = SMESH_Comment( oldGroupDS->GetStoreName() ) << "_" << suffix << "_" << nb++;
6686         }
6687         else if ( isTop ) {
6688           name += "_top";
6689         }
6690         newGroupDS->SetStoreName( name.c_str() );
6691
6692         // make a SMESH_Groups
6693         mesh->AddGroup( newGroupDS );
6694         if ( isTop )
6695           topGrouIds.push_back( newGroupDS->GetID() );
6696         else
6697           newGroupIDs->push_back( newGroupDS->GetID() );
6698       }
6699     }
6700   }
6701   newGroupIDs->splice( newGroupIDs->end(), topGrouIds );
6702
6703   return newGroupIDs;
6704 }
6705
6706 //================================================================================
6707 /*!
6708  *  * \brief Return list of group of nodes close to each other within theTolerance
6709  *  *        Search among theNodes or in the whole mesh if theNodes is empty using
6710  *  *        an Octree algorithm
6711  *  \param [in,out] theNodes - the nodes to treat
6712  *  \param [in]     theTolerance - the tolerance
6713  *  \param [out]    theGroupsOfNodes - the result groups of coincident nodes
6714  *  \param [in]     theSeparateCornersAndMedium - if \c true, in quadratic mesh puts 
6715  *         corner and medium nodes in separate groups
6716  */
6717 //================================================================================
6718
6719 void SMESH_MeshEditor::FindCoincidentNodes (TIDSortedNodeSet &   theNodes,
6720                                             const double         theTolerance,
6721                                             TListOfListOfNodes & theGroupsOfNodes,
6722                                             bool                 theSeparateCornersAndMedium)
6723 {
6724   ClearLastCreated();
6725
6726   if ( myMesh->NbEdges  ( ORDER_QUADRATIC ) +
6727        myMesh->NbFaces  ( ORDER_QUADRATIC ) +
6728        myMesh->NbVolumes( ORDER_QUADRATIC ) == 0 )
6729     theSeparateCornersAndMedium = false;
6730
6731   TIDSortedNodeSet& corners = theNodes;
6732   TIDSortedNodeSet  medium;
6733
6734   if ( theNodes.empty() ) // get all nodes in the mesh
6735   {
6736     TIDSortedNodeSet* nodes[2] = { &corners, &medium };
6737     SMDS_NodeIteratorPtr nIt = GetMeshDS()->nodesIterator();
6738     if ( theSeparateCornersAndMedium )
6739       while ( nIt->more() )
6740       {
6741         const SMDS_MeshNode* n = nIt->next();
6742         TIDSortedNodeSet* & nodeSet = nodes[ SMESH_MesherHelper::IsMedium( n )];
6743         nodeSet->insert( nodeSet->end(), n );
6744       }
6745     else
6746       while ( nIt->more() )
6747         theNodes.insert( theNodes.end(), nIt->next() );
6748   }
6749   else if ( theSeparateCornersAndMedium ) // separate corners from medium nodes
6750   {
6751     TIDSortedNodeSet::iterator nIt = corners.begin();
6752     while ( nIt != corners.end() )
6753       if ( SMESH_MesherHelper::IsMedium( *nIt ))
6754       {
6755         medium.insert( medium.end(), *nIt );
6756         corners.erase( nIt++ );
6757       }
6758       else
6759       {
6760         ++nIt;
6761       }
6762   }
6763
6764   if ( !corners.empty() )
6765     SMESH_OctreeNode::FindCoincidentNodes ( corners, &theGroupsOfNodes, theTolerance );
6766   if ( !medium.empty() )
6767     SMESH_OctreeNode::FindCoincidentNodes ( medium, &theGroupsOfNodes, theTolerance );
6768 }
6769
6770 //=======================================================================
6771 //function : SimplifyFace
6772 //purpose  : split a chain of nodes into several closed chains
6773 //=======================================================================
6774
6775 int SMESH_MeshEditor::SimplifyFace (const vector<const SMDS_MeshNode *>& faceNodes,
6776                                     vector<const SMDS_MeshNode *>&       poly_nodes,
6777                                     vector<smIdType>&                    quantities) const
6778 {
6779   int nbNodes = faceNodes.size();
6780   while ( faceNodes[ 0 ] == faceNodes[ nbNodes-1 ] && nbNodes > 2 )
6781     --nbNodes;
6782   if ( nbNodes < 3 )
6783     return 0;
6784   size_t prevNbQuant = quantities.size();
6785
6786   vector< const SMDS_MeshNode* > simpleNodes; simpleNodes.reserve( nbNodes );
6787   map< const SMDS_MeshNode*, int > nodeIndices; // indices within simpleNodes
6788   map< const SMDS_MeshNode*, int >::iterator nInd;
6789
6790   nodeIndices.insert( make_pair( faceNodes[0], 0 ));
6791   simpleNodes.push_back( faceNodes[0] );
6792   for ( int iCur = 1; iCur < nbNodes; iCur++ )
6793   {
6794     if ( faceNodes[ iCur ] != simpleNodes.back() )
6795     {
6796       int index = simpleNodes.size();
6797       nInd = nodeIndices.insert( make_pair( faceNodes[ iCur ], index )).first;
6798       int prevIndex = nInd->second;
6799       if ( prevIndex < index )
6800       {
6801         // a sub-loop found
6802         int loopLen = index - prevIndex;
6803         if ( loopLen > 2 )
6804         {
6805           // store the sub-loop
6806           quantities.push_back( loopLen );
6807           for ( int i = prevIndex; i < index; i++ )
6808             poly_nodes.push_back( simpleNodes[ i ]);
6809         }
6810         simpleNodes.resize( prevIndex+1 );
6811       }
6812       else
6813       {
6814         simpleNodes.push_back( faceNodes[ iCur ]);
6815       }
6816     }
6817   }
6818
6819   if ( simpleNodes.size() > 2 )
6820   {
6821     quantities.push_back( simpleNodes.size() );
6822     poly_nodes.insert ( poly_nodes.end(), simpleNodes.begin(), simpleNodes.end() );
6823   }
6824
6825   return quantities.size() - prevNbQuant;
6826 }
6827
6828 //=======================================================================
6829 //function : MergeNodes
6830 //purpose  : In each group, the cdr of nodes are substituted by the first one
6831 //           in all elements.
6832 //=======================================================================
6833
6834 void SMESH_MeshEditor::MergeNodes (TListOfListOfNodes & theGroupsOfNodes,
6835                                    const bool           theAvoidMakingHoles)
6836 {
6837   ClearLastCreated();
6838
6839   SMESHDS_Mesh* mesh = GetMeshDS();
6840
6841   TNodeNodeMap nodeNodeMap; // node to replace - new node
6842   set<const SMDS_MeshElement*> elems; // all elements with changed nodes
6843   list< int > rmElemIds, rmNodeIds;
6844   vector< ElemFeatures > newElemDefs;
6845
6846   // Fill nodeNodeMap and elems
6847
6848   TListOfListOfNodes::iterator grIt = theGroupsOfNodes.begin();
6849   for ( ; grIt != theGroupsOfNodes.end(); grIt++ )
6850   {
6851     list<const SMDS_MeshNode*>& nodes = *grIt;
6852     list<const SMDS_MeshNode*>::iterator nIt = nodes.begin();
6853     const SMDS_MeshNode* nToKeep = *nIt;
6854     for ( ++nIt; nIt != nodes.end(); nIt++ )
6855     {
6856       const SMDS_MeshNode* nToRemove = *nIt;
6857       nodeNodeMap.insert( make_pair( nToRemove, nToKeep ));
6858       SMDS_ElemIteratorPtr invElemIt = nToRemove->GetInverseElementIterator();
6859       while ( invElemIt->more() ) {
6860         const SMDS_MeshElement* elem = invElemIt->next();
6861         elems.insert(elem);
6862       }
6863     }
6864   }
6865
6866   // Apply recursive replacements (BUG 0020185)
6867   TNodeNodeMap::iterator nnIt = nodeNodeMap.begin();
6868   for ( ; nnIt != nodeNodeMap.end(); ++nnIt )
6869   {
6870     const SMDS_MeshNode* nToKeep = nnIt->second;
6871     TNodeNodeMap::iterator nnIt_i = nodeNodeMap.find( nToKeep );
6872     while ( nnIt_i != nodeNodeMap.end() && nnIt_i->second != nnIt->second )
6873     {
6874       nToKeep = nnIt_i->second;
6875       nnIt->second = nToKeep;
6876       nnIt_i = nodeNodeMap.find( nToKeep );
6877     }
6878   }
6879
6880   if ( theAvoidMakingHoles )
6881   {
6882     // find elements whose topology changes
6883
6884     vector<const SMDS_MeshElement*> pbElems;
6885     set<const SMDS_MeshElement*>::iterator eIt = elems.begin();
6886     for ( ; eIt != elems.end(); ++eIt )
6887     {
6888       const SMDS_MeshElement* elem = *eIt;
6889       SMDS_ElemIteratorPtr     itN = elem->nodesIterator();
6890       while ( itN->more() )
6891       {
6892         const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( itN->next() );
6893         TNodeNodeMap::iterator nnIt = nodeNodeMap.find( n );
6894         if ( nnIt != nodeNodeMap.end() && elem->GetNodeIndex( nnIt->second ) >= 0 )
6895         {
6896           // several nodes of elem stick
6897           pbElems.push_back( elem );
6898           break;
6899         }
6900       }
6901     }
6902     // exclude from merge nodes causing spoiling element
6903     for ( size_t iLoop = 0; iLoop < pbElems.size(); ++iLoop ) // avoid infinite cycle
6904     {
6905       bool nodesExcluded = false;
6906       for ( size_t i = 0; i < pbElems.size(); ++i )
6907       {
6908         size_t prevNbMergeNodes = nodeNodeMap.size();
6909         if ( !applyMerge( pbElems[i], newElemDefs, nodeNodeMap, /*noHoles=*/true ) &&
6910              prevNbMergeNodes < nodeNodeMap.size() )
6911           nodesExcluded = true;
6912       }
6913       if ( !nodesExcluded )
6914         break;
6915     }
6916   }
6917
6918   for ( nnIt = nodeNodeMap.begin(); nnIt != nodeNodeMap.end(); ++nnIt )
6919   {
6920     const SMDS_MeshNode* nToRemove = nnIt->first;
6921     const SMDS_MeshNode* nToKeep   = nnIt->second;
6922     if ( nToRemove != nToKeep )
6923     {
6924       rmNodeIds.push_back( nToRemove->GetID() );
6925       AddToSameGroups( nToKeep, nToRemove, mesh );
6926       // set _alwaysComputed to a sub-mesh of VERTEX to enable further mesh computing
6927       // w/o creating node in place of merged ones.
6928       SMDS_PositionPtr pos = nToRemove->GetPosition();
6929       if ( pos && pos->GetTypeOfPosition() == SMDS_TOP_VERTEX )
6930         if ( SMESH_subMesh* sm = myMesh->GetSubMeshContaining( nToRemove->getshapeId() ))
6931           sm->SetIsAlwaysComputed( true );
6932     }
6933   }
6934
6935   // Change element nodes or remove an element
6936
6937   set<const SMDS_MeshElement*>::iterator eIt = elems.begin();
6938   for ( ; eIt != elems.end(); eIt++ )
6939   {
6940     const SMDS_MeshElement* elem = *eIt;
6941     SMESHDS_SubMesh*          sm = mesh->MeshElements( elem->getshapeId() );
6942
6943     bool keepElem = applyMerge( elem, newElemDefs, nodeNodeMap, /*noHoles=*/false );
6944     if ( !keepElem )
6945       rmElemIds.push_back( elem->GetID() );
6946
6947     for ( size_t i = 0; i < newElemDefs.size(); ++i )
6948     {
6949       if ( i > 0 || !mesh->ChangeElementNodes( elem,
6950                                                & newElemDefs[i].myNodes[0],
6951                                                newElemDefs[i].myNodes.size() ))
6952       {
6953         if ( i == 0 )
6954         {
6955           newElemDefs[i].SetID( elem->GetID() );
6956           mesh->RemoveFreeElement(elem, sm, /*fromGroups=*/false);
6957           if ( !keepElem ) rmElemIds.pop_back();
6958         }
6959         else
6960         {
6961           newElemDefs[i].SetID( -1 );
6962         }
6963         SMDS_MeshElement* newElem = this->AddElement( newElemDefs[i].myNodes, newElemDefs[i] );
6964         if ( sm && newElem )
6965           sm->AddElement( newElem );
6966         if ( elem != newElem )
6967           ReplaceElemInGroups( elem, newElem, mesh );
6968       }
6969     }
6970   }
6971
6972   // Remove bad elements, then equal nodes (order important)
6973   Remove( rmElemIds, /*isNodes=*/false );
6974   Remove( rmNodeIds, /*isNodes=*/true );
6975
6976   return;
6977 }
6978
6979 //=======================================================================
6980 //function : applyMerge
6981 //purpose  : Compute new connectivity of an element after merging nodes
6982 //  \param [in] elems - the element
6983 //  \param [out] newElemDefs - definition(s) of result element(s)
6984 //  \param [inout] nodeNodeMap - nodes to merge
6985 //  \param [in] avoidMakingHoles - if true and and the element becomes invalid
6986 //              after merging (but not degenerated), removes nodes causing
6987 //              the invalidity from \a nodeNodeMap.
6988 //  \return bool - true if the element should be removed
6989 //=======================================================================
6990
6991 bool SMESH_MeshEditor::applyMerge( const SMDS_MeshElement* elem,
6992                                    vector< ElemFeatures >& newElemDefs,
6993                                    TNodeNodeMap&           nodeNodeMap,
6994                                    const bool              avoidMakingHoles )
6995 {
6996   bool toRemove = false; // to remove elem
6997   int nbResElems = 1;    // nb new elements
6998
6999   newElemDefs.resize(nbResElems);
7000   newElemDefs[0].Init( elem );
7001   newElemDefs[0].myNodes.clear();
7002
7003   set<const SMDS_MeshNode*> nodeSet;
7004   vector< const SMDS_MeshNode*>   curNodes;
7005   vector< const SMDS_MeshNode*> & uniqueNodes = newElemDefs[0].myNodes;
7006   vector<int> iRepl;
7007
7008   const        int  nbNodes = elem->NbNodes();
7009   SMDSAbs_EntityType entity = elem->GetEntityType();
7010
7011   curNodes.resize( nbNodes );
7012   uniqueNodes.resize( nbNodes );
7013   iRepl.resize( nbNodes );
7014   int iUnique = 0, iCur = 0, nbRepl = 0;
7015
7016   // Get new seq of nodes
7017
7018   SMDS_ElemIteratorPtr itN = elem->nodesIterator();
7019   while ( itN->more() )
7020   {
7021     const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( itN->next() );
7022
7023     TNodeNodeMap::iterator nnIt = nodeNodeMap.find( n );
7024     if ( nnIt != nodeNodeMap.end() ) {
7025       n = (*nnIt).second;
7026     }
7027     curNodes[ iCur ] = n;
7028     bool isUnique = nodeSet.insert( n ).second;
7029     if ( isUnique )
7030       uniqueNodes[ iUnique++ ] = n;
7031     else
7032       iRepl[ nbRepl++ ] = iCur;
7033     iCur++;
7034   }
7035
7036   // Analyse element topology after replacement
7037
7038   int nbUniqueNodes = nodeSet.size();
7039   if ( nbNodes != nbUniqueNodes ) // some nodes stick
7040   {
7041     toRemove = true;
7042     nbResElems = 0;
7043
7044     if ( newElemDefs[0].myIsQuad && newElemDefs[0].myType == SMDSAbs_Face && nbNodes > 6 )
7045     {
7046       // if corner nodes stick, remove medium nodes between them from uniqueNodes
7047       int nbCorners = nbNodes / 2;
7048       for ( int iCur = 0; iCur < nbCorners; ++iCur )
7049       {
7050         int iNext = ( iCur + 1 ) % nbCorners;
7051         if ( curNodes[ iCur ] == curNodes[ iNext ] ) // corners stick
7052         {
7053           int iMedium = iCur + nbCorners;
7054           vector< const SMDS_MeshNode* >::iterator i =
7055             std::find( uniqueNodes.begin() + nbCorners - nbRepl,
7056                        uniqueNodes.end(),
7057                        curNodes[ iMedium ]);
7058           if ( i != uniqueNodes.end() )
7059           {
7060             --nbUniqueNodes;
7061             for ( ; i+1 != uniqueNodes.end(); ++i )
7062               *i = *(i+1);
7063           }
7064         }
7065       }
7066     }
7067
7068     switch ( entity )
7069     {
7070     case SMDSEntity_Polygon:
7071     case SMDSEntity_Quad_Polygon: // Polygon
7072     {
7073       ElemFeatures* elemType = & newElemDefs[0];
7074       const bool isQuad = elemType->myIsQuad;
7075       if ( isQuad )
7076         SMDS_MeshCell::applyInterlace // interlace medium and corner nodes
7077           ( SMDS_MeshCell::interlacedSmdsOrder( SMDSEntity_Quad_Polygon, nbNodes ), curNodes );
7078
7079       // a polygon can divide into several elements
7080       vector<const SMDS_MeshNode *> polygons_nodes;
7081       vector<smIdType> quantities;
7082       nbResElems = SimplifyFace( curNodes, polygons_nodes, quantities );
7083       newElemDefs.resize( nbResElems );
7084       for ( int inode = 0, iface = 0; iface < nbResElems; iface++ )
7085       {
7086         ElemFeatures* elemType = & newElemDefs[iface];
7087         if ( iface ) elemType->Init( elem );
7088
7089         vector<const SMDS_MeshNode *>& face_nodes = elemType->myNodes;
7090         int nbNewNodes = quantities[iface];
7091         face_nodes.assign( polygons_nodes.begin() + inode,
7092                            polygons_nodes.begin() + inode + nbNewNodes );
7093         inode += nbNewNodes;
7094         if ( isQuad ) // check if a result elem is a valid quadratic polygon
7095         {
7096           bool isValid = ( nbNewNodes % 2 == 0 );
7097           for ( int i = 0; i < nbNewNodes && isValid; ++i )
7098             isValid = ( elem->IsMediumNode( face_nodes[i]) == bool( i % 2 ));
7099           elemType->SetQuad( isValid );
7100           if ( isValid ) // put medium nodes after corners
7101             SMDS_MeshCell::applyInterlaceRev
7102               ( SMDS_MeshCell::interlacedSmdsOrder( SMDSEntity_Quad_Polygon,
7103                                                     nbNewNodes ), face_nodes );
7104         }
7105         elemType->SetPoly(( nbNewNodes / ( elemType->myIsQuad + 1 ) > 4 ));
7106       }
7107       nbUniqueNodes = newElemDefs[0].myNodes.size();
7108       break;
7109     } // Polygon
7110
7111     case SMDSEntity_Polyhedra: // Polyhedral volume
7112     {
7113       if ( nbUniqueNodes >= 4 )
7114       {
7115         // each face has to be analyzed in order to check volume validity
7116         if ( const SMDS_MeshVolume* aPolyedre = SMDS_Mesh::DownCast< SMDS_MeshVolume >( elem ))
7117         {
7118           int nbFaces = aPolyedre->NbFaces();
7119
7120           vector<const SMDS_MeshNode *>& poly_nodes = newElemDefs[0].myNodes;
7121           vector<smIdType>             & quantities = newElemDefs[0].myPolyhedQuantities;
7122           vector<const SMDS_MeshNode *>  faceNodes;
7123           poly_nodes.clear();
7124           quantities.clear();
7125
7126           for (int iface = 1; iface <= nbFaces; iface++)
7127           {
7128             int nbFaceNodes = aPolyedre->NbFaceNodes(iface);
7129             faceNodes.resize( nbFaceNodes );
7130             for (int inode = 1; inode <= nbFaceNodes; inode++)
7131             {
7132               const SMDS_MeshNode * faceNode = aPolyedre->GetFaceNode(iface, inode);
7133               TNodeNodeMap::iterator nnIt = nodeNodeMap.find(faceNode);
7134               if ( nnIt != nodeNodeMap.end() ) // faceNode sticks
7135                 faceNode = (*nnIt).second;
7136               faceNodes[inode - 1] = faceNode;
7137             }
7138             SimplifyFace(faceNodes, poly_nodes, quantities);
7139           }
7140
7141           if ( quantities.size() > 3 )
7142           {
7143             // TODO: remove coincident faces
7144             nbResElems = 1;
7145             nbUniqueNodes = newElemDefs[0].myNodes.size();
7146           }
7147         }
7148       }
7149     }
7150     break;
7151
7152     // Regular elements
7153     // TODO not all the possible cases are solved. Find something more generic?
7154     case SMDSEntity_Edge: //////// EDGE
7155     case SMDSEntity_Triangle: //// TRIANGLE
7156     case SMDSEntity_Quad_Triangle:
7157     case SMDSEntity_Tetra:
7158     case SMDSEntity_Quad_Tetra: // TETRAHEDRON
7159     {
7160       break;
7161     }
7162     case SMDSEntity_Quad_Edge:
7163     {
7164       break;
7165     }
7166     case SMDSEntity_Quadrangle: //////////////////////////////////// QUADRANGLE
7167     {
7168       if ( nbUniqueNodes < 3 )
7169         toRemove = true;
7170       else if ( nbRepl == 1 && curNodes[ iRepl[0]] == curNodes[( iRepl[0]+2 )%4 ])
7171         toRemove = true; // opposite nodes stick
7172       else
7173         toRemove = false;
7174       break;
7175     }
7176     case SMDSEntity_Quad_Quadrangle: // Quadratic QUADRANGLE
7177     {
7178       //   1    5    2
7179       //    +---+---+
7180       //    |       |
7181       //   4+       +6
7182       //    |       |
7183       //    +---+---+
7184       //   0    7    3
7185       if ( nbUniqueNodes == 6 &&
7186            iRepl[0] < 4       &&
7187            ( nbRepl == 1 || iRepl[1] >= 4 ))
7188       {
7189         toRemove = false;
7190       }
7191       break;
7192     }
7193     case SMDSEntity_BiQuad_Quadrangle: // Bi-Quadratic QUADRANGLE
7194     {
7195       //   1    5    2
7196       //    +---+---+
7197       //    |       |
7198       //   4+  8+   +6
7199       //    |       |
7200       //    +---+---+
7201       //   0    7    3
7202       if ( nbUniqueNodes == 7 &&
7203            iRepl[0] < 4       &&
7204            ( nbRepl == 1 || iRepl[1] != 8 ))
7205       {
7206         toRemove = false;
7207       }
7208       break;
7209     }
7210     case SMDSEntity_Penta: ///////////////////////////////////// PENTAHEDRON
7211     {
7212       if ( nbUniqueNodes == 4 ) {
7213         // ---------------------------------> tetrahedron
7214         if ( curNodes[3] == curNodes[4] &&
7215              curNodes[3] == curNodes[5] ) {
7216           // top nodes stick
7217           toRemove = false;
7218         }
7219         else if ( curNodes[0] == curNodes[1] &&
7220                   curNodes[0] == curNodes[2] ) {
7221           // bottom nodes stick: set a top before
7222           uniqueNodes[ 3 ] = uniqueNodes [ 0 ];
7223           uniqueNodes[ 0 ] = curNodes [ 5 ];
7224           uniqueNodes[ 1 ] = curNodes [ 4 ];
7225           uniqueNodes[ 2 ] = curNodes [ 3 ];
7226           toRemove = false;
7227         }
7228         else if (( curNodes[0] == curNodes[3] ) +
7229                  ( curNodes[1] == curNodes[4] ) +
7230                  ( curNodes[2] == curNodes[5] ) == 2 ) {
7231           // a lateral face turns into a line
7232           toRemove = false;
7233         }
7234       }
7235       else if ( nbUniqueNodes == 5 ) {
7236         // PENTAHEDRON --------------------> pyramid
7237         if ( curNodes[0] == curNodes[3] )
7238         {
7239           uniqueNodes[ 0 ] = curNodes[ 1 ];
7240           uniqueNodes[ 1 ] = curNodes[ 4 ];
7241           uniqueNodes[ 2 ] = curNodes[ 5 ];
7242           uniqueNodes[ 3 ] = curNodes[ 2 ];
7243           uniqueNodes[ 4 ] = curNodes[ 0 ];
7244           toRemove = false;
7245         }
7246         if ( curNodes[1] == curNodes[4] )
7247         {
7248           uniqueNodes[ 0 ] = curNodes[ 0 ];
7249           uniqueNodes[ 1 ] = curNodes[ 2 ];
7250           uniqueNodes[ 2 ] = curNodes[ 5 ];
7251           uniqueNodes[ 3 ] = curNodes[ 3 ];
7252           uniqueNodes[ 4 ] = curNodes[ 1 ];
7253           toRemove = false;
7254         }
7255         if ( curNodes[2] == curNodes[5] )
7256         {
7257           uniqueNodes[ 0 ] = curNodes[ 0 ];
7258           uniqueNodes[ 1 ] = curNodes[ 3 ];
7259           uniqueNodes[ 2 ] = curNodes[ 4 ];
7260           uniqueNodes[ 3 ] = curNodes[ 1 ];
7261           uniqueNodes[ 4 ] = curNodes[ 2 ];
7262           toRemove = false;
7263         }
7264       }
7265       break;
7266     }
7267     case SMDSEntity_Hexa:
7268     {
7269       //////////////////////////////////// HEXAHEDRON
7270       SMDS_VolumeTool hexa (elem);
7271       hexa.SetExternalNormal();
7272       if ( nbUniqueNodes == 4 && nbRepl == 4 ) {
7273         //////////////////////// HEX ---> tetrahedron
7274         for ( int iFace = 0; iFace < 6; iFace++ ) {
7275           const int *ind = hexa.GetFaceNodesIndices( iFace ); // indices of face nodes
7276           if (curNodes[ind[ 0 ]] == curNodes[ind[ 1 ]] &&
7277               curNodes[ind[ 0 ]] == curNodes[ind[ 2 ]] &&
7278               curNodes[ind[ 0 ]] == curNodes[ind[ 3 ]] ) {
7279             // one face turns into a point ...
7280             int  pickInd = ind[ 0 ];
7281             int iOppFace = hexa.GetOppFaceIndex( iFace );
7282             ind = hexa.GetFaceNodesIndices( iOppFace );
7283             int nbStick = 0;
7284             uniqueNodes.clear();
7285             for ( iCur = 0; iCur < 4 && nbStick < 2; iCur++ ) {
7286               if ( curNodes[ind[ iCur ]] == curNodes[ind[ iCur + 1 ]] )
7287                 nbStick++;
7288               else
7289                 uniqueNodes.push_back( curNodes[ind[ iCur ]]);
7290             }
7291             if ( nbStick == 1 ) {
7292               // ... and the opposite one - into a triangle.
7293               // set a top node
7294               uniqueNodes.push_back( curNodes[ pickInd ]);
7295               toRemove = false;
7296             }
7297             break;
7298           }
7299         }
7300       }
7301       else if ( nbUniqueNodes == 6 && nbRepl == 2 ) {
7302         //////////////////////// HEX ---> prism
7303         int nbTria = 0, iTria[3];
7304         const int *ind; // indices of face nodes
7305         // look for triangular faces
7306         for ( int iFace = 0; iFace < 6 && nbTria < 3; iFace++ ) {
7307           ind = hexa.GetFaceNodesIndices( iFace );
7308           TIDSortedNodeSet faceNodes;
7309           for ( iCur = 0; iCur < 4; iCur++ )
7310             faceNodes.insert( curNodes[ind[iCur]] );
7311           if ( faceNodes.size() == 3 )
7312             iTria[ nbTria++ ] = iFace;
7313         }
7314         // check if triangles are opposite
7315         if ( nbTria == 2 && iTria[0] == hexa.GetOppFaceIndex( iTria[1] ))
7316         {
7317           // set nodes of the bottom triangle
7318           ind = hexa.GetFaceNodesIndices( iTria[ 0 ]);
7319           vector<int> indB;
7320           for ( iCur = 0; iCur < 4; iCur++ )
7321             if ( ind[iCur] != iRepl[0] && ind[iCur] != iRepl[1])
7322               indB.push_back( ind[iCur] );
7323           if ( !hexa.IsForward() )
7324             std::swap( indB[0], indB[2] );
7325           for ( iCur = 0; iCur < 3; iCur++ )
7326             uniqueNodes[ iCur ] = curNodes[indB[iCur]];
7327           // set nodes of the top triangle
7328           const int *indT = hexa.GetFaceNodesIndices( iTria[ 1 ]);
7329           for ( iCur = 0; iCur < 3; ++iCur )
7330             for ( int j = 0; j < 4; ++j )
7331               if ( hexa.IsLinked( indB[ iCur ], indT[ j ] ))
7332               {
7333                 uniqueNodes[ iCur + 3 ] = curNodes[ indT[ j ]];
7334                 break;
7335               }
7336           toRemove = false;
7337           break;
7338         }
7339       }
7340       else if (nbUniqueNodes == 5 && nbRepl == 3 ) {
7341         //////////////////// HEXAHEDRON ---> pyramid
7342         for ( int iFace = 0; iFace < 6; iFace++ ) {
7343           const int *ind = hexa.GetFaceNodesIndices( iFace ); // indices of face nodes
7344           if (curNodes[ind[ 0 ]] == curNodes[ind[ 1 ]] &&
7345               curNodes[ind[ 0 ]] == curNodes[ind[ 2 ]] &&
7346               curNodes[ind[ 0 ]] == curNodes[ind[ 3 ]] ) {
7347             // one face turns into a point ...
7348             int iOppFace = hexa.GetOppFaceIndex( iFace );
7349             ind = hexa.GetFaceNodesIndices( iOppFace );
7350             uniqueNodes.clear();
7351             for ( iCur = 0; iCur < 4; iCur++ ) {
7352               if ( curNodes[ind[ iCur ]] == curNodes[ind[ iCur + 1 ]] )
7353                 break;
7354               else
7355                 uniqueNodes.push_back( curNodes[ind[ iCur ]]);
7356             }
7357             if ( uniqueNodes.size() == 4 ) {
7358               // ... and the opposite one is a quadrangle
7359               // set a top node
7360               const int* indTop = hexa.GetFaceNodesIndices( iFace );
7361               uniqueNodes.push_back( curNodes[indTop[ 0 ]]);
7362               toRemove = false;
7363             }
7364             break;
7365           }
7366         }
7367       }
7368
7369       if ( toRemove && nbUniqueNodes > 4 ) {
7370         ////////////////// HEXAHEDRON ---> polyhedron
7371         hexa.SetExternalNormal();
7372         vector<const SMDS_MeshNode *>& poly_nodes = newElemDefs[0].myNodes;
7373         vector<smIdType>             & quantities = newElemDefs[0].myPolyhedQuantities;
7374         poly_nodes.reserve( 6 * 4 ); poly_nodes.clear();
7375         quantities.reserve( 6 );     quantities.clear();
7376         for ( int iFace = 0; iFace < 6; iFace++ )
7377         {
7378           const int *ind = hexa.GetFaceNodesIndices( iFace ); // indices of face nodes
7379           if ( curNodes[ind[0]] == curNodes[ind[2]] ||
7380                curNodes[ind[1]] == curNodes[ind[3]] )
7381           {
7382             quantities.clear();
7383             break; // opposite nodes stick
7384           }
7385           nodeSet.clear();
7386           for ( iCur = 0; iCur < 4; iCur++ )
7387           {
7388             if ( nodeSet.insert( curNodes[ind[ iCur ]] ).second )
7389               poly_nodes.push_back( curNodes[ind[ iCur ]]);
7390           }
7391           if ( nodeSet.size() < 3 )
7392             poly_nodes.resize( poly_nodes.size() - nodeSet.size() );
7393           else
7394             quantities.push_back( nodeSet.size() );
7395         }
7396         if ( quantities.size() >= 4 )
7397         {
7398           nbResElems = 1;
7399           nbUniqueNodes = poly_nodes.size();
7400           newElemDefs[0].SetPoly(true);
7401         }
7402       }
7403       break;
7404     } // case HEXAHEDRON
7405
7406     default:
7407       toRemove = true;
7408
7409     } // switch ( entity )
7410
7411     if ( toRemove && nbResElems == 0 && avoidMakingHoles )
7412     {
7413       // erase from nodeNodeMap nodes whose merge spoils elem
7414       vector< const SMDS_MeshNode* > noMergeNodes;
7415       SMESH_MeshAlgos::DeMerge( elem, curNodes, noMergeNodes );
7416       for ( size_t i = 0; i < noMergeNodes.size(); ++i )
7417         nodeNodeMap.erase( noMergeNodes[i] );
7418     }
7419     
7420   } // if ( nbNodes != nbUniqueNodes ) // some nodes stick
7421
7422   uniqueNodes.resize( nbUniqueNodes );
7423
7424   if ( !toRemove && nbResElems == 0 )
7425     nbResElems = 1;
7426
7427   newElemDefs.resize( nbResElems );
7428
7429   return !toRemove;
7430 }
7431
7432
7433 // ========================================================
7434 // class   : ComparableElement
7435 // purpose : allow comparing elements basing on their nodes
7436 // ========================================================
7437
7438 class ComparableElement : public boost::container::flat_set< int >
7439 {
7440   typedef boost::container::flat_set< int >  int_set;
7441
7442   const SMDS_MeshElement* myElem;
7443   int                     mySumID;
7444   mutable int             myGroupID;
7445
7446 public:
7447
7448   ComparableElement( const SMDS_MeshElement* theElem ):
7449     myElem ( theElem ), mySumID( 0 ), myGroupID( -1 )
7450   {
7451     this->reserve( theElem->NbNodes() );
7452     for ( SMDS_ElemIteratorPtr nodeIt = theElem->nodesIterator(); nodeIt->more(); )
7453     {
7454       int id = nodeIt->next()->GetID();
7455       mySumID += id;
7456       this->insert( id );
7457     }
7458   }
7459
7460   const SMDS_MeshElement* GetElem() const { return myElem; }
7461
7462   int& GroupID() const { return myGroupID; }
7463   //int& GroupID() const { return const_cast< int& >( myGroupID ); }
7464
7465   ComparableElement( const ComparableElement& theSource ) // move copy
7466     : int_set()
7467   {
7468     ComparableElement& src = const_cast< ComparableElement& >( theSource );
7469     (int_set&) (*this ) = std::move( src );
7470     myElem    = src.myElem;
7471     mySumID   = src.mySumID;
7472     myGroupID = src.myGroupID;
7473   }
7474
7475   static int HashCode(const ComparableElement& se, int limit )
7476   {
7477     return ::HashCode( se.mySumID, limit );
7478   }
7479   static Standard_Boolean IsEqual(const ComparableElement& se1, const ComparableElement& se2 )
7480   {
7481     return ( se1 == se2 );
7482   }
7483
7484 };
7485
7486 //=======================================================================
7487 //function : FindEqualElements
7488 //purpose  : Return list of group of elements built on the same nodes.
7489 //           Search among theElements or in the whole mesh if theElements is empty
7490 //=======================================================================
7491
7492 void SMESH_MeshEditor::FindEqualElements( TIDSortedElemSet &        theElements,
7493                                           TListOfListOfElementsID & theGroupsOfElementsID )
7494 {
7495   ClearLastCreated();
7496
7497   SMDS_ElemIteratorPtr elemIt;
7498   if ( theElements.empty() ) elemIt = GetMeshDS()->elementsIterator();
7499   else                       elemIt = SMESHUtils::elemSetIterator( theElements );
7500
7501   typedef NCollection_Map< ComparableElement, ComparableElement > TMapOfElements;
7502   typedef std::list<int>                                          TGroupOfElems;
7503   TMapOfElements               mapOfElements;
7504   std::vector< TGroupOfElems > arrayOfGroups;
7505   TGroupOfElems                groupOfElems;
7506
7507   while ( elemIt->more() )
7508   {
7509     const SMDS_MeshElement* curElem = elemIt->next();
7510     if ( curElem->IsNull() )
7511       continue;
7512     ComparableElement      compElem = curElem;
7513     // check uniqueness
7514     const ComparableElement& elemInSet = mapOfElements.Added( compElem );
7515     if ( elemInSet.GetElem() != curElem ) // coincident elem
7516     {
7517       int& iG = elemInSet.GroupID();
7518       if ( iG < 0 )
7519       {
7520         iG = arrayOfGroups.size();
7521         arrayOfGroups.push_back( groupOfElems );
7522         arrayOfGroups[ iG ].push_back( elemInSet.GetElem()->GetID() );
7523       }
7524       arrayOfGroups[ iG ].push_back( curElem->GetID() );
7525     }
7526   }
7527
7528   groupOfElems.clear();
7529   std::vector< TGroupOfElems >::iterator groupIt = arrayOfGroups.begin();
7530   for ( ; groupIt != arrayOfGroups.end(); ++groupIt )
7531   {
7532     if ( groupIt->size() > 1 ) {
7533       //groupOfElems.sort(); -- theElements are sorted already
7534       theGroupsOfElementsID.emplace_back( *groupIt );
7535     }
7536   }
7537 }
7538
7539 //=======================================================================
7540 //function : MergeElements
7541 //purpose  : In each given group, substitute all elements by the first one.
7542 //=======================================================================
7543
7544 void SMESH_MeshEditor::MergeElements(TListOfListOfElementsID & theGroupsOfElementsID)
7545 {
7546   ClearLastCreated();
7547
7548   typedef list<int> TListOfIDs;
7549   TListOfIDs rmElemIds; // IDs of elems to remove
7550
7551   SMESHDS_Mesh* aMesh = GetMeshDS();
7552
7553   TListOfListOfElementsID::iterator groupsIt = theGroupsOfElementsID.begin();
7554   while ( groupsIt != theGroupsOfElementsID.end() ) {
7555     TListOfIDs& aGroupOfElemID = *groupsIt;
7556     aGroupOfElemID.sort();
7557     int elemIDToKeep = aGroupOfElemID.front();
7558     const SMDS_MeshElement* elemToKeep = aMesh->FindElement(elemIDToKeep);
7559     aGroupOfElemID.pop_front();
7560     TListOfIDs::iterator idIt = aGroupOfElemID.begin();
7561     while ( idIt != aGroupOfElemID.end() ) {
7562       int elemIDToRemove = *idIt;
7563       const SMDS_MeshElement* elemToRemove = aMesh->FindElement(elemIDToRemove);
7564       // add the kept element in groups of removed one (PAL15188)
7565       AddToSameGroups( elemToKeep, elemToRemove, aMesh );
7566       rmElemIds.push_back( elemIDToRemove );
7567       ++idIt;
7568     }
7569     ++groupsIt;
7570   }
7571
7572   Remove( rmElemIds, false );
7573 }
7574
7575 //=======================================================================
7576 //function : MergeEqualElements
7577 //purpose  : Remove all but one of elements built on the same nodes.
7578 //=======================================================================
7579
7580 void SMESH_MeshEditor::MergeEqualElements()
7581 {
7582   TIDSortedElemSet aMeshElements; /* empty input ==
7583                                      to merge equal elements in the whole mesh */
7584   TListOfListOfElementsID aGroupsOfElementsID;
7585   FindEqualElements( aMeshElements, aGroupsOfElementsID );
7586   MergeElements( aGroupsOfElementsID );
7587 }
7588
7589 //=======================================================================
7590 //function : findAdjacentFace
7591 //purpose  :
7592 //=======================================================================
7593
7594 static const SMDS_MeshElement* findAdjacentFace(const SMDS_MeshNode* n1,
7595                                                 const SMDS_MeshNode* n2,
7596                                                 const SMDS_MeshElement* elem)
7597 {
7598   TIDSortedElemSet elemSet, avoidSet;
7599   if ( elem )
7600     avoidSet.insert ( elem );
7601   return SMESH_MeshAlgos::FindFaceInSet( n1, n2, elemSet, avoidSet );
7602 }
7603
7604 //=======================================================================
7605 //function : findSegment
7606 //purpose  : Return a mesh segment by two nodes one of which can be medium
7607 //=======================================================================
7608
7609 static const SMDS_MeshElement* findSegment(const SMDS_MeshNode* n1,
7610                                            const SMDS_MeshNode* n2)
7611 {
7612   SMDS_ElemIteratorPtr it = n1->GetInverseElementIterator( SMDSAbs_Edge );
7613   while ( it->more() )
7614   {
7615     const SMDS_MeshElement* seg = it->next();
7616     if ( seg->GetNodeIndex( n2 ) >= 0 )
7617       return seg;
7618   }
7619   return 0;
7620 }
7621
7622 //=======================================================================
7623 //function : FindFreeBorder
7624 //purpose  :
7625 //=======================================================================
7626
7627 #define ControlFreeBorder SMESH::Controls::FreeEdges::IsFreeEdge
7628
7629 bool SMESH_MeshEditor::FindFreeBorder (const SMDS_MeshNode*             theFirstNode,
7630                                        const SMDS_MeshNode*             theSecondNode,
7631                                        const SMDS_MeshNode*             theLastNode,
7632                                        list< const SMDS_MeshNode* > &   theNodes,
7633                                        list< const SMDS_MeshElement* >& theFaces)
7634 {
7635   if ( !theFirstNode || !theSecondNode )
7636     return false;
7637   // find border face between theFirstNode and theSecondNode
7638   const SMDS_MeshElement* curElem = findAdjacentFace( theFirstNode, theSecondNode, 0 );
7639   if ( !curElem )
7640     return false;
7641
7642   theFaces.push_back( curElem );
7643   theNodes.push_back( theFirstNode );
7644   theNodes.push_back( theSecondNode );
7645
7646   const SMDS_MeshNode *nIgnore = theFirstNode, *nStart = theSecondNode;
7647   //TIDSortedElemSet foundElems;
7648   bool needTheLast = ( theLastNode != 0 );
7649
7650   vector<const SMDS_MeshNode*> nodes;
7651   
7652   while ( nStart != theLastNode ) {
7653     if ( nStart == theFirstNode )
7654       return !needTheLast;
7655
7656     // find all free border faces sharing nStart
7657
7658     list< const SMDS_MeshElement* > curElemList;
7659     list< const SMDS_MeshNode* >    nStartList;
7660     SMDS_ElemIteratorPtr invElemIt = nStart->GetInverseElementIterator(SMDSAbs_Face);
7661     while ( invElemIt->more() ) {
7662       const SMDS_MeshElement* e = invElemIt->next();
7663       //if ( e == curElem || foundElems.insert( e ).second ) // e can encounter twice in border
7664       {
7665         // get nodes
7666         nodes.assign( SMDS_MeshElement::iterator( e->interlacedNodesIterator() ),
7667                       SMDS_MeshElement::iterator() );
7668         nodes.push_back( nodes[ 0 ]);
7669
7670         // check 2 links
7671         int iNode = 0, nbNodes = nodes.size() - 1;
7672         for ( iNode = 0; iNode < nbNodes; iNode++ )
7673           if ((( nodes[ iNode ] == nStart && nodes[ iNode + 1] != nIgnore ) ||
7674                ( nodes[ iNode + 1] == nStart && nodes[ iNode ] != nIgnore )) &&
7675               ( ControlFreeBorder( &nodes[ iNode ], e->GetID() )))
7676           {
7677             nStartList.push_back( nodes[ iNode + ( nodes[ iNode ] == nStart )]);
7678             curElemList.push_back( e );
7679           }
7680       }
7681     }
7682     // analyse the found
7683
7684     int nbNewBorders = curElemList.size();
7685     if ( nbNewBorders == 0 ) {
7686       // no free border furthermore
7687       return !needTheLast;
7688     }
7689     else if ( nbNewBorders == 1 ) {
7690       // one more element found
7691       nIgnore = nStart;
7692       nStart = nStartList.front();
7693       curElem = curElemList.front();
7694       theFaces.push_back( curElem );
7695       theNodes.push_back( nStart );
7696     }
7697     else {
7698       // several continuations found
7699       list< const SMDS_MeshElement* >::iterator curElemIt;
7700       list< const SMDS_MeshNode* >::iterator nStartIt;
7701       // check if one of them reached the last node
7702       if ( needTheLast ) {
7703         for (curElemIt = curElemList.begin(), nStartIt = nStartList.begin();
7704              curElemIt!= curElemList.end();
7705              curElemIt++, nStartIt++ )
7706           if ( *nStartIt == theLastNode ) {
7707             theFaces.push_back( *curElemIt );
7708             theNodes.push_back( *nStartIt );
7709             return true;
7710           }
7711       }
7712       // find the best free border by the continuations
7713       list<const SMDS_MeshNode*>    contNodes[ 2 ], *cNL;
7714       list<const SMDS_MeshElement*> contFaces[ 2 ], *cFL;
7715       for (curElemIt = curElemList.begin(), nStartIt = nStartList.begin();
7716            curElemIt!= curElemList.end();
7717            curElemIt++, nStartIt++ )
7718       {
7719         cNL = & contNodes[ contNodes[0].empty() ? 0 : 1 ];
7720         cFL = & contFaces[ contFaces[0].empty() ? 0 : 1 ];
7721         // find one more free border
7722         if ( ! SMESH_MeshEditor::FindFreeBorder( nStart, *nStartIt, theLastNode, *cNL, *cFL )) {
7723           cNL->clear();
7724           cFL->clear();
7725         }
7726         else if ( !contNodes[0].empty() && !contNodes[1].empty() ) {
7727           // choice: clear a worse one
7728           int iLongest = ( contNodes[0].size() < contNodes[1].size() ? 1 : 0 );
7729           int   iWorse = ( needTheLast ? 1 - iLongest : iLongest );
7730           contNodes[ iWorse ].clear();
7731           contFaces[ iWorse ].clear();
7732         }
7733       }
7734       if ( contNodes[0].empty() && contNodes[1].empty() )
7735         return false;
7736
7737       // push_back the best free border
7738       cNL = & contNodes[ contNodes[0].empty() ? 1 : 0 ];
7739       cFL = & contFaces[ contFaces[0].empty() ? 1 : 0 ];
7740       //theNodes.pop_back(); // remove nIgnore
7741       theNodes.pop_back(); // remove nStart
7742       //theFaces.pop_back(); // remove curElem
7743       theNodes.splice( theNodes.end(), *cNL );
7744       theFaces.splice( theFaces.end(), *cFL );
7745       return true;
7746
7747     } // several continuations found
7748   } // while ( nStart != theLastNode )
7749
7750   return true;
7751 }
7752
7753 //=======================================================================
7754 //function : CheckFreeBorderNodes
7755 //purpose  : Return true if the tree nodes are on a free border
7756 //=======================================================================
7757
7758 bool SMESH_MeshEditor::CheckFreeBorderNodes(const SMDS_MeshNode* theNode1,
7759                                             const SMDS_MeshNode* theNode2,
7760                                             const SMDS_MeshNode* theNode3)
7761 {
7762   list< const SMDS_MeshNode* > nodes;
7763   list< const SMDS_MeshElement* > faces;
7764   return FindFreeBorder( theNode1, theNode2, theNode3, nodes, faces);
7765 }
7766
7767 //=======================================================================
7768 //function : SewFreeBorder
7769 //purpose  :
7770 //warning  : for border-to-side sewing theSideSecondNode is considered as
7771 //           the last side node and theSideThirdNode is not used
7772 //=======================================================================
7773
7774 SMESH_MeshEditor::Sew_Error
7775 SMESH_MeshEditor::SewFreeBorder (const SMDS_MeshNode* theBordFirstNode,
7776                                  const SMDS_MeshNode* theBordSecondNode,
7777                                  const SMDS_MeshNode* theBordLastNode,
7778                                  const SMDS_MeshNode* theSideFirstNode,
7779                                  const SMDS_MeshNode* theSideSecondNode,
7780                                  const SMDS_MeshNode* theSideThirdNode,
7781                                  const bool           theSideIsFreeBorder,
7782                                  const bool           toCreatePolygons,
7783                                  const bool           toCreatePolyedrs)
7784 {
7785   ClearLastCreated();
7786
7787   Sew_Error aResult = SEW_OK;
7788
7789   // ====================================
7790   //    find side nodes and elements
7791   // ====================================
7792
7793   list< const SMDS_MeshNode* >    nSide[ 2 ];
7794   list< const SMDS_MeshElement* > eSide[ 2 ];
7795   list< const SMDS_MeshNode* >::iterator    nIt[ 2 ];
7796   list< const SMDS_MeshElement* >::iterator eIt[ 2 ];
7797
7798   // Free border 1
7799   // --------------
7800   if (!FindFreeBorder(theBordFirstNode,theBordSecondNode,theBordLastNode,
7801                       nSide[0], eSide[0])) {
7802     MESSAGE(" Free Border 1 not found " );
7803     aResult = SEW_BORDER1_NOT_FOUND;
7804   }
7805   if (theSideIsFreeBorder) {
7806     // Free border 2
7807     // --------------
7808     if (!FindFreeBorder(theSideFirstNode, theSideSecondNode, theSideThirdNode,
7809                         nSide[1], eSide[1])) {
7810       MESSAGE(" Free Border 2 not found " );
7811       aResult = ( aResult != SEW_OK ? SEW_BOTH_BORDERS_NOT_FOUND : SEW_BORDER2_NOT_FOUND );
7812     }
7813   }
7814   if ( aResult != SEW_OK )
7815     return aResult;
7816
7817   if (!theSideIsFreeBorder) {
7818     // Side 2
7819     // --------------
7820
7821     // -------------------------------------------------------------------------
7822     // Algo:
7823     // 1. If nodes to merge are not coincident, move nodes of the free border
7824     //    from the coord sys defined by the direction from the first to last
7825     //    nodes of the border to the correspondent sys of the side 2
7826     // 2. On the side 2, find the links most co-directed with the correspondent
7827     //    links of the free border
7828     // -------------------------------------------------------------------------
7829
7830     // 1. Since sewing may break if there are volumes to split on the side 2,
7831     //    we won't move nodes but just compute new coordinates for them
7832     typedef map<const SMDS_MeshNode*, gp_XYZ> TNodeXYZMap;
7833     TNodeXYZMap nBordXYZ;
7834     list< const SMDS_MeshNode* >& bordNodes = nSide[ 0 ];
7835     list< const SMDS_MeshNode* >::iterator nBordIt;
7836
7837     gp_XYZ Pb1( theBordFirstNode->X(), theBordFirstNode->Y(), theBordFirstNode->Z() );
7838     gp_XYZ Pb2( theBordLastNode->X(), theBordLastNode->Y(), theBordLastNode->Z() );
7839     gp_XYZ Ps1( theSideFirstNode->X(), theSideFirstNode->Y(), theSideFirstNode->Z() );
7840     gp_XYZ Ps2( theSideSecondNode->X(), theSideSecondNode->Y(), theSideSecondNode->Z() );
7841     double tol2 = 1.e-8;
7842     gp_Vec Vbs1( Pb1 - Ps1 ),Vbs2( Pb2 - Ps2 );
7843     if ( Vbs1.SquareMagnitude() > tol2 || Vbs2.SquareMagnitude() > tol2 ) {
7844       // Need node movement.
7845
7846       // find X and Z axes to create trsf
7847       gp_Vec Zb( Pb1 - Pb2 ), Zs( Ps1 - Ps2 );
7848       gp_Vec X = Zs ^ Zb;
7849       if ( X.SquareMagnitude() <= gp::Resolution() * gp::Resolution() )
7850         // Zb || Zs
7851         X = gp_Ax2( gp::Origin(), Zb ).XDirection();
7852
7853       // coord systems
7854       gp_Ax3 toBordAx( Pb1, Zb, X );
7855       gp_Ax3 fromSideAx( Ps1, Zs, X );
7856       gp_Ax3 toGlobalAx( gp::Origin(), gp::DZ(), gp::DX() );
7857       // set trsf
7858       gp_Trsf toBordSys, fromSide2Sys;
7859       toBordSys.SetTransformation( toBordAx );
7860       fromSide2Sys.SetTransformation( fromSideAx, toGlobalAx );
7861       fromSide2Sys.SetScaleFactor( Zs.Magnitude() / Zb.Magnitude() );
7862
7863       // move
7864       for ( nBordIt = bordNodes.begin(); nBordIt != bordNodes.end(); nBordIt++ ) {
7865         const SMDS_MeshNode* n = *nBordIt;
7866         gp_XYZ xyz( n->X(),n->Y(),n->Z() );
7867         toBordSys.Transforms( xyz );
7868         fromSide2Sys.Transforms( xyz );
7869         nBordXYZ.insert( TNodeXYZMap::value_type( n, xyz ));
7870       }
7871     }
7872     else {
7873       // just insert nodes XYZ in the nBordXYZ map
7874       for ( nBordIt = bordNodes.begin(); nBordIt != bordNodes.end(); nBordIt++ ) {
7875         const SMDS_MeshNode* n = *nBordIt;
7876         nBordXYZ.insert( TNodeXYZMap::value_type( n, gp_XYZ( n->X(),n->Y(),n->Z() )));
7877       }
7878     }
7879
7880     // 2. On the side 2, find the links most co-directed with the correspondent
7881     //    links of the free border
7882
7883     list< const SMDS_MeshElement* >& sideElems = eSide[ 1 ];
7884     list< const SMDS_MeshNode* >& sideNodes = nSide[ 1 ];
7885     sideNodes.push_back( theSideFirstNode );
7886
7887     bool hasVolumes = false;
7888     LinkID_Gen aLinkID_Gen( GetMeshDS() );
7889     set<long> foundSideLinkIDs, checkedLinkIDs;
7890     SMDS_VolumeTool volume;
7891     //const SMDS_MeshNode* faceNodes[ 4 ];
7892
7893     const SMDS_MeshNode*    sideNode;
7894     const SMDS_MeshElement* sideElem  = 0;
7895     const SMDS_MeshNode* prevSideNode = theSideFirstNode;
7896     const SMDS_MeshNode* prevBordNode = theBordFirstNode;
7897     nBordIt = bordNodes.begin();
7898     nBordIt++;
7899     // border node position and border link direction to compare with
7900     gp_XYZ bordPos = nBordXYZ[ *nBordIt ];
7901     gp_XYZ bordDir = bordPos - nBordXYZ[ prevBordNode ];
7902     // choose next side node by link direction or by closeness to
7903     // the current border node:
7904     bool searchByDir = ( *nBordIt != theBordLastNode );
7905     do {
7906       // find the next node on the Side 2
7907       sideNode = 0;
7908       double maxDot = -DBL_MAX, minDist = DBL_MAX;
7909       long linkID;
7910       checkedLinkIDs.clear();
7911       gp_XYZ prevXYZ( prevSideNode->X(), prevSideNode->Y(), prevSideNode->Z() );
7912
7913       // loop on inverse elements of current node (prevSideNode) on the Side 2
7914       SMDS_ElemIteratorPtr invElemIt = prevSideNode->GetInverseElementIterator();
7915       while ( invElemIt->more() )
7916       {
7917         const SMDS_MeshElement* elem = invElemIt->next();
7918         // prepare data for a loop on links coming to prevSideNode, of a face or a volume
7919         int iPrevNode = 0, iNode = 0, nbNodes = elem->NbNodes();
7920         vector< const SMDS_MeshNode* > faceNodes( nbNodes, (const SMDS_MeshNode*)0 );
7921         bool isVolume = volume.Set( elem );
7922         const SMDS_MeshNode** nodes = isVolume ? volume.GetNodes() : & faceNodes[0];
7923         if ( isVolume ) // --volume
7924           hasVolumes = true;
7925         else if ( elem->GetType() == SMDSAbs_Face ) { // --face
7926           // retrieve all face nodes and find iPrevNode - an index of the prevSideNode
7927           SMDS_NodeIteratorPtr nIt = elem->interlacedNodesIterator();
7928           while ( nIt->more() ) {
7929             nodes[ iNode ] = cast2Node( nIt->next() );
7930             if ( nodes[ iNode++ ] == prevSideNode )
7931               iPrevNode = iNode - 1;
7932           }
7933           // there are 2 links to check
7934           nbNodes = 2;
7935         }
7936         else // --edge
7937           continue;
7938         // loop on links, to be precise, on the second node of links
7939         for ( iNode = 0; iNode < nbNodes; iNode++ ) {
7940           const SMDS_MeshNode* n = nodes[ iNode ];
7941           if ( isVolume ) {
7942             if ( !volume.IsLinked( n, prevSideNode ))
7943               continue;
7944           }
7945           else {
7946             if ( iNode ) // a node before prevSideNode
7947               n = nodes[ iPrevNode == 0 ? elem->NbNodes() - 1 : iPrevNode - 1 ];
7948             else         // a node after prevSideNode
7949               n = nodes[ iPrevNode + 1 == elem->NbNodes() ? 0 : iPrevNode + 1 ];
7950           }
7951           // check if this link was already used
7952           long iLink = aLinkID_Gen.GetLinkID( prevSideNode, n );
7953           bool isJustChecked = !checkedLinkIDs.insert( iLink ).second;
7954           if (!isJustChecked &&
7955               foundSideLinkIDs.find( iLink ) == foundSideLinkIDs.end() )
7956           {
7957             // test a link geometrically
7958             gp_XYZ nextXYZ ( n->X(), n->Y(), n->Z() );
7959             bool linkIsBetter = false;
7960             double dot = 0.0, dist = 0.0;
7961             if ( searchByDir ) { // choose most co-directed link
7962               dot = bordDir * ( nextXYZ - prevXYZ ).Normalized();
7963               linkIsBetter = ( dot > maxDot );
7964             }
7965             else { // choose link with the node closest to bordPos
7966               dist = ( nextXYZ - bordPos ).SquareModulus();
7967               linkIsBetter = ( dist < minDist );
7968             }
7969             if ( linkIsBetter ) {
7970               maxDot = dot;
7971               minDist = dist;
7972               linkID = iLink;
7973               sideNode = n;
7974               sideElem = elem;
7975             }
7976           }
7977         }
7978       } // loop on inverse elements of prevSideNode
7979
7980       if ( !sideNode ) {
7981         MESSAGE(" Can't find path by links of the Side 2 ");
7982         return SEW_BAD_SIDE_NODES;
7983       }
7984       sideNodes.push_back( sideNode );
7985       sideElems.push_back( sideElem );
7986       foundSideLinkIDs.insert ( linkID );
7987       prevSideNode = sideNode;
7988
7989       if ( *nBordIt == theBordLastNode )
7990         searchByDir = false;
7991       else {
7992         // find the next border link to compare with
7993         gp_XYZ sidePos( sideNode->X(), sideNode->Y(), sideNode->Z() );
7994         searchByDir = ( bordDir * ( sidePos - bordPos ) <= 0 );
7995         // move to next border node if sideNode is before forward border node (bordPos)
7996         while ( *nBordIt != theBordLastNode && !searchByDir ) {
7997           prevBordNode = *nBordIt;
7998           nBordIt++;
7999           bordPos = nBordXYZ[ *nBordIt ];
8000           bordDir = bordPos - nBordXYZ[ prevBordNode ];
8001           searchByDir = ( bordDir * ( sidePos - bordPos ) <= 0 );
8002         }
8003       }
8004     }
8005     while ( sideNode != theSideSecondNode );
8006
8007     if ( hasVolumes && sideNodes.size () != bordNodes.size() && !toCreatePolyedrs) {
8008       MESSAGE("VOLUME SPLITTING IS FORBIDDEN");
8009       return SEW_VOLUMES_TO_SPLIT; // volume splitting is forbidden
8010     }
8011   } // end nodes search on the side 2
8012
8013   // ============================
8014   // sew the border to the side 2
8015   // ============================
8016
8017   int nbNodes[]  = { (int)nSide[0].size(), (int)nSide[1].size() };
8018   int maxNbNodes = Max( nbNodes[0], nbNodes[1] );
8019
8020   bool toMergeConformal = ( nbNodes[0] == nbNodes[1] );
8021   if ( toMergeConformal && toCreatePolygons )
8022   {
8023     // do not merge quadrangles if polygons are OK (IPAL0052824)
8024     eIt[0] = eSide[0].begin();
8025     eIt[1] = eSide[1].begin();
8026     bool allQuads[2] = { true, true };
8027     for ( int iBord = 0; iBord < 2; iBord++ ) { // loop on 2 borders
8028       for ( ; allQuads[iBord] && eIt[iBord] != eSide[iBord].end(); ++eIt[iBord] )
8029         allQuads[iBord] = ( (*eIt[iBord])->NbCornerNodes() == 4 );
8030     }
8031     toMergeConformal = ( !allQuads[0] && !allQuads[1] );
8032   }
8033
8034   TListOfListOfNodes nodeGroupsToMerge;
8035   if (( toMergeConformal ) ||
8036       ( theSideIsFreeBorder && !theSideThirdNode )) {
8037
8038     // all nodes are to be merged
8039
8040     for (nIt[0] = nSide[0].begin(), nIt[1] = nSide[1].begin();
8041          nIt[0] != nSide[0].end() && nIt[1] != nSide[1].end();
8042          nIt[0]++, nIt[1]++ )
8043     {
8044       nodeGroupsToMerge.push_back( list<const SMDS_MeshNode*>() );
8045       nodeGroupsToMerge.back().push_back( *nIt[1] ); // to keep
8046       nodeGroupsToMerge.back().push_back( *nIt[0] ); // to remove
8047     }
8048   }
8049   else {
8050
8051     // insert new nodes into the border and the side to get equal nb of segments
8052
8053     // get normalized parameters of nodes on the borders
8054     vector< double > param[ 2 ];
8055     param[0].resize( maxNbNodes );
8056     param[1].resize( maxNbNodes );
8057     int iNode, iBord;
8058     for ( iBord = 0; iBord < 2; iBord++ ) { // loop on 2 borders
8059       list< const SMDS_MeshNode* >& nodes = nSide[ iBord ];
8060       list< const SMDS_MeshNode* >::iterator nIt = nodes.begin();
8061       const SMDS_MeshNode* nPrev = *nIt;
8062       double bordLength = 0;
8063       for ( iNode = 0; nIt != nodes.end(); nIt++, iNode++ ) { // loop on border nodes
8064         const SMDS_MeshNode* nCur = *nIt;
8065         gp_XYZ segment (nCur->X() - nPrev->X(),
8066                         nCur->Y() - nPrev->Y(),
8067                         nCur->Z() - nPrev->Z());
8068         double segmentLen = segment.Modulus();
8069         bordLength += segmentLen;
8070         param[ iBord ][ iNode ] = bordLength;
8071         nPrev = nCur;
8072       }
8073       // normalize within [0,1]
8074       for ( iNode = 0; iNode < nbNodes[ iBord ]; iNode++ ) {
8075         param[ iBord ][ iNode ] /= bordLength;
8076       }
8077     }
8078
8079     // loop on border segments
8080     const SMDS_MeshNode *nPrev[ 2 ] = { 0, 0 };
8081     int i[ 2 ] = { 0, 0 };
8082     nIt[0] = nSide[0].begin(); eIt[0] = eSide[0].begin();
8083     nIt[1] = nSide[1].begin(); eIt[1] = eSide[1].begin();
8084
8085     // element can be split while iterating on border if it has two edges in the border
8086     std::map< const SMDS_MeshElement* , const SMDS_MeshElement* > elemReplaceMap;
8087     std::map< const SMDS_MeshElement* , const SMDS_MeshElement* >::iterator elemReplaceMapIt;
8088
8089     TElemOfNodeListMap insertMap;
8090     TElemOfNodeListMap::iterator insertMapIt;
8091     // insertMap is
8092     // key:   elem to insert nodes into
8093     // value: 2 nodes to insert between + nodes to be inserted
8094     do {
8095       bool next[ 2 ] = { false, false };
8096
8097       // find min adjacent segment length after sewing
8098       double nextParam = 10., prevParam = 0;
8099       for ( iBord = 0; iBord < 2; iBord++ ) { // loop on 2 borders
8100         if ( i[ iBord ] + 1 < nbNodes[ iBord ])
8101           nextParam = Min( nextParam, param[iBord][ i[iBord] + 1 ]);
8102         if ( i[ iBord ] > 0 )
8103           prevParam = Max( prevParam, param[iBord][ i[iBord] - 1 ]);
8104       }
8105       double  minParam = Min( param[ 0 ][ i[0] ], param[ 1 ][ i[1] ]);
8106       double  maxParam = Max( param[ 0 ][ i[0] ], param[ 1 ][ i[1] ]);
8107       double minSegLen = Min( nextParam - minParam, maxParam - prevParam );
8108
8109       // choose to insert or to merge nodes
8110       double du = param[ 1 ][ i[1] ] - param[ 0 ][ i[0] ];
8111       if ( Abs( du ) <= minSegLen * 0.2 ) {
8112         // merge
8113         // ------
8114         nodeGroupsToMerge.push_back( list<const SMDS_MeshNode*>() );
8115         const SMDS_MeshNode* n0 = *nIt[0];
8116         const SMDS_MeshNode* n1 = *nIt[1];
8117         nodeGroupsToMerge.back().push_back( n1 );
8118         nodeGroupsToMerge.back().push_back( n0 );
8119         // position of node of the border changes due to merge
8120         param[ 0 ][ i[0] ] += du;
8121         // move n1 for the sake of elem shape evaluation during insertion.
8122         // n1 will be removed by MergeNodes() anyway
8123         const_cast<SMDS_MeshNode*>( n0 )->setXYZ( n1->X(), n1->Y(), n1->Z() );
8124         next[0] = next[1] = true;
8125       }
8126       else {
8127         // insert
8128         // ------
8129         int intoBord = ( du < 0 ) ? 0 : 1;
8130         const SMDS_MeshElement* elem = *eIt [ intoBord ];
8131         const SMDS_MeshNode*    n1   = nPrev[ intoBord ];
8132         const SMDS_MeshNode*    n2   = *nIt [ intoBord ];
8133         const SMDS_MeshNode*    nIns = *nIt [ 1 - intoBord ];
8134         if ( intoBord == 1 ) {
8135           // move node of the border to be on a link of elem of the side
8136           SMESH_NodeXYZ p1( n1 ), p2( n2 );
8137           double ratio = du / ( param[ 1 ][ i[1] ] - param[ 1 ][ i[1]-1 ]);
8138           gp_XYZ p = p2 * ( 1 - ratio ) + p1 * ratio;
8139           GetMeshDS()->MoveNode( nIns, p.X(), p.Y(), p.Z() );
8140         }
8141         elemReplaceMapIt = elemReplaceMap.find( elem );
8142         if ( elemReplaceMapIt != elemReplaceMap.end() )
8143           elem = elemReplaceMapIt->second;
8144
8145         insertMapIt = insertMap.find( elem );
8146         bool  notFound = ( insertMapIt == insertMap.end() );
8147         bool otherLink = ( !notFound && (*insertMapIt).second.front() != n1 );
8148         if ( otherLink ) {
8149           // insert into another link of the same element:
8150           // 1. perform insertion into the other link of the elem
8151           list<const SMDS_MeshNode*> & nodeList = (*insertMapIt).second;
8152           const SMDS_MeshNode* n12 = nodeList.front(); nodeList.pop_front();
8153           const SMDS_MeshNode* n22 = nodeList.front(); nodeList.pop_front();
8154           InsertNodesIntoLink( elem, n12, n22, nodeList, toCreatePolygons );
8155           // 2. perform insertion into the link of adjacent faces
8156           while ( const SMDS_MeshElement* adjElem = findAdjacentFace( n12, n22, elem )) {
8157             InsertNodesIntoLink( adjElem, n12, n22, nodeList, toCreatePolygons );
8158           }
8159           while ( const SMDS_MeshElement* seg = findSegment( n12, n22 )) {
8160             InsertNodesIntoLink( seg, n12, n22, nodeList );
8161           }
8162           if (toCreatePolyedrs) {
8163             // perform insertion into the links of adjacent volumes
8164             UpdateVolumes(n12, n22, nodeList);
8165           }
8166           // 3. find an element appeared on n1 and n2 after the insertion
8167           insertMap.erase( insertMapIt );
8168           const SMDS_MeshElement* elem2 = findAdjacentFace( n1, n2, 0 );
8169           elemReplaceMap.insert( std::make_pair( elem, elem2 ));
8170           elem = elem2;
8171         }
8172         if ( notFound || otherLink ) {
8173           // add element and nodes of the side into the insertMap
8174           insertMapIt = insertMap.insert( make_pair( elem, list<const SMDS_MeshNode*>() )).first;
8175           (*insertMapIt).second.push_back( n1 );
8176           (*insertMapIt).second.push_back( n2 );
8177         }
8178         // add node to be inserted into elem
8179         (*insertMapIt).second.push_back( nIns );
8180         next[ 1 - intoBord ] = true;
8181       }
8182
8183       // go to the next segment
8184       for ( iBord = 0; iBord < 2; iBord++ ) { // loop on 2 borders
8185         if ( next[ iBord ] ) {
8186           if ( i[ iBord ] != 0 && eIt[ iBord ] != eSide[ iBord ].end())
8187             eIt[ iBord ]++;
8188           nPrev[ iBord ] = *nIt[ iBord ];
8189           nIt[ iBord ]++; i[ iBord ]++;
8190         }
8191       }
8192     }
8193     while ( nIt[0] != nSide[0].end() && nIt[1] != nSide[1].end());
8194
8195     // perform insertion of nodes into elements
8196
8197     for (insertMapIt = insertMap.begin();
8198          insertMapIt != insertMap.end();
8199          insertMapIt++ )
8200     {
8201       const SMDS_MeshElement* elem = (*insertMapIt).first;
8202       list<const SMDS_MeshNode*> & nodeList = (*insertMapIt).second;
8203       if ( nodeList.size() < 3 ) continue;
8204       const SMDS_MeshNode* n1 = nodeList.front(); nodeList.pop_front();
8205       const SMDS_MeshNode* n2 = nodeList.front(); nodeList.pop_front();
8206
8207       InsertNodesIntoLink( elem, n1, n2, nodeList, toCreatePolygons );
8208
8209       while ( const SMDS_MeshElement* seg = findSegment( n1, n2 )) {
8210         InsertNodesIntoLink( seg, n1, n2, nodeList );
8211       }
8212
8213       if ( !theSideIsFreeBorder ) {
8214         // look for and insert nodes into the faces adjacent to elem
8215         while ( const SMDS_MeshElement* adjElem = findAdjacentFace( n1, n2, elem )) {
8216           InsertNodesIntoLink( adjElem, n1, n2, nodeList, toCreatePolygons );
8217         }
8218       }
8219       if (toCreatePolyedrs) {
8220         // perform insertion into the links of adjacent volumes
8221         UpdateVolumes(n1, n2, nodeList);
8222       }
8223     }
8224   } // end: insert new nodes
8225
8226   MergeNodes ( nodeGroupsToMerge );
8227
8228
8229   // Remove coincident segments
8230
8231   // get new segments
8232   TIDSortedElemSet segments;
8233   SMESH_SequenceOfElemPtr newFaces;
8234   for ( size_t i = 0; i < myLastCreatedElems.size(); ++i )
8235   {
8236     if ( !myLastCreatedElems[i] ) continue;
8237     if ( myLastCreatedElems[i]->GetType() == SMDSAbs_Edge )
8238       segments.insert( segments.end(), myLastCreatedElems[i] );
8239     else
8240       newFaces.push_back( myLastCreatedElems[i] );
8241   }
8242   // get segments adjacent to merged nodes
8243   TListOfListOfNodes::iterator groupIt = nodeGroupsToMerge.begin();
8244   for ( ; groupIt != nodeGroupsToMerge.end(); groupIt++ )
8245   {
8246     const list<const SMDS_MeshNode*>& nodes = *groupIt;
8247     if ( nodes.front()->IsNull() ) continue;
8248     SMDS_ElemIteratorPtr segIt = nodes.front()->GetInverseElementIterator( SMDSAbs_Edge );
8249     while ( segIt->more() )
8250       segments.insert( segIt->next() );
8251   }
8252
8253   // find coincident
8254   TListOfListOfElementsID equalGroups;
8255   if ( !segments.empty() )
8256     FindEqualElements( segments, equalGroups );
8257   if ( !equalGroups.empty() )
8258   {
8259     // remove from segments those that will be removed
8260     TListOfListOfElementsID::iterator itGroups = equalGroups.begin();
8261     for ( ; itGroups != equalGroups.end(); ++itGroups )
8262     {
8263       list< int >& group = *itGroups;
8264       list< int >::iterator id = group.begin();
8265       for ( ++id; id != group.end(); ++id )
8266         if ( const SMDS_MeshElement* seg = GetMeshDS()->FindElement( *id ))
8267           segments.erase( seg );
8268     }
8269     // remove equal segments
8270     MergeElements( equalGroups );
8271
8272     // restore myLastCreatedElems
8273     myLastCreatedElems = newFaces;
8274     TIDSortedElemSet::iterator seg = segments.begin();
8275     for ( ; seg != segments.end(); ++seg )
8276       myLastCreatedElems.push_back( *seg );
8277   }
8278
8279   return aResult;
8280 }
8281
8282 //=======================================================================
8283 //function : InsertNodesIntoLink
8284 //purpose  : insert theNodesToInsert into theElement between theBetweenNode1
8285 //           and theBetweenNode2 and split theElement
8286 //=======================================================================
8287
8288 void SMESH_MeshEditor::InsertNodesIntoLink(const SMDS_MeshElement*     theElement,
8289                                            const SMDS_MeshNode*        theBetweenNode1,
8290                                            const SMDS_MeshNode*        theBetweenNode2,
8291                                            list<const SMDS_MeshNode*>& theNodesToInsert,
8292                                            const bool                  toCreatePoly)
8293 {
8294   if ( !theElement ) return;
8295
8296   SMESHDS_Mesh *aMesh = GetMeshDS();
8297   vector<const SMDS_MeshElement*> newElems;
8298
8299   if ( theElement->GetType() == SMDSAbs_Edge )
8300   {
8301     theNodesToInsert.push_front( theBetweenNode1 );
8302     theNodesToInsert.push_back ( theBetweenNode2 );
8303     list<const SMDS_MeshNode*>::iterator n = theNodesToInsert.begin();
8304     const SMDS_MeshNode* n1 = *n;
8305     for ( ++n; n != theNodesToInsert.end(); ++n )
8306     {
8307       const SMDS_MeshNode* n2 = *n;
8308       if ( const SMDS_MeshElement* seg = aMesh->FindEdge( n1, n2 ))
8309         AddToSameGroups( seg, theElement, aMesh );
8310       else
8311         newElems.push_back( aMesh->AddEdge ( n1, n2 ));
8312       n1 = n2;
8313     }
8314     theNodesToInsert.pop_front();
8315     theNodesToInsert.pop_back();
8316
8317     if ( theElement->IsQuadratic() ) // add a not split part
8318     {
8319       vector<const SMDS_MeshNode*> nodes( theElement->begin_nodes(),
8320                                           theElement->end_nodes() );
8321       int iOther = 0, nbN = nodes.size();
8322       for ( ; iOther < nbN; ++iOther )
8323         if ( nodes[iOther] != theBetweenNode1 &&
8324              nodes[iOther] != theBetweenNode2 )
8325           break;
8326       if      ( iOther == 0 )
8327       {
8328         if ( const SMDS_MeshElement* seg = aMesh->FindEdge( nodes[0], nodes[1] ))
8329           AddToSameGroups( seg, theElement, aMesh );
8330         else
8331           newElems.push_back( aMesh->AddEdge ( nodes[0], nodes[1] ));
8332       }
8333       else if ( iOther == 2 )
8334       {
8335         if ( const SMDS_MeshElement* seg = aMesh->FindEdge( nodes[1], nodes[2] ))
8336           AddToSameGroups( seg, theElement, aMesh );
8337         else
8338           newElems.push_back( aMesh->AddEdge ( nodes[1], nodes[2] ));
8339       }
8340     }
8341     // treat new elements
8342     for ( size_t i = 0; i < newElems.size(); ++i )
8343       if ( newElems[i] )
8344       {
8345         aMesh->SetMeshElementOnShape( newElems[i], theElement->getshapeId() );
8346         myLastCreatedElems.push_back( newElems[i] );
8347       }
8348     ReplaceElemInGroups( theElement, newElems, aMesh );
8349     aMesh->RemoveElement( theElement );
8350     return;
8351
8352   } // if ( theElement->GetType() == SMDSAbs_Edge )
8353
8354   const SMDS_MeshElement* theFace = theElement;
8355   if ( theFace->GetType() != SMDSAbs_Face ) return;
8356
8357   // find indices of 2 link nodes and of the rest nodes
8358   int iNode = 0, il1, il2, i3, i4;
8359   il1 = il2 = i3 = i4 = -1;
8360   vector<const SMDS_MeshNode*> nodes( theFace->NbNodes() );
8361
8362   SMDS_NodeIteratorPtr nodeIt = theFace->interlacedNodesIterator();
8363   while ( nodeIt->more() ) {
8364     const SMDS_MeshNode* n = nodeIt->next();
8365     if ( n == theBetweenNode1 )
8366       il1 = iNode;
8367     else if ( n == theBetweenNode2 )
8368       il2 = iNode;
8369     else if ( i3 < 0 )
8370       i3 = iNode;
8371     else
8372       i4 = iNode;
8373     nodes[ iNode++ ] = n;
8374   }
8375   if ( il1 < 0 || il2 < 0 || i3 < 0 )
8376     return ;
8377
8378   // arrange link nodes to go one after another regarding the face orientation
8379   bool reverse = ( Abs( il2 - il1 ) == 1 ? il2 < il1 : il1 < il2 );
8380   list<const SMDS_MeshNode *> aNodesToInsert = theNodesToInsert;
8381   if ( reverse ) {
8382     iNode = il1;
8383     il1 = il2;
8384     il2 = iNode;
8385     aNodesToInsert.reverse();
8386   }
8387   // check that not link nodes of a quadrangles are in good order
8388   int nbFaceNodes = theFace->NbNodes();
8389   if ( nbFaceNodes == 4 && i4 - i3 != 1 ) {
8390     iNode = i3;
8391     i3 = i4;
8392     i4 = iNode;
8393   }
8394
8395   if (toCreatePoly || theFace->IsPoly()) {
8396
8397     iNode = 0;
8398     vector<const SMDS_MeshNode *> poly_nodes (nbFaceNodes + aNodesToInsert.size());
8399
8400     // add nodes of face up to first node of link
8401     bool isFLN = false;
8402     SMDS_NodeIteratorPtr nodeIt = theFace->interlacedNodesIterator();
8403     while ( nodeIt->more() && !isFLN ) {
8404       const SMDS_MeshNode* n = nodeIt->next();
8405       poly_nodes[iNode++] = n;
8406       isFLN = ( n == nodes[il1] );
8407     }
8408     // add nodes to insert
8409     list<const SMDS_MeshNode*>::iterator nIt = aNodesToInsert.begin();
8410     for (; nIt != aNodesToInsert.end(); nIt++) {
8411       poly_nodes[iNode++] = *nIt;
8412     }
8413     // add nodes of face starting from last node of link
8414     while ( nodeIt->more() ) {
8415       const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
8416       poly_nodes[iNode++] = n;
8417     }
8418
8419     // make a new face
8420     newElems.push_back( aMesh->AddPolygonalFace( poly_nodes ));
8421   }
8422
8423   else if ( !theFace->IsQuadratic() )
8424   {
8425     // put aNodesToInsert between theBetweenNode1 and theBetweenNode2
8426     int nbLinkNodes = 2 + aNodesToInsert.size();
8427     //const SMDS_MeshNode* linkNodes[ nbLinkNodes ];
8428     vector<const SMDS_MeshNode*> linkNodes( nbLinkNodes );
8429     linkNodes[ 0 ] = nodes[ il1 ];
8430     linkNodes[ nbLinkNodes - 1 ] = nodes[ il2 ];
8431     list<const SMDS_MeshNode*>::iterator nIt = aNodesToInsert.begin();
8432     for ( iNode = 1; nIt != aNodesToInsert.end(); nIt++ ) {
8433       linkNodes[ iNode++ ] = *nIt;
8434     }
8435     // decide how to split a quadrangle: compare possible variants
8436     // and choose which of splits to be a quadrangle
8437     int i1, i2, iSplit, nbSplits = nbLinkNodes - 1, iBestQuad = 0;
8438     if ( nbFaceNodes == 3 ) {
8439       iBestQuad = nbSplits;
8440       i4 = i3;
8441     }
8442     else if ( nbFaceNodes == 4 ) {
8443       SMESH::Controls::NumericalFunctorPtr aCrit( new SMESH::Controls::AspectRatio);
8444       double aBestRate = DBL_MAX;
8445       for ( int iQuad = 0; iQuad < nbSplits; iQuad++ ) {
8446         i1 = 0; i2 = 1;
8447         double aBadRate = 0;
8448         // evaluate elements quality
8449         for ( iSplit = 0; iSplit < nbSplits; iSplit++ ) {
8450           if ( iSplit == iQuad ) {
8451             SMDS_FaceOfNodes quad (linkNodes[ i1++ ],
8452                                    linkNodes[ i2++ ],
8453                                    nodes[ i3 ],
8454                                    nodes[ i4 ]);
8455             aBadRate += getBadRate( &quad, aCrit );
8456           }
8457           else {
8458             SMDS_FaceOfNodes tria (linkNodes[ i1++ ],
8459                                    linkNodes[ i2++ ],
8460                                    nodes[ iSplit < iQuad ? i4 : i3 ]);
8461             aBadRate += getBadRate( &tria, aCrit );
8462           }
8463         }
8464         // choice
8465         if ( aBadRate < aBestRate ) {
8466           iBestQuad = iQuad;
8467           aBestRate = aBadRate;
8468         }
8469       }
8470     }
8471
8472     // create new elements
8473     i1 = 0; i2 = 1;
8474     for ( iSplit = 0; iSplit < nbSplits - 1; iSplit++ )
8475     {
8476       if ( iSplit == iBestQuad )
8477         newElems.push_back( aMesh->AddFace (linkNodes[ i1++ ],
8478                                             linkNodes[ i2++ ],
8479                                             nodes[ i3 ],
8480                                             nodes[ i4 ]));
8481       else
8482         newElems.push_back( aMesh->AddFace (linkNodes[ i1++ ],
8483                                             linkNodes[ i2++ ],
8484                                             nodes[ iSplit < iBestQuad ? i4 : i3 ]));
8485     }
8486
8487     const SMDS_MeshNode* newNodes[ 4 ];
8488     newNodes[ 0 ] = linkNodes[ i1 ];
8489     newNodes[ 1 ] = linkNodes[ i2 ];
8490     newNodes[ 2 ] = nodes[ iSplit >= iBestQuad ? i3 : i4 ];
8491     newNodes[ 3 ] = nodes[ i4 ];
8492     if (iSplit == iBestQuad)
8493       newElems.push_back( aMesh->AddFace( newNodes[0], newNodes[1], newNodes[2], newNodes[3] ));
8494     else
8495       newElems.push_back( aMesh->AddFace( newNodes[0], newNodes[1], newNodes[2] ));
8496
8497   } // end if(!theFace->IsQuadratic())
8498
8499   else { // theFace is quadratic
8500     // we have to split theFace on simple triangles and one simple quadrangle
8501     int tmp = il1/2;
8502     int nbshift = tmp*2;
8503     // shift nodes in nodes[] by nbshift
8504     int i,j;
8505     for(i=0; i<nbshift; i++) {
8506       const SMDS_MeshNode* n = nodes[0];
8507       for(j=0; j<nbFaceNodes-1; j++) {
8508         nodes[j] = nodes[j+1];
8509       }
8510       nodes[nbFaceNodes-1] = n;
8511     }
8512     il1 = il1 - nbshift;
8513     // now have to insert nodes between n0 and n1 or n1 and n2 (see below)
8514     //   n0      n1     n2    n0      n1     n2
8515     //     +-----+-----+        +-----+-----+
8516     //      \         /         |           |
8517     //       \       /          |           |
8518     //      n5+     +n3       n7+           +n3
8519     //         \   /            |           |
8520     //          \ /             |           |
8521     //           +              +-----+-----+
8522     //           n4           n6      n5     n4
8523
8524     // create new elements
8525     int n1,n2,n3;
8526     if ( nbFaceNodes == 6 ) { // quadratic triangle
8527       newElems.push_back( aMesh->AddFace( nodes[3], nodes[4], nodes[5] ));
8528       if ( theFace->IsMediumNode(nodes[il1]) ) {
8529         // create quadrangle
8530         newElems.push_back( aMesh->AddFace( nodes[0], nodes[1], nodes[3], nodes[5] ));
8531         n1 = 1;
8532         n2 = 2;
8533         n3 = 3;
8534       }
8535       else {
8536         // create quadrangle
8537         newElems.push_back( aMesh->AddFace( nodes[1], nodes[2], nodes[3], nodes[5] ));
8538         n1 = 0;
8539         n2 = 1;
8540         n3 = 5;
8541       }
8542     }
8543     else { // nbFaceNodes==8 - quadratic quadrangle
8544       newElems.push_back( aMesh->AddFace( nodes[3], nodes[4], nodes[5] ));
8545       newElems.push_back( aMesh->AddFace( nodes[5], nodes[6], nodes[7] ));
8546       newElems.push_back( aMesh->AddFace( nodes[5], nodes[7], nodes[3] ));
8547       if ( theFace->IsMediumNode( nodes[ il1 ])) {
8548         // create quadrangle
8549         newElems.push_back( aMesh->AddFace( nodes[0], nodes[1], nodes[3], nodes[7] ));
8550         n1 = 1;
8551         n2 = 2;
8552         n3 = 3;
8553       }
8554       else {
8555         // create quadrangle
8556         newElems.push_back( aMesh->AddFace( nodes[1], nodes[2], nodes[3], nodes[7] ));
8557         n1 = 0;
8558         n2 = 1;
8559         n3 = 7;
8560       }
8561     }
8562     // create needed triangles using n1,n2,n3 and inserted nodes
8563     int nbn = 2 + aNodesToInsert.size();
8564     vector<const SMDS_MeshNode*> aNodes(nbn);
8565     aNodes[0    ] = nodes[n1];
8566     aNodes[nbn-1] = nodes[n2];
8567     list<const SMDS_MeshNode*>::iterator nIt = aNodesToInsert.begin();
8568     for ( iNode = 1; nIt != aNodesToInsert.end(); nIt++ ) {
8569       aNodes[iNode++] = *nIt;
8570     }
8571     for ( i = 1; i < nbn; i++ )
8572       newElems.push_back( aMesh->AddFace( aNodes[i-1], aNodes[i], nodes[n3] ));
8573   }
8574
8575   // remove the old face
8576   for ( size_t i = 0; i < newElems.size(); ++i )
8577     if ( newElems[i] )
8578     {
8579       aMesh->SetMeshElementOnShape( newElems[i], theFace->getshapeId() );
8580       myLastCreatedElems.push_back( newElems[i] );
8581     }
8582   ReplaceElemInGroups( theFace, newElems, aMesh );
8583   aMesh->RemoveElement(theFace);
8584
8585 } // InsertNodesIntoLink()
8586
8587 //=======================================================================
8588 //function : UpdateVolumes
8589 //purpose  :
8590 //=======================================================================
8591
8592 void SMESH_MeshEditor::UpdateVolumes (const SMDS_MeshNode*        theBetweenNode1,
8593                                       const SMDS_MeshNode*        theBetweenNode2,
8594                                       list<const SMDS_MeshNode*>& theNodesToInsert)
8595 {
8596   ClearLastCreated();
8597
8598   SMDS_ElemIteratorPtr invElemIt = theBetweenNode1->GetInverseElementIterator(SMDSAbs_Volume);
8599   while (invElemIt->more()) { // loop on inverse elements of theBetweenNode1
8600     const SMDS_MeshElement* elem = invElemIt->next();
8601
8602     // check, if current volume has link theBetweenNode1 - theBetweenNode2
8603     SMDS_VolumeTool aVolume (elem);
8604     if (!aVolume.IsLinked(theBetweenNode1, theBetweenNode2))
8605       continue;
8606
8607     // insert new nodes in all faces of the volume, sharing link theBetweenNode1 - theBetweenNode2
8608     int iface, nbFaces = aVolume.NbFaces();
8609     vector<const SMDS_MeshNode *> poly_nodes;
8610     vector<smIdType> quantities (nbFaces);
8611
8612     for (iface = 0; iface < nbFaces; iface++) {
8613       int nbFaceNodes = aVolume.NbFaceNodes(iface), nbInserted = 0;
8614       // faceNodes will contain (nbFaceNodes + 1) nodes, last = first
8615       const SMDS_MeshNode** faceNodes = aVolume.GetFaceNodes(iface);
8616
8617       for (int inode = 0; inode < nbFaceNodes; inode++) {
8618         poly_nodes.push_back(faceNodes[inode]);
8619
8620         if (nbInserted == 0) {
8621           if (faceNodes[inode] == theBetweenNode1) {
8622             if (faceNodes[inode + 1] == theBetweenNode2) {
8623               nbInserted = theNodesToInsert.size();
8624
8625               // add nodes to insert
8626               list<const SMDS_MeshNode*>::iterator nIt = theNodesToInsert.begin();
8627               for (; nIt != theNodesToInsert.end(); nIt++) {
8628                 poly_nodes.push_back(*nIt);
8629               }
8630             }
8631           }
8632           else if (faceNodes[inode] == theBetweenNode2) {
8633             if (faceNodes[inode + 1] == theBetweenNode1) {
8634               nbInserted = theNodesToInsert.size();
8635
8636               // add nodes to insert in reversed order
8637               list<const SMDS_MeshNode*>::iterator nIt = theNodesToInsert.end();
8638               nIt--;
8639               for (; nIt != theNodesToInsert.begin(); nIt--) {
8640                 poly_nodes.push_back(*nIt);
8641               }
8642               poly_nodes.push_back(*nIt);
8643             }
8644           }
8645           else {
8646           }
8647         }
8648       }
8649       quantities[iface] = nbFaceNodes + nbInserted;
8650     }
8651
8652     // Replace the volume
8653     SMESHDS_Mesh *aMesh = GetMeshDS();
8654
8655     if ( SMDS_MeshElement* newElem = aMesh->AddPolyhedralVolume( poly_nodes, quantities ))
8656     {
8657       aMesh->SetMeshElementOnShape( newElem, elem->getshapeId() );
8658       myLastCreatedElems.push_back( newElem );
8659       ReplaceElemInGroups( elem, newElem, aMesh );
8660     }
8661     aMesh->RemoveElement( elem );
8662   }
8663 }
8664
8665 namespace
8666 {
8667   //================================================================================
8668   /*!
8669    * \brief Transform any volume into data of SMDSEntity_Polyhedra
8670    */
8671   //================================================================================
8672
8673   void volumeToPolyhedron( const SMDS_MeshElement*         elem,
8674                            vector<const SMDS_MeshNode *> & nodes,
8675                            vector<smIdType> &                   nbNodeInFaces )
8676   {
8677     nodes.clear();
8678     nbNodeInFaces.clear();
8679     SMDS_VolumeTool vTool ( elem );
8680     for ( int iF = 0; iF < vTool.NbFaces(); ++iF )
8681     {
8682       const SMDS_MeshNode** fNodes = vTool.GetFaceNodes( iF );
8683       nodes.insert( nodes.end(), fNodes, fNodes + vTool.NbFaceNodes( iF ));
8684       nbNodeInFaces.push_back( vTool.NbFaceNodes( iF ));
8685     }
8686   }
8687 }
8688
8689 //=======================================================================
8690 /*!
8691  * \brief Convert elements contained in a sub-mesh to quadratic
8692  * \return int - nb of checked elements
8693  */
8694 //=======================================================================
8695
8696 int SMESH_MeshEditor::convertElemToQuadratic(SMESHDS_SubMesh *   theSm,
8697                                              SMESH_MesherHelper& theHelper,
8698                                              const bool          theForce3d)
8699 {
8700   //MESSAGE("convertElemToQuadratic");
8701   int nbElem = 0;
8702   if( !theSm ) return nbElem;
8703
8704   vector<smIdType> nbNodeInFaces;
8705   vector<const SMDS_MeshNode *> nodes;
8706   SMDS_ElemIteratorPtr ElemItr = theSm->GetElements();
8707   while(ElemItr->more())
8708   {
8709     nbElem++;
8710     const SMDS_MeshElement* elem = ElemItr->next();
8711     if( !elem ) continue;
8712
8713     // analyse a necessity of conversion
8714     const SMDSAbs_ElementType aType = elem->GetType();
8715     if ( aType < SMDSAbs_Edge || aType > SMDSAbs_Volume )
8716       continue;
8717     const SMDSAbs_EntityType aGeomType = elem->GetEntityType();
8718     bool hasCentralNodes = false;
8719     if ( elem->IsQuadratic() )
8720     {
8721       bool alreadyOK;
8722       switch ( aGeomType ) {
8723       case SMDSEntity_Quad_Triangle:
8724       case SMDSEntity_Quad_Quadrangle:
8725       case SMDSEntity_Quad_Hexa:
8726       case SMDSEntity_Quad_Penta:
8727         alreadyOK = !theHelper.GetIsBiQuadratic(); break;
8728
8729       case SMDSEntity_BiQuad_Triangle:
8730       case SMDSEntity_BiQuad_Quadrangle:
8731       case SMDSEntity_TriQuad_Hexa:
8732       case SMDSEntity_BiQuad_Penta:
8733         alreadyOK = theHelper.GetIsBiQuadratic();
8734         hasCentralNodes = true;
8735         break;
8736       default:
8737         alreadyOK = true;
8738       }
8739       // take into account already present medium nodes
8740       switch ( aType ) {
8741       case SMDSAbs_Volume:
8742         theHelper.AddTLinks( static_cast< const SMDS_MeshVolume* >( elem )); break;
8743       case SMDSAbs_Face:
8744         theHelper.AddTLinks( static_cast< const SMDS_MeshFace* >( elem )); break;
8745       case SMDSAbs_Edge:
8746         theHelper.AddTLinks( static_cast< const SMDS_MeshEdge* >( elem )); break;
8747       default:;
8748       }
8749       if ( alreadyOK )
8750         continue;
8751     }
8752     // get elem data needed to re-create it
8753     //
8754     const int id      = elem->GetID();
8755     const int nbNodes = elem->NbCornerNodes();
8756     nodes.assign(elem->begin_nodes(), elem->end_nodes());
8757     if ( aGeomType == SMDSEntity_Polyhedra )
8758       nbNodeInFaces = static_cast<const SMDS_MeshVolume* >( elem )->GetQuantities();
8759     else if ( aGeomType == SMDSEntity_Hexagonal_Prism )
8760       volumeToPolyhedron( elem, nodes, nbNodeInFaces );
8761
8762     // remove a linear element
8763     GetMeshDS()->RemoveFreeElement(elem, theSm, /*fromGroups=*/false);
8764
8765     // remove central nodes of biquadratic elements (biquad->quad conversion)
8766     if ( hasCentralNodes )
8767       for ( size_t i = nbNodes * 2; i < nodes.size(); ++i )
8768         if ( nodes[i]->NbInverseElements() == 0 )
8769           GetMeshDS()->RemoveFreeNode( nodes[i], theSm, /*fromGroups=*/true );
8770
8771     const SMDS_MeshElement* NewElem = 0;
8772
8773     switch( aType )
8774     {
8775     case SMDSAbs_Edge :
8776     {
8777       NewElem = theHelper.AddEdge(nodes[0], nodes[1], id, theForce3d);
8778       break;
8779     }
8780     case SMDSAbs_Face :
8781     {
8782       switch(nbNodes)
8783       {
8784       case 3:
8785         NewElem = theHelper.AddFace(nodes[0], nodes[1], nodes[2], id, theForce3d);
8786         break;
8787       case 4:
8788         NewElem = theHelper.AddFace(nodes[0], nodes[1], nodes[2], nodes[3], id, theForce3d);
8789         break;
8790       default:
8791         NewElem = theHelper.AddPolygonalFace(nodes, id, theForce3d);
8792       }
8793       break;
8794     }
8795     case SMDSAbs_Volume :
8796     {
8797       switch( aGeomType )
8798       {
8799       case SMDSEntity_Tetra:
8800         NewElem = theHelper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3], id, theForce3d);
8801         break;
8802       case SMDSEntity_Pyramid:
8803         NewElem = theHelper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3], nodes[4], id, theForce3d);
8804         break;
8805       case SMDSEntity_Penta:
8806       case SMDSEntity_Quad_Penta:
8807       case SMDSEntity_BiQuad_Penta:
8808         NewElem = theHelper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3], nodes[4], nodes[5], id, theForce3d);
8809         break;
8810       case SMDSEntity_Hexa:
8811       case SMDSEntity_Quad_Hexa:
8812       case SMDSEntity_TriQuad_Hexa:
8813         NewElem = theHelper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3],
8814                                       nodes[4], nodes[5], nodes[6], nodes[7], id, theForce3d);
8815         break;
8816       case SMDSEntity_Hexagonal_Prism:
8817       default:
8818         NewElem = theHelper.AddPolyhedralVolume(nodes, nbNodeInFaces, id, theForce3d);
8819       }
8820       break;
8821     }
8822     default :
8823       continue;
8824     }
8825     ReplaceElemInGroups( elem, NewElem, GetMeshDS());
8826     if( NewElem && NewElem->getshapeId() < 1 )
8827       theSm->AddElement( NewElem );
8828   }
8829   return nbElem;
8830 }
8831 //=======================================================================
8832 //function : ConvertToQuadratic
8833 //purpose  :
8834 //=======================================================================
8835
8836 void SMESH_MeshEditor::ConvertToQuadratic(const bool theForce3d, const bool theToBiQuad)
8837 {
8838   //MESSAGE("ConvertToQuadratic "<< theForce3d << " " << theToBiQuad);
8839   SMESHDS_Mesh* meshDS = GetMeshDS();
8840
8841   SMESH_MesherHelper aHelper(*myMesh);
8842
8843   aHelper.SetIsQuadratic( true );
8844   aHelper.SetIsBiQuadratic( theToBiQuad );
8845   aHelper.SetElementsOnShape(true);
8846   aHelper.ToFixNodeParameters( true );
8847
8848   // convert elements assigned to sub-meshes
8849   int nbCheckedElems = 0;
8850   if ( myMesh->HasShapeToMesh() )
8851   {
8852     if ( SMESH_subMesh *aSubMesh = myMesh->GetSubMeshContaining(myMesh->GetShapeToMesh()))
8853     {
8854       SMESH_subMeshIteratorPtr smIt = aSubMesh->getDependsOnIterator(true,false);
8855       while ( smIt->more() ) {
8856         SMESH_subMesh* sm = smIt->next();
8857         if ( SMESHDS_SubMesh *smDS = sm->GetSubMeshDS() ) {
8858           aHelper.SetSubShape( sm->GetSubShape() );
8859           nbCheckedElems += convertElemToQuadratic(smDS, aHelper, theForce3d);
8860         }
8861       }
8862     }
8863   }
8864
8865   // convert elements NOT assigned to sub-meshes
8866   int totalNbElems = meshDS->NbEdges() + meshDS->NbFaces() + meshDS->NbVolumes();
8867   if ( nbCheckedElems < totalNbElems ) // not all elements are in sub-meshes
8868   {
8869     aHelper.SetElementsOnShape(false);
8870     SMESHDS_SubMesh *smDS = 0;
8871
8872     // convert edges
8873     SMDS_EdgeIteratorPtr aEdgeItr = meshDS->edgesIterator();
8874     while( aEdgeItr->more() )
8875     {
8876       const SMDS_MeshEdge* edge = aEdgeItr->next();
8877       if ( !edge->IsQuadratic() )
8878       {
8879         int                  id = edge->GetID();
8880         const SMDS_MeshNode* n1 = edge->GetNode(0);
8881         const SMDS_MeshNode* n2 = edge->GetNode(1);
8882
8883         meshDS->RemoveFreeElement(edge, smDS, /*fromGroups=*/false);
8884
8885         const SMDS_MeshEdge* NewEdge = aHelper.AddEdge(n1, n2, id, theForce3d);
8886         ReplaceElemInGroups( edge, NewEdge, GetMeshDS());
8887       }
8888       else
8889       {
8890         aHelper.AddTLinks( static_cast< const SMDS_MeshEdge* >( edge ));
8891       }
8892     }
8893
8894     // convert faces
8895     SMDS_FaceIteratorPtr aFaceItr = meshDS->facesIterator();
8896     while( aFaceItr->more() )
8897     {
8898       const SMDS_MeshFace* face = aFaceItr->next();
8899       if ( !face ) continue;
8900       
8901       const SMDSAbs_EntityType type = face->GetEntityType();
8902       bool alreadyOK;
8903       switch( type )
8904       {
8905       case SMDSEntity_Quad_Triangle:
8906       case SMDSEntity_Quad_Quadrangle:
8907         alreadyOK = !theToBiQuad;
8908         aHelper.AddTLinks( static_cast< const SMDS_MeshFace* >( face ));
8909         break;
8910       case SMDSEntity_BiQuad_Triangle:
8911       case SMDSEntity_BiQuad_Quadrangle:
8912         alreadyOK = theToBiQuad;
8913         aHelper.AddTLinks( static_cast< const SMDS_MeshFace* >( face ));
8914         break;
8915       default: alreadyOK = false;
8916       }
8917       if ( alreadyOK )
8918         continue;
8919
8920       const int id = face->GetID();
8921       vector<const SMDS_MeshNode *> nodes ( face->begin_nodes(), face->end_nodes());
8922
8923       meshDS->RemoveFreeElement(face, smDS, /*fromGroups=*/false);
8924
8925       SMDS_MeshFace * NewFace = 0;
8926       switch( type )
8927       {
8928       case SMDSEntity_Triangle:
8929       case SMDSEntity_Quad_Triangle:
8930       case SMDSEntity_BiQuad_Triangle:
8931         NewFace = aHelper.AddFace(nodes[0], nodes[1], nodes[2], id, theForce3d);
8932         if ( nodes.size() == 7 && nodes[6]->NbInverseElements() == 0 ) // rm a central node
8933           GetMeshDS()->RemoveFreeNode( nodes[6], /*sm=*/0, /*fromGroups=*/true );
8934         break;
8935
8936       case SMDSEntity_Quadrangle:
8937       case SMDSEntity_Quad_Quadrangle:
8938       case SMDSEntity_BiQuad_Quadrangle:
8939         NewFace = aHelper.AddFace(nodes[0], nodes[1], nodes[2], nodes[3], id, theForce3d);
8940         if ( nodes.size() == 9 && nodes[8]->NbInverseElements() == 0 ) // rm a central node
8941           GetMeshDS()->RemoveFreeNode( nodes[8], /*sm=*/0, /*fromGroups=*/true );
8942         break;
8943
8944       default:;
8945         NewFace = aHelper.AddPolygonalFace(nodes, id, theForce3d);
8946       }
8947       ReplaceElemInGroups( face, NewFace, GetMeshDS());
8948     }
8949
8950     // convert volumes
8951     vector<smIdType> nbNodeInFaces;
8952     SMDS_VolumeIteratorPtr aVolumeItr = meshDS->volumesIterator();
8953     while(aVolumeItr->more())
8954     {
8955       const SMDS_MeshVolume* volume = aVolumeItr->next();
8956       if ( !volume ) continue;
8957
8958       const SMDSAbs_EntityType type = volume->GetEntityType();
8959       if ( volume->IsQuadratic() )
8960       {
8961         bool alreadyOK;
8962         switch ( type )
8963         {
8964         case SMDSEntity_Quad_Hexa:    alreadyOK = !theToBiQuad; break;
8965         case SMDSEntity_TriQuad_Hexa: alreadyOK = theToBiQuad; break;
8966         case SMDSEntity_Quad_Penta:   alreadyOK = !theToBiQuad; break;
8967         case SMDSEntity_BiQuad_Penta: alreadyOK = theToBiQuad; break;
8968         default:                      alreadyOK = true;
8969         }
8970         if ( alreadyOK )
8971         {
8972           aHelper.AddTLinks( static_cast< const SMDS_MeshVolume* >( volume ));
8973           continue;
8974         }
8975       }
8976       const int id = volume->GetID();
8977       vector<const SMDS_MeshNode *> nodes (volume->begin_nodes(), volume->end_nodes());
8978       if ( type == SMDSEntity_Polyhedra )
8979         nbNodeInFaces = static_cast<const SMDS_MeshVolume* >(volume)->GetQuantities();
8980       else if ( type == SMDSEntity_Hexagonal_Prism )
8981         volumeToPolyhedron( volume, nodes, nbNodeInFaces );
8982
8983       meshDS->RemoveFreeElement(volume, smDS, /*fromGroups=*/false);
8984
8985       SMDS_MeshVolume * NewVolume = 0;
8986       switch ( type )
8987       {
8988       case SMDSEntity_Tetra:
8989         NewVolume = aHelper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3], id, theForce3d );
8990         break;
8991       case SMDSEntity_Hexa:
8992       case SMDSEntity_Quad_Hexa:
8993       case SMDSEntity_TriQuad_Hexa:
8994         NewVolume = aHelper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3],
8995                                       nodes[4], nodes[5], nodes[6], nodes[7], id, theForce3d);
8996         for ( size_t i = 20; i < nodes.size(); ++i ) // rm central nodes
8997           if ( nodes[i]->NbInverseElements() == 0 )
8998             GetMeshDS()->RemoveFreeNode( nodes[i], /*sm=*/0, /*fromGroups=*/true );
8999         break;
9000       case SMDSEntity_Pyramid:
9001         NewVolume = aHelper.AddVolume(nodes[0], nodes[1], nodes[2],
9002                                       nodes[3], nodes[4], id, theForce3d);
9003         break;
9004       case SMDSEntity_Penta:
9005       case SMDSEntity_Quad_Penta:
9006       case SMDSEntity_BiQuad_Penta:
9007         NewVolume = aHelper.AddVolume(nodes[0], nodes[1], nodes[2],
9008                                       nodes[3], nodes[4], nodes[5], id, theForce3d);
9009         for ( size_t i = 15; i < nodes.size(); ++i ) // rm central nodes
9010           if ( nodes[i]->NbInverseElements() == 0 )
9011             GetMeshDS()->RemoveFreeNode( nodes[i], /*sm=*/0, /*fromGroups=*/true );
9012         break;
9013       case SMDSEntity_Hexagonal_Prism:
9014       default:
9015         NewVolume = aHelper.AddPolyhedralVolume(nodes, nbNodeInFaces, id, theForce3d);
9016       }
9017       ReplaceElemInGroups(volume, NewVolume, meshDS);
9018     }
9019   }
9020
9021   if ( !theForce3d )
9022   { // setenv NO_FixQuadraticElements to know if FixQuadraticElements() is guilty of bad conversion
9023     // aHelper.SetSubShape(0); // apply FixQuadraticElements() to the whole mesh
9024     // aHelper.FixQuadraticElements(myError);
9025     SMESH_MesherHelper( *myMesh ).FixQuadraticElements(myError);
9026   }
9027 }
9028
9029 //================================================================================
9030 /*!
9031  * \brief Makes given elements quadratic
9032  *  \param theForce3d - if true, the medium nodes will be placed in the middle of link
9033  *  \param theElements - elements to make quadratic
9034  */
9035 //================================================================================
9036
9037 void SMESH_MeshEditor::ConvertToQuadratic(const bool        theForce3d,
9038                                           TIDSortedElemSet& theElements,
9039                                           const bool        theToBiQuad)
9040 {
9041   if ( theElements.empty() ) return;
9042
9043   // we believe that all theElements are of the same type
9044   const SMDSAbs_ElementType elemType = (*theElements.begin())->GetType();
9045
9046   // get all nodes shared by theElements
9047   TIDSortedNodeSet allNodes;
9048   TIDSortedElemSet::iterator eIt = theElements.begin();
9049   for ( ; eIt != theElements.end(); ++eIt )
9050     allNodes.insert( (*eIt)->begin_nodes(), (*eIt)->end_nodes() );
9051
9052   // complete theElements with elements of lower dim whose all nodes are in allNodes
9053
9054   TIDSortedElemSet quadAdjacentElems    [ SMDSAbs_NbElementTypes ]; // quadratic adjacent elements
9055   TIDSortedElemSet checkedAdjacentElems [ SMDSAbs_NbElementTypes ];
9056   TIDSortedNodeSet::iterator nIt = allNodes.begin();
9057   for ( ; nIt != allNodes.end(); ++nIt )
9058   {
9059     const SMDS_MeshNode* n = *nIt;
9060     SMDS_ElemIteratorPtr invIt = n->GetInverseElementIterator();
9061     while ( invIt->more() )
9062     {
9063       const SMDS_MeshElement*      e = invIt->next();
9064       const SMDSAbs_ElementType type = e->GetType();
9065       if ( e->IsQuadratic() )
9066       {
9067         quadAdjacentElems[ type ].insert( e );
9068
9069         bool alreadyOK;
9070         switch ( e->GetEntityType() ) {
9071         case SMDSEntity_Quad_Triangle:
9072         case SMDSEntity_Quad_Quadrangle:
9073         case SMDSEntity_Quad_Hexa:         alreadyOK = !theToBiQuad; break;
9074         case SMDSEntity_BiQuad_Triangle:
9075         case SMDSEntity_BiQuad_Quadrangle:
9076         case SMDSEntity_TriQuad_Hexa:      alreadyOK = theToBiQuad; break;
9077         default:                           alreadyOK = true;
9078         }
9079         if ( alreadyOK )
9080           continue;
9081       }
9082       if ( type >= elemType )
9083         continue; // same type or more complex linear element
9084
9085       if ( !checkedAdjacentElems[ type ].insert( e ).second )
9086         continue; // e is already checked
9087
9088       // check nodes
9089       bool allIn = true;
9090       SMDS_NodeIteratorPtr nodeIt = e->nodeIterator();
9091       while ( nodeIt->more() && allIn )
9092         allIn = allNodes.count( nodeIt->next() );
9093       if ( allIn )
9094         theElements.insert(e );
9095     }
9096   }
9097
9098   SMESH_MesherHelper helper(*myMesh);
9099   helper.SetIsQuadratic( true );
9100   helper.SetIsBiQuadratic( theToBiQuad );
9101
9102   // add links of quadratic adjacent elements to the helper
9103
9104   if ( !quadAdjacentElems[SMDSAbs_Edge].empty() )
9105     for ( eIt  = quadAdjacentElems[SMDSAbs_Edge].begin();
9106           eIt != quadAdjacentElems[SMDSAbs_Edge].end(); ++eIt )
9107     {
9108       helper.AddTLinks( static_cast< const SMDS_MeshEdge*> (*eIt) );
9109     }
9110   if ( !quadAdjacentElems[SMDSAbs_Face].empty() )
9111     for ( eIt  = quadAdjacentElems[SMDSAbs_Face].begin();
9112           eIt != quadAdjacentElems[SMDSAbs_Face].end(); ++eIt )
9113     {
9114       helper.AddTLinks( static_cast< const SMDS_MeshFace*> (*eIt) );
9115     }
9116   if ( !quadAdjacentElems[SMDSAbs_Volume].empty() )
9117     for ( eIt  = quadAdjacentElems[SMDSAbs_Volume].begin();
9118           eIt != quadAdjacentElems[SMDSAbs_Volume].end(); ++eIt )
9119     {
9120       helper.AddTLinks( static_cast< const SMDS_MeshVolume*> (*eIt) );
9121     }
9122
9123   // make quadratic (or bi-tri-quadratic) elements instead of linear ones
9124
9125   SMESHDS_Mesh*  meshDS = GetMeshDS();
9126   SMESHDS_SubMesh* smDS = 0;
9127   for ( eIt = theElements.begin(); eIt != theElements.end(); ++eIt )
9128   {
9129     const SMDS_MeshElement* elem = *eIt;
9130
9131     bool alreadyOK;
9132     int nbCentralNodes = 0;
9133     switch ( elem->GetEntityType() ) {
9134       // linear convertible
9135     case SMDSEntity_Edge:
9136     case SMDSEntity_Triangle:
9137     case SMDSEntity_Quadrangle:
9138     case SMDSEntity_Tetra:
9139     case SMDSEntity_Pyramid:
9140     case SMDSEntity_Hexa:
9141     case SMDSEntity_Penta:             alreadyOK = false;       nbCentralNodes = 0; break;
9142       // quadratic that can become bi-quadratic
9143     case SMDSEntity_Quad_Triangle:
9144     case SMDSEntity_Quad_Quadrangle:
9145     case SMDSEntity_Quad_Hexa:         alreadyOK =!theToBiQuad; nbCentralNodes = 0; break;
9146       // bi-quadratic
9147     case SMDSEntity_BiQuad_Triangle:
9148     case SMDSEntity_BiQuad_Quadrangle: alreadyOK = theToBiQuad; nbCentralNodes = 1; break;
9149     case SMDSEntity_TriQuad_Hexa:      alreadyOK = theToBiQuad; nbCentralNodes = 7; break;
9150       // the rest
9151     default:                           alreadyOK = true;
9152     }
9153     if ( alreadyOK ) continue;
9154
9155     const SMDSAbs_ElementType type = elem->GetType();
9156     const int                   id = elem->GetID();
9157     const int              nbNodes = elem->NbCornerNodes();
9158     vector<const SMDS_MeshNode *> nodes ( elem->begin_nodes(), elem->end_nodes());
9159
9160     helper.SetSubShape( elem->getshapeId() );
9161
9162     if ( !smDS || !smDS->Contains( elem ))
9163       smDS = meshDS->MeshElements( elem->getshapeId() );
9164     meshDS->RemoveFreeElement(elem, smDS, /*fromGroups=*/false);
9165
9166     SMDS_MeshElement * newElem = 0;
9167     switch( nbNodes )
9168     {
9169     case 4: // cases for most frequently used element types go first (for optimization)
9170       if ( type == SMDSAbs_Volume )
9171         newElem = helper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3], id, theForce3d);
9172       else
9173         newElem = helper.AddFace  (nodes[0], nodes[1], nodes[2], nodes[3], id, theForce3d);
9174       break;
9175     case 8:
9176       newElem = helper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3],
9177                                  nodes[4], nodes[5], nodes[6], nodes[7], id, theForce3d);
9178       break;
9179     case 3:
9180       newElem = helper.AddFace  (nodes[0], nodes[1], nodes[2], id, theForce3d);
9181       break;
9182     case 2:
9183       newElem = helper.AddEdge(nodes[0], nodes[1], id, theForce3d);
9184       break;
9185     case 5:
9186       newElem = helper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3],
9187                                  nodes[4], id, theForce3d);
9188       break;
9189     case 6:
9190       newElem = helper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3],
9191                                  nodes[4], nodes[5], id, theForce3d);
9192       break;
9193     default:;
9194     }
9195     ReplaceElemInGroups( elem, newElem, meshDS);
9196     if( newElem && smDS )
9197       smDS->AddElement( newElem );
9198
9199     // remove central nodes
9200     for ( size_t i = nodes.size() - nbCentralNodes; i < nodes.size(); ++i )
9201       if ( nodes[i]->NbInverseElements() == 0 )
9202         meshDS->RemoveFreeNode( nodes[i], smDS, /*fromGroups=*/true );
9203
9204   } // loop on theElements
9205
9206   if ( !theForce3d )
9207   { // setenv NO_FixQuadraticElements to know if FixQuadraticElements() is guilty of bad conversion
9208     // helper.SetSubShape(0); // apply FixQuadraticElements() to the whole mesh
9209     // helper.FixQuadraticElements( myError );
9210     SMESH_MesherHelper( *myMesh ).FixQuadraticElements(myError);
9211   }
9212 }
9213
9214 //=======================================================================
9215 /*!
9216  * \brief Convert quadratic elements to linear ones and remove quadratic nodes
9217  * \return int - nb of checked elements
9218  */
9219 //=======================================================================
9220
9221 int SMESH_MeshEditor::removeQuadElem(SMESHDS_SubMesh *    theSm,
9222                                      SMDS_ElemIteratorPtr theItr,
9223                                      const int            /*theShapeID*/)
9224 {
9225   int nbElem = 0;
9226   SMESHDS_Mesh* meshDS = GetMeshDS();
9227   ElemFeatures elemType;
9228   vector<const SMDS_MeshNode *> nodes;
9229
9230   while( theItr->more() )
9231   {
9232     const SMDS_MeshElement* elem = theItr->next();
9233     nbElem++;
9234     if( elem && elem->IsQuadratic())
9235     {
9236       // get elem data
9237       int nbCornerNodes = elem->NbCornerNodes();
9238       nodes.assign( elem->begin_nodes(), elem->end_nodes() );
9239
9240       elemType.Init( elem, /*basicOnly=*/false ).SetID( elem->GetID() ).SetQuad( false );
9241
9242       //remove a quadratic element
9243       if ( !theSm || !theSm->Contains( elem ))
9244         theSm = meshDS->MeshElements( elem->getshapeId() );
9245       meshDS->RemoveFreeElement( elem, theSm, /*fromGroups=*/false );
9246
9247       // remove medium nodes
9248       for ( size_t i = nbCornerNodes; i < nodes.size(); ++i )
9249         if ( nodes[i]->NbInverseElements() == 0 )
9250           meshDS->RemoveFreeNode( nodes[i], theSm );
9251
9252       // add a linear element
9253       nodes.resize( nbCornerNodes );
9254       SMDS_MeshElement * newElem = AddElement( nodes, elemType );
9255       ReplaceElemInGroups(elem, newElem, meshDS);
9256       if( theSm && newElem )
9257         theSm->AddElement( newElem );
9258     }
9259   }
9260   return nbElem;
9261 }
9262
9263 //=======================================================================
9264 //function : ConvertFromQuadratic
9265 //purpose  :
9266 //=======================================================================
9267
9268 bool SMESH_MeshEditor::ConvertFromQuadratic()
9269 {
9270   int nbCheckedElems = 0;
9271   if ( myMesh->HasShapeToMesh() )
9272   {
9273     if ( SMESH_subMesh *aSubMesh = myMesh->GetSubMeshContaining(myMesh->GetShapeToMesh()))
9274     {
9275       SMESH_subMeshIteratorPtr smIt = aSubMesh->getDependsOnIterator(true,false);
9276       while ( smIt->more() ) {
9277         SMESH_subMesh* sm = smIt->next();
9278         if ( SMESHDS_SubMesh *smDS = sm->GetSubMeshDS() )
9279           nbCheckedElems += removeQuadElem( smDS, smDS->GetElements(), sm->GetId() );
9280       }
9281     }
9282   }
9283
9284   int totalNbElems =
9285     GetMeshDS()->NbEdges() + GetMeshDS()->NbFaces() + GetMeshDS()->NbVolumes();
9286   if ( nbCheckedElems < totalNbElems ) // not all elements are in submeshes
9287   {
9288     SMESHDS_SubMesh *aSM = 0;
9289     removeQuadElem( aSM, GetMeshDS()->elementsIterator(), 0 );
9290   }
9291
9292   return true;
9293 }
9294
9295 namespace
9296 {
9297   //================================================================================
9298   /*!
9299    * \brief Return true if all medium nodes of the element are in the node set
9300    */
9301   //================================================================================
9302
9303   bool allMediumNodesIn(const SMDS_MeshElement* elem, TIDSortedNodeSet& nodeSet )
9304   {
9305     for ( int i = elem->NbCornerNodes(); i < elem->NbNodes(); ++i )
9306       if ( !nodeSet.count( elem->GetNode(i) ))
9307         return false;
9308     return true;
9309   }
9310 }
9311
9312 //================================================================================
9313 /*!
9314  * \brief Makes given elements linear
9315  */
9316 //================================================================================
9317
9318 void SMESH_MeshEditor::ConvertFromQuadratic(TIDSortedElemSet& theElements)
9319 {
9320   if ( theElements.empty() ) return;
9321
9322   // collect IDs of medium nodes of theElements; some of these nodes will be removed
9323   set<int> mediumNodeIDs;
9324   TIDSortedElemSet::iterator eIt = theElements.begin();
9325   for ( ; eIt != theElements.end(); ++eIt )
9326   {
9327     const SMDS_MeshElement* e = *eIt;
9328     for ( int i = e->NbCornerNodes(); i < e->NbNodes(); ++i )
9329       mediumNodeIDs.insert( e->GetNode(i)->GetID() );
9330   }
9331
9332   // replace given elements by linear ones
9333   SMDS_ElemIteratorPtr elemIt = SMESHUtils::elemSetIterator( theElements );
9334   removeQuadElem( /*theSm=*/0, elemIt, /*theShapeID=*/0 );
9335
9336   // we need to convert remaining elements whose all medium nodes are in mediumNodeIDs
9337   // except those elements sharing medium nodes of quadratic element whose medium nodes
9338   // are not all in mediumNodeIDs
9339
9340   // get remaining medium nodes
9341   TIDSortedNodeSet mediumNodes;
9342   set<int>::iterator nIdsIt = mediumNodeIDs.begin();
9343   for ( ; nIdsIt != mediumNodeIDs.end(); ++nIdsIt )
9344     if ( const SMDS_MeshNode* n = GetMeshDS()->FindNode( *nIdsIt ))
9345       mediumNodes.insert( mediumNodes.end(), n );
9346
9347   // find more quadratic elements to convert
9348   TIDSortedElemSet moreElemsToConvert;
9349   TIDSortedNodeSet::iterator nIt = mediumNodes.begin();
9350   for ( ; nIt != mediumNodes.end(); ++nIt )
9351   {
9352     SMDS_ElemIteratorPtr invIt = (*nIt)->GetInverseElementIterator();
9353     while ( invIt->more() )
9354     {
9355       const SMDS_MeshElement* e = invIt->next();
9356       if ( e->IsQuadratic() && allMediumNodesIn( e, mediumNodes ))
9357       {
9358         // find a more complex element including e and
9359         // whose medium nodes are not in mediumNodes
9360         bool complexFound = false;
9361         for ( int type = e->GetType() + 1; type < SMDSAbs_0DElement; ++type )
9362         {
9363           SMDS_ElemIteratorPtr invIt2 =
9364             (*nIt)->GetInverseElementIterator( SMDSAbs_ElementType( type ));
9365           while ( invIt2->more() )
9366           {
9367             const SMDS_MeshElement* eComplex = invIt2->next();
9368             if ( eComplex->IsQuadratic() && !allMediumNodesIn( eComplex, mediumNodes))
9369             {
9370               int nbCommonNodes = SMESH_MeshAlgos::NbCommonNodes( e, eComplex );
9371               if ( nbCommonNodes == e->NbNodes())
9372               {
9373                 complexFound = true;
9374                 type = SMDSAbs_NbElementTypes; // to quit from the outer loop
9375                 break;
9376               }
9377             }
9378           }
9379         }
9380         if ( !complexFound )
9381           moreElemsToConvert.insert( e );
9382       }
9383     }
9384   }
9385   elemIt = SMESHUtils::elemSetIterator( moreElemsToConvert );
9386   removeQuadElem( /*theSm=*/0, elemIt, /*theShapeID=*/0 );
9387 }
9388
9389 //=======================================================================
9390 //function : SewSideElements
9391 //purpose  :
9392 //=======================================================================
9393
9394 SMESH_MeshEditor::Sew_Error
9395 SMESH_MeshEditor::SewSideElements (TIDSortedElemSet&    theSide1,
9396                                    TIDSortedElemSet&    theSide2,
9397                                    const SMDS_MeshNode* theFirstNode1,
9398                                    const SMDS_MeshNode* theFirstNode2,
9399                                    const SMDS_MeshNode* theSecondNode1,
9400                                    const SMDS_MeshNode* theSecondNode2)
9401 {
9402   ClearLastCreated();
9403
9404   if ( theSide1.size() != theSide2.size() )
9405     return SEW_DIFF_NB_OF_ELEMENTS;
9406
9407   Sew_Error aResult = SEW_OK;
9408   // Algo:
9409   // 1. Build set of faces representing each side
9410   // 2. Find which nodes of the side 1 to merge with ones on the side 2
9411   // 3. Replace nodes in elements of the side 1 and remove replaced nodes
9412
9413   // =======================================================================
9414   // 1. Build set of faces representing each side:
9415   // =======================================================================
9416   // a. build set of nodes belonging to faces
9417   // b. complete set of faces: find missing faces whose nodes are in set of nodes
9418   // c. create temporary faces representing side of volumes if correspondent
9419   //    face does not exist
9420
9421   SMESHDS_Mesh* aMesh = GetMeshDS();
9422   // TODO algorithm not OK with vtkUnstructuredGrid: 2 meshes can't share nodes
9423   //SMDS_Mesh aTmpFacesMesh; // try to use the same mesh
9424   TIDSortedElemSet             faceSet1, faceSet2;
9425   set<const SMDS_MeshElement*> volSet1,  volSet2;
9426   set<const SMDS_MeshNode*>    nodeSet1, nodeSet2;
9427   TIDSortedElemSet             * faceSetPtr[] = { &faceSet1, &faceSet2 };
9428   set<const SMDS_MeshElement*> *  volSetPtr[] = { &volSet1,  &volSet2  };
9429   set<const SMDS_MeshNode*>    * nodeSetPtr[] = { &nodeSet1, &nodeSet2 };
9430   TIDSortedElemSet             * elemSetPtr[] = { &theSide1, &theSide2 };
9431   int iSide, iFace, iNode;
9432
9433   list<const SMDS_MeshElement* > tempFaceList;
9434   for ( iSide = 0; iSide < 2; iSide++ ) {
9435     set<const SMDS_MeshNode*>    * nodeSet = nodeSetPtr[ iSide ];
9436     TIDSortedElemSet             * elemSet = elemSetPtr[ iSide ];
9437     TIDSortedElemSet             * faceSet = faceSetPtr[ iSide ];
9438     set<const SMDS_MeshElement*> * volSet  = volSetPtr [ iSide ];
9439     set<const SMDS_MeshElement*>::iterator vIt;
9440     TIDSortedElemSet::iterator eIt;
9441     set<const SMDS_MeshNode*>::iterator    nIt;
9442
9443     // check that given nodes belong to given elements
9444     const SMDS_MeshNode* n1 = ( iSide == 0 ) ? theFirstNode1 : theFirstNode2;
9445     const SMDS_MeshNode* n2 = ( iSide == 0 ) ? theSecondNode1 : theSecondNode2;
9446     int firstIndex = -1, secondIndex = -1;
9447     for (eIt = elemSet->begin(); eIt != elemSet->end(); eIt++ ) {
9448       const SMDS_MeshElement* elem = *eIt;
9449       if ( firstIndex  < 0 ) firstIndex  = elem->GetNodeIndex( n1 );
9450       if ( secondIndex < 0 ) secondIndex = elem->GetNodeIndex( n2 );
9451       if ( firstIndex > -1 && secondIndex > -1 ) break;
9452     }
9453     if ( firstIndex < 0 || secondIndex < 0 ) {
9454       // we can simply return until temporary faces created
9455       return (iSide == 0 ) ? SEW_BAD_SIDE1_NODES : SEW_BAD_SIDE2_NODES;
9456     }
9457
9458     // -----------------------------------------------------------
9459     // 1a. Collect nodes of existing faces
9460     //     and build set of face nodes in order to detect missing
9461     //     faces corresponding to sides of volumes
9462     // -----------------------------------------------------------
9463
9464     set< set <const SMDS_MeshNode*> > setOfFaceNodeSet;
9465
9466     // loop on the given element of a side
9467     for (eIt = elemSet->begin(); eIt != elemSet->end(); eIt++ ) {
9468       //const SMDS_MeshElement* elem = *eIt;
9469       const SMDS_MeshElement* elem = *eIt;
9470       if ( elem->GetType() == SMDSAbs_Face ) {
9471         faceSet->insert( elem );
9472         set <const SMDS_MeshNode*> faceNodeSet;
9473         SMDS_ElemIteratorPtr nodeIt = elem->nodesIterator();
9474         while ( nodeIt->more() ) {
9475           const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
9476           nodeSet->insert( n );
9477           faceNodeSet.insert( n );
9478         }
9479         setOfFaceNodeSet.insert( faceNodeSet );
9480       }
9481       else if ( elem->GetType() == SMDSAbs_Volume )
9482         volSet->insert( elem );
9483     }
9484     // ------------------------------------------------------------------------------
9485     // 1b. Complete set of faces: find missing faces whose nodes are in set of nodes
9486     // ------------------------------------------------------------------------------
9487
9488     for ( nIt = nodeSet->begin(); nIt != nodeSet->end(); nIt++ ) { // loop on nodes of iSide
9489       SMDS_ElemIteratorPtr fIt = (*nIt)->GetInverseElementIterator(SMDSAbs_Face);
9490       while ( fIt->more() ) { // loop on faces sharing a node
9491         const SMDS_MeshElement* f = fIt->next();
9492         if ( faceSet->find( f ) == faceSet->end() ) {
9493           // check if all nodes are in nodeSet and
9494           // complete setOfFaceNodeSet if they are
9495           set <const SMDS_MeshNode*> faceNodeSet;
9496           SMDS_ElemIteratorPtr nodeIt = f->nodesIterator();
9497           bool allInSet = true;
9498           while ( nodeIt->more() && allInSet ) { // loop on nodes of a face
9499             const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
9500             if ( nodeSet->find( n ) == nodeSet->end() )
9501               allInSet = false;
9502             else
9503               faceNodeSet.insert( n );
9504           }
9505           if ( allInSet ) {
9506             faceSet->insert( f );
9507             setOfFaceNodeSet.insert( faceNodeSet );
9508           }
9509         }
9510       }
9511     }
9512
9513     // -------------------------------------------------------------------------
9514     // 1c. Create temporary faces representing sides of volumes if correspondent
9515     //     face does not exist
9516     // -------------------------------------------------------------------------
9517
9518     if ( !volSet->empty() ) {
9519       //int nodeSetSize = nodeSet->size();
9520
9521       // loop on given volumes
9522       for ( vIt = volSet->begin(); vIt != volSet->end(); vIt++ ) {
9523         SMDS_VolumeTool vol (*vIt);
9524         // loop on volume faces: find free faces
9525         // --------------------------------------
9526         list<const SMDS_MeshElement* > freeFaceList;
9527         for ( iFace = 0; iFace < vol.NbFaces(); iFace++ ) {
9528           if ( !vol.IsFreeFace( iFace ))
9529             continue;
9530           // check if there is already a face with same nodes in a face set
9531           const SMDS_MeshElement* aFreeFace = 0;
9532           const SMDS_MeshNode** fNodes = vol.GetFaceNodes( iFace );
9533           int nbNodes = vol.NbFaceNodes( iFace );
9534           set <const SMDS_MeshNode*> faceNodeSet;
9535           vol.GetFaceNodes( iFace, faceNodeSet );
9536           bool isNewFace = setOfFaceNodeSet.insert( faceNodeSet ).second;
9537           if ( isNewFace ) {
9538             // no such a face is given but it still can exist, check it
9539             vector<const SMDS_MeshNode *> nodes ( fNodes, fNodes + nbNodes);
9540             aFreeFace = aMesh->FindElement( nodes, SMDSAbs_Face, /*noMedium=*/false );
9541           }
9542           if ( !aFreeFace ) {
9543             // create a temporary face
9544             if ( nbNodes == 3 ) {
9545               //aFreeFace = aTmpFacesMesh.AddFace( fNodes[0],fNodes[1],fNodes[2] );
9546               aFreeFace = aMesh->AddFace( fNodes[0],fNodes[1],fNodes[2] );
9547             }
9548             else if ( nbNodes == 4 ) {
9549               //aFreeFace = aTmpFacesMesh.AddFace( fNodes[0],fNodes[1],fNodes[2],fNodes[3] );
9550               aFreeFace = aMesh->AddFace( fNodes[0],fNodes[1],fNodes[2],fNodes[3] );
9551             }
9552             else {
9553               vector<const SMDS_MeshNode *> poly_nodes ( fNodes, & fNodes[nbNodes]);
9554               //aFreeFace = aTmpFacesMesh.AddPolygonalFace(poly_nodes);
9555               aFreeFace = aMesh->AddPolygonalFace(poly_nodes);
9556             }
9557             if ( aFreeFace )
9558               tempFaceList.push_back( aFreeFace );
9559           }
9560
9561           if ( aFreeFace )
9562             freeFaceList.push_back( aFreeFace );
9563
9564         } // loop on faces of a volume
9565
9566         // choose one of several free faces of a volume
9567         // --------------------------------------------
9568         if ( freeFaceList.size() > 1 ) {
9569           // choose a face having max nb of nodes shared by other elems of a side
9570           int maxNbNodes = -1;
9571           list<const SMDS_MeshElement* >::iterator fIt = freeFaceList.begin();
9572           while ( fIt != freeFaceList.end() ) { // loop on free faces
9573             int nbSharedNodes = 0;
9574             SMDS_ElemIteratorPtr nodeIt = (*fIt)->nodesIterator();
9575             while ( nodeIt->more() ) { // loop on free face nodes
9576               const SMDS_MeshNode* n =
9577                 static_cast<const SMDS_MeshNode*>( nodeIt->next() );
9578               SMDS_ElemIteratorPtr invElemIt = n->GetInverseElementIterator();
9579               while ( invElemIt->more() ) {
9580                 const SMDS_MeshElement* e = invElemIt->next();
9581                 nbSharedNodes += faceSet->count( e );
9582                 nbSharedNodes += elemSet->count( e );
9583               }
9584             }
9585             if ( nbSharedNodes > maxNbNodes ) {
9586               maxNbNodes = nbSharedNodes;
9587               freeFaceList.erase( freeFaceList.begin(), fIt++ );
9588             }
9589             else if ( nbSharedNodes == maxNbNodes ) {
9590               fIt++;
9591             }
9592             else {
9593               freeFaceList.erase( fIt++ ); // here fIt++ occurs before erase
9594             }
9595           }
9596           if ( freeFaceList.size() > 1 )
9597           {
9598             // could not choose one face, use another way
9599             // choose a face most close to the bary center of the opposite side
9600             gp_XYZ aBC( 0., 0., 0. );
9601             set <const SMDS_MeshNode*> addedNodes;
9602             TIDSortedElemSet * elemSet2 = elemSetPtr[ 1 - iSide ];
9603             eIt = elemSet2->begin();
9604             for ( eIt = elemSet2->begin(); eIt != elemSet2->end(); eIt++ ) {
9605               SMDS_ElemIteratorPtr nodeIt = (*eIt)->nodesIterator();
9606               while ( nodeIt->more() ) { // loop on free face nodes
9607                 const SMDS_MeshNode* n =
9608                   static_cast<const SMDS_MeshNode*>( nodeIt->next() );
9609                 if ( addedNodes.insert( n ).second )
9610                   aBC += gp_XYZ( n->X(),n->Y(),n->Z() );
9611               }
9612             }
9613             aBC /= addedNodes.size();
9614             double minDist = DBL_MAX;
9615             fIt = freeFaceList.begin();
9616             while ( fIt != freeFaceList.end() ) { // loop on free faces
9617               double dist = 0;
9618               SMDS_ElemIteratorPtr nodeIt = (*fIt)->nodesIterator();
9619               while ( nodeIt->more() ) { // loop on free face nodes
9620                 const SMDS_MeshNode* n =
9621                   static_cast<const SMDS_MeshNode*>( nodeIt->next() );
9622                 gp_XYZ p( n->X(),n->Y(),n->Z() );
9623                 dist += ( aBC - p ).SquareModulus();
9624               }
9625               if ( dist < minDist ) {
9626                 minDist = dist;
9627                 freeFaceList.erase( freeFaceList.begin(), fIt++ );
9628               }
9629               else
9630                 fIt = freeFaceList.erase( fIt++ );
9631             }
9632           }
9633         } // choose one of several free faces of a volume
9634
9635         if ( freeFaceList.size() == 1 ) {
9636           const SMDS_MeshElement* aFreeFace = freeFaceList.front();
9637           faceSet->insert( aFreeFace );
9638           // complete a node set with nodes of a found free face
9639           //           for ( iNode = 0; iNode < ; iNode++ )
9640           //             nodeSet->insert( fNodes[ iNode ] );
9641         }
9642
9643       } // loop on volumes of a side
9644
9645       //       // complete a set of faces if new nodes in a nodeSet appeared
9646       //       // ----------------------------------------------------------
9647       //       if ( nodeSetSize != nodeSet->size() ) {
9648       //         for ( ; nIt != nodeSet->end(); nIt++ ) { // loop on nodes of iSide
9649       //           SMDS_ElemIteratorPtr fIt = (*nIt)->GetInverseElementIterator(SMDSAbs_Face);
9650       //           while ( fIt->more() ) { // loop on faces sharing a node
9651       //             const SMDS_MeshElement* f = fIt->next();
9652       //             if ( faceSet->find( f ) == faceSet->end() ) {
9653       //               // check if all nodes are in nodeSet and
9654       //               // complete setOfFaceNodeSet if they are
9655       //               set <const SMDS_MeshNode*> faceNodeSet;
9656       //               SMDS_ElemIteratorPtr nodeIt = f->nodesIterator();
9657       //               bool allInSet = true;
9658       //               while ( nodeIt->more() && allInSet ) { // loop on nodes of a face
9659       //                 const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
9660       //                 if ( nodeSet->find( n ) == nodeSet->end() )
9661       //                   allInSet = false;
9662       //                 else
9663       //                   faceNodeSet.insert( n );
9664       //               }
9665       //               if ( allInSet ) {
9666       //                 faceSet->insert( f );
9667       //                 setOfFaceNodeSet.insert( faceNodeSet );
9668       //               }
9669       //             }
9670       //           }
9671       //         }
9672       //       }
9673     } // Create temporary faces, if there are volumes given
9674   } // loop on sides
9675
9676   if ( faceSet1.size() != faceSet2.size() ) {
9677     // delete temporary faces: they are in reverseElements of actual nodes
9678     //    SMDS_FaceIteratorPtr tmpFaceIt = aTmpFacesMesh.facesIterator();
9679     //    while ( tmpFaceIt->more() )
9680     //      aTmpFacesMesh.RemoveElement( tmpFaceIt->next() );
9681     //    list<const SMDS_MeshElement* >::iterator tmpFaceIt = tempFaceList.begin();
9682     //    for (; tmpFaceIt !=tempFaceList.end(); ++tmpFaceIt)
9683     //      aMesh->RemoveElement(*tmpFaceIt);
9684     MESSAGE("Diff nb of faces");
9685     return SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
9686   }
9687
9688   // ============================================================
9689   // 2. Find nodes to merge:
9690   //              bind a node to remove to a node to put instead
9691   // ============================================================
9692
9693   TNodeNodeMap nReplaceMap; // bind a node to remove to a node to put instead
9694   if ( theFirstNode1 != theFirstNode2 )
9695     nReplaceMap.insert( make_pair( theFirstNode1, theFirstNode2 ));
9696   if ( theSecondNode1 != theSecondNode2 )
9697     nReplaceMap.insert( make_pair( theSecondNode1, theSecondNode2 ));
9698
9699   LinkID_Gen aLinkID_Gen( GetMeshDS() );
9700   set< long > linkIdSet; // links to process
9701   linkIdSet.insert( aLinkID_Gen.GetLinkID( theFirstNode1, theSecondNode1 ));
9702
9703   typedef pair< const SMDS_MeshNode*, const SMDS_MeshNode* > NLink;
9704   list< NLink > linkList[2];
9705   linkList[0].push_back( NLink( theFirstNode1, theSecondNode1 ));
9706   linkList[1].push_back( NLink( theFirstNode2, theSecondNode2 ));
9707   // loop on links in linkList; find faces by links and append links
9708   // of the found faces to linkList
9709   list< NLink >::iterator linkIt[] = { linkList[0].begin(), linkList[1].begin() } ;
9710   for ( ; linkIt[0] != linkList[0].end(); linkIt[0]++, linkIt[1]++ )
9711   {
9712     NLink link[] = { *linkIt[0], *linkIt[1] };
9713     long linkID = aLinkID_Gen.GetLinkID( link[0].first, link[0].second );
9714     if ( !linkIdSet.count( linkID ) )
9715       continue;
9716
9717     // by links, find faces in the face sets,
9718     // and find indices of link nodes in the found faces;
9719     // in a face set, there is only one or no face sharing a link
9720     // ---------------------------------------------------------------
9721
9722     const SMDS_MeshElement* face[] = { 0, 0 };
9723     vector<const SMDS_MeshNode*> fnodes[2];
9724     int iLinkNode[2][2];
9725     TIDSortedElemSet avoidSet;
9726     for ( iSide = 0; iSide < 2; iSide++ ) { // loop on 2 sides
9727       const SMDS_MeshNode* n1 = link[iSide].first;
9728       const SMDS_MeshNode* n2 = link[iSide].second;
9729       //cout << "Side " << iSide << " ";
9730       //cout << "L( " << n1->GetID() << ", " << n2->GetID() << " ) " << endl;
9731       // find a face by two link nodes
9732       face[ iSide ] = SMESH_MeshAlgos::FindFaceInSet( n1, n2,
9733                                                       *faceSetPtr[ iSide ], avoidSet,
9734                                                       &iLinkNode[iSide][0],
9735                                                       &iLinkNode[iSide][1] );
9736       if ( face[ iSide ])
9737       {
9738         //cout << " F " << face[ iSide]->GetID() <<endl;
9739         faceSetPtr[ iSide ]->erase( face[ iSide ]);
9740         // put face nodes to fnodes
9741         SMDS_MeshElement::iterator nIt( face[ iSide ]->interlacedNodesIterator() ), nEnd;
9742         fnodes[ iSide ].assign( nIt, nEnd );
9743         fnodes[ iSide ].push_back( fnodes[ iSide ].front());
9744       }
9745     }
9746
9747     // check similarity of elements of the sides
9748     if (aResult == SEW_OK && (( face[0] && !face[1] ) || ( !face[0] && face[1] ))) {
9749       MESSAGE("Correspondent face not found on side " << ( face[0] ? 1 : 0 ));
9750       if ( nReplaceMap.size() == 2 ) { // faces on input nodes not found
9751         aResult = ( face[0] ? SEW_BAD_SIDE2_NODES : SEW_BAD_SIDE1_NODES );
9752       }
9753       else {
9754         aResult = SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
9755       }
9756       break; // do not return because it's necessary to remove tmp faces
9757     }
9758
9759     // set nodes to merge
9760     // -------------------
9761
9762     if ( face[0] && face[1] )  {
9763       const int nbNodes = face[0]->NbNodes();
9764       if ( nbNodes != face[1]->NbNodes() ) {
9765         MESSAGE("Diff nb of face nodes");
9766         aResult = SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
9767         break; // do not return because it s necessary to remove tmp faces
9768       }
9769       bool reverse[] = { false, false }; // order of nodes in the link
9770       for ( iSide = 0; iSide < 2; iSide++ ) { // loop on 2 sides
9771         // analyse link orientation in faces
9772         int i1 = iLinkNode[ iSide ][ 0 ];
9773         int i2 = iLinkNode[ iSide ][ 1 ];
9774         reverse[ iSide ] = Abs( i1 - i2 ) == 1 ? i1 > i2 : i2 > i1;
9775       }
9776       int di1 = reverse[0] ? -1 : +1, i1 = iLinkNode[0][1] + di1;
9777       int di2 = reverse[1] ? -1 : +1, i2 = iLinkNode[1][1] + di2;
9778       for ( int i = nbNodes - 2; i > 0; --i, i1 += di1, i2 += di2 )
9779       {
9780         nReplaceMap.insert  ( make_pair ( fnodes[0][ ( i1 + nbNodes ) % nbNodes ],
9781                                           fnodes[1][ ( i2 + nbNodes ) % nbNodes ]));
9782       }
9783
9784       // add other links of the faces to linkList
9785       // -----------------------------------------
9786
9787       for ( iNode = 0; iNode < nbNodes; iNode++ )  {
9788         linkID = aLinkID_Gen.GetLinkID( fnodes[0][iNode], fnodes[0][iNode+1] );
9789         pair< set<long>::iterator, bool > iter_isnew = linkIdSet.insert( linkID );
9790         if ( !iter_isnew.second ) { // already in a set: no need to process
9791           linkIdSet.erase( iter_isnew.first );
9792         }
9793         else // new in set == encountered for the first time: add
9794         {
9795           const SMDS_MeshNode* n1 = fnodes[0][ iNode ];
9796           const SMDS_MeshNode* n2 = fnodes[0][ iNode + 1];
9797           linkList[0].push_back ( NLink( n1, n2 ));
9798           linkList[1].push_back ( NLink( nReplaceMap[n1], nReplaceMap[n2] ));
9799         }
9800       }
9801     } // 2 faces found
9802
9803     if ( faceSetPtr[0]->empty() || faceSetPtr[1]->empty() )
9804       break;
9805
9806   } // loop on link lists
9807
9808   if ( aResult == SEW_OK &&
9809        ( //linkIt[0] != linkList[0].end() ||
9810         !faceSetPtr[0]->empty() || !faceSetPtr[1]->empty() )) {
9811     MESSAGE( (linkIt[0] != linkList[0].end()) <<" "<< (faceSetPtr[0]->empty()) <<
9812              " " << (faceSetPtr[1]->empty()));
9813     aResult = SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
9814   }
9815
9816   // ====================================================================
9817   // 3. Replace nodes in elements of the side 1 and remove replaced nodes
9818   // ====================================================================
9819
9820   // delete temporary faces
9821   //  SMDS_FaceIteratorPtr tmpFaceIt = aTmpFacesMesh.facesIterator();
9822   //  while ( tmpFaceIt->more() )
9823   //    aTmpFacesMesh.RemoveElement( tmpFaceIt->next() );
9824   list<const SMDS_MeshElement* >::iterator tmpFaceIt = tempFaceList.begin();
9825   for (; tmpFaceIt !=tempFaceList.end(); ++tmpFaceIt)
9826     aMesh->RemoveElement(*tmpFaceIt);
9827
9828   if ( aResult != SEW_OK)
9829     return aResult;
9830
9831   list< int > nodeIDsToRemove;
9832   vector< const SMDS_MeshNode*> nodes;
9833   ElemFeatures elemType;
9834
9835   // loop on nodes replacement map
9836   TNodeNodeMap::iterator nReplaceMapIt = nReplaceMap.begin(), nnIt;
9837   for ( ; nReplaceMapIt != nReplaceMap.end(); nReplaceMapIt++ )
9838     if ( (*nReplaceMapIt).first != (*nReplaceMapIt).second )
9839     {
9840       const SMDS_MeshNode* nToRemove = (*nReplaceMapIt).first;
9841       nodeIDsToRemove.push_back( nToRemove->GetID() );
9842       // loop on elements sharing nToRemove
9843       SMDS_ElemIteratorPtr invElemIt = nToRemove->GetInverseElementIterator();
9844       while ( invElemIt->more() ) {
9845         const SMDS_MeshElement* e = invElemIt->next();
9846         // get a new suite of nodes: make replacement
9847         int nbReplaced = 0, i = 0, nbNodes = e->NbNodes();
9848         nodes.resize( nbNodes );
9849         SMDS_ElemIteratorPtr nIt = e->nodesIterator();
9850         while ( nIt->more() ) {
9851           const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nIt->next() );
9852           nnIt = nReplaceMap.find( n );
9853           if ( nnIt != nReplaceMap.end() ) {
9854             nbReplaced++;
9855             n = (*nnIt).second;
9856           }
9857           nodes[ i++ ] = n;
9858         }
9859         //       if ( nbReplaced == nbNodes && e->GetType() == SMDSAbs_Face )
9860         //         elemIDsToRemove.push_back( e->GetID() );
9861         //       else
9862         if ( nbReplaced )
9863         {
9864           elemType.Init( e, /*basicOnly=*/false ).SetID( e->GetID() );
9865           aMesh->RemoveElement( e );
9866
9867           if ( SMDS_MeshElement* newElem = this->AddElement( nodes, elemType ))
9868           {
9869             AddToSameGroups( newElem, e, aMesh );
9870             if ( int aShapeId = e->getshapeId() )
9871               aMesh->SetMeshElementOnShape( newElem, aShapeId );
9872           }
9873         }
9874       }
9875     }
9876
9877   Remove( nodeIDsToRemove, true );
9878
9879   return aResult;
9880 }
9881
9882 //================================================================================
9883 /*!
9884  * \brief Find corresponding nodes in two sets of faces
9885  * \param theSide1 - first face set
9886  * \param theSide2 - second first face
9887  * \param theFirstNode1 - a boundary node of set 1
9888  * \param theFirstNode2 - a node of set 2 corresponding to theFirstNode1
9889  * \param theSecondNode1 - a boundary node of set 1 linked with theFirstNode1
9890  * \param theSecondNode2 - a node of set 2 corresponding to theSecondNode1
9891  * \param nReplaceMap - output map of corresponding nodes
9892  * \return bool  - is a success or not
9893  */
9894 //================================================================================
9895
9896 #ifdef _DEBUG_
9897 //#define DEBUG_MATCHING_NODES
9898 #endif
9899
9900 SMESH_MeshEditor::Sew_Error
9901 SMESH_MeshEditor::FindMatchingNodes(set<const SMDS_MeshElement*>& theSide1,
9902                                     set<const SMDS_MeshElement*>& theSide2,
9903                                     const SMDS_MeshNode*          theFirstNode1,
9904                                     const SMDS_MeshNode*          theFirstNode2,
9905                                     const SMDS_MeshNode*          theSecondNode1,
9906                                     const SMDS_MeshNode*          theSecondNode2,
9907                                     TNodeNodeMap &                nReplaceMap)
9908 {
9909   set<const SMDS_MeshElement*> * faceSetPtr[] = { &theSide1, &theSide2 };
9910
9911   nReplaceMap.clear();
9912   //if ( theFirstNode1 != theFirstNode2 )
9913   nReplaceMap.insert( make_pair( theFirstNode1, theFirstNode2 ));
9914   //if ( theSecondNode1 != theSecondNode2 )
9915   nReplaceMap.insert( make_pair( theSecondNode1, theSecondNode2 ));
9916
9917   set< SMESH_TLink > linkSet; // set of nodes where order of nodes is ignored
9918   linkSet.insert( SMESH_TLink( theFirstNode1, theSecondNode1 ));
9919
9920   list< NLink > linkList[2];
9921   linkList[0].push_back( NLink( theFirstNode1, theSecondNode1 ));
9922   linkList[1].push_back( NLink( theFirstNode2, theSecondNode2 ));
9923
9924   // loop on links in linkList; find faces by links and append links
9925   // of the found faces to linkList
9926   list< NLink >::iterator linkIt[] = { linkList[0].begin(), linkList[1].begin() } ;
9927   for ( ; linkIt[0] != linkList[0].end(); linkIt[0]++, linkIt[1]++ ) {
9928     NLink link[] = { *linkIt[0], *linkIt[1] };
9929     if ( linkSet.find( link[0] ) == linkSet.end() )
9930       continue;
9931
9932     // by links, find faces in the face sets,
9933     // and find indices of link nodes in the found faces;
9934     // in a face set, there is only one or no face sharing a link
9935     // ---------------------------------------------------------------
9936
9937     const SMDS_MeshElement* face[] = { 0, 0 };
9938     list<const SMDS_MeshNode*> notLinkNodes[2];
9939     //bool reverse[] = { false, false }; // order of notLinkNodes
9940     int nbNodes[2];
9941     for ( int iSide = 0; iSide < 2; iSide++ ) // loop on 2 sides
9942     {
9943       const SMDS_MeshNode* n1 = link[iSide].first;
9944       const SMDS_MeshNode* n2 = link[iSide].second;
9945       set<const SMDS_MeshElement*> * faceSet = faceSetPtr[ iSide ];
9946       set< const SMDS_MeshElement* > facesOfNode1;
9947       for ( int iNode = 0; iNode < 2; iNode++ ) // loop on 2 nodes of a link
9948       {
9949         // during a loop of the first node, we find all faces around n1,
9950         // during a loop of the second node, we find one face sharing both n1 and n2
9951         const SMDS_MeshNode* n = iNode ? n1 : n2; // a node of a link
9952         SMDS_ElemIteratorPtr fIt = n->GetInverseElementIterator(SMDSAbs_Face);
9953         while ( fIt->more() ) { // loop on faces sharing a node
9954           const SMDS_MeshElement* f = fIt->next();
9955           if (faceSet->find( f ) != faceSet->end() && // f is in face set
9956               ! facesOfNode1.insert( f ).second ) // f encounters twice
9957           {
9958             if ( face[ iSide ] ) {
9959               MESSAGE( "2 faces per link " );
9960               return ( iSide ? SEW_BAD_SIDE2_NODES : SEW_BAD_SIDE1_NODES );
9961             }
9962             face[ iSide ] = f;
9963             faceSet->erase( f );
9964
9965             // get not link nodes
9966             int nbN = f->NbNodes();
9967             if ( f->IsQuadratic() )
9968               nbN /= 2;
9969             nbNodes[ iSide ] = nbN;
9970             list< const SMDS_MeshNode* > & nodes = notLinkNodes[ iSide ];
9971             int i1 = f->GetNodeIndex( n1 );
9972             int i2 = f->GetNodeIndex( n2 );
9973             int iEnd = nbN, iBeg = -1, iDelta = 1;
9974             bool reverse = ( Abs( i1 - i2 ) == 1 ? i1 > i2 : i2 > i1 );
9975             if ( reverse ) {
9976               std::swap( iEnd, iBeg ); iDelta = -1;
9977             }
9978             int i = i2;
9979             while ( true ) {
9980               i += iDelta;
9981               if ( i == iEnd ) i = iBeg + iDelta;
9982               if ( i == i1 ) break;
9983               nodes.push_back ( f->GetNode( i ) );
9984             }
9985           }
9986         }
9987       }
9988     }
9989     // check similarity of elements of the sides
9990     if (( face[0] && !face[1] ) || ( !face[0] && face[1] )) {
9991       MESSAGE("Correspondent face not found on side " << ( face[0] ? 1 : 0 ));
9992       if ( nReplaceMap.size() == 2 ) { // faces on input nodes not found
9993         return ( face[0] ? SEW_BAD_SIDE2_NODES : SEW_BAD_SIDE1_NODES );
9994       }
9995       else {
9996         return SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
9997       }
9998     }
9999
10000     // set nodes to merge
10001     // -------------------
10002
10003     if ( face[0] && face[1] )  {
10004       if ( nbNodes[0] != nbNodes[1] ) {
10005         MESSAGE("Diff nb of face nodes");
10006         return SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
10007       }
10008 #ifdef DEBUG_MATCHING_NODES
10009       MESSAGE ( " Link 1: " << link[0].first->GetID() <<" "<< link[0].second->GetID()
10010                 << " F 1: " << face[0] << "| Link 2: " << link[1].first->GetID() <<" "
10011                 << link[1].second->GetID() << " F 2: " << face[1] << " | Bind: " ) ;
10012 #endif
10013       int nbN = nbNodes[0];
10014       {
10015         list<const SMDS_MeshNode*>::iterator n1 = notLinkNodes[0].begin();
10016         list<const SMDS_MeshNode*>::iterator n2 = notLinkNodes[1].begin();
10017         for ( int i = 0 ; i < nbN - 2; ++i ) {
10018 #ifdef DEBUG_MATCHING_NODES
10019           MESSAGE ( (*n1)->GetID() << " to " << (*n2)->GetID() );
10020 #endif
10021           nReplaceMap.insert( make_pair( *(n1++), *(n2++) ));
10022         }
10023       }
10024
10025       // add other links of the face 1 to linkList
10026       // -----------------------------------------
10027
10028       const SMDS_MeshElement* f0 = face[0];
10029       const SMDS_MeshNode* n1 = f0->GetNode( nbN - 1 );
10030       for ( int i = 0; i < nbN; i++ )
10031       {
10032         const SMDS_MeshNode* n2 = f0->GetNode( i );
10033         pair< set< SMESH_TLink >::iterator, bool > iter_isnew =
10034           linkSet.insert( SMESH_TLink( n1, n2 ));
10035         if ( !iter_isnew.second ) { // already in a set: no need to process
10036           linkSet.erase( iter_isnew.first );
10037         }
10038         else // new in set == encountered for the first time: add
10039         {
10040 #ifdef DEBUG_MATCHING_NODES
10041           MESSAGE ( "Add link 1: " << n1->GetID() << " " << n2->GetID() << " "
10042                     << " | link 2: " << nReplaceMap[n1]->GetID() << " " << nReplaceMap[n2]->GetID() << " " );
10043 #endif
10044           linkList[0].push_back ( NLink( n1, n2 ));
10045           linkList[1].push_back ( NLink( nReplaceMap[n1], nReplaceMap[n2] ));
10046         }
10047         n1 = n2;
10048       }
10049     } // 2 faces found
10050   } // loop on link lists
10051
10052   return SEW_OK;
10053 }
10054
10055 namespace // automatically find theAffectedElems for DoubleNodes()
10056 {
10057   bool isOut( const SMDS_MeshNode* n, const gp_XYZ& norm, const SMDS_MeshElement* elem );
10058
10059   //--------------------------------------------------------------------------------
10060   // Nodes shared by adjacent FissureBorder's.
10061   // 1 node  if FissureBorder separates faces
10062   // 2 nodes if FissureBorder separates volumes
10063   struct SubBorder
10064   {
10065     const SMDS_MeshNode* _nodes[2];
10066     int                  _nbNodes;
10067
10068     SubBorder( const SMDS_MeshNode* n1, const SMDS_MeshNode* n2 = 0 )
10069     {
10070       _nodes[0] = n1;
10071       _nodes[1] = n2;
10072       _nbNodes = bool( n1 ) + bool( n2 );
10073       if ( _nbNodes == 2 && n1 > n2 )
10074         std::swap( _nodes[0], _nodes[1] );
10075     }
10076     bool operator<( const SubBorder& other ) const
10077     {
10078       for ( int i = 0; i < _nbNodes; ++i )
10079       {
10080         if ( _nodes[i] < other._nodes[i] ) return true;
10081         if ( _nodes[i] > other._nodes[i] ) return false;
10082       }
10083       return false;
10084     }
10085   };
10086
10087   //--------------------------------------------------------------------------------
10088   // Map a SubBorder to all FissureBorder it bounds
10089   struct FissureBorder;
10090   typedef std::map< SubBorder, std::vector< FissureBorder* > > TBorderLinks;
10091   typedef TBorderLinks::iterator                               TMappedSub;
10092
10093   //--------------------------------------------------------------------------------
10094   /*!
10095    * \brief Element border (volume facet or face edge) at a fissure
10096    */
10097   struct FissureBorder
10098   {
10099     std::vector< const SMDS_MeshNode* > _nodes;    // border nodes
10100     const SMDS_MeshElement*             _elems[2]; // volume or face adjacent to fissure
10101
10102     std::vector< TMappedSub           > _mappedSubs;  // Sub() in TBorderLinks map
10103     std::vector< const SMDS_MeshNode* > _sortedNodes; // to compare FissureBorder's
10104
10105     FissureBorder( FissureBorder && from ) // move constructor
10106     {
10107       std::swap( _nodes,       from._nodes );
10108       std::swap( _sortedNodes, from._sortedNodes );
10109       _elems[0] = from._elems[0];
10110       _elems[1] = from._elems[1];
10111     }
10112
10113     FissureBorder( const SMDS_MeshElement*                  elemToDuplicate,
10114                    std::vector< const SMDS_MeshElement* > & adjElems)
10115       : _nodes( elemToDuplicate->NbCornerNodes() )
10116     {
10117       for ( size_t i = 0; i < _nodes.size(); ++i )
10118         _nodes[i] = elemToDuplicate->GetNode( i );
10119
10120       SMDSAbs_ElementType type = SMDSAbs_ElementType( elemToDuplicate->GetType() + 1 );
10121       findAdjacent( type, adjElems );
10122     }
10123
10124     FissureBorder( const SMDS_MeshNode**                    nodes,
10125                    const size_t                             nbNodes,
10126                    const SMDSAbs_ElementType                adjElemsType,
10127                    std::vector< const SMDS_MeshElement* > & adjElems)
10128       : _nodes( nodes, nodes + nbNodes )
10129     {
10130       findAdjacent( adjElemsType, adjElems );
10131     }
10132
10133     void findAdjacent( const SMDSAbs_ElementType                adjElemsType,
10134                        std::vector< const SMDS_MeshElement* > & adjElems)
10135     {
10136       _elems[0] = _elems[1] = 0;
10137       adjElems.clear();
10138       if ( SMDS_Mesh::GetElementsByNodes( _nodes, adjElems, adjElemsType ))
10139         for ( size_t i = 0; i < adjElems.size() && i < 2; ++i )
10140           _elems[i] = adjElems[i];
10141     }
10142
10143     bool operator<( const FissureBorder& other ) const
10144     {
10145       return GetSortedNodes() < other.GetSortedNodes();
10146     }
10147
10148     const std::vector< const SMDS_MeshNode* >& GetSortedNodes() const
10149     {
10150       if ( _sortedNodes.empty() && !_nodes.empty() )
10151       {
10152         FissureBorder* me = const_cast<FissureBorder*>( this );
10153         me->_sortedNodes = me->_nodes;
10154         std::sort( me->_sortedNodes.begin(), me->_sortedNodes.end() );
10155       }
10156       return _sortedNodes;
10157     }
10158
10159     size_t NbSub() const
10160     {
10161       return _nodes.size();
10162     }
10163
10164     SubBorder Sub(size_t i) const
10165     {
10166       return SubBorder( _nodes[i], NbSub() > 2 ? _nodes[ (i+1)%NbSub() ] : 0 );
10167     }
10168
10169     void AddSelfTo( TBorderLinks& borderLinks )
10170     {
10171       _mappedSubs.resize( NbSub() );
10172       for ( size_t i = 0; i < NbSub(); ++i )
10173       {
10174         TBorderLinks::iterator s2b =
10175           borderLinks.insert( std::make_pair( Sub(i), TBorderLinks::mapped_type() )).first;
10176         s2b->second.push_back( this );
10177         _mappedSubs[ i ] = s2b;
10178       }
10179     }
10180
10181     void Clear()
10182     {
10183       _nodes.clear();
10184     }
10185
10186     const SMDS_MeshElement* GetMarkedElem() const
10187     {
10188       if ( _nodes.empty() ) return 0; // cleared
10189       if ( _elems[0] && _elems[0]->isMarked() ) return _elems[0];
10190       if ( _elems[1] && _elems[1]->isMarked() ) return _elems[1];
10191       return 0;
10192     }
10193
10194     gp_XYZ GetNorm() const // normal to the border
10195     {
10196       gp_XYZ norm;
10197       if ( _nodes.size() == 2 )
10198       {
10199         gp_XYZ avgNorm( 0,0,0 ); // sum of normals of adjacent faces
10200         if ( SMESH_MeshAlgos::FaceNormal( _elems[0], norm ))
10201           avgNorm += norm;
10202         if ( SMESH_MeshAlgos::FaceNormal( _elems[1], norm ))
10203           avgNorm += norm;
10204
10205         gp_XYZ bordDir( SMESH_NodeXYZ( this->_nodes[0] ) - SMESH_NodeXYZ( this->_nodes[1] ));
10206         norm = bordDir ^ avgNorm;
10207       }
10208       else
10209       {
10210         SMESH_NodeXYZ p0( _nodes[0] );
10211         SMESH_NodeXYZ p1( _nodes[1] );
10212         SMESH_NodeXYZ p2( _nodes[2] );
10213         norm = ( p0 - p1 ) ^ ( p2 - p1 );
10214       }
10215       if ( isOut( _nodes[0], norm, GetMarkedElem() ))
10216         norm.Reverse();
10217
10218       return norm;
10219     }
10220
10221     void ChooseSide() // mark an _elem located at positive side of fissure
10222     {
10223       _elems[0]->setIsMarked( true );
10224       gp_XYZ norm = GetNorm();
10225       double maxX = norm.Coord(1);
10226       if ( Abs( maxX ) < Abs( norm.Coord(2)) ) maxX = norm.Coord(2);
10227       if ( Abs( maxX ) < Abs( norm.Coord(3)) ) maxX = norm.Coord(3);
10228       if ( maxX < 0 )
10229       {
10230         _elems[0]->setIsMarked( false );
10231         _elems[1]->setIsMarked( true );
10232       }
10233     }
10234
10235   }; // struct FissureBorder
10236
10237   //--------------------------------------------------------------------------------
10238   /*!
10239    * \brief Classifier of elements at fissure edge
10240    */
10241   class FissureNormal
10242   {
10243     std::vector< gp_XYZ > _normals;
10244     bool                  _bothIn;
10245
10246   public:
10247     void Add( const SMDS_MeshNode* n, const FissureBorder& bord )
10248     {
10249       _bothIn = false;
10250       _normals.reserve(2);
10251       _normals.push_back( bord.GetNorm() );
10252       if ( _normals.size() == 2 )
10253         _bothIn = !isOut( n, _normals[0], bord.GetMarkedElem() );
10254     }
10255
10256     bool IsIn( const SMDS_MeshNode* n, const SMDS_MeshElement* elem ) const
10257     {
10258       bool isIn = false;
10259       switch ( _normals.size() ) {
10260       case 1:
10261       {
10262         isIn = !isOut( n, _normals[0], elem );
10263         break;
10264       }
10265       case 2:
10266       {
10267         bool in1 = !isOut( n, _normals[0], elem );
10268         bool in2 = !isOut( n, _normals[1], elem );
10269         isIn = _bothIn ? ( in1 && in2 ) : ( in1 || in2 );
10270       }
10271       }
10272       return isIn;
10273     }
10274   };
10275
10276   //================================================================================
10277   /*!
10278    * \brief Classify an element by a plane passing through a node
10279    */
10280   //================================================================================
10281
10282   bool isOut( const SMDS_MeshNode* n, const gp_XYZ& norm, const SMDS_MeshElement* elem )
10283   {
10284     SMESH_NodeXYZ p = n;
10285     double sumDot = 0;
10286     for ( int i = 0, nb = elem->NbCornerNodes(); i < nb; ++i )
10287     {
10288       SMESH_NodeXYZ pi = elem->GetNode( i );
10289       sumDot += norm * ( pi - p );
10290     }
10291     return sumDot < -1e-100;
10292   }
10293
10294   //================================================================================
10295   /*!
10296    * \brief Find FissureBorder's by nodes to duplicate
10297    */
10298   //================================================================================
10299
10300   void findFissureBorders( const TIDSortedElemSet&        theNodes,
10301                            std::vector< FissureBorder > & theFissureBorders )
10302   {
10303     TIDSortedElemSet::const_iterator nIt = theNodes.begin();
10304     const SMDS_MeshNode* n = dynamic_cast< const SMDS_MeshNode*>( *nIt );
10305     if ( !n ) return;
10306     SMDSAbs_ElementType elemType = SMDSAbs_Volume;
10307     if ( n->NbInverseElements( elemType ) == 0 )
10308     {
10309       elemType = SMDSAbs_Face;
10310       if ( n->NbInverseElements( elemType ) == 0 )
10311         return;
10312     }
10313     // unmark elements touching the fissure
10314     for ( ; nIt != theNodes.end(); ++nIt )
10315       SMESH_MeshAlgos::MarkElems( cast2Node(*nIt)->GetInverseElementIterator(), false );
10316
10317     // loop on elements touching the fissure to get their borders belonging to the fissure
10318     std::set< FissureBorder >              fissureBorders;
10319     std::vector< const SMDS_MeshElement* > adjElems;
10320     std::vector< const SMDS_MeshNode* >    nodes;
10321     SMDS_VolumeTool volTool;
10322     for ( nIt = theNodes.begin(); nIt != theNodes.end(); ++nIt )
10323     {
10324       SMDS_ElemIteratorPtr invIt = cast2Node(*nIt)->GetInverseElementIterator( elemType );
10325       while ( invIt->more() )
10326       {
10327         const SMDS_MeshElement* eInv = invIt->next();
10328         if ( eInv->isMarked() ) continue;
10329         eInv->setIsMarked( true );
10330
10331         if ( elemType == SMDSAbs_Volume )
10332         {
10333           volTool.Set( eInv );
10334           int iQuad = eInv->IsQuadratic() ? 2 : 1;
10335           for ( int iF = 0, nbF = volTool.NbFaces(); iF < nbF; ++iF )
10336           {
10337             const SMDS_MeshNode** nn = volTool.GetFaceNodes( iF );
10338             int                  nbN = volTool.NbFaceNodes( iF ) / iQuad;
10339             nodes.clear();
10340             bool allOnFissure = true;
10341             for ( int iN = 0; iN < nbN  && allOnFissure; iN += iQuad )
10342               if (( allOnFissure = theNodes.count( nn[ iN ])))
10343                 nodes.push_back( nn[ iN ]);
10344             if ( allOnFissure )
10345               fissureBorders.insert( std::move( FissureBorder( &nodes[0], nodes.size(),
10346                                                                elemType, adjElems )));
10347           }
10348         }
10349         else // elemType == SMDSAbs_Face
10350         {
10351           const SMDS_MeshNode* nn[2] = { eInv->GetNode( eInv->NbCornerNodes()-1 ), 0 };
10352           bool            onFissure0 = theNodes.count( nn[0] ), onFissure1;
10353           for ( int iN = 0, nbN = eInv->NbCornerNodes(); iN < nbN; ++iN )
10354           {
10355             nn[1]      = eInv->GetNode( iN );
10356             onFissure1 = theNodes.count( nn[1] );
10357             if ( onFissure0 && onFissure1 )
10358               fissureBorders.insert( std::move( FissureBorder( nn, 2, elemType, adjElems )));
10359             nn[0]      = nn[1];
10360             onFissure0 = onFissure1;
10361           }
10362         }
10363       }
10364     }
10365
10366     theFissureBorders.reserve( theFissureBorders.size() + fissureBorders.size());
10367     std::set< FissureBorder >::iterator bord = fissureBorders.begin();
10368     for ( ; bord != fissureBorders.end(); ++bord )
10369     {
10370       theFissureBorders.push_back( std::move( const_cast<FissureBorder&>( *bord ) ));
10371     }
10372     return;
10373   } // findFissureBorders()
10374
10375   //================================================================================
10376   /*!
10377    * \brief Find elements on one side of a fissure defined by elements or nodes to duplicate
10378    *  \param [in] theElemsOrNodes - elements or nodes to duplicate
10379    *  \param [in] theNodesNot - nodes not to duplicate
10380    *  \param [out] theAffectedElems - the found elements
10381    */
10382   //================================================================================
10383
10384   void findAffectedElems( const TIDSortedElemSet& theElemsOrNodes,
10385                           TIDSortedElemSet&       theAffectedElems)
10386   {
10387     if ( theElemsOrNodes.empty() ) return;
10388
10389     // find FissureBorder's
10390
10391     std::vector< FissureBorder >           fissure;
10392     std::vector< const SMDS_MeshElement* > elemsByFacet;
10393
10394     TIDSortedElemSet::const_iterator elIt = theElemsOrNodes.begin();
10395     if ( (*elIt)->GetType() == SMDSAbs_Node )
10396     {
10397       findFissureBorders( theElemsOrNodes, fissure );
10398     }
10399     else
10400     {
10401       fissure.reserve( theElemsOrNodes.size() );
10402       for ( ; elIt != theElemsOrNodes.end(); ++elIt )
10403         fissure.push_back( std::move( FissureBorder( *elIt, elemsByFacet )));
10404     }
10405     if ( fissure.empty() )
10406       return;
10407
10408     // fill borderLinks
10409
10410     TBorderLinks borderLinks;
10411
10412     for ( size_t i = 0; i < fissure.size(); ++i )
10413     {
10414       fissure[i].AddSelfTo( borderLinks );
10415     }
10416
10417     // get theAffectedElems
10418
10419     // unmark elements having nodes on the fissure, theAffectedElems elements will be marked
10420     for ( size_t i = 0; i < fissure.size(); ++i )
10421       for ( size_t j = 0; j < fissure[i]._nodes.size(); ++j )
10422       {
10423         SMESH_MeshAlgos::MarkElemNodes( fissure[i]._nodes[j]->GetInverseElementIterator(),
10424                                         false, /*markElem=*/true );
10425       }
10426
10427     std::vector<const SMDS_MeshNode *>                 facetNodes;
10428     std::map< const SMDS_MeshNode*, FissureNormal >    fissEdgeNodes2Norm;
10429     boost::container::flat_set< const SMDS_MeshNode* > fissureNodes;
10430
10431     // choose a side of fissure
10432     fissure[0].ChooseSide();
10433     theAffectedElems.insert( fissure[0].GetMarkedElem() );
10434
10435     size_t nbCheckedBorders = 0;
10436     while ( nbCheckedBorders < fissure.size() )
10437     {
10438       // find a FissureBorder to treat
10439       FissureBorder* bord = 0;
10440       for ( size_t i = 0; i < fissure.size()  && !bord; ++i )
10441         if ( fissure[i].GetMarkedElem() )
10442           bord = & fissure[i];
10443       for ( size_t i = 0; i < fissure.size()  && !bord; ++i )
10444         if ( fissure[i].NbSub() > 0 && fissure[i]._elems[0] )
10445         {
10446           bord = & fissure[i];
10447           bord->ChooseSide();
10448           theAffectedElems.insert( bord->GetMarkedElem() );
10449         }
10450       if ( !bord ) return;
10451       ++nbCheckedBorders;
10452
10453       // treat FissureBorder's linked to bord
10454       fissureNodes.clear();
10455       fissureNodes.insert( bord->_nodes.begin(), bord->_nodes.end() );
10456       for ( size_t i = 0; i < bord->NbSub(); ++i )
10457       {
10458         TBorderLinks::iterator l2b = bord->_mappedSubs[ i ];
10459         if ( l2b == borderLinks.end() || l2b->second.empty() ) continue;
10460         std::vector< FissureBorder* >& linkedBorders = l2b->second;
10461         const SubBorder&                          sb = l2b->first;
10462         const SMDS_MeshElement*             bordElem = bord->GetMarkedElem();
10463
10464         if ( linkedBorders.size() == 1 ) // fissure edge reached, fill fissEdgeNodes2Norm
10465         {
10466           for ( int j = 0; j < sb._nbNodes; ++j )
10467             fissEdgeNodes2Norm[ sb._nodes[j] ].Add( sb._nodes[j], *bord );
10468           continue;
10469         }
10470
10471         // add to theAffectedElems elems sharing nodes of a SubBorder and a node of bordElem
10472         // until an elem adjacent to a neighbour FissureBorder is found
10473         facetNodes.clear();
10474         facetNodes.insert( facetNodes.end(), sb._nodes, sb._nodes + sb._nbNodes );
10475         facetNodes.resize( sb._nbNodes + 1 );
10476
10477         while ( bordElem )
10478         {
10479           // check if bordElem is adjacent to a neighbour FissureBorder
10480           for ( size_t j = 0; j < linkedBorders.size(); ++j )
10481           {
10482             FissureBorder* bord2 = linkedBorders[j];
10483             if ( bord2 == bord ) continue;
10484             if ( bordElem == bord2->_elems[0] || bordElem == bord2->_elems[1] )
10485               bordElem = 0;
10486             else
10487               fissureNodes.insert( bord2->_nodes.begin(), bord2->_nodes.end() );
10488           }
10489           if ( !bordElem )
10490             break;
10491
10492           // find the next bordElem
10493           const SMDS_MeshElement* nextBordElem = 0;
10494           for ( int iN = 0, nbN = bordElem->NbCornerNodes(); iN < nbN  && !nextBordElem; ++iN )
10495           {
10496             const SMDS_MeshNode* n = bordElem->GetNode( iN );
10497             if ( fissureNodes.count( n )) continue;
10498
10499             facetNodes[ sb._nbNodes ] = n;
10500             elemsByFacet.clear();
10501             if ( SMDS_Mesh::GetElementsByNodes( facetNodes, elemsByFacet ) > 1 )
10502             {
10503               for ( size_t iE = 0; iE < elemsByFacet.size(); ++iE )
10504                 if ( elemsByFacet[ iE ] != bordElem &&
10505                      !elemsByFacet[ iE ]->isMarked() )
10506                 {
10507                   theAffectedElems.insert( elemsByFacet[ iE ]);
10508                   elemsByFacet[ iE ]->setIsMarked( true );
10509                   if ( elemsByFacet[ iE ]->GetType() == bordElem->GetType() )
10510                     nextBordElem = elemsByFacet[ iE ];
10511                 }
10512             }
10513           }
10514           bordElem = nextBordElem;
10515
10516         } // while ( bordElem )
10517
10518         linkedBorders.clear(); // not to treat this link any more
10519
10520       } // loop on SubBorder's of a FissureBorder
10521
10522       bord->Clear();
10523
10524     } // loop on FissureBorder's
10525
10526
10527     // add elements sharing only one node of the fissure, except those sharing fissure edge nodes
10528
10529     // mark nodes of theAffectedElems
10530     SMESH_MeshAlgos::MarkElemNodes( theAffectedElems.begin(), theAffectedElems.end(), true );
10531
10532     // unmark nodes of the fissure
10533     elIt = theElemsOrNodes.begin();
10534     if ( (*elIt)->GetType() == SMDSAbs_Node )
10535       SMESH_MeshAlgos::MarkElems( elIt, theElemsOrNodes.end(), false );
10536     else
10537       SMESH_MeshAlgos::MarkElemNodes( elIt, theElemsOrNodes.end(), false );
10538
10539     std::vector< gp_XYZ > normVec;
10540
10541     // loop on nodes of the fissure, add elements having marked nodes
10542     for ( elIt = theElemsOrNodes.begin(); elIt != theElemsOrNodes.end(); ++elIt )
10543     {
10544       const SMDS_MeshElement* e = (*elIt);
10545       if ( e->GetType() != SMDSAbs_Node )
10546         e->setIsMarked( true ); // avoid adding a fissure element
10547
10548       for ( int iN = 0, nbN = e->NbCornerNodes(); iN < nbN; ++iN )
10549       {
10550         const SMDS_MeshNode* n = e->GetNode( iN );
10551         if ( fissEdgeNodes2Norm.count( n ))
10552           continue;
10553
10554         SMDS_ElemIteratorPtr invIt = n->GetInverseElementIterator();
10555         while ( invIt->more() )
10556         {
10557           const SMDS_MeshElement* eInv = invIt->next();
10558           if ( eInv->isMarked() ) continue;
10559           eInv->setIsMarked( true );
10560
10561           SMDS_ElemIteratorPtr nIt = eInv->nodesIterator();
10562           while( nIt->more() )
10563             if ( nIt->next()->isMarked())
10564             {
10565               theAffectedElems.insert( eInv );
10566               SMESH_MeshAlgos::MarkElems( eInv->nodesIterator(), true );
10567               n->setIsMarked( false );
10568               break;
10569             }
10570         }
10571       }
10572     }
10573
10574     // add elements on the fissure edge
10575     std::map< const SMDS_MeshNode*, FissureNormal >::iterator n2N;
10576     for ( n2N = fissEdgeNodes2Norm.begin(); n2N != fissEdgeNodes2Norm.end(); ++n2N )
10577     {
10578       const SMDS_MeshNode* edgeNode = n2N->first;
10579       const FissureNormal & normals = n2N->second;
10580
10581       SMDS_ElemIteratorPtr invIt = edgeNode->GetInverseElementIterator();
10582       while ( invIt->more() )
10583       {
10584         const SMDS_MeshElement* eInv = invIt->next();
10585         if ( eInv->isMarked() ) continue;
10586         eInv->setIsMarked( true );
10587
10588         // classify eInv using normals
10589         bool toAdd = normals.IsIn( edgeNode, eInv );
10590         if ( toAdd ) // check if all nodes lie on the fissure edge
10591         {
10592           bool notOnEdge = false;
10593           for ( int iN = 0, nbN = eInv->NbCornerNodes(); iN < nbN  && !notOnEdge; ++iN )
10594             notOnEdge = !fissEdgeNodes2Norm.count( eInv->GetNode( iN ));
10595           toAdd = notOnEdge;
10596         }
10597         if ( toAdd )
10598         {
10599           theAffectedElems.insert( eInv );
10600         }
10601       }
10602     }
10603
10604     return;
10605   } // findAffectedElems()
10606 } // namespace
10607
10608 //================================================================================
10609 /*!
10610  * \brief Create elements equal (on same nodes) to given ones
10611  *  \param [in] theElements - a set of elems to duplicate. If it is empty, all
10612  *              elements of the uppest dimension are duplicated.
10613  */
10614 //================================================================================
10615
10616 void SMESH_MeshEditor::DoubleElements( const TIDSortedElemSet& theElements )
10617 {
10618   ClearLastCreated();
10619   SMESHDS_Mesh* mesh = GetMeshDS();
10620
10621   // get an element type and an iterator over elements
10622
10623   SMDSAbs_ElementType type = SMDSAbs_All;
10624   SMDS_ElemIteratorPtr elemIt;
10625   if ( theElements.empty() )
10626   {
10627     if ( mesh->NbNodes() == 0 )
10628       return;
10629     // get most complex type
10630     SMDSAbs_ElementType types[SMDSAbs_NbElementTypes] = {
10631       SMDSAbs_Volume, SMDSAbs_Face, SMDSAbs_Edge,
10632       SMDSAbs_0DElement, SMDSAbs_Ball, SMDSAbs_Node
10633     };
10634     for ( int i = 0; i < SMDSAbs_NbElementTypes; ++i )
10635       if ( mesh->GetMeshInfo().NbElements( types[i] ))
10636       {
10637         type = types[i];
10638         elemIt = mesh->elementsIterator( type );
10639         break;
10640       }
10641   }
10642   else
10643   {
10644     //type = (*theElements.begin())->GetType();
10645     elemIt = SMESHUtils::elemSetIterator( theElements );
10646   }
10647
10648   // un-mark all elements to avoid duplicating just created elements
10649   SMESH_MeshAlgos::MarkElems( mesh->elementsIterator( type ), false );
10650
10651   // duplicate elements
10652
10653   ElemFeatures elemType;
10654
10655   vector< const SMDS_MeshNode* > nodes;
10656   while ( elemIt->more() )
10657   {
10658     const SMDS_MeshElement* elem = elemIt->next();
10659     if (( type != SMDSAbs_All && elem->GetType() != type ) ||
10660         ( elem->isMarked() ))
10661       continue;
10662
10663     elemType.Init( elem, /*basicOnly=*/false );
10664     nodes.assign( elem->begin_nodes(), elem->end_nodes() );
10665
10666     if ( const SMDS_MeshElement* newElem = AddElement( nodes, elemType ))
10667       newElem->setIsMarked( true );
10668   }
10669 }
10670
10671 //================================================================================
10672 /*!
10673   \brief Creates a hole in a mesh by doubling the nodes of some particular elements
10674   \param theElems - the list of elements (edges or faces) to be replicated
10675   The nodes for duplication could be found from these elements
10676   \param theNodesNot - list of nodes to NOT replicate
10677   \param theAffectedElems - the list of elements (cells and edges) to which the
10678   replicated nodes should be associated to.
10679   \return TRUE if operation has been completed successfully, FALSE otherwise
10680 */
10681 //================================================================================
10682
10683 bool SMESH_MeshEditor::DoubleNodes( const TIDSortedElemSet& theElems,
10684                                     const TIDSortedElemSet& theNodesNot,
10685                                     const TIDSortedElemSet& theAffectedElems )
10686 {
10687   ClearLastCreated();
10688
10689   if ( theElems.size() == 0 )
10690     return false;
10691
10692   SMESHDS_Mesh* aMeshDS = GetMeshDS();
10693   if ( !aMeshDS )
10694     return false;
10695
10696   bool res = false;
10697   TNodeNodeMap anOldNodeToNewNode;
10698   // duplicate elements and nodes
10699   res = doubleNodes( aMeshDS, theElems, theNodesNot, anOldNodeToNewNode, true );
10700   // replce nodes by duplications
10701   res = doubleNodes( aMeshDS, theAffectedElems, theNodesNot, anOldNodeToNewNode, false );
10702   return res;
10703 }
10704
10705 //================================================================================
10706 /*!
10707   \brief Creates a hole in a mesh by doubling the nodes of some particular elements
10708   \param theMeshDS - mesh instance
10709   \param theElems - the elements replicated or modified (nodes should be changed)
10710   \param theNodesNot - nodes to NOT replicate
10711   \param theNodeNodeMap - relation of old node to new created node
10712   \param theIsDoubleElem - flag os to replicate element or modify
10713   \return TRUE if operation has been completed successfully, FALSE otherwise
10714 */
10715 //================================================================================
10716
10717 bool SMESH_MeshEditor::doubleNodes(SMESHDS_Mesh*           theMeshDS,
10718                                    const TIDSortedElemSet& theElems,
10719                                    const TIDSortedElemSet& theNodesNot,
10720                                    TNodeNodeMap&           theNodeNodeMap,
10721                                    const bool              theIsDoubleElem )
10722 {
10723   // iterate through element and duplicate them (by nodes duplication)
10724   bool res = false;
10725   std::vector<const SMDS_MeshNode*> newNodes;
10726   ElemFeatures elemType;
10727
10728   TIDSortedElemSet::const_iterator elemItr = theElems.begin();
10729   for ( ;  elemItr != theElems.end(); ++elemItr )
10730   {
10731     const SMDS_MeshElement* anElem = *elemItr;
10732     // if (!anElem)
10733     //   continue;
10734
10735     // duplicate nodes to duplicate element
10736     bool isDuplicate = false;
10737     newNodes.resize( anElem->NbNodes() );
10738     SMDS_ElemIteratorPtr anIter = anElem->nodesIterator();
10739     int ind = 0;
10740     while ( anIter->more() )
10741     {
10742       const SMDS_MeshNode* aCurrNode = static_cast<const SMDS_MeshNode*>( anIter->next() );
10743       const SMDS_MeshNode*  aNewNode = aCurrNode;
10744       TNodeNodeMap::iterator     n2n = theNodeNodeMap.find( aCurrNode );
10745       if ( n2n != theNodeNodeMap.end() )
10746       {
10747         aNewNode = n2n->second;
10748       }
10749       else if ( theIsDoubleElem && !theNodesNot.count( aCurrNode ))
10750       {
10751         // duplicate node
10752         aNewNode = theMeshDS->AddNode( aCurrNode->X(), aCurrNode->Y(), aCurrNode->Z() );
10753         copyPosition( aCurrNode, aNewNode );
10754         theNodeNodeMap[ aCurrNode ] = aNewNode;
10755         myLastCreatedNodes.push_back( aNewNode );
10756       }
10757       isDuplicate |= (aCurrNode != aNewNode);
10758       newNodes[ ind++ ] = aNewNode;
10759     }
10760     if ( !isDuplicate )
10761       continue;
10762
10763     if ( theIsDoubleElem )
10764       AddElement( newNodes, elemType.Init( anElem, /*basicOnly=*/false ));
10765     else
10766       theMeshDS->ChangeElementNodes( anElem, &newNodes[ 0 ], newNodes.size() );
10767
10768     res = true;
10769   }
10770   return res;
10771 }
10772
10773 //================================================================================
10774 /*!
10775   \brief Creates a hole in a mesh by doubling the nodes of some particular elements
10776   \param theNodes - identifiers of nodes to be doubled
10777   \param theModifiedElems - identifiers of elements to be updated by the new (doubled)
10778   nodes. If list of element identifiers is empty then nodes are doubled but
10779   they not assigned to elements
10780   \return TRUE if operation has been completed successfully, FALSE otherwise
10781 */
10782 //================================================================================
10783
10784 bool SMESH_MeshEditor::DoubleNodes( const std::list< int >& theListOfNodes,
10785                                     const std::list< int >& theListOfModifiedElems )
10786 {
10787   ClearLastCreated();
10788
10789   if ( theListOfNodes.size() == 0 )
10790     return false;
10791
10792   SMESHDS_Mesh* aMeshDS = GetMeshDS();
10793   if ( !aMeshDS )
10794     return false;
10795
10796   // iterate through nodes and duplicate them
10797
10798   std::map< const SMDS_MeshNode*, const SMDS_MeshNode* > anOldNodeToNewNode;
10799
10800   std::list< int >::const_iterator aNodeIter;
10801   for ( aNodeIter = theListOfNodes.begin(); aNodeIter != theListOfNodes.end(); ++aNodeIter )
10802   {
10803     const SMDS_MeshNode* aNode = aMeshDS->FindNode( *aNodeIter );
10804     if ( !aNode )
10805       continue;
10806
10807     // duplicate node
10808
10809     const SMDS_MeshNode* aNewNode = aMeshDS->AddNode( aNode->X(), aNode->Y(), aNode->Z() );
10810     if ( aNewNode )
10811     {
10812       copyPosition( aNode, aNewNode );
10813       anOldNodeToNewNode[ aNode ] = aNewNode;
10814       myLastCreatedNodes.push_back( aNewNode );
10815     }
10816   }
10817
10818   // Change nodes of elements
10819
10820   std::vector<const SMDS_MeshNode*> aNodeArr;
10821
10822   std::list< int >::const_iterator anElemIter;
10823   for ( anElemIter =  theListOfModifiedElems.begin();
10824         anElemIter != theListOfModifiedElems.end();
10825         anElemIter++ )
10826   {
10827     const SMDS_MeshElement* anElem = aMeshDS->FindElement( *anElemIter );
10828     if ( !anElem )
10829       continue;
10830
10831     aNodeArr.assign( anElem->begin_nodes(), anElem->end_nodes() );
10832     for( size_t i = 0; i < aNodeArr.size(); ++i )
10833     {
10834       std::map< const SMDS_MeshNode*, const SMDS_MeshNode* >::iterator n2n =
10835         anOldNodeToNewNode.find( aNodeArr[ i ]);
10836       if ( n2n != anOldNodeToNewNode.end() )
10837         aNodeArr[ i ] = n2n->second;
10838     }
10839     aMeshDS->ChangeElementNodes( anElem, &aNodeArr[ 0 ], aNodeArr.size() );
10840   }
10841
10842   return true;
10843 }
10844
10845 namespace {
10846
10847   //================================================================================
10848   /*!
10849     \brief Check if element located inside shape
10850     \return TRUE if IN or ON shape, FALSE otherwise
10851   */
10852   //================================================================================
10853
10854   template<class Classifier>
10855   bool isInside(const SMDS_MeshElement* theElem,
10856                 Classifier&             theClassifier,
10857                 const double            theTol)
10858   {
10859     gp_XYZ centerXYZ (0, 0, 0);
10860     for ( SMDS_ElemIteratorPtr aNodeItr = theElem->nodesIterator(); aNodeItr->more(); )
10861       centerXYZ += SMESH_NodeXYZ( aNodeItr->next() );
10862
10863     gp_Pnt aPnt = centerXYZ / theElem->NbNodes();
10864     theClassifier.Perform(aPnt, theTol);
10865     TopAbs_State aState = theClassifier.State();
10866     return (aState == TopAbs_IN || aState == TopAbs_ON );
10867   }
10868
10869   //================================================================================
10870   /*!
10871    * \brief Classifier of the 3D point on the TopoDS_Face
10872    *        with interaface suitable for isInside()
10873    */
10874   //================================================================================
10875
10876   struct _FaceClassifier
10877   {
10878     Extrema_ExtPS       _extremum;
10879     BRepAdaptor_Surface _surface;
10880     TopAbs_State        _state;
10881
10882     _FaceClassifier(const TopoDS_Face& face):_extremum(),_surface(face),_state(TopAbs_OUT)
10883     {
10884       _extremum.Initialize( _surface,
10885                             _surface.FirstUParameter(), _surface.LastUParameter(),
10886                             _surface.FirstVParameter(), _surface.LastVParameter(),
10887                             _surface.Tolerance(), _surface.Tolerance() );
10888     }
10889     void Perform(const gp_Pnt& aPnt, double theTol)
10890     {
10891       theTol *= theTol;
10892       _state = TopAbs_OUT;
10893       _extremum.Perform(aPnt);
10894       if ( _extremum.IsDone() )
10895         for ( int iSol = 1; iSol <= _extremum.NbExt() && _state == TopAbs_OUT; ++iSol)
10896           _state = ( _extremum.SquareDistance(iSol) <= theTol ? TopAbs_IN : TopAbs_OUT );
10897     }
10898     TopAbs_State State() const
10899     {
10900       return _state;
10901     }
10902   };
10903 }
10904
10905 //================================================================================
10906 /*!
10907   \brief Identify the elements that will be affected by node duplication (actual duplication is not performed).
10908   This method is the first step of DoubleNodeElemGroupsInRegion.
10909   \param theElems - list of groups of elements (edges or faces) to be replicated
10910   \param theNodesNot - list of groups of nodes not to replicated
10911   \param theShape - shape to detect affected elements (element which geometric center
10912          located on or inside shape). If the shape is null, detection is done on faces orientations
10913          (select elements with a gravity center on the side given by faces normals).
10914          This mode (null shape) is faster, but works only when theElems are faces, with coherents orientations.
10915          The replicated nodes should be associated to affected elements.
10916   \return true
10917   \sa DoubleNodeElemGroupsInRegion()
10918 */
10919 //================================================================================
10920
10921 bool SMESH_MeshEditor::AffectedElemGroupsInRegion( const TIDSortedElemSet& theElems,
10922                                                    const TIDSortedElemSet& theNodesNot,
10923                                                    const TopoDS_Shape&     theShape,
10924                                                    TIDSortedElemSet&       theAffectedElems)
10925 {
10926   if ( theShape.IsNull() )
10927   {
10928     findAffectedElems( theElems, theAffectedElems );
10929   }
10930   else
10931   {
10932     const double aTol = Precision::Confusion();
10933     std::unique_ptr< BRepClass3d_SolidClassifier> bsc3d;
10934     std::unique_ptr<_FaceClassifier>              aFaceClassifier;
10935     if ( theShape.ShapeType() == TopAbs_SOLID )
10936     {
10937       bsc3d.reset( new BRepClass3d_SolidClassifier(theShape));;
10938       bsc3d->PerformInfinitePoint(aTol);
10939     }
10940     else if (theShape.ShapeType() == TopAbs_FACE )
10941     {
10942       aFaceClassifier.reset( new _FaceClassifier(TopoDS::Face(theShape)));
10943     }
10944
10945     // iterates on indicated elements and get elements by back references from their nodes
10946     TIDSortedElemSet::const_iterator elemItr = theElems.begin();
10947     for ( ;  elemItr != theElems.end(); ++elemItr )
10948     {
10949       SMDS_MeshElement*     anElem = (SMDS_MeshElement*)*elemItr;
10950       SMDS_ElemIteratorPtr nodeItr = anElem->nodesIterator();
10951       while ( nodeItr->more() )
10952       {
10953         const SMDS_MeshNode* aNode = cast2Node(nodeItr->next());
10954         if ( !aNode || theNodesNot.find(aNode) != theNodesNot.end() )
10955           continue;
10956         SMDS_ElemIteratorPtr backElemItr = aNode->GetInverseElementIterator();
10957         while ( backElemItr->more() )
10958         {
10959           const SMDS_MeshElement* curElem = backElemItr->next();
10960           if ( curElem && theElems.find(curElem) == theElems.end() &&
10961                ( bsc3d.get() ?
10962                  isInside( curElem, *bsc3d, aTol ) :
10963                  isInside( curElem, *aFaceClassifier, aTol )))
10964             theAffectedElems.insert( curElem );
10965         }
10966       }
10967     }
10968   }
10969   return true;
10970 }
10971
10972 //================================================================================
10973 /*!
10974   \brief Creates a hole in a mesh by doubling the nodes of some particular elements
10975   \param theElems - group of of elements (edges or faces) to be replicated
10976   \param theNodesNot - group of nodes not to replicate
10977   \param theShape - shape to detect affected elements (element which geometric center
10978   located on or inside shape).
10979   The replicated nodes should be associated to affected elements.
10980   \return TRUE if operation has been completed successfully, FALSE otherwise
10981 */
10982 //================================================================================
10983
10984 bool SMESH_MeshEditor::DoubleNodesInRegion( const TIDSortedElemSet& theElems,
10985                                             const TIDSortedElemSet& theNodesNot,
10986                                             const TopoDS_Shape&     theShape )
10987 {
10988   if ( theShape.IsNull() )
10989     return false;
10990
10991   const double aTol = Precision::Confusion();
10992   SMESHUtils::Deleter< BRepClass3d_SolidClassifier> bsc3d;
10993   SMESHUtils::Deleter<_FaceClassifier>              aFaceClassifier;
10994   if ( theShape.ShapeType() == TopAbs_SOLID )
10995   {
10996     bsc3d._obj = new BRepClass3d_SolidClassifier( theShape );
10997     bsc3d->PerformInfinitePoint(aTol);
10998   }
10999   else if (theShape.ShapeType() == TopAbs_FACE )
11000   {
11001     aFaceClassifier._obj = new _FaceClassifier( TopoDS::Face( theShape ));
11002   }
11003
11004   // iterates on indicated elements and get elements by back references from their nodes
11005   TIDSortedElemSet anAffected;
11006   TIDSortedElemSet::const_iterator elemItr = theElems.begin();
11007   for ( ;  elemItr != theElems.end(); ++elemItr )
11008   {
11009     SMDS_MeshElement* anElem = (SMDS_MeshElement*)*elemItr;
11010     if (!anElem)
11011       continue;
11012
11013     SMDS_ElemIteratorPtr nodeItr = anElem->nodesIterator();
11014     while ( nodeItr->more() )
11015     {
11016       const SMDS_MeshNode* aNode = cast2Node(nodeItr->next());
11017       if ( !aNode || theNodesNot.find(aNode) != theNodesNot.end() )
11018         continue;
11019       SMDS_ElemIteratorPtr backElemItr = aNode->GetInverseElementIterator();
11020       while ( backElemItr->more() )
11021       {
11022         const SMDS_MeshElement* curElem = backElemItr->next();
11023         if ( curElem && theElems.find(curElem) == theElems.end() &&
11024              ( bsc3d ?
11025                isInside( curElem, *bsc3d, aTol ) :
11026                isInside( curElem, *aFaceClassifier, aTol )))
11027           anAffected.insert( curElem );
11028       }
11029     }
11030   }
11031   return DoubleNodes( theElems, theNodesNot, anAffected );
11032 }
11033
11034 /*!
11035  *  \brief compute an oriented angle between two planes defined by four points.
11036  *  The vector (p0,p1) defines the intersection of the 2 planes (p0,p1,g1) and (p0,p1,g2)
11037  *  @param p0 base of the rotation axe
11038  *  @param p1 extremity of the rotation axe
11039  *  @param g1 belongs to the first plane
11040  *  @param g2 belongs to the second plane
11041  */
11042 double SMESH_MeshEditor::OrientedAngle(const gp_Pnt& p0, const gp_Pnt& p1, const gp_Pnt& g1, const gp_Pnt& g2)
11043 {
11044   gp_Vec vref(p0, p1);
11045   gp_Vec v1(p0, g1);
11046   gp_Vec v2(p0, g2);
11047   gp_Vec n1 = vref.Crossed(v1);
11048   gp_Vec n2 = vref.Crossed(v2);
11049   try {
11050     return n2.AngleWithRef(n1, vref);
11051   }
11052   catch ( Standard_Failure& ) {
11053   }
11054   return Max( v1.Magnitude(), v2.Magnitude() );
11055 }
11056
11057 /*!
11058  * \brief Double nodes on shared faces between groups of volumes and create flat elements on demand.
11059  *  The list of groups must contain at least two groups. The groups have to be disjoint: no common element into two different groups.
11060  * The nodes of the internal faces at the boundaries of the groups are doubled. Optionally, the internal faces are replaced by flat elements.
11061  * Triangles are transformed into prisms, and quadrangles into hexahedrons.
11062  * The flat elements are stored in groups of volumes. These groups are named according to the position of the group in the list:
11063  * the group j_n_p is the group of the flat elements that are built between the group #n and the group #p in the list.
11064  * If there is no shared faces between the group #n and the group #p in the list, the group j_n_p is not created.
11065  * All the flat elements are gathered into the group named "joints3D" (or "joints2D" in 2D situation).
11066  * The flat element of the multiple junctions between the simple junction are stored in a group named "jointsMultiples".
11067  * \param theElems - list of groups of volumes, where a group of volume is a set of
11068  *        SMDS_MeshElements sorted by Id.
11069  * \param createJointElems - if TRUE, create the elements
11070  * \param onAllBoundaries - if TRUE, the nodes and elements are also created on
11071  *        the boundary between \a theDomains and the rest mesh
11072  * \return TRUE if operation has been completed successfully, FALSE otherwise
11073  */
11074 bool SMESH_MeshEditor::DoubleNodesOnGroupBoundaries( const std::vector<TIDSortedElemSet>& theElems,
11075                                                      bool                                 createJointElems,
11076                                                      bool                                 onAllBoundaries)
11077 {
11078   // MESSAGE("----------------------------------------------");
11079   // MESSAGE("SMESH_MeshEditor::doubleNodesOnGroupBoundaries");
11080   // MESSAGE("----------------------------------------------");
11081
11082   SMESHDS_Mesh *meshDS = this->myMesh->GetMeshDS();
11083   meshDS->BuildDownWardConnectivity(true);
11084   CHRONO(50);
11085   SMDS_UnstructuredGrid *grid = meshDS->GetGrid();
11086
11087   // --- build the list of faces shared by 2 domains (group of elements), with their domain and volume indexes
11088   //     build the list of cells with only a node or an edge on the border, with their domain and volume indexes
11089   //     build the list of nodes shared by 2 or more domains, with their domain indexes
11090
11091   std::map<DownIdType, std::map<int,int>, DownIdCompare> faceDomains; // face --> (id domain --> id volume)
11092   std::map<int,int>celldom; // cell vtkId --> domain
11093   std::map<DownIdType, std::map<int,int>, DownIdCompare> cellDomains;  // oldNode --> (id domain --> id cell)
11094   std::map<int, std::map<int,int> > nodeDomains; // oldId -->  (domainId --> newId)
11095   faceDomains.clear();
11096   celldom.clear();
11097   cellDomains.clear();
11098   nodeDomains.clear();
11099   std::map<int,int> emptyMap;
11100   std::set<int> emptySet;
11101   emptyMap.clear();
11102
11103   //MESSAGE(".. Number of domains :"<<theElems.size());
11104
11105   TIDSortedElemSet theRestDomElems;
11106   const int iRestDom  = -1;
11107   const int idom0     = onAllBoundaries ? iRestDom : 0;
11108   const int nbDomains = theElems.size();
11109
11110   // Check if the domains do not share an element
11111   for (int idom = 0; idom < nbDomains-1; idom++)
11112   {
11113     //       MESSAGE("... Check of domain #" << idom);
11114     const TIDSortedElemSet& domain = theElems[idom];
11115     TIDSortedElemSet::const_iterator elemItr = domain.begin();
11116     for (; elemItr != domain.end(); ++elemItr)
11117     {
11118       const SMDS_MeshElement* anElem = *elemItr;
11119       int idombisdeb = idom + 1 ;
11120       // check if the element belongs to a domain further in the list
11121       for ( size_t idombis = idombisdeb; idombis < theElems.size(); idombis++ )
11122       {
11123         const TIDSortedElemSet& domainbis = theElems[idombis];
11124         if ( domainbis.count( anElem ))
11125         {
11126           MESSAGE(".... Domain #" << idom);
11127           MESSAGE(".... Domain #" << idombis);
11128           throw SALOME_Exception("The domains are not disjoint.");
11129           return false ;
11130         }
11131       }
11132     }
11133   }
11134
11135   for (int idom = 0; idom < nbDomains; idom++)
11136   {
11137
11138     // --- build a map (face to duplicate --> volume to modify)
11139     //     with all the faces shared by 2 domains (group of elements)
11140     //     and corresponding volume of this domain, for each shared face.
11141     //     a volume has a face shared by 2 domains if it has a neighbor which is not in his domain.
11142
11143     //MESSAGE("... Neighbors of domain #" << idom);
11144     const TIDSortedElemSet& domain = theElems[idom];
11145     TIDSortedElemSet::const_iterator elemItr = domain.begin();
11146     for (; elemItr != domain.end(); ++elemItr)
11147     {
11148       const SMDS_MeshElement* anElem = *elemItr;
11149       if (!anElem)
11150         continue;
11151       int vtkId = anElem->GetVtkID();
11152       //MESSAGE("  vtkId " << vtkId << " smdsId " << anElem->GetID());
11153       int neighborsVtkIds[NBMAXNEIGHBORS];
11154       int downIds[NBMAXNEIGHBORS];
11155       unsigned char downTypes[NBMAXNEIGHBORS];
11156       int nbNeighbors = grid->GetNeighbors(neighborsVtkIds, downIds, downTypes, vtkId);
11157       for (int n = 0; n < nbNeighbors; n++)
11158       {
11159         int smdsId = meshDS->FromVtkToSmds(neighborsVtkIds[n]);
11160         const SMDS_MeshElement* elem = meshDS->FindElement(smdsId);
11161         if (elem && ! domain.count(elem)) // neighbor is in another domain : face is shared
11162         {
11163           bool ok = false;
11164           for ( size_t idombis = 0; idombis < theElems.size() && !ok; idombis++) // check if the neighbor belongs to another domain of the list
11165           {
11166             // MESSAGE("Domain " << idombis);
11167             const TIDSortedElemSet& domainbis = theElems[idombis];
11168             if ( domainbis.count(elem)) ok = true ; // neighbor is in a correct domain : face is kept
11169           }
11170           if ( ok || onAllBoundaries ) // the characteristics of the face is stored
11171           {
11172             DownIdType face(downIds[n], downTypes[n]);
11173             if (!faceDomains[face].count(idom))
11174             {
11175               faceDomains[face][idom] = vtkId; // volume associated to face in this domain
11176               celldom[vtkId] = idom;
11177               //MESSAGE("       cell with a border " << vtkId << " domain " << idom);
11178             }
11179             if ( !ok )
11180             {
11181               theRestDomElems.insert( elem );
11182               faceDomains[face][iRestDom] = neighborsVtkIds[n];
11183               celldom[neighborsVtkIds[n]] = iRestDom;
11184             }
11185           }
11186         }
11187       }
11188     }
11189   }
11190
11191   //MESSAGE("Number of shared faces " << faceDomains.size());
11192   std::map<DownIdType, std::map<int, int>, DownIdCompare>::iterator itface;
11193
11194   // --- explore the shared faces domain by domain,
11195   //     explore the nodes of the face and see if they belong to a cell in the domain,
11196   //     which has only a node or an edge on the border (not a shared face)
11197
11198   for (int idomain = idom0; idomain < nbDomains; idomain++)
11199   {
11200     //MESSAGE("Domain " << idomain);
11201     const TIDSortedElemSet& domain = (idomain == iRestDom) ? theRestDomElems : theElems[idomain];
11202     itface = faceDomains.begin();
11203     for (; itface != faceDomains.end(); ++itface)
11204     {
11205       const std::map<int, int>& domvol = itface->second;
11206       if (!domvol.count(idomain))
11207         continue;
11208       DownIdType face = itface->first;
11209       //MESSAGE(" --- face " << face.cellId);
11210       std::set<int> oldNodes;
11211       oldNodes.clear();
11212       grid->GetNodeIds(oldNodes, face.cellId, face.cellType);
11213       std::set<int>::iterator itn = oldNodes.begin();
11214       for (; itn != oldNodes.end(); ++itn)
11215       {
11216         int oldId = *itn;
11217         //MESSAGE("     node " << oldId);
11218         vtkCellLinks::Link l = (static_cast <vtkCellLinks *>(grid->GetCellLinks()))->GetLink(oldId);
11219         for (int i=0; i<l.ncells; i++)
11220         {
11221           int vtkId = l.cells[i];
11222           const SMDS_MeshElement* anElem = GetMeshDS()->FindElement(GetMeshDS()->FromVtkToSmds(vtkId));
11223           if (!domain.count(anElem))
11224             continue;
11225           int vtkType = grid->GetCellType(vtkId);
11226           int downId = grid->CellIdToDownId(vtkId);
11227           if (downId < 0)
11228           {
11229             MESSAGE("doubleNodesOnGroupBoundaries: internal algorithm problem");
11230             continue; // not OK at this stage of the algorithm:
11231             //no cells created after BuildDownWardConnectivity
11232           }
11233           DownIdType aCell(downId, vtkType);
11234           cellDomains[aCell][idomain] = vtkId;
11235           celldom[vtkId] = idomain;
11236           //MESSAGE("       cell " << vtkId << " domain " << idomain);
11237         }
11238       }
11239     }
11240   }
11241
11242   // --- explore the shared faces domain by domain, to duplicate the nodes in a coherent way
11243   //     for each shared face, get the nodes
11244   //     for each node, for each domain of the face, create a clone of the node
11245
11246   // --- edges at the intersection of 3 or 4 domains, with the order of domains to build
11247   //     junction elements of type prism or hexa. the key is the pair of nodesId (lower first)
11248   //     the value is the ordered domain ids. (more than 4 domains not taken into account)
11249
11250   std::map<std::vector<int>, std::vector<int> > edgesMultiDomains; // nodes of edge --> ordered domains
11251   std::map<int, std::vector<int> > mutipleNodes; // nodes multi domains with domain order
11252   std::map<int, std::vector<int> > mutipleNodesToFace; // nodes multi domains with domain order to transform in Face (junction between 3 or more 2D domains)
11253
11254   //MESSAGE(".. Duplication of the nodes");
11255   for (int idomain = idom0; idomain < nbDomains; idomain++)
11256   {
11257     itface = faceDomains.begin();
11258     for (; itface != faceDomains.end(); ++itface)
11259     {
11260       const std::map<int, int>& domvol = itface->second;
11261       if (!domvol.count(idomain))
11262         continue;
11263       DownIdType face = itface->first;
11264       //MESSAGE(" --- face " << face.cellId);
11265       std::set<int> oldNodes;
11266       oldNodes.clear();
11267       grid->GetNodeIds(oldNodes, face.cellId, face.cellType);
11268       std::set<int>::iterator itn = oldNodes.begin();
11269       for (; itn != oldNodes.end(); ++itn)
11270       {
11271         int oldId = *itn;
11272         if (nodeDomains[oldId].empty())
11273         {
11274           nodeDomains[oldId][idomain] = oldId; // keep the old node in the first domain
11275           //MESSAGE("-+-+-b     oldNode " << oldId << " domain " << idomain);
11276         }
11277         std::map<int, int>::const_iterator itdom = domvol.begin();
11278         for (; itdom != domvol.end(); ++itdom)
11279         {
11280           int idom = itdom->first;
11281           //MESSAGE("         domain " << idom);
11282           if (!nodeDomains[oldId].count(idom)) // --- node to clone
11283           {
11284             if (nodeDomains[oldId].size() >= 2) // a multiple node
11285             {
11286               vector<int> orderedDoms;
11287               //MESSAGE("multiple node " << oldId);
11288               if (mutipleNodes.count(oldId))
11289                 orderedDoms = mutipleNodes[oldId];
11290               else
11291               {
11292                 map<int,int>::iterator it = nodeDomains[oldId].begin();
11293                 for (; it != nodeDomains[oldId].end(); ++it)
11294                   orderedDoms.push_back(it->first);
11295               }
11296               orderedDoms.push_back(idom); // TODO order ==> push_front or back
11297               //stringstream txt;
11298               //for (int i=0; i<orderedDoms.size(); i++)
11299               //  txt << orderedDoms[i] << " ";
11300               //MESSAGE("orderedDoms " << txt.str());
11301               mutipleNodes[oldId] = orderedDoms;
11302             }
11303             double *coords = grid->GetPoint(oldId);
11304             SMDS_MeshNode *newNode = meshDS->AddNode(coords[0], coords[1], coords[2]);
11305             copyPosition( meshDS->FindNodeVtk( oldId ), newNode );
11306             int newId = newNode->GetVtkID();
11307             nodeDomains[oldId][idom] = newId; // cloned node for other domains
11308             //MESSAGE("-+-+-c     oldNode " << oldId << " domain " << idomain << " newNode " << newId << " domain " << idom << " size=" <<nodeDomains[oldId].size());
11309           }
11310         }
11311       }
11312     }
11313   }
11314
11315   //MESSAGE(".. Creation of elements");
11316   for (int idomain = idom0; idomain < nbDomains; idomain++)
11317   {
11318     itface = faceDomains.begin();
11319     for (; itface != faceDomains.end(); ++itface)
11320     {
11321       std::map<int, int> domvol = itface->second;
11322       if (!domvol.count(idomain))
11323         continue;
11324       DownIdType face = itface->first;
11325       //MESSAGE(" --- face " << face.cellId);
11326       std::set<int> oldNodes;
11327       oldNodes.clear();
11328       grid->GetNodeIds(oldNodes, face.cellId, face.cellType);
11329       int nbMultipleNodes = 0;
11330       std::set<int>::iterator itn = oldNodes.begin();
11331       for (; itn != oldNodes.end(); ++itn)
11332       {
11333         int oldId = *itn;
11334         if (mutipleNodes.count(oldId))
11335           nbMultipleNodes++;
11336       }
11337       if (nbMultipleNodes > 1) // check if an edge of the face is shared between 3 or more domains
11338       {
11339         //MESSAGE("multiple Nodes detected on a shared face");
11340         int downId = itface->first.cellId;
11341         unsigned char cellType = itface->first.cellType;
11342         // --- shared edge or shared face ?
11343         if ((cellType == VTK_LINE) || (cellType == VTK_QUADRATIC_EDGE)) // shared edge (between two faces)
11344         {
11345           int nodes[3];
11346           int nbNodes = grid->getDownArray(cellType)->getNodes(downId, nodes);
11347           for (int i=0; i< nbNodes; i=i+nbNodes-1) // i=0 , i=nbNodes-1
11348             if (mutipleNodes.count(nodes[i]))
11349               if (!mutipleNodesToFace.count(nodes[i]))
11350                 mutipleNodesToFace[nodes[i]] = mutipleNodes[nodes[i]];
11351         }
11352         else // shared face (between two volumes)
11353         {
11354           int nbEdges = grid->getDownArray(cellType)->getNumberOfDownCells(downId);
11355           const int* downEdgeIds = grid->getDownArray(cellType)->getDownCells(downId);
11356           const unsigned char* edgeType = grid->getDownArray(cellType)->getDownTypes(downId);
11357           for (int ie =0; ie < nbEdges; ie++)
11358           {
11359             int nodes[3];
11360             int nbNodes = grid->getDownArray(edgeType[ie])->getNodes(downEdgeIds[ie], nodes);
11361             if ( mutipleNodes.count(nodes[0]) && mutipleNodes.count( nodes[ nbNodes-1 ]))
11362             {
11363               vector<int> vn0 = mutipleNodes[nodes[0]];
11364               vector<int> vn1 = mutipleNodes[nodes[nbNodes - 1]];
11365               vector<int> doms;
11366               for ( size_t i0 = 0; i0 < vn0.size(); i0++ )
11367                 for ( size_t i1 = 0; i1 < vn1.size(); i1++ )
11368                   if ( vn0[i0] == vn1[i1] )
11369                     doms.push_back( vn0[ i0 ]);
11370               if ( doms.size() > 2 )
11371               {
11372                 //MESSAGE(" detect edgesMultiDomains " << nodes[0] << " " << nodes[nbNodes - 1]);
11373                 double *coords = grid->GetPoint(nodes[0]);
11374                 gp_Pnt p0(coords[0], coords[1], coords[2]);
11375                 coords = grid->GetPoint(nodes[nbNodes - 1]);
11376                 gp_Pnt p1(coords[0], coords[1], coords[2]);
11377                 gp_Pnt gref;
11378                 int vtkVolIds[1000];  // an edge can belong to a lot of volumes
11379                 map<int, SMDS_MeshVolume*> domvol; // domain --> a volume with the edge
11380                 map<int, double> angleDom; // oriented angles between planes defined by edge and volume centers
11381                 int nbvol = grid->GetParentVolumes(vtkVolIds, downEdgeIds[ie], edgeType[ie]);
11382                 for ( size_t id = 0; id < doms.size(); id++ )
11383                 {
11384                   int idom = doms[id];
11385                   const TIDSortedElemSet& domain = (idom == iRestDom) ? theRestDomElems : theElems[idom];
11386                   for ( int ivol = 0; ivol < nbvol; ivol++ )
11387                   {
11388                     int smdsId = meshDS->FromVtkToSmds(vtkVolIds[ivol]);
11389                     const SMDS_MeshElement* elem = meshDS->FindElement(smdsId);
11390                     if (domain.count(elem))
11391                     {
11392                       const SMDS_MeshVolume* svol = SMDS_Mesh::DownCast<SMDS_MeshVolume>(elem);
11393                       domvol[idom] = (SMDS_MeshVolume*) svol;
11394                       //MESSAGE("  domain " << idom << " volume " << elem->GetID());
11395                       double values[3] = { 0,0,0 };
11396                       vtkIdType npts = 0;
11397                       vtkIdType const *pts(nullptr);
11398                       grid->GetCellPoints(vtkVolIds[ivol], npts, pts);
11399                       for ( vtkIdType i = 0; i < npts; ++i )
11400                       {
11401                         double *coords = grid->GetPoint( pts[i] );
11402                         for ( int j = 0; j < 3; ++j )
11403                           values[j] += coords[j] / npts;
11404                       }
11405                       if ( id == 0 )
11406                       {
11407                         gref.SetCoord( values[0], values[1], values[2] );
11408                         angleDom[idom] = 0;
11409                       }
11410                       else
11411                       {
11412                         gp_Pnt g( values[0], values[1], values[2] );
11413                         angleDom[idom] = OrientedAngle(p0, p1, gref, g); // -pi<angle<+pi
11414                         //MESSAGE("  angle=" << angleDom[idom]);
11415                       }
11416                       break;
11417                     }
11418                   }
11419                 }
11420                 map<double, int> sortedDom; // sort domains by angle
11421                 for (map<int, double>::iterator ia = angleDom.begin(); ia != angleDom.end(); ++ia)
11422                   sortedDom[ia->second] = ia->first;
11423                 vector<int> vnodes;
11424                 vector<int> vdom;
11425                 for (map<double, int>::iterator ib = sortedDom.begin(); ib != sortedDom.end(); ++ib)
11426                 {
11427                   vdom.push_back(ib->second);
11428                   //MESSAGE("  ordered domain " << ib->second << "  angle " << ib->first);
11429                 }
11430                 for (int ino = 0; ino < nbNodes; ino++)
11431                   vnodes.push_back(nodes[ino]);
11432                 edgesMultiDomains[vnodes] = vdom; // nodes vector --> ordered domains
11433               }
11434             }
11435           }
11436         }
11437       }
11438     }
11439   }
11440
11441   // --- iterate on shared faces (volumes to modify, face to extrude)
11442   //     get node id's of the face (id SMDS = id VTK)
11443   //     create flat element with old and new nodes if requested
11444
11445   // --- new quad nodes on flat quad elements: oldId --> ((domain1 X domain2) --> newId)
11446   //     (domain1 X domain2) = domain1 + MAXINT*domain2
11447
11448   std::map<int, std::map<long,int> > nodeQuadDomains;
11449   std::map<std::string, SMESH_Group*> mapOfJunctionGroups;
11450
11451   //MESSAGE(".. Creation of elements: simple junction");
11452   if (createJointElems)
11453   {
11454     string joints2DName = "joints2D";
11455     mapOfJunctionGroups[joints2DName] = this->myMesh->AddGroup(SMDSAbs_Face, joints2DName.c_str());
11456     SMESHDS_Group *joints2DGrp = dynamic_cast<SMESHDS_Group*>(mapOfJunctionGroups[joints2DName]->GetGroupDS());
11457     string joints3DName = "joints3D";
11458     mapOfJunctionGroups[joints3DName] = this->myMesh->AddGroup(SMDSAbs_Volume, joints3DName.c_str());
11459     SMESHDS_Group *joints3DGrp = dynamic_cast<SMESHDS_Group*>(mapOfJunctionGroups[joints3DName]->GetGroupDS());
11460
11461     itface = faceDomains.begin();
11462     for (; itface != faceDomains.end(); ++itface)
11463     {
11464       DownIdType face = itface->first;
11465       std::set<int> oldNodes;
11466       std::set<int>::iterator itn;
11467       oldNodes.clear();
11468       grid->GetNodeIds(oldNodes, face.cellId, face.cellType);
11469
11470       std::map<int, int> domvol = itface->second;
11471       std::map<int, int>::iterator itdom = domvol.begin();
11472       int dom1 = itdom->first;
11473       int vtkVolId = itdom->second;
11474       itdom++;
11475       int dom2 = itdom->first;
11476       SMDS_MeshCell *vol = grid->extrudeVolumeFromFace(vtkVolId, dom1, dom2, oldNodes, nodeDomains,
11477                                                        nodeQuadDomains);
11478       stringstream grpname;
11479       grpname << "j_";
11480       if (dom1 < dom2)
11481         grpname << dom1 << "_" << dom2;
11482       else
11483         grpname << dom2 << "_" << dom1;
11484       string namegrp = grpname.str();
11485       if (!mapOfJunctionGroups.count(namegrp))
11486         mapOfJunctionGroups[namegrp] = this->myMesh->AddGroup(vol->GetType(), namegrp.c_str());
11487       SMESHDS_Group *sgrp = dynamic_cast<SMESHDS_Group*>(mapOfJunctionGroups[namegrp]->GetGroupDS());
11488       if (sgrp)
11489         sgrp->Add(vol->GetID());
11490       if (vol->GetType() == SMDSAbs_Volume)
11491         joints3DGrp->Add(vol->GetID());
11492       else if (vol->GetType() == SMDSAbs_Face)
11493         joints2DGrp->Add(vol->GetID());
11494     }
11495   }
11496
11497   // --- create volumes on multiple domain intersection if requested
11498   //     iterate on mutipleNodesToFace
11499   //     iterate on edgesMultiDomains
11500
11501   //MESSAGE(".. Creation of elements: multiple junction");
11502   if (createJointElems)
11503   {
11504     // --- iterate on mutipleNodesToFace
11505
11506     std::map<int, std::vector<int> >::iterator itn =  mutipleNodesToFace.begin();
11507     for (; itn != mutipleNodesToFace.end(); ++itn)
11508     {
11509       int node = itn->first;
11510       vector<int> orderDom = itn->second;
11511       vector<vtkIdType> orderedNodes;
11512       for ( size_t idom = 0; idom < orderDom.size(); idom++ )
11513         orderedNodes.push_back( nodeDomains[ node ][ orderDom[ idom ]]);
11514       SMDS_MeshFace* face = this->GetMeshDS()->AddFaceFromVtkIds(orderedNodes);
11515
11516       stringstream grpname;
11517       grpname << "m2j_";
11518       grpname << 0 << "_" << 0;
11519       string namegrp = grpname.str();
11520       if (!mapOfJunctionGroups.count(namegrp))
11521         mapOfJunctionGroups[namegrp] = this->myMesh->AddGroup(SMDSAbs_Face, namegrp.c_str());
11522       SMESHDS_Group *sgrp = dynamic_cast<SMESHDS_Group*>(mapOfJunctionGroups[namegrp]->GetGroupDS());
11523       if (sgrp)
11524         sgrp->Add(face->GetID());
11525     }
11526
11527     // --- iterate on edgesMultiDomains
11528
11529     std::map<std::vector<int>, std::vector<int> >::iterator ite = edgesMultiDomains.begin();
11530     for (; ite != edgesMultiDomains.end(); ++ite)
11531     {
11532       vector<int> nodes = ite->first;
11533       vector<int> orderDom = ite->second;
11534       vector<vtkIdType> orderedNodes;
11535       if (nodes.size() == 2)
11536       {
11537         //MESSAGE(" use edgesMultiDomains " << nodes[0] << " " << nodes[1]);
11538         for ( size_t ino = 0; ino < nodes.size(); ino++ )
11539           if ( orderDom.size() == 3 )
11540             for ( size_t idom = 0; idom < orderDom.size(); idom++ )
11541               orderedNodes.push_back( nodeDomains[ nodes[ ino ]][ orderDom[ idom ]]);
11542           else
11543             for (int idom = orderDom.size()-1; idom >=0; idom--)
11544               orderedNodes.push_back( nodeDomains[ nodes[ ino ]][ orderDom[ idom ]]);
11545         SMDS_MeshVolume* vol = this->GetMeshDS()->AddVolumeFromVtkIds(orderedNodes);
11546
11547         string namegrp = "jointsMultiples";
11548         if (!mapOfJunctionGroups.count(namegrp))
11549           mapOfJunctionGroups[namegrp] = this->myMesh->AddGroup(SMDSAbs_Volume, namegrp.c_str());
11550         SMESHDS_Group *sgrp = dynamic_cast<SMESHDS_Group*>(mapOfJunctionGroups[namegrp]->GetGroupDS());
11551         if (sgrp)
11552           sgrp->Add(vol->GetID());
11553       }
11554       else
11555       {
11556         //INFOS("Quadratic multiple joints not implemented");
11557         // TODO quadratic nodes
11558       }
11559     }
11560   }
11561
11562   // --- list the explicit faces and edges of the mesh that need to be modified,
11563   //     i.e. faces and edges built with one or more duplicated nodes.
11564   //     associate these faces or edges to their corresponding domain.
11565   //     only the first domain found is kept when a face or edge is shared
11566
11567   std::map<DownIdType, std::map<int,int>, DownIdCompare> faceOrEdgeDom; // cellToModify --> (id domain --> id cell)
11568   std::map<int,int> feDom; // vtk id of cell to modify --> id domain
11569   faceOrEdgeDom.clear();
11570   feDom.clear();
11571
11572   //MESSAGE(".. Modification of elements");
11573   for (int idomain = idom0; idomain < nbDomains; idomain++)
11574   {
11575     std::map<int, std::map<int, int> >::const_iterator itnod = nodeDomains.begin();
11576     for (; itnod != nodeDomains.end(); ++itnod)
11577     {
11578       int oldId = itnod->first;
11579       //MESSAGE("     node " << oldId);
11580       vtkCellLinks::Link l = (static_cast< vtkCellLinks *>(grid->GetCellLinks()))->GetLink(oldId);
11581       for (int i = 0; i < l.ncells; i++)
11582       {
11583         int vtkId = l.cells[i];
11584         int vtkType = grid->GetCellType(vtkId);
11585         int downId = grid->CellIdToDownId(vtkId);
11586         if (downId < 0)
11587           continue; // new cells: not to be modified
11588         DownIdType aCell(downId, vtkType);
11589         int volParents[1000];
11590         int nbvol = grid->GetParentVolumes(volParents, vtkId);
11591         for (int j = 0; j < nbvol; j++)
11592           if (celldom.count(volParents[j]) && (celldom[volParents[j]] == idomain))
11593             if (!feDom.count(vtkId))
11594             {
11595               feDom[vtkId] = idomain;
11596               faceOrEdgeDom[aCell] = emptyMap;
11597               faceOrEdgeDom[aCell][idomain] = vtkId; // affect face or edge to the first domain only
11598               //MESSAGE("affect cell " << this->GetMeshDS()->FromVtkToSmds(vtkId) << " domain " << idomain
11599               //        << " type " << vtkType << " downId " << downId);
11600             }
11601       }
11602     }
11603   }
11604
11605   // --- iterate on shared faces (volumes to modify, face to extrude)
11606   //     get node id's of the face
11607   //     replace old nodes by new nodes in volumes, and update inverse connectivity
11608
11609   std::map<DownIdType, std::map<int,int>, DownIdCompare>* maps[3] = {&faceDomains, &cellDomains, &faceOrEdgeDom};
11610   for (int m=0; m<3; m++)
11611   {
11612     std::map<DownIdType, std::map<int,int>, DownIdCompare>* amap = maps[m];
11613     itface = (*amap).begin();
11614     for (; itface != (*amap).end(); ++itface)
11615     {
11616       DownIdType face = itface->first;
11617       std::set<int> oldNodes;
11618       std::set<int>::iterator itn;
11619       oldNodes.clear();
11620       grid->GetNodeIds(oldNodes, face.cellId, face.cellType);
11621       //MESSAGE("examine cell, downId " << face.cellId << " type " << int(face.cellType));
11622       std::map<int, int> localClonedNodeIds;
11623
11624       std::map<int, int> domvol = itface->second;
11625       std::map<int, int>::iterator itdom = domvol.begin();
11626       for (; itdom != domvol.end(); ++itdom)
11627       {
11628         int idom = itdom->first;
11629         int vtkVolId = itdom->second;
11630         //MESSAGE("modify nodes of cell " << this->GetMeshDS()->FromVtkToSmds(vtkVolId) << " domain " << idom);
11631         localClonedNodeIds.clear();
11632         for (itn = oldNodes.begin(); itn != oldNodes.end(); ++itn)
11633         {
11634           int oldId = *itn;
11635           if (nodeDomains[oldId].count(idom))
11636           {
11637             localClonedNodeIds[oldId] = nodeDomains[oldId][idom];
11638             //MESSAGE("     node " << oldId << " --> " << localClonedNodeIds[oldId]);
11639           }
11640         }
11641         meshDS->ModifyCellNodes(vtkVolId, localClonedNodeIds);
11642       }
11643     }
11644   }
11645
11646   // Remove empty groups (issue 0022812)
11647   std::map<std::string, SMESH_Group*>::iterator name_group = mapOfJunctionGroups.begin();
11648   for ( ; name_group != mapOfJunctionGroups.end(); ++name_group )
11649   {
11650     if ( name_group->second && name_group->second->GetGroupDS()->IsEmpty() )
11651       myMesh->RemoveGroup( name_group->second->GetGroupDS()->GetID() );
11652   }
11653
11654   meshDS->CleanDownWardConnectivity(); // Mesh has been modified, downward connectivity is no more usable, free memory
11655   grid->DeleteLinks();
11656
11657   CHRONOSTOP(50);
11658   counters::stats();
11659   return true;
11660 }
11661
11662 /*!
11663  * \brief Double nodes on some external faces and create flat elements.
11664  * Flat elements are mainly used by some types of mechanic calculations.
11665  *
11666  * Each group of the list must be constituted of faces.
11667  * Triangles are transformed in prisms, and quadrangles in hexahedrons.
11668  * @param theElems - list of groups of faces, where a group of faces is a set of
11669  * SMDS_MeshElements sorted by Id.
11670  * @return TRUE if operation has been completed successfully, FALSE otherwise
11671  */
11672 bool SMESH_MeshEditor::CreateFlatElementsOnFacesGroups(const std::vector<TIDSortedElemSet>& theElems)
11673 {
11674   // MESSAGE("-------------------------------------------------");
11675   // MESSAGE("SMESH_MeshEditor::CreateFlatElementsOnFacesGroups");
11676   // MESSAGE("-------------------------------------------------");
11677
11678   SMESHDS_Mesh *meshDS = this->myMesh->GetMeshDS();
11679
11680   // --- For each group of faces
11681   //     duplicate the nodes, create a flat element based on the face
11682   //     replace the nodes of the faces by their clones
11683
11684   std::map<const SMDS_MeshNode*, const SMDS_MeshNode*> clonedNodes;
11685   std::map<const SMDS_MeshNode*, const SMDS_MeshNode*> intermediateNodes;
11686   clonedNodes.clear();
11687   intermediateNodes.clear();
11688   std::map<std::string, SMESH_Group*> mapOfJunctionGroups;
11689   mapOfJunctionGroups.clear();
11690
11691   for ( size_t idom = 0; idom < theElems.size(); idom++ )
11692   {
11693     const TIDSortedElemSet&           domain = theElems[idom];
11694     TIDSortedElemSet::const_iterator elemItr = domain.begin();
11695     for ( ; elemItr != domain.end(); ++elemItr )
11696     {
11697       const SMDS_MeshFace* aFace = meshDS->DownCast<SMDS_MeshFace> ( *elemItr );
11698       if (!aFace)
11699         continue;
11700       // MESSAGE("aFace=" << aFace->GetID());
11701       bool isQuad = aFace->IsQuadratic();
11702       vector<const SMDS_MeshNode*> ln0, ln1, ln2, ln3, ln4;
11703
11704       // --- clone the nodes, create intermediate nodes for non medium nodes of a quad face
11705
11706       SMDS_NodeIteratorPtr nodeIt = aFace->nodeIterator();
11707       while (nodeIt->more())
11708       {
11709         const SMDS_MeshNode* node = nodeIt->next();
11710         bool isMedium = ( isQuad && aFace->IsMediumNode( node ));
11711         if (isMedium)
11712           ln2.push_back(node);
11713         else
11714           ln0.push_back(node);
11715
11716         const SMDS_MeshNode* clone = 0;
11717         if (!clonedNodes.count(node))
11718         {
11719           clone = meshDS->AddNode(node->X(), node->Y(), node->Z());
11720           copyPosition( node, clone );
11721           clonedNodes[node] = clone;
11722         }
11723         else
11724           clone = clonedNodes[node];
11725
11726         if (isMedium)
11727           ln3.push_back(clone);
11728         else
11729           ln1.push_back(clone);
11730
11731         const SMDS_MeshNode* inter = 0;
11732         if (isQuad && (!isMedium))
11733         {
11734           if (!intermediateNodes.count(node))
11735           {
11736             inter = meshDS->AddNode(node->X(), node->Y(), node->Z());
11737             copyPosition( node, inter );
11738             intermediateNodes[node] = inter;
11739           }
11740           else
11741             inter = intermediateNodes[node];
11742           ln4.push_back(inter);
11743         }
11744       }
11745
11746       // --- extrude the face
11747
11748       vector<const SMDS_MeshNode*> ln;
11749       SMDS_MeshVolume* vol = 0;
11750       vtkIdType aType = aFace->GetVtkType();
11751       switch (aType)
11752       {
11753       case VTK_TRIANGLE:
11754         vol = meshDS->AddVolume(ln0[2], ln0[1], ln0[0], ln1[2], ln1[1], ln1[0]);
11755         // MESSAGE("vol prism " << vol->GetID());
11756         ln.push_back(ln1[0]);
11757         ln.push_back(ln1[1]);
11758         ln.push_back(ln1[2]);
11759         break;
11760       case VTK_QUAD:
11761         vol = meshDS->AddVolume(ln0[3], ln0[2], ln0[1], ln0[0], ln1[3], ln1[2], ln1[1], ln1[0]);
11762         // MESSAGE("vol hexa " << vol->GetID());
11763         ln.push_back(ln1[0]);
11764         ln.push_back(ln1[1]);
11765         ln.push_back(ln1[2]);
11766         ln.push_back(ln1[3]);
11767         break;
11768       case VTK_QUADRATIC_TRIANGLE:
11769         vol = meshDS->AddVolume(ln1[0], ln1[1], ln1[2], ln0[0], ln0[1], ln0[2], ln3[0], ln3[1], ln3[2],
11770                                 ln2[0], ln2[1], ln2[2], ln4[0], ln4[1], ln4[2]);
11771         // MESSAGE("vol quad prism " << vol->GetID());
11772         ln.push_back(ln1[0]);
11773         ln.push_back(ln1[1]);
11774         ln.push_back(ln1[2]);
11775         ln.push_back(ln3[0]);
11776         ln.push_back(ln3[1]);
11777         ln.push_back(ln3[2]);
11778         break;
11779       case VTK_QUADRATIC_QUAD:
11780         //              vol = meshDS->AddVolume(ln0[0], ln0[1], ln0[2], ln0[3], ln1[0], ln1[1], ln1[2], ln1[3],
11781         //                                      ln2[0], ln2[1], ln2[2], ln2[3], ln3[0], ln3[1], ln3[2], ln3[3],
11782         //                                      ln4[0], ln4[1], ln4[2], ln4[3]);
11783         vol = meshDS->AddVolume(ln1[0], ln1[1], ln1[2], ln1[3], ln0[0], ln0[1], ln0[2], ln0[3],
11784                                 ln3[0], ln3[1], ln3[2], ln3[3], ln2[0], ln2[1], ln2[2], ln2[3],
11785                                 ln4[0], ln4[1], ln4[2], ln4[3]);
11786         // MESSAGE("vol quad hexa " << vol->GetID());
11787         ln.push_back(ln1[0]);
11788         ln.push_back(ln1[1]);
11789         ln.push_back(ln1[2]);
11790         ln.push_back(ln1[3]);
11791         ln.push_back(ln3[0]);
11792         ln.push_back(ln3[1]);
11793         ln.push_back(ln3[2]);
11794         ln.push_back(ln3[3]);
11795         break;
11796       case VTK_POLYGON:
11797         break;
11798       default:
11799         break;
11800       }
11801
11802       if (vol)
11803       {
11804         stringstream grpname;
11805         grpname << "jf_";
11806         grpname << idom;
11807         string namegrp = grpname.str();
11808         if (!mapOfJunctionGroups.count(namegrp))
11809           mapOfJunctionGroups[namegrp] = this->myMesh->AddGroup(SMDSAbs_Volume, namegrp.c_str());
11810         SMESHDS_Group *sgrp = dynamic_cast<SMESHDS_Group*>(mapOfJunctionGroups[namegrp]->GetGroupDS());
11811         if (sgrp)
11812           sgrp->Add(vol->GetID());
11813       }
11814
11815       // --- modify the face
11816
11817       const_cast<SMDS_MeshFace*>( aFace )->ChangeNodes( &ln[0], ln.size() );
11818     }
11819   }
11820   return true;
11821 }
11822
11823 /*!
11824  *  \brief identify all the elements around a geom shape, get the faces delimiting the hole
11825  *  Build groups of volume to remove, groups of faces to replace on the skin of the object,
11826  *  groups of faces to remove inside the object, (idem edges).
11827  *  Build ordered list of nodes at the border of each group of faces to replace (to be used to build a geom subshape)
11828  */
11829 void SMESH_MeshEditor::CreateHoleSkin(double                          radius,
11830                                       const TopoDS_Shape&             theShape,
11831                                       SMESH_NodeSearcher*             theNodeSearcher,
11832                                       const char*                     groupName,
11833                                       std::vector<double>&            nodesCoords,
11834                                       std::vector<std::vector<int> >& listOfListOfNodes)
11835 {
11836   // MESSAGE("--------------------------------");
11837   // MESSAGE("SMESH_MeshEditor::CreateHoleSkin");
11838   // MESSAGE("--------------------------------");
11839
11840   // --- zone of volumes to remove is given :
11841   //     1 either by a geom shape (one or more vertices) and a radius,
11842   //     2 either by a group of nodes (representative of the shape)to use with the radius,
11843   //     3 either by a group of nodes where all the elements build on one of this nodes are to remove,
11844   //     In the case 2, the group of nodes is an external group of nodes from another mesh,
11845   //     In the case 3, the group of nodes is an internal group of the mesh (obtained for instance by a filter),
11846   //     defined by it's name.
11847
11848   SMESHDS_GroupBase* groupDS = 0;
11849   SMESH_Mesh::GroupIteratorPtr groupIt = this->myMesh->GetGroups();
11850   while ( groupIt->more() )
11851   {
11852     groupDS = 0;
11853     SMESH_Group * group = groupIt->next();
11854     if ( !group ) continue;
11855     groupDS = group->GetGroupDS();
11856     if ( !groupDS || groupDS->IsEmpty() ) continue;
11857     std::string grpName = group->GetName();
11858     //MESSAGE("grpName=" << grpName);
11859     if (grpName == groupName)
11860       break;
11861     else
11862       groupDS = 0;
11863   }
11864
11865   bool isNodeGroup = false;
11866   bool isNodeCoords = false;
11867   if (groupDS)
11868   {
11869     if (groupDS->GetType() != SMDSAbs_Node)
11870       return;
11871     isNodeGroup = true;     // a group of nodes exists and it is in this mesh
11872   }
11873
11874   if (nodesCoords.size() > 0)
11875     isNodeCoords = true; // a list o nodes given by their coordinates
11876   //MESSAGE("---" << isNodeGroup << " " << isNodeCoords);
11877
11878   // --- define groups to build
11879
11880   // --- group of SMDS volumes
11881   string grpvName = groupName;
11882   grpvName += "_vol";
11883   SMESH_Group *grp = this->myMesh->AddGroup(SMDSAbs_Volume, grpvName.c_str());
11884   if (!grp)
11885   {
11886     MESSAGE("group not created " << grpvName);
11887     return;
11888   }
11889   SMESHDS_Group *sgrp = dynamic_cast<SMESHDS_Group*>(grp->GetGroupDS());
11890
11891   // --- group of SMDS faces on the skin
11892   string grpsName = groupName;
11893   grpsName += "_skin";
11894   SMESH_Group *grps = this->myMesh->AddGroup(SMDSAbs_Face, grpsName.c_str());
11895   if (!grps)
11896   {
11897     MESSAGE("group not created " << grpsName);
11898     return;
11899   }
11900   SMESHDS_Group *sgrps = dynamic_cast<SMESHDS_Group*>(grps->GetGroupDS());
11901
11902   // --- group of SMDS faces internal (several shapes)
11903   string grpiName = groupName;
11904   grpiName += "_internalFaces";
11905   SMESH_Group *grpi = this->myMesh->AddGroup(SMDSAbs_Face, grpiName.c_str());
11906   if (!grpi)
11907   {
11908     MESSAGE("group not created " << grpiName);
11909     return;
11910   }
11911   SMESHDS_Group *sgrpi = dynamic_cast<SMESHDS_Group*>(grpi->GetGroupDS());
11912
11913   // --- group of SMDS faces internal (several shapes)
11914   string grpeiName = groupName;
11915   grpeiName += "_internalEdges";
11916   SMESH_Group *grpei = this->myMesh->AddGroup(SMDSAbs_Edge, grpeiName.c_str());
11917   if (!grpei)
11918   {
11919     MESSAGE("group not created " << grpeiName);
11920     return;
11921   }
11922   SMESHDS_Group *sgrpei = dynamic_cast<SMESHDS_Group*>(grpei->GetGroupDS());
11923
11924   // --- build downward connectivity
11925
11926   SMESHDS_Mesh *meshDS = this->myMesh->GetMeshDS();
11927   meshDS->BuildDownWardConnectivity(true);
11928   SMDS_UnstructuredGrid* grid = meshDS->GetGrid();
11929
11930   // --- set of volumes detected inside
11931
11932   std::set<int> setOfInsideVol;
11933   std::set<int> setOfVolToCheck;
11934
11935   std::vector<gp_Pnt> gpnts;
11936   gpnts.clear();
11937
11938   if (isNodeGroup) // --- a group of nodes is provided : find all the volumes using one or more of this nodes
11939   {
11940     //MESSAGE("group of nodes provided");
11941     SMDS_ElemIteratorPtr elemIt = groupDS->GetElements();
11942     while ( elemIt->more() )
11943     {
11944       const SMDS_MeshElement* elem = elemIt->next();
11945       if (!elem)
11946         continue;
11947       const SMDS_MeshNode* node = dynamic_cast<const SMDS_MeshNode*>(elem);
11948       if (!node)
11949         continue;
11950       SMDS_MeshElement* vol = 0;
11951       SMDS_ElemIteratorPtr volItr = node->GetInverseElementIterator(SMDSAbs_Volume);
11952       while (volItr->more())
11953       {
11954         vol = (SMDS_MeshElement*)volItr->next();
11955         setOfInsideVol.insert(vol->GetVtkID());
11956         sgrp->Add(vol->GetID());
11957       }
11958     }
11959   }
11960   else if (isNodeCoords)
11961   {
11962     //MESSAGE("list of nodes coordinates provided");
11963     size_t i = 0;
11964     int k = 0;
11965     while ( i < nodesCoords.size()-2 )
11966     {
11967       double x = nodesCoords[i++];
11968       double y = nodesCoords[i++];
11969       double z = nodesCoords[i++];
11970       gp_Pnt p = gp_Pnt(x, y ,z);
11971       gpnts.push_back(p);
11972       //MESSAGE("TopoDS_Vertex " << k << " " << p.X() << " " << p.Y() << " " << p.Z());
11973       k++;
11974     }
11975   }
11976   else // --- no group, no coordinates : use the vertices of the geom shape provided, and radius
11977   {
11978     //MESSAGE("no group of nodes provided, using vertices from geom shape, and radius");
11979     TopTools_IndexedMapOfShape vertexMap;
11980     TopExp::MapShapes( theShape, TopAbs_VERTEX, vertexMap );
11981     gp_Pnt p = gp_Pnt(0,0,0);
11982     if (vertexMap.Extent() < 1)
11983       return;
11984
11985     for ( int i = 1; i <= vertexMap.Extent(); ++i )
11986     {
11987       const TopoDS_Vertex& vertex = TopoDS::Vertex( vertexMap( i ));
11988       p = BRep_Tool::Pnt(vertex);
11989       gpnts.push_back(p);
11990       //MESSAGE("TopoDS_Vertex " << i << " " << p.X() << " " << p.Y() << " " << p.Z());
11991     }
11992   }
11993
11994   if (gpnts.size() > 0)
11995   {
11996     const SMDS_MeshNode* startNode = theNodeSearcher->FindClosestTo(gpnts[0]);
11997     //MESSAGE("startNode->nodeId " << nodeId);
11998
11999     double radius2 = radius*radius;
12000     //MESSAGE("radius2 " << radius2);
12001
12002     // --- volumes on start node
12003
12004     setOfVolToCheck.clear();
12005     SMDS_MeshElement* startVol = 0;
12006     SMDS_ElemIteratorPtr volItr = startNode->GetInverseElementIterator(SMDSAbs_Volume);
12007     while (volItr->more())
12008     {
12009       startVol = (SMDS_MeshElement*)volItr->next();
12010       setOfVolToCheck.insert(startVol->GetVtkID());
12011     }
12012     if (setOfVolToCheck.empty())
12013     {
12014       MESSAGE("No volumes found");
12015       return;
12016     }
12017
12018     // --- starting with central volumes then their neighbors, check if they are inside
12019     //     or outside the domain, until no more new neighbor volume is inside.
12020     //     Fill the group of inside volumes
12021
12022     std::map<int, double> mapOfNodeDistance2;
12023     mapOfNodeDistance2.clear();
12024     std::set<int> setOfOutsideVol;
12025     while (!setOfVolToCheck.empty())
12026     {
12027       std::set<int>::iterator it = setOfVolToCheck.begin();
12028       int vtkId = *it;
12029       //MESSAGE("volume to check,  vtkId " << vtkId << " smdsId " << meshDS->FromVtkToSmds(vtkId));
12030       bool volInside = false;
12031       vtkIdType npts = 0;
12032       vtkIdType const *pts(nullptr);
12033       grid->GetCellPoints(vtkId, npts, pts);
12034       for (int i=0; i<npts; i++)
12035       {
12036         double distance2 = 0;
12037         if (mapOfNodeDistance2.count(pts[i]))
12038         {
12039           distance2 = mapOfNodeDistance2[pts[i]];
12040           //MESSAGE("point " << pts[i] << " distance2 " << distance2);
12041         }
12042         else
12043         {
12044           double *coords = grid->GetPoint(pts[i]);
12045           gp_Pnt aPoint = gp_Pnt(coords[0], coords[1], coords[2]);
12046           distance2 = 1.E40;
12047           for ( size_t j = 0; j < gpnts.size(); j++ )
12048           {
12049             double d2 = aPoint.SquareDistance( gpnts[ j ]);
12050             if (d2 < distance2)
12051             {
12052               distance2 = d2;
12053               if (distance2 < radius2)
12054                 break;
12055             }
12056           }
12057           mapOfNodeDistance2[pts[i]] = distance2;
12058           //MESSAGE("  point "  << pts[i]  << " distance2 " << distance2 << " coords " << coords[0] << " " << coords[1] << " " <<  coords[2]);
12059         }
12060         if (distance2 < radius2)
12061         {
12062           volInside = true; // one or more nodes inside the domain
12063           sgrp->Add(meshDS->FromVtkToSmds(vtkId));
12064           break;
12065         }
12066       }
12067       if (volInside)
12068       {
12069         setOfInsideVol.insert(vtkId);
12070         //MESSAGE("  volume inside,  vtkId " << vtkId << " smdsId " << meshDS->FromVtkToSmds(vtkId));
12071         int neighborsVtkIds[NBMAXNEIGHBORS];
12072         int downIds[NBMAXNEIGHBORS];
12073         unsigned char downTypes[NBMAXNEIGHBORS];
12074         int nbNeighbors = grid->GetNeighbors(neighborsVtkIds, downIds, downTypes, vtkId);
12075         for (int n = 0; n < nbNeighbors; n++)
12076           if (!setOfInsideVol.count(neighborsVtkIds[n]) ||setOfOutsideVol.count(neighborsVtkIds[n]))
12077             setOfVolToCheck.insert(neighborsVtkIds[n]);
12078       }
12079       else
12080       {
12081         setOfOutsideVol.insert(vtkId);
12082         //MESSAGE("  volume outside, vtkId " << vtkId << " smdsId " << meshDS->FromVtkToSmds(vtkId));
12083       }
12084       setOfVolToCheck.erase(vtkId);
12085     }
12086   }
12087
12088   // --- for outside hexahedrons, check if they have more than one neighbor volume inside
12089   //     If yes, add the volume to the inside set
12090
12091   bool addedInside = true;
12092   std::set<int> setOfVolToReCheck;
12093   while (addedInside)
12094   {
12095     //MESSAGE(" --------------------------- re check");
12096     addedInside = false;
12097     std::set<int>::iterator itv = setOfInsideVol.begin();
12098     for (; itv != setOfInsideVol.end(); ++itv)
12099     {
12100       int vtkId = *itv;
12101       int neighborsVtkIds[NBMAXNEIGHBORS];
12102       int downIds[NBMAXNEIGHBORS];
12103       unsigned char downTypes[NBMAXNEIGHBORS];
12104       int nbNeighbors = grid->GetNeighbors(neighborsVtkIds, downIds, downTypes, vtkId);
12105       for (int n = 0; n < nbNeighbors; n++)
12106         if (!setOfInsideVol.count(neighborsVtkIds[n]))
12107           setOfVolToReCheck.insert(neighborsVtkIds[n]);
12108     }
12109     setOfVolToCheck = setOfVolToReCheck;
12110     setOfVolToReCheck.clear();
12111     while  (!setOfVolToCheck.empty())
12112     {
12113       std::set<int>::iterator it = setOfVolToCheck.begin();
12114       int vtkId = *it;
12115       if (grid->GetCellType(vtkId) == VTK_HEXAHEDRON)
12116       {
12117         //MESSAGE("volume to recheck,  vtkId " << vtkId << " smdsId " << meshDS->FromVtkToSmds(vtkId));
12118         int countInside = 0;
12119         int neighborsVtkIds[NBMAXNEIGHBORS];
12120         int downIds[NBMAXNEIGHBORS];
12121         unsigned char downTypes[NBMAXNEIGHBORS];
12122         int nbNeighbors = grid->GetNeighbors(neighborsVtkIds, downIds, downTypes, vtkId);
12123         for (int n = 0; n < nbNeighbors; n++)
12124           if (setOfInsideVol.count(neighborsVtkIds[n]))
12125             countInside++;
12126         //MESSAGE("countInside " << countInside);
12127         if (countInside > 1)
12128         {
12129           //MESSAGE("  volume inside,  vtkId " << vtkId << " smdsId " << meshDS->FromVtkToSmds(vtkId));
12130           setOfInsideVol.insert(vtkId);
12131           sgrp->Add(meshDS->FromVtkToSmds(vtkId));
12132           addedInside = true;
12133         }
12134         else
12135           setOfVolToReCheck.insert(vtkId);
12136       }
12137       setOfVolToCheck.erase(vtkId);
12138     }
12139   }
12140
12141   // --- map of Downward faces at the boundary, inside the global volume
12142   //     map of Downward faces on the skin of the global volume (equivalent to SMDS faces on the skin)
12143   //     fill group of SMDS faces inside the volume (when several volume shapes)
12144   //     fill group of SMDS faces on the skin of the global volume (if skin)
12145
12146   std::map<DownIdType, int, DownIdCompare> boundaryFaces; // boundary faces inside the volume --> corresponding cell
12147   std::map<DownIdType, int, DownIdCompare> skinFaces;     // faces on the skin of the global volume --> corresponding cell
12148   std::set<int>::iterator it = setOfInsideVol.begin();
12149   for (; it != setOfInsideVol.end(); ++it)
12150   {
12151     int vtkId = *it;
12152     //MESSAGE("  vtkId " << vtkId  << " smdsId " << meshDS->FromVtkToSmds(vtkId));
12153     int neighborsVtkIds[NBMAXNEIGHBORS];
12154     int downIds[NBMAXNEIGHBORS];
12155     unsigned char downTypes[NBMAXNEIGHBORS];
12156     int nbNeighbors = grid->GetNeighbors(neighborsVtkIds, downIds, downTypes, vtkId, true);
12157     for (int n = 0; n < nbNeighbors; n++)
12158     {
12159       int neighborDim = SMDS_Downward::getCellDimension(grid->GetCellType(neighborsVtkIds[n]));
12160       if (neighborDim == 3)
12161       {
12162         if (! setOfInsideVol.count(neighborsVtkIds[n])) // neighbor volume is not inside : face is boundary
12163         {
12164           DownIdType face(downIds[n], downTypes[n]);
12165           boundaryFaces[face] = vtkId;
12166         }
12167         // if the face between to volumes is in the mesh, get it (internal face between shapes)
12168         int vtkFaceId = grid->getDownArray(downTypes[n])->getVtkCellId(downIds[n]);
12169         if (vtkFaceId >= 0)
12170         {
12171           sgrpi->Add(meshDS->FromVtkToSmds(vtkFaceId));
12172           // find also the smds edges on this face
12173           int nbEdges = grid->getDownArray(downTypes[n])->getNumberOfDownCells(downIds[n]);
12174           const int* dEdges = grid->getDownArray(downTypes[n])->getDownCells(downIds[n]);
12175           const unsigned char* dTypes = grid->getDownArray(downTypes[n])->getDownTypes(downIds[n]);
12176           for (int i = 0; i < nbEdges; i++)
12177           {
12178             int vtkEdgeId = grid->getDownArray(dTypes[i])->getVtkCellId(dEdges[i]);
12179             if (vtkEdgeId >= 0)
12180               sgrpei->Add(meshDS->FromVtkToSmds(vtkEdgeId));
12181           }
12182         }
12183       }
12184       else if (neighborDim == 2) // skin of the volume
12185       {
12186         DownIdType face(downIds[n], downTypes[n]);
12187         skinFaces[face] = vtkId;
12188         int vtkFaceId = grid->getDownArray(downTypes[n])->getVtkCellId(downIds[n]);
12189         if (vtkFaceId >= 0)
12190           sgrps->Add(meshDS->FromVtkToSmds(vtkFaceId));
12191       }
12192     }
12193   }
12194
12195   // --- identify the edges constituting the wire of each subshape on the skin
12196   //     define polylines with the nodes of edges, equivalent to wires
12197   //     project polylines on subshapes, and partition, to get geom faces
12198
12199   std::map<int, std::set<int> > shapeIdToVtkIdSet; // shapeId --> set of vtkId on skin
12200   std::set<int> emptySet;
12201   emptySet.clear();
12202   std::set<int> shapeIds;
12203
12204   SMDS_ElemIteratorPtr itelem = sgrps->GetElements();
12205   while (itelem->more())
12206   {
12207     const SMDS_MeshElement *elem = itelem->next();
12208     int shapeId = elem->getshapeId();
12209     int   vtkId = elem->GetVtkID();
12210     if (!shapeIdToVtkIdSet.count(shapeId))
12211     {
12212       shapeIdToVtkIdSet[shapeId] = emptySet;
12213       shapeIds.insert(shapeId);
12214     }
12215     shapeIdToVtkIdSet[shapeId].insert(vtkId);
12216   }
12217
12218   std::map<int, std::set<DownIdType, DownIdCompare> > shapeIdToEdges; // shapeId --> set of downward edges
12219   std::set<DownIdType, DownIdCompare> emptyEdges;
12220   emptyEdges.clear();
12221
12222   std::map<int, std::set<int> >::iterator itShape =  shapeIdToVtkIdSet.begin();
12223   for (; itShape != shapeIdToVtkIdSet.end(); ++itShape)
12224   {
12225     int shapeId = itShape->first;
12226     //MESSAGE(" --- Shape ID --- "<< shapeId);
12227     shapeIdToEdges[shapeId] = emptyEdges;
12228
12229     std::vector<int> nodesEdges;
12230
12231     std::set<int>::iterator its = itShape->second.begin();
12232     for (; its != itShape->second.end(); ++its)
12233     {
12234       int vtkId = *its;
12235       //MESSAGE("     " << vtkId);
12236       int neighborsVtkIds[NBMAXNEIGHBORS];
12237       int downIds[NBMAXNEIGHBORS];
12238       unsigned char downTypes[NBMAXNEIGHBORS];
12239       int nbNeighbors = grid->GetNeighbors(neighborsVtkIds, downIds, downTypes, vtkId);
12240       for (int n = 0; n < nbNeighbors; n++)
12241       {
12242         if (neighborsVtkIds[n]<0) // only smds faces are considered as neighbors here
12243           continue;
12244         int smdsId = meshDS->FromVtkToSmds(neighborsVtkIds[n]);
12245         const SMDS_MeshElement* elem = meshDS->FindElement(smdsId);
12246         if ( shapeIds.count(elem->getshapeId()) && !sgrps->Contains(elem)) // edge : neighbor in the set of shape, not in the group
12247         {
12248           DownIdType edge(downIds[n], downTypes[n]);
12249           if (!shapeIdToEdges[shapeId].count(edge))
12250           {
12251             shapeIdToEdges[shapeId].insert(edge);
12252             int vtkNodeId[3];
12253             int nbNodes = grid->getDownArray(downTypes[n])->getNodes(downIds[n],vtkNodeId);
12254             nodesEdges.push_back(vtkNodeId[0]);
12255             nodesEdges.push_back(vtkNodeId[nbNodes-1]);
12256             //MESSAGE("       --- nodes " << vtkNodeId[0]+1 << " " << vtkNodeId[nbNodes-1]+1);
12257           }
12258         }
12259       }
12260     }
12261
12262     std::list<int> order;
12263     order.clear();
12264     if (nodesEdges.size() > 0)
12265     {
12266       order.push_back(nodesEdges[0]); //MESSAGE("       --- back " << order.back()+1); // SMDS id = VTK id + 1;
12267       nodesEdges[0] = -1;
12268       order.push_back(nodesEdges[1]); //MESSAGE("       --- back " << order.back()+1);
12269       nodesEdges[1] = -1; // do not reuse this edge
12270       bool found = true;
12271       while (found)
12272       {
12273         int nodeTofind = order.back(); // try first to push back
12274         int i = 0;
12275         for ( i = 0; i < (int)nodesEdges.size(); i++ )
12276           if (nodesEdges[i] == nodeTofind)
12277             break;
12278         if ( i == (int) nodesEdges.size() )
12279           found = false; // no follower found on back
12280         else
12281         {
12282           if (i%2) // odd ==> use the previous one
12283             if (nodesEdges[i-1] < 0)
12284               found = false;
12285             else
12286             {
12287               order.push_back(nodesEdges[i-1]); //MESSAGE("       --- back " << order.back()+1);
12288               nodesEdges[i-1] = -1;
12289             }
12290           else // even ==> use the next one
12291             if (nodesEdges[i+1] < 0)
12292               found = false;
12293             else
12294             {
12295               order.push_back(nodesEdges[i+1]); //MESSAGE("       --- back " << order.back()+1);
12296               nodesEdges[i+1] = -1;
12297             }
12298         }
12299         if (found)
12300           continue;
12301         // try to push front
12302         found = true;
12303         nodeTofind = order.front(); // try to push front
12304         for ( i = 0;  i < (int)nodesEdges.size(); i++ )
12305           if ( nodesEdges[i] == nodeTofind )
12306             break;
12307         if ( i == (int)nodesEdges.size() )
12308         {
12309           found = false; // no predecessor found on front
12310           continue;
12311         }
12312         if (i%2) // odd ==> use the previous one
12313           if (nodesEdges[i-1] < 0)
12314             found = false;
12315           else
12316           {
12317             order.push_front(nodesEdges[i-1]); //MESSAGE("       --- front " << order.front()+1);
12318             nodesEdges[i-1] = -1;
12319           }
12320         else // even ==> use the next one
12321           if (nodesEdges[i+1] < 0)
12322             found = false;
12323           else
12324           {
12325             order.push_front(nodesEdges[i+1]); //MESSAGE("       --- front " << order.front()+1);
12326             nodesEdges[i+1] = -1;
12327           }
12328       }
12329     }
12330
12331
12332     std::vector<int> nodes;
12333     nodes.push_back(shapeId);
12334     std::list<int>::iterator itl = order.begin();
12335     for (; itl != order.end(); itl++)
12336     {
12337       nodes.push_back((*itl) + 1); // SMDS id = VTK id + 1;
12338       //MESSAGE("              ordered node " << nodes[nodes.size()-1]);
12339     }
12340     listOfListOfNodes.push_back(nodes);
12341   }
12342
12343   //     partition geom faces with blocFissure
12344   //     mesh blocFissure and geom faces of the skin (external wires given, triangle algo to choose)
12345   //     mesh volume around blocFissure (skin triangles and quadrangle given, tetra algo to choose)
12346
12347   return;
12348 }
12349
12350
12351 //================================================================================
12352 /*!
12353  * \brief Generates skin mesh (containing 2D cells) from 3D mesh
12354  * The created 2D mesh elements based on nodes of free faces of boundary volumes
12355  * \return TRUE if operation has been completed successfully, FALSE otherwise
12356  */
12357 //================================================================================
12358
12359 bool SMESH_MeshEditor::Make2DMeshFrom3D()
12360 {
12361   // iterates on volume elements and detect all free faces on them
12362   SMESHDS_Mesh* aMesh = GetMeshDS();
12363   if (!aMesh)
12364     return false;
12365
12366   ElemFeatures faceType( SMDSAbs_Face );
12367   int nbFree = 0, nbExisted = 0, nbCreated = 0;
12368   SMDS_VolumeIteratorPtr vIt = aMesh->volumesIterator();
12369   while(vIt->more())
12370   {
12371     const SMDS_MeshVolume* volume = vIt->next();
12372     SMDS_VolumeTool vTool( volume, /*ignoreCentralNodes=*/false );
12373     vTool.SetExternalNormal();
12374     const int iQuad = volume->IsQuadratic();
12375     faceType.SetQuad( iQuad );
12376     for ( int iface = 0, n = vTool.NbFaces(); iface < n; iface++ )
12377     {
12378       if (!vTool.IsFreeFace(iface))
12379         continue;
12380       nbFree++;
12381       vector<const SMDS_MeshNode *> nodes;
12382       int nbFaceNodes = vTool.NbFaceNodes(iface);
12383       const SMDS_MeshNode** faceNodes = vTool.GetFaceNodes(iface);
12384       int inode = 0;
12385       for ( ; inode < nbFaceNodes; inode += iQuad+1)
12386         nodes.push_back(faceNodes[inode]);
12387
12388       if (iQuad) // add medium nodes
12389       {
12390         for ( inode = 1; inode < nbFaceNodes; inode += 2)
12391           nodes.push_back(faceNodes[inode]);
12392         if ( nbFaceNodes == 9 ) // bi-quadratic quad
12393           nodes.push_back(faceNodes[8]);
12394       }
12395       // add new face based on volume nodes
12396       if (aMesh->FindElement( nodes, SMDSAbs_Face, /*noMedium=*/false) )
12397       {
12398         nbExisted++; // face already exists
12399       }
12400       else
12401       {
12402         AddElement( nodes, faceType.SetPoly( nbFaceNodes/(iQuad+1) > 4 ));
12403         nbCreated++;
12404       }
12405     }
12406   }
12407   return ( nbFree == ( nbExisted + nbCreated ));
12408 }
12409
12410 namespace
12411 {
12412   inline const SMDS_MeshNode* getNodeWithSameID(SMESHDS_Mesh* mesh, const SMDS_MeshNode* node)
12413   {
12414     if ( const SMDS_MeshNode* n = mesh->FindNode( node->GetID() ))
12415       return n;
12416     return mesh->AddNodeWithID( node->X(),node->Y(),node->Z(), node->GetID() );
12417   }
12418 }
12419 //================================================================================
12420 /*!
12421  * \brief Creates missing boundary elements
12422  *  \param elements - elements whose boundary is to be checked
12423  *  \param dimension - defines type of boundary elements to create
12424  *  \param group - a group to store created boundary elements in
12425  *  \param targetMesh - a mesh to store created boundary elements in
12426  *  \param toCopyElements - if true, the checked elements will be copied into the targetMesh
12427  *  \param toCopyExistingBoundary - if true, not only new but also pre-existing
12428  *                                boundary elements will be copied into the targetMesh
12429  *  \param toAddExistingBondary - if true, not only new but also pre-existing
12430  *                                boundary elements will be added into the new group
12431  *  \param aroundElements - if true, elements will be created on boundary of given
12432  *                          elements else, on boundary of the whole mesh.
12433  * \return nb of added boundary elements
12434  */
12435 //================================================================================
12436
12437 int SMESH_MeshEditor::MakeBoundaryMesh(const TIDSortedElemSet& elements,
12438                                        Bnd_Dimension           dimension,
12439                                        SMESH_Group*            group/*=0*/,
12440                                        SMESH_Mesh*             targetMesh/*=0*/,
12441                                        bool                    toCopyElements/*=false*/,
12442                                        bool                    toCopyExistingBoundary/*=false*/,
12443                                        bool                    toAddExistingBondary/*= false*/,
12444                                        bool                    aroundElements/*= false*/)
12445 {
12446   SMDSAbs_ElementType missType = (dimension == BND_2DFROM3D) ? SMDSAbs_Face : SMDSAbs_Edge;
12447   SMDSAbs_ElementType elemType = (dimension == BND_1DFROM2D) ? SMDSAbs_Face : SMDSAbs_Volume;
12448   // hope that all elements are of the same type, do not check them all
12449   if ( !elements.empty() && (*elements.begin())->GetType() != elemType )
12450     throw SALOME_Exception(LOCALIZED("wrong element type"));
12451
12452   if ( !targetMesh )
12453     toCopyElements = toCopyExistingBoundary = false;
12454
12455   SMESH_MeshEditor tgtEditor( targetMesh ? targetMesh : myMesh );
12456   SMESHDS_Mesh* aMesh = GetMeshDS(), *tgtMeshDS = tgtEditor.GetMeshDS();
12457   int nbAddedBnd = 0;
12458
12459   // editor adding present bnd elements and optionally holding elements to add to the group
12460   SMESH_MeshEditor* presentEditor;
12461   SMESH_MeshEditor tgtEditor2( tgtEditor.GetMesh() );
12462   presentEditor = toAddExistingBondary ? &tgtEditor : &tgtEditor2;
12463
12464   SMESH_MesherHelper helper( *myMesh );
12465   const TopAbs_ShapeEnum missShapeType = ( missType==SMDSAbs_Face ? TopAbs_FACE : TopAbs_EDGE );
12466   SMDS_VolumeTool vTool;
12467   TIDSortedElemSet avoidSet;
12468   const TIDSortedElemSet emptySet, *elemSet = aroundElements ? &elements : &emptySet;
12469   size_t inode;
12470
12471   typedef vector<const SMDS_MeshNode*> TConnectivity;
12472   TConnectivity tgtNodes;
12473   ElemFeatures elemKind( missType ), elemToCopy;
12474
12475   vector<const SMDS_MeshElement*> presentBndElems;
12476   vector<TConnectivity>           missingBndElems;
12477   vector<int>                     freeFacets;
12478   TConnectivity nodes, elemNodes;
12479
12480   SMDS_ElemIteratorPtr eIt;
12481   if (elements.empty()) eIt = aMesh->elementsIterator(elemType);
12482   else                  eIt = SMESHUtils::elemSetIterator( elements );
12483
12484   while ( eIt->more() )
12485   {
12486     const SMDS_MeshElement* elem = eIt->next();
12487     const int              iQuad = elem->IsQuadratic();
12488     elemKind.SetQuad( iQuad );
12489
12490     // ------------------------------------------------------------------------------------
12491     // 1. For an elem, get present bnd elements and connectivities of missing bnd elements
12492     // ------------------------------------------------------------------------------------
12493     presentBndElems.clear();
12494     missingBndElems.clear();
12495     freeFacets.clear(); nodes.clear(); elemNodes.clear();
12496     if ( vTool.Set(elem, /*ignoreCentralNodes=*/true) ) // elem is a volume --------------
12497     {
12498       const SMDS_MeshElement* otherVol = 0;
12499       for ( int iface = 0, n = vTool.NbFaces(); iface < n; iface++ )
12500       {
12501         if ( !vTool.IsFreeFace(iface, &otherVol) &&
12502              ( !aroundElements || elements.count( otherVol )))
12503           continue;
12504         freeFacets.push_back( iface );
12505       }
12506       if ( missType == SMDSAbs_Face )
12507         vTool.SetExternalNormal();
12508       for ( size_t i = 0; i < freeFacets.size(); ++i )
12509       {
12510         int                iface = freeFacets[i];
12511         const SMDS_MeshNode** nn = vTool.GetFaceNodes(iface);
12512         const size_t nbFaceNodes = vTool.NbFaceNodes (iface);
12513         if ( missType == SMDSAbs_Edge ) // boundary edges
12514         {
12515           nodes.resize( 2+iQuad );
12516           for ( size_t i = 0; i < nbFaceNodes; i += 1+iQuad )
12517           {
12518             for ( size_t j = 0; j < nodes.size(); ++j )
12519               nodes[ j ] = nn[ i+j ];
12520             if ( const SMDS_MeshElement* edge =
12521                  aMesh->FindElement( nodes, SMDSAbs_Edge, /*noMedium=*/false ))
12522               presentBndElems.push_back( edge );
12523             else
12524               missingBndElems.push_back( nodes );
12525           }
12526         }
12527         else // boundary face
12528         {
12529           nodes.clear();
12530           for ( inode = 0; inode < nbFaceNodes; inode += 1+iQuad)
12531             nodes.push_back( nn[inode] ); // add corner nodes
12532           if (iQuad)
12533             for ( inode = 1; inode < nbFaceNodes; inode += 2)
12534               nodes.push_back( nn[inode] ); // add medium nodes
12535           int iCenter = vTool.GetCenterNodeIndex(iface); // for HEX27
12536           if ( iCenter > 0 )
12537             nodes.push_back( vTool.GetNodes()[ iCenter ] );
12538
12539           if (const SMDS_MeshElement * f = aMesh->FindElement( nodes,
12540                                                                SMDSAbs_Face, /*noMedium=*/false ))
12541             presentBndElems.push_back( f );
12542           else
12543             missingBndElems.push_back( nodes );
12544
12545           if ( targetMesh != myMesh )
12546           {
12547             // add 1D elements on face boundary to be added to a new mesh
12548             const SMDS_MeshElement* edge;
12549             for ( inode = 0; inode < nbFaceNodes; inode += 1+iQuad)
12550             {
12551               if ( iQuad )
12552                 edge = aMesh->FindEdge( nn[inode], nn[inode+1], nn[inode+2]);
12553               else
12554                 edge = aMesh->FindEdge( nn[inode], nn[inode+1]);
12555               if ( edge && avoidSet.insert( edge ).second )
12556                 presentBndElems.push_back( edge );
12557             }
12558           }
12559         }
12560       }
12561     }
12562     else if ( elem->GetType() == SMDSAbs_Face ) // elem is a face ------------------------
12563     {
12564       avoidSet.clear(), avoidSet.insert( elem );
12565       elemNodes.assign( SMDS_MeshElement::iterator( elem->interlacedNodesIterator() ),
12566                         SMDS_MeshElement::iterator() );
12567       elemNodes.push_back( elemNodes[0] );
12568       nodes.resize( 2 + iQuad );
12569       const int nbLinks = elem->NbCornerNodes();
12570       for ( int i = 0, iN = 0; i < nbLinks; i++, iN += 1+iQuad )
12571       {
12572         nodes[0] = elemNodes[iN];
12573         nodes[1] = elemNodes[iN+1+iQuad];
12574         if ( SMESH_MeshAlgos::FindFaceInSet( nodes[0], nodes[1], *elemSet, avoidSet))
12575           continue; // not free link
12576
12577         if ( iQuad ) nodes[2] = elemNodes[iN+1];
12578         if ( const SMDS_MeshElement* edge =
12579              aMesh->FindElement(nodes,SMDSAbs_Edge,/*noMedium=*/false))
12580           presentBndElems.push_back( edge );
12581         else
12582           missingBndElems.push_back( nodes );
12583       }
12584     }
12585
12586     // ---------------------------------
12587     // 2. Add missing boundary elements
12588     // ---------------------------------
12589     if ( targetMesh != myMesh )
12590       // instead of making a map of nodes in this mesh and targetMesh,
12591       // we create nodes with same IDs.
12592       for ( size_t i = 0; i < missingBndElems.size(); ++i )
12593       {
12594         TConnectivity& srcNodes = missingBndElems[i];
12595         tgtNodes.resize( srcNodes.size() );
12596         for ( inode = 0; inode < srcNodes.size(); ++inode )
12597           tgtNodes[inode] = getNodeWithSameID( tgtMeshDS, srcNodes[inode] );
12598         if ( /*aroundElements && */tgtEditor.GetMeshDS()->FindElement( tgtNodes,
12599                                                                        missType,
12600                                                                        /*noMedium=*/false))
12601           continue;
12602         tgtEditor.AddElement( tgtNodes, elemKind.SetPoly( tgtNodes.size()/(iQuad+1) > 4 ));
12603         ++nbAddedBnd;
12604       }
12605     else
12606       for ( size_t i = 0; i < missingBndElems.size(); ++i )
12607       {
12608         TConnectivity& nodes = missingBndElems[ i ];
12609         if ( /*aroundElements && */tgtEditor.GetMeshDS()->FindElement( nodes,
12610                                                                        missType,
12611                                                                        /*noMedium=*/false))
12612           continue;
12613         SMDS_MeshElement* newElem =
12614           tgtEditor.AddElement( nodes, elemKind.SetPoly( nodes.size()/(iQuad+1) > 4 ));
12615         nbAddedBnd += bool( newElem );
12616
12617         // try to set a new element to a shape
12618         if ( myMesh->HasShapeToMesh() )
12619         {
12620           bool ok = true;
12621           set< pair<TopAbs_ShapeEnum, int > > mediumShapes;
12622           const size_t nbN = nodes.size() / (iQuad+1 );
12623           for ( inode = 0; inode < nbN && ok; ++inode )
12624           {
12625             pair<int, TopAbs_ShapeEnum> i_stype =
12626               helper.GetMediumPos( nodes[inode], nodes[(inode+1)%nbN]);
12627             if (( ok = ( i_stype.first > 0 && i_stype.second >= TopAbs_FACE )))
12628               mediumShapes.insert( make_pair ( i_stype.second, i_stype.first ));
12629           }
12630           if ( ok && mediumShapes.size() > 1 )
12631           {
12632             set< pair<TopAbs_ShapeEnum, int > >::iterator stype_i = mediumShapes.begin();
12633             pair<TopAbs_ShapeEnum, int> stype_i_0 = *stype_i;
12634             for ( ++stype_i; stype_i != mediumShapes.end() && ok; ++stype_i )
12635             {
12636               if (( ok = ( stype_i->first != stype_i_0.first )))
12637                 ok = helper.IsSubShape( aMesh->IndexToShape( stype_i->second ),
12638                                         aMesh->IndexToShape( stype_i_0.second ));
12639             }
12640           }
12641           if ( ok && mediumShapes.begin()->first == missShapeType )
12642             aMesh->SetMeshElementOnShape( newElem, mediumShapes.begin()->second );
12643         }
12644       }
12645
12646     // ----------------------------------
12647     // 3. Copy present boundary elements
12648     // ----------------------------------
12649     if ( toCopyExistingBoundary )
12650       for ( size_t i = 0 ; i < presentBndElems.size(); ++i )
12651       {
12652         const SMDS_MeshElement* e = presentBndElems[i];
12653         tgtNodes.resize( e->NbNodes() );
12654         for ( inode = 0; inode < tgtNodes.size(); ++inode )
12655           tgtNodes[inode] = getNodeWithSameID( tgtMeshDS, e->GetNode(inode) );
12656         presentEditor->AddElement( tgtNodes, elemToCopy.Init( e ));
12657       }
12658     else // store present elements to add them to a group
12659       for ( size_t i = 0 ; i < presentBndElems.size(); ++i )
12660       {
12661         presentEditor->myLastCreatedElems.push_back( presentBndElems[ i ]);
12662       }
12663
12664   } // loop on given elements
12665
12666   // ---------------------------------------------
12667   // 4. Fill group with boundary elements
12668   // ---------------------------------------------
12669   if ( group )
12670   {
12671     if ( SMESHDS_Group* g = dynamic_cast<SMESHDS_Group*>( group->GetGroupDS() ))
12672       for ( size_t i = 0; i < tgtEditor.myLastCreatedElems.size(); ++i )
12673         g->SMDSGroup().Add( tgtEditor.myLastCreatedElems[ i ]);
12674   }
12675   tgtEditor.myLastCreatedElems.clear();
12676   tgtEditor2.myLastCreatedElems.clear();
12677
12678   // -----------------------
12679   // 5. Copy given elements
12680   // -----------------------
12681   if ( toCopyElements && targetMesh != myMesh )
12682   {
12683     if (elements.empty()) eIt = aMesh->elementsIterator(elemType);
12684     else                  eIt = SMESHUtils::elemSetIterator( elements );
12685     while (eIt->more())
12686     {
12687       const SMDS_MeshElement* elem = eIt->next();
12688       tgtNodes.resize( elem->NbNodes() );
12689       for ( inode = 0; inode < tgtNodes.size(); ++inode )
12690         tgtNodes[inode] = getNodeWithSameID( tgtMeshDS, elem->GetNode(inode) );
12691       tgtEditor.AddElement( tgtNodes, elemToCopy.Init( elem ));
12692
12693       tgtEditor.myLastCreatedElems.clear();
12694     }
12695   }
12696   return nbAddedBnd;
12697 }
12698
12699 //================================================================================
12700 /*!
12701  * \brief Copy node position and set \a to node on the same geometry
12702  */
12703 //================================================================================
12704
12705 void SMESH_MeshEditor::copyPosition( const SMDS_MeshNode* from,
12706                                      const SMDS_MeshNode* to )
12707 {
12708   if ( !from || !to ) return;
12709
12710   SMDS_PositionPtr pos = from->GetPosition();
12711   if ( !pos || from->getshapeId() < 1 ) return;
12712
12713   switch ( pos->GetTypeOfPosition() )
12714   {
12715   case SMDS_TOP_3DSPACE: break;
12716
12717   case SMDS_TOP_FACE:
12718   {
12719     SMDS_FacePositionPtr fPos = pos;
12720     GetMeshDS()->SetNodeOnFace( to, from->getshapeId(),
12721                                 fPos->GetUParameter(), fPos->GetVParameter() );
12722     break;
12723   }
12724   case SMDS_TOP_EDGE:
12725   {
12726     // WARNING: it is dangerous to set equal nodes on one EDGE!!!!!!!!
12727     SMDS_EdgePositionPtr ePos = pos;
12728     GetMeshDS()->SetNodeOnEdge( to, from->getshapeId(), ePos->GetUParameter() );
12729     break;
12730   }
12731   case SMDS_TOP_VERTEX:
12732   {
12733     GetMeshDS()->SetNodeOnVertex( to, from->getshapeId() );
12734     break;
12735   }
12736   case SMDS_TOP_UNSPEC:
12737   default:;
12738   }
12739 }